@openrewrite/rewrite 8.67.0-20251106-140126 → 8.67.0-20251107-071946
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 +2 -0
- package/dist/java/tree.d.ts.map +1 -1
- package/dist/java/tree.js +5 -1
- package/dist/java/tree.js.map +1 -1
- package/dist/javascript/assertions.js +2 -2
- package/dist/javascript/assertions.js.map +1 -1
- package/dist/javascript/format.js +1 -1
- package/dist/javascript/format.js.map +1 -1
- package/dist/javascript/templating/engine.d.ts +34 -8
- package/dist/javascript/templating/engine.d.ts.map +1 -1
- package/dist/javascript/templating/engine.js +317 -60
- package/dist/javascript/templating/engine.js.map +1 -1
- package/dist/javascript/templating/pattern.d.ts +11 -0
- package/dist/javascript/templating/pattern.d.ts.map +1 -1
- package/dist/javascript/templating/pattern.js +36 -295
- package/dist/javascript/templating/pattern.js.map +1 -1
- package/dist/javascript/templating/placeholder-replacement.d.ts +1 -1
- package/dist/javascript/templating/placeholder-replacement.d.ts.map +1 -1
- package/dist/javascript/templating/template.d.ts +9 -2
- package/dist/javascript/templating/template.d.ts.map +1 -1
- package/dist/javascript/templating/template.js +37 -0
- package/dist/javascript/templating/template.js.map +1 -1
- package/dist/javascript/templating/types.d.ts +26 -11
- package/dist/javascript/templating/types.d.ts.map +1 -1
- package/dist/javascript/templating/utils.d.ts +41 -22
- package/dist/javascript/templating/utils.d.ts.map +1 -1
- package/dist/javascript/templating/utils.js +111 -76
- package/dist/javascript/templating/utils.js.map +1 -1
- package/dist/version.txt +1 -1
- package/package.json +3 -1
- package/src/java/tree.ts +2 -0
- package/src/javascript/assertions.ts +1 -1
- package/src/javascript/format.ts +1 -1
- package/src/javascript/templating/engine.ts +376 -54
- package/src/javascript/templating/pattern.ts +55 -322
- package/src/javascript/templating/placeholder-replacement.ts +1 -1
- package/src/javascript/templating/template.ts +57 -3
- package/src/javascript/templating/types.ts +27 -11
- package/src/javascript/templating/utils.ts +113 -81
|
@@ -13,15 +13,12 @@
|
|
|
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} from '../..';
|
|
18
17
|
import {J} from '../../java';
|
|
19
18
|
import {JS} from '../index';
|
|
20
|
-
import {JavaScriptParser} from '../parser';
|
|
21
|
-
import {DependencyWorkspace} from '../dependency-workspace';
|
|
22
19
|
import {Marker, Markers} from '../../markers';
|
|
23
20
|
import {randomId} from '../../uuid';
|
|
24
|
-
import {VariadicOptions
|
|
21
|
+
import {VariadicOptions} from './types';
|
|
25
22
|
|
|
26
23
|
/**
|
|
27
24
|
* Internal storage value type for pattern match captures.
|
|
@@ -38,102 +35,85 @@ export type CaptureStorageValue = J | J.RightPadded<J> | J[] | J.RightPadded<J>[
|
|
|
38
35
|
export const WRAPPERS_MAP_SYMBOL = Symbol('wrappersMap');
|
|
39
36
|
|
|
40
37
|
/**
|
|
41
|
-
*
|
|
38
|
+
* Shared wrapper function name used by both patterns and templates.
|
|
39
|
+
* Using the same name allows cache sharing when pattern and template code is identical.
|
|
42
40
|
*/
|
|
43
|
-
|
|
41
|
+
export const WRAPPER_FUNCTION_NAME = '__WRAPPER__';
|
|
44
42
|
|
|
45
43
|
/**
|
|
46
|
-
*
|
|
44
|
+
* Simple LRU (Least Recently Used) cache implementation using Map's insertion order.
|
|
45
|
+
* JavaScript Map maintains insertion order, so the first entry is the oldest.
|
|
47
46
|
*
|
|
48
|
-
*
|
|
47
|
+
* Used by both Pattern and Template caching to provide bounded memory usage.
|
|
49
48
|
*/
|
|
50
|
-
export
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Cache for compiled templates and patterns.
|
|
56
|
-
* Stores parsed ASTs to avoid expensive re-parsing and dependency resolution.
|
|
57
|
-
*/
|
|
58
|
-
export class TemplateCache {
|
|
59
|
-
private cache = new Map<string, JS.CompilationUnit>();
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Generates a cache key from template string, captures, and options.
|
|
63
|
-
*/
|
|
64
|
-
private generateKey(
|
|
65
|
-
templateString: string,
|
|
66
|
-
captures: (Capture | Any<any>)[],
|
|
67
|
-
contextStatements: string[],
|
|
68
|
-
dependencies: Record<string, string>
|
|
69
|
-
): string {
|
|
70
|
-
// Use the actual template string (with placeholders) as the primary key
|
|
71
|
-
const templateKey = templateString;
|
|
72
|
-
|
|
73
|
-
// Capture names
|
|
74
|
-
const capturesKey = captures.map(c => c.getName()).join(',');
|
|
49
|
+
export class LRUCache<K, V> {
|
|
50
|
+
private cache = new Map<K, V>();
|
|
75
51
|
|
|
76
|
-
|
|
77
|
-
const contextKey = contextStatements.join(';');
|
|
52
|
+
constructor(private maxSize: number) {}
|
|
78
53
|
|
|
79
|
-
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
54
|
+
get(key: K): V | undefined {
|
|
55
|
+
const value = this.cache.get(key);
|
|
56
|
+
if (value !== undefined) {
|
|
57
|
+
// Move to end (most recently used)
|
|
58
|
+
this.cache.delete(key);
|
|
59
|
+
this.cache.set(key, value);
|
|
60
|
+
}
|
|
61
|
+
return value;
|
|
83
62
|
}
|
|
84
63
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
async getOrParse(
|
|
89
|
-
templateString: string,
|
|
90
|
-
captures: (Capture | Any)[],
|
|
91
|
-
contextStatements: string[],
|
|
92
|
-
dependencies: Record<string, string>
|
|
93
|
-
): Promise<JS.CompilationUnit> {
|
|
94
|
-
const key = this.generateKey(templateString, captures, contextStatements, dependencies);
|
|
64
|
+
set(key: K, value: V): void {
|
|
65
|
+
// Remove if exists (to update position)
|
|
66
|
+
this.cache.delete(key);
|
|
95
67
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
return cu;
|
|
99
|
-
}
|
|
68
|
+
// Add to end
|
|
69
|
+
this.cache.set(key, value);
|
|
100
70
|
|
|
101
|
-
//
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
71
|
+
// Evict oldest if over capacity
|
|
72
|
+
if (this.cache.size > this.maxSize) {
|
|
73
|
+
const iterator = this.cache.keys();
|
|
74
|
+
const firstEntry = iterator.next();
|
|
75
|
+
if (!firstEntry.done) {
|
|
76
|
+
this.cache.delete(firstEntry.value);
|
|
77
|
+
}
|
|
107
78
|
}
|
|
108
|
-
|
|
109
|
-
// Prepend context statements for type attribution context
|
|
110
|
-
const fullTemplateString = contextStatements.length > 0
|
|
111
|
-
? contextStatements.join('\n') + '\n' + templateString
|
|
112
|
-
: templateString;
|
|
113
|
-
|
|
114
|
-
// Parse and cache (workspace only needed during parsing)
|
|
115
|
-
// Use templateSourceFileCache if configured for ~3.2x speedup on dependency file parsing
|
|
116
|
-
const parser = new JavaScriptParser({
|
|
117
|
-
relativeTo: workspaceDir,
|
|
118
|
-
sourceFileCache: templateSourceFileCache
|
|
119
|
-
});
|
|
120
|
-
const parseGenerator = parser.parse({text: fullTemplateString, sourcePath: 'template.ts'});
|
|
121
|
-
cu = (await parseGenerator.next()).value as JS.CompilationUnit;
|
|
122
|
-
|
|
123
|
-
this.cache.set(key, cu);
|
|
124
|
-
return cu;
|
|
125
79
|
}
|
|
126
80
|
|
|
127
|
-
/**
|
|
128
|
-
* Clears the cache.
|
|
129
|
-
*/
|
|
130
81
|
clear(): void {
|
|
131
82
|
this.cache.clear();
|
|
132
83
|
}
|
|
133
84
|
}
|
|
134
85
|
|
|
135
|
-
|
|
136
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Shared global LRU cache for both pattern and template ASTs.
|
|
88
|
+
* When pattern and template code is identical, they share the same cached AST.
|
|
89
|
+
* This mirrors JavaTemplate's unified approach in the Java implementation.
|
|
90
|
+
* Bounded to 100 entries using LRU eviction.
|
|
91
|
+
*/
|
|
92
|
+
export const globalAstCache = new LRUCache<string, J>(100);
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Generates a cache key for template/pattern processing.
|
|
96
|
+
* Used by both Pattern and Template for consistent cache key generation.
|
|
97
|
+
*
|
|
98
|
+
* @param templateParts The template string parts
|
|
99
|
+
* @param itemsKey String representing the captures/parameters (comma-separated)
|
|
100
|
+
* @param contextStatements Context declarations
|
|
101
|
+
* @param dependencies NPM dependencies
|
|
102
|
+
* @returns A cache key string
|
|
103
|
+
*/
|
|
104
|
+
export function generateCacheKey(
|
|
105
|
+
templateParts: string[] | TemplateStringsArray,
|
|
106
|
+
itemsKey: string,
|
|
107
|
+
contextStatements: string[],
|
|
108
|
+
dependencies: Record<string, string>
|
|
109
|
+
): string {
|
|
110
|
+
return [
|
|
111
|
+
Array.from(templateParts).join('|'),
|
|
112
|
+
itemsKey,
|
|
113
|
+
contextStatements.join(';'),
|
|
114
|
+
JSON.stringify(dependencies || {})
|
|
115
|
+
].join('::');
|
|
116
|
+
}
|
|
137
117
|
|
|
138
118
|
/**
|
|
139
119
|
* Marker that stores capture metadata on pattern AST nodes.
|
|
@@ -262,4 +242,56 @@ export class PlaceholderUtils {
|
|
|
262
242
|
}
|
|
263
243
|
return undefined;
|
|
264
244
|
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Extracts the relevant AST node from a wrapper function.
|
|
248
|
+
* Used by both pattern and template processors to intelligently extract
|
|
249
|
+
* code from `function __WRAPPER__() { code }` wrappers.
|
|
250
|
+
*
|
|
251
|
+
* @param lastStatement The last statement from the compilation unit
|
|
252
|
+
* @param contextName Context name for error messages (e.g., 'Pattern', 'Template')
|
|
253
|
+
* @returns The extracted AST node
|
|
254
|
+
*/
|
|
255
|
+
static extractFromWrapper(lastStatement: J, contextName: string): J {
|
|
256
|
+
let extracted: J;
|
|
257
|
+
|
|
258
|
+
// Since we always wrap in function __WRAPPER__() { code }, look for it
|
|
259
|
+
if (lastStatement.kind === J.Kind.MethodDeclaration) {
|
|
260
|
+
const method = lastStatement as J.MethodDeclaration;
|
|
261
|
+
if (method.name?.simpleName === WRAPPER_FUNCTION_NAME && method.body) {
|
|
262
|
+
const body = method.body;
|
|
263
|
+
|
|
264
|
+
// Intelligently extract based on what's in the function body
|
|
265
|
+
if (body.statements.length === 0) {
|
|
266
|
+
throw new Error(`${contextName} function body is empty`);
|
|
267
|
+
} else if (body.statements.length === 1) {
|
|
268
|
+
const stmt = body.statements[0].element;
|
|
269
|
+
|
|
270
|
+
// Single expression statement → extract the expression
|
|
271
|
+
if (stmt.kind === JS.Kind.ExpressionStatement) {
|
|
272
|
+
extracted = (stmt as JS.ExpressionStatement).expression;
|
|
273
|
+
}
|
|
274
|
+
// Single block statement → keep the block
|
|
275
|
+
else if (stmt.kind === J.Kind.Block) {
|
|
276
|
+
extracted = stmt;
|
|
277
|
+
}
|
|
278
|
+
// Other single statement → keep it
|
|
279
|
+
else {
|
|
280
|
+
extracted = stmt;
|
|
281
|
+
}
|
|
282
|
+
} else {
|
|
283
|
+
// Multiple statements → keep the block
|
|
284
|
+
extracted = body;
|
|
285
|
+
}
|
|
286
|
+
} else {
|
|
287
|
+
// Not our wrapper function
|
|
288
|
+
extracted = lastStatement;
|
|
289
|
+
}
|
|
290
|
+
} else {
|
|
291
|
+
// Shouldn't happen with our wrapping strategy, but handle it
|
|
292
|
+
extracted = lastStatement;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return extracted;
|
|
296
|
+
}
|
|
265
297
|
}
|