@webergency-utils/typechecker 0.1.10 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +169 -47
- package/dist/engine/generators.d.ts +2 -1
- package/dist/engine/generators.js +37 -11
- package/dist/engine/resolver.js +279 -68
- package/dist/engine/staticAsserts.js +2 -1
- package/dist/index.d.ts +17 -13
- package/dist/index.js +35 -0
- package/dist/runtime/tags/format.d.ts +7 -0
- package/dist/runtime/tags/tag.d.ts +1 -1
- package/dist/runtime/tags.d.ts +1 -1
- package/dist/runtime/validators.d.ts +70 -16
- package/dist/runtime/validators.js +935 -219
- package/dist/transformer.js +37 -58
- package/package.json +12 -3
package/dist/transformer.js
CHANGED
|
@@ -3,7 +3,14 @@ import { buildValidator, generateHash, buildJsonSchema, objectToAst } from './en
|
|
|
3
3
|
export { buildValidator, generateHash, buildJsonSchema } from './engine/resolver.js';
|
|
4
4
|
import { hoistRegistrations } from './engine/hoister.js';
|
|
5
5
|
import { installStaticConstraintDiagnostics } from './engine/staticAsserts.js';
|
|
6
|
-
const
|
|
6
|
+
const TYPE_FUNCTIONS = ['is', 'assert', 'assertGuard', 'validate', 'jsonSchema'];
|
|
7
|
+
const SCHEMA_FUNCTIONS = ['isSchema', 'assertSchema', 'assertGuardSchema', 'validateSchema'];
|
|
8
|
+
function metadataCall(method, args) {
|
|
9
|
+
return ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('MetadataStore'), method), undefined, args);
|
|
10
|
+
}
|
|
11
|
+
function argOrUndefined(args, index) {
|
|
12
|
+
return args[index] || ts.factory.createIdentifier('undefined');
|
|
13
|
+
}
|
|
7
14
|
export default function transformer(program) {
|
|
8
15
|
const checker = program.getTypeChecker();
|
|
9
16
|
installStaticConstraintDiagnostics(program);
|
|
@@ -13,14 +20,29 @@ export default function transformer(program) {
|
|
|
13
20
|
const schemasCache = new Map();
|
|
14
21
|
const requiredUtils = new Set();
|
|
15
22
|
const visitor = (node) => {
|
|
16
|
-
// Skip visiting ImportDeclarations to preserve their original symbols and avoid compiler crashes
|
|
17
23
|
if (ts.isImportDeclaration(node)) {
|
|
18
24
|
return node;
|
|
19
25
|
}
|
|
20
|
-
// Handle runtime function calls (is, assert, assertGuard, validate, jsonSchema)
|
|
21
26
|
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {
|
|
22
27
|
const fnName = node.expression.text;
|
|
23
|
-
if (
|
|
28
|
+
if (SCHEMA_FUNCTIONS.includes(fnName)) {
|
|
29
|
+
requiredUtils.add('MetadataStore');
|
|
30
|
+
const schemaArg = argOrUndefined(node.arguments, 0);
|
|
31
|
+
const inputArg = argOrUndefined(node.arguments, 1);
|
|
32
|
+
const optionsArg = argOrUndefined(node.arguments, 2);
|
|
33
|
+
const compiled = metadataCall('getOrCompileSchema', [schemaArg]);
|
|
34
|
+
if (fnName === 'validateSchema') {
|
|
35
|
+
return metadataCall('validate', [compiled, inputArg, optionsArg]);
|
|
36
|
+
}
|
|
37
|
+
if (fnName === 'isSchema') {
|
|
38
|
+
return metadataCall('is', [compiled, inputArg, optionsArg]);
|
|
39
|
+
}
|
|
40
|
+
if (fnName === 'assertSchema') {
|
|
41
|
+
return metadataCall('assert', [compiled, inputArg, optionsArg]);
|
|
42
|
+
}
|
|
43
|
+
return metadataCall('assertGuard', [compiled, inputArg, optionsArg]);
|
|
44
|
+
}
|
|
45
|
+
if (TYPE_FUNCTIONS.includes(fnName)) {
|
|
24
46
|
const typeArg = node.typeArguments?.[0];
|
|
25
47
|
if (typeArg) {
|
|
26
48
|
const type = checker.getTypeFromTypeNode(typeArg);
|
|
@@ -32,65 +54,22 @@ export default function transformer(program) {
|
|
|
32
54
|
const schemaObj = buildJsonSchema(type, checker);
|
|
33
55
|
schemasCache.set(hash, objectToAst(schemaObj));
|
|
34
56
|
}
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
let hasSchema = false;
|
|
39
|
-
let schemaExpr;
|
|
40
|
-
if (node.arguments[1]) {
|
|
41
|
-
const optArg = node.arguments[1];
|
|
42
|
-
const optType = checker.getTypeAtLocation(optArg);
|
|
43
|
-
const schemaProp = optType.getProperty('schema');
|
|
44
|
-
if (schemaProp) {
|
|
45
|
-
hasSchema = true;
|
|
46
|
-
if (ts.isObjectLiteralExpression(optArg)) {
|
|
47
|
-
const prop = optArg.properties.find(p => {
|
|
48
|
-
if (ts.isPropertyAssignment(p) && ts.isIdentifier(p.name) && p.name.text === 'schema') {
|
|
49
|
-
return true;
|
|
50
|
-
}
|
|
51
|
-
if (ts.isShorthandPropertyAssignment(p) && p.name.text === 'schema') {
|
|
52
|
-
return true;
|
|
53
|
-
}
|
|
54
|
-
return false;
|
|
55
|
-
});
|
|
56
|
-
if (prop) {
|
|
57
|
-
if (ts.isPropertyAssignment(prop)) {
|
|
58
|
-
schemaExpr = prop.initializer;
|
|
59
|
-
}
|
|
60
|
-
else if (ts.isShorthandPropertyAssignment(prop)) {
|
|
61
|
-
schemaExpr = prop.name;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
if (!schemaExpr) {
|
|
66
|
-
schemaExpr = ts.factory.createPropertyAccessExpression(optArg, 'schema');
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
if (hasSchema && schemaExpr) {
|
|
71
|
-
const compileAccess = ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('MetadataStore'), 'getOrCompileSchema');
|
|
72
|
-
getCall = ts.factory.createCallExpression(compileAccess, undefined, [schemaExpr]);
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
const mdStoreAccess = ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('MetadataStore'), 'getValidator');
|
|
76
|
-
getCall = ts.factory.createCallExpression(mdStoreAccess, undefined, [ts.factory.createStringLiteral(hash)]);
|
|
77
|
-
}
|
|
57
|
+
const inputArg = argOrUndefined(node.arguments, 0);
|
|
58
|
+
const optionsArg = argOrUndefined(node.arguments, 1);
|
|
59
|
+
const getValidator = metadataCall('getValidator', [ts.factory.createStringLiteral(hash)]);
|
|
78
60
|
if (fnName === 'jsonSchema') {
|
|
79
|
-
|
|
80
|
-
return ts.factory.createCallExpression(getSchemaAccess, undefined, [ts.factory.createStringLiteral(hash)]);
|
|
61
|
+
return metadataCall('getSchema', [ts.factory.createStringLiteral(hash)]);
|
|
81
62
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
return ts.factory.createCallExpression(mdStoreAccess, undefined, [getCall, arg0, arg1]);
|
|
63
|
+
if (fnName === 'validate') {
|
|
64
|
+
return metadataCall('validate', [getValidator, inputArg, optionsArg]);
|
|
85
65
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
return ts.factory.createCallExpression(mdStoreAccess, undefined, [getCall, arg0, arg1]);
|
|
66
|
+
if (fnName === 'is') {
|
|
67
|
+
return metadataCall('is', [getValidator, inputArg, optionsArg]);
|
|
89
68
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
return ts.factory.createCallExpression(mdStoreAccess, undefined, [getCall, arg0, arg1]);
|
|
69
|
+
if (fnName === 'assert') {
|
|
70
|
+
return metadataCall('assert', [getValidator, inputArg, optionsArg]);
|
|
93
71
|
}
|
|
72
|
+
return metadataCall('assertGuard', [getValidator, inputArg, optionsArg]);
|
|
94
73
|
}
|
|
95
74
|
}
|
|
96
75
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webergency-utils/typechecker",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "TypeScript compiler plugin for runtime validation",
|
|
6
6
|
"author": "radixxko",
|
|
7
|
+
"license": "MIT",
|
|
7
8
|
"main": "dist/index.js",
|
|
8
9
|
"types": "dist/index.d.ts",
|
|
9
10
|
"exports": {
|
|
@@ -32,15 +33,21 @@
|
|
|
32
33
|
"default": "./dist/plugin.js"
|
|
33
34
|
}
|
|
34
35
|
},
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
35
39
|
"files": [
|
|
36
40
|
"dist/**/*"
|
|
37
41
|
],
|
|
38
42
|
"scripts": {
|
|
39
43
|
"lint": "eslint .",
|
|
40
44
|
"test": "vitest run",
|
|
45
|
+
"fuzz": "npm run build:fuzz && jazzer fuzz_typechecker.cjs",
|
|
41
46
|
"coverage": "vitest run --coverage",
|
|
42
|
-
"clean": "rm -rf ./dist
|
|
47
|
+
"clean": "rm -rf ./dist ./dist-fuzz",
|
|
48
|
+
"reset": "npm run clean && rm -rf node_modules package-lock.json && npm i",
|
|
43
49
|
"build": "npm run clean && tsc && node update_imports.js",
|
|
50
|
+
"build:fuzz": "esbuild src/fuzz-runtime.ts --bundle --platform=node --format=cjs --outfile=dist-fuzz/runtime.cjs",
|
|
44
51
|
"commit": "node -e \"const version = require('./package.json').version.trim(); require('child_process').execSync('git add . && git commit -m \\\"Version ' + version + '\\\"');\"",
|
|
45
52
|
"version": "npm run build && npm publish --access public && npm run commit && git push"
|
|
46
53
|
},
|
|
@@ -57,10 +64,12 @@
|
|
|
57
64
|
},
|
|
58
65
|
"devDependencies": {
|
|
59
66
|
"@eslint/js": "^10.0.1",
|
|
67
|
+
"@jazzer.js/core": "^4.0.0",
|
|
60
68
|
"@stylistic/eslint-plugin": "^5.10.0",
|
|
61
|
-
"@types/node": "^
|
|
69
|
+
"@types/node": "^26.1.1",
|
|
62
70
|
"@typescript/typescript6": "^6.0.2",
|
|
63
71
|
"@vitest/coverage-v8": "^4.1.6",
|
|
72
|
+
"esbuild": "^0.28.1",
|
|
64
73
|
"eslint": "^10.4.1",
|
|
65
74
|
"typescript": "^6.0.3 || ^7.0.0",
|
|
66
75
|
"typescript-eslint": "^8.60.0",
|