Skip to content

Commit 66e1404

Browse files
committed
feat(core): add configuration validation using typia
1 parent 8cc9d3f commit 66e1404

File tree

6 files changed

+257
-3
lines changed

6 files changed

+257
-3
lines changed

packages/core/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@
5656
"rslib": "npm:@rslib/[email protected]",
5757
"rslog": "^1.2.3",
5858
"tsconfck": "3.1.4",
59-
"typescript": "^5.7.3"
59+
"typescript": "^5.7.3",
60+
"typia": "^7.6.2",
61+
"typia-rspack-plugin": "^1.0.1"
6062
},
6163
"peerDependencies": {
6264
"@microsoft/api-extractor": "^7",

packages/core/rslib.config.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import path from 'node:path';
33
import type { RsbuildPlugin } from '@rsbuild/core';
44
import { pluginPublint } from 'rsbuild-plugin-publint';
55
import { defineConfig } from 'rslib';
6+
import { TypiaRspackPlugin } from 'typia-rspack-plugin';
67

78
const pluginFixDtsTypes: RsbuildPlugin = {
89
name: 'fix-dts-types',
@@ -55,4 +56,14 @@ export default defineConfig({
5556
rslog: '../compiled/rslog/index.js',
5657
},
5758
},
59+
tools: {
60+
rspack: {
61+
plugins: [
62+
new TypiaRspackPlugin({
63+
log: false,
64+
include: [path.resolve('./src/validate.ts')],
65+
}),
66+
],
67+
},
68+
},
5869
});

packages/core/src/config.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ import {
8080
transformSyntaxToRspackTarget,
8181
} from './utils/syntax';
8282
import { loadTsconfig } from './utils/tsconfig';
83+
import { validate } from './validate';
8384

8485
/**
8586
* This function helps you to autocomplete configuration types.
@@ -138,7 +139,9 @@ export async function loadConfig({
138139
envMode,
139140
});
140141

141-
return { content: content as RslibConfig, filePath: configFilePath };
142+
const rslibConfig = validate(content, configFilePath);
143+
144+
return { content: rslibConfig, filePath: configFilePath };
142145
}
143146

144147
const composeExternalsWarnConfig = (

packages/core/src/validate.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import color from 'picocolors';
2+
import * as typia from 'typia';
3+
import type { RslibConfig } from './types';
4+
5+
export const validateConfig: (
6+
input: unknown,
7+
) => typia.IValidation<RslibConfig> = typia.createValidateEquals<RslibConfig>();
8+
9+
export function validate(input: unknown, configPath?: string): RslibConfig {
10+
const result = validateConfig(input);
11+
12+
if (result.success) {
13+
return result.data;
14+
}
15+
16+
const messages = result.errors.flatMap(({ expected, path, value }) => {
17+
if (expected === 'undefined') {
18+
// Unknown properties
19+
return [`Unknown property: \`${color.red(path)}\` in configuration`, ''];
20+
}
21+
22+
return [
23+
`Invalid config on \`${color.red(path)}\`.`,
24+
` - Expect to be ${color.green(expected)}`,
25+
` - Got: ${color.red(whatIs(value))}`,
26+
'',
27+
];
28+
});
29+
30+
// We use `Array.isArray` outside to deal with error messages
31+
throw new Error(
32+
[
33+
`Invalid configuration${
34+
configPath ? ` loaded from ${color.dim(configPath)}` : '.'
35+
}`,
36+
'',
37+
]
38+
.concat(messages)
39+
.join('\n'),
40+
);
41+
}
42+
43+
function whatIs(value: unknown): string {
44+
return Object.prototype.toString
45+
.call(value)
46+
.replace(/^\[object\s+([a-z]+)\]$/i, '$1')
47+
.toLowerCase();
48+
}

0 commit comments

Comments
 (0)