@openrewrite/rewrite 8.91.1 → 8.91.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/execution.d.ts +8 -0
- package/dist/execution.d.ts.map +1 -1
- package/dist/execution.js +31 -0
- package/dist/execution.js.map +1 -1
- package/dist/javascript/add-import.d.ts +127 -38
- package/dist/javascript/add-import.d.ts.map +1 -1
- package/dist/javascript/add-import.js +684 -195
- package/dist/javascript/add-import.js.map +1 -1
- package/dist/javascript/amd.d.ts +148 -0
- package/dist/javascript/amd.d.ts.map +1 -0
- package/dist/javascript/amd.js +802 -0
- package/dist/javascript/amd.js.map +1 -0
- package/dist/javascript/binding.d.ts +102 -0
- package/dist/javascript/binding.d.ts.map +1 -0
- package/dist/javascript/binding.js +308 -0
- package/dist/javascript/binding.js.map +1 -0
- package/dist/javascript/comparator.d.ts +2 -0
- package/dist/javascript/comparator.d.ts.map +1 -1
- package/dist/javascript/comparator.js +5 -1
- package/dist/javascript/comparator.js.map +1 -1
- package/dist/javascript/format/format.d.ts +5 -2
- package/dist/javascript/format/format.d.ts.map +1 -1
- package/dist/javascript/format/format.js +51 -11
- package/dist/javascript/format/format.js.map +1 -1
- package/dist/javascript/format/minimum-viable-spacing-visitor.d.ts +19 -0
- package/dist/javascript/format/minimum-viable-spacing-visitor.d.ts.map +1 -1
- package/dist/javascript/format/minimum-viable-spacing-visitor.js +180 -7
- package/dist/javascript/format/minimum-viable-spacing-visitor.js.map +1 -1
- package/dist/javascript/format/prettier-format.d.ts +2 -1
- package/dist/javascript/format/prettier-format.d.ts.map +1 -1
- package/dist/javascript/format/prettier-format.js +33 -23
- package/dist/javascript/format/prettier-format.js.map +1 -1
- package/dist/javascript/index.d.ts +8 -1
- package/dist/javascript/index.d.ts.map +1 -1
- package/dist/javascript/index.js +46 -1
- package/dist/javascript/index.js.map +1 -1
- package/dist/javascript/parser-utils.d.ts.map +1 -1
- package/dist/javascript/parser-utils.js +7 -9
- package/dist/javascript/parser-utils.js.map +1 -1
- package/dist/javascript/parser.d.ts +7 -1
- package/dist/javascript/parser.d.ts.map +1 -1
- package/dist/javascript/parser.js +55 -4
- package/dist/javascript/parser.js.map +1 -1
- package/dist/javascript/print.d.ts +1 -0
- package/dist/javascript/print.d.ts.map +1 -1
- package/dist/javascript/print.js +9 -0
- package/dist/javascript/print.js.map +1 -1
- package/dist/javascript/recipes/change-import.d.ts +4 -3
- package/dist/javascript/recipes/change-import.d.ts.map +1 -1
- package/dist/javascript/recipes/change-import.js +12 -504
- package/dist/javascript/recipes/change-import.js.map +1 -1
- package/dist/javascript/remove-import.d.ts +2 -28
- package/dist/javascript/remove-import.d.ts.map +1 -1
- package/dist/javascript/remove-import.js +19 -57
- package/dist/javascript/remove-import.js.map +1 -1
- package/dist/javascript/rpc.js +2 -0
- package/dist/javascript/rpc.js.map +1 -1
- package/dist/javascript/scope.d.ts +82 -0
- package/dist/javascript/scope.d.ts.map +1 -0
- package/dist/javascript/scope.js +476 -0
- package/dist/javascript/scope.js.map +1 -0
- package/dist/javascript/templating/bindings.d.ts +0 -11
- package/dist/javascript/templating/bindings.d.ts.map +1 -1
- package/dist/javascript/templating/bindings.js +2 -49
- package/dist/javascript/templating/bindings.js.map +1 -1
- package/dist/javascript/templating/comparator.d.ts +12 -0
- package/dist/javascript/templating/comparator.d.ts.map +1 -1
- package/dist/javascript/templating/comparator.js +68 -14
- package/dist/javascript/templating/comparator.js.map +1 -1
- package/dist/javascript/templating/engine.d.ts +22 -4
- package/dist/javascript/templating/engine.d.ts.map +1 -1
- package/dist/javascript/templating/engine.js +68 -24
- package/dist/javascript/templating/engine.js.map +1 -1
- package/dist/javascript/templating/index.d.ts +1 -1
- package/dist/javascript/templating/index.d.ts.map +1 -1
- package/dist/javascript/templating/index.js.map +1 -1
- package/dist/javascript/templating/pattern.d.ts.map +1 -1
- package/dist/javascript/templating/pattern.js +2 -2
- package/dist/javascript/templating/pattern.js.map +1 -1
- package/dist/javascript/templating/placeholder-replacement.d.ts +2 -0
- package/dist/javascript/templating/placeholder-replacement.d.ts.map +1 -1
- package/dist/javascript/templating/placeholder-replacement.js +10 -5
- package/dist/javascript/templating/placeholder-replacement.js.map +1 -1
- package/dist/javascript/templating/precedence.d.ts +12 -4
- package/dist/javascript/templating/precedence.d.ts.map +1 -1
- package/dist/javascript/templating/precedence.js +18 -11
- package/dist/javascript/templating/precedence.js.map +1 -1
- package/dist/javascript/templating/rewrite.d.ts.map +1 -1
- package/dist/javascript/templating/rewrite.js +7 -1
- package/dist/javascript/templating/rewrite.js.map +1 -1
- package/dist/javascript/templating/template.d.ts +7 -1
- package/dist/javascript/templating/template.d.ts.map +1 -1
- package/dist/javascript/templating/template.js +54 -28
- package/dist/javascript/templating/template.js.map +1 -1
- package/dist/javascript/templating/types.d.ts +15 -18
- package/dist/javascript/templating/types.d.ts.map +1 -1
- package/dist/javascript/templating/utils.d.ts +1 -1
- package/dist/javascript/templating/utils.d.ts.map +1 -1
- package/dist/javascript/templating/utils.js +3 -2
- package/dist/javascript/templating/utils.js.map +1 -1
- package/dist/javascript/tree.d.ts +1 -0
- package/dist/javascript/tree.d.ts.map +1 -1
- package/dist/javascript/tree.js.map +1 -1
- package/dist/javascript/type-mapping.d.ts.map +1 -1
- package/dist/javascript/type-mapping.js +14 -0
- package/dist/javascript/type-mapping.js.map +1 -1
- package/dist/javascript/visitor.d.ts.map +1 -1
- package/dist/javascript/visitor.js +1 -0
- package/dist/javascript/visitor.js.map +1 -1
- package/dist/parser.d.ts +6 -0
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +23 -1
- package/dist/parser.js.map +1 -1
- package/dist/print.d.ts.map +1 -1
- package/dist/print.js +5 -2
- package/dist/print.js.map +1 -1
- package/dist/rewrite-javascript-version.txt +1 -1
- package/dist/rpc/request/parse-project.d.ts +11 -1
- package/dist/rpc/request/parse-project.d.ts.map +1 -1
- package/dist/rpc/request/parse-project.js +7 -2
- package/dist/rpc/request/parse-project.js.map +1 -1
- package/dist/rpc/request/parse.d.ts +13 -1
- package/dist/rpc/request/parse.d.ts.map +1 -1
- package/dist/rpc/request/parse.js +8 -2
- package/dist/rpc/request/parse.js.map +1 -1
- package/package.json +2 -2
- package/src/execution.ts +23 -0
- package/src/javascript/add-import.ts +753 -238
- package/src/javascript/amd.ts +954 -0
- package/src/javascript/binding.ts +435 -0
- package/src/javascript/comparator.ts +6 -1
- package/src/javascript/format/format.ts +56 -12
- package/src/javascript/format/minimum-viable-spacing-visitor.ts +196 -7
- package/src/javascript/format/prettier-format.ts +35 -25
- package/src/javascript/index.ts +19 -1
- package/src/javascript/parser-utils.ts +7 -11
- package/src/javascript/parser.ts +78 -6
- package/src/javascript/print.ts +10 -0
- package/src/javascript/recipes/change-import.ts +13 -593
- package/src/javascript/remove-import.ts +20 -56
- package/src/javascript/rpc.ts +2 -0
- package/src/javascript/scope.ts +517 -0
- package/src/javascript/templating/bindings.ts +2 -55
- package/src/javascript/templating/comparator.ts +81 -16
- package/src/javascript/templating/engine.ts +107 -38
- package/src/javascript/templating/index.ts +0 -1
- package/src/javascript/templating/pattern.ts +4 -2
- package/src/javascript/templating/placeholder-replacement.ts +16 -6
- package/src/javascript/templating/precedence.ts +21 -13
- package/src/javascript/templating/rewrite.ts +9 -1
- package/src/javascript/templating/template.ts +68 -29
- package/src/javascript/templating/types.ts +17 -18
- package/src/javascript/templating/utils.ts +4 -2
- package/src/javascript/tree.ts +1 -0
- package/src/javascript/type-mapping.ts +15 -0
- package/src/javascript/visitor.ts +1 -0
- package/src/parser.ts +24 -1
- package/src/print.ts +5 -2
- package/src/rpc/request/parse-project.ts +6 -2
- package/src/rpc/request/parse.ts +7 -2
|
@@ -86,9 +86,10 @@ export class MinimumViableSpacingVisitor<P> extends JavaScriptVisitor<P> {
|
|
|
86
86
|
// e.g., "class DataTable<Row>" not "class DataTable <Row>"
|
|
87
87
|
// Note: body.prefix spacing (space before '{') is handled by SpacesVisitor, not here.
|
|
88
88
|
|
|
89
|
-
if (c.extends
|
|
89
|
+
if (c.extends) {
|
|
90
90
|
c = produce(c, draft => {
|
|
91
91
|
this.ensureSpace(draft.extends!.before);
|
|
92
|
+
this.ensureSpace(draft.extends!.element.prefix);
|
|
92
93
|
});
|
|
93
94
|
}
|
|
94
95
|
|
|
@@ -156,10 +157,9 @@ export class MinimumViableSpacingVisitor<P> extends JavaScriptVisitor<P> {
|
|
|
156
157
|
protected async visitNewClass(newClass: J.NewClass, p: P): Promise<J | undefined> {
|
|
157
158
|
const ret = await super.visitNewClass(newClass, p) as J.NewClass;
|
|
158
159
|
return produce(ret, draft => {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
160
|
+
// a parenthesized class expression separates itself from `new`
|
|
161
|
+
if (draft.class && draft.class.kind !== J.Kind.Parentheses) {
|
|
162
|
+
this.ensureSpace((draft.class as Draft<J>).prefix);
|
|
163
163
|
}
|
|
164
164
|
});
|
|
165
165
|
}
|
|
@@ -232,12 +232,54 @@ export class MinimumViableSpacingVisitor<P> extends JavaScriptVisitor<P> {
|
|
|
232
232
|
return ret;
|
|
233
233
|
}
|
|
234
234
|
|
|
235
|
+
protected async visitAlias(alias: JS.Alias, p: P): Promise<J | undefined> {
|
|
236
|
+
const ret = await super.visitAlias(alias, p) as JS.Alias;
|
|
237
|
+
return produce(ret, draft => {
|
|
238
|
+
this.ensureSpace(draft.propertyName.after);
|
|
239
|
+
this.ensureSpace(draft.alias.prefix);
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
protected async visitAs(as_: JS.As, p: P): Promise<J | undefined> {
|
|
244
|
+
const ret = await super.visitAs(as_, p) as JS.As;
|
|
245
|
+
return produce(ret, draft => {
|
|
246
|
+
this.ensureSpace(draft.left.after);
|
|
247
|
+
this.ensureSpace(draft.right.prefix);
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
protected async visitBinaryExtensions(jsBinary: JS.Binary, p: P): Promise<J | undefined> {
|
|
252
|
+
const ret = await super.visitBinaryExtensions(jsBinary, p) as JS.Binary;
|
|
253
|
+
// `in` is the only word operator here; the rest are punctuators that need no separation
|
|
254
|
+
if (ret.operator.element !== JS.Binary.Type.In) {
|
|
255
|
+
return ret;
|
|
256
|
+
}
|
|
257
|
+
return produce(ret, draft => {
|
|
258
|
+
this.ensureSpace(draft.operator.before);
|
|
259
|
+
this.ensureSpace(draft.right.prefix);
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
protected async visitBreak(breakNode: J.Break, p: P): Promise<J | undefined> {
|
|
264
|
+
const ret = await super.visitBreak(breakNode, p) as J.Break;
|
|
265
|
+
return ret.label ? produce(ret, draft => {
|
|
266
|
+
this.ensureSpace(draft.label!.prefix);
|
|
267
|
+
}) : ret;
|
|
268
|
+
}
|
|
235
269
|
|
|
236
270
|
protected async visitCase(caseNode: J.Case, p: P): Promise<J | undefined> {
|
|
237
|
-
|
|
271
|
+
let c = await super.visitCase(caseNode, p) as J.Case;
|
|
272
|
+
|
|
273
|
+
// `default` prints without the `case` keyword, so its label needs no separator
|
|
274
|
+
const first = c.caseLabels.elements[0]?.element;
|
|
275
|
+
if (first && (first.kind !== J.Kind.Identifier || (first as J.Identifier).simpleName !== "default")) {
|
|
276
|
+
c = produce(c, draft => {
|
|
277
|
+
this.ensureSpace(draft.caseLabels.before);
|
|
278
|
+
});
|
|
279
|
+
}
|
|
238
280
|
|
|
239
281
|
if (c.guard && c.caseLabels.elements.length > 0 && c.caseLabels.elements[c.caseLabels.elements.length - 1].after.whitespace === "") {
|
|
240
|
-
|
|
282
|
+
c = produce(c, draft => {
|
|
241
283
|
const last = draft.caseLabels.elements.length - 1;
|
|
242
284
|
draft.caseLabels.elements[last].after.whitespace = " ";
|
|
243
285
|
});
|
|
@@ -246,6 +288,153 @@ export class MinimumViableSpacingVisitor<P> extends JavaScriptVisitor<P> {
|
|
|
246
288
|
return c;
|
|
247
289
|
}
|
|
248
290
|
|
|
291
|
+
protected async visitContinue(continueNode: J.Continue, p: P): Promise<J | undefined> {
|
|
292
|
+
const ret = await super.visitContinue(continueNode, p) as J.Continue;
|
|
293
|
+
return ret.label ? produce(ret, draft => {
|
|
294
|
+
this.ensureSpace(draft.label!.prefix);
|
|
295
|
+
}) : ret;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
protected async visitDelete(delete_: JS.Delete, p: P): Promise<J | undefined> {
|
|
299
|
+
const ret = await super.visitDelete(delete_, p) as JS.Delete;
|
|
300
|
+
return produce(ret, draft => {
|
|
301
|
+
this.ensureSpace(draft.expression.prefix);
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
protected async visitExportAssignment(exportAssignment: JS.ExportAssignment, p: P): Promise<J | undefined> {
|
|
306
|
+
const ret = await super.visitExportAssignment(exportAssignment, p) as JS.ExportAssignment;
|
|
307
|
+
if (ret.exportEquals) {
|
|
308
|
+
return ret;
|
|
309
|
+
}
|
|
310
|
+
return produce(ret, draft => {
|
|
311
|
+
this.ensureSpace(draft.expression.before);
|
|
312
|
+
this.ensureSpace(draft.expression.element.prefix);
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
protected async visitExportDeclaration(exportDeclaration: JS.ExportDeclaration, p: P): Promise<J | undefined> {
|
|
317
|
+
const ret = await super.visitExportDeclaration(exportDeclaration, p) as JS.ExportDeclaration;
|
|
318
|
+
return produce(ret, draft => {
|
|
319
|
+
if (draft.typeOnly.element) {
|
|
320
|
+
this.ensureSpace(draft.typeOnly.before);
|
|
321
|
+
}
|
|
322
|
+
// a namespace re-export ends its clause with the alias, unlike `}` or a bare `*`
|
|
323
|
+
if (draft.moduleSpecifier && draft.exportClause?.kind === JS.Kind.Alias) {
|
|
324
|
+
this.ensureSpace(draft.moduleSpecifier.before);
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
protected async visitForInLoop(forInLoop: JS.ForInLoop, p: P): Promise<J | undefined> {
|
|
330
|
+
const ret = await super.visitForInLoop(forInLoop, p) as JS.ForInLoop;
|
|
331
|
+
return produce(ret, draft => {
|
|
332
|
+
this.ensureSpace(draft.control.variable.after);
|
|
333
|
+
this.ensureSpace(draft.control.iterable.element.prefix);
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
protected async visitForOfLoop(forOfLoop: JS.ForOfLoop, p: P): Promise<J | undefined> {
|
|
338
|
+
const ret = await super.visitForOfLoop(forOfLoop, p) as JS.ForOfLoop;
|
|
339
|
+
return produce(ret, draft => {
|
|
340
|
+
this.ensureSpace(draft.loop.control.variable.after);
|
|
341
|
+
this.ensureSpace(draft.loop.control.iterable.element.prefix);
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
protected async visitImportClause(importClause: JS.ImportClause, p: P): Promise<J | undefined> {
|
|
346
|
+
const ret = await super.visitImportClause(importClause, p) as JS.ImportClause;
|
|
347
|
+
return produce(ret, draft => {
|
|
348
|
+
// named bindings open with a punctuator, which separates itself from `import` and `type`
|
|
349
|
+
if (draft.typeOnly || draft.name) {
|
|
350
|
+
this.ensureSpace(draft.prefix);
|
|
351
|
+
}
|
|
352
|
+
if (draft.typeOnly && draft.name) {
|
|
353
|
+
this.ensureSpace(draft.name.element.prefix);
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
protected async visitImportDeclaration(jsImport: JS.Import, p: P): Promise<J | undefined> {
|
|
359
|
+
const ret = await super.visitImportDeclaration(jsImport, p) as JS.Import;
|
|
360
|
+
// `from` prints only with a clause, and not at all in the `= require(...)` form; `}` separates
|
|
361
|
+
// named imports from it, and the specifier after it is always a string literal
|
|
362
|
+
const bindings = ret.importClause?.namedBindings;
|
|
363
|
+
if (!ret.importClause || !ret.moduleSpecifier || bindings?.kind === JS.Kind.NamedImports) {
|
|
364
|
+
return ret;
|
|
365
|
+
}
|
|
366
|
+
return produce(ret, draft => {
|
|
367
|
+
this.ensureSpace(draft.moduleSpecifier!.before);
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
protected async visitInstanceOf(instanceOf: J.InstanceOf, p: P): Promise<J | undefined> {
|
|
372
|
+
const ret = await super.visitInstanceOf(instanceOf, p) as J.InstanceOf;
|
|
373
|
+
return produce(ret, draft => {
|
|
374
|
+
this.ensureSpace(draft.expression.after);
|
|
375
|
+
this.ensureSpace(draft.class.prefix);
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
protected async visitSatisfiesExpression(satisfies: JS.SatisfiesExpression, p: P): Promise<J | undefined> {
|
|
380
|
+
const ret = await super.visitSatisfiesExpression(satisfies, p) as JS.SatisfiesExpression;
|
|
381
|
+
return produce(ret, draft => {
|
|
382
|
+
this.ensureSpace(draft.satisfiesType.before);
|
|
383
|
+
this.ensureSpace(draft.satisfiesType.element.prefix);
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
protected async visitScopedVariableDeclarations(scoped: JS.ScopedVariableDeclarations, p: P): Promise<J | undefined> {
|
|
388
|
+
const ret = await super.visitScopedVariableDeclarations(scoped, p) as JS.ScopedVariableDeclarations;
|
|
389
|
+
if (ret.modifiers.length === 0 || ret.variables.length === 0) {
|
|
390
|
+
return ret;
|
|
391
|
+
}
|
|
392
|
+
return produce(ret, draft => {
|
|
393
|
+
for (let i = 1; i < draft.modifiers.length; i++) {
|
|
394
|
+
this.ensureSpace(draft.modifiers[i].prefix);
|
|
395
|
+
}
|
|
396
|
+
this.ensureSpace(draft.variables[0].element.prefix);
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
protected async visitTypeOperator(typeOperator: JS.TypeOperator, p: P): Promise<J | undefined> {
|
|
401
|
+
const ret = await super.visitTypeOperator(typeOperator, p) as JS.TypeOperator;
|
|
402
|
+
return produce(ret, draft => {
|
|
403
|
+
this.ensureSpace(draft.expression.before);
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
protected async visitTypePredicate(typePredicate: JS.TypePredicate, p: P): Promise<J | undefined> {
|
|
408
|
+
const ret = await super.visitTypePredicate(typePredicate, p) as JS.TypePredicate;
|
|
409
|
+
return produce(ret, draft => {
|
|
410
|
+
if (draft.asserts.element) {
|
|
411
|
+
this.ensureSpace(draft.parameterName.prefix);
|
|
412
|
+
}
|
|
413
|
+
if (draft.expression) {
|
|
414
|
+
this.ensureSpace(draft.expression.before);
|
|
415
|
+
this.ensureSpace(draft.expression.element.prefix);
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
protected async visitVoid(void_: JS.Void, p: P): Promise<J | undefined> {
|
|
421
|
+
const ret = await super.visitVoid(void_, p) as JS.Void;
|
|
422
|
+
return produce(ret, draft => {
|
|
423
|
+
this.ensureSpace(draft.expression.prefix);
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
protected async visitYield(aYield: J.Yield, p: P): Promise<J | undefined> {
|
|
428
|
+
const ret = await super.visitYield(aYield, p) as J.Yield;
|
|
429
|
+
// `yield*` separates itself from the value
|
|
430
|
+
if (!ret.value || findMarker(ret, JS.Markers.DelegatedYield)) {
|
|
431
|
+
return ret;
|
|
432
|
+
}
|
|
433
|
+
return produce(ret, draft => {
|
|
434
|
+
this.ensureSpace(draft.value!.prefix);
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
|
|
249
438
|
private ensureSpace(spaceDraft: Draft<J.Space>) {
|
|
250
439
|
if (spaceDraft.whitespace.length === 0 && spaceDraft.comments.length === 0) {
|
|
251
440
|
spaceDraft.whitespace = " ";
|
|
@@ -357,6 +357,15 @@ function pruneNode(node: any, path: PathSegment[], pathIndex: number, target: an
|
|
|
357
357
|
return node;
|
|
358
358
|
}
|
|
359
359
|
|
|
360
|
+
// A compilation unit's statements are laid out at column 0, so nothing beside the target bears
|
|
361
|
+
// on how Prettier lays it out and the printed program can be the target alone.
|
|
362
|
+
if (node.kind === JS.Kind.CompilationUnit && segment.property === 'statements' && segment.index !== undefined) {
|
|
363
|
+
const statements = value as J.RightPadded<Statement>[];
|
|
364
|
+
return updateIfChanged(node, {
|
|
365
|
+
statements: [pruneNode(statements[segment.index], path, pathIndex + 1, target)]
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
|
|
360
369
|
// Handle J.Block#statements specially - prune siblings
|
|
361
370
|
if (node.kind === J.Kind.Block && segment.property === 'statements' && segment.index !== undefined) {
|
|
362
371
|
const statements = value as J.RightPadded<Statement>[];
|
|
@@ -430,10 +439,10 @@ function findByPath(tree: any, path: PathSegment[]): any {
|
|
|
430
439
|
if (value == null) return undefined;
|
|
431
440
|
|
|
432
441
|
if (Array.isArray(value) && segment.index !== undefined) {
|
|
433
|
-
//
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
const index =
|
|
442
|
+
// In pruned statement lists the target is last, following siblings having been omitted
|
|
443
|
+
const isPrunedStatements = segment.property === 'statements' &&
|
|
444
|
+
(current.kind === J.Kind.Block || current.kind === JS.Kind.CompilationUnit);
|
|
445
|
+
const index = isPrunedStatements ? value.length - 1 : segment.index;
|
|
437
446
|
const item = value[index];
|
|
438
447
|
if (item == null) return undefined;
|
|
439
448
|
current = item;
|
|
@@ -474,6 +483,12 @@ export async function prettierFormatSubtree<T extends J>(
|
|
|
474
483
|
return undefined;
|
|
475
484
|
}
|
|
476
485
|
|
|
486
|
+
// Whatever stands between a statement and the top of its file is the file's business, so a whole
|
|
487
|
+
// statement keeps the prefix it came with. Prettier sees it, for the directives — a leading
|
|
488
|
+
// `prettier-ignore` — that a statement's own layout answers to.
|
|
489
|
+
const wholeStatement = path.length === 2 && path[0].property === 'statements' &&
|
|
490
|
+
path[0].index !== undefined && path[1].property === 'element';
|
|
491
|
+
|
|
477
492
|
// Prune the tree for efficient formatting and substitute the (potentially modified) target.
|
|
478
493
|
// This ensures that if the visitor modified the target before calling autoFormat,
|
|
479
494
|
// we format the modified content, not the original from the cursor.
|
|
@@ -492,7 +507,12 @@ export async function prettierFormatSubtree<T extends J>(
|
|
|
492
507
|
const reconciler = new WhitespaceReconciler();
|
|
493
508
|
const reconciled = reconciler.reconcile(target as J, formattedTarget as J, undefined, stopAfter);
|
|
494
509
|
|
|
495
|
-
|
|
510
|
+
// The walk that carries whitespace back pairs the two trees node for node, which a change to
|
|
511
|
+
// the code itself — Prettier dropping redundant parentheses, say — makes impossible
|
|
512
|
+
if (!reconciler.isCompatible()) {
|
|
513
|
+
return undefined;
|
|
514
|
+
}
|
|
515
|
+
return (wholeStatement ? {...reconciled as T, prefix: target.prefix} : reconciled as T);
|
|
496
516
|
}
|
|
497
517
|
|
|
498
518
|
/**
|
|
@@ -554,7 +574,8 @@ export function getPrettierStyle(
|
|
|
554
574
|
* @param p The visitor parameter
|
|
555
575
|
* @param cursor Optional cursor for subtree formatting
|
|
556
576
|
* @param stopAfter Optional tree to stop after
|
|
557
|
-
* @returns The formatted tree
|
|
577
|
+
* @returns The formatted tree, or `undefined` where Prettier's result cannot be carried back,
|
|
578
|
+
* leaving the caller to lay the tree out itself
|
|
558
579
|
*/
|
|
559
580
|
export async function applyPrettierFormatting<R extends J, P>(
|
|
560
581
|
tree: R,
|
|
@@ -589,31 +610,20 @@ export async function applyPrettierFormatting<R extends J, P>(
|
|
|
589
610
|
prettierVersion: prettierStyle.prettierVersion,
|
|
590
611
|
};
|
|
591
612
|
|
|
613
|
+
const wholeFile = t.kind === JS.Kind.CompilationUnit;
|
|
592
614
|
try {
|
|
593
|
-
if (
|
|
615
|
+
if (wholeFile) {
|
|
594
616
|
// Format and reconcile the entire compilation unit
|
|
595
617
|
const formatted = await prettierFormat(t as unknown as JS.CompilationUnit, prettierOpts, stopAfter as J | undefined);
|
|
596
618
|
return formatted as unknown as R;
|
|
597
619
|
}
|
|
598
620
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
console.warn('Prettier formatting: No cursor provided for subtree, returning with essential formatting only');
|
|
602
|
-
return t;
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
// Use prettierFormatSubtree for subtree formatting
|
|
606
|
-
const formatted = await prettierFormatSubtree(t, cursor, prettierOpts, stopAfter as J | undefined);
|
|
607
|
-
if (formatted) {
|
|
608
|
-
return formatted as R;
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
// Subtree formatting failed, return with essential formatting applied
|
|
612
|
-
console.warn('Prettier formatting: Subtree formatting failed, returning with essential formatting only');
|
|
613
|
-
return t;
|
|
621
|
+
// Pruning and reconciling a subtree both go by where it sits in its file
|
|
622
|
+
return cursor && await prettierFormatSubtree(t, cursor, prettierOpts, stopAfter as J | undefined) as R | undefined;
|
|
614
623
|
} catch (e) {
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
624
|
+
console.warn('Prettier formatting failed:', e);
|
|
625
|
+
// The built-in visitors lay out every line they are given, so a whole file — the author's
|
|
626
|
+
// layout rather than a recipe's — keeps the one it came with; a subtree is handed on.
|
|
627
|
+
return wholeFile ? t : undefined;
|
|
618
628
|
}
|
|
619
629
|
}
|
package/src/javascript/index.ts
CHANGED
|
@@ -31,7 +31,25 @@ export * from "./autodetect";
|
|
|
31
31
|
export * from "./tree-debug";
|
|
32
32
|
export * from "./project-parser";
|
|
33
33
|
|
|
34
|
-
export
|
|
34
|
+
export type {Scope} from "./scope";
|
|
35
|
+
// `cursorOf` is deliberately absent: a visitor of one's own reaches `this.cursor` directly, and
|
|
36
|
+
// the free functions that have no visitor to reach it through are already in this list.
|
|
37
|
+
export {
|
|
38
|
+
scopeOf, namesDeclaredIn, namesDeclaredWithin, namesUsedIn, bindingNames, deconflict,
|
|
39
|
+
isValueReference, declarationsOf, compilationUnitOf, walk
|
|
40
|
+
} from "./scope";
|
|
41
|
+
export type {QuoteChar, AddImportOptions} from "./add-import";
|
|
42
|
+
export {ImportStyle, moduleNameOf, AddImport} from "./add-import";
|
|
43
|
+
// AMD mechanics `recipes-ui5` builds on directly, beyond the `maybeBind` surface below.
|
|
44
|
+
export type {AmdBlock, AmdCalleeOptions} from "./amd";
|
|
45
|
+
export {
|
|
46
|
+
DEFAULT_AMD_CALLEES, amdBlockOf, enclosingAmdBlock, present, elementsOf, parametersOf, identifierOf,
|
|
47
|
+
dependencyNames, parameterNames, bodyOf, references, namesUsed, lastSegment, derivedBindingName,
|
|
48
|
+
withDependency, withUnboundDependency, withoutDependencyAt,
|
|
49
|
+
RemoveAmdDependency, removeNewlyUnusedAmdBindings
|
|
50
|
+
} from "./amd";
|
|
51
|
+
export type {MaybeBindOptions, MaybeUnbindOptions, MaybeRebindOptions, ModuleBindings} from "./binding";
|
|
52
|
+
export {maybeBind, maybeUnbind, maybeRebind, moduleBindings, isAmdBlock, maybeRemoveImport, maybeAddImport} from "./binding";
|
|
35
53
|
export * from "./remove-import";
|
|
36
54
|
export * from "./cleanup/index";
|
|
37
55
|
export * from "./recipes/index";
|
|
@@ -351,8 +351,9 @@ export function hasFlowAnnotation(sourceFile: ts.SourceFile) {
|
|
|
351
351
|
}
|
|
352
352
|
|
|
353
353
|
export function checkSyntaxErrors(program: ts.Program, sourceFile: ts.SourceFile) {
|
|
354
|
-
|
|
355
|
-
//
|
|
354
|
+
// Only parse diagnostics decide whether a file gets an LST, so the visitor has to map every slot the
|
|
355
|
+
// parser fills — including ones the checker would reject — or the file loses text on print.
|
|
356
|
+
const diagnostics = program.getSyntacticDiagnostics(sourceFile);
|
|
356
357
|
let syntaxErrors : [errorMsg: string, errorCode: number][] = [];
|
|
357
358
|
if (diagnostics.length > 0) {
|
|
358
359
|
const errors = diagnostics.filter(d => (d.category === ts.DiagnosticCategory.Error) && isCriticalDiagnostic(d.code, sourceFile));
|
|
@@ -373,18 +374,11 @@ export function checkSyntaxErrors(program: ts.Program, sourceFile: ts.SourceFile
|
|
|
373
374
|
return syntaxErrors;
|
|
374
375
|
}
|
|
375
376
|
|
|
376
|
-
const additionalCriticalCodes = new Set([
|
|
377
|
-
// Syntax errors
|
|
378
|
-
17019, // "'{0}' at the end of a type is not valid TypeScript syntax. Did you mean to write '{1}'?"
|
|
379
|
-
17020, // "'{0}' at the start of a type is not valid TypeScript syntax. Did you mean to write '{1}'?"
|
|
380
|
-
|
|
381
|
-
// Other critical errors
|
|
382
|
-
]);
|
|
383
|
-
|
|
384
377
|
// errors code description available at https://github.com/microsoft/TypeScript/blob/main/src/compiler/diagnosticMessages.json
|
|
385
378
|
const excludedCodes = new Set([
|
|
386
379
|
1039, // Initializers are not allowed in ambient contexts.
|
|
387
380
|
1064, // The return type of an async function or method must be the global Promise<T> type. Did you mean to write 'Promise<{0}>'?
|
|
381
|
+
1101, // 'with' statements are not allowed in strict mode.
|
|
388
382
|
1107, // Jump target cannot cross function boundary.
|
|
389
383
|
1111, // Private field '{0}' must be declared in an enclosing class.
|
|
390
384
|
1117, // An object literal cannot have multiple properties with the same name.
|
|
@@ -394,6 +388,7 @@ const excludedCodes = new Set([
|
|
|
394
388
|
1183, // An implementation cannot be declared in ambient contexts.
|
|
395
389
|
1203, // Export assignment cannot be used when targeting ECMAScript modules. Consider using 'export default' or another module format instead.
|
|
396
390
|
1207, // Decorators cannot be applied to multiple get/set accessors of the same name.
|
|
391
|
+
1212, // Identifier expected. '{0}' is a reserved word in strict mode. The node is still parsed as an identifier.
|
|
397
392
|
1215, // Invalid use of '{0}'. Modules are automatically in strict mode.
|
|
398
393
|
1238, // Unable to resolve signature of class decorator when called as an expression.
|
|
399
394
|
1239, // Unable to resolve signature of parameter decorator when called as an expression.
|
|
@@ -422,6 +417,7 @@ const excludedCodes = new Set([
|
|
|
422
417
|
1375, // 'await' expressions are only allowed at the top level of a file when that file is a module, but this file has no imports or exports. Consider adding an empty 'export {}' to make this file a module.
|
|
423
418
|
1378, // Top-level 'await' expressions are only allowed when the 'module' option is set to 'es2022', 'esnext', 'system', 'node16', 'node18', 'node20', 'nodenext', or 'preserve', and the 'target' option is set to 'es2017' or higher.
|
|
424
419
|
1432, // Top-level 'for await' loops are only allowed when the 'module' option is set to 'es2022', 'esnext', 'system', 'node16', 'node18', 'node20', 'nodenext', or 'preserve', and the 'target' option is set to 'es2017' or higher.
|
|
420
|
+
1540, // A 'namespace' declaration should not be declared using the 'module' keyword. The `module` spelling yields a ModuleDeclaration.
|
|
425
421
|
]);
|
|
426
422
|
|
|
427
423
|
// Errors to exclude only for JavaScript files (.js, .jsx, .mjs, .cjs)
|
|
@@ -444,7 +440,7 @@ function isCriticalDiagnostic(code: number, sourceFile: ts.SourceFile): boolean
|
|
|
444
440
|
}
|
|
445
441
|
}
|
|
446
442
|
|
|
447
|
-
return
|
|
443
|
+
return code > 1000 && code < 2000 && !excludedCodes.has(code);
|
|
448
444
|
}
|
|
449
445
|
|
|
450
446
|
export function isValidSurrogateRange(unicodeString: string): boolean {
|
package/src/javascript/parser.ts
CHANGED
|
@@ -54,6 +54,12 @@ import SpreadAttribute = JSX.SpreadAttribute;
|
|
|
54
54
|
export interface JavaScriptParserOptions extends ParserOptions {
|
|
55
55
|
styles?: NamedStyles[],
|
|
56
56
|
sourceFileCache?: Map<string, ts.SourceFile>,
|
|
57
|
+
/**
|
|
58
|
+
* Type packages to load whose declarations nothing imports. Unset leaves TypeScript's default,
|
|
59
|
+
* which reads `@types/*` and nothing else; a package declaring its modules ambiently needs
|
|
60
|
+
* naming here for those declarations to be in scope.
|
|
61
|
+
*/
|
|
62
|
+
types?: string[],
|
|
57
63
|
}
|
|
58
64
|
|
|
59
65
|
function getScriptKindFromFileName(fileName: string): ts.ScriptKind {
|
|
@@ -73,6 +79,15 @@ function getScriptKindFromFileName(fileName: string): ts.ScriptKind {
|
|
|
73
79
|
}
|
|
74
80
|
}
|
|
75
81
|
|
|
82
|
+
/**
|
|
83
|
+
* TypeScript's public typings model valid syntax only, so slots its parser still fills for invalid code —
|
|
84
|
+
* an initializer on a type member, a modifier on an object literal member — are missing from them.
|
|
85
|
+
*/
|
|
86
|
+
type WithInvalidSyntaxSlots<T> = T & {
|
|
87
|
+
initializer?: ts.Expression;
|
|
88
|
+
modifiers?: ts.NodeArray<ts.ModifierLike>;
|
|
89
|
+
};
|
|
90
|
+
|
|
76
91
|
export class JavaScriptParser extends Parser {
|
|
77
92
|
|
|
78
93
|
private readonly compilerOptions: ts.CompilerOptions;
|
|
@@ -86,6 +101,7 @@ export class JavaScriptParser extends Parser {
|
|
|
86
101
|
relativeTo,
|
|
87
102
|
styles,
|
|
88
103
|
sourceFileCache,
|
|
104
|
+
types,
|
|
89
105
|
}: JavaScriptParserOptions = {},
|
|
90
106
|
) {
|
|
91
107
|
super({ctx, relativeTo});
|
|
@@ -108,6 +124,12 @@ export class JavaScriptParser extends Parser {
|
|
|
108
124
|
emitDecoratorMetadata: true,
|
|
109
125
|
forceConsistentCasingInFileNames: false,
|
|
110
126
|
jsx: ts.JsxEmit.Preserve,
|
|
127
|
+
// Strictness is a property of the parsed project rather than of the compiler we pin: under
|
|
128
|
+
// `strictNullChecks` every nullable type carries an extra `null` union constituent.
|
|
129
|
+
strict: false,
|
|
130
|
+
// `types` defaults to `[]`, which attributes ambient `@types/*` packages only when named;
|
|
131
|
+
// `*` enumerates everything under `node_modules/@types`.
|
|
132
|
+
types: types ?? ["*"],
|
|
111
133
|
baseUrl: relativeTo || process.cwd()
|
|
112
134
|
};
|
|
113
135
|
this.styles = styles;
|
|
@@ -366,14 +388,14 @@ export class JavaScriptParser extends Parser {
|
|
|
366
388
|
}
|
|
367
389
|
|
|
368
390
|
try {
|
|
369
|
-
yield produce(
|
|
391
|
+
yield await this.requirePrintEqualsInput(produce(
|
|
370
392
|
new JavaScriptParserVisitor(sourceFile, this.relativePath(input), typeMapping)
|
|
371
393
|
.visit(sourceFile) as SourceFile,
|
|
372
394
|
draft => {
|
|
373
395
|
if (this.styles) {
|
|
374
396
|
draft.markers = this.styles.reduce((m, s) => replaceMarkerByKind(m, s), draft.markers);
|
|
375
397
|
}
|
|
376
|
-
});
|
|
398
|
+
}), input, escapeLoneSurrogates(sourceFile.getFullText()));
|
|
377
399
|
} catch (error) {
|
|
378
400
|
yield this.error(input, error instanceof Error ? error : new Error('Parser threw unknown error: ' + error));
|
|
379
401
|
}
|
|
@@ -560,7 +582,12 @@ export class JavaScriptParserVisitor {
|
|
|
560
582
|
| ts.FunctionDeclaration | ts.ParameterDeclaration | ts.MethodDeclaration | ts.EnumDeclaration | ts.InterfaceDeclaration
|
|
561
583
|
| ts.PropertySignature | ts.ConstructorDeclaration | ts.ModuleDeclaration | ts.GetAccessorDeclaration | ts.SetAccessorDeclaration
|
|
562
584
|
| ts.ArrowFunction | ts.IndexSignatureDeclaration | ts.TypeAliasDeclaration | ts.ExportDeclaration | ts.ExportAssignment | ts.FunctionExpression
|
|
563
|
-
| ts.ConstructorTypeNode | ts.TypeParameterDeclaration | ts.ImportDeclaration | ts.ImportEqualsDeclaration
|
|
585
|
+
| ts.ConstructorTypeNode | ts.TypeParameterDeclaration | ts.ImportDeclaration | ts.ImportEqualsDeclaration
|
|
586
|
+
| ts.PropertyAssignment | ts.ShorthandPropertyAssignment): J.Modifier[] {
|
|
587
|
+
if (ts.isPropertyAssignment(node) || ts.isShorthandPropertyAssignment(node)) {
|
|
588
|
+
const modifiers = (node as WithInvalidSyntaxSlots<typeof node>).modifiers;
|
|
589
|
+
return modifiers ? modifiers.filter(ts.isModifier).map(this.mapModifier) : [];
|
|
590
|
+
}
|
|
564
591
|
if (ts.isVariableStatement(node) || ts.isModuleDeclaration(node) || ts.isClassDeclaration(node) || ts.isEnumDeclaration(node)
|
|
565
592
|
|| ts.isInterfaceDeclaration(node) || ts.isPropertyDeclaration(node) || ts.isPropertySignature(node) || ts.isParameter(node)
|
|
566
593
|
|| ts.isMethodDeclaration(node) || ts.isConstructorDeclaration(node) || ts.isArrowFunction(node)
|
|
@@ -1162,6 +1189,8 @@ export class JavaScriptParserVisitor {
|
|
|
1162
1189
|
visitPropertySignature(node: ts.PropertySignature): J.VariableDeclarations {
|
|
1163
1190
|
// FIXME We are mapping the literals in things like type ascii = { " ": 32; "!": 33; } to
|
|
1164
1191
|
// named variables, which is not a good use of this construct.
|
|
1192
|
+
|
|
1193
|
+
const initializer = (node as WithInvalidSyntaxSlots<ts.PropertySignature>).initializer;
|
|
1165
1194
|
return {
|
|
1166
1195
|
kind: J.Kind.VariableDeclarations,
|
|
1167
1196
|
id: randomId(),
|
|
@@ -1180,6 +1209,7 @@ export class JavaScriptParserVisitor {
|
|
|
1180
1209
|
draft.markers = this.maybeAddOptionalMarker(draft, node);
|
|
1181
1210
|
}) as VariableDeclarator,
|
|
1182
1211
|
dimensionsAfterName: [],
|
|
1212
|
+
initializer: initializer && this.leftPadded(this.prefix(node.getChildAt(node.getChildren().indexOf(initializer) - 1)), this.visit(initializer)),
|
|
1183
1213
|
variableType: this.mapVariableType(node)
|
|
1184
1214
|
},
|
|
1185
1215
|
emptySpace
|
|
@@ -1342,7 +1372,8 @@ export class JavaScriptParserVisitor {
|
|
|
1342
1372
|
|
|
1343
1373
|
private mapTypeInfo(node: ts.MethodDeclaration | ts.PropertyDeclaration | ts.VariableDeclaration | ts.ParameterDeclaration
|
|
1344
1374
|
| ts.PropertySignature | ts.MethodSignature | ts.ArrowFunction | ts.CallSignatureDeclaration | ts.GetAccessorDeclaration
|
|
1345
|
-
| ts.FunctionDeclaration | ts.ConstructSignatureDeclaration | ts.FunctionExpression | ts.NamedTupleMember
|
|
1375
|
+
| ts.FunctionDeclaration | ts.ConstructSignatureDeclaration | ts.FunctionExpression | ts.NamedTupleMember
|
|
1376
|
+
| ts.ConstructorDeclaration | ts.SetAccessorDeclaration): JS.TypeInfo | undefined {
|
|
1346
1377
|
return node.type && {
|
|
1347
1378
|
kind: JS.Kind.TypeInfo,
|
|
1348
1379
|
id: randomId(),
|
|
@@ -1384,6 +1415,7 @@ export class JavaScriptParserVisitor {
|
|
|
1384
1415
|
leadingAnnotations: this.mapDecorators(node),
|
|
1385
1416
|
modifiers: this.mapModifiers(node),
|
|
1386
1417
|
nameAnnotations: [],
|
|
1418
|
+
returnTypeExpression: this.mapTypeInfo(node),
|
|
1387
1419
|
name: {...this.mapIdentifier(constructorKeyword, constructorKeyword.getText(), false), type: methodType},
|
|
1388
1420
|
parameters: this.mapCommaSeparatedList(this.getParameterListNodes(node)),
|
|
1389
1421
|
dimensionsAfterName: [],
|
|
@@ -1403,6 +1435,7 @@ export class JavaScriptParserVisitor {
|
|
|
1403
1435
|
markers: emptyMarkers,
|
|
1404
1436
|
leadingAnnotations: this.mapDecorators(node),
|
|
1405
1437
|
modifiers: this.mapModifiers(node),
|
|
1438
|
+
typeParameters: node.typeParameters && this.mapTypeParametersAsObject(node),
|
|
1406
1439
|
returnTypeExpression: this.mapTypeInfo(node),
|
|
1407
1440
|
name: name as ComputedPropertyName,
|
|
1408
1441
|
parameters: this.mapCommaSeparatedList(this.getParameterListNodes(node)),
|
|
@@ -1418,6 +1451,7 @@ export class JavaScriptParserVisitor {
|
|
|
1418
1451
|
markers: emptyMarkers,
|
|
1419
1452
|
leadingAnnotations: this.mapDecorators(node),
|
|
1420
1453
|
modifiers: this.mapModifiers(node),
|
|
1454
|
+
typeParameters: node.typeParameters && this.mapTypeParametersAsObject(node),
|
|
1421
1455
|
returnTypeExpression: this.mapTypeInfo(node),
|
|
1422
1456
|
nameAnnotations: [],
|
|
1423
1457
|
name: name as J.Identifier,
|
|
@@ -1439,6 +1473,8 @@ export class JavaScriptParserVisitor {
|
|
|
1439
1473
|
markers: emptyMarkers,
|
|
1440
1474
|
leadingAnnotations: this.mapDecorators(node),
|
|
1441
1475
|
modifiers: this.mapModifiers(node),
|
|
1476
|
+
typeParameters: node.typeParameters && this.mapTypeParametersAsObject(node),
|
|
1477
|
+
returnTypeExpression: this.mapTypeInfo(node),
|
|
1442
1478
|
name: name as ComputedPropertyName,
|
|
1443
1479
|
parameters: this.mapCommaSeparatedList(this.getParameterListNodes(node)),
|
|
1444
1480
|
body: node.body && this.convert<J.Block>(node.body),
|
|
@@ -1453,6 +1489,8 @@ export class JavaScriptParserVisitor {
|
|
|
1453
1489
|
markers: emptyMarkers,
|
|
1454
1490
|
leadingAnnotations: this.mapDecorators(node),
|
|
1455
1491
|
modifiers: this.mapModifiers(node),
|
|
1492
|
+
typeParameters: node.typeParameters && this.mapTypeParametersAsObject(node),
|
|
1493
|
+
returnTypeExpression: this.mapTypeInfo(node),
|
|
1456
1494
|
nameAnnotations: [],
|
|
1457
1495
|
name: name as J.Identifier,
|
|
1458
1496
|
parameters: this.mapCommaSeparatedList(this.getParameterListNodes(node)),
|
|
@@ -4206,6 +4244,7 @@ export class JavaScriptParserVisitor {
|
|
|
4206
4244
|
id: randomId(),
|
|
4207
4245
|
prefix: this.prefix(node),
|
|
4208
4246
|
markers: emptyMarkers,
|
|
4247
|
+
modifiers: this.mapModifiers(node),
|
|
4209
4248
|
name: this.rightPadded(this.visit(node.name), this.suffix(node.name)),
|
|
4210
4249
|
assigmentToken: JS.PropertyAssignment.Token.Colon,
|
|
4211
4250
|
initializer: this.visit(node.initializer)
|
|
@@ -4218,6 +4257,7 @@ export class JavaScriptParserVisitor {
|
|
|
4218
4257
|
id: randomId(),
|
|
4219
4258
|
prefix: this.prefix(node),
|
|
4220
4259
|
markers: emptyMarkers,
|
|
4260
|
+
modifiers: this.mapModifiers(node),
|
|
4221
4261
|
name: this.rightPadded(this.visit(node.name), this.suffix(node.name)),
|
|
4222
4262
|
assigmentToken: JS.PropertyAssignment.Token.Equals,
|
|
4223
4263
|
initializer: node.objectAssignmentInitializer && this.visit(node.objectAssignmentInitializer)
|
|
@@ -4641,7 +4681,8 @@ export class JavaScriptParserVisitor {
|
|
|
4641
4681
|
}
|
|
4642
4682
|
|
|
4643
4683
|
private mapTypeParametersAsObject(node: ts.MethodDeclaration | ts.MethodSignature | ts.FunctionDeclaration
|
|
4644
|
-
| ts.CallSignatureDeclaration | ts.ConstructSignatureDeclaration | ts.FunctionExpression | ts.ArrowFunction | ts.TypeAliasDeclaration | ts.FunctionTypeNode | ts.ConstructorTypeNode
|
|
4684
|
+
| ts.CallSignatureDeclaration | ts.ConstructSignatureDeclaration | ts.FunctionExpression | ts.ArrowFunction | ts.TypeAliasDeclaration | ts.FunctionTypeNode | ts.ConstructorTypeNode
|
|
4685
|
+
| ts.GetAccessorDeclaration | ts.SetAccessorDeclaration): J.TypeParameters | undefined {
|
|
4645
4686
|
const typeParameters = node.typeParameters;
|
|
4646
4687
|
if (!typeParameters) return undefined;
|
|
4647
4688
|
|
|
@@ -4793,6 +4834,8 @@ class FlowSyntaxNotSupportedError extends SyntaxError {
|
|
|
4793
4834
|
|
|
4794
4835
|
const SURR_FIRST = 0xD800;
|
|
4795
4836
|
const SURR_LAST = 0xDFFF;
|
|
4837
|
+
const HIGH_SURR_LAST = 0xDBFF;
|
|
4838
|
+
const LOW_SURR_FIRST = 0xDC00;
|
|
4796
4839
|
|
|
4797
4840
|
/**
|
|
4798
4841
|
* Extracts invalid UTF-16 surrogate pairs from a string literal's value source.
|
|
@@ -4806,6 +4849,26 @@ const SURR_LAST = 0xDFFF;
|
|
|
4806
4849
|
* 1. Unicode escape sequences (\uXXXX) where XXXX is in the surrogate range
|
|
4807
4850
|
* 2. Raw surrogate characters in the source (character codes 0xD800-0xDFFF)
|
|
4808
4851
|
*/
|
|
4852
|
+
/** The form {@link extractSurrogateEscapes} can hold, against which print idempotence is measured. */
|
|
4853
|
+
function escapeLoneSurrogates(source: string): string {
|
|
4854
|
+
let escaped = '';
|
|
4855
|
+
for (let j = 0; j < source.length; j++) {
|
|
4856
|
+
const charCode = source.charCodeAt(j);
|
|
4857
|
+
if (charCode >= SURR_FIRST && charCode <= SURR_LAST) {
|
|
4858
|
+
const next = source.charCodeAt(j + 1);
|
|
4859
|
+
if (charCode <= HIGH_SURR_LAST && next >= LOW_SURR_FIRST && next <= SURR_LAST) {
|
|
4860
|
+
escaped += source.charAt(j) + source.charAt(j + 1);
|
|
4861
|
+
j++;
|
|
4862
|
+
continue;
|
|
4863
|
+
}
|
|
4864
|
+
escaped += "\\u" + charCode.toString(16).toUpperCase().padStart(4, '0');
|
|
4865
|
+
continue;
|
|
4866
|
+
}
|
|
4867
|
+
escaped += source.charAt(j);
|
|
4868
|
+
}
|
|
4869
|
+
return escaped;
|
|
4870
|
+
}
|
|
4871
|
+
|
|
4809
4872
|
function extractSurrogateEscapes(valueSource: string): { cleanedSource: string, unicodeEscapes: J.LiteralUnicodeEscape[] } {
|
|
4810
4873
|
const unicodeEscapes: J.LiteralUnicodeEscape[] = [];
|
|
4811
4874
|
let cleanedSource = '';
|
|
@@ -4829,8 +4892,17 @@ function extractSurrogateEscapes(valueSource: string): { cleanedSource: string,
|
|
|
4829
4892
|
}
|
|
4830
4893
|
}
|
|
4831
4894
|
|
|
4832
|
-
//
|
|
4895
|
+
// A raw surrogate pair spells one code point — an emoji, say — and is carried as itself. A lone
|
|
4896
|
+
// surrogate is not text on its own and does not survive serialization (#6599), so it is held as a
|
|
4897
|
+
// `\uXXXX` escape and prints back as one.
|
|
4833
4898
|
if (charCode >= SURR_FIRST && charCode <= SURR_LAST) {
|
|
4899
|
+
const next = valueSource.charCodeAt(j + 1);
|
|
4900
|
+
if (charCode <= HIGH_SURR_LAST && next >= LOW_SURR_FIRST && next <= SURR_LAST) {
|
|
4901
|
+
cleanedSource += c + valueSource.charAt(j + 1);
|
|
4902
|
+
cleanedIndex += 2;
|
|
4903
|
+
j++;
|
|
4904
|
+
continue;
|
|
4905
|
+
}
|
|
4834
4906
|
const codePoint = charCode.toString(16).toUpperCase().padStart(4, '0');
|
|
4835
4907
|
unicodeEscapes.push({ valueSourceIndex: cleanedIndex, codePoint });
|
|
4836
4908
|
continue;
|