Vendor Cordis framework packages as source
cordis 4.0.0-rc.6, plugin-loader, -include, -group, -timer, -hmr, -logger-console, cosmokit 1.8.1, schemastery 3.18.0 — copied from the cordis-workspace checkout, flattened under vendor/, original npm names, private: true. vendor/README.md is the manifest: upstream repos + commit SHAs, local-modification log, sync procedure. Local modification: hmr's locale YAML imports and .i18n() call removed (avoids a runtime YAML import hook we don't vendor).
This commit is contained in:
Vendored
+42
@@ -0,0 +1,42 @@
|
||||
import { isNullable } from './misc'
|
||||
|
||||
/** Return true when every item in `array2` is present in `array1`. */
|
||||
export function contain(array1: readonly any[], array2: readonly any[]) {
|
||||
return array2.every(item => array1.includes(item))
|
||||
}
|
||||
|
||||
/** Return items that appear in both arrays. */
|
||||
export function intersection<T>(array1: readonly T[], array2: readonly T[]) {
|
||||
return array1.filter(item => array2.includes(item))
|
||||
}
|
||||
|
||||
/** Return items from `array1` that do not appear in `array2`. */
|
||||
export function difference<S>(array1: readonly S[], array2: readonly any[]) {
|
||||
return array1.filter(item => !array2.includes(item))
|
||||
}
|
||||
|
||||
/** Return the set-union of two arrays while preserving first occurrence order. */
|
||||
export function union<T>(array1: readonly T[], array2: readonly T[]) {
|
||||
return Array.from(new Set([...array1, ...array2]))
|
||||
}
|
||||
|
||||
/** Remove duplicate values while preserving first occurrence order. */
|
||||
export function deduplicate<T>(array: readonly T[]) {
|
||||
return [...new Set(array)]
|
||||
}
|
||||
|
||||
/** Remove one item from an array and report whether it was found. */
|
||||
export function remove<T>(list: T[], item: T) {
|
||||
const index = list?.indexOf(item)
|
||||
if (index >= 0) {
|
||||
list.splice(index, 1)
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/** Normalize nullish, scalar, or array input to an array. */
|
||||
export function makeArray<T>(source: null | undefined | T | T[]) {
|
||||
return Array.isArray(source) ? source : isNullable(source) ? [] : [source]
|
||||
}
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
/** Array set and normalization helpers. */
|
||||
export * from './array'
|
||||
/** Runtime type, binary, clone, and equality helpers. */
|
||||
export * from './types'
|
||||
/** Shared utility types and object helpers. */
|
||||
export * from './misc'
|
||||
/** String case, path, and property formatting helpers. */
|
||||
export * from './string'
|
||||
/** Time constants, parsing, and formatting helpers. */
|
||||
export * from './time'
|
||||
Vendored
+78
@@ -0,0 +1,78 @@
|
||||
/** String/symbol keyed dictionary type. */
|
||||
export type Dict<T = any, K extends string | symbol = string> = { [key in K]: T }
|
||||
/** Safely read `T[K]`, returning `never` when `K` is not a key of `T`. */
|
||||
export type Get<T extends {}, K> = K extends keyof T ? T[K] : never
|
||||
/** Conditional extraction helper with a configurable return type. */
|
||||
export type Extract<S, T, U = S> = S extends T ? U : never
|
||||
/** Accept a value or an array, unless the value is already an array type. */
|
||||
export type MaybeArray<T> = [T] extends [unknown[]] ? T : T | T[]
|
||||
/** Wrap a value in `Promise`, preserving the resolved type of existing promises. */
|
||||
export type Promisify<T> = Promise<T extends Promise<infer S> ? S : T>
|
||||
/** Accept a value or promise unless the value type is already promise-like. */
|
||||
export type Awaitable<T> = [T] extends [Promise<unknown>] ? T : T | Promise<T>
|
||||
/** Convert a union type to an intersection type. */
|
||||
export type Intersect<U> = (U extends any ? (arg: U) => void : never) extends ((arg: infer I) => void) ? I : never
|
||||
|
||||
/** No-op callback returning `undefined` at runtime and `any` at type level. */
|
||||
export function noop(): any {}
|
||||
|
||||
/** Return true when a value is `null` or `undefined`. */
|
||||
export function isNullable(value: any): value is null | undefined | void {
|
||||
return value === null || value === undefined
|
||||
}
|
||||
|
||||
/** Return true when a value is neither `null` nor `undefined`. */
|
||||
export function isNonNullable<T>(value: T): value is NonNullable<T> {
|
||||
return !isNullable(value)
|
||||
}
|
||||
|
||||
/** Return true for non-array object values. */
|
||||
export function isPlainObject(data: any) {
|
||||
return data && typeof data === 'object' && !Array.isArray(data)
|
||||
}
|
||||
|
||||
/** Filter object entries with a key type guard. */
|
||||
export function filterKeys<T, K extends string, U extends K>(object: Dict<T, K>, filter: (key: K, value: T) => key is U): Dict<T, U>
|
||||
/** Filter object entries with a boolean predicate. */
|
||||
export function filterKeys<T, K extends string>(object: Dict<T, K>, filter: (key: K, value: T) => boolean): Dict<T, K>
|
||||
/** Filter object entries and return a new object. */
|
||||
export function filterKeys(object: {}, filter: (key: string, value: any) => boolean) {
|
||||
return Object.fromEntries(Object.entries(object).filter(([key, value]) => filter(key, value)))
|
||||
}
|
||||
|
||||
/** Map object values while preserving the original key set. */
|
||||
export function mapValues<U, T, K extends string>(object: Dict<T, K>, transform: (value: T, key: K) => U) {
|
||||
return Object.fromEntries(Object.entries(object).map(([key, value]) => [key, (transform as any)(value, key)])) as Dict<U, K>
|
||||
}
|
||||
|
||||
/** Alias for `mapValues`. */
|
||||
export { mapValues as valueMap }
|
||||
|
||||
/** Pick selected keys from an object, optionally including `undefined` values. */
|
||||
export function pick<T extends object, K extends keyof T>(source: T, keys?: Iterable<K>, forced?: boolean) {
|
||||
if (!keys) return { ...source }
|
||||
const result = {} as Pick<T, K>
|
||||
for (const key of keys) {
|
||||
if (forced || source[key] !== undefined) result[key] = source[key]
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/** Omit selected keys from a shallow object copy. */
|
||||
export function omit<T, K extends keyof T>(source: T, keys?: Iterable<K>) {
|
||||
if (!keys) return { ...source }
|
||||
const result = { ...source } as Omit<T, K>
|
||||
for (const key of keys) {
|
||||
Reflect.deleteProperty(result, key)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/** Define a non-enumerable writable property with a typed key. */
|
||||
export function defineProperty<T, K extends keyof T>(object: T, key: K, value: T[K]): T
|
||||
/** Define a non-enumerable writable property with an arbitrary key. */
|
||||
export function defineProperty<T, K extends keyof any>(object: T, key: K, value: any): T
|
||||
/** Define a non-enumerable writable property and return the object. */
|
||||
export function defineProperty<T, K extends keyof any>(object: T, key: K, value: any) {
|
||||
return Object.defineProperty(object, key, { writable: true, value, enumerable: false })
|
||||
}
|
||||
Vendored
+113
@@ -0,0 +1,113 @@
|
||||
/** Uppercase the first character of a string. */
|
||||
export function capitalize(source: string) {
|
||||
return source.charAt(0).toUpperCase() + source.slice(1)
|
||||
}
|
||||
|
||||
/** Lowercase the first character of a string. */
|
||||
export function uncapitalize(source: string) {
|
||||
return source.charAt(0).toLowerCase() + source.slice(1)
|
||||
}
|
||||
|
||||
/** Convert dash or underscore delimited text to camelCase. */
|
||||
export function camelCase(source: string) {
|
||||
return source.replace(/[_-][a-z]/g, str => str.slice(1).toUpperCase())
|
||||
}
|
||||
|
||||
const enum State {
|
||||
DELIM,
|
||||
UPPER,
|
||||
LOWER,
|
||||
}
|
||||
|
||||
function tokenize(source: string, delimiters: number[], delimiter: number) {
|
||||
const output: number[] = []
|
||||
let state = State.DELIM
|
||||
for (let i = 0; i < source.length; i++) {
|
||||
const code = source.charCodeAt(i)
|
||||
if (code >= 65 && code <= 90) {
|
||||
if (state === State.UPPER) {
|
||||
const next = source.charCodeAt(i + 1)
|
||||
if (next >= 97 && next <= 122) {
|
||||
output.push(delimiter)
|
||||
}
|
||||
output.push(code + 32)
|
||||
} else {
|
||||
if (state !== State.DELIM) {
|
||||
output.push(delimiter)
|
||||
}
|
||||
output.push(code + 32)
|
||||
}
|
||||
state = State.UPPER
|
||||
} else if (code >= 97 && code <= 122) {
|
||||
output.push(code)
|
||||
state = State.LOWER
|
||||
} else if (delimiters.includes(code)) {
|
||||
if (state !== State.DELIM) {
|
||||
output.push(delimiter)
|
||||
}
|
||||
state = State.DELIM
|
||||
} else {
|
||||
output.push(code)
|
||||
}
|
||||
}
|
||||
return String.fromCharCode(...output)
|
||||
}
|
||||
|
||||
/** Convert text to dash-delimited parameter case. */
|
||||
export function paramCase(source: string) {
|
||||
return tokenize(source, [45, 95], 45)
|
||||
}
|
||||
|
||||
/** Convert text to underscore-delimited snake case. */
|
||||
export function snakeCase(source: string) {
|
||||
return tokenize(source, [45, 95], 95)
|
||||
}
|
||||
|
||||
/** Runtime alias for `camelCase`. */
|
||||
export const camelize = camelCase
|
||||
/** Runtime alias for `paramCase`. */
|
||||
export const hyphenate = paramCase
|
||||
|
||||
namespace Letter {
|
||||
/* eslint-disable @typescript-eslint/member-delimiter-style */
|
||||
interface LowerToUpper {
|
||||
a: 'A', b: 'B', c: 'C', d: 'D', e: 'E', f: 'F', g: 'G', h: 'H', i: 'I', j: 'J', k: 'K', l: 'L', m: 'M',
|
||||
n: 'N', o: 'O', p: 'P', q: 'Q', r: 'R', s: 'S', t: 'T', u: 'U', v: 'V', w: 'W', x: 'X', y: 'Y', z: 'Z',
|
||||
}
|
||||
|
||||
interface UpperToLower {
|
||||
A: 'a', B: 'b', C: 'c', D: 'd', E: 'e', F: 'f', G: 'g', H: 'h', I: 'i', J: 'j', K: 'k', L: 'l', M: 'm',
|
||||
N: 'n', O: 'o', P: 'p', Q: 'q', R: 'r', S: 's', T: 't', U: 'u', V: 'v', W: 'w', X: 'x', Y: 'y', Z: 'z',
|
||||
}
|
||||
/* eslint-enable @typescript-eslint/member-delimiter-style */
|
||||
|
||||
export type Upper = keyof UpperToLower
|
||||
export type Lower = keyof LowerToUpper
|
||||
|
||||
export type ToUpper<S extends string> = S extends Lower ? LowerToUpper[S] : S
|
||||
export type ToLower<S extends string, P extends string = ''> = S extends Upper ? `${P}${UpperToLower[S]}` : S
|
||||
}
|
||||
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
/** Type-level conversion from dash-delimited text to camelCase. */
|
||||
export type camelize<S extends string> = S extends `${infer L}-${infer M}${infer R}` ? `${L}${Letter.ToUpper<M>}${camelize<R>}` : S
|
||||
/** Type-level conversion from camelCase text to dash-delimited text. */
|
||||
export type hyphenate<S extends string> = S extends `${infer L}${infer R}` ? `${Letter.ToLower<L, '-'>}${hyphenate<R>}` : S
|
||||
/* eslint-enable @typescript-eslint/naming-convention */
|
||||
|
||||
/** Format a property key as a JavaScript member access suffix. */
|
||||
export function formatProperty(key: keyof any) {
|
||||
if (typeof key !== 'string') return `[${key.toString()}]`
|
||||
return /^[a-z_$][\w$]*$/i.test(key) ? `.${key}` : `[${JSON.stringify(key)}]`
|
||||
}
|
||||
|
||||
/** Remove one trailing slash from a path string. */
|
||||
export function trimSlash(source: string) {
|
||||
return source.replace(/\/$/, '')
|
||||
}
|
||||
|
||||
/** Ensure a path starts with `/` and has no trailing slash. */
|
||||
export function sanitize(source: string) {
|
||||
if (!source.startsWith('/')) source = '/' + source
|
||||
return trimSlash(source)
|
||||
}
|
||||
Vendored
+92
@@ -0,0 +1,92 @@
|
||||
/** Time constants plus parsing and formatting helpers. */
|
||||
export namespace Time {
|
||||
export const millisecond = 1
|
||||
export const second = 1000
|
||||
export const minute = second * 60
|
||||
export const hour = minute * 60
|
||||
export const day = hour * 24
|
||||
export const week = day * 7
|
||||
|
||||
let timezoneOffset = new Date().getTimezoneOffset()
|
||||
|
||||
export function setTimezoneOffset(offset: number) {
|
||||
timezoneOffset = offset
|
||||
}
|
||||
|
||||
export function getTimezoneOffset() {
|
||||
return timezoneOffset
|
||||
}
|
||||
|
||||
export function getDateNumber(date: number | Date = new Date(), offset?: number) {
|
||||
if (typeof date === 'number') date = new Date(date)
|
||||
if (offset === undefined) offset = timezoneOffset
|
||||
return Math.floor((date.valueOf() / minute - offset) / 1440)
|
||||
}
|
||||
|
||||
export function fromDateNumber(value: number, offset?: number) {
|
||||
const date = new Date(value * day)
|
||||
if (offset === undefined) offset = timezoneOffset
|
||||
return new Date(+date + offset * minute)
|
||||
}
|
||||
|
||||
const numeric = /\d+(?:\.\d+)?/.source
|
||||
const timeRegExp = new RegExp(`^${[
|
||||
'w(?:eek(?:s)?)?',
|
||||
'd(?:ay(?:s)?)?',
|
||||
'h(?:our(?:s)?)?',
|
||||
'm(?:in(?:ute)?(?:s)?)?',
|
||||
's(?:ec(?:ond)?(?:s)?)?',
|
||||
].map(unit => `(${numeric}${unit})?`).join('')}$`)
|
||||
|
||||
export function parseTime(source: string) {
|
||||
const capture = timeRegExp.exec(source)
|
||||
if (!capture) return 0
|
||||
return (parseFloat(capture[1]) * week || 0)
|
||||
+ (parseFloat(capture[2]) * day || 0)
|
||||
+ (parseFloat(capture[3]) * hour || 0)
|
||||
+ (parseFloat(capture[4]) * minute || 0)
|
||||
+ (parseFloat(capture[5]) * second || 0)
|
||||
}
|
||||
|
||||
export function parseDate(date: string) {
|
||||
const parsed = parseTime(date)
|
||||
if (parsed) {
|
||||
date = Date.now() + parsed as any
|
||||
} else if (/^\d{1,2}(:\d{1,2}){1,2}$/.test(date)) {
|
||||
date = `${new Date().toLocaleDateString()}-${date}`
|
||||
} else if (/^\d{1,2}-\d{1,2}-\d{1,2}(:\d{1,2}){1,2}$/.test(date)) {
|
||||
date = `${new Date().getFullYear()}-${date}`
|
||||
}
|
||||
return date ? new Date(date) : new Date()
|
||||
}
|
||||
|
||||
export function format(ms: number) {
|
||||
const abs = Math.abs(ms)
|
||||
if (abs >= day - hour / 2) {
|
||||
return Math.round(ms / day) + 'd'
|
||||
} else if (abs >= hour - minute / 2) {
|
||||
return Math.round(ms / hour) + 'h'
|
||||
} else if (abs >= minute - second / 2) {
|
||||
return Math.round(ms / minute) + 'm'
|
||||
} else if (abs >= second) {
|
||||
return Math.round(ms / second) + 's'
|
||||
}
|
||||
return ms + 'ms'
|
||||
}
|
||||
|
||||
export function toDigits(source: number, length = 2) {
|
||||
return source.toString().padStart(length, '0')
|
||||
}
|
||||
|
||||
export function template(template: string, time = new Date()) {
|
||||
return template
|
||||
.replace('yyyy', time.getFullYear().toString())
|
||||
.replace('yy', time.getFullYear().toString().slice(2))
|
||||
.replace('MM', toDigits(time.getMonth() + 1))
|
||||
.replace('dd', toDigits(time.getDate()))
|
||||
.replace('hh', toDigits(time.getHours()))
|
||||
.replace('mm', toDigits(time.getMinutes()))
|
||||
.replace('ss', toDigits(time.getSeconds()))
|
||||
.replace('SSS', toDigits(time.getMilliseconds(), 3))
|
||||
}
|
||||
}
|
||||
Vendored
+142
@@ -0,0 +1,142 @@
|
||||
import { isNullable } from './misc'
|
||||
|
||||
type GlobalConstructorNames = keyof {
|
||||
[K in keyof typeof globalThis as typeof globalThis[K] extends abstract new (...args: any) => any ? K : never]: K
|
||||
}
|
||||
|
||||
/** Create a predicate for a global constructor name. */
|
||||
export function is<K extends GlobalConstructorNames>(type: K): (value: any) => value is InstanceType<typeof globalThis[K]>
|
||||
/** Test whether a value matches a global constructor name. */
|
||||
export function is<K extends GlobalConstructorNames>(type: K, value: any): value is InstanceType<typeof globalThis[K]>
|
||||
/** Test values using `instanceof` with a `toStringTag` fallback. */
|
||||
export function is<K extends GlobalConstructorNames>(type: K, value?: any): any {
|
||||
if (arguments.length === 1) return (value: any) => is(type, value)
|
||||
return type in globalThis && value instanceof (globalThis[type] as any)
|
||||
|| Object.prototype.toString.call(value).slice(8, -1) === type
|
||||
}
|
||||
|
||||
function isArrayBufferLike(value: any): value is ArrayBufferLike {
|
||||
return is('ArrayBuffer', value) || is('SharedArrayBuffer', value)
|
||||
}
|
||||
|
||||
function isArrayBufferSource(value: any): value is Binary.Source {
|
||||
return isArrayBufferLike(value) || ArrayBuffer.isView(value)
|
||||
}
|
||||
|
||||
/** Binary source detection and base64/hex conversion helpers. */
|
||||
export namespace Binary {
|
||||
export type Source<T extends ArrayBufferLike = ArrayBufferLike> = T | ArrayBufferView<T>
|
||||
|
||||
export const is = isArrayBufferLike
|
||||
export const isSource = isArrayBufferSource
|
||||
|
||||
export function fromSource<T extends ArrayBufferLike>(source: Source<T>): T {
|
||||
if (ArrayBuffer.isView(source)) {
|
||||
// https://stackoverflow.com/questions/8609289/convert-a-binary-nodejs-buffer-to-javascript-arraybuffer#answer-31394257
|
||||
return source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength) as T
|
||||
} else {
|
||||
return source
|
||||
}
|
||||
}
|
||||
|
||||
export function toBase64(source: Source) {
|
||||
source = fromSource(source)
|
||||
if (typeof Buffer !== 'undefined') {
|
||||
return Buffer.from(source).toString('base64')
|
||||
}
|
||||
let binary = ''
|
||||
const bytes = new Uint8Array(source)
|
||||
for (let i = 0; i < bytes.byteLength; i++) {
|
||||
binary += String.fromCharCode(bytes[i])
|
||||
}
|
||||
return btoa(binary)
|
||||
}
|
||||
|
||||
export function fromBase64(source: string) {
|
||||
if (typeof Buffer !== 'undefined') return fromSource(Buffer.from(source, 'base64'))
|
||||
return Uint8Array.from(atob(source), c => c.charCodeAt(0))
|
||||
}
|
||||
|
||||
export function toHex(source: Source) {
|
||||
source = fromSource(source)
|
||||
if (typeof Buffer !== 'undefined') return Buffer.from(source).toString('hex')
|
||||
return Array.from(new Uint8Array(source), byte => byte.toString(16).padStart(2, '0')).join('')
|
||||
}
|
||||
|
||||
export function fromHex(source: string) {
|
||||
if (typeof Buffer !== 'undefined') return fromSource(Buffer.from(source, 'hex'))
|
||||
const hex = source.length % 2 === 0 ? source : source.slice(0, source.length - 1)
|
||||
const buffer: number[] = []
|
||||
for (let i = 0; i < hex.length; i += 2) {
|
||||
buffer.push(parseInt(`${hex[i]}${hex[i + 1]}`, 16))
|
||||
}
|
||||
return Uint8Array.from(buffer).buffer
|
||||
}
|
||||
}
|
||||
|
||||
/** Decode a base64 string into binary data. */
|
||||
export const base64ToArrayBuffer = Binary.fromBase64
|
||||
/** Encode binary data as base64. */
|
||||
export const arrayBufferToBase64 = Binary.toBase64
|
||||
/** Decode a hex string into binary data. */
|
||||
export const hexToArrayBuffer = Binary.fromHex
|
||||
/** Encode binary data as hex. */
|
||||
export const arrayBufferToHex = Binary.toHex
|
||||
|
||||
/** Deep-clone common JavaScript values while preserving prototypes. */
|
||||
export function clone<T>(source: T): T
|
||||
/** Deep-clone common JavaScript values while preserving prototypes and cycles. */
|
||||
export function clone(source: any, refs = new Map<any, any>()) {
|
||||
if (!source || typeof source !== 'object') return source
|
||||
if (is('Date', source)) return new Date(source.valueOf())
|
||||
if (is('RegExp', source)) return new RegExp(source.source, source.flags)
|
||||
if (isArrayBufferLike(source)) return source.slice(0)
|
||||
if (ArrayBuffer.isView(source)) return source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength)
|
||||
const cached = refs.get(source)
|
||||
if (cached) return cached
|
||||
if (Array.isArray(source)) {
|
||||
const result: any[] = []
|
||||
refs.set(source, result)
|
||||
source.forEach((value, index) => {
|
||||
result[index] = Reflect.apply(clone, null, [value, refs])
|
||||
})
|
||||
return result
|
||||
}
|
||||
const result = Object.create(Object.getPrototypeOf(source))
|
||||
refs.set(source, result)
|
||||
for (const key of Reflect.ownKeys(source)) {
|
||||
const descriptor = { ...Reflect.getOwnPropertyDescriptor(source, key) }
|
||||
if ('value' in descriptor) {
|
||||
descriptor.value = Reflect.apply(clone, null, [descriptor.value, refs])
|
||||
}
|
||||
Reflect.defineProperty(result, key, descriptor)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/** Deeply compare arrays, dates, regexps, buffers, and plain object fields. */
|
||||
export function deepEqual(a: any, b: any, strict?: boolean): boolean {
|
||||
if (a === b) return true
|
||||
if (!strict && isNullable(a) && isNullable(b)) return true
|
||||
if (typeof a !== typeof b) return false
|
||||
if (typeof a !== 'object') return false
|
||||
if (!a || !b) return false
|
||||
|
||||
function check<T>(test: (x: any) => x is T, then: (a: T, b: T) => boolean) {
|
||||
return test(a) ? test(b) ? then(a, b) : false : test(b) ? false : undefined
|
||||
}
|
||||
|
||||
return check(Array.isArray, (a, b) => a.length === b.length && a.every((item, index) => deepEqual(item, b[index])))
|
||||
?? check(is('Date'), (a, b) => a.valueOf() === b.valueOf())
|
||||
?? check(is('RegExp'), (a, b) => a.source === b.source && a.flags === b.flags)
|
||||
?? check(isArrayBufferLike, (a, b) => {
|
||||
if (a.byteLength !== b.byteLength) return false
|
||||
const viewA = new Uint8Array(a)
|
||||
const viewB = new Uint8Array(b)
|
||||
for (let i = 0; i < viewA.length; i++) {
|
||||
if (viewA[i] !== viewB[i]) return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
?? Object.keys({ ...a, ...b }).every(key => deepEqual(a[key], b[key], strict))
|
||||
}
|
||||
Reference in New Issue
Block a user