@openrewrite/rewrite 8.69.0-20251212-132620 → 8.69.0-20251212-152027

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.
@@ -0,0 +1,892 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright 2025 the original author or authors.
4
+ * <p>
5
+ * Licensed under the Moderne Source Available License (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ * <p>
9
+ * https://docs.moderne.io/licensing/moderne-source-available-license
10
+ * <p>
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ var desc = Object.getOwnPropertyDescriptor(m, k);
20
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
21
+ desc = { enumerable: true, get: function() { return m[k]; } };
22
+ }
23
+ Object.defineProperty(o, k2, desc);
24
+ }) : (function(o, m, k, k2) {
25
+ if (k2 === undefined) k2 = k;
26
+ o[k2] = m[k];
27
+ }));
28
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
29
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
30
+ }) : function(o, v) {
31
+ o["default"] = v;
32
+ });
33
+ var __importStar = (this && this.__importStar) || (function () {
34
+ var ownKeys = function(o) {
35
+ ownKeys = Object.getOwnPropertyNames || function (o) {
36
+ var ar = [];
37
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
38
+ return ar;
39
+ };
40
+ return ownKeys(o);
41
+ };
42
+ return function (mod) {
43
+ if (mod && mod.__esModule) return mod;
44
+ var result = {};
45
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
46
+ __setModuleDefault(result, mod);
47
+ return result;
48
+ };
49
+ })();
50
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
51
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
52
+ return new (P || (P = Promise))(function (resolve, reject) {
53
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
54
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
55
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
56
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
57
+ });
58
+ };
59
+ Object.defineProperty(exports, "__esModule", { value: true });
60
+ exports.LstDebugVisitor = exports.LstDebugPrinter = void 0;
61
+ exports.formatWhitespace = formatWhitespace;
62
+ exports.formatSpace = formatSpace;
63
+ exports.formatCursorMessages = formatCursorMessages;
64
+ exports.findPropertyPath = findPropertyPath;
65
+ exports.debugPrint = debugPrint;
66
+ exports.debugPrintCursorPath = debugPrintCursorPath;
67
+ const java_1 = require("../java");
68
+ const visitor_1 = require("./visitor");
69
+ const fs = __importStar(require("fs"));
70
+ const DEFAULT_OPTIONS = {
71
+ includeCursorMessages: true,
72
+ includeMarkers: false,
73
+ includeIds: false,
74
+ maxDepth: -1,
75
+ excludeProperties: [],
76
+ output: 'console',
77
+ indent: ' ',
78
+ };
79
+ /**
80
+ * Properties to always exclude from debug output (noisy/large).
81
+ */
82
+ const EXCLUDED_PROPERTIES = new Set([
83
+ 'type', // JavaType - very verbose
84
+ 'methodType', // JavaType.Method
85
+ 'variableType', // JavaType.Variable
86
+ 'fieldType', // JavaType.Variable
87
+ 'constructorType', // JavaType.Method
88
+ ]);
89
+ /**
90
+ * Subscript digits for counts (index 0-9 maps to ₀-₉).
91
+ */
92
+ const SUBSCRIPTS = ['₀', '₁', '₂', '₃', '₄', '₅', '₆', '₇', '₈', '₉'];
93
+ /**
94
+ * Format a count as subscript. Count of 1 is implicit (empty string).
95
+ */
96
+ function subscript(count) {
97
+ if (count <= 1)
98
+ return '';
99
+ if (count < 10)
100
+ return SUBSCRIPTS[count];
101
+ // For counts >= 10, build from individual digits
102
+ return String(count).split('').map(d => SUBSCRIPTS[parseInt(d)]).join('');
103
+ }
104
+ /**
105
+ * Format whitespace string for readable debug output.
106
+ * Uses compact notation with subscript counts:
107
+ * - '\n' = 1 newline (implicit ₁)
108
+ * - '\n₂' = 2 newlines
109
+ * - '·₄' = 4 spaces
110
+ * - '-₂' = 2 tabs
111
+ * - '\n·₄' = newline + 4 spaces
112
+ * - '\n·₄-₂' = newline + 4 spaces + 2 tabs
113
+ */
114
+ function formatWhitespace(whitespace) {
115
+ if (whitespace === undefined || whitespace === '') {
116
+ return "''";
117
+ }
118
+ let result = '';
119
+ let newlineCount = 0;
120
+ let spaceCount = 0;
121
+ let tabCount = 0;
122
+ const flushCounts = () => {
123
+ if (newlineCount > 0) {
124
+ result += '\\n' + subscript(newlineCount);
125
+ newlineCount = 0;
126
+ }
127
+ if (spaceCount > 0) {
128
+ result += '·' + subscript(spaceCount);
129
+ spaceCount = 0;
130
+ }
131
+ if (tabCount > 0) {
132
+ result += '-' + subscript(tabCount);
133
+ tabCount = 0;
134
+ }
135
+ };
136
+ for (let i = 0; i < whitespace.length; i++) {
137
+ const c = whitespace[i];
138
+ if (c === '\n') {
139
+ // Flush spaces/tabs before starting newline count
140
+ if (spaceCount > 0 || tabCount > 0) {
141
+ flushCounts();
142
+ }
143
+ newlineCount++;
144
+ }
145
+ else if (c === '\r') {
146
+ flushCounts();
147
+ result += '\\r';
148
+ }
149
+ else if (c === ' ') {
150
+ // Flush newlines and tabs before counting spaces
151
+ if (newlineCount > 0) {
152
+ result += '\\n' + subscript(newlineCount);
153
+ newlineCount = 0;
154
+ }
155
+ if (tabCount > 0) {
156
+ result += '-' + subscript(tabCount);
157
+ tabCount = 0;
158
+ }
159
+ spaceCount++;
160
+ }
161
+ else if (c === '\t') {
162
+ // Flush newlines and spaces before counting tabs
163
+ if (newlineCount > 0) {
164
+ result += '\\n' + subscript(newlineCount);
165
+ newlineCount = 0;
166
+ }
167
+ if (spaceCount > 0) {
168
+ result += '·' + subscript(spaceCount);
169
+ spaceCount = 0;
170
+ }
171
+ tabCount++;
172
+ }
173
+ else {
174
+ flushCounts();
175
+ // Unexpected character (probably a bug in the parser)
176
+ result += c;
177
+ }
178
+ }
179
+ flushCounts();
180
+ return `'${result}'`;
181
+ }
182
+ /**
183
+ * Format a single comment for debug output.
184
+ */
185
+ function formatComment(comment) {
186
+ var _a;
187
+ const textComment = comment;
188
+ const text = (_a = textComment.text) !== null && _a !== void 0 ? _a : '';
189
+ // Truncate long comments
190
+ const truncated = text.length > 20 ? text.substring(0, 17) + '...' : text;
191
+ if (textComment.multiline) {
192
+ return `/*${truncated}*/`;
193
+ }
194
+ else {
195
+ return `//${truncated}`;
196
+ }
197
+ }
198
+ /**
199
+ * Format a J.Space for debug output.
200
+ *
201
+ * Compact format:
202
+ * - Empty space: `''`
203
+ * - Whitespace only: `'\n·₄'`
204
+ * - Comment only: `//comment`
205
+ * - Comment with suffix: `//comment'\n'`
206
+ * - Multiple comments: `//c1'\n' + //c2'\n·₄'`
207
+ */
208
+ function formatSpace(space) {
209
+ if (space === undefined) {
210
+ return '<undefined>';
211
+ }
212
+ const hasComments = space.comments.length > 0;
213
+ const hasWhitespace = space.whitespace !== undefined && space.whitespace !== '';
214
+ // Completely empty
215
+ if (!hasComments && !hasWhitespace) {
216
+ return "''";
217
+ }
218
+ // Whitespace only (common case) - just show the formatted whitespace
219
+ if (!hasComments) {
220
+ return formatWhitespace(space.whitespace);
221
+ }
222
+ // Format comments with their suffixes
223
+ const parts = [];
224
+ for (const comment of space.comments) {
225
+ let part = formatComment(comment);
226
+ // Add suffix if present
227
+ if (comment.suffix && comment.suffix !== '') {
228
+ part += formatWhitespace(comment.suffix);
229
+ }
230
+ parts.push(part);
231
+ }
232
+ // Add trailing whitespace if present
233
+ if (hasWhitespace) {
234
+ parts.push(formatWhitespace(space.whitespace));
235
+ }
236
+ return parts.join(' + ');
237
+ }
238
+ /**
239
+ * Format cursor messages for debug output.
240
+ * Returns '<no messages>' if no messages, otherwise returns '⟨key=value, ...⟩'
241
+ */
242
+ function formatCursorMessages(cursor) {
243
+ if (!cursor || cursor.messages.size === 0) {
244
+ return '<no messages>';
245
+ }
246
+ const entries = [];
247
+ cursor.messages.forEach((value, key) => {
248
+ let valueStr;
249
+ if (Array.isArray(value)) {
250
+ valueStr = `[${value.map(v => JSON.stringify(v)).join(', ')}]`;
251
+ }
252
+ else if (typeof value === 'object' && value !== null) {
253
+ valueStr = JSON.stringify(value);
254
+ }
255
+ else {
256
+ valueStr = String(value);
257
+ }
258
+ const keyStr = typeof key === 'symbol' ? key.toString() : String(key);
259
+ entries.push(`${keyStr}=${valueStr}`);
260
+ });
261
+ return `⟨${entries.join(', ')}⟩`;
262
+ }
263
+ /**
264
+ * Get a short type name from a kind string.
265
+ */
266
+ function shortTypeName(kind) {
267
+ if (!kind)
268
+ return 'Unknown';
269
+ // Extract the last part after the last dot
270
+ const lastDot = kind.lastIndexOf('.');
271
+ return lastDot >= 0 ? kind.substring(lastDot + 1) : kind;
272
+ }
273
+ /**
274
+ * Find which property of the parent contains the given child element.
275
+ * Returns the property name, or property name with array index if in an array.
276
+ * Returns undefined if the relationship cannot be determined.
277
+ *
278
+ * @param cursor - The cursor at the current position
279
+ * @param child - Optional: the actual child node being visited (for RightPadded/LeftPadded/Container visits where cursor.value is the parent)
280
+ */
281
+ function findPropertyPath(cursor, child) {
282
+ var _a, _b, _c, _d;
283
+ if (!cursor) {
284
+ return undefined;
285
+ }
286
+ // If child is provided, use cursor.value as parent; otherwise use cursor.parent.value
287
+ const actualChild = child !== null && child !== void 0 ? child : cursor.value;
288
+ const parent = child ? cursor.value : (_a = cursor.parent) === null || _a === void 0 ? void 0 : _a.value;
289
+ if (!parent || typeof parent !== 'object') {
290
+ return undefined;
291
+ }
292
+ // Properties to skip when searching
293
+ const skipProps = new Set(['kind', 'id', 'prefix', 'markers', 'type', 'methodType', 'variableType', 'fieldType', 'constructorType']);
294
+ // Special case: if parent is a Container, we need to look at grandparent to find the property name
295
+ if (parent.kind === java_1.J.Kind.Container) {
296
+ const container = parent;
297
+ const grandparent = child ? (_b = cursor.parent) === null || _b === void 0 ? void 0 : _b.value : (_d = (_c = cursor.parent) === null || _c === void 0 ? void 0 : _c.parent) === null || _d === void 0 ? void 0 : _d.value;
298
+ // Find the index of actualChild in container.elements
299
+ let childIndex = -1;
300
+ if (container.elements) {
301
+ for (let i = 0; i < container.elements.length; i++) {
302
+ if (container.elements[i] === actualChild) {
303
+ childIndex = i;
304
+ break;
305
+ }
306
+ }
307
+ }
308
+ // Find which property of grandparent holds this container
309
+ if (grandparent && typeof grandparent === 'object') {
310
+ for (const [key, value] of Object.entries(grandparent)) {
311
+ if (skipProps.has(key))
312
+ continue;
313
+ if (value === parent) {
314
+ if (childIndex >= 0) {
315
+ return `${key}[${childIndex}]`;
316
+ }
317
+ return key;
318
+ }
319
+ }
320
+ }
321
+ // Fallback: just show the index
322
+ if (childIndex >= 0) {
323
+ return `[${childIndex}]`;
324
+ }
325
+ }
326
+ for (const [key, value] of Object.entries(parent)) {
327
+ if (skipProps.has(key))
328
+ continue;
329
+ // Direct match
330
+ if (value === actualChild) {
331
+ return key;
332
+ }
333
+ // Check if child is in an array
334
+ if (Array.isArray(value)) {
335
+ for (let i = 0; i < value.length; i++) {
336
+ if (value[i] === actualChild) {
337
+ return `${key}[${i}]`;
338
+ }
339
+ // Check inside RightPadded/LeftPadded wrappers
340
+ if (value[i] && typeof value[i] === 'object') {
341
+ if (value[i].element === actualChild) {
342
+ return `${key}[${i}].element`;
343
+ }
344
+ }
345
+ }
346
+ }
347
+ // Check inside Container
348
+ if (value && typeof value === 'object' && value.kind === java_1.J.Kind.Container) {
349
+ const container = value;
350
+ if (container.elements) {
351
+ for (let i = 0; i < container.elements.length; i++) {
352
+ const rp = container.elements[i];
353
+ if (rp === actualChild) {
354
+ return `${key}[${i}]`;
355
+ }
356
+ if (rp.element === actualChild) {
357
+ return `${key}[${i}].element`;
358
+ }
359
+ }
360
+ }
361
+ }
362
+ // Check inside LeftPadded/RightPadded
363
+ if (value && typeof value === 'object') {
364
+ if (value.kind === java_1.J.Kind.LeftPadded || value.kind === java_1.J.Kind.RightPadded) {
365
+ if (value.element === actualChild) {
366
+ return `${key}.element`;
367
+ }
368
+ }
369
+ }
370
+ }
371
+ return undefined;
372
+ }
373
+ /**
374
+ * Format a literal value for inline display.
375
+ */
376
+ function formatLiteralValue(lit) {
377
+ if (lit.valueSource !== undefined) {
378
+ // Truncate long literals
379
+ return lit.valueSource.length > 20
380
+ ? lit.valueSource.substring(0, 17) + '...'
381
+ : lit.valueSource;
382
+ }
383
+ return String(lit.value);
384
+ }
385
+ /**
386
+ * Get a compact inline summary for certain node types.
387
+ * - For Identifier: shows "simpleName"
388
+ * - For Literal: shows the value
389
+ * - For other nodes: shows all Identifier/Literal properties inline
390
+ */
391
+ function getNodeSummary(node) {
392
+ if ((0, java_1.isIdentifier)(node)) {
393
+ return `"${node.simpleName}"`;
394
+ }
395
+ if ((0, java_1.isLiteral)(node)) {
396
+ return formatLiteralValue(node);
397
+ }
398
+ // For other nodes, find all Identifier and Literal properties
399
+ const parts = [];
400
+ const skipProps = new Set(['kind', 'id', 'prefix', 'markers', 'type', 'methodType', 'variableType', 'fieldType', 'constructorType']);
401
+ for (const [key, value] of Object.entries(node)) {
402
+ if (skipProps.has(key))
403
+ continue;
404
+ if (value === null || value === undefined)
405
+ continue;
406
+ if ((0, java_1.isIdentifier)(value)) {
407
+ parts.push(`${key}='${value.simpleName}'`);
408
+ }
409
+ else if ((0, java_1.isLiteral)(value)) {
410
+ parts.push(`${key}=${formatLiteralValue(value)}`);
411
+ }
412
+ }
413
+ return parts.length > 0 ? parts.join(' ') : undefined;
414
+ }
415
+ /**
416
+ * LST Debug Printer - prints LST nodes in a readable format.
417
+ *
418
+ * Usage from within a visitor:
419
+ * ```typescript
420
+ * class MyVisitor extends JavaScriptVisitor<P> {
421
+ * private debug = new LstDebugPrinter({ includeCursorMessages: true });
422
+ *
423
+ * async visitMethodInvocation(mi: J.MethodInvocation, p: P) {
424
+ * this.debug.print(mi, this.cursor);
425
+ * return super.visitMethodInvocation(mi, p);
426
+ * }
427
+ * }
428
+ * ```
429
+ */
430
+ class LstDebugPrinter {
431
+ constructor(options = {}) {
432
+ this.outputLines = [];
433
+ this.options = Object.assign(Object.assign({}, DEFAULT_OPTIONS), options);
434
+ }
435
+ /**
436
+ * Print a tree node with optional cursor context.
437
+ * @param tree The tree node to print
438
+ * @param cursor Optional cursor for context
439
+ * @param label Optional label to identify this debug output (shown as comment before output)
440
+ */
441
+ print(tree, cursor, label) {
442
+ this.outputLines = [];
443
+ if (label) {
444
+ this.outputLines.push(`// ${label}`);
445
+ }
446
+ this.printNode(tree, cursor, 0);
447
+ this.flush();
448
+ }
449
+ /**
450
+ * Print the cursor path from root to current position.
451
+ */
452
+ printCursorPath(cursor) {
453
+ var _a;
454
+ this.outputLines = [];
455
+ this.outputLines.push('=== Cursor Path ===');
456
+ const path = [];
457
+ for (let c = cursor; c; c = c.parent) {
458
+ path.unshift(c);
459
+ }
460
+ for (let i = 0; i < path.length; i++) {
461
+ const c = path[i];
462
+ const indent = this.options.indent.repeat(i);
463
+ const kind = (_a = c.value) === null || _a === void 0 ? void 0 : _a.kind;
464
+ const typeName = shortTypeName(kind);
465
+ let line = `${indent}${typeName}`;
466
+ if (this.options.includeCursorMessages && c.messages.size > 0) {
467
+ line += ` [${formatCursorMessages(c)}]`;
468
+ }
469
+ this.outputLines.push(line);
470
+ }
471
+ this.flush();
472
+ }
473
+ printNode(node, cursor, depth) {
474
+ if (this.options.maxDepth >= 0 && depth > this.options.maxDepth) {
475
+ this.outputLines.push(`${this.indent(depth)}...`);
476
+ return;
477
+ }
478
+ if (node === null || node === undefined) {
479
+ this.outputLines.push(`${this.indent(depth)}null`);
480
+ return;
481
+ }
482
+ // Handle special types
483
+ if (this.isSpace(node)) {
484
+ this.outputLines.push(`${this.indent(depth)}${formatSpace(node)}`);
485
+ return;
486
+ }
487
+ if (this.isContainer(node)) {
488
+ this.printContainer(node, cursor, depth);
489
+ return;
490
+ }
491
+ if (this.isLeftPadded(node)) {
492
+ this.printLeftPadded(node, cursor, depth);
493
+ return;
494
+ }
495
+ if (this.isRightPadded(node)) {
496
+ this.printRightPadded(node, cursor, depth);
497
+ return;
498
+ }
499
+ if ((0, java_1.isJava)(node)) {
500
+ this.printJavaNode(node, cursor, depth);
501
+ return;
502
+ }
503
+ // Primitive or unknown type
504
+ if (typeof node !== 'object') {
505
+ this.outputLines.push(`${this.indent(depth)}${JSON.stringify(node)}`);
506
+ return;
507
+ }
508
+ // Generic object - print as JSON-like
509
+ this.printGenericObject(node, depth);
510
+ }
511
+ printJavaNode(node, cursor, depth) {
512
+ var _a, _b;
513
+ const typeName = shortTypeName(node.kind);
514
+ let header = `${this.indent(depth)}${typeName}`;
515
+ // Add inline summary for certain types (Identifier, Literal)
516
+ const summary = getNodeSummary(node);
517
+ if (summary) {
518
+ header += ` ${summary}`;
519
+ }
520
+ // Add cursor messages if available
521
+ if (this.options.includeCursorMessages && cursor) {
522
+ const messages = formatCursorMessages(cursor);
523
+ if (messages !== '<no messages>') {
524
+ header += ` [${messages}]`;
525
+ }
526
+ }
527
+ // Add ID if requested
528
+ if (this.options.includeIds && node.id) {
529
+ header += ` (id=${node.id.substring(0, 8)}...)`;
530
+ }
531
+ this.outputLines.push(header);
532
+ // Print prefix
533
+ if (node.prefix) {
534
+ this.outputLines.push(`${this.indent(depth + 1)}prefix: ${formatSpace(node.prefix)}`);
535
+ }
536
+ // Print markers if requested
537
+ if (this.options.includeMarkers && ((_b = (_a = node.markers) === null || _a === void 0 ? void 0 : _a.markers) === null || _b === void 0 ? void 0 : _b.length) > 0) {
538
+ this.outputLines.push(`${this.indent(depth + 1)}markers: [${node.markers.markers.map((m) => shortTypeName(m.kind)).join(', ')}]`);
539
+ }
540
+ // Print other properties
541
+ this.printNodeProperties(node, cursor, depth + 1);
542
+ }
543
+ printNodeProperties(node, cursor, depth) {
544
+ const excludedProps = new Set([
545
+ ...EXCLUDED_PROPERTIES,
546
+ ...this.options.excludeProperties,
547
+ 'kind',
548
+ 'id',
549
+ 'prefix',
550
+ 'markers',
551
+ ]);
552
+ for (const [key, value] of Object.entries(node)) {
553
+ if (excludedProps.has(key))
554
+ continue;
555
+ if (value === undefined || value === null)
556
+ continue;
557
+ if (this.isSpace(value)) {
558
+ this.outputLines.push(`${this.indent(depth)}${key}: ${formatSpace(value)}`);
559
+ }
560
+ else if (this.isContainer(value)) {
561
+ this.outputLines.push(`${this.indent(depth)}${key}:`);
562
+ this.printContainer(value, undefined, depth + 1);
563
+ }
564
+ else if (this.isLeftPadded(value)) {
565
+ this.outputLines.push(`${this.indent(depth)}${key}:`);
566
+ this.printLeftPadded(value, undefined, depth + 1);
567
+ }
568
+ else if (this.isRightPadded(value)) {
569
+ this.outputLines.push(`${this.indent(depth)}${key}:`);
570
+ this.printRightPadded(value, undefined, depth + 1);
571
+ }
572
+ else if (Array.isArray(value)) {
573
+ if (value.length === 0) {
574
+ this.outputLines.push(`${this.indent(depth)}${key}: []`);
575
+ }
576
+ else if (value.every(v => this.isRightPadded(v))) {
577
+ this.outputLines.push(`${this.indent(depth)}${key}: [${value.length} RightPadded elements]`);
578
+ for (let i = 0; i < value.length; i++) {
579
+ this.outputLines.push(`${this.indent(depth + 1)}[${i}]:`);
580
+ this.printRightPadded(value[i], undefined, depth + 2);
581
+ }
582
+ }
583
+ else if (value.every(v => (0, java_1.isJava)(v))) {
584
+ this.outputLines.push(`${this.indent(depth)}${key}: [${value.length} elements]`);
585
+ for (let i = 0; i < value.length; i++) {
586
+ this.outputLines.push(`${this.indent(depth + 1)}[${i}]:`);
587
+ this.printNode(value[i], undefined, depth + 2);
588
+ }
589
+ }
590
+ else {
591
+ this.outputLines.push(`${this.indent(depth)}${key}: [${value.length} items]`);
592
+ }
593
+ }
594
+ else if ((0, java_1.isJava)(value)) {
595
+ this.outputLines.push(`${this.indent(depth)}${key}:`);
596
+ this.printNode(value, undefined, depth + 1);
597
+ }
598
+ else if (typeof value === 'object') {
599
+ // Skip complex objects that aren't J nodes
600
+ this.outputLines.push(`${this.indent(depth)}${key}: <object>`);
601
+ }
602
+ else {
603
+ this.outputLines.push(`${this.indent(depth)}${key}: ${JSON.stringify(value)}`);
604
+ }
605
+ }
606
+ }
607
+ printContainer(container, cursor, depth) {
608
+ var _a, _b;
609
+ const elemCount = (_b = (_a = container.elements) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
610
+ let header = `${this.indent(depth)}Container<${elemCount} elements>`;
611
+ if (this.options.includeCursorMessages && cursor) {
612
+ const messages = formatCursorMessages(cursor);
613
+ if (messages !== '<no messages>') {
614
+ header += ` [${messages}]`;
615
+ }
616
+ }
617
+ this.outputLines.push(header);
618
+ this.outputLines.push(`${this.indent(depth + 1)}before: ${formatSpace(container.before)}`);
619
+ if (container.elements && container.elements.length > 0) {
620
+ this.outputLines.push(`${this.indent(depth + 1)}elements:`);
621
+ for (let i = 0; i < container.elements.length; i++) {
622
+ this.outputLines.push(`${this.indent(depth + 2)}[${i}]:`);
623
+ this.printRightPadded(container.elements[i], undefined, depth + 3);
624
+ }
625
+ }
626
+ }
627
+ printLeftPadded(lp, cursor, depth) {
628
+ let header = `${this.indent(depth)}LeftPadded`;
629
+ if (this.options.includeCursorMessages && cursor) {
630
+ const messages = formatCursorMessages(cursor);
631
+ if (messages !== '<no messages>') {
632
+ header += ` [${messages}]`;
633
+ }
634
+ }
635
+ this.outputLines.push(header);
636
+ this.outputLines.push(`${this.indent(depth + 1)}before: ${formatSpace(lp.before)}`);
637
+ if (lp.element !== undefined) {
638
+ if ((0, java_1.isJava)(lp.element)) {
639
+ this.outputLines.push(`${this.indent(depth + 1)}element:`);
640
+ this.printNode(lp.element, undefined, depth + 2);
641
+ }
642
+ else if (this.isSpace(lp.element)) {
643
+ this.outputLines.push(`${this.indent(depth + 1)}element: ${formatSpace(lp.element)}`);
644
+ }
645
+ else {
646
+ this.outputLines.push(`${this.indent(depth + 1)}element: ${JSON.stringify(lp.element)}`);
647
+ }
648
+ }
649
+ }
650
+ printRightPadded(rp, cursor, depth) {
651
+ let header = `${this.indent(depth)}RightPadded`;
652
+ if (this.options.includeCursorMessages && cursor) {
653
+ const messages = formatCursorMessages(cursor);
654
+ if (messages !== '<no messages>') {
655
+ header += ` [${messages}]`;
656
+ }
657
+ }
658
+ this.outputLines.push(header);
659
+ if (rp.element !== undefined) {
660
+ if ((0, java_1.isJava)(rp.element)) {
661
+ this.outputLines.push(`${this.indent(depth + 1)}element:`);
662
+ this.printNode(rp.element, undefined, depth + 2);
663
+ }
664
+ else {
665
+ this.outputLines.push(`${this.indent(depth + 1)}element: ${JSON.stringify(rp.element)}`);
666
+ }
667
+ }
668
+ this.outputLines.push(`${this.indent(depth + 1)}after: ${formatSpace(rp.after)}`);
669
+ }
670
+ printGenericObject(obj, depth) {
671
+ this.outputLines.push(`${this.indent(depth)}{`);
672
+ for (const [key, value] of Object.entries(obj)) {
673
+ if (typeof value === 'object' && value !== null) {
674
+ this.outputLines.push(`${this.indent(depth + 1)}${key}: <object>`);
675
+ }
676
+ else {
677
+ this.outputLines.push(`${this.indent(depth + 1)}${key}: ${JSON.stringify(value)}`);
678
+ }
679
+ }
680
+ this.outputLines.push(`${this.indent(depth)}}`);
681
+ }
682
+ isSpace(value) {
683
+ return value !== null &&
684
+ typeof value === 'object' &&
685
+ 'whitespace' in value &&
686
+ 'comments' in value &&
687
+ !('kind' in value);
688
+ }
689
+ isContainer(value) {
690
+ return value !== null &&
691
+ typeof value === 'object' &&
692
+ value.kind === java_1.J.Kind.Container;
693
+ }
694
+ isLeftPadded(value) {
695
+ return value !== null &&
696
+ typeof value === 'object' &&
697
+ value.kind === java_1.J.Kind.LeftPadded;
698
+ }
699
+ isRightPadded(value) {
700
+ return value !== null &&
701
+ typeof value === 'object' &&
702
+ value.kind === java_1.J.Kind.RightPadded;
703
+ }
704
+ indent(depth) {
705
+ return this.options.indent.repeat(depth);
706
+ }
707
+ flush() {
708
+ const output = this.outputLines.join('\n');
709
+ if (this.options.output === 'console') {
710
+ console.info(output);
711
+ }
712
+ else {
713
+ fs.appendFileSync(this.options.output, output + '\n\n');
714
+ }
715
+ this.outputLines = [];
716
+ }
717
+ }
718
+ exports.LstDebugPrinter = LstDebugPrinter;
719
+ /**
720
+ * A visitor that prints the LST structure as it traverses.
721
+ * Useful for debugging the entire tree or a subtree.
722
+ *
723
+ * Usage:
724
+ * ```typescript
725
+ * const debugVisitor = new LstDebugVisitor({ maxDepth: 3 });
726
+ * await debugVisitor.visit(tree, ctx);
727
+ * ```
728
+ */
729
+ class LstDebugVisitor extends visitor_1.JavaScriptVisitor {
730
+ constructor(options = {}, config = {}) {
731
+ var _a, _b;
732
+ super();
733
+ this.depth = 0;
734
+ this.printer = new LstDebugPrinter(options);
735
+ this.printPreVisit = (_a = config.printPreVisit) !== null && _a !== void 0 ? _a : true;
736
+ this.printPostVisit = (_b = config.printPostVisit) !== null && _b !== void 0 ? _b : false;
737
+ }
738
+ preVisit(tree, _p) {
739
+ return __awaiter(this, void 0, void 0, function* () {
740
+ if (this.printPreVisit) {
741
+ const typeName = shortTypeName(tree.kind);
742
+ const indent = ' '.repeat(this.depth);
743
+ const messages = formatCursorMessages(this.cursor);
744
+ const prefix = formatSpace(tree.prefix);
745
+ const summary = getNodeSummary(tree);
746
+ const propPath = findPropertyPath(this.cursor);
747
+ let line = indent;
748
+ if (propPath) {
749
+ line += `${propPath}: `;
750
+ }
751
+ line += `${typeName}{`;
752
+ if (summary) {
753
+ line += `${summary} `;
754
+ }
755
+ line += `prefix=${prefix}}`;
756
+ console.info(line);
757
+ // Show cursor messages on a separate indented line
758
+ if (messages !== '<no messages>') {
759
+ console.info(`${indent} ⤷ ${messages}`);
760
+ }
761
+ }
762
+ this.depth++;
763
+ return tree;
764
+ });
765
+ }
766
+ postVisit(tree, _p) {
767
+ return __awaiter(this, void 0, void 0, function* () {
768
+ this.depth--;
769
+ if (this.printPostVisit) {
770
+ const typeName = shortTypeName(tree.kind);
771
+ const indent = ' '.repeat(this.depth);
772
+ console.info(`${indent}← ${typeName}`);
773
+ }
774
+ return tree;
775
+ });
776
+ }
777
+ visitContainer(container, p) {
778
+ const _super = Object.create(null, {
779
+ visitContainer: { get: () => super.visitContainer }
780
+ });
781
+ return __awaiter(this, void 0, void 0, function* () {
782
+ if (this.printPreVisit) {
783
+ const indent = ' '.repeat(this.depth);
784
+ const messages = formatCursorMessages(this.cursor);
785
+ const before = formatSpace(container.before);
786
+ // Pass container as the child since cursor.value is the parent node
787
+ const propPath = findPropertyPath(this.cursor, container);
788
+ let line = indent;
789
+ if (propPath) {
790
+ line += `${propPath}: `;
791
+ }
792
+ line += `Container<${container.elements.length}>{before=${before}}`;
793
+ console.info(line);
794
+ if (messages !== '<no messages>') {
795
+ console.info(`${indent} ⤷ ${messages}`);
796
+ }
797
+ }
798
+ this.depth++;
799
+ const result = yield _super.visitContainer.call(this, container, p);
800
+ this.depth--;
801
+ return result;
802
+ });
803
+ }
804
+ visitLeftPadded(left, p) {
805
+ const _super = Object.create(null, {
806
+ visitLeftPadded: { get: () => super.visitLeftPadded }
807
+ });
808
+ return __awaiter(this, void 0, void 0, function* () {
809
+ if (this.printPreVisit) {
810
+ const indent = ' '.repeat(this.depth);
811
+ const messages = formatCursorMessages(this.cursor);
812
+ const before = formatSpace(left.before);
813
+ // Pass left as the child since cursor.value is the parent node
814
+ const propPath = findPropertyPath(this.cursor, left);
815
+ let line = indent;
816
+ if (propPath) {
817
+ line += `${propPath}: `;
818
+ }
819
+ line += `LeftPadded{before=${before}`;
820
+ // Show element value if it's a primitive (string, number, boolean)
821
+ if (left.element !== null && left.element !== undefined) {
822
+ const elemType = typeof left.element;
823
+ if (elemType === 'string' || elemType === 'number' || elemType === 'boolean') {
824
+ line += ` element=${JSON.stringify(left.element)}`;
825
+ }
826
+ }
827
+ line += '}';
828
+ console.info(line);
829
+ if (messages !== '<no messages>') {
830
+ console.info(`${indent} ⤷ ${messages}`);
831
+ }
832
+ }
833
+ this.depth++;
834
+ const result = yield _super.visitLeftPadded.call(this, left, p);
835
+ this.depth--;
836
+ return result;
837
+ });
838
+ }
839
+ visitRightPadded(right, p) {
840
+ const _super = Object.create(null, {
841
+ visitRightPadded: { get: () => super.visitRightPadded }
842
+ });
843
+ return __awaiter(this, void 0, void 0, function* () {
844
+ if (this.printPreVisit) {
845
+ const indent = ' '.repeat(this.depth);
846
+ const messages = formatCursorMessages(this.cursor);
847
+ const after = formatSpace(right.after);
848
+ // Pass right as the child since cursor.value is the parent node
849
+ const propPath = findPropertyPath(this.cursor, right);
850
+ let line = indent;
851
+ if (propPath) {
852
+ line += `${propPath}: `;
853
+ }
854
+ line += `RightPadded{after=${after}`;
855
+ // Show element value if it's a primitive (string, number, boolean)
856
+ if (right.element !== null && right.element !== undefined) {
857
+ const elemType = typeof right.element;
858
+ if (elemType === 'string' || elemType === 'number' || elemType === 'boolean') {
859
+ line += ` element=${JSON.stringify(right.element)}`;
860
+ }
861
+ }
862
+ line += '}';
863
+ console.info(line);
864
+ if (messages !== '<no messages>') {
865
+ console.info(`${indent} ⤷ ${messages}`);
866
+ }
867
+ }
868
+ this.depth++;
869
+ const result = yield _super.visitRightPadded.call(this, right, p);
870
+ this.depth--;
871
+ return result;
872
+ });
873
+ }
874
+ }
875
+ exports.LstDebugVisitor = LstDebugVisitor;
876
+ /**
877
+ * Convenience function to print a tree node.
878
+ * @param tree The tree node to print
879
+ * @param cursor Optional cursor for context
880
+ * @param label Optional label to identify this debug output
881
+ * @param options Optional debug options
882
+ */
883
+ function debugPrint(tree, cursor, label, options) {
884
+ new LstDebugPrinter(options).print(tree, cursor, label);
885
+ }
886
+ /**
887
+ * Convenience function to print cursor path.
888
+ */
889
+ function debugPrintCursorPath(cursor, options) {
890
+ new LstDebugPrinter(options).printCursorPath(cursor);
891
+ }
892
+ //# sourceMappingURL=tree-debug.js.map