@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,681 @@
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.MatchResult = exports.Pattern = exports.PatternBuilder = void 0;
13
+ exports.pattern = pattern;
14
+ /*
15
+ * Copyright 2025 the original author or authors.
16
+ * <p>
17
+ * Licensed under the Moderne Source Available License (the "License");
18
+ * you may not use this file except in compliance with the License.
19
+ * You may obtain a copy of the License at
20
+ * <p>
21
+ * https://docs.moderne.io/licensing/moderne-source-available-license
22
+ * <p>
23
+ * Unless required by applicable law or agreed to in writing, software
24
+ * distributed under the License is distributed on an "AS IS" BASIS,
25
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26
+ * See the License for the specific language governing permissions and
27
+ * limitations under the License.
28
+ */
29
+ const immer_1 = require("immer");
30
+ const java_1 = require("../../java");
31
+ const index_1 = require("../index");
32
+ const uuid_1 = require("../../uuid");
33
+ const capture_1 = require("./capture");
34
+ const comparator_1 = require("./comparator");
35
+ const utils_1 = require("./utils");
36
+ /**
37
+ * Builder for creating patterns programmatically.
38
+ * Use when pattern structure is not known at compile time.
39
+ *
40
+ * @example
41
+ * // Loop-based pattern generation
42
+ * const builder = Pattern.builder().code('myFunction(');
43
+ * for (let i = 0; i < argCount; i++) {
44
+ * if (i > 0) builder.code(', ');
45
+ * builder.capture(capture(`arg${i}`));
46
+ * }
47
+ * builder.code(')');
48
+ * const pat = builder.build();
49
+ *
50
+ * @example
51
+ * // Conditional pattern construction
52
+ * const builder = Pattern.builder().code('foo(');
53
+ * builder.capture(capture('first'));
54
+ * if (needsSecondArg) {
55
+ * builder.code(', ').capture(capture('second'));
56
+ * }
57
+ * builder.code(')');
58
+ * const pat = builder.build();
59
+ */
60
+ class PatternBuilder {
61
+ constructor() {
62
+ this.parts = [];
63
+ this.captures = [];
64
+ }
65
+ /**
66
+ * Adds a static string part to the pattern.
67
+ *
68
+ * @param str The string to add
69
+ * @returns This builder for chaining
70
+ */
71
+ code(str) {
72
+ // If there are already captures, we need to add an empty string before this
73
+ if (this.captures.length > this.parts.length) {
74
+ this.parts.push('');
75
+ }
76
+ // Append to the last part or start a new one
77
+ if (this.parts.length === 0) {
78
+ this.parts.push(str);
79
+ }
80
+ else {
81
+ this.parts[this.parts.length - 1] += str;
82
+ }
83
+ return this;
84
+ }
85
+ /**
86
+ * Adds a capture to the pattern.
87
+ *
88
+ * @param value The capture object (Capture or Any) or string name
89
+ * @returns This builder for chaining
90
+ */
91
+ capture(value) {
92
+ // Ensure we have a part for after this capture
93
+ if (this.parts.length === 0) {
94
+ this.parts.push('');
95
+ }
96
+ // Convert string to Capture if needed
97
+ const captureObj = typeof value === 'string' ? new capture_1.CaptureImpl(value) : value;
98
+ this.captures.push(captureObj);
99
+ // Add an empty string for the next part
100
+ this.parts.push('');
101
+ return this;
102
+ }
103
+ /**
104
+ * Builds the pattern from accumulated parts and captures.
105
+ *
106
+ * @returns A Pattern instance
107
+ */
108
+ build() {
109
+ // Ensure parts array is one longer than captures array
110
+ while (this.parts.length <= this.captures.length) {
111
+ this.parts.push('');
112
+ }
113
+ // Create a synthetic TemplateStringsArray
114
+ const templateStrings = this.parts.slice();
115
+ templateStrings.raw = this.parts.slice();
116
+ Object.defineProperty(templateStrings, 'raw', {
117
+ value: this.parts.slice(),
118
+ writable: false
119
+ });
120
+ // Delegate to the pattern() function
121
+ return pattern(templateStrings, ...this.captures);
122
+ }
123
+ }
124
+ exports.PatternBuilder = PatternBuilder;
125
+ /**
126
+ * Represents a pattern that can be matched against AST nodes.
127
+ */
128
+ class Pattern {
129
+ /**
130
+ * Gets the configuration options for this pattern.
131
+ * @readonly
132
+ */
133
+ get options() {
134
+ return this._options;
135
+ }
136
+ /**
137
+ * Creates a new builder for constructing patterns programmatically.
138
+ *
139
+ * @returns A new PatternBuilder instance
140
+ *
141
+ * @example
142
+ * const pat = Pattern.builder()
143
+ * .code('function ')
144
+ * .capture(capture('name'))
145
+ * .code('() { return ')
146
+ * .capture(capture('value'))
147
+ * .code('; }')
148
+ * .build();
149
+ */
150
+ static builder() {
151
+ return new PatternBuilder();
152
+ }
153
+ /**
154
+ * Creates a new pattern from template parts and captures.
155
+ *
156
+ * @param templateParts The string parts of the template
157
+ * @param captures The captures between the string parts (can be Capture or Any)
158
+ */
159
+ constructor(templateParts, captures) {
160
+ this.templateParts = templateParts;
161
+ this.captures = captures;
162
+ this._options = {};
163
+ }
164
+ /**
165
+ * Configures this pattern with additional options.
166
+ *
167
+ * @param options Configuration options
168
+ * @returns This pattern for method chaining
169
+ *
170
+ * @example
171
+ * pattern`isDate(${capture('date')})`
172
+ * .configure({
173
+ * imports: ['import { isDate } from \"util\"'],
174
+ * dependencies: { 'util': '^1.0.0' }
175
+ * })
176
+ */
177
+ configure(options) {
178
+ this._options = Object.assign(Object.assign({}, this._options), options);
179
+ return this;
180
+ }
181
+ /**
182
+ * Creates a matcher for this pattern against a specific AST node.
183
+ *
184
+ * @param ast The AST node to match against
185
+ * @returns A Matcher object
186
+ */
187
+ match(ast) {
188
+ return __awaiter(this, void 0, void 0, function* () {
189
+ const matcher = new Matcher(this, ast);
190
+ const success = yield matcher.matches();
191
+ if (!success) {
192
+ return undefined;
193
+ }
194
+ // Create MatchResult with unified storage
195
+ const storage = matcher.storage;
196
+ return new MatchResult(new Map(storage));
197
+ });
198
+ }
199
+ }
200
+ exports.Pattern = Pattern;
201
+ /**
202
+ * Result of a successful pattern match containing captured values.
203
+ *
204
+ * Provides access to captured AST nodes from pattern matching operations.
205
+ * Use the `get()` method to retrieve captured values by name or by Capture object.
206
+ *
207
+ * @example
208
+ * const x = capture('x');
209
+ * const pat = pattern`foo(${x})`;
210
+ * const match = await pat.match(someNode);
211
+ * if (match) {
212
+ * const captured = match.get('x'); // Get by name
213
+ * // or
214
+ * const captured = match.get(x); // Get by Capture object
215
+ * }
216
+ *
217
+ * @example
218
+ * // Variadic captures return arrays
219
+ * const args = capture({ variadic: true });
220
+ * const pat = pattern`foo(${args})`;
221
+ * const match = await pat.match(methodInvocation);
222
+ * if (match) {
223
+ * const capturedArgs = match.get(args); // Returns J[] for variadic captures
224
+ * }
225
+ */
226
+ class MatchResult {
227
+ constructor(storage = new Map()) {
228
+ this.storage = storage;
229
+ }
230
+ // Implementation
231
+ get(capture) {
232
+ // Use symbol to get internal name without triggering Proxy
233
+ const name = typeof capture === "string" ? capture : (capture[capture_1.CAPTURE_NAME_SYMBOL] || capture.getName());
234
+ const value = this.storage.get(name);
235
+ if (value === undefined) {
236
+ return undefined;
237
+ }
238
+ return this.extractElements(value);
239
+ }
240
+ /**
241
+ * Extracts semantic elements from storage value.
242
+ * For wrappers, extracts the .element; for arrays, returns array of elements.
243
+ *
244
+ * @param value The storage value
245
+ * @returns The semantic element(s)
246
+ */
247
+ extractElements(value) {
248
+ if (Array.isArray(value)) {
249
+ // Check if it's an array of wrappers
250
+ if (value.length > 0 && value[0].element !== undefined) {
251
+ // Array of J.RightPadded - extract elements
252
+ return value.map(w => w.element);
253
+ }
254
+ // Already an array of elements
255
+ return value;
256
+ }
257
+ // Check if it's a scalar wrapper
258
+ if (value.element !== undefined) {
259
+ return value.element;
260
+ }
261
+ // Scalar element
262
+ return value;
263
+ }
264
+ /**
265
+ * Internal method to get wrappers (used by template expansion).
266
+ * Returns both scalar and variadic wrappers.
267
+ * @internal
268
+ */
269
+ [utils_1.WRAPPERS_MAP_SYMBOL]() {
270
+ const result = new Map();
271
+ for (const [name, value] of this.storage) {
272
+ if (Array.isArray(value) && value.length > 0 && value[0].element !== undefined) {
273
+ // This is an array of wrappers (variadic)
274
+ result.set(name, value);
275
+ }
276
+ else if (!Array.isArray(value) && value.element !== undefined) {
277
+ // This is a scalar wrapper
278
+ result.set(name, value);
279
+ }
280
+ }
281
+ return result;
282
+ }
283
+ }
284
+ exports.MatchResult = MatchResult;
285
+ /**
286
+ * Matcher for checking if a pattern matches an AST node and extracting captured nodes.
287
+ */
288
+ class Matcher {
289
+ /**
290
+ * Creates a new matcher for a pattern against an AST node.
291
+ *
292
+ * @param pattern The pattern to match
293
+ * @param ast The AST node to match against
294
+ */
295
+ constructor(pattern, ast) {
296
+ this.pattern = pattern;
297
+ this.ast = ast;
298
+ // Unified storage: holds J for scalar captures, J.RightPadded<J>[] or J[] for variadic captures
299
+ this.storage = new Map();
300
+ }
301
+ /**
302
+ * Checks if the pattern matches the AST node.
303
+ *
304
+ * @returns true if the pattern matches, false otherwise
305
+ */
306
+ matches() {
307
+ return __awaiter(this, void 0, void 0, function* () {
308
+ if (!this.patternAst) {
309
+ // Prefer 'context' over deprecated 'imports'
310
+ const contextStatements = this.pattern.options.context || this.pattern.options.imports || [];
311
+ const templateProcessor = new TemplateProcessor(this.pattern.templateParts, this.pattern.captures, contextStatements, this.pattern.options.dependencies || {});
312
+ this.patternAst = yield templateProcessor.toAstPattern();
313
+ }
314
+ return this.matchNode(this.patternAst, this.ast);
315
+ });
316
+ }
317
+ /**
318
+ * Gets all captured nodes (projected view: extracts elements from wrappers).
319
+ *
320
+ * @returns A map of capture names to captured nodes
321
+ */
322
+ getAll() {
323
+ const result = new Map();
324
+ for (const [name, value] of this.storage) {
325
+ result.set(name, this.extractElements(value));
326
+ }
327
+ return result;
328
+ }
329
+ /**
330
+ * Extracts semantic elements from storage value.
331
+ * For wrappers, extracts the .element; for arrays, returns array of elements.
332
+ *
333
+ * @param value The storage value
334
+ * @returns The semantic element(s)
335
+ */
336
+ extractElements(value) {
337
+ if (Array.isArray(value)) {
338
+ // Check if it's an array of wrappers
339
+ if (value.length > 0 && value[0].element !== undefined) {
340
+ // Array of J.RightPadded - extract elements
341
+ return value.map(w => w.element);
342
+ }
343
+ // Already an array of elements
344
+ return value;
345
+ }
346
+ // Check if it's a scalar wrapper
347
+ if (value.element !== undefined) {
348
+ return value.element;
349
+ }
350
+ // Scalar element
351
+ return value;
352
+ }
353
+ /**
354
+ * Matches a pattern node against a target node.
355
+ *
356
+ * @param pattern The pattern node
357
+ * @param target The target node
358
+ * @returns true if the pattern matches the target, false otherwise
359
+ */
360
+ matchNode(pattern, target) {
361
+ return __awaiter(this, void 0, void 0, function* () {
362
+ var _a;
363
+ // Check if pattern is a capture placeholder
364
+ if (utils_1.PlaceholderUtils.isCapture(pattern)) {
365
+ return this.handleCapture(pattern, target);
366
+ }
367
+ // Check if nodes have the same kind
368
+ if (pattern.kind !== target.kind) {
369
+ return false;
370
+ }
371
+ // Use the pattern matching comparator with configured lenient type matching
372
+ // Default to true for backward compatibility with existing patterns
373
+ const lenientTypeMatching = (_a = this.pattern.options.lenientTypeMatching) !== null && _a !== void 0 ? _a : true;
374
+ const comparator = new comparator_1.PatternMatchingComparator({
375
+ handleCapture: (p, t) => this.handleCapture(p, t),
376
+ handleVariadicCapture: (p, ts, ws) => this.handleVariadicCapture(p, ts, ws),
377
+ saveState: () => this.saveState(),
378
+ restoreState: (state) => this.restoreState(state)
379
+ }, lenientTypeMatching);
380
+ return yield comparator.compare(pattern, target);
381
+ });
382
+ }
383
+ /**
384
+ * Saves the current state of storage for backtracking.
385
+ *
386
+ * @returns A snapshot of the current state
387
+ */
388
+ saveState() {
389
+ return new Map(this.storage);
390
+ }
391
+ /**
392
+ * Restores a previously saved state for backtracking.
393
+ *
394
+ * @param state The state to restore
395
+ */
396
+ restoreState(state) {
397
+ this.storage.clear();
398
+ state.forEach((value, key) => this.storage.set(key, value));
399
+ }
400
+ /**
401
+ * Handles a capture placeholder.
402
+ *
403
+ * @param pattern The pattern node
404
+ * @param target The target node
405
+ * @param wrapper Optional wrapper containing the target (for preserving markers)
406
+ * @returns true if the capture is successful, false otherwise
407
+ */
408
+ handleCapture(pattern, target, wrapper) {
409
+ var _a, _b;
410
+ const captureName = utils_1.PlaceholderUtils.getCaptureName(pattern);
411
+ if (!captureName) {
412
+ return false;
413
+ }
414
+ // Find the original capture object to get constraint and capturing flag
415
+ const captureObj = this.pattern.captures.find(c => c.getName() === captureName);
416
+ const constraint = (_a = captureObj === null || captureObj === void 0 ? void 0 : captureObj.getConstraint) === null || _a === void 0 ? void 0 : _a.call(captureObj);
417
+ // Apply constraint if present
418
+ if (constraint && !constraint(target)) {
419
+ return false;
420
+ }
421
+ // Only store the binding if this is a capturing placeholder
422
+ const capturing = (_b = captureObj === null || captureObj === void 0 ? void 0 : captureObj[capture_1.CAPTURE_CAPTURING_SYMBOL]) !== null && _b !== void 0 ? _b : true;
423
+ if (capturing) {
424
+ // Store wrapper if available (preserves markers), otherwise store element
425
+ this.storage.set(captureName, wrapper !== null && wrapper !== void 0 ? wrapper : target);
426
+ }
427
+ return true;
428
+ }
429
+ /**
430
+ * Handles a variadic capture placeholder.
431
+ *
432
+ * @param pattern The pattern node (the variadic capture)
433
+ * @param targets The target nodes that were matched
434
+ * @param wrappers Optional wrappers to preserve markers
435
+ * @returns true if the capture is successful, false otherwise
436
+ */
437
+ handleVariadicCapture(pattern, targets, wrappers) {
438
+ var _a, _b;
439
+ const captureName = utils_1.PlaceholderUtils.getCaptureName(pattern);
440
+ if (!captureName) {
441
+ return false;
442
+ }
443
+ // Find the original capture object to get constraint and capturing flag
444
+ const captureObj = this.pattern.captures.find(c => c.getName() === captureName);
445
+ const constraint = (_a = captureObj === null || captureObj === void 0 ? void 0 : captureObj.getConstraint) === null || _a === void 0 ? void 0 : _a.call(captureObj);
446
+ // Apply constraint if present - for variadic captures, constraint receives the array of elements
447
+ if (constraint && !constraint(targets)) {
448
+ return false;
449
+ }
450
+ // Only store the binding if this is a capturing placeholder
451
+ const capturing = (_b = captureObj === null || captureObj === void 0 ? void 0 : captureObj[capture_1.CAPTURE_CAPTURING_SYMBOL]) !== null && _b !== void 0 ? _b : true;
452
+ if (capturing) {
453
+ // Store the richest representation: wrappers if available, otherwise elements
454
+ if (wrappers && wrappers.length > 0) {
455
+ this.storage.set(captureName, wrappers);
456
+ }
457
+ else {
458
+ this.storage.set(captureName, targets);
459
+ }
460
+ }
461
+ return true;
462
+ }
463
+ }
464
+ /**
465
+ * Processor for template strings.
466
+ * Converts a template string with captures into an AST pattern.
467
+ */
468
+ class TemplateProcessor {
469
+ /**
470
+ * Creates a new template processor.
471
+ *
472
+ * @param templateParts The string parts of the template
473
+ * @param captures The captures between the string parts (can be Capture or Any)
474
+ * @param contextStatements Context declarations (imports, types, etc.) to prepend for type attribution
475
+ * @param dependencies NPM dependencies for type attribution
476
+ */
477
+ constructor(templateParts, captures, contextStatements = [], dependencies = {}) {
478
+ this.templateParts = templateParts;
479
+ this.captures = captures;
480
+ this.contextStatements = contextStatements;
481
+ this.dependencies = dependencies;
482
+ }
483
+ /**
484
+ * Converts the template to an AST pattern.
485
+ *
486
+ * @returns A Promise resolving to the AST pattern
487
+ */
488
+ toAstPattern() {
489
+ return __awaiter(this, void 0, void 0, function* () {
490
+ // Combine template parts and placeholders
491
+ const templateString = this.buildTemplateString();
492
+ // Use cache to get or parse the compilation unit
493
+ const cu = yield utils_1.templateCache.getOrParse(templateString, this.captures, this.contextStatements, this.dependencies);
494
+ // Extract the relevant part of the AST
495
+ return this.extractPatternFromAst(cu);
496
+ });
497
+ }
498
+ /**
499
+ * Builds a template string with placeholders for captures.
500
+ * If the template looks like a block pattern, wraps it in a function.
501
+ *
502
+ * @returns The template string
503
+ */
504
+ buildTemplateString() {
505
+ let result = '';
506
+ for (let i = 0; i < this.templateParts.length; i++) {
507
+ result += this.templateParts[i];
508
+ if (i < this.captures.length) {
509
+ const capture = this.captures[i];
510
+ // Use symbol to access capture name without triggering Proxy
511
+ const captureName = capture[capture_1.CAPTURE_NAME_SYMBOL] || capture.getName();
512
+ result += utils_1.PlaceholderUtils.createCapture(captureName, undefined);
513
+ }
514
+ }
515
+ // Check if this looks like a block pattern (starts with { and contains statement keywords)
516
+ const trimmed = result.trim();
517
+ if (trimmed.startsWith('{') && trimmed.endsWith('}')) {
518
+ // Check for statement keywords that indicate this is a block, not an object literal
519
+ const hasStatementKeywords = /\b(return|if|for|while|do|switch|try|throw|break|continue|const|let|var|function|class)\b/.test(result);
520
+ if (hasStatementKeywords) {
521
+ // Wrap in a function to ensure it parses as a block
522
+ return `function __PATTERN__() ${result}`;
523
+ }
524
+ }
525
+ return result;
526
+ }
527
+ /**
528
+ * Extracts the pattern from the parsed AST.
529
+ *
530
+ * @param cu The compilation unit
531
+ * @returns The extracted pattern
532
+ */
533
+ extractPatternFromAst(cu) {
534
+ var _a, _b;
535
+ // Skip context statements to get to the actual pattern code
536
+ const patternStatementIndex = this.contextStatements.length;
537
+ // Check if we have any statements at the pattern index
538
+ if (!cu.statements || patternStatementIndex >= cu.statements.length) {
539
+ // If there's no statement at the index, but we have exactly one statement
540
+ // and it's a block, it might be the pattern itself (e.g., pattern`{ ... }`)
541
+ if (cu.statements && cu.statements.length === 1 && cu.statements[0].element.kind === java_1.J.Kind.Block) {
542
+ return this.attachCaptureMarkers(cu.statements[0].element);
543
+ }
544
+ throw new Error(`No statement found at index ${patternStatementIndex} in compilation unit with ${((_a = cu.statements) === null || _a === void 0 ? void 0 : _a.length) || 0} statements`);
545
+ }
546
+ // Extract the relevant part of the AST based on the template content
547
+ const firstStatement = cu.statements[patternStatementIndex].element;
548
+ let extracted;
549
+ // Check if this is our wrapper function for block patterns
550
+ if (firstStatement.kind === java_1.J.Kind.MethodDeclaration) {
551
+ const method = firstStatement;
552
+ if (((_b = method.name) === null || _b === void 0 ? void 0 : _b.simpleName) === '__PATTERN__' && method.body) {
553
+ // Extract the block from the wrapper function
554
+ extracted = method.body;
555
+ }
556
+ else {
557
+ extracted = firstStatement;
558
+ }
559
+ }
560
+ else if (firstStatement.kind === index_1.JS.Kind.ExpressionStatement) {
561
+ // If the first statement is an expression statement, extract the expression
562
+ extracted = firstStatement.expression;
563
+ }
564
+ else {
565
+ // Otherwise, return the statement itself
566
+ extracted = firstStatement;
567
+ }
568
+ // Attach CaptureMarkers to capture identifiers
569
+ return this.attachCaptureMarkers(extracted);
570
+ }
571
+ /**
572
+ * Attaches CaptureMarkers to capture identifiers in the AST.
573
+ * This allows efficient capture detection without string parsing.
574
+ *
575
+ * @param ast The AST to process
576
+ * @returns The AST with CaptureMarkers attached
577
+ */
578
+ attachCaptureMarkers(ast) {
579
+ const visited = new Set();
580
+ return (0, immer_1.produce)(ast, draft => {
581
+ this.visitAndAttachMarkers(draft, visited);
582
+ });
583
+ }
584
+ /**
585
+ * Recursively visits AST nodes and attaches CaptureMarkers to capture identifiers.
586
+ * For statement-level captures (identifiers in ExpressionStatement), the marker
587
+ * is attached to the ExpressionStatement itself rather than the nested identifier.
588
+ *
589
+ * @param node The node to visit
590
+ * @param visited Set of already visited nodes to avoid cycles
591
+ */
592
+ visitAndAttachMarkers(node, visited) {
593
+ var _a, _b, _c;
594
+ if (!node || typeof node !== 'object' || visited.has(node)) {
595
+ return;
596
+ }
597
+ // Mark as visited to avoid cycles
598
+ visited.add(node);
599
+ // Check if this is an ExpressionStatement containing a capture identifier
600
+ // For statement-level captures, we attach the marker to the ExpressionStatement itself
601
+ if (node.kind === index_1.JS.Kind.ExpressionStatement &&
602
+ ((_a = node.expression) === null || _a === void 0 ? void 0 : _a.kind) === java_1.J.Kind.Identifier &&
603
+ ((_b = node.expression.simpleName) === null || _b === void 0 ? void 0 : _b.startsWith(utils_1.PlaceholderUtils.CAPTURE_PREFIX))) {
604
+ const captureInfo = utils_1.PlaceholderUtils.parseCapture(node.expression.simpleName);
605
+ if (captureInfo) {
606
+ // Initialize markers on the ExpressionStatement
607
+ if (!node.markers) {
608
+ node.markers = { kind: 'org.openrewrite.marker.Markers', id: (0, uuid_1.randomId)(), markers: [] };
609
+ }
610
+ if (!node.markers.markers) {
611
+ node.markers.markers = [];
612
+ }
613
+ // Find the original capture object to get variadic options
614
+ const captureObj = this.captures.find(c => c.getName() === captureInfo.name);
615
+ const variadicOptions = captureObj === null || captureObj === void 0 ? void 0 : captureObj.getVariadicOptions();
616
+ // Add CaptureMarker to the ExpressionStatement
617
+ node.markers.markers.push(new utils_1.CaptureMarker(captureInfo.name, variadicOptions));
618
+ }
619
+ }
620
+ // For non-statement captures (expressions), attach marker to the identifier
621
+ else if (node.kind === java_1.J.Kind.Identifier && ((_c = node.simpleName) === null || _c === void 0 ? void 0 : _c.startsWith(utils_1.PlaceholderUtils.CAPTURE_PREFIX))) {
622
+ const captureInfo = utils_1.PlaceholderUtils.parseCapture(node.simpleName);
623
+ if (captureInfo) {
624
+ // Initialize markers if needed
625
+ if (!node.markers) {
626
+ node.markers = { kind: 'org.openrewrite.marker.Markers', id: (0, uuid_1.randomId)(), markers: [] };
627
+ }
628
+ if (!node.markers.markers) {
629
+ node.markers.markers = [];
630
+ }
631
+ // Find the original capture object to get variadic options
632
+ const captureObj = this.captures.find(c => c.getName() === captureInfo.name);
633
+ const variadicOptions = captureObj === null || captureObj === void 0 ? void 0 : captureObj.getVariadicOptions();
634
+ // Add CaptureMarker with variadic options if available
635
+ node.markers.markers.push(new utils_1.CaptureMarker(captureInfo.name, variadicOptions));
636
+ }
637
+ }
638
+ // Recursively visit all properties
639
+ for (const key in node) {
640
+ if (node.hasOwnProperty(key)) {
641
+ const value = node[key];
642
+ if (Array.isArray(value)) {
643
+ value.forEach(item => this.visitAndAttachMarkers(item, visited));
644
+ }
645
+ else if (typeof value === 'object' && value !== null) {
646
+ this.visitAndAttachMarkers(value, visited);
647
+ }
648
+ }
649
+ }
650
+ }
651
+ }
652
+ /**
653
+ * Tagged template function for creating patterns.
654
+ *
655
+ * @param strings The string parts of the template
656
+ * @param captures The captures between the string parts (Capture, Any, or string names)
657
+ * @returns A Pattern object
658
+ *
659
+ * @example
660
+ * // Using the same capture multiple times for repeated patterns
661
+ * const expr = capture('expr');
662
+ * const redundantOr = pattern`${expr} || ${expr}`;
663
+ *
664
+ * @example
665
+ * // Using any() for non-capturing matches
666
+ * const pat = pattern`foo(${any()})`;
667
+ */
668
+ function pattern(strings, ...captures) {
669
+ const capturesByName = captures.reduce((map, c) => {
670
+ const capture = typeof c === "string" ? new capture_1.CaptureImpl(c) : c;
671
+ // Use symbol to get internal name without triggering Proxy
672
+ const name = capture[capture_1.CAPTURE_NAME_SYMBOL] || capture.getName();
673
+ return map.set(name, capture);
674
+ }, new Map());
675
+ return new Pattern(strings, captures.map(c => {
676
+ // Use symbol to get internal name without triggering Proxy
677
+ const name = typeof c === "string" ? c : (c[capture_1.CAPTURE_NAME_SYMBOL] || c.getName());
678
+ return capturesByName.get(name);
679
+ }));
680
+ }
681
+ //# sourceMappingURL=pattern.js.map