@openrewrite/rewrite 8.66.0-20251031-152250 → 8.66.0-20251031-160320
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 +24 -1
- package/dist/javascript/comparator.d.ts.map +1 -1
- package/dist/javascript/comparator.js +532 -673
- package/dist/javascript/comparator.js.map +1 -1
- package/dist/javascript/templating.d.ts.map +1 -1
- package/dist/javascript/templating.js +1 -137
- package/dist/javascript/templating.js.map +1 -1
- package/dist/version.txt +1 -1
- package/package.json +1 -1
- package/src/javascript/comparator.ts +553 -670
- package/src/javascript/templating.ts +3 -147
|
@@ -17,9 +17,9 @@ import {JS} from '.';
|
|
|
17
17
|
import {JavaScriptParser} from './parser';
|
|
18
18
|
import {JavaScriptVisitor} from './visitor';
|
|
19
19
|
import {Cursor, isTree, Tree} from '..';
|
|
20
|
-
import {J
|
|
20
|
+
import {J} from '../java';
|
|
21
21
|
import {produce} from "immer";
|
|
22
|
-
import {
|
|
22
|
+
import {JavaScriptSemanticComparatorVisitor} from "./comparator";
|
|
23
23
|
import {DependencyWorkspace} from './dependency-workspace';
|
|
24
24
|
import {Marker} from '../markers';
|
|
25
25
|
import {randomId} from '../uuid';
|
|
@@ -264,150 +264,6 @@ export class MatchResult implements Pick<Map<string, J>, "get"> {
|
|
|
264
264
|
}
|
|
265
265
|
}
|
|
266
266
|
|
|
267
|
-
/**
|
|
268
|
-
* A comparator visitor that checks semantic equality including type attribution.
|
|
269
|
-
* This ensures that patterns only match code with compatible types, not just
|
|
270
|
-
* structurally similar code.
|
|
271
|
-
*/
|
|
272
|
-
class JavaScriptTemplateSemanticallyEqualVisitor extends JavaScriptComparatorVisitor {
|
|
273
|
-
/**
|
|
274
|
-
* Checks if two types are semantically equal.
|
|
275
|
-
* For method types, this checks that the declaring type and method name match.
|
|
276
|
-
*/
|
|
277
|
-
private isOfType(target?: Type, source?: Type): boolean {
|
|
278
|
-
if (!target || !source) {
|
|
279
|
-
return target === source;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
if (target.kind !== source.kind) {
|
|
283
|
-
return false;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// For method types, check declaring type
|
|
287
|
-
// Note: We don't check the name field because it might not be fully resolved in patterns
|
|
288
|
-
// The method invocation visitor already checks that simple names match
|
|
289
|
-
if (target.kind === Type.Kind.Method && source.kind === Type.Kind.Method) {
|
|
290
|
-
const targetMethod = target as Type.Method;
|
|
291
|
-
const sourceMethod = source as Type.Method;
|
|
292
|
-
|
|
293
|
-
// Only check that declaring types match
|
|
294
|
-
return this.isOfType(targetMethod.declaringType, sourceMethod.declaringType);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
// For fully qualified types, check the fully qualified name
|
|
298
|
-
if (Type.isFullyQualified(target) && Type.isFullyQualified(source)) {
|
|
299
|
-
return Type.FullyQualified.getFullyQualifiedName(target) ===
|
|
300
|
-
Type.FullyQualified.getFullyQualifiedName(source);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
// Default: types are equal if they're the same kind
|
|
304
|
-
return true;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
* Override method invocation comparison to include type attribution checking.
|
|
309
|
-
* When types match semantically, we allow matching even if one has a receiver
|
|
310
|
-
* and the other doesn't (e.g., `isDate(x)` vs `util.isDate(x)`).
|
|
311
|
-
*/
|
|
312
|
-
override async visitMethodInvocation(method: J.MethodInvocation, other: J): Promise<J | undefined> {
|
|
313
|
-
if (other.kind !== J.Kind.MethodInvocation) {
|
|
314
|
-
return method;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
const otherMethod = other as J.MethodInvocation;
|
|
318
|
-
|
|
319
|
-
// Check basic structural equality first
|
|
320
|
-
if (method.name.simpleName !== otherMethod.name.simpleName ||
|
|
321
|
-
method.arguments.elements.length !== otherMethod.arguments.elements.length) {
|
|
322
|
-
this.abort();
|
|
323
|
-
return method;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// Check type attribution
|
|
327
|
-
// Both must have method types for semantic equality
|
|
328
|
-
if (!method.methodType || !otherMethod.methodType) {
|
|
329
|
-
// If template has type but target doesn't, they don't match
|
|
330
|
-
if (method.methodType || otherMethod.methodType) {
|
|
331
|
-
this.abort();
|
|
332
|
-
return method;
|
|
333
|
-
}
|
|
334
|
-
// If neither has type, fall through to structural comparison
|
|
335
|
-
return super.visitMethodInvocation(method, other);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// Both have types - check they match semantically
|
|
339
|
-
const typesMatch = this.isOfType(method.methodType, otherMethod.methodType);
|
|
340
|
-
if (!typesMatch) {
|
|
341
|
-
// Types don't match - abort comparison
|
|
342
|
-
this.abort();
|
|
343
|
-
return method;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// Types match! Now we can ignore receiver differences and just compare arguments.
|
|
347
|
-
// This allows pattern `isDate(x)` to match both `isDate(x)` and `util.isDate(x)`
|
|
348
|
-
// when they have the same type attribution.
|
|
349
|
-
|
|
350
|
-
// Compare type parameters
|
|
351
|
-
if ((method.typeParameters === undefined) !== (otherMethod.typeParameters === undefined)) {
|
|
352
|
-
this.abort();
|
|
353
|
-
return method;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
if (method.typeParameters && otherMethod.typeParameters) {
|
|
357
|
-
if (method.typeParameters.elements.length !== otherMethod.typeParameters.elements.length) {
|
|
358
|
-
this.abort();
|
|
359
|
-
return method;
|
|
360
|
-
}
|
|
361
|
-
for (let i = 0; i < method.typeParameters.elements.length; i++) {
|
|
362
|
-
await this.visit(method.typeParameters.elements[i].element, otherMethod.typeParameters.elements[i].element);
|
|
363
|
-
if (!this.match) return method;
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
// Compare name (already checked simpleName above, but visit for markers/prefix)
|
|
368
|
-
await this.visit(method.name, otherMethod.name);
|
|
369
|
-
if (!this.match) return method;
|
|
370
|
-
|
|
371
|
-
// Compare arguments
|
|
372
|
-
for (let i = 0; i < method.arguments.elements.length; i++) {
|
|
373
|
-
await this.visit(method.arguments.elements[i].element, otherMethod.arguments.elements[i].element);
|
|
374
|
-
if (!this.match) return method;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
return method;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
/**
|
|
381
|
-
* Override identifier comparison to include type checking for field access.
|
|
382
|
-
*/
|
|
383
|
-
override async visitIdentifier(identifier: J.Identifier, other: J): Promise<J | undefined> {
|
|
384
|
-
if (other.kind !== J.Kind.Identifier) {
|
|
385
|
-
return identifier;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
const otherIdentifier = other as J.Identifier;
|
|
389
|
-
|
|
390
|
-
// Check name matches
|
|
391
|
-
if (identifier.simpleName !== otherIdentifier.simpleName) {
|
|
392
|
-
return identifier;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
// For identifiers with field types, check type attribution
|
|
396
|
-
if (identifier.fieldType && otherIdentifier.fieldType) {
|
|
397
|
-
if (!this.isOfType(identifier.fieldType, otherIdentifier.fieldType)) {
|
|
398
|
-
this.abort();
|
|
399
|
-
return identifier;
|
|
400
|
-
}
|
|
401
|
-
} else if (identifier.fieldType || otherIdentifier.fieldType) {
|
|
402
|
-
// If only one has a type, they don't match
|
|
403
|
-
this.abort();
|
|
404
|
-
return identifier;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
return super.visitIdentifier(identifier, other);
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
|
|
411
267
|
/**
|
|
412
268
|
* Matcher for checking if a pattern matches an AST node and extracting captured nodes.
|
|
413
269
|
*/
|
|
@@ -474,7 +330,7 @@ class Matcher {
|
|
|
474
330
|
}
|
|
475
331
|
|
|
476
332
|
const matcher = this;
|
|
477
|
-
return await ((new class extends
|
|
333
|
+
return await ((new class extends JavaScriptSemanticComparatorVisitor {
|
|
478
334
|
protected hasSameKind(j: J, other: J): boolean {
|
|
479
335
|
return super.hasSameKind(j, other) || j.kind == J.Kind.Identifier && this.matchesParameter(j as J.Identifier, other);
|
|
480
336
|
}
|