@openrewrite/rewrite 8.67.0-20251112-160335 → 8.67.0-20251113-160321
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/javascript/comparator.d.ts +64 -3
- package/dist/javascript/comparator.d.ts.map +1 -1
- package/dist/javascript/comparator.js +216 -155
- package/dist/javascript/comparator.js.map +1 -1
- package/dist/javascript/templating/comparator.d.ts +118 -9
- package/dist/javascript/templating/comparator.d.ts.map +1 -1
- package/dist/javascript/templating/comparator.js +821 -73
- package/dist/javascript/templating/comparator.js.map +1 -1
- package/dist/javascript/templating/index.d.ts +1 -1
- package/dist/javascript/templating/index.d.ts.map +1 -1
- package/dist/javascript/templating/index.js.map +1 -1
- package/dist/javascript/templating/pattern.d.ts +89 -5
- package/dist/javascript/templating/pattern.d.ts.map +1 -1
- package/dist/javascript/templating/pattern.js +442 -31
- package/dist/javascript/templating/pattern.js.map +1 -1
- package/dist/javascript/templating/types.d.ts +157 -1
- package/dist/javascript/templating/types.d.ts.map +1 -1
- package/dist/version.txt +1 -1
- package/package.json +1 -1
- package/src/javascript/comparator.ts +249 -169
- package/src/javascript/templating/comparator.ts +952 -87
- package/src/javascript/templating/index.ts +6 -1
- package/src/javascript/templating/pattern.ts +543 -23
- package/src/javascript/templating/types.ts +178 -1
|
@@ -74,37 +74,161 @@ class JavaScriptComparatorVisitor extends visitor_1.JavaScriptVisitor {
|
|
|
74
74
|
}
|
|
75
75
|
/**
|
|
76
76
|
* Aborts the visit operation by setting the match flag to false.
|
|
77
|
+
*
|
|
78
|
+
* @param t The node being compared
|
|
79
|
+
* @param reason Optional reason for the mismatch (e.g., 'kind-mismatch', 'property-mismatch')
|
|
80
|
+
* @param propertyName Optional property name where mismatch occurred
|
|
81
|
+
* @param expected Optional expected value
|
|
82
|
+
* @param actual Optional actual value
|
|
77
83
|
*/
|
|
78
|
-
abort(t) {
|
|
84
|
+
abort(t, reason, propertyName, expected, actual) {
|
|
79
85
|
this.match = false;
|
|
80
86
|
return t;
|
|
81
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Specialized abort methods for common mismatch scenarios.
|
|
90
|
+
* These provide a cleaner API at call sites.
|
|
91
|
+
* Can be overridden in subclasses to extract values from cursors and provide richer error messages.
|
|
92
|
+
*/
|
|
93
|
+
kindMismatch() {
|
|
94
|
+
var _a;
|
|
95
|
+
const pattern = (_a = this.cursor) === null || _a === void 0 ? void 0 : _a.value;
|
|
96
|
+
return this.abort(pattern, 'kind-mismatch');
|
|
97
|
+
}
|
|
98
|
+
structuralMismatch(propertyName) {
|
|
99
|
+
var _a;
|
|
100
|
+
const pattern = (_a = this.cursor) === null || _a === void 0 ? void 0 : _a.value;
|
|
101
|
+
return this.abort(pattern, 'structural-mismatch', propertyName);
|
|
102
|
+
}
|
|
103
|
+
arrayLengthMismatch(propertyName) {
|
|
104
|
+
var _a;
|
|
105
|
+
const pattern = (_a = this.cursor) === null || _a === void 0 ? void 0 : _a.value;
|
|
106
|
+
return this.abort(pattern, 'array-length-mismatch', propertyName);
|
|
107
|
+
}
|
|
108
|
+
valueMismatch(propertyName, expected, actual) {
|
|
109
|
+
var _a, _b, _c, _d;
|
|
110
|
+
const pattern = (_a = this.cursor) === null || _a === void 0 ? void 0 : _a.value;
|
|
111
|
+
// If values not provided, try to extract from cursors (only if propertyName is available)
|
|
112
|
+
const expectedVal = expected !== undefined ? expected : (propertyName ? pattern === null || pattern === void 0 ? void 0 : pattern[propertyName] : pattern);
|
|
113
|
+
const actualVal = actual !== undefined ? actual : (propertyName ? (_c = (_b = this.targetCursor) === null || _b === void 0 ? void 0 : _b.value) === null || _c === void 0 ? void 0 : _c[propertyName] : (_d = this.targetCursor) === null || _d === void 0 ? void 0 : _d.value);
|
|
114
|
+
return this.abort(pattern, 'value-mismatch', propertyName, expectedVal, actualVal);
|
|
115
|
+
}
|
|
116
|
+
typeMismatch(propertyName) {
|
|
117
|
+
var _a, _b;
|
|
118
|
+
const pattern = (_a = this.cursor) === null || _a === void 0 ? void 0 : _a.value;
|
|
119
|
+
const target = (_b = this.targetCursor) === null || _b === void 0 ? void 0 : _b.value;
|
|
120
|
+
return this.abort(pattern, 'type-mismatch', propertyName, pattern === null || pattern === void 0 ? void 0 : pattern.type, target === null || target === void 0 ? void 0 : target.type);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Helper method to visit an array property by iterating through both arrays in lock-step.
|
|
124
|
+
* Checks length mismatch first, then visits each element pair.
|
|
125
|
+
* Can be overridden in subclasses to add path tracking or other instrumentation.
|
|
126
|
+
*
|
|
127
|
+
* @param parent The parent node containing the array property
|
|
128
|
+
* @param propertyName The name of the array property
|
|
129
|
+
* @param array1 The array from the first tree
|
|
130
|
+
* @param array2 The array from the second tree
|
|
131
|
+
* @param visitor Function to visit each element pair (no need to return anything)
|
|
132
|
+
* @returns undefined, modifying this.match if a mismatch occurs
|
|
133
|
+
*/
|
|
134
|
+
visitArrayProperty(parent, propertyName, array1, array2, visitor) {
|
|
135
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
136
|
+
// Check length mismatch
|
|
137
|
+
if (array1.length !== array2.length) {
|
|
138
|
+
this.arrayLengthMismatch(propertyName);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
// Visit each element in lock step
|
|
142
|
+
for (let i = 0; i < array1.length; i++) {
|
|
143
|
+
yield visitor(array1[i], array2[i], i);
|
|
144
|
+
if (!this.match)
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Helper method to visit a container property with proper context.
|
|
151
|
+
* Can be overridden in subclasses to add path tracking or other instrumentation.
|
|
152
|
+
*
|
|
153
|
+
* @param parent The parent node containing the container property
|
|
154
|
+
* @param propertyName The name of the container property
|
|
155
|
+
* @param container The container from the first tree
|
|
156
|
+
* @param otherContainer The container from the second tree
|
|
157
|
+
* @returns The container from the first tree
|
|
158
|
+
*/
|
|
159
|
+
visitContainerProperty(propertyName, container, otherContainer) {
|
|
160
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
161
|
+
// Default implementation just calls visitContainer
|
|
162
|
+
// Subclasses can override to add property context
|
|
163
|
+
yield this.visitContainer(container, otherContainer);
|
|
164
|
+
return container;
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Helper to visit a RightPadded property with property context.
|
|
169
|
+
* This allows subclasses to track which property is being visited.
|
|
170
|
+
*
|
|
171
|
+
* @param propertyName The property name for context
|
|
172
|
+
* @param rightPadded The RightPadded from the first tree
|
|
173
|
+
* @param otherRightPadded The RightPadded from the second tree
|
|
174
|
+
* @returns The RightPadded from the first tree
|
|
175
|
+
*/
|
|
176
|
+
visitRightPaddedProperty(propertyName, rightPadded, otherRightPadded) {
|
|
177
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
178
|
+
// Default implementation just calls visitRightPadded
|
|
179
|
+
// Subclasses can override to add property context
|
|
180
|
+
return yield this.visitRightPadded(rightPadded, otherRightPadded);
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Helper to visit a LeftPadded property with property context.
|
|
185
|
+
* This allows subclasses to track which property is being visited.
|
|
186
|
+
*
|
|
187
|
+
* @param propertyName The property name for context
|
|
188
|
+
* @param leftPadded The LeftPadded from the first tree
|
|
189
|
+
* @param otherLeftPadded The LeftPadded from the second tree
|
|
190
|
+
* @returns The LeftPadded from the first tree
|
|
191
|
+
*/
|
|
192
|
+
visitLeftPaddedProperty(propertyName, leftPadded, otherLeftPadded) {
|
|
193
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
194
|
+
// Default implementation just calls visitLeftPadded
|
|
195
|
+
// Subclasses can override to add property context
|
|
196
|
+
return yield this.visitLeftPadded(leftPadded, otherLeftPadded);
|
|
197
|
+
});
|
|
198
|
+
}
|
|
82
199
|
/**
|
|
83
200
|
* Generic method to visit a property value using the appropriate visitor method.
|
|
84
201
|
* This ensures wrappers (RightPadded, LeftPadded, Container) are properly tracked on the cursor.
|
|
85
202
|
*
|
|
86
203
|
* @param j The property value from the first tree
|
|
87
204
|
* @param other The corresponding property value from the second tree
|
|
205
|
+
* @param propertyName Optional property name for error reporting
|
|
88
206
|
* @returns The visited property value from the first tree
|
|
89
207
|
*/
|
|
90
|
-
visitProperty(j, other) {
|
|
208
|
+
visitProperty(j, other, propertyName) {
|
|
91
209
|
return __awaiter(this, void 0, void 0, function* () {
|
|
92
210
|
// Handle null/undefined (but not other falsy values like 0, false, '')
|
|
93
211
|
if (j == null || other == null) {
|
|
94
212
|
if (j !== other) {
|
|
95
|
-
this.
|
|
213
|
+
return this.structuralMismatch(propertyName);
|
|
96
214
|
}
|
|
97
215
|
return j;
|
|
98
216
|
}
|
|
99
217
|
const kind = j.kind;
|
|
100
218
|
// Check wrappers by kind
|
|
101
219
|
if (kind === java_1.J.Kind.RightPadded) {
|
|
102
|
-
return yield this.
|
|
220
|
+
return propertyName ? yield this.visitRightPaddedProperty(propertyName, j, other) :
|
|
221
|
+
yield this.visitRightPadded(j, other);
|
|
103
222
|
}
|
|
104
223
|
if (kind === java_1.J.Kind.LeftPadded) {
|
|
105
|
-
return yield this.
|
|
224
|
+
return propertyName ? yield this.visitLeftPaddedProperty(propertyName, j, other) :
|
|
225
|
+
yield this.visitLeftPadded(j, other);
|
|
106
226
|
}
|
|
107
227
|
if (kind === java_1.J.Kind.Container) {
|
|
228
|
+
// Use visitContainerProperty when propertyName is provided for proper context tracking
|
|
229
|
+
if (propertyName) {
|
|
230
|
+
return yield this.visitContainerProperty(propertyName, j, other);
|
|
231
|
+
}
|
|
108
232
|
return yield this.visitContainer(j, other);
|
|
109
233
|
}
|
|
110
234
|
// Check if it's a Space (skip comparison)
|
|
@@ -121,7 +245,7 @@ class JavaScriptComparatorVisitor extends visitor_1.JavaScriptVisitor {
|
|
|
121
245
|
}
|
|
122
246
|
// For primitive values, compare directly
|
|
123
247
|
if (j !== other) {
|
|
124
|
-
this.
|
|
248
|
+
return this.valueMismatch(propertyName, j, other);
|
|
125
249
|
}
|
|
126
250
|
return j;
|
|
127
251
|
});
|
|
@@ -137,17 +261,16 @@ class JavaScriptComparatorVisitor extends visitor_1.JavaScriptVisitor {
|
|
|
137
261
|
*/
|
|
138
262
|
visitElement(j, other) {
|
|
139
263
|
return __awaiter(this, void 0, void 0, function* () {
|
|
140
|
-
if (!this.match)
|
|
264
|
+
if (!this.match)
|
|
141
265
|
return j;
|
|
142
|
-
}
|
|
143
266
|
// Check if kinds match
|
|
144
267
|
if (j.kind !== other.kind) {
|
|
145
|
-
return this.
|
|
268
|
+
return this.kindMismatch();
|
|
146
269
|
}
|
|
147
270
|
// Iterate over all properties
|
|
148
271
|
for (const key of Object.keys(j)) {
|
|
149
272
|
// Skip internal/private properties, id property, and markers property
|
|
150
|
-
if (key.startsWith('_') || key === 'id' || key === 'markers') {
|
|
273
|
+
if (key.startsWith('_') || key === 'kind' || key === 'id' || key === 'markers') {
|
|
151
274
|
continue;
|
|
152
275
|
}
|
|
153
276
|
const jValue = j[key];
|
|
@@ -155,21 +278,19 @@ class JavaScriptComparatorVisitor extends visitor_1.JavaScriptVisitor {
|
|
|
155
278
|
// Handle arrays - compare element by element
|
|
156
279
|
if (Array.isArray(jValue)) {
|
|
157
280
|
if (!Array.isArray(otherValue) || jValue.length !== otherValue.length) {
|
|
158
|
-
return this.
|
|
281
|
+
return this.arrayLengthMismatch(key);
|
|
159
282
|
}
|
|
160
283
|
for (let i = 0; i < jValue.length; i++) {
|
|
161
|
-
yield this.visitProperty(jValue[i], otherValue[i]);
|
|
162
|
-
if (!this.match)
|
|
284
|
+
yield this.visitProperty(jValue[i], otherValue[i], `${key}[${i}]`);
|
|
285
|
+
if (!this.match)
|
|
163
286
|
return j;
|
|
164
|
-
}
|
|
165
287
|
}
|
|
166
288
|
}
|
|
167
289
|
else {
|
|
168
290
|
// Visit the property (which will handle wrappers, trees, primitives, etc.)
|
|
169
|
-
yield this.visitProperty(jValue, otherValue);
|
|
170
|
-
if (!this.match)
|
|
291
|
+
yield this.visitProperty(jValue, otherValue, key);
|
|
292
|
+
if (!this.match)
|
|
171
293
|
return j;
|
|
172
|
-
}
|
|
173
294
|
}
|
|
174
295
|
}
|
|
175
296
|
return j;
|
|
@@ -181,12 +302,11 @@ class JavaScriptComparatorVisitor extends visitor_1.JavaScriptVisitor {
|
|
|
181
302
|
});
|
|
182
303
|
return __awaiter(this, void 0, void 0, function* () {
|
|
183
304
|
// If we've already found a mismatch, abort further processing
|
|
184
|
-
if (!this.match)
|
|
305
|
+
if (!this.match)
|
|
185
306
|
return j;
|
|
186
|
-
}
|
|
187
307
|
// Check if the nodes have the same kind
|
|
188
308
|
if (!this.hasSameKind(j, p)) {
|
|
189
|
-
return this.
|
|
309
|
+
return this.kindMismatch();
|
|
190
310
|
}
|
|
191
311
|
// Update targetCursor to track the target node in parallel with the pattern cursor
|
|
192
312
|
// (Can be overridden by subclasses if they need cursor access before calling super)
|
|
@@ -209,9 +329,8 @@ class JavaScriptComparatorVisitor extends visitor_1.JavaScriptVisitor {
|
|
|
209
329
|
*/
|
|
210
330
|
visitRightPadded(right, p) {
|
|
211
331
|
return __awaiter(this, void 0, void 0, function* () {
|
|
212
|
-
if (!this.match)
|
|
332
|
+
if (!this.match)
|
|
213
333
|
return right;
|
|
214
|
-
}
|
|
215
334
|
// Extract the other element if it's also a RightPadded
|
|
216
335
|
const isRightPadded = p.kind === java_1.J.Kind.RightPadded;
|
|
217
336
|
const otherWrapper = isRightPadded ? p : undefined;
|
|
@@ -222,6 +341,8 @@ class JavaScriptComparatorVisitor extends visitor_1.JavaScriptVisitor {
|
|
|
222
341
|
this.cursor = new tree_2.Cursor(right, this.cursor);
|
|
223
342
|
this.targetCursor = otherWrapper ? new tree_2.Cursor(otherWrapper, this.targetCursor) : this.targetCursor;
|
|
224
343
|
try {
|
|
344
|
+
// Call visitProperty without propertyName to avoid pushing spurious 'element' path entries
|
|
345
|
+
// The property context should be provided through visitRightPaddedProperty() if needed
|
|
225
346
|
yield this.visitProperty(right.element, otherElement);
|
|
226
347
|
}
|
|
227
348
|
finally {
|
|
@@ -239,9 +360,8 @@ class JavaScriptComparatorVisitor extends visitor_1.JavaScriptVisitor {
|
|
|
239
360
|
*/
|
|
240
361
|
visitLeftPadded(left, p) {
|
|
241
362
|
return __awaiter(this, void 0, void 0, function* () {
|
|
242
|
-
if (!this.match)
|
|
363
|
+
if (!this.match)
|
|
243
364
|
return left;
|
|
244
|
-
}
|
|
245
365
|
// Extract the other element if it's also a LeftPadded
|
|
246
366
|
const isLeftPadded = p.kind === java_1.J.Kind.LeftPadded;
|
|
247
367
|
const otherWrapper = isLeftPadded ? p : undefined;
|
|
@@ -252,6 +372,8 @@ class JavaScriptComparatorVisitor extends visitor_1.JavaScriptVisitor {
|
|
|
252
372
|
this.cursor = new tree_2.Cursor(left, this.cursor);
|
|
253
373
|
this.targetCursor = otherWrapper ? new tree_2.Cursor(otherWrapper, this.targetCursor) : this.targetCursor;
|
|
254
374
|
try {
|
|
375
|
+
// Call visitProperty without propertyName to avoid pushing spurious 'element' path entries
|
|
376
|
+
// The property context should be provided through visitLeftPaddedProperty() if needed
|
|
255
377
|
yield this.visitProperty(left.element, otherElement);
|
|
256
378
|
}
|
|
257
379
|
finally {
|
|
@@ -269,16 +391,15 @@ class JavaScriptComparatorVisitor extends visitor_1.JavaScriptVisitor {
|
|
|
269
391
|
*/
|
|
270
392
|
visitContainer(container, p) {
|
|
271
393
|
return __awaiter(this, void 0, void 0, function* () {
|
|
272
|
-
if (!this.match)
|
|
394
|
+
if (!this.match)
|
|
273
395
|
return container;
|
|
274
|
-
}
|
|
275
396
|
// Extract the other elements if it's also a Container
|
|
276
397
|
const isContainer = p.kind === java_1.J.Kind.Container;
|
|
277
398
|
const otherContainer = isContainer ? p : undefined;
|
|
278
399
|
const otherElements = isContainer ? otherContainer.elements : p;
|
|
279
400
|
// Compare elements array length
|
|
280
401
|
if (container.elements.length !== otherElements.length) {
|
|
281
|
-
return this.
|
|
402
|
+
return this.arrayLengthMismatch('elements');
|
|
282
403
|
}
|
|
283
404
|
// Push wrappers onto both cursors, then compare each element
|
|
284
405
|
const savedCursor = this.cursor;
|
|
@@ -288,9 +409,8 @@ class JavaScriptComparatorVisitor extends visitor_1.JavaScriptVisitor {
|
|
|
288
409
|
try {
|
|
289
410
|
for (let i = 0; i < container.elements.length; i++) {
|
|
290
411
|
yield this.visitProperty(container.elements[i], otherElements[i]);
|
|
291
|
-
if (!this.match)
|
|
292
|
-
return
|
|
293
|
-
}
|
|
412
|
+
if (!this.match)
|
|
413
|
+
return container;
|
|
294
414
|
}
|
|
295
415
|
}
|
|
296
416
|
finally {
|
|
@@ -1988,9 +2108,8 @@ class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVisitor {
|
|
|
1988
2108
|
visit(j, p, parent) {
|
|
1989
2109
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1990
2110
|
// If we've already found a mismatch, abort further processing
|
|
1991
|
-
if (!this.match)
|
|
2111
|
+
if (!this.match)
|
|
1992
2112
|
return j;
|
|
1993
|
-
}
|
|
1994
2113
|
// Unwrap parentheses from both trees before comparing
|
|
1995
2114
|
const unwrappedJ = this.unwrap(j) || j;
|
|
1996
2115
|
const unwrappedP = this.unwrap(p) || p;
|
|
@@ -2018,11 +2137,10 @@ class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVisitor {
|
|
|
2018
2137
|
*/
|
|
2019
2138
|
visitArrowFunction(arrowFunction, other) {
|
|
2020
2139
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2021
|
-
if (!this.match)
|
|
2140
|
+
if (!this.match)
|
|
2022
2141
|
return arrowFunction;
|
|
2023
|
-
}
|
|
2024
2142
|
if (other.kind !== tree_1.JS.Kind.ArrowFunction) {
|
|
2025
|
-
return this.
|
|
2143
|
+
return this.kindMismatch();
|
|
2026
2144
|
}
|
|
2027
2145
|
const otherArrow = other;
|
|
2028
2146
|
// Compare all properties reflectively except lambda (handled specially below)
|
|
@@ -2035,7 +2153,7 @@ class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVisitor {
|
|
|
2035
2153
|
// Handle arrays
|
|
2036
2154
|
if (Array.isArray(jValue)) {
|
|
2037
2155
|
if (!Array.isArray(otherValue) || jValue.length !== otherValue.length) {
|
|
2038
|
-
return this.
|
|
2156
|
+
return this.arrayLengthMismatch(key);
|
|
2039
2157
|
}
|
|
2040
2158
|
for (let i = 0; i < jValue.length; i++) {
|
|
2041
2159
|
yield this.visitProperty(jValue[i], otherValue[i]);
|
|
@@ -2053,7 +2171,7 @@ class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVisitor {
|
|
|
2053
2171
|
const params1 = arrowFunction.lambda.parameters.parameters;
|
|
2054
2172
|
const params2 = otherArrow.lambda.parameters.parameters;
|
|
2055
2173
|
if (params1.length !== params2.length) {
|
|
2056
|
-
return this.
|
|
2174
|
+
return this.arrayLengthMismatch('lambda.parameters.parameters');
|
|
2057
2175
|
}
|
|
2058
2176
|
for (let i = 0; i < params1.length; i++) {
|
|
2059
2177
|
yield this.visitProperty(params1[i], params2[i]);
|
|
@@ -2087,11 +2205,10 @@ class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVisitor {
|
|
|
2087
2205
|
*/
|
|
2088
2206
|
visitLambdaParameters(parameters, other) {
|
|
2089
2207
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2090
|
-
if (!this.match)
|
|
2208
|
+
if (!this.match)
|
|
2091
2209
|
return parameters;
|
|
2092
|
-
}
|
|
2093
2210
|
if (other.kind !== java_1.J.Kind.LambdaParameters) {
|
|
2094
|
-
return this.
|
|
2211
|
+
return this.kindMismatch();
|
|
2095
2212
|
}
|
|
2096
2213
|
const otherParams = other;
|
|
2097
2214
|
// Compare all properties except 'parenthesized' using reflection
|
|
@@ -2104,7 +2221,7 @@ class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVisitor {
|
|
|
2104
2221
|
// Handle arrays
|
|
2105
2222
|
if (Array.isArray(jValue)) {
|
|
2106
2223
|
if (!Array.isArray(otherValue) || jValue.length !== otherValue.length) {
|
|
2107
|
-
return this.
|
|
2224
|
+
return this.arrayLengthMismatch(key);
|
|
2108
2225
|
}
|
|
2109
2226
|
for (let i = 0; i < jValue.length; i++) {
|
|
2110
2227
|
yield this.visitProperty(jValue[i], otherValue[i]);
|
|
@@ -2134,11 +2251,10 @@ class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVisitor {
|
|
|
2134
2251
|
visitPropertyAssignment: { get: () => super.visitPropertyAssignment }
|
|
2135
2252
|
});
|
|
2136
2253
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2137
|
-
if (!this.match)
|
|
2254
|
+
if (!this.match)
|
|
2138
2255
|
return propertyAssignment;
|
|
2139
|
-
}
|
|
2140
2256
|
if (other.kind !== tree_1.JS.Kind.PropertyAssignment) {
|
|
2141
|
-
return this.
|
|
2257
|
+
return this.kindMismatch();
|
|
2142
2258
|
}
|
|
2143
2259
|
const otherProp = other;
|
|
2144
2260
|
// Extract property names for semantic comparison
|
|
@@ -2165,7 +2281,7 @@ class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVisitor {
|
|
|
2165
2281
|
}
|
|
2166
2282
|
else {
|
|
2167
2283
|
// Not equivalent (e.g., { x: y })
|
|
2168
|
-
return this.
|
|
2284
|
+
return this.structuralMismatch('initializer');
|
|
2169
2285
|
}
|
|
2170
2286
|
});
|
|
2171
2287
|
}
|
|
@@ -2214,7 +2330,7 @@ class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVisitor {
|
|
|
2214
2330
|
* When lenientTypeMatching is enabled, null vs Type comparisons are allowed
|
|
2215
2331
|
* (where one value is null/undefined and the other is a Type object).
|
|
2216
2332
|
*/
|
|
2217
|
-
visitProperty(j, other) {
|
|
2333
|
+
visitProperty(j, other, propertyName) {
|
|
2218
2334
|
const _super = Object.create(null, {
|
|
2219
2335
|
visitProperty: { get: () => super.visitProperty }
|
|
2220
2336
|
});
|
|
@@ -2228,7 +2344,7 @@ class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVisitor {
|
|
|
2228
2344
|
const isTypeComparison = (jKind && typeof jKind === 'string' && jKind.startsWith('org.openrewrite.java.tree.JavaType$')) ||
|
|
2229
2345
|
(otherKind && typeof otherKind === 'string' && otherKind.startsWith('org.openrewrite.java.tree.JavaType$'));
|
|
2230
2346
|
if (!isTypeComparison) {
|
|
2231
|
-
this.
|
|
2347
|
+
this.structuralMismatch(propertyName);
|
|
2232
2348
|
}
|
|
2233
2349
|
}
|
|
2234
2350
|
return j;
|
|
@@ -2314,13 +2430,9 @@ class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVisitor {
|
|
|
2314
2430
|
});
|
|
2315
2431
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2316
2432
|
if (other.kind !== java_1.J.Kind.MethodInvocation) {
|
|
2317
|
-
return this.
|
|
2433
|
+
return this.kindMismatch();
|
|
2318
2434
|
}
|
|
2319
2435
|
const otherMethod = other;
|
|
2320
|
-
// Check argument length (always required)
|
|
2321
|
-
if (method.arguments.elements.length !== otherMethod.arguments.elements.length) {
|
|
2322
|
-
return this.abort(method);
|
|
2323
|
-
}
|
|
2324
2436
|
// Check if we can skip name checking based on type attribution
|
|
2325
2437
|
// We can only skip the name check if both have method types AND they represent the SAME method
|
|
2326
2438
|
// (not just type-compatible methods, but the actual same function with same FQN)
|
|
@@ -2346,14 +2458,14 @@ class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVisitor {
|
|
|
2346
2458
|
// Check names unless we determined we can skip based on type FQN matching
|
|
2347
2459
|
if (!canSkipNameCheck) {
|
|
2348
2460
|
if (method.name.simpleName !== otherMethod.name.simpleName) {
|
|
2349
|
-
return this.
|
|
2461
|
+
return this.valueMismatch('name.simpleName', method.name.simpleName, otherMethod.name.simpleName);
|
|
2350
2462
|
}
|
|
2351
2463
|
// In strict mode, check type attribution requirements
|
|
2352
2464
|
if (!this.lenientTypeMatching) {
|
|
2353
2465
|
// Strict mode: if one has type but the other doesn't, they don't match
|
|
2354
2466
|
if ((method.methodType && !otherMethod.methodType) ||
|
|
2355
2467
|
(!method.methodType && otherMethod.methodType)) {
|
|
2356
|
-
return this.
|
|
2468
|
+
return this.typeMismatch('methodType');
|
|
2357
2469
|
}
|
|
2358
2470
|
}
|
|
2359
2471
|
// If neither has type, use structural comparison
|
|
@@ -2371,7 +2483,7 @@ class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVisitor {
|
|
|
2371
2483
|
const otherFQN = java_1.Type.FullyQualified.getFullyQualifiedName(otherDeclaringType);
|
|
2372
2484
|
// Different declaring types = different methods, even with same name
|
|
2373
2485
|
if (methodFQN !== otherFQN) {
|
|
2374
|
-
return this.
|
|
2486
|
+
return this.valueMismatch('methodType.declaringType');
|
|
2375
2487
|
}
|
|
2376
2488
|
}
|
|
2377
2489
|
}
|
|
@@ -2381,47 +2493,36 @@ class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVisitor {
|
|
|
2381
2493
|
if (!canSkipNameCheck) {
|
|
2382
2494
|
// Types didn't provide a match - must compare receivers structurally
|
|
2383
2495
|
if ((method.select === undefined) !== (otherMethod.select === undefined)) {
|
|
2384
|
-
return this.
|
|
2496
|
+
return this.structuralMismatch('select');
|
|
2385
2497
|
}
|
|
2386
2498
|
if (method.select && otherMethod.select) {
|
|
2387
|
-
yield this.
|
|
2388
|
-
if (!this.match)
|
|
2389
|
-
return
|
|
2390
|
-
}
|
|
2499
|
+
yield this.visitRightPaddedProperty('select', method.select, otherMethod.select);
|
|
2500
|
+
if (!this.match)
|
|
2501
|
+
return method;
|
|
2391
2502
|
}
|
|
2392
2503
|
}
|
|
2393
2504
|
// else: types matched, skip select comparison (allows namespace vs named imports)
|
|
2394
2505
|
// Compare type parameters
|
|
2395
2506
|
if ((method.typeParameters === undefined) !== (otherMethod.typeParameters === undefined)) {
|
|
2396
|
-
return this.
|
|
2507
|
+
return this.structuralMismatch('typeParameters');
|
|
2397
2508
|
}
|
|
2398
2509
|
if (method.typeParameters && otherMethod.typeParameters) {
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
for (let i = 0; i < method.typeParameters.elements.length; i++) {
|
|
2403
|
-
yield this.visitRightPadded(method.typeParameters.elements[i], otherMethod.typeParameters.elements[i]);
|
|
2404
|
-
if (!this.match) {
|
|
2405
|
-
return this.abort(method);
|
|
2406
|
-
}
|
|
2407
|
-
}
|
|
2510
|
+
yield this.visitContainerProperty('typeParameters', method.typeParameters, otherMethod.typeParameters);
|
|
2511
|
+
if (!this.match)
|
|
2512
|
+
return method;
|
|
2408
2513
|
}
|
|
2409
2514
|
// Compare name
|
|
2410
2515
|
// If we determined we can skip name check (same FQN method, possibly aliased), skip it
|
|
2411
2516
|
// This allows matching aliased imports where names differ but types are the same
|
|
2412
2517
|
if (!canSkipNameCheck) {
|
|
2413
2518
|
yield this.visit(method.name, otherMethod.name);
|
|
2414
|
-
if (!this.match)
|
|
2415
|
-
return
|
|
2416
|
-
}
|
|
2417
|
-
}
|
|
2418
|
-
// Compare arguments (visit RightPadded to check for markers)
|
|
2419
|
-
for (let i = 0; i < method.arguments.elements.length; i++) {
|
|
2420
|
-
yield this.visitRightPadded(method.arguments.elements[i], otherMethod.arguments.elements[i]);
|
|
2421
|
-
if (!this.match) {
|
|
2422
|
-
return this.abort(method);
|
|
2423
|
-
}
|
|
2519
|
+
if (!this.match)
|
|
2520
|
+
return method;
|
|
2424
2521
|
}
|
|
2522
|
+
// Compare arguments
|
|
2523
|
+
yield this.visitContainerProperty('arguments', method.arguments, otherMethod.arguments);
|
|
2524
|
+
if (!this.match)
|
|
2525
|
+
return method;
|
|
2425
2526
|
return method;
|
|
2426
2527
|
});
|
|
2427
2528
|
}
|
|
@@ -2441,24 +2542,24 @@ class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVisitor {
|
|
|
2441
2542
|
return identifier;
|
|
2442
2543
|
}
|
|
2443
2544
|
if (other.kind !== java_1.J.Kind.Identifier) {
|
|
2444
|
-
return this.
|
|
2545
|
+
return this.kindMismatch();
|
|
2445
2546
|
}
|
|
2446
2547
|
const otherIdentifier = other;
|
|
2447
2548
|
// Check name matches
|
|
2448
2549
|
if (identifier.simpleName !== otherIdentifier.simpleName) {
|
|
2449
|
-
return this.
|
|
2550
|
+
return this.valueMismatch('simpleName');
|
|
2450
2551
|
}
|
|
2451
2552
|
// For identifiers with field types, check type attribution
|
|
2452
2553
|
if (identifier.fieldType && otherIdentifier.fieldType) {
|
|
2453
2554
|
if (!this.isOfType(identifier.fieldType, otherIdentifier.fieldType)) {
|
|
2454
|
-
return this.
|
|
2555
|
+
return this.typeMismatch('fieldType');
|
|
2455
2556
|
}
|
|
2456
2557
|
}
|
|
2457
2558
|
else if (identifier.fieldType || otherIdentifier.fieldType) {
|
|
2458
2559
|
// Lenient mode: if either has no type, allow structural matching
|
|
2459
2560
|
if (!this.lenientTypeMatching) {
|
|
2460
2561
|
// Strict mode: if only one has a type, they don't match
|
|
2461
|
-
return this.
|
|
2562
|
+
return this.typeMismatch('fieldType');
|
|
2462
2563
|
}
|
|
2463
2564
|
}
|
|
2464
2565
|
return _super.visitIdentifier.call(this, identifier, other);
|
|
@@ -2473,27 +2574,17 @@ class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVisitor {
|
|
|
2473
2574
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2474
2575
|
const otherVariableDeclarations = other;
|
|
2475
2576
|
// Visit leading annotations
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
for (let i = 0; i < variableDeclarations.leadingAnnotations.length; i++) {
|
|
2480
|
-
yield this.visit(variableDeclarations.leadingAnnotations[i], otherVariableDeclarations.leadingAnnotations[i]);
|
|
2481
|
-
if (!this.match)
|
|
2482
|
-
return variableDeclarations;
|
|
2483
|
-
}
|
|
2577
|
+
yield this.visitArrayProperty(variableDeclarations, 'leadingAnnotations', variableDeclarations.leadingAnnotations, otherVariableDeclarations.leadingAnnotations, (ann1, ann2) => __awaiter(this, void 0, void 0, function* () { yield this.visit(ann1, ann2); }));
|
|
2578
|
+
if (!this.match)
|
|
2579
|
+
return variableDeclarations;
|
|
2484
2580
|
// Visit modifiers
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
for (let i = 0; i < variableDeclarations.modifiers.length; i++) {
|
|
2489
|
-
yield this.visit(variableDeclarations.modifiers[i], otherVariableDeclarations.modifiers[i]);
|
|
2490
|
-
if (!this.match)
|
|
2491
|
-
return variableDeclarations;
|
|
2492
|
-
}
|
|
2581
|
+
yield this.visitArrayProperty(variableDeclarations, 'modifiers', variableDeclarations.modifiers, otherVariableDeclarations.modifiers, (mod1, mod2) => __awaiter(this, void 0, void 0, function* () { yield this.visit(mod1, mod2); }));
|
|
2582
|
+
if (!this.match)
|
|
2583
|
+
return variableDeclarations;
|
|
2493
2584
|
// Compare typeExpression - lenient matching allows one to be undefined
|
|
2494
2585
|
if ((variableDeclarations.typeExpression === undefined) !== (otherVariableDeclarations.typeExpression === undefined)) {
|
|
2495
2586
|
if (!this.lenientTypeMatching) {
|
|
2496
|
-
return this.
|
|
2587
|
+
return this.structuralMismatch('typeExpression');
|
|
2497
2588
|
}
|
|
2498
2589
|
// In lenient mode, skip type comparison and continue
|
|
2499
2590
|
}
|
|
@@ -2505,18 +2596,12 @@ class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVisitor {
|
|
|
2505
2596
|
}
|
|
2506
2597
|
// Compare varargs
|
|
2507
2598
|
if ((variableDeclarations.varargs === undefined) !== (otherVariableDeclarations.varargs === undefined)) {
|
|
2508
|
-
return this.
|
|
2599
|
+
return this.structuralMismatch('varargs');
|
|
2509
2600
|
}
|
|
2510
2601
|
// Compare variables
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
// Visit each variable in lock step
|
|
2515
|
-
for (let i = 0; i < variableDeclarations.variables.length; i++) {
|
|
2516
|
-
yield this.visitRightPadded(variableDeclarations.variables[i], otherVariableDeclarations.variables[i]);
|
|
2517
|
-
if (!this.match)
|
|
2518
|
-
return variableDeclarations;
|
|
2519
|
-
}
|
|
2602
|
+
yield this.visitArrayProperty(variableDeclarations, 'variables', variableDeclarations.variables, otherVariableDeclarations.variables, (var1, var2) => __awaiter(this, void 0, void 0, function* () { yield this.visitRightPadded(var1, var2); }));
|
|
2603
|
+
if (!this.match)
|
|
2604
|
+
return variableDeclarations;
|
|
2520
2605
|
return variableDeclarations;
|
|
2521
2606
|
});
|
|
2522
2607
|
}
|
|
@@ -2529,26 +2614,16 @@ class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVisitor {
|
|
|
2529
2614
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2530
2615
|
const otherMethodDeclaration = other;
|
|
2531
2616
|
// Visit leading annotations
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
for (let i = 0; i < methodDeclaration.leadingAnnotations.length; i++) {
|
|
2536
|
-
yield this.visit(methodDeclaration.leadingAnnotations[i], otherMethodDeclaration.leadingAnnotations[i]);
|
|
2537
|
-
if (!this.match)
|
|
2538
|
-
return methodDeclaration;
|
|
2539
|
-
}
|
|
2617
|
+
yield this.visitArrayProperty(methodDeclaration, 'leadingAnnotations', methodDeclaration.leadingAnnotations, otherMethodDeclaration.leadingAnnotations, (ann1, ann2) => __awaiter(this, void 0, void 0, function* () { yield this.visit(ann1, ann2); }));
|
|
2618
|
+
if (!this.match)
|
|
2619
|
+
return methodDeclaration;
|
|
2540
2620
|
// Visit modifiers
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
for (let i = 0; i < methodDeclaration.modifiers.length; i++) {
|
|
2545
|
-
yield this.visit(methodDeclaration.modifiers[i], otherMethodDeclaration.modifiers[i]);
|
|
2546
|
-
if (!this.match)
|
|
2547
|
-
return methodDeclaration;
|
|
2548
|
-
}
|
|
2621
|
+
yield this.visitArrayProperty(methodDeclaration, 'modifiers', methodDeclaration.modifiers, otherMethodDeclaration.modifiers, (mod1, mod2) => __awaiter(this, void 0, void 0, function* () { yield this.visit(mod1, mod2); }));
|
|
2622
|
+
if (!this.match)
|
|
2623
|
+
return methodDeclaration;
|
|
2549
2624
|
// Visit type parameters if present
|
|
2550
2625
|
if (!!methodDeclaration.typeParameters !== !!otherMethodDeclaration.typeParameters) {
|
|
2551
|
-
return this.
|
|
2626
|
+
return this.structuralMismatch('typeParameters');
|
|
2552
2627
|
}
|
|
2553
2628
|
if (methodDeclaration.typeParameters && otherMethodDeclaration.typeParameters) {
|
|
2554
2629
|
yield this.visit(methodDeclaration.typeParameters, otherMethodDeclaration.typeParameters);
|
|
@@ -2558,7 +2633,7 @@ class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVisitor {
|
|
|
2558
2633
|
// Compare returnTypeExpression - lenient matching allows one to be undefined
|
|
2559
2634
|
if ((methodDeclaration.returnTypeExpression === undefined) !== (otherMethodDeclaration.returnTypeExpression === undefined)) {
|
|
2560
2635
|
if (!this.lenientTypeMatching) {
|
|
2561
|
-
return this.
|
|
2636
|
+
return this.typeMismatch('returnTypeExpression');
|
|
2562
2637
|
}
|
|
2563
2638
|
// In lenient mode, skip type comparison and continue
|
|
2564
2639
|
}
|
|
@@ -2573,33 +2648,21 @@ class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVisitor {
|
|
|
2573
2648
|
if (!this.match)
|
|
2574
2649
|
return methodDeclaration;
|
|
2575
2650
|
// Compare parameters
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
// Visit each parameter in lock step
|
|
2580
|
-
for (let i = 0; i < methodDeclaration.parameters.elements.length; i++) {
|
|
2581
|
-
yield this.visitRightPadded(methodDeclaration.parameters.elements[i], otherMethodDeclaration.parameters.elements[i]);
|
|
2582
|
-
if (!this.match)
|
|
2583
|
-
return methodDeclaration;
|
|
2584
|
-
}
|
|
2651
|
+
yield this.visitContainer(methodDeclaration.parameters, otherMethodDeclaration.parameters);
|
|
2652
|
+
if (!this.match)
|
|
2653
|
+
return methodDeclaration;
|
|
2585
2654
|
// Visit throws if present
|
|
2586
2655
|
if (!!methodDeclaration.throws !== !!otherMethodDeclaration.throws) {
|
|
2587
|
-
return this.
|
|
2656
|
+
return this.structuralMismatch('throws');
|
|
2588
2657
|
}
|
|
2589
2658
|
if (methodDeclaration.throws && otherMethodDeclaration.throws) {
|
|
2590
|
-
|
|
2591
|
-
if (
|
|
2592
|
-
return
|
|
2593
|
-
}
|
|
2594
|
-
for (let i = 0; i < methodDeclaration.throws.elements.length; i++) {
|
|
2595
|
-
yield this.visitRightPadded(methodDeclaration.throws.elements[i], otherMethodDeclaration.throws.elements[i]);
|
|
2596
|
-
if (!this.match)
|
|
2597
|
-
return methodDeclaration;
|
|
2598
|
-
}
|
|
2659
|
+
yield this.visitContainer(methodDeclaration.throws, otherMethodDeclaration.throws);
|
|
2660
|
+
if (!this.match)
|
|
2661
|
+
return methodDeclaration;
|
|
2599
2662
|
}
|
|
2600
2663
|
// Visit body if present
|
|
2601
2664
|
if (!!methodDeclaration.body !== !!otherMethodDeclaration.body) {
|
|
2602
|
-
return this.
|
|
2665
|
+
return this.structuralMismatch('body');
|
|
2603
2666
|
}
|
|
2604
2667
|
if (methodDeclaration.body && otherMethodDeclaration.body) {
|
|
2605
2668
|
yield this.visit(methodDeclaration.body, otherMethodDeclaration.body);
|
|
@@ -2624,9 +2687,8 @@ class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVisitor {
|
|
|
2624
2687
|
visitVoid: { get: () => super.visitVoid }
|
|
2625
2688
|
});
|
|
2626
2689
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2627
|
-
if (!this.match)
|
|
2690
|
+
if (!this.match)
|
|
2628
2691
|
return voidExpr;
|
|
2629
|
-
}
|
|
2630
2692
|
// Check if the other is an undefined identifier
|
|
2631
2693
|
if (other.kind === java_1.J.Kind.Identifier) {
|
|
2632
2694
|
const identifier = other;
|
|
@@ -2654,18 +2716,17 @@ class JavaScriptSemanticComparatorVisitor extends JavaScriptComparatorVisitor {
|
|
|
2654
2716
|
visitLiteral: { get: () => super.visitLiteral }
|
|
2655
2717
|
});
|
|
2656
2718
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2657
|
-
if (!this.match)
|
|
2719
|
+
if (!this.match)
|
|
2658
2720
|
return literal;
|
|
2659
|
-
}
|
|
2660
2721
|
if (other.kind !== java_1.J.Kind.Literal) {
|
|
2661
2722
|
return yield _super.visitLiteral.call(this, literal, other);
|
|
2662
2723
|
}
|
|
2663
2724
|
const otherLiteral = other;
|
|
2664
2725
|
// Only compare value and type, ignoring valueSource (text representation) and unicodeEscapes
|
|
2665
|
-
yield this.visitProperty(literal.value, otherLiteral.value);
|
|
2726
|
+
yield this.visitProperty(literal.value, otherLiteral.value, 'value');
|
|
2666
2727
|
if (!this.match)
|
|
2667
2728
|
return literal;
|
|
2668
|
-
yield this.visitProperty(literal.type, otherLiteral.type);
|
|
2729
|
+
yield this.visitProperty(literal.type, otherLiteral.type, 'type');
|
|
2669
2730
|
if (!this.match)
|
|
2670
2731
|
return literal;
|
|
2671
2732
|
return literal;
|