Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 13 additions & 12 deletions rewrite-javascript/rewrite/src/javascript/recipes/order-imports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {ExecutionContext} from "../../execution";
import {JavaScriptVisitor, JS} from "../index";
import {J} from "../../java";
import {create as produce, Draft} from "mutative";
import {SpacesStyle, styleFromSourceFile, StyleKind} from "../style";

/**
* Import type categories for sorting order:
Expand Down Expand Up @@ -57,12 +56,8 @@ export class OrderImports extends Recipe {
const originalImportPosition = Object.fromEntries(imports.map((item, i) => [item.element.id, i]));
const restStatements = cu.statements.slice(importCount);

// Get style for consistent brace spacing
const spacesStyle = styleFromSourceFile(StyleKind.SpacesStyle, cu) as SpacesStyle | undefined;
const useBraceSpaces = spacesStyle?.within.es6ImportExportBraces ?? false;

// Sort named specifiers within each import
const sortedSpecifiers = this.sortNamedSpecifiersWithinImports(imports, useBraceSpaces);
const sortedSpecifiers = this.sortNamedSpecifiersWithinImports(imports);

// Sort imports by category and module path
sortedSpecifiers.sort((aPadded, bPadded) => {
Expand Down Expand Up @@ -153,7 +148,7 @@ export class OrderImports extends Recipe {
/**
* Sort named specifiers within each import statement alphabetically.
*/
private sortNamedSpecifiersWithinImports(imports: J.RightPadded<JS.Import>[], useBraceSpaces: boolean): J.RightPadded<JS.Import>[] {
private sortNamedSpecifiersWithinImports(imports: J.RightPadded<JS.Import>[]): J.RightPadded<JS.Import>[] {
const ret = [];
for (const importPadded of imports) {
const import_ = importPadded.element;
Expand All @@ -166,6 +161,13 @@ export class OrderImports extends Recipe {
return; // Nothing to sort
}

// Detect brace spacing from the current import before sorting
const firstEl = elements[0];
const lastEl = elements[elements.length - 1];
const hasBraceSpaces = (firstEl.element.prefix?.whitespace?.includes(' ') ?? false) ||
(lastEl.after?.whitespace?.includes(' ') ?? false);
const braceSpace = hasBraceSpaces ? " " : "";

// Handle trailing comma
const trailingComma = elements.length > 0 &&
elements[elements.length - 1].markers?.markers.find(m => m.kind === J.Markers.TrailingComma);
Expand All @@ -181,18 +183,17 @@ export class OrderImports extends Recipe {
return nameA.localeCompare(nameB);
});

// Normalize spacing based on es6ImportExportBraces style
const braceSpace = useBraceSpaces ? " " : "";
// Normalize all spacing after sorting
for (let i = 0; i < elements.length; i++) {
if (i === 0) {
// First element: space after opening brace based on style
elements[i].element.prefix = {kind: J.Kind.Space, whitespace: braceSpace, comments: []};
} else {
// Other elements: space after comma
elements[i].element.prefix = {kind: J.Kind.Space, whitespace: ' ', comments: []};
}
if (i < elements.length - 1) {
elements[i].after = {kind: J.Kind.Space, whitespace: '', comments: []};
}
}
// Last element: space before closing brace based on style
elements[elements.length - 1].after = {kind: J.Kind.Space, whitespace: braceSpace, comments: []};

// Restore trailing comma to last element
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,21 @@ const x = 1;
`))
});

test("sorts inline type specifiers correctly within named imports", () => {
return spec.rewriteRun(
typescript(
`
import { AuthService } from '$lib/services/auth.service';
import { inject } from '@angular/core';
import { RedirectCommand, Router, type CanActivateFn } from '@angular/router';
`,
`
import { inject } from '@angular/core';
import { type CanActivateFn, RedirectCommand, Router } from '@angular/router';
import { AuthService } from '$lib/services/auth.service';
`))
});

test("comprehensive: basic example from original test", () => {
return spec.rewriteRun(
typescript(
Expand Down