Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): add configuration validation using typia #730

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@
"rslib": "npm:@rslib/core@0.4.0",
"rslog": "^1.2.3",
"tsconfck": "3.1.4",
"typescript": "^5.7.3"
"typescript": "^5.7.3",
"typia": "^7.6.2",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typia has so many dependencies, this is a bit hard to accept...
image

https://pkg-graph.info/typia

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It indeed has too many dependencies, but it is tree-shakable and we are using it as devDependencies.

The bundle size of Rslib is increased from 106.8 kB to 2484.4 kB. But the size change mainly produced by the validation functions generated by typia:

image

As you can see, the src/validate.ts has 2.33 MB in stats. And we can make validation opt-in and lazy loaded.

For end users, no additional dependencies need to be installed, and the bundle size of @rslib/core increases by only approximately 2.5 MB.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we make the validation opt-in, how can users enable the validation?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

E.g.: if the TypiaRspackPlugin(which transforms src/validation.ts) is commented out, the bundle size of @rslib/core in this PR is only 108.4 kB.

image

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we make the validation opt-in, how can users enable the validation?

Maybe through a environment variable?

// rslib.config.js
process.env['RSLIB_CONFIG_VALIDATION'] = true

export default {}

Or maybe a strictDefineConfig API?

import {strictDefineConfig} from '@rslib/core'

export default strictDefineConfig({})

But I would prefer enabling by default. And opt-out using environment variables.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's opt-in, I don't think most users will actively enable it...

If it's opt-out, the performance overhead doesn't seem worth it, we can write code to do some validation manually.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I'm closing this PR. Thank you for your review

"typia-rspack-plugin": "^1.0.1"
},
"peerDependencies": {
"@microsoft/api-extractor": "^7",
Expand Down
11 changes: 11 additions & 0 deletions packages/core/rslib.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import path from 'node:path';
import type { RsbuildPlugin } from '@rsbuild/core';
import { pluginPublint } from 'rsbuild-plugin-publint';
import { defineConfig } from 'rslib';
import { TypiaRspackPlugin } from 'typia-rspack-plugin';

const pluginFixDtsTypes: RsbuildPlugin = {
name: 'fix-dts-types',
Expand Down Expand Up @@ -55,4 +56,14 @@ export default defineConfig({
rslog: '../compiled/rslog/index.js',
},
},
tools: {
rspack: {
plugins: [
new TypiaRspackPlugin({
log: false,
include: [path.resolve('./src/validate.ts')],
}),
],
},
},
});
5 changes: 4 additions & 1 deletion packages/core/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ import {
transformSyntaxToRspackTarget,
} from './utils/syntax';
import { loadTsconfig } from './utils/tsconfig';
import { validate } from './validate';

/**
* This function helps you to autocomplete configuration types.
Expand Down Expand Up @@ -138,7 +139,9 @@ export async function loadConfig({
envMode,
});

return { content: content as RslibConfig, filePath: configFilePath };
const rslibConfig = validate(content, configFilePath);

return { content: rslibConfig, filePath: configFilePath };
}

const composeExternalsWarnConfig = (
Expand Down
48 changes: 48 additions & 0 deletions packages/core/src/validate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import color from 'picocolors';
import * as typia from 'typia';
import type { RslibConfig } from './types';

export const validateConfig: (
input: unknown,
) => typia.IValidation<RslibConfig> = typia.createValidateEquals<RslibConfig>();

Check failure on line 7 in packages/core/src/validate.ts

View workflow job for this annotation

GitHub Actions / ut (ubuntu-latest, 18)

tests/config.test.ts

Error: Error on typia.createValidateEquals(): no transform has been configured. Read and follow https://typia.io/docs/setup please. ❯ halt ../../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:934:9 ❯ Proxy.createValidateEquals ../../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:895:3 ❯ src/validate.ts:7:45 ❯ src/config.ts:15:32

Check failure on line 7 in packages/core/src/validate.ts

View workflow job for this annotation

GitHub Actions / ut (ubuntu-latest, 18)

tests/entry.test.ts

Error: Error on typia.createValidateEquals(): no transform has been configured. Read and follow https://typia.io/docs/setup please. ❯ halt ../../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:934:9 ❯ Proxy.createValidateEquals ../../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:895:3 ❯ src/validate.ts:7:45 ❯ src/config.ts:15:32

Check failure on line 7 in packages/core/src/validate.ts

View workflow job for this annotation

GitHub Actions / ut (ubuntu-latest, 18)

tests/external.test.ts

Error: Error on typia.createValidateEquals(): no transform has been configured. Read and follow https://typia.io/docs/setup please. ❯ halt ../../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:934:9 ❯ Proxy.createValidateEquals ../../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:895:3 ❯ src/validate.ts:7:45 ❯ src/config.ts:15:32

Check failure on line 7 in packages/core/src/validate.ts

View workflow job for this annotation

GitHub Actions / integration-e2e (ubuntu-latest, 18)

integration/auto-external/index.test.ts

Error: Error on typia.createValidateEquals(): no transform has been configured. Read and follow https://typia.io/docs/setup please. ❯ halt ../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:934:9 ❯ Proxy.createValidateEquals ../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:895:3 ❯ ../packages/core/src/validate.ts:7:45 ❯ ../packages/core/src/config.ts:15:32

Check failure on line 7 in packages/core/src/validate.ts

View workflow job for this annotation

GitHub Actions / integration-e2e (ubuntu-latest, 18)

integration/externals/index.test.ts

Error: Error on typia.createValidateEquals(): no transform has been configured. Read and follow https://typia.io/docs/setup please. ❯ halt ../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:934:9 ❯ Proxy.createValidateEquals ../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:895:3 ❯ ../packages/core/src/validate.ts:7:45 ❯ ../packages/core/src/config.ts:15:32

Check failure on line 7 in packages/core/src/validate.ts

View workflow job for this annotation

GitHub Actions / ut (ubuntu-latest, 20)

tests/config.test.ts

Error: Error on typia.createValidateEquals(): no transform has been configured. Read and follow https://typia.io/docs/setup please. ❯ halt ../../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:934:9 ❯ Proxy.createValidateEquals ../../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:895:3 ❯ src/validate.ts:7:45 ❯ src/config.ts:15:32

Check failure on line 7 in packages/core/src/validate.ts

View workflow job for this annotation

GitHub Actions / ut (ubuntu-latest, 20)

tests/entry.test.ts

Error: Error on typia.createValidateEquals(): no transform has been configured. Read and follow https://typia.io/docs/setup please. ❯ halt ../../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:934:9 ❯ Proxy.createValidateEquals ../../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:895:3 ❯ src/validate.ts:7:45 ❯ src/config.ts:15:32

Check failure on line 7 in packages/core/src/validate.ts

View workflow job for this annotation

GitHub Actions / ut (ubuntu-latest, 20)

tests/external.test.ts

Error: Error on typia.createValidateEquals(): no transform has been configured. Read and follow https://typia.io/docs/setup please. ❯ halt ../../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:934:9 ❯ Proxy.createValidateEquals ../../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:895:3 ❯ src/validate.ts:7:45 ❯ src/config.ts:15:32

Check failure on line 7 in packages/core/src/validate.ts

View workflow job for this annotation

GitHub Actions / integration-e2e (ubuntu-latest, 20)

integration/auto-external/index.test.ts

Error: Error on typia.createValidateEquals(): no transform has been configured. Read and follow https://typia.io/docs/setup please. ❯ halt ../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:934:9 ❯ Proxy.createValidateEquals ../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:895:3 ❯ ../packages/core/src/validate.ts:7:45 ❯ ../packages/core/src/config.ts:15:32

Check failure on line 7 in packages/core/src/validate.ts

View workflow job for this annotation

GitHub Actions / integration-e2e (ubuntu-latest, 20)

integration/externals/index.test.ts

Error: Error on typia.createValidateEquals(): no transform has been configured. Read and follow https://typia.io/docs/setup please. ❯ halt ../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:934:9 ❯ Proxy.createValidateEquals ../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:895:3 ❯ ../packages/core/src/validate.ts:7:45 ❯ ../packages/core/src/config.ts:15:32

Check failure on line 7 in packages/core/src/validate.ts

View workflow job for this annotation

GitHub Actions / ut (ubuntu-latest, 22)

tests/config.test.ts

Error: Error on typia.createValidateEquals(): no transform has been configured. Read and follow https://typia.io/docs/setup please. ❯ halt ../../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:934:9 ❯ Proxy.createValidateEquals ../../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:895:3 ❯ src/validate.ts:7:45 ❯ src/config.ts:15:32

Check failure on line 7 in packages/core/src/validate.ts

View workflow job for this annotation

GitHub Actions / ut (ubuntu-latest, 22)

tests/entry.test.ts

Error: Error on typia.createValidateEquals(): no transform has been configured. Read and follow https://typia.io/docs/setup please. ❯ halt ../../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:934:9 ❯ Proxy.createValidateEquals ../../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:895:3 ❯ src/validate.ts:7:45 ❯ src/config.ts:15:32

Check failure on line 7 in packages/core/src/validate.ts

View workflow job for this annotation

GitHub Actions / ut (ubuntu-latest, 22)

tests/external.test.ts

Error: Error on typia.createValidateEquals(): no transform has been configured. Read and follow https://typia.io/docs/setup please. ❯ halt ../../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:934:9 ❯ Proxy.createValidateEquals ../../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:895:3 ❯ src/validate.ts:7:45 ❯ src/config.ts:15:32

Check failure on line 7 in packages/core/src/validate.ts

View workflow job for this annotation

GitHub Actions / integration-e2e (ubuntu-latest, 22)

integration/auto-external/index.test.ts

Error: Error on typia.createValidateEquals(): no transform has been configured. Read and follow https://typia.io/docs/setup please. ❯ halt ../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:934:9 ❯ Proxy.createValidateEquals ../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:895:3 ❯ ../packages/core/src/validate.ts:7:45 ❯ ../packages/core/src/config.ts:15:32

Check failure on line 7 in packages/core/src/validate.ts

View workflow job for this annotation

GitHub Actions / integration-e2e (ubuntu-latest, 22)

integration/externals/index.test.ts

Error: Error on typia.createValidateEquals(): no transform has been configured. Read and follow https://typia.io/docs/setup please. ❯ halt ../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:934:9 ❯ Proxy.createValidateEquals ../node_modules/.pnpm/typia@7.6.2_typescript@5.7.3/node_modules/typia/src/module.ts:895:3 ❯ ../packages/core/src/validate.ts:7:45 ❯ ../packages/core/src/config.ts:15:32

export function validate(input: unknown, configPath?: string): RslibConfig {
const result = validateConfig(input);

if (result.success) {
return result.data;
}

const messages = result.errors.flatMap(({ expected, path, value }) => {
if (expected === 'undefined') {
// Unknown properties
return [`Unknown property: \`${color.red(path)}\` in configuration`, ''];
}

return [
`Invalid config on \`${color.red(path)}\`.`,
` - Expect to be ${color.green(expected)}`,
` - Got: ${color.red(whatIs(value))}`,
'',
];
});

// We use `Array.isArray` outside to deal with error messages
throw new Error(
[
`Invalid configuration${
configPath ? ` loaded from ${color.dim(configPath)}` : '.'
}`,
'',
]
.concat(messages)
.join('\n'),
);
}

function whatIs(value: unknown): string {
return Object.prototype.toString
.call(value)
.replace(/^\[object\s+([a-z]+)\]$/i, '$1')
.toLowerCase();
}
Loading
Loading