@venizia/dev-configs 0.4.7-0 → 0.4.7-1

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 (182) hide show
  1. package/LICENSE.md +1 -3
  2. package/README.md +1 -1
  3. package/dist/checks/catalog.d.ts +4 -2
  4. package/dist/checks/catalog.d.ts.map +1 -1
  5. package/dist/checks/catalog.js +72 -70
  6. package/dist/checks/catalog.js.map +1 -1
  7. package/dist/checks/module-cycles.d.ts +11 -9
  8. package/dist/checks/module-cycles.d.ts.map +1 -1
  9. package/dist/checks/module-cycles.js +32 -30
  10. package/dist/checks/module-cycles.js.map +1 -1
  11. package/dist/checks/purity/manifest.d.ts +44 -38
  12. package/dist/checks/purity/manifest.d.ts.map +1 -1
  13. package/dist/checks/purity/manifest.js +121 -115
  14. package/dist/checks/purity/manifest.js.map +1 -1
  15. package/dist/checks/purity/probe.d.ts +22 -18
  16. package/dist/checks/purity/probe.d.ts.map +1 -1
  17. package/dist/checks/purity/probe.js +99 -98
  18. package/dist/checks/purity/probe.js.map +1 -1
  19. package/dist/checks/purity/run.d.ts +18 -16
  20. package/dist/checks/purity/run.d.ts.map +1 -1
  21. package/dist/checks/purity/run.js +90 -86
  22. package/dist/checks/purity/run.js.map +1 -1
  23. package/dist/checks/test-controls.d.ts +17 -15
  24. package/dist/checks/test-controls.d.ts.map +1 -1
  25. package/dist/checks/test-controls.js +71 -70
  26. package/dist/checks/test-controls.js.map +1 -1
  27. package/dist/checks/test-dead-code.d.ts +5 -3
  28. package/dist/checks/test-dead-code.d.ts.map +1 -1
  29. package/dist/checks/test-dead-code.js +23 -21
  30. package/dist/checks/test-dead-code.js.map +1 -1
  31. package/dist/checks/test-mutate.d.ts +12 -7
  32. package/dist/checks/test-mutate.d.ts.map +1 -1
  33. package/dist/checks/test-mutate.js +59 -56
  34. package/dist/checks/test-mutate.js.map +1 -1
  35. package/dist/checks/test-weight.d.ts +11 -8
  36. package/dist/checks/test-weight.d.ts.map +1 -1
  37. package/dist/checks/test-weight.js +98 -94
  38. package/dist/checks/test-weight.js.map +1 -1
  39. package/dist/cli/check.d.ts.map +1 -1
  40. package/dist/cli/check.js +11 -8
  41. package/dist/cli/check.js.map +1 -1
  42. package/dist/cli/codemod/async-style.d.ts +29 -8
  43. package/dist/cli/codemod/async-style.d.ts.map +1 -1
  44. package/dist/cli/codemod/async-style.js +102 -20
  45. package/dist/cli/codemod/async-style.js.map +1 -1
  46. package/dist/cli/codemod/index.d.ts.map +1 -1
  47. package/dist/cli/codemod/index.js +6 -2
  48. package/dist/cli/codemod/index.js.map +1 -1
  49. package/dist/cli/codemod/model-settings.d.ts +7 -5
  50. package/dist/cli/codemod/model-settings.d.ts.map +1 -1
  51. package/dist/cli/codemod/model-settings.js +293 -291
  52. package/dist/cli/codemod/model-settings.js.map +1 -1
  53. package/dist/cli/codemod/namespace-functions/index.d.ts +20 -0
  54. package/dist/cli/codemod/namespace-functions/index.d.ts.map +1 -0
  55. package/dist/cli/codemod/namespace-functions/index.js +182 -0
  56. package/dist/cli/codemod/namespace-functions/index.js.map +1 -0
  57. package/dist/cli/codemod/namespace-functions/logger-scope.d.ts +32 -0
  58. package/dist/cli/codemod/namespace-functions/logger-scope.d.ts.map +1 -0
  59. package/dist/cli/codemod/namespace-functions/logger-scope.js +128 -0
  60. package/dist/cli/codemod/namespace-functions/logger-scope.js.map +1 -0
  61. package/dist/cli/codemod/namespace-functions/mapping.d.ts +66 -0
  62. package/dist/cli/codemod/namespace-functions/mapping.d.ts.map +1 -0
  63. package/dist/cli/codemod/namespace-functions/mapping.js +99 -0
  64. package/dist/cli/codemod/namespace-functions/mapping.js.map +1 -0
  65. package/dist/cli/codemod/namespace-functions/mappings/boot.d.ts +7 -0
  66. package/dist/cli/codemod/namespace-functions/mappings/boot.d.ts.map +1 -0
  67. package/dist/cli/codemod/namespace-functions/mappings/boot.js +28 -0
  68. package/dist/cli/codemod/namespace-functions/mappings/boot.js.map +1 -0
  69. package/dist/cli/codemod/namespace-functions/mappings/connectors.d.ts +4 -0
  70. package/dist/cli/codemod/namespace-functions/mappings/connectors.d.ts.map +1 -0
  71. package/dist/cli/codemod/namespace-functions/mappings/connectors.js +218 -0
  72. package/dist/cli/codemod/namespace-functions/mappings/connectors.js.map +1 -0
  73. package/dist/cli/codemod/namespace-functions/mappings/core-server.d.ts +7 -0
  74. package/dist/cli/codemod/namespace-functions/mappings/core-server.d.ts.map +1 -0
  75. package/dist/cli/codemod/namespace-functions/mappings/core-server.js +162 -0
  76. package/dist/cli/codemod/namespace-functions/mappings/core-server.js.map +1 -0
  77. package/dist/cli/codemod/namespace-functions/mappings/core-worker.d.ts +7 -0
  78. package/dist/cli/codemod/namespace-functions/mappings/core-worker.d.ts.map +1 -0
  79. package/dist/cli/codemod/namespace-functions/mappings/core-worker.js +18 -0
  80. package/dist/cli/codemod/namespace-functions/mappings/core-worker.js.map +1 -0
  81. package/dist/cli/codemod/namespace-functions/mappings/dev-configs.d.ts +7 -0
  82. package/dist/cli/codemod/namespace-functions/mappings/dev-configs.d.ts.map +1 -0
  83. package/dist/cli/codemod/namespace-functions/mappings/dev-configs.js +192 -0
  84. package/dist/cli/codemod/namespace-functions/mappings/dev-configs.js.map +1 -0
  85. package/dist/cli/codemod/namespace-functions/mappings/filter.d.ts +7 -0
  86. package/dist/cli/codemod/namespace-functions/mappings/filter.d.ts.map +1 -0
  87. package/dist/cli/codemod/namespace-functions/mappings/filter.js +30 -0
  88. package/dist/cli/codemod/namespace-functions/mappings/filter.js.map +1 -0
  89. package/dist/cli/codemod/namespace-functions/mappings/helpers.d.ts +16 -0
  90. package/dist/cli/codemod/namespace-functions/mappings/helpers.d.ts.map +1 -0
  91. package/dist/cli/codemod/namespace-functions/mappings/helpers.js +535 -0
  92. package/dist/cli/codemod/namespace-functions/mappings/helpers.js.map +1 -0
  93. package/dist/cli/codemod/namespace-functions/mappings/index.d.ts +4 -0
  94. package/dist/cli/codemod/namespace-functions/mappings/index.d.ts.map +1 -0
  95. package/dist/cli/codemod/namespace-functions/mappings/index.js +25 -0
  96. package/dist/cli/codemod/namespace-functions/mappings/index.js.map +1 -0
  97. package/dist/cli/codemod/namespace-functions/mappings/inversion.d.ts +10 -0
  98. package/dist/cli/codemod/namespace-functions/mappings/inversion.d.ts.map +1 -0
  99. package/dist/cli/codemod/namespace-functions/mappings/inversion.js +81 -0
  100. package/dist/cli/codemod/namespace-functions/mappings/inversion.js.map +1 -0
  101. package/dist/cli/codemod/namespace-functions/mappings/kernel.d.ts +17 -0
  102. package/dist/cli/codemod/namespace-functions/mappings/kernel.d.ts.map +1 -0
  103. package/dist/cli/codemod/namespace-functions/mappings/kernel.js +229 -0
  104. package/dist/cli/codemod/namespace-functions/mappings/kernel.js.map +1 -0
  105. package/dist/cli/codemod/namespace-functions/rewriter.d.ts +61 -0
  106. package/dist/cli/codemod/namespace-functions/rewriter.d.ts.map +1 -0
  107. package/dist/cli/codemod/namespace-functions/rewriter.js +564 -0
  108. package/dist/cli/codemod/namespace-functions/rewriter.js.map +1 -0
  109. package/dist/cli/index.js +2 -1
  110. package/dist/cli/index.js.map +1 -1
  111. package/dist/compilers/bun.d.ts +1 -1
  112. package/dist/compilers/bun.js +1 -1
  113. package/dist/compilers/bun.js.map +1 -1
  114. package/dist/linters/house/await-support.d.ts +17 -3
  115. package/dist/linters/house/await-support.d.ts.map +1 -1
  116. package/dist/linters/house/await-support.js +52 -23
  117. package/dist/linters/house/await-support.js.map +1 -1
  118. package/dist/linters/house/common.d.ts +13 -9
  119. package/dist/linters/house/common.d.ts.map +1 -1
  120. package/dist/linters/house/common.js +18 -15
  121. package/dist/linters/house/common.js.map +1 -1
  122. package/dist/linters/house/configs.d.ts +5 -2
  123. package/dist/linters/house/configs.d.ts.map +1 -1
  124. package/dist/linters/house/configs.js +11 -2
  125. package/dist/linters/house/configs.js.map +1 -1
  126. package/dist/linters/house/const-class-values.rule.d.ts.map +1 -1
  127. package/dist/linters/house/const-class-values.rule.js +27 -19
  128. package/dist/linters/house/const-class-values.rule.js.map +1 -1
  129. package/dist/linters/house/effect-cleanup-consistency.rule.js +3 -3
  130. package/dist/linters/house/effect-cleanup-consistency.rule.js.map +1 -1
  131. package/dist/linters/house/hook-support.d.ts.map +1 -1
  132. package/dist/linters/house/hook-support.js +17 -14
  133. package/dist/linters/house/hook-support.js.map +1 -1
  134. package/dist/linters/house/index.d.ts +3 -0
  135. package/dist/linters/house/index.d.ts.map +1 -1
  136. package/dist/linters/house/index.js +3 -0
  137. package/dist/linters/house/index.js.map +1 -1
  138. package/dist/linters/house/max-params-own.rule.d.ts.map +1 -1
  139. package/dist/linters/house/max-params-own.rule.js +33 -24
  140. package/dist/linters/house/max-params-own.rule.js.map +1 -1
  141. package/dist/linters/house/no-async-hook-callback.rule.js +1 -1
  142. package/dist/linters/house/no-async-hook-callback.rule.js.map +1 -1
  143. package/dist/linters/house/no-await-promise-chain.rule.d.ts +24 -0
  144. package/dist/linters/house/no-await-promise-chain.rule.d.ts.map +1 -0
  145. package/dist/linters/house/no-await-promise-chain.rule.js +298 -0
  146. package/dist/linters/house/no-await-promise-chain.rule.js.map +1 -0
  147. package/dist/linters/house/no-inline-await.rule.d.ts.map +1 -1
  148. package/dist/linters/house/no-inline-await.rule.js +6 -12
  149. package/dist/linters/house/no-inline-await.rule.js.map +1 -1
  150. package/dist/linters/house/no-new-error.rule.js +4 -4
  151. package/dist/linters/house/no-new-error.rule.js.map +1 -1
  152. package/dist/linters/house/no-return-await.rule.d.ts.map +1 -1
  153. package/dist/linters/house/no-return-await.rule.js +11 -11
  154. package/dist/linters/house/no-return-await.rule.js.map +1 -1
  155. package/dist/linters/house/no-silent-catch.rule.d.ts +22 -0
  156. package/dist/linters/house/no-silent-catch.rule.d.ts.map +1 -0
  157. package/dist/linters/house/no-silent-catch.rule.js +88 -0
  158. package/dist/linters/house/no-silent-catch.rule.js.map +1 -0
  159. package/dist/linters/house/plugin.d.ts.map +1 -1
  160. package/dist/linters/house/plugin.js +4 -0
  161. package/dist/linters/house/plugin.js.map +1 -1
  162. package/dist/linters/house/promise-chain-support.d.ts +49 -0
  163. package/dist/linters/house/promise-chain-support.d.ts.map +1 -0
  164. package/dist/linters/house/promise-chain-support.js +188 -0
  165. package/dist/linters/house/promise-chain-support.js.map +1 -0
  166. package/dist/linters/rules/no-restricted-properties.rule.js +1 -1
  167. package/dist/linters/rules/no-restricted-properties.rule.js.map +1 -1
  168. package/dist/testing/rejection.helper.d.ts +25 -20
  169. package/dist/testing/rejection.helper.d.ts.map +1 -1
  170. package/dist/testing/rejection.helper.js +33 -31
  171. package/dist/testing/rejection.helper.js.map +1 -1
  172. package/dist/testing/repo-tmp.d.ts +19 -9
  173. package/dist/testing/repo-tmp.d.ts.map +1 -1
  174. package/dist/testing/repo-tmp.js +50 -48
  175. package/dist/testing/repo-tmp.js.map +1 -1
  176. package/dist/testing/spawn.helper.d.ts +12 -10
  177. package/dist/testing/spawn.helper.d.ts.map +1 -1
  178. package/dist/testing/spawn.helper.js +22 -16
  179. package/dist/testing/spawn.helper.js.map +1 -1
  180. package/dist/testing/tmpdir-preload.js +1 -1
  181. package/dist/testing/tmpdir-preload.js.map +1 -1
  182. package/package.json +2 -3
@@ -0,0 +1,564 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NamespaceFunctions = void 0;
4
+ /**
5
+ * Rewrites the calls of functions that moved into a class, `oldName(a, b)` to
6
+ * `ClassName.method({ first: a, second: b })`, from a mapping table. Syntactic: it reads one file and
7
+ * needs no type checker, so it only follows names imported from a module the table lists. Every edit
8
+ * is a text edit by position: the argument text, its comments and the untouched code stay as they are.
9
+ */
10
+ class NamespaceFunctions {
11
+ static rewrite(opts) {
12
+ const { typescript, fileName, source, mappings } = opts;
13
+ const sourceFile = typescript.createSourceFile(fileName, source, typescript.ScriptTarget.Latest, true);
14
+ const reports = [];
15
+ const report = (reportOpts) => {
16
+ const { line, character } = sourceFile.getLineAndCharacterOfPosition(reportOpts.node.getStart(sourceFile));
17
+ reports.push({ line: line + 1, column: character + 1, reason: reportOpts.reason });
18
+ };
19
+ const lineOf = (node) => sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1;
20
+ const byModule = new Map();
21
+ for (const mapping of mappings) {
22
+ for (const module of mapping.modules) {
23
+ byModule.set(module, [...(byModule.get(module) ?? []), mapping]);
24
+ }
25
+ }
26
+ const bindings = NamespaceFunctions.findBindings({
27
+ typescript,
28
+ sourceFile,
29
+ byModule,
30
+ report,
31
+ });
32
+ if (bindings.length === 0) {
33
+ return { output: source, changed: false, rewritten: 0, reports };
34
+ }
35
+ const identifiers = NamespaceFunctions.collectIdentifiers({ typescript, sourceFile });
36
+ const declarationsOf = (name) => (identifiers.get(name) ?? []).filter((identifier) => NamespaceFunctions.isDeclarationName({ typescript, identifier }));
37
+ const edits = [];
38
+ const removals = new Set();
39
+ /** The imports that lose an old name. */
40
+ const trimmed = new Set();
41
+ const additions = new Map();
42
+ const newImports = new Map();
43
+ /** The class names this run imports, and from which module. */
44
+ const planned = new Map();
45
+ let rewritten = 0;
46
+ for (const binding of bindings) {
47
+ const { mapping } = binding;
48
+ const uses = NamespaceFunctions.findUses({ typescript, binding, identifiers });
49
+ if (uses.calls.length === 0 && uses.values.length === 0) {
50
+ continue;
51
+ }
52
+ const target = NamespaceFunctions.describeTarget({ mapping });
53
+ for (const value of uses.values) {
54
+ report({
55
+ node: value,
56
+ reason: `\`${mapping.oldName}\` is used as a value (passed, stored, exported or in typeof), so its import stays; change it by hand to ${mapping.className}.${mapping.method}`,
57
+ });
58
+ }
59
+ if (uses.calls.length === 0) {
60
+ continue;
61
+ }
62
+ const shadow = declarationsOf(binding.local).find((identifier) => identifier !== binding.declarationName);
63
+ if (shadow) {
64
+ report({
65
+ node: shadow,
66
+ reason: `\`${binding.local}\` is declared again in this file, so a call cannot be told apart from the import; rewrite the calls of \`${mapping.oldName}\` by hand as ${target}`,
67
+ });
68
+ continue;
69
+ }
70
+ const classModules = mapping.newModules ?? [binding.module];
71
+ const isNamespaceReach = !binding.specifier && classModules.includes(binding.module);
72
+ let classReference = `${binding.local}.${mapping.className}`;
73
+ let needsImport = false;
74
+ if (!isNamespaceReach) {
75
+ const existing = NamespaceFunctions.findClassImport({
76
+ typescript,
77
+ sourceFile,
78
+ className: mapping.className,
79
+ modules: classModules,
80
+ });
81
+ const plannedModule = planned.get(mapping.className);
82
+ const conflict = existing
83
+ ? declarationsOf(existing.text).find((identifier) => identifier !== existing)
84
+ : plannedModule === undefined
85
+ ? declarationsOf(mapping.className)[0]
86
+ : undefined;
87
+ if (conflict) {
88
+ report({
89
+ node: uses.calls[0] ?? conflict,
90
+ reason: `the name \`${conflict.text}\` is already declared in this file (line ${lineOf(conflict)}), so \`${mapping.oldName}\` is left; rewrite its calls by hand as ${target}`,
91
+ });
92
+ continue;
93
+ }
94
+ if (!existing && plannedModule !== undefined && !classModules.includes(plannedModule)) {
95
+ report({
96
+ node: uses.calls[0] ?? binding.declaration,
97
+ reason: `\`${mapping.className}\` would be imported from both ${plannedModule} and ${classModules[0]}; rewrite the calls of \`${mapping.oldName}\` by hand as ${target}`,
98
+ });
99
+ continue;
100
+ }
101
+ classReference = existing?.text ?? mapping.className;
102
+ needsImport = !existing && plannedModule === undefined;
103
+ }
104
+ let count = 0;
105
+ let left = uses.values.length;
106
+ for (const call of uses.calls) {
107
+ const problem = NamespaceFunctions.checkCall({ typescript, call, mapping });
108
+ if (problem) {
109
+ left += 1;
110
+ report({ node: call, reason: `${problem}; rewrite it by hand as ${target}` });
111
+ continue;
112
+ }
113
+ edits.push(...NamespaceFunctions.planCall({
114
+ typescript,
115
+ sourceFile,
116
+ call,
117
+ mapping,
118
+ callee: `${classReference}.${mapping.method}`,
119
+ }));
120
+ count += 1;
121
+ }
122
+ rewritten += count;
123
+ if (count === 0) {
124
+ continue;
125
+ }
126
+ if (needsImport) {
127
+ const sameDeclaration = binding.specifier && classModules.includes(binding.module)
128
+ ? binding.declaration
129
+ : undefined;
130
+ const declaration = sameDeclaration ??
131
+ NamespaceFunctions.findNamedImport({ typescript, sourceFile, modules: classModules });
132
+ if (declaration) {
133
+ additions.set(declaration, new Set([...(additions.get(declaration) ?? []), mapping.className]));
134
+ planned.set(mapping.className, sameDeclaration ? binding.module : NamespaceFunctions.moduleOf({ declaration }));
135
+ }
136
+ else {
137
+ const module = classModules[0] ?? binding.module;
138
+ const entry = newImports.get(module) ?? {
139
+ anchor: binding.declaration,
140
+ names: new Set(),
141
+ };
142
+ entry.names.add(mapping.className);
143
+ newImports.set(module, entry);
144
+ planned.set(mapping.className, module);
145
+ }
146
+ }
147
+ if (binding.specifier && left === 0) {
148
+ removals.add(binding.specifier);
149
+ trimmed.add(binding.declaration);
150
+ }
151
+ }
152
+ if (rewritten === 0) {
153
+ return { output: source, changed: false, rewritten: 0, reports };
154
+ }
155
+ for (const declaration of new Set([...additions.keys(), ...trimmed])) {
156
+ edits.push(...NamespaceFunctions.planImport({
157
+ typescript,
158
+ sourceFile,
159
+ declaration,
160
+ removals,
161
+ additions: [...(additions.get(declaration) ?? [])],
162
+ report,
163
+ }));
164
+ }
165
+ for (const [module, { anchor, names }] of newImports) {
166
+ const quote = source.charAt(anchor.moduleSpecifier.getStart(sourceFile));
167
+ edits.push({
168
+ start: anchor.getStart(sourceFile),
169
+ end: anchor.getStart(sourceFile),
170
+ text: `import { ${[...names].join(', ')} } from ${quote}${module}${quote};\n`,
171
+ });
172
+ }
173
+ // At one position a replacement (the longer range) is applied before an insertion, so the
174
+ // inserted key of an outer call lands in front of the rewritten callee of an inner one.
175
+ let output = source;
176
+ for (const edit of edits.sort((a, b) => b.start - a.start || b.end - a.end)) {
177
+ output = output.slice(0, edit.start) + edit.text + output.slice(edit.end);
178
+ }
179
+ return { output, changed: output !== source, rewritten, reports };
180
+ }
181
+ /** The named and namespace imports of an old name; reports the type-only imports and the re-exports. */
182
+ static findBindings(opts) {
183
+ const { typescript, sourceFile, byModule, report } = opts;
184
+ const bindings = [];
185
+ for (const statement of sourceFile.statements) {
186
+ if (typescript.isExportDeclaration(statement) &&
187
+ statement.moduleSpecifier &&
188
+ typescript.isStringLiteral(statement.moduleSpecifier) &&
189
+ statement.exportClause &&
190
+ typescript.isNamedExports(statement.exportClause)) {
191
+ const candidates = byModule.get(statement.moduleSpecifier.text) ?? [];
192
+ for (const element of statement.exportClause.elements) {
193
+ const name = (element.propertyName ?? element.name).text;
194
+ const mapping = candidates.find((candidate) => candidate.oldName === name);
195
+ if (mapping) {
196
+ report({
197
+ node: element,
198
+ reason: `re-exports \`${name}\`; re-export ${mapping.className} as well, by hand (the old name goes away in 0.5)`,
199
+ });
200
+ }
201
+ }
202
+ continue;
203
+ }
204
+ if (!typescript.isImportDeclaration(statement) ||
205
+ !typescript.isStringLiteral(statement.moduleSpecifier) ||
206
+ !statement.importClause) {
207
+ continue;
208
+ }
209
+ const module = statement.moduleSpecifier.text;
210
+ const candidates = byModule.get(module);
211
+ const clause = statement.importClause;
212
+ const named = clause.namedBindings;
213
+ if (!candidates || !named) {
214
+ continue;
215
+ }
216
+ if (typescript.isNamespaceImport(named)) {
217
+ if (clause.isTypeOnly) {
218
+ continue;
219
+ }
220
+ for (const mapping of candidates) {
221
+ bindings.push({
222
+ mapping,
223
+ declaration: statement,
224
+ module,
225
+ local: named.name.text,
226
+ declarationName: named.name,
227
+ });
228
+ }
229
+ continue;
230
+ }
231
+ for (const element of named.elements) {
232
+ const imported = (element.propertyName ?? element.name).text;
233
+ const mapping = candidates.find((candidate) => candidate.oldName === imported);
234
+ if (!mapping) {
235
+ continue;
236
+ }
237
+ if (clause.isTypeOnly || element.isTypeOnly) {
238
+ report({
239
+ node: element,
240
+ reason: `\`${imported}\` is imported as a type only; change it by hand to \`typeof ${mapping.className}.${mapping.method}\``,
241
+ });
242
+ continue;
243
+ }
244
+ bindings.push({
245
+ mapping,
246
+ declaration: statement,
247
+ module,
248
+ local: element.name.text,
249
+ declarationName: element.name,
250
+ specifier: element,
251
+ });
252
+ }
253
+ }
254
+ return bindings;
255
+ }
256
+ /** Every identifier of the file by its text; JSDoc is not walked, so a `{@link name}` never counts. */
257
+ static collectIdentifiers(opts) {
258
+ const { typescript, sourceFile } = opts;
259
+ const identifiers = new Map();
260
+ const walk = (node) => {
261
+ if (typescript.isIdentifier(node)) {
262
+ identifiers.set(node.text, [...(identifiers.get(node.text) ?? []), node]);
263
+ }
264
+ typescript.forEachChild(node, walk);
265
+ };
266
+ walk(sourceFile);
267
+ return identifiers;
268
+ }
269
+ /** The calls of the old name, and every other use of it. */
270
+ static findUses(opts) {
271
+ const { typescript, binding, identifiers } = opts;
272
+ const uses = { calls: [], values: [] };
273
+ for (const identifier of identifiers.get(binding.local) ?? []) {
274
+ if (identifier === binding.declarationName ||
275
+ !NamespaceFunctions.isReference({ typescript, identifier })) {
276
+ continue;
277
+ }
278
+ if (!binding.specifier) {
279
+ const parent = identifier.parent;
280
+ const isMember = typescript.isPropertyAccessExpression(parent) &&
281
+ parent.expression === identifier &&
282
+ parent.name.text === binding.mapping.oldName;
283
+ if (isMember) {
284
+ const call = parent.parent;
285
+ if (typescript.isCallExpression(call) && call.expression === parent) {
286
+ uses.calls.push(call);
287
+ }
288
+ else {
289
+ uses.values.push(parent);
290
+ }
291
+ continue;
292
+ }
293
+ if (typescript.isQualifiedName(parent) &&
294
+ parent.left === identifier &&
295
+ parent.right.text === binding.mapping.oldName) {
296
+ uses.values.push(parent);
297
+ }
298
+ continue;
299
+ }
300
+ const parent = identifier.parent;
301
+ if (typescript.isCallExpression(parent) && parent.expression === identifier) {
302
+ uses.calls.push(parent);
303
+ continue;
304
+ }
305
+ uses.values.push(identifier);
306
+ }
307
+ return uses;
308
+ }
309
+ /** The identifier names a declaration: a variable, a parameter, a function, a class, an import, a type. */
310
+ static isDeclarationName(opts) {
311
+ const { typescript, identifier } = opts;
312
+ const parent = identifier.parent;
313
+ if (typescript.isVariableDeclaration(parent) ||
314
+ typescript.isParameter(parent) ||
315
+ typescript.isBindingElement(parent) ||
316
+ typescript.isFunctionDeclaration(parent) ||
317
+ typescript.isFunctionExpression(parent) ||
318
+ typescript.isClassDeclaration(parent) ||
319
+ typescript.isClassExpression(parent) ||
320
+ typescript.isEnumDeclaration(parent) ||
321
+ typescript.isInterfaceDeclaration(parent) ||
322
+ typescript.isTypeAliasDeclaration(parent) ||
323
+ typescript.isModuleDeclaration(parent) ||
324
+ typescript.isImportSpecifier(parent) ||
325
+ typescript.isImportClause(parent) ||
326
+ typescript.isNamespaceImport(parent) ||
327
+ typescript.isImportEqualsDeclaration(parent) ||
328
+ typescript.isTypeParameterDeclaration(parent)) {
329
+ return parent.name === identifier;
330
+ }
331
+ return false;
332
+ }
333
+ /** The identifier reads a binding: not a property name, a label, a declaration or a lowercase JSX tag. */
334
+ static isReference(opts) {
335
+ const { typescript, identifier } = opts;
336
+ const parent = identifier.parent;
337
+ if (NamespaceFunctions.isDeclarationName({ typescript, identifier })) {
338
+ return false;
339
+ }
340
+ if (typescript.isPropertyAccessExpression(parent) || typescript.isQualifiedName(parent)) {
341
+ return typescript.isPropertyAccessExpression(parent)
342
+ ? parent.name !== identifier
343
+ : parent.right !== identifier;
344
+ }
345
+ if (typescript.isPropertyAssignment(parent) ||
346
+ typescript.isPropertyDeclaration(parent) ||
347
+ typescript.isPropertySignature(parent) ||
348
+ typescript.isMethodDeclaration(parent) ||
349
+ typescript.isMethodSignature(parent) ||
350
+ typescript.isGetAccessorDeclaration(parent) ||
351
+ typescript.isSetAccessorDeclaration(parent) ||
352
+ typescript.isEnumMember(parent) ||
353
+ typescript.isJsxAttribute(parent)) {
354
+ return parent.name !== identifier;
355
+ }
356
+ if (typescript.isBindingElement(parent)) {
357
+ return parent.propertyName !== identifier;
358
+ }
359
+ if (typescript.isExportSpecifier(parent)) {
360
+ return (!parent.parent.parent.moduleSpecifier && (parent.propertyName ?? parent.name) === identifier);
361
+ }
362
+ if (typescript.isLabeledStatement(parent) ||
363
+ typescript.isBreakOrContinueStatement(parent) ||
364
+ typescript.isMetaProperty(parent)) {
365
+ return false;
366
+ }
367
+ if ((typescript.isJsxOpeningElement(parent) ||
368
+ typescript.isJsxSelfClosingElement(parent) ||
369
+ typescript.isJsxClosingElement(parent)) &&
370
+ parent.tagName === identifier) {
371
+ return !/^[a-z]/.test(identifier.text);
372
+ }
373
+ return true;
374
+ }
375
+ /** Why a call cannot be rewritten, or `undefined` when it can. */
376
+ static checkCall(opts) {
377
+ const { typescript, call, mapping } = opts;
378
+ const { params, restKey, oldName } = mapping;
379
+ const count = call.arguments.length;
380
+ if (mapping.keepsOptions) {
381
+ return undefined;
382
+ }
383
+ if (call.arguments.some((argument) => typescript.isSpreadElement(argument))) {
384
+ return `this call of \`${oldName}\` has a spread argument`;
385
+ }
386
+ const required = params.reduce((last, parameter, index) => (parameter.optional ? last : index + 1), 0);
387
+ if (count < required) {
388
+ return `this call of \`${oldName}\` passes ${count} argument(s), fewer than the ${required} it needs`;
389
+ }
390
+ if (restKey === undefined && count > params.length) {
391
+ return `this call of \`${oldName}\` passes ${count} argument(s), more than its ${params.length} parameter(s)`;
392
+ }
393
+ return undefined;
394
+ }
395
+ /** The edits that turn one call into the class form; the arguments keep their text and comments. */
396
+ static planCall(opts) {
397
+ const { typescript, sourceFile, call, mapping, callee } = opts;
398
+ const { params, restKey } = mapping;
399
+ const edits = [
400
+ { start: call.expression.getStart(sourceFile), end: call.expression.end, text: callee },
401
+ ];
402
+ if (call.questionDotToken) {
403
+ edits.push({
404
+ start: call.questionDotToken.getStart(sourceFile),
405
+ end: call.questionDotToken.end,
406
+ text: '',
407
+ });
408
+ }
409
+ if (mapping.keepsOptions) {
410
+ return edits;
411
+ }
412
+ const argumentList = [...call.arguments];
413
+ if (argumentList.length === 0) {
414
+ if (params.length > 0 || restKey !== undefined) {
415
+ const text = restKey === undefined ? '{}' : `{ ${restKey}: [] }`;
416
+ edits.push({ start: call.arguments.pos, end: call.arguments.pos, text });
417
+ }
418
+ return edits;
419
+ }
420
+ const insert = (insertOpts) => {
421
+ if (insertOpts.text !== '') {
422
+ edits.push({ start: insertOpts.at, end: insertOpts.at, text: insertOpts.text });
423
+ }
424
+ };
425
+ const positional = argumentList.slice(0, params.length);
426
+ const rest = argumentList.slice(params.length);
427
+ positional.forEach((argument, index) => {
428
+ const key = params[index]?.key ?? '';
429
+ const isShorthand = typescript.isIdentifier(argument) && argument.text === key;
430
+ insert({
431
+ at: argument.getStart(sourceFile),
432
+ text: `${index === 0 ? '{ ' : ''}${isShorthand ? '' : `${key}: `}`,
433
+ });
434
+ });
435
+ const first = rest[0];
436
+ const last = argumentList[argumentList.length - 1];
437
+ let suffix = ' }';
438
+ if (first && restKey !== undefined) {
439
+ insert({
440
+ at: first.getStart(sourceFile),
441
+ text: `${positional.length === 0 ? '{ ' : ''}${restKey}: [`,
442
+ });
443
+ suffix = '] }';
444
+ }
445
+ else if (restKey !== undefined) {
446
+ suffix = `, ${restKey}: [] }`;
447
+ }
448
+ insert({ at: last?.end ?? call.arguments.end, text: suffix });
449
+ return edits;
450
+ }
451
+ /** The local name of a value import of the class from one of `modules`. */
452
+ static findClassImport(opts) {
453
+ const { typescript, sourceFile, className, modules } = opts;
454
+ for (const statement of sourceFile.statements) {
455
+ const declaration = NamespaceFunctions.asValueImport({ typescript, statement, modules });
456
+ const named = declaration?.importClause?.namedBindings;
457
+ if (!named || !typescript.isNamedImports(named)) {
458
+ continue;
459
+ }
460
+ const element = named.elements.find((candidate) => !candidate.isTypeOnly && (candidate.propertyName ?? candidate.name).text === className);
461
+ if (element) {
462
+ return element.name;
463
+ }
464
+ }
465
+ return undefined;
466
+ }
467
+ /** The first value import with braces from one of `modules`, to add a class to. */
468
+ static findNamedImport(opts) {
469
+ const { typescript, sourceFile, modules } = opts;
470
+ for (const statement of sourceFile.statements) {
471
+ const declaration = NamespaceFunctions.asValueImport({ typescript, statement, modules });
472
+ const named = declaration?.importClause?.namedBindings;
473
+ if (declaration && named && typescript.isNamedImports(named)) {
474
+ return declaration;
475
+ }
476
+ }
477
+ return undefined;
478
+ }
479
+ /** `statement` as an import that is not `import type`, from one of `modules`. */
480
+ static asValueImport(opts) {
481
+ const { typescript, statement, modules } = opts;
482
+ if (typescript.isImportDeclaration(statement) &&
483
+ typescript.isStringLiteral(statement.moduleSpecifier) &&
484
+ modules.includes(statement.moduleSpecifier.text) &&
485
+ statement.importClause &&
486
+ !statement.importClause.isTypeOnly) {
487
+ return statement;
488
+ }
489
+ return undefined;
490
+ }
491
+ static moduleOf(opts) {
492
+ const specifier = opts.declaration.moduleSpecifier;
493
+ return 'text' in specifier && typeof specifier.text === 'string' ? specifier.text : '';
494
+ }
495
+ /**
496
+ * The edit of one import's braces: the removed old names go, the added classes take the place of
497
+ * the first removed one. Braces that hold a comment are not rewritten: the classes are appended
498
+ * and the old names stay, reported. An import left with nothing is removed.
499
+ */
500
+ static planImport(opts) {
501
+ const { typescript, sourceFile, declaration, removals, additions, report } = opts;
502
+ const clause = declaration.importClause;
503
+ const named = clause?.namedBindings;
504
+ if (!clause || !named || !typescript.isNamedImports(named)) {
505
+ return [];
506
+ }
507
+ const source = sourceFile.text;
508
+ const elements = [...named.elements];
509
+ const braces = source.slice(named.getStart(sourceFile), named.end);
510
+ if (/\/\*|\/\//.test(braces)) {
511
+ for (const element of elements.filter((candidate) => removals.has(candidate))) {
512
+ report({
513
+ node: element,
514
+ reason: `the braces of this import hold a comment, so \`${element.name.text}\` stays imported; remove it by hand`,
515
+ });
516
+ }
517
+ const last = elements[elements.length - 1];
518
+ if (!last || additions.length === 0) {
519
+ return [];
520
+ }
521
+ return [{ start: last.end, end: last.end, text: `, ${additions.join(', ')}` }];
522
+ }
523
+ const items = [];
524
+ let isPlaced = false;
525
+ for (const element of elements) {
526
+ if (!removals.has(element)) {
527
+ items.push(element.getText(sourceFile));
528
+ continue;
529
+ }
530
+ if (!isPlaced) {
531
+ items.push(...additions);
532
+ isPlaced = true;
533
+ }
534
+ }
535
+ if (!isPlaced) {
536
+ items.push(...additions);
537
+ }
538
+ if (items.length > 0) {
539
+ const start = named.getStart(sourceFile);
540
+ const lineStart = source.lastIndexOf('\n', declaration.getStart(sourceFile)) + 1;
541
+ const indent = /^[ \t]*/.exec(source.slice(lineStart))?.[0] ?? '';
542
+ const text = braces.includes('\n')
543
+ ? `{\n${indent} ${items.join(`,\n${indent} `)},\n${indent}}`
544
+ : `{ ${items.join(', ')} }`;
545
+ return [{ start, end: named.end, text }];
546
+ }
547
+ if (clause.name) {
548
+ return [{ start: clause.name.end, end: named.end, text: '' }];
549
+ }
550
+ const start = declaration.getStart(sourceFile);
551
+ const newline = /^\r?\n/.exec(source.slice(declaration.end))?.[0] ?? '';
552
+ return [{ start, end: declaration.end + newline.length, text: '' }];
553
+ }
554
+ /** The call the old one becomes, for a report: `ParseUtility.toFloat({ input, digit })`. */
555
+ static describeTarget(opts) {
556
+ const { className, method, params, restKey } = opts.mapping;
557
+ const keys = [...params.map((parameter) => parameter.key), ...(restKey ? [restKey] : [])];
558
+ return keys.length === 0
559
+ ? `${className}.${method}()`
560
+ : `${className}.${method}({ ${keys.join(', ')} })`;
561
+ }
562
+ }
563
+ exports.NamespaceFunctions = NamespaceFunctions;
564
+ //# sourceMappingURL=rewriter.js.map