@openrewrite/rewrite 8.69.0-20251207-184829 → 8.69.0-20251207-220615

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 (53) hide show
  1. package/dist/cli/cli-utils.d.ts.map +1 -1
  2. package/dist/cli/cli-utils.js +3 -2
  3. package/dist/cli/cli-utils.js.map +1 -1
  4. package/dist/cli/rewrite.js +2 -1
  5. package/dist/cli/rewrite.js.map +1 -1
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +3 -2
  8. package/dist/index.js.map +1 -1
  9. package/dist/javascript/parser.d.ts.map +1 -1
  10. package/dist/javascript/parser.js +48 -8
  11. package/dist/javascript/parser.js.map +1 -1
  12. package/dist/javascript/recipes/auto-format.d.ts +24 -0
  13. package/dist/javascript/recipes/auto-format.d.ts.map +1 -0
  14. package/dist/javascript/recipes/auto-format.js +58 -0
  15. package/dist/javascript/recipes/auto-format.js.map +1 -0
  16. package/dist/javascript/recipes/change-import.d.ts +51 -0
  17. package/dist/javascript/recipes/change-import.d.ts.map +1 -0
  18. package/dist/javascript/recipes/change-import.js +658 -0
  19. package/dist/javascript/recipes/change-import.js.map +1 -0
  20. package/dist/javascript/recipes/index.d.ts +3 -0
  21. package/dist/javascript/recipes/index.d.ts.map +1 -1
  22. package/dist/javascript/recipes/index.js +3 -0
  23. package/dist/javascript/recipes/index.js.map +1 -1
  24. package/dist/javascript/recipes/order-imports.d.ts +10 -0
  25. package/dist/javascript/recipes/order-imports.d.ts.map +1 -0
  26. package/dist/javascript/recipes/order-imports.js +240 -0
  27. package/dist/javascript/recipes/order-imports.js.map +1 -0
  28. package/dist/javascript/style.js +2 -2
  29. package/dist/javascript/style.js.map +1 -1
  30. package/dist/json/parser.js +78 -30
  31. package/dist/json/parser.js.map +1 -1
  32. package/dist/version.txt +1 -1
  33. package/package.json +1 -1
  34. package/src/cli/cli-utils.ts +3 -2
  35. package/src/cli/rewrite.ts +2 -1
  36. package/src/index.ts +3 -2
  37. package/src/javascript/parser.ts +49 -8
  38. package/src/javascript/recipes/auto-format.ts +44 -0
  39. package/src/javascript/recipes/change-import.ts +700 -0
  40. package/src/javascript/recipes/index.ts +3 -0
  41. package/src/javascript/recipes/order-imports.ts +242 -0
  42. package/src/javascript/style.ts +2 -2
  43. package/src/json/parser.ts +69 -24
  44. package/dist/recipe/index.d.ts +0 -2
  45. package/dist/recipe/index.d.ts.map +0 -1
  46. package/dist/recipe/index.js +0 -21
  47. package/dist/recipe/index.js.map +0 -1
  48. package/dist/recipe/order-imports.d.ts +0 -10
  49. package/dist/recipe/order-imports.d.ts.map +0 -1
  50. package/dist/recipe/order-imports.js +0 -213
  51. package/dist/recipe/order-imports.js.map +0 -1
  52. package/src/recipe/index.ts +0 -17
  53. package/src/recipe/order-imports.ts +0 -195
package/src/index.ts CHANGED
@@ -35,16 +35,16 @@ export * from "./run";
35
35
 
36
36
  // register all recipes in this package
37
37
  export async function activate(registry: RecipeRegistry): Promise<void> {
38
- const {OrderImports} = await import("./recipe/index.js");
39
38
  const {ModernizeOctalEscapeSequences, ModernizeOctalLiterals, RemoveDuplicateObjectKeys} = await import("./javascript/migrate/es6/index.js");
40
39
  const {ExportAssignmentToExportDefault} = await import("./javascript/migrate/typescript/index.js");
41
40
  const {UseObjectPropertyShorthand, PreferOptionalChain, AddParseIntRadix} = await import("./javascript/cleanup/index.js");
42
- const {AsyncCallbackInSyncArrayMethod, UpgradeDependencyVersion} = await import("./javascript/recipes/index.js");
41
+ const {AsyncCallbackInSyncArrayMethod, AutoFormat, UpgradeDependencyVersion, OrderImports, ChangeImport} = await import("./javascript/recipes/index.js");
43
42
  const {FindDependency} = await import("./javascript/search/index.js");
44
43
 
45
44
  registry.register(ExportAssignmentToExportDefault);
46
45
  registry.register(FindDependency);
47
46
  registry.register(OrderImports);
47
+ registry.register(ChangeImport);
48
48
  registry.register(ModernizeOctalEscapeSequences);
49
49
  registry.register(ModernizeOctalLiterals);
50
50
  registry.register(RemoveDuplicateObjectKeys);
@@ -52,6 +52,7 @@ export async function activate(registry: RecipeRegistry): Promise<void> {
52
52
  registry.register(PreferOptionalChain);
53
53
  registry.register(AddParseIntRadix);
54
54
  registry.register(AsyncCallbackInSyncArrayMethod);
55
+ registry.register(AutoFormat);
55
56
  registry.register(UpgradeDependencyVersion);
56
57
  }
57
58
 
@@ -367,11 +367,14 @@ export class JavaScriptParserVisitor {
367
367
  }
368
368
 
369
369
  let shebangStatement: J.RightPadded<JS.Shebang> | undefined;
370
+ let shebangTrailingSpace: J.Space | undefined;
370
371
  if (prefix.whitespace?.startsWith('#!')) {
371
372
  const newlineIndex = prefix.whitespace.indexOf('\n');
372
373
  const shebangText = newlineIndex === -1 ? prefix.whitespace : prefix.whitespace.slice(0, newlineIndex);
373
- // Include all whitespace after shebang (including blank lines) in the shebang's after space
374
- const afterShebang = newlineIndex === -1 ? '' : prefix.whitespace.slice(newlineIndex);
374
+ // Shebang's after only contains the newline that terminates the shebang line
375
+ // The remaining whitespace and comments go into the first statement's prefix
376
+ const afterShebangNewline = newlineIndex === -1 ? '' : '\n';
377
+ const remainingWhitespace = newlineIndex === -1 ? '' : prefix.whitespace.slice(newlineIndex + 1);
375
378
 
376
379
  shebangStatement = this.rightPadded<JS.Shebang>({
377
380
  kind: JS.Kind.Shebang,
@@ -379,14 +382,38 @@ export class JavaScriptParserVisitor {
379
382
  prefix: emptySpace,
380
383
  markers: emptyMarkers,
381
384
  text: shebangText
382
- }, {kind: J.Kind.Space, whitespace: afterShebang, comments: []}, emptyMarkers);
385
+ }, {kind: J.Kind.Space, whitespace: afterShebangNewline, comments: []}, emptyMarkers);
386
+
387
+ // Store the trailing whitespace and comments to prepend to first statement
388
+ if (remainingWhitespace || prefix.comments.length > 0) {
389
+ shebangTrailingSpace = {kind: J.Kind.Space, whitespace: remainingWhitespace, comments: prefix.comments};
390
+ }
383
391
 
384
392
  // CU prefix should be empty when there's a shebang
385
393
  prefix = produce(prefix, draft => {
386
394
  draft.whitespace = '';
395
+ draft.comments = [];
387
396
  });
388
397
  }
389
398
 
399
+ let statements = this.semicolonPaddedStatementList(node.statements);
400
+
401
+ // If there's trailing whitespace/comments after the shebang, prepend to first statement's prefix
402
+ if (shebangTrailingSpace && statements.length > 0) {
403
+ const firstStmt = statements[0];
404
+ statements = [
405
+ produce(firstStmt, draft => {
406
+ const existingPrefix = draft.element.prefix;
407
+ draft.element.prefix = {
408
+ kind: J.Kind.Space,
409
+ whitespace: shebangTrailingSpace!.whitespace + existingPrefix.whitespace,
410
+ comments: [...shebangTrailingSpace!.comments, ...existingPrefix.comments]
411
+ };
412
+ }),
413
+ ...statements.slice(1)
414
+ ];
415
+ }
416
+
390
417
  return {
391
418
  kind: JS.Kind.CompilationUnit,
392
419
  id: randomId(),
@@ -396,8 +423,8 @@ export class JavaScriptParserVisitor {
396
423
  charsetName: bomAndTextEncoding.encoding,
397
424
  charsetBomMarked: bomAndTextEncoding.hasBom,
398
425
  statements: shebangStatement
399
- ? [shebangStatement, ...this.semicolonPaddedStatementList(node.statements)]
400
- : this.semicolonPaddedStatementList(node.statements),
426
+ ? [shebangStatement, ...statements]
427
+ : statements,
401
428
  eof: this.prefix(node.endOfFileToken)
402
429
  };
403
430
  }
@@ -3788,15 +3815,29 @@ export class JavaScriptParserVisitor {
3788
3815
  }
3789
3816
 
3790
3817
  visitJsxExpression(node: ts.JsxExpression): JSX.EmbeddedExpression {
3818
+ let expr: Expression;
3819
+ if (node.expression) {
3820
+ if (node.dotDotDotToken) {
3821
+ expr = produce(this.convert<Expression>(node.expression), draft => {
3822
+ draft.markers.markers.push({
3823
+ kind: JS.Markers.Spread,
3824
+ id: randomId(),
3825
+ prefix: this.prefix(node.dotDotDotToken!)
3826
+ } satisfies Spread as Spread);
3827
+ });
3828
+ } else {
3829
+ expr = this.convert<Expression>(node.expression);
3830
+ }
3831
+ } else {
3832
+ expr = this.newEmpty();
3833
+ }
3791
3834
  return {
3792
3835
  kind: JS.Kind.JsxEmbeddedExpression,
3793
3836
  id: randomId(),
3794
3837
  prefix: this.prefix(node),
3795
3838
  markers: emptyMarkers,
3796
3839
  expression: this.rightPadded(
3797
- node.expression ?
3798
- this.convert<Expression>(node.expression) :
3799
- this.newEmpty(),
3840
+ expr,
3800
3841
  this.prefix(this.findChildNode(node, ts.SyntaxKind.CloseBraceToken)!)
3801
3842
  )
3802
3843
  };
@@ -0,0 +1,44 @@
1
+ /*
2
+ * Copyright 2025 the original author or authors.
3
+ * <p>
4
+ * Licensed under the Moderne Source Available License (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * <p>
8
+ * https://docs.moderne.io/licensing/moderne-source-available-license
9
+ * <p>
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import {Recipe} from "../../recipe";
18
+ import {TreeVisitor} from "../../visitor";
19
+ import {ExecutionContext} from "../../execution";
20
+ import {AutoformatVisitor} from "../format";
21
+
22
+ /**
23
+ * Formats JavaScript/TypeScript code using a comprehensive set of formatting rules.
24
+ *
25
+ * This recipe applies the following formatting:
26
+ * - Normalizes whitespace
27
+ * - Ensures minimum viable spacing
28
+ * - Applies blank line rules
29
+ * - Applies wrapping and braces rules
30
+ * - Applies spacing rules
31
+ * - Applies tabs and indentation rules
32
+ *
33
+ * The formatting rules are determined by the style settings attached to the source file,
34
+ * or defaults to IntelliJ IDEA style if no custom style is specified.
35
+ */
36
+ export class AutoFormat extends Recipe {
37
+ readonly name = "org.openrewrite.javascript.format.auto-format";
38
+ readonly displayName = "Auto-format JavaScript/TypeScript code";
39
+ readonly description = "Format JavaScript and TypeScript code using a comprehensive set of formatting rules based on the project's style settings.";
40
+
41
+ async editor(): Promise<TreeVisitor<any, ExecutionContext>> {
42
+ return new AutoformatVisitor();
43
+ }
44
+ }