@openrewrite/rewrite 8.91.2 → 8.91.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/dist/execution.d.ts +8 -0
  2. package/dist/execution.d.ts.map +1 -1
  3. package/dist/execution.js +31 -0
  4. package/dist/execution.js.map +1 -1
  5. package/dist/javascript/add-import.d.ts +64 -9
  6. package/dist/javascript/add-import.d.ts.map +1 -1
  7. package/dist/javascript/add-import.js +398 -71
  8. package/dist/javascript/add-import.js.map +1 -1
  9. package/dist/javascript/amd.d.ts +11 -1
  10. package/dist/javascript/amd.d.ts.map +1 -1
  11. package/dist/javascript/amd.js +43 -9
  12. package/dist/javascript/amd.js.map +1 -1
  13. package/dist/javascript/binding.d.ts +10 -2
  14. package/dist/javascript/binding.d.ts.map +1 -1
  15. package/dist/javascript/binding.js +44 -71
  16. package/dist/javascript/binding.js.map +1 -1
  17. package/dist/javascript/comparator.d.ts +2 -0
  18. package/dist/javascript/comparator.d.ts.map +1 -1
  19. package/dist/javascript/comparator.js +5 -1
  20. package/dist/javascript/comparator.js.map +1 -1
  21. package/dist/javascript/format/format.d.ts +5 -2
  22. package/dist/javascript/format/format.d.ts.map +1 -1
  23. package/dist/javascript/format/format.js +51 -11
  24. package/dist/javascript/format/format.js.map +1 -1
  25. package/dist/javascript/format/minimum-viable-spacing-visitor.d.ts +19 -0
  26. package/dist/javascript/format/minimum-viable-spacing-visitor.d.ts.map +1 -1
  27. package/dist/javascript/format/minimum-viable-spacing-visitor.js +180 -7
  28. package/dist/javascript/format/minimum-viable-spacing-visitor.js.map +1 -1
  29. package/dist/javascript/format/prettier-format.d.ts +2 -1
  30. package/dist/javascript/format/prettier-format.d.ts.map +1 -1
  31. package/dist/javascript/format/prettier-format.js +33 -23
  32. package/dist/javascript/format/prettier-format.js.map +1 -1
  33. package/dist/javascript/index.d.ts +3 -3
  34. package/dist/javascript/index.d.ts.map +1 -1
  35. package/dist/javascript/index.js +21 -1
  36. package/dist/javascript/index.js.map +1 -1
  37. package/dist/javascript/parser-utils.d.ts.map +1 -1
  38. package/dist/javascript/parser-utils.js +5 -9
  39. package/dist/javascript/parser-utils.js.map +1 -1
  40. package/dist/javascript/parser.d.ts +3 -2
  41. package/dist/javascript/parser.d.ts.map +1 -1
  42. package/dist/javascript/parser.js +202 -117
  43. package/dist/javascript/parser.js.map +1 -1
  44. package/dist/javascript/print.d.ts +1 -0
  45. package/dist/javascript/print.d.ts.map +1 -1
  46. package/dist/javascript/print.js +9 -0
  47. package/dist/javascript/print.js.map +1 -1
  48. package/dist/javascript/recipes/change-import.d.ts +6 -3
  49. package/dist/javascript/recipes/change-import.d.ts.map +1 -1
  50. package/dist/javascript/recipes/change-import.js +17 -277
  51. package/dist/javascript/recipes/change-import.js.map +1 -1
  52. package/dist/javascript/rpc.js +2 -0
  53. package/dist/javascript/rpc.js.map +1 -1
  54. package/dist/javascript/scope.d.ts +40 -7
  55. package/dist/javascript/scope.d.ts.map +1 -1
  56. package/dist/javascript/scope.js +182 -30
  57. package/dist/javascript/scope.js.map +1 -1
  58. package/dist/javascript/templating/bindings.js +2 -20
  59. package/dist/javascript/templating/bindings.js.map +1 -1
  60. package/dist/javascript/templating/comparator.d.ts +2 -0
  61. package/dist/javascript/templating/comparator.d.ts.map +1 -1
  62. package/dist/javascript/templating/comparator.js +25 -0
  63. package/dist/javascript/templating/comparator.js.map +1 -1
  64. package/dist/javascript/templating/engine.d.ts +5 -0
  65. package/dist/javascript/templating/engine.d.ts.map +1 -1
  66. package/dist/javascript/templating/engine.js +30 -12
  67. package/dist/javascript/templating/engine.js.map +1 -1
  68. package/dist/javascript/templating/template.d.ts.map +1 -1
  69. package/dist/javascript/templating/template.js +6 -0
  70. package/dist/javascript/templating/template.js.map +1 -1
  71. package/dist/javascript/templating/types.d.ts +5 -0
  72. package/dist/javascript/templating/types.d.ts.map +1 -1
  73. package/dist/javascript/tree.d.ts +1 -0
  74. package/dist/javascript/tree.d.ts.map +1 -1
  75. package/dist/javascript/tree.js.map +1 -1
  76. package/dist/javascript/tsconfig.d.ts +32 -0
  77. package/dist/javascript/tsconfig.d.ts.map +1 -0
  78. package/dist/javascript/tsconfig.js +205 -0
  79. package/dist/javascript/tsconfig.js.map +1 -0
  80. package/dist/javascript/type-mapping.d.ts.map +1 -1
  81. package/dist/javascript/type-mapping.js +14 -0
  82. package/dist/javascript/type-mapping.js.map +1 -1
  83. package/dist/javascript/visitor.d.ts.map +1 -1
  84. package/dist/javascript/visitor.js +1 -0
  85. package/dist/javascript/visitor.js.map +1 -1
  86. package/dist/parser.d.ts +6 -0
  87. package/dist/parser.d.ts.map +1 -1
  88. package/dist/parser.js +23 -1
  89. package/dist/parser.js.map +1 -1
  90. package/dist/print.d.ts.map +1 -1
  91. package/dist/print.js +5 -2
  92. package/dist/print.js.map +1 -1
  93. package/dist/rewrite-javascript-version.txt +1 -1
  94. package/dist/rpc/request/parse-project.d.ts +11 -1
  95. package/dist/rpc/request/parse-project.d.ts.map +1 -1
  96. package/dist/rpc/request/parse-project.js +7 -2
  97. package/dist/rpc/request/parse-project.js.map +1 -1
  98. package/dist/rpc/request/parse.d.ts +13 -1
  99. package/dist/rpc/request/parse.d.ts.map +1 -1
  100. package/dist/rpc/request/parse.js +8 -2
  101. package/dist/rpc/request/parse.js.map +1 -1
  102. package/package.json +1 -1
  103. package/src/execution.ts +23 -0
  104. package/src/javascript/add-import.ts +449 -78
  105. package/src/javascript/amd.ts +49 -10
  106. package/src/javascript/binding.ts +60 -74
  107. package/src/javascript/comparator.ts +6 -1
  108. package/src/javascript/format/format.ts +56 -12
  109. package/src/javascript/format/minimum-viable-spacing-visitor.ts +196 -7
  110. package/src/javascript/format/prettier-format.ts +35 -25
  111. package/src/javascript/index.ts +10 -3
  112. package/src/javascript/parser-utils.ts +5 -11
  113. package/src/javascript/parser.ts +167 -62
  114. package/src/javascript/print.ts +10 -0
  115. package/src/javascript/recipes/change-import.ts +19 -349
  116. package/src/javascript/rpc.ts +2 -0
  117. package/src/javascript/scope.ts +210 -31
  118. package/src/javascript/templating/bindings.ts +2 -25
  119. package/src/javascript/templating/comparator.ts +29 -2
  120. package/src/javascript/templating/engine.ts +41 -14
  121. package/src/javascript/templating/template.ts +6 -0
  122. package/src/javascript/templating/types.ts +6 -0
  123. package/src/javascript/tree.ts +1 -0
  124. package/src/javascript/tsconfig.ts +177 -0
  125. package/src/javascript/type-mapping.ts +15 -0
  126. package/src/javascript/visitor.ts +1 -0
  127. package/src/parser.ts +24 -1
  128. package/src/print.ts +5 -2
  129. package/src/rpc/request/parse-project.ts +6 -2
  130. 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 && c.extends.before.whitespace === "") {
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
- if (draft.class) {
160
- if (draft.class.kind == J.Kind.Identifier) {
161
- this.ensureSpace((draft.class as Draft<J.Identifier>).prefix);
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
- const c = await super.visitCase(caseNode, p) as J.Case;
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
- return produce(c, draft => {
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
- // For block statements, target is always at the last index
434
- // since following siblings are omitted during pruning
435
- const isBlockStatements = current.kind === J.Kind.Block && segment.property === 'statements';
436
- const index = isBlockStatements ? value.length - 1 : segment.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
- return reconciled as T;
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 (t.kind === JS.Kind.CompilationUnit) {
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
- if (!cursor) {
600
- // No cursor provided - can't use subtree formatting, return with essential formatting
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
- // If Prettier fails, return tree with essential formatting applied
616
- console.warn('Prettier formatting failed, returning with essential formatting only:', e);
617
- return t;
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
  }
@@ -32,13 +32,20 @@ export * from "./tree-debug";
32
32
  export * from "./project-parser";
33
33
 
34
34
  export type {Scope} from "./scope";
35
- export {scopeOf, namesDeclaredIn, bindingNames} 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";
36
41
  export type {QuoteChar, AddImportOptions} from "./add-import";
37
42
  export {ImportStyle, moduleNameOf, AddImport} from "./add-import";
38
43
  // AMD mechanics `recipes-ui5` builds on directly, beyond the `maybeBind` surface below.
39
- export type {AmdBlock} from "./amd";
44
+ export type {AmdBlock, AmdCalleeOptions} from "./amd";
40
45
  export {
41
- DEFAULT_AMD_CALLEES, amdBlockOf, dependencyNames, parameterNames, withDependency, withoutDependencyAt,
46
+ DEFAULT_AMD_CALLEES, amdBlockOf, enclosingAmdBlock, present, elementsOf, parametersOf, identifierOf,
47
+ dependencyNames, parameterNames, bodyOf, references, namesUsed, lastSegment, derivedBindingName,
48
+ withDependency, withUnboundDependency, withoutDependencyAt,
42
49
  RemoveAmdDependency, removeNewlyUnusedAmdBindings
43
50
  } from "./amd";
44
51
  export type {MaybeBindOptions, MaybeUnbindOptions, MaybeRebindOptions, ModuleBindings} from "./binding";
@@ -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
- const diagnostics = ts.getPreEmitDiagnostics(program, sourceFile);
355
- // checking Parsing and Syntax Errors
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.
@@ -446,7 +440,7 @@ function isCriticalDiagnostic(code: number, sourceFile: ts.SourceFile): boolean
446
440
  }
447
441
  }
448
442
 
449
- return (code > 1000 && code < 2000 && !excludedCodes.has(code)) || additionalCriticalCodes.has(code);
443
+ return code > 1000 && code < 2000 && !excludedCodes.has(code);
450
444
  }
451
445
 
452
446
  export function isValidSurrogateRange(unicodeString: string): boolean {