Skip to content

Commit

Permalink
Have flatMap return a ReadonlyArray by default (#28205)
Browse files Browse the repository at this point in the history
  • Loading branch information
Andy authored Oct 29, 2018
1 parent c97fc64 commit 672b0e3
Show file tree
Hide file tree
Showing 19 changed files with 80 additions and 57 deletions.
2 changes: 1 addition & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28090,7 +28090,7 @@ namespace ts {
return ts.typeHasCallOrConstructSignatures(type, checker);
}

function getRootSymbols(symbol: Symbol): Symbol[] {
function getRootSymbols(symbol: Symbol): ReadonlyArray<Symbol> {
const roots = getImmediateRootSymbols(symbol);
return roots ? flatMap(roots, getRootSymbols) : [symbol];
}
Expand Down
23 changes: 19 additions & 4 deletions src/compiler/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -511,12 +511,27 @@ namespace ts {
* @param array The array to map.
* @param mapfn The callback used to map the result into one or more values.
*/
export function flatMap<T, U>(array: ReadonlyArray<T>, mapfn: (x: T, i: number) => U | ReadonlyArray<U> | undefined): U[];
export function flatMap<T, U>(array: ReadonlyArray<T> | undefined, mapfn: (x: T, i: number) => U | ReadonlyArray<U> | undefined): U[] | undefined;
export function flatMap<T, U>(array: ReadonlyArray<T> | undefined, mapfn: (x: T, i: number) => U | ReadonlyArray<U> | undefined): U[] | undefined {
export function flatMap<T, U>(array: ReadonlyArray<T> | undefined, mapfn: (x: T, i: number) => U | ReadonlyArray<U> | undefined): ReadonlyArray<U> {
let result: U[] | undefined;
if (array) {
result = [];
for (let i = 0; i < array.length; i++) {
const v = mapfn(array[i], i);
if (v) {
if (isArray(v)) {
result = addRange(result, v);
}
else {
result = append(result, v);
}
}
}
}
return result || emptyArray;
}

export function flatMapToMutable<T, U>(array: ReadonlyArray<T> | undefined, mapfn: (x: T, i: number) => U | ReadonlyArray<U> | undefined): U[] {
const result: U[] = [];
if (array) {
for (let i = 0; i < array.length; i++) {
const v = mapfn(array[i], i);
if (v) {
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/transformers/declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1043,7 +1043,7 @@ namespace ts {
const modifiers = createNodeArray(ensureModifiers(input, isPrivate));
const typeParameters = ensureTypeParams(input, input.typeParameters);
const ctor = getFirstConstructorWithBody(input);
let parameterProperties: PropertyDeclaration[] | undefined;
let parameterProperties: ReadonlyArray<PropertyDeclaration> | undefined;
if (ctor) {
const oldDiag = getSymbolAccessibilityDiagnostic;
parameterProperties = compact(flatMap(ctor.parameters, param => {
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2793,7 +2793,7 @@ namespace ts {
export interface ParseConfigHost {
useCaseSensitiveFileNames: boolean;

readDirectory(rootDir: string, extensions: ReadonlyArray<string>, excludes: ReadonlyArray<string> | undefined, includes: ReadonlyArray<string>, depth?: number): string[];
readDirectory(rootDir: string, extensions: ReadonlyArray<string>, excludes: ReadonlyArray<string> | undefined, includes: ReadonlyArray<string>, depth?: number): ReadonlyArray<string>;

/**
* Gets a value indicating whether the specified path exists and is a file.
Expand Down Expand Up @@ -3079,7 +3079,7 @@ namespace ts {

getFullyQualifiedName(symbol: Symbol): string;
getAugmentedPropertiesOfType(type: Type): Symbol[];
getRootSymbols(symbol: Symbol): Symbol[];
getRootSymbols(symbol: Symbol): ReadonlyArray<Symbol>;
getContextualType(node: Expression): Type | undefined;
/* @internal */ getContextualTypeForObjectLiteralElement(element: ObjectLiteralElementLike): Type | undefined;
/* @internal */ getContextualTypeForArgumentAtIndex(call: CallLikeExpression, argIndex: number): Type | undefined;
Expand Down
6 changes: 3 additions & 3 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3038,7 +3038,7 @@ namespace ts {
return fileDiagnostics.get(fileName) || [];
}

const fileDiags: Diagnostic[] = flatMap(filesWithDiagnostics, f => fileDiagnostics.get(f));
const fileDiags: Diagnostic[] = flatMapToMutable(filesWithDiagnostics, f => fileDiagnostics.get(f));
if (!nonFileDiagnostics.length) {
return fileDiags;
}
Expand Down Expand Up @@ -5234,7 +5234,7 @@ namespace ts {
}
if (isJSDocTypeAlias(node)) {
Debug.assert(node.parent.kind === SyntaxKind.JSDocComment);
return flatMap(node.parent.tags, tag => isJSDocTemplateTag(tag) ? tag.typeParameters : undefined) as ReadonlyArray<TypeParameterDeclaration>;
return flatMap(node.parent.tags, tag => isJSDocTemplateTag(tag) ? tag.typeParameters : undefined);
}
if (node.typeParameters) {
return node.typeParameters;
Expand Down Expand Up @@ -7777,7 +7777,7 @@ namespace ts {
return `^(${pattern})${terminator}`;
}

export function getRegularExpressionsForWildcards(specs: ReadonlyArray<string> | undefined, basePath: string, usage: "files" | "directories" | "exclude"): string[] | undefined {
export function getRegularExpressionsForWildcards(specs: ReadonlyArray<string> | undefined, basePath: string, usage: "files" | "directories" | "exclude"): ReadonlyArray<string> | undefined {
if (specs === undefined || specs.length === 0) {
return undefined;
}
Expand Down
14 changes: 7 additions & 7 deletions src/harness/fourslash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ namespace FourSlash {
];
}

private getAllDiagnostics(): ts.Diagnostic[] {
private getAllDiagnostics(): ReadonlyArray<ts.Diagnostic> {
return ts.flatMap(this.languageServiceAdapterHost.getFilenames(), fileName => {
if (!ts.isAnySupportedFileExtension(fileName)) {
return [];
Expand Down Expand Up @@ -532,7 +532,7 @@ namespace FourSlash {
predicate(start!, start! + length!, startMarker.position, endMarker === undefined ? undefined : endMarker.position)); // TODO: GH#18217
}

private printErrorLog(expectErrors: boolean, errors: ts.Diagnostic[]) {
private printErrorLog(expectErrors: boolean, errors: ReadonlyArray<ts.Diagnostic>): void {
if (expectErrors) {
Harness.IO.log("Expected error not found. Error list is:");
}
Expand Down Expand Up @@ -613,7 +613,7 @@ namespace FourSlash {
this.verifyGoToX(arg0, endMarkerNames, () => this.getGoToDefinitionAndBoundSpan());
}

private getGoToDefinition(): ts.DefinitionInfo[] {
private getGoToDefinition(): ReadonlyArray<ts.DefinitionInfo> {
return this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition)!;
}

Expand All @@ -626,7 +626,7 @@ namespace FourSlash {
this.languageService.getTypeDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition));
}

private verifyGoToX(arg0: any, endMarkerNames: ArrayOrSingle<string> | undefined, getDefs: () => ts.DefinitionInfo[] | ts.DefinitionInfoAndBoundSpan | undefined) {
private verifyGoToX(arg0: any, endMarkerNames: ArrayOrSingle<string> | undefined, getDefs: () => ReadonlyArray<ts.DefinitionInfo> | ts.DefinitionInfoAndBoundSpan | undefined) {
if (endMarkerNames) {
this.verifyGoToXPlain(arg0, endMarkerNames, getDefs);
}
Expand All @@ -646,7 +646,7 @@ namespace FourSlash {
}
}

private verifyGoToXPlain(startMarkerNames: ArrayOrSingle<string>, endMarkerNames: ArrayOrSingle<string>, getDefs: () => ts.DefinitionInfo[] | ts.DefinitionInfoAndBoundSpan | undefined) {
private verifyGoToXPlain(startMarkerNames: ArrayOrSingle<string>, endMarkerNames: ArrayOrSingle<string>, getDefs: () => ReadonlyArray<ts.DefinitionInfo> | ts.DefinitionInfoAndBoundSpan | undefined) {
for (const start of toArray(startMarkerNames)) {
this.verifyGoToXSingle(start, endMarkerNames, getDefs);
}
Expand Down Expand Up @@ -1890,7 +1890,7 @@ Actual: ${stringify(fullActual)}`);

public verifyRangesInImplementationList(markerName: string) {
this.goToMarker(markerName);
const implementations: ImplementationLocationInformation[] = this.languageService.getImplementationAtPosition(this.activeFile.fileName, this.currentCaretPosition)!;
const implementations: ReadonlyArray<ImplementationLocationInformation> = this.languageService.getImplementationAtPosition(this.activeFile.fileName, this.currentCaretPosition)!;
if (!implementations || !implementations.length) {
this.raiseError("verifyRangesInImplementationList failed - expected to find at least one implementation location but got 0");
}
Expand Down Expand Up @@ -2383,7 +2383,7 @@ Actual: ${stringify(fullActual)}`);
* Rerieves a codefix satisfying the parameters, or undefined if no such codefix is found.
* @param fileName Path to file where error should be retrieved from.
*/
private getCodeFixes(fileName: string, errorCode?: number, preferences: ts.UserPreferences = ts.emptyOptions): ts.CodeFixAction[] {
private getCodeFixes(fileName: string, errorCode?: number, preferences: ts.UserPreferences = ts.emptyOptions): ReadonlyArray<ts.CodeFixAction> {
const diagnosticsForCodeFix = this.getDiagnostics(fileName, /*includeSuggestions*/ true).map(diagnostic => ({
start: diagnostic.start,
length: diagnostic.length,
Expand Down
2 changes: 1 addition & 1 deletion src/harness/harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ namespace Harness {
getExecutingFilePath(): string;
getWorkspaceRoot(): string;
exit(exitCode?: number): void;
readDirectory(path: string, extension?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[];
readDirectory(path: string, extension?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): ReadonlyArray<string>;
getAccessibleFileSystemEntries(dirname: string): ts.FileSystemEntries;
tryEnableSourceMapsForHost?(): void;
getEnvironmentVariable?(name: string): string;
Expand Down
2 changes: 1 addition & 1 deletion src/server/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ namespace ts.server {
}

getExternalFiles(): SortedReadonlyArray<string> {
return toSortedArray(flatMap(this.plugins, plugin => {
return toSortedArray(flatMapToMutable(this.plugins, plugin => {
if (typeof plugin.getExternalFiles !== "function") return;
try {
return plugin.getExternalFiles(this);
Expand Down
2 changes: 1 addition & 1 deletion src/server/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1023,7 +1023,7 @@ namespace ts.server.protocol {
/**
* The file locations referencing the symbol.
*/
refs: ReferencesResponseItem[];
refs: ReadonlyArray<ReferencesResponseItem>;

/**
* The name of the symbol.
Expand Down
4 changes: 2 additions & 2 deletions src/server/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ namespace ts.server {
projects: Projects,
action: (project: Project, value: T) => ReadonlyArray<U> | U | undefined,
): U[] {
const outputs = flatMap(isArray(projects) ? projects : projects.projects, project => action(project, defaultValue));
const outputs = flatMapToMutable(isArray(projects) ? projects : projects.projects, project => action(project, defaultValue));
if (!isArray(projects) && projects.symLinkedProjects) {
projects.symLinkedProjects.forEach((projects, path) => {
const value = getValue(path as Path);
Expand Down Expand Up @@ -1230,7 +1230,7 @@ namespace ts.server {
const nameSpan = nameInfo && nameInfo.textSpan;
const symbolStartOffset = nameSpan ? scriptInfo.positionToLineOffset(nameSpan.start).offset : 0;
const symbolName = nameSpan ? scriptInfo.getSnapshot().getText(nameSpan.start, textSpanEnd(nameSpan)) : "";
const refs: protocol.ReferencesResponseItem[] = flatMap(references, referencedSymbol =>
const refs: ReadonlyArray<protocol.ReferencesResponseItem> = flatMap(references, referencedSymbol =>
referencedSymbol.references.map(({ fileName, textSpan, isWriteAccess, isDefinition }): protocol.ReferencesResponseItem => {
const scriptInfo = Debug.assertDefined(this.projectService.getScriptInfo(fileName));
const start = scriptInfo.positionToLineOffset(textSpan.start);
Expand Down
2 changes: 1 addition & 1 deletion src/services/codeFixProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ namespace ts {
return arrayFrom(errorCodeToFixes.keys());
}

export function getFixes(context: CodeFixContext): CodeFixAction[] {
export function getFixes(context: CodeFixContext): ReadonlyArray<CodeFixAction> {
return flatMap(errorCodeToFixes.get(String(context.errorCode)) || emptyArray, f => f.getCodeActions(context));
}

Expand Down
2 changes: 1 addition & 1 deletion src/services/codefixes/importFixes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ namespace ts.codefix {
// `position` should only be undefined at a missing jsx namespace, in which case we shouldn't be looking for pure types.
exportedSymbolIsTypeOnly && isJs ? { kind: ImportFixKind.ImportType, moduleSpecifier, position: Debug.assertDefined(position) } : { kind: ImportFixKind.AddNew, moduleSpecifier, importKind }));
// Sort to keep the shortest paths first
return choicesForEachExportingModule.sort((a, b) => a.moduleSpecifier.length - b.moduleSpecifier.length);
return sort(choicesForEachExportingModule, (a, b) => a.moduleSpecifier.length - b.moduleSpecifier.length);
}

function getFixesForAddImport(
Expand Down
2 changes: 1 addition & 1 deletion src/services/codefixes/inferFromUsage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ namespace ts.codefix {

function addJSDocTags(changes: textChanges.ChangeTracker, sourceFile: SourceFile, parent: HasJSDoc, newTags: ReadonlyArray<JSDocTag>): void {
const comments = mapDefined(parent.jsDoc, j => j.comment);
const oldTags = flatMap(parent.jsDoc, j => j.tags);
const oldTags = flatMapToMutable(parent.jsDoc, j => j.tags);
const unmergedNewTags = newTags.filter(newTag => !oldTags || !oldTags.some((tag, i) => {
const merged = tryMergeJsdocTags(tag, newTag);
if (merged) oldTags[i] = merged;
Expand Down
18 changes: 13 additions & 5 deletions src/services/findAllReferences.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/* @internal */
namespace ts.FindAllReferences {
export interface SymbolAndEntries {
definition: Definition | undefined;
references: Entry[];
readonly definition: Definition | undefined;
readonly references: ReadonlyArray<Entry>;
}

export const enum DefinitionKind { Symbol, Label, Keyword, This, String }
Expand Down Expand Up @@ -60,7 +60,7 @@ namespace ts.FindAllReferences {
return map(referenceEntries, entry => toImplementationLocation(entry, checker));
}

function getImplementationReferenceEntries(program: Program, cancellationToken: CancellationToken, sourceFiles: ReadonlyArray<SourceFile>, node: Node, position: number): Entry[] | undefined {
function getImplementationReferenceEntries(program: Program, cancellationToken: CancellationToken, sourceFiles: ReadonlyArray<SourceFile>, node: Node, position: number): ReadonlyArray<Entry> | undefined {
if (node.kind === SyntaxKind.SourceFile) {
return undefined;
}
Expand Down Expand Up @@ -94,11 +94,19 @@ namespace ts.FindAllReferences {

export type ToReferenceOrRenameEntry<T> = (entry: Entry, originalNode: Node) => T;

export function getReferenceEntriesForNode(position: number, node: Node, program: Program, sourceFiles: ReadonlyArray<SourceFile>, cancellationToken: CancellationToken, options: Options = {}, sourceFilesSet: ReadonlyMap<true> = arrayToSet(sourceFiles, f => f.fileName)): Entry[] | undefined {
export function getReferenceEntriesForNode(
position: number,
node: Node,
program: Program,
sourceFiles: ReadonlyArray<SourceFile>,
cancellationToken: CancellationToken,
options: Options = {},
sourceFilesSet: ReadonlyMap<true> = arrayToSet(sourceFiles, f => f.fileName),
): ReadonlyArray<Entry> | undefined {
return flattenEntries(Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, options, sourceFilesSet));
}

function flattenEntries(referenceSymbols: SymbolAndEntries[] | undefined): Entry[] | undefined {
function flattenEntries(referenceSymbols: SymbolAndEntries[] | undefined): ReadonlyArray<Entry> | undefined {
return referenceSymbols && flatMap(referenceSymbols, r => r.references);
}

Expand Down
6 changes: 3 additions & 3 deletions src/services/goToDefinition.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* @internal */
namespace ts.GoToDefinition {
export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile, position: number): DefinitionInfo[] | undefined {
export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile, position: number): ReadonlyArray<DefinitionInfo> | undefined {
const reference = getReferenceAtPosition(sourceFile, position, program);
if (reference) {
return [getDefinitionInfoForFileReference(reference.fileName, reference.file.fileName)];
Expand Down Expand Up @@ -129,7 +129,7 @@ namespace ts.GoToDefinition {
}

/// Goto type
export function getTypeDefinitionAtPosition(typeChecker: TypeChecker, sourceFile: SourceFile, position: number): DefinitionInfo[] | undefined {
export function getTypeDefinitionAtPosition(typeChecker: TypeChecker, sourceFile: SourceFile, position: number): ReadonlyArray<DefinitionInfo> | undefined {
const node = getTouchingPropertyName(sourceFile, position);
if (node === sourceFile) {
return undefined;
Expand All @@ -145,7 +145,7 @@ namespace ts.GoToDefinition {
return fromReturnType && fromReturnType.length !== 0 ? fromReturnType : definitionFromType(typeAtLocation, typeChecker, node);
}

function definitionFromType(type: Type, checker: TypeChecker, node: Node): DefinitionInfo[] {
function definitionFromType(type: Type, checker: TypeChecker, node: Node): ReadonlyArray<DefinitionInfo> {
return flatMap(type.isUnion() && !(type.flags & TypeFlags.Enum) ? type.types : [type], t =>
t.symbol && getDefinitionFromSymbol(checker, t.symbol, node));
}
Expand Down
6 changes: 3 additions & 3 deletions src/services/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1496,7 +1496,7 @@ namespace ts {
}

/// Goto definition
function getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] | undefined {
function getDefinitionAtPosition(fileName: string, position: number): ReadonlyArray<DefinitionInfo> | undefined {
synchronizeHostData();
return GoToDefinition.getDefinitionAtPosition(program, getValidSourceFile(fileName), position);
}
Expand All @@ -1506,7 +1506,7 @@ namespace ts {
return GoToDefinition.getDefinitionAndBoundSpan(program, getValidSourceFile(fileName), position);
}

function getTypeDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] | undefined {
function getTypeDefinitionAtPosition(fileName: string, position: number): ReadonlyArray<DefinitionInfo> | undefined {
synchronizeHostData();
return GoToDefinition.getTypeDefinitionAtPosition(program.getTypeChecker(), getValidSourceFile(fileName), position);
}
Expand All @@ -1519,7 +1519,7 @@ namespace ts {
}

/// References and Occurrences
function getOccurrencesAtPosition(fileName: string, position: number): ReferenceEntry[] | undefined {
function getOccurrencesAtPosition(fileName: string, position: number): ReadonlyArray<ReferenceEntry> | undefined {
return flatMap(getDocumentHighlights(fileName, position, [fileName]), entry => entry.highlightSpans.map<ReferenceEntry>(highlightSpan => ({
fileName: entry.fileName,
textSpan: highlightSpan.textSpan,
Expand Down
Loading

0 comments on commit 672b0e3

Please sign in to comment.