@elliots/typical 0.1.9 → 0.1.10
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 +161 -4
- package/dist/src/cli.js +33 -6
- package/dist/src/cli.js.map +1 -1
- package/dist/src/config.d.ts +56 -0
- package/dist/src/config.js +93 -1
- package/dist/src/config.js.map +1 -1
- package/dist/src/esm-loader.d.ts +1 -0
- package/dist/src/esm-loader.js +13 -3
- package/dist/src/esm-loader.js.map +1 -1
- package/dist/src/index.d.ts +4 -2
- package/dist/src/index.js +2 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/source-map.d.ts +78 -0
- package/dist/src/source-map.js +133 -0
- package/dist/src/source-map.js.map +1 -0
- package/dist/src/transformer.d.ts +71 -4
- package/dist/src/transformer.js +773 -330
- package/dist/src/transformer.js.map +1 -1
- package/dist/src/tsc-plugin.js +2 -2
- package/dist/src/tsc-plugin.js.map +1 -1
- package/package.json +8 -2
- package/src/cli.ts +44 -10
- package/src/config.ts +145 -3
- package/src/esm-loader.ts +15 -3
- package/src/index.ts +10 -2
- package/src/source-map.ts +202 -0
- package/src/transformer.ts +1047 -419
- package/src/tsc-plugin.ts +2 -2
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import MagicString from 'magic-string';
|
|
2
|
+
import remapping from '@ampproject/remapping';
|
|
3
|
+
/**
|
|
4
|
+
* Default source map options.
|
|
5
|
+
*/
|
|
6
|
+
export const defaultSourceMapOptions = {
|
|
7
|
+
enabled: true,
|
|
8
|
+
includeContent: true,
|
|
9
|
+
inline: false,
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Compose multiple source maps together.
|
|
13
|
+
* Given maps [A->B, B->C], produces A->C.
|
|
14
|
+
* Maps are applied in order: first map is closest to original source.
|
|
15
|
+
*/
|
|
16
|
+
export function composeSourceMaps(maps, originalFileName) {
|
|
17
|
+
// Filter out null/undefined maps
|
|
18
|
+
const validMaps = maps.filter((m) => m !== null && m !== undefined);
|
|
19
|
+
if (validMaps.length === 0)
|
|
20
|
+
return null;
|
|
21
|
+
if (validMaps.length === 1) {
|
|
22
|
+
const map = validMaps[0];
|
|
23
|
+
if (typeof map === 'string') {
|
|
24
|
+
return JSON.parse(map);
|
|
25
|
+
}
|
|
26
|
+
return map;
|
|
27
|
+
}
|
|
28
|
+
// remapping expects maps in reverse order (final output first)
|
|
29
|
+
// and a loader function that returns the source map for a given file
|
|
30
|
+
const reversedMaps = [...validMaps].reverse();
|
|
31
|
+
try {
|
|
32
|
+
const result = remapping(reversedMaps, () => null);
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
catch (e) {
|
|
36
|
+
// If remapping fails, return the last valid map
|
|
37
|
+
console.warn('Source map composition failed:', e);
|
|
38
|
+
const lastMap = validMaps[validMaps.length - 1];
|
|
39
|
+
if (typeof lastMap === 'string') {
|
|
40
|
+
return JSON.parse(lastMap);
|
|
41
|
+
}
|
|
42
|
+
return lastMap;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Generate an inline source map comment (data URL).
|
|
47
|
+
*/
|
|
48
|
+
export function inlineSourceMapComment(map) {
|
|
49
|
+
const mapString = typeof map === 'string' ? map : JSON.stringify(map);
|
|
50
|
+
const base64 = Buffer.from(mapString).toString('base64');
|
|
51
|
+
return `//# sourceMappingURL=data:application/json;charset=utf-8;base64,${base64}`;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Generate an external source map URL comment.
|
|
55
|
+
*/
|
|
56
|
+
export function externalSourceMapComment(mapFileName) {
|
|
57
|
+
return `//# sourceMappingURL=${mapFileName}`;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Create a MagicString instance for tracking source modifications.
|
|
61
|
+
*/
|
|
62
|
+
export function createMagicString(source, filename) {
|
|
63
|
+
return new MagicString(source, {
|
|
64
|
+
filename,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Generate a source map from a MagicString instance.
|
|
69
|
+
*/
|
|
70
|
+
export function generateSourceMap(ms, options) {
|
|
71
|
+
return ms.generateMap({
|
|
72
|
+
source: options.source,
|
|
73
|
+
file: options.file ?? options.source,
|
|
74
|
+
includeContent: options.includeContent ?? true,
|
|
75
|
+
hires: options.hires ?? true,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Create an identity source map (maps each position to itself).
|
|
80
|
+
* Useful as a placeholder when no transformation occurred.
|
|
81
|
+
*/
|
|
82
|
+
export function createIdentityMap(source, fileName, includeContent = true) {
|
|
83
|
+
const ms = new MagicString(source);
|
|
84
|
+
return ms.generateMap({
|
|
85
|
+
source: fileName,
|
|
86
|
+
file: fileName,
|
|
87
|
+
includeContent,
|
|
88
|
+
hires: true,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Apply a list of modifications to source code using MagicString.
|
|
93
|
+
* Returns the modified code and source map.
|
|
94
|
+
*/
|
|
95
|
+
export function applyModifications(source, fileName, modifications, includeContent = true) {
|
|
96
|
+
const ms = createMagicString(source, fileName);
|
|
97
|
+
// Sort modifications by position (descending) to apply from end to start
|
|
98
|
+
// This prevents position shifts from affecting subsequent modifications
|
|
99
|
+
const sorted = [...modifications].sort((a, b) => b.start - a.start);
|
|
100
|
+
for (const mod of sorted) {
|
|
101
|
+
switch (mod.type) {
|
|
102
|
+
case 'insert-before':
|
|
103
|
+
ms.prependLeft(mod.start, mod.replacement);
|
|
104
|
+
break;
|
|
105
|
+
case 'insert-after':
|
|
106
|
+
ms.appendRight(mod.end, mod.replacement);
|
|
107
|
+
break;
|
|
108
|
+
case 'replace':
|
|
109
|
+
ms.overwrite(mod.start, mod.end, mod.replacement);
|
|
110
|
+
break;
|
|
111
|
+
case 'prepend':
|
|
112
|
+
ms.prepend(mod.replacement);
|
|
113
|
+
break;
|
|
114
|
+
case 'append':
|
|
115
|
+
ms.append(mod.replacement);
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
code: ms.toString(),
|
|
121
|
+
map: generateSourceMap(ms, {
|
|
122
|
+
source: fileName,
|
|
123
|
+
includeContent,
|
|
124
|
+
}),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Strip any existing source map comments from code.
|
|
129
|
+
*/
|
|
130
|
+
export function stripSourceMapComment(code) {
|
|
131
|
+
return code.replace(/\/\/[#@]\s*sourceMappingURL=.*/g, '');
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=source-map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-map.js","sourceRoot":"","sources":["../../src/source-map.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,24 +1,60 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
2
|
import { TypicalConfig } from "./config.js";
|
|
3
|
+
import { TransformResult } from "./source-map.js";
|
|
4
|
+
export type { TransformResult } from "./source-map.js";
|
|
3
5
|
export interface TransformContext {
|
|
4
6
|
ts: typeof ts;
|
|
5
7
|
factory: ts.NodeFactory;
|
|
6
8
|
context: ts.TransformationContext;
|
|
9
|
+
sourceFile: ts.SourceFile;
|
|
7
10
|
}
|
|
8
11
|
export declare class TypicalTransformer {
|
|
9
12
|
config: TypicalConfig;
|
|
10
13
|
private program;
|
|
11
14
|
private ts;
|
|
15
|
+
private compiledPatterns;
|
|
12
16
|
private typeValidators;
|
|
13
17
|
private typeStringifiers;
|
|
14
18
|
private typeParsers;
|
|
15
19
|
constructor(config?: TypicalConfig, program?: ts.Program, tsInstance?: typeof ts);
|
|
20
|
+
/**
|
|
21
|
+
* Create a new TypeScript program with transformed source code.
|
|
22
|
+
* This is needed so typia can resolve types from our generated typia.createAssert<T>() calls.
|
|
23
|
+
*/
|
|
24
|
+
private createTypiaProgram;
|
|
25
|
+
/**
|
|
26
|
+
* Write intermediate file for debugging purposes.
|
|
27
|
+
* Creates a .typical.ts file showing the code after typical's transformations
|
|
28
|
+
* but before typia processes it.
|
|
29
|
+
*/
|
|
30
|
+
private writeIntermediateFile;
|
|
31
|
+
/**
|
|
32
|
+
* Format typia diagnostic errors into readable error messages.
|
|
33
|
+
*/
|
|
34
|
+
private formatTypiaErrors;
|
|
35
|
+
/**
|
|
36
|
+
* Check for untransformed typia calls and throw an error if found.
|
|
37
|
+
* This is a fallback in case typia silently fails without reporting a diagnostic.
|
|
38
|
+
*/
|
|
39
|
+
private checkUntransformedTypiaCalls;
|
|
16
40
|
createSourceFile(fileName: string, content: string): ts.SourceFile;
|
|
17
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Transform options for controlling source map generation.
|
|
43
|
+
*/
|
|
44
|
+
transform(sourceFile: ts.SourceFile | string, mode: "basic" | "typia" | "js", options?: {
|
|
45
|
+
sourceMap?: boolean;
|
|
46
|
+
skippedTypes?: Set<string>;
|
|
47
|
+
}): TransformResult;
|
|
48
|
+
/**
|
|
49
|
+
* Legacy transform method that returns just the code string.
|
|
50
|
+
* @deprecated Use transform() with options.sourceMap instead
|
|
51
|
+
*/
|
|
52
|
+
transformCode(sourceFile: ts.SourceFile | string, mode: "basic" | "typia" | "js", skippedTypes?: Set<string>): string;
|
|
18
53
|
/**
|
|
19
54
|
* Apply typia transformation in a separate ts.transform() context.
|
|
20
55
|
* This avoids mixing program contexts and eliminates the need for import recreation.
|
|
21
|
-
* Returns either the transformed code
|
|
56
|
+
* Returns either the transformed code, or a retry signal with the failed type.
|
|
57
|
+
* Source map markers in the code are preserved through the typia transformation.
|
|
22
58
|
*/
|
|
23
59
|
private applyTypiaTransform;
|
|
24
60
|
/**
|
|
@@ -34,11 +70,38 @@ export declare class TypicalTransformer {
|
|
|
34
70
|
* source so typia can resolve the types from our generated typia.createAssert<T>() calls.
|
|
35
71
|
*/
|
|
36
72
|
getTransformer(withTypia: boolean): ts.TransformerFactory<ts.SourceFile>;
|
|
73
|
+
/**
|
|
74
|
+
* Transform JSON.stringify or JSON.parse calls to use typia's validated versions.
|
|
75
|
+
* Returns the transformed node if applicable, or undefined to indicate no transformation.
|
|
76
|
+
*/
|
|
77
|
+
private transformJSONCall;
|
|
78
|
+
/**
|
|
79
|
+
* Check if a type should be skipped (failed in typia on previous attempt).
|
|
80
|
+
*/
|
|
81
|
+
private shouldSkipType;
|
|
82
|
+
/**
|
|
83
|
+
* Create an AST visitor function for transforming a source file.
|
|
84
|
+
* The visitor handles JSON calls, type casts, and function declarations.
|
|
85
|
+
*/
|
|
86
|
+
private createVisitor;
|
|
37
87
|
/**
|
|
38
88
|
* Transform a single source file with TypeScript AST
|
|
39
89
|
*/
|
|
40
90
|
private transformSourceFile;
|
|
91
|
+
/**
|
|
92
|
+
* Add @L line markers to nodes that have original source positions.
|
|
93
|
+
* This preserves identity mappings for original code, so lines from the source
|
|
94
|
+
* file map back to themselves rather than inheriting from generated code markers.
|
|
95
|
+
*
|
|
96
|
+
* We need to add markers to every node that will be printed on its own line,
|
|
97
|
+
* including nested members of interfaces, classes, etc.
|
|
98
|
+
*/
|
|
99
|
+
private addLineMarkersToStatements;
|
|
41
100
|
shouldTransformFile(fileName: string): boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Get pre-compiled ignore patterns, caching them for performance.
|
|
103
|
+
*/
|
|
104
|
+
private getCompiledPatterns;
|
|
42
105
|
/**
|
|
43
106
|
* Check if a TypeNode represents a type that shouldn't be validated.
|
|
44
107
|
* This includes:
|
|
@@ -66,12 +129,16 @@ export declare class TypicalTransformer {
|
|
|
66
129
|
/**
|
|
67
130
|
* Check if a single type (not a union) should be ignored.
|
|
68
131
|
* Checks both the type name and its base classes.
|
|
132
|
+
* Uses Set-based cycle detection to handle recursive type hierarchies.
|
|
133
|
+
* @param patterns Pre-compiled RegExp patterns
|
|
134
|
+
* @param visited Set of type IDs already visited (for cycle detection)
|
|
69
135
|
*/
|
|
70
136
|
private isIgnoredSingleType;
|
|
71
137
|
/**
|
|
72
|
-
* Check if a single type name matches any ignore pattern.
|
|
138
|
+
* Check if a single type name matches any pre-compiled ignore pattern.
|
|
139
|
+
* @param patterns Pre-compiled RegExp patterns
|
|
73
140
|
*/
|
|
74
|
-
private
|
|
141
|
+
private matchesIgnorePatternCompiled;
|
|
75
142
|
/**
|
|
76
143
|
* Find untransformed typia calls in the output code.
|
|
77
144
|
* These indicate types that typia could not process.
|