Remove stableSort, rename sort to toSorted (#55728)

This commit is contained in:
Jake Bailey 2024-07-23 18:17:07 -07:00 committed by GitHub
parent ab7b624558
commit 3f6f3164d6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 41 additions and 54 deletions

View File

@ -806,7 +806,7 @@ export function sortAndDeduplicate(array: readonly string[]): SortedReadonlyArra
export function sortAndDeduplicate<T>(array: readonly T[], comparer: Comparer<T>, equalityComparer?: EqualityComparer<T>): SortedReadonlyArray<T>;
/** @internal */
export function sortAndDeduplicate<T>(array: readonly T[], comparer?: Comparer<T>, equalityComparer?: EqualityComparer<T>): SortedReadonlyArray<T> {
return deduplicateSorted(sort(array, comparer), equalityComparer ?? comparer ?? compareStringsCaseSensitive as any as Comparer<T>);
return deduplicateSorted(toSorted(array, comparer), equalityComparer ?? comparer ?? compareStringsCaseSensitive as any as Comparer<T>);
}
/** @internal */
@ -1035,12 +1035,12 @@ function stableSortIndices<T>(array: readonly T[], indices: number[], comparer:
}
/**
* Returns a new sorted array.
* Returns a new sorted array. This sort is stable, meaning elements equal to each other maintain their relative position in the array.
*
* @internal
*/
export function sort<T>(array: readonly T[], comparer?: Comparer<T>): SortedReadonlyArray<T> {
return (array.length === 0 ? array : array.slice().sort(comparer)) as SortedReadonlyArray<T>;
export function toSorted<T>(array: readonly T[], comparer?: Comparer<T>): SortedReadonlyArray<T> {
return (array.length === 0 ? emptyArray : array.slice().sort(comparer)) as readonly T[] as SortedReadonlyArray<T>;
}
/** @internal */
@ -1050,17 +1050,6 @@ export function* arrayReverseIterator<T>(array: readonly T[]) {
}
}
/**
* Stable sort of an array. Elements equal to each other maintain their relative position in the array.
*
* @internal
*/
export function stableSort<T>(array: readonly T[], comparer: Comparer<T>): SortedReadonlyArray<T> {
const indices = indicesOf(array);
stableSortIndices(array, indices, comparer);
return indices.map(i => array[i]) as SortedArray<T> as SortedReadonlyArray<T>;
}
/** @internal */
export function rangeEquals<T>(array1: readonly T[], array2: readonly T[], pos: number, end: number) {
while (pos < end) {

View File

@ -79,11 +79,11 @@ import {
SignatureFlags,
SnippetKind,
SortedReadonlyArray,
stableSort,
Symbol,
SymbolFlags,
symbolName,
SyntaxKind,
toSorted,
TransformFlags,
Type,
TypeFacts,
@ -436,7 +436,7 @@ export namespace Debug {
}
}
const sorted = stableSort<[number, string]>(result, (x, y) => compareValues(x[0], y[0]));
const sorted = toSorted<[number, string]>(result, (x, y) => compareValues(x[0], y[0]));
enumMemberCache.set(enumObject, sorted);
return sorted;
}

View File

@ -374,7 +374,6 @@ import {
SourceMapSource,
SpreadAssignment,
SpreadElement,
stableSort,
Statement,
StringLiteral,
supportedJSExtensionsFlat,
@ -394,6 +393,7 @@ import {
ThrowStatement,
TokenFlags,
tokenToString,
toSorted,
tracing,
TransformationResult,
transformNodes,
@ -2072,7 +2072,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
function getSortedEmitHelpers(node: Node) {
const helpers = getEmitHelpers(node);
return helpers && stableSort(helpers, compareEmitHelpers);
return helpers && toSorted(helpers, compareEmitHelpers);
}
//

View File

@ -71,7 +71,6 @@ import {
ReportEmitErrorSummary,
SolutionBuilder,
SolutionBuilderHostBase,
sort,
SourceFile,
startsWith,
startTracing,
@ -80,6 +79,7 @@ import {
sys,
System,
toPath,
toSorted,
tracing,
validateLocaleAndSetLanguage,
version,
@ -170,7 +170,7 @@ function shouldBePretty(sys: System, options: CompilerOptions | BuildOptions) {
function getOptionsForHelp(commandLine: ParsedCommandLine) {
// Sort our options by their names, (e.g. "--noImplicitAny" comes before "--watch")
return !!commandLine.options.all ?
sort(optionDeclarations, (a, b) => compareStringsCaseInsensitive(a.name, b.name)) :
toSorted(optionDeclarations, (a, b) => compareStringsCaseInsensitive(a.name, b.name)) :
filter(optionDeclarations.slice(), v => !!v.showInSimplifiedHelpView);
}

View File

@ -94,12 +94,12 @@ import {
ResolvedTypeReferenceDirective,
ResolvedTypeReferenceDirectiveWithFailedLookupLocations,
some,
sort,
startsWith,
supportedDeclarationExtensions,
supportedJSExtensionsFlat,
supportedTSImplementationExtensions,
toPath,
toSorted,
tryExtractTSExtension,
tryGetExtensionFromPath,
tryParsePatterns,
@ -2695,7 +2695,7 @@ function loadModuleFromImportsOrExports(extensions: Extensions, state: ModuleRes
const target = (lookupTable as { [idx: string]: unknown; })[moduleName];
return loadModuleFromTargetImportOrExport(target, /*subpath*/ "", /*pattern*/ false, moduleName);
}
const expandingKeys = sort(filter(getOwnKeys(lookupTable as MapLike<unknown>), k => hasOneAsterisk(k) || endsWith(k, "/")), comparePatternKeys);
const expandingKeys = toSorted(filter(getOwnKeys(lookupTable as MapLike<unknown>), k => hasOneAsterisk(k) || endsWith(k, "/")), comparePatternKeys);
for (const potentialTarget of expandingKeys) {
if (state.features & NodeResolutionFeatures.ExportsPatternTrailers && matchesPatternWithTrailer(potentialTarget, moduleName)) {
const target = (lookupTable as { [idx: string]: unknown; })[potentialTarget];

View File

@ -302,7 +302,6 @@ import {
sourceFileAffectingCompilerOptions,
sourceFileMayBeEmitted,
SourceOfProjectReferenceRedirect,
stableSort,
startsWith,
Statement,
StringLiteral,
@ -316,6 +315,7 @@ import {
toFileNameLowerCase,
tokenToString,
toPath as ts_toPath,
toSorted,
trace,
tracing,
tryCast,
@ -1887,7 +1887,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
}
}
files = stableSort(processingDefaultLibFiles, compareDefaultLibFiles).concat(processingOtherFiles);
files = toSorted(processingDefaultLibFiles, compareDefaultLibFiles).concat(processingOtherFiles);
processingDefaultLibFiles = undefined;
processingOtherFiles = undefined;
filesWithReferencesProcessed = undefined;

View File

@ -510,7 +510,6 @@ import {
skipTrivia,
SnippetKind,
some,
sort,
SortedArray,
SourceFile,
SourceFileLike,
@ -545,6 +544,7 @@ import {
TokenFlags,
tokenToString,
toPath,
toSorted,
tracing,
TransformFlags,
TransientSymbol,
@ -9596,7 +9596,7 @@ export function matchFiles(path: string, extensions: readonly string[] | undefin
visited.set(canonicalPath, true);
const { files, directories } = getFileSystemEntries(path);
for (const current of sort<string>(files, compareStringsCaseSensitive)) {
for (const current of toSorted<string>(files, compareStringsCaseSensitive)) {
const name = combinePaths(path, current);
const absoluteName = combinePaths(absolutePath, current);
if (extensions && !fileExtensionIsOneOf(name, extensions)) continue;
@ -9619,7 +9619,7 @@ export function matchFiles(path: string, extensions: readonly string[] | undefin
}
}
for (const current of sort<string>(directories, compareStringsCaseSensitive)) {
for (const current of toSorted<string>(directories, compareStringsCaseSensitive)) {
const name = combinePaths(path, current);
const absoluteName = combinePaths(absolutePath, current);
if (

View File

@ -1621,7 +1621,7 @@ export class TestState {
}
}
let pos = 0;
const sortedDetails = ts.stableSort(details, (a, b) => ts.compareValues(a.location, b.location));
const sortedDetails = ts.toSorted(details, (a, b) => ts.compareValues(a.location, b.location));
if (!canDetermineContextIdInline) {
// Assign contextIds
sortedDetails.forEach(({ span, type }) => {

View File

@ -1121,7 +1121,7 @@ export namespace Completion {
].map(keywordEntry);
export function sorted(entries: readonly ExpectedCompletionEntry[]): readonly ExpectedCompletionEntry[] {
return ts.stableSort(entries, compareExpectedCompletionEntries);
return ts.toSorted(entries, compareExpectedCompletionEntries);
}
// If you want to use a function like `globalsPlus`, that function needs to sort

View File

@ -547,7 +547,7 @@ export namespace Compiler {
export const diagnosticSummaryMarker = "__diagnosticSummary";
export const globalErrorsMarker = "__globalErrors";
export function* iterateErrorBaseline(inputFiles: readonly TestFile[], diagnostics: readonly ts.Diagnostic[], options?: { pretty?: boolean; caseSensitive?: boolean; currentDirectory?: string; }): IterableIterator<[string, string, number]> {
diagnostics = ts.sort(diagnostics, ts.compareDiagnostics);
diagnostics = ts.toSorted(diagnostics, ts.compareDiagnostics);
let outputLines = "";
// Count up all errors that were found in files other than lib.d.ts so we don't miss any
let totalErrorsReportedInNonLibraryNonTsconfigFiles = 0;

View File

@ -112,7 +112,6 @@ import {
returnTrue,
ScriptKind,
some,
sort,
sortAndDeduplicate,
SortedReadonlyArray,
SourceFile,
@ -125,6 +124,7 @@ import {
ThrottledCancellationToken,
timestamp,
toPath,
toSorted,
tracing,
TypeAcquisition,
updateErrorForNoInputFiles,
@ -1085,7 +1085,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
}
getExternalFiles(updateLevel?: ProgramUpdateLevel): SortedReadonlyArray<string> {
return sort(flatMap(this.plugins, plugin => {
return toSorted(flatMap(this.plugins, plugin => {
if (typeof plugin.module.getExternalFiles !== "function") return;
try {
return plugin.module.getExternalFiles(this, updateLevel || ProgramUpdateLevel.Update);
@ -1508,7 +1508,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
typeAcquisition,
unresolvedImports,
};
const typingFiles = !typeAcquisition || !typeAcquisition.enable ? emptyArray : sort(newTypings);
const typingFiles = !typeAcquisition || !typeAcquisition.enable ? emptyArray : toSorted(newTypings);
if (enumerateInsertsAndDeletes<string, string>(typingFiles, this.typingFiles, getStringComparer(!this.useCaseSensitiveFileNames()), /*inserted*/ noop, removed => this.detachScriptInfoFromProject(removed))) {
// If typing files changed, then only schedule project update
this.typingFiles = typingFiles;

View File

@ -137,9 +137,7 @@ import {
single,
skipAlias,
some,
sort,
SourceFile,
stableSort,
startsWith,
StringLiteral,
stripQuotes,
@ -150,6 +148,7 @@ import {
SyntaxKind,
textChanges,
toPath,
toSorted,
tryCast,
tryGetModuleSpecifierFromDeclaration,
TypeChecker,
@ -1290,7 +1289,7 @@ function getFixInfos(context: CodeFixContextBase, errorCode: number, pos: number
function sortFixInfo(fixes: readonly (FixInfo & { fix: ImportFixWithModuleSpecifier; })[], sourceFile: SourceFile, program: Program, packageJsonImportFilter: PackageJsonImportFilter, host: LanguageServiceHost, preferences: UserPreferences): readonly (FixInfo & { fix: ImportFixWithModuleSpecifier; })[] {
const _toPath = (fileName: string) => toPath(fileName, host.getCurrentDirectory(), hostGetCanonicalFileName(host));
return sort(fixes, (a, b) =>
return toSorted(fixes, (a, b) =>
compareBooleans(!!a.isJsxNamespaceFix, !!b.isJsxNamespaceFix) ||
compareValues(a.fix.kind, b.fix.kind) ||
compareModuleSpecifiers(a.fix, b.fix, sourceFile, program, preferences, packageJsonImportFilter.allowsImportingSpecifier, _toPath));
@ -1822,7 +1821,7 @@ function doAddExistingFix(
if (namedImports.length) {
const { specifierComparer, isSorted } = OrganizeImports.getNamedImportSpecifierComparerWithDetection(clause.parent, preferences, sourceFile);
const newSpecifiers = stableSort(
const newSpecifiers = toSorted(
namedImports.map(namedImport =>
factory.createImportSpecifier(
(!clause.isTypeOnly || promoteFromTypeOnly) && shouldUseTypeOnly(namedImport, preferences),
@ -1842,7 +1841,7 @@ function doAddExistingFix(
clause.namedBindings!,
factory.updateNamedImports(
clause.namedBindings as NamedImports,
stableSort([...existingSpecifiers!.filter(s => !removeExistingImportSpecifiers.has(s)), ...newSpecifiers], specifierComparer),
toSorted([...existingSpecifiers!.filter(s => !removeExistingImportSpecifiers.has(s)), ...newSpecifiers], specifierComparer),
),
);
}

View File

@ -352,7 +352,6 @@ import {
SortedArray,
SourceFile,
SpreadAssignment,
stableSort,
startsWith,
stringToToken,
stripQuotes,
@ -374,6 +373,7 @@ import {
Token,
TokenSyntaxKind,
tokenToString,
toSorted,
tryCast,
tryGetImportFromModuleSpecifier,
tryGetTextOfPropertyName,
@ -2459,7 +2459,7 @@ function createSnippetPrinter(
});
const allChanges = escapes
? stableSort(concatenate(changes, escapes), (a, b) => compareTextSpans(a.span, b.span))
? toSorted(concatenate(changes, escapes), (a, b) => compareTextSpans(a.span, b.span))
: changes;
return textChanges.applyChanges(syntheticFile.text, allChanges);
}
@ -2506,7 +2506,7 @@ function createSnippetPrinter(
);
const allChanges = escapes
? stableSort(concatenate(changes, escapes), (a, b) => compareTextSpans(a.span, b.span))
? toSorted(concatenate(changes, escapes), (a, b) => compareTextSpans(a.span, b.span))
: changes;
return textChanges.applyChanges(syntheticFile.text, allChanges);
}

View File

@ -56,11 +56,10 @@ import {
Scanner,
setEmitFlags,
some,
sort,
SourceFile,
stableSort,
SyntaxKind,
textChanges,
toSorted,
TransformFlags,
tryCast,
UserPreferences,
@ -159,7 +158,7 @@ export function organizeImports(
? group(oldImportDecls, importDecl => getExternalModuleName(importDecl.moduleSpecifier)!)
: [oldImportDecls];
const sortedImportGroups = shouldSort
? stableSort(oldImportGroups, (group1, group2) => compareModuleSpecifiersWorker(group1[0].moduleSpecifier, group2[0].moduleSpecifier, comparer.moduleSpecifierComparer ?? defaultComparer))
? toSorted(oldImportGroups, (group1, group2) => compareModuleSpecifiersWorker(group1[0].moduleSpecifier, group2[0].moduleSpecifier, comparer.moduleSpecifierComparer ?? defaultComparer))
: oldImportGroups;
const newImportDecls = flatMap(sortedImportGroups, importGroup =>
getExternalModuleName(importGroup[0].moduleSpecifier) || importGroup[0].moduleSpecifier === undefined
@ -199,7 +198,7 @@ export function organizeImports(
const processImportsOfSameModuleSpecifier = (importGroup: readonly ImportDeclaration[]) => {
if (shouldRemove) importGroup = removeUnusedImports(importGroup, sourceFile, program);
if (shouldCombine) importGroup = coalesceImportsWorker(importGroup, detectedModuleCaseComparer, specifierComparer, sourceFile);
if (shouldSort) importGroup = stableSort(importGroup, (s1, s2) => compareImportsOrRequireStatements(s1, s2, detectedModuleCaseComparer));
if (shouldSort) importGroup = toSorted(importGroup, (s1, s2) => compareImportsOrRequireStatements(s1, s2, detectedModuleCaseComparer));
return importGroup;
};
@ -428,7 +427,7 @@ function coalesceImportsWorker(importGroup: readonly ImportDeclaration[], compar
const importGroupsByAttributes = groupBy(importGroup, decl => {
if (decl.attributes) {
let attrs = decl.attributes.token + " ";
for (const x of sort(decl.attributes.elements, (x, y) => compareStringsCaseSensitive(x.name.text, y.name.text))) {
for (const x of toSorted(decl.attributes.elements, (x, y) => compareStringsCaseSensitive(x.name.text, y.name.text))) {
attrs += x.name.text + ":";
attrs += isStringLiteralLike(x.value) ? `"${x.value.text}"` : x.value.getText() + " ";
}
@ -461,7 +460,7 @@ function coalesceImportsWorker(importGroup: readonly ImportDeclaration[], compar
continue;
}
const sortedNamespaceImports = stableSort(namespaceImports, (i1, i2) => comparer(i1.importClause.namedBindings.name.text, i2.importClause.namedBindings.name.text));
const sortedNamespaceImports = toSorted(namespaceImports, (i1, i2) => comparer(i1.importClause.namedBindings.name.text, i2.importClause.namedBindings.name.text));
for (const namespaceImport of sortedNamespaceImports) {
// Drop the name, if any
@ -493,7 +492,7 @@ function coalesceImportsWorker(importGroup: readonly ImportDeclaration[], compar
newImportSpecifiers.push(...getNewImportSpecifiers(namedImports));
const sortedImportSpecifiers = factory.createNodeArray(
stableSort(newImportSpecifiers, specifierComparer),
toSorted(newImportSpecifiers, specifierComparer),
firstNamedImport?.importClause.namedBindings.elements.hasTrailingComma,
);
@ -579,7 +578,7 @@ function coalesceExportsWorker(exportGroup: readonly ExportDeclaration[], specif
const newExportSpecifiers: ExportSpecifier[] = [];
newExportSpecifiers.push(...flatMap(exportGroup, i => i.exportClause && isNamedExports(i.exportClause) ? i.exportClause.elements : emptyArray));
const sortedExportSpecifiers = stableSort(newExportSpecifiers, specifierComparer);
const sortedExportSpecifiers = toSorted(newExportSpecifiers, specifierComparer);
const exportDecl = exportGroup[0];
coalescedExports.push(

View File

@ -154,7 +154,6 @@ import {
skipTrivia,
SourceFile,
SourceFileLike,
stableSort,
Statement,
stringContainsAt,
Symbol,
@ -164,6 +163,7 @@ import {
textSpanEnd,
Token,
tokenToString,
toSorted,
TransformationContext,
TypeLiteralNode,
TypeNode,
@ -1264,7 +1264,7 @@ namespace changesToText {
const sourceFile = changesInFile[0].sourceFile;
// order changes by start position
// If the start position is the same, put the shorter range first, since an empty range (x, x) may precede (x, y) but not vice-versa.
const normalized = stableSort(changesInFile, (a, b) => (a.range.pos - b.range.pos) || (a.range.end - b.range.end));
const normalized = toSorted(changesInFile, (a, b) => (a.range.pos - b.range.pos) || (a.range.end - b.range.end));
// verify that change intervals do not overlap, except possibly at end points.
for (let i = 0; i < normalized.length - 1; i++) {
Debug.assert(normalized[i].range.end <= normalized[i + 1].range.pos, "Changes overlap", () => `${JSON.stringify(normalized[i].range)} and ${JSON.stringify(normalized[i + 1].range)}`);

View File

@ -342,7 +342,6 @@ import {
SourceFileLike,
SourceMapper,
SpreadElement,
stableSort,
startsWith,
StringLiteral,
StringLiteralLike,
@ -371,6 +370,7 @@ import {
Token,
tokenToString,
toPath,
toSorted,
tryCast,
tryParseJson,
Type,
@ -2625,7 +2625,7 @@ export function insertImports(changes: textChanges.ChangeTracker, sourceFile: So
const importKindPredicate: (node: Node) => node is AnyImportOrRequireStatement = decl.kind === SyntaxKind.VariableStatement ? isRequireVariableStatement : isAnyImportSyntax;
const existingImportStatements = filter(sourceFile.statements, importKindPredicate);
const { comparer, isSorted } = OrganizeImports.getOrganizeImportsStringComparerWithDetection(existingImportStatements, preferences);
const sortedNewImports = isArray(imports) ? stableSort(imports, (a, b) => OrganizeImports.compareImportsOrRequireStatements(a, b, comparer)) : [imports];
const sortedNewImports = isArray(imports) ? toSorted(imports, (a, b) => OrganizeImports.compareImportsOrRequireStatements(a, b, comparer)) : [imports];
if (!existingImportStatements?.length) {
if (isFullSourceFile(sourceFile)) {
changes.insertNodesAtTopOfFile(sourceFile, sortedNewImports, blankLineBetween);