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:
Tianyi Cui
2026-06-11 10:53:32 +08:00
parent ae2e08b4d6
commit 72688a3888
69 changed files with 6659 additions and 0 deletions
+42
View File
@@ -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]
}
+10
View File
@@ -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'
+78
View File
@@ -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 })
}
+113
View File
@@ -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)
}
+92
View File
@@ -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))
}
}
+142
View File
@@ -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))
}