ts-const-value-transformer 0.1.1 → 0.2.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 +8 -0
- package/README.md +7 -1
- package/dist/transform.d.mts +6 -0
- package/dist/transform.mjs +74 -7
- package/dist/version.d.mts +1 -1
- package/dist/version.mjs +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -150,14 +150,20 @@ export interface TransformOptions {
|
|
|
150
150
|
ts?: typeof ts;
|
|
151
151
|
/** Hoist property expressions (`x.prop`) which the value is constant. Default is true, but if the property getter has side effects (not recommended), set false explicitly. */
|
|
152
152
|
hoistProperty?: boolean | undefined;
|
|
153
|
+
/** Hoist TypeScript's `enum` values (which are constant). Default is true, but if you want to preserve references, set false explicitly. Note that TypeScript compiler erases `const enum` references unless `preserveConstEnums` is true. */
|
|
154
|
+
hoistEnumValues?: boolean | undefined;
|
|
155
|
+
/** Hoist values defined in the external libraries. Default is true, but if the external libraries are not bundled, set false explicitly to keep references. */
|
|
156
|
+
hoistExternalValues?: boolean | undefined;
|
|
153
157
|
/** Hoist function calls which the return value is constant. Default is false because function calls may have side effects. */
|
|
154
158
|
unsafeHoistFunctionCall?: boolean | undefined;
|
|
159
|
+
/** Hoist function calls, with `@__PURE__` (or `#__PURE__`) comment annotation (must be a multi-line comment), which the return value is constant. Default is false, but if the function really has no side effects, you can safely specify true. If true, `unsafeHoistFunctionCall` option is ignored for `@__PURE__` functions */
|
|
160
|
+
hoistPureFunctionCall?: boolean | undefined;
|
|
155
161
|
/** Hoist expressions with `as XXX`. Default is false because the base (non-`as`) value may be non-constant. */
|
|
156
162
|
unsafeHoistAsExpresion?: boolean | undefined;
|
|
157
163
|
}
|
|
158
164
|
```
|
|
159
165
|
|
|
160
|
-
Note that you must pass `options` field to `createTransformer` function or `"plugins"` specifier.
|
|
166
|
+
Note that you must pass `options` field to `createTransformer` function or `"plugins"` specifier (see above examples).
|
|
161
167
|
|
|
162
168
|
### APIs
|
|
163
169
|
|
package/dist/transform.d.mts
CHANGED
|
@@ -5,8 +5,14 @@ export interface TransformOptions {
|
|
|
5
5
|
ts?: typeof ts;
|
|
6
6
|
/** Hoist property expressions (`x.prop`) which the value is constant. Default is true, but if the property getter has side effects (not recommended), set false explicitly. */
|
|
7
7
|
hoistProperty?: boolean | undefined;
|
|
8
|
+
/** Hoist TypeScript's `enum` values (which are constant). Default is true, but if you want to preserve references, set false explicitly. Note that TypeScript compiler erases `const enum` references unless `preserveConstEnums` is true. */
|
|
9
|
+
hoistEnumValues?: boolean | undefined;
|
|
10
|
+
/** Hoist values defined in the external libraries. Default is true, but if the external libraries are not bundled, set false explicitly to keep references. */
|
|
11
|
+
hoistExternalValues?: boolean | undefined;
|
|
8
12
|
/** Hoist function calls which the return value is constant. Default is false because function calls may have side effects. */
|
|
9
13
|
unsafeHoistFunctionCall?: boolean | undefined;
|
|
14
|
+
/** Hoist function calls, with `@__PURE__` (or `#__PURE__`) comment annotation (must be a multi-line comment), which the return value is constant. Default is false, but if the function really has no side effects, you can safely specify true. If true, `unsafeHoistFunctionCall` option is ignored for `@__PURE__` functions */
|
|
15
|
+
hoistPureFunctionCall?: boolean | undefined;
|
|
10
16
|
/** Hoist expressions with `as XXX`. Default is false because the base (non-`as`) value may be non-constant. */
|
|
11
17
|
unsafeHoistAsExpresion?: boolean | undefined;
|
|
12
18
|
}
|
package/dist/transform.mjs
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import * as sourceMap from 'source-map';
|
|
2
2
|
import * as ts from 'typescript';
|
|
3
3
|
const SYMBOL_ORIGINAL_NODE = Symbol('originalNode');
|
|
4
|
-
function assignDefaultValues(options) {
|
|
4
|
+
function assignDefaultValues(options = {}) {
|
|
5
5
|
return {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
// avoid using spread syntax to override `undefined` (not missing) values
|
|
7
|
+
ts: options.ts ?? ts,
|
|
8
|
+
hoistProperty: options.hoistProperty ?? true,
|
|
9
|
+
hoistEnumValues: options.hoistEnumValues ?? true,
|
|
10
|
+
hoistExternalValues: options.hoistExternalValues ?? true,
|
|
11
|
+
unsafeHoistAsExpresion: options.unsafeHoistAsExpresion ?? false,
|
|
12
|
+
hoistPureFunctionCall: options.hoistPureFunctionCall ?? false,
|
|
13
|
+
unsafeHoistFunctionCall: options.unsafeHoistFunctionCall ?? false,
|
|
11
14
|
};
|
|
12
15
|
}
|
|
13
16
|
////////////////////////////////////////////////////////////////////////////////
|
|
@@ -37,12 +40,24 @@ function visitNodeAndReplaceIfNeeded(node, sourceFile, program, context, options
|
|
|
37
40
|
(!options.hoistProperty &&
|
|
38
41
|
ts.isPropertyAccessExpression(node) &&
|
|
39
42
|
!isEnumAccess(node, program, ts)) ||
|
|
40
|
-
(!options.
|
|
43
|
+
(!options.hoistEnumValues &&
|
|
44
|
+
((ts.isPropertyAccessExpression(node) &&
|
|
45
|
+
isEnumAccess(node, program, ts)) ||
|
|
46
|
+
(ts.isIdentifier(node) && isEnumIdentifier(node, program, ts)))) ||
|
|
41
47
|
node.kind === ts.SyntaxKind.TrueKeyword ||
|
|
42
48
|
node.kind === ts.SyntaxKind.FalseKeyword ||
|
|
43
49
|
node.kind === ts.SyntaxKind.NullKeyword) {
|
|
44
50
|
return node;
|
|
45
51
|
}
|
|
52
|
+
if (!options.unsafeHoistFunctionCall &&
|
|
53
|
+
(!options.hoistPureFunctionCall || !hasPureAnnotation(node, sourceFile, ts))) {
|
|
54
|
+
if (ts.isCallLikeExpression(node)) {
|
|
55
|
+
return node;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (!options.hoistExternalValues && isExternalReference(node, program)) {
|
|
59
|
+
return node;
|
|
60
|
+
}
|
|
46
61
|
if (ts.isIdentifier(node)) {
|
|
47
62
|
if (
|
|
48
63
|
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
@@ -111,6 +126,43 @@ function isEnumAccess(node, program, tsInstance) {
|
|
|
111
126
|
const type = typeChecker.getTypeAtLocation(node);
|
|
112
127
|
return (type.getFlags() & ts.TypeFlags.EnumLiteral) !== 0;
|
|
113
128
|
}
|
|
129
|
+
function isEnumIdentifier(node, program, tsInstance) {
|
|
130
|
+
const ts = tsInstance;
|
|
131
|
+
const typeChecker = program.getTypeChecker();
|
|
132
|
+
const type = typeChecker.getTypeAtLocation(node);
|
|
133
|
+
return (type.getFlags() & ts.TypeFlags.EnumLiteral) !== 0;
|
|
134
|
+
}
|
|
135
|
+
function isExternalReference(node, program) {
|
|
136
|
+
const typeChecker = program.getTypeChecker();
|
|
137
|
+
const nodeSym = typeChecker.getSymbolAtLocation(node);
|
|
138
|
+
let nodeFrom = nodeSym?.getDeclarations()?.[0];
|
|
139
|
+
while (nodeFrom) {
|
|
140
|
+
if (program.isSourceFileFromExternalLibrary(nodeFrom.getSourceFile())) {
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
// Walk into the 'import' variables
|
|
144
|
+
if (!ts.isImportSpecifier(nodeFrom)) {
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
const baseName = nodeFrom.propertyName ?? nodeFrom.name;
|
|
148
|
+
const baseSym = typeChecker.getSymbolAtLocation(baseName);
|
|
149
|
+
nodeFrom = baseSym?.getDeclarations()?.[0];
|
|
150
|
+
}
|
|
151
|
+
const type = typeChecker.getTypeAtLocation(node);
|
|
152
|
+
const sym = type.getSymbol();
|
|
153
|
+
if (!sym) {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
const def = sym.getDeclarations()?.[0];
|
|
157
|
+
if (!def) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
const typeDefinitionSource = def.getSourceFile();
|
|
161
|
+
if (program.isSourceFileFromExternalLibrary(typeDefinitionSource)) {
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
114
166
|
function isAsConstExpression(node) {
|
|
115
167
|
return node.type.getText() === 'const';
|
|
116
168
|
}
|
|
@@ -145,6 +197,21 @@ function hasParentAsExpression(node, context, tsInstance) {
|
|
|
145
197
|
}
|
|
146
198
|
return hasParentAsExpression(node.parent, context, ts);
|
|
147
199
|
}
|
|
200
|
+
function hasPureAnnotation(node, sourceFile, tsInstance) {
|
|
201
|
+
const ts = tsInstance;
|
|
202
|
+
const fullText = node.getFullText(sourceFile);
|
|
203
|
+
const ranges = ts.getLeadingCommentRanges(fullText, 0) ?? [];
|
|
204
|
+
for (const range of ranges) {
|
|
205
|
+
if (range.kind !== ts.SyntaxKind.MultiLineCommentTrivia) {
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
const text = fullText.slice(range.pos + 2, range.end - 2).trim();
|
|
209
|
+
if ((text[0] === '@' || text[0] === '#') && text.slice(1) === '__PURE__') {
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
148
215
|
////////////////////////////////////////////////////////////////////////////////
|
|
149
216
|
export function printSource(sourceFile) {
|
|
150
217
|
return printSourceImpl(sourceFile)[0];
|
package/dist/version.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: "0.
|
|
1
|
+
declare const _default: "0.2.0";
|
|
2
2
|
export default _default;
|
package/dist/version.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export default '0.
|
|
1
|
+
export default '0.2.0';
|