Use more explicit operations in core helpers (and other nits) (#58873)

This commit is contained in:
Daniel Rosenwasser
2024-06-18 16:00:00 -07:00
committed by GitHub
parent 4239025fa3
commit 4935e14901
9 changed files with 102 additions and 123 deletions
+3 -3
View File
@@ -17,10 +17,10 @@ import {
appendIfUnique,
ArrayBindingPattern,
arrayFrom,
arrayIsEqualTo,
arrayIsHomogeneous,
ArrayLiteralExpression,
arrayOf,
arraysEqual,
arrayToMultiMap,
ArrayTypeNode,
ArrowFunction,
@@ -25861,7 +25861,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
function inferTypesFromTemplateLiteralType(source: Type, target: TemplateLiteralType): Type[] | undefined {
return source.flags & TypeFlags.StringLiteral ? inferFromLiteralPartsToTemplateLiteral([(source as StringLiteralType).value], emptyArray, target) :
source.flags & TypeFlags.TemplateLiteral ?
arraysEqual((source as TemplateLiteralType).texts, target.texts) ? map((source as TemplateLiteralType).types, (s, i) => {
arrayIsEqualTo((source as TemplateLiteralType).texts, target.texts) ? map((source as TemplateLiteralType).types, (s, i) => {
return isTypeAssignableTo(getBaseConstraintOrType(s), getBaseConstraintOrType(target.types[i])) ? s : getStringLikeTypeForType(s);
}) :
inferFromLiteralPartsToTemplateLiteral((source as TemplateLiteralType).texts, (source as TemplateLiteralType).types, target) :
@@ -28628,7 +28628,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return getEvolvingArrayType(getUnionType(map(types, getElementTypeOfEvolvingArrayType)));
}
const result = recombineUnknownType(getUnionType(sameMap(types, finalizeEvolvingArrayType), subtypeReduction));
if (result !== declaredType && result.flags & declaredType.flags & TypeFlags.Union && arraysEqual((result as UnionType).types, (declaredType as UnionType).types)) {
if (result !== declaredType && result.flags & declaredType.flags & TypeFlags.Union && arrayIsEqualTo((result as UnionType).types, (declaredType as UnionType).types)) {
return declaredType;
}
return result;
+1 -3
View File
@@ -2576,9 +2576,7 @@ export function convertToTSConfig(configParseResult: ParsedCommandLine, configFi
/** @internal */
export function optionMapToObject(optionMap: Map<string, CompilerOptionsValue>): object {
return {
...arrayFrom(optionMap.entries()).reduce((prev, cur) => ({ ...prev, [cur[0]]: cur[1] }), {}),
};
return Object.fromEntries(optionMap);
}
function filterSameAsDefaultInclude(specs: readonly string[] | undefined) {
+79 -95
View File
@@ -11,6 +11,8 @@ import {
TextSpan,
} from "./_namespaces/ts.js";
/* eslint-disable @typescript-eslint/prefer-for-of */
/** @internal */
export const emptyArray: never[] = [] as never[];
/** @internal */
@@ -20,7 +22,7 @@ export const emptySet: ReadonlySet<never> = new Set<never>();
/** @internal */
export function length(array: readonly any[] | undefined): number {
return array ? array.length : 0;
return array !== undefined ? array.length : 0;
}
/**
@@ -31,7 +33,7 @@ export function length(array: readonly any[] | undefined): number {
* @internal
*/
export function forEach<T, U>(array: readonly T[] | undefined, callback: (element: T, index: number) => U | undefined): U | undefined {
if (array) {
if (array !== undefined) {
for (let i = 0; i < array.length; i++) {
const result = callback(array[i], i);
if (result) {
@@ -48,7 +50,7 @@ export function forEach<T, U>(array: readonly T[] | undefined, callback: (elemen
* @internal
*/
export function forEachRight<T, U>(array: readonly T[] | undefined, callback: (element: T, index: number) => U | undefined): U | undefined {
if (array) {
if (array !== undefined) {
for (let i = array.length - 1; i >= 0; i--) {
const result = callback(array[i], i);
if (result) {
@@ -124,7 +126,7 @@ export function intersperse<T>(input: T[], element: T): T[] {
}
const result: T[] = [];
for (let i = 0, n = input.length; i < n; i++) {
if (i) result.push(element);
if (i !== 0) result.push(element);
result.push(input[i]);
}
return result;
@@ -143,7 +145,7 @@ export function every<T, U extends T>(array: readonly T[] | undefined, callback:
/** @internal */
export function every<T>(array: readonly T[] | undefined, callback: (element: T, index: number) => boolean): boolean;
export function every<T>(array: readonly T[] | undefined, callback: (element: T, index: number) => boolean): boolean {
if (array) {
if (array !== undefined) {
for (let i = 0; i < array.length; i++) {
if (!callback(array[i], i)) {
return false;
@@ -234,9 +236,9 @@ export function findMap<T, U>(array: readonly T[], callback: (element: T, index:
/** @internal */
export function contains<T>(array: readonly T[] | undefined, value: T, equalityComparer: EqualityComparer<T> = equateValues): boolean {
if (array) {
for (const v of array) {
if (equalityComparer(v, value)) {
if (array !== undefined) {
for (let i = 0; i < array.length; i++) {
if (equalityComparer(array[i], value)) {
return true;
}
}
@@ -244,14 +246,9 @@ export function contains<T>(array: readonly T[] | undefined, value: T, equalityC
return false;
}
/** @internal */
export function arraysEqual<T>(a: readonly T[], b: readonly T[], equalityComparer: EqualityComparer<T> = equateValues): boolean {
return a.length === b.length && a.every((x, i) => equalityComparer(x, b[i]));
}
/** @internal */
export function indexOfAnyCharCode(text: string, charCodes: readonly number[], start?: number): number {
for (let i = start || 0; i < text.length; i++) {
for (let i = start ?? 0; i < text.length; i++) {
if (contains(charCodes, text.charCodeAt(i))) {
return i;
}
@@ -262,7 +259,7 @@ export function indexOfAnyCharCode(text: string, charCodes: readonly number[], s
/** @internal */
export function countWhere<T>(array: readonly T[] | undefined, predicate: (x: T, i: number) => boolean): number {
let count = 0;
if (array) {
if (array !== undefined) {
for (let i = 0; i < array.length; i++) {
const v = array[i];
if (predicate(v, i)) {
@@ -296,7 +293,7 @@ export function filter<T, U extends T>(array: readonly T[] | undefined, f: (x: T
export function filter<T>(array: readonly T[] | undefined, f: (x: T) => boolean): readonly T[] | undefined;
/** @internal */
export function filter<T>(array: readonly T[] | undefined, f: (x: T) => boolean): readonly T[] | undefined {
if (array) {
if (array !== undefined) {
const len = array.length;
let i = 0;
while (i < len && f(array[i])) i++;
@@ -340,7 +337,7 @@ export function map<T, U>(array: readonly T[] | undefined, f: (x: T, i: number)
/** @internal */
export function map<T, U>(array: readonly T[] | undefined, f: (x: T, i: number) => U): U[] | undefined {
let result: U[] | undefined;
if (array) {
if (array !== undefined) {
result = [];
for (let i = 0; i < array.length; i++) {
result.push(f(array[i], i));
@@ -369,7 +366,7 @@ export function sameMap<T, U = T>(array: T[] | undefined, f: (x: T, i: number) =
export function sameMap<T, U = T>(array: readonly T[] | undefined, f: (x: T, i: number) => U): readonly U[] | undefined;
/** @internal */
export function sameMap<T, U = T>(array: readonly T[] | undefined, f: (x: T, i: number) => U): readonly U[] | undefined {
if (array) {
if (array !== undefined) {
for (let i = 0; i < array.length; i++) {
const item = array[i];
const mapped = f(item, i);
@@ -395,7 +392,8 @@ export function sameMap<T, U = T>(array: readonly T[] | undefined, f: (x: T, i:
*/
export function flatten<T>(array: T[][] | readonly (T | readonly T[] | undefined)[]): T[] {
const result = [];
for (const v of array) {
for (let i = 0; i < array.length; i++) {
const v = array[i];
if (v) {
if (isArray(v)) {
addRange(result, v);
@@ -418,7 +416,7 @@ export function flatten<T>(array: T[][] | readonly (T | readonly T[] | undefined
*/
export function flatMap<T, U>(array: readonly T[] | undefined, mapfn: (x: T, i: number) => U | readonly U[] | undefined): readonly U[] {
let result: U[] | undefined;
if (array) {
if (array !== undefined) {
for (let i = 0; i < array.length; i++) {
const v = mapfn(array[i], i);
if (v) {
@@ -431,13 +429,13 @@ export function flatMap<T, U>(array: readonly T[] | undefined, mapfn: (x: T, i:
}
}
}
return result || emptyArray;
return result ?? emptyArray;
}
/** @internal */
export function flatMapToMutable<T, U>(array: readonly T[] | undefined, mapfn: (x: T, i: number) => U | readonly U[] | undefined): U[] {
const result: U[] = [];
if (array) {
if (array !== undefined) {
for (let i = 0; i < array.length; i++) {
const v = mapfn(array[i], i);
if (v) {
@@ -477,7 +475,7 @@ export function sameFlatMap<T>(array: readonly T[], mapfn: (x: T, i: number) =>
/** @internal */
export function sameFlatMap<T>(array: readonly T[], mapfn: (x: T, i: number) => T | readonly T[]): readonly T[] {
let result: T[] | undefined;
if (array) {
if (array !== undefined) {
for (let i = 0; i < array.length; i++) {
const item = array[i];
const mapped = mapfn(item, i);
@@ -494,7 +492,7 @@ export function sameFlatMap<T>(array: readonly T[], mapfn: (x: T, i: number) =>
}
}
}
return result || array;
return result ?? array;
}
/** @internal */
@@ -513,7 +511,7 @@ export function mapAllOrFail<T, U>(array: readonly T[], mapFn: (x: T, i: number)
/** @internal */
export function mapDefined<T, U>(array: readonly T[] | undefined, mapFn: (x: T, i: number) => U | undefined): U[] {
const result: U[] = [];
if (array) {
if (array !== undefined) {
for (let i = 0; i < array.length; i++) {
const mapped = mapFn(array[i], i);
if (mapped !== undefined) {
@@ -534,30 +532,6 @@ export function* mapDefinedIterator<T, U>(iter: Iterable<T>, mapFn: (x: T) => U
}
}
/** @internal */
export function mapDefinedEntries<K1, V1, K2, V2>(map: ReadonlyMap<K1, V1>, f: (key: K1, value: V1) => readonly [K2, V2] | undefined): Map<K2, V2>;
/** @internal */
export function mapDefinedEntries<K1, V1, K2, V2>(map: ReadonlyMap<K1, V1> | undefined, f: (key: K1, value: V1) => readonly [K2 | undefined, V2 | undefined] | undefined): Map<K2, V2> | undefined;
/** @internal */
export function mapDefinedEntries<K1, V1, K2, V2>(map: ReadonlyMap<K1, V1> | undefined, f: (key: K1, value: V1) => readonly [K2 | undefined, V2 | undefined] | undefined): Map<K2, V2> | undefined {
if (!map) {
return undefined;
}
const result = new Map<K2, V2>();
map.forEach((value, key) => {
const entry = f(key, value);
if (entry !== undefined) {
const [newKey, newValue] = entry;
if (newKey !== undefined && newValue !== undefined) {
result.set(newKey, newValue);
}
}
});
return result;
}
/** @internal */
export function getOrUpdate<K, V>(map: Map<K, V>, key: K, callback: () => V) {
if (map.has(key)) {
@@ -597,7 +571,7 @@ export function spanMap<T, K, U>(array: readonly T[] | undefined, keyfn: (x: T,
/** @internal */
export function spanMap<T, K, U>(array: readonly T[] | undefined, keyfn: (x: T, i: number) => K, mapfn: (chunk: T[], key: K, start: number, end: number) => U): U[] | undefined {
let result: U[] | undefined;
if (array) {
if (array !== undefined) {
result = [];
const len = array.length;
let previousKey: K | undefined;
@@ -641,7 +615,7 @@ export function mapEntries<K1, V1, K2, V2>(map: ReadonlyMap<K1, V1>, f: (key: K1
export function mapEntries<K1, V1, K2, V2>(map: ReadonlyMap<K1, V1> | undefined, f: (key: K1, value: V1) => readonly [K2, V2]): Map<K2, V2> | undefined;
/** @internal */
export function mapEntries<K1, V1, K2, V2>(map: ReadonlyMap<K1, V1> | undefined, f: (key: K1, value: V1) => readonly [K2, V2]): Map<K2, V2> | undefined {
if (!map) {
if (map === undefined) {
return undefined;
}
@@ -659,10 +633,10 @@ export function some<T>(array: readonly T[] | undefined): array is readonly T[];
export function some<T>(array: readonly T[] | undefined, predicate: (value: T) => boolean): boolean;
/** @internal */
export function some<T>(array: readonly T[] | undefined, predicate?: (value: T) => boolean): boolean {
if (array) {
if (predicate) {
for (const v of array) {
if (predicate(v)) {
if (array !== undefined) {
if (predicate !== undefined) {
for (let i = 0; i < array.length; i++) {
if (predicate(array[i])) {
return true;
}
}
@@ -713,8 +687,8 @@ export function concatenate<T>(array1: T[] | undefined, array2: T[] | undefined)
export function concatenate<T>(array1: readonly T[] | undefined, array2: readonly T[] | undefined): readonly T[] | undefined;
/** @internal */
export function concatenate<T>(array1: readonly T[] | undefined, array2: readonly T[] | undefined): readonly T[] | undefined {
if (!some(array2)) return array1;
if (!some(array1)) return array2;
if (array2 === undefined || array2.length === 0) return array1;
if (array1 === undefined || array1.length === 0) return array2;
return [...array1, ...array2];
}
@@ -751,8 +725,8 @@ function deduplicateRelational<T>(array: readonly T[], equalityComparer: Equalit
function deduplicateEquality<T>(array: readonly T[], equalityComparer: EqualityComparer<T>) {
const result: T[] = [];
for (const item of array) {
pushIfUnique(result, item, equalityComparer);
for (let i = 0; i < array.length; i++) {
pushIfUnique(result, array[i], equalityComparer);
}
return result;
}
@@ -850,7 +824,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(sort(array, comparer), equalityComparer ?? comparer ?? compareStringsCaseSensitive as any as Comparer<T>);
}
/** @internal */
@@ -866,7 +840,7 @@ export function arrayIsSorted<T>(array: readonly T[], comparer: Comparer<T>) {
/** @internal */
export function arrayIsEqualTo<T>(array1: readonly T[] | undefined, array2: readonly T[] | undefined, equalityComparer: (a: T, b: T, index: number) => boolean = equateValues): boolean {
if (!array1 || !array2) {
if (array1 === undefined || array2 === undefined) {
return array1 === array2;
}
@@ -899,20 +873,20 @@ export function compact<T>(array: readonly T[]): readonly T[]; // eslint-disable
/** @internal */
export function compact<T>(array: readonly T[]): readonly T[] {
let result: T[] | undefined;
if (array) {
if (array !== undefined) {
for (let i = 0; i < array.length; i++) {
const v = array[i];
if (result || !v) {
if (!result) {
result = array.slice(0, i);
}
// Either the result has been initialized (and is looking to collect truthy values separately),
// or we've hit our first falsy value and need to copy over the current stretch of truthy values.
if (result ?? !v) {
result ??= array.slice(0, i);
if (v) {
result.push(v);
}
}
}
}
return result || array;
return result ?? array;
}
/**
@@ -1075,7 +1049,7 @@ export function pushIfUnique<T>(array: T[], toAdd: T, equalityComparer?: Equalit
* @internal
*/
export function appendIfUnique<T>(array: T[] | undefined, toAdd: T, equalityComparer?: EqualityComparer<T>): T[] {
if (array) {
if (array !== undefined) {
pushIfUnique(array, toAdd, equalityComparer);
return array;
}
@@ -1136,7 +1110,7 @@ export function rangeEquals<T>(array1: readonly T[], array2: readonly T[], pos:
export const elementAt: <T>(array: readonly T[] | undefined, offset: number) => T | undefined = !!Array.prototype.at
? (array, offset) => array?.at(offset)
: (array, offset) => {
if (array) {
if (array !== undefined) {
offset = toOffset(array, offset);
if (offset < array.length) {
return array[offset];
@@ -1156,7 +1130,7 @@ export function firstOrUndefined<T>(array: readonly T[] | undefined): T | undefi
/** @internal */
export function firstOrUndefinedIterator<T>(iter: Iterable<T> | undefined): T | undefined {
if (iter) {
if (iter !== undefined) {
for (const value of iter) {
return value;
}
@@ -1199,7 +1173,7 @@ export function last<T>(array: readonly T[]): T {
* @internal
*/
export function singleOrUndefined<T>(array: readonly T[] | undefined): T | undefined {
return array && array.length === 1
return array !== undefined && array.length === 1
? array[0]
: undefined;
}
@@ -1228,7 +1202,7 @@ export function singleOrMany<T>(array: T[] | undefined): T | T[] | undefined;
export function singleOrMany<T>(array: readonly T[] | undefined): T | readonly T[] | undefined;
/** @internal */
export function singleOrMany<T>(array: readonly T[] | undefined): T | readonly T[] | undefined {
return array && array.length === 1
return array !== undefined && array.length === 1
? array[0]
: array;
}
@@ -1274,7 +1248,7 @@ export function binarySearchKey<T, U>(array: readonly T[], key: U, keySelector:
return -1;
}
let low = offset || 0;
let low = offset ?? 0;
let high = array.length - 1;
while (low <= high) {
const middle = low + ((high - low) >> 1);
@@ -1478,7 +1452,8 @@ export function arrayToMap<T, U>(array: readonly T[], makeKey: (value: T) => str
/** @internal */
export function arrayToMap<K, V1, V2>(array: readonly V1[], makeKey: (value: V1) => K | undefined, makeValue: (value: V1) => V1 | V2 = identity): Map<K, V1 | V2> {
const result = new Map<K, V1 | V2>();
for (const value of array) {
for (let i = 0; i < array.length; i++) {
const value = array[i];
const key = makeKey(value);
if (key !== undefined) result.set(key, makeValue(value));
}
@@ -1492,7 +1467,8 @@ export function arrayToNumericMap<T, U>(array: readonly T[], makeKey: (value: T)
/** @internal */
export function arrayToNumericMap<T, U>(array: readonly T[], makeKey: (value: T) => number, makeValue: (value: T) => T | U = identity): (T | U)[] {
const result: (T | U)[] = [];
for (const value of array) {
for (let i = 0; i < array.length; i++) {
const value = array[i];
result[makeKey(value)] = makeValue(value);
}
return result;
@@ -1505,7 +1481,8 @@ export function arrayToMultiMap<K, V, U>(values: readonly V[], makeKey: (value:
/** @internal */
export function arrayToMultiMap<K, V, U>(values: readonly V[], makeKey: (value: V) => K, makeValue: (value: V) => V | U = identity): MultiMap<K, V | U> {
const result = createMultiMap<K, V | U>();
for (const value of values) {
for (let i = 0; i < values.length; i++) {
const value = values[i];
result.add(makeKey(value), makeValue(value));
}
return result;
@@ -1530,8 +1507,9 @@ export function groupBy<T, U extends T>(values: readonly T[] | undefined, keySel
export function groupBy<T, K extends string | number | boolean | null | undefined>(values: readonly T[] | undefined, keySelector: (value: T) => K): { [P in K as `${P}`]?: T[]; }; // eslint-disable-line no-restricted-syntax
export function groupBy<T, K extends string | number | boolean | null | undefined>(values: readonly T[] | undefined, keySelector: (value: T) => K): { [P in K as `${P}`]?: T[]; } { // eslint-disable-line no-restricted-syntax
const result: Record<string, T[]> = {};
if (values) {
for (const value of values) {
if (values !== undefined) {
for (let i = 0; i < values.length; i++) {
const value = values[i];
const key = `${keySelector(value)}`;
const array = result[key] ??= [];
array.push(value);
@@ -1586,7 +1564,7 @@ export function copyProperties<T1 extends T2, T2>(first: T1, second: T2) {
/** @internal */
export function maybeBind<T, A extends any[], R>(obj: T, fn: ((this: T, ...args: A) => R) | undefined): ((...args: A) => R) | undefined {
return fn ? fn.bind(obj) : undefined;
return fn?.bind(obj);
}
/** @internal */
@@ -1613,7 +1591,7 @@ export function createMultiMap<K, V>(): MultiMap<K, V> {
}
function multiMapAdd<K, V>(this: MultiMap<K, V>, key: K, value: V) {
let values = this.get(key);
if (values) {
if (values !== undefined) {
values.push(value);
}
else {
@@ -1623,7 +1601,7 @@ function multiMapAdd<K, V>(this: MultiMap<K, V>, key: K, value: V) {
}
function multiMapRemove<K, V>(this: MultiMap<K, V>, key: K, value: V) {
const values = this.get(key);
if (values) {
if (values !== undefined) {
unorderedRemoveItem(values, value);
if (!values.length) {
this.delete(key);
@@ -1633,7 +1611,7 @@ function multiMapRemove<K, V>(this: MultiMap<K, V>, key: K, value: V) {
/** @internal */
export function createQueue<T>(items?: readonly T[]): Queue<T> {
const elements: (T | undefined)[] = items?.slice() || [];
const elements: (T | undefined)[] = items?.slice() ?? [];
let headIndex = 0;
function isEmpty() {
@@ -1705,14 +1683,9 @@ export function createSet<TElement, THash = number>(getHashCode: (element: TElem
const hash = getHashCode(element);
if (!multiMap.has(hash)) return false;
const candidates = multiMap.get(hash)!;
if (!isArray(candidates)) return equals(candidates, element);
if (isArray(candidates)) return contains(candidates, element, equals);
for (const candidate of candidates) {
if (equals(candidate, element)) {
return true;
}
}
return false;
return equals(candidates, element);
},
add(element: TElement): Set<TElement> {
const hash = getHashCode(element);
@@ -1779,6 +1752,8 @@ export function createSet<TElement, THash = number>(getHashCode: (element: TElem
return size;
},
forEach(action: (value: TElement, key: TElement, set: Set<TElement>) => void): void {
// NOTE: arrayFrom means that if the callback mutates the underlying collection,
// we won't have an accurate set of values
for (const elements of arrayFrom(multiMap.values())) {
if (isArray(elements)) {
for (const element of elements) {
@@ -2145,6 +2120,14 @@ export function compareTextSpans(a: Partial<TextSpan> | undefined, b: Partial<Te
return compareValues(a?.start, b?.start) || compareValues(a?.length, b?.length);
}
/** @internal */
export function maxBy<T>(arr: readonly T[], init: number, mapper: (x: T) => number): number {
for (let i = 0; i < arr.length; i++) {
init = Math.max(init, mapper(arr[i]));
}
return init;
}
/** @internal */
export function min<T>(items: readonly [T, ...T[]], compare: Comparer<T>): T;
/** @internal */
@@ -2270,8 +2253,8 @@ export function setUILocale(value: string | undefined) {
* @internal
*/
export function compareStringsCaseSensitiveUI(a: string, b: string) {
const comparer = uiComparerCaseSensitive || (uiComparerCaseSensitive = createUIStringComparer(uiLocale));
return comparer(a, b);
uiComparerCaseSensitive ??= createUIStringComparer(uiLocale);
return uiComparerCaseSensitive(a, b);
}
/** @internal */
@@ -2554,7 +2537,8 @@ export function findBestPatternMatch<T>(values: readonly T[], getPattern: (value
// use length of prefix as betterness criteria
let longestMatchPrefixLength = -1;
for (const v of values) {
for (let i = 0; i < values.length; i++) {
const v = values[i];
const pattern = getPattern(v);
if (isPatternMatch(pattern, candidate) && pattern.prefix.length > longestMatchPrefixLength) {
longestMatchPrefixLength = pattern.prefix.length;
@@ -2629,7 +2613,7 @@ export function singleElementArray<T>(t: T | undefined): T[] | undefined {
/** @internal */
export function enumerateInsertsAndDeletes<T, U>(newItems: readonly T[], oldItems: readonly U[], comparer: (a: T, b: U) => Comparison, inserted: (newItem: T) => void, deleted: (oldItem: U) => void, unchanged?: (oldItem: U, newItem: T) => void) {
unchanged = unchanged || noop;
unchanged ??= noop;
let newIndex = 0;
let oldIndex = 0;
const newLen = newItems.length;
@@ -2697,7 +2681,7 @@ export function takeWhile<T, U extends T>(array: readonly T[], predicate: (eleme
/** @internal */
export function takeWhile<T, U extends T>(array: readonly T[] | undefined, predicate: (element: T) => element is U): U[] | undefined;
export function takeWhile<T, U extends T>(array: readonly T[] | undefined, predicate: (element: T) => element is U): U[] | undefined {
if (array) {
if (array !== undefined) {
const len = array.length;
let index = 0;
while (index < len && predicate(array[index])) {
@@ -2713,7 +2697,7 @@ export function skipWhile<T, U extends T>(array: readonly T[], predicate: (eleme
export function skipWhile<T, U extends T>(array: readonly T[] | undefined, predicate: (element: T) => element is U): Exclude<T, U>[] | undefined;
/** @internal */
export function skipWhile<T, U extends T>(array: readonly T[] | undefined, predicate: (element: T) => element is U): Exclude<T, U>[] | undefined {
if (array) {
if (array !== undefined) {
const len = array.length;
let index = 0;
while (index < len && predicate(array[index])) {
+2 -1
View File
@@ -61,6 +61,7 @@ import {
LiteralType,
map,
MatchingKeys,
maxBy,
ModifierFlags,
Node,
NodeArray,
@@ -1126,7 +1127,7 @@ m2: ${(this.mapper2 as unknown as DebugTypeMapper).__debugToString().split("\n")
function renderGraph() {
const columnCount = columnWidths.length;
const laneCount = nodes.reduce((x, n) => Math.max(x, n.lane), 0) + 1;
const laneCount = maxBy(nodes, 0, n => n.lane) + 1;
const lanes: string[] = fill(Array(laneCount), "");
const grid: (FlowGraphNode | undefined)[][] = columnWidths.map(() => Array(laneCount));
const connectors: Connection[][] = columnWidths.map(() => fill(Array(laneCount), 0));
+2 -2
View File
@@ -1,6 +1,6 @@
import {
append,
arraysEqual,
arrayIsEqualTo,
binarySearch,
CharacterCodes,
CommentDirective,
@@ -475,7 +475,7 @@ export function computePositionOfLineAndCharacter(lineStarts: readonly number[],
line = line < 0 ? 0 : line >= lineStarts.length ? lineStarts.length - 1 : line;
}
else {
Debug.fail(`Bad line number. Line: ${line}, lineStarts.length: ${lineStarts.length} , line map is correct? ${debugText !== undefined ? arraysEqual(lineStarts, computeLineStarts(debugText)) : "unknown"}`);
Debug.fail(`Bad line number. Line: ${line}, lineStarts.length: ${lineStarts.length} , line map is correct? ${debugText !== undefined ? arrayIsEqualTo(lineStarts, computeLineStarts(debugText)) : "unknown"}`);
}
}
+2 -1
View File
@@ -73,6 +73,7 @@ import {
isReferenceFileLocation,
isString,
last,
maxBy,
maybeBind,
memoize,
ModuleKind,
@@ -304,7 +305,7 @@ function createTabularErrorsDisplay(filesInError: (ReportFileInError | undefined
const numberLength = (num: number) => Math.log(num) * Math.LOG10E + 1;
const fileToErrorCount = distinctFiles.map(file => ([file, countWhere(filesInError, fileInError => fileInError!.fileName === file!.fileName)] as const));
const maxErrors = fileToErrorCount.reduce((acc, value) => Math.max(acc, value[1] || 0), 0);
const maxErrors = maxBy(fileToErrorCount, 0, value => value[1]);
const headerRow = Diagnostics.Errors_Files.message;
const leftColumnHeadingLength = headerRow.split(" ")[0].length;
+5 -10
View File
@@ -2673,17 +2673,12 @@ export class TestState {
if (info === undefined) return "No completion info.";
const { entries } = info;
function pad(s: string, length: number) {
return s + new Array(length - s.length + 1).join(" ");
}
function max<T>(arr: T[], selector: (x: T) => number): number {
return arr.reduce((prev, x) => Math.max(prev, selector(x)), 0);
}
const longestNameLength = max(entries, m => m.name.length);
const longestKindLength = max(entries, m => m.kind.length);
const longestNameLength = ts.maxBy(entries, 0, m => m.name.length);
const longestKindLength = ts.maxBy(entries, 0, m => m.kind.length);
entries.sort((m, n) => m.sortText > n.sortText ? 1 : m.sortText < n.sortText ? -1 : m.name > n.name ? 1 : m.name < n.name ? -1 : 0);
const membersString = entries.map(m => `${pad(m.name, longestNameLength)} ${pad(m.kind, longestKindLength)} ${m.kindModifiers} ${m.isRecommended ? "recommended " : ""}${m.source === undefined ? "" : m.source}`).join("\n");
Harness.IO.log(membersString);
const formattedEntries = entries.map(m => `${m.name.padEnd(longestNameLength)} ${m.kind.padEnd(longestKindLength)} ${m.kindModifiers} ${m.isRecommended ? "recommended " : ""}${m.source ?? ""}`);
Harness.IO.log(formattedEntries.join("\n"));
}
public printContext() {
+6 -6
View File
@@ -77,7 +77,6 @@ import {
LanguageServiceMode,
length,
map,
mapDefinedEntries,
mapDefinedIterator,
missingFileModifiedTime,
MultiMap,
@@ -4347,14 +4346,15 @@ export class ProjectService {
/** @internal */
loadAncestorProjectTree(forProjects?: ReadonlyCollection<string>) {
forProjects = forProjects || mapDefinedEntries(
this.configuredProjects,
(key, project) => !project.isInitialLoadPending() ? [key, true] : undefined,
forProjects ??= new Set(
mapDefinedIterator(this.configuredProjects.entries(), ([key, project]) => !project.isInitialLoadPending() ? key : undefined),
);
const seenProjects = new Set<NormalizedPath>();
// Work on array copy as we could add more projects as part of callback
for (const project of arrayFrom(this.configuredProjects.values())) {
// We must copy the current configured projects into a separate array,
// as we could end up creating and adding more projects indirectly.
const currentConfiguredProjects = arrayFrom(this.configuredProjects.values());
for (const project of currentConfiguredProjects) {
// If this project has potential project reference for any of the project we are loading ancestor tree for
// load this project first
if (forEachPotentialProjectReference(project, potentialRefPath => forProjects.has(potentialRefPath))) {
+2 -2
View File
@@ -1,5 +1,5 @@
import {
arraysEqual,
arrayIsEqualTo,
ArrowFunction,
AssignmentDeclarationKind,
BinaryExpression,
@@ -222,7 +222,7 @@ export function getJsDocCommentsFromDeclarations(declarations: readonly Declarat
}
function isIdenticalListOfDisplayParts(parts1: SymbolDisplayPart[], parts2: SymbolDisplayPart[]) {
return arraysEqual(parts1, parts2, (p1, p2) => p1.kind === p2.kind && p1.text === p2.text);
return arrayIsEqualTo(parts1, parts2, (p1, p2) => p1.kind === p2.kind && p1.text === p2.text);
}
function getCommentHavingNodes(declaration: Declaration): readonly (JSDoc | JSDocTag)[] {