@openrewrite/rewrite 8.66.0 → 8.66.2
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/java/tree.d.ts +10 -1
- package/dist/java/tree.d.ts.map +1 -1
- package/dist/java/tree.js +21 -5
- package/dist/java/tree.js.map +1 -1
- package/dist/java/type-visitor.d.ts +1 -1
- package/dist/java/type-visitor.d.ts.map +1 -1
- package/dist/java/visitor.d.ts +2 -2
- package/dist/java/visitor.d.ts.map +1 -1
- package/dist/java/visitor.js +8 -2
- package/dist/java/visitor.js.map +1 -1
- package/dist/javascript/assertions.d.ts +6 -0
- package/dist/javascript/assertions.d.ts.map +1 -1
- package/dist/javascript/assertions.js +14 -6
- package/dist/javascript/assertions.js.map +1 -1
- package/dist/javascript/comparator.d.ts +217 -7
- package/dist/javascript/comparator.d.ts.map +1 -1
- package/dist/javascript/comparator.js +1020 -2848
- package/dist/javascript/comparator.js.map +1 -1
- package/dist/javascript/format.d.ts +5 -3
- package/dist/javascript/format.d.ts.map +1 -1
- package/dist/javascript/format.js +87 -44
- package/dist/javascript/format.js.map +1 -1
- package/dist/javascript/index.d.ts +2 -1
- package/dist/javascript/index.d.ts.map +1 -1
- package/dist/javascript/index.js +2 -1
- package/dist/javascript/index.js.map +1 -1
- package/dist/javascript/parser.d.ts +2 -1
- package/dist/javascript/parser.d.ts.map +1 -1
- package/dist/javascript/parser.js +54 -43
- package/dist/javascript/parser.js.map +1 -1
- package/dist/javascript/templating/capture.d.ts +293 -0
- package/dist/javascript/templating/capture.d.ts.map +1 -0
- package/dist/javascript/templating/capture.js +461 -0
- package/dist/javascript/templating/capture.js.map +1 -0
- package/dist/javascript/templating/comparator.d.ts +171 -0
- package/dist/javascript/templating/comparator.d.ts.map +1 -0
- package/dist/javascript/templating/comparator.js +1221 -0
- package/dist/javascript/templating/comparator.js.map +1 -0
- package/dist/javascript/templating/engine.d.ts +108 -0
- package/dist/javascript/templating/engine.d.ts.map +1 -0
- package/dist/javascript/templating/engine.js +661 -0
- package/dist/javascript/templating/engine.js.map +1 -0
- package/dist/javascript/templating/index.d.ts +6 -0
- package/dist/javascript/templating/index.d.ts.map +1 -0
- package/dist/javascript/templating/index.js +44 -0
- package/dist/javascript/templating/index.js.map +1 -0
- package/dist/javascript/templating/pattern.d.ts +276 -0
- package/dist/javascript/templating/pattern.d.ts.map +1 -0
- package/dist/javascript/templating/pattern.js +952 -0
- package/dist/javascript/templating/pattern.js.map +1 -0
- package/dist/javascript/templating/placeholder-replacement.d.ts +83 -0
- package/dist/javascript/templating/placeholder-replacement.d.ts.map +1 -0
- package/dist/javascript/templating/placeholder-replacement.js +467 -0
- package/dist/javascript/templating/placeholder-replacement.js.map +1 -0
- package/dist/javascript/templating/rewrite.d.ts +84 -0
- package/dist/javascript/templating/rewrite.d.ts.map +1 -0
- package/dist/javascript/templating/rewrite.js +208 -0
- package/dist/javascript/templating/rewrite.js.map +1 -0
- package/dist/javascript/templating/template.d.ts +230 -0
- package/dist/javascript/templating/template.d.ts.map +1 -0
- package/dist/javascript/templating/template.js +367 -0
- package/dist/javascript/templating/template.js.map +1 -0
- package/dist/javascript/templating/types.d.ts +610 -0
- package/dist/javascript/templating/types.d.ts.map +1 -0
- package/dist/javascript/templating/types.js +3 -0
- package/dist/javascript/templating/types.js.map +1 -0
- package/dist/javascript/templating/utils.d.ts +135 -0
- package/dist/javascript/templating/utils.d.ts.map +1 -0
- package/dist/javascript/templating/utils.js +251 -0
- package/dist/javascript/templating/utils.js.map +1 -0
- package/dist/javascript/type-mapping.d.ts.map +1 -1
- package/dist/javascript/type-mapping.js +21 -11
- package/dist/javascript/type-mapping.js.map +1 -1
- package/dist/json/rpc.js +2 -2
- package/dist/json/rpc.js.map +1 -1
- package/dist/recipe/order-imports.js.map +1 -1
- package/dist/test/rewrite-test.d.ts.map +1 -1
- package/dist/test/rewrite-test.js +10 -6
- package/dist/test/rewrite-test.js.map +1 -1
- package/dist/version.txt +1 -1
- package/dist/visitor.d.ts +4 -4
- package/dist/visitor.d.ts.map +1 -1
- package/dist/visitor.js +8 -3
- package/dist/visitor.js.map +1 -1
- package/package.json +5 -2
- package/src/java/tree.ts +10 -3
- package/src/java/type-visitor.ts +1 -1
- package/src/java/visitor.ts +11 -5
- package/src/javascript/assertions.ts +9 -3
- package/src/javascript/comparator.ts +1095 -3373
- package/src/javascript/format.ts +72 -33
- package/src/javascript/index.ts +2 -1
- package/src/javascript/parser.ts +67 -45
- package/src/javascript/templating/capture.ts +595 -0
- package/src/javascript/templating/comparator.ts +1383 -0
- package/src/javascript/templating/engine.ts +750 -0
- package/src/javascript/templating/index.ts +67 -0
- package/src/javascript/templating/pattern.ts +1101 -0
- package/src/javascript/templating/placeholder-replacement.ts +475 -0
- package/src/javascript/templating/rewrite.ts +229 -0
- package/src/javascript/templating/template.ts +414 -0
- package/src/javascript/templating/types.ts +674 -0
- package/src/javascript/templating/utils.ts +298 -0
- package/src/javascript/type-mapping.ts +20 -11
- package/src/json/rpc.ts +2 -2
- package/src/recipe/order-imports.ts +1 -1
- package/src/test/rewrite-test.ts +12 -7
- package/src/visitor.ts +14 -6
- package/dist/javascript/templating.d.ts +0 -265
- package/dist/javascript/templating.d.ts.map +0 -1
- package/dist/javascript/templating.js +0 -1027
- package/dist/javascript/templating.js.map +0 -1
- package/src/javascript/templating.ts +0 -1226
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { ExecutionContext, Recipe } from '../..';
|
|
2
|
+
import { RewriteRule, RewriteConfig } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a replacement rule using a capture context and configuration.
|
|
5
|
+
*
|
|
6
|
+
* @param builderFn Function that takes a capture context and returns before/after configuration
|
|
7
|
+
* @returns A replacement rule that can be applied to AST nodes
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* // Single pattern
|
|
11
|
+
* const swapOperands = rewrite(() => {
|
|
12
|
+
* const { left, right } = { left: capture(), right: capture() };
|
|
13
|
+
* return {
|
|
14
|
+
* before: pattern`${left} + ${right}`,
|
|
15
|
+
* after: template`${right} + ${left}`
|
|
16
|
+
* };
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // Multiple patterns
|
|
21
|
+
* const normalizeComparisons = rewrite(() => {
|
|
22
|
+
* const { left, right } = { left: capture(), right: capture() };
|
|
23
|
+
* return {
|
|
24
|
+
* before: [
|
|
25
|
+
* pattern`${left} == ${right}`,
|
|
26
|
+
* pattern`${left} === ${right}`
|
|
27
|
+
* ],
|
|
28
|
+
* after: template`${left} === ${right}`
|
|
29
|
+
* };
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* // Using in a visitor - IMPORTANT: use `|| node` to handle undefined when no match
|
|
34
|
+
* class MyVisitor extends JavaScriptVisitor<any> {
|
|
35
|
+
* override async visitBinary(binary: J.Binary, p: any): Promise<J | undefined> {
|
|
36
|
+
* const rule = rewrite(() => ({
|
|
37
|
+
* before: pattern`${capture('a')} + ${capture('b')}`,
|
|
38
|
+
* after: template`${capture('b')} + ${capture('a')}`
|
|
39
|
+
* }));
|
|
40
|
+
* // tryOn() returns undefined if no pattern matches, so always use || node
|
|
41
|
+
* return await rule.tryOn(this.cursor, binary) || binary;
|
|
42
|
+
* }
|
|
43
|
+
* }
|
|
44
|
+
*/
|
|
45
|
+
export declare function rewrite(builderFn: () => RewriteConfig): RewriteRule;
|
|
46
|
+
/**
|
|
47
|
+
* Creates a RewriteRule from a Recipe by using its editor visitor.
|
|
48
|
+
*
|
|
49
|
+
* This allows recipes to be used in the same chaining pattern as other rewrite rules,
|
|
50
|
+
* enabling composition with `andThen()`.
|
|
51
|
+
*
|
|
52
|
+
* @param recipe The recipe whose editor will be used to transform nodes
|
|
53
|
+
* @param ctx The execution context to pass to the recipe's editor
|
|
54
|
+
* @returns A RewriteRule that applies the recipe's editor to nodes
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* class MyRecipe extends Recipe {
|
|
59
|
+
* name = "my.recipe";
|
|
60
|
+
* displayName = "My Recipe";
|
|
61
|
+
* description = "Transforms code.";
|
|
62
|
+
*
|
|
63
|
+
* async editor(): Promise<TreeVisitor<any, ExecutionContext>> {
|
|
64
|
+
* return new MyVisitor();
|
|
65
|
+
* }
|
|
66
|
+
* }
|
|
67
|
+
*
|
|
68
|
+
* // In a visitor:
|
|
69
|
+
* override async visitBinary(binary: J.Binary, p: ExecutionContext): Promise<J | undefined> {
|
|
70
|
+
* const rule1 = rewrite(() => ({
|
|
71
|
+
* before: pattern`${capture('a')} + ${capture('b')}`,
|
|
72
|
+
* after: template`${capture('b')} + ${capture('a')}`
|
|
73
|
+
* }));
|
|
74
|
+
*
|
|
75
|
+
* const rule2 = fromRecipe(new MyRecipe(), p);
|
|
76
|
+
*
|
|
77
|
+
* // Chain the pattern-based rule with the recipe
|
|
78
|
+
* const combined = rule1.andThen(rule2);
|
|
79
|
+
* return await combined.tryOn(this.cursor, binary) || binary;
|
|
80
|
+
* }
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export declare const fromRecipe: (recipe: Recipe, ctx: ExecutionContext) => RewriteRule;
|
|
84
|
+
//# sourceMappingURL=rewrite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rewrite.d.ts","sourceRoot":"","sources":["../../../src/javascript/templating/rewrite.ts"],"names":[],"mappings":"AAeA,OAAO,EAAS,gBAAgB,EAAE,MAAM,EAAC,MAAM,OAAO,CAAC;AAEvD,OAAO,EAAC,WAAW,EAAE,aAAa,EAAC,MAAM,SAAS,CAAC;AAkGnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,wBAAgB,OAAO,CACnB,SAAS,EAAE,MAAM,aAAa,GAC/B,WAAW,CAcb;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,eAAO,MAAM,UAAU,GAAI,QAAQ,MAAM,EAAE,KAAK,gBAAgB,KAAG,WAgBlE,CAAA"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.fromRecipe = void 0;
|
|
13
|
+
exports.rewrite = rewrite;
|
|
14
|
+
/**
|
|
15
|
+
* Implementation of a replacement rule.
|
|
16
|
+
*/
|
|
17
|
+
class RewriteRuleImpl {
|
|
18
|
+
constructor(before, after, where, whereNot) {
|
|
19
|
+
this.before = before;
|
|
20
|
+
this.after = after;
|
|
21
|
+
this.where = where;
|
|
22
|
+
this.whereNot = whereNot;
|
|
23
|
+
}
|
|
24
|
+
tryOn(cursor, node) {
|
|
25
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
26
|
+
for (const pattern of this.before) {
|
|
27
|
+
// Pass cursor to pattern.match() for context-aware capture constraints
|
|
28
|
+
const match = yield pattern.match(node, cursor);
|
|
29
|
+
if (match) {
|
|
30
|
+
// Evaluate context predicates after structural match
|
|
31
|
+
if (this.where) {
|
|
32
|
+
const whereResult = yield this.where(node, cursor);
|
|
33
|
+
if (!whereResult) {
|
|
34
|
+
continue; // Pattern matched but context doesn't, try next pattern
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (this.whereNot) {
|
|
38
|
+
const whereNotResult = yield this.whereNot(node, cursor);
|
|
39
|
+
if (whereNotResult) {
|
|
40
|
+
continue; // Pattern matched but context is excluded, try next pattern
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Apply transformation
|
|
44
|
+
let result;
|
|
45
|
+
if (typeof this.after === 'function') {
|
|
46
|
+
// Call the function to get a template, then apply it
|
|
47
|
+
const template = this.after(match);
|
|
48
|
+
result = yield template.apply(cursor, node, match);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
// Use template.apply() as before
|
|
52
|
+
result = yield this.after.apply(cursor, node, match);
|
|
53
|
+
}
|
|
54
|
+
if (result) {
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Return undefined if no patterns match or all context checks failed
|
|
60
|
+
return undefined;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
andThen(next) {
|
|
64
|
+
const first = this;
|
|
65
|
+
return new (class extends RewriteRuleImpl {
|
|
66
|
+
constructor() {
|
|
67
|
+
// Pass empty patterns and a function that will never be called
|
|
68
|
+
// since we override tryOn
|
|
69
|
+
super([], () => undefined);
|
|
70
|
+
}
|
|
71
|
+
tryOn(cursor, node) {
|
|
72
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
73
|
+
const firstResult = yield first.tryOn(cursor, node);
|
|
74
|
+
if (firstResult !== undefined) {
|
|
75
|
+
const secondResult = yield next.tryOn(cursor, firstResult);
|
|
76
|
+
return secondResult !== null && secondResult !== void 0 ? secondResult : firstResult;
|
|
77
|
+
}
|
|
78
|
+
return undefined;
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
})();
|
|
82
|
+
}
|
|
83
|
+
orElse(alternative) {
|
|
84
|
+
const first = this;
|
|
85
|
+
return new (class extends RewriteRuleImpl {
|
|
86
|
+
constructor() {
|
|
87
|
+
// Pass empty patterns and a function that will never be called
|
|
88
|
+
// since we override tryOn
|
|
89
|
+
super([], () => undefined);
|
|
90
|
+
}
|
|
91
|
+
tryOn(cursor, node) {
|
|
92
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
93
|
+
const firstResult = yield first.tryOn(cursor, node);
|
|
94
|
+
if (firstResult !== undefined) {
|
|
95
|
+
return firstResult;
|
|
96
|
+
}
|
|
97
|
+
return yield alternative.tryOn(cursor, node);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
})();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Creates a replacement rule using a capture context and configuration.
|
|
105
|
+
*
|
|
106
|
+
* @param builderFn Function that takes a capture context and returns before/after configuration
|
|
107
|
+
* @returns A replacement rule that can be applied to AST nodes
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* // Single pattern
|
|
111
|
+
* const swapOperands = rewrite(() => {
|
|
112
|
+
* const { left, right } = { left: capture(), right: capture() };
|
|
113
|
+
* return {
|
|
114
|
+
* before: pattern`${left} + ${right}`,
|
|
115
|
+
* after: template`${right} + ${left}`
|
|
116
|
+
* };
|
|
117
|
+
* });
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* // Multiple patterns
|
|
121
|
+
* const normalizeComparisons = rewrite(() => {
|
|
122
|
+
* const { left, right } = { left: capture(), right: capture() };
|
|
123
|
+
* return {
|
|
124
|
+
* before: [
|
|
125
|
+
* pattern`${left} == ${right}`,
|
|
126
|
+
* pattern`${left} === ${right}`
|
|
127
|
+
* ],
|
|
128
|
+
* after: template`${left} === ${right}`
|
|
129
|
+
* };
|
|
130
|
+
* });
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* // Using in a visitor - IMPORTANT: use `|| node` to handle undefined when no match
|
|
134
|
+
* class MyVisitor extends JavaScriptVisitor<any> {
|
|
135
|
+
* override async visitBinary(binary: J.Binary, p: any): Promise<J | undefined> {
|
|
136
|
+
* const rule = rewrite(() => ({
|
|
137
|
+
* before: pattern`${capture('a')} + ${capture('b')}`,
|
|
138
|
+
* after: template`${capture('b')} + ${capture('a')}`
|
|
139
|
+
* }));
|
|
140
|
+
* // tryOn() returns undefined if no pattern matches, so always use || node
|
|
141
|
+
* return await rule.tryOn(this.cursor, binary) || binary;
|
|
142
|
+
* }
|
|
143
|
+
* }
|
|
144
|
+
*/
|
|
145
|
+
function rewrite(builderFn) {
|
|
146
|
+
const config = builderFn();
|
|
147
|
+
// Ensure we have valid before and after properties
|
|
148
|
+
if (!config.before || !config.after) {
|
|
149
|
+
throw new Error('Builder function must return an object with before and after properties');
|
|
150
|
+
}
|
|
151
|
+
return new RewriteRuleImpl(Array.isArray(config.before) ? config.before : [config.before], config.after, config.where, config.whereNot);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Creates a RewriteRule from a Recipe by using its editor visitor.
|
|
155
|
+
*
|
|
156
|
+
* This allows recipes to be used in the same chaining pattern as other rewrite rules,
|
|
157
|
+
* enabling composition with `andThen()`.
|
|
158
|
+
*
|
|
159
|
+
* @param recipe The recipe whose editor will be used to transform nodes
|
|
160
|
+
* @param ctx The execution context to pass to the recipe's editor
|
|
161
|
+
* @returns A RewriteRule that applies the recipe's editor to nodes
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```typescript
|
|
165
|
+
* class MyRecipe extends Recipe {
|
|
166
|
+
* name = "my.recipe";
|
|
167
|
+
* displayName = "My Recipe";
|
|
168
|
+
* description = "Transforms code.";
|
|
169
|
+
*
|
|
170
|
+
* async editor(): Promise<TreeVisitor<any, ExecutionContext>> {
|
|
171
|
+
* return new MyVisitor();
|
|
172
|
+
* }
|
|
173
|
+
* }
|
|
174
|
+
*
|
|
175
|
+
* // In a visitor:
|
|
176
|
+
* override async visitBinary(binary: J.Binary, p: ExecutionContext): Promise<J | undefined> {
|
|
177
|
+
* const rule1 = rewrite(() => ({
|
|
178
|
+
* before: pattern`${capture('a')} + ${capture('b')}`,
|
|
179
|
+
* after: template`${capture('b')} + ${capture('a')}`
|
|
180
|
+
* }));
|
|
181
|
+
*
|
|
182
|
+
* const rule2 = fromRecipe(new MyRecipe(), p);
|
|
183
|
+
*
|
|
184
|
+
* // Chain the pattern-based rule with the recipe
|
|
185
|
+
* const combined = rule1.andThen(rule2);
|
|
186
|
+
* return await combined.tryOn(this.cursor, binary) || binary;
|
|
187
|
+
* }
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
const fromRecipe = (recipe, ctx) => {
|
|
191
|
+
return new (class extends RewriteRuleImpl {
|
|
192
|
+
constructor() {
|
|
193
|
+
// Pass empty patterns and a function that will never be called
|
|
194
|
+
// since we override tryOn
|
|
195
|
+
super([], () => undefined);
|
|
196
|
+
}
|
|
197
|
+
tryOn(cursor, tree) {
|
|
198
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
199
|
+
const visitor = yield recipe.editor();
|
|
200
|
+
const result = yield visitor.visit(tree, ctx, cursor);
|
|
201
|
+
// Return undefined if the visitor didn't change the node
|
|
202
|
+
return result !== tree ? result : undefined;
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
})();
|
|
206
|
+
};
|
|
207
|
+
exports.fromRecipe = fromRecipe;
|
|
208
|
+
//# sourceMappingURL=rewrite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rewrite.js","sourceRoot":"","sources":["../../../src/javascript/templating/rewrite.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { Cursor, Tree } from '../..';
|
|
2
|
+
import { J } from '../../java';
|
|
3
|
+
import { Capture, Parameter, TemplateOptions, TemplateParameter } from './types';
|
|
4
|
+
import { JS } from '..';
|
|
5
|
+
/**
|
|
6
|
+
* Coordinates for template application.
|
|
7
|
+
*/
|
|
8
|
+
type JavaCoordinates = {
|
|
9
|
+
tree?: Tree;
|
|
10
|
+
loc?: JavaCoordinates.Location;
|
|
11
|
+
mode?: JavaCoordinates.Mode;
|
|
12
|
+
};
|
|
13
|
+
declare namespace JavaCoordinates {
|
|
14
|
+
type Location = 'EXPRESSION_PREFIX' | 'STATEMENT_PREFIX' | 'BLOCK_END';
|
|
15
|
+
enum Mode {
|
|
16
|
+
Before = 0,
|
|
17
|
+
After = 1,
|
|
18
|
+
Replace = 2
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Builder for creating templates programmatically.
|
|
23
|
+
* Use when template structure is not known at compile time.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* // Conditional construction
|
|
27
|
+
* const builder = Template.builder().code('function foo(x) {');
|
|
28
|
+
* if (needsValidation) {
|
|
29
|
+
* builder.code('if (typeof x !== "number") throw new Error("Invalid");');
|
|
30
|
+
* }
|
|
31
|
+
* builder.code('return x * 2; }');
|
|
32
|
+
* const tmpl = builder.build();
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* // Composition from fragments
|
|
36
|
+
* function createWrapper(innerBody: Capture): Template {
|
|
37
|
+
* return Template.builder()
|
|
38
|
+
* .code('function wrapper() { try { ')
|
|
39
|
+
* .param(innerBody)
|
|
40
|
+
* .code(' } catch(e) { console.error(e); } }')
|
|
41
|
+
* .build();
|
|
42
|
+
* }
|
|
43
|
+
*/
|
|
44
|
+
export declare class TemplateBuilder {
|
|
45
|
+
private parts;
|
|
46
|
+
private params;
|
|
47
|
+
/**
|
|
48
|
+
* Adds a static string part to the template.
|
|
49
|
+
*
|
|
50
|
+
* @param str The string to add
|
|
51
|
+
* @returns This builder for chaining
|
|
52
|
+
*/
|
|
53
|
+
code(str: string): this;
|
|
54
|
+
/**
|
|
55
|
+
* Adds a parameter to the template.
|
|
56
|
+
*
|
|
57
|
+
* @param value The parameter value (Capture, Tree, or primitive)
|
|
58
|
+
* @returns This builder for chaining
|
|
59
|
+
*/
|
|
60
|
+
param(value: TemplateParameter): this;
|
|
61
|
+
/**
|
|
62
|
+
* Builds the template from accumulated parts and parameters.
|
|
63
|
+
*
|
|
64
|
+
* @returns A Template instance
|
|
65
|
+
*/
|
|
66
|
+
build(): Template;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Template for creating AST nodes.
|
|
70
|
+
*
|
|
71
|
+
* This class provides the public API for template generation.
|
|
72
|
+
* The actual templating logic is handled by the internal TemplateEngine.
|
|
73
|
+
*
|
|
74
|
+
* Templates can reference captures from patterns, and you can access properties
|
|
75
|
+
* of captured nodes using dot notation. This allows you to extract and insert
|
|
76
|
+
* specific subtrees from matched AST nodes.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* // Generate a literal AST node
|
|
80
|
+
* const result = template`2`.apply(cursor, coordinates);
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* // Generate an AST node with a parameter
|
|
84
|
+
* const result = template`${capture()}`.apply(cursor, coordinates);
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* // Access properties of captured nodes in templates
|
|
88
|
+
* const method = capture<J.MethodInvocation>('method');
|
|
89
|
+
* const pat = pattern`foo(${method})`;
|
|
90
|
+
* const tmpl = template`bar(${method.name})`; // Access the 'name' property
|
|
91
|
+
*
|
|
92
|
+
* const match = await pat.match(someNode);
|
|
93
|
+
* if (match) {
|
|
94
|
+
* // The template will insert just the 'name' subtree from the captured method
|
|
95
|
+
* const result = await tmpl.apply(cursor, someNode, match);
|
|
96
|
+
* }
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* // Deep property access chains
|
|
100
|
+
* const method = capture<J.MethodInvocation>('method');
|
|
101
|
+
* template`console.log(${method.name.simpleName})` // Navigate multiple properties
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* // Array element access
|
|
105
|
+
* const invocation = capture<J.MethodInvocation>('invocation');
|
|
106
|
+
* template`bar(${invocation.arguments.elements[0].element})` // Access array elements
|
|
107
|
+
*/
|
|
108
|
+
export declare class Template {
|
|
109
|
+
private readonly templateParts;
|
|
110
|
+
private readonly parameters;
|
|
111
|
+
private options;
|
|
112
|
+
private _cachedTemplate?;
|
|
113
|
+
/**
|
|
114
|
+
* Creates a new builder for constructing templates programmatically.
|
|
115
|
+
*
|
|
116
|
+
* @returns A new TemplateBuilder instance
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* const tmpl = Template.builder()
|
|
120
|
+
* .code('function foo() {')
|
|
121
|
+
* .code('return ')
|
|
122
|
+
* .param(capture('value'))
|
|
123
|
+
* .code('; }')
|
|
124
|
+
* .build();
|
|
125
|
+
*/
|
|
126
|
+
static builder(): TemplateBuilder;
|
|
127
|
+
/**
|
|
128
|
+
* Creates a new template.
|
|
129
|
+
*
|
|
130
|
+
* @param templateParts The string parts of the template
|
|
131
|
+
* @param parameters The parameters between the string parts
|
|
132
|
+
*/
|
|
133
|
+
constructor(templateParts: TemplateStringsArray, parameters: Parameter[]);
|
|
134
|
+
/**
|
|
135
|
+
* Configures this template with additional options.
|
|
136
|
+
*
|
|
137
|
+
* @param options Configuration options
|
|
138
|
+
* @returns This template for method chaining
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* template`isDate(${capture('date')})`
|
|
142
|
+
* .configure({
|
|
143
|
+
* context: ['import { isDate } from "util"'],
|
|
144
|
+
* dependencies: { 'util': '^1.0.0' }
|
|
145
|
+
* })
|
|
146
|
+
*/
|
|
147
|
+
configure(options: TemplateOptions): Template;
|
|
148
|
+
/**
|
|
149
|
+
* Gets the template tree for this template, using two-level caching:
|
|
150
|
+
* - Level 1: Instance cache (this._cachedTemplate) - fastest, no lookup needed
|
|
151
|
+
* - Level 2: Global cache (globalAstCache) - fast, shared across all templates
|
|
152
|
+
* - Level 3: TemplateEngine - slow, parses and processes the template
|
|
153
|
+
*
|
|
154
|
+
* Most parameters use placeholders that are replaced during application, so templates
|
|
155
|
+
* with the same structure share cached ASTs. However, raw() parameters are spliced at
|
|
156
|
+
* construction time, so their values must be included in the cache key.
|
|
157
|
+
*
|
|
158
|
+
* @returns The cached or newly computed template tree
|
|
159
|
+
* @internal
|
|
160
|
+
*/
|
|
161
|
+
getTemplateTree(): Promise<JS.CompilationUnit>;
|
|
162
|
+
/**
|
|
163
|
+
* Applies this template and returns the resulting tree.
|
|
164
|
+
*
|
|
165
|
+
* @param cursor The cursor pointing to the current location in the AST
|
|
166
|
+
* @param tree Input tree
|
|
167
|
+
* @param values values for parameters in template
|
|
168
|
+
* @returns A Promise resolving to the generated AST node
|
|
169
|
+
*/
|
|
170
|
+
apply(cursor: Cursor, tree: J, values?: Map<Capture | string, J> | Pick<Map<string, J>, 'get'> | Record<string, J>): Promise<J | undefined>;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Tagged template function for creating templates that generate AST nodes.
|
|
174
|
+
*
|
|
175
|
+
* Templates support property access on captures from patterns, allowing you to
|
|
176
|
+
* extract and insert specific subtrees from matched AST nodes. Use dot notation
|
|
177
|
+
* to navigate properties (e.g., `method.name`) or array bracket notation to
|
|
178
|
+
* access array elements (e.g., `args.elements[0].element`).
|
|
179
|
+
*
|
|
180
|
+
* Templates can also accept AST wrapper types directly:
|
|
181
|
+
* - J.RightPadded<T>: The element will be extracted and inserted
|
|
182
|
+
* - J.RightPadded<T>[]: Elements will be expanded in place
|
|
183
|
+
* - J.Container<T>: Elements will be expanded in place
|
|
184
|
+
*
|
|
185
|
+
* @param strings The string parts of the template
|
|
186
|
+
* @param parameters The parameters between the string parts (Capture, CaptureValue, TemplateParam, Tree, Tree[], J.RightPadded, J.RightPadded[], or J.Container)
|
|
187
|
+
* @returns A Template object that can be applied to generate AST nodes
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* // Simple template with literal
|
|
191
|
+
* const tmpl = template`console.log("hello")`;
|
|
192
|
+
* const result = await tmpl.apply(cursor, node);
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* // Template with capture - matches captured value from pattern
|
|
196
|
+
* const expr = capture('expr');
|
|
197
|
+
* const pat = pattern`foo(${expr})`;
|
|
198
|
+
* const tmpl = template`bar(${expr})`;
|
|
199
|
+
*
|
|
200
|
+
* const match = await pat.match(node);
|
|
201
|
+
* if (match) {
|
|
202
|
+
* const result = await tmpl.apply(cursor, node, match);
|
|
203
|
+
* }
|
|
204
|
+
*
|
|
205
|
+
* @example
|
|
206
|
+
* // Property access on captures - extract subtrees
|
|
207
|
+
* const method = capture<J.MethodInvocation>('method');
|
|
208
|
+
* const pat = pattern`foo(${method})`;
|
|
209
|
+
* // Access the 'name' property of the captured method invocation
|
|
210
|
+
* const tmpl = template`bar(${method.name})`;
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* // Deep property chains
|
|
214
|
+
* const method = capture<J.MethodInvocation>('method');
|
|
215
|
+
* template`console.log(${method.name.simpleName})`
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* // Array element access
|
|
219
|
+
* const invocation = capture<J.MethodInvocation>('invocation');
|
|
220
|
+
* template`bar(${invocation.arguments.elements[0].element})`
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* // Using J.RightPadded and J.Container directly
|
|
224
|
+
* const selectExpr = method.select; // J.RightPadded<Expression>
|
|
225
|
+
* const args = method.arguments; // J.Container<Expression>
|
|
226
|
+
* template`${selectExpr}.newMethod(${args})`
|
|
227
|
+
*/
|
|
228
|
+
export declare function template(strings: TemplateStringsArray, ...parameters: TemplateParameter[]): Template;
|
|
229
|
+
export type { JavaCoordinates };
|
|
230
|
+
//# sourceMappingURL=template.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../../../src/javascript/templating/template.ts"],"names":[],"mappings":"AAeA,OAAO,EAAC,MAAM,EAAE,IAAI,EAAC,MAAM,OAAO,CAAC;AACnC,OAAO,EAAC,CAAC,EAAC,MAAM,YAAY,CAAC;AAC7B,OAAO,EAAC,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,iBAAiB,EAAC,MAAM,SAAS,CAAC;AAK/E,OAAO,EAAC,EAAE,EAAC,MAAM,IAAI,CAAC;AAEtB;;GAEG;AACH,KAAK,eAAe,GAAG;IACnB,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,GAAG,CAAC,EAAE,eAAe,CAAC,QAAQ,CAAC;IAC/B,IAAI,CAAC,EAAE,eAAe,CAAC,IAAI,CAAC;CAC/B,CAAC;AAEF,kBAAU,eAAe,CAAC;IAEtB,KAAY,QAAQ,GAAG,mBAAmB,GAAG,kBAAkB,GAAG,WAAW,CAAC;IAE9E,KAAY,IAAI;QACZ,MAAM,IAAA;QACN,KAAK,IAAA;QACL,OAAO,IAAA;KACV;CACJ;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,eAAe;IACxB,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,MAAM,CAA2B;IAEzC;;;;;OAKG;IACH,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAcvB;;;;;OAKG;IACH,KAAK,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI;IAWrC;;;;OAIG;IACH,KAAK,IAAI,QAAQ;CAiBpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,qBAAa,QAAQ;IA4Bb,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,UAAU;IA5B/B,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,eAAe,CAAC,CAAI;IAE5B;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,OAAO,IAAI,eAAe;IAIjC;;;;;OAKG;gBAEkB,aAAa,EAAE,oBAAoB,EACnC,UAAU,EAAE,SAAS,EAAE;IAI5C;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,OAAO,EAAE,eAAe,GAAG,QAAQ;IAO7C;;;;;;;;;;;;OAYG;IACG,eAAe,IAAI,OAAO,CAAC,EAAE,CAAC,eAAe,CAAC;IA+CpD;;;;;;;OAOG;IACG,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,GAAG,CAAC,OAAO,GAAG,MAAM,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;CAoDpJ;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,UAAU,EAAE,iBAAiB,EAAE,GAAG,QAAQ,CAQpG;AAED,YAAY,EAAC,eAAe,EAAC,CAAC"}
|