Skip to content

Collate-free import sorting#4349

Open
jakebailey wants to merge 6 commits into
mainfrom
jabaile/no-collate
Open

Collate-free import sorting#4349
jakebailey wants to merge 6 commits into
mainfrom
jabaile/no-collate

Conversation

@jakebailey

@jakebailey jakebailey commented Jun 17, 2026

Copy link
Copy Markdown
Member

We currently import x/text/collate to implement import sorting. But, this has cost:

  • The tables are huge. They add 1.3MB to our binary.
  • The tables are very out of date. They're on CLDR 23, which was for Unicode 6.3!

While I think I can fix the latter with a CL stack I've been trying, the former is just unfixable.

I do not think anyone out there is actually writing non-ASCII imports, but the case sensitivity and "natural" sorting is useful. It turns out you can get really close to the old behavior with just the stdlib and x/text/norm for accent normalization.

My proposal is this:

  • Create a new import sorting scheme that does not require collation.
  • Transparently use the new import sorting scheme that matches best for the old options.
  • Deprecate the old options.

As mentioned before, this drops 1.3MB out of our binary.

The new options are:

type OrganizeImportsSort int

const (
	OrganizeImportsSortAuto OrganizeImportsSort = iota
	OrganizeImportsSortOrdinal
	OrganizeImportsSortOrdinalIgnoreCase
	OrganizeImportsSortNatural
	OrganizeImportsSortNaturalIgnoreCase
)

Which do what they say on the tin.

In terms of which tools are closest to which option:

  • eslint-plugin-simple-import-sort: naturalIgnoreCase.
  • dprint: ordinal or ordinalIgnoreCase.
  • ESLint's built-in sort-imports: ordinal or ordinalIgnoreCase.
  • eslint-plugin-import/order: ordinal or ordinalIgnoreCase.
  • @trivago/prettier-plugin-sort-imports / @ianvs/prettier-plugin-sort-imports: natural or naturalIgnoreCase
  • biome: natural or ordinal
  • oxfmt: natural or naturalIgnoreCase
  • eslint-plugin-perfectionist/sort-imports: in natural mode, natural or naturalIgnoreCase (plus a mode that is more like ordinalIgnoreCase but it's actually system locale dependent, ouch)

Copilot AI review requested due to automatic review settings June 17, 2026 15:44
throw new Error(`Unsupported value for organizeImportsIgnoreCase: ${propValue.getText()}`);
}
}
else if (propName === "organizeImportsSort") {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll note that no tests change behavior with this mapping; no manual test changes etc etc. This gives me hope!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, almost, see #4349 (comment)

caseInsensitiveOrganizeImportsComparer[0],
caseSensitiveOrganizeImportsComparer[0],
}
"golang.org/x/text/unicode/norm"

@jakebailey jakebailey Jun 17, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is here solely to split letters from their accents for case insensitive sorting. We do test this.

Unfortunately, this is more tables internally, also out of date.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR replaces the existing import-sorting implementation that depended on x/text/collate with a collate-free approach, introducing a new OrganizeImportsSort preset enum and wiring it through LSP preferences, tests, and fourslash fixtures/baselines.

Changes:

  • Added OrganizeImportsSort preference (including parsing/serialization) and updated config/baselines to emit "sort": "auto".
  • Reimplemented organize-import string comparison without collate, including natural/numeric/diacritic-aware comparisons and updated sorting/detection logic.
  • Updated LSP/session tests and fourslash tests (and conversion script) to use the new organizeImportsSort preference.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
testdata/baselines/reference/fourslash/state/codeLensAcrossProjects.baseline Baseline update to include new organizeImports.sort field.
internal/project/session_test.go Updates session preference parsing expectations to use organizeImportsSort.
internal/ls/organizeimports.go Integrates resolved sort mode into organize-imports comparer selection/detection.
internal/ls/lsutil/utilities_test.go Adds tests for sort resolution and natural string comparison behavior.
internal/ls/lsutil/userpreferences.go Adds OrganizeImportsSort enum + config plumbing; refactors raw-field config handling.
internal/ls/lsutil/userpreferences_test.go Extends preference parsing tests for old/new organize-import settings.
internal/ls/lsutil/organizeimports.go Removes collate-based comparer; adds collate-free comparison and detection updates.
internal/fourslash/tests/organizeImports_sortModuleSpecifiers_test.go Switches fourslash preferences to OrganizeImportsSortOrdinalIgnoreCase.
internal/fourslash/tests/organizeImports_coalesceImports_test.go Switches fourslash preferences to OrganizeImportsSortOrdinalIgnoreCase.
internal/fourslash/tests/organizeImports_coalesceExports_test.go Switches fourslash preferences to OrganizeImportsSortOrdinalIgnoreCase.
internal/fourslash/_scripts/convertFourslash.mts Teaches converter to map organizeImportsSort into Go preferences.

Comment thread internal/ls/organizeimports.go
Comment thread internal/ls/lsutil/organizeimports.go Outdated
Comment thread internal/ls/lsutil/organizeimports.go Outdated
Comment thread internal/ls/lsutil/userpreferences.go

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Comment thread internal/ls/lsutil/organizeimports.go Outdated

fullCollator := collate.New(tag, opts...)
if !accents {
return strings.Compare(b, a)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strada actually did this wrong, which is terrible

@jakebailey jakebailey added this to the TypeScript 7.0 Stable milestone Jun 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants