ts-const-value-transformer 0.6.0 → 0.7.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/CHANGELOG.md +12 -0
- package/README.md +2 -0
- package/dist/createPortalTransformer.d.mts +13 -3
- package/dist/createPortalTransformer.mjs +25 -11
- package/dist/index.d.mts +2 -2
- package/dist/loader.mjs +4 -4
- package/dist/transform.mjs +42 -16
- package/dist/version.d.mts +1 -1
- package/dist/version.mjs +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v0.7.1
|
|
4
|
+
|
|
5
|
+
- Fix to wrap import() with eval to prevent from static analysis
|
|
6
|
+
|
|
7
|
+
## v0.7.0
|
|
8
|
+
|
|
9
|
+
- Fix for printing 'minus numeric value' and 'void 0', and remove using `ts.createPrinter`
|
|
10
|
+
- Fix that `recreateProgram` creates the new fresh program instead of passing `oldProgram`
|
|
11
|
+
- Fix to cache source code with no transformation
|
|
12
|
+
- Add option to disable caching original source content (changed to false by default)
|
|
13
|
+
- Fix some codes for better memory usage
|
|
14
|
+
|
|
3
15
|
## v0.6.0
|
|
4
16
|
|
|
5
17
|
- Remove skipping satisfies expression
|
package/README.md
CHANGED
|
@@ -295,6 +295,8 @@ interface CreatePortalTransformerOptions extends TransformOptions {
|
|
|
295
295
|
* If 0 or `undefined`, recreation will not be performed.
|
|
296
296
|
*/
|
|
297
297
|
recreateProgramOnTransformCount?: number;
|
|
298
|
+
/** Specifies to cache base (original) source code for check if the input is changed. Default is false. */
|
|
299
|
+
cacheBaseSource?: boolean;
|
|
298
300
|
}
|
|
299
301
|
```
|
|
300
302
|
|
|
@@ -9,12 +9,22 @@ export interface CreatePortalTransformerOptions extends TransformOptions {
|
|
|
9
9
|
/** The current directory for file search. Also affects to `project` option. */
|
|
10
10
|
cwd?: string;
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
12
|
+
* Specifies the count. When the transformation count reaches this value, `program` instance will be recreated (and count will be reset).
|
|
13
13
|
* This is useful if the project is big and out-of-memory occurs during transformation, but the process may be slower.
|
|
14
14
|
* If 0 or `undefined`, recreation will not be performed.
|
|
15
15
|
*/
|
|
16
16
|
recreateProgramOnTransformCount?: number;
|
|
17
|
+
/** Specifies to cache base (original) source code for check if the input is changed. Default is false. */
|
|
18
|
+
cacheBaseSource?: boolean;
|
|
17
19
|
}
|
|
20
|
+
export type PortalTransformerResult = [
|
|
21
|
+
newSource: string | null,
|
|
22
|
+
newSourceMap: RawSourceMap | undefined
|
|
23
|
+
];
|
|
24
|
+
export type PortalTransformerResultNonNull = [
|
|
25
|
+
newSource: string,
|
|
26
|
+
newSourceMap: RawSourceMap | undefined
|
|
27
|
+
];
|
|
18
28
|
export interface PortalTransformer {
|
|
19
29
|
/** The `typescript` namespace object */
|
|
20
30
|
readonly ts: typeof tsNamespace;
|
|
@@ -32,7 +42,7 @@ export interface PortalTransformer {
|
|
|
32
42
|
* @param options Transform options (addition to `options` passed to `createPortalTransformer`)
|
|
33
43
|
* @returns Tuple of new source code and source map. Source map may be undefined if source code is unchanged.
|
|
34
44
|
*/
|
|
35
|
-
transform(content: string, fileName: string, sourceMap?: string | RawSourceMap | null, options?: TransformOptions):
|
|
45
|
+
transform(content: string, fileName: string, sourceMap?: string | RawSourceMap | null, options?: TransformOptions): PortalTransformerResultNonNull;
|
|
36
46
|
/**
|
|
37
47
|
* Performs transformation.
|
|
38
48
|
* @param content Base source code. If null, uses loaded source code in the TS project.
|
|
@@ -41,7 +51,7 @@ export interface PortalTransformer {
|
|
|
41
51
|
* @param options Transform options (addition to `options` passed to `createPortalTransformer`)
|
|
42
52
|
* @returns Tuple of new source code and source map. Source map may be undefined if source code is unchanged.
|
|
43
53
|
*/
|
|
44
|
-
transform(content: string | null, fileName: string, sourceMap?: string | RawSourceMap | null, options?: TransformOptions):
|
|
54
|
+
transform(content: string | null, fileName: string, sourceMap?: string | RawSourceMap | null, options?: TransformOptions): PortalTransformerResult;
|
|
45
55
|
}
|
|
46
56
|
/**
|
|
47
57
|
* Creates the new portal transformer instance for the TS project.
|
|
@@ -20,6 +20,7 @@ function createPortalTransformerImpl(options, ts) {
|
|
|
20
20
|
const ignoreFiles = getIgnoreFilesFunction(options.ignoreFiles);
|
|
21
21
|
const cwd = options.cwd ?? process.cwd();
|
|
22
22
|
const recreateProgramOnTransformCount = options.recreateProgramOnTransformCount ?? 0;
|
|
23
|
+
const cacheBaseSource = options.cacheBaseSource ?? false;
|
|
23
24
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
24
25
|
const foundConfigPath = ts.findConfigFile(cwd, ts.sys.fileExists, project);
|
|
25
26
|
if (foundConfigPath == null) {
|
|
@@ -50,11 +51,15 @@ function createPortalTransformerImpl(options, ts) {
|
|
|
50
51
|
});
|
|
51
52
|
let transformationCount = 0;
|
|
52
53
|
const recreateProgram = () => {
|
|
53
|
-
|
|
54
|
+
// @ts-expect-error: We must clear reference first to give change for gc
|
|
55
|
+
delete instance.program;
|
|
56
|
+
// @ts-expect-error: We must clear reference first to give change for gc
|
|
57
|
+
program = null;
|
|
58
|
+
// We don't pass `oldProgram` because the transformed source codes should not be necessary (the transformation does not change logics and types)
|
|
59
|
+
// If we pass `oldProgram`, temporal memory usage may increase because gc cannot release `oldProgram` before creating new program
|
|
54
60
|
program = ts.createProgram({
|
|
55
61
|
options: config.options,
|
|
56
62
|
rootNames: config.fileNames,
|
|
57
|
-
oldProgram,
|
|
58
63
|
});
|
|
59
64
|
instance.program = program;
|
|
60
65
|
transformationCount = 0;
|
|
@@ -69,7 +74,7 @@ function createPortalTransformerImpl(options, ts) {
|
|
|
69
74
|
const individualOptionsJson = optionsToString(individualOptions ?? {});
|
|
70
75
|
const cachedData = cache.get(fileName);
|
|
71
76
|
if (cachedData &&
|
|
72
|
-
cachedData.content === content &&
|
|
77
|
+
(!cacheBaseSource || cachedData.content === content) &&
|
|
73
78
|
cachedData.optJson === individualOptionsJson) {
|
|
74
79
|
return cachedData.result;
|
|
75
80
|
}
|
|
@@ -80,15 +85,15 @@ function createPortalTransformerImpl(options, ts) {
|
|
|
80
85
|
if (ignoreFiles(fileName)) {
|
|
81
86
|
return [content, rawSourceMap];
|
|
82
87
|
}
|
|
88
|
+
const sourceFile = program.getSourceFile(fileName);
|
|
89
|
+
if (!sourceFile) {
|
|
90
|
+
return [content, rawSourceMap];
|
|
91
|
+
}
|
|
83
92
|
transformationCount++;
|
|
84
93
|
if (recreateProgramOnTransformCount > 0 &&
|
|
85
94
|
transformationCount >= recreateProgramOnTransformCount) {
|
|
86
95
|
recreateProgram();
|
|
87
96
|
}
|
|
88
|
-
const sourceFile = program.getSourceFile(fileName);
|
|
89
|
-
if (!sourceFile) {
|
|
90
|
-
return [content, rawSourceMap];
|
|
91
|
-
}
|
|
92
97
|
// If input content is changed, replace it
|
|
93
98
|
if (content != null && sourceFile.text !== content) {
|
|
94
99
|
sourceFile.update(content, {
|
|
@@ -102,12 +107,19 @@ function createPortalTransformerImpl(options, ts) {
|
|
|
102
107
|
});
|
|
103
108
|
const transformResult = ts.transform(sourceFile, [transformer], program.getCompilerOptions());
|
|
104
109
|
const transformedSource = transformResult.transformed[0];
|
|
110
|
+
let result;
|
|
105
111
|
// If unchanged, return base file as-is
|
|
106
112
|
if (transformedSource === sourceFile) {
|
|
107
|
-
|
|
113
|
+
result = [content ?? sourceFile.text, rawSourceMap];
|
|
108
114
|
}
|
|
109
|
-
|
|
110
|
-
|
|
115
|
+
else {
|
|
116
|
+
result = printSourceWithMap(transformedSource, fileName, rawSourceMap, ts);
|
|
117
|
+
}
|
|
118
|
+
cache.set(fileName, {
|
|
119
|
+
content: cacheBaseSource ? content : '',
|
|
120
|
+
optJson: individualOptionsJson,
|
|
121
|
+
result,
|
|
122
|
+
});
|
|
111
123
|
return result;
|
|
112
124
|
},
|
|
113
125
|
};
|
|
@@ -121,7 +133,9 @@ export default async function createPortalTransformer(options = {}) {
|
|
|
121
133
|
let ts;
|
|
122
134
|
if (options.typescript != null) {
|
|
123
135
|
if (typeof options.typescript === 'string') {
|
|
124
|
-
|
|
136
|
+
// Use eval to avoid webpack warnings
|
|
137
|
+
// eslint-disable-next-line no-eval
|
|
138
|
+
ts = (await eval('import(options.typescript)'));
|
|
125
139
|
}
|
|
126
140
|
else {
|
|
127
141
|
ts = options.typescript;
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import createPortalTransformer, { createPortalTransformerSync, type CreatePortalTransformerOptions, type PortalTransformer } from './createPortalTransformer.mjs';
|
|
1
|
+
import createPortalTransformer, { createPortalTransformerSync, type CreatePortalTransformerOptions, type PortalTransformer, type PortalTransformerResult, type PortalTransformerResultNonNull } from './createPortalTransformer.mjs';
|
|
2
2
|
import createTransformer from './createTransformer.mjs';
|
|
3
3
|
import version from './version.mjs';
|
|
4
4
|
export { printSource, printSourceWithMap, transformSource, type TransformOptions, } from './transform.mjs';
|
|
5
|
-
export { createPortalTransformer, createPortalTransformerSync, createTransformer, type CreatePortalTransformerOptions, type PortalTransformer, version, };
|
|
5
|
+
export { createPortalTransformer, createPortalTransformerSync, createTransformer, type CreatePortalTransformerOptions, type PortalTransformer, type PortalTransformerResult, type PortalTransformerResultNonNull, version, };
|
package/dist/loader.mjs
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import * as path from 'path';
|
|
2
|
-
import
|
|
2
|
+
import createPortalTransformer, {} from './createPortalTransformer.mjs';
|
|
3
3
|
const transformerMap = new Map();
|
|
4
4
|
const loader = function (content, sourceMap) {
|
|
5
5
|
// eslint-disable-next-line @typescript-eslint/no-unused-expressions, @typescript-eslint/strict-boolean-expressions
|
|
6
6
|
this.cacheable && this.cacheable();
|
|
7
7
|
this.async();
|
|
8
|
-
void
|
|
8
|
+
void (async () => {
|
|
9
9
|
try {
|
|
10
10
|
const options = this.getOptions() || {};
|
|
11
11
|
const project = options.project ?? 'tsconfig.json';
|
|
12
12
|
let transformer = transformerMap.get(project);
|
|
13
13
|
if (!transformer) {
|
|
14
|
-
transformer =
|
|
14
|
+
transformer = await createPortalTransformer({
|
|
15
15
|
cwd: path.dirname(this.resourcePath),
|
|
16
16
|
...options,
|
|
17
17
|
});
|
|
@@ -23,6 +23,6 @@ const loader = function (content, sourceMap) {
|
|
|
23
23
|
catch (e) {
|
|
24
24
|
this.callback(e);
|
|
25
25
|
}
|
|
26
|
-
});
|
|
26
|
+
})();
|
|
27
27
|
};
|
|
28
28
|
export default loader;
|
package/dist/transform.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as sourceMap from 'source-map';
|
|
2
2
|
import * as tsNamespace from 'typescript';
|
|
3
|
-
const
|
|
3
|
+
const SYMBOL_ORIGINAL_NODE_DATA = Symbol('originalNodeData');
|
|
4
4
|
function assignDefaultValues(options = {}) {
|
|
5
5
|
return {
|
|
6
6
|
// avoid using spread syntax to override `undefined` (not missing) values
|
|
@@ -46,7 +46,7 @@ export function transformSource(sourceFile, program, context, options) {
|
|
|
46
46
|
function visitNodeChildren(node, parent, sourceFile, program, options) {
|
|
47
47
|
const ts = options.ts;
|
|
48
48
|
const newNode = visitNodeAndReplaceIfNeeded(node, parent, sourceFile, program, options);
|
|
49
|
-
if (newNode[
|
|
49
|
+
if (newNode[SYMBOL_ORIGINAL_NODE_DATA]) {
|
|
50
50
|
return newNode;
|
|
51
51
|
}
|
|
52
52
|
// skip statements which would not have 'value' expressions
|
|
@@ -126,34 +126,50 @@ function visitNodeAndReplaceIfNeeded(node, parent, sourceFile, program, options)
|
|
|
126
126
|
if (type.isUnionOrIntersection()) {
|
|
127
127
|
return node;
|
|
128
128
|
}
|
|
129
|
+
let newSource;
|
|
129
130
|
if (type.isStringLiteral()) {
|
|
130
131
|
newNode = ts.factory.createStringLiteral(type.value);
|
|
132
|
+
newSource =
|
|
133
|
+
// TypeScript namespace may export `function escapeNonAsciiString(s: string, quoteChar?: CharacterCodes.doubleQuote | CharacterCodes.singleQuote | CharacterCodes.backtick): string`
|
|
134
|
+
'escapeNonAsciiString' in ts
|
|
135
|
+
? `"${ts.escapeNonAsciiString(type.value, 'CharacterCodes' in ts
|
|
136
|
+
? ts.CharacterCodes.doubleQuote
|
|
137
|
+
: 34 /* doubleQuote */)}"`
|
|
138
|
+
: JSON.stringify(type.value);
|
|
131
139
|
}
|
|
132
140
|
else if (type.isNumberLiteral()) {
|
|
133
141
|
if (type.value < 0) {
|
|
134
|
-
newNode = ts.factory.createPrefixUnaryExpression(ts.SyntaxKind.MinusToken, ts.factory.createNumericLiteral(-type.value));
|
|
142
|
+
newNode = ts.factory.createParenthesizedExpression(ts.factory.createPrefixUnaryExpression(ts.SyntaxKind.MinusToken, ts.factory.createNumericLiteral(-type.value)));
|
|
143
|
+
newSource = `(-${-type.value})`;
|
|
135
144
|
}
|
|
136
145
|
else {
|
|
137
146
|
newNode = ts.factory.createNumericLiteral(type.value);
|
|
147
|
+
newSource = `${type.value}`;
|
|
138
148
|
}
|
|
139
149
|
}
|
|
140
150
|
else if (flags & ts.TypeFlags.BigIntLiteral) {
|
|
141
|
-
|
|
151
|
+
const text = typeChecker.typeToString(type);
|
|
152
|
+
newNode = ts.factory.createBigIntLiteral(text);
|
|
153
|
+
newSource = text;
|
|
142
154
|
}
|
|
143
155
|
else if (flags & ts.TypeFlags.BooleanLiteral) {
|
|
144
156
|
const text = typeChecker.typeToString(type);
|
|
145
157
|
newNode =
|
|
146
158
|
text === 'true' ? ts.factory.createTrue() : ts.factory.createFalse();
|
|
159
|
+
newSource = text;
|
|
147
160
|
}
|
|
148
161
|
else if (flags & ts.TypeFlags.Null) {
|
|
149
162
|
newNode = ts.factory.createNull();
|
|
163
|
+
newSource = 'null';
|
|
150
164
|
}
|
|
151
165
|
else if (flags & ts.TypeFlags.Undefined) {
|
|
152
166
|
if (options.useUndefinedSymbolForUndefinedValue) {
|
|
153
167
|
newNode = ts.factory.createIdentifier('undefined');
|
|
168
|
+
newSource = 'undefined';
|
|
154
169
|
}
|
|
155
170
|
else {
|
|
156
|
-
newNode = ts.factory.createVoidZero();
|
|
171
|
+
newNode = ts.factory.createParenthesizedExpression(ts.factory.createVoidZero());
|
|
172
|
+
newSource = '(void 0)';
|
|
157
173
|
}
|
|
158
174
|
}
|
|
159
175
|
else {
|
|
@@ -161,7 +177,12 @@ function visitNodeAndReplaceIfNeeded(node, parent, sourceFile, program, options)
|
|
|
161
177
|
}
|
|
162
178
|
const result = ts.addSyntheticTrailingComment(newNode, ts.SyntaxKind.MultiLineCommentTrivia, ` ${node.getText(sourceFile)} `);
|
|
163
179
|
ts.setTextRange(result, node);
|
|
164
|
-
result[
|
|
180
|
+
result[SYMBOL_ORIGINAL_NODE_DATA] = [
|
|
181
|
+
node.getText(sourceFile),
|
|
182
|
+
newSource,
|
|
183
|
+
node.pos,
|
|
184
|
+
node.end,
|
|
185
|
+
];
|
|
165
186
|
return result;
|
|
166
187
|
}
|
|
167
188
|
catch {
|
|
@@ -432,22 +453,27 @@ function positionToLineAndColumn(sourceFile, pos, generatedDiff) {
|
|
|
432
453
|
}
|
|
433
454
|
function printSourceImpl(tsInstance, sourceFile, originalSourceName, mapGenerator) {
|
|
434
455
|
const ts = tsInstance ?? tsNamespace;
|
|
435
|
-
const
|
|
436
|
-
|
|
437
|
-
|
|
456
|
+
const r = printNode(ts, sourceFile.getFullText(), sourceFile, sourceFile, { pos: 0, diff: 0, lastLine: 0 }, originalSourceName, mapGenerator);
|
|
457
|
+
// This forces to concatenate strings into flatten one to reduce object trees for ConsString
|
|
458
|
+
void (r | 0);
|
|
459
|
+
const json = mapGenerator?.toJSON();
|
|
460
|
+
if (json) {
|
|
461
|
+
void (json.mappings | 0);
|
|
462
|
+
}
|
|
463
|
+
return [r, json];
|
|
438
464
|
}
|
|
439
|
-
function printNode(tsInstance,
|
|
440
|
-
const
|
|
441
|
-
if (
|
|
442
|
-
let result =
|
|
465
|
+
function printNode(tsInstance, baseSource, sourceFile, node, posContext, originalSourceName, mapGenerator) {
|
|
466
|
+
const originalNodeData = node[SYMBOL_ORIGINAL_NODE_DATA];
|
|
467
|
+
if (originalNodeData) {
|
|
468
|
+
let result = originalNodeData[1];
|
|
443
469
|
const comments = tsInstance.getSyntheticTrailingComments(node);
|
|
444
470
|
if (comments) {
|
|
445
471
|
for (const comment of comments) {
|
|
446
472
|
result += ` /*${comment.text}*/`;
|
|
447
473
|
}
|
|
448
474
|
}
|
|
449
|
-
const old =
|
|
450
|
-
const oldFull = baseSource.substring(
|
|
475
|
+
const old = originalNodeData[0];
|
|
476
|
+
const oldFull = baseSource.substring(originalNodeData[2], originalNodeData[3]);
|
|
451
477
|
const i = oldFull.lastIndexOf(old);
|
|
452
478
|
const leadingUnchanged = i < 0 ? 0 : i;
|
|
453
479
|
const newText = i < 0
|
|
@@ -490,7 +516,7 @@ function printNode(tsInstance, printer, baseSource, sourceFile, node, posContext
|
|
|
490
516
|
addMappingForCurrent();
|
|
491
517
|
posContext.pos = child.pos;
|
|
492
518
|
}
|
|
493
|
-
output += printNode(tsInstance,
|
|
519
|
+
output += printNode(tsInstance, baseSource, sourceFile, child, posContext, originalSourceName, mapGenerator);
|
|
494
520
|
lastChildPos = child.end;
|
|
495
521
|
return child;
|
|
496
522
|
}, void 0);
|
package/dist/version.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: "0.
|
|
1
|
+
declare const _default: "0.7.1";
|
|
2
2
|
export default _default;
|
package/dist/version.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export default '0.
|
|
1
|
+
export default '0.7.1';
|