@openrewrite/rewrite 8.67.0-20251107-071946 → 8.67.0-20251107-112238
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/dist/javascript/format.d.ts.map +1 -1
- package/dist/javascript/format.js +4 -9
- package/dist/javascript/format.js.map +1 -1
- package/dist/javascript/templating/engine.d.ts +11 -21
- package/dist/javascript/templating/engine.d.ts.map +1 -1
- package/dist/javascript/templating/engine.js +94 -65
- package/dist/javascript/templating/engine.js.map +1 -1
- package/dist/javascript/templating/rewrite.d.ts +17 -11
- package/dist/javascript/templating/rewrite.d.ts.map +1 -1
- package/dist/javascript/templating/rewrite.js +17 -11
- package/dist/javascript/templating/rewrite.js.map +1 -1
- package/dist/javascript/templating/template.d.ts +12 -5
- package/dist/javascript/templating/template.d.ts.map +1 -1
- package/dist/javascript/templating/template.js +19 -16
- package/dist/javascript/templating/template.js.map +1 -1
- package/dist/javascript/templating/types.d.ts +10 -2
- package/dist/javascript/templating/types.d.ts.map +1 -1
- package/dist/javascript/templating/utils.d.ts.map +1 -1
- package/dist/javascript/templating/utils.js +1 -1
- package/dist/javascript/templating/utils.js.map +1 -1
- package/dist/version.txt +1 -1
- package/package.json +1 -1
- package/src/javascript/format.ts +3 -7
- package/src/javascript/templating/engine.ts +94 -82
- package/src/javascript/templating/rewrite.ts +17 -11
- package/src/javascript/templating/template.ts +25 -24
- package/src/javascript/templating/types.ts +10 -2
- package/src/javascript/templating/utils.ts +3 -2
|
@@ -75,7 +75,7 @@ function generateCacheKey(templateParts, itemsKey, contextStatements, dependenci
|
|
|
75
75
|
Array.from(templateParts).join('|'),
|
|
76
76
|
itemsKey,
|
|
77
77
|
contextStatements.join(';'),
|
|
78
|
-
JSON.stringify(dependencies
|
|
78
|
+
JSON.stringify(dependencies)
|
|
79
79
|
].join('::');
|
|
80
80
|
}
|
|
81
81
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/javascript/templating/utils.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/javascript/templating/utils.ts"],"names":[],"mappings":"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"}
|
package/dist/version.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
8.67.0-20251107-
|
|
1
|
+
8.67.0-20251107-112238
|
package/package.json
CHANGED
package/src/javascript/format.ts
CHANGED
|
@@ -936,15 +936,11 @@ export class BlankLinesVisitor<P> extends JavaScriptVisitor<P> {
|
|
|
936
936
|
}
|
|
937
937
|
});
|
|
938
938
|
}
|
|
939
|
-
if (ret.kind ===
|
|
939
|
+
if (ret.kind === J.Kind.MethodDeclaration
|
|
940
|
+
&& this.cursor.parent?.parent?.parent?.value.kind === J.Kind.ClassDeclaration) {
|
|
940
941
|
ret = produce(ret as JS.StatementExpression, draft => {
|
|
941
942
|
this.ensurePrefixHasNewLine(draft);
|
|
942
943
|
});
|
|
943
|
-
} else if (ret.kind === J.Kind.MethodDeclaration && this.cursor.parent?.value.kind != JS.Kind.StatementExpression
|
|
944
|
-
&& (this.cursor.parent?.parent?.value.kind != JS.Kind.CompilationUnit || (this.cursor.parent?.parent?.value as JS.CompilationUnit).statements[0].element.id != ret.id)) {
|
|
945
|
-
ret = produce(ret as J.MethodDeclaration, draft => {
|
|
946
|
-
this.ensurePrefixHasNewLine(draft);
|
|
947
|
-
});
|
|
948
944
|
}
|
|
949
945
|
|
|
950
946
|
return ret;
|
|
@@ -1115,7 +1111,7 @@ export class TabsAndIndentsVisitor<P> extends JavaScriptVisitor<P> {
|
|
|
1115
1111
|
let indentShouldIncrease =
|
|
1116
1112
|
tree.kind === J.Kind.Block
|
|
1117
1113
|
|| this.cursor.parent?.parent?.parent?.value.kind == J.Kind.Case
|
|
1118
|
-
|| (tree.kind === JS.Kind.StatementExpression && (tree as JS.StatementExpression).statement.kind == J.Kind.MethodDeclaration);
|
|
1114
|
+
|| (tree.kind === JS.Kind.StatementExpression && (tree as JS.StatementExpression).statement.kind == J.Kind.MethodDeclaration && tree.prefix.whitespace.includes("\n"));
|
|
1119
1115
|
|
|
1120
1116
|
const previousIndent = this.currentIndent;
|
|
1121
1117
|
|
|
@@ -13,19 +13,20 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import ts from 'typescript';
|
|
17
16
|
import {Cursor, isTree, produceAsync, Tree, updateIfChanged} from '../..';
|
|
18
|
-
import {J, Type} from '../../java';
|
|
19
|
-
import {JS} from '..';
|
|
17
|
+
import {emptySpace, J, Statement, Type} from '../../java';
|
|
18
|
+
import {Any, Capture, JavaScriptParser, JavaScriptVisitor, JS} from '..';
|
|
20
19
|
import {produce} from 'immer';
|
|
21
20
|
import {CaptureMarker, PlaceholderUtils, WRAPPER_FUNCTION_NAME} from './utils';
|
|
22
|
-
import {CAPTURE_NAME_SYMBOL, CAPTURE_TYPE_SYMBOL, CaptureImpl, CaptureValue
|
|
21
|
+
import {CAPTURE_NAME_SYMBOL, CAPTURE_TYPE_SYMBOL, CaptureImpl, CaptureValue} from './capture';
|
|
23
22
|
import {PlaceholderReplacementVisitor} from './placeholder-replacement';
|
|
24
23
|
import {JavaCoordinates} from './template';
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import
|
|
24
|
+
import {maybeAutoFormat} from '../format';
|
|
25
|
+
import {isExpression, isStatement} from '../parser-utils';
|
|
26
|
+
import {randomId} from '../../uuid';
|
|
27
|
+
import ts from "typescript";
|
|
28
|
+
import {DependencyWorkspace} from "../dependency-workspace";
|
|
29
|
+
import {Parameter} from "./types";
|
|
29
30
|
|
|
30
31
|
/**
|
|
31
32
|
* Simple LRU (Least Recently Used) cache implementation.
|
|
@@ -95,7 +96,7 @@ class TemplateCache {
|
|
|
95
96
|
*/
|
|
96
97
|
private generateKey(
|
|
97
98
|
templateString: string,
|
|
98
|
-
captures: (Capture | Any
|
|
99
|
+
captures: (Capture | Any)[],
|
|
99
100
|
contextStatements: string[],
|
|
100
101
|
dependencies: Record<string, string>
|
|
101
102
|
): string {
|
|
@@ -229,47 +230,29 @@ export class TemplateEngine {
|
|
|
229
230
|
// Extract from wrapper using shared utility
|
|
230
231
|
const extracted = PlaceholderUtils.extractFromWrapper(lastStatement, 'Template');
|
|
231
232
|
|
|
232
|
-
// Create a copy to avoid sharing cached AST instances
|
|
233
233
|
return produce(extracted, _ => {});
|
|
234
234
|
}
|
|
235
235
|
|
|
236
236
|
/**
|
|
237
|
-
* Applies a template
|
|
237
|
+
* Applies a template from a pre-parsed AST and returns the resulting AST.
|
|
238
|
+
* This method is used by Template.apply() after getting the cached template tree.
|
|
238
239
|
*
|
|
239
|
-
* @param
|
|
240
|
+
* @param ast The pre-parsed template AST
|
|
240
241
|
* @param parameters The parameters between the string parts
|
|
241
242
|
* @param cursor The cursor pointing to the current location in the AST
|
|
242
243
|
* @param coordinates The coordinates specifying where and how to insert the generated AST
|
|
243
244
|
* @param values Map of capture names to values to replace the parameters with
|
|
244
245
|
* @param wrappersMap Map of capture names to J.RightPadded wrappers (for preserving markers)
|
|
245
|
-
* @param contextStatements Context declarations (imports, types, etc.) to prepend for type attribution
|
|
246
|
-
* @param dependencies NPM dependencies for type attribution
|
|
247
246
|
* @returns A Promise resolving to the generated AST node
|
|
248
247
|
*/
|
|
249
|
-
static async
|
|
250
|
-
|
|
248
|
+
static async applyTemplateFromAst(
|
|
249
|
+
ast: JS.CompilationUnit,
|
|
251
250
|
parameters: Parameter[],
|
|
252
251
|
cursor: Cursor,
|
|
253
252
|
coordinates: JavaCoordinates,
|
|
254
253
|
values: Pick<Map<string, J>, 'get'> = new Map(),
|
|
255
|
-
wrappersMap: Pick<Map<string, J.RightPadded<J> | J.RightPadded<J>[]>, 'get'> = new Map()
|
|
256
|
-
contextStatements: string[] = [],
|
|
257
|
-
dependencies: Record<string, string> = {}
|
|
254
|
+
wrappersMap: Pick<Map<string, J.RightPadded<J> | J.RightPadded<J>[]>, 'get'> = new Map()
|
|
258
255
|
): Promise<J | undefined> {
|
|
259
|
-
// Build the template string to check if empty
|
|
260
|
-
const templateString = TemplateEngine.buildTemplateString(templateParts, parameters);
|
|
261
|
-
if (!templateString.trim()) {
|
|
262
|
-
return undefined;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// Get the parsed and extracted template tree
|
|
266
|
-
const ast = await TemplateEngine.getTemplateTree(
|
|
267
|
-
templateParts,
|
|
268
|
-
parameters,
|
|
269
|
-
contextStatements,
|
|
270
|
-
dependencies
|
|
271
|
-
);
|
|
272
|
-
|
|
273
256
|
// Create substitutions map for placeholders
|
|
274
257
|
const substitutions = new Map<string, Parameter>();
|
|
275
258
|
for (let i = 0; i < parameters.length; i++) {
|
|
@@ -300,7 +283,7 @@ export class TemplateEngine {
|
|
|
300
283
|
|
|
301
284
|
// Check for Capture (could be a Proxy, so check for symbol property)
|
|
302
285
|
const isCapture = param instanceof CaptureImpl ||
|
|
303
|
-
|
|
286
|
+
(param && typeof param === 'object' && param[CAPTURE_NAME_SYMBOL]);
|
|
304
287
|
const isCaptureValue = param instanceof CaptureValue;
|
|
305
288
|
const isTreeArray = Array.isArray(param) && param.length > 0 && isTree(param[0]);
|
|
306
289
|
|
|
@@ -352,21 +335,10 @@ export class TemplateEngine {
|
|
|
352
335
|
for (let i = 0; i < templateParts.length; i++) {
|
|
353
336
|
result += templateParts[i];
|
|
354
337
|
if (i < parameters.length) {
|
|
355
|
-
|
|
356
|
-
//
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
const isCapture = param instanceof CaptureImpl ||
|
|
360
|
-
(param && typeof param === 'object' && param[CAPTURE_NAME_SYMBOL]);
|
|
361
|
-
const isTemplateParam = param instanceof TemplateParamImpl;
|
|
362
|
-
const isCaptureValue = param instanceof CaptureValue;
|
|
363
|
-
const isTreeArray = Array.isArray(param) && param.length > 0 && isTree(param[0]);
|
|
364
|
-
if (isCapture || isTemplateParam || isCaptureValue || isTree(param) || isTreeArray) {
|
|
365
|
-
const placeholder = `${PlaceholderUtils.PLACEHOLDER_PREFIX}${i}__`;
|
|
366
|
-
result += placeholder;
|
|
367
|
-
} else {
|
|
368
|
-
result += param;
|
|
369
|
-
}
|
|
338
|
+
// All parameters are now placeholders (no primitive inlining)
|
|
339
|
+
// This ensures templates with the same structure always produce the same AST
|
|
340
|
+
const placeholder = `${PlaceholderUtils.PLACEHOLDER_PREFIX}${i}__`;
|
|
341
|
+
result += placeholder;
|
|
370
342
|
}
|
|
371
343
|
}
|
|
372
344
|
|
|
@@ -435,7 +407,7 @@ export class TemplateEngine {
|
|
|
435
407
|
*/
|
|
436
408
|
static async getPatternTree(
|
|
437
409
|
templateParts: TemplateStringsArray,
|
|
438
|
-
captures: (Capture | Any
|
|
410
|
+
captures: (Capture | Any)[],
|
|
439
411
|
contextStatements: string[] = [],
|
|
440
412
|
dependencies: Record<string, string> = {}
|
|
441
413
|
): Promise<J> {
|
|
@@ -509,7 +481,7 @@ export class TemplateEngine {
|
|
|
509
481
|
* Used by TemplateEngine.getPatternTree() for pattern-specific processing.
|
|
510
482
|
*/
|
|
511
483
|
class MarkerAttachmentVisitor extends JavaScriptVisitor<undefined> {
|
|
512
|
-
constructor(private readonly captures: (Capture | Any
|
|
484
|
+
constructor(private readonly captures: (Capture | Any)[]) {
|
|
513
485
|
super();
|
|
514
486
|
}
|
|
515
487
|
|
|
@@ -621,11 +593,9 @@ export class TemplateApplier {
|
|
|
621
593
|
// Apply the template based on the location and mode
|
|
622
594
|
switch (loc || 'EXPRESSION_PREFIX') {
|
|
623
595
|
case 'EXPRESSION_PREFIX':
|
|
624
|
-
return this.applyToExpression();
|
|
625
596
|
case 'STATEMENT_PREFIX':
|
|
626
|
-
return this.applyToStatement();
|
|
627
597
|
case 'BLOCK_END':
|
|
628
|
-
return this.
|
|
598
|
+
return this.applyInternal();
|
|
629
599
|
default:
|
|
630
600
|
throw new Error(`Unsupported location: ${loc}`);
|
|
631
601
|
}
|
|
@@ -636,40 +606,82 @@ export class TemplateApplier {
|
|
|
636
606
|
*
|
|
637
607
|
* @returns A Promise resolving to the modified AST
|
|
638
608
|
*/
|
|
639
|
-
private async
|
|
609
|
+
private async applyInternal(): Promise<J | undefined> {
|
|
640
610
|
const {tree} = this.coordinates;
|
|
641
611
|
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
}) : this.ast;
|
|
646
|
-
}
|
|
612
|
+
if (!tree) {
|
|
613
|
+
return this.ast;
|
|
614
|
+
}
|
|
647
615
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
*/
|
|
653
|
-
private async applyToStatement(): Promise<J | undefined> {
|
|
654
|
-
const {tree} = this.coordinates;
|
|
616
|
+
const originalTree = tree as J;
|
|
617
|
+
const resultToUse = this.wrapTree(originalTree, this.ast);
|
|
618
|
+
return this.format(resultToUse, originalTree);
|
|
619
|
+
}
|
|
655
620
|
|
|
621
|
+
private async format(resultToUse: J, originalTree: J) {
|
|
656
622
|
// Create a copy of the AST with the prefix from the target
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
623
|
+
const result = {
|
|
624
|
+
...resultToUse,
|
|
625
|
+
// We temporarily set the ID so that the formatter can identify the tree
|
|
626
|
+
id: originalTree.id,
|
|
627
|
+
prefix: originalTree.prefix
|
|
628
|
+
};
|
|
629
|
+
|
|
630
|
+
// Apply auto-formatting to the result
|
|
631
|
+
const formatted =
|
|
632
|
+
await maybeAutoFormat(originalTree, result, null, undefined, this.cursor?.parent);
|
|
633
|
+
|
|
634
|
+
// Restore the original ID
|
|
635
|
+
return {...formatted, id: resultToUse.id};
|
|
660
636
|
}
|
|
661
637
|
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
638
|
+
private wrapTree(originalTree: J, resultToUse: J) {
|
|
639
|
+
const parentTree = this.cursor?.parentTree()?.value;
|
|
640
|
+
|
|
641
|
+
// Only apply wrapping logic if we have parent context
|
|
642
|
+
if (parentTree) {
|
|
643
|
+
// FIXME: This is a heuristic to determine if the parent expects a statement child
|
|
644
|
+
const parentExpectsStatement = parentTree.kind === J.Kind.Block ||
|
|
645
|
+
parentTree.kind === J.Kind.Case ||
|
|
646
|
+
parentTree.kind === J.Kind.DoWhileLoop ||
|
|
647
|
+
parentTree.kind === J.Kind.ForEachLoop ||
|
|
648
|
+
parentTree.kind === J.Kind.ForLoop ||
|
|
649
|
+
parentTree.kind === J.Kind.If ||
|
|
650
|
+
parentTree.kind === J.Kind.IfElse ||
|
|
651
|
+
parentTree.kind === J.Kind.WhileLoop ||
|
|
652
|
+
parentTree.kind === JS.Kind.CompilationUnit ||
|
|
653
|
+
parentTree.kind === JS.Kind.ForInLoop;
|
|
654
|
+
const originalIsStatement = isStatement(originalTree);
|
|
655
|
+
|
|
656
|
+
const resultIsStatement = isStatement(resultToUse);
|
|
657
|
+
const resultIsExpression = isExpression(resultToUse);
|
|
658
|
+
|
|
659
|
+
// Determine context and wrap if needed
|
|
660
|
+
if (parentExpectsStatement && originalIsStatement) {
|
|
661
|
+
// Statement context: wrap in ExpressionStatement if result is not a statement
|
|
662
|
+
if (!resultIsStatement && resultIsExpression) {
|
|
663
|
+
resultToUse = {
|
|
664
|
+
kind: JS.Kind.ExpressionStatement,
|
|
665
|
+
id: randomId(),
|
|
666
|
+
prefix: resultToUse.prefix,
|
|
667
|
+
markers: resultToUse.markers,
|
|
668
|
+
expression: { ...resultToUse, prefix: emptySpace }
|
|
669
|
+
} as JS.ExpressionStatement;
|
|
670
|
+
}
|
|
671
|
+
} else if (!parentExpectsStatement) {
|
|
672
|
+
// Expression context: wrap in StatementExpression if result is statement-only
|
|
673
|
+
if (resultIsStatement && !resultIsExpression) {
|
|
674
|
+
const stmt = resultToUse as Statement;
|
|
675
|
+
resultToUse = {
|
|
676
|
+
kind: JS.Kind.StatementExpression,
|
|
677
|
+
id: randomId(),
|
|
678
|
+
prefix: stmt.prefix,
|
|
679
|
+
markers: stmt.markers,
|
|
680
|
+
statement: { ...stmt, prefix: emptySpace }
|
|
681
|
+
} as JS.StatementExpression;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
return resultToUse;
|
|
674
686
|
}
|
|
675
687
|
}
|
|
@@ -121,20 +121,26 @@ class RewriteRuleImpl implements RewriteRule {
|
|
|
121
121
|
*
|
|
122
122
|
* @example
|
|
123
123
|
* // Single pattern
|
|
124
|
-
* const swapOperands = rewrite(() =>
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
* }
|
|
124
|
+
* const swapOperands = rewrite(() => {
|
|
125
|
+
* const { left, right } = { left: capture(), right: capture() };
|
|
126
|
+
* return {
|
|
127
|
+
* before: pattern`${left} + ${right}`,
|
|
128
|
+
* after: template`${right} + ${left}`
|
|
129
|
+
* };
|
|
130
|
+
* });
|
|
128
131
|
*
|
|
129
132
|
* @example
|
|
130
133
|
* // Multiple patterns
|
|
131
|
-
* const normalizeComparisons = rewrite(() =>
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
134
|
+
* const normalizeComparisons = rewrite(() => {
|
|
135
|
+
* const { left, right } = { left: capture(), right: capture() };
|
|
136
|
+
* return {
|
|
137
|
+
* before: [
|
|
138
|
+
* pattern`${left} == ${right}`,
|
|
139
|
+
* pattern`${left} === ${right}`
|
|
140
|
+
* ],
|
|
141
|
+
* after: template`${left} === ${right}`
|
|
142
|
+
* };
|
|
143
|
+
* });
|
|
138
144
|
*
|
|
139
145
|
* @example
|
|
140
146
|
* // Using in a visitor - IMPORTANT: use `|| node` to handle undefined when no match
|
|
@@ -20,6 +20,7 @@ import {MatchResult} from './pattern';
|
|
|
20
20
|
import {generateCacheKey, globalAstCache, WRAPPERS_MAP_SYMBOL} from './utils';
|
|
21
21
|
import {CAPTURE_NAME_SYMBOL} from './capture';
|
|
22
22
|
import {TemplateEngine} from './engine';
|
|
23
|
+
import {JS} from '..';
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
26
|
* Coordinates for template application.
|
|
@@ -223,23 +224,30 @@ export class Template {
|
|
|
223
224
|
}
|
|
224
225
|
|
|
225
226
|
/**
|
|
226
|
-
* Gets the
|
|
227
|
-
*
|
|
227
|
+
* Gets the template tree for this template, using two-level caching:
|
|
228
|
+
* - Level 1: Instance cache (this._cachedTemplate) - fastest, no lookup needed
|
|
229
|
+
* - Level 2: Global cache (globalAstCache) - fast, shared across all templates
|
|
230
|
+
* - Level 3: TemplateEngine - slow, parses and processes the template
|
|
228
231
|
*
|
|
229
|
-
*
|
|
232
|
+
* Since all parameters are now placeholders (no primitives), templates with the same
|
|
233
|
+
* structure always parse to the same AST regardless of parameter values.
|
|
234
|
+
*
|
|
235
|
+
* @returns The cached or newly computed template tree
|
|
236
|
+
* @internal
|
|
230
237
|
*/
|
|
231
|
-
|
|
238
|
+
async getTemplateTree(): Promise<JS.CompilationUnit> {
|
|
232
239
|
// Level 1: Instance cache (fastest path)
|
|
233
240
|
if (this._cachedTemplate) {
|
|
234
|
-
return this._cachedTemplate;
|
|
241
|
+
return this._cachedTemplate as JS.CompilationUnit;
|
|
235
242
|
}
|
|
236
243
|
|
|
237
244
|
// Generate cache key for global lookup
|
|
245
|
+
// Since all parameters use placeholders, we only need the template structure
|
|
238
246
|
const contextStatements = this.options.context || this.options.imports || [];
|
|
239
|
-
const
|
|
247
|
+
const parametersKey = this.parameters.length.toString(); // Just the count
|
|
240
248
|
const cacheKey = generateCacheKey(
|
|
241
249
|
this.templateParts,
|
|
242
|
-
|
|
250
|
+
parametersKey,
|
|
243
251
|
contextStatements,
|
|
244
252
|
this.options.dependencies || {}
|
|
245
253
|
);
|
|
@@ -247,8 +255,8 @@ export class Template {
|
|
|
247
255
|
// Level 2: Global cache (fast path - shared with Pattern)
|
|
248
256
|
const cached = globalAstCache.get(cacheKey);
|
|
249
257
|
if (cached) {
|
|
250
|
-
this._cachedTemplate = cached;
|
|
251
|
-
return cached;
|
|
258
|
+
this._cachedTemplate = cached as JS.CompilationUnit;
|
|
259
|
+
return cached as JS.CompilationUnit;
|
|
252
260
|
}
|
|
253
261
|
|
|
254
262
|
// Level 3: Compute via TemplateEngine (slow path)
|
|
@@ -257,7 +265,7 @@ export class Template {
|
|
|
257
265
|
this.parameters,
|
|
258
266
|
contextStatements,
|
|
259
267
|
this.options.dependencies || {}
|
|
260
|
-
);
|
|
268
|
+
) as JS.CompilationUnit;
|
|
261
269
|
|
|
262
270
|
// Cache in both levels
|
|
263
271
|
globalAstCache.set(cacheKey, result);
|
|
@@ -310,17 +318,12 @@ export class Template {
|
|
|
310
318
|
}
|
|
311
319
|
}
|
|
312
320
|
|
|
313
|
-
//
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
// Prefer 'context' over deprecated 'imports'
|
|
317
|
-
const contextStatements = this.options.context || this.options.imports || [];
|
|
321
|
+
// Use instance-level cache to get the template tree
|
|
322
|
+
const ast = await this.getTemplateTree();
|
|
318
323
|
|
|
319
|
-
//
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
return TemplateEngine.applyTemplate(
|
|
323
|
-
this.templateParts,
|
|
324
|
+
// Delegate to TemplateEngine for placeholder substitution and application
|
|
325
|
+
return TemplateEngine.applyTemplateFromAst(
|
|
326
|
+
ast,
|
|
324
327
|
this.parameters,
|
|
325
328
|
cursor,
|
|
326
329
|
{
|
|
@@ -328,9 +331,7 @@ export class Template {
|
|
|
328
331
|
mode: JavaCoordinates.Mode.Replace
|
|
329
332
|
},
|
|
330
333
|
normalizedValues,
|
|
331
|
-
wrappersMap
|
|
332
|
-
contextStatements,
|
|
333
|
-
this.options.dependencies || {}
|
|
334
|
+
wrappersMap
|
|
334
335
|
);
|
|
335
336
|
}
|
|
336
337
|
}
|
|
@@ -344,7 +345,7 @@ export class Template {
|
|
|
344
345
|
* access array elements (e.g., `args.elements[0].element`).
|
|
345
346
|
*
|
|
346
347
|
* @param strings The string parts of the template
|
|
347
|
-
* @param parameters The parameters between the string parts (Capture, Tree, or
|
|
348
|
+
* @param parameters The parameters between the string parts (Capture, CaptureValue, TemplateParam, Tree, or Tree[])
|
|
348
349
|
* @returns A Template object that can be applied to generate AST nodes
|
|
349
350
|
*
|
|
350
351
|
* @example
|
|
@@ -17,6 +17,7 @@ import {Cursor, Tree} from '../..';
|
|
|
17
17
|
import {J, Type} from '../../java';
|
|
18
18
|
import type {MatchResult, Pattern} from "./pattern";
|
|
19
19
|
import type {Template} from "./template";
|
|
20
|
+
import type {CaptureValue} from "./capture";
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* Options for variadic captures that match zero or more nodes in a sequence.
|
|
@@ -274,16 +275,23 @@ export interface PatternOptions {
|
|
|
274
275
|
* Valid parameter types for template literals.
|
|
275
276
|
* - Capture: For pattern matching and reuse
|
|
276
277
|
* - CaptureValue: Result of property access or array operations on captures (e.g., capture.prop, capture[0], capture.slice(1))
|
|
278
|
+
* - TemplateParam: For standalone template parameters
|
|
277
279
|
* - Tree: AST nodes to be inserted directly
|
|
278
280
|
* - Tree[]: Arrays of AST nodes (from variadic capture operations like slice)
|
|
279
|
-
*
|
|
281
|
+
*
|
|
282
|
+
* Note: Primitive values (string, number, boolean) are NOT supported in template literals.
|
|
283
|
+
* Use Template.builder() API if you need to insert literal values.
|
|
280
284
|
*/
|
|
281
|
-
export type TemplateParameter = Capture |
|
|
285
|
+
export type TemplateParameter = Capture | CaptureValue | TemplateParam | Tree | Tree[];
|
|
282
286
|
|
|
283
287
|
/**
|
|
284
288
|
* Parameter specification for template generation (internal).
|
|
285
289
|
* Represents a placeholder in a template that will be replaced with a parameter value.
|
|
286
290
|
* This is the internal wrapper used by the template engine.
|
|
291
|
+
*
|
|
292
|
+
* Note: The value is typed as `any` rather than `TemplateParameter` to allow flexible
|
|
293
|
+
* internal handling without excessive type guards. The public API (template function)
|
|
294
|
+
* constrains inputs to `TemplateParameter`, providing type safety at the API boundary.
|
|
287
295
|
*/
|
|
288
296
|
export interface Parameter {
|
|
289
297
|
/**
|
|
@@ -49,7 +49,8 @@ export const WRAPPER_FUNCTION_NAME = '__WRAPPER__';
|
|
|
49
49
|
export class LRUCache<K, V> {
|
|
50
50
|
private cache = new Map<K, V>();
|
|
51
51
|
|
|
52
|
-
constructor(private maxSize: number) {
|
|
52
|
+
constructor(private maxSize: number) {
|
|
53
|
+
}
|
|
53
54
|
|
|
54
55
|
get(key: K): V | undefined {
|
|
55
56
|
const value = this.cache.get(key);
|
|
@@ -111,7 +112,7 @@ export function generateCacheKey(
|
|
|
111
112
|
Array.from(templateParts).join('|'),
|
|
112
113
|
itemsKey,
|
|
113
114
|
contextStatements.join(';'),
|
|
114
|
-
JSON.stringify(dependencies
|
|
115
|
+
JSON.stringify(dependencies)
|
|
115
116
|
].join('::');
|
|
116
117
|
}
|
|
117
118
|
|