@elliots/typical 0.2.1 → 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.
- package/README.md +45 -6
- package/dist/src/config.d.ts +7 -3
- package/dist/src/config.js +5 -20
- package/dist/src/config.js.map +1 -1
- package/dist/src/transformer.js +2 -2
- package/dist/src/transformer.js.map +1 -1
- package/package.json +2 -2
- package/src/config.ts +12 -27
- package/src/transformer.ts +2 -2
package/README.md
CHANGED
|
@@ -294,6 +294,7 @@ Create a `typical.json` file in your project root (optional):
|
|
|
294
294
|
| `validateCasts` | `false` | Validate type assertions (`as Type`) |
|
|
295
295
|
| `transformJSONParse` | `true` | Transform `JSON.parse` to validate and filter to typed properties |
|
|
296
296
|
| `transformJSONStringify` | `true` | Transform `JSON.stringify` to only include typed properties |
|
|
297
|
+
| `reusableValidators` | `true` | Hoist validators to module scope for reduced code size |
|
|
297
298
|
|
|
298
299
|
---
|
|
299
300
|
|
|
@@ -346,15 +347,15 @@ Typical uses a Go-based compiler that leverages the TypeScript type checker to a
|
|
|
346
347
|
|
|
347
348
|
Types that can't be validated at runtime (like generic type parameters `T`) are skipped. You can still use `any` and `unknown` to opt out of validation.
|
|
348
349
|
|
|
349
|
-
## Compiler
|
|
350
|
+
## Compiler Optimisations
|
|
350
351
|
|
|
351
|
-
The generated validation code is
|
|
352
|
+
The generated validation code is optimised for runtime performance:
|
|
352
353
|
|
|
353
|
-
- **
|
|
354
|
-
- **
|
|
355
|
-
- **
|
|
356
|
-
- **Type-aware dirty tracking** - Primitives stay validated after being passed to functions (they're copied), but objects are re-validated (they could be mutated)
|
|
354
|
+
- **Reusable validators** - When the same type is validated multiple times, Typical hoists the validation logic to a reusable function at module scope. Nested types that appear in multiple places (e.g., `Address` used in both `User` and `Company`) are also extracted and reused.
|
|
355
|
+
- **Smart redundancy elimination** - Skips validation when returning values that are already known to be valid: validated parameters, properties of validated objects, variables assigned from casts or `JSON.parse`, and aliased variables
|
|
356
|
+
- **Type-aware dirty tracking** - Tracks when validated values might become invalid. Primitives stay valid after being passed to functions (they're copied), but objects are re-validated if passed to unknown functions. Pure functions (listed in the config) like `console.log` don't invalidate objects.
|
|
357
357
|
- **Union early bail-out** - Union type checks use if-else chains so the first matching type succeeds immediately
|
|
358
|
+
- **Skip comments** - Add `// @typical-ignore` before a function to skip all validation for it
|
|
358
359
|
|
|
359
360
|
## Debugging
|
|
360
361
|
|
|
@@ -370,3 +371,41 @@ DEBUG=1 npm run build
|
|
|
370
371
|
- Type-only imports of classes aren't checked (can't do instanceof on type-only imports)
|
|
371
372
|
- Validation of functions is just not done. Need to think about that one.
|
|
372
373
|
- Some complex types may not be fully supported yet. If you find any that fail, please open an issue!
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## Benchmarks
|
|
378
|
+
|
|
379
|
+
Runtime validation performance comparing Typical vs Zod vs no validation:
|
|
380
|
+
|
|
381
|
+
| Scenario | Nothing | Typical | Zod | vs Nothing | vs Zod |
|
|
382
|
+
| ---------------------------------- | --------: | --------: | --------: | -----------------------------: | ------------------------------: |
|
|
383
|
+
| string | 23.91M/s | 24.86M/s | 24.80M/s | ${\textsf{\color{olive}1.0x}}$ | ${\textsf{\color{olive}1.0x}}$ |
|
|
384
|
+
| number | 24.33M/s | 25.44M/s | 24.44M/s | ${\textsf{\color{olive}1.0x}}$ | ${\textsf{\color{olive}1.0x}}$ |
|
|
385
|
+
| boolean | 24.49M/s | 24.49M/s | 24.19M/s | ${\textsf{\color{olive}1.0x}}$ | ${\textsf{\color{olive}1.0x}}$ |
|
|
386
|
+
| object w/ template literals | 24.53M/s | 21.39M/s | 7.71M/s | ${\textsf{\color{olive}0.9x}}$ | ${\textsf{\color{green}2.8x}}$ |
|
|
387
|
+
| nested w/ template literals | 24.69M/s | 8.05M/s | 2.31M/s | ${\textsf{\color{red}0.3x}}$ | ${\textsf{\color{green}3.5x}}$ |
|
|
388
|
+
| array w/ templates (10) | 29.89M/s | 7.10M/s | 1.54M/s | ${\textsf{\color{red}0.2x}}$ | ${\textsf{\color{green}4.6x}}$ |
|
|
389
|
+
| array w/ templates (100) | 30.18M/s | 795.31K/s | 150.09K/s | ${\textsf{\color{red}0.0x}}$ | ${\textsf{\color{green}5.3x}}$ |
|
|
390
|
+
| union types | 29.77M/s | 30.69M/s | 10.76M/s | ${\textsf{\color{olive}1.0x}}$ | ${\textsf{\color{green}2.9x}}$ |
|
|
391
|
+
| template literals | 30.09M/s | 17.23M/s | 1.71M/s | ${\textsf{\color{red}0.6x}}$ | ${\textsf{\color{green}10.1x}}$ |
|
|
392
|
+
| complex config | 30.56M/s | 29.14M/s | 3.51M/s | ${\textsf{\color{olive}1.0x}}$ | ${\textsf{\color{green}8.3x}}$ |
|
|
393
|
+
| JSON.parse (small) | 4.61M/s | 4.37M/s | 3.85M/s | ${\textsf{\color{olive}0.9x}}$ | ${\textsf{\color{green}1.1x}}$ |
|
|
394
|
+
| JSON.parse (small+filtered extras) | 4.65M/s | 4.32M/s | 3.79M/s | ${\textsf{\color{olive}0.9x}}$ | ${\textsf{\color{green}1.1x}}$ |
|
|
395
|
+
| JSON.parse (medium) | 2.85M/s | 2.26M/s | 928.42K/s | ${\textsf{\color{red}0.8x}}$ | ${\textsf{\color{green}2.4x}}$ |
|
|
396
|
+
| JSON.parse (large) | 209.41K/s | 186.91K/s | 99.28K/s | ${\textsf{\color{olive}0.9x}}$ | ${\textsf{\color{green}1.9x}}$ |
|
|
397
|
+
| JSON.parse (1000 large) | 211/s | 212/s | 104/s | ${\textsf{\color{olive}1.0x}}$ | ${\textsf{\color{green}2.0x}}$ |
|
|
398
|
+
| JSON.stringify (small) | 9.99M/s | 9.30M/s | 6.70M/s | ${\textsf{\color{olive}0.9x}}$ | ${\textsf{\color{green}1.4x}}$ |
|
|
399
|
+
| JSON.stringify (small+extras) | 2.85M/s | 9.20M/s | 6.98M/s | ${\textsf{\color{green}3.2x}}$ | ${\textsf{\color{green}1.3x}}$ |
|
|
400
|
+
| JSON.stringify (medium) | 5.09M/s | 3.82M/s | 1.16M/s | ${\textsf{\color{red}0.8x}}$ | ${\textsf{\color{green}3.3x}}$ |
|
|
401
|
+
| JSON.stringify (large) | 392.53K/s | 330.45K/s | 132.50K/s | ${\textsf{\color{red}0.8x}}$ | ${\textsf{\color{green}2.5x}}$ |
|
|
402
|
+
| JSON.stringify (1000 large) | 362/s | 339/s | 128/s | ${\textsf{\color{olive}0.9x}}$ | ${\textsf{\color{green}2.7x}}$ |
|
|
403
|
+
|
|
404
|
+
- **vs Nothing**: Speed relative to no validation or filtering (1.0x = same speed)
|
|
405
|
+
- **vs Zod**: Speed relative to Zod (1.0x = same speed)
|
|
406
|
+
|
|
407
|
+
Key findings:
|
|
408
|
+
|
|
409
|
+
- Primitives and simple types have near-zero overhead
|
|
410
|
+
- Typical is **2-10x faster than Zod** for complex types
|
|
411
|
+
- JSON operations have minimal overhead while providing full type safety
|
package/dist/src/config.d.ts
CHANGED
|
@@ -21,7 +21,13 @@ export interface TypicalSourceMapConfig {
|
|
|
21
21
|
export interface TypicalConfig {
|
|
22
22
|
include?: string[];
|
|
23
23
|
exclude?: string[];
|
|
24
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Controls whether validators are hoisted to module scope for reuse.
|
|
26
|
+
* - 'auto' (default): Hoist only validators used more than once
|
|
27
|
+
* - 'never': Never hoist, always generate inline validators
|
|
28
|
+
* - 'always': Always hoist validators, even if only used once
|
|
29
|
+
*/
|
|
30
|
+
reusableValidators?: 'auto' | 'never' | 'always';
|
|
25
31
|
validateCasts?: boolean;
|
|
26
32
|
hoistRegex?: boolean;
|
|
27
33
|
debug?: TypicalDebugConfig;
|
|
@@ -67,8 +73,6 @@ export declare const defaultConfig: TypicalConfig;
|
|
|
67
73
|
export declare function loadConfig(configPath?: string): TypicalConfig;
|
|
68
74
|
/**
|
|
69
75
|
* Validate and adjust config for consistency.
|
|
70
|
-
* Currently handles:
|
|
71
|
-
* - Disabling reusableValidators when source maps are enabled (required for accurate mappings)
|
|
72
76
|
*
|
|
73
77
|
* @param config The config to validate
|
|
74
78
|
* @returns Validated/adjusted config
|
package/dist/src/config.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export const defaultConfig = {
|
|
2
2
|
include: ['**/*.ts', '**/*.tsx'],
|
|
3
3
|
exclude: ['node_modules/**', '**/*.d.ts', 'dist/**', 'build/**'],
|
|
4
|
-
reusableValidators:
|
|
4
|
+
reusableValidators: 'auto', // Hoists validators to module scope for reduced code size
|
|
5
5
|
validateCasts: false,
|
|
6
6
|
validateFunctions: true,
|
|
7
7
|
transformJSONParse: true,
|
|
@@ -11,7 +11,7 @@ export const defaultConfig = {
|
|
|
11
11
|
writeIntermediateFiles: false,
|
|
12
12
|
},
|
|
13
13
|
sourceMap: {
|
|
14
|
-
enabled: true,
|
|
14
|
+
enabled: true,
|
|
15
15
|
includeContent: true,
|
|
16
16
|
inline: false,
|
|
17
17
|
},
|
|
@@ -36,30 +36,15 @@ export function loadConfig(configPath) {
|
|
|
36
36
|
}
|
|
37
37
|
return defaultConfig;
|
|
38
38
|
}
|
|
39
|
-
let warnedAboutSourceMaps = false;
|
|
40
39
|
/**
|
|
41
40
|
* Validate and adjust config for consistency.
|
|
42
|
-
* Currently handles:
|
|
43
|
-
* - Disabling reusableValidators when source maps are enabled (required for accurate mappings)
|
|
44
41
|
*
|
|
45
42
|
* @param config The config to validate
|
|
46
43
|
* @returns Validated/adjusted config
|
|
47
44
|
*/
|
|
48
45
|
export function validateConfig(config) {
|
|
49
|
-
|
|
50
|
-
//
|
|
51
|
-
|
|
52
|
-
// With reusable validators, the expanded typia code would all map to the validator
|
|
53
|
-
// declaration rather than the individual usage sites.
|
|
54
|
-
const sourceMapEnabled = config.sourceMap?.enabled !== false;
|
|
55
|
-
const reusableValidatorsEnabled = config.reusableValidators === true;
|
|
56
|
-
if (sourceMapEnabled && reusableValidatorsEnabled) {
|
|
57
|
-
if (!warnedAboutSourceMaps) {
|
|
58
|
-
warnedAboutSourceMaps = true;
|
|
59
|
-
console.warn('TYPICAL: Both sourceMap and reusableValidators are enabled. ' + 'Disabling reusableValidators for accurate source mapping. ' + 'For production builds, set sourceMap.enabled: false to use reusableValidators.');
|
|
60
|
-
}
|
|
61
|
-
result = { ...result, reusableValidators: false };
|
|
62
|
-
}
|
|
63
|
-
return result;
|
|
46
|
+
// Reusable validators now throw at the call site, so they work correctly
|
|
47
|
+
// with source maps. No need for special handling.
|
|
48
|
+
return config;
|
|
64
49
|
}
|
|
65
50
|
//# sourceMappingURL=config.js.map
|
package/dist/src/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AA0EA,MAAM,CAAC,MAAM,aAAa,GAAkB;IAC1C,OAAO,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC;IAChC,OAAO,EAAE,CAAC,iBAAiB,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,CAAC;IAChE,kBAAkB,EAAE,MAAM,EAAE,0DAA0D;IACtF,aAAa,EAAE,KAAK;IACpB,iBAAiB,EAAE,IAAI;IACvB,kBAAkB,EAAE,IAAI;IACxB,sBAAsB,EAAE,IAAI;IAC5B,UAAU,EAAE,IAAI;IAChB,KAAK,EAAE;QACL,sBAAsB,EAAE,KAAK;KAC9B;IACD,SAAS,EAAE;QACT,OAAO,EAAE,IAAI;QACb,cAAc,EAAE,IAAI;QACpB,MAAM,EAAE,KAAK;KACd;CACF,CAAA;AAED,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,IAAI,MAAM,MAAM,CAAA;AAEvB,MAAM,UAAU,UAAU,CAAC,UAAmB;IAC5C,MAAM,UAAU,GAAG,UAAU,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC,CAAA;IAEzE,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9B,IAAI,CAAC;YACH,MAAM,aAAa,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;YACzD,MAAM,UAAU,GAA2B,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAA;YAEpE,OAAO;gBACL,GAAG,aAAa;gBAChB,GAAG,UAAU;aACd,CAAA;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,+BAA+B,UAAU,GAAG,EAAE,KAAK,CAAC,CAAA;YACjE,OAAO,aAAa,CAAA;QACtB,CAAC;IACH,CAAC;IAED,OAAO,aAAa,CAAA;AACtB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,MAAqB;IAClD,yEAAyE;IACzE,kDAAkD;IAClD,OAAO,MAAM,CAAA;AACf,CAAC"}
|
package/dist/src/transformer.js
CHANGED
|
@@ -45,8 +45,8 @@ export class TypicalTransformer {
|
|
|
45
45
|
}
|
|
46
46
|
await this.ensureInitialized();
|
|
47
47
|
const resolvedPath = resolve(fileName);
|
|
48
|
-
// Pass
|
|
49
|
-
const result = await this.compiler.transformFile(this.projectHandle, resolvedPath, this.config.ignoreTypes, this.config.maxGeneratedFunctions);
|
|
48
|
+
// Pass config options to the Go compiler
|
|
49
|
+
const result = await this.compiler.transformFile(this.projectHandle, resolvedPath, this.config.ignoreTypes, this.config.maxGeneratedFunctions, this.config.reusableValidators);
|
|
50
50
|
return {
|
|
51
51
|
code: result.code,
|
|
52
52
|
map: result.sourceMap ?? null,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transformer.js","sourceRoot":"","sources":["../../src/transformer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAC9B,OAAO,EAAE,eAAe,EAAyC,MAAM,2BAA2B,CAAA;AAElG,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAOxC,MAAM,OAAO,kBAAkB;IACtB,MAAM,CAAe;IACpB,QAAQ,CAAiB;IACzB,aAAa,GAAyB,IAAI,CAAA;IAC1C,WAAW,GAAyB,IAAI,CAAA;IACxC,UAAU,CAAQ;IAE1B,YAAY,MAAsB,EAAE,aAAqB,eAAe;QACtE,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,UAAU,EAAE,CAAA;QACpC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAC5B,IAAI,CAAC,QAAQ,GAAG,IAAI,eAAe,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;IAC7D,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,iBAAiB;QAC7B,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,IAAI,CAAC,WAAW,GAAG,CAAC,KAAK,IAAI,EAAE;gBAC7B,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAA;gBAC3B,IAAI,CAAC,aAAa,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;YACvE,CAAC,CAAC,EAAE,CAAA;QACN,CAAC;QACD,MAAM,IAAI,CAAC,WAAW,CAAA;IACxB,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,SAAS,CAAC,QAAgB,EAAE,OAAoB,IAAI;QACxD,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAA;QACpF,CAAC;QAED,MAAM,IAAI,CAAC,iBAAiB,EAAE,CAAA;QAE9B,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;QACtC,
|
|
1
|
+
{"version":3,"file":"transformer.js","sourceRoot":"","sources":["../../src/transformer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAC9B,OAAO,EAAE,eAAe,EAAyC,MAAM,2BAA2B,CAAA;AAElG,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAOxC,MAAM,OAAO,kBAAkB;IACtB,MAAM,CAAe;IACpB,QAAQ,CAAiB;IACzB,aAAa,GAAyB,IAAI,CAAA;IAC1C,WAAW,GAAyB,IAAI,CAAA;IACxC,UAAU,CAAQ;IAE1B,YAAY,MAAsB,EAAE,aAAqB,eAAe;QACtE,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,UAAU,EAAE,CAAA;QACpC,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAC5B,IAAI,CAAC,QAAQ,GAAG,IAAI,eAAe,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;IAC7D,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,iBAAiB;QAC7B,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,IAAI,CAAC,WAAW,GAAG,CAAC,KAAK,IAAI,EAAE;gBAC7B,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAA;gBAC3B,IAAI,CAAC,aAAa,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;YACvE,CAAC,CAAC,EAAE,CAAA;QACN,CAAC;QACD,MAAM,IAAI,CAAC,WAAW,CAAA;IACxB,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,SAAS,CAAC,QAAgB,EAAE,OAAoB,IAAI;QACxD,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAA;QACpF,CAAC;QAED,MAAM,IAAI,CAAC,iBAAiB,EAAE,CAAA;QAE9B,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;QACtC,yCAAyC;QACzC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,aAAc,EAAE,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,qBAAqB,EAAE,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAA;QAE/K,OAAO;YACL,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,GAAG,EAAE,MAAM,CAAC,SAAS,IAAI,IAAI;SAC9B,CAAA;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,aAAa,GAAG,IAAI,CAAA;QACzB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAA;QACvB,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAA;IAC7B,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elliots/typical",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Runtime safe TypeScript transformer using typia",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"runtime",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"commander": "14.0.2",
|
|
43
|
-
"@elliots/typical-compiler": "0.2.
|
|
43
|
+
"@elliots/typical-compiler": "0.2.3"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/node": "22",
|
package/src/config.ts
CHANGED
|
@@ -23,7 +23,13 @@ export interface TypicalSourceMapConfig {
|
|
|
23
23
|
export interface TypicalConfig {
|
|
24
24
|
include?: string[]
|
|
25
25
|
exclude?: string[]
|
|
26
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Controls whether validators are hoisted to module scope for reuse.
|
|
28
|
+
* - 'auto' (default): Hoist only validators used more than once
|
|
29
|
+
* - 'never': Never hoist, always generate inline validators
|
|
30
|
+
* - 'always': Always hoist validators, even if only used once
|
|
31
|
+
*/
|
|
32
|
+
reusableValidators?: 'auto' | 'never' | 'always'
|
|
27
33
|
validateCasts?: boolean
|
|
28
34
|
hoistRegex?: boolean
|
|
29
35
|
debug?: TypicalDebugConfig
|
|
@@ -69,7 +75,7 @@ export interface TypicalConfig {
|
|
|
69
75
|
export const defaultConfig: TypicalConfig = {
|
|
70
76
|
include: ['**/*.ts', '**/*.tsx'],
|
|
71
77
|
exclude: ['node_modules/**', '**/*.d.ts', 'dist/**', 'build/**'],
|
|
72
|
-
reusableValidators:
|
|
78
|
+
reusableValidators: 'auto', // Hoists validators to module scope for reduced code size
|
|
73
79
|
validateCasts: false,
|
|
74
80
|
validateFunctions: true,
|
|
75
81
|
transformJSONParse: true,
|
|
@@ -79,7 +85,7 @@ export const defaultConfig: TypicalConfig = {
|
|
|
79
85
|
writeIntermediateFiles: false,
|
|
80
86
|
},
|
|
81
87
|
sourceMap: {
|
|
82
|
-
enabled: true,
|
|
88
|
+
enabled: true,
|
|
83
89
|
includeContent: true,
|
|
84
90
|
inline: false,
|
|
85
91
|
},
|
|
@@ -109,35 +115,14 @@ export function loadConfig(configPath?: string): TypicalConfig {
|
|
|
109
115
|
return defaultConfig
|
|
110
116
|
}
|
|
111
117
|
|
|
112
|
-
let warnedAboutSourceMaps = false
|
|
113
|
-
|
|
114
118
|
/**
|
|
115
119
|
* Validate and adjust config for consistency.
|
|
116
|
-
* Currently handles:
|
|
117
|
-
* - Disabling reusableValidators when source maps are enabled (required for accurate mappings)
|
|
118
120
|
*
|
|
119
121
|
* @param config The config to validate
|
|
120
122
|
* @returns Validated/adjusted config
|
|
121
123
|
*/
|
|
122
124
|
export function validateConfig(config: TypicalConfig): TypicalConfig {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
// call needs its own source map marker pointing to the correct type annotation.
|
|
127
|
-
// With reusable validators, the expanded typia code would all map to the validator
|
|
128
|
-
// declaration rather than the individual usage sites.
|
|
129
|
-
const sourceMapEnabled = config.sourceMap?.enabled !== false
|
|
130
|
-
const reusableValidatorsEnabled = config.reusableValidators === true
|
|
131
|
-
|
|
132
|
-
if (sourceMapEnabled && reusableValidatorsEnabled) {
|
|
133
|
-
if (!warnedAboutSourceMaps) {
|
|
134
|
-
warnedAboutSourceMaps = true
|
|
135
|
-
console.warn(
|
|
136
|
-
'TYPICAL: Both sourceMap and reusableValidators are enabled. ' + 'Disabling reusableValidators for accurate source mapping. ' + 'For production builds, set sourceMap.enabled: false to use reusableValidators.',
|
|
137
|
-
)
|
|
138
|
-
}
|
|
139
|
-
result = { ...result, reusableValidators: false }
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return result
|
|
125
|
+
// Reusable validators now throw at the call site, so they work correctly
|
|
126
|
+
// with source maps. No need for special handling.
|
|
127
|
+
return config
|
|
143
128
|
}
|
package/src/transformer.ts
CHANGED
|
@@ -58,8 +58,8 @@ export class TypicalTransformer {
|
|
|
58
58
|
await this.ensureInitialized()
|
|
59
59
|
|
|
60
60
|
const resolvedPath = resolve(fileName)
|
|
61
|
-
// Pass
|
|
62
|
-
const result = await this.compiler.transformFile(this.projectHandle!, resolvedPath, this.config.ignoreTypes, this.config.maxGeneratedFunctions)
|
|
61
|
+
// Pass config options to the Go compiler
|
|
62
|
+
const result = await this.compiler.transformFile(this.projectHandle!, resolvedPath, this.config.ignoreTypes, this.config.maxGeneratedFunctions, this.config.reusableValidators)
|
|
63
63
|
|
|
64
64
|
return {
|
|
65
65
|
code: result.code,
|