ts-const-value-transformer 0.5.1 → 0.7.0
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 +18 -0
- package/README.md +20 -1
- package/dist/createPortalTransformer.d.mts +25 -2
- package/dist/createPortalTransformer.mjs +68 -10
- package/dist/createTransformer.d.mts +2 -1
- package/dist/createTransformer.mjs +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/loader.d.mts +2 -6
- package/dist/loader.mjs +7 -5
- package/dist/transform.d.mts +4 -4
- package/dist/transform.mjs +75 -52
- 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,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v0.7.0
|
|
4
|
+
|
|
5
|
+
- Fix for printing 'minus numeric value' and 'void 0', and remove using `ts.createPrinter`
|
|
6
|
+
- Fix that `recreateProgram` creates the new fresh program instead of passing `oldProgram`
|
|
7
|
+
- Fix to cache source code with no transformation
|
|
8
|
+
- Add option to disable caching original source content (changed to false by default)
|
|
9
|
+
- Fix some codes for better memory usage
|
|
10
|
+
|
|
11
|
+
## v0.6.0
|
|
12
|
+
|
|
13
|
+
- Remove skipping satisfies expression
|
|
14
|
+
- Accept `undefined` for `context` and remove dependencies for `context`
|
|
15
|
+
- Fix referring `ts` instance and add `ts` parameter for printSource
|
|
16
|
+
- Add cache to createPortalTransformer
|
|
17
|
+
- Add `recreateProgramOnTransformCount` option for PortalTransformer
|
|
18
|
+
- Fix to use `createPortalTransformerSync` for webpack loader
|
|
19
|
+
- Search tsconfig before loading
|
|
20
|
+
|
|
3
21
|
## v0.5.1
|
|
4
22
|
|
|
5
23
|
- Fix missing for handling `ignoreFiles` for `createTransformer` (used from ts-loader, etc.)
|
package/README.md
CHANGED
|
@@ -279,7 +279,26 @@ See [Transform options](#transform-options).
|
|
|
279
279
|
Creates 'portal transformer', which can be used the transformer easily from the code which does not use TypeScript Compiler API.
|
|
280
280
|
The return object has `transform` method with signature: `(content: string, fileName: string, sourceMap?: string | RawSourceMap | null, options?: TransformOptions) => [newSource: string, newSourceMap: RawSourceMap | undefined]`. You can call to transform TypeScript source code. (Note that this API does not transpile to JavaScript; the output code is still TypeScript code.)
|
|
281
281
|
|
|
282
|
-
`CreatePortalTransformerOptions` has
|
|
282
|
+
`CreatePortalTransformerOptions` has a following signature. Also, `ignoreFiles` of `TransformOptions` can be used.
|
|
283
|
+
|
|
284
|
+
```ts
|
|
285
|
+
interface CreatePortalTransformerOptions extends TransformOptions {
|
|
286
|
+
/** Path to tsconfig.json. If omitted, `tsconfig.json` will be used. */
|
|
287
|
+
project?: string;
|
|
288
|
+
/** Package path to `typescript` or `typescript` namespace object. */
|
|
289
|
+
typescript?: string | typeof tsNamespace;
|
|
290
|
+
/** The current directory for file search. Also affects to `project` option. */
|
|
291
|
+
cwd?: string;
|
|
292
|
+
/**
|
|
293
|
+
* Speficies the count. When the transformation count reaches this value, `program` instance will be recreated (and count will be reset).
|
|
294
|
+
* This is useful if the project is big and out-of-memory occurs during transformation, but the process may be slower.
|
|
295
|
+
* If 0 or `undefined`, recreation will not be performed.
|
|
296
|
+
*/
|
|
297
|
+
recreateProgramOnTransformCount?: number;
|
|
298
|
+
/** Specifies to cache base (original) source code for check if the input is changed. Default is false. */
|
|
299
|
+
cacheBaseSource?: boolean;
|
|
300
|
+
}
|
|
301
|
+
```
|
|
283
302
|
|
|
284
303
|
If `Promise` cannot be used for some reason, use `createPortalTransformerSync` instead.
|
|
285
304
|
|
|
@@ -2,15 +2,38 @@ import type { RawSourceMap } from 'source-map';
|
|
|
2
2
|
import type * as tsNamespace from 'typescript';
|
|
3
3
|
import { type TransformOptions } from './transform.mjs';
|
|
4
4
|
export interface CreatePortalTransformerOptions extends TransformOptions {
|
|
5
|
+
/** Path to tsconfig.json. If omitted, `tsconfig.json` will be used. */
|
|
5
6
|
project?: string;
|
|
7
|
+
/** Package path to `typescript` or `typescript` namespace object. */
|
|
6
8
|
typescript?: string | typeof tsNamespace;
|
|
9
|
+
/** The current directory for file search. Also affects to `project` option. */
|
|
7
10
|
cwd?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Specifies the count. When the transformation count reaches this value, `program` instance will be recreated (and count will be reset).
|
|
13
|
+
* This is useful if the project is big and out-of-memory occurs during transformation, but the process may be slower.
|
|
14
|
+
* If 0 or `undefined`, recreation will not be performed.
|
|
15
|
+
*/
|
|
16
|
+
recreateProgramOnTransformCount?: number;
|
|
17
|
+
/** Specifies to cache base (original) source code for check if the input is changed. Default is false. */
|
|
18
|
+
cacheBaseSource?: boolean;
|
|
8
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
|
+
];
|
|
9
28
|
export interface PortalTransformer {
|
|
10
29
|
/** The `typescript` namespace object */
|
|
11
30
|
readonly ts: typeof tsNamespace;
|
|
12
31
|
/** Active `Program` instance for the transformer */
|
|
13
32
|
readonly program: tsNamespace.Program;
|
|
33
|
+
/** Clears transformed cache. */
|
|
34
|
+
clearCache(): void;
|
|
35
|
+
/** Forces `program` recreation. The transformation count for `recreateProgramOnTransformCount` will also be resetted. */
|
|
36
|
+
recreateProgram(): void;
|
|
14
37
|
/**
|
|
15
38
|
* Performs transformation.
|
|
16
39
|
* @param content Base source code. If null, uses loaded source code in the TS project.
|
|
@@ -19,7 +42,7 @@ export interface PortalTransformer {
|
|
|
19
42
|
* @param options Transform options (addition to `options` passed to `createPortalTransformer`)
|
|
20
43
|
* @returns Tuple of new source code and source map. Source map may be undefined if source code is unchanged.
|
|
21
44
|
*/
|
|
22
|
-
transform(content: string, fileName: string, sourceMap?: string | RawSourceMap | null, options?: TransformOptions):
|
|
45
|
+
transform(content: string, fileName: string, sourceMap?: string | RawSourceMap | null, options?: TransformOptions): PortalTransformerResultNonNull;
|
|
23
46
|
/**
|
|
24
47
|
* Performs transformation.
|
|
25
48
|
* @param content Base source code. If null, uses loaded source code in the TS project.
|
|
@@ -28,7 +51,7 @@ export interface PortalTransformer {
|
|
|
28
51
|
* @param options Transform options (addition to `options` passed to `createPortalTransformer`)
|
|
29
52
|
* @returns Tuple of new source code and source map. Source map may be undefined if source code is unchanged.
|
|
30
53
|
*/
|
|
31
|
-
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;
|
|
32
55
|
}
|
|
33
56
|
/**
|
|
34
57
|
* Creates the new portal transformer instance for the TS project.
|
|
@@ -4,12 +4,30 @@ import * as path from 'path';
|
|
|
4
4
|
import createTransformer from './createTransformer.mjs';
|
|
5
5
|
import { getIgnoreFilesFunction, printSourceWithMap, } from './transform.mjs';
|
|
6
6
|
const require = createRequire(import.meta.url);
|
|
7
|
+
function optionsToString(options) {
|
|
8
|
+
return JSON.stringify(options, (key, value) => {
|
|
9
|
+
if (typeof value === 'function' || value instanceof RegExp) {
|
|
10
|
+
return value.toString();
|
|
11
|
+
}
|
|
12
|
+
if (key === 'typescript' && typeof value === 'object' && value != null) {
|
|
13
|
+
return '[object typescript]';
|
|
14
|
+
}
|
|
15
|
+
return value;
|
|
16
|
+
});
|
|
17
|
+
}
|
|
7
18
|
function createPortalTransformerImpl(options, ts) {
|
|
8
19
|
const project = options.project ?? 'tsconfig.json';
|
|
9
20
|
const ignoreFiles = getIgnoreFilesFunction(options.ignoreFiles);
|
|
10
21
|
const cwd = options.cwd ?? process.cwd();
|
|
22
|
+
const recreateProgramOnTransformCount = options.recreateProgramOnTransformCount ?? 0;
|
|
23
|
+
const cacheBaseSource = options.cacheBaseSource ?? false;
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
25
|
+
const foundConfigPath = ts.findConfigFile(cwd, ts.sys.fileExists, project);
|
|
26
|
+
if (foundConfigPath == null) {
|
|
27
|
+
throw new Error(`[ts-const-value-transformer] Unable to load tsconfig file (effective name = '${project}')`);
|
|
28
|
+
}
|
|
11
29
|
const getCurrentDirectory = () => cwd;
|
|
12
|
-
const config = ts.getParsedCommandLineOfConfigFile(
|
|
30
|
+
const config = ts.getParsedCommandLineOfConfigFile(foundConfigPath, void 0, {
|
|
13
31
|
fileExists: fs.existsSync,
|
|
14
32
|
getCurrentDirectory,
|
|
15
33
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
@@ -25,16 +43,41 @@ function createPortalTransformerImpl(options, ts) {
|
|
|
25
43
|
},
|
|
26
44
|
});
|
|
27
45
|
if (!config) {
|
|
28
|
-
throw new Error(`[ts-const-value-transformer] Unable to load tsconfig file (effective name = '${
|
|
46
|
+
throw new Error(`[ts-const-value-transformer] Unable to load tsconfig file (effective name = '${foundConfigPath}')`);
|
|
29
47
|
}
|
|
30
|
-
|
|
48
|
+
let program = ts.createProgram({
|
|
31
49
|
options: config.options,
|
|
32
50
|
rootNames: config.fileNames,
|
|
33
51
|
});
|
|
34
|
-
|
|
52
|
+
let transformationCount = 0;
|
|
53
|
+
const recreateProgram = () => {
|
|
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
|
|
60
|
+
program = ts.createProgram({
|
|
61
|
+
options: config.options,
|
|
62
|
+
rootNames: config.fileNames,
|
|
63
|
+
});
|
|
64
|
+
instance.program = program;
|
|
65
|
+
transformationCount = 0;
|
|
66
|
+
};
|
|
67
|
+
const cache = new Map();
|
|
68
|
+
const instance = {
|
|
35
69
|
ts,
|
|
36
70
|
program,
|
|
71
|
+
clearCache: () => cache.clear(),
|
|
72
|
+
recreateProgram,
|
|
37
73
|
transform: (content, fileName, sourceMap, individualOptions) => {
|
|
74
|
+
const individualOptionsJson = optionsToString(individualOptions ?? {});
|
|
75
|
+
const cachedData = cache.get(fileName);
|
|
76
|
+
if (cachedData &&
|
|
77
|
+
(!cacheBaseSource || cachedData.content === content) &&
|
|
78
|
+
cachedData.optJson === individualOptionsJson) {
|
|
79
|
+
return cachedData.result;
|
|
80
|
+
}
|
|
38
81
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
39
82
|
const rawSourceMap = typeof sourceMap === 'string'
|
|
40
83
|
? JSON.parse(sourceMap)
|
|
@@ -46,26 +89,41 @@ function createPortalTransformerImpl(options, ts) {
|
|
|
46
89
|
if (!sourceFile) {
|
|
47
90
|
return [content, rawSourceMap];
|
|
48
91
|
}
|
|
92
|
+
transformationCount++;
|
|
93
|
+
if (recreateProgramOnTransformCount > 0 &&
|
|
94
|
+
transformationCount >= recreateProgramOnTransformCount) {
|
|
95
|
+
recreateProgram();
|
|
96
|
+
}
|
|
49
97
|
// If input content is changed, replace it
|
|
50
|
-
if (content != null && sourceFile.
|
|
98
|
+
if (content != null && sourceFile.text !== content) {
|
|
51
99
|
sourceFile.update(content, {
|
|
52
100
|
span: { start: 0, length: sourceFile.end },
|
|
53
101
|
newLength: content.length,
|
|
54
102
|
});
|
|
103
|
+
sourceFile.text = content;
|
|
55
104
|
}
|
|
56
105
|
const transformer = createTransformer(program, {
|
|
57
106
|
options: { ...options, ...individualOptions, ts },
|
|
58
107
|
});
|
|
59
|
-
const
|
|
60
|
-
const transformedSource =
|
|
108
|
+
const transformResult = ts.transform(sourceFile, [transformer], program.getCompilerOptions());
|
|
109
|
+
const transformedSource = transformResult.transformed[0];
|
|
110
|
+
let result;
|
|
61
111
|
// If unchanged, return base file as-is
|
|
62
112
|
if (transformedSource === sourceFile) {
|
|
63
|
-
|
|
113
|
+
result = [content ?? sourceFile.text, rawSourceMap];
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
result = printSourceWithMap(transformedSource, fileName, rawSourceMap, ts);
|
|
64
117
|
}
|
|
65
|
-
|
|
66
|
-
|
|
118
|
+
cache.set(fileName, {
|
|
119
|
+
content: cacheBaseSource ? content : '',
|
|
120
|
+
optJson: individualOptionsJson,
|
|
121
|
+
result,
|
|
122
|
+
});
|
|
123
|
+
return result;
|
|
67
124
|
},
|
|
68
125
|
};
|
|
126
|
+
return instance;
|
|
69
127
|
}
|
|
70
128
|
/**
|
|
71
129
|
* Creates the new portal transformer instance for the TS project.
|
|
@@ -3,7 +3,8 @@ import { type TransformOptions } from './transform.mjs';
|
|
|
3
3
|
interface Config {
|
|
4
4
|
options?: TransformOptions;
|
|
5
5
|
}
|
|
6
|
+
export type TransformerFactory = (context?: ts.TransformationContext) => (sourceFile: ts.SourceFile) => ts.SourceFile;
|
|
6
7
|
export default function createTransformer(program: ts.Program, config?: Config, extras?: {
|
|
7
8
|
ts?: typeof ts;
|
|
8
|
-
}):
|
|
9
|
+
}): TransformerFactory;
|
|
9
10
|
export {};
|
|
@@ -9,12 +9,12 @@ extras) {
|
|
|
9
9
|
...(extras?.ts && { ts: extras?.ts }),
|
|
10
10
|
};
|
|
11
11
|
const ignoreFiles = getIgnoreFilesFunction(options.ignoreFiles);
|
|
12
|
-
return (context) => {
|
|
12
|
+
return ((context) => {
|
|
13
13
|
return (sourceFile) => {
|
|
14
14
|
if (ignoreFiles(sourceFile.fileName)) {
|
|
15
15
|
return sourceFile;
|
|
16
16
|
}
|
|
17
17
|
return transformSource(sourceFile, program, context, options);
|
|
18
18
|
};
|
|
19
|
-
};
|
|
19
|
+
});
|
|
20
20
|
}
|
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.d.mts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import type * as tsNamespace from 'typescript';
|
|
2
1
|
import type * as webpack from 'webpack';
|
|
3
|
-
import type
|
|
4
|
-
export
|
|
5
|
-
project?: string;
|
|
6
|
-
typescript?: string | typeof tsNamespace;
|
|
7
|
-
}
|
|
2
|
+
import { type CreatePortalTransformerOptions } from './createPortalTransformer.mjs';
|
|
3
|
+
export type TsConstValueTransformerLoaderOptions = CreatePortalTransformerOptions;
|
|
8
4
|
declare const loader: webpack.LoaderDefinitionFunction<TsConstValueTransformerLoaderOptions | undefined>;
|
|
9
5
|
export default loader;
|
package/dist/loader.mjs
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import * as path from 'path';
|
|
2
|
-
import
|
|
2
|
+
import { createPortalTransformerSync, } from './createPortalTransformer.mjs';
|
|
3
3
|
const transformerMap = new Map();
|
|
4
4
|
const loader = function (content, sourceMap) {
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions, @typescript-eslint/strict-boolean-expressions
|
|
6
|
+
this.cacheable && this.cacheable();
|
|
5
7
|
this.async();
|
|
6
|
-
void (
|
|
8
|
+
void Promise.resolve().then(() => {
|
|
7
9
|
try {
|
|
8
10
|
const options = this.getOptions() || {};
|
|
9
11
|
const project = options.project ?? 'tsconfig.json';
|
|
10
12
|
let transformer = transformerMap.get(project);
|
|
11
13
|
if (!transformer) {
|
|
12
|
-
transformer =
|
|
13
|
-
...options,
|
|
14
|
+
transformer = createPortalTransformerSync({
|
|
14
15
|
cwd: path.dirname(this.resourcePath),
|
|
16
|
+
...options,
|
|
15
17
|
});
|
|
16
18
|
transformerMap.set(project, transformer);
|
|
17
19
|
}
|
|
@@ -21,6 +23,6 @@ const loader = function (content, sourceMap) {
|
|
|
21
23
|
catch (e) {
|
|
22
24
|
this.callback(e);
|
|
23
25
|
}
|
|
24
|
-
})
|
|
26
|
+
});
|
|
25
27
|
};
|
|
26
28
|
export default loader;
|
package/dist/transform.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as sourceMap from 'source-map';
|
|
2
|
-
import * as ts from 'typescript';
|
|
2
|
+
import type * as ts from 'typescript';
|
|
3
3
|
export interface TransformOptions {
|
|
4
4
|
/** `typescript` namespace object */
|
|
5
5
|
ts?: typeof ts;
|
|
@@ -36,6 +36,6 @@ export interface TransformOptions {
|
|
|
36
36
|
ignoreFiles?: ReadonlyArray<string | RegExp> | ((fileName: string) => boolean);
|
|
37
37
|
}
|
|
38
38
|
export declare function getIgnoreFilesFunction(ignoreFiles: TransformOptions['ignoreFiles']): (fileName: string) => boolean;
|
|
39
|
-
export declare function transformSource(sourceFile: ts.SourceFile, program: ts.Program, context: ts.TransformationContext, options?: TransformOptions): ts.SourceFile;
|
|
40
|
-
export declare function printSource(sourceFile: ts.SourceFile): string;
|
|
41
|
-
export declare function printSourceWithMap(sourceFile: ts.SourceFile, originalSourceName: string, startOfSourceMap?: sourceMap.RawSourceMap): [string, sourceMap.RawSourceMap];
|
|
39
|
+
export declare function transformSource(sourceFile: ts.SourceFile, program: ts.Program, context: ts.TransformationContext | undefined, options?: TransformOptions): ts.SourceFile;
|
|
40
|
+
export declare function printSource(sourceFile: ts.SourceFile, tsInstance?: typeof ts): string;
|
|
41
|
+
export declare function printSourceWithMap(sourceFile: ts.SourceFile, originalSourceName: string, startOfSourceMap?: sourceMap.RawSourceMap, tsInstance?: typeof ts): [string, sourceMap.RawSourceMap];
|
package/dist/transform.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as sourceMap from 'source-map';
|
|
2
|
-
import * as
|
|
3
|
-
const
|
|
2
|
+
import * as tsNamespace from 'typescript';
|
|
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
|
|
7
|
-
ts: options.ts ??
|
|
7
|
+
ts: options.ts ?? tsNamespace,
|
|
8
8
|
hoistProperty: options.hoistProperty ?? true,
|
|
9
9
|
hoistEnumValues: options.hoistEnumValues ?? true,
|
|
10
10
|
hoistExternalValues: options.hoistExternalValues ?? true,
|
|
@@ -40,15 +40,13 @@ export function getIgnoreFilesFunction(ignoreFiles) {
|
|
|
40
40
|
}
|
|
41
41
|
////////////////////////////////////////////////////////////////////////////////
|
|
42
42
|
export function transformSource(sourceFile, program, context, options) {
|
|
43
|
-
|
|
43
|
+
const requiredOptions = assignDefaultValues(options);
|
|
44
|
+
return requiredOptions.ts.visitEachChild(sourceFile, (node) => visitNodeChildren(node, sourceFile, sourceFile, program, requiredOptions), context);
|
|
44
45
|
}
|
|
45
|
-
function visitNodeChildren(node, parent, sourceFile, program,
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
// skip children for satisifes expression
|
|
51
|
-
if (ts.isSatisfiesExpression(newNode)) {
|
|
46
|
+
function visitNodeChildren(node, parent, sourceFile, program, options) {
|
|
47
|
+
const ts = options.ts;
|
|
48
|
+
const newNode = visitNodeAndReplaceIfNeeded(node, parent, sourceFile, program, options);
|
|
49
|
+
if (newNode[SYMBOL_ORIGINAL_NODE_DATA]) {
|
|
52
50
|
return newNode;
|
|
53
51
|
}
|
|
54
52
|
// skip statements which would not have 'value' expressions
|
|
@@ -59,9 +57,9 @@ function visitNodeChildren(node, parent, sourceFile, program, context, options)
|
|
|
59
57
|
ts.isTypeOnlyExportDeclaration(newNode)) {
|
|
60
58
|
return newNode;
|
|
61
59
|
}
|
|
62
|
-
return ts.visitEachChild(newNode, (node) => visitNodeChildren(node, newNode, sourceFile, program,
|
|
60
|
+
return ts.visitEachChild(newNode, (node) => visitNodeChildren(node, newNode, sourceFile, program, options), void 0);
|
|
63
61
|
}
|
|
64
|
-
function visitNodeAndReplaceIfNeeded(node, parent, sourceFile, program,
|
|
62
|
+
function visitNodeAndReplaceIfNeeded(node, parent, sourceFile, program, options) {
|
|
65
63
|
const ts = options.ts;
|
|
66
64
|
if (ts.isCallLikeExpression(node)) {
|
|
67
65
|
if (!ts.isExpression(node) ||
|
|
@@ -107,12 +105,11 @@ function visitNodeAndReplaceIfNeeded(node, parent, sourceFile, program, context,
|
|
|
107
105
|
return node;
|
|
108
106
|
}
|
|
109
107
|
if (!options.hoistExternalValues &&
|
|
110
|
-
isExternalReference(node, program, options.externalNames)) {
|
|
108
|
+
isExternalReference(node, program, options.externalNames, ts)) {
|
|
111
109
|
return node;
|
|
112
110
|
}
|
|
113
111
|
if (!options.unsafeHoistAsExpresion &&
|
|
114
|
-
(hasAsExpression(node,
|
|
115
|
-
hasParentAsExpression(parent, context, ts))) {
|
|
112
|
+
(hasAsExpression(node, ts) || hasParentAsExpression(parent, ts))) {
|
|
116
113
|
return node;
|
|
117
114
|
}
|
|
118
115
|
if (!options.unsafeHoistWritableValues) {
|
|
@@ -129,36 +126,50 @@ function visitNodeAndReplaceIfNeeded(node, parent, sourceFile, program, context,
|
|
|
129
126
|
if (type.isUnionOrIntersection()) {
|
|
130
127
|
return node;
|
|
131
128
|
}
|
|
129
|
+
let newSource;
|
|
132
130
|
if (type.isStringLiteral()) {
|
|
133
|
-
newNode =
|
|
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);
|
|
134
139
|
}
|
|
135
140
|
else if (type.isNumberLiteral()) {
|
|
136
141
|
if (type.value < 0) {
|
|
137
|
-
newNode =
|
|
142
|
+
newNode = ts.factory.createParenthesizedExpression(ts.factory.createPrefixUnaryExpression(ts.SyntaxKind.MinusToken, ts.factory.createNumericLiteral(-type.value)));
|
|
143
|
+
newSource = `(-${-type.value})`;
|
|
138
144
|
}
|
|
139
145
|
else {
|
|
140
|
-
newNode =
|
|
146
|
+
newNode = ts.factory.createNumericLiteral(type.value);
|
|
147
|
+
newSource = `${type.value}`;
|
|
141
148
|
}
|
|
142
149
|
}
|
|
143
150
|
else if (flags & ts.TypeFlags.BigIntLiteral) {
|
|
144
|
-
|
|
151
|
+
const text = typeChecker.typeToString(type);
|
|
152
|
+
newNode = ts.factory.createBigIntLiteral(text);
|
|
153
|
+
newSource = text;
|
|
145
154
|
}
|
|
146
155
|
else if (flags & ts.TypeFlags.BooleanLiteral) {
|
|
147
156
|
const text = typeChecker.typeToString(type);
|
|
148
157
|
newNode =
|
|
149
|
-
text === 'true'
|
|
150
|
-
|
|
151
|
-
: context.factory.createFalse();
|
|
158
|
+
text === 'true' ? ts.factory.createTrue() : ts.factory.createFalse();
|
|
159
|
+
newSource = text;
|
|
152
160
|
}
|
|
153
161
|
else if (flags & ts.TypeFlags.Null) {
|
|
154
|
-
newNode =
|
|
162
|
+
newNode = ts.factory.createNull();
|
|
163
|
+
newSource = 'null';
|
|
155
164
|
}
|
|
156
165
|
else if (flags & ts.TypeFlags.Undefined) {
|
|
157
166
|
if (options.useUndefinedSymbolForUndefinedValue) {
|
|
158
|
-
newNode =
|
|
167
|
+
newNode = ts.factory.createIdentifier('undefined');
|
|
168
|
+
newSource = 'undefined';
|
|
159
169
|
}
|
|
160
170
|
else {
|
|
161
|
-
newNode =
|
|
171
|
+
newNode = ts.factory.createParenthesizedExpression(ts.factory.createVoidZero());
|
|
172
|
+
newSource = '(void 0)';
|
|
162
173
|
}
|
|
163
174
|
}
|
|
164
175
|
else {
|
|
@@ -166,7 +177,12 @@ function visitNodeAndReplaceIfNeeded(node, parent, sourceFile, program, context,
|
|
|
166
177
|
}
|
|
167
178
|
const result = ts.addSyntheticTrailingComment(newNode, ts.SyntaxKind.MultiLineCommentTrivia, ` ${node.getText(sourceFile)} `);
|
|
168
179
|
ts.setTextRange(result, node);
|
|
169
|
-
result[
|
|
180
|
+
result[SYMBOL_ORIGINAL_NODE_DATA] = [
|
|
181
|
+
node.getText(sourceFile),
|
|
182
|
+
newSource,
|
|
183
|
+
node.pos,
|
|
184
|
+
node.end,
|
|
185
|
+
];
|
|
170
186
|
return result;
|
|
171
187
|
}
|
|
172
188
|
catch {
|
|
@@ -185,7 +201,8 @@ function isEnumIdentifier(node, program, tsInstance) {
|
|
|
185
201
|
const type = typeChecker.getTypeAtLocation(node);
|
|
186
202
|
return (type.getFlags() & ts.TypeFlags.EnumLiteral) !== 0;
|
|
187
203
|
}
|
|
188
|
-
function isExternalReference(node, program, externalNames) {
|
|
204
|
+
function isExternalReference(node, program, externalNames, tsInstance) {
|
|
205
|
+
const ts = tsInstance;
|
|
189
206
|
const typeChecker = program.getTypeChecker();
|
|
190
207
|
const nodeSym = typeChecker.getSymbolAtLocation(node);
|
|
191
208
|
let nodeFrom = nodeSym?.getDeclarations()?.[0];
|
|
@@ -238,7 +255,7 @@ function isExternalReference(node, program, externalNames) {
|
|
|
238
255
|
function isAsConstExpression(node) {
|
|
239
256
|
return node.type.getText() === 'const';
|
|
240
257
|
}
|
|
241
|
-
function hasAsExpression(node,
|
|
258
|
+
function hasAsExpression(node, tsInstance) {
|
|
242
259
|
const ts = tsInstance;
|
|
243
260
|
// including 'as const'
|
|
244
261
|
if (ts.isAsExpression(node)) {
|
|
@@ -247,13 +264,13 @@ function hasAsExpression(node, context, tsInstance) {
|
|
|
247
264
|
let found = false;
|
|
248
265
|
ts.visitEachChild(node, (node) => {
|
|
249
266
|
if (!found) {
|
|
250
|
-
found = hasAsExpression(node,
|
|
267
|
+
found = hasAsExpression(node, ts);
|
|
251
268
|
}
|
|
252
269
|
return node;
|
|
253
|
-
},
|
|
270
|
+
}, void 0);
|
|
254
271
|
return found;
|
|
255
272
|
}
|
|
256
|
-
function hasParentAsExpression(node,
|
|
273
|
+
function hasParentAsExpression(node, tsInstance) {
|
|
257
274
|
const ts = tsInstance;
|
|
258
275
|
if (node == null) {
|
|
259
276
|
return false;
|
|
@@ -264,11 +281,11 @@ function hasParentAsExpression(node, context, tsInstance) {
|
|
|
264
281
|
}
|
|
265
282
|
if (ts.isPropertyAccessExpression(node) ||
|
|
266
283
|
ts.isElementAccessExpression(node)) {
|
|
267
|
-
if (hasAsExpression(node.expression,
|
|
284
|
+
if (hasAsExpression(node.expression, ts)) {
|
|
268
285
|
return true;
|
|
269
286
|
}
|
|
270
287
|
}
|
|
271
|
-
return hasParentAsExpression(node.parent,
|
|
288
|
+
return hasParentAsExpression(node.parent, ts);
|
|
272
289
|
}
|
|
273
290
|
function hasPureAnnotation(node, sourceFile, tsInstance) {
|
|
274
291
|
const ts = tsInstance;
|
|
@@ -408,19 +425,19 @@ function isUndefinedIdentifier(node, parent, program, tsInstance) {
|
|
|
408
425
|
return false;
|
|
409
426
|
}
|
|
410
427
|
if (type.isUnionOrIntersection() ||
|
|
411
|
-
!(type.getFlags() &
|
|
428
|
+
!(type.getFlags() & tsInstance.TypeFlags.Undefined)) {
|
|
412
429
|
return false;
|
|
413
430
|
}
|
|
414
431
|
return true;
|
|
415
432
|
}
|
|
416
433
|
////////////////////////////////////////////////////////////////////////////////
|
|
417
|
-
export function printSource(sourceFile) {
|
|
418
|
-
return printSourceImpl(sourceFile)[0];
|
|
434
|
+
export function printSource(sourceFile, tsInstance) {
|
|
435
|
+
return printSourceImpl(tsInstance, sourceFile)[0];
|
|
419
436
|
}
|
|
420
|
-
export function printSourceWithMap(sourceFile, originalSourceName, startOfSourceMap) {
|
|
437
|
+
export function printSourceWithMap(sourceFile, originalSourceName, startOfSourceMap, tsInstance) {
|
|
421
438
|
const generator = new sourceMap.SourceMapGenerator(startOfSourceMap);
|
|
422
439
|
generator.setSourceContent(originalSourceName, sourceFile.getFullText());
|
|
423
|
-
return printSourceImpl(sourceFile, originalSourceName, generator);
|
|
440
|
+
return printSourceImpl(tsInstance, sourceFile, originalSourceName, generator);
|
|
424
441
|
}
|
|
425
442
|
function positionToLineAndColumn(sourceFile, pos, generatedDiff) {
|
|
426
443
|
let line = 0;
|
|
@@ -434,23 +451,29 @@ function positionToLineAndColumn(sourceFile, pos, generatedDiff) {
|
|
|
434
451
|
}
|
|
435
452
|
return { line, column: pos - lastLinePos + generatedDiff };
|
|
436
453
|
}
|
|
437
|
-
function printSourceImpl(sourceFile, originalSourceName, mapGenerator) {
|
|
438
|
-
const
|
|
439
|
-
const r = printNode(
|
|
440
|
-
|
|
454
|
+
function printSourceImpl(tsInstance, sourceFile, originalSourceName, mapGenerator) {
|
|
455
|
+
const ts = tsInstance ?? tsNamespace;
|
|
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];
|
|
441
464
|
}
|
|
442
|
-
function printNode(
|
|
443
|
-
const
|
|
444
|
-
if (
|
|
445
|
-
let result =
|
|
446
|
-
const comments =
|
|
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];
|
|
469
|
+
const comments = tsInstance.getSyntheticTrailingComments(node);
|
|
447
470
|
if (comments) {
|
|
448
471
|
for (const comment of comments) {
|
|
449
472
|
result += ` /*${comment.text}*/`;
|
|
450
473
|
}
|
|
451
474
|
}
|
|
452
|
-
const old =
|
|
453
|
-
const oldFull = baseSource.substring(
|
|
475
|
+
const old = originalNodeData[0];
|
|
476
|
+
const oldFull = baseSource.substring(originalNodeData[2], originalNodeData[3]);
|
|
454
477
|
const i = oldFull.lastIndexOf(old);
|
|
455
478
|
const leadingUnchanged = i < 0 ? 0 : i;
|
|
456
479
|
const newText = i < 0
|
|
@@ -477,7 +500,7 @@ function printNode(printer, baseSource, sourceFile, node, posContext, originalSo
|
|
|
477
500
|
let output = '';
|
|
478
501
|
let headPrinted = false;
|
|
479
502
|
let lastChildPos = 0;
|
|
480
|
-
|
|
503
|
+
tsInstance.visitEachChild(node, (child) => {
|
|
481
504
|
if (!headPrinted) {
|
|
482
505
|
headPrinted = true;
|
|
483
506
|
if (child.pos > node.pos) {
|
|
@@ -493,7 +516,7 @@ function printNode(printer, baseSource, sourceFile, node, posContext, originalSo
|
|
|
493
516
|
addMappingForCurrent();
|
|
494
517
|
posContext.pos = child.pos;
|
|
495
518
|
}
|
|
496
|
-
output += printNode(
|
|
519
|
+
output += printNode(tsInstance, baseSource, sourceFile, child, posContext, originalSourceName, mapGenerator);
|
|
497
520
|
lastChildPos = child.end;
|
|
498
521
|
return child;
|
|
499
522
|
}, void 0);
|
package/dist/version.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: "0.
|
|
1
|
+
declare const _default: "0.7.0";
|
|
2
2
|
export default _default;
|
package/dist/version.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export default '0.
|
|
1
|
+
export default '0.7.0';
|