@openrewrite/rewrite 8.67.0-20251104-084009 → 8.67.0-20251104-114312

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.
Files changed (71) hide show
  1. package/dist/javascript/comparator.d.ts +67 -4
  2. package/dist/javascript/comparator.d.ts.map +1 -1
  3. package/dist/javascript/comparator.js +523 -2794
  4. package/dist/javascript/comparator.js.map +1 -1
  5. package/dist/javascript/format.d.ts.map +1 -1
  6. package/dist/javascript/format.js +3 -2
  7. package/dist/javascript/format.js.map +1 -1
  8. package/dist/javascript/index.d.ts +1 -1
  9. package/dist/javascript/index.d.ts.map +1 -1
  10. package/dist/javascript/index.js +1 -1
  11. package/dist/javascript/index.js.map +1 -1
  12. package/dist/javascript/templating/capture.d.ts +226 -0
  13. package/dist/javascript/templating/capture.d.ts.map +1 -0
  14. package/dist/javascript/templating/capture.js +371 -0
  15. package/dist/javascript/templating/capture.js.map +1 -0
  16. package/dist/javascript/templating/comparator.d.ts +61 -0
  17. package/dist/javascript/templating/comparator.d.ts.map +1 -0
  18. package/dist/javascript/templating/comparator.js +393 -0
  19. package/dist/javascript/templating/comparator.js.map +1 -0
  20. package/dist/javascript/templating/engine.d.ts +75 -0
  21. package/dist/javascript/templating/engine.d.ts.map +1 -0
  22. package/dist/javascript/templating/engine.js +228 -0
  23. package/dist/javascript/templating/engine.js.map +1 -0
  24. package/dist/javascript/templating/index.d.ts +6 -0
  25. package/dist/javascript/templating/index.d.ts.map +1 -0
  26. package/dist/javascript/templating/index.js +42 -0
  27. package/dist/javascript/templating/index.js.map +1 -0
  28. package/dist/javascript/templating/pattern.d.ts +171 -0
  29. package/dist/javascript/templating/pattern.d.ts.map +1 -0
  30. package/dist/javascript/templating/pattern.js +681 -0
  31. package/dist/javascript/templating/pattern.js.map +1 -0
  32. package/dist/javascript/templating/placeholder-replacement.d.ts +58 -0
  33. package/dist/javascript/templating/placeholder-replacement.d.ts.map +1 -0
  34. package/dist/javascript/templating/placeholder-replacement.js +365 -0
  35. package/dist/javascript/templating/placeholder-replacement.js.map +1 -0
  36. package/dist/javascript/templating/rewrite.d.ts +39 -0
  37. package/dist/javascript/templating/rewrite.d.ts.map +1 -0
  38. package/dist/javascript/templating/rewrite.js +81 -0
  39. package/dist/javascript/templating/rewrite.js.map +1 -0
  40. package/dist/javascript/templating/template.d.ts +204 -0
  41. package/dist/javascript/templating/template.d.ts.map +1 -0
  42. package/dist/javascript/templating/template.js +293 -0
  43. package/dist/javascript/templating/template.js.map +1 -0
  44. package/dist/javascript/templating/types.d.ts +263 -0
  45. package/dist/javascript/templating/types.d.ts.map +1 -0
  46. package/dist/javascript/templating/types.js +3 -0
  47. package/dist/javascript/templating/types.js.map +1 -0
  48. package/dist/javascript/templating/utils.d.ts +118 -0
  49. package/dist/javascript/templating/utils.d.ts.map +1 -0
  50. package/dist/javascript/templating/utils.js +253 -0
  51. package/dist/javascript/templating/utils.js.map +1 -0
  52. package/dist/version.txt +1 -1
  53. package/package.json +2 -1
  54. package/src/javascript/comparator.ts +554 -3323
  55. package/src/javascript/format.ts +2 -1
  56. package/src/javascript/index.ts +1 -1
  57. package/src/javascript/templating/capture.ts +503 -0
  58. package/src/javascript/templating/comparator.ts +430 -0
  59. package/src/javascript/templating/engine.ts +252 -0
  60. package/src/javascript/templating/index.ts +60 -0
  61. package/src/javascript/templating/pattern.ts +727 -0
  62. package/src/javascript/templating/placeholder-replacement.ts +372 -0
  63. package/src/javascript/templating/rewrite.ts +95 -0
  64. package/src/javascript/templating/template.ts +326 -0
  65. package/src/javascript/templating/types.ts +300 -0
  66. package/src/javascript/templating/utils.ts +284 -0
  67. package/dist/javascript/templating.d.ts +0 -265
  68. package/dist/javascript/templating.d.ts.map +0 -1
  69. package/dist/javascript/templating.js +0 -1027
  70. package/dist/javascript/templating.js.map +0 -1
  71. package/src/javascript/templating.ts +0 -1226
@@ -0,0 +1,326 @@
1
+ /*
2
+ * Copyright 2025 the original author or authors.
3
+ * <p>
4
+ * Licensed under the Moderne Source Available License (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * <p>
8
+ * https://docs.moderne.io/licensing/moderne-source-available-license
9
+ * <p>
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import {Cursor, Tree} from '../..';
17
+ import {J} from '../../java';
18
+ import {TemplateOptions, TemplateParameter, Capture} from './types';
19
+ import {MatchResult} from './pattern';
20
+ import {WRAPPERS_MAP_SYMBOL} from './utils';
21
+ import {CAPTURE_NAME_SYMBOL} from './capture';
22
+ import {TemplateEngine, Parameter} from './engine';
23
+
24
+ /**
25
+ * Coordinates for template application.
26
+ */
27
+ type JavaCoordinates = {
28
+ tree?: Tree;
29
+ loc?: JavaCoordinates.Location;
30
+ mode?: JavaCoordinates.Mode;
31
+ };
32
+
33
+ namespace JavaCoordinates {
34
+ // FIXME need to come up with the equivalent of `Space.Location` support
35
+ export type Location = 'EXPRESSION_PREFIX' | 'STATEMENT_PREFIX' | 'BLOCK_END';
36
+
37
+ export enum Mode {
38
+ Before,
39
+ After,
40
+ Replace,
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Builder for creating templates programmatically.
46
+ * Use when template structure is not known at compile time.
47
+ *
48
+ * @example
49
+ * // Conditional construction
50
+ * const builder = Template.builder().code('function foo(x) {');
51
+ * if (needsValidation) {
52
+ * builder.code('if (typeof x !== "number") throw new Error("Invalid");');
53
+ * }
54
+ * builder.code('return x * 2; }');
55
+ * const tmpl = builder.build();
56
+ *
57
+ * @example
58
+ * // Composition from fragments
59
+ * function createWrapper(innerBody: Capture): Template {
60
+ * return Template.builder()
61
+ * .code('function wrapper() { try { ')
62
+ * .param(innerBody)
63
+ * .code(' } catch(e) { console.error(e); } }')
64
+ * .build();
65
+ * }
66
+ */
67
+ export class TemplateBuilder {
68
+ private parts: string[] = [];
69
+ private params: TemplateParameter[] = [];
70
+
71
+ /**
72
+ * Adds a static string part to the template.
73
+ *
74
+ * @param str The string to add
75
+ * @returns This builder for chaining
76
+ */
77
+ code(str: string): this {
78
+ // If there are already params, we need to add an empty string before this
79
+ if (this.params.length > this.parts.length) {
80
+ this.parts.push('');
81
+ }
82
+ // Append to the last part or start a new one
83
+ if (this.parts.length === 0) {
84
+ this.parts.push(str);
85
+ } else {
86
+ this.parts[this.parts.length - 1] += str;
87
+ }
88
+ return this;
89
+ }
90
+
91
+ /**
92
+ * Adds a parameter to the template.
93
+ *
94
+ * @param value The parameter value (Capture, Tree, or primitive)
95
+ * @returns This builder for chaining
96
+ */
97
+ param(value: TemplateParameter): this {
98
+ // Ensure we have a part for after this parameter
99
+ if (this.parts.length === 0) {
100
+ this.parts.push('');
101
+ }
102
+ this.params.push(value);
103
+ // Add an empty string for the next part
104
+ this.parts.push('');
105
+ return this;
106
+ }
107
+
108
+ /**
109
+ * Builds the template from accumulated parts and parameters.
110
+ *
111
+ * @returns A Template instance
112
+ */
113
+ build(): Template {
114
+ // Ensure parts array is one longer than params array
115
+ while (this.parts.length <= this.params.length) {
116
+ this.parts.push('');
117
+ }
118
+
119
+ // Create a synthetic TemplateStringsArray
120
+ const templateStrings = this.parts.slice() as any;
121
+ templateStrings.raw = this.parts.slice();
122
+ Object.defineProperty(templateStrings, 'raw', {
123
+ value: this.parts.slice(),
124
+ writable: false
125
+ });
126
+
127
+ // Delegate to the template() function
128
+ return template(templateStrings, ...this.params);
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Template for creating AST nodes.
134
+ *
135
+ * This class provides the public API for template generation.
136
+ * The actual templating logic is handled by the internal TemplateEngine.
137
+ *
138
+ * Templates can reference captures from patterns, and you can access properties
139
+ * of captured nodes using dot notation. This allows you to extract and insert
140
+ * specific subtrees from matched AST nodes.
141
+ *
142
+ * @example
143
+ * // Generate a literal AST node
144
+ * const result = template`2`.apply(cursor, coordinates);
145
+ *
146
+ * @example
147
+ * // Generate an AST node with a parameter
148
+ * const result = template`${capture()}`.apply(cursor, coordinates);
149
+ *
150
+ * @example
151
+ * // Access properties of captured nodes in templates
152
+ * const method = capture<J.MethodInvocation>('method');
153
+ * const pat = pattern`foo(${method})`;
154
+ * const tmpl = template`bar(${method.name})`; // Access the 'name' property
155
+ *
156
+ * const match = await pat.match(someNode);
157
+ * if (match) {
158
+ * // The template will insert just the 'name' subtree from the captured method
159
+ * const result = await tmpl.apply(cursor, someNode, match);
160
+ * }
161
+ *
162
+ * @example
163
+ * // Deep property access chains
164
+ * const method = capture<J.MethodInvocation>('method');
165
+ * template`console.log(${method.name.simpleName})` // Navigate multiple properties
166
+ *
167
+ * @example
168
+ * // Array element access
169
+ * const invocation = capture<J.MethodInvocation>('invocation');
170
+ * template`bar(${invocation.arguments.elements[0].element})` // Access array elements
171
+ */
172
+ export class Template {
173
+ private options: TemplateOptions = {};
174
+
175
+ /**
176
+ * Creates a new builder for constructing templates programmatically.
177
+ *
178
+ * @returns A new TemplateBuilder instance
179
+ *
180
+ * @example
181
+ * const tmpl = Template.builder()
182
+ * .code('function foo() {')
183
+ * .code('return ')
184
+ * .param(capture('value'))
185
+ * .code('; }')
186
+ * .build();
187
+ */
188
+ static builder(): TemplateBuilder {
189
+ return new TemplateBuilder();
190
+ }
191
+
192
+ /**
193
+ * Creates a new template.
194
+ *
195
+ * @param templateParts The string parts of the template
196
+ * @param parameters The parameters between the string parts
197
+ */
198
+ constructor(
199
+ private readonly templateParts: TemplateStringsArray,
200
+ private readonly parameters: Parameter[]
201
+ ) {
202
+ }
203
+
204
+ /**
205
+ * Configures this template with additional options.
206
+ *
207
+ * @param options Configuration options
208
+ * @returns This template for method chaining
209
+ *
210
+ * @example
211
+ * template`isDate(${capture('date')})`
212
+ * .configure({
213
+ * imports: ['import { isDate } from "util"'],
214
+ * dependencies: { 'util': '^1.0.0' }
215
+ * })
216
+ */
217
+ configure(options: TemplateOptions): Template {
218
+ this.options = { ...this.options, ...options };
219
+ return this;
220
+ }
221
+
222
+ /**
223
+ * Applies this template and returns the resulting tree.
224
+ *
225
+ * @param cursor The cursor pointing to the current location in the AST
226
+ * @param tree Input tree
227
+ * @param values values for parameters in template
228
+ * @returns A Promise resolving to the generated AST node
229
+ */
230
+ async apply(cursor: Cursor, tree: J, values?: Map<Capture | string, J> | Pick<Map<string, J>, 'get'>): Promise<J | undefined> {
231
+ // Normalize the values map: convert any Capture keys to string keys
232
+ let normalizedValues: Pick<Map<string, J>, 'get'> | undefined;
233
+ let wrappersMap: Map<string, J.RightPadded<J> | J.RightPadded<J>[]> = new Map();
234
+
235
+ if (values instanceof Map) {
236
+ const normalized = new Map<string, J>();
237
+ for (const [key, value] of values.entries()) {
238
+ const stringKey = typeof key === 'string'
239
+ ? key
240
+ : ((key as any)[CAPTURE_NAME_SYMBOL] || key.getName());
241
+ normalized.set(stringKey, value);
242
+ }
243
+ normalizedValues = normalized;
244
+ } else if (values instanceof MatchResult) {
245
+ // MatchResult - extract both bindings and wrappersMap
246
+ normalizedValues = values;
247
+ wrappersMap = (values as any)[WRAPPERS_MAP_SYMBOL]();
248
+ } else {
249
+ // Other Pick<Map> implementation
250
+ normalizedValues = values;
251
+ }
252
+
253
+ // Prefer 'context' over deprecated 'imports'
254
+ const contextStatements = this.options.context || this.options.imports || [];
255
+ return TemplateEngine.applyTemplate(
256
+ this.templateParts,
257
+ this.parameters,
258
+ cursor,
259
+ {
260
+ tree,
261
+ mode: JavaCoordinates.Mode.Replace
262
+ },
263
+ normalizedValues,
264
+ wrappersMap,
265
+ contextStatements,
266
+ this.options.dependencies || {}
267
+ );
268
+ }
269
+ }
270
+
271
+ /**
272
+ * Tagged template function for creating templates that generate AST nodes.
273
+ *
274
+ * Templates support property access on captures from patterns, allowing you to
275
+ * extract and insert specific subtrees from matched AST nodes. Use dot notation
276
+ * to navigate properties (e.g., `method.name`) or array bracket notation to
277
+ * access array elements (e.g., `args.elements[0].element`).
278
+ *
279
+ * @param strings The string parts of the template
280
+ * @param parameters The parameters between the string parts (Capture, Tree, or primitives)
281
+ * @returns A Template object that can be applied to generate AST nodes
282
+ *
283
+ * @example
284
+ * // Simple template with literal
285
+ * const tmpl = template`console.log("hello")`;
286
+ * const result = await tmpl.apply(cursor, node);
287
+ *
288
+ * @example
289
+ * // Template with capture - matches captured value from pattern
290
+ * const expr = capture('expr');
291
+ * const pat = pattern`foo(${expr})`;
292
+ * const tmpl = template`bar(${expr})`;
293
+ *
294
+ * const match = await pat.match(node);
295
+ * if (match) {
296
+ * const result = await tmpl.apply(cursor, node, match);
297
+ * }
298
+ *
299
+ * @example
300
+ * // Property access on captures - extract subtrees
301
+ * const method = capture<J.MethodInvocation>('method');
302
+ * const pat = pattern`foo(${method})`;
303
+ * // Access the 'name' property of the captured method invocation
304
+ * const tmpl = template`bar(${method.name})`;
305
+ *
306
+ * @example
307
+ * // Deep property chains
308
+ * const method = capture<J.MethodInvocation>('method');
309
+ * template`console.log(${method.name.simpleName})`
310
+ *
311
+ * @example
312
+ * // Array element access
313
+ * const invocation = capture<J.MethodInvocation>('invocation');
314
+ * template`bar(${invocation.arguments.elements[0].element})`
315
+ */
316
+ export function template(strings: TemplateStringsArray, ...parameters: TemplateParameter[]): Template {
317
+ // Convert parameters to Parameter objects (no longer need to check for mutable tree property)
318
+ const processedParameters = parameters.map(param => {
319
+ // Just wrap each parameter value in a Parameter object
320
+ return {value: param};
321
+ });
322
+
323
+ return new Template(strings, processedParameters);
324
+ }
325
+
326
+ export type {JavaCoordinates};
@@ -0,0 +1,300 @@
1
+ /*
2
+ * Copyright 2025 the original author or authors.
3
+ * <p>
4
+ * Licensed under the Moderne Source Available License (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * <p>
8
+ * https://docs.moderne.io/licensing/moderne-source-available-license
9
+ * <p>
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import {Cursor, Tree} from '../..';
17
+ import {J} from '../../java';
18
+
19
+ /**
20
+ * Options for variadic captures that match zero or more nodes in a sequence.
21
+ */
22
+ export interface VariadicOptions {
23
+ /**
24
+ * Minimum number of nodes that must be matched (default: 0).
25
+ */
26
+ min?: number;
27
+
28
+ /**
29
+ * Maximum number of nodes that can be matched (default: unlimited).
30
+ */
31
+ max?: number;
32
+ }
33
+
34
+ /**
35
+ * Options for the capture function.
36
+ *
37
+ * The constraint function receives different parameter types depending on whether
38
+ * the capture is variadic:
39
+ * - For regular captures: constraint receives a single node of type T
40
+ * - For variadic captures: constraint receives an array of nodes of type T[]
41
+ */
42
+ export interface CaptureOptions<T = any> {
43
+ name?: string;
44
+ variadic?: boolean | VariadicOptions;
45
+ constraint?: (node: T) => boolean;
46
+ }
47
+
48
+ /**
49
+ * Capture specification for pattern matching.
50
+ * Represents a placeholder in a template pattern that can capture a part of the AST.
51
+ *
52
+ * @template T The expected type of the captured AST node (for TypeScript autocomplete)
53
+ *
54
+ * @remarks
55
+ * **Important: Type Parameter is for IDE Support Only**
56
+ *
57
+ * The generic type parameter `<T>` provides IDE autocomplete and type checking in your code,
58
+ * but does NOT enforce any runtime constraints on what the capture will match.
59
+ *
60
+ * **Pattern Matching Behavior:**
61
+ * - A bare `pattern`${capture('x')}`` will structurally match ANY expression
62
+ * - Pattern structure determines matching: `pattern`foo(${capture('x')})`` only matches `foo()` calls
63
+ * - Use structural patterns to narrow matching scope before applying semantic validation
64
+ *
65
+ * **Variadic Captures:**
66
+ * Use `{ variadic: true }` to match zero or more nodes in a sequence:
67
+ * ```typescript
68
+ * const args = capture('args', { variadic: true });
69
+ * pattern`foo(${args})` // Matches: foo(), foo(a), foo(a, b, c)
70
+ * ```
71
+ */
72
+ export interface Capture<T = any> {
73
+ /**
74
+ * Gets the string name of this capture.
75
+ */
76
+ getName(): string;
77
+
78
+ /**
79
+ * Returns true if this is a variadic capture (matching zero or more nodes).
80
+ */
81
+ isVariadic(): boolean;
82
+
83
+ /**
84
+ * Returns the variadic options if this is a variadic capture, undefined otherwise.
85
+ */
86
+ getVariadicOptions(): VariadicOptions | undefined;
87
+
88
+ /**
89
+ * Gets the constraint function if this capture has one.
90
+ * For regular captures (T = Expression), constraint receives a single node.
91
+ * For variadic captures (T = Expression[]), constraint receives an array of nodes.
92
+ */
93
+ getConstraint?(): ((node: T) => boolean) | undefined;
94
+ }
95
+
96
+ /**
97
+ * Non-capturing pattern match specification.
98
+ * Represents a placeholder in a pattern that matches AST nodes without binding them to a name.
99
+ *
100
+ * Use `any()` when you need to match structure without caring about the specific values.
101
+ * The key difference from `Capture` is that `Any` cannot be used in templates - the TypeScript
102
+ * type system prevents this at compile time.
103
+ *
104
+ * @template T The expected type of the matched AST node (for TypeScript autocomplete and constraints)
105
+ *
106
+ * @remarks
107
+ * **Why Any<T> is Separate from Capture<T>:**
108
+ *
109
+ * Using a separate type provides compile-time safety:
110
+ * - `pattern`foo(${any()})`` - ✅ OK in patterns
111
+ * - `template`bar(${any()})`` - ❌ TypeScript error (Any<T> not assignable to template parameters)
112
+ *
113
+ * This prevents logical errors where you try to use a non-capturing match in a template.
114
+ *
115
+ * **Semantic Parallel with TypeScript's `any`:**
116
+ *
117
+ * Just as TypeScript's `any` type means "be permissive about types here",
118
+ * pattern matching's `any()` means "be permissive about values here":
119
+ * - TypeScript `any`: Accept any type, don't check it
120
+ * - Pattern `any()`: Match any value, don't bind it
121
+ *
122
+ * @example
123
+ * // Match without capturing
124
+ * const pat = pattern`foo(${any()})`
125
+ *
126
+ * @example
127
+ * // Variadic any - match zero or more without capturing
128
+ * const rest = any({ variadic: true });
129
+ * const pat = pattern`bar(${capture('first')}, ${rest})`
130
+ *
131
+ * @example
132
+ * // With constraints - validate but don't capture
133
+ * const numericArg = any<J.Literal>({
134
+ * constraint: (node) => typeof node.value === 'number'
135
+ * });
136
+ * const pat = pattern`process(${numericArg})`
137
+ */
138
+ export interface Any<T = any> {
139
+ /**
140
+ * Gets the internal identifier for this any pattern.
141
+ */
142
+ getName(): string;
143
+
144
+ /**
145
+ * Returns true if this is a variadic any (matching zero or more nodes).
146
+ */
147
+ isVariadic(): boolean;
148
+
149
+ /**
150
+ * Returns the variadic options if this is a variadic any, undefined otherwise.
151
+ */
152
+ getVariadicOptions(): VariadicOptions | undefined;
153
+
154
+ /**
155
+ * Gets the constraint function if this any pattern has one.
156
+ * For regular any (T = Expression), constraint receives a single node.
157
+ * For variadic any (T = Expression[]), constraint receives an array of nodes.
158
+ */
159
+ getConstraint?(): ((node: T) => boolean) | undefined;
160
+ }
161
+
162
+ /**
163
+ * Template parameter specification for template-only parameter substitution.
164
+ * Unlike Capture, TemplateParam does not support property access and is simpler.
165
+ *
166
+ * @template T The expected type of the parameter value (for TypeScript autocomplete only)
167
+ */
168
+ export interface TemplateParam<T = any> {
169
+ /**
170
+ * The name of the parameter, used to look up the value in the values map.
171
+ */
172
+ readonly name: string;
173
+
174
+ /**
175
+ * Gets the string name of this parameter.
176
+ */
177
+ getName(): string;
178
+ }
179
+
180
+ /**
181
+ * Configuration options for patterns.
182
+ */
183
+ export interface PatternOptions {
184
+ /**
185
+ * Declarations to provide type attribution context for the pattern.
186
+ * These can include import statements, type declarations, function declarations, or any
187
+ * other declarations needed for proper type information. They are prepended to the pattern
188
+ * when parsing to ensure proper type attribution.
189
+ *
190
+ * @example
191
+ * ```typescript
192
+ * pattern`forwardRef(${capture('comp')})`
193
+ * .configure({
194
+ * context: [
195
+ * `import { forwardRef } from 'react'`,
196
+ * `type MyType = { value: number }`
197
+ * ]
198
+ * })
199
+ * ```
200
+ */
201
+ context?: string[];
202
+
203
+ /**
204
+ * @deprecated Use `context` instead. This alias will be removed in a future version.
205
+ *
206
+ * Import statements to provide type attribution context.
207
+ * These are prepended to the pattern when parsing to ensure proper type information.
208
+ */
209
+ imports?: string[];
210
+
211
+ /**
212
+ * NPM dependencies required for import resolution and type attribution.
213
+ * Maps package names to version specifiers (e.g., { 'util': '^1.0.0' }).
214
+ * The template engine will create a package.json with these dependencies.
215
+ */
216
+ dependencies?: Record<string, string>;
217
+
218
+ /**
219
+ * When true, allows patterns without type annotations to match code with type annotations.
220
+ * This enables more flexible pattern matching during development or when full type attribution
221
+ * is not needed. When false, enforces strict type matching where both pattern and target must
222
+ * have matching type annotations.
223
+ *
224
+ * @default true (lenient matching enabled for backward compatibility)
225
+ */
226
+ lenientTypeMatching?: boolean;
227
+ }
228
+
229
+ /**
230
+ * Valid parameter types for template literals.
231
+ * - Capture: For pattern matching and reuse
232
+ * - CaptureValue: Result of property access or array operations on captures (e.g., capture.prop, capture[0], capture.slice(1))
233
+ * - Tree: AST nodes to be inserted directly
234
+ * - Tree[]: Arrays of AST nodes (from variadic capture operations like slice)
235
+ * - Primitives: Values to be converted to literals
236
+ */
237
+ export type TemplateParameter = Capture | any | TemplateParam | Tree | Tree[] | string | number | boolean;
238
+
239
+ /**
240
+ * Configuration options for templates.
241
+ */
242
+ export interface TemplateOptions {
243
+ /**
244
+ * Declarations to provide type attribution context for the template.
245
+ * These can include import statements, type declarations, function declarations, or any
246
+ * other declarations needed for proper type information. They are prepended to the template
247
+ * when parsing to ensure proper type attribution.
248
+ *
249
+ * @example
250
+ * ```typescript
251
+ * template`console.log(${capture('value')})`
252
+ * .configure({
253
+ * context: [
254
+ * `type MyType = { value: number }`,
255
+ * `const console = { log: (x: any) => void 0 }`
256
+ * ]
257
+ * })
258
+ * ```
259
+ */
260
+ context?: string[];
261
+
262
+ /**
263
+ * @deprecated Use `context` instead. This alias will be removed in a future version.
264
+ *
265
+ * Import statements to provide type attribution context.
266
+ * These are prepended to the template when parsing to ensure proper type information.
267
+ */
268
+ imports?: string[];
269
+
270
+ /**
271
+ * NPM dependencies required for import resolution and type attribution.
272
+ * Maps package names to version specifiers (e.g., { 'util': '^1.0.0' }).
273
+ * The template engine will create a package.json with these dependencies.
274
+ */
275
+ dependencies?: Record<string, string>;
276
+ }
277
+
278
+ /**
279
+ * Represents a replacement rule that can match a pattern and apply a template.
280
+ */
281
+ export interface RewriteRule {
282
+ /**
283
+ * Attempts to apply this rewrite rule to the given AST node.
284
+ *
285
+ * @param cursor The cursor context at the current position in the AST
286
+ * @param node The AST node to try matching and transforming
287
+ * @returns The transformed node if a pattern matched, or `undefined` if no pattern matched.
288
+ * When using in a visitor, always use the `|| node` pattern to return the original
289
+ * node when there's no match: `return await rule.tryOn(this.cursor, node) || node;`
290
+ */
291
+ tryOn(cursor: Cursor, node: J): Promise<J | undefined>;
292
+ }
293
+
294
+ /**
295
+ * Configuration for a replacement rule.
296
+ */
297
+ export interface RewriteConfig {
298
+ before: any; // Pattern | Pattern[], but we'll import Pattern in rewrite.ts
299
+ after: any; // Template, but we'll import Template in rewrite.ts
300
+ }