Initial Sample.

This commit is contained in:
2024-06-03 20:23:50 +05:30
parent ef2b65f673
commit 5269ec3c66
2575 changed files with 282312 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
/** Conveniently represents flow's "Maybe" type https://flow.org/en/docs/types/maybe/ */
export declare type Maybe<T> = null | undefined | T;

View File

@@ -0,0 +1,5 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,16 @@
export interface ObjMap<T> {
[key: string]: T;
}
export declare type ObjMapLike<T> =
| ObjMap<T>
| {
[key: string]: T;
};
export interface ReadOnlyObjMap<T> {
readonly [key: string]: T;
}
export declare type ReadOnlyObjMapLike<T> =
| ReadOnlyObjMap<T>
| {
readonly [key: string]: T;
};

View File

@@ -0,0 +1,5 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,20 @@
import type { Maybe } from './Maybe';
export interface Path {
readonly prev: Path | undefined;
readonly key: string | number;
readonly typename: string | undefined;
}
/**
* Given a Path and a key, return a new Path containing the new key.
*/
export declare function addPath(
prev: Readonly<Path> | undefined,
key: string | number,
typename: string | undefined,
): Path;
/**
* Given a Path, return an Array of the path keys.
*/
export declare function pathToArray(
path: Maybe<Readonly<Path>>,
): Array<string | number>;

View File

@@ -0,0 +1,33 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.addPath = addPath;
exports.pathToArray = pathToArray;
/**
* Given a Path and a key, return a new Path containing the new key.
*/
function addPath(prev, key, typename) {
return {
prev,
key,
typename,
};
}
/**
* Given a Path, return an Array of the path keys.
*/
function pathToArray(path) {
const flattened = [];
let curr = path;
while (curr) {
flattened.push(curr.key);
curr = curr.prev;
}
return flattened.reverse();
}

View File

@@ -0,0 +1,25 @@
/**
* Given a Path and a key, return a new Path containing the new key.
*/
export function addPath(prev, key, typename) {
return {
prev,
key,
typename,
};
}
/**
* Given a Path, return an Array of the path keys.
*/
export function pathToArray(path) {
const flattened = [];
let curr = path;
while (curr) {
flattened.push(curr.key);
curr = curr.prev;
}
return flattened.reverse();
}

View File

@@ -0,0 +1 @@
export declare type PromiseOrValue<T> = Promise<T> | T;

View File

@@ -0,0 +1,5 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1 @@
export declare function devAssert(condition: unknown, message: string): void;

View File

@@ -0,0 +1,14 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.devAssert = devAssert;
function devAssert(condition, message) {
const booleanCondition = Boolean(condition);
if (!booleanCondition) {
throw new Error(message);
}
}

View File

@@ -0,0 +1,7 @@
export function devAssert(condition, message) {
const booleanCondition = Boolean(condition);
if (!booleanCondition) {
throw new Error(message);
}
}

View File

@@ -0,0 +1,8 @@
/**
* Given [ A, B, C ] return ' Did you mean A, B, or C?'.
*/
export declare function didYouMean(suggestions: ReadonlyArray<string>): string;
export declare function didYouMean(
subMessage: string,
suggestions: ReadonlyArray<string>,
): string;

View File

@@ -0,0 +1,38 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.didYouMean = didYouMean;
const MAX_SUGGESTIONS = 5;
/**
* Given [ A, B, C ] return ' Did you mean A, B, or C?'.
*/
function didYouMean(firstArg, secondArg) {
const [subMessage, suggestionsArg] = secondArg
? [firstArg, secondArg]
: [undefined, firstArg];
let message = ' Did you mean ';
if (subMessage) {
message += subMessage + ' ';
}
const suggestions = suggestionsArg.map((x) => `"${x}"`);
switch (suggestions.length) {
case 0:
return '';
case 1:
return message + suggestions[0] + '?';
case 2:
return message + suggestions[0] + ' or ' + suggestions[1] + '?';
}
const selected = suggestions.slice(0, MAX_SUGGESTIONS);
const lastItem = selected.pop();
return message + selected.join(', ') + ', or ' + lastItem + '?';
}

View File

@@ -0,0 +1,32 @@
const MAX_SUGGESTIONS = 5;
/**
* Given [ A, B, C ] return ' Did you mean A, B, or C?'.
*/
export function didYouMean(firstArg, secondArg) {
const [subMessage, suggestionsArg] = secondArg
? [firstArg, secondArg]
: [undefined, firstArg];
let message = ' Did you mean ';
if (subMessage) {
message += subMessage + ' ';
}
const suggestions = suggestionsArg.map((x) => `"${x}"`);
switch (suggestions.length) {
case 0:
return '';
case 1:
return message + suggestions[0] + '?';
case 2:
return message + suggestions[0] + ' or ' + suggestions[1] + '?';
}
const selected = suggestions.slice(0, MAX_SUGGESTIONS);
const lastItem = selected.pop();
return message + selected.join(', ') + ', or ' + lastItem + '?';
}

View File

@@ -0,0 +1,7 @@
/**
* Groups array items into a Map, given a function to produce grouping key.
*/
export declare function groupBy<K, T>(
list: ReadonlyArray<T>,
keyFn: (item: T) => K,
): Map<K, ReadonlyArray<T>>;

View File

@@ -0,0 +1,26 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.groupBy = groupBy;
/**
* Groups array items into a Map, given a function to produce grouping key.
*/
function groupBy(list, keyFn) {
const result = new Map();
for (const item of list) {
const key = keyFn(item);
const group = result.get(key);
if (group === undefined) {
result.set(key, [item]);
} else {
group.push(item);
}
}
return result;
}

View File

@@ -0,0 +1,19 @@
/**
* Groups array items into a Map, given a function to produce grouping key.
*/
export function groupBy(list, keyFn) {
const result = new Map();
for (const item of list) {
const key = keyFn(item);
const group = result.get(key);
if (group === undefined) {
result.set(key, [item]);
} else {
group.push(item);
}
}
return result;
}

View File

@@ -0,0 +1,4 @@
/**
* Returns the first argument it receives.
*/
export declare function identityFunc<T>(x: T): T;

View File

@@ -0,0 +1,13 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.identityFunc = identityFunc;
/**
* Returns the first argument it receives.
*/
function identityFunc(x) {
return x;
}

View File

@@ -0,0 +1,6 @@
/**
* Returns the first argument it receives.
*/
export function identityFunc(x) {
return x;
}

View File

@@ -0,0 +1,4 @@
/**
* Used to print values in error messages.
*/
export declare function inspect(value: unknown): string;

View File

@@ -0,0 +1,121 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.inspect = inspect;
const MAX_ARRAY_LENGTH = 10;
const MAX_RECURSIVE_DEPTH = 2;
/**
* Used to print values in error messages.
*/
function inspect(value) {
return formatValue(value, []);
}
function formatValue(value, seenValues) {
switch (typeof value) {
case 'string':
return JSON.stringify(value);
case 'function':
return value.name ? `[function ${value.name}]` : '[function]';
case 'object':
return formatObjectValue(value, seenValues);
default:
return String(value);
}
}
function formatObjectValue(value, previouslySeenValues) {
if (value === null) {
return 'null';
}
if (previouslySeenValues.includes(value)) {
return '[Circular]';
}
const seenValues = [...previouslySeenValues, value];
if (isJSONable(value)) {
const jsonValue = value.toJSON(); // check for infinite recursion
if (jsonValue !== value) {
return typeof jsonValue === 'string'
? jsonValue
: formatValue(jsonValue, seenValues);
}
} else if (Array.isArray(value)) {
return formatArray(value, seenValues);
}
return formatObject(value, seenValues);
}
function isJSONable(value) {
return typeof value.toJSON === 'function';
}
function formatObject(object, seenValues) {
const entries = Object.entries(object);
if (entries.length === 0) {
return '{}';
}
if (seenValues.length > MAX_RECURSIVE_DEPTH) {
return '[' + getObjectTag(object) + ']';
}
const properties = entries.map(
([key, value]) => key + ': ' + formatValue(value, seenValues),
);
return '{ ' + properties.join(', ') + ' }';
}
function formatArray(array, seenValues) {
if (array.length === 0) {
return '[]';
}
if (seenValues.length > MAX_RECURSIVE_DEPTH) {
return '[Array]';
}
const len = Math.min(MAX_ARRAY_LENGTH, array.length);
const remaining = array.length - len;
const items = [];
for (let i = 0; i < len; ++i) {
items.push(formatValue(array[i], seenValues));
}
if (remaining === 1) {
items.push('... 1 more item');
} else if (remaining > 1) {
items.push(`... ${remaining} more items`);
}
return '[' + items.join(', ') + ']';
}
function getObjectTag(object) {
const tag = Object.prototype.toString
.call(object)
.replace(/^\[object /, '')
.replace(/]$/, '');
if (tag === 'Object' && typeof object.constructor === 'function') {
const name = object.constructor.name;
if (typeof name === 'string' && name !== '') {
return name;
}
}
return tag;
}

View File

@@ -0,0 +1,115 @@
const MAX_ARRAY_LENGTH = 10;
const MAX_RECURSIVE_DEPTH = 2;
/**
* Used to print values in error messages.
*/
export function inspect(value) {
return formatValue(value, []);
}
function formatValue(value, seenValues) {
switch (typeof value) {
case 'string':
return JSON.stringify(value);
case 'function':
return value.name ? `[function ${value.name}]` : '[function]';
case 'object':
return formatObjectValue(value, seenValues);
default:
return String(value);
}
}
function formatObjectValue(value, previouslySeenValues) {
if (value === null) {
return 'null';
}
if (previouslySeenValues.includes(value)) {
return '[Circular]';
}
const seenValues = [...previouslySeenValues, value];
if (isJSONable(value)) {
const jsonValue = value.toJSON(); // check for infinite recursion
if (jsonValue !== value) {
return typeof jsonValue === 'string'
? jsonValue
: formatValue(jsonValue, seenValues);
}
} else if (Array.isArray(value)) {
return formatArray(value, seenValues);
}
return formatObject(value, seenValues);
}
function isJSONable(value) {
return typeof value.toJSON === 'function';
}
function formatObject(object, seenValues) {
const entries = Object.entries(object);
if (entries.length === 0) {
return '{}';
}
if (seenValues.length > MAX_RECURSIVE_DEPTH) {
return '[' + getObjectTag(object) + ']';
}
const properties = entries.map(
([key, value]) => key + ': ' + formatValue(value, seenValues),
);
return '{ ' + properties.join(', ') + ' }';
}
function formatArray(array, seenValues) {
if (array.length === 0) {
return '[]';
}
if (seenValues.length > MAX_RECURSIVE_DEPTH) {
return '[Array]';
}
const len = Math.min(MAX_ARRAY_LENGTH, array.length);
const remaining = array.length - len;
const items = [];
for (let i = 0; i < len; ++i) {
items.push(formatValue(array[i], seenValues));
}
if (remaining === 1) {
items.push('... 1 more item');
} else if (remaining > 1) {
items.push(`... ${remaining} more items`);
}
return '[' + items.join(', ') + ']';
}
function getObjectTag(object) {
const tag = Object.prototype.toString
.call(object)
.replace(/^\[object /, '')
.replace(/]$/, '');
if (tag === 'Object' && typeof object.constructor === 'function') {
const name = object.constructor.name;
if (typeof name === 'string' && name !== '') {
return name;
}
}
return tag;
}

View File

@@ -0,0 +1,16 @@
/**
* A replacement for instanceof which includes an error warning when multi-realm
* constructors are detected.
* See: https://expressjs.com/en/advanced/best-practice-performance.html#set-node_env-to-production
* See: https://webpack.js.org/guides/production/
*/
export declare const instanceOf: (
value: unknown,
constructor: Constructor,
) => boolean;
interface Constructor extends Function {
prototype: {
[Symbol.toStringTag]: string;
};
}
export {};

View File

@@ -0,0 +1,60 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.instanceOf = void 0;
var _inspect = require('./inspect.js');
/**
* A replacement for instanceof which includes an error warning when multi-realm
* constructors are detected.
* See: https://expressjs.com/en/advanced/best-practice-performance.html#set-node_env-to-production
* See: https://webpack.js.org/guides/production/
*/
const instanceOf =
/* c8 ignore next 6 */
// FIXME: https://github.com/graphql/graphql-js/issues/2317
globalThis.process && globalThis.process.env.NODE_ENV === 'production'
? function instanceOf(value, constructor) {
return value instanceof constructor;
}
: function instanceOf(value, constructor) {
if (value instanceof constructor) {
return true;
}
if (typeof value === 'object' && value !== null) {
var _value$constructor;
// Prefer Symbol.toStringTag since it is immune to minification.
const className = constructor.prototype[Symbol.toStringTag];
const valueClassName = // We still need to support constructor's name to detect conflicts with older versions of this library.
Symbol.toStringTag in value // @ts-expect-error TS bug see, https://github.com/microsoft/TypeScript/issues/38009
? value[Symbol.toStringTag]
: (_value$constructor = value.constructor) === null ||
_value$constructor === void 0
? void 0
: _value$constructor.name;
if (className === valueClassName) {
const stringifiedValue = (0, _inspect.inspect)(value);
throw new Error(`Cannot use ${className} "${stringifiedValue}" from another module or realm.
Ensure that there is only one instance of "graphql" in the node_modules
directory. If different versions of "graphql" are the dependencies of other
relied on modules, use "resolutions" to ensure only one version is installed.
https://yarnpkg.com/en/docs/selective-version-resolutions
Duplicate "graphql" modules cannot be used at the same time since different
versions may have different capabilities and behavior. The data from one
version used in the function from another could produce confusing and
spurious results.`);
}
}
return false;
};
exports.instanceOf = instanceOf;

View File

@@ -0,0 +1,52 @@
import { inspect } from './inspect.mjs';
/**
* A replacement for instanceof which includes an error warning when multi-realm
* constructors are detected.
* See: https://expressjs.com/en/advanced/best-practice-performance.html#set-node_env-to-production
* See: https://webpack.js.org/guides/production/
*/
export const instanceOf =
/* c8 ignore next 6 */
// FIXME: https://github.com/graphql/graphql-js/issues/2317
globalThis.process && globalThis.process.env.NODE_ENV === 'production'
? function instanceOf(value, constructor) {
return value instanceof constructor;
}
: function instanceOf(value, constructor) {
if (value instanceof constructor) {
return true;
}
if (typeof value === 'object' && value !== null) {
var _value$constructor;
// Prefer Symbol.toStringTag since it is immune to minification.
const className = constructor.prototype[Symbol.toStringTag];
const valueClassName = // We still need to support constructor's name to detect conflicts with older versions of this library.
Symbol.toStringTag in value // @ts-expect-error TS bug see, https://github.com/microsoft/TypeScript/issues/38009
? value[Symbol.toStringTag]
: (_value$constructor = value.constructor) === null ||
_value$constructor === void 0
? void 0
: _value$constructor.name;
if (className === valueClassName) {
const stringifiedValue = inspect(value);
throw new Error(`Cannot use ${className} "${stringifiedValue}" from another module or realm.
Ensure that there is only one instance of "graphql" in the node_modules
directory. If different versions of "graphql" are the dependencies of other
relied on modules, use "resolutions" to ensure only one version is installed.
https://yarnpkg.com/en/docs/selective-version-resolutions
Duplicate "graphql" modules cannot be used at the same time since different
versions may have different capabilities and behavior. The data from one
version used in the function from another could produce confusing and
spurious results.`);
}
}
return false;
};

View File

@@ -0,0 +1,4 @@
export declare function invariant(
condition: unknown,
message?: string,
): asserts condition;

View File

@@ -0,0 +1,16 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.invariant = invariant;
function invariant(condition, message) {
const booleanCondition = Boolean(condition);
if (!booleanCondition) {
throw new Error(
message != null ? message : 'Unexpected invariant triggered.',
);
}
}

View File

@@ -0,0 +1,9 @@
export function invariant(condition, message) {
const booleanCondition = Boolean(condition);
if (!booleanCondition) {
throw new Error(
message != null ? message : 'Unexpected invariant triggered.',
);
}
}

View File

@@ -0,0 +1,7 @@
/**
* Returns true if the provided object implements the AsyncIterator protocol via
* implementing a `Symbol.asyncIterator` method.
*/
export declare function isAsyncIterable(
maybeAsyncIterable: any,
): maybeAsyncIterable is AsyncIterable<unknown>;

View File

@@ -0,0 +1,18 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.isAsyncIterable = isAsyncIterable;
/**
* Returns true if the provided object implements the AsyncIterator protocol via
* implementing a `Symbol.asyncIterator` method.
*/
function isAsyncIterable(maybeAsyncIterable) {
return (
typeof (maybeAsyncIterable === null || maybeAsyncIterable === void 0
? void 0
: maybeAsyncIterable[Symbol.asyncIterator]) === 'function'
);
}

View File

@@ -0,0 +1,11 @@
/**
* Returns true if the provided object implements the AsyncIterator protocol via
* implementing a `Symbol.asyncIterator` method.
*/
export function isAsyncIterable(maybeAsyncIterable) {
return (
typeof (maybeAsyncIterable === null || maybeAsyncIterable === void 0
? void 0
: maybeAsyncIterable[Symbol.asyncIterator]) === 'function'
);
}

View File

@@ -0,0 +1,20 @@
/**
* Returns true if the provided object is an Object (i.e. not a string literal)
* and implements the Iterator protocol.
*
* This may be used in place of [Array.isArray()][isArray] to determine if
* an object should be iterated-over e.g. Array, Map, Set, Int8Array,
* TypedArray, etc. but excludes string literals.
*
* @example
* ```ts
* isIterableObject([ 1, 2, 3 ]) // true
* isIterableObject(new Map()) // true
* isIterableObject('ABC') // false
* isIterableObject({ key: 'value' }) // false
* isIterableObject({ length: 1, 0: 'Alpha' }) // false
* ```
*/
export declare function isIterableObject(
maybeIterable: any,
): maybeIterable is Iterable<unknown>;

View File

@@ -0,0 +1,32 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.isIterableObject = isIterableObject;
/**
* Returns true if the provided object is an Object (i.e. not a string literal)
* and implements the Iterator protocol.
*
* This may be used in place of [Array.isArray()][isArray] to determine if
* an object should be iterated-over e.g. Array, Map, Set, Int8Array,
* TypedArray, etc. but excludes string literals.
*
* @example
* ```ts
* isIterableObject([ 1, 2, 3 ]) // true
* isIterableObject(new Map()) // true
* isIterableObject('ABC') // false
* isIterableObject({ key: 'value' }) // false
* isIterableObject({ length: 1, 0: 'Alpha' }) // false
* ```
*/
function isIterableObject(maybeIterable) {
return (
typeof maybeIterable === 'object' &&
typeof (maybeIterable === null || maybeIterable === void 0
? void 0
: maybeIterable[Symbol.iterator]) === 'function'
);
}

View File

@@ -0,0 +1,25 @@
/**
* Returns true if the provided object is an Object (i.e. not a string literal)
* and implements the Iterator protocol.
*
* This may be used in place of [Array.isArray()][isArray] to determine if
* an object should be iterated-over e.g. Array, Map, Set, Int8Array,
* TypedArray, etc. but excludes string literals.
*
* @example
* ```ts
* isIterableObject([ 1, 2, 3 ]) // true
* isIterableObject(new Map()) // true
* isIterableObject('ABC') // false
* isIterableObject({ key: 'value' }) // false
* isIterableObject({ length: 1, 0: 'Alpha' }) // false
* ```
*/
export function isIterableObject(maybeIterable) {
return (
typeof maybeIterable === 'object' &&
typeof (maybeIterable === null || maybeIterable === void 0
? void 0
: maybeIterable[Symbol.iterator]) === 'function'
);
}

View File

@@ -0,0 +1,7 @@
/**
* Return true if `value` is object-like. A value is object-like if it's not
* `null` and has a `typeof` result of "object".
*/
export declare function isObjectLike(value: unknown): value is {
[key: string]: unknown;
};

View File

@@ -0,0 +1,14 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.isObjectLike = isObjectLike;
/**
* Return true if `value` is object-like. A value is object-like if it's not
* `null` and has a `typeof` result of "object".
*/
function isObjectLike(value) {
return typeof value == 'object' && value !== null;
}

View File

@@ -0,0 +1,7 @@
/**
* Return true if `value` is object-like. A value is object-like if it's not
* `null` and has a `typeof` result of "object".
*/
export function isObjectLike(value) {
return typeof value == 'object' && value !== null;
}

View File

@@ -0,0 +1,5 @@
/**
* Returns true if the value acts like a Promise, i.e. has a "then" function,
* otherwise returns false.
*/
export declare function isPromise(value: any): value is Promise<unknown>;

View File

@@ -0,0 +1,17 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.isPromise = isPromise;
/**
* Returns true if the value acts like a Promise, i.e. has a "then" function,
* otherwise returns false.
*/
function isPromise(value) {
return (
typeof (value === null || value === void 0 ? void 0 : value.then) ===
'function'
);
}

View File

@@ -0,0 +1,10 @@
/**
* Returns true if the value acts like a Promise, i.e. has a "then" function,
* otherwise returns false.
*/
export function isPromise(value) {
return (
typeof (value === null || value === void 0 ? void 0 : value.then) ===
'function'
);
}

View File

@@ -0,0 +1,32 @@
import type { ObjMap } from './ObjMap';
/**
* Creates a keyed JS object from an array, given a function to produce the keys
* for each value in the array.
*
* This provides a convenient lookup for the array items if the key function
* produces unique results.
* ```ts
* const phoneBook = [
* { name: 'Jon', num: '555-1234' },
* { name: 'Jenny', num: '867-5309' }
* ]
*
* const entriesByName = keyMap(
* phoneBook,
* entry => entry.name
* )
*
* // {
* // Jon: { name: 'Jon', num: '555-1234' },
* // Jenny: { name: 'Jenny', num: '867-5309' }
* // }
*
* const jennyEntry = entriesByName['Jenny']
*
* // { name: 'Jenny', num: '857-6309' }
* ```
*/
export declare function keyMap<T>(
list: ReadonlyArray<T>,
keyFn: (item: T) => string,
): ObjMap<T>;

View File

@@ -0,0 +1,43 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.keyMap = keyMap;
/**
* Creates a keyed JS object from an array, given a function to produce the keys
* for each value in the array.
*
* This provides a convenient lookup for the array items if the key function
* produces unique results.
* ```ts
* const phoneBook = [
* { name: 'Jon', num: '555-1234' },
* { name: 'Jenny', num: '867-5309' }
* ]
*
* const entriesByName = keyMap(
* phoneBook,
* entry => entry.name
* )
*
* // {
* // Jon: { name: 'Jon', num: '555-1234' },
* // Jenny: { name: 'Jenny', num: '867-5309' }
* // }
*
* const jennyEntry = entriesByName['Jenny']
*
* // { name: 'Jenny', num: '857-6309' }
* ```
*/
function keyMap(list, keyFn) {
const result = Object.create(null);
for (const item of list) {
result[keyFn(item)] = item;
}
return result;
}

View File

@@ -0,0 +1,36 @@
/**
* Creates a keyed JS object from an array, given a function to produce the keys
* for each value in the array.
*
* This provides a convenient lookup for the array items if the key function
* produces unique results.
* ```ts
* const phoneBook = [
* { name: 'Jon', num: '555-1234' },
* { name: 'Jenny', num: '867-5309' }
* ]
*
* const entriesByName = keyMap(
* phoneBook,
* entry => entry.name
* )
*
* // {
* // Jon: { name: 'Jon', num: '555-1234' },
* // Jenny: { name: 'Jenny', num: '867-5309' }
* // }
*
* const jennyEntry = entriesByName['Jenny']
*
* // { name: 'Jenny', num: '857-6309' }
* ```
*/
export function keyMap(list, keyFn) {
const result = Object.create(null);
for (const item of list) {
result[keyFn(item)] = item;
}
return result;
}

View File

@@ -0,0 +1,23 @@
import type { ObjMap } from './ObjMap';
/**
* Creates a keyed JS object from an array, given a function to produce the keys
* and a function to produce the values from each item in the array.
* ```ts
* const phoneBook = [
* { name: 'Jon', num: '555-1234' },
* { name: 'Jenny', num: '867-5309' }
* ]
*
* // { Jon: '555-1234', Jenny: '867-5309' }
* const phonesByName = keyValMap(
* phoneBook,
* entry => entry.name,
* entry => entry.num
* )
* ```
*/
export declare function keyValMap<T, V>(
list: ReadonlyArray<T>,
keyFn: (item: T) => string,
valFn: (item: T) => V,
): ObjMap<V>;

View File

@@ -0,0 +1,33 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.keyValMap = keyValMap;
/**
* Creates a keyed JS object from an array, given a function to produce the keys
* and a function to produce the values from each item in the array.
* ```ts
* const phoneBook = [
* { name: 'Jon', num: '555-1234' },
* { name: 'Jenny', num: '867-5309' }
* ]
*
* // { Jon: '555-1234', Jenny: '867-5309' }
* const phonesByName = keyValMap(
* phoneBook,
* entry => entry.name,
* entry => entry.num
* )
* ```
*/
function keyValMap(list, keyFn, valFn) {
const result = Object.create(null);
for (const item of list) {
result[keyFn(item)] = valFn(item);
}
return result;
}

View File

@@ -0,0 +1,26 @@
/**
* Creates a keyed JS object from an array, given a function to produce the keys
* and a function to produce the values from each item in the array.
* ```ts
* const phoneBook = [
* { name: 'Jon', num: '555-1234' },
* { name: 'Jenny', num: '867-5309' }
* ]
*
* // { Jon: '555-1234', Jenny: '867-5309' }
* const phonesByName = keyValMap(
* phoneBook,
* entry => entry.name,
* entry => entry.num
* )
* ```
*/
export function keyValMap(list, keyFn, valFn) {
const result = Object.create(null);
for (const item of list) {
result[keyFn(item)] = valFn(item);
}
return result;
}

View File

@@ -0,0 +1,9 @@
import type { ObjMap, ReadOnlyObjMap } from './ObjMap';
/**
* Creates an object map with the same keys as `map` and values generated by
* running each value of `map` thru `fn`.
*/
export declare function mapValue<T, V>(
map: ReadOnlyObjMap<T>,
fn: (value: T, key: string) => V,
): ObjMap<V>;

View File

@@ -0,0 +1,20 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.mapValue = mapValue;
/**
* Creates an object map with the same keys as `map` and values generated by
* running each value of `map` thru `fn`.
*/
function mapValue(map, fn) {
const result = Object.create(null);
for (const key of Object.keys(map)) {
result[key] = fn(map[key], key);
}
return result;
}

View File

@@ -0,0 +1,13 @@
/**
* Creates an object map with the same keys as `map` and values generated by
* running each value of `map` thru `fn`.
*/
export function mapValue(map, fn) {
const result = Object.create(null);
for (const key of Object.keys(map)) {
result[key] = fn(map[key], key);
}
return result;
}

View File

@@ -0,0 +1,9 @@
/**
* Memoizes the provided three-argument function.
*/
export declare function memoize3<
A1 extends object,
A2 extends object,
A3 extends object,
R,
>(fn: (a1: A1, a2: A2, a3: A3) => R): (a1: A1, a2: A2, a3: A3) => R;

View File

@@ -0,0 +1,41 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.memoize3 = memoize3;
/**
* Memoizes the provided three-argument function.
*/
function memoize3(fn) {
let cache0;
return function memoized(a1, a2, a3) {
if (cache0 === undefined) {
cache0 = new WeakMap();
}
let cache1 = cache0.get(a1);
if (cache1 === undefined) {
cache1 = new WeakMap();
cache0.set(a1, cache1);
}
let cache2 = cache1.get(a2);
if (cache2 === undefined) {
cache2 = new WeakMap();
cache1.set(a2, cache2);
}
let fnResult = cache2.get(a3);
if (fnResult === undefined) {
fnResult = fn(a1, a2, a3);
cache2.set(a3, fnResult);
}
return fnResult;
};
}

View File

@@ -0,0 +1,34 @@
/**
* Memoizes the provided three-argument function.
*/
export function memoize3(fn) {
let cache0;
return function memoized(a1, a2, a3) {
if (cache0 === undefined) {
cache0 = new WeakMap();
}
let cache1 = cache0.get(a1);
if (cache1 === undefined) {
cache1 = new WeakMap();
cache0.set(a1, cache1);
}
let cache2 = cache1.get(a2);
if (cache2 === undefined) {
cache2 = new WeakMap();
cache1.set(a2, cache2);
}
let fnResult = cache2.get(a3);
if (fnResult === undefined) {
fnResult = fn(a1, a2, a3);
cache2.set(a3, fnResult);
}
return fnResult;
};
}

View File

@@ -0,0 +1,8 @@
/**
* Returns a number indicating whether a reference string comes before, or after,
* or is the same as the given string in natural sort order.
*
* See: https://en.wikipedia.org/wiki/Natural_sort_order
*
*/
export declare function naturalCompare(aStr: string, bStr: string): number;

View File

@@ -0,0 +1,69 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.naturalCompare = naturalCompare;
/**
* Returns a number indicating whether a reference string comes before, or after,
* or is the same as the given string in natural sort order.
*
* See: https://en.wikipedia.org/wiki/Natural_sort_order
*
*/
function naturalCompare(aStr, bStr) {
let aIndex = 0;
let bIndex = 0;
while (aIndex < aStr.length && bIndex < bStr.length) {
let aChar = aStr.charCodeAt(aIndex);
let bChar = bStr.charCodeAt(bIndex);
if (isDigit(aChar) && isDigit(bChar)) {
let aNum = 0;
do {
++aIndex;
aNum = aNum * 10 + aChar - DIGIT_0;
aChar = aStr.charCodeAt(aIndex);
} while (isDigit(aChar) && aNum > 0);
let bNum = 0;
do {
++bIndex;
bNum = bNum * 10 + bChar - DIGIT_0;
bChar = bStr.charCodeAt(bIndex);
} while (isDigit(bChar) && bNum > 0);
if (aNum < bNum) {
return -1;
}
if (aNum > bNum) {
return 1;
}
} else {
if (aChar < bChar) {
return -1;
}
if (aChar > bChar) {
return 1;
}
++aIndex;
++bIndex;
}
}
return aStr.length - bStr.length;
}
const DIGIT_0 = 48;
const DIGIT_9 = 57;
function isDigit(code) {
return !isNaN(code) && DIGIT_0 <= code && code <= DIGIT_9;
}

View File

@@ -0,0 +1,61 @@
/**
* Returns a number indicating whether a reference string comes before, or after,
* or is the same as the given string in natural sort order.
*
* See: https://en.wikipedia.org/wiki/Natural_sort_order
*
*/
export function naturalCompare(aStr, bStr) {
let aIndex = 0;
let bIndex = 0;
while (aIndex < aStr.length && bIndex < bStr.length) {
let aChar = aStr.charCodeAt(aIndex);
let bChar = bStr.charCodeAt(bIndex);
if (isDigit(aChar) && isDigit(bChar)) {
let aNum = 0;
do {
++aIndex;
aNum = aNum * 10 + aChar - DIGIT_0;
aChar = aStr.charCodeAt(aIndex);
} while (isDigit(aChar) && aNum > 0);
let bNum = 0;
do {
++bIndex;
bNum = bNum * 10 + bChar - DIGIT_0;
bChar = bStr.charCodeAt(bIndex);
} while (isDigit(bChar) && bNum > 0);
if (aNum < bNum) {
return -1;
}
if (aNum > bNum) {
return 1;
}
} else {
if (aChar < bChar) {
return -1;
}
if (aChar > bChar) {
return 1;
}
++aIndex;
++bIndex;
}
}
return aStr.length - bStr.length;
}
const DIGIT_0 = 48;
const DIGIT_9 = 57;
function isDigit(code) {
return !isNaN(code) && DIGIT_0 <= code && code <= DIGIT_9;
}

View File

@@ -0,0 +1,6 @@
/**
* Build a string describing the path.
*/
export declare function printPathArray(
path: ReadonlyArray<string | number>,
): string;

View File

@@ -0,0 +1,17 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.printPathArray = printPathArray;
/**
* Build a string describing the path.
*/
function printPathArray(path) {
return path
.map((key) =>
typeof key === 'number' ? '[' + key.toString() + ']' : '.' + key,
)
.join('');
}

View File

@@ -0,0 +1,10 @@
/**
* Build a string describing the path.
*/
export function printPathArray(path) {
return path
.map((key) =>
typeof key === 'number' ? '[' + key.toString() + ']' : '.' + key,
)
.join('');
}

View File

@@ -0,0 +1,11 @@
import type { ObjMap } from './ObjMap';
/**
* This function transforms a JS object `ObjMap<Promise<T>>` into
* a `Promise<ObjMap<T>>`
*
* This is akin to bluebird's `Promise.props`, but implemented only using
* `Promise.all` so it will work with any implementation of ES6 promises.
*/
export declare function promiseForObject<T>(
object: ObjMap<Promise<T>>,
): Promise<ObjMap<T>>;

View File

@@ -0,0 +1,25 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.promiseForObject = promiseForObject;
/**
* This function transforms a JS object `ObjMap<Promise<T>>` into
* a `Promise<ObjMap<T>>`
*
* This is akin to bluebird's `Promise.props`, but implemented only using
* `Promise.all` so it will work with any implementation of ES6 promises.
*/
function promiseForObject(object) {
return Promise.all(Object.values(object)).then((resolvedValues) => {
const resolvedObject = Object.create(null);
for (const [i, key] of Object.keys(object).entries()) {
resolvedObject[key] = resolvedValues[i];
}
return resolvedObject;
});
}

View File

@@ -0,0 +1,18 @@
/**
* This function transforms a JS object `ObjMap<Promise<T>>` into
* a `Promise<ObjMap<T>>`
*
* This is akin to bluebird's `Promise.props`, but implemented only using
* `Promise.all` so it will work with any implementation of ES6 promises.
*/
export function promiseForObject(object) {
return Promise.all(Object.values(object)).then((resolvedValues) => {
const resolvedObject = Object.create(null);
for (const [i, key] of Object.keys(object).entries()) {
resolvedObject[key] = resolvedValues[i];
}
return resolvedObject;
});
}

View File

@@ -0,0 +1,13 @@
import type { PromiseOrValue } from './PromiseOrValue';
/**
* Similar to Array.prototype.reduce(), however the reducing callback may return
* a Promise, in which case reduction will continue after each promise resolves.
*
* If the callback does not return a Promise, then this function will also not
* return a Promise.
*/
export declare function promiseReduce<T, U>(
values: Iterable<T>,
callbackFn: (accumulator: U, currentValue: T) => PromiseOrValue<U>,
initialValue: PromiseOrValue<U>,
): PromiseOrValue<U>;

View File

@@ -0,0 +1,27 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.promiseReduce = promiseReduce;
var _isPromise = require('./isPromise.js');
/**
* Similar to Array.prototype.reduce(), however the reducing callback may return
* a Promise, in which case reduction will continue after each promise resolves.
*
* If the callback does not return a Promise, then this function will also not
* return a Promise.
*/
function promiseReduce(values, callbackFn, initialValue) {
let accumulator = initialValue;
for (const value of values) {
accumulator = (0, _isPromise.isPromise)(accumulator)
? accumulator.then((resolved) => callbackFn(resolved, value))
: callbackFn(accumulator, value);
}
return accumulator;
}

View File

@@ -0,0 +1,20 @@
import { isPromise } from './isPromise.mjs';
/**
* Similar to Array.prototype.reduce(), however the reducing callback may return
* a Promise, in which case reduction will continue after each promise resolves.
*
* If the callback does not return a Promise, then this function will also not
* return a Promise.
*/
export function promiseReduce(values, callbackFn, initialValue) {
let accumulator = initialValue;
for (const value of values) {
accumulator = isPromise(accumulator)
? accumulator.then((resolved) => callbackFn(resolved, value))
: callbackFn(accumulator, value);
}
return accumulator;
}

View File

@@ -0,0 +1,8 @@
/**
* Given an invalid input string and a list of valid options, returns a filtered
* list of valid options sorted based on their similarity with the input.
*/
export declare function suggestionList(
input: string,
options: ReadonlyArray<string>,
): Array<string>;

View File

@@ -0,0 +1,139 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.suggestionList = suggestionList;
var _naturalCompare = require('./naturalCompare.js');
/**
* Given an invalid input string and a list of valid options, returns a filtered
* list of valid options sorted based on their similarity with the input.
*/
function suggestionList(input, options) {
const optionsByDistance = Object.create(null);
const lexicalDistance = new LexicalDistance(input);
const threshold = Math.floor(input.length * 0.4) + 1;
for (const option of options) {
const distance = lexicalDistance.measure(option, threshold);
if (distance !== undefined) {
optionsByDistance[option] = distance;
}
}
return Object.keys(optionsByDistance).sort((a, b) => {
const distanceDiff = optionsByDistance[a] - optionsByDistance[b];
return distanceDiff !== 0
? distanceDiff
: (0, _naturalCompare.naturalCompare)(a, b);
});
}
/**
* Computes the lexical distance between strings A and B.
*
* The "distance" between two strings is given by counting the minimum number
* of edits needed to transform string A into string B. An edit can be an
* insertion, deletion, or substitution of a single character, or a swap of two
* adjacent characters.
*
* Includes a custom alteration from Damerau-Levenshtein to treat case changes
* as a single edit which helps identify mis-cased values with an edit distance
* of 1.
*
* This distance can be useful for detecting typos in input or sorting
*/
class LexicalDistance {
constructor(input) {
this._input = input;
this._inputLowerCase = input.toLowerCase();
this._inputArray = stringToArray(this._inputLowerCase);
this._rows = [
new Array(input.length + 1).fill(0),
new Array(input.length + 1).fill(0),
new Array(input.length + 1).fill(0),
];
}
measure(option, threshold) {
if (this._input === option) {
return 0;
}
const optionLowerCase = option.toLowerCase(); // Any case change counts as a single edit
if (this._inputLowerCase === optionLowerCase) {
return 1;
}
let a = stringToArray(optionLowerCase);
let b = this._inputArray;
if (a.length < b.length) {
const tmp = a;
a = b;
b = tmp;
}
const aLength = a.length;
const bLength = b.length;
if (aLength - bLength > threshold) {
return undefined;
}
const rows = this._rows;
for (let j = 0; j <= bLength; j++) {
rows[0][j] = j;
}
for (let i = 1; i <= aLength; i++) {
const upRow = rows[(i - 1) % 3];
const currentRow = rows[i % 3];
let smallestCell = (currentRow[0] = i);
for (let j = 1; j <= bLength; j++) {
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
let currentCell = Math.min(
upRow[j] + 1, // delete
currentRow[j - 1] + 1, // insert
upRow[j - 1] + cost, // substitute
);
if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
// transposition
const doubleDiagonalCell = rows[(i - 2) % 3][j - 2];
currentCell = Math.min(currentCell, doubleDiagonalCell + 1);
}
if (currentCell < smallestCell) {
smallestCell = currentCell;
}
currentRow[j] = currentCell;
} // Early exit, since distance can't go smaller than smallest element of the previous row.
if (smallestCell > threshold) {
return undefined;
}
}
const distance = rows[aLength % 3][bLength];
return distance <= threshold ? distance : undefined;
}
}
function stringToArray(str) {
const strLength = str.length;
const array = new Array(strLength);
for (let i = 0; i < strLength; ++i) {
array[i] = str.charCodeAt(i);
}
return array;
}

View File

@@ -0,0 +1,130 @@
import { naturalCompare } from './naturalCompare.mjs';
/**
* Given an invalid input string and a list of valid options, returns a filtered
* list of valid options sorted based on their similarity with the input.
*/
export function suggestionList(input, options) {
const optionsByDistance = Object.create(null);
const lexicalDistance = new LexicalDistance(input);
const threshold = Math.floor(input.length * 0.4) + 1;
for (const option of options) {
const distance = lexicalDistance.measure(option, threshold);
if (distance !== undefined) {
optionsByDistance[option] = distance;
}
}
return Object.keys(optionsByDistance).sort((a, b) => {
const distanceDiff = optionsByDistance[a] - optionsByDistance[b];
return distanceDiff !== 0 ? distanceDiff : naturalCompare(a, b);
});
}
/**
* Computes the lexical distance between strings A and B.
*
* The "distance" between two strings is given by counting the minimum number
* of edits needed to transform string A into string B. An edit can be an
* insertion, deletion, or substitution of a single character, or a swap of two
* adjacent characters.
*
* Includes a custom alteration from Damerau-Levenshtein to treat case changes
* as a single edit which helps identify mis-cased values with an edit distance
* of 1.
*
* This distance can be useful for detecting typos in input or sorting
*/
class LexicalDistance {
constructor(input) {
this._input = input;
this._inputLowerCase = input.toLowerCase();
this._inputArray = stringToArray(this._inputLowerCase);
this._rows = [
new Array(input.length + 1).fill(0),
new Array(input.length + 1).fill(0),
new Array(input.length + 1).fill(0),
];
}
measure(option, threshold) {
if (this._input === option) {
return 0;
}
const optionLowerCase = option.toLowerCase(); // Any case change counts as a single edit
if (this._inputLowerCase === optionLowerCase) {
return 1;
}
let a = stringToArray(optionLowerCase);
let b = this._inputArray;
if (a.length < b.length) {
const tmp = a;
a = b;
b = tmp;
}
const aLength = a.length;
const bLength = b.length;
if (aLength - bLength > threshold) {
return undefined;
}
const rows = this._rows;
for (let j = 0; j <= bLength; j++) {
rows[0][j] = j;
}
for (let i = 1; i <= aLength; i++) {
const upRow = rows[(i - 1) % 3];
const currentRow = rows[i % 3];
let smallestCell = (currentRow[0] = i);
for (let j = 1; j <= bLength; j++) {
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
let currentCell = Math.min(
upRow[j] + 1, // delete
currentRow[j - 1] + 1, // insert
upRow[j - 1] + cost, // substitute
);
if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
// transposition
const doubleDiagonalCell = rows[(i - 2) % 3][j - 2];
currentCell = Math.min(currentCell, doubleDiagonalCell + 1);
}
if (currentCell < smallestCell) {
smallestCell = currentCell;
}
currentRow[j] = currentCell;
} // Early exit, since distance can't go smaller than smallest element of the previous row.
if (smallestCell > threshold) {
return undefined;
}
}
const distance = rows[aLength % 3][bLength];
return distance <= threshold ? distance : undefined;
}
}
function stringToArray(str) {
const strLength = str.length;
const array = new Array(strLength);
for (let i = 0; i < strLength; ++i) {
array[i] = str.charCodeAt(i);
}
return array;
}

View File

@@ -0,0 +1,4 @@
/**
* Sometimes a non-error is thrown, wrap it as an Error instance to ensure a consistent Error interface.
*/
export declare function toError(thrownValue: unknown): Error;

View File

@@ -0,0 +1,25 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.toError = toError;
var _inspect = require('./inspect.js');
/**
* Sometimes a non-error is thrown, wrap it as an Error instance to ensure a consistent Error interface.
*/
function toError(thrownValue) {
return thrownValue instanceof Error
? thrownValue
: new NonErrorThrown(thrownValue);
}
class NonErrorThrown extends Error {
constructor(thrownValue) {
super('Unexpected error value: ' + (0, _inspect.inspect)(thrownValue));
this.name = 'NonErrorThrown';
this.thrownValue = thrownValue;
}
}

View File

@@ -0,0 +1,18 @@
import { inspect } from './inspect.mjs';
/**
* Sometimes a non-error is thrown, wrap it as an Error instance to ensure a consistent Error interface.
*/
export function toError(thrownValue) {
return thrownValue instanceof Error
? thrownValue
: new NonErrorThrown(thrownValue);
}
class NonErrorThrown extends Error {
constructor(thrownValue) {
super('Unexpected error value: ' + inspect(thrownValue));
this.name = 'NonErrorThrown';
this.thrownValue = thrownValue;
}
}

View File

@@ -0,0 +1,5 @@
import type { Maybe } from './Maybe';
import type { ReadOnlyObjMap, ReadOnlyObjMapLike } from './ObjMap';
export declare function toObjMap<T>(
obj: Maybe<ReadOnlyObjMapLike<T>>,
): ReadOnlyObjMap<T>;

View File

@@ -0,0 +1,24 @@
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.toObjMap = toObjMap;
function toObjMap(obj) {
if (obj == null) {
return Object.create(null);
}
if (Object.getPrototypeOf(obj) === null) {
return obj;
}
const map = Object.create(null);
for (const [key, value] of Object.entries(obj)) {
map[key] = value;
}
return map;
}

View File

@@ -0,0 +1,17 @@
export function toObjMap(obj) {
if (obj == null) {
return Object.create(null);
}
if (Object.getPrototypeOf(obj) === null) {
return obj;
}
const map = Object.create(null);
for (const [key, value] of Object.entries(obj)) {
map[key] = value;
}
return map;
}