@openrewrite/rewrite 8.96.2 → 8.96.4

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 (52) hide show
  1. package/dist/java/tree.d.ts +11 -11
  2. package/dist/java/tree.d.ts.map +1 -1
  3. package/dist/java/visitor.d.ts.map +1 -1
  4. package/dist/java/visitor.js +30 -0
  5. package/dist/java/visitor.js.map +1 -1
  6. package/dist/javascript/add-import.d.ts.map +1 -1
  7. package/dist/javascript/add-import.js +3 -29
  8. package/dist/javascript/add-import.js.map +1 -1
  9. package/dist/javascript/format/format.d.ts +2 -0
  10. package/dist/javascript/format/format.d.ts.map +1 -1
  11. package/dist/javascript/format/format.js +7 -1
  12. package/dist/javascript/format/format.js.map +1 -1
  13. package/dist/javascript/parser-utils.d.ts.map +1 -1
  14. package/dist/javascript/parser-utils.js +15 -7
  15. package/dist/javascript/parser-utils.js.map +1 -1
  16. package/dist/javascript/scope.d.ts +5 -0
  17. package/dist/javascript/scope.d.ts.map +1 -1
  18. package/dist/javascript/scope.js +9 -0
  19. package/dist/javascript/scope.js.map +1 -1
  20. package/dist/javascript/templating/precedence.js +1 -1
  21. package/dist/javascript/templating/precedence.js.map +1 -1
  22. package/dist/javascript/tree.d.ts +12 -12
  23. package/dist/javascript/tree.d.ts.map +1 -1
  24. package/dist/javascript/visitor.d.ts.map +1 -1
  25. package/dist/javascript/visitor.js +75 -0
  26. package/dist/javascript/visitor.js.map +1 -1
  27. package/dist/rewrite-javascript-version.txt +1 -1
  28. package/dist/test/rewrite-test.d.ts +1 -0
  29. package/dist/test/rewrite-test.d.ts.map +1 -1
  30. package/dist/test/rewrite-test.js +13 -1
  31. package/dist/test/rewrite-test.js.map +1 -1
  32. package/node_modules/picomatch/LICENSE +21 -0
  33. package/node_modules/picomatch/README.md +743 -0
  34. package/node_modules/picomatch/index.js +17 -0
  35. package/node_modules/picomatch/lib/constants.js +184 -0
  36. package/node_modules/picomatch/lib/parse.js +1506 -0
  37. package/node_modules/picomatch/lib/picomatch.js +361 -0
  38. package/node_modules/picomatch/lib/scan.js +403 -0
  39. package/node_modules/picomatch/lib/utils.js +72 -0
  40. package/node_modules/picomatch/package.json +83 -0
  41. package/node_modules/picomatch/posix.js +3 -0
  42. package/package.json +88 -90
  43. package/src/java/tree.ts +11 -11
  44. package/src/java/visitor.ts +36 -0
  45. package/src/javascript/add-import.ts +4 -33
  46. package/src/javascript/format/format.ts +7 -1
  47. package/src/javascript/parser-utils.ts +15 -7
  48. package/src/javascript/scope.ts +9 -0
  49. package/src/javascript/templating/precedence.ts +1 -1
  50. package/src/javascript/tree.ts +12 -12
  51. package/src/javascript/visitor.ts +90 -0
  52. package/src/test/rewrite-test.ts +14 -1
package/package.json CHANGED
@@ -1,108 +1,106 @@
1
1
  {
2
- "name": "@openrewrite/rewrite",
3
- "version": "8.96.2",
4
- "license": "Moderne Source Available License",
5
- "description": "OpenRewrite JavaScript.",
6
- "repository": {
7
- "type": "git",
8
- "url": "https://github.com/openrewrite/rewrite",
9
- "directory": "rewrite-javascript/rewrite"
2
+ "name" : "@openrewrite/rewrite",
3
+ "version" : "8.96.4",
4
+ "license" : "Moderne Source Available License",
5
+ "description" : "OpenRewrite JavaScript.",
6
+ "repository" : {
7
+ "type" : "git",
8
+ "url" : "https://github.com/openrewrite/rewrite",
9
+ "directory" : "rewrite-javascript/rewrite"
10
10
  },
11
- "homepage": "https://github.com/openrewrite/rewrite",
12
- "main": "./dist/index.js",
13
- "types": "./dist/index.d.ts",
14
- "files": [
15
- "dist/**",
16
- "src/**"
17
- ],
18
- "allowScripts": {
19
- "bun": true,
20
- "@datadog/pprof": true
11
+ "homepage" : "https://github.com/openrewrite/rewrite",
12
+ "main" : "./dist/index.js",
13
+ "types" : "./dist/index.d.ts",
14
+ "files" : [ "dist/**", "src/**" ],
15
+ "allowScripts" : {
16
+ "bun" : true,
17
+ "@datadog/pprof" : true
21
18
  },
22
- "exports": {
23
- ".": {
24
- "types": "./dist/index.d.ts",
25
- "default": "./dist/index.js"
19
+ "exports" : {
20
+ "." : {
21
+ "types" : "./dist/index.d.ts",
22
+ "default" : "./dist/index.js"
26
23
  },
27
- "./text": {
28
- "types": "./dist/text/index.d.ts",
29
- "default": "./dist/text/index.js"
24
+ "./text" : {
25
+ "types" : "./dist/text/index.d.ts",
26
+ "default" : "./dist/text/index.js"
30
27
  },
31
- "./json": {
32
- "types": "./dist/json/index.d.ts",
33
- "default": "./dist/json/index.js"
28
+ "./json" : {
29
+ "types" : "./dist/json/index.d.ts",
30
+ "default" : "./dist/json/index.js"
34
31
  },
35
- "./java": {
36
- "types": "./dist/java/index.d.ts",
37
- "default": "./dist/java/index.js"
32
+ "./java" : {
33
+ "types" : "./dist/java/index.d.ts",
34
+ "default" : "./dist/java/index.js"
38
35
  },
39
- "./javascript": {
40
- "types": "./dist/javascript/index.d.ts",
41
- "default": "./dist/javascript/index.js"
36
+ "./javascript" : {
37
+ "types" : "./dist/javascript/index.d.ts",
38
+ "default" : "./dist/javascript/index.js"
42
39
  },
43
- "./rpc": {
44
- "types": "./dist/rpc/index.d.ts",
45
- "default": "./dist/rpc/index.js"
40
+ "./rpc" : {
41
+ "types" : "./dist/rpc/index.d.ts",
42
+ "default" : "./dist/rpc/index.js"
46
43
  },
47
- "./test": {
48
- "types": "./dist/test/index.d.ts",
49
- "default": "./dist/test/index.js"
44
+ "./test" : {
45
+ "types" : "./dist/test/index.d.ts",
46
+ "default" : "./dist/test/index.js"
50
47
  },
51
- "./test/java-rpc": {
52
- "types": "./dist/test/java-rpc.d.ts",
53
- "default": "./dist/test/java-rpc.js"
48
+ "./test/java-rpc" : {
49
+ "types" : "./dist/test/java-rpc.d.ts",
50
+ "default" : "./dist/test/java-rpc.js"
54
51
  },
55
- "./yaml": {
56
- "types": "./dist/yaml/index.d.ts",
57
- "default": "./dist/yaml/index.js"
52
+ "./yaml" : {
53
+ "types" : "./dist/yaml/index.d.ts",
54
+ "default" : "./dist/yaml/index.js"
58
55
  }
59
56
  },
60
- "scripts": {
61
- "prebuild": "bun -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && bun -e \"require('fs').rmSync('tsconfig.build.tsbuildinfo',{force:true})\"",
62
- "build": "tsc --build tsconfig.build.json",
63
- "postbuild": "bun -e \"require('fs').chmodSync('dist/rpc/server.js', 0o755); require('fs').chmodSync('dist/javascript/type-report-cli.js', 0o755)\" && npm link --no-audit --no-fund --loglevel=warn",
64
- "typecheck": "tsc --noEmit -p tsconfig.test.json",
65
- "dev": "tsc --watch -p tsconfig.json",
66
- "test": "npm run typecheck && npm run build && vitest run",
67
- "testhelper": "vitest run",
68
- "build:fixtures": "tsc --build fixtures/tsconfig.json",
69
- "start": "npm run build && node ./dist/rpc/server.js"
57
+ "scripts" : {
58
+ "prebuild" : "bun -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && bun -e \"require('fs').rmSync('tsconfig.build.tsbuildinfo',{force:true})\"",
59
+ "build" : "tsc --build tsconfig.build.json",
60
+ "postbuild" : "bun -e \"require('fs').chmodSync('dist/rpc/server.js', 0o755); require('fs').chmodSync('dist/javascript/type-report-cli.js', 0o755)\" && npm link --no-audit --no-fund --loglevel=warn",
61
+ "typecheck" : "tsc --noEmit -p tsconfig.test.json",
62
+ "dev" : "tsc --watch -p tsconfig.json",
63
+ "test" : "npm run typecheck && npm run build && vitest run",
64
+ "testhelper" : "vitest run",
65
+ "build:fixtures" : "tsc --build fixtures/tsconfig.json",
66
+ "start" : "npm run build && node ./dist/rpc/server.js"
70
67
  },
71
- "dependencies": {
72
- "@akashrajpurohit/snowflake-id": "^2.0.0",
73
- "@types/node": "^22.5.4",
74
- "commander": "^10.0.1",
75
- "diff": "^8.0.0",
76
- "jsonc-parser": "^3.3.1",
77
- "mutative": "^1.3.0",
78
- "picomatch": "^4.0.4",
79
- "semver": "^7.7.4",
80
- "tmp-promise": "^3.0.3",
81
- "typescript": "^6.0.3",
82
- "vscode-jsonrpc": "^8.2.1",
83
- "yaml": "^2.9.0"
68
+ "dependencies" : {
69
+ "@akashrajpurohit/snowflake-id" : "^2.0.0",
70
+ "@types/node" : "^22.5.4",
71
+ "commander" : "^10.0.1",
72
+ "diff" : "^8.0.0",
73
+ "jsonc-parser" : "^3.3.1",
74
+ "mutative" : "^1.3.0",
75
+ "picomatch" : "4.0.8-backpatch-00001",
76
+ "semver" : "^7.7.4",
77
+ "tmp-promise" : "^3.0.3",
78
+ "typescript" : "^6.0.3",
79
+ "vscode-jsonrpc" : "^8.2.1",
80
+ "yaml" : "^2.9.0"
84
81
  },
85
- "devDependencies": {
86
- "@types/benchmark": "^2.1.5",
87
- "@types/diff": "^8.0.0",
88
- "@types/picomatch": "^4.0.2",
89
- "@types/semver": "^7.7.1",
90
- "@types/tmp": "^0.2.6",
91
- "benchmark": "^2.1.4",
92
- "bun": "^1.3.5",
93
- "prettier": "^3.7.4",
94
- "vitest": "^4.1.8"
82
+ "devDependencies" : {
83
+ "@types/benchmark" : "^2.1.5",
84
+ "@types/diff" : "^8.0.0",
85
+ "@types/picomatch" : "^4.0.2",
86
+ "@types/semver" : "^7.7.1",
87
+ "@types/tmp" : "^0.2.6",
88
+ "benchmark" : "^2.1.4",
89
+ "bun" : "^1.3.5",
90
+ "prettier" : "^3.7.4",
91
+ "vitest" : "^4.1.8"
95
92
  },
96
- "optionalDependencies": {
97
- "@pyroscope/nodejs": "^0.4.0",
98
- "prettier": "^3.7.4"
93
+ "optionalDependencies" : {
94
+ "@pyroscope/nodejs" : "^0.4.0",
95
+ "prettier" : "^3.7.4"
99
96
  },
100
- "overrides": {
101
- "tmp": "^0.2.7",
102
- "lodash": "^4.18.1"
97
+ "overrides" : {
98
+ "tmp" : "^0.2.7",
99
+ "lodash" : "^4.18.1"
103
100
  },
104
- "bin": {
105
- "rewrite-rpc": "./dist/rpc/server.js",
106
- "rewrite-javascript-types": "./dist/javascript/type-report-cli.js"
107
- }
108
- }
101
+ "bin" : {
102
+ "rewrite-rpc" : "./dist/rpc/server.js",
103
+ "rewrite-javascript-types" : "./dist/javascript/type-report-cli.js"
104
+ },
105
+ "bundleDependencies" : [ "picomatch" ]
106
+ }
package/src/java/tree.ts CHANGED
@@ -267,7 +267,7 @@ export namespace J {
267
267
  }
268
268
  }
269
269
 
270
- export interface Block extends J {
270
+ export interface Block extends J, Statement {
271
271
  readonly kind: typeof Kind.Block;
272
272
  readonly static: RightPadded<boolean>;
273
273
  readonly statements: RightPadded<Statement>[];
@@ -426,7 +426,7 @@ export namespace J {
426
426
  }
427
427
  }
428
428
 
429
- export interface Import extends J {
429
+ export interface Import extends J, Statement {
430
430
  readonly kind: typeof Kind.Import;
431
431
  readonly static: LeftPadded<boolean>;
432
432
  readonly qualid: FieldAccess;
@@ -442,7 +442,7 @@ export namespace J {
442
442
  readonly modifier?: Modifier;
443
443
  }
444
444
 
445
- export interface DeconstructionPattern extends J, TypedTree {
445
+ export interface DeconstructionPattern extends J, Expression, TypedTree {
446
446
  readonly kind: typeof Kind.DeconstructionPattern;
447
447
  readonly deconstructor: Expression;
448
448
  readonly nested: Container<J>;
@@ -490,7 +490,7 @@ export namespace J {
490
490
  readonly codePoint: string;
491
491
  }
492
492
 
493
- export interface MemberReference extends J, MethodCall {
493
+ export interface MemberReference extends J, TypedTree, MethodCall {
494
494
  readonly kind: typeof Kind.MemberReference;
495
495
  readonly containing: RightPadded<Expression>;
496
496
  readonly typeParameters?: Container<Expression>;
@@ -499,7 +499,7 @@ export namespace J {
499
499
  readonly variableType?: Type.Variable;
500
500
  }
501
501
 
502
- export interface MethodDeclaration extends J, TypedTree {
502
+ export interface MethodDeclaration extends J, Statement, TypedTree {
503
503
  readonly kind: typeof Kind.MethodDeclaration;
504
504
  readonly leadingAnnotations: Annotation[];
505
505
  readonly modifiers: Modifier[];
@@ -515,7 +515,7 @@ export namespace J {
515
515
  readonly methodType?: Type.Method;
516
516
  }
517
517
 
518
- export interface MethodInvocation extends J, TypedTree, MethodCall {
518
+ export interface MethodInvocation extends J, Statement, TypedTree, MethodCall {
519
519
  readonly kind: typeof Kind.MethodInvocation;
520
520
  readonly select?: RightPadded<Expression>;
521
521
  readonly typeParameters?: Container<Expression>;
@@ -567,7 +567,7 @@ export namespace J {
567
567
  readonly type?: Type;
568
568
  }
569
569
 
570
- export interface NewClass extends J, TypedTree, MethodCall {
570
+ export interface NewClass extends J, Statement, TypedTree, MethodCall {
571
571
  readonly kind: typeof Kind.NewClass;
572
572
  readonly enclosing?: RightPadded<Expression>;
573
573
  readonly new: Space;
@@ -583,13 +583,13 @@ export namespace J {
583
583
  readonly typeTree: RightPadded<TypeTree>;
584
584
  }
585
585
 
586
- export interface Package extends J {
586
+ export interface Package extends J, Statement {
587
587
  readonly kind: typeof Kind.Package;
588
588
  readonly expression: Expression;
589
589
  readonly annotations?: Annotation[];
590
590
  }
591
591
 
592
- export interface ParameterizedType extends J, TypeTree {
592
+ export interface ParameterizedType extends J, TypeTree, Expression {
593
593
  readonly kind: typeof Kind.ParameterizedType;
594
594
  readonly class: NameTree;
595
595
  readonly typeParameters?: Container<Expression>;
@@ -711,7 +711,7 @@ export namespace J {
711
711
  }
712
712
  }
713
713
 
714
- export interface VariableDeclarations extends J, TypedTree {
714
+ export interface VariableDeclarations extends J, Statement, TypedTree {
715
715
  readonly kind: typeof Kind.VariableDeclarations;
716
716
  readonly leadingAnnotations: Annotation[];
717
717
  readonly modifiers: Modifier[];
@@ -721,7 +721,7 @@ export namespace J {
721
721
  }
722
722
 
723
723
  export namespace VariableDeclarations {
724
- export interface NamedVariable extends J {
724
+ export interface NamedVariable extends J, NameTree {
725
725
  readonly kind: typeof Kind.NamedVariable;
726
726
  readonly name: VariableDeclarator;
727
727
  readonly dimensionsAfterName: LeftPadded<Space>[];
@@ -199,6 +199,12 @@ export class JavaVisitor<P> extends TreeVisitor<J, P> {
199
199
  }
200
200
  assignOp = expression as J.AssignmentOperation;
201
201
 
202
+ const statement = await this.visitStatement(assignOp, p);
203
+ if (!statement?.kind || statement.kind !== J.Kind.AssignmentOperation) {
204
+ return statement;
205
+ }
206
+ assignOp = statement as J.AssignmentOperation;
207
+
202
208
  const updates = {
203
209
  prefix: await this.visitSpace(assignOp.prefix, p),
204
210
  markers: await this.visitMarkers(assignOp.markers, p),
@@ -229,6 +235,12 @@ export class JavaVisitor<P> extends TreeVisitor<J, P> {
229
235
  }
230
236
 
231
237
  protected async visitBlock(block: J.Block, p: P): Promise<J | undefined> {
238
+ const statement = await this.visitStatement(block, p);
239
+ if (!statement?.kind || statement.kind !== J.Kind.Block) {
240
+ return statement;
241
+ }
242
+ block = statement as J.Block;
243
+
232
244
  const updates = {
233
245
  prefix: await this.visitSpace(block.prefix, p),
234
246
  markers: await this.visitMarkers(block.markers, p),
@@ -340,6 +352,12 @@ export class JavaVisitor<P> extends TreeVisitor<J, P> {
340
352
  }
341
353
 
342
354
  protected async visitControlParentheses<T extends J>(controlParens: J.ControlParentheses<T>, p: P): Promise<J | undefined> {
355
+ const expression = await this.visitExpression(controlParens, p);
356
+ if (!expression?.kind || expression.kind !== J.Kind.ControlParentheses) {
357
+ return expression;
358
+ }
359
+ controlParens = expression as J.ControlParentheses<T>;
360
+
343
361
  const updates: any = {
344
362
  prefix: await this.visitSpace(controlParens.prefix, p),
345
363
  markers: await this.visitMarkers(controlParens.markers, p),
@@ -797,6 +815,12 @@ export class JavaVisitor<P> extends TreeVisitor<J, P> {
797
815
  }
798
816
  newClass = expression as J.NewClass;
799
817
 
818
+ const statement = await this.visitStatement(newClass, p);
819
+ if (!statement?.kind || statement.kind !== J.Kind.NewClass) {
820
+ return statement;
821
+ }
822
+ newClass = statement as J.NewClass;
823
+
800
824
  const updates: any = {
801
825
  prefix: await this.visitSpace(newClass.prefix, p),
802
826
  markers: await this.visitMarkers(newClass.markers, p),
@@ -845,6 +869,12 @@ export class JavaVisitor<P> extends TreeVisitor<J, P> {
845
869
  }
846
870
 
847
871
  protected async visitParameterizedType(parameterizedType: J.ParameterizedType, p: P): Promise<J | undefined> {
872
+ const expression = await this.visitExpression(parameterizedType, p);
873
+ if (!expression?.kind || expression.kind !== J.Kind.ParameterizedType) {
874
+ return expression;
875
+ }
876
+ parameterizedType = expression as J.ParameterizedType;
877
+
848
878
  const updates: any = {
849
879
  prefix: await this.visitSpace(parameterizedType.prefix, p),
850
880
  markers: await this.visitMarkers(parameterizedType.markers, p),
@@ -856,6 +886,12 @@ export class JavaVisitor<P> extends TreeVisitor<J, P> {
856
886
  }
857
887
 
858
888
  protected async visitParentheses<T extends J>(parentheses: J.Parentheses<T>, p: P): Promise<J | undefined> {
889
+ const expression = await this.visitExpression(parentheses, p);
890
+ if (!expression?.kind || expression.kind !== J.Kind.Parentheses) {
891
+ return expression;
892
+ }
893
+ parentheses = expression as J.Parentheses<T>;
894
+
859
895
  const updates: any = {
860
896
  prefix: await this.visitSpace(parentheses.prefix, p),
861
897
  markers: await this.visitMarkers(parentheses.markers, p),
@@ -8,7 +8,7 @@ import {moduleName, packageNameOf, sameModule, spelledLike} from "./package-name
8
8
  import {emptyMarkers, findMarker, markers, MarkersKind} from "../markers";
9
9
  import {NamedStyles} from "../style";
10
10
  import {getStyle, SpacesStyle, StyleKind} from "./style";
11
- import {bindingNames, compilationUnitOf, cursorOf, declarationsOf, deconflict, namesDeclaredIn, resolve, scopeOf, walk} from "./scope";
11
+ import {bindingNames, compilationUnitOf, cursorOf, declarationsOf, deconflict, isFree, namesDeclaredIn, resolve, scopeOf, walk} from "./scope";
12
12
  import {create as produce, Draft} from "mutative";
13
13
  import {autoFormat} from "./format";
14
14
  import {getPrettierStyle} from "./format/prettier-format";
@@ -1346,14 +1346,13 @@ export class AddImport<P> extends JavaScriptVisitor<P> {
1346
1346
  const self = this;
1347
1347
  const matchesModule = (name: string | undefined) =>
1348
1348
  name !== undefined && (name === expectedDeclaringType || name === targetModule);
1349
- const alreadyBound = moduleScopeBindings(compilationUnit).some(b => b.name === targetName);
1350
1349
 
1351
1350
  // If no existing imports from this module, look for unresolved references
1352
1351
  // If there ARE existing imports, look for references with the expected declaring type
1353
1352
 
1354
1353
  const collector = new class extends JavaScriptVisitor<void> {
1355
1354
  override async visitIdentifier(identifier: J.Identifier, p: void): Promise<J | undefined> {
1356
- if (identifier.simpleName === targetName) {
1355
+ if (!found && identifier.simpleName === targetName && isFree(this.cursor, identifier)) {
1357
1356
  const type = identifier.type;
1358
1357
  const fieldType = identifier.fieldType;
1359
1358
  if (expectedDeclaringType) {
@@ -1364,7 +1363,7 @@ export class AddImport<P> extends JavaScriptVisitor<P> {
1364
1363
  found = true;
1365
1364
  }
1366
1365
  }
1367
- else if (!alreadyBound && type && Type.isClass(type)) {
1366
+ else if (type && Type.isClass(type)) {
1368
1367
  if (self.classTypeMatchesModule(type as Type.Class, expectedDeclaringType) ||
1369
1368
  self.classTypeMatchesModule(type as Type.Class, targetModule)) {
1370
1369
  found = true;
@@ -1417,7 +1416,7 @@ export class AddImport<P> extends JavaScriptVisitor<P> {
1417
1416
  }
1418
1417
  }
1419
1418
  // 4. References typed as the module's namespace object (e.g. `z` from zod)
1420
- else if (!alreadyBound && type && Type.isClass(type) &&
1419
+ else if (type && Type.isClass(type) &&
1421
1420
  sameModule((type as Type.Class).fullyQualifiedName, targetModule)) {
1422
1421
  found = true;
1423
1422
  }
@@ -1425,34 +1424,6 @@ export class AddImport<P> extends JavaScriptVisitor<P> {
1425
1424
  }
1426
1425
  return super.visitIdentifier(identifier, p);
1427
1426
  }
1428
-
1429
- override async visitMethodInvocation(methodInvocation: J.MethodInvocation, p: void): Promise<J | undefined> {
1430
- if (expectedDeclaringType && methodInvocation.methodType && methodInvocation.methodType.name === targetName &&
1431
- matchesModule(Type.FullyQualified.getFullyQualifiedName(methodInvocation.methodType.declaringType))) {
1432
- found = true;
1433
- }
1434
- return super.visitMethodInvocation(methodInvocation, p);
1435
- }
1436
-
1437
- override async visitFunctionCall(functionCall: JS.FunctionCall, p: void): Promise<J | undefined> {
1438
- if (expectedDeclaringType && functionCall.methodType && functionCall.methodType.name === targetName &&
1439
- matchesModule(Type.FullyQualified.getFullyQualifiedName(functionCall.methodType.declaringType))) {
1440
- found = true;
1441
- }
1442
- return super.visitFunctionCall(functionCall, p);
1443
- }
1444
-
1445
- override async visitFieldAccess(fieldAccess: J.FieldAccess, p: void): Promise<J | undefined> {
1446
- const type = fieldAccess.type;
1447
- if (type && Type.isMethod(type)) {
1448
- const methodType = type as Type.Method;
1449
- if (expectedDeclaringType && methodType.name === targetName &&
1450
- matchesModule(Type.FullyQualified.getFullyQualifiedName(methodType.declaringType))) {
1451
- found = true;
1452
- }
1453
- }
1454
- return super.visitFieldAccess(fieldAccess, p);
1455
- }
1456
1427
  };
1457
1428
 
1458
1429
  await collector.visit(compilationUnit, undefined);
@@ -1121,7 +1121,7 @@ export class BlankLinesVisitor<P> extends JavaScriptVisitor<P> {
1121
1121
  } else if (parent?.kind === J.Kind.Block && grandparent?.kind !== J.Kind.NewClass && grandparent?.kind !== JS.Kind.TypeLiteral ||
1122
1122
  (parent?.kind === JS.Kind.CompilationUnit && (parent! as JS.CompilationUnit).statements[0].element.id != draft.id) ||
1123
1123
  (parent?.kind === J.Kind.Case && this.isInsideCaseStatements(parent as J.Case, draft))) {
1124
- if (draft.kind != J.Kind.Case) {
1124
+ if (draft.kind != J.Kind.Case && !this.opensCaseBody(parent, draft)) {
1125
1125
  this.ensurePrefixHasNewLine(draft);
1126
1126
  }
1127
1127
  }
@@ -1151,6 +1151,12 @@ export class BlankLinesVisitor<P> extends JavaScriptVisitor<P> {
1151
1151
  * Check if a statement is inside a Case's statements container or body,
1152
1152
  * not inside the caseLabels container.
1153
1153
  */
1154
+ /** A block that opens a case's statements stays on the line of its label, as in `case X: {`. */
1155
+ private opensCaseBody(parent: J | undefined, statement: J): boolean {
1156
+ return parent?.kind === J.Kind.Case && statement.kind === J.Kind.Block &&
1157
+ (parent as J.Case).statements.elements[0]?.element.id === statement.id;
1158
+ }
1159
+
1154
1160
  private isInsideCaseStatements(caseNode: J.Case, statement: J): boolean {
1155
1161
  // Check if statement is in the statements container
1156
1162
  if (caseNode.statements.elements.some(s => s.element.id === statement.id)) {
@@ -17,7 +17,7 @@ import * as ts from "typescript";
17
17
  import {Expression, J, Statement} from "../java";
18
18
  import {JS} from "./tree";
19
19
 
20
- const is_statements: string[] = [
20
+ const is_statements = new Set<string>([
21
21
  J.Kind.Assert,
22
22
  J.Kind.Assignment,
23
23
  J.Kind.AssignmentOperation,
@@ -55,7 +55,6 @@ const is_statements: string[] = [
55
55
  JS.Kind.ArrowFunction,
56
56
  JS.Kind.BindingElement,
57
57
  JS.Kind.Delete,
58
- JS.Kind.Export,
59
58
  JS.Kind.ExportAssignment,
60
59
  JS.Kind.ExportDeclaration,
61
60
  JS.Kind.ForInLoop,
@@ -70,6 +69,8 @@ const is_statements: string[] = [
70
69
  JS.Kind.NamespaceDeclaration,
71
70
  JS.Kind.PropertyAssignment,
72
71
  JS.Kind.ScopedVariableDeclarations,
72
+ JS.Kind.Shebang,
73
+ JS.Kind.Spread,
73
74
  JS.Kind.TaggedTemplateExpression,
74
75
  JS.Kind.TemplateExpression,
75
76
  JS.Kind.TypeDeclaration,
@@ -77,9 +78,9 @@ const is_statements: string[] = [
77
78
  JS.Kind.WithStatement,
78
79
  JS.Kind.ExpressionStatement,
79
80
  JS.Kind.StatementExpression
80
- ]
81
+ ])
81
82
 
82
- const is_expressions: string[] = [
83
+ const is_expressions = new Set<string>([
83
84
  J.Kind.AnnotatedType,
84
85
  J.Kind.Annotation,
85
86
  J.Kind.ArrayAccess,
@@ -88,6 +89,7 @@ const is_expressions: string[] = [
88
89
  J.Kind.AssignmentOperation,
89
90
  J.Kind.Binary,
90
91
  J.Kind.ControlParentheses,
92
+ J.Kind.DeconstructionPattern,
91
93
  J.Kind.Empty,
92
94
  J.Kind.Erroneous,
93
95
  J.Kind.FieldAccess,
@@ -114,18 +116,23 @@ const is_expressions: string[] = [
114
116
  JS.Kind.Alias,
115
117
  JS.Kind.ArrayBindingPattern,
116
118
  JS.Kind.ArrowFunction,
119
+ JS.Kind.As,
117
120
  JS.Kind.Await,
118
121
  JS.Kind.BindingElement,
122
+ JS.Kind.ComputedPropertyName,
119
123
  JS.Kind.ConditionalType,
120
124
  JS.Kind.Delete,
121
125
  JS.Kind.ExportSpecifier,
122
126
  JS.Kind.ExpressionWithTypeArguments,
127
+ JS.Kind.FunctionCall,
123
128
  JS.Kind.FunctionType,
124
129
  JS.Kind.ImportType,
125
130
  JS.Kind.IndexedAccessType,
126
131
  JS.Kind.IndexedAccessTypeIndexType,
127
132
  JS.Kind.InferType,
128
133
  JS.Kind.Intersection,
134
+ JS.Kind.JsxEmbeddedExpression,
135
+ JS.Kind.JsxTag,
129
136
  JS.Kind.AssignmentOperation,
130
137
  JS.Kind.Binary,
131
138
  JS.Kind.ImportSpecifier,
@@ -135,6 +142,7 @@ const is_expressions: string[] = [
135
142
  JS.Kind.NamedImports,
136
143
  JS.Kind.ObjectBindingPattern,
137
144
  JS.Kind.SatisfiesExpression,
145
+ JS.Kind.Spread,
138
146
  JS.Kind.TaggedTemplateExpression,
139
147
  JS.Kind.TemplateExpression,
140
148
  JS.Kind.Tuple,
@@ -149,14 +157,14 @@ const is_expressions: string[] = [
149
157
  JS.Kind.Void,
150
158
  JS.Kind.ExpressionStatement,
151
159
  JS.Kind.StatementExpression
152
- ]
160
+ ])
153
161
 
154
162
  export function isStatement(statement: J): statement is Statement {
155
- return is_statements.includes(statement.kind);
163
+ return is_statements.has(statement.kind);
156
164
  }
157
165
 
158
166
  export function isExpression(expression: J): expression is Expression {
159
- return is_expressions.includes(expression.kind);
167
+ return is_expressions.has(expression.kind);
160
168
  }
161
169
 
162
170
  export function getNextSibling(node: ts.Node): ts.Node | undefined {
@@ -1075,6 +1075,15 @@ export function resolve(cursor: Cursor, identifier: J.Identifier): J | undefined
1075
1075
  return reading && (bindingFrame(scopes, identifier.simpleName, reading)?.node as J | undefined);
1076
1076
  }
1077
1077
 
1078
+ /**
1079
+ * Whether the identifier reads a name nothing in the file binds where it stands, a global or nothing
1080
+ * at all. An identifier that names rather than reads is not free. The cursor is as {@link resolve} takes it.
1081
+ */
1082
+ export function isFree(cursor: Cursor, identifier: J.Identifier): boolean {
1083
+ const [scopes, reading] = position(pathTo(cursor, identifier), identifier);
1084
+ return reading !== undefined && bindingFrame(scopes, identifier.simpleName, reading) === undefined;
1085
+ }
1086
+
1078
1087
  /**
1079
1088
  * Whether the identifier is assigned to where it stands. An assignment's target, plain or compound,
1080
1089
  * is, and so are the operand of `++` or `--`, the head of a for-in or for-of declaring nothing, and
@@ -305,7 +305,7 @@ function slotConstraints(parent: J, childId: string): SlotConstraints | undefine
305
305
  case J.Kind.ClassDeclaration:
306
306
  // `class A extends B {}` takes a LeftHandSideExpression
307
307
  return (parent as J.ClassDeclaration).extends?.element?.id === childId ?
308
- {precedence: Precedence.Call} : undefined;
308
+ {precedence: Precedence.Call, typeTree: true} : undefined;
309
309
 
310
310
  case JS.Kind.ExpressionStatement:
311
311
  return (parent as JS.ExpressionStatement).expression?.id === childId ?