diff --git a/.changeset/publish-types-layout.md b/.changeset/publish-types-layout.md new file mode 100644 index 000000000..1b50e5c9c --- /dev/null +++ b/.changeset/publish-types-layout.md @@ -0,0 +1,33 @@ +--- +"@tko/bind": patch +"@tko/binding.component": patch +"@tko/binding.core": patch +"@tko/binding.foreach": patch +"@tko/binding.if": patch +"@tko/binding.template": patch +"@tko/builder": patch +"@tko/build.knockout": patch +"@tko/build.reference": patch +"@tko/computed": patch +"@tko/filter.punches": patch +"@tko/lifecycle": patch +"@tko/observable": patch +"@tko/provider": patch +"@tko/provider.attr": patch +"@tko/provider.bindingstring": patch +"@tko/provider.component": patch +"@tko/provider.databind": patch +"@tko/provider.multi": patch +"@tko/provider.mustache": patch +"@tko/provider.native": patch +"@tko/provider.virtual": patch +"@tko/utils": patch +"@tko/utils.component": patch +"@tko/utils.functionrewrite": patch +"@tko/utils.jsx": patch +"@tko/utils.parser": patch +--- + +Publish generated `types/` folders for all public packages and both bundled builds, and advertise those declarations through package `types` metadata and `exports` conditions so consumer imports resolve the shipped type surface instead of repo-only sources. + +This also corrects the published module metadata for modern TypeScript package modes by routing `import` and `require` consumers to mode-appropriate JavaScript and declaration entrypoints. Packages now publish ESM/CJS-aware declaration entries so `bundler`, `node16`, and `nodenext` consumers resolve the shipped surface consistently instead of hitting Node-specific module-resolution mismatches. diff --git a/.github/workflows/lint-and-typecheck.yml b/.github/workflows/lint-and-typecheck.yml index b3fd0b3eb..798782a11 100644 --- a/.github/workflows/lint-and-typecheck.yml +++ b/.github/workflows/lint-and-typecheck.yml @@ -32,3 +32,6 @@ jobs: - name: Typecheck run: bunx tsc + + - name: Verify types (smoke test .d.ts) + run: bun run verify:types diff --git a/.github/workflows/publish-check.yml b/.github/workflows/publish-check.yml index d9de07a06..477233d8c 100644 --- a/.github/workflows/publish-check.yml +++ b/.github/workflows/publish-check.yml @@ -30,35 +30,5 @@ jobs: - name: Build all packages run: bun run build - - name: Check package contents - run: | - # Verify each public package has dist files and valid package.json - for pkg in packages/*/; do - if [ -f "$pkg/package.json" ]; then - name=$(node -e "const p=require('./$pkg/package.json'); if(!p.private) console.log(p.name)") - if [ -n "$name" ]; then - echo "Checking $name..." - # Verify dist directory exists and has files - if [ ! -d "$pkg/dist" ] || [ -z "$(ls -A "$pkg/dist" 2>/dev/null)" ]; then - echo "ERROR: $name has no dist output" - exit 1 - fi - # Run npm pack dry-run to verify publishable - (cd "$pkg" && npm pack --dry-run 2>&1) || exit 1 - fi - fi - done - for pkg in builds/*/; do - if [ -f "$pkg/package.json" ]; then - name=$(node -e "const p=require('./$pkg/package.json'); if(!p.private) console.log(p.name)") - if [ -n "$name" ]; then - echo "Checking $name..." - if [ ! -d "$pkg/dist" ] || [ -z "$(ls -A "$pkg/dist" 2>/dev/null)" ]; then - echo "ERROR: $name has no dist output" - exit 1 - fi - (cd "$pkg" && npm pack --dry-run 2>&1) || exit 1 - fi - fi - done - echo "All packages pass publish check." + - name: Check published package layout and types + run: bun run verify:publish-types diff --git a/.gitignore b/.gitignore index bd410d818..8a547d8ac 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,8 @@ COVERAGE.md builds/**/meta .nyc_output **/dist/* +packages/*/types/* +builds/*/types/* !packages/tko/dist/* *-debug.log diff --git a/builds/knockout/package.json b/builds/knockout/package.json index eaaff8984..7c9532836 100644 --- a/builds/knockout/package.json +++ b/builds/knockout/package.json @@ -26,7 +26,8 @@ ] }, "files": [ - "dist/" + "dist/", + "types/" ], "licenses": [ { @@ -53,8 +54,14 @@ }, "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.mjs" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "tko": { @@ -71,5 +78,6 @@ "mvvm", "data-binding", "compatible" - ] + ], + "types": "./types/index.d.ts" } diff --git a/builds/knockout/src/index.ts b/builds/knockout/src/index.ts index 81ebf0c67..05b3e3edf 100644 --- a/builds/knockout/src/index.ts +++ b/builds/knockout/src/index.ts @@ -31,6 +31,13 @@ const expressionRewriting = { preProcessBindings: s => dataBindProvider.preProcessBindings(s) } +type KnockoutBuildExtensions = { + version: string + components: typeof components + Component: typeof components.ComponentABC + expressionRewriting: typeof expressionRewriting +} + const provider = new MultiProvider({ providers: [new ComponentProvider(), dataBindProvider, new VirtualProvider(), new AttributeProvider()] }) @@ -47,9 +54,11 @@ const builder = new Builder({ }) const version = BUILD_VERSION -export default builder.create({ +const knockoutBuild: KnockoutBuildExtensions = { version, components, Component: components.ComponentABC, expressionRewriting -}) +} + +export default builder.create(knockoutBuild) diff --git a/builds/reference/package.json b/builds/reference/package.json index a696d4083..10180b494 100644 --- a/builds/reference/package.json +++ b/builds/reference/package.json @@ -28,7 +28,8 @@ "@tko/utils": "^4.1.0" }, "files": [ - "dist/" + "dist/", + "types/" ], "homepage": "https://tko.io", "licenses": [ @@ -39,8 +40,14 @@ ], "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.mjs" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "bugs": { @@ -59,5 +66,6 @@ "mvvm", "tsx", "modern" - ] + ], + "types": "./types/index.d.ts" } diff --git a/builds/reference/src/index.ts b/builds/reference/src/index.ts index e79cb2001..d6b303b44 100644 --- a/builds/reference/src/index.ts +++ b/builds/reference/src/index.ts @@ -17,8 +17,8 @@ import { bindings as componentBindings } from '@tko/binding.component' import { filters } from '@tko/filter.punches' import components from '@tko/utils.component' -import { createElement, Fragment } from '@tko/utils.jsx' -import { JsxObserver } from '@tko/utils.jsx' +import { createElement, Fragment, render } from '@tko/utils.jsx' +import type { JsxRenderResult } from '@tko/utils.jsx' import { options } from '@tko/utils' @@ -27,6 +27,17 @@ declare const BUILD_VERSION: string /** Use === and !== instead of == and != in binding expressions */ options.strictEquality = true +type ReferenceBuildExtensions = { + jsx: { + createElement: typeof createElement + Fragment: typeof Fragment + render(jsx: any): JsxRenderResult + } + components: typeof components + version: string + Component: typeof components.ComponentABC +} + const builder = new Builder({ filters, extenders: {}, @@ -54,23 +65,15 @@ const builder = new Builder({ const version = BUILD_VERSION -export default builder.create({ +const referenceBuild: ReferenceBuildExtensions = { jsx: { createElement, Fragment, - /** Public render function that converts JSX to DOM nodes */ - render(jsx: any) { - const fragment = document.createDocumentFragment() - const observer = new JsxObserver(jsx, fragment) - // Return the first child if single node, or the fragment if multiple - const node = fragment.childNodes.length === 1 ? fragment.firstChild : fragment - return { - node, - dispose: () => observer.dispose() - } - } + render }, components, version, Component: components.ComponentABC -}) +} + +export default builder.create(referenceBuild) diff --git a/bun.lock b/bun.lock index 40e2d5cb3..10649c068 100644 --- a/bun.lock +++ b/bun.lock @@ -4,6 +4,7 @@ "workspaces": { "": { "devDependencies": { + "@arethetypeswrong/cli": "^0.18.3", "@biomejs/biome": "^2.4.16", "@changesets/cli": "^2.31.0", "@types/jquery": "^4.0.0", @@ -17,6 +18,7 @@ "jquery": "^4.0.0", "knip": "^6.15.0", "playwright": "^1.60.0", + "publint": "^0.3.21", "sinon": "^22.0.0", "typescript": "^6.0.3", "vitest": "^4.1.7", @@ -296,6 +298,12 @@ }, }, "packages": { + "@andrewbranch/untar.js": ["@andrewbranch/untar.js@1.0.3", "", {}, "sha512-Jh15/qVmrLGhkKJBdXlK1+9tY4lZruYjsgkDFj08ZmDiWVBLJcqkok7Z0/R0In+i1rScBpJlSvrTS2Lm41Pbnw=="], + + "@arethetypeswrong/cli": ["@arethetypeswrong/cli@0.18.3", "", { "dependencies": { "@arethetypeswrong/core": "0.18.3", "chalk": "^4.1.2", "cli-table3": "^0.6.3", "commander": "^10.0.1", "marked": "^9.1.2", "marked-terminal": "^7.1.0", "semver": "^7.5.4" }, "bin": { "attw": "./dist/index.js" } }, "sha512-GeAlc+lUD4gKHD/LDQNvQY30FfQ+xAXg2inbQKUjFZgTOdI5ygEweaOnGHGBPSKXSLGQC7VLhpXu9zMnYk/4sQ=="], + + "@arethetypeswrong/core": ["@arethetypeswrong/core@0.18.3", "", { "dependencies": { "@andrewbranch/untar.js": "^1.0.3", "@loaderkit/resolve": "^1.0.2", "cjs-module-lexer": "^1.2.3", "fflate": "^0.8.3", "lru-cache": "^11.0.1", "semver": "^7.5.4", "typescript": "5.6.1-rc", "validate-npm-package-name": "^5.0.0" } }, "sha512-sWBB/tdIktaT5xMq0Dz6CJyqcf6oMNdmiKiuPU1lWoJLTL6gjRSsksBuSgqot21hylkklBQY1wiSu+PkZhW7sw=="], + "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], @@ -328,6 +336,8 @@ "@blazediff/core": ["@blazediff/core@1.9.1", "", {}, "sha512-ehg3jIkYKulZh+8om/O25vkvSsXXwC+skXmyA87FFx6A/45eqOkZsBltMw/TVteb0mloiGT8oGRTcjRAz66zaA=="], + "@braidai/lang": ["@braidai/lang@1.1.2", "", {}, "sha512-qBcknbBufNHlui137Hft8xauQMTZDKdophmLFv05r2eNmdIv/MlPuP4TdUknHG68UdWLgVZwgxVe735HzJNIwA=="], + "@changesets/apply-release-plan": ["@changesets/apply-release-plan@7.1.1", "", { "dependencies": { "@changesets/config": "^3.1.4", "@changesets/get-version-range-type": "^0.4.0", "@changesets/git": "^3.0.4", "@changesets/should-skip-package": "^0.1.2", "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3", "detect-indent": "^6.0.0", "fs-extra": "^7.0.1", "lodash.startcase": "^4.4.0", "outdent": "^0.5.0", "prettier": "^2.7.1", "resolve-from": "^5.0.0", "semver": "^7.5.3" } }, "sha512-9qPCm/rLx/xoOFXIHGB229+4GOL76S4MC+7tyOuTsR6+1jYlfFDQORdvwR5hDA6y4FL2BPt3qpbcQIS+dW85LA=="], "@changesets/assemble-release-plan": ["@changesets/assemble-release-plan@6.0.10", "", { "dependencies": { "@changesets/errors": "^0.2.0", "@changesets/get-dependents-graph": "^2.1.4", "@changesets/should-skip-package": "^0.1.2", "@changesets/types": "^6.1.0", "@manypkg/get-packages": "^1.1.3", "semver": "^7.5.3" } }, "sha512-rSDcqdJ9KbVyjpBIuCidhvZNIiVt1XaIYp73ycVQRIA5n/j6wQaEk0ChRLMUQ1vkxZe51PTQ9OIhbg6HQMW45A=="], @@ -362,6 +372,8 @@ "@changesets/write": ["@changesets/write@0.4.0", "", { "dependencies": { "@changesets/types": "^6.1.0", "fs-extra": "^7.0.1", "human-id": "^4.1.1", "prettier": "^2.7.1" } }, "sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q=="], + "@colors/colors": ["@colors/colors@1.5.0", "", {}, "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ=="], + "@emnapi/core": ["@emnapi/core@1.10.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw=="], "@emnapi/runtime": ["@emnapi/runtime@1.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA=="], @@ -428,6 +440,8 @@ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + "@loaderkit/resolve": ["@loaderkit/resolve@1.0.6", "", { "dependencies": { "@braidai/lang": "^1.0.0" } }, "sha512-G8FdIoF5CypfwmD9rl8BXod5HDn8JqB0CCNBXDTaRZ+yRYhARrrSToX1zg1zy9jX3zLqigsELwhT4gNtkdQAUg=="], + "@manypkg/find-root": ["@manypkg/find-root@1.1.0", "", { "dependencies": { "@babel/runtime": "^7.5.5", "@types/node": "^12.7.1", "find-up": "^4.1.0", "fs-extra": "^8.1.0" } }, "sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA=="], "@manypkg/get-packages": ["@manypkg/get-packages@1.1.3", "", { "dependencies": { "@babel/runtime": "^7.5.5", "@changesets/types": "^4.0.1", "@manypkg/find-root": "^1.1.0", "fs-extra": "^8.1.0", "globby": "^11.0.0", "read-yaml-file": "^1.1.0" } }, "sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A=="], @@ -522,6 +536,8 @@ "@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="], + "@publint/pack": ["@publint/pack@0.1.4", "", {}, "sha512-HDVTWq3H0uTXiU0eeSQntcVUTPP3GamzeXI41+x7uU9J65JgWQh3qWZHblR1i0npXfFtF+mxBiU2nJH8znxWnQ=="], + "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-rc.15", "", { "os": "android", "cpu": "arm64" }, "sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA=="], "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0-rc.15", "", { "os": "darwin", "cpu": "arm64" }, "sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg=="], @@ -554,6 +570,8 @@ "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.15", "", {}, "sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g=="], + "@sindresorhus/is": ["@sindresorhus/is@4.6.0", "", {}, "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw=="], + "@sinonjs/commons": ["@sinonjs/commons@3.0.1", "", { "dependencies": { "type-detect": "4.0.8" } }, "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ=="], "@sinonjs/fake-timers": ["@sinonjs/fake-timers@15.4.0", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-DsG+8/LscQIQg68J6Ef3dv10u6nVyetYn923s3/sus5eaGfTo1of5WMZSLf0UJc9KDuKPilPH0UDJCjvNbDNCA=="], @@ -656,7 +674,13 @@ "ansi-colors": ["ansi-colors@4.1.3", "", {}, "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw=="], - "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "ansi-escapes": ["ansi-escapes@7.3.0", "", { "dependencies": { "environment": "^1.0.0" } }, "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg=="], + + "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="], "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], @@ -672,8 +696,26 @@ "chai": ["chai@6.2.2", "", {}, "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg=="], + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "char-regex": ["char-regex@1.0.2", "", {}, "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw=="], + "chardet": ["chardet@2.1.1", "", {}, "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ=="], + "cjs-module-lexer": ["cjs-module-lexer@1.4.3", "", {}, "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q=="], + + "cli-highlight": ["cli-highlight@2.1.11", "", { "dependencies": { "chalk": "^4.0.0", "highlight.js": "^10.7.1", "mz": "^2.4.0", "parse5": "^5.1.1", "parse5-htmlparser2-tree-adapter": "^6.0.0", "yargs": "^16.0.0" }, "bin": { "highlight": "bin/highlight" } }, "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg=="], + + "cli-table3": ["cli-table3@0.6.5", "", { "dependencies": { "string-width": "^4.2.0" }, "optionalDependencies": { "@colors/colors": "1.5.0" } }, "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ=="], + + "cliui": ["cliui@7.0.4", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" } }, "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ=="], + + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "commander": ["commander@10.0.1", "", {}, "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug=="], + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], @@ -686,14 +728,22 @@ "dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="], + "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "emojilib": ["emojilib@2.4.0", "", {}, "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw=="], + "enquirer": ["enquirer@2.4.1", "", { "dependencies": { "ansi-colors": "^4.1.1", "strip-ansi": "^6.0.1" } }, "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ=="], "entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="], + "environment": ["environment@1.1.0", "", {}, "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q=="], + "es-module-lexer": ["es-module-lexer@2.0.0", "", {}, "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw=="], "esbuild": ["esbuild@0.28.0", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.0", "@esbuild/android-arm": "0.28.0", "@esbuild/android-arm64": "0.28.0", "@esbuild/android-x64": "0.28.0", "@esbuild/darwin-arm64": "0.28.0", "@esbuild/darwin-x64": "0.28.0", "@esbuild/freebsd-arm64": "0.28.0", "@esbuild/freebsd-x64": "0.28.0", "@esbuild/linux-arm": "0.28.0", "@esbuild/linux-arm64": "0.28.0", "@esbuild/linux-ia32": "0.28.0", "@esbuild/linux-loong64": "0.28.0", "@esbuild/linux-mips64el": "0.28.0", "@esbuild/linux-ppc64": "0.28.0", "@esbuild/linux-riscv64": "0.28.0", "@esbuild/linux-s390x": "0.28.0", "@esbuild/linux-x64": "0.28.0", "@esbuild/netbsd-arm64": "0.28.0", "@esbuild/netbsd-x64": "0.28.0", "@esbuild/openbsd-arm64": "0.28.0", "@esbuild/openbsd-x64": "0.28.0", "@esbuild/openharmony-arm64": "0.28.0", "@esbuild/sunos-x64": "0.28.0", "@esbuild/win32-arm64": "0.28.0", "@esbuild/win32-ia32": "0.28.0", "@esbuild/win32-x64": "0.28.0" }, "bin": "bin/esbuild" }, "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw=="], + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="], "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], @@ -710,6 +760,8 @@ "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" } }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + "fflate": ["fflate@0.8.3", "", {}, "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA=="], + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], "find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], @@ -720,6 +772,8 @@ "fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="], + "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + "get-tsconfig": ["get-tsconfig@4.14.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA=="], "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], @@ -732,6 +786,8 @@ "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + "highlight.js": ["highlight.js@10.7.3", "", {}, "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="], + "html-escaper": ["html-escaper@2.0.2", "", {}, "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg=="], "human-id": ["human-id@4.1.3", "", { "bin": "dist/cli.js" }, "sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q=="], @@ -742,6 +798,8 @@ "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], + "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], @@ -798,12 +856,18 @@ "lodash.startcase": ["lodash.startcase@4.4.0", "", {}, "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg=="], + "lru-cache": ["lru-cache@11.5.1", "", {}, "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A=="], + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], "magicast": ["magicast@0.5.2", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "source-map-js": "^1.2.1" } }, "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ=="], "make-dir": ["make-dir@4.0.0", "", { "dependencies": { "semver": "^7.5.3" } }, "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw=="], + "marked": ["marked@9.1.6", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q=="], + + "marked-terminal": ["marked-terminal@7.3.0", "", { "dependencies": { "ansi-escapes": "^7.0.0", "ansi-regex": "^6.1.0", "chalk": "^5.4.1", "cli-highlight": "^2.1.11", "cli-table3": "^0.6.5", "node-emoji": "^2.2.0", "supports-hyperlinks": "^3.1.0" }, "peerDependencies": { "marked": ">=1 <16" } }, "sha512-t4rBvPsHc57uE/2nJOLmMbZCQ4tgAccAED3ngXQqW6g+TxA488JzJ+FK3lQkzBQOI1mRV/r/Kq+1ZlJ4D0owQw=="], + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], @@ -814,8 +878,14 @@ "mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="], + "mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="], + "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + "node-emoji": ["node-emoji@2.2.0", "", { "dependencies": { "@sindresorhus/is": "^4.6.0", "char-regex": "^1.0.2", "emojilib": "^2.4.0", "skin-tone": "^2.0.0" } }, "sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw=="], + + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], + "obug": ["obug@2.1.1", "", {}, "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ=="], "outdent": ["outdent@0.5.0", "", {}, "sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q=="], @@ -836,6 +906,10 @@ "package-manager-detector": ["package-manager-detector@0.2.11", "", { "dependencies": { "quansync": "^0.2.7" } }, "sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ=="], + "parse5": ["parse5@5.1.1", "", {}, "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug=="], + + "parse5-htmlparser2-tree-adapter": ["parse5-htmlparser2-tree-adapter@6.0.1", "", { "dependencies": { "parse5": "^6.0.1" } }, "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA=="], + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], @@ -860,12 +934,16 @@ "prettier": ["prettier@2.8.8", "", { "bin": "bin-prettier.js" }, "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q=="], + "publint": ["publint@0.3.21", "", { "dependencies": { "@publint/pack": "^0.1.4", "package-manager-detector": "^1.6.0", "picocolors": "^1.1.1", "sade": "^1.8.1" }, "bin": { "publint": "src/cli.js" } }, "sha512-OqejcnMV6E9zel2oCrUOJEiiFkGiAAni0A6ibfQNh1k9Gu5z4F+Yso8lllam7AzmV6Do0vp7u3UpZNRBwuXaHQ=="], + "quansync": ["quansync@0.2.11", "", {}, "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA=="], "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], "read-yaml-file": ["read-yaml-file@1.1.0", "", { "dependencies": { "graceful-fs": "^4.1.5", "js-yaml": "^3.6.1", "pify": "^4.0.1", "strip-bom": "^3.0.0" } }, "sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA=="], + "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], @@ -876,6 +954,8 @@ "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], + "sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="], + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], "semver": ["semver@7.7.4", "", { "bin": "bin/semver.js" }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], @@ -892,6 +972,8 @@ "sirv": ["sirv@3.0.2", "", { "dependencies": { "@polka/url": "^1.0.0-next.24", "mrmime": "^2.0.0", "totalist": "^3.0.0" } }, "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g=="], + "skin-tone": ["skin-tone@2.0.0", "", { "dependencies": { "unicode-emoji-modifier-base": "^1.0.0" } }, "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA=="], + "slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], "smol-toml": ["smol-toml@1.6.1", "", {}, "sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg=="], @@ -906,6 +988,8 @@ "std-env": ["std-env@4.0.0", "", {}, "sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ=="], + "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="], @@ -914,8 +998,14 @@ "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + "supports-hyperlinks": ["supports-hyperlinks@3.2.0", "", { "dependencies": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" } }, "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig=="], + "term-size": ["term-size@2.2.1", "", {}, "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg=="], + "thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="], + + "thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="], + "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="], "tinyexec": ["tinyexec@1.1.1", "", {}, "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg=="], @@ -938,8 +1028,12 @@ "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], + "unicode-emoji-modifier-base": ["unicode-emoji-modifier-base@1.0.0", "", {}, "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g=="], + "universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], + "validate-npm-package-name": ["validate-npm-package-name@5.0.1", "", {}, "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ=="], + "vite": ["vite@8.0.8", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.8", "rolldown": "1.0.0-rc.15", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.1.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw=="], "vitest": ["vitest@4.1.7", "", { "dependencies": { "@vitest/expect": "4.1.7", "@vitest/mocker": "4.1.7", "@vitest/pretty-format": "4.1.7", "@vitest/runner": "4.1.7", "@vitest/snapshot": "4.1.7", "@vitest/spy": "4.1.7", "@vitest/utils": "4.1.7", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.1.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.1.7", "@vitest/browser-preview": "4.1.7", "@vitest/browser-webdriverio": "4.1.7", "@vitest/coverage-istanbul": "4.1.7", "@vitest/coverage-v8": "4.1.7", "@vitest/ui": "4.1.7", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/coverage-istanbul", "@vitest/coverage-v8", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-flYyaFd2CgoCoU+0UKt3pxksgC+S02iTDN0n3LtqaMeXsI9SBcdNujc2k0DeFLzUn/0k538yNjOSdwgCqcrwJA=="], @@ -952,12 +1046,22 @@ "why-is-node-running": ["why-is-node-running@2.3.0", "", { "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": { "why-is-node-running": "cli.js" } }, "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w=="], + "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + "ws": ["ws@8.20.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA=="], + "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + "yaml": ["yaml@2.9.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA=="], + "yargs": ["yargs@16.2.0", "", { "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.0", "y18n": "^5.0.5", "yargs-parser": "^20.2.2" } }, "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw=="], + + "yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="], + "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], + "@arethetypeswrong/core/typescript": ["typescript@5.6.1-rc", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-E3b2+1zEFu84jB0YQi9BORDjz9+jGbwwy1Zi3G0LUNw7a7cePUrHMRNy8aPh53nXpkFGVHSxIZo5vKTfYaFiBQ=="], + "@manypkg/find-root/@types/node": ["@types/node@12.20.55", "", {}, "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ=="], "@manypkg/find-root/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], @@ -974,12 +1078,20 @@ "@sinonjs/samsam/type-detect": ["type-detect@4.1.0", "", {}, "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw=="], + "marked-terminal/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], + "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "parse5-htmlparser2-tree-adapter/parse5": ["parse5@6.0.1", "", {}, "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="], + + "publint/package-manager-detector": ["package-manager-detector@1.6.0", "", {}, "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA=="], + "read-yaml-file/js-yaml": ["js-yaml@3.14.2", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": "bin/js-yaml.js" }, "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg=="], "rolldown/@oxc-project/types": ["@oxc-project/types@0.124.0", "", {}, "sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg=="], + "strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "vite/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], "read-yaml-file/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], diff --git a/package.json b/package.json index 08c004a0d..e19d626ea 100644 --- a/package.json +++ b/package.json @@ -7,12 +7,14 @@ "url": "https://github.com/knockout/tko.git" }, "scripts": { - "build": "bun run --filter './packages/*' build && bun run --filter './builds/*' build", + "build": "bun run dts && bun run --filter './packages/*' build && bun run --filter './builds/*' build", "test": "bunx @biomejs/biome ci . && bun run build && bunx vitest run", "test:ff": "bunx @biomejs/biome ci . && bun run build && VITEST_BROWSERS=firefox bunx vitest run", "test:coverage": "bun run build && bunx vitest run --coverage --project browser", "tsc": "bunx tsc", - "dts": "bunx tsc --build tsconfig.dts.json", + "dts": "bun tools/build-dts.ts", + "verify:types": "bunx tsc -p tools/types-smoke/tsconfig.json && bunx tsc -p tools/types-smoke/tsconfig.node16.json && bunx tsc -p tools/types-smoke/tsconfig.nodenext.json", + "verify:publish-types": "bun tools/verify-publish-types.ts", "format": "bunx @biomejs/biome format .", "format:fix": "bunx @biomejs/biome format --write .", "lint": "bunx @biomejs/biome lint .", @@ -20,8 +22,8 @@ "check": "bunx @biomejs/biome check .", "knip": "knip", "verify:esm": "bun tools/verify-esm-extensions.ts", - "verify": "bunx @biomejs/biome check . && bunx tsc && bun run build && bun run verify:esm && bunx vitest run", - "clean": "rm -rf packages/*/dist builds/*/dist coverage" + "verify": "bunx @biomejs/biome check . && bunx tsc && bun run build && bun run verify:types && bun run verify:esm && bun run verify:publish-types && bunx vitest run", + "clean": "rm -rf packages/*/dist packages/*/types builds/*/dist builds/*/types coverage .dts-tmp" }, "bugs": "https://github.com/knockout/tko/issues", "licenses": [ @@ -31,6 +33,7 @@ } ], "devDependencies": { + "@arethetypeswrong/cli": "^0.18.3", "@biomejs/biome": "^2.4.16", "@changesets/cli": "^2.31.0", "@types/jquery": "^4.0.0", @@ -44,6 +47,7 @@ "jquery": "^4.0.0", "knip": "^6.15.0", "playwright": "^1.60.0", + "publint": "^0.3.21", "sinon": "^22.0.0", "typescript": "^6.0.3", "vitest": "^4.1.7" diff --git a/packages/bind/package.json b/packages/bind/package.json index 435decacb..aca773b71 100644 --- a/packages/bind/package.json +++ b/packages/bind/package.json @@ -2,7 +2,7 @@ "version": "4.1.0", "name": "@tko/bind", "description": "TKO DOM-Observable Binding", - "module": "dist/index.js", + "module": "dist/index.mjs", "dependencies": { "@tko/computed": "^4.1.0", "@tko/lifecycle": "^4.1.0", @@ -12,7 +12,8 @@ "@tko/builder": "^4.1.0" }, "files": [ - "dist/" + "dist/", + "types/" ], "repository": { "type": "git", @@ -33,8 +34,14 @@ ], "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "scripts": { @@ -47,5 +54,6 @@ "dom", "observable", "data-binding" - ] + ], + "types": "./types/index.d.ts" } diff --git a/packages/binding.component/package.json b/packages/binding.component/package.json index f94c23c30..aa4c2b984 100644 --- a/packages/binding.component/package.json +++ b/packages/binding.component/package.json @@ -2,7 +2,7 @@ "version": "4.1.0", "name": "@tko/binding.component", "description": "component: binding for web components", - "module": "dist/index.js", + "module": "dist/index.mjs", "license": "MIT", "dependencies": { "@tko/bind": "^4.1.0", @@ -14,7 +14,8 @@ "@tko/utils.jsx": "^4.1.0" }, "files": [ - "dist/" + "dist/", + "types/" ], "homepage": "https://tko.io", "licenses": [ @@ -25,8 +26,14 @@ ], "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "bugs": { @@ -46,5 +53,6 @@ "binding", "web-components", "custom-elements" - ] + ], + "types": "./types/index.d.ts" } diff --git a/packages/binding.core/package.json b/packages/binding.core/package.json index fef66bb15..6bb8a3804 100644 --- a/packages/binding.core/package.json +++ b/packages/binding.core/package.json @@ -2,9 +2,10 @@ "version": "4.1.0", "name": "@tko/binding.core", "description": "TKO Core bindings", - "module": "dist/index.js", + "module": "dist/index.mjs", "files": [ - "dist/" + "dist/", + "types/" ], "repository": { "type": "git", @@ -37,11 +38,18 @@ ], "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "scripts": { "build": "bun ../../tools/build.ts" - } + }, + "types": "./types/index.d.ts" } diff --git a/packages/binding.foreach/package.json b/packages/binding.foreach/package.json index ee50c181a..0f9505712 100644 --- a/packages/binding.foreach/package.json +++ b/packages/binding.foreach/package.json @@ -2,9 +2,10 @@ "version": "4.1.0", "name": "@tko/binding.foreach", "description": "Knockout Foreach Binding", - "module": "dist/index.js", + "module": "dist/index.mjs", "files": [ - "dist/" + "dist/", + "types/" ], "repository": { "type": "git", @@ -36,11 +37,18 @@ ], "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "scripts": { "build": "bun ../../tools/build.ts" - } + }, + "types": "./types/index.d.ts" } diff --git a/packages/binding.if/package.json b/packages/binding.if/package.json index c40bb1d0d..6982b157b 100644 --- a/packages/binding.if/package.json +++ b/packages/binding.if/package.json @@ -2,9 +2,10 @@ "version": "4.1.0", "name": "@tko/binding.if", "description": "TKO conditional (if/ifnot/unless/with/else) bindings", - "module": "dist/index.js", + "module": "dist/index.mjs", "files": [ - "dist/" + "dist/", + "types/" ], "repository": { "type": "git", @@ -36,11 +37,18 @@ ], "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "scripts": { "build": "bun ../../tools/build.ts" - } + }, + "types": "./types/index.d.ts" } diff --git a/packages/binding.template/package.json b/packages/binding.template/package.json index 36e247054..088cbc03e 100644 --- a/packages/binding.template/package.json +++ b/packages/binding.template/package.json @@ -2,9 +2,10 @@ "version": "4.1.0", "name": "@tko/binding.template", "description": "TKO Template bindings", - "module": "dist/index.js", + "module": "dist/index.mjs", "files": [ - "dist/" + "dist/", + "types/" ], "repository": { "type": "git", @@ -37,11 +38,18 @@ ], "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "scripts": { "build": "bun ../../tools/build.ts" - } + }, + "types": "./types/index.d.ts" } diff --git a/packages/builder/package.json b/packages/builder/package.json index 105de0015..a9533f585 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -26,18 +26,25 @@ } ], "files": [ - "dist/" + "dist/", + "types/" ], "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "bugs": { "url": "https://github.com/knockout/tko/issues" }, - "module": "dist/index.js", + "module": "dist/index.mjs", "scripts": { "build": "bun ../../tools/build.ts" }, @@ -47,5 +54,6 @@ "builder", "framework", "customizable" - ] + ], + "types": "./types/index.d.ts" } diff --git a/packages/builder/spec/builderBehaviors.ts b/packages/builder/spec/builderBehaviors.ts index 8d6fc6759..7744c4e00 100644 --- a/packages/builder/spec/builderBehaviors.ts +++ b/packages/builder/spec/builderBehaviors.ts @@ -1,3 +1,5 @@ +import { assert } from 'chai' + import { VirtualProvider } from '@tko/provider.virtual' import { bindings as ifBindings } from '@tko/binding.if' import { options } from '@tko/utils' @@ -21,4 +23,66 @@ describe('Builder', () => { // We're just testing that the builder constructs, here. const builder = new Builder({ filters: {}, provider: new VirtualProvider(), bindings: [ifBindings], options: {} }) }) + + describe('create()', () => { + let builder: InstanceType + + beforeEach(function () { + // @ts-ignore — global helper from mocha-test-helpers.js + restoreAfter(options, 'filters') + // @ts-ignore — global helper from mocha-test-helpers.js + restoreAfter(options, 'bindingProviderInstance') + builder = new Builder({ filters: {}, provider: new VirtualProvider(), bindings: [ifBindings], options: {} }) + }) + + it('merges additional properties onto the returned instance', function () { + const version = '9.9.9-test' + const extra = { version, testProp: 'hello' } + const instance = builder.create(extra) + assert.equal(instance.version, version) + assert.equal((instance as any).testProp, 'hello') + }) + + it('returns an object that is also a KnockoutInstance with standard ko properties', function () { + const instance = builder.create({ myExtension: true }) + // KnockoutInstance includes these standard properties + assert.isFunction(instance.observable) + assert.isFunction(instance.computed) + assert.isFunction(instance.applyBindings) + }) + + it('accepts an empty object and returns a valid instance', function () { + const instance = builder.create({}) + assert.isFunction(instance.observable) + assert.isFunction(instance.applyBindings) + }) + + it('merges multiple additional properties from a single object', function () { + const extra = { propA: 1, propB: 'two', propC: true } + const instance = builder.create(extra) + assert.equal((instance as any).propA, 1) + assert.equal((instance as any).propB, 'two') + assert.equal((instance as any).propC, true) + }) + + it('additionalProperties take precedence over pre-existing instance properties', function () { + // The `version` property is intentionally overridable in builds. + // Passing the same key through additionalProperties should win over whatever + // the base knockout object provides for that key. + const version = 'overridden-version' + const instance = builder.create({ version }) + assert.equal(instance.version, version) + }) + + it('sets options.knockoutInstance to the returned instance', function () { + const instance = builder.create({ sentinel: 'check-instance' }) + assert.strictEqual(options.knockoutInstance, instance) + }) + + it('preserves the getBindingHandler accessor on the returned instance', function () { + const instance = builder.create({}) + // getBindingHandler should be a property (accessor) on the instance + assert.property(instance, 'getBindingHandler') + }) + }) }) diff --git a/packages/builder/src/Builder.ts b/packages/builder/src/Builder.ts index a5e1da4be..ea5fa7e2d 100644 --- a/packages/builder/src/Builder.ts +++ b/packages/builder/src/Builder.ts @@ -312,10 +312,10 @@ export class Builder { } /** - * @return {KnockoutInstance} An instance of Knockout. + * @return {KnockoutInstance & T} An instance of Knockout with merged extension properties. */ - create(...additionalProperties): KnockoutInstance { - const instance: KnockoutInstance = Object.assign( + create(additionalProperties: T): KnockoutInstance & T { + const instance = Object.assign( { get getBindingHandler() { return options.getBindingHandler @@ -326,8 +326,8 @@ export class Builder { }, knockout, //never change the order of these this.providedProperties, - ...additionalProperties - ) + additionalProperties + ) as KnockoutInstance & T instance.options.knockoutInstance = instance diff --git a/packages/computed/package.json b/packages/computed/package.json index 8043196be..36d2e350b 100644 --- a/packages/computed/package.json +++ b/packages/computed/package.json @@ -2,9 +2,10 @@ "version": "4.1.0", "name": "@tko/computed", "description": "TKO Computed Observables", - "module": "dist/index.js", + "module": "dist/index.mjs", "files": [ - "dist/" + "dist/", + "types/" ], "dependencies": { "@tko/observable": "^4.1.0", @@ -35,11 +36,18 @@ ], "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "scripts": { "build": "bun ../../tools/build.ts" - } + }, + "types": "./types/index.d.ts" } diff --git a/packages/filter.punches/package.json b/packages/filter.punches/package.json index 1247b1224..ec95d4c73 100644 --- a/packages/filter.punches/package.json +++ b/packages/filter.punches/package.json @@ -2,9 +2,10 @@ "version": "4.1.0", "name": "@tko/filter.punches", "description": "TKO filters from knockout punches", - "module": "dist/index.js", + "module": "dist/index.mjs", "files": [ - "dist/" + "dist/", + "types/" ], "repository": { "type": "git", @@ -34,11 +35,18 @@ ], "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "scripts": { "build": "bun ../../tools/build.ts" - } + }, + "types": "./types/index.d.ts" } diff --git a/packages/lifecycle/package.json b/packages/lifecycle/package.json index 2c7a583ee..76ccb02aa 100644 --- a/packages/lifecycle/package.json +++ b/packages/lifecycle/package.json @@ -1,13 +1,14 @@ { "version": "4.1.0", - "module": "dist/index.js", + "module": "dist/index.mjs", "dependencies": { "@tko/computed": "^4.1.0", "@tko/observable": "^4.1.0", "@tko/utils": "^4.1.0" }, "files": [ - "dist/" + "dist/", + "types/" ], "name": "@tko/lifecycle", "description": "Knockout LifeCycle for object instances", @@ -26,8 +27,14 @@ ], "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "bugs": { @@ -42,5 +49,6 @@ "lifecycle", "mixin", "observable" - ] + ], + "types": "./types/index.d.ts" } diff --git a/packages/observable/package.json b/packages/observable/package.json index 6926ade7d..999374c9c 100644 --- a/packages/observable/package.json +++ b/packages/observable/package.json @@ -8,12 +8,19 @@ }, "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "files": [ - "dist/" + "dist/", + "types/" ], "keywords": [ "knockout", @@ -37,8 +44,9 @@ "url": "https://opensource.org/licenses/MIT" } ], - "module": "dist/index.js", + "module": "dist/index.mjs", "scripts": { "build": "bun ../../tools/build.ts" - } + }, + "types": "./types/index.d.ts" } diff --git a/packages/provider.attr/package.json b/packages/provider.attr/package.json index afc7a813b..304f21a7e 100644 --- a/packages/provider.attr/package.json +++ b/packages/provider.attr/package.json @@ -2,9 +2,10 @@ "version": "4.1.0", "name": "@tko/provider.attr", "description": "Link HTML attributes (e.g. ko-handler-name) to binding handlers", - "module": "dist/index.js", + "module": "dist/index.mjs", "files": [ - "dist/" + "dist/", + "types/" ], "license": "MIT", "dependencies": { @@ -19,8 +20,14 @@ ], "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "bugs": { @@ -40,5 +47,6 @@ "provider", "attributes", "ko-attr" - ] + ], + "types": "./types/index.d.ts" } diff --git a/packages/provider.bindingstring/package.json b/packages/provider.bindingstring/package.json index 24aa53651..7e5197707 100644 --- a/packages/provider.bindingstring/package.json +++ b/packages/provider.bindingstring/package.json @@ -2,9 +2,10 @@ "version": "4.1.0", "name": "@tko/provider.bindingstring", "description": "Abstract Base Class for providers that parse a binding string", - "module": "dist/index.js", + "module": "dist/index.mjs", "files": [ - "dist/" + "dist/", + "types/" ], "license": "MIT", "dependencies": { @@ -20,8 +21,14 @@ ], "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "bugs": { @@ -41,5 +48,6 @@ "provider", "parser", "binding-string" - ] + ], + "types": "./types/index.d.ts" } diff --git a/packages/provider.component/package.json b/packages/provider.component/package.json index fe5ca559b..87c4b204f 100644 --- a/packages/provider.component/package.json +++ b/packages/provider.component/package.json @@ -2,9 +2,10 @@ "version": "4.1.0", "name": "@tko/provider.component", "description": "Bind custom web components e.g. ", - "module": "dist/index.js", + "module": "dist/index.mjs", "files": [ - "dist/" + "dist/", + "types/" ], "license": "MIT", "dependencies": { @@ -24,8 +25,14 @@ ], "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "bugs": { @@ -45,5 +52,6 @@ "provider", "web-components", "custom-elements" - ] + ], + "types": "./types/index.d.ts" } diff --git a/packages/provider.databind/package.json b/packages/provider.databind/package.json index 52b3b5377..c81c6f03d 100644 --- a/packages/provider.databind/package.json +++ b/packages/provider.databind/package.json @@ -2,9 +2,10 @@ "version": "4.1.0", "name": "@tko/provider.databind", "description": "Link HTML attributes based on a `data-bind` HTML attribute", - "module": "dist/index.js", + "module": "dist/index.mjs", "files": [ - "dist/" + "dist/", + "types/" ], "license": "MIT", "dependencies": { @@ -20,8 +21,14 @@ ], "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "bugs": { @@ -41,5 +48,6 @@ "provider", "data-bind", "declarative" - ] + ], + "types": "./types/index.d.ts" } diff --git a/packages/provider.multi/package.json b/packages/provider.multi/package.json index 9f1066d3e..b2eff6380 100644 --- a/packages/provider.multi/package.json +++ b/packages/provider.multi/package.json @@ -2,9 +2,10 @@ "version": "4.1.0", "name": "@tko/provider.multi", "description": "Combine multiple other providers into one", - "module": "dist/index.js", + "module": "dist/index.mjs", "files": [ - "dist/" + "dist/", + "types/" ], "license": "MIT", "dependencies": { @@ -20,8 +21,14 @@ ], "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "bugs": { @@ -41,5 +48,6 @@ "provider", "composition", "multi-provider" - ] + ], + "types": "./types/index.d.ts" } diff --git a/packages/provider.mustache/package.json b/packages/provider.mustache/package.json index c2198e39a..b330af9e5 100644 --- a/packages/provider.mustache/package.json +++ b/packages/provider.mustache/package.json @@ -2,9 +2,10 @@ "version": "4.1.0", "name": "@tko/provider.mustache", "description": "Interpolate text/node attributes {{ }}", - "module": "dist/index.js", + "module": "dist/index.mjs", "files": [ - "dist/" + "dist/", + "types/" ], "repository": { "type": "git", @@ -36,11 +37,18 @@ ], "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "scripts": { "build": "bun ../../tools/build.ts" - } + }, + "types": "./types/index.d.ts" } diff --git a/packages/provider.native/package.json b/packages/provider.native/package.json index d204b0154..70514b513 100644 --- a/packages/provider.native/package.json +++ b/packages/provider.native/package.json @@ -2,9 +2,10 @@ "version": "4.1.0", "name": "@tko/provider.native", "description": "Link binding handlers whose value is already attached to the node", - "module": "dist/index.js", + "module": "dist/index.mjs", "files": [ - "dist/" + "dist/", + "types/" ], "license": "MIT", "dependencies": { @@ -21,8 +22,14 @@ ], "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "bugs": { @@ -42,5 +49,6 @@ "provider", "native", "jsx" - ] + ], + "types": "./types/index.d.ts" } diff --git a/packages/provider.virtual/package.json b/packages/provider.virtual/package.json index 8e1feef6a..3d889863f 100644 --- a/packages/provider.virtual/package.json +++ b/packages/provider.virtual/package.json @@ -2,9 +2,10 @@ "version": "4.1.0", "name": "@tko/provider.virtual", "description": "Binding provider for virtual elements", - "module": "dist/index.js", + "module": "dist/index.mjs", "files": [ - "dist/" + "dist/", + "types/" ], "author": "The Knockout Team", "license": "MIT", @@ -22,8 +23,14 @@ ], "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "bugs": { @@ -42,5 +49,6 @@ "provider", "virtual-elements", "comments" - ] + ], + "types": "./types/index.d.ts" } diff --git a/packages/provider/package.json b/packages/provider/package.json index a02244c5a..825a373f5 100644 --- a/packages/provider/package.json +++ b/packages/provider/package.json @@ -2,9 +2,10 @@ "version": "4.1.0", "name": "@tko/provider", "description": "Abstract base class of tko Provider (HTML <-> Data Binding linker)", - "module": "dist/index.js", + "module": "dist/index.mjs", "files": [ - "dist/" + "dist/", + "types/" ], "author": "The Knockout Team", "license": "MIT", @@ -22,8 +23,14 @@ ], "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "bugs": { @@ -42,5 +49,6 @@ "provider", "binding-provider", "abstract" - ] + ], + "types": "./types/index.d.ts" } diff --git a/packages/utils.component/package.json b/packages/utils.component/package.json index ede1e5b55..c8ede19f4 100644 --- a/packages/utils.component/package.json +++ b/packages/utils.component/package.json @@ -2,9 +2,10 @@ "version": "4.1.0", "name": "@tko/utils.component", "description": "Registry and loading utilities for web components", - "module": "dist/index.js", + "module": "dist/index.mjs", "files": [ - "dist/" + "dist/", + "types/" ], "license": "MIT", "dependencies": { @@ -21,8 +22,14 @@ ], "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "bugs": { @@ -42,5 +49,6 @@ "components", "registry", "loader" - ] + ], + "types": "./types/index.d.ts" } diff --git a/packages/utils.functionrewrite/package.json b/packages/utils.functionrewrite/package.json index 98c08cf92..f1c2c53be 100644 --- a/packages/utils.functionrewrite/package.json +++ b/packages/utils.functionrewrite/package.json @@ -2,9 +2,10 @@ "version": "4.1.0", "name": "@tko/utils.functionrewrite", "description": "Rewrite `function {}` as lambdas (=>)", - "module": "dist/index.js", + "module": "dist/index.mjs", "files": [ - "dist/" + "dist/", + "types/" ], "license": "MIT", "dependencies": {}, @@ -17,8 +18,14 @@ ], "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "bugs": { @@ -37,5 +44,6 @@ "tko", "function-rewrite", "arrow-functions" - ] + ], + "types": "./types/index.d.ts" } diff --git a/packages/utils.jsx/package.json b/packages/utils.jsx/package.json index 16cf3898d..fa7d3904d 100644 --- a/packages/utils.jsx/package.json +++ b/packages/utils.jsx/package.json @@ -2,9 +2,10 @@ "version": "4.1.0", "name": "@tko/utils.jsx", "description": "TKO JSX Rendering", - "module": "dist/index.js", + "module": "dist/index.mjs", "files": [ - "dist/" + "dist/", + "types/" ], "repository": { "type": "git", @@ -36,8 +37,14 @@ ], "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "bugs": { @@ -45,5 +52,6 @@ }, "scripts": { "build": "bun ../../tools/build.ts" - } + }, + "types": "./types/index.d.ts" } diff --git a/packages/utils.jsx/spec/jsxBehaviors.ts b/packages/utils.jsx/spec/jsxBehaviors.ts index ca1b2270a..bec23ec96 100644 --- a/packages/utils.jsx/spec/jsxBehaviors.ts +++ b/packages/utils.jsx/spec/jsxBehaviors.ts @@ -18,7 +18,7 @@ import { bindings as componentBindings } from '@tko/binding.component' import { ComponentProvider } from '@tko/provider.component' -import { JsxObserver } from '../src' +import { JsxObserver, render } from '../src' import { ORIGINAL_JSX_SYM } from '../src/JsxObserver' @@ -1034,3 +1034,74 @@ describe('jsx', function () { }) }) }) + +describe('render()', () => { + it('returns an object with a node and dispose function', () => { + const result = render({ elementName: 'div', children: [], attributes: {} }) + assert.isObject(result) + assert.property(result, 'node') + assert.isFunction(result.dispose) + result.dispose() + }) + + it('returns the single child node when jsx produces exactly one element', () => { + const result = render({ elementName: 'span', children: [], attributes: { id: 'test' } }) + assert.instanceOf(result.node, window.Element) + assert.equal((result.node as Element).tagName.toLowerCase(), 'span') + result.dispose() + }) + + it('returns the single text node when jsx is a plain string', () => { + const result = render('hello world') + assert.instanceOf(result.node, window.Text) + assert.equal((result.node as Text).nodeValue, 'hello world') + result.dispose() + }) + + it('returns a DocumentFragment when jsx produces multiple top-level nodes', () => { + // An observable with a string value renders a text node + a comment (), + // which is two child nodes inside the fragment, so render() returns the fragment. + const obs = observable('a') + const result = render(obs) + assert.instanceOf(result.node, DocumentFragment) + result.dispose() + }) + + it('returns a DocumentFragment when jsx is an array of multiple items', () => { + const result = render(['first', 'second']) + assert.instanceOf(result.node, DocumentFragment) + result.dispose() + }) + + it('dispose() can be called without throwing', () => { + const result = render({ elementName: 'div', children: ['text'], attributes: {} }) + assert.doesNotThrow(() => result.dispose()) + }) + + it('returns null node when jsx produces no children (empty array)', () => { + // An empty array inserts nothing — fragment stays empty, so firstChild is null. + // fragment.childNodes.length === 0 → falls to the fragment branch (length !== 1) + const result = render([]) + // The fragment branch is taken when childNodes.length !== 1. + // Either null (firstChild of empty fragment) would be wrong — the fragment path + // is chosen, which is a DocumentFragment instance. + assert.instanceOf(result.node, DocumentFragment) + result.dispose() + }) + + it('node property reflects the rendered element tag name', () => { + const result = render({ elementName: 'article', children: ['content'], attributes: { class: 'main' } }) + // A single element + text child inside it is still one root element node. + assert.instanceOf(result.node, window.Element) + assert.equal((result.node as Element).tagName.toLowerCase(), 'article') + result.dispose() + }) + + it('dispose() tears down the observer so observable updates no longer apply', () => { + const obs = observable({ elementName: 'p', children: ['initial'], attributes: {} }) + const result = render(obs) + result.dispose() + // After dispose, updating the observable should not throw. + assert.doesNotThrow(() => obs({ elementName: 'p', children: ['updated'], attributes: {} })) + }) +}) diff --git a/packages/utils.jsx/src/index.ts b/packages/utils.jsx/src/index.ts index 4b3eefdcc..2ab1af172 100644 --- a/packages/utils.jsx/src/index.ts +++ b/packages/utils.jsx/src/index.ts @@ -1,3 +1,4 @@ -export { getOriginalJsxForNode, maybeJsx, createElement, Fragment } from './jsx' +export { getOriginalJsxForNode, maybeJsx, createElement, Fragment, render } from './jsx' +export type { JsxRenderResult } from './jsx' export { default as JsxObserver } from './JsxObserver' diff --git a/packages/utils.jsx/src/jsx.ts b/packages/utils.jsx/src/jsx.ts index 378bc771c..e580c99ed 100644 --- a/packages/utils.jsx/src/jsx.ts +++ b/packages/utils.jsx/src/jsx.ts @@ -1,6 +1,6 @@ import { isObservable, unwrap } from '@tko/observable' -import { ORIGINAL_JSX_SYM } from './JsxObserver' +import { JsxObserver, ORIGINAL_JSX_SYM } from './JsxObserver' /** * @@ -55,3 +55,20 @@ export function createElement(elementName, attributes, ...children) { } export const Fragment = Symbol('JSX Fragment') + +/** The shape returned by `render()`. */ +export type JsxRenderResult = { + node: ChildNode | DocumentFragment | null + dispose: () => void +} + +/** Converts JSX to DOM nodes, returning the node and a dispose callback. */ +export function render(jsx: any): JsxRenderResult { + const fragment = document.createDocumentFragment() + const observer = new JsxObserver(jsx, fragment) + const node = fragment.childNodes.length === 1 ? fragment.firstChild : fragment + return { + node, + dispose: () => observer.dispose() + } +} diff --git a/packages/utils.parser/package.json b/packages/utils.parser/package.json index 8e25f0275..0ea77f403 100644 --- a/packages/utils.parser/package.json +++ b/packages/utils.parser/package.json @@ -2,9 +2,10 @@ "version": "4.1.0", "name": "@tko/utils.parser", "description": "Parse the Javascript-like language used in data-bind and other HTML attributes (CSP-safe)", - "module": "dist/index.js", + "module": "dist/index.mjs", "files": [ - "dist/" + "dist/", + "types/" ], "license": "MIT", "dependencies": { @@ -20,8 +21,14 @@ ], "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "bugs": { @@ -41,5 +48,6 @@ "parser", "csp-safe", "expression" - ] + ], + "types": "./types/index.d.ts" } diff --git a/packages/utils/package.json b/packages/utils/package.json index b026750d9..83e8e81a0 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -4,7 +4,8 @@ "description": "TKO Utilities", "type": "module", "files": [ - "dist/" + "dist/", + "types/" ], "repository": { "type": "git", @@ -35,12 +36,19 @@ ], "exports": { ".": { - "require": "./dist/index.cjs", - "import": "./dist/index.js" + "import": { + "types": "./types/index.d.mts", + "default": "./dist/index.js" + }, + "require": { + "types": "./types/index.d.cts", + "default": "./dist/index.cjs" + } } }, "module": "dist/index.js", "scripts": { "build": "bun ../../tools/build.ts" - } + }, + "types": "./types/index.d.ts" } diff --git a/plans/2026-06-04-dts-types-layout.md b/plans/2026-06-04-dts-types-layout.md new file mode 100644 index 000000000..9b5e8b24a --- /dev/null +++ b/plans/2026-06-04-dts-types-layout.md @@ -0,0 +1,167 @@ +# Plan: Per-Package Types Output and Reference Build Declarations + +## Summary + +Replace the current repo-wide declaration emit with a published-layout model: + +- every publishable workspace gets a generated `types/` folder +- `@tko/build.reference` publishes a bundled declaration entry from its own + `types/` folder +- `@tko/build.knockout` publishes declarations for the KO-compatible default + import that consumers already use at runtime +- package manifests advertise the generated declaration files instead of + relying on source-only resolution + +This is a packaging and build-pipeline change, not a runtime API redesign. +The goal is to make the shipped type surface match the shipped JS surface. + +This plan addresses GitHub issue #384: the 4.x packages are TypeScript-authored +and ship source maps that point at `.ts` files, but the published packages do +not include `.d.ts` files or `types`/`typings` metadata. Consumers currently +hit missing-declaration errors for `@tko/build.knockout`, +`@tko/build.reference`, and modular `@tko/*` imports. + +## Current State + +- Root `package.json` runs `bunx tsc --build tsconfig.dts.json`. +- `tsconfig.dts.json` emits one + repo-level declaration bundle to `builds/dts/dist/tko.d.ts`. +- Published package manifests currently ship only `dist/`. +- Most package manifests expose JS through `exports` and `module`, but do not + point TypeScript at a published declaration artifact. +- Consumers importing `@tko/build.knockout`, `@tko/build.reference`, or an + individual `@tko/*` package get missing-declaration errors because no + package publishes `.d.ts` files. +- `builds/reference/types` + exists in the tree today but is empty, so there is no established generated + output contract yet. + +## Desired State + +- Each published package under `packages/*` generates `types/**/*.d.ts`. +- `@tko/build.reference` generates and publishes `types/index.d.ts` as its + public declaration entrypoint. +- `@tko/build.knockout` generates and publishes `types/index.d.ts` for the + backwards-compatible default import surface. +- Package consumers resolve declarations from published artifacts, not from + repo-only source paths. +- The repo still supports fast local typechecking against source via + `tsconfig.json` `paths`, but declaration generation uses a packaging-aware + pipeline. +- Clean/verify scripts remove and rebuild `types/` outputs just like `dist/`. + +## Constraints + +- Do not weaken the current `moduleResolution: "bundler"` setup or the source + resolution that keeps local `tsc` fast and accurate. +- Preserve the public JS entrypoints for all packages, especially + `@tko/build.knockout`. +- Avoid introducing runtime dependencies into framework packages. +- Treat manifest changes as public-package surface changes: the generated type + layout should be intentional and stable enough to publish. + +## Implementation Plan + +### 1. Replace the single-bundle d.ts strategy + +- Retire the current `outFile`-based `tsconfig.dts.json` flow. +- Introduce a declaration-generation script or tsconfig setup that emits + workspace-local declarations into `types/`. +- Add the types-folder to .gitignore +- Scope the generator to the 27 publishable workspaces (`packages/*`, + `builds/reference`, `builds/knockout`) so the output layout mirrors publish + boundaries. +- Emit declarations for `@tko/build.knockout` and `@tko/build.reference` + explicitly, because issue #384 reports both build packages as currently + untyped for consumers. + +### 2. Emit per-package declarations + +- For each package in `packages/*`, emit declarations rooted at + `types/index.d.ts` plus any sibling declaration files needed by imports. +- Ensure emitted paths stay self-contained inside each package's `types/` + folder and do not point back to repo-only source files. +- Verify that packages with re-export-heavy entrypoints still produce usable + published declarations. + +### 3. Bundle declarations for `@tko/build.reference` + +- Generate declarations for the reference build from its published entrypoint, + not from an ad hoc hand-maintained file. +- Bundle or flatten the reference build's public type surface into + `builds/reference/types/index.d.ts`. +- Make the bundled reference declaration the only public type entry for + `@tko/build.reference`, while its internal dependencies continue to publish + their own package-local `types/` folders. +- Confirm the reference declaration captures the builder-created default export + shape and its re-exported public symbols. + +### 4. Generate declarations for `@tko/build.knockout` + +- Generate declarations from the knockout build's published entrypoint. +- Preserve the KO-compatible default import surface so + `import ko from '@tko/build.knockout'` typechecks without depending on the old + `knockout` package or DefinitelyTyped. +- Verify the declaration output is compatible with the runtime export shape and + does not accidentally advertise source-only internals. + +### 5. Update package manifests + +- Update every published workspace `package.json` to ship `types/` alongside + `dist/`. +- Add top-level `"types"` entries that point at the generated declarations. +- Add `"types"` conditions inside `exports` for the main entrypoint so bundler + resolution and published consumption agree. +- Update `builds/reference/package.json` to publish its bundled declaration + entry from `types/index.d.ts`. +- Update `builds/knockout/package.json` to publish its declaration entry from + `types/index.d.ts`. +- Update the root `package.json` + scripts so `bun run dts` and `bun run clean` reflect the new output layout. + +### 6. Clean up ignored/generated artifacts + +- Extend ignore/cleanup rules so generated `types/` directories are treated the + same way as generated `dist/` output. +- Remove any obsolete references to `builds/dts/dist/tko.d.ts`. +- Decide whether the empty checked-in `builds/reference/types/` directory stays + as a generated path only or gains committed placeholders. Prefer generated + output only unless a tool requires the directory to exist. + +## Likely Files Touched During Implementation + +- `package.json` +- `tsconfig.dts.json` +- `tsconfig.json` +- `.gitignore` +- `builds/reference/package.json` +- `builds/knockout/package.json` +- `packages/*/package.json` +- one new shared declaration-build script or supporting tsconfig files under + `tools/` and/or repo root + +## Verification + +1. `bun run dts` creates `types/` folders for every publishable workspace. +2. `find packages builds -maxdepth 2 -name types -type d` shows the expected + generated directories and no stray `builds/dts` output. +3. Consumer-style TypeScript smoke tests pass for: + `import ko from '@tko/build.knockout'`, + `import ko from '@tko/build.reference'`, and at least one modular + `@tko/*` import. +4. `bun run build` still succeeds after the manifest changes. +5. `bun run tsc` still typechecks against source without published-artifact + regressions. +6. `bun run verify` passes, since this change touches shared packaging + infrastructure. +7. Spot-check packed contents for at least one leaf package, + `@tko/build.knockout`, and `@tko/build.reference` to confirm both `dist/` + and `types/` would publish. + +## Release Notes / Follow-up + +- Add a changeset when implementation lands, because this changes the + published package layout and TypeScript consumption contract. +- If declaration bundling for `@tko/build.reference` needs a new dev-only tool, + justify it explicitly in the implementation PR and keep it out of runtime + package dependencies. diff --git a/plans/2026-06-07-module-resolution-publish-check.md b/plans/2026-06-07-module-resolution-publish-check.md new file mode 100644 index 000000000..f5c420741 --- /dev/null +++ b/plans/2026-06-07-module-resolution-publish-check.md @@ -0,0 +1,80 @@ +# Plan: Node16/Nodenext-Compatible Published Types and Packaging + +## Summary + +Make the published `@tko/*` packages resolve cleanly across TypeScript's +modern package modes, not just `moduleResolution: "bundler"`. + +This plan extends the per-package declaration work from +`plans/2026-06-04-dts-types-layout.md` by aligning the published JS entrypoints +and published declaration entrypoints for both `require` and `import` +consumers, then wiring those guarantees into publish verification. + +## Current State + +- Public packages publish `types/**/*.d.ts` and expose them through top-level + `"types"` plus an `exports["."].types` condition. +- Most packages still point `exports["."].import` at `./dist/index.js` even + though packages without `"type": "module"` also emit `./dist/index.mjs`. +- The generated declarations preserve extensionless relative imports, which are + fine for bundler/CJS-style resolution but fail under ESM-flavored + `node16`/`nodenext` declaration resolution. +- `@tko/build.knockout` and `@tko/build.reference` publish default-exported + declarations that match the ESM surface but not the CommonJS surface. +- `.github/workflows/publish-check.yml` only does `npm pack --dry-run`, so + published type regressions are not gated today. + +## Desired State + +- Every public package resolves under `bundler`, `node16`, and `nodenext` + without ATTW suppressions for TKO's shipped entrypoints. +- Non-`type:module` packages expose ESM through `.mjs`, not `.js`. +- Published declarations are mode-aware: + `import` consumers get ESM-compatible declarations and `require` consumers + get CJS-compatible declarations. +- Publish verification fails on broken type/package metadata before merge. + +## Implementation Plan + +### 1. Generate mode-aware declarations + +- Extend `tools/build-dts.ts` so each workspace gets: + - baseline `.d.ts` output + - ESM-flavored declaration copies (`.d.mts`) with explicit relative `.js` + specifiers + - CJS-flavored declaration copies (`.d.cts`) where needed for `require` + resolution +- Special-case the build entrypoints so their CJS declaration entry advertises + `export =` instead of `export default`. + +### 2. Align package manifests with runtime output + +- Update public package manifests so non-`type:module` packages expose + `./dist/index.mjs` for the `import` condition. +- Use nested `exports` conditions so TypeScript can pick ESM declarations for + `import` and CJS declarations for `require`. +- Keep backwards-compatible public entrypoints, especially for + `@tko/build.knockout`. + +### 3. Add publish-time verification + +- Add `publint` and `@arethetypeswrong/cli --pack` to the publish-check + workflow for every public package. +- Mirror the same checks in local scripts so regressions are caught before CI. + +## Likely Files Touched + +- `package.json` +- `.github/workflows/publish-check.yml` +- `tools/build-dts.ts` +- `packages/*/package.json` +- `builds/*/package.json` + +## Verification + +1. `bun run dts` +2. `bun run build` +3. `bun run verify:types` plus new node16/nodenext smoke coverage +4. `npx @arethetypeswrong/cli --pack ` for leaf, + utility, and build packages +5. `bun run verify:publish-types` and publish-check workflow parity diff --git a/tools/build-dts.ts b/tools/build-dts.ts new file mode 100644 index 000000000..dac2afbb2 --- /dev/null +++ b/tools/build-dts.ts @@ -0,0 +1,86 @@ +#!/usr/bin/env bun +import { $, Glob } from 'bun' + +const tempOutDir = '.dts-tmp/emit' +const buildWorkspaces = ['builds/knockout', 'builds/reference'] +const packageWorkspaces: string[] = [] +// These entrypoints publish a package-level default export, but their CommonJS +// runtime shape is module.exports = value rather than { default: value }. +const cjsEntrypointsNeedingExportEquals = new Set(['builds/knockout', 'builds/reference', 'packages/utils.component']) + +function hasKnownExtension(specifier: string) { + return /\.(?:[cm]?js|json|[cm]?ts|tsx|jsx)$/i.test(specifier) +} + +function rewriteRelativeModuleSpecifiers(source: string, extension: '.mjs' | '.cjs') { + const rewrite = (_match: string, prefix: string, specifier: string, suffix: string) => { + if (!specifier.startsWith('./') && !specifier.startsWith('../')) { + return `${prefix}${specifier}${suffix}` + } + if (hasKnownExtension(specifier)) { + return `${prefix}${specifier}${suffix}` + } + return `${prefix}${specifier}${extension}${suffix}` + } + + return source + .replace(/(from\s+['"])(\.\.?\/[^'"]+)(['"])/g, rewrite) + .replace(/(import\s+['"])(\.\.?\/[^'"]+)(['"])/g, rewrite) + .replace(/(import\(\s*['"])(\.\.?\/[^'"]+)(['"]\s*\))/g, rewrite) +} + +function toCjsDeclaration(source: string, workspace: string, declarationPath: string) { + const rewritten = rewriteRelativeModuleSpecifiers(source, '.cjs') + + if ( + declarationPath === 'index.d.ts' && + cjsEntrypointsNeedingExportEquals.has(workspace) && + rewritten.includes('export default _default;') + ) { + return rewritten.replace('export default _default;', 'export = _default;') + } + + return rewritten +} + +for await (const manifest of new Glob('packages/*/package.json').scan('.')) { + packageWorkspaces.push(manifest.replace('/package.json', '')) +} + +const workspaces = [...packageWorkspaces.sort(), ...buildWorkspaces].sort() + +const WORKSPACES_EXPECTED_COUNT = 27 +if (workspaces.length !== WORKSPACES_EXPECTED_COUNT) { + throw new Error(`Expected ${WORKSPACES_EXPECTED_COUNT} publishable workspaces, found ${workspaces.length}`) +} + +await $`rm -rf ${tempOutDir}`.quiet() +await $`bunx tsc -p tsconfig.dts.json` + +for (const workspace of workspaces) { + const emittedTypesDir = `${tempOutDir}/${workspace}/src` + const packageTypesDir = `${workspace}/types` + const indexDeclaration = `${emittedTypesDir}/index.d.ts` + const result = await $`test -f ${indexDeclaration}`.nothrow().quiet() + + if (result.exitCode !== 0) { + throw new Error(`Missing declaration entry for ${workspace}: ${indexDeclaration}`) + } + + await $`rm -rf ${packageTypesDir}`.quiet() + await $`mkdir -p ${packageTypesDir}`.quiet() + await $`cp -R ${emittedTypesDir}/. ${packageTypesDir}/`.quiet() + + const declarationGlob = new Glob('**/*.d.ts') + for await (const declarationPath of declarationGlob.scan(packageTypesDir)) { + const declarationFile = `${packageTypesDir}/${declarationPath}` + const declarationSource = await Bun.file(declarationFile).text() + const esmFile = declarationFile.replace(/\.d\.ts$/, '.d.mts') + const cjsFile = declarationFile.replace(/\.d\.ts$/, '.d.cts') + + await Bun.write(esmFile, rewriteRelativeModuleSpecifiers(declarationSource, '.mjs')) + await Bun.write(cjsFile, toCjsDeclaration(declarationSource, workspace, declarationPath)) + } +} + +await $`rm -rf ${tempOutDir}`.quiet() diff --git a/tools/types-smoke/consumer.cts b/tools/types-smoke/consumer.cts new file mode 100644 index 000000000..e72e373d1 --- /dev/null +++ b/tools/types-smoke/consumer.cts @@ -0,0 +1,41 @@ +import ko = require('@tko/build.knockout') +import reference = require('@tko/build.reference') +import observablePkg = require('@tko/observable') +import computedPkg = require('@tko/computed') +import bindingCorePkg = require('@tko/binding.core') +import providerDataBindPkg = require('@tko/provider.databind') +import providerPkg = require('@tko/provider') +import utilsPkg = require('@tko/utils') + +const name = observablePkg.observable('TKO') +const knockoutVersion: string = ko.version +const referenceVersion: string = reference.version +const bindingString: string = ko.expressionRewriting.preProcessBindings('text: name') +const jsxTree = reference.jsx.createElement('div', null, name) +const rendered = reference.jsx.render(jsxTree) + +rendered.dispose() + +const doubled = computedPkg.computed(() => 2 * 2) +const doubledValue: number = doubled() + +const coreBindingCount: number = Object.keys(bindingCorePkg.bindings).length +const _hasTextBinding: boolean = 'text' in bindingCorePkg.bindings + +const dbProvider = new providerDataBindPkg.DataBindProvider() +const _asProvider: InstanceType = dbProvider + +const parsed: number | null = utilsPkg.parseJson('42') +if (parsed !== null) { + const _narrowed: number = parsed +} + +export = { + bindingString, + knockoutVersion, + referenceVersion, + doubledValue, + coreBindingCount, + dbProvider, + parsed +} diff --git a/tools/types-smoke/consumer.mts b/tools/types-smoke/consumer.mts new file mode 100644 index 000000000..9f1f42dd4 --- /dev/null +++ b/tools/types-smoke/consumer.mts @@ -0,0 +1,37 @@ +import ko from '@tko/build.knockout' +import reference from '@tko/build.reference' +import { observable } from '@tko/observable' +import { computed } from '@tko/computed' +import type { Computed } from '@tko/computed' +import { bindings } from '@tko/binding.core' +import { DataBindProvider } from '@tko/provider.databind' +import type { Provider } from '@tko/provider' +import { parseJson } from '@tko/utils' + +const name = observable('TKO') +const knockoutVersion: string = ko.version +const referenceVersion: string = reference.version +const bindingString: string = ko.expressionRewriting.preProcessBindings('text: name') +const jsxTree = reference.jsx.createElement('div', null, name) +const rendered = reference.jsx.render(jsxTree) + +rendered.dispose() + +const doubled: Computed = computed(() => 2 * 2) +const doubledValue: number = doubled() + +// @ts-expect-error -- Computed must not be assignable to Computed +const _notComputedString: Computed = doubled + +const coreBindingCount: number = Object.keys(bindings).length +const _hasTextBinding: boolean = 'text' in bindings + +const dbProvider = new DataBindProvider() +const _asProvider: Provider = dbProvider + +const parsed: number | null = parseJson('42') +if (parsed !== null) { + const _narrowed: number = parsed +} + +export { bindingString, knockoutVersion, referenceVersion, doubled, doubledValue, coreBindingCount, dbProvider, parsed } diff --git a/tools/types-smoke/consumer.ts b/tools/types-smoke/consumer.ts new file mode 100644 index 000000000..3c69bfd1d --- /dev/null +++ b/tools/types-smoke/consumer.ts @@ -0,0 +1,42 @@ +import ko from '@tko/build.knockout' +import reference from '@tko/build.reference' +import { observable } from '@tko/observable' +import { computed } from '@tko/computed' +import type { Computed } from '@tko/computed' +import { bindings } from '@tko/binding.core' +import { DataBindProvider } from '@tko/provider.databind' +import type { Provider } from '@tko/provider' +import { parseJson } from '@tko/utils' + +const name = observable('TKO') +const knockoutVersion: string = ko.version +const referenceVersion: string = reference.version +const bindingString: string = ko.expressionRewriting.preProcessBindings('text: name') +const jsxTree = reference.jsx.createElement('div', null, name) +const rendered = reference.jsx.render(jsxTree) + +rendered.dispose() + +// @tko/computed — Computed is callable and its return type is T +const doubled: Computed = computed(() => 2 * 2) +const doubledValue: number = doubled() + +// @ts-expect-error — Computed must not be assignable to Computed +const _notComputedString: Computed = doubled + +// @tko/binding.core — built-in bindings map has known keys +const coreBindingCount: number = Object.keys(bindings).length +const _hasTextBinding: boolean = 'text' in bindings + +// @tko/provider.databind — DataBindProvider must be assignable to Provider +// (exercises 3-level inheritance chain through generated .d.ts files) +const dbProvider = new DataBindProvider() +const _asProvider: Provider = dbProvider + +// @tko/utils — parseJson returns T | null; null guard narrows to T +const parsed: number | null = parseJson('42') +if (parsed !== null) { + const _narrowed: number = parsed +} + +export { bindingString, knockoutVersion, referenceVersion, doubled, doubledValue, coreBindingCount, dbProvider, parsed } diff --git a/tools/types-smoke/tsconfig.json b/tools/types-smoke/tsconfig.json new file mode 100644 index 000000000..8cdb85948 --- /dev/null +++ b/tools/types-smoke/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "es2022", + "module": "es2022", + "moduleResolution": "bundler", + "strict": true, + "noImplicitAny": false, + "skipLibCheck": true, + "noEmit": true, + "types": ["jquery"], + "lib": ["es2022", "dom"] + }, + "include": ["./consumer.ts"] +} diff --git a/tools/types-smoke/tsconfig.node16.json b/tools/types-smoke/tsconfig.node16.json new file mode 100644 index 000000000..695985a1c --- /dev/null +++ b/tools/types-smoke/tsconfig.node16.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "es2022", + "module": "node16", + "moduleResolution": "node16", + "strict": true, + "noImplicitAny": false, + "skipLibCheck": true, + "noEmit": true, + "types": ["jquery"], + "lib": ["es2022", "dom"] + }, + "include": ["./consumer.mts", "./consumer.cts"] +} diff --git a/tools/types-smoke/tsconfig.nodenext.json b/tools/types-smoke/tsconfig.nodenext.json new file mode 100644 index 000000000..1dbfda96b --- /dev/null +++ b/tools/types-smoke/tsconfig.nodenext.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "es2022", + "module": "nodenext", + "moduleResolution": "nodenext", + "strict": true, + "noImplicitAny": false, + "skipLibCheck": true, + "noEmit": true, + "types": ["jquery"], + "lib": ["es2022", "dom"] + }, + "include": ["./consumer.mts", "./consumer.cts"] +} diff --git a/tools/verify-publish-types.ts b/tools/verify-publish-types.ts new file mode 100644 index 000000000..98bbd7983 --- /dev/null +++ b/tools/verify-publish-types.ts @@ -0,0 +1,64 @@ +#!/usr/bin/env bun +import { Glob } from 'bun' + +const buildWorkspaces = ['builds/knockout', 'builds/reference'] +const packageWorkspaces: string[] = [] +const rootBinDir = `${process.cwd()}/node_modules/.bin` +const publintBin = `${rootBinDir}/publint` +const attwBin = `${rootBinDir}/attw` + +for await (const manifest of new Glob('packages/*/package.json').scan('.')) { + packageWorkspaces.push(manifest.replace('/package.json', '')) +} + +const workspaces = [...packageWorkspaces.sort(), ...buildWorkspaces].sort() + +const WORKSPACES_EXPECTED_COUNT = 27 +if (workspaces.length !== WORKSPACES_EXPECTED_COUNT) { + throw new Error(`Expected ${WORKSPACES_EXPECTED_COUNT} publishable workspaces, found ${workspaces.length}`) +} + +async function dirHasFiles(dir: string) { + for await (const _file of new Glob('**/*').scan(dir)) { + return true + } + + return false +} + +async function run(command: string[], cwd: string, label: string) { + console.log(`[verify:publish-types] ${cwd} :: ${label}`) + + const proc = Bun.spawn(command, { + cwd, + stdin: 'inherit', + stdout: 'inherit', + stderr: 'inherit' + }) + + const exitCode = await proc.exited + if (exitCode !== 0) { + throw new Error(`${cwd} failed ${label}`) + } +} + +for (const workspace of workspaces) { + const manifest = await Bun.file(`${workspace}/package.json`).json() + if (manifest.private) { + continue + } + + if (!(await dirHasFiles(`${workspace}/dist`))) { + throw new Error(`${manifest.name} has no dist output`) + } + + if (!(await dirHasFiles(`${workspace}/types`))) { + throw new Error(`${manifest.name} has no types output`) + } + + await run(['npm', 'pack', '--dry-run'], workspace, 'npm pack --dry-run') + await run([publintBin, '.'], workspace, 'publint') + await run([attwBin, '--pack', '.'], workspace, 'attw --pack') +} + +console.log('All packages pass publish/type verification.') diff --git a/tsconfig.dts.json b/tsconfig.dts.json index d8bdb939d..234366137 100644 --- a/tsconfig.dts.json +++ b/tsconfig.dts.json @@ -1,15 +1,24 @@ { "extends": "./tsconfig.json", - "compilerOptions": { + "compilerOptions": { "noEmit": false, "emitDeclarationOnly": true, - "outFile": "builds/dts/dist/tko.d.ts", + "rootDir": ".", + "outDir": "./.dts-tmp/emit" }, + "include": [ + "global.d.ts", + "packages/*/src/**/*.ts", + "builds/reference/src/**/*.ts", + "builds/knockout/src/**/*.ts" + ], "exclude": [ + "packages/*/src/**/*.d.ts", + "builds/reference/src/**/*.d.ts", + "builds/knockout/src/**/*.d.ts", + "**/spec/**", "node_modules", - "builds", - "docs", - "tools", - "**/spec/**" + "tko.io", + "tools" ] }