ts-const-value-transformer 0.7.1 → 0.8.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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.8.1
4
+
5
+ - Fix to parenthesize expression with multi-line
6
+ - Reduce mappings to only have position changings
7
+ - Minor changes in development environment
8
+
9
+ ## v0.8.0
10
+
11
+ - Add `cacheResult` option (enable by default but disable by default for webpack loader)
12
+ - Fix for treating `as` expression (don't see parent expression)
13
+ - Fix some codes
14
+
3
15
  ## v0.7.1
4
16
 
5
17
  - Fix to wrap import() with eval to prevent from static analysis
package/README.md CHANGED
@@ -279,7 +279,7 @@ 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 a following signature. Also, `ignoreFiles` of `TransformOptions` can be used.
282
+ `CreatePortalTransformerOptions` has a following signature. Also, `TransformOptions` fields, including `ignoreFiles`, can be used.
283
283
 
284
284
  ```ts
285
285
  interface CreatePortalTransformerOptions extends TransformOptions {
@@ -297,6 +297,8 @@ interface CreatePortalTransformerOptions extends TransformOptions {
297
297
  recreateProgramOnTransformCount?: number;
298
298
  /** Specifies to cache base (original) source code for check if the input is changed. Default is false. */
299
299
  cacheBaseSource?: boolean;
300
+ /** Specifies to cache result source code. Default is true (false for webpack loader). If the latter process has cache system, specifies false to reduce memory usage. */
301
+ cacheResult?: boolean;
300
302
  }
301
303
  ```
302
304
 
@@ -16,6 +16,8 @@ export interface CreatePortalTransformerOptions extends TransformOptions {
16
16
  recreateProgramOnTransformCount?: number;
17
17
  /** Specifies to cache base (original) source code for check if the input is changed. Default is false. */
18
18
  cacheBaseSource?: boolean;
19
+ /** Specifies to cache result source code. Default is true (false for webpack loader). If the latter process has cache system, specifies false to reduce memory usage. */
20
+ cacheResult?: boolean;
19
21
  }
20
22
  export type PortalTransformerResult = [
21
23
  newSource: string | null,
@@ -21,6 +21,7 @@ function createPortalTransformerImpl(options, ts) {
21
21
  const cwd = options.cwd ?? process.cwd();
22
22
  const recreateProgramOnTransformCount = options.recreateProgramOnTransformCount ?? 0;
23
23
  const cacheBaseSource = options.cacheBaseSource ?? false;
24
+ const cacheResult = options.cacheResult ?? true;
24
25
  // eslint-disable-next-line @typescript-eslint/unbound-method
25
26
  const foundConfigPath = ts.findConfigFile(cwd, ts.sys.fileExists, project);
26
27
  if (foundConfigPath == null) {
@@ -72,11 +73,13 @@ function createPortalTransformerImpl(options, ts) {
72
73
  recreateProgram,
73
74
  transform: (content, fileName, sourceMap, individualOptions) => {
74
75
  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;
76
+ if (cacheResult) {
77
+ const cachedData = cache.get(fileName);
78
+ if (cachedData &&
79
+ (!cacheBaseSource || cachedData.content === content) &&
80
+ cachedData.optJson === individualOptionsJson) {
81
+ return cachedData.result;
82
+ }
80
83
  }
81
84
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
82
85
  const rawSourceMap = typeof sourceMap === 'string'
@@ -115,11 +118,19 @@ function createPortalTransformerImpl(options, ts) {
115
118
  else {
116
119
  result = printSourceWithMap(transformedSource, fileName, rawSourceMap, ts);
117
120
  }
118
- cache.set(fileName, {
119
- content: cacheBaseSource ? content : '',
120
- optJson: individualOptionsJson,
121
- result,
122
- });
121
+ if (cacheResult) {
122
+ // This forces to concatenate strings into flatten one, to reduce object trees for ConsString
123
+ void (result[0] | 0);
124
+ const json = result[1];
125
+ if (json) {
126
+ void (json.mappings | 0);
127
+ }
128
+ cache.set(fileName, {
129
+ content: cacheBaseSource ? content : '',
130
+ optJson: individualOptionsJson,
131
+ result,
132
+ });
133
+ }
123
134
  return result;
124
135
  },
125
136
  };
package/dist/loader.mjs CHANGED
@@ -9,11 +9,14 @@ const loader = function (content, sourceMap) {
9
9
  try {
10
10
  const options = this.getOptions() || {};
11
11
  const project = options.project ?? 'tsconfig.json';
12
+ // Use webpack's cache system by default
13
+ const cacheResult = options.cacheResult ?? false;
12
14
  let transformer = transformerMap.get(project);
13
15
  if (!transformer) {
14
16
  transformer = await createPortalTransformer({
15
17
  cwd: path.dirname(this.resourcePath),
16
18
  ...options,
19
+ cacheResult,
17
20
  });
18
21
  transformerMap.set(project, transformer);
19
22
  }
@@ -41,11 +41,11 @@ export function getIgnoreFilesFunction(ignoreFiles) {
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
+ return requiredOptions.ts.visitEachChild(sourceFile, (node) => visitNodeChildren(node, sourceFile, sourceFile, program, requiredOptions, context), context);
45
45
  }
46
- function visitNodeChildren(node, parent, sourceFile, program, options) {
46
+ function visitNodeChildren(node, parent, sourceFile, program, options, context) {
47
47
  const ts = options.ts;
48
- const newNode = visitNodeAndReplaceIfNeeded(node, parent, sourceFile, program, options);
48
+ const newNode = visitNodeAndReplaceIfNeeded(node, parent, sourceFile, program, options, context);
49
49
  if (newNode[SYMBOL_ORIGINAL_NODE_DATA]) {
50
50
  return newNode;
51
51
  }
@@ -57,9 +57,9 @@ function visitNodeChildren(node, parent, sourceFile, program, options) {
57
57
  ts.isTypeOnlyExportDeclaration(newNode)) {
58
58
  return newNode;
59
59
  }
60
- return ts.visitEachChild(newNode, (node) => visitNodeChildren(node, newNode, sourceFile, program, options), void 0);
60
+ return ts.visitEachChild(newNode, (node) => visitNodeChildren(node, newNode, sourceFile, program, options, context), context);
61
61
  }
62
- function visitNodeAndReplaceIfNeeded(node, parent, sourceFile, program, options) {
62
+ function visitNodeAndReplaceIfNeeded(node, parent, sourceFile, program, options, context) {
63
63
  const ts = options.ts;
64
64
  if (ts.isCallLikeExpression(node)) {
65
65
  if (!ts.isExpression(node) ||
@@ -108,8 +108,7 @@ function visitNodeAndReplaceIfNeeded(node, parent, sourceFile, program, options)
108
108
  isExternalReference(node, program, options.externalNames, ts)) {
109
109
  return node;
110
110
  }
111
- if (!options.unsafeHoistAsExpresion &&
112
- (hasAsExpression(node, ts) || hasParentAsExpression(parent, ts))) {
111
+ if (!options.unsafeHoistAsExpresion && hasAsExpression(node, ts, context)) {
113
112
  return node;
114
113
  }
115
114
  if (!options.unsafeHoistWritableValues) {
@@ -175,10 +174,17 @@ function visitNodeAndReplaceIfNeeded(node, parent, sourceFile, program, options)
175
174
  else {
176
175
  return node;
177
176
  }
178
- const result = ts.addSyntheticTrailingComment(newNode, ts.SyntaxKind.MultiLineCommentTrivia, ` ${node.getText(sourceFile)} `);
177
+ const originalSource = node.getText(sourceFile);
178
+ const comment = ` ${originalSource.replace(/\/\*/g, ' *').replace(/\*\//g, '* ')} `;
179
+ let result = ts.addSyntheticTrailingComment(newNode, ts.SyntaxKind.MultiLineCommentTrivia, comment);
180
+ newSource = `${newSource} /*${comment}*/`;
181
+ if (/[\r\n]/m.test(originalSource)) {
182
+ result = ts.factory.createParenthesizedExpression(result);
183
+ newSource = `(${newSource})`;
184
+ }
179
185
  ts.setTextRange(result, node);
180
186
  result[SYMBOL_ORIGINAL_NODE_DATA] = [
181
- node.getText(sourceFile),
187
+ originalSource,
182
188
  newSource,
183
189
  node.pos,
184
190
  node.end,
@@ -252,10 +258,7 @@ function isExternalReference(node, program, externalNames, tsInstance) {
252
258
  }
253
259
  return false;
254
260
  }
255
- function isAsConstExpression(node) {
256
- return node.type.getText() === 'const';
257
- }
258
- function hasAsExpression(node, tsInstance) {
261
+ function hasAsExpression(node, tsInstance, context) {
259
262
  const ts = tsInstance;
260
263
  // including 'as const'
261
264
  if (ts.isAsExpression(node)) {
@@ -264,29 +267,12 @@ function hasAsExpression(node, tsInstance) {
264
267
  let found = false;
265
268
  ts.visitEachChild(node, (node) => {
266
269
  if (!found) {
267
- found = hasAsExpression(node, ts);
270
+ found = hasAsExpression(node, ts, context);
268
271
  }
269
272
  return node;
270
- }, void 0);
273
+ }, context);
271
274
  return found;
272
275
  }
273
- function hasParentAsExpression(node, tsInstance) {
274
- const ts = tsInstance;
275
- if (node == null) {
276
- return false;
277
- }
278
- // excluding 'as const'
279
- if (ts.isAsExpression(node) && !isAsConstExpression(node)) {
280
- return true;
281
- }
282
- if (ts.isPropertyAccessExpression(node) ||
283
- ts.isElementAccessExpression(node)) {
284
- if (hasAsExpression(node.expression, ts)) {
285
- return true;
286
- }
287
- }
288
- return hasParentAsExpression(node.parent, ts);
289
- }
290
276
  function hasPureAnnotation(node, sourceFile, tsInstance) {
291
277
  const ts = tsInstance;
292
278
  const fullText = node.getFullText(sourceFile);
@@ -454,24 +440,12 @@ function positionToLineAndColumn(sourceFile, pos, generatedDiff) {
454
440
  function printSourceImpl(tsInstance, sourceFile, originalSourceName, mapGenerator) {
455
441
  const ts = tsInstance ?? tsNamespace;
456
442
  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];
443
+ return [r, mapGenerator?.toJSON()];
464
444
  }
465
445
  function printNode(tsInstance, baseSource, sourceFile, node, posContext, originalSourceName, mapGenerator) {
466
446
  const originalNodeData = node[SYMBOL_ORIGINAL_NODE_DATA];
467
447
  if (originalNodeData) {
468
- let result = originalNodeData[1];
469
- const comments = tsInstance.getSyntheticTrailingComments(node);
470
- if (comments) {
471
- for (const comment of comments) {
472
- result += ` /*${comment.text}*/`;
473
- }
474
- }
448
+ const result = originalNodeData[1];
475
449
  const old = originalNodeData[0];
476
450
  const oldFull = baseSource.substring(originalNodeData[2], originalNodeData[3]);
477
451
  const i = oldFull.lastIndexOf(old);
@@ -479,22 +453,12 @@ function printNode(tsInstance, baseSource, sourceFile, node, posContext, origina
479
453
  const newText = i < 0
480
454
  ? result
481
455
  : oldFull.substring(0, i) + result + oldFull.substring(i + old.length);
482
- if (mapGenerator) {
483
- if (posContext.pos < node.pos) {
484
- addMappingForCurrent();
485
- }
486
- posContext.pos = node.pos;
487
- if (leadingUnchanged > 0) {
488
- addMappingForCurrent();
489
- }
490
- posContext.pos = node.pos + leadingUnchanged;
491
- addMappingForCurrent(old);
492
- }
456
+ posContext.pos = node.pos + leadingUnchanged;
457
+ addMappingForCurrent(old);
493
458
  posContext.diff += result.length - old.length;
494
459
  posContext.pos += old.length;
495
460
  addMappingForCurrent();
496
461
  posContext.pos = node.end;
497
- addMappingForCurrent();
498
462
  return newText;
499
463
  }
500
464
  let output = '';
@@ -506,14 +470,12 @@ function printNode(tsInstance, baseSource, sourceFile, node, posContext, origina
506
470
  if (child.pos > node.pos) {
507
471
  const text = baseSource.substring(node.pos, child.pos);
508
472
  output += text;
509
- addMappingForCurrent();
510
473
  posContext.pos = child.pos;
511
474
  }
512
475
  }
513
476
  else if (child.pos > lastChildPos) {
514
477
  const text = baseSource.substring(lastChildPos, child.pos);
515
478
  output += text;
516
- addMappingForCurrent();
517
479
  posContext.pos = child.pos;
518
480
  }
519
481
  output += printNode(tsInstance, baseSource, sourceFile, child, posContext, originalSourceName, mapGenerator);
@@ -522,29 +484,19 @@ function printNode(tsInstance, baseSource, sourceFile, node, posContext, origina
522
484
  }, void 0);
523
485
  if (!headPrinted) {
524
486
  output = baseSource.substring(node.pos, node.end);
525
- addMappingForCurrent();
526
487
  posContext.pos = node.end;
527
488
  }
528
489
  else if (lastChildPos < node.end) {
529
490
  const text = baseSource.substring(lastChildPos, node.end);
530
491
  output += text;
531
- addMappingForCurrent();
532
492
  posContext.pos = node.end;
533
493
  }
534
- addMappingForCurrent();
535
494
  return output;
536
495
  function addMappingForCurrent(name) {
537
496
  const original = positionToLineAndColumn(sourceFile, posContext.pos, 0);
538
497
  if (original.line !== posContext.lastLine) {
539
498
  posContext.diff = 0;
540
499
  posContext.lastLine = original.line;
541
- if (mapGenerator && original.column > 0) {
542
- mapGenerator.addMapping({
543
- original: { line: original.line, column: 0 },
544
- generated: { line: original.line, column: 0 },
545
- source: originalSourceName,
546
- });
547
- }
548
500
  }
549
501
  if (mapGenerator) {
550
502
  mapGenerator.addMapping({
@@ -1,2 +1,2 @@
1
- declare const _default: "0.7.1";
1
+ declare const _default: "0.8.1";
2
2
  export default _default;
package/dist/version.mjs CHANGED
@@ -1 +1 @@
1
- export default '0.7.1';
1
+ export default '0.8.1';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-const-value-transformer",
3
- "version": "0.7.1",
3
+ "version": "0.8.1",
4
4
  "engines": {
5
5
  "node": ">=20.19.3"
6
6
  },
@@ -90,10 +90,13 @@
90
90
  "version": "node ./tools/updateVersion.mjs ./src/main/version.mts && git add -A ./src/main/version.mts"
91
91
  },
92
92
  "devDependencies": {
93
+ "@babel/preset-typescript": "^7.28.5",
94
+ "@swc/core": "^1.15.10",
93
95
  "@types/jest": "^30.0.0",
94
96
  "@types/node": "~20.19.22",
95
97
  "@typescript-eslint/eslint-plugin": "^8.48.0",
96
98
  "@typescript-eslint/parser": "^8.48.0",
99
+ "babel-loader": "^10.0.0",
97
100
  "eslint": "^9.39.1",
98
101
  "eslint-config-prettier": "^10.1.8",
99
102
  "eslint-plugin-import-x": "^4.16.1",
@@ -103,6 +106,7 @@
103
106
  "memfs": "^4.51.0",
104
107
  "neostandard": "^0.12.2",
105
108
  "prettier": "^3.6.2",
109
+ "swc-loader": "^0.2.7",
106
110
  "ts-jest": "^29.4.5",
107
111
  "ts-loader": "^9.5.4",
108
112
  "ts-patch": "^3.3.0",