@openrewrite/rewrite 8.92.17 → 8.92.18

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 (199) hide show
  1. package/README.md +48 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +2 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/java/formatting-utils.d.ts +2 -1
  6. package/dist/java/formatting-utils.d.ts.map +1 -1
  7. package/dist/java/formatting-utils.js +4 -3
  8. package/dist/java/formatting-utils.js.map +1 -1
  9. package/dist/java/rpc.d.ts.map +1 -1
  10. package/dist/java/rpc.js +2 -0
  11. package/dist/java/rpc.js.map +1 -1
  12. package/dist/java/tree.d.ts +8 -0
  13. package/dist/java/tree.d.ts.map +1 -1
  14. package/dist/java/tree.js +11 -1
  15. package/dist/java/tree.js.map +1 -1
  16. package/dist/java/type.d.ts +7 -1
  17. package/dist/java/type.d.ts.map +1 -1
  18. package/dist/java/type.js +16 -1
  19. package/dist/java/type.js.map +1 -1
  20. package/dist/javascript/add-import.d.ts +27 -21
  21. package/dist/javascript/add-import.d.ts.map +1 -1
  22. package/dist/javascript/add-import.js +303 -143
  23. package/dist/javascript/add-import.js.map +1 -1
  24. package/dist/javascript/amd.d.ts.map +1 -1
  25. package/dist/javascript/amd.js +25 -10
  26. package/dist/javascript/amd.js.map +1 -1
  27. package/dist/javascript/autodetect.js +36 -45
  28. package/dist/javascript/autodetect.js.map +1 -1
  29. package/dist/javascript/binding.d.ts +6 -4
  30. package/dist/javascript/binding.d.ts.map +1 -1
  31. package/dist/javascript/binding.js +54 -18
  32. package/dist/javascript/binding.js.map +1 -1
  33. package/dist/javascript/comparator.d.ts +22 -5
  34. package/dist/javascript/comparator.d.ts.map +1 -1
  35. package/dist/javascript/comparator.js +116 -38
  36. package/dist/javascript/comparator.js.map +1 -1
  37. package/dist/javascript/format/format.d.ts +2 -0
  38. package/dist/javascript/format/format.d.ts.map +1 -1
  39. package/dist/javascript/format/format.js +11 -1
  40. package/dist/javascript/format/format.js.map +1 -1
  41. package/dist/javascript/index.d.ts +4 -2
  42. package/dist/javascript/index.d.ts.map +1 -1
  43. package/dist/javascript/index.js +10 -1
  44. package/dist/javascript/index.js.map +1 -1
  45. package/dist/javascript/markers.d.ts.map +1 -1
  46. package/dist/javascript/markers.js +64 -0
  47. package/dist/javascript/markers.js.map +1 -1
  48. package/dist/javascript/method-matcher.d.ts +13 -2
  49. package/dist/javascript/method-matcher.d.ts.map +1 -1
  50. package/dist/javascript/method-matcher.js +32 -19
  51. package/dist/javascript/method-matcher.js.map +1 -1
  52. package/dist/javascript/package-name.d.ts +6 -0
  53. package/dist/javascript/package-name.d.ts.map +1 -0
  54. package/dist/javascript/package-name.js +47 -0
  55. package/dist/javascript/package-name.js.map +1 -0
  56. package/dist/javascript/preconditions.d.ts +4 -1
  57. package/dist/javascript/preconditions.d.ts.map +1 -1
  58. package/dist/javascript/preconditions.js +7 -4
  59. package/dist/javascript/preconditions.js.map +1 -1
  60. package/dist/javascript/recipes/change-method-target-to-import.d.ts +29 -0
  61. package/dist/javascript/recipes/change-method-target-to-import.d.ts.map +1 -0
  62. package/dist/javascript/recipes/change-method-target-to-import.js +164 -0
  63. package/dist/javascript/recipes/change-method-target-to-import.js.map +1 -0
  64. package/dist/javascript/recipes/index.d.ts +1 -0
  65. package/dist/javascript/recipes/index.d.ts.map +1 -1
  66. package/dist/javascript/recipes/index.js +1 -0
  67. package/dist/javascript/recipes/index.js.map +1 -1
  68. package/dist/javascript/scope.d.ts +60 -16
  69. package/dist/javascript/scope.d.ts.map +1 -1
  70. package/dist/javascript/scope.js +596 -131
  71. package/dist/javascript/scope.js.map +1 -1
  72. package/dist/javascript/search/uses-method.d.ts +1 -1
  73. package/dist/javascript/search/uses-method.d.ts.map +1 -1
  74. package/dist/javascript/search/uses-method.js +2 -2
  75. package/dist/javascript/search/uses-method.js.map +1 -1
  76. package/dist/javascript/search/uses-type.d.ts +14 -1
  77. package/dist/javascript/search/uses-type.d.ts.map +1 -1
  78. package/dist/javascript/search/uses-type.js +24 -9
  79. package/dist/javascript/search/uses-type.js.map +1 -1
  80. package/dist/javascript/templating/bindings.d.ts +1 -1
  81. package/dist/javascript/templating/bindings.d.ts.map +1 -1
  82. package/dist/javascript/templating/bindings.js +10 -50
  83. package/dist/javascript/templating/bindings.js.map +1 -1
  84. package/dist/javascript/templating/comparator.d.ts +8 -11
  85. package/dist/javascript/templating/comparator.d.ts.map +1 -1
  86. package/dist/javascript/templating/comparator.js +12 -110
  87. package/dist/javascript/templating/comparator.js.map +1 -1
  88. package/dist/javascript/templating/engine.d.ts +34 -24
  89. package/dist/javascript/templating/engine.d.ts.map +1 -1
  90. package/dist/javascript/templating/engine.js +200 -112
  91. package/dist/javascript/templating/engine.js.map +1 -1
  92. package/dist/javascript/templating/pattern.d.ts +11 -5
  93. package/dist/javascript/templating/pattern.d.ts.map +1 -1
  94. package/dist/javascript/templating/pattern.js +86 -20
  95. package/dist/javascript/templating/pattern.js.map +1 -1
  96. package/dist/javascript/templating/placeholder-replacement.d.ts +34 -3
  97. package/dist/javascript/templating/placeholder-replacement.d.ts.map +1 -1
  98. package/dist/javascript/templating/placeholder-replacement.js +126 -60
  99. package/dist/javascript/templating/placeholder-replacement.js.map +1 -1
  100. package/dist/javascript/templating/precedence.d.ts +3 -1
  101. package/dist/javascript/templating/precedence.d.ts.map +1 -1
  102. package/dist/javascript/templating/precedence.js +28 -8
  103. package/dist/javascript/templating/precedence.js.map +1 -1
  104. package/dist/javascript/templating/template.d.ts +7 -6
  105. package/dist/javascript/templating/template.d.ts.map +1 -1
  106. package/dist/javascript/templating/template.js +31 -28
  107. package/dist/javascript/templating/template.js.map +1 -1
  108. package/dist/javascript/templating/types.d.ts +6 -3
  109. package/dist/javascript/templating/types.d.ts.map +1 -1
  110. package/dist/javascript/templating/utils.d.ts +10 -1
  111. package/dist/javascript/templating/utils.d.ts.map +1 -1
  112. package/dist/javascript/templating/utils.js +22 -3
  113. package/dist/javascript/templating/utils.js.map +1 -1
  114. package/dist/javascript/tree-debug.d.ts +2 -0
  115. package/dist/javascript/tree-debug.d.ts.map +1 -1
  116. package/dist/javascript/tree-debug.js +6 -0
  117. package/dist/javascript/tree-debug.js.map +1 -1
  118. package/dist/javascript/tsconfig.d.ts.map +1 -1
  119. package/dist/javascript/tsconfig.js +7 -17
  120. package/dist/javascript/tsconfig.js.map +1 -1
  121. package/dist/javascript/type-mapping.d.ts +34 -16
  122. package/dist/javascript/type-mapping.d.ts.map +1 -1
  123. package/dist/javascript/type-mapping.js +253 -249
  124. package/dist/javascript/type-mapping.js.map +1 -1
  125. package/dist/javascript/type-report-cli.d.ts +7 -0
  126. package/dist/javascript/type-report-cli.d.ts.map +1 -0
  127. package/dist/javascript/type-report-cli.js +129 -0
  128. package/dist/javascript/type-report-cli.js.map +1 -0
  129. package/dist/javascript/type-report.d.ts +61 -0
  130. package/dist/javascript/type-report.d.ts.map +1 -0
  131. package/dist/javascript/type-report.js +488 -0
  132. package/dist/javascript/type-report.js.map +1 -0
  133. package/dist/markers.d.ts +4 -0
  134. package/dist/markers.d.ts.map +1 -1
  135. package/dist/markers.js +8 -0
  136. package/dist/markers.js.map +1 -1
  137. package/dist/recipe.d.ts +5 -0
  138. package/dist/recipe.d.ts.map +1 -1
  139. package/dist/recipe.js +5 -0
  140. package/dist/recipe.js.map +1 -1
  141. package/dist/rewrite-javascript-version.txt +1 -1
  142. package/dist/rpc/queue.d.ts +16 -0
  143. package/dist/rpc/queue.d.ts.map +1 -1
  144. package/dist/rpc/queue.js +27 -9
  145. package/dist/rpc/queue.js.map +1 -1
  146. package/dist/rpc/request/prepare-recipe.d.ts +3 -1
  147. package/dist/rpc/request/prepare-recipe.d.ts.map +1 -1
  148. package/dist/rpc/request/prepare-recipe.js +13 -6
  149. package/dist/rpc/request/prepare-recipe.js.map +1 -1
  150. package/dist/search/is-source-file.d.ts +1 -0
  151. package/dist/search/is-source-file.d.ts.map +1 -1
  152. package/dist/search/is-source-file.js +7 -2
  153. package/dist/search/is-source-file.js.map +1 -1
  154. package/dist/test/rewrite-test.d.ts +5 -0
  155. package/dist/test/rewrite-test.d.ts.map +1 -1
  156. package/dist/test/rewrite-test.js +14 -3
  157. package/dist/test/rewrite-test.js.map +1 -1
  158. package/package.json +4 -3
  159. package/src/index.ts +3 -1
  160. package/src/java/formatting-utils.ts +5 -4
  161. package/src/java/rpc.ts +2 -0
  162. package/src/java/tree.ts +15 -0
  163. package/src/java/type.ts +19 -2
  164. package/src/javascript/add-import.ts +338 -152
  165. package/src/javascript/amd.ts +28 -12
  166. package/src/javascript/autodetect.ts +32 -41
  167. package/src/javascript/binding.ts +64 -22
  168. package/src/javascript/comparator.ts +119 -43
  169. package/src/javascript/format/format.ts +9 -0
  170. package/src/javascript/index.ts +6 -3
  171. package/src/javascript/markers.ts +43 -1
  172. package/src/javascript/method-matcher.ts +34 -22
  173. package/src/javascript/package-name.ts +45 -0
  174. package/src/javascript/preconditions.ts +7 -4
  175. package/src/javascript/recipes/change-method-target-to-import.ts +178 -0
  176. package/src/javascript/recipes/index.ts +1 -0
  177. package/src/javascript/scope.ts +705 -169
  178. package/src/javascript/search/uses-method.ts +2 -2
  179. package/src/javascript/search/uses-type.ts +30 -9
  180. package/src/javascript/templating/bindings.ts +13 -38
  181. package/src/javascript/templating/comparator.ts +16 -127
  182. package/src/javascript/templating/engine.ts +229 -127
  183. package/src/javascript/templating/pattern.ts +107 -28
  184. package/src/javascript/templating/placeholder-replacement.ts +154 -62
  185. package/src/javascript/templating/precedence.ts +33 -11
  186. package/src/javascript/templating/template.ts +35 -30
  187. package/src/javascript/templating/types.ts +6 -3
  188. package/src/javascript/templating/utils.ts +24 -2
  189. package/src/javascript/tree-debug.ts +9 -0
  190. package/src/javascript/tsconfig.ts +7 -17
  191. package/src/javascript/type-mapping.ts +258 -252
  192. package/src/javascript/type-report-cli.ts +96 -0
  193. package/src/javascript/type-report.ts +575 -0
  194. package/src/markers.ts +8 -0
  195. package/src/recipe.ts +6 -0
  196. package/src/rpc/queue.ts +44 -5
  197. package/src/rpc/request/prepare-recipe.ts +16 -6
  198. package/src/search/is-source-file.ts +8 -3
  199. package/src/test/rewrite-test.ts +14 -3
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isValueReference = void 0;
3
4
  exports.scopeOf = scopeOf;
4
5
  exports.namesDeclaredIn = namesDeclaredIn;
5
6
  exports.namesUsedIn = namesUsedIn;
@@ -12,7 +13,10 @@ exports.cursorOf = cursorOf;
12
13
  exports.compilationUnitOf = compilationUnitOf;
13
14
  exports.deconflict = deconflict;
14
15
  exports.declarationsOf = declarationsOf;
15
- exports.isValueReference = isValueReference;
16
+ exports.isReference = isReference;
17
+ exports.resolve = resolve;
18
+ exports.isWrite = isWrite;
19
+ exports.referencesOf = referencesOf;
16
20
  /*
17
21
  * Copyright 2025 the original author or authors.
18
22
  * <p>
@@ -32,6 +36,28 @@ const tree_1 = require("../tree");
32
36
  const java_1 = require("../java");
33
37
  const tree_2 = require("./tree");
34
38
  const noNames = new Set();
39
+ const noBindings = new Map();
40
+ /** Whether `bindings` holds `name` with `meaning`, or with any meaning where none is asked for. */
41
+ function binds(bindings, name, meaning) {
42
+ const binding = bindings.get(name);
43
+ return binding !== undefined && (meaning === undefined || binding.meanings.has(meaning));
44
+ }
45
+ function bound(identifiers, ...meanings) {
46
+ return identifiers.map(identifier => ({ identifier, meanings }));
47
+ }
48
+ function toBindings(bound) {
49
+ const bindings = new Map();
50
+ for (const declaration of bound) {
51
+ const name = declaration.identifier.simpleName;
52
+ let held = bindings.get(name);
53
+ if (!held) {
54
+ bindings.set(name, held = { meanings: new Set(), declarations: [] });
55
+ }
56
+ declaration.meanings.forEach(meaning => held.meanings.add(meaning));
57
+ held.declarations.push(declaration);
58
+ }
59
+ return bindings;
60
+ }
35
61
  /**
36
62
  * The innermost scope holding `cursor`, which a visitor's own cursor rarely is: it stands on
37
63
  * whatever node it is visiting. Where a declaration's shape leaves its reach unreadable the answer
@@ -43,7 +69,7 @@ function scopeOf(cursor) {
43
69
  }
44
70
  function scopeAt(cursor) {
45
71
  return {
46
- names: () => { var _a; return frameBindings(cursor.value, (_a = cursor.parent) === null || _a === void 0 ? void 0 : _a.value); },
72
+ names: () => new Set(bindingsAt(cursor).keys()),
47
73
  walk: visit => {
48
74
  for (let c = cursor; c; c = enclosingScopeCursor(c.parent)) {
49
75
  if (!visit(scopeAt(c))) {
@@ -51,8 +77,8 @@ function scopeAt(cursor) {
51
77
  }
52
78
  }
53
79
  },
54
- declares: name => declaringScopeOf(cursor, name) !== undefined,
55
- declaringScope: name => declaringScopeOf(cursor, name)
80
+ declares: (name, meaning) => declaringScopeOf(cursor, name, meaning) !== undefined,
81
+ declaringScope: (name, meaning) => declaringScopeOf(cursor, name, meaning)
56
82
  };
57
83
  }
58
84
  function enclosingScopeCursor(from) {
@@ -66,8 +92,10 @@ function enclosingScopeCursor(from) {
66
92
  }
67
93
  /** The nodes {@link readBindings} answers for; everything else binds nothing and is not a scope. */
68
94
  const scopeKinds = new Set([
69
- tree_2.JS.Kind.CompilationUnit, java_1.J.Kind.Block, java_1.J.Kind.MethodDeclaration, java_1.J.Kind.Lambda,
70
- java_1.J.Kind.ClassDeclaration, java_1.J.Kind.TryCatch, java_1.J.Kind.ForLoop, java_1.J.Kind.ForEachLoop, tree_2.JS.Kind.ForInLoop
95
+ tree_2.JS.Kind.CompilationUnit, java_1.J.Kind.Block, java_1.J.Kind.MethodDeclaration, tree_2.JS.Kind.ComputedPropertyMethodDeclaration,
96
+ java_1.J.Kind.Lambda, tree_2.JS.Kind.ArrowFunction, java_1.J.Kind.ClassDeclaration, java_1.J.Kind.TryCatch, java_1.J.Kind.ForLoop,
97
+ java_1.J.Kind.ForEachLoop, tree_2.JS.Kind.ForInLoop, tree_2.JS.Kind.NamespaceDeclaration, tree_2.JS.Kind.TypeDeclaration,
98
+ tree_2.JS.Kind.FunctionType, tree_2.JS.Kind.MappedType, tree_2.JS.Kind.ConditionalType
71
99
  ]);
72
100
  /**
73
101
  * Every name the file declares, wherever it sits. A binding the whole file shares is referenced from
@@ -114,15 +142,20 @@ function namesDeclaredWithin(node, cacheKey = node) {
114
142
  }
115
143
  const names = new Set();
116
144
  const collect = (node) => {
117
- var _a, _b;
118
- declarationNames(node).forEach(name => names.add(name));
119
- if (node.kind !== java_1.J.Kind.ClassDeclaration) {
145
+ declarationNames(node).forEach(({ identifier }) => names.add(identifier.simpleName));
146
+ const members = membersOf(node);
147
+ if (!members) {
120
148
  return true;
121
149
  }
122
- // The walk ends at this branch, so the class's own type parameters are read here.
123
- typeParameterNames(node).forEach(name => names.add(name));
150
+ // The walk ends at this branch, so what else the node holds is read here.
151
+ if (node.kind === java_1.J.Kind.ClassDeclaration) {
152
+ typeParameterNames(node).forEach(({ identifier }) => names.add(identifier.simpleName));
153
+ }
154
+ else if (node.kind === java_1.J.Kind.NewClass) {
155
+ walk(node.arguments, collect);
156
+ }
124
157
  // A member's name is not one the file binds, though the code inside one still declares names.
125
- for (const member of (_b = (_a = node.body) === null || _a === void 0 ? void 0 : _a.statements) !== null && _b !== void 0 ? _b : []) {
158
+ for (const member of members.statements) {
126
159
  const element = unwrap(member);
127
160
  walk(element, node => node === element || collect(node));
128
161
  }
@@ -135,7 +168,8 @@ function namesDeclaredWithin(node, cacheKey = node) {
135
168
  /**
136
169
  * The names `node` reads and nothing within it binds, so each one reaches a binding further out.
137
170
  * A name its parent introduces rather than reads is not one, nor is a name an inner scope rebinds:
138
- * that reference reads the rebinding.
171
+ * that reference reads the rebinding. A value position is hidden only by a value binding, a type
172
+ * position only by a type.
139
173
  */
140
174
  function namesReferencedWithin(node, cacheKey = node) {
141
175
  if (cacheKey === null || typeof cacheKey !== 'object') {
@@ -146,122 +180,309 @@ function namesReferencedWithin(node, cacheKey = node) {
146
180
  return cached;
147
181
  }
148
182
  const names = new Set();
149
- collectReferences(node, undefined, undefined, names);
183
+ treesIn(node).forEach(tree => readReferences(tree, undefined, undefined, 'value', (identifier, reading, scopes) => {
184
+ if (reading !== undefined && !bindingFrame(scopes, identifier.simpleName, reading)) {
185
+ names.add(identifier.simpleName);
186
+ }
187
+ }));
150
188
  referenced.set(cacheKey, names);
151
189
  return names;
152
190
  }
153
- /** Whether a scope between the name and where the walk began binds it. */
154
- function shadowed(scopes, name) {
191
+ /** The innermost of `scopes` binding `name` as `reading` asks, or undefined where none does. */
192
+ function bindingFrame(scopes, name, reading) {
155
193
  for (let scope = scopes; scope; scope = scope.outer) {
156
- if (frameBindings(scope.node, scope.parent).has(name)) {
157
- return true;
194
+ if (binds(frameBindings(scope.node, scope.parent), name, meaningRead(reading))) {
195
+ return scope;
158
196
  }
159
197
  }
160
- return false;
198
+ return undefined;
161
199
  }
162
- function collectReferences(node, parent, scopes, names) {
163
- if (Array.isArray(node)) {
164
- node.forEach(child => collectReferences(child, parent, scopes, names));
165
- return;
200
+ /** The meaning a reading resolves against, or undefined for any. */
201
+ function meaningRead(reading) {
202
+ return reading === 'any' ? undefined : reading === 'write' ? 'value' : reading;
203
+ }
204
+ /**
205
+ * Walks `node` top-down, telling `onIdentifier` of every identifier. `reading` is what `node`
206
+ * itself reads with, or undefined under a slot that names rather than reads.
207
+ */
208
+ function readReferences(node, parent, scopes, reading, onIdentifier, trail = []) {
209
+ trail.push(node);
210
+ if (node.kind === java_1.J.Kind.Identifier) {
211
+ onIdentifier(node, reading, scopes, trail);
212
+ }
213
+ const within = framesAt(node, parent, scopes);
214
+ for (const [key, value] of Object.entries(node)) {
215
+ if (key !== 'markers') {
216
+ const [below, reads] = descend(node, parent, key, within, reading);
217
+ // A naming position reads against the tree parent, so the padding between is stepped over.
218
+ treesIn(value).forEach(child => readReferences(child, node, below, reads, onIdentifier, trail));
219
+ }
166
220
  }
167
- const kind = node === null || node === void 0 ? void 0 : node.kind;
168
- if (kind === java_1.J.Kind.RightPadded || kind === java_1.J.Kind.LeftPadded) {
169
- // A naming position reads against the tree parent, so padding forwards the one it was handed.
170
- collectReferences(node.element, parent, scopes, names);
171
- return;
221
+ trail.pop();
222
+ }
223
+ /** The scopes a node sits in, with its own in front where it is one. */
224
+ function framesAt(node, parent, scopes) {
225
+ return scopeKinds.has(node.kind) ? { node, parent, outer: scopes } : scopes;
226
+ }
227
+ /** The scopes the slot `key` of `node` resolves against, and what a read in it reads with. */
228
+ function descend(node, parent, key, within, reading) {
229
+ return [reachOf(node, parent, key, within), meaningOf(node, key, reading)];
230
+ }
231
+ /**
232
+ * The scopes the slot `key` of `node` resolves against, `within` being those `node` sits in. A
233
+ * conditional type's `infer` names reach its extends clause and true branch alone, so its check
234
+ * type and false branch read past them.
235
+ */
236
+ function reachOf(node, parent, key, within) {
237
+ const pastInferred = node.kind === tree_2.JS.Kind.ConditionalType && key === 'checkType' ||
238
+ node.kind === java_1.J.Kind.Ternary && (parent === null || parent === void 0 ? void 0 : parent.kind) === tree_2.JS.Kind.ConditionalType && key === 'falsePart';
239
+ return pastInferred ? within === null || within === void 0 ? void 0 : within.outer : within;
240
+ }
241
+ /**
242
+ * What a read in slot `key` of `node` reads with, given what `node` itself reads with. Undefined
243
+ * is a slot that names rather than reads, and so is everything under it. A whole import declares
244
+ * what it spells, and a re-export's clause names another module's members.
245
+ */
246
+ function meaningOf(node, key, reading) {
247
+ // A computed key and a binding's default value read from within a naming slot.
248
+ if (node.kind === tree_2.JS.Kind.ComputedPropertyName || node.kind === tree_2.JS.Kind.BindingElement && key === 'initializer') {
249
+ return 'value';
172
250
  }
173
- if (kind === java_1.J.Kind.Container) {
174
- collectReferences(node.elements, parent, scopes, names);
175
- return;
251
+ if (reading === undefined) {
252
+ return undefined;
176
253
  }
177
- if (!(0, tree_1.isTree)(node)) {
178
- return;
254
+ if (reading === 'write') {
255
+ return carriesWrite(node, key) ? 'write' : meaningOf(node, key, 'value');
256
+ }
257
+ if (key === 'typeParameters' || key === 'typeArguments') {
258
+ return 'type';
259
+ }
260
+ if (key === 'label' || key === namingSlots[node.kind] || key === 'name' && !readsItsName(node)) {
261
+ return undefined;
179
262
  }
180
- const name = kind === java_1.J.Kind.Identifier ? node.simpleName : undefined;
181
- if (name && reads(node, parent) && !shadowed(scopes, name)) {
182
- names.add(name);
263
+ if (writes(node, key)) {
264
+ return 'write';
265
+ }
266
+ switch (node.kind) {
267
+ case tree_2.JS.Kind.Import:
268
+ // `import a = NS.b` reads `NS` as whatever it is. The rest of an import declares.
269
+ return key === 'initializer' ? 'any' : undefined;
270
+ case tree_2.JS.Kind.ExportDeclaration:
271
+ if (key !== 'exportClause') {
272
+ return reading;
273
+ }
274
+ return node.moduleSpecifier === undefined ? 'any' : undefined;
275
+ case java_1.J.Kind.FieldAccess:
276
+ // In a type, `NS.Foo` reads the namespace `NS`, as `A.B.C` reads `A`.
277
+ return key === 'target' && reading === 'type' ? 'namespace' : reading;
278
+ case tree_2.JS.Kind.TypeInfo:
279
+ case tree_2.JS.Kind.TypeDeclaration:
280
+ case java_1.J.Kind.TypeParameter:
281
+ return 'type';
282
+ case tree_2.JS.Kind.TypeQuery:
283
+ // `typeof x` reads the value `x` from within a type.
284
+ return key === 'typeExpression' ? 'value' : reading;
285
+ case tree_2.JS.Kind.TypePredicate:
286
+ // `x is Foo` names the parameter `x`, a value, from within a return type.
287
+ return key === 'parameterName' ? 'value' : reading;
288
+ case tree_2.JS.Kind.IndexSignatureDeclaration:
289
+ return key === 'typeExpression' ? 'type' : reading;
290
+ case tree_2.JS.Kind.As:
291
+ return key === 'right' ? 'type' : reading;
292
+ case tree_2.JS.Kind.SatisfiesExpression:
293
+ return key === 'satisfiesType' ? 'type' : reading;
294
+ case java_1.J.Kind.TypeCast:
295
+ return key === 'class' ? 'type' : reading;
296
+ case java_1.J.Kind.ClassDeclaration:
297
+ if (node.classKind.type === java_1.J.ClassDeclaration.Kind.Type.Interface) {
298
+ return 'type';
299
+ }
300
+ return key === 'implements' ? 'type' : reading;
301
+ default:
302
+ return reading;
183
303
  }
184
- const within = scopeKinds.has(kind) ? { node, parent, outer: scopes } : scopes;
185
- Object.entries(node).forEach(([key, value]) => key !== 'markers' && collectReferences(value, node, within, names));
186
304
  }
305
+ /** Whether slot `key` of `node` is one {@link isWrite} counts as assigned to. A declaring loop head names instead. */
306
+ function writes(node, key) {
307
+ switch (node.kind) {
308
+ case java_1.J.Kind.Assignment:
309
+ case java_1.J.Kind.AssignmentOperation:
310
+ case tree_2.JS.Kind.AssignmentOperation:
311
+ return key === 'variable';
312
+ case java_1.J.Kind.Unary:
313
+ return key === 'expression' && incrementing.has(node.operator.element);
314
+ case java_1.J.Kind.ForEachLoopControl:
315
+ return key === 'variable';
316
+ default:
317
+ return false;
318
+ }
319
+ }
320
+ const incrementing = new Set([
321
+ java_1.J.Unary.Type.PreIncrement, java_1.J.Unary.Type.PreDecrement, java_1.J.Unary.Type.PostIncrement, java_1.J.Unary.Type.PostDecrement
322
+ ]);
323
+ /**
324
+ * Whether slot `key` of `node` passes a write on to what it holds, which parentheses, a type
325
+ * assertion and the shapes of a destructuring target do. Anything else under a target reads, as
326
+ * `x` does in `x.y = 1`.
327
+ */
328
+ function carriesWrite(node, key) {
329
+ switch (node.kind) {
330
+ case java_1.J.Kind.Parentheses:
331
+ return key === 'tree';
332
+ case tree_2.JS.Kind.As:
333
+ return key === 'left';
334
+ case tree_2.JS.Kind.ExpressionStatement:
335
+ case tree_2.JS.Kind.Spread:
336
+ case tree_2.JS.Kind.SatisfiesExpression:
337
+ case java_1.J.Kind.TypeCast:
338
+ return key === 'expression';
339
+ case java_1.J.Kind.NewArray:
340
+ return key === 'initializer';
341
+ case java_1.J.Kind.NewClass:
342
+ return key === 'body';
343
+ case java_1.J.Kind.Block:
344
+ return key === 'statements';
345
+ case tree_2.JS.Kind.PropertyAssignment:
346
+ return key === (isShorthand(node) ? 'name' : 'initializer');
347
+ case tree_2.JS.Kind.ArrayBindingPattern:
348
+ return key === 'elements';
349
+ case tree_2.JS.Kind.ObjectBindingPattern:
350
+ return key === 'bindings';
351
+ case tree_2.JS.Kind.BindingElement:
352
+ return key === 'name';
353
+ default:
354
+ return false;
355
+ }
356
+ }
357
+ /**
358
+ * Whether a node's `name` slot reads rather than names. A call names a member of whatever it
359
+ * selects from, so with nothing selected its name is the function called, and a shorthand `{x}`
360
+ * reads the `x` it also names.
361
+ */
362
+ function readsItsName(node) {
363
+ return node.kind === java_1.J.Kind.MethodInvocation && !node.select || isShorthand(node);
364
+ }
365
+ /** A shorthand property `{x}` or `{x = 1}`, which reads the `x` it names. */
366
+ function isShorthand(node) {
367
+ return (node === null || node === void 0 ? void 0 : node.kind) === tree_2.JS.Kind.PropertyAssignment &&
368
+ node.assigmentToken === tree_2.JS.PropertyAssignment.Token.Equals;
369
+ }
370
+ /** The slot, beside `name` and `label`, in which a node names rather than reads. */
371
+ const namingSlots = {
372
+ [tree_2.JS.Kind.Alias]: 'alias',
373
+ [tree_2.JS.Kind.BindingElement]: 'propertyName',
374
+ [tree_2.JS.Kind.ImportType]: 'qualifier',
375
+ [tree_2.JS.Kind.JsxAttribute]: 'key'
376
+ };
187
377
  /**
188
378
  * Every name a binding pattern introduces. `member` is the property a name takes its value from,
189
379
  * which only a name an object pattern binds directly has: anything deeper reads a property of a
190
380
  * property, an array element is chosen by position, and a rest name gathers what nothing claimed.
191
381
  */
192
382
  function bindingNames(pattern) {
383
+ return patternBindings(pattern).map(({ identifier, member }) => member === undefined ? { name: identifier.simpleName } : { name: identifier.simpleName, member });
384
+ }
385
+ /** As {@link bindingNames}, with the identifier each name is read from. */
386
+ function patternBindings(pattern) {
193
387
  var _a;
194
388
  switch (pattern === null || pattern === void 0 ? void 0 : pattern.kind) {
195
389
  case java_1.J.Kind.Identifier: {
196
- const simpleName = pattern.simpleName;
197
- return simpleName ? [{ name: simpleName }] : [];
390
+ const identifier = pattern;
391
+ return identifier.simpleName ? [{ identifier }] : [];
198
392
  }
199
393
  case tree_2.JS.Kind.Spread:
200
- return bindingNames(pattern.expression);
394
+ return patternBindings(pattern.expression);
201
395
  case tree_2.JS.Kind.ArrayBindingPattern:
202
396
  return unnamedMembers(pattern.elements.elements
203
- .flatMap(element => bindingNames(unwrap(element))));
397
+ .flatMap(element => patternBindings(unwrap(element))));
204
398
  case tree_2.JS.Kind.ObjectBindingPattern:
205
399
  return pattern.bindings.elements
206
- .flatMap(element => bindingNames(unwrap(element)));
400
+ .flatMap(element => patternBindings(unwrap(element)));
207
401
  case tree_2.JS.Kind.BindingElement: {
208
402
  const element = pattern;
209
403
  if (((_a = element.name) === null || _a === void 0 ? void 0 : _a.kind) !== java_1.J.Kind.Identifier) {
210
- return unnamedMembers(bindingNames(element.name));
404
+ return unnamedMembers(patternBindings(element.name));
211
405
  }
212
- const name = element.name.simpleName;
406
+ const identifier = element.name;
213
407
  const propertyName = unwrap(element.propertyName);
214
408
  return [{
215
- name,
216
- member: (propertyName === null || propertyName === void 0 ? void 0 : propertyName.kind) === java_1.J.Kind.Identifier ? propertyName.simpleName : name
409
+ identifier,
410
+ member: (propertyName === null || propertyName === void 0 ? void 0 : propertyName.kind) === java_1.J.Kind.Identifier
411
+ ? propertyName.simpleName
412
+ : identifier.simpleName
217
413
  }];
218
414
  }
219
415
  default:
220
416
  return [];
221
417
  }
222
418
  }
419
+ function boundIdentifiers(pattern) {
420
+ return patternBindings(pattern).map(bound => bound.identifier);
421
+ }
223
422
  function unnamedMembers(bound) {
224
- return bound.map(({ name }) => ({ name }));
423
+ return bound.map(({ identifier }) => ({ identifier }));
225
424
  }
226
- function declaringScopeOf(cursor, name) {
227
- var _a;
425
+ /**
426
+ * The block of members a class, object literal or type literal holds. A member is reached through
427
+ * the value or type holding it, so its name binds nowhere.
428
+ */
429
+ function membersOf(node) {
430
+ switch (node === null || node === void 0 ? void 0 : node.kind) {
431
+ case java_1.J.Kind.ClassDeclaration:
432
+ return node.body;
433
+ case java_1.J.Kind.NewClass:
434
+ return node.body;
435
+ case tree_2.JS.Kind.TypeLiteral:
436
+ return node.members;
437
+ default:
438
+ return undefined;
439
+ }
440
+ }
441
+ function declaringScopeOf(cursor, name, meaning) {
228
442
  for (let c = cursor; c; c = c.parent) {
229
- if (frameBindings(c.value, (_a = c.parent) === null || _a === void 0 ? void 0 : _a.value).has(name)) {
443
+ if (binds(bindingsAt(c), name, meaning)) {
230
444
  return c.value;
231
445
  }
232
446
  }
233
447
  return undefined;
234
448
  }
449
+ /** What the node a cursor stands on binds, which is nothing where it stands on padding or the root. */
450
+ function bindingsAt(cursor) {
451
+ var _a;
452
+ const parent = (_a = cursor.parent) === null || _a === void 0 ? void 0 : _a.value;
453
+ return (0, tree_1.isTree)(cursor.value) ? frameBindings(cursor.value, (0, tree_1.isTree)(parent) ? parent : undefined) : noBindings;
454
+ }
235
455
  /**
236
456
  * What one node on the cursor path binds, `parent` being the node it hangs from. Only these two
237
457
  * answers turn on the parent; a node alone settles the rest, which is what makes them cacheable.
238
458
  */
239
459
  function frameBindings(node, parent) {
240
- // A class body holds members, which are reached through an instance rather than by name.
241
- if ((node === null || node === void 0 ? void 0 : node.kind) === java_1.J.Kind.Block && (parent === null || parent === void 0 ? void 0 : parent.kind) === java_1.J.Kind.ClassDeclaration) {
242
- return noNames;
460
+ if (node.kind === java_1.J.Kind.Block && membersOf(parent) === node) {
461
+ // An enum's members are in scope in its body, where an initializer may name an earlier one.
462
+ return isEnum(parent) ? toBindings(enumMemberNames(node)) : noBindings;
463
+ }
464
+ // An arrow binds its lambda's parameters itself, since its return type reads them.
465
+ if (node.kind === java_1.J.Kind.Lambda && (parent === null || parent === void 0 ? void 0 : parent.kind) === tree_2.JS.Kind.ArrowFunction) {
466
+ return noBindings;
243
467
  }
244
468
  // A function expression is the only function whose own name its body reaches: a declaration's
245
469
  // name belongs to the enclosing block, a method's to an instance.
246
- if ((node === null || node === void 0 ? void 0 : node.kind) === java_1.J.Kind.MethodDeclaration && (parent === null || parent === void 0 ? void 0 : parent.kind) === tree_2.JS.Kind.StatementExpression) {
247
- let names = selfNamed.get(node);
248
- if (!names) {
249
- const self = bindingNames(node.name).map(bound => bound.name);
250
- selfNamed.set(node, names = new Set([...self, ...ownBindings(node)]));
470
+ if (node.kind === java_1.J.Kind.MethodDeclaration && (parent === null || parent === void 0 ? void 0 : parent.kind) === tree_2.JS.Kind.StatementExpression) {
471
+ let bindings = selfNamed.get(node);
472
+ if (!bindings) {
473
+ const self = bound(boundIdentifiers(node.name), 'value');
474
+ selfNamed.set(node, bindings = toBindings([...self, ...readBindings(node)]));
251
475
  }
252
- return names;
476
+ return bindings;
253
477
  }
254
478
  return ownBindings(node);
255
479
  }
256
480
  function ownBindings(node) {
257
- if (typeof node !== 'object' || node === null) {
258
- return noNames;
481
+ let bindings = frames.get(node);
482
+ if (!bindings) {
483
+ frames.set(node, bindings = toBindings(readBindings(node)));
259
484
  }
260
- let names = frames.get(node);
261
- if (!names) {
262
- frames.set(node, names = new Set(readBindings(node)));
263
- }
264
- return names;
485
+ return bindings;
265
486
  }
266
487
  function readBindings(node) {
267
488
  switch (node.kind) {
@@ -269,26 +490,52 @@ function readBindings(node) {
269
490
  const statements = node.statements;
270
491
  return [...declaredNames(statements), ...hoistedNames(statements)];
271
492
  }
272
- case java_1.J.Kind.Block:
273
- return blockScopedNames(node.statements);
274
- case java_1.J.Kind.MethodDeclaration: {
493
+ case java_1.J.Kind.Block: {
494
+ const block = node;
495
+ // A class static block is a var scope, as a function body is.
496
+ return block.static.element
497
+ ? [...blockScopedNames(block.statements), ...hoistedNames(block.statements)]
498
+ : blockScopedNames(block.statements);
499
+ }
500
+ case java_1.J.Kind.MethodDeclaration:
501
+ case tree_2.JS.Kind.ComputedPropertyMethodDeclaration: {
275
502
  const method = node;
276
- return [...declaredNames(method.parameters.elements), ...hoistedNames(method.body)];
503
+ return [
504
+ ...typeParameterNames(method),
505
+ ...declaredNames(method.parameters.elements),
506
+ ...hoistedNames(method.body)
507
+ ];
277
508
  }
278
509
  case java_1.J.Kind.Lambda: {
279
510
  const lambda = node;
280
511
  return [...declaredNames(lambda.parameters.parameters), ...hoistedNames(lambda.body)];
281
512
  }
282
513
  case java_1.J.Kind.ClassDeclaration:
283
- return bindingNames(node.name).map(bound => bound.name);
514
+ return [...declarationNames(node), ...typeParameterNames(node)];
515
+ // A namespace is where the functions and `var`s in its body hoist to, its block binding the rest.
516
+ case tree_2.JS.Kind.NamespaceDeclaration:
517
+ return isGlobalAugmentation(node)
518
+ ? []
519
+ : hoistedNames(node.body);
520
+ case tree_2.JS.Kind.ArrowFunction:
521
+ return [...typeParameterNames(node), ...readBindings(node.lambda)];
522
+ case tree_2.JS.Kind.TypeDeclaration:
523
+ return typeParameterNames(node);
524
+ case tree_2.JS.Kind.FunctionType:
525
+ return [...typeParameterNames(node), ...declaredNames(node.parameters.elements)];
526
+ case tree_2.JS.Kind.MappedType:
527
+ return declarationNames(unwrap(node.keysRemapping.typeParameter));
528
+ case tree_2.JS.Kind.ConditionalType:
529
+ return inferredNames(node.condition.element.condition);
284
530
  case java_1.J.Kind.TryCatch:
285
531
  return declaredNames([node.parameter.tree]);
532
+ // A loop head's `var` hoists past the loop, as one anywhere in a function body does.
286
533
  case java_1.J.Kind.ForLoop:
287
- return declaredNames(node.control.init);
534
+ return blockScopedNames(node.control.init);
288
535
  case java_1.J.Kind.ForEachLoop:
289
- return declaredNames([node.control.variable]);
536
+ return blockScopedNames([node.control.variable]);
290
537
  case tree_2.JS.Kind.ForInLoop:
291
- return declaredNames([node.control.variable]);
538
+ return blockScopedNames([node.control.variable]);
292
539
  default:
293
540
  return [];
294
541
  }
@@ -321,28 +568,48 @@ function isBlockScoped(declaration) {
321
568
  function declaredNames(statements) {
322
569
  return statements.flatMap(statement => declarationNames(unwrap(statement)));
323
570
  }
571
+ /** The names a declaration binds, each with the meanings it has there. */
324
572
  function declarationNames(statement) {
325
573
  switch (statement === null || statement === void 0 ? void 0 : statement.kind) {
326
574
  case tree_2.JS.Kind.Import:
327
575
  return importNames(statement);
328
576
  case java_1.J.Kind.VariableDeclarations:
329
- return statement.variables
330
- .flatMap(variable => { var _a; return bindingNames((_a = unwrap(variable)) === null || _a === void 0 ? void 0 : _a.name); })
331
- .map(bound => bound.name);
577
+ return bound(statement.variables.flatMap(variable => {
578
+ const named = unwrap(variable);
579
+ return boundIdentifiers(named === null || named === void 0 ? void 0 : named.name);
580
+ }), 'value');
332
581
  case tree_2.JS.Kind.ScopedVariableDeclarations:
333
582
  return declaredNames(statement.variables);
334
583
  case java_1.J.Kind.MethodDeclaration:
335
- return bindingNames(statement.name).map(bound => bound.name);
336
- case java_1.J.Kind.ClassDeclaration:
337
- return bindingNames(statement.name).map(bound => bound.name);
338
- case tree_2.JS.Kind.NamespaceDeclaration:
339
- return bindingNames(unwrap(statement.name)).map(bound => bound.name);
584
+ return bound(boundIdentifiers(statement.name), 'value');
585
+ case java_1.J.Kind.ClassDeclaration: {
586
+ const declaration = statement;
587
+ switch (declaration.classKind.type) {
588
+ case java_1.J.ClassDeclaration.Kind.Type.Interface:
589
+ return bound(boundIdentifiers(declaration.name), 'type');
590
+ case java_1.J.ClassDeclaration.Kind.Type.Enum:
591
+ // An enum's members are read as `E.A` in a type, so it is a namespace too.
592
+ return bound(boundIdentifiers(declaration.name), 'value', 'type', 'namespace');
593
+ default:
594
+ return bound(boundIdentifiers(declaration.name), 'value', 'type');
595
+ }
596
+ }
597
+ case tree_2.JS.Kind.NamespaceDeclaration: {
598
+ const declaration = statement;
599
+ if (isGlobalAugmentation(declaration)) {
600
+ return [];
601
+ }
602
+ const names = boundIdentifiers(rootName(unwrap(declaration.name)));
603
+ return isInstantiated(declaration) ? bound(names, 'namespace', 'value') : bound(names, 'namespace');
604
+ }
340
605
  case tree_2.JS.Kind.TypeDeclaration:
341
- return bindingNames(unwrap(statement.name)).map(bound => bound.name);
606
+ return bound(boundIdentifiers(unwrap(statement.name)), 'type');
342
607
  case java_1.J.Kind.TypeParameter:
343
- // Reached by namesDeclaredWithin's walk, never through a statement list: a type
344
- // parameter binds across the declaration carrying it, not in the scope that one sits in.
345
- return bindingNames(statement.name).map(bound => bound.name);
608
+ // A type parameter binds across the declaration carrying it, not in the scope that one
609
+ // sits in, so no statement list leads here.
610
+ return bound(boundIdentifiers(statement.name), 'type');
611
+ case tree_2.JS.Kind.MappedTypeParameter:
612
+ return bound(boundIdentifiers(statement.name), 'type');
346
613
  case java_1.J.Kind.Case:
347
614
  // The cases of a switch share the block it opens, so each one's declarations bind in all.
348
615
  return declaredNames(statement.statements.elements);
@@ -350,24 +617,87 @@ function declarationNames(statement) {
350
617
  return [];
351
618
  }
352
619
  }
620
+ /**
621
+ * Whether a namespace binds a value, which it does once its body holds something other than
622
+ * interfaces, type aliases, unexported imports and namespaces that do not. That is the binder's
623
+ * rule, under which a `const enum` counts, whatever the emitter later drops.
624
+ */
625
+ function isInstantiated(declaration) {
626
+ var _a, _b;
627
+ return ((_b = (_a = declaration.body) === null || _a === void 0 ? void 0 : _a.statements) !== null && _b !== void 0 ? _b : []).some(statement => {
628
+ const element = unwrap(statement);
629
+ switch (element === null || element === void 0 ? void 0 : element.kind) {
630
+ case tree_2.JS.Kind.TypeDeclaration:
631
+ return false;
632
+ case java_1.J.Kind.ClassDeclaration:
633
+ return element.classKind.type !== java_1.J.ClassDeclaration.Kind.Type.Interface;
634
+ case tree_2.JS.Kind.Import:
635
+ return element.modifiers.some(modifier => modifier.keyword === 'export');
636
+ case tree_2.JS.Kind.NamespaceDeclaration:
637
+ return isInstantiated(element);
638
+ default:
639
+ return true;
640
+ }
641
+ });
642
+ }
643
+ /** `declare global { … }`, whose declarations the whole file sees, as if written at its top. */
644
+ function isGlobalAugmentation(declaration) {
645
+ const name = unwrap(declaration.name);
646
+ return declaration.keywordType.element === tree_2.JS.NamespaceDeclaration.KeywordType.Empty &&
647
+ (name === null || name === void 0 ? void 0 : name.kind) === java_1.J.Kind.Identifier && name.simpleName === 'global';
648
+ }
649
+ function isEnum(node) {
650
+ return (node === null || node === void 0 ? void 0 : node.kind) === java_1.J.Kind.ClassDeclaration &&
651
+ node.classKind.type === java_1.J.ClassDeclaration.Kind.Type.Enum;
652
+ }
653
+ function enumMemberNames(body) {
654
+ return body.statements.flatMap(statement => {
655
+ const element = unwrap(statement);
656
+ return (element === null || element === void 0 ? void 0 : element.kind) === java_1.J.Kind.EnumValueSet
657
+ ? bound(element.enums.map(value => value.element.name), 'value')
658
+ : [];
659
+ });
660
+ }
661
+ /** The identifier a dotted name `A.B.C` declares, which is `A`: the rest are members of it. */
662
+ function rootName(name) {
663
+ return (name === null || name === void 0 ? void 0 : name.kind) === java_1.J.Kind.FieldAccess ? rootName(name.target) : name;
664
+ }
353
665
  /**
354
666
  * The names a declaration's type parameters bind. A class keeps them in a container and everything
355
667
  * else in a `J.TypeParameters`, and both hold the same right-padded list.
356
668
  */
357
669
  function typeParameterNames(node) {
358
- const held = node === null || node === void 0 ? void 0 : node.typeParameters;
670
+ const held = node.typeParameters;
359
671
  const parameters = (held === null || held === void 0 ? void 0 : held.kind) === java_1.J.Kind.TypeParameters
360
672
  ? held.typeParameters
361
673
  : held === null || held === void 0 ? void 0 : held.elements;
362
674
  return (parameters !== null && parameters !== void 0 ? parameters : []).flatMap(parameter => declarationNames(unwrap(parameter)));
363
675
  }
364
- /** The names an import binds, which for an aliased or namespace specifier is the alias. */
676
+ /**
677
+ * The names the `infer` declarations in a conditional type's extends clause bind. A conditional
678
+ * type nested in the clause keeps its own `infer` names to itself.
679
+ */
680
+ function inferredNames(extendsType) {
681
+ const names = [];
682
+ walk(extendsType, node => {
683
+ if (node.kind === tree_2.JS.Kind.InferType) {
684
+ names.push(...declarationNames(unwrap(node.typeParameter)));
685
+ }
686
+ return node.kind !== tree_2.JS.Kind.ConditionalType;
687
+ });
688
+ return names;
689
+ }
690
+ /**
691
+ * The names an import binds, which for an aliased or namespace specifier is the alias, each with
692
+ * every meaning. A `type` import is no exception: `typeof X` reads it as a value from within a
693
+ * type, and a value use outside one is the checker's error rather than a read of a free name.
694
+ */
365
695
  function importNames(jsImport) {
366
696
  const importClause = jsImport.importClause;
367
697
  if (!importClause) {
368
698
  return [];
369
699
  }
370
- const names = bindingNames(unwrap(importClause.name)).map(bound => bound.name);
700
+ const names = boundIdentifiers(unwrap(importClause.name));
371
701
  const namedBindings = importClause.namedBindings;
372
702
  if ((namedBindings === null || namedBindings === void 0 ? void 0 : namedBindings.kind) === tree_2.JS.Kind.NamedImports) {
373
703
  for (const element of namedBindings.elements.elements) {
@@ -380,11 +710,11 @@ function importNames(jsImport) {
380
710
  else {
381
711
  names.push(...aliasedName(namedBindings));
382
712
  }
383
- return names;
713
+ return bound(names, 'value', 'type', 'namespace');
384
714
  }
385
715
  function aliasedName(specifier) {
386
716
  const name = (specifier === null || specifier === void 0 ? void 0 : specifier.kind) === tree_2.JS.Kind.Alias ? specifier.alias : specifier;
387
- return bindingNames(name).map(bound => bound.name);
717
+ return boundIdentifiers(name);
388
718
  }
389
719
  const blockScoped = new Set(['let', 'const', 'using']);
390
720
  // A walk of an immutable subtree has one answer, so it runs once. Keyed on the subtree itself, a
@@ -395,6 +725,7 @@ const hoisted = new WeakMap();
395
725
  const declared = new WeakMap();
396
726
  const used = new WeakMap();
397
727
  const referenced = new WeakMap();
728
+ const slots = new WeakMap();
398
729
  const frames = new WeakMap();
399
730
  const selfNamed = new WeakMap();
400
731
  /**
@@ -416,6 +747,8 @@ function hoistedNames(scope) {
416
747
  case java_1.J.Kind.MethodDeclaration:
417
748
  names.push(...declarationNames(node));
418
749
  return false;
750
+ case tree_2.JS.Kind.ComputedPropertyMethodDeclaration:
751
+ return false;
419
752
  case java_1.J.Kind.VariableDeclarations:
420
753
  case tree_2.JS.Kind.ScopedVariableDeclarations:
421
754
  if (!isBlockScoped(node)) {
@@ -429,8 +762,14 @@ function hoistedNames(scope) {
429
762
  case tree_2.JS.Kind.StatementExpression:
430
763
  // A function or class used as an expression names itself for its own body alone.
431
764
  return false;
765
+ case tree_2.JS.Kind.NamespaceDeclaration:
766
+ // A namespace keeps its hoisting to itself, a global augmentation gives it to the file.
767
+ return isGlobalAugmentation(node);
432
768
  case java_1.J.Kind.Lambda:
433
769
  case java_1.J.Kind.ClassDeclaration:
770
+ case java_1.J.Kind.NewClass:
771
+ case tree_2.JS.Kind.TypeLiteral:
772
+ // Nothing in an expression or a type hoists past it.
434
773
  return false;
435
774
  default:
436
775
  return true;
@@ -463,9 +802,13 @@ function walk(node, visit) {
463
802
  Object.entries(node).forEach(([key, value]) => key !== 'markers' && walk(value, visit));
464
803
  }
465
804
  }
466
- /** The element a padding wrapper holds, or the node itself. */
805
+ /** The tree a padding wrapper holds, or the node itself where it is a tree. */
467
806
  function unwrap(node) {
468
- return (node === null || node === void 0 ? void 0 : node.kind) === java_1.J.Kind.RightPadded || (node === null || node === void 0 ? void 0 : node.kind) === java_1.J.Kind.LeftPadded ? unwrap(node.element) : node;
807
+ const kind = node === null || node === void 0 ? void 0 : node.kind;
808
+ if (kind === java_1.J.Kind.RightPadded || kind === java_1.J.Kind.LeftPadded) {
809
+ return unwrap(node.element);
810
+ }
811
+ return (0, tree_1.isTree)(node) ? node : undefined;
469
812
  }
470
813
  /** `cursor` is protected on `TreeVisitor` and these APIs are free functions, so reaching it takes a cast. */
471
814
  function cursorOf(visitor) {
@@ -505,52 +848,174 @@ function declarationsOf(statement) {
505
848
  return [];
506
849
  }
507
850
  /**
508
- * Whether the identifier references a binding rather than naming one, which is what tells a rename
509
- * which occurrences to follow. A name its parent introduces does not — a property, a method, a
510
- * variable, a type parameter — nor one drawn from a namespace of its own: a statement label,
511
- * declaring (`x:`) or referencing (`break x`), and a JSX attribute's prop. Position is all this
512
- * reads: an import specifier's own name answers true, and a type position reads alike to a value.
851
+ * Whether the identifier may be renamed in place, which is so where its slot reads rather than
852
+ * names. A shorthand property `{x}` answers false though it reads `x`, since a rename has to
853
+ * expand it to `{x: y}`. Position is all this reads, so a type position reads alike to a value,
854
+ * and what `x` reads is {@link resolve}'s question.
513
855
  */
514
- function isValueReference(cursor, identifier) {
515
- let c = cursor.parent;
516
- while (c && isPadding(c.value)) {
517
- c = c.parent;
856
+ function isReference(cursor, identifier) {
857
+ const path = pathTo(cursor, identifier);
858
+ return !isShorthand(path[path.length - 1]) && position(path, identifier)[1] !== undefined;
859
+ }
860
+ /**
861
+ * The tree nodes from the nearest compilation unit on `cursor`, or its outermost tree, down to the
862
+ * one holding `identifier`, which is the cursor's own node or that node's parent.
863
+ */
864
+ function pathTo(cursor, identifier) {
865
+ const path = treePath(cursor);
866
+ if (path[path.length - 1] === identifier) {
867
+ path.pop();
518
868
  }
519
- return references(identifier, c === null || c === void 0 ? void 0 : c.value);
869
+ return path;
520
870
  }
521
- /** The position half of {@link isValueReference}, against a parent already found. */
522
- function references(identifier, parent) {
871
+ /** The cursors on `cursor`'s chain holding tree nodes, down from the nearest compilation unit or outermost tree. */
872
+ function treeCursors(cursor) {
523
873
  var _a;
524
- const owner = parent;
525
- // A call names a member of whatever it selects from. With nothing selected there is no member,
526
- // and its `name` is a reference to the function being called.
527
- if ((owner === null || owner === void 0 ? void 0 : owner.kind) === java_1.J.Kind.MethodInvocation && !owner.select) {
528
- return true;
874
+ const cursors = [];
875
+ for (let c = cursor; c; c = c.parent) {
876
+ if ((0, tree_1.isTree)(c.value)) {
877
+ cursors.unshift(c);
878
+ }
879
+ if (((_a = c.value) === null || _a === void 0 ? void 0 : _a.kind) === tree_2.JS.Kind.CompilationUnit) {
880
+ break;
881
+ }
529
882
  }
530
- // A binding element names the property it destructures and binds under `name`, so both slots
531
- // name rather than reference.
532
- if ((owner === null || owner === void 0 ? void 0 : owner.kind) === tree_2.JS.Kind.BindingElement && holds(owner.propertyName, identifier)) {
533
- return false;
883
+ return cursors;
884
+ }
885
+ function treePath(cursor) {
886
+ return treeCursors(cursor).map(c => c.value);
887
+ }
888
+ /**
889
+ * The scopes around `leaf` and what it reads with, folded down `path`, which ends at the node
890
+ * holding `leaf`, and what each node of `path` reads with. The fold runs to the end since a naming
891
+ * slot can hold a read deeper down.
892
+ */
893
+ function position(path, leaf) {
894
+ var _a, _b;
895
+ let scopes;
896
+ let reading = 'value';
897
+ const readings = [];
898
+ for (let i = 0; i < path.length; i++) {
899
+ readings.push(reading);
900
+ const child = (_a = path[i + 1]) !== null && _a !== void 0 ? _a : leaf;
901
+ const key = slotOf(path[i], child);
902
+ if (key === undefined) {
903
+ const spelled = (_b = child.simpleName) !== null && _b !== void 0 ? _b : child.kind;
904
+ throw new Error(`\`${spelled}\` is not under the cursor it is resolved from`);
905
+ }
906
+ [scopes, reading] = descend(path[i], path[i - 1], key, framesAt(path[i], path[i - 1], scopes), reading);
907
+ }
908
+ return [scopes, reading, readings];
909
+ }
910
+ /**
911
+ * The slot of `node` holding `child`, by id, so a copy or a rebuilt node is found as the original.
912
+ * A node's slots are indexed once, through padding, containers and lists.
913
+ */
914
+ function slotOf(node, child) {
915
+ let index = slots.get(node);
916
+ if (!index) {
917
+ index = new Map();
918
+ for (const [key, value] of Object.entries(node)) {
919
+ if (key !== 'markers') {
920
+ for (const held of treesIn(value)) {
921
+ index.set(held.id, key);
922
+ }
923
+ }
924
+ }
925
+ slots.set(node, index);
926
+ }
927
+ return index.get(child.id);
928
+ }
929
+ /** The tree nodes a slot holds directly, through padding, containers and lists. */
930
+ function treesIn(slot) {
931
+ if (Array.isArray(slot)) {
932
+ return slot.flatMap(treesIn);
933
+ }
934
+ const kind = slot === null || slot === void 0 ? void 0 : slot.kind;
935
+ if (kind === java_1.J.Kind.RightPadded || kind === java_1.J.Kind.LeftPadded) {
936
+ return treesIn(slot.element);
937
+ }
938
+ if (kind === java_1.J.Kind.Container) {
939
+ return treesIn(slot.elements);
534
940
  }
535
- // A JSX attribute keeps its prop name on `key`; the three label-bearing nodes keep theirs on
536
- // `label`. Every other kind that names rather than references keeps it on `name`.
537
- return !holds((owner === null || owner === void 0 ? void 0 : owner.kind) === tree_2.JS.Kind.JsxAttribute ? owner.key : ((_a = owner === null || owner === void 0 ? void 0 : owner.name) !== null && _a !== void 0 ? _a : owner === null || owner === void 0 ? void 0 : owner.label), identifier);
941
+ return (0, tree_1.isTree)(slot) ? [slot] : [];
942
+ }
943
+ /**
944
+ * @deprecated Use {@link isReference}. Unlike this function once did, it answers false for an
945
+ * import's own name, an alias and a re-export's specifier, which name rather than read.
946
+ */
947
+ exports.isValueReference = isReference;
948
+ /**
949
+ * The node owning the scope that binds what `identifier` reads, or undefined where it reads a
950
+ * global or reads nothing. Position is what resolves it, so the cursor stands on the identifier
951
+ * or on the node holding it, and a node the cursor does not hold is refused.
952
+ */
953
+ function resolve(cursor, identifier) {
954
+ var _a;
955
+ const [scopes, reading] = position(pathTo(cursor, identifier), identifier);
956
+ return reading && ((_a = bindingFrame(scopes, identifier.simpleName, reading)) === null || _a === void 0 ? void 0 : _a.node);
538
957
  }
539
- /** Whether a node slot, padded or not, is the identifier itself. */
540
- function holds(slot, identifier) {
541
- return slot === identifier || (slot === null || slot === void 0 ? void 0 : slot.element) === identifier;
958
+ /**
959
+ * Whether the identifier is assigned to where it stands. An assignment's target, plain or compound,
960
+ * is, and so are the operand of `++` or `--`, the head of a for-in or for-of declaring nothing, and
961
+ * a name in such a target's destructuring pattern. A write resolves as a value read, since
962
+ * `x = 2` assigns to the `x` it reads. The cursor is as {@link resolve} takes it.
963
+ */
964
+ function isWrite(cursor, identifier) {
965
+ return position(pathTo(cursor, identifier), identifier)[1] === 'write';
542
966
  }
543
967
  /**
544
- * As {@link references}, for a collector rather than a renamer: a shorthand property's name slot is
545
- * also the value it reads, which a rename has to expand rather than follow.
968
+ * Every identifier referring to the binding `name` has at `cursor`, the ones declaring it and the
969
+ * ones resolving to it, in the order the tree holds them, which a type annotation can depart from.
970
+ * The binding is the innermost one of the name with `meaning`, or with any meaning where none is
971
+ * asked for. A read with any meaning, as an export clause reads, refers to every meaning it finds.
972
+ * A name bound nowhere has no references. Each reference's cursor continues the caller's chain.
546
973
  */
547
- function reads(identifier, parent) {
548
- const owner = parent;
549
- return ((owner === null || owner === void 0 ? void 0 : owner.kind) === tree_2.JS.Kind.PropertyAssignment && owner.initializer === undefined) ||
550
- references(identifier, parent);
551
- }
552
- function isPadding(value) {
553
- const kind = value === null || value === void 0 ? void 0 : value.kind;
554
- return kind === java_1.J.Kind.RightPadded || kind === java_1.J.Kind.LeftPadded || kind === java_1.J.Kind.Container;
974
+ function referencesOf(cursor, name, meaning) {
975
+ const cursors = treeCursors(cursor);
976
+ const path = cursors.map(c => c.value);
977
+ if (path.length === 0) {
978
+ return [];
979
+ }
980
+ const [scopes, reading, readings] = position(path.slice(0, -1), path[path.length - 1]);
981
+ readings.push(reading);
982
+ const here = framesAt(path[path.length - 1], path[path.length - 2], scopes);
983
+ const frame = bindingFrame(here, name, meaning !== null && meaning !== void 0 ? meaning : 'any');
984
+ if (!frame) {
985
+ return [];
986
+ }
987
+ const declarations = new Set(frameBindings(frame.node, frame.parent).get(name).declarations
988
+ .filter(declaration => meaning === undefined || declaration.meanings.includes(meaning))
989
+ .map(declaration => declaration.identifier.id));
990
+ // A class binds its own name in its body too, so a frame further out declaring the same
991
+ // identifier holds the same binding, and its references sit under that frame.
992
+ const sharesBinding = (scope) => {
993
+ var _a, _b;
994
+ return scope !== undefined &&
995
+ ((_b = (_a = frameBindings(scope.node, scope.parent).get(name)) === null || _a === void 0 ? void 0 : _a.declarations) !== null && _b !== void 0 ? _b : [])
996
+ .some(declaration => declarations.has(declaration.identifier.id));
997
+ };
998
+ let root = frame;
999
+ for (let outer = frame.outer; outer; outer = outer.outer) {
1000
+ if (sharesBinding(outer)) {
1001
+ root = outer;
1002
+ }
1003
+ }
1004
+ const at = path.indexOf(root.node);
1005
+ const references = [];
1006
+ readReferences(root.node, root.parent, root.outer, readings[at], (identifier, reads, scopes, trail) => {
1007
+ if (identifier.simpleName !== name) {
1008
+ return;
1009
+ }
1010
+ const declares = declarations.has(identifier.id);
1011
+ const refers = !declares && reads !== undefined &&
1012
+ (meaning === undefined || reads === 'any' || meaningRead(reads) === meaning) &&
1013
+ sharesBinding(bindingFrame(scopes, name, reads));
1014
+ if (declares || refers) {
1015
+ const standing = trail.reduce((above, node) => new tree_1.Cursor(node, above), cursors[at].parent);
1016
+ references.push({ cursor: standing, identifier, declares, writes: reads === 'write' });
1017
+ }
1018
+ });
1019
+ return references;
555
1020
  }
556
1021
  //# sourceMappingURL=scope.js.map