@webergency-utils/typechecker 0.2.2 → 0.2.3

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.
@@ -5,6 +5,7 @@ import { hoistRegistrations } from './engine/hoister.js';
5
5
  import { installStaticConstraintDiagnostics } from './engine/staticAsserts.js';
6
6
  const TYPE_FUNCTIONS = ['is', 'assert', 'assertGuard', 'validate', 'jsonSchema'];
7
7
  const SCHEMA_FUNCTIONS = ['isSchema', 'assertSchema', 'assertGuardSchema', 'validateSchema'];
8
+ const VALIDATION_FUNCTIONS = ['is', 'assert', 'assertGuard', 'validate'];
8
9
  function metadataCall(method, args) {
9
10
  return ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('MetadataStore'), method), undefined, args);
10
11
  }
@@ -19,13 +20,62 @@ export default function transformer(program) {
19
20
  const validatorCache = new Map();
20
21
  const schemasCache = new Map();
21
22
  const requiredUtils = new Set();
23
+ const helperBindings = new Map();
24
+ const helperNamespaces = new Set();
25
+ const hashByTypeId = new Map();
26
+ const getTypeHash = (type) => {
27
+ const typeId = type.id;
28
+ if (typeof typeId === 'number') {
29
+ const cached = hashByTypeId.get(typeId);
30
+ if (cached) {
31
+ return cached;
32
+ }
33
+ const hash = generateHash(type, checker);
34
+ hashByTypeId.set(typeId, hash);
35
+ return hash;
36
+ }
37
+ return generateHash(type, checker);
38
+ };
39
+ for (const statement of sourceFile.statements) {
40
+ if (!ts.isImportDeclaration(statement)) {
41
+ continue;
42
+ }
43
+ const moduleName = ts.isStringLiteral(statement.moduleSpecifier)
44
+ ? statement.moduleSpecifier.text
45
+ : '';
46
+ const isTypecheckerImport = moduleName === '@webergency-utils/typechecker' ||
47
+ /(?:^|\/)(?:src\/)?index\.(?:js|ts)$/.test(moduleName);
48
+ if (!isTypecheckerImport) {
49
+ continue;
50
+ }
51
+ const bindings = statement.importClause?.namedBindings;
52
+ if (bindings && ts.isNamedImports(bindings)) {
53
+ for (const element of bindings.elements) {
54
+ const importedName = element.propertyName?.text || element.name.text;
55
+ if (TYPE_FUNCTIONS.includes(importedName) || SCHEMA_FUNCTIONS.includes(importedName)) {
56
+ helperBindings.set(element.name.text, importedName);
57
+ }
58
+ }
59
+ }
60
+ else if (bindings && ts.isNamespaceImport(bindings)) {
61
+ helperNamespaces.add(bindings.name.text);
62
+ }
63
+ }
22
64
  const visitor = (node) => {
23
65
  if (ts.isImportDeclaration(node)) {
24
66
  return node;
25
67
  }
26
- if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {
27
- const fnName = node.expression.text;
28
- if (SCHEMA_FUNCTIONS.includes(fnName)) {
68
+ if (ts.isCallExpression(node)) {
69
+ let fnName;
70
+ if (ts.isIdentifier(node.expression)) {
71
+ fnName = helperBindings.get(node.expression.text);
72
+ }
73
+ else if (ts.isPropertyAccessExpression(node.expression) &&
74
+ ts.isIdentifier(node.expression.expression) &&
75
+ helperNamespaces.has(node.expression.expression.text)) {
76
+ fnName = node.expression.name.text;
77
+ }
78
+ if (fnName && SCHEMA_FUNCTIONS.includes(fnName)) {
29
79
  requiredUtils.add('MetadataStore');
30
80
  const schemaArg = argOrUndefined(node.arguments, 0);
31
81
  const inputArg = argOrUndefined(node.arguments, 1);
@@ -42,34 +92,37 @@ export default function transformer(program) {
42
92
  }
43
93
  return metadataCall('assertGuard', [compiled, inputArg, optionsArg]);
44
94
  }
45
- if (TYPE_FUNCTIONS.includes(fnName)) {
95
+ if (fnName && TYPE_FUNCTIONS.includes(fnName)) {
46
96
  const typeArg = node.typeArguments?.[0];
47
97
  if (typeArg) {
48
98
  const type = checker.getTypeFromTypeNode(typeArg);
49
- const hash = generateHash(type, checker);
50
- if (!validatorCache.has(hash)) {
51
- buildValidator(type, checker, validatorCache, requiredUtils);
52
- }
53
- if (!schemasCache.has(hash)) {
54
- const schemaObj = buildJsonSchema(type, checker);
55
- schemasCache.set(hash, objectToAst(schemaObj));
56
- }
57
- const inputArg = argOrUndefined(node.arguments, 0);
58
- const optionsArg = argOrUndefined(node.arguments, 1);
59
- const getValidator = metadataCall('getValidator', [ts.factory.createStringLiteral(hash)]);
99
+ const hash = getTypeHash(type);
60
100
  if (fnName === 'jsonSchema') {
101
+ requiredUtils.add('MetadataStore');
102
+ if (!schemasCache.has(hash)) {
103
+ const schemaObj = buildJsonSchema(type, checker);
104
+ schemasCache.set(hash, objectToAst(schemaObj));
105
+ }
61
106
  return metadataCall('getSchema', [ts.factory.createStringLiteral(hash)]);
62
107
  }
63
- if (fnName === 'validate') {
64
- return metadataCall('validate', [getValidator, inputArg, optionsArg]);
65
- }
66
- if (fnName === 'is') {
67
- return metadataCall('is', [getValidator, inputArg, optionsArg]);
68
- }
69
- if (fnName === 'assert') {
70
- return metadataCall('assert', [getValidator, inputArg, optionsArg]);
108
+ if (VALIDATION_FUNCTIONS.includes(fnName)) {
109
+ if (!validatorCache.has(hash)) {
110
+ buildValidator(type, checker, validatorCache, requiredUtils, hash);
111
+ }
112
+ const inputArg = argOrUndefined(node.arguments, 0);
113
+ const optionsArg = argOrUndefined(node.arguments, 1);
114
+ const getValidator = metadataCall('getValidator', [ts.factory.createStringLiteral(hash)]);
115
+ if (fnName === 'validate') {
116
+ return metadataCall('validate', [getValidator, inputArg, optionsArg]);
117
+ }
118
+ if (fnName === 'is') {
119
+ return metadataCall('is', [getValidator, inputArg, optionsArg]);
120
+ }
121
+ if (fnName === 'assert') {
122
+ return metadataCall('assert', [getValidator, inputArg, optionsArg]);
123
+ }
124
+ return metadataCall('assertGuard', [getValidator, inputArg, optionsArg]);
71
125
  }
72
- return metadataCall('assertGuard', [getValidator, inputArg, optionsArg]);
73
126
  }
74
127
  }
75
128
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webergency-utils/typechecker",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "type": "module",
5
5
  "description": "TypeScript compiler plugin for runtime validation",
6
6
  "author": "radixxko",
@@ -42,6 +42,7 @@
42
42
  "scripts": {
43
43
  "lint": "eslint .",
44
44
  "test": "vitest run",
45
+ "bench": "npm run build && node scripts/perf-microbench.mjs",
45
46
  "fuzz": "npm run build:fuzz && jazzer fuzz_typechecker.cjs",
46
47
  "coverage": "vitest run --coverage",
47
48
  "clean": "rm -rf ./dist ./dist-fuzz",