@elliots/typical 0.2.0-beta.1 → 0.2.1
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 +61 -6
- package/dist/src/config.d.ts +20 -36
- package/dist/src/config.js +2 -103
- package/dist/src/config.js.map +1 -1
- package/dist/src/transformer.js +2 -1
- package/dist/src/transformer.js.map +1 -1
- package/package.json +2 -2
- package/src/config.ts +22 -131
- package/src/transformer.ts +2 -1
package/README.md
CHANGED
|
@@ -286,12 +286,57 @@ Create a `typical.json` file in your project root (optional):
|
|
|
286
286
|
|
|
287
287
|
### Options
|
|
288
288
|
|
|
289
|
-
| Option
|
|
290
|
-
|
|
|
291
|
-
| `include`
|
|
292
|
-
| `exclude`
|
|
293
|
-
| `validateFunctions`
|
|
294
|
-
| `validateCasts`
|
|
289
|
+
| Option | Default | Description |
|
|
290
|
+
| ------------------------ | --------------------------------------------------------- | ----------------------------------------------------------------- |
|
|
291
|
+
| `include` | `["**/*.ts", "**/*.tsx"]` | Files to transform |
|
|
292
|
+
| `exclude` | `["node_modules/**", "**/*.d.ts", "dist/**", "build/**"]` | Files to skip |
|
|
293
|
+
| `validateFunctions` | `true` | Validate function parameters and return types |
|
|
294
|
+
| `validateCasts` | `false` | Validate type assertions (`as Type`) |
|
|
295
|
+
| `transformJSONParse` | `true` | Transform `JSON.parse` to validate and filter to typed properties |
|
|
296
|
+
| `transformJSONStringify` | `true` | Transform `JSON.stringify` to only include typed properties |
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## JSON Transformations
|
|
301
|
+
|
|
302
|
+
Typical automatically transforms `JSON.parse` and `JSON.stringify` calls when type information is available.
|
|
303
|
+
|
|
304
|
+
### JSON.parse
|
|
305
|
+
|
|
306
|
+
When you cast the result of `JSON.parse`, Typical validates the parsed data and filters it to only include properties defined in your type:
|
|
307
|
+
|
|
308
|
+
```ts
|
|
309
|
+
interface User {
|
|
310
|
+
name: string;
|
|
311
|
+
age: number;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Input: '{"name":"Alice","age":30,"password":"secret"}'
|
|
315
|
+
const user = JSON.parse(jsonString) as User;
|
|
316
|
+
// Result: { name: "Alice", age: 30 } - password is filtered out!
|
|
317
|
+
// Throws TypeError if name isn't a string or age isn't a number
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### JSON.stringify
|
|
321
|
+
|
|
322
|
+
When you use a type assertion with `JSON.stringify`, only properties defined in your type are included - preventing accidental data leaks:
|
|
323
|
+
|
|
324
|
+
```ts
|
|
325
|
+
interface PublicUser {
|
|
326
|
+
name: string;
|
|
327
|
+
age: number;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const user = { name: "Alice", age: 30, password: "secret", ssn: "123-45-6789" };
|
|
331
|
+
const json = JSON.stringify(user as PublicUser);
|
|
332
|
+
// Result: '{"name":"Alice","age":30}' - sensitive data excluded!
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
Both patterns detect type information from:
|
|
336
|
+
|
|
337
|
+
- Type assertions: `JSON.parse(str) as User` or `JSON.stringify(obj as User)`
|
|
338
|
+
- Variable declarations: `const user: User = JSON.parse(str)`
|
|
339
|
+
- Function return types: `function getUser(): User { return JSON.parse(str) }`
|
|
295
340
|
|
|
296
341
|
---
|
|
297
342
|
|
|
@@ -301,6 +346,16 @@ Typical uses a Go-based compiler that leverages the TypeScript type checker to a
|
|
|
301
346
|
|
|
302
347
|
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.
|
|
303
348
|
|
|
349
|
+
## Compiler Optimizations
|
|
350
|
+
|
|
351
|
+
The generated validation code is optimized for runtime performance:
|
|
352
|
+
|
|
353
|
+
- **Skip redundant validation** - When returning a validated parameter directly, the return validation is skipped (e.g., `return x` where `x: string` was already validated)
|
|
354
|
+
- **Subtype-aware skipping** - If a validated type is assignable to the return type, validation is skipped (e.g., `string` parameter returned as `string | null`)
|
|
355
|
+
- **Property chain tracking** - Accessing properties of validated objects skips re-validation (e.g., `return user.name` when `user: User` was validated)
|
|
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)
|
|
357
|
+
- **Union early bail-out** - Union type checks use if-else chains so the first matching type succeeds immediately
|
|
358
|
+
|
|
304
359
|
## Debugging
|
|
305
360
|
|
|
306
361
|
Set `DEBUG=1` for verbose logging:
|
package/dist/src/config.d.ts
CHANGED
|
@@ -31,55 +31,39 @@ export interface TypicalConfig {
|
|
|
31
31
|
* Example: ["React.*", "Express.Request", "*.Event"]
|
|
32
32
|
*/
|
|
33
33
|
ignoreTypes?: string[];
|
|
34
|
-
/**
|
|
35
|
-
* Skip validation for DOM types (Document, Element, Node, etc.) and their subclasses.
|
|
36
|
-
* These types have complex Window intersections that typia cannot process.
|
|
37
|
-
* Default: true
|
|
38
|
-
*/
|
|
39
|
-
ignoreDOMTypes?: boolean;
|
|
40
34
|
/**
|
|
41
35
|
* Validate function parameters and return types at runtime.
|
|
42
36
|
* When enabled, typed function parameters get runtime validation calls injected.
|
|
43
37
|
* Default: true
|
|
44
38
|
*/
|
|
45
39
|
validateFunctions?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Transform JSON.parse<T>() calls to validate and filter the parsed result
|
|
42
|
+
* to only include properties defined in type T.
|
|
43
|
+
* Default: true
|
|
44
|
+
*/
|
|
45
|
+
transformJSONParse?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Transform JSON.stringify<T>() calls to only stringify properties defined
|
|
48
|
+
* in type T, preventing accidental data leaks.
|
|
49
|
+
* Default: true
|
|
50
|
+
*/
|
|
51
|
+
transformJSONStringify?: boolean;
|
|
46
52
|
/**
|
|
47
53
|
* Source map generation settings.
|
|
48
54
|
* Controls whether and how source maps are generated for transformed code.
|
|
49
55
|
*/
|
|
50
56
|
sourceMap?: TypicalSourceMapConfig;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
/** Compiled patterns from DOM_TYPES_TO_IGNORE (when ignoreDOMTypes is true) */
|
|
60
|
-
domPatterns: RegExp[];
|
|
61
|
-
/** All patterns combined for quick checking */
|
|
62
|
-
allPatterns: RegExp[];
|
|
57
|
+
/**
|
|
58
|
+
* Maximum number of helper functions (_io0, _io1, etc.) that can be generated
|
|
59
|
+
* for a single type before erroring. Complex DOM types or library types can
|
|
60
|
+
* generate hundreds of functions which indicates a type that should be excluded.
|
|
61
|
+
* Set to 0 to disable the limit.
|
|
62
|
+
* Default: 50
|
|
63
|
+
*/
|
|
64
|
+
maxGeneratedFunctions?: number;
|
|
63
65
|
}
|
|
64
66
|
export declare const defaultConfig: TypicalConfig;
|
|
65
|
-
/**
|
|
66
|
-
* DOM types that typia cannot process due to Window global intersections.
|
|
67
|
-
* These are the base DOM types - classes extending them are checked separately.
|
|
68
|
-
*/
|
|
69
|
-
export declare const DOM_TYPES_TO_IGNORE: string[];
|
|
70
|
-
/**
|
|
71
|
-
* Convert a glob pattern to a RegExp for type matching.
|
|
72
|
-
* Supports wildcards: "React.*" -> /^React\..*$/
|
|
73
|
-
*/
|
|
74
|
-
export declare function compileIgnorePattern(pattern: string): RegExp | null;
|
|
75
|
-
/**
|
|
76
|
-
* Pre-compile all ignore patterns for efficient matching.
|
|
77
|
-
*/
|
|
78
|
-
export declare function compileIgnorePatterns(config: TypicalConfig): CompiledIgnorePatterns;
|
|
79
|
-
/**
|
|
80
|
-
* Get compiled ignore patterns, using cache if config hasn't changed.
|
|
81
|
-
*/
|
|
82
|
-
export declare function getCompiledIgnorePatterns(config: TypicalConfig): CompiledIgnorePatterns;
|
|
83
67
|
export declare function loadConfig(configPath?: string): TypicalConfig;
|
|
84
68
|
/**
|
|
85
69
|
* Validate and adjust config for consistency.
|
package/dist/src/config.js
CHANGED
|
@@ -4,8 +4,9 @@ export const defaultConfig = {
|
|
|
4
4
|
reusableValidators: false, // Off by default for accurate source maps (set to true for production)
|
|
5
5
|
validateCasts: false,
|
|
6
6
|
validateFunctions: true,
|
|
7
|
+
transformJSONParse: true,
|
|
8
|
+
transformJSONStringify: true,
|
|
7
9
|
hoistRegex: true,
|
|
8
|
-
ignoreDOMTypes: true,
|
|
9
10
|
debug: {
|
|
10
11
|
writeIntermediateFiles: false,
|
|
11
12
|
},
|
|
@@ -15,110 +16,8 @@ export const defaultConfig = {
|
|
|
15
16
|
inline: false,
|
|
16
17
|
},
|
|
17
18
|
};
|
|
18
|
-
// FIXME: find a better way to work out which types to ignore
|
|
19
|
-
/**
|
|
20
|
-
* DOM types that typia cannot process due to Window global intersections.
|
|
21
|
-
* These are the base DOM types - classes extending them are checked separately.
|
|
22
|
-
*/
|
|
23
|
-
export const DOM_TYPES_TO_IGNORE = [
|
|
24
|
-
// Core DOM types
|
|
25
|
-
'Document',
|
|
26
|
-
'DocumentFragment',
|
|
27
|
-
'Element',
|
|
28
|
-
'Node',
|
|
29
|
-
'ShadowRoot',
|
|
30
|
-
'Window',
|
|
31
|
-
'EventTarget',
|
|
32
|
-
// HTML Elements
|
|
33
|
-
'HTML*Element',
|
|
34
|
-
'HTMLElement',
|
|
35
|
-
'HTMLCollection',
|
|
36
|
-
// SVG Elements
|
|
37
|
-
'SVG*Element',
|
|
38
|
-
'SVGElement',
|
|
39
|
-
// Events
|
|
40
|
-
'*Event',
|
|
41
|
-
// Other common DOM types
|
|
42
|
-
'NodeList',
|
|
43
|
-
'DOMTokenList',
|
|
44
|
-
'NamedNodeMap',
|
|
45
|
-
'CSSStyleDeclaration',
|
|
46
|
-
'Selection',
|
|
47
|
-
'Range',
|
|
48
|
-
'Text',
|
|
49
|
-
'Comment',
|
|
50
|
-
'CDATASection',
|
|
51
|
-
'ProcessingInstruction',
|
|
52
|
-
'DocumentType',
|
|
53
|
-
'Attr',
|
|
54
|
-
'Table',
|
|
55
|
-
'TableRow',
|
|
56
|
-
'TableCell',
|
|
57
|
-
'StyleSheet',
|
|
58
|
-
];
|
|
59
19
|
import fs from 'fs';
|
|
60
20
|
import path from 'path';
|
|
61
|
-
/**
|
|
62
|
-
* Convert a glob pattern to a RegExp for type matching.
|
|
63
|
-
* Supports wildcards: "React.*" -> /^React\..*$/
|
|
64
|
-
*/
|
|
65
|
-
export function compileIgnorePattern(pattern) {
|
|
66
|
-
try {
|
|
67
|
-
const regexStr = '^' +
|
|
68
|
-
pattern
|
|
69
|
-
.replace(/[.+^${}()|[\]\\]/g, '\\$&') // Escape special regex chars except *
|
|
70
|
-
.replace(/\*/g, '.*') +
|
|
71
|
-
'$';
|
|
72
|
-
return new RegExp(regexStr);
|
|
73
|
-
}
|
|
74
|
-
catch (error) {
|
|
75
|
-
console.warn(`TYPICAL: Invalid ignoreTypes pattern "${pattern}": ${error.message}`);
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Pre-compile all ignore patterns for efficient matching.
|
|
81
|
-
*/
|
|
82
|
-
export function compileIgnorePatterns(config) {
|
|
83
|
-
const userPatterns = [];
|
|
84
|
-
const domPatterns = [];
|
|
85
|
-
// Compile user patterns
|
|
86
|
-
for (const pattern of config.ignoreTypes ?? []) {
|
|
87
|
-
const compiled = compileIgnorePattern(pattern);
|
|
88
|
-
if (compiled) {
|
|
89
|
-
userPatterns.push(compiled);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
// Compile DOM patterns if enabled (default: true)
|
|
93
|
-
if (config.ignoreDOMTypes !== false) {
|
|
94
|
-
for (const pattern of DOM_TYPES_TO_IGNORE) {
|
|
95
|
-
const compiled = compileIgnorePattern(pattern);
|
|
96
|
-
if (compiled) {
|
|
97
|
-
domPatterns.push(compiled);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
return {
|
|
102
|
-
userPatterns,
|
|
103
|
-
domPatterns,
|
|
104
|
-
allPatterns: [...userPatterns, ...domPatterns],
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
// Cache for compiled patterns, keyed by config identity
|
|
108
|
-
let cachedPatterns = null;
|
|
109
|
-
let cachedConfig = null;
|
|
110
|
-
/**
|
|
111
|
-
* Get compiled ignore patterns, using cache if config hasn't changed.
|
|
112
|
-
*/
|
|
113
|
-
export function getCompiledIgnorePatterns(config) {
|
|
114
|
-
// Simple identity check - if same config object, use cache
|
|
115
|
-
if (cachedConfig === config && cachedPatterns) {
|
|
116
|
-
return cachedPatterns;
|
|
117
|
-
}
|
|
118
|
-
cachedConfig = config;
|
|
119
|
-
cachedPatterns = compileIgnorePatterns(config);
|
|
120
|
-
return cachedPatterns;
|
|
121
|
-
}
|
|
122
21
|
export function loadConfig(configPath) {
|
|
123
22
|
const configFile = configPath || path.join(process.cwd(), 'typical.json');
|
|
124
23
|
if (fs.existsSync(configFile)) {
|
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":"AAoEA,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,KAAK,EAAE,uEAAuE;IAClG,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,EAAE,4DAA4D;QAC3E,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,IAAI,qBAAqB,GAAG,KAAK,CAAA;AAEjC;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,MAAqB;IAClD,IAAI,MAAM,GAAG,MAAM,CAAA;IAEnB,+EAA+E;IAC/E,gFAAgF;IAChF,mFAAmF;IACnF,sDAAsD;IACtD,MAAM,gBAAgB,GAAG,MAAM,CAAC,SAAS,EAAE,OAAO,KAAK,KAAK,CAAA;IAC5D,MAAM,yBAAyB,GAAG,MAAM,CAAC,kBAAkB,KAAK,IAAI,CAAA;IAEpE,IAAI,gBAAgB,IAAI,yBAAyB,EAAE,CAAC;QAClD,IAAI,CAAC,qBAAqB,EAAE,CAAC;YAC3B,qBAAqB,GAAG,IAAI,CAAA;YAC5B,OAAO,CAAC,IAAI,CACV,8DAA8D,GAAG,4DAA4D,GAAG,gFAAgF,CACjN,CAAA;QACH,CAAC;QACD,MAAM,GAAG,EAAE,GAAG,MAAM,EAAE,kBAAkB,EAAE,KAAK,EAAE,CAAA;IACnD,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC"}
|
package/dist/src/transformer.js
CHANGED
|
@@ -45,7 +45,8 @@ export class TypicalTransformer {
|
|
|
45
45
|
}
|
|
46
46
|
await this.ensureInitialized();
|
|
47
47
|
const resolvedPath = resolve(fileName);
|
|
48
|
-
|
|
48
|
+
// Pass ignoreTypes and maxGeneratedFunctions from config to the Go compiler
|
|
49
|
+
const result = await this.compiler.transformFile(this.projectHandle, resolvedPath, this.config.ignoreTypes, this.config.maxGeneratedFunctions);
|
|
49
50
|
return {
|
|
50
51
|
code: result.code,
|
|
51
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,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,aAAc,EAAE,YAAY,CAAC,CAAA;
|
|
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,4EAA4E;QAC5E,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,CAAC,CAAA;QAE/I,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.1",
|
|
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.1"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/node": "22",
|
package/src/config.ts
CHANGED
|
@@ -33,36 +33,37 @@ export interface TypicalConfig {
|
|
|
33
33
|
* Example: ["React.*", "Express.Request", "*.Event"]
|
|
34
34
|
*/
|
|
35
35
|
ignoreTypes?: string[]
|
|
36
|
-
/**
|
|
37
|
-
* Skip validation for DOM types (Document, Element, Node, etc.) and their subclasses.
|
|
38
|
-
* These types have complex Window intersections that typia cannot process.
|
|
39
|
-
* Default: true
|
|
40
|
-
*/
|
|
41
|
-
ignoreDOMTypes?: boolean
|
|
42
36
|
/**
|
|
43
37
|
* Validate function parameters and return types at runtime.
|
|
44
38
|
* When enabled, typed function parameters get runtime validation calls injected.
|
|
45
39
|
* Default: true
|
|
46
40
|
*/
|
|
47
41
|
validateFunctions?: boolean
|
|
42
|
+
/**
|
|
43
|
+
* Transform JSON.parse<T>() calls to validate and filter the parsed result
|
|
44
|
+
* to only include properties defined in type T.
|
|
45
|
+
* Default: true
|
|
46
|
+
*/
|
|
47
|
+
transformJSONParse?: boolean
|
|
48
|
+
/**
|
|
49
|
+
* Transform JSON.stringify<T>() calls to only stringify properties defined
|
|
50
|
+
* in type T, preventing accidental data leaks.
|
|
51
|
+
* Default: true
|
|
52
|
+
*/
|
|
53
|
+
transformJSONStringify?: boolean
|
|
48
54
|
/**
|
|
49
55
|
* Source map generation settings.
|
|
50
56
|
* Controls whether and how source maps are generated for transformed code.
|
|
51
57
|
*/
|
|
52
58
|
sourceMap?: TypicalSourceMapConfig
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
userPatterns: RegExp[]
|
|
62
|
-
/** Compiled patterns from DOM_TYPES_TO_IGNORE (when ignoreDOMTypes is true) */
|
|
63
|
-
domPatterns: RegExp[]
|
|
64
|
-
/** All patterns combined for quick checking */
|
|
65
|
-
allPatterns: RegExp[]
|
|
59
|
+
/**
|
|
60
|
+
* Maximum number of helper functions (_io0, _io1, etc.) that can be generated
|
|
61
|
+
* for a single type before erroring. Complex DOM types or library types can
|
|
62
|
+
* generate hundreds of functions which indicates a type that should be excluded.
|
|
63
|
+
* Set to 0 to disable the limit.
|
|
64
|
+
* Default: 50
|
|
65
|
+
*/
|
|
66
|
+
maxGeneratedFunctions?: number
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
export const defaultConfig: TypicalConfig = {
|
|
@@ -71,8 +72,9 @@ export const defaultConfig: TypicalConfig = {
|
|
|
71
72
|
reusableValidators: false, // Off by default for accurate source maps (set to true for production)
|
|
72
73
|
validateCasts: false,
|
|
73
74
|
validateFunctions: true,
|
|
75
|
+
transformJSONParse: true,
|
|
76
|
+
transformJSONStringify: true,
|
|
74
77
|
hoistRegex: true,
|
|
75
|
-
ignoreDOMTypes: true,
|
|
76
78
|
debug: {
|
|
77
79
|
writeIntermediateFiles: false,
|
|
78
80
|
},
|
|
@@ -83,120 +85,9 @@ export const defaultConfig: TypicalConfig = {
|
|
|
83
85
|
},
|
|
84
86
|
}
|
|
85
87
|
|
|
86
|
-
// FIXME: find a better way to work out which types to ignore
|
|
87
|
-
/**
|
|
88
|
-
* DOM types that typia cannot process due to Window global intersections.
|
|
89
|
-
* These are the base DOM types - classes extending them are checked separately.
|
|
90
|
-
*/
|
|
91
|
-
export const DOM_TYPES_TO_IGNORE = [
|
|
92
|
-
// Core DOM types
|
|
93
|
-
'Document',
|
|
94
|
-
'DocumentFragment',
|
|
95
|
-
'Element',
|
|
96
|
-
'Node',
|
|
97
|
-
'ShadowRoot',
|
|
98
|
-
'Window',
|
|
99
|
-
'EventTarget',
|
|
100
|
-
// HTML Elements
|
|
101
|
-
'HTML*Element',
|
|
102
|
-
'HTMLElement',
|
|
103
|
-
'HTMLCollection',
|
|
104
|
-
// SVG Elements
|
|
105
|
-
'SVG*Element',
|
|
106
|
-
'SVGElement',
|
|
107
|
-
// Events
|
|
108
|
-
'*Event',
|
|
109
|
-
// Other common DOM types
|
|
110
|
-
'NodeList',
|
|
111
|
-
'DOMTokenList',
|
|
112
|
-
'NamedNodeMap',
|
|
113
|
-
'CSSStyleDeclaration',
|
|
114
|
-
'Selection',
|
|
115
|
-
'Range',
|
|
116
|
-
'Text',
|
|
117
|
-
'Comment',
|
|
118
|
-
'CDATASection',
|
|
119
|
-
'ProcessingInstruction',
|
|
120
|
-
'DocumentType',
|
|
121
|
-
'Attr',
|
|
122
|
-
'Table',
|
|
123
|
-
'TableRow',
|
|
124
|
-
'TableCell',
|
|
125
|
-
'StyleSheet',
|
|
126
|
-
]
|
|
127
|
-
|
|
128
88
|
import fs from 'fs'
|
|
129
89
|
import path from 'path'
|
|
130
90
|
|
|
131
|
-
/**
|
|
132
|
-
* Convert a glob pattern to a RegExp for type matching.
|
|
133
|
-
* Supports wildcards: "React.*" -> /^React\..*$/
|
|
134
|
-
*/
|
|
135
|
-
export function compileIgnorePattern(pattern: string): RegExp | null {
|
|
136
|
-
try {
|
|
137
|
-
const regexStr =
|
|
138
|
-
'^' +
|
|
139
|
-
pattern
|
|
140
|
-
.replace(/[.+^${}()|[\]\\]/g, '\\$&') // Escape special regex chars except *
|
|
141
|
-
.replace(/\*/g, '.*') +
|
|
142
|
-
'$'
|
|
143
|
-
return new RegExp(regexStr)
|
|
144
|
-
} catch (error) {
|
|
145
|
-
console.warn(`TYPICAL: Invalid ignoreTypes pattern "${pattern}": ${(error as Error).message}`)
|
|
146
|
-
return null
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Pre-compile all ignore patterns for efficient matching.
|
|
152
|
-
*/
|
|
153
|
-
export function compileIgnorePatterns(config: TypicalConfig): CompiledIgnorePatterns {
|
|
154
|
-
const userPatterns: RegExp[] = []
|
|
155
|
-
const domPatterns: RegExp[] = []
|
|
156
|
-
|
|
157
|
-
// Compile user patterns
|
|
158
|
-
for (const pattern of config.ignoreTypes ?? []) {
|
|
159
|
-
const compiled = compileIgnorePattern(pattern)
|
|
160
|
-
if (compiled) {
|
|
161
|
-
userPatterns.push(compiled)
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// Compile DOM patterns if enabled (default: true)
|
|
166
|
-
if (config.ignoreDOMTypes !== false) {
|
|
167
|
-
for (const pattern of DOM_TYPES_TO_IGNORE) {
|
|
168
|
-
const compiled = compileIgnorePattern(pattern)
|
|
169
|
-
if (compiled) {
|
|
170
|
-
domPatterns.push(compiled)
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
return {
|
|
176
|
-
userPatterns,
|
|
177
|
-
domPatterns,
|
|
178
|
-
allPatterns: [...userPatterns, ...domPatterns],
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// Cache for compiled patterns, keyed by config identity
|
|
183
|
-
let cachedPatterns: CompiledIgnorePatterns | null = null
|
|
184
|
-
let cachedConfig: TypicalConfig | null = null
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Get compiled ignore patterns, using cache if config hasn't changed.
|
|
188
|
-
*/
|
|
189
|
-
export function getCompiledIgnorePatterns(config: TypicalConfig): CompiledIgnorePatterns {
|
|
190
|
-
// Simple identity check - if same config object, use cache
|
|
191
|
-
if (cachedConfig === config && cachedPatterns) {
|
|
192
|
-
return cachedPatterns
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
cachedConfig = config
|
|
196
|
-
cachedPatterns = compileIgnorePatterns(config)
|
|
197
|
-
return cachedPatterns
|
|
198
|
-
}
|
|
199
|
-
|
|
200
91
|
export function loadConfig(configPath?: string): TypicalConfig {
|
|
201
92
|
const configFile = configPath || path.join(process.cwd(), 'typical.json')
|
|
202
93
|
|
package/src/transformer.ts
CHANGED
|
@@ -58,7 +58,8 @@ export class TypicalTransformer {
|
|
|
58
58
|
await this.ensureInitialized()
|
|
59
59
|
|
|
60
60
|
const resolvedPath = resolve(fileName)
|
|
61
|
-
|
|
61
|
+
// Pass ignoreTypes and maxGeneratedFunctions from config to the Go compiler
|
|
62
|
+
const result = await this.compiler.transformFile(this.projectHandle!, resolvedPath, this.config.ignoreTypes, this.config.maxGeneratedFunctions)
|
|
62
63
|
|
|
63
64
|
return {
|
|
64
65
|
code: result.code,
|