Files
AstralRinth/packages/tooling-config/script-utils/import-sort.ts

74 lines
2.1 KiB
TypeScript

/**
* Import sorting utility that matches eslint-plugin-simple-import-sort's algorithm.
* Use this to pre-sort generated imports so ESLint doesn't need to reformat them - which can cause it to have different diffs
*/
const collator = new Intl.Collator('en', {
sensitivity: 'base',
numeric: true,
})
function compare(a: string, b: string): number {
return collator.compare(a, b) || (a < b ? -1 : a > b ? 1 : 0)
}
/**
* Transforms an import source path the same way simple-import-sort does internally.
* This swaps certain characters to achieve the desired sort order:
* - `.` and `/` sort before other punctuation
* - `..` sorts like `../,` to come after `../../` but before `../a`
*/
function transformSource(source: string): string {
return source
.replace(/^[./]*\.$/, '$&/')
.replace(/^[./]*\/$/, '$&,')
.replace(/[./_-]/g, (char) => {
switch (char) {
case '.':
return '_'
case '/':
return '-'
case '_':
return '.'
case '-':
return '/'
default:
return char
}
})
}
/**
* Compares two import source paths using the same algorithm as simple-import-sort.
* Use this as a comparator function for Array.sort().
*
* @example
* const imports = ['./foo', './bar', './baz'];
* imports.sort(compareImportSources);
*/
export function compareImportSources(a: string, b: string): number {
return compare(transformSource(a), transformSource(b))
}
/**
* Sorts an array of import source paths using the same algorithm as simple-import-sort.
*
* @example
* const sorted = sortImportSources(['./z', './a', './m']);
* // Returns: ['./a', './m', './z']
*/
export function sortImportSources<T extends string>(sources: T[]): T[] {
return sources.slice().sort(compareImportSources)
}
/**
* Sorts an array of items by their import source path.
*
* @example
* const items = [{ path: './z' }, { path: './a' }];
* const sorted = sortByImportSource(items, item => item.path);
*/
export function sortByImportSource<T>(items: T[], getSource: (item: T) => string): T[] {
return items.slice().sort((a, b) => compareImportSources(getSource(a), getSource(b)))
}