From ad5fd99f538c33cd61b0418c96d6f492628b70bd Mon Sep 17 00:00:00 2001 From: Jos de Jong Date: Fri, 11 Oct 2024 12:15:17 +0200 Subject: [PATCH 1/9] chore: add reflected type information to the .js files in `./build` --- package.json5 | 3 ++- src/core/Dispatcher.ts | 4 +-- tools/reflectTypes.mjs | 58 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 tools/reflectTypes.mjs diff --git a/package.json5 b/package.json5 index 5ede49d..12d0a32 100644 --- a/package.json5 +++ b/package.json5 @@ -4,7 +4,8 @@ description: 'Another prototype for a math core', scripts: { build: 'tsc && cp etc/package.json build/', - go: 'pnpm build && pnpm start', + reflect: 'node tools/reflectTypes.mjs', + go: 'pnpm build && pnpm reflect && pnpm start', start: 'node --experimental-loader tsc-module-loader build', test: 'echo Error no test specified && exit 1', }, diff --git a/src/core/Dispatcher.ts b/src/core/Dispatcher.ts index 69b90ee..5b4bd1d 100644 --- a/src/core/Dispatcher.ts +++ b/src/core/Dispatcher.ts @@ -135,7 +135,7 @@ interface ImplementationBuilder< Specs & {[K in NewKeys]: DepCheck} > - ship(): Implementations + ship(): Implementations & { reflectedType5: string } } // And a function that actually provides the builder interface: @@ -189,7 +189,7 @@ function impBuilder< }, ship() { return (sofar as - Implementations) + Implementations & { reflectedType5: string }) } } } diff --git a/tools/reflectTypes.mjs b/tools/reflectTypes.mjs new file mode 100644 index 0000000..4ffa0ad --- /dev/null +++ b/tools/reflectTypes.mjs @@ -0,0 +1,58 @@ +import { readFileSync, writeFileSync, readdirSync } from 'node:fs' +import { fileURLToPath } from 'node:url' +import { dirname, join, relative } from 'node:path' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) + +const buildDir = join(__dirname, '..', 'build') +const files = (await readdirSync(buildDir, { recursive: true })) + .filter(file => file.endsWith('.js')) + .map(file => join(buildDir, file)) + +for (const file of files) { + reflectType(file, { debug: true }) +} + +function reflectType(srcFile, options = { debug: false }) { + log(`Reflecting file "${relative(__dirname, srcFile)}"`) + + const defFile = srcFile.replace(/.js$/, '.d.ts') + const src = String(readFileSync(srcFile)) + const defs = String(readFileSync(defFile)) + + if (src.includes('.reflectedType5')) { + log(' Source file already contains reflected types and will be ignored') + return + } + + const matches = Array.from(src.matchAll(/[^\n](export +)?const +([\w$]+) += +implementations\b/g)) + + if (matches.length === 0) { + log(` No implementations found`) + return + } + + for (const match of matches) { + const name = match[2] + log(` Found an implementations definition: "${name}"`) + + const def = new RegExp(`export declare const ${name}: {(?:(?!\n}).)+\n}`, 's').exec(defs) + + if (def) { + log(` Injected type definitions for "${name}"`) + + const srcReflected = `${src}\n${name}.reflectedType5 = \`${def}\`\n` + + writeFileSync(srcFile, srcReflected) + } else { + log(` No type definitions found for "${name}"`) + } + } + + function log(...args) { + if (options.debug) { + console.log(...args) + } + } +} From b9675c6d592a96809a2202c78331e2220f595b6f Mon Sep 17 00:00:00 2001 From: Jos de Jong Date: Fri, 11 Oct 2024 13:37:07 +0200 Subject: [PATCH 2/9] chore: inject the reflected type information inside the `.ship()` occurrences --- src/core/Dispatcher.ts | 11 +++++++---- tools/reflectTypes.mjs | 42 ++++++++++++++++++------------------------ 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/src/core/Dispatcher.ts b/src/core/Dispatcher.ts index 5b4bd1d..198b69a 100644 --- a/src/core/Dispatcher.ts +++ b/src/core/Dispatcher.ts @@ -102,6 +102,10 @@ type Implementations< Specs extends Specifications > = {[K in NeedKeys]: ImpType} +export interface ReflectedTypeInfo { + reflectedType5: string +} + // The builder interface that lets us assemble narrowly-typed Implementations: interface ImplementationBuilder< Signatures extends GenSigs, @@ -135,7 +139,7 @@ interface ImplementationBuilder< Specs & {[K in NewKeys]: DepCheck} > - ship(): Implementations & { reflectedType5: string } + ship(info?: ReflectedTypeInfo): Implementations & ReflectedTypeInfo } // And a function that actually provides the builder interface: @@ -187,9 +191,8 @@ function impBuilder< Specs & {[K in NewKeys]: DepCheck} > }, - ship() { - return (sofar as - Implementations & { reflectedType5: string }) + ship(info?: ReflectedTypeInfo) { + return { ...sofar, ...info } } } } diff --git a/tools/reflectTypes.mjs b/tools/reflectTypes.mjs index 4ffa0ad..89c6af6 100644 --- a/tools/reflectTypes.mjs +++ b/tools/reflectTypes.mjs @@ -11,44 +11,38 @@ const files = (await readdirSync(buildDir, { recursive: true })) .map(file => join(buildDir, file)) for (const file of files) { - reflectType(file, { debug: true }) + reflectType5(file, { debug: true }) } -function reflectType(srcFile, options = { debug: false }) { +function reflectType5(srcFile, options = { debug: false }) { log(`Reflecting file "${relative(__dirname, srcFile)}"`) const defFile = srcFile.replace(/.js$/, '.d.ts') const src = String(readFileSync(srcFile)) const defs = String(readFileSync(defFile)) - if (src.includes('.reflectedType5')) { - log(' Source file already contains reflected types and will be ignored') + const typeDefMatches = defs.matchAll(/: ({(?:(?!\n}).)+\n}) & (?:(?!ReflectedTypeInfo).)+ReflectedTypeInfo/gs) + if (!typeDefMatches) { + log('No ReflectedTypeInfo found.') return } - const matches = Array.from(src.matchAll(/[^\n](export +)?const +([\w$]+) += +implementations\b/g)) + const typeDefs = Array.from(typeDefMatches).map(def => def[1]) + log(` ${typeDefs.length} ReflectedTypeInfo found`) - if (matches.length === 0) { - log(` No implementations found`) - return + let index = 0 + const srcReflected = src.replaceAll(/(\s*)\.ship\(\)/g, () => { + const def = typeDefs[index] + index++ + return `.ship({ reflectedType5: \`${def}\` })` + }) + log(` ReflectedTypeInfo injected in ${index} occurrences of .ship()`) + + if (index !== typeDefs.length) { + log(' WARNING: not all ReflectedTypeInfo occurrences could be injected') } - for (const match of matches) { - const name = match[2] - log(` Found an implementations definition: "${name}"`) - - const def = new RegExp(`export declare const ${name}: {(?:(?!\n}).)+\n}`, 's').exec(defs) - - if (def) { - log(` Injected type definitions for "${name}"`) - - const srcReflected = `${src}\n${name}.reflectedType5 = \`${def}\`\n` - - writeFileSync(srcFile, srcReflected) - } else { - log(` No type definitions found for "${name}"`) - } - } + writeFileSync(srcFile, srcReflected) function log(...args) { if (options.debug) { From df339df94dc8dab848bf312232fdc8661e4ee9ca Mon Sep 17 00:00:00 2001 From: Glen Whitney Date: Mon, 21 Oct 2024 16:57:59 +0000 Subject: [PATCH 3/9] Reflect types into properties on top-level symbols as well. (#4) Co-authored-by: Jos de Jong Reviewed-on: https://code.studioinfinity.org/glen/math5/pulls/4 Co-authored-by: Glen Whitney Co-committed-by: Glen Whitney --- package.json5 | 9 +- pnpm-lock.yaml | 309 ++++++++++++++++++++++++++++++++++++++++- src/Complex/type.ts | 3 +- src/index.ts | 2 +- tools/reflectTypes.mjs | 14 +- tools/ts2json.mjs | 233 +++++++++++++++++++++++++++++++ 6 files changed, 559 insertions(+), 11 deletions(-) create mode 100644 tools/ts2json.mjs diff --git a/package.json5 b/package.json5 index 12d0a32..921d164 100644 --- a/package.json5 +++ b/package.json5 @@ -3,7 +3,7 @@ version: '0.0.1', description: 'Another prototype for a math core', scripts: { - build: 'tsc && cp etc/package.json build/', + build: 'tsc && cpy etc/package.json build/ --flat', reflect: 'node tools/reflectTypes.mjs', go: 'pnpm build && pnpm reflect && pnpm start', start: 'node --experimental-loader tsc-module-loader build', @@ -22,9 +22,10 @@ url: 'https://code.studioinfinity.org/glen/math5.git', }, devDependencies: { - '@types/node': '^22.7.5', - typescript: '^5.6.3', - 'undici-types': '^6.20.0', + '@types/node': '22.7.5', + 'cpy-cli': '5.0.0', + typescript: '5.6.3', + 'undici-types': '6.20.0', }, dependencies: { 'tsc-module-loader': '^0.0.1', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2eb420d..cee7e06 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,45 +13,204 @@ importers: version: 0.0.1 devDependencies: '@types/node': - specifier: ^22.7.5 + specifier: 22.7.5 version: 22.7.5 + cpy-cli: + specifier: 5.0.0 + version: 5.0.0 typescript: - specifier: ^5.6.3 + specifier: 5.6.3 version: 5.6.3 undici-types: - specifier: ^6.20.0 + specifier: 6.20.0 version: 6.20.0 packages: + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + '@types/node@22.7.5': resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==} + aggregate-error@4.0.1: + resolution: {integrity: sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==} + engines: {node: '>=12'} + + arrify@3.0.0: + resolution: {integrity: sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==} + engines: {node: '>=12'} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + clean-stack@4.2.0: + resolution: {integrity: sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==} + engines: {node: '>=12'} + commonjs-extension-resolution-loader@0.1.0: resolution: {integrity: sha512-XDCkM/cYIt1CfPs+LNX8nC2KKrzTx5AAlGLpx7A4BjWQCHR9LphDu9Iq5zXYf+PXhCkpLGBFiyiTnwmSnNxbWQ==} + cp-file@10.0.0: + resolution: {integrity: sha512-vy2Vi1r2epK5WqxOLnskeKeZkdZvTKfFZQCplE3XWsP+SUJyd5XAUFC9lFgTjjXJF2GMne/UML14iEmkAaDfFg==} + engines: {node: '>=14.16'} + + cpy-cli@5.0.0: + resolution: {integrity: sha512-fb+DZYbL9KHc0BC4NYqGRrDIJZPXUmjjtqdw4XRRg8iV8dIfghUX/WiL+q4/B/KFTy3sK6jsbUhBaz0/Hxg7IQ==} + engines: {node: '>=16'} + hasBin: true + + cpy@10.1.0: + resolution: {integrity: sha512-VC2Gs20JcTyeQob6UViBLnyP0bYHkBh6EiKzot9vi2DmeGlFT9Wd7VG3NBrkNx/jYvFBeyDOMMHdHQhbtKLgHQ==} + engines: {node: '>=16'} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + + fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + + fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + globby@13.2.2: + resolution: {integrity: sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + indent-string@5.0.0: + resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} + engines: {node: '>=12'} + is-core-module@2.15.1: resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} engines: {node: '>= 0.4'} + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + junk@4.0.1: + resolution: {integrity: sha512-Qush0uP+G8ZScpGMZvHUiRfI0YBWuB3gVBYlI0v0vvOJt5FLicco+IkP0a50LqTTQhmts/m6tP5SWE+USyIvcQ==} + engines: {node: '>=12.20'} + + meow@12.1.1: + resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==} + engines: {node: '>=16.10'} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + nested-error-stacks@2.1.1: + resolution: {integrity: sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==} + + p-event@5.0.1: + resolution: {integrity: sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + p-filter@3.0.0: + resolution: {integrity: sha512-QtoWLjXAW++uTX67HZQz1dbTpqBfiidsB6VtQUC9iR85S120+s0T5sO6s+B5MLzFcZkrEd/DGMmCjR+f2Qpxwg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + p-map@5.5.0: + resolution: {integrity: sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==} + engines: {node: '>=12'} + + p-map@6.0.0: + resolution: {integrity: sha512-T8BatKGY+k5rU+Q/GTYgrEf2r4xRMevAN5mtXc2aPc4rS1j3s+vWTaO2Wag94neXuCAUAs8cxBL9EeB5EA6diw==} + engines: {node: '>=16'} + + p-timeout@5.1.0: + resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==} + engines: {node: '>=12'} + path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + slash@4.0.0: + resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} + engines: {node: '>=12'} + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + tsc-module-loader@0.0.1: resolution: {integrity: sha512-3SIydFXw96jYU2imgULgIHKlUY8FnfDZlazvNmw4Umx/8qCwXsyDg0V2QOULf2Fw7zaI1Hbibh0mB8VzRZ/Ghg==} @@ -68,34 +227,178 @@ packages: snapshots: + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.17.1 + '@types/node@22.7.5': dependencies: undici-types: 6.19.8 + aggregate-error@4.0.1: + dependencies: + clean-stack: 4.2.0 + indent-string: 5.0.0 + + arrify@3.0.0: {} + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + clean-stack@4.2.0: + dependencies: + escape-string-regexp: 5.0.0 + commonjs-extension-resolution-loader@0.1.0: dependencies: resolve: 1.22.8 + cp-file@10.0.0: + dependencies: + graceful-fs: 4.2.11 + nested-error-stacks: 2.1.1 + p-event: 5.0.1 + + cpy-cli@5.0.0: + dependencies: + cpy: 10.1.0 + meow: 12.1.1 + + cpy@10.1.0: + dependencies: + arrify: 3.0.0 + cp-file: 10.0.0 + globby: 13.2.2 + junk: 4.0.1 + micromatch: 4.0.8 + nested-error-stacks: 2.1.1 + p-filter: 3.0.0 + p-map: 6.0.0 + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + escape-string-regexp@5.0.0: {} + + fast-glob@3.3.2: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fastq@1.17.1: + dependencies: + reusify: 1.0.4 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + function-bind@1.1.2: {} + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + globby@13.2.2: + dependencies: + dir-glob: 3.0.1 + fast-glob: 3.3.2 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 4.0.0 + + graceful-fs@4.2.11: {} + hasown@2.0.2: dependencies: function-bind: 1.1.2 + ignore@5.3.2: {} + + indent-string@5.0.0: {} + is-core-module@2.15.1: dependencies: hasown: 2.0.2 + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + junk@4.0.1: {} + + meow@12.1.1: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + nested-error-stacks@2.1.1: {} + + p-event@5.0.1: + dependencies: + p-timeout: 5.1.0 + + p-filter@3.0.0: + dependencies: + p-map: 5.5.0 + + p-map@5.5.0: + dependencies: + aggregate-error: 4.0.1 + + p-map@6.0.0: {} + + p-timeout@5.1.0: {} + path-parse@1.0.7: {} + path-type@4.0.0: {} + + picomatch@2.3.1: {} + + queue-microtask@1.2.3: {} + resolve@1.22.8: dependencies: is-core-module: 2.15.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + reusify@1.0.4: {} + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + slash@4.0.0: {} + supports-preserve-symlinks-flag@1.0.0: {} + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + tsc-module-loader@0.0.1: dependencies: commonjs-extension-resolution-loader: 0.1.0 diff --git a/src/Complex/type.ts b/src/Complex/type.ts index 44525d6..ff42a3b 100644 --- a/src/Complex/type.ts +++ b/src/Complex/type.ts @@ -17,7 +17,8 @@ export const Complex_type = { (z: Complex) => joinTypes(dep.typeOf(z.re), dep.typeOf(z.im)), from: { Complex: (dep: {convert: CommonSignature['convert']}) => - (z: Complex) => ({re: dep.convert(z.re), im: dep.convert(z.im)}), + (z: Complex): Complex => + ({re: dep.convert(z.re), im: dep.convert(z.im)}), T: (dep: {zero: CommonSignature['zero']}) => (t: T) => ({re: t, im: dep.zero(t)}) } diff --git a/src/index.ts b/src/index.ts index 66d4a5b..c575454 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,4 +2,4 @@ import {inspect} from 'node:util' import * as specifications from './all' -console.log(inspect(specifications, {depth: 8, colors: true})) +console.log(inspect(specifications, {depth: 18, colors: true})) diff --git a/tools/reflectTypes.mjs b/tools/reflectTypes.mjs index 89c6af6..c232072 100644 --- a/tools/reflectTypes.mjs +++ b/tools/reflectTypes.mjs @@ -2,6 +2,8 @@ import { readFileSync, writeFileSync, readdirSync } from 'node:fs' import { fileURLToPath } from 'node:url' import { dirname, join, relative } from 'node:path' +import ts2json from './ts2json.mjs' + const __filename = fileURLToPath(import.meta.url) const __dirname = dirname(__filename) @@ -15,11 +17,12 @@ for (const file of files) { } function reflectType5(srcFile, options = { debug: false }) { - log(`Reflecting file "${relative(__dirname, srcFile)}"`) + log(`=========Reflecting file "${relative(__dirname, srcFile)}"`) const defFile = srcFile.replace(/.js$/, '.d.ts') const src = String(readFileSync(srcFile)) const defs = String(readFileSync(defFile)) + const parsedDefs = ts2json(defFile) const typeDefMatches = defs.matchAll(/: ({(?:(?!\n}).)+\n}) & (?:(?!ReflectedTypeInfo).)+ReflectedTypeInfo/gs) if (!typeDefMatches) { @@ -31,7 +34,7 @@ function reflectType5(srcFile, options = { debug: false }) { log(` ${typeDefs.length} ReflectedTypeInfo found`) let index = 0 - const srcReflected = src.replaceAll(/(\s*)\.ship\(\)/g, () => { + let srcReflected = src.replaceAll(/(\s*)\.ship\(\)/g, () => { const def = typeDefs[index] index++ return `.ship({ reflectedType5: \`${def}\` })` @@ -42,6 +45,13 @@ function reflectType5(srcFile, options = { debug: false }) { log(' WARNING: not all ReflectedTypeInfo occurrences could be injected') } + for (const id in parsedDefs) { + if (id.includes('interface')) continue + if (parsedDefs[id] === undefined) continue + log(` Tagging ${id} with type data`, parsedDefs[id]) + srcReflected += + `\n${id}._reflectedType5 = ${JSON.stringify(parsedDefs[id])}\n` + } writeFileSync(srcFile, srcReflected) function log(...args) { diff --git a/tools/ts2json.mjs b/tools/ts2json.mjs new file mode 100644 index 0000000..4013acd --- /dev/null +++ b/tools/ts2json.mjs @@ -0,0 +1,233 @@ +import * as ts from 'typescript' + +const intrinsicTypeKeywords = new Set([ + ts.SyntaxKind.AnyKeyword, + ts.SyntaxKind.BooleanKeyword, + ts.SyntaxKind.NeverKeyword, + ts.SyntaxKind.NumberKeyword, + ts.SyntaxKind.StringKeyword, + ts.SyntaxKind.UndefinedKeyword, + ts.SyntaxKind.UnknownKeyword, + ts.SyntaxKind.VoidKeyword +]) + +const typeOperatorKeywords = new Map([ + [ts.SyntaxKind.KeyofKeyword, '_keyof'], + [ts.SyntaxKind.ReadonlyKeyword, '_readonly'], + [ts.SyntaxKind.UniqueKeyword, '_unique'], +]) + +class TSNode { + constructor(name, type) { + this.children = [] + this.addChild = (name, type) => { + let node = new TSNode(name, type) + this.children.push(node) + return node + } + this.getType = () => this.type + this.getObject = () => { + let map = {} + map[this.name] = this.children.length + ? this.children + .map(child => child.getObject()) + .reduce((pv, child) => { + for (let key in child) { + if (pv.hasOwnProperty(key) || key in pv) { + if (child[key]) { + Object.assign(pv[key], child[key]) + } + } else { + pv[key] = child[key] + } + } + return pv + }, {}) + : this.type + return map + }; + this.name = name + this.type = type + } +} + +function parameterTypeStructure(paramNode, checker) { + let typeStruc = typeStructure(paramNode.type, checker) + if (paramNode.questionToken) typeStruc = {_optional: typeStruc} + return typeStruc +} + +function typeStructure(typeNode, checker) { + switch (typeNode.kind) { + case ts.SyntaxKind.UnionType: + return { + _union: typeNode.types.map(t => typeStructure(t, checker)) + } + case ts.SyntaxKind.IntersectionType: + return { + _intersection: typeNode.types.map(t => typeStructure(t, checker)) + } + case ts.SyntaxKind.ImportType: { + const typeStruc = { + _importedFrom: typeNode.argument.literal.text, + _name: typeNode.qualifier.text + } + if (typeNode.typeArguments) { + typeStruc._typeArguments = typeNode.typeArguments.map( + p => typeStructure(p, checker)) + } + return typeStruc + } + case ts.SyntaxKind.ArrayType: + return {_array: typeStructure(typeNode.elementType, checker)} + case ts.SyntaxKind.TypeLiteral: // Seems to be plain object types + return Object.fromEntries(typeNode.members.map( + mem => [mem.name.text, typeStructure(mem.type, checker)])) + case ts.SyntaxKind.FunctionType: { + const typeStruc = { + _parameters: typeNode.parameters.map( + p => parameterTypeStructure(p, checker)), + _returns: typeStructure(typeNode.type, checker) + } + if (typeNode.typeParameters) { + typeStruc._typeParameters = typeNode.typeParameters.map( + p => p.name.text) + } + return typeStruc + } + case ts.SyntaxKind.IndexedAccessType: + return { + _ofType: typeStructure(typeNode.objectType, checker), + _index: typeStructure(typeNode.indexType, checker) + } + case ts.SyntaxKind.TypeOperator: + const key = typeOperatorKeywords.get( + typeNode.operator, + '_unidentified_operator' + ) + return { + [key]: + typeStructure(typeNode.type, checker) + } + case ts.SyntaxKind.ConditionalType: + return { + _subtype: typeStructure(typeNode.checkType, checker), + _basetype: typeStructure(typeNode.extendsType, checker), + _truetype: typeStructure(typeNode.trueType, checker), + _falsetype: typeStructure(typeNode.falseType, checker), + } + case ts.SyntaxKind.TypeReference: { + const typeStruc = {_typeParameter: typeNode.typeName.text} + if (typeNode.typeArguments) { + typeStruc._typeArguments = typeNode.typeArguments.map( + arg => typeStructure(arg, checker)) + } + return typeStruc + } + case ts.SyntaxKind.TypePredicate: + return {_is: typeStructure(typeNode.type, checker)} + case ts.SyntaxKind.LiteralType: + return checker.typeToString(checker.getTypeFromTypeNode(typeNode)) + default: + if (intrinsicTypeKeywords.has(typeNode.kind)) { + return checker.getTypeFromTypeNode(typeNode).intrinsicName + } + } + throw new Error(`Unhandled type node ${ts.SyntaxKind[typeNode.kind]}`) +} + +const visit = (parent, checker) => node => { + switch (node.kind) { + // Currently, we are ignoring the following sorts of statements + // that may appear in .d.ts files. We may need to revisit these, + // especially the InterfaceDeclaration and TypeAliasDeclaration, + // if we want to generate runtime information on pure type + // declarations. I think this may be necessary for example to compute + // the "RealType" of a type at runtime. + case ts.SyntaxKind.EndOfFileToken: + case ts.SyntaxKind.ExportDeclaration: + case ts.SyntaxKind.ImportDeclaration: + case ts.SyntaxKind.InterfaceDeclaration: + case ts.SyntaxKind.TypeAliasDeclaration: + break + case ts.SyntaxKind.VariableStatement: + node.declarationList.declarations.forEach(visit(parent, checker)) + break + case ts.SyntaxKind.VariableDeclaration: { + const typeStruc = typeStructure(node.type, checker) + parent.addChild(node.name.text, typeStruc) + break + } + case ts.SyntaxKind.FunctionDeclaration: { + const typeStruc = { + _parameters: node.parameters.map( + p => parameterTypeStructure(p, checker)), + _returns: typeStructure(node.type, checker) + } + if (node.typeParameters) { + typeStruc._typeParameters = node.typeParameters.map( + p => p.name.text) + } + parent.addChild(node.name.text, typeStruc) + break + } + case ts.SyntaxKind.ModuleDeclaration: + let moduleName = node.name.text + visit(parent.addChild(moduleName), checker)(node.body) + break + case ts.SyntaxKind.ModuleBlock: + ts.forEachChild(node, visit(parent, checker)); + break + case ts.SyntaxKind.PropertySignature: + let propertyName = node.name + let propertyType = node.type + let arrayDeep = 0 + let realPropertyName = + 'string' !== typeof propertyName && 'text' in propertyName + ? propertyName.text + : propertyName + console.log('Property', realPropertyName) + while (propertyType.kind === ts.SyntaxKind.ArrayType) { + arrayDeep++ + propertyType = propertyType.elementType + } + if (propertyType.kind === ts.SyntaxKind.TypeReference) { + let realPropertyType = propertyType.typeName + parent.addChild( + realPropertyName, + 'Array<'.repeat(arrayDeep) + + (realPropertyType.kind === ts.SyntaxKind.QualifiedName + ? realPropertyType.getText() + : 'text' in realPropertyType + ? realPropertyType.text + : realPropertyType) + + '>'.repeat(arrayDeep) + ) + } else { + if (intrinsicTypeKeywords.has(propertyType.kind)) { + parent.addChild( + realPropertyName, + checker.getTypeFromTypeNode(propertyType).intrinsicName) + } + } + break + default: + console.warn( + 'Unhandled node kind', + node.kind, ts.SyntaxKind[node.kind]) + } +} + +export default function(filename, options = {}) { + const ROOT_NAME = 'root' + const node = new TSNode(ROOT_NAME) + + let program = ts.createProgram([filename], options) + let checker = program.getTypeChecker() + const sourceFiles = program.getSourceFiles() + let sourceFile = sourceFiles.find(file => file.fileName === filename) + + ts.forEachChild(sourceFile, visit(node, checker)) + + return node.getObject()[ROOT_NAME] +} From 59c325ff6cd52ff49f08bb192418dae39a109e4f Mon Sep 17 00:00:00 2001 From: Glen Whitney Date: Mon, 21 Oct 2024 17:00:58 +0000 Subject: [PATCH 4/9] feat: Try two different kinds of type reflection (#5) Co-authored-by: Jos de Jong Reviewed-on: https://code.studioinfinity.org/glen/math5/pulls/5 Co-authored-by: Glen Whitney Co-committed-by: Glen Whitney --- package.json5 | 12 +- pnpm-lock.yaml | 309 ++++++++++++++++++++++++++++++++++++++++- src/Complex/type.ts | 3 +- src/core/Dispatcher.ts | 11 +- src/index.ts | 2 +- tools/reflectTypes.mjs | 62 +++++++++ tools/ts2json.mjs | 233 +++++++++++++++++++++++++++++++ 7 files changed, 618 insertions(+), 14 deletions(-) create mode 100644 tools/reflectTypes.mjs create mode 100644 tools/ts2json.mjs diff --git a/package.json5 b/package.json5 index 5ede49d..921d164 100644 --- a/package.json5 +++ b/package.json5 @@ -3,8 +3,9 @@ version: '0.0.1', description: 'Another prototype for a math core', scripts: { - build: 'tsc && cp etc/package.json build/', - go: 'pnpm build && pnpm start', + build: 'tsc && cpy etc/package.json build/ --flat', + reflect: 'node tools/reflectTypes.mjs', + go: 'pnpm build && pnpm reflect && pnpm start', start: 'node --experimental-loader tsc-module-loader build', test: 'echo Error no test specified && exit 1', }, @@ -21,9 +22,10 @@ url: 'https://code.studioinfinity.org/glen/math5.git', }, devDependencies: { - '@types/node': '^22.7.5', - typescript: '^5.6.3', - 'undici-types': '^6.20.0', + '@types/node': '22.7.5', + 'cpy-cli': '5.0.0', + typescript: '5.6.3', + 'undici-types': '6.20.0', }, dependencies: { 'tsc-module-loader': '^0.0.1', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2eb420d..cee7e06 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,45 +13,204 @@ importers: version: 0.0.1 devDependencies: '@types/node': - specifier: ^22.7.5 + specifier: 22.7.5 version: 22.7.5 + cpy-cli: + specifier: 5.0.0 + version: 5.0.0 typescript: - specifier: ^5.6.3 + specifier: 5.6.3 version: 5.6.3 undici-types: - specifier: ^6.20.0 + specifier: 6.20.0 version: 6.20.0 packages: + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + '@types/node@22.7.5': resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==} + aggregate-error@4.0.1: + resolution: {integrity: sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==} + engines: {node: '>=12'} + + arrify@3.0.0: + resolution: {integrity: sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==} + engines: {node: '>=12'} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + clean-stack@4.2.0: + resolution: {integrity: sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==} + engines: {node: '>=12'} + commonjs-extension-resolution-loader@0.1.0: resolution: {integrity: sha512-XDCkM/cYIt1CfPs+LNX8nC2KKrzTx5AAlGLpx7A4BjWQCHR9LphDu9Iq5zXYf+PXhCkpLGBFiyiTnwmSnNxbWQ==} + cp-file@10.0.0: + resolution: {integrity: sha512-vy2Vi1r2epK5WqxOLnskeKeZkdZvTKfFZQCplE3XWsP+SUJyd5XAUFC9lFgTjjXJF2GMne/UML14iEmkAaDfFg==} + engines: {node: '>=14.16'} + + cpy-cli@5.0.0: + resolution: {integrity: sha512-fb+DZYbL9KHc0BC4NYqGRrDIJZPXUmjjtqdw4XRRg8iV8dIfghUX/WiL+q4/B/KFTy3sK6jsbUhBaz0/Hxg7IQ==} + engines: {node: '>=16'} + hasBin: true + + cpy@10.1.0: + resolution: {integrity: sha512-VC2Gs20JcTyeQob6UViBLnyP0bYHkBh6EiKzot9vi2DmeGlFT9Wd7VG3NBrkNx/jYvFBeyDOMMHdHQhbtKLgHQ==} + engines: {node: '>=16'} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + + fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + + fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + globby@13.2.2: + resolution: {integrity: sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + indent-string@5.0.0: + resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} + engines: {node: '>=12'} + is-core-module@2.15.1: resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} engines: {node: '>= 0.4'} + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + junk@4.0.1: + resolution: {integrity: sha512-Qush0uP+G8ZScpGMZvHUiRfI0YBWuB3gVBYlI0v0vvOJt5FLicco+IkP0a50LqTTQhmts/m6tP5SWE+USyIvcQ==} + engines: {node: '>=12.20'} + + meow@12.1.1: + resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==} + engines: {node: '>=16.10'} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + nested-error-stacks@2.1.1: + resolution: {integrity: sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==} + + p-event@5.0.1: + resolution: {integrity: sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + p-filter@3.0.0: + resolution: {integrity: sha512-QtoWLjXAW++uTX67HZQz1dbTpqBfiidsB6VtQUC9iR85S120+s0T5sO6s+B5MLzFcZkrEd/DGMmCjR+f2Qpxwg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + p-map@5.5.0: + resolution: {integrity: sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==} + engines: {node: '>=12'} + + p-map@6.0.0: + resolution: {integrity: sha512-T8BatKGY+k5rU+Q/GTYgrEf2r4xRMevAN5mtXc2aPc4rS1j3s+vWTaO2Wag94neXuCAUAs8cxBL9EeB5EA6diw==} + engines: {node: '>=16'} + + p-timeout@5.1.0: + resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==} + engines: {node: '>=12'} + path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + slash@4.0.0: + resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} + engines: {node: '>=12'} + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + tsc-module-loader@0.0.1: resolution: {integrity: sha512-3SIydFXw96jYU2imgULgIHKlUY8FnfDZlazvNmw4Umx/8qCwXsyDg0V2QOULf2Fw7zaI1Hbibh0mB8VzRZ/Ghg==} @@ -68,34 +227,178 @@ packages: snapshots: + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.17.1 + '@types/node@22.7.5': dependencies: undici-types: 6.19.8 + aggregate-error@4.0.1: + dependencies: + clean-stack: 4.2.0 + indent-string: 5.0.0 + + arrify@3.0.0: {} + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + clean-stack@4.2.0: + dependencies: + escape-string-regexp: 5.0.0 + commonjs-extension-resolution-loader@0.1.0: dependencies: resolve: 1.22.8 + cp-file@10.0.0: + dependencies: + graceful-fs: 4.2.11 + nested-error-stacks: 2.1.1 + p-event: 5.0.1 + + cpy-cli@5.0.0: + dependencies: + cpy: 10.1.0 + meow: 12.1.1 + + cpy@10.1.0: + dependencies: + arrify: 3.0.0 + cp-file: 10.0.0 + globby: 13.2.2 + junk: 4.0.1 + micromatch: 4.0.8 + nested-error-stacks: 2.1.1 + p-filter: 3.0.0 + p-map: 6.0.0 + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + escape-string-regexp@5.0.0: {} + + fast-glob@3.3.2: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fastq@1.17.1: + dependencies: + reusify: 1.0.4 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + function-bind@1.1.2: {} + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + globby@13.2.2: + dependencies: + dir-glob: 3.0.1 + fast-glob: 3.3.2 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 4.0.0 + + graceful-fs@4.2.11: {} + hasown@2.0.2: dependencies: function-bind: 1.1.2 + ignore@5.3.2: {} + + indent-string@5.0.0: {} + is-core-module@2.15.1: dependencies: hasown: 2.0.2 + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + junk@4.0.1: {} + + meow@12.1.1: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + nested-error-stacks@2.1.1: {} + + p-event@5.0.1: + dependencies: + p-timeout: 5.1.0 + + p-filter@3.0.0: + dependencies: + p-map: 5.5.0 + + p-map@5.5.0: + dependencies: + aggregate-error: 4.0.1 + + p-map@6.0.0: {} + + p-timeout@5.1.0: {} + path-parse@1.0.7: {} + path-type@4.0.0: {} + + picomatch@2.3.1: {} + + queue-microtask@1.2.3: {} + resolve@1.22.8: dependencies: is-core-module: 2.15.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + reusify@1.0.4: {} + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + slash@4.0.0: {} + supports-preserve-symlinks-flag@1.0.0: {} + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + tsc-module-loader@0.0.1: dependencies: commonjs-extension-resolution-loader: 0.1.0 diff --git a/src/Complex/type.ts b/src/Complex/type.ts index 44525d6..ff42a3b 100644 --- a/src/Complex/type.ts +++ b/src/Complex/type.ts @@ -17,7 +17,8 @@ export const Complex_type = { (z: Complex) => joinTypes(dep.typeOf(z.re), dep.typeOf(z.im)), from: { Complex: (dep: {convert: CommonSignature['convert']}) => - (z: Complex) => ({re: dep.convert(z.re), im: dep.convert(z.im)}), + (z: Complex): Complex => + ({re: dep.convert(z.re), im: dep.convert(z.im)}), T: (dep: {zero: CommonSignature['zero']}) => (t: T) => ({re: t, im: dep.zero(t)}) } diff --git a/src/core/Dispatcher.ts b/src/core/Dispatcher.ts index 69b90ee..198b69a 100644 --- a/src/core/Dispatcher.ts +++ b/src/core/Dispatcher.ts @@ -102,6 +102,10 @@ type Implementations< Specs extends Specifications > = {[K in NeedKeys]: ImpType} +export interface ReflectedTypeInfo { + reflectedType5: string +} + // The builder interface that lets us assemble narrowly-typed Implementations: interface ImplementationBuilder< Signatures extends GenSigs, @@ -135,7 +139,7 @@ interface ImplementationBuilder< Specs & {[K in NewKeys]: DepCheck} > - ship(): Implementations + ship(info?: ReflectedTypeInfo): Implementations & ReflectedTypeInfo } // And a function that actually provides the builder interface: @@ -187,9 +191,8 @@ function impBuilder< Specs & {[K in NewKeys]: DepCheck} > }, - ship() { - return (sofar as - Implementations) + ship(info?: ReflectedTypeInfo) { + return { ...sofar, ...info } } } } diff --git a/src/index.ts b/src/index.ts index 66d4a5b..c575454 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,4 +2,4 @@ import {inspect} from 'node:util' import * as specifications from './all' -console.log(inspect(specifications, {depth: 8, colors: true})) +console.log(inspect(specifications, {depth: 18, colors: true})) diff --git a/tools/reflectTypes.mjs b/tools/reflectTypes.mjs new file mode 100644 index 0000000..c232072 --- /dev/null +++ b/tools/reflectTypes.mjs @@ -0,0 +1,62 @@ +import { readFileSync, writeFileSync, readdirSync } from 'node:fs' +import { fileURLToPath } from 'node:url' +import { dirname, join, relative } from 'node:path' + +import ts2json from './ts2json.mjs' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) + +const buildDir = join(__dirname, '..', 'build') +const files = (await readdirSync(buildDir, { recursive: true })) + .filter(file => file.endsWith('.js')) + .map(file => join(buildDir, file)) + +for (const file of files) { + reflectType5(file, { debug: true }) +} + +function reflectType5(srcFile, options = { debug: false }) { + log(`=========Reflecting file "${relative(__dirname, srcFile)}"`) + + const defFile = srcFile.replace(/.js$/, '.d.ts') + const src = String(readFileSync(srcFile)) + const defs = String(readFileSync(defFile)) + const parsedDefs = ts2json(defFile) + + const typeDefMatches = defs.matchAll(/: ({(?:(?!\n}).)+\n}) & (?:(?!ReflectedTypeInfo).)+ReflectedTypeInfo/gs) + if (!typeDefMatches) { + log('No ReflectedTypeInfo found.') + return + } + + const typeDefs = Array.from(typeDefMatches).map(def => def[1]) + log(` ${typeDefs.length} ReflectedTypeInfo found`) + + let index = 0 + let srcReflected = src.replaceAll(/(\s*)\.ship\(\)/g, () => { + const def = typeDefs[index] + index++ + return `.ship({ reflectedType5: \`${def}\` })` + }) + log(` ReflectedTypeInfo injected in ${index} occurrences of .ship()`) + + if (index !== typeDefs.length) { + log(' WARNING: not all ReflectedTypeInfo occurrences could be injected') + } + + for (const id in parsedDefs) { + if (id.includes('interface')) continue + if (parsedDefs[id] === undefined) continue + log(` Tagging ${id} with type data`, parsedDefs[id]) + srcReflected += + `\n${id}._reflectedType5 = ${JSON.stringify(parsedDefs[id])}\n` + } + writeFileSync(srcFile, srcReflected) + + function log(...args) { + if (options.debug) { + console.log(...args) + } + } +} diff --git a/tools/ts2json.mjs b/tools/ts2json.mjs new file mode 100644 index 0000000..4013acd --- /dev/null +++ b/tools/ts2json.mjs @@ -0,0 +1,233 @@ +import * as ts from 'typescript' + +const intrinsicTypeKeywords = new Set([ + ts.SyntaxKind.AnyKeyword, + ts.SyntaxKind.BooleanKeyword, + ts.SyntaxKind.NeverKeyword, + ts.SyntaxKind.NumberKeyword, + ts.SyntaxKind.StringKeyword, + ts.SyntaxKind.UndefinedKeyword, + ts.SyntaxKind.UnknownKeyword, + ts.SyntaxKind.VoidKeyword +]) + +const typeOperatorKeywords = new Map([ + [ts.SyntaxKind.KeyofKeyword, '_keyof'], + [ts.SyntaxKind.ReadonlyKeyword, '_readonly'], + [ts.SyntaxKind.UniqueKeyword, '_unique'], +]) + +class TSNode { + constructor(name, type) { + this.children = [] + this.addChild = (name, type) => { + let node = new TSNode(name, type) + this.children.push(node) + return node + } + this.getType = () => this.type + this.getObject = () => { + let map = {} + map[this.name] = this.children.length + ? this.children + .map(child => child.getObject()) + .reduce((pv, child) => { + for (let key in child) { + if (pv.hasOwnProperty(key) || key in pv) { + if (child[key]) { + Object.assign(pv[key], child[key]) + } + } else { + pv[key] = child[key] + } + } + return pv + }, {}) + : this.type + return map + }; + this.name = name + this.type = type + } +} + +function parameterTypeStructure(paramNode, checker) { + let typeStruc = typeStructure(paramNode.type, checker) + if (paramNode.questionToken) typeStruc = {_optional: typeStruc} + return typeStruc +} + +function typeStructure(typeNode, checker) { + switch (typeNode.kind) { + case ts.SyntaxKind.UnionType: + return { + _union: typeNode.types.map(t => typeStructure(t, checker)) + } + case ts.SyntaxKind.IntersectionType: + return { + _intersection: typeNode.types.map(t => typeStructure(t, checker)) + } + case ts.SyntaxKind.ImportType: { + const typeStruc = { + _importedFrom: typeNode.argument.literal.text, + _name: typeNode.qualifier.text + } + if (typeNode.typeArguments) { + typeStruc._typeArguments = typeNode.typeArguments.map( + p => typeStructure(p, checker)) + } + return typeStruc + } + case ts.SyntaxKind.ArrayType: + return {_array: typeStructure(typeNode.elementType, checker)} + case ts.SyntaxKind.TypeLiteral: // Seems to be plain object types + return Object.fromEntries(typeNode.members.map( + mem => [mem.name.text, typeStructure(mem.type, checker)])) + case ts.SyntaxKind.FunctionType: { + const typeStruc = { + _parameters: typeNode.parameters.map( + p => parameterTypeStructure(p, checker)), + _returns: typeStructure(typeNode.type, checker) + } + if (typeNode.typeParameters) { + typeStruc._typeParameters = typeNode.typeParameters.map( + p => p.name.text) + } + return typeStruc + } + case ts.SyntaxKind.IndexedAccessType: + return { + _ofType: typeStructure(typeNode.objectType, checker), + _index: typeStructure(typeNode.indexType, checker) + } + case ts.SyntaxKind.TypeOperator: + const key = typeOperatorKeywords.get( + typeNode.operator, + '_unidentified_operator' + ) + return { + [key]: + typeStructure(typeNode.type, checker) + } + case ts.SyntaxKind.ConditionalType: + return { + _subtype: typeStructure(typeNode.checkType, checker), + _basetype: typeStructure(typeNode.extendsType, checker), + _truetype: typeStructure(typeNode.trueType, checker), + _falsetype: typeStructure(typeNode.falseType, checker), + } + case ts.SyntaxKind.TypeReference: { + const typeStruc = {_typeParameter: typeNode.typeName.text} + if (typeNode.typeArguments) { + typeStruc._typeArguments = typeNode.typeArguments.map( + arg => typeStructure(arg, checker)) + } + return typeStruc + } + case ts.SyntaxKind.TypePredicate: + return {_is: typeStructure(typeNode.type, checker)} + case ts.SyntaxKind.LiteralType: + return checker.typeToString(checker.getTypeFromTypeNode(typeNode)) + default: + if (intrinsicTypeKeywords.has(typeNode.kind)) { + return checker.getTypeFromTypeNode(typeNode).intrinsicName + } + } + throw new Error(`Unhandled type node ${ts.SyntaxKind[typeNode.kind]}`) +} + +const visit = (parent, checker) => node => { + switch (node.kind) { + // Currently, we are ignoring the following sorts of statements + // that may appear in .d.ts files. We may need to revisit these, + // especially the InterfaceDeclaration and TypeAliasDeclaration, + // if we want to generate runtime information on pure type + // declarations. I think this may be necessary for example to compute + // the "RealType" of a type at runtime. + case ts.SyntaxKind.EndOfFileToken: + case ts.SyntaxKind.ExportDeclaration: + case ts.SyntaxKind.ImportDeclaration: + case ts.SyntaxKind.InterfaceDeclaration: + case ts.SyntaxKind.TypeAliasDeclaration: + break + case ts.SyntaxKind.VariableStatement: + node.declarationList.declarations.forEach(visit(parent, checker)) + break + case ts.SyntaxKind.VariableDeclaration: { + const typeStruc = typeStructure(node.type, checker) + parent.addChild(node.name.text, typeStruc) + break + } + case ts.SyntaxKind.FunctionDeclaration: { + const typeStruc = { + _parameters: node.parameters.map( + p => parameterTypeStructure(p, checker)), + _returns: typeStructure(node.type, checker) + } + if (node.typeParameters) { + typeStruc._typeParameters = node.typeParameters.map( + p => p.name.text) + } + parent.addChild(node.name.text, typeStruc) + break + } + case ts.SyntaxKind.ModuleDeclaration: + let moduleName = node.name.text + visit(parent.addChild(moduleName), checker)(node.body) + break + case ts.SyntaxKind.ModuleBlock: + ts.forEachChild(node, visit(parent, checker)); + break + case ts.SyntaxKind.PropertySignature: + let propertyName = node.name + let propertyType = node.type + let arrayDeep = 0 + let realPropertyName = + 'string' !== typeof propertyName && 'text' in propertyName + ? propertyName.text + : propertyName + console.log('Property', realPropertyName) + while (propertyType.kind === ts.SyntaxKind.ArrayType) { + arrayDeep++ + propertyType = propertyType.elementType + } + if (propertyType.kind === ts.SyntaxKind.TypeReference) { + let realPropertyType = propertyType.typeName + parent.addChild( + realPropertyName, + 'Array<'.repeat(arrayDeep) + + (realPropertyType.kind === ts.SyntaxKind.QualifiedName + ? realPropertyType.getText() + : 'text' in realPropertyType + ? realPropertyType.text + : realPropertyType) + + '>'.repeat(arrayDeep) + ) + } else { + if (intrinsicTypeKeywords.has(propertyType.kind)) { + parent.addChild( + realPropertyName, + checker.getTypeFromTypeNode(propertyType).intrinsicName) + } + } + break + default: + console.warn( + 'Unhandled node kind', + node.kind, ts.SyntaxKind[node.kind]) + } +} + +export default function(filename, options = {}) { + const ROOT_NAME = 'root' + const node = new TSNode(ROOT_NAME) + + let program = ts.createProgram([filename], options) + let checker = program.getTypeChecker() + const sourceFiles = program.getSourceFiles() + let sourceFile = sourceFiles.find(file => file.fileName === filename) + + ts.forEachChild(sourceFile, visit(node, checker)) + + return node.getObject()[ROOT_NAME] +} From 2a8823c5f7b75774980a7c5ddd2db8bbcaa57880 Mon Sep 17 00:00:00 2001 From: Jos de Jong Date: Mon, 21 Oct 2024 20:22:31 +0200 Subject: [PATCH 5/9] fix: `ts2json` not working on Windows --- tools/ts2json.mjs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/ts2json.mjs b/tools/ts2json.mjs index 4013acd..7a1c3e6 100644 --- a/tools/ts2json.mjs +++ b/tools/ts2json.mjs @@ -225,7 +225,8 @@ export default function(filename, options = {}) { let program = ts.createProgram([filename], options) let checker = program.getTypeChecker() const sourceFiles = program.getSourceFiles() - let sourceFile = sourceFiles.find(file => file.fileName === filename) + const filenameUnix = filename.replaceAll('\\', '/') + let sourceFile = sourceFiles.find(file => file.fileName === filenameUnix) ts.forEachChild(sourceFile, visit(node, checker)) From 75a950e830e823b3a89a54ea98e684beb2aaf7e3 Mon Sep 17 00:00:00 2001 From: Glen Whitney Date: Mon, 21 Oct 2024 21:46:52 +0000 Subject: [PATCH 6/9] chore: Remove string-based type injection via ship() (#8) Resolves #6. Reviewed-on: https://code.studioinfinity.org/glen/math5/pulls/8 Co-authored-by: Glen Whitney Co-committed-by: Glen Whitney --- tools/reflectTypes.mjs | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/tools/reflectTypes.mjs b/tools/reflectTypes.mjs index c232072..6ba6d9d 100644 --- a/tools/reflectTypes.mjs +++ b/tools/reflectTypes.mjs @@ -20,39 +20,17 @@ function reflectType5(srcFile, options = { debug: false }) { log(`=========Reflecting file "${relative(__dirname, srcFile)}"`) const defFile = srcFile.replace(/.js$/, '.d.ts') - const src = String(readFileSync(srcFile)) + let src = String(readFileSync(srcFile)) const defs = String(readFileSync(defFile)) const parsedDefs = ts2json(defFile) - const typeDefMatches = defs.matchAll(/: ({(?:(?!\n}).)+\n}) & (?:(?!ReflectedTypeInfo).)+ReflectedTypeInfo/gs) - if (!typeDefMatches) { - log('No ReflectedTypeInfo found.') - return - } - - const typeDefs = Array.from(typeDefMatches).map(def => def[1]) - log(` ${typeDefs.length} ReflectedTypeInfo found`) - - let index = 0 - let srcReflected = src.replaceAll(/(\s*)\.ship\(\)/g, () => { - const def = typeDefs[index] - index++ - return `.ship({ reflectedType5: \`${def}\` })` - }) - log(` ReflectedTypeInfo injected in ${index} occurrences of .ship()`) - - if (index !== typeDefs.length) { - log(' WARNING: not all ReflectedTypeInfo occurrences could be injected') - } - for (const id in parsedDefs) { if (id.includes('interface')) continue if (parsedDefs[id] === undefined) continue log(` Tagging ${id} with type data`, parsedDefs[id]) - srcReflected += - `\n${id}._reflectedType5 = ${JSON.stringify(parsedDefs[id])}\n` + src += `\n${id}._reflectedType5 = ${JSON.stringify(parsedDefs[id])}\n` } - writeFileSync(srcFile, srcReflected) + writeFileSync(srcFile, src) function log(...args) { if (options.debug) { From 3bc55fc3e0249bb1dd40af81d929320088911569 Mon Sep 17 00:00:00 2001 From: Glen Whitney Date: Mon, 21 Oct 2024 22:02:35 +0000 Subject: [PATCH 7/9] refactor: Rename `ship()` to `done()` (#9) Resolves #7. Reviewed-on: https://code.studioinfinity.org/glen/math5/pulls/9 Co-authored-by: Glen Whitney Co-committed-by: Glen Whitney --- src/Complex/arithmetic.ts | 4 ++-- src/Complex/type.ts | 4 ++-- src/core/Dispatcher.ts | 4 ++-- src/numbers/arithmetic.ts | 2 +- src/numbers/type.ts | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Complex/arithmetic.ts b/src/Complex/arithmetic.ts index f041d82..ac5a5b9 100644 --- a/src/Complex/arithmetic.ts +++ b/src/Complex/arithmetic.ts @@ -125,7 +125,7 @@ export function common() { return dep.divideReal(num, denom) } }) - .ship() + .done() } // Additional implementations for non-uniform signatures @@ -148,5 +148,5 @@ export function mixed() { divide: dep => (z, r) => dep.complex(dep.divTR(z.re, r), dep.divTR(z.im, r)) }) - .ship() + .done() } diff --git a/src/Complex/type.ts b/src/Complex/type.ts index ff42a3b..a97a894 100644 --- a/src/Complex/type.ts +++ b/src/Complex/type.ts @@ -48,7 +48,7 @@ export function lift() { return implementations>() .dependent({zero: {}}, { complex: dep => (a, b) => cplex(a, b || dep.zero(a)) - }).ship() + }).done() } export function common() { @@ -68,5 +68,5 @@ export function common() { .dependent(baseSignature({re: {}}), { re: dep => z => dep.re(z.re) }) - .ship() + .done() } diff --git a/src/core/Dispatcher.ts b/src/core/Dispatcher.ts index 198b69a..5ae8e06 100644 --- a/src/core/Dispatcher.ts +++ b/src/core/Dispatcher.ts @@ -139,7 +139,7 @@ interface ImplementationBuilder< Specs & {[K in NewKeys]: DepCheck} > - ship(info?: ReflectedTypeInfo): Implementations & ReflectedTypeInfo + done(info?: ReflectedTypeInfo): Implementations & ReflectedTypeInfo } // And a function that actually provides the builder interface: @@ -191,7 +191,7 @@ function impBuilder< Specs & {[K in NewKeys]: DepCheck} > }, - ship(info?: ReflectedTypeInfo) { + done(info?: ReflectedTypeInfo) { return { ...sofar, ...info } } } diff --git a/src/numbers/arithmetic.ts b/src/numbers/arithmetic.ts index 799d8b8..b4f45b3 100644 --- a/src/numbers/arithmetic.ts +++ b/src/numbers/arithmetic.ts @@ -23,4 +23,4 @@ export const common = implementations>() return dep.complex(0, Math.sqrt(-a)) } }}) - .ship() + .done() diff --git a/src/numbers/type.ts b/src/numbers/type.ts index 7807d54..2d53929 100644 --- a/src/numbers/type.ts +++ b/src/numbers/type.ts @@ -28,4 +28,4 @@ export const common = implementations>() one: a => 1, nan: a => NaN, re: a => a - }).ship() + }).done() From 06909a6a5ecab92e5b025b2bc37e45f055485aa5 Mon Sep 17 00:00:00 2001 From: Glen Whitney Date: Fri, 25 Oct 2024 15:27:02 +0000 Subject: [PATCH 8/9] feat: Barest outline of a Dispatcher, providing only typeOf so far (#11) Reviewed-on: https://code.studioinfinity.org/glen/math5/pulls/11 Co-authored-by: Glen Whitney Co-committed-by: Glen Whitney --- src/Complex/type.ts | 4 +- src/core/Dispatcher.ts | 132 ++++++++++++++++++++++++++++++++++++++--- src/index.ts | 11 +++- 3 files changed, 136 insertions(+), 11 deletions(-) diff --git a/src/Complex/type.ts b/src/Complex/type.ts index a97a894..623d20b 100644 --- a/src/Complex/type.ts +++ b/src/Complex/type.ts @@ -14,7 +14,9 @@ export const Complex_type = { typeof z === 'object' && z != null && 're' in z && 'im' in z && dep.testT(z.re) && dep.testT(z.im), infer: (dep: {typeOf: CommonSignature['typeOf']}) => - (z: Complex) => joinTypes(dep.typeOf(z.re), dep.typeOf(z.im)), + (z: Complex) => ({ + T: joinTypes(dep.typeOf(z.re), dep.typeOf(z.im)) + }), from: { Complex: (dep: {convert: CommonSignature['convert']}) => (z: Complex): Complex => diff --git a/src/core/Dispatcher.ts b/src/core/Dispatcher.ts index 5ae8e06..73d2aae 100644 --- a/src/core/Dispatcher.ts +++ b/src/core/Dispatcher.ts @@ -1,3 +1,4 @@ +import {inspect} from 'node:util' import type {AnyFunc, CommonSignature, GenSigs} from '@/interfaces/type' // A base type that roughly describes the dependencies of a single factory @@ -102,10 +103,6 @@ type Implementations< Specs extends Specifications > = {[K in NeedKeys]: ImpType} -export interface ReflectedTypeInfo { - reflectedType5: string -} - // The builder interface that lets us assemble narrowly-typed Implementations: interface ImplementationBuilder< Signatures extends GenSigs, @@ -139,7 +136,7 @@ interface ImplementationBuilder< Specs & {[K in NewKeys]: DepCheck} > - done(info?: ReflectedTypeInfo): Implementations & ReflectedTypeInfo + done(): Implementations } // And a function that actually provides the builder interface: @@ -191,8 +188,8 @@ function impBuilder< Specs & {[K in NewKeys]: DepCheck} > }, - done(info?: ReflectedTypeInfo) { - return { ...sofar, ...info } + done() { + return sofar } } } @@ -202,3 +199,124 @@ export function implementations( ): ImplementationBuilder { return impBuilder({}) } + +// Now we turn to creating a Dispatcher itself. For this we use loose types, +// and rely on the type annotations from our special build for runtime type +// identification. + +type Callable = (...args: any) => any +type Implementation = {implementation: Callable} +type Factory = {factory: Callable, dependencies: Record} +type Reflected = {_reflectedType5: any} +type TypeSpec = { + name: string, + before?: string[], + test: Callable, + from: Record, + infer?: Callable +} +type ImpItem = Implementation | Factory +type ImpGroup = Record + +// When this is being compiled, TypeScript can't tell that the +// ImpSpecification entities will have been reflected: +type ImpSpecification = (ImpGroup | (() => ImpGroup) | TypeSpec) // & Reflected + +interface ImpSpecs extends Record {} + +type ImpHolder = { + implementations: Record, // Key is a signature + factories: Record +} + +type DispatcherInstance = { + implementationData: Record, // Key is an operation name + types: TypeSpec[], // Order is order to try types in + behaviors: Record, // Key is opname; actually executable! +} + +function newDispatcherInstance(): DispatcherInstance { + return { + implementationData: {}, + types: [], + behaviors: {} + } +} + +function isTypeSpec(spec: ImpSpecification | ImpSpecs): spec is TypeSpec { + if ('name' in spec + && typeof spec.name === 'string' + && 'test' in spec + && 'from' in spec + ) { + return true + } + return false +} + +// The assemble function creates a dispatcher from a mess of specifications +export function assemble(specifications: ImpSpecs, into?: DispatcherInstance ) { + if (into === undefined) { + into = newDispatcherInstance() + const show = inspect(specifications, {depth: 18, colors: true}) + console.log('Specifications are', show) + } + for (const specName in specifications) { + console.log('Processing', specName) + const spec = specifications[specName] + if ('_reflectedType5' in spec) { + if (isTypeSpec(spec)) { + registerTypeSpec(spec, into) + continue + } + // implementations that we need to deal with + console.log('Need to incorporate', Object.keys(spec)) + } else { + // Just another layer of specification + assemble(spec as ImpSpecs, into) + } + } + into.behaviors.typeOf = (a: unknown) => whichType(a, into.types) + return into.behaviors +} + +function registerTypeSpec(typeSpec: TypeSpec, into: DispatcherInstance) { + let position = into.types.length + if ('before' in typeSpec) { + for (const typeName of typeSpec.before) { + const typeIndex = into.types.findIndex(t => t.name = typeName) + if (typeIndex >= 0 && typeIndex < position) position = typeIndex + } + } + into.types.splice(position, 0, typeSpec) + // likely there will be more to do in the long run +} + +// Returns the string name of the type of _a_ per the type specifications +// in _types_, or 'unknown' if no type matches +function whichType(a: unknown, types: TypeSpec[]) { + for (const typeSpec of types) { + const typeName = typeSpec.name + // First check if this is a ground type or a generic: + const typeSpecType = (typeSpec as TypeSpec & Reflected)._reflectedType5 + if (!('_typeParameters' in typeSpecType.test)) { + // ground type, just test it + if (typeSpec.test(a)) return typeName + continue + } + // Generic type. In this case, the test will be a factory, dependent + // on a test for each of the type parameters. So assemble those + // dependencies: + const typePars = typeSpecType.test._typeParameters + const permissiveTests = Object.fromEntries(typePars.map(k => + [`test${k}`, x => true])) + const testAllUnknown = typeSpec.test(permissiveTests) + if (!testAllUnknown(a)) continue + // Here, a seems to be in some instantiation of this generic type. + // Need to infer which instantiation + const thisInfer = typeSpec.infer({typeOf: x => whichType(x, types)}) + const typeArguments = thisInfer(a) + return `${typeName}<${typePars.map(k => typeArguments[k]).join(',')}>` + } + return 'unknown' +} diff --git a/src/index.ts b/src/index.ts index c575454..2523518 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,10 @@ -import {inspect} from 'node:util' - +import {assemble} from '@/core/Dispatcher' import * as specifications from './all' -console.log(inspect(specifications, {depth: 18, colors: true})) +const math = assemble(specifications) +console.log('PRODUCED', math) + +console.log(math.typeOf(17)) +console.log(math.typeOf({re: 3.4, im: -0.1})) +console.log(math.typeOf({re: {re: 1, im: 0}, im: {re: 0, im: -1}})) +console.log(math.typeOf('no string type yet')) From 047385d56b472f4d1b6bc3be9786306f85aca4d4 Mon Sep 17 00:00:00 2001 From: Glen Whitney Date: Mon, 28 Oct 2024 22:34:55 +0000 Subject: [PATCH 9/9] Enable testing with vitest (#13) Resolves #12. Co-authored-by: Jos de Jong Reviewed-on: https://code.studioinfinity.org/glen/math5/pulls/13 Co-authored-by: Glen Whitney Co-committed-by: Glen Whitney --- .gitignore | 3 + etc/vitest.config.ts | 16 + package.json5 | 6 +- pnpm-lock.yaml | 770 +++++++++++++++++++++++++++++++++++++++++++ src/index.ts | 11 +- src/math5.ts | 20 ++ tsconfig.json | 8 +- 7 files changed, 820 insertions(+), 14 deletions(-) create mode 100644 etc/vitest.config.ts create mode 100644 src/math5.ts diff --git a/.gitignore b/.gitignore index af4b6f4..4e61efd 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,6 @@ node_modules/ # IDE .idea + +# Vitest +.vite diff --git a/etc/vitest.config.ts b/etc/vitest.config.ts new file mode 100644 index 0000000..8614e26 --- /dev/null +++ b/etc/vitest.config.ts @@ -0,0 +1,16 @@ +import {dirname} from 'node:path' +import {defineConfig} from 'vitest/config' + +const rootDir = dirname(__dirname) + +export default defineConfig({ + test: { + includeSource: ['build/**/*.js'], + alias: [ + { + find: /^@(.*)/, + replacement: rootDir + '/build$1.js' + }, + ], + }, +}) diff --git a/package.json5 b/package.json5 index 921d164..d29e4f5 100644 --- a/package.json5 +++ b/package.json5 @@ -5,9 +5,10 @@ scripts: { build: 'tsc && cpy etc/package.json build/ --flat', reflect: 'node tools/reflectTypes.mjs', - go: 'pnpm build && pnpm reflect && pnpm start', + refbuild: 'pnpm build && pnpm reflect', + go: 'pnpm refbuild && pnpm start', start: 'node --experimental-loader tsc-module-loader build', - test: 'echo Error no test specified && exit 1', + test: 'pnpm refbuild && vitest run --config etc/vitest.config.ts', }, packageManager: 'pnpm@9', keywords: [ @@ -26,6 +27,7 @@ 'cpy-cli': '5.0.0', typescript: '5.6.3', 'undici-types': '6.20.0', + vitest: '^2.1.3', }, dependencies: { 'tsc-module-loader': '^0.0.1', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cee7e06..71b3474 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,9 +24,153 @@ importers: undici-types: specifier: 6.20.0 version: 6.20.0 + vitest: + specifier: ^2.1.3 + version: 2.1.3(@types/node@22.7.5) packages: + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -39,9 +183,122 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@rollup/rollup-android-arm-eabi@4.24.0': + resolution: {integrity: sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.24.0': + resolution: {integrity: sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.24.0': + resolution: {integrity: sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.24.0': + resolution: {integrity: sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-linux-arm-gnueabihf@4.24.0': + resolution: {integrity: sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.24.0': + resolution: {integrity: sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.24.0': + resolution: {integrity: sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.24.0': + resolution: {integrity: sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.24.0': + resolution: {integrity: sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.24.0': + resolution: {integrity: sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.24.0': + resolution: {integrity: sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.24.0': + resolution: {integrity: sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.24.0': + resolution: {integrity: sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.24.0': + resolution: {integrity: sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.24.0': + resolution: {integrity: sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.24.0': + resolution: {integrity: sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==} + cpu: [x64] + os: [win32] + + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/node@22.7.5': resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==} + '@vitest/expect@2.1.3': + resolution: {integrity: sha512-SNBoPubeCJhZ48agjXruCI57DvxcsivVDdWz+SSsmjTT4QN/DfHk3zB/xKsJqMs26bLZ/pNRLnCf0j679i0uWQ==} + + '@vitest/mocker@2.1.3': + resolution: {integrity: sha512-eSpdY/eJDuOvuTA3ASzCjdithHa+GIF1L4PqtEELl6Qa3XafdMLBpBlZCIUCX2J+Q6sNmjmxtosAG62fK4BlqQ==} + peerDependencies: + '@vitest/spy': 2.1.3 + msw: ^2.3.5 + vite: ^5.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@2.1.3': + resolution: {integrity: sha512-XH1XdtoLZCpqV59KRbPrIhFCOO0hErxrQCMcvnQete3Vibb9UeIOX02uFPfVn3Z9ZXsq78etlfyhnkmIZSzIwQ==} + + '@vitest/runner@2.1.3': + resolution: {integrity: sha512-JGzpWqmFJ4fq5ZKHtVO3Xuy1iF2rHGV4d/pdzgkYHm1+gOzNZtqjvyiaDGJytRyMU54qkxpNzCx+PErzJ1/JqQ==} + + '@vitest/snapshot@2.1.3': + resolution: {integrity: sha512-qWC2mWc7VAXmjAkEKxrScWHWFyCQx/cmiZtuGqMi+WwqQJ2iURsVY4ZfAK6dVo6K2smKRU6l3BPwqEBvhnpQGg==} + + '@vitest/spy@2.1.3': + resolution: {integrity: sha512-Nb2UzbcUswzeSP7JksMDaqsI43Sj5+Kry6ry6jQJT4b5gAK+NS9NED6mDb8FlMRCX8m5guaHCDZmqYMMWRy5nQ==} + + '@vitest/utils@2.1.3': + resolution: {integrity: sha512-xpiVfDSg1RrYT0tX6czgerkpcKFmFOF/gCr30+Mve5V2kewCy4Prn1/NDMSRwaSmT7PRaOF83wu+bEtsY1wrvA==} + aggregate-error@4.0.1: resolution: {integrity: sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==} engines: {node: '>=12'} @@ -50,10 +307,26 @@ packages: resolution: {integrity: sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==} engines: {node: '>=12'} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + chai@5.1.2: + resolution: {integrity: sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==} + engines: {node: '>=12'} + + check-error@2.1.1: + resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + engines: {node: '>= 16'} + clean-stack@4.2.0: resolution: {integrity: sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==} engines: {node: '>=12'} @@ -74,14 +347,35 @@ packages: resolution: {integrity: sha512-VC2Gs20JcTyeQob6UViBLnyP0bYHkBh6EiKzot9vi2DmeGlFT9Wd7VG3NBrkNx/jYvFBeyDOMMHdHQhbtKLgHQ==} engines: {node: '>=16'} + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + escape-string-regexp@5.0.0: resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} engines: {node: '>=12'} + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} @@ -93,6 +387,11 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} @@ -139,6 +438,12 @@ packages: resolution: {integrity: sha512-Qush0uP+G8ZScpGMZvHUiRfI0YBWuB3gVBYlI0v0vvOJt5FLicco+IkP0a50LqTTQhmts/m6tP5SWE+USyIvcQ==} engines: {node: '>=12.20'} + loupe@3.1.2: + resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==} + + magic-string@0.30.12: + resolution: {integrity: sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==} + meow@12.1.1: resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==} engines: {node: '>=16.10'} @@ -151,6 +456,14 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + nested-error-stacks@2.1.1: resolution: {integrity: sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==} @@ -181,10 +494,24 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + + pathval@2.0.0: + resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} + engines: {node: '>= 14.16'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + postcss@8.4.47: + resolution: {integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==} + engines: {node: ^10 || ^12 || >=14} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -196,17 +523,53 @@ packages: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rollup@4.24.0: + resolution: {integrity: sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + slash@4.0.0: resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} engines: {node: '>=12'} + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@3.7.0: + resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.1: + resolution: {integrity: sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==} + + tinypool@1.0.1: + resolution: {integrity: sha512-URZYihUbRPcGv95En+sz6MfghfIc2OJ1sv/RmhWZLouPY0/8Vo80viwPvg3dlaS9fuq7fQMEfgRRK7BBZThBEA==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@1.2.0: + resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==} + engines: {node: '>=14.0.0'} + + tinyspy@3.0.2: + resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} + engines: {node: '>=14.0.0'} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -225,8 +588,145 @@ packages: undici-types@6.20.0: resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + vite-node@2.1.3: + resolution: {integrity: sha512-I1JadzO+xYX887S39Do+paRePCKoiDrWRRjp9kkG5he0t7RXNvPAJPCQSJqbGN4uCrFFeS3Kj3sLqY8NMYBEdA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + + vite@5.4.10: + resolution: {integrity: sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + vitest@2.1.3: + resolution: {integrity: sha512-Zrxbg/WiIvUP2uEzelDNTXmEMJXuzJ1kCpbDvaKByFA9MNeO95V+7r/3ti0qzJzrxdyuUw5VduN7k+D3VmVOSA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 2.1.3 + '@vitest/ui': 2.1.3 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + snapshots: + '@esbuild/aix-ppc64@0.21.5': + optional: true + + '@esbuild/android-arm64@0.21.5': + optional: true + + '@esbuild/android-arm@0.21.5': + optional: true + + '@esbuild/android-x64@0.21.5': + optional: true + + '@esbuild/darwin-arm64@0.21.5': + optional: true + + '@esbuild/darwin-x64@0.21.5': + optional: true + + '@esbuild/freebsd-arm64@0.21.5': + optional: true + + '@esbuild/freebsd-x64@0.21.5': + optional: true + + '@esbuild/linux-arm64@0.21.5': + optional: true + + '@esbuild/linux-arm@0.21.5': + optional: true + + '@esbuild/linux-ia32@0.21.5': + optional: true + + '@esbuild/linux-loong64@0.21.5': + optional: true + + '@esbuild/linux-mips64el@0.21.5': + optional: true + + '@esbuild/linux-ppc64@0.21.5': + optional: true + + '@esbuild/linux-riscv64@0.21.5': + optional: true + + '@esbuild/linux-s390x@0.21.5': + optional: true + + '@esbuild/linux-x64@0.21.5': + optional: true + + '@esbuild/netbsd-x64@0.21.5': + optional: true + + '@esbuild/openbsd-x64@0.21.5': + optional: true + + '@esbuild/sunos-x64@0.21.5': + optional: true + + '@esbuild/win32-arm64@0.21.5': + optional: true + + '@esbuild/win32-ia32@0.21.5': + optional: true + + '@esbuild/win32-x64@0.21.5': + optional: true + + '@jridgewell/sourcemap-codec@1.5.0': {} + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -239,10 +739,100 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 + '@rollup/rollup-android-arm-eabi@4.24.0': + optional: true + + '@rollup/rollup-android-arm64@4.24.0': + optional: true + + '@rollup/rollup-darwin-arm64@4.24.0': + optional: true + + '@rollup/rollup-darwin-x64@4.24.0': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.24.0': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.24.0': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.24.0': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.24.0': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.24.0': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.24.0': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.24.0': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.24.0': + optional: true + + '@rollup/rollup-linux-x64-musl@4.24.0': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.24.0': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.24.0': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.24.0': + optional: true + + '@types/estree@1.0.6': {} + '@types/node@22.7.5': dependencies: undici-types: 6.19.8 + '@vitest/expect@2.1.3': + dependencies: + '@vitest/spy': 2.1.3 + '@vitest/utils': 2.1.3 + chai: 5.1.2 + tinyrainbow: 1.2.0 + + '@vitest/mocker@2.1.3(@vitest/spy@2.1.3)(vite@5.4.10(@types/node@22.7.5))': + dependencies: + '@vitest/spy': 2.1.3 + estree-walker: 3.0.3 + magic-string: 0.30.12 + optionalDependencies: + vite: 5.4.10(@types/node@22.7.5) + + '@vitest/pretty-format@2.1.3': + dependencies: + tinyrainbow: 1.2.0 + + '@vitest/runner@2.1.3': + dependencies: + '@vitest/utils': 2.1.3 + pathe: 1.1.2 + + '@vitest/snapshot@2.1.3': + dependencies: + '@vitest/pretty-format': 2.1.3 + magic-string: 0.30.12 + pathe: 1.1.2 + + '@vitest/spy@2.1.3': + dependencies: + tinyspy: 3.0.2 + + '@vitest/utils@2.1.3': + dependencies: + '@vitest/pretty-format': 2.1.3 + loupe: 3.1.2 + tinyrainbow: 1.2.0 + aggregate-error@4.0.1: dependencies: clean-stack: 4.2.0 @@ -250,10 +840,24 @@ snapshots: arrify@3.0.0: {} + assertion-error@2.0.1: {} + braces@3.0.3: dependencies: fill-range: 7.1.1 + cac@6.7.14: {} + + chai@5.1.2: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.1.2 + pathval: 2.0.0 + + check-error@2.1.1: {} + clean-stack@4.2.0: dependencies: escape-string-regexp: 5.0.0 @@ -284,12 +888,48 @@ snapshots: p-filter: 3.0.0 p-map: 6.0.0 + debug@4.3.7: + dependencies: + ms: 2.1.3 + + deep-eql@5.0.2: {} + dir-glob@3.0.1: dependencies: path-type: 4.0.0 + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + escape-string-regexp@5.0.0: {} + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.6 + fast-glob@3.3.2: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -306,6 +946,9 @@ snapshots: dependencies: to-regex-range: 5.0.1 + fsevents@2.3.3: + optional: true + function-bind@1.1.2: {} glob-parent@5.1.2: @@ -344,6 +987,12 @@ snapshots: junk@4.0.1: {} + loupe@3.1.2: {} + + magic-string@0.30.12: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + meow@12.1.1: {} merge2@1.4.1: {} @@ -353,6 +1002,10 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 + ms@2.1.3: {} + + nanoid@3.3.7: {} + nested-error-stacks@2.1.1: {} p-event@5.0.1: @@ -375,8 +1028,20 @@ snapshots: path-type@4.0.0: {} + pathe@1.1.2: {} + + pathval@2.0.0: {} + + picocolors@1.1.1: {} + picomatch@2.3.1: {} + postcss@8.4.47: + dependencies: + nanoid: 3.3.7 + picocolors: 1.1.1 + source-map-js: 1.2.1 + queue-microtask@1.2.3: {} resolve@1.22.8: @@ -387,14 +1052,54 @@ snapshots: reusify@1.0.4: {} + rollup@4.24.0: + dependencies: + '@types/estree': 1.0.6 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.24.0 + '@rollup/rollup-android-arm64': 4.24.0 + '@rollup/rollup-darwin-arm64': 4.24.0 + '@rollup/rollup-darwin-x64': 4.24.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.24.0 + '@rollup/rollup-linux-arm-musleabihf': 4.24.0 + '@rollup/rollup-linux-arm64-gnu': 4.24.0 + '@rollup/rollup-linux-arm64-musl': 4.24.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.24.0 + '@rollup/rollup-linux-riscv64-gnu': 4.24.0 + '@rollup/rollup-linux-s390x-gnu': 4.24.0 + '@rollup/rollup-linux-x64-gnu': 4.24.0 + '@rollup/rollup-linux-x64-musl': 4.24.0 + '@rollup/rollup-win32-arm64-msvc': 4.24.0 + '@rollup/rollup-win32-ia32-msvc': 4.24.0 + '@rollup/rollup-win32-x64-msvc': 4.24.0 + fsevents: 2.3.3 + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 + siginfo@2.0.0: {} + slash@4.0.0: {} + source-map-js@1.2.1: {} + + stackback@0.0.2: {} + + std-env@3.7.0: {} + supports-preserve-symlinks-flag@1.0.0: {} + tinybench@2.9.0: {} + + tinyexec@0.3.1: {} + + tinypool@1.0.1: {} + + tinyrainbow@1.2.0: {} + + tinyspy@3.0.2: {} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -409,3 +1114,68 @@ snapshots: undici-types@6.19.8: {} undici-types@6.20.0: {} + + vite-node@2.1.3(@types/node@22.7.5): + dependencies: + cac: 6.7.14 + debug: 4.3.7 + pathe: 1.1.2 + vite: 5.4.10(@types/node@22.7.5) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + vite@5.4.10(@types/node@22.7.5): + dependencies: + esbuild: 0.21.5 + postcss: 8.4.47 + rollup: 4.24.0 + optionalDependencies: + '@types/node': 22.7.5 + fsevents: 2.3.3 + + vitest@2.1.3(@types/node@22.7.5): + dependencies: + '@vitest/expect': 2.1.3 + '@vitest/mocker': 2.1.3(@vitest/spy@2.1.3)(vite@5.4.10(@types/node@22.7.5)) + '@vitest/pretty-format': 2.1.3 + '@vitest/runner': 2.1.3 + '@vitest/snapshot': 2.1.3 + '@vitest/spy': 2.1.3 + '@vitest/utils': 2.1.3 + chai: 5.1.2 + debug: 4.3.7 + magic-string: 0.30.12 + pathe: 1.1.2 + std-env: 3.7.0 + tinybench: 2.9.0 + tinyexec: 0.3.1 + tinypool: 1.0.1 + tinyrainbow: 1.2.0 + vite: 5.4.10(@types/node@22.7.5) + vite-node: 2.1.3(@types/node@22.7.5) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 22.7.5 + transitivePeerDependencies: + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 diff --git a/src/index.ts b/src/index.ts index 2523518..606cb1c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,3 @@ -import {assemble} from '@/core/Dispatcher' -import * as specifications from './all' +import math from './math5' -const math = assemble(specifications) -console.log('PRODUCED', math) - -console.log(math.typeOf(17)) -console.log(math.typeOf({re: 3.4, im: -0.1})) -console.log(math.typeOf({re: {re: 1, im: 0}, im: {re: 0, im: -1}})) -console.log(math.typeOf('no string type yet')) +console.log('The math module:', math) diff --git a/src/math5.ts b/src/math5.ts new file mode 100644 index 0000000..f9e82f8 --- /dev/null +++ b/src/math5.ts @@ -0,0 +1,20 @@ +import {assemble} from '@/core/Dispatcher' +import * as specifications from './all' + +const math = assemble(specifications) +export default math + +if (import.meta.vitest) { + const {it, expect} = import.meta.vitest + + it('Can type numbers and Complex', () => { + expect(math.typeOf(-7.5)).toBe('number') + expect(math.typeOf({re:2, im: 0.5})).toBe('Complex') + expect(math.typeOf({re: {re: -1, im: 3}, im: {re: 0, im: 2.2}})) + .toBe('Complex>') + }) + + it("Doesn't have a string type yet", () => { + expect(math.typeOf('foo')).toBe('unknown') + }) +} diff --git a/tsconfig.json b/tsconfig.json index 8e4baa2..a61b2e9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,13 +6,15 @@ "paths": { "@/*": ["./src/*"], "ts-macros": ["./node_modules/ts-macros/dist/index.js"], - "undici-types": ["./node_modules/undici-types/index.d.ts"] + "undici-types": ["./node_modules/undici-types/index.d.ts"], + "vitest": ["./node_modules/vitest/dist/index.js"], }, "plugins": [ { "transform": "ts-macros" } ], "rootDir": "./src", "target": "esnext", - "types": ["node"] - } + "types": ["node", "vitest/importMeta"] + }, + "include": ["src/**/*"] }