diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml new file mode 100644 index 000000000..1b2f127d9 --- /dev/null +++ b/.github/workflows/deploy-docs.yml @@ -0,0 +1,47 @@ +name: Deploy Documentation + +on: + push: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + + - name: Install dependencies + run: cd tko.io && bun install + + - name: Build site + run: cd tko.io && bun run build + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: tko.io/_site + + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 1163adbb0..0f9690c97 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,4 @@ coverage/ .vscode/extensions.json !.vscode/launch.json .vscode/settings.json +.playwright-mcp diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8f36b6d96..24b324839 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,6 +26,39 @@ If the issue is an enhancement, consider also including: 1. Explain why it would be **useful**. 2. List **other applications** that have the enhancement. +## Documentation + +All TKO documentation lives in `tko.io/src/docs/`. + +To contribute documentation: + +1. Edit files in `tko.io/src/docs/[category]/` where category is: + - `bindings/` - All binding handlers + - `observables/` - Observable and observable array docs + - `computed/` - Computed observable docs + - `components/` - Component system docs + - `binding-context/` - Binding context and custom bindings + - `advanced/` - Advanced topics (lifecycle, providers, parsers) + +2. Each file requires frontmatter: + ```yaml + --- + layout: base.njk + title: Page Title + --- + ``` + +3. Test locally: + ```bash + cd tko.io + bun run dev + ``` + Then visit http://localhost:8080 + +4. Submit a PR with your changes + +The documentation site is automatically deployed when changes are merged to main. + ## Pull Requests A good pull request might include: diff --git a/builds/reference/docs/intro.md b/builds/reference/docs/intro.md index f8126fe0f..4b26f43c5 100644 --- a/builds/reference/docs/intro.md +++ b/builds/reference/docs/intro.md @@ -24,11 +24,6 @@ TKO has a comprehensive suite of tests that ensure its correct functioning and a ## Sponsors -Support Knockout: - - - via Patreon to Brian M Hunt - ## First Example diff --git a/builds/reference/src/index.ts b/builds/reference/src/index.ts index 10928995e..7b815a5a7 100644 --- a/builds/reference/src/index.ts +++ b/builds/reference/src/index.ts @@ -22,6 +22,7 @@ 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 { overloadOperator } from '@tko/utils.parser' @@ -57,10 +58,22 @@ const builder = new Builder({ }) const version = BUILD_VERSION + export default builder.create({ 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() + } + }, }, components, version, diff --git a/packages/binding.if/docs/_config.yml b/packages/binding.if/docs/_config.yml deleted file mode 100644 index 99273f014..000000000 --- a/packages/binding.if/docs/_config.yml +++ /dev/null @@ -1,2 +0,0 @@ -# theme: jekyll-theme-slate - diff --git a/tko.io/.eleventy.js b/tko.io/.eleventy.js new file mode 100644 index 000000000..0b6552fe3 --- /dev/null +++ b/tko.io/.eleventy.js @@ -0,0 +1,88 @@ +import markdownIt from "markdown-it"; + +export default function(eleventyConfig) { + // Follow symlinks + eleventyConfig.setServerOptions({ + followSymlinks: true + }); + + // Copy static assets + eleventyConfig.addPassthroughCopy("src/css"); + eleventyConfig.addPassthroughCopy("src/js"); + eleventyConfig.addPassthroughCopy("src/lib"); + eleventyConfig.addPassthroughCopy("src/CNAME"); + + // Watch for changes + eleventyConfig.addWatchTarget("src/css/"); + eleventyConfig.addWatchTarget("src/js/"); + + // Configure markdown + const md = markdownIt({ + html: true, + breaks: false, + linkify: true + }); + + eleventyConfig.setLibrary("md", md); + + // Create collections for each documentation category + eleventyConfig.addCollection("bindingDocs", function(collectionApi) { + return collectionApi.getFilteredByGlob("src/docs/bindings/*.md") + .filter(page => !page.url.endsWith('/bindings/')) + .sort((a, b) => a.fileSlug.localeCompare(b.fileSlug)); + }); + + eleventyConfig.addCollection("observableDocs", function(collectionApi) { + return collectionApi.getFilteredByGlob("src/docs/observables/*.md") + .filter(page => !page.url.endsWith('/observables/')) + .sort((a, b) => a.fileSlug.localeCompare(b.fileSlug)); + }); + + eleventyConfig.addCollection("computedDocs", function(collectionApi) { + return collectionApi.getFilteredByGlob("src/docs/computed/*.md") + .filter(page => !page.url.endsWith('/computed/')) + .sort((a, b) => a.fileSlug.localeCompare(b.fileSlug)); + }); + + eleventyConfig.addCollection("componentDocs", function(collectionApi) { + return collectionApi.getFilteredByGlob("src/docs/components/*.md") + .filter(page => !page.url.endsWith('/components/')) + .sort((a, b) => a.fileSlug.localeCompare(b.fileSlug)); + }); + + eleventyConfig.addCollection("bindingContextDocs", function(collectionApi) { + return collectionApi.getFilteredByGlob("src/docs/binding-context/*.md") + .filter(page => !page.url.endsWith('/binding-context/')) + .sort((a, b) => a.fileSlug.localeCompare(b.fileSlug)); + }); + + eleventyConfig.addCollection("advancedDocs", function(collectionApi) { + return collectionApi.getFilteredByGlob("src/docs/advanced/*.md") + .filter(page => !page.url.endsWith('/advanced/')) + .sort((a, b) => a.fileSlug.localeCompare(b.fileSlug)); + }); + + // Add filter to format titles from file slugs + eleventyConfig.addFilter("formatTitle", function(slug) { + return slug + .split('-') + .map(word => word.charAt(0).toUpperCase() + word.slice(1)) + .join(' '); + }); + + // Add filter to format binding names (keeps lowercase, removes -binding suffix) + eleventyConfig.addFilter("formatBindingName", function(slug) { + return slug.replace(/-binding$/, ''); + }); + + return { + dir: { + input: "src", + output: "_site", + includes: "_includes", + layouts: "_layouts" + }, + markdownTemplateEngine: "njk", + htmlTemplateEngine: "njk" + }; +} diff --git a/tko.io/.gitignore b/tko.io/.gitignore index 378eac25d..b35c36980 100644 --- a/tko.io/.gitignore +++ b/tko.io/.gitignore @@ -1 +1,4 @@ -build +node_modules/ +_site/ +package-lock.json +src/lib/ diff --git a/tko.io/README.md b/tko.io/README.md new file mode 100644 index 000000000..7c8f5048c --- /dev/null +++ b/tko.io/README.md @@ -0,0 +1,64 @@ +# TKO Documentation Site + +This is the documentation website for TKO, built with 11ty (Eleventy). + +## Development + +```bash +# Install dependencies +bun install + +# Start local development server +bun run dev + +# Build for production +bun run build +``` + +The site will be available at http://localhost:8080/ + +## Features + +- Written in Markdown +- Interactive JSX examples using esbuild-wasm +- Examples are written in code blocks and automatically transformed into editable textareas with live preview +- Styled with the classic TKO theme + +## Structure + +``` +tko.io/ +├── src/ +│ ├── _layouts/ # Page layouts (Nunjucks) +│ ├── _includes/ # Reusable components +│ ├── css/ # Stylesheets +│ ├── js/ # JavaScript (example system) +│ ├── docs/ # Documentation pages (Markdown) +│ └── index.md # Homepage +├── _site/ # Built site (gitignored) +└── .eleventy.js # 11ty configuration +``` + +## Adding Documentation + +1. Create a new `.md` file in `src/docs/` +2. Add front matter with layout and title: + ```yaml + --- + layout: base.njk + title: Your Page Title + --- + ``` +3. Write content in Markdown +4. Add interactive JSX examples using: + ````markdown + ```jsx + function Example() { + return
Hello World
+ } + ``` + ```` + +## Deployment + +The site is automatically deployed to GitHub Pages when changes are pushed to the `main` branch. diff --git a/tko.io/app.yaml b/tko.io/app.yaml deleted file mode 100644 index fd142e2ef..000000000 --- a/tko.io/app.yaml +++ /dev/null @@ -1,42 +0,0 @@ -# -# This is the Google App Engine standard config. -# -# Deploy with the `gcloud` tool using: -# -# $ gcloud app deploy --project tko-io . -# -# Test with `dev_appserver.py .` -# -runtime: python27 -api_version: 1 -threadsafe: true - -default_expiration: 30s - -handlers: - -- url: / - secure: always - static_files: build/index.html - upload: build/index.html - # http_headers: ... - -- url: /3to4 - secure: always - static_files: build/3to4.html - upload: build/3to4.html - -- url: /(.*\.js)$ - secure: always - static_files: src/\1 - upload: src/.*$ - -- url: / - secure: always - static_dir: build/ - - -skip_files: - - node_modules - - ".*.yaml" - - ".*.lock" diff --git a/tko.io/bun.lock b/tko.io/bun.lock new file mode 100644 index 000000000..34055fbaf --- /dev/null +++ b/tko.io/bun.lock @@ -0,0 +1,286 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "tko-docs", + "devDependencies": { + "@11ty/eleventy": "^3.0.0", + "esbuild-wasm": "^0.24.0", + "markdown-it": "^14.1.0", + }, + }, + }, + "packages": { + "@11ty/dependency-tree": ["@11ty/dependency-tree@4.0.1", "", { "dependencies": { "@11ty/eleventy-utils": "^2.0.1" } }, "sha512-6EPI9ZkGU4BX2KNZpWlf4WdV3vrmIWQpn//nAXicTzdPubI3jZlmFdqEv0Yj5M7oavRUGNzw9GbV9cBxhulZWw=="], + + "@11ty/dependency-tree-esm": ["@11ty/dependency-tree-esm@2.0.4", "", { "dependencies": { "@11ty/eleventy-utils": "^2.0.7", "acorn": "^8.15.0", "dependency-graph": "^1.0.0", "normalize-path": "^3.0.0" } }, "sha512-MYKC0Ac77ILr1HnRJalzKDlb9Z8To3kXQCltx299pUXXUFtJ1RIONtULlknknqW8cLe19DLVgmxVCtjEFm7h0A=="], + + "@11ty/eleventy": ["@11ty/eleventy@3.1.2", "", { "dependencies": { "@11ty/dependency-tree": "^4.0.0", "@11ty/dependency-tree-esm": "^2.0.0", "@11ty/eleventy-dev-server": "^2.0.8", "@11ty/eleventy-plugin-bundle": "^3.0.6", "@11ty/eleventy-utils": "^2.0.7", "@11ty/lodash-custom": "^4.17.21", "@11ty/posthtml-urls": "^1.0.1", "@11ty/recursive-copy": "^4.0.2", "@sindresorhus/slugify": "^2.2.1", "bcp-47-normalize": "^2.3.0", "chokidar": "^3.6.0", "debug": "^4.4.1", "dependency-graph": "^1.0.0", "entities": "^6.0.1", "filesize": "^10.1.6", "gray-matter": "^4.0.3", "iso-639-1": "^3.1.5", "js-yaml": "^4.1.0", "kleur": "^4.1.5", "liquidjs": "^10.21.1", "luxon": "^3.6.1", "markdown-it": "^14.1.0", "minimist": "^1.2.8", "moo": "^0.5.2", "node-retrieve-globals": "^6.0.1", "nunjucks": "^3.2.4", "picomatch": "^4.0.2", "please-upgrade-node": "^3.2.0", "posthtml": "^0.16.6", "posthtml-match-helper": "^2.0.3", "semver": "^7.7.2", "slugify": "^1.6.6", "tinyglobby": "^0.2.14" }, "bin": { "eleventy": "cmd.cjs" } }, "sha512-IcsDlbXnBf8cHzbM1YBv3JcTyLB35EK88QexmVyFdVJVgUU6bh9g687rpxryJirHzo06PuwnYaEEdVZQfIgRGg=="], + + "@11ty/eleventy-dev-server": ["@11ty/eleventy-dev-server@2.0.8", "", { "dependencies": { "@11ty/eleventy-utils": "^2.0.1", "chokidar": "^3.6.0", "debug": "^4.4.0", "finalhandler": "^1.3.1", "mime": "^3.0.0", "minimist": "^1.2.8", "morphdom": "^2.7.4", "please-upgrade-node": "^3.2.0", "send": "^1.1.0", "ssri": "^11.0.0", "urlpattern-polyfill": "^10.0.0", "ws": "^8.18.1" }, "bin": { "eleventy-dev-server": "cmd.js" } }, "sha512-15oC5M1DQlCaOMUq4limKRYmWiGecDaGwryr7fTE/oM9Ix8siqMvWi+I8VjsfrGr+iViDvWcH/TVI6D12d93mA=="], + + "@11ty/eleventy-plugin-bundle": ["@11ty/eleventy-plugin-bundle@3.0.7", "", { "dependencies": { "@11ty/eleventy-utils": "^2.0.2", "debug": "^4.4.0", "posthtml-match-helper": "^2.0.3" } }, "sha512-QK1tRFBhQdZASnYU8GMzpTdsMMFLVAkuU0gVVILqNyp09xJJZb81kAS3AFrNrwBCsgLxTdWHJ8N64+OTTsoKkA=="], + + "@11ty/eleventy-utils": ["@11ty/eleventy-utils@2.0.7", "", {}, "sha512-6QE+duqSQ0GY9rENXYb4iPR4AYGdrFpqnmi59tFp9VrleOl0QSh8VlBr2yd6dlhkdtj7904poZW5PvGr9cMiJQ=="], + + "@11ty/lodash-custom": ["@11ty/lodash-custom@4.17.21", "", {}, "sha512-Mqt6im1xpb1Ykn3nbcCovWXK3ggywRJa+IXIdoz4wIIK+cvozADH63lexcuPpGS/gJ6/m2JxyyXDyupkMr5DHw=="], + + "@11ty/posthtml-urls": ["@11ty/posthtml-urls@1.0.2", "", { "dependencies": { "evaluate-value": "^2.0.0", "http-equiv-refresh": "^2.0.1", "list-to-array": "^1.1.0", "parse-srcset": "^1.0.2" } }, "sha512-0vaV3Wt0surZ+oS1VdKKe0axeeupuM+l7W/Z866WFQwF+dGg2Tc/nmhk/5l74/Y55P8KyImnLN9CdygNw2huHg=="], + + "@11ty/recursive-copy": ["@11ty/recursive-copy@4.0.3", "", { "dependencies": { "errno": "^1.0.0", "junk": "^3.1.0", "maximatch": "^0.1.0", "slash": "^3.0.0" } }, "sha512-SX48BTLEGX8T/OsKWORsHAAeiDsbFl79Oa/0Wg/mv/d27b7trCVZs7fMHvpSgDvZz/fZqx5rDk8+nx5oyT7xBw=="], + + "@sindresorhus/slugify": ["@sindresorhus/slugify@2.2.1", "", { "dependencies": { "@sindresorhus/transliterate": "^1.0.0", "escape-string-regexp": "^5.0.0" } }, "sha512-MkngSCRZ8JdSOCHRaYd+D01XhvU3Hjy6MGl06zhOk614hp9EOAp5gIkBeQg7wtmxpitU6eAL4kdiRMcJa2dlrw=="], + + "@sindresorhus/transliterate": ["@sindresorhus/transliterate@1.6.0", "", { "dependencies": { "escape-string-regexp": "^5.0.0" } }, "sha512-doH1gimEu3A46VX6aVxpHTeHrytJAG6HgdxntYnCFiIFHEM/ZGpG8KiZGBChchjQmG0XFIBL552kBTjVcMZXwQ=="], + + "a-sync-waterfall": ["a-sync-waterfall@1.0.1", "", {}, "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA=="], + + "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], + + "acorn-walk": ["acorn-walk@8.3.4", "", { "dependencies": { "acorn": "^8.11.0" } }, "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g=="], + + "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], + + "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + + "array-differ": ["array-differ@1.0.0", "", {}, "sha512-LeZY+DZDRnvP7eMuQ6LHfCzUGxAAIViUBliK24P3hWXL6y4SortgR6Nim6xrkfSLlmH0+k+9NYNwVC2s53ZrYQ=="], + + "array-union": ["array-union@1.0.2", "", { "dependencies": { "array-uniq": "^1.0.1" } }, "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng=="], + + "array-uniq": ["array-uniq@1.0.3", "", {}, "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q=="], + + "arrify": ["arrify@1.0.1", "", {}, "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA=="], + + "asap": ["asap@2.0.6", "", {}, "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="], + + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "bcp-47": ["bcp-47@2.1.0", "", { "dependencies": { "is-alphabetical": "^2.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0" } }, "sha512-9IIS3UPrvIa1Ej+lVDdDwO7zLehjqsaByECw0bu2RRGP73jALm6FYbzI5gWbgHLvNdkvfXB5YrSbocZdOS0c0w=="], + + "bcp-47-match": ["bcp-47-match@2.0.3", "", {}, "sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ=="], + + "bcp-47-normalize": ["bcp-47-normalize@2.3.0", "", { "dependencies": { "bcp-47": "^2.0.0", "bcp-47-match": "^2.0.0" } }, "sha512-8I/wfzqQvttUFz7HVJgIZ7+dj3vUaIyIxYXaTRP1YWoSDfzt6TUmxaKZeuXR62qBmYr+nvuWINFRl6pZ5DlN4Q=="], + + "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], + + "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], + + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], + + "chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], + + "commander": ["commander@10.0.1", "", {}, "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug=="], + + "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], + + "dependency-graph": ["dependency-graph@1.0.0", "", {}, "sha512-cW3gggJ28HZ/LExwxP2B++aiKxhJXMSIt9K48FOXQkm+vuG5gyatXnLsONRJdzO/7VfjDIiaOOa/bs4l464Lwg=="], + + "dom-serializer": ["dom-serializer@1.4.1", "", { "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", "entities": "^2.0.0" } }, "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag=="], + + "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], + + "domhandler": ["domhandler@4.3.1", "", { "dependencies": { "domelementtype": "^2.2.0" } }, "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ=="], + + "domutils": ["domutils@2.8.0", "", { "dependencies": { "dom-serializer": "^1.0.1", "domelementtype": "^2.2.0", "domhandler": "^4.2.0" } }, "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A=="], + + "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], + + "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], + + "entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], + + "errno": ["errno@1.0.0", "", { "dependencies": { "prr": "~1.0.1" }, "bin": { "errno": "cli.js" } }, "sha512-3zV5mFS1E8/1bPxt/B0xxzI1snsg3uSCIh6Zo1qKg6iMw93hzPANk9oBFzSFBFrwuVoQuE3rLoouAUfwOAj1wQ=="], + + "esbuild-wasm": ["esbuild-wasm@0.24.2", "", { "bin": { "esbuild": "bin/esbuild" } }, "sha512-03/7Z1gD+ohDnScFztvI4XddTAbKVmMEzCvvkBpQdWKEXJ+73dTyeNrmdxP1Q0zpDMFjzUJwtK4rLjqwiHbzkw=="], + + "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], + + "escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], + + "esm-import-transformer": ["esm-import-transformer@3.0.5", "", { "dependencies": { "acorn": "^8.15.0" } }, "sha512-1GKLvfuMnnpI75l8c6sHoz0L3Z872xL5akGuBudgqTDPv4Vy6f2Ec7jEMKTxlqWl/3kSvNbHELeimJtnqgYniw=="], + + "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="], + + "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], + + "evaluate-value": ["evaluate-value@2.0.0", "", {}, "sha512-VonfiuDJc0z4sOO7W0Pd130VLsXN6vmBWZlrog1mCb/o7o/Nl5Lr25+Kj/nkCCAhG+zqeeGjxhkK9oHpkgTHhQ=="], + + "extend-shallow": ["extend-shallow@2.0.1", "", { "dependencies": { "is-extendable": "^0.1.0" } }, "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug=="], + + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + + "filesize": ["filesize@10.1.6", "", {}, "sha512-sJslQKU2uM33qH5nqewAwVB2QgR6w1aMNsYUp3aN5rMRyXEwJGmZvaWzeJFNTOXWlHQyBFCWrdj3fV/fsTOX8w=="], + + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + + "finalhandler": ["finalhandler@1.3.2", "", { "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "~2.4.1", "parseurl": "~1.3.3", "statuses": "~2.0.2", "unpipe": "~1.0.0" } }, "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg=="], + + "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "gray-matter": ["gray-matter@4.0.3", "", { "dependencies": { "js-yaml": "^3.13.1", "kind-of": "^6.0.2", "section-matter": "^1.0.0", "strip-bom-string": "^1.0.0" } }, "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q=="], + + "htmlparser2": ["htmlparser2@7.2.0", "", { "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.2", "domutils": "^2.8.0", "entities": "^3.0.1" } }, "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog=="], + + "http-equiv-refresh": ["http-equiv-refresh@2.0.1", "", {}, "sha512-XJpDL/MLkV3dKwLzHwr2dY05dYNfBNlyPu4STQ8WvKCFdc6vC5tPXuq28of663+gHVg03C+16pHHs/+FmmDjcw=="], + + "http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="], + + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + + "is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="], + + "is-alphanumerical": ["is-alphanumerical@2.0.1", "", { "dependencies": { "is-alphabetical": "^2.0.0", "is-decimal": "^2.0.0" } }, "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw=="], + + "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], + + "is-decimal": ["is-decimal@2.0.1", "", {}, "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A=="], + + "is-extendable": ["is-extendable@0.1.1", "", {}, "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw=="], + + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], + + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], + + "is-json": ["is-json@2.0.1", "", {}, "sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA=="], + + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + + "iso-639-1": ["iso-639-1@3.1.5", "", {}, "sha512-gXkz5+KN7HrG0Q5UGqSMO2qB9AsbEeyLP54kF1YrMsIxmu+g4BdB7rflReZTSTZGpfj8wywu6pfPBCylPIzGQA=="], + + "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], + + "junk": ["junk@3.1.0", "", {}, "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ=="], + + "kind-of": ["kind-of@6.0.3", "", {}, "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="], + + "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], + + "linkify-it": ["linkify-it@5.0.0", "", { "dependencies": { "uc.micro": "^2.0.0" } }, "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ=="], + + "liquidjs": ["liquidjs@10.24.0", "", { "dependencies": { "commander": "^10.0.0" }, "bin": { "liquidjs": "bin/liquid.js", "liquid": "bin/liquid.js" } }, "sha512-TAUNAdgwaAXjjcUFuYVJm9kOVH7zc0mTKxsG9t9Lu4qdWjB2BEblyVIYpjWcmJLMGgiYqnGNJjpNMHx0gp/46A=="], + + "list-to-array": ["list-to-array@1.1.0", "", {}, "sha512-+dAZZ2mM+/m+vY9ezfoueVvrgnHIGi5FvgSymbIgJOFwiznWyA59mav95L+Mc6xPtL3s9gm5eNTlNtxJLbNM1g=="], + + "luxon": ["luxon@3.7.2", "", {}, "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew=="], + + "markdown-it": ["markdown-it@14.1.0", "", { "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", "linkify-it": "^5.0.0", "mdurl": "^2.0.0", "punycode.js": "^2.3.1", "uc.micro": "^2.1.0" }, "bin": { "markdown-it": "bin/markdown-it.mjs" } }, "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg=="], + + "maximatch": ["maximatch@0.1.0", "", { "dependencies": { "array-differ": "^1.0.0", "array-union": "^1.0.1", "arrify": "^1.0.0", "minimatch": "^3.0.0" } }, "sha512-9ORVtDUFk4u/NFfo0vG/ND/z7UQCVZBL539YW0+U1I7H1BkZwizcPx5foFv7LCPcBnm2U6RjFnQOsIvN4/Vm2A=="], + + "mdurl": ["mdurl@2.0.0", "", {}, "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w=="], + + "mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="], + + "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], + + "mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], + + "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], + + "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], + + "moo": ["moo@0.5.2", "", {}, "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q=="], + + "morphdom": ["morphdom@2.7.7", "", {}, "sha512-04GmsiBcalrSCNmzfo+UjU8tt3PhZJKzcOy+r1FlGA7/zri8wre3I1WkYN9PT3sIeIKfW9bpyElA+VzOg2E24g=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "node-retrieve-globals": ["node-retrieve-globals@6.0.1", "", { "dependencies": { "acorn": "^8.14.1", "acorn-walk": "^8.3.4", "esm-import-transformer": "^3.0.3" } }, "sha512-j0DeFuZ/Wg3VlklfbxUgZF/mdHMTEiEipBb3q0SpMMbHaV3AVfoUQF8UGxh1s/yjqO0TgRZd4Pi/x2yRqoQ4Eg=="], + + "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], + + "nunjucks": ["nunjucks@3.2.4", "", { "dependencies": { "a-sync-waterfall": "^1.0.0", "asap": "^2.0.3", "commander": "^5.1.0" }, "peerDependencies": { "chokidar": "^3.3.0" }, "optionalPeers": ["chokidar"], "bin": { "nunjucks-precompile": "bin/precompile" } }, "sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ=="], + + "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], + + "parse-srcset": ["parse-srcset@1.0.2", "", {}, "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q=="], + + "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], + + "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + + "please-upgrade-node": ["please-upgrade-node@3.2.0", "", { "dependencies": { "semver-compare": "^1.0.0" } }, "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg=="], + + "posthtml": ["posthtml@0.16.7", "", { "dependencies": { "posthtml-parser": "^0.11.0", "posthtml-render": "^3.0.0" } }, "sha512-7Hc+IvlQ7hlaIfQFZnxlRl0jnpWq2qwibORBhQYIb0QbNtuicc5ZxvKkVT71HJ4Py1wSZ/3VR1r8LfkCtoCzhw=="], + + "posthtml-match-helper": ["posthtml-match-helper@2.0.3", "", { "peerDependencies": { "posthtml": "^0.16.6" } }, "sha512-p9oJgTdMF2dyd7WE54QI1LvpBIkNkbSiiECKezNnDVYhGhD1AaOnAkw0Uh0y5TW+OHO8iBdSqnd8Wkpb6iUqmw=="], + + "posthtml-parser": ["posthtml-parser@0.11.0", "", { "dependencies": { "htmlparser2": "^7.1.1" } }, "sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw=="], + + "posthtml-render": ["posthtml-render@3.0.0", "", { "dependencies": { "is-json": "^2.0.1" } }, "sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA=="], + + "prr": ["prr@1.0.1", "", {}, "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw=="], + + "punycode.js": ["punycode.js@2.3.1", "", {}, "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA=="], + + "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], + + "readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], + + "section-matter": ["section-matter@1.0.0", "", { "dependencies": { "extend-shallow": "^2.0.1", "kind-of": "^6.0.0" } }, "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA=="], + + "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + + "semver-compare": ["semver-compare@1.0.0", "", {}, "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow=="], + + "send": ["send@1.2.1", "", { "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="], + + "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], + + "slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], + + "slugify": ["slugify@1.6.6", "", {}, "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw=="], + + "sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], + + "ssri": ["ssri@11.0.0", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-aZpUoMN/Jj2MqA4vMCeiKGnc/8SuSyHbGSBdgFbZxP8OJGF/lFkIuElzPxsN0q8TQQ+prw3P4EDfB3TBHHgfXw=="], + + "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], + + "strip-bom-string": ["strip-bom-string@1.0.0", "", {}, "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g=="], + + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], + + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + + "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], + + "uc.micro": ["uc.micro@2.1.0", "", {}, "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A=="], + + "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], + + "urlpattern-polyfill": ["urlpattern-polyfill@10.1.0", "", {}, "sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw=="], + + "ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="], + + "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "dom-serializer/entities": ["entities@2.2.0", "", {}, "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="], + + "finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "gray-matter/js-yaml": ["js-yaml@3.14.2", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg=="], + + "htmlparser2/entities": ["entities@3.0.1", "", {}, "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q=="], + + "markdown-it/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + + "nunjucks/commander": ["commander@5.1.0", "", {}, "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg=="], + + "readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "gray-matter/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], + } +} diff --git a/tko.io/make.js b/tko.io/make.js deleted file mode 100755 index 02e0a3a85..000000000 --- a/tko.io/make.js +++ /dev/null @@ -1,110 +0,0 @@ -#!/usr/bin/env node - -const fs = require('fs-extra') -const yaml = require('js-yaml') -const pug = require('pug') -const debounce = require('lodash.debounce') -const hljs = require('highlight.js') -const {spawn} = require('child_process') -const {argv} = process - -function highlight (str, lang) { - if (!lang) { return '' } - if (hljs.getLanguage(lang)) { - try { - return hljs.highlight(lang, str).value - } catch (__) {} - } - return '' -} - -const md = require('markdown-it')({ - html: true, - linkify: true, - typographer: true, - highlight -}) - -const ENC = {encoding: 'utf8'} - -function * genHtmlIncludes ({includes}, htmlSettings, config) { - for (const relPath of includes || []) { - const sourcePath = '../packages/' + relPath - console.log(' | ', sourcePath) - const source = fs.readFileSync(sourcePath, ENC) - if (sourcePath.endsWith('.md')) { - yield ` - ${md.render(source)}` - } else if (sourcePath.endsWith('.pug')) { - yield pug.render(source, Object.assign({}, htmlSettings, config)) - } else { - throw new Error(`Bad extension: ${sourcePath} (not .md or .pug)`) - } - } -} - -function * genSections (htmlConfig, config) { - for (const section of htmlConfig.sections) { - console.log(` |- ${section.title}`) - section.html = Array.from(genHtmlIncludes(section, htmlConfig, config)).join('\n') - yield section - } -} - -function makeHtml({htmlSettings, scripts, links, styles}, config) { - /** - * Make build/index.html - */ - console.log(` Making ${htmlSettings.dest}`) - Object.assign(htmlSettings, {scripts, links, styles}) // add links + scripts - const sections = Array.from(genSections(htmlSettings, config)) - const locals = Object.assign(htmlSettings, {sections}) - const html = pug.renderFile('src/index.pug', locals) - fs.writeFileSync(htmlSettings.dest, html) -} - -function make () { - console.log('👲 Starting at ', new Date()) - - /** - * Make build/ - */ - fs.mkdirs('build/') - - const styles = fs.readFileSync('src/tko.css') - const config = yaml.load(fs.readFileSync('./settings.yaml', ENC)) - const {scripts, links} = config - - makeHtml({ htmlSettings: config.index, styles, scripts, links }, config) - makeHtml({ htmlSettings: config['3to4'], styles, scripts, links }, config) - - console.log("🏁 Complete.", new Date()) - /** - * Make Legacy Javascript - */ - // console.log('Making build/tko-io.js') - // fs.copySync('src/tko-io.js', 'build/tko-io.js') -} - -if (argv.includes('-w')) { - const ignored = '' // /(^|[\/\\])(\..|build\/*)/ - require('chokidar') - .watch(['settings.yaml', 'src', '../packages'], {ignored}) - .on('all', debounce(make, 150)) -} else { - console.log(` - Usage: make.js [-w] [-s] - - -w Watch and rebuild on change - -s Start the server with 'dev_appserver.py .' (from Google Cloud) - - Deploy with: - - $ gcloud app deploy --project tko-io . - `) - make() -} - -if (argv.includes('-s')) { - spawn('dev_appserver.py', ['.'], {stdio: 'inherit'}) -} diff --git a/tko.io/package.json b/tko.io/package.json index 244c811e7..8896b963f 100644 --- a/tko.io/package.json +++ b/tko.io/package.json @@ -1,18 +1,24 @@ { "name": "tko.io", "version": "1.0.0", - "description": "Landing page for tko.io", - "main": "index.js", - "author": "Knockout Team", + "type": "module", + "description": "TKO documentation site", + "scripts": { + "build:libdir": "mkdir -p src/lib", + "build:ko": "cd ../builds/knockout && make browser && cp dist/browser.min.js ../../tko.io/src/lib/ko.js", + "build:tko": "cd ../builds/reference && make browser && cp dist/browser.min.js ../../tko.io/src/lib/tko.js", + "prebuild": "npm run build:libdir && npm run build:ko && npm run build:tko", + "predev": "npm run prebuild", + "dev": "bunx @11ty/eleventy --serve", + "build": "bunx @11ty/eleventy", + "start": "bunx @11ty/eleventy --serve" + }, + "keywords": ["tko", "knockout", "documentation"], + "author": "", "license": "MIT", - "dependencies": { - "chokidar": "^1.7.0", - "fs-extra": "^4.0.2", - "gray-matter": "^3.1.1", - "highlight.js": "^9.12.0", - "js-yaml": "^3.10.0", - "lodash.debounce": "^4.0.8", - "markdown-it": "^8.4.0", - "pug": "^3.0.3" + "devDependencies": { + "@11ty/eleventy": "^3.0.0", + "esbuild-wasm": "^0.24.0", + "markdown-it": "^14.1.0" } } diff --git a/tko.io/settings.yaml b/tko.io/settings.yaml deleted file mode 100644 index f950678e4..000000000 --- a/tko.io/settings.yaml +++ /dev/null @@ -1,428 +0,0 @@ - -links: -- href: https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css - integrity: sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M - -- href: https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/atom-one-dark.min.css - integrity: sha256-akwTLZec/XAFvgYgVH1T5/369lhA2Efr22xzCNl1nHs= - -- href: https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css - integrity: sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN - -scripts: -- src: https://unpkg.com/tko@4.0.0-alpha4a/dist/tko.js - integrity: sha384-MJ/drYzT5bwJWdFxjHRDTJHTNccRZb70G7rQ9GeBnrSW/ssr3+A0kA1Ul7IHBZ/Y - crossorigin: anonymous - -- src: https://production-assets.codepen.io/assets/embed/ei.js - async: async - -- src: tko-io.js - type: application/javascript - async: async - -3to4: - dest: build/3to4.html - sections: - - title: Knockout 3 to 4 Guide - includes: - - tko/docs/3to4.md - -index: - dest: build/index.html - sections: - - title: Introduction - includes: - - tko/docs/intro.md - - tko/docs/books.pug - # - tko/docs/amd-loading.md - # - tko/docs/animated.md - # - tko/docs/api.md - # - tko/docs/browser-support.md - # - tko/docs/docs.md - # - tko/docs/fn.md - # - tko/docs/installation.md - # - tko/docs/intro.md - # - tko/docs/links.md - # - tko/docs/plugins.md - - # - title: Binding DOM and Javascript - # includes: - # - tko.bind/docs/binding-syntax.md - # - tko.bind/docs/binding-context.md - # - tko.provider.databind/docs/databind-parser.md - # - tko.provider/docs/provider.md - # - tko.bind/docs/binding-preprocessing.md - # - tko.bind/docs/custom-bindings.md - # - tko.bind/docs/custom-bindings-for-virtual-elements.md - # - tko.bind/docs/custom-bindings-controlling-descendant-bindings.md - # - tko.bind/docs/custom-bindings-disposal.md - - # - title: Included bindings - # includes: - # - tko.binding.core/docs/attr-binding.md - # - tko.binding.core/docs/checked-binding.md - # - tko.binding.core/docs/click-binding.md - # - tko.binding.core/docs/css-binding.md - # - tko.binding.core/docs/disable-binding.md - # - tko.binding.core/docs/enable-binding.md - # - tko.binding.core/docs/event-binding.md - # - tko.binding.core/docs/hasfocus-binding.md - # - tko.binding.core/docs/html-binding.md - # - tko.binding.core/docs/options-binding.md - # - tko.binding.core/docs/selectedOptions-binding.md - # - tko.binding.core/docs/style-binding.md - # - tko.binding.core/docs/submit-binding.md - # - tko.binding.core/docs/text-binding.md - # - tko.binding.core/docs/textInput-binding.md - # - tko.binding.core/docs/uniqueName-binding.md - # - tko.binding.core/docs/unobtrusive-event-handling.md - # - tko.binding.core/docs/value-binding.md - # - tko.binding.core/docs/visible-binding.md - # - tko.binding.if/docs/if-binding.md - # - tko.binding.if/docs/ifnot-binding.md - # - tko.binding.if/docs/index.md - # - tko.binding.if/docs/with-binding.md - # - tko.binding.template/docs/foreach-binding.md - # - tko.binding.template/docs/template-binding.md - - # - title: Observables - # includes: - # - tko.observable/docs/arraychange.md - # - tko.observable/docs/observableArrays.md - # - tko.observable/docs/observables.md - # - tko.observable/docs/rateLimit-observable.md - # - tko.observable/docs/extenders.md - # - tko.observable/docs/throttle-extender.md - # - tko/docs/json-data.md - - - # - title: Computed Observables - # includes: - # - tko.computed/docs/computed-dependency-tracking.md - # - tko.computed/docs/computed-pure.md - # - tko.computed/docs/computed-reference.md - # - tko.computed/docs/computed-writable.md - # - tko.computed/docs/computedObservables.md - - # - title: Components & Custom Tags - # includes: - # - tko.utils.component/docs/component-binding.md - # - tko.utils.component/docs/component-custom-elements.md - # - tko.utils.component/docs/component-loaders.md - # - tko.utils.component/docs/component-overview.md - # - tko.utils.component/docs/component-registration.md - - - # - title: Life Cycles - # includes: - # - tko.lifecycle/docs/life-cycle.md - - # - title: Plugins - - # - title: API - - -# The following can be auto-generated from `volumeInfo` via -# https://www.googleapis.com/books/v1/volumes/${id} -books: - - - title: Knockout.js - subtitle: Building Dynamic Client-Side Web Applications - authors: - - Jamie Munro - publisher: Oreilly & Associates Incorporated - publishedDate: '2015-01-03' - description: "

Use Knockout.js to design and build dynamic client-side web applications - that are extremely responsive and easy to maintain. This example-driven book shows - you how to use this lightweight JavaScript framework and its Model-View-ViewModel - (MVVM) pattern. You’ll learn how to build your own data bindings, extend the framework - with reusable functions, and work with a server to enhance your client-side application - with persistence. In the final chapter, you’ll build a shopping cart to see how - everything fits together.

If you’re a web developer with experience in - JavaScript, HTML, and CSS, you’re ready for Knockout.

" - industryIdentifiers: - - type: ISBN_10 - identifier: '1491914319' - - type: ISBN_13 - identifier: '9781491914311' - readingModes: - text: false - image: false - pageCount: 86 - printedPageCount: 86 - dimensions: - height: 23.30 cm - width: 17.80 cm - thickness: 0.50 cm - printType: BOOK - categories: - - Computers / Programming Languages / JavaScript - - Computers / Internet / Application Development - - Computers / Web / Web Programming - maturityRating: NOT_MATURE - allowAnonLogging: false - contentVersion: preview-1.0.0 - imageLinks: - smallThumbnail: https://books.google.ca/books/content?id=ZPDnoQEACAAJ&printsec=frontcover&img=1&zoom=5&imgtk=AFLRE73xh8xZACPIjOtB8rD5RE06-ElVbzgtH5e0nmkyo0UjgGwBZweLwET2ieAFeO_E6k4vI1gqVVxyRWIhOlXmxrprvBuMm-oQigjlTEfm9M9bABMXNcxwZKRTZvvdUBkP14nJ6MIp&source=gbs_api - thumbnail: https://books.google.ca/books/content?id=ZPDnoQEACAAJ&printsec=frontcover&img=1&zoom=1&imgtk=AFLRE717dECAVjOpJblfNu0EPHVMBQmgOOan5rn21GWN2OQhSbPiehsljCYRsxdJQ1wcejFwt0wBmNnRraYQUHHWPqjrHJW0kRSrXjobRrKukJDD-hhmn5DWwNGA--8nQVITS2vbv8t6&source=gbs_api - language: en - previewLink: https://books.google.ca/books?id=ZPDnoQEACAAJ&hl=&source=gbs_api - infoLink: https://books.google.ca/books?id=ZPDnoQEACAAJ&hl=&source=gbs_api - canonicalVolumeLink: https://books.google.ca/books/about/Knockout_js.html?hl=&id=ZPDnoQEACAAJ - - - title: Asp.net Mvc 5 With Bootstrap and Knockout.js - subtitle: Building Dynamic, Responsive Web Applications - authors: - - Jamie Munro - publisher: O'Reilly Media, Incorporated - publishedDate: '2015-03-25' - description: "

Bring dynamic server-side web content and responsive web design - together to build websites that work and display well on any resolution, desktop - or mobile. With this practical book, you’ll learn how by combining the ASP.NET - MVC server-side language, the Bootstrap front-end framework, and Knockout.js—the - JavaScript implementation of the Model-View-ViewModel pattern.

Author Jamie - Munro introduces these and other related technologies by having you work with - sophisticated web forms. At the end of the book, experienced and aspiring web - developers alike will learn how to build a complete shopping cart that demonstrates - how these technologies interact with each other in a sleek, dynamic, and responsive - web application.

" - industryIdentifiers: - - type: ISBN_10 - identifier: '1491914394' - - type: ISBN_13 - identifier: '9781491914397' - readingModes: - text: false - image: false - pageCount: 278 - printedPageCount: 278 - dimensions: - height: 23.30 cm - width: 17.80 cm - thickness: 1.30 cm - printType: BOOK - categories: - - Computers / Programming Languages / ASP.NET - - Computers / Web / General - - Computers / Web / Web Programming - maturityRating: NOT_MATURE - allowAnonLogging: false - contentVersion: preview-1.0.0 - imageLinks: - smallThumbnail: https://books.google.ca/books/content?id=try8oQEACAAJ&printsec=frontcover&img=1&zoom=5&imgtk=AFLRE71NgZ3twak4WXm7mMrpPXQwM5LLeI3zeLgpf4CSBir_nKmU0mZJoh6Z5JPwwrMk_WjQE_j04VenoDv3PBQAY0yCp4w_tW5TM4BjdModKb6BhbGfnYR0Qt1Qmn6SmtV6WDNhsqd2&source=gbs_api - thumbnail: https://books.google.ca/books/content?id=try8oQEACAAJ&printsec=frontcover&img=1&zoom=1&imgtk=AFLRE71KQ8fmuM2sSfN0TOooxRRz51cBqbN-oSufwl2TKH6qSzuzhI_Sarc_I5dMWgvbKB1SmWvA3IREW1ByGHSRAnTsybrM8B4LxCKEjavv9Zq2VxVBR3pweSl2UWtLe4Oav0m5_S5G&source=gbs_api - language: en - previewLink: https://books.google.ca/books?id=try8oQEACAAJ&hl=&source=gbs_api - infoLink: https://books.google.ca/books?id=try8oQEACAAJ&hl=&source=gbs_api - canonicalVolumeLink: https://books.google.ca/books/about/Asp_net_Mvc_5_With_Bootstrap_and_Knockou.html?hl=&id=try8oQEACAAJ - - - title: Getting Started with Knockout.js for .NET Developers - authors: - - Andrey Akinshin - publisher: Packt Publishing Ltd - publishedDate: '2015-05-27' - description: This book is intended for .NET developers who want to use the MVVM - design pattern to create powerful client-side JavaScript linked to server-side - C# logic. Basic experience with ASP.NET, Razor, and creating web applications - is needed. - industryIdentifiers: - - type: ISBN_10 - identifier: '1783984015' - - type: ISBN_13 - identifier: '9781783984015' - readingModes: - text: true - image: true - pageCount: 188 - printedPageCount: 188 - printType: BOOK - categories: - - Computers / Programming Languages / JavaScript - - Computers / Internet / Application Development - - Computers / Programming Languages / ASP.NET - maturityRating: NOT_MATURE - allowAnonLogging: false - contentVersion: 0.1.1.0.preview.3 - imageLinks: - smallThumbnail: https://books.google.ca/books/content?id=A-iuCQAAQBAJ&printsec=frontcover&img=1&zoom=5&edge=curl&imgtk=AFLRE700Ur2bUx3-xG1lJ7dhXYNiVxT0TlvFTCLKBDmCgsc2s1pOb_YVZxtI6jUwv53hOOAMnvSH2j3GR2NKExvEev5ALEK68u7oLyrUTxA-4j5iwmH7jEV0USmCSJE8PE6Nke2aUWS2&source=gbs_api - thumbnail: https://books.google.ca/books/content?id=A-iuCQAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&imgtk=AFLRE72rh8mTdqUnmJDjLIi1wLaea_frTsNMmKGHxTa2lID6PyuW_qNH_XzvkxqDVn3QEa2LfnTsvAmj6Vq_Wd73Zl4Q9_gIQA0lmIwRfK0Zr17YFHAV9uSx-9q5bTOOepwmRpwG3fbG&source=gbs_api - small: https://books.google.ca/books/content?id=A-iuCQAAQBAJ&printsec=frontcover&img=1&zoom=2&edge=curl&imgtk=AFLRE71Y9WVxVSRTitqbcivBU-WgoXUCyyPTuNsjEn7uZ9oFTc7vKFCJekAx1vMoo_v4lV59_ehco3Lt8vcJTalPxGaIZj57lo1DPirPBwRhGu_kuQtALcu0khKaKimJdwj4Sp_kEIEj&source=gbs_api - medium: https://books.google.ca/books/content?id=A-iuCQAAQBAJ&printsec=frontcover&img=1&zoom=3&edge=curl&imgtk=AFLRE71n9MaRenbMt90bPtLsyELGmzZq6U4KEbYvVRl7e_kLBJD0QvZ36lTpLejO3BJ4i3WWHL-hzY10ThMf3Qg5vSGD4q3TFoHU62YmSImkw1obbyph6p04pfMutEekEHYXO6d-Yuc9&source=gbs_api - large: https://books.google.ca/books/content?id=A-iuCQAAQBAJ&printsec=frontcover&img=1&zoom=4&edge=curl&imgtk=AFLRE73BGDB8DqNQzhG2wE-jBgyb-JdjNtiNXeqazRtGxQUwrTnpjHSg2G5LSXaassUEItKLZbyrt8myz6fLL2dl5M_xvH-tZosq63njrzlZYkJuJqjhj2ZxNItqlkYShzh6C0jMklxu&source=gbs_api - extraLarge: https://books.google.ca/books/content?id=A-iuCQAAQBAJ&printsec=frontcover&img=1&zoom=6&edge=curl&imgtk=AFLRE72ntS5Ll1QmMWu-A2hwAdGAqTBeG9EEYgH4qlIvCZH3p5gaoPJO4XxPTCKfOZVpVzPN0gTVAoTclhd6v1Yrmk5dvyfX4032bvw9fEp9HP1AemUNgCh_Cjtgzcwma2HlyVG9n7jh&source=gbs_api - language: en - previewLink: https://books.google.ca/books?id=A-iuCQAAQBAJ&hl=&source=gbs_api - infoLink: https://books.google.ca/books?id=A-iuCQAAQBAJ&hl=&source=gbs_api - canonicalVolumeLink: https://books.google.ca/books/about/Getting_Started_with_Knockout_js_for_NET.html?hl=&id=A-iuCQAAQBAJ - - - title: Mastering KnockoutJS - authors: - - Timothy Moran - publisher: Packt Publishing Ltd - publishedDate: '2014-11-26' - description: If you are an experienced JavaScript developer who is looking for new - tools to build web applications and get an understanding of core elements and - applications, this is the book for you. A basic knowledge of DOM, JavaScript, - and KnockoutJS is assumed. - industryIdentifiers: - - type: ISBN_10 - identifier: '1783981016' - - type: ISBN_13 - identifier: '9781783981014' - readingModes: - text: true - image: true - pageCount: 270 - printedPageCount: 489 - printType: BOOK - categories: - - Computers / Web / Design - - Computers / Programming Languages / JavaScript - - Computers / Internet / Application Development - maturityRating: NOT_MATURE - allowAnonLogging: true - contentVersion: 1.1.1.0.preview.3 - imageLinks: - smallThumbnail: https://books.google.ca/books/content?id=BoqbBQAAQBAJ&printsec=frontcover&img=1&zoom=5&edge=curl&imgtk=AFLRE71OGVtK3R39HAA3YPPexcAfdqkhHpK2qY2aqN2VwnuRbzJ5pWfCdPP_5p0KuPpod7GvQPI8wHYLAO8zssun_5j31mq5DrjNHULX097DHieG55cZxoF3R3nX4po7w9urdhoH83CT&source=gbs_api - thumbnail: https://books.google.ca/books/content?id=BoqbBQAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&imgtk=AFLRE70GS42a68O_DBLirScLduiYOUbk80jGntqSuuykg8RU1usaN5xdHy5Gl13pgEb2LdZYZ7b5sYtt4qmedX1FiwDuhbprf-X1ADNLHolZCVletNeHvoUvy0gFKPplc4eopBGHQnPG&source=gbs_api - small: https://books.google.ca/books/content?id=BoqbBQAAQBAJ&printsec=frontcover&img=1&zoom=2&edge=curl&imgtk=AFLRE72HypPfd5WB7VNPF5ovT8veIkql_616DZvT64hc5QPN8HhYCwP3F_XuPKD5D3euB0qJSau7qlRgyrp7VjnOACjsF10v9PekqqAw7fnOakZVnLGBJ3_tWNTl-GByWWxzTDi1rXrQ&source=gbs_api - medium: https://books.google.ca/books/content?id=BoqbBQAAQBAJ&printsec=frontcover&img=1&zoom=3&edge=curl&imgtk=AFLRE72bJ_PJ9fydBJC1A4b8n-F1x_VHnyeBSp9uRJTFYxQVcIyEO-hCcU51x-TmUrH4JOblv0J2g2OzpwxQK2oELDtzlE7qzE0a_D-KsqSqoFFPXLlPrL45r8fLLXvTRUubJNJy31No&source=gbs_api - large: https://books.google.ca/books/content?id=BoqbBQAAQBAJ&printsec=frontcover&img=1&zoom=4&edge=curl&imgtk=AFLRE70OgKfn3_48ic1MFdtFGQyoOBg8JHQwln0q5M1fKTYREAuugBOOtf5Q7m6_yD-DEN_n933Y5labtoiq-KM_BEWWukCgkOeJvT1Xr-XuATJrtXX9N-cq1Z-1qbfO3ncRz0yMo-_c&source=gbs_api - extraLarge: https://books.google.ca/books/content?id=BoqbBQAAQBAJ&printsec=frontcover&img=1&zoom=6&edge=curl&imgtk=AFLRE71OClJjx-G3VrcH4lga7AKeiw0CGOSwyAvjxfZ8ns3TKv_o8SLzY_p3_e5Q8kJgiVXA1GWpNT-kWgwNwHa5BYsVHbF5DXlGpqyLGxOT8fOXBlsBr8e_H375DucdcSP-0v7L1jF8&source=gbs_api - language: en - previewLink: https://books.google.ca/books?id=BoqbBQAAQBAJ&hl=&source=gbs_api - infoLink: https://books.google.ca/books?id=BoqbBQAAQBAJ&hl=&source=gbs_api - canonicalVolumeLink: https://books.google.ca/books/about/Mastering_KnockoutJS.html?hl=&id=BoqbBQAAQBAJ - - - title: Web App Testing Using Knockout.JS - authors: - - Roberto Messora - publisher: Packt Publishing Ltd - publishedDate: '2014-11-17' - description: If you are a JavaScript developer, beginner, or an expert who wants - to improve quality standards in terms of solutions design and functional verification, - this book is for you. Basic understanding of web development, HTML, and JavaScript - is required. - industryIdentifiers: - - type: ISBN_10 - identifier: '1783982853' - - type: ISBN_13 - identifier: '9781783982851' - readingModes: - text: true - image: true - pageCount: 154 - printedPageCount: 237 - printType: BOOK - categories: - - Computers / Software Development & Engineering / Quality Assurance & Testing - - Computers / Programming Languages / JavaScript - - Computers / Web / Web Programming - averageRating: 5 - ratingsCount: 2 - maturityRating: NOT_MATURE - allowAnonLogging: false - contentVersion: 1.1.1.0.preview.3 - imageLinks: - smallThumbnail: https://books.google.ca/books/content?id=dZN1BQAAQBAJ&printsec=frontcover&img=1&zoom=5&edge=curl&imgtk=AFLRE70A3vdwml0dXDKn1YCWpz8n0p8IKHaCN6FnhytFUt7ZiwPTttCa3_2-Q6ZRyyeCrTzWd3AvkTSQwvO31hHUZjEbUVKlNij50crBaQerevytbQWF6ZMvTW6qxlFH-DfN-AvUv6e2&source=gbs_api - thumbnail: https://books.google.ca/books/content?id=dZN1BQAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&imgtk=AFLRE71zzDoAJ8_68JqPI9sZ3Tlvyhyqxiyi_z0QwpVpjChRp5YC3bKNGiUBlDLThbtmQ3uIdVes5uGumrDrmUPlvGA_3PSqev9ZbCwthmLIjwEisbAwI1z2nJNzqwSHb7b-8uEekpvB&source=gbs_api - small: https://books.google.ca/books/content?id=dZN1BQAAQBAJ&printsec=frontcover&img=1&zoom=2&edge=curl&imgtk=AFLRE71Bq-gmv0FqD2RAIGkqGsnAMEI2VSAlzOme8QiPTpwA09b16Xx9fwBL7WAHIONiyVnFu6iACEO9SVQqZDGf9l56_gTMChhENAXWnM_ZnV5l-K4ouOHjqhAzx61yzxdj2OgmS7Bl&source=gbs_api - medium: https://books.google.ca/books/content?id=dZN1BQAAQBAJ&printsec=frontcover&img=1&zoom=3&edge=curl&imgtk=AFLRE72glYr_QFUGY7Xc2cBVMa1kXnEaRIn5W2ULqSu6McZlyOZLXhZ1Aw2EYxWmfIzkpr9Le6d8D0AmMCP2YI8RRAAkmrrtQxTO3ow44Gf_kINC2GIrZtLywg9ul7tGgtJNdqMLyfWi&source=gbs_api - large: https://books.google.ca/books/content?id=dZN1BQAAQBAJ&printsec=frontcover&img=1&zoom=4&edge=curl&imgtk=AFLRE72x5vBQpMoPigr6fGa246ERfQvakIU7pB6PpTEUbktcoWhXxik5WF8TohPvbPuOGXqG0Lzh1JmSy6N7PIVpqCJXIyHV2UIzOxz1u1SeyfQNatsajdpQ16rGp6uaJxPhT31o0JUy&source=gbs_api - extraLarge: https://books.google.ca/books/content?id=dZN1BQAAQBAJ&printsec=frontcover&img=1&zoom=6&edge=curl&imgtk=AFLRE73xjKYwV0fwumEQIryeYX8vFDu7KUe8WgpYN-QvZU8ZMbVU5b5Ua8cYnD_FBBGpDTf22w_tiYOC8G9BpvSOkHaO07HRV-YDM51FaVQWlXywSXL7UVgOWUaI0iG5xbY3M6CJWMOz&source=gbs_api - language: en - previewLink: https://books.google.ca/books?id=dZN1BQAAQBAJ&hl=&source=gbs_api - infoLink: https://books.google.ca/books?id=dZN1BQAAQBAJ&hl=&source=gbs_api - canonicalVolumeLink: https://books.google.ca/books/about/Web_App_Testing_Using_Knockout_JS.html?hl=&id=dZN1BQAAQBAJ - - - title: KnockoutJS Essentials - authors: - - Jorge Ferrando - publisher: Packt Publishing Ltd - publishedDate: '2015-02-27' - description: If you are a JavaScript developer who has been using DOM manipulation - libraries such as Mootools or Scriptaculous, and you want go further in modern - JavaScript development with a simple and well-documented library, then this book - is for you. Learning how to use Knockout will be perfect as your next step towards - building JavaScript applications that respond to user interaction. - industryIdentifiers: - - type: ISBN_10 - identifier: '1784395285' - - type: ISBN_13 - identifier: '9781784395285' - readingModes: - text: true - image: true - pageCount: 232 - printedPageCount: 232 - printType: BOOK - categories: - - Computers / Internet / General - - Computers / Internet / Application Development - - Computers / Programming Languages / Java - maturityRating: NOT_MATURE - allowAnonLogging: false - contentVersion: 2.2.2.0.preview.3 - imageLinks: - smallThumbnail: https://books.google.ca/books/content?id=HEXfBgAAQBAJ&printsec=frontcover&img=1&zoom=5&edge=curl&imgtk=AFLRE73KcIEK76fLL4WMQf9A1CJTvx-SGdI5O2ezmLb54SZbJGzguyU7PjmjzBRqRYw0fFGHmcGBjfwozfYegr6gQ12u-c5vUhXf7szQkTjXEXWV5Y0KQcgDfg_OFQmKi9h-9cm-4zdb&source=gbs_api - thumbnail: https://books.google.ca/books/content?id=HEXfBgAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&imgtk=AFLRE72iT2HkL3gawhD9TqH0Ozcj5SZW5bchxnpKvWAjxtYdxh8HcnIKbul_cXzv6zK-EDmZh5QY29qCYf-JQQEGU6sjiaaVSoeGbbezRI32UgWJNVpiPu6kd2aeMSZa5Vamelt0nAda&source=gbs_api - small: https://books.google.ca/books/content?id=HEXfBgAAQBAJ&printsec=frontcover&img=1&zoom=2&edge=curl&imgtk=AFLRE72qNwfz7Ar9qbXS_7Z_y2lsYAYpWy2pEy37MmEtZSajj0E7AMzXnEHIk2EG6otNwbELtO63zSSVjiAs3jvlerXq_N-uD227lrRMSDt8-N2-rZr0d396FW0F0oukatK3HcBwkBzc&source=gbs_api - medium: https://books.google.ca/books/content?id=HEXfBgAAQBAJ&printsec=frontcover&img=1&zoom=3&edge=curl&imgtk=AFLRE72m6oGoEwL5xAbLyuU4C_334JN-IgaHkW70a4mFNRW58iirrlcuJaZ8hDEPGcADH_Qd1HeLukT2e_1gxJUEqOVGAqdTJopfflSRdEFSy_d3R3TFxvTCvrWqw2b9RBsbgnWL-vu2&source=gbs_api - large: https://books.google.ca/books/content?id=HEXfBgAAQBAJ&printsec=frontcover&img=1&zoom=4&edge=curl&imgtk=AFLRE727dgJxfT9K-HpbDFySw0YytRHfJV1Nr8z87ClKXeljh02ZGsv-9KyehOnyFMH11gXgyN7Rks3adufGjMDwsMgxCVvvsFQgX2LHt1_jeB7EoPeoVgRdKllAd6TqnHSvPYG5dePq&source=gbs_api - extraLarge: https://books.google.ca/books/content?id=HEXfBgAAQBAJ&printsec=frontcover&img=1&zoom=6&edge=curl&imgtk=AFLRE70WdC_9qZ_FtUczIwDq4_4XBZMUl-HwNXyucuOI0v4OCtyRxQAgvDM3m7jJDeXcrm83b-Bi5-TdzSkjxZu4RbpTzW4NL8mPDRAFUlMGPViNw4xMw-ebSHRkgWYsMriAUYjYp_OZ&source=gbs_api - language: en - previewLink: https://books.google.ca/books?id=HEXfBgAAQBAJ&hl=&source=gbs_api - infoLink: https://books.google.ca/books?id=HEXfBgAAQBAJ&hl=&source=gbs_api - canonicalVolumeLink: https://books.google.ca/books/about/KnockoutJS_Essentials.html?hl=&id=HEXfBgAAQBAJ - - - title: KnockoutJS Blueprints - authors: - - Carlo Russo - publisher: Packt Publishing Ltd - publishedDate: '2015-02-25' - description: If you are a JavaScript developer and already know the basics of KnockoutJS - and you want to get the most out of it, then this book is for you. This book will - help in your transition from a small site to a large web application that is easily - maintainable. - industryIdentifiers: - - type: ISBN_10 - identifier: '1783980850' - - type: ISBN_13 - identifier: '9781783980857' - readingModes: - text: true - image: true - pageCount: 218 - printedPageCount: 218 - printType: BOOK - categories: - - Computers / General - - Computers / Programming Languages / JavaScript - maturityRating: NOT_MATURE - allowAnonLogging: false - contentVersion: 2.2.2.0.preview.3 - imageLinks: - smallThumbnail: https://books.google.ca/books/content?id=5ljTBgAAQBAJ&printsec=frontcover&img=1&zoom=5&edge=curl&imgtk=AFLRE73zg0-XBzMzQAcMQW_DYHtbhQovG3pLSICrTsQiuPtQjcoh0uUD8mixpJOoQ5Jyhx_Q39QcF8zNZW9vZxYpfOY2H-vNHZ1Q3F-RtZ4urPVrSSKQauMG9YeZOtFE_uyJhwPTkVmA&source=gbs_api - thumbnail: https://books.google.ca/books/content?id=5ljTBgAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&imgtk=AFLRE709pFQ7H1gOnU-LAndEX0z9bqHUPQAi5rRoYbighr68U9tTN7ONHq8sgiLrkmhFBO5isUK3dKydyNM1aWDgk4FqErfk2DSbjC2T_jd7nfsnQzXHcFCVEcD3rLNxV7n0pegmMoEy&source=gbs_api - small: https://books.google.ca/books/content?id=5ljTBgAAQBAJ&printsec=frontcover&img=1&zoom=2&edge=curl&imgtk=AFLRE70TIZJ2jb02xZbyrF-pi7rCkKtRbM9QNCKS-7PZfJcNhsqHXwROEZ1W6tasXaC0cOmDdIrUrgAVLgDmP6Yg6HGwxqeV_MyZdZeeJ8zbhL4R9M0jQpKGggoGGLzLzoJ39ID5dCIn&source=gbs_api - medium: https://books.google.ca/books/content?id=5ljTBgAAQBAJ&printsec=frontcover&img=1&zoom=3&edge=curl&imgtk=AFLRE714ZgU0oxMuFEtbSrhaZJwsYhvkBEr1D_wYVJsJyiy6NE80XQxdDKopHEcJtSOG-WVKnjsrgrvidnWoxo2kvauH97Nr4iE44nAJeTFsjlLOG0Xv8anJAMSd2_aA4KYAK5cXZ0u8&source=gbs_api - large: https://books.google.ca/books/content?id=5ljTBgAAQBAJ&printsec=frontcover&img=1&zoom=4&edge=curl&imgtk=AFLRE72zC_ZRz28WbKJAHvaFUB6LqLgItZOT3XobgdMZDn_fnYVVWIg8iv1gMPtNek1yrVlTFwWmWa061ZS5xZVFRxlkXRWPmxiroQjmhiAoCEQ7cjp2Gb6Tos7xcoH1rjVU7GCbMYhH&source=gbs_api - extraLarge: https://books.google.ca/books/content?id=5ljTBgAAQBAJ&printsec=frontcover&img=1&zoom=6&edge=curl&imgtk=AFLRE732FDrzmu-zRydUQ7jmyI9LnQxtWx49_kOuxlwgjW2jI95C_GWB_UWIg02hmKbYRHXbU7jtLw_VL38n-_DUntiCj_f9AG5Lswlq1KaXyjlwfCEXWTIsH82VkQeqnC77S3bqLkFV&source=gbs_api - language: en - previewLink: https://books.google.ca/books?id=5ljTBgAAQBAJ&hl=&source=gbs_api - infoLink: https://books.google.ca/books?id=5ljTBgAAQBAJ&hl=&source=gbs_api - canonicalVolumeLink: https://books.google.ca/books/about/KnockoutJS_Blueprints.html?hl=&id=5ljTBgAAQBAJ diff --git a/tko.io/src/3to4.md b/tko.io/src/3to4.md new file mode 100644 index 000000000..55b5413c9 --- /dev/null +++ b/tko.io/src/3to4.md @@ -0,0 +1,249 @@ +--- +layout: base.njk +title: Knockout 3 to 4 Guide +--- + +# Overview of the Differences + +TKO is a fundamental change in the foundation of the code behind Knockout, representing the reverse engineering, compartmentalization, and reintegration of the original code that dates back to 2010. + +With this reengineering of Knockout into discrete pieces, it will be easier to update, build, and test the features of Knockout, as well as put the individual packages that make up Knockout to use in situations outside Knockout itself. + +To see the differences, have a look at the [CHANGELOG.md](https://github.com/knockout/tko/blob/master/CHANGELOG.md). + + +# Version Comparison + +| Version | tko.js | Knockout 4 | Knockout 3.x | +| --- | --- | --- | --- | +| Browser compatibility | Modern browsers (i.e. [`Proxy`](https://caniuse.com/#feat=proxy) support) | Internet Explorer 9+ | Internet Explorer 6+ | +| `ko.BindingHandler` | Yes | Yes | No | +| `observableArray.length` | Yes | Browsers with [Array subclass](https://kangax.github.io/compat-table/es6/#test-Array_is_subclassable_length_property_(accessing)) support [More info](http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/#wrappers_prototype_chain_injection) | No | +| iterable `observableArray` | Yes | Browsers with [Symbol support](https://kangax.github.io/compat-table/es6/#test-Symbol) | No | +| event `throttle` / `debounce` | Yes | Yes | No | +| `ko.Component` | Yes | Yes | No | +| `applyBindings` returns `Promise` | Yes | Yes | No | +| Polyfills included | None | Up to ES6 | `Object.prototype.bind` | +| `ko.proxy` | Yes | No | No | +| `ko.onError` | Does not automatically throw (you need to add `throw error` to `ko.options.onError`) | Does not rethrow automatically | Always re-throws error | +| `foreach` binding | FastForEach | Template foreach | Template foreach | +| `each` binding | FastForEach | FastForEach | Template foreach + +# Security advantages in TKO +TKO is ready for strict Content Security Policies (CSP) and does not use `evil-eval` or `new function` techniques. It also provides HTML sanitization through configurable options. To sanitize HTML templates, override the `options.sanitizeHtmlTemplate` setting using a library such as DOMPurify or Validator.js. +# Build System + +TKO has a complete build system rewrite and a conversion of the code from a concatenation of source files to discrete ES6 modules with `import` and `export` statements. This process has been complex and taken years, with the result being a Knockout with a strong foundation of discrete reusable components. + +Knockout 4 and TKO will be maintained at the new monorepo [knockout/tko](https://github.com/knockout/tko) on GitHub. Knockout 3.x will continue to be maintained at [knockout/knockout](https://github.com/knockout/knockout). + +TKO now uses standard tools like `lerna` and `yarn`, and employs [StandardJS](https://standardjs.com/) for code style — though all the old code is not yet updated to StandardJS yet. + +# Test System + +Knockout 3 used Jasmine 1 to perform tests. Some packages in TKO continue to use Jasmine 1, while others now use Mocha. + +## Backwards compatibility and 💥 breaking changes + +We've strived to have backwards compatibility, and the numerous test cases we've run it through have been successful. A key value of Knockout has been and remains the comprehensive test cases that enforce performance to a predictable standard, and TKO meets all the tests that were enforced on Knockout 3.x, notwithstanding a few issues: + +- The `function` no longer works in `data-bind`, having been replaced by lambdas, so `data-bind='click: function () { x++ }'` will have to be replaced by e.g. `data-bind='click: => x++'` +- The `data-bind` is now interpreted by a LL compiler (based on [knockout-secure-binding](https://github.com/brianmhunt/knockout-secure-binding)), so some edge case parsing issues may crop up + +## Browser support + +Knockout 4 and TKO and the underlying packages will start support from IE9 forward. We aim to test Knockout across all browsers from this point forward. + +If you need IE6, 7, and 8 support you may prefer to keep using the Knockout 3.x line, or be prepared for workarounds or missing functionality. + +# Options + +* (options) Allow importing `ko` in node +* various new [`options`](https://github.com/knockout/tko.utils/blob/master/src/options.js) + +# Utilities + +* (utils) Several array utilities use native functions now (`arrayPushAll`, `arrayFilter`, `arrayGetDistinctValues`, `arrayFirst`, `arrayIndexOf`) +* The `throttle` and `debounce` utilities now pass arguments to the target functions +* utils + * utils.domNodeDisposal is now exposed as domNodeDisposal + * arguments to setHtml that are functions are called (not just observables) + * cleanExternalData now exposed in domNodeDisposal.otherNodeCleanerFunctions + +* error handling + * onError no longer throws if overloaded; default function is to re-throw. + * error is thrown when an extender is not found + +# Life Cycles + +* (internal) Add the ES6 LifeCycle class (see tko.lifecycle) + +# Observables + +* (observable) When supported, `observable.length` will now be undefined (was `0` before), and `observableArray.length` will now be the length of the wrapped array +* (observableArray) `observableArray` is now iterable (has a `Symbol.iterator` property) +* (subscribable) Add the `once`, `then`, `when`, `yet`, and `next` functions + +# Components + +* (components) Warn with custom-element names that cannot be used with custom elements re. #43 & knockout/knockout#1603 +* (components) Add `ko.Component`, an abstract base class that simplifies the Component creation and registration API (see `tko.utils.component/src/ComponentABC.js`) +* (components) Add `getBindingHandler(key)` to use binding handlers local to a component + +Components can control their binding handlers. + +## ko.Component example + +

See the Pen Commented ko.Component by Knockout (@Knockout) on CodePen.

+ +# Bindings + +* (binding) `ko.applyBindings` now returns a Promise that resolves when bindings are completed + +* (binding handlers) Add new-style ES6 Binding Handler class (see custom-bindings documentation and tko.bind/src/BindingHandler.js), descended from the LifeCycle class +* (bind) String errors on binding are now propagated + +## Binding Handlers and ko.BindingHandler + +In TKO, binding handlers can be either an `object`, a `function` or a descendant of `ko.BindingHandler`. The following are all valid binding handlers: + +```javascript +class NewHandler extends ko.BindingHandler { + constructor ({$element, valueAccessor, allBindings, $context, onError}) { + /* + this.value is valueAccessor() + this.value(x) is valueAccessor(x); + if valueAccessor() is observable or a property, it will be set properly. + */ + } + + get controlsDescendants () { return true|false } + + get bindingComplete () { + /* overload where binding is asynchronous. See e.g. Component binding*/ + } + static get allowVirtualElements () { return true|false } +} + +handler_fn = (element, valueAccessor, allBindings, viewModel, bindingContext) => { /* ... */ } + +the_knockout_3_way = { + init (element, valueAccessor, allBindings, viewModel, bindingContext) { + /* ... */ + }, + + update (element, valueAccessor, allBindings, viewModel, bindingContext) { + /* ... */ + }, + + allowVirtualElements: true|false +} + +// Virtual Elements may be permitted for a binding explicitly. +virtualElements.allowedBindings[handler_name] = true|false +``` + +Binding handlers can be registered in the following ways: + +```javascript +// Globally, where NewHandler is a BindingHandler descendant. +NewHandler.registerAs('handler') + +// Globally, for any handler type. +ko.bindingHandlers.set(handler_name: handler) + +// Knockout 3.x style +ko.bindingHandlers[handler_name] = handler + +// For a component +class Component { + getBindingHandler(bindingKey) { + if (bindingKey === handler_name) { return handler } + // Alternatively: + // return { bindingKey[bindingKey]: handler }[bindingKey] + } +} +``` + +## Parsing + +* (parser) Fix interpretation of unicode characters as identifiers / variables +* `==` and `===` use `===` for comparison (same for `!=` and `!==`); fuzzy equality ~== / ~!= for the evil twins +* Knockout 4 will work with a Content Security Policy that prohibits unsafe-eval. + * add "naked" `=>` lambdas (even in legacy browsers e.g. `data-bind='click: => was_clicked(true)'` + * inline functions are no longer supported (e.g. `data-bind='click: function (){...}'` will fail) + * No longer uses `with` statements + * No longer uses `eval`/`new Function` + +## Namespacing + + * incorporate punches namespacing i.e. `data-bind='event.click: => thing(true)'` is equivalent to `data-bind='event: {click: => thing(true)}'` + +## Attribute Interpolation + + +## Text Interpolation + +* incorporate punches {% raw %}`{{ }}`{% endraw %} and {% raw %}`{{{}}}` {% endraw %}text and attribute interpolation + + +## Event +* (`event` binding) Add object-based event handler e.g. `event.click: { handler: fn, once: true, capture: true, bubble: false, passive: false}`. Also, bubbling can be prevented with `event.click: {bubble: false }` re #32 +* (`event` binding) Add `throttle` and `debounce` parameters + +## With +* (with binding) Fix dependency count for function-arguments [knockout/knockout#2285] + +## Attr +* (attr) Support namespaced attributes with `attr` binding #27 + +## Foreach + +* Use tko.binding.foreach for the `foreach` binding (based on brianmhunt/knockout-fast-foreach) +* Add `each` as an alias of `foreach` +* Rewritten as O(1) +* (foreach binding) When using the `as` parameter, the `$data` remains unchanged (i.e. the context inside a `foreach` is no longer a "child" context, but an extension of the current context); this deprecates the `noContext` parameter +* (foreach binding) Expose the `conditional` on the `domData` for use by the `else` binding (when the array is empty, the `else` binding will be rendered) +* (foreach binding) Expose `$list` inside the foreach +* (foreach binding) Allow `noIndex` as a peer binding parameter (e.g. `foreach: items, noIndex: true`) +* (foreach) Preserve focus when items are deleted and re-added (i.e. moved) in the same animation frame. + +## Template + +* Make the `template` binding expose a conditional for else-binding +* support template literals (\`\`) in bindings (even in legacy browsers) +* add the `@` prefix operator that calls/unwrap functions (i.e. `obs()()` is the same as `@obs`) + +## If / Else + +* add `` inside the `if` binding, and add an `else` binding (following the brianmhunt/knockout-else plugin) +* Add `else` binding +* Add `unless` binding + +## Using + +## Hidden + + * add `hidden` binding (knockout/knockut#2103) + +## HTML + +The HTML binding now works in virtual elements. Based on ko.punches. + +## Filtering + +Filters can be applied to modify values in bindings. Based on ko.punches. + + +# Deprecated + + - Template binding options are deprecated + - expressionWriting (twoWayBinding) + - ‘.’ in binding handler names + - jsonExpressionRewriting (expressionRewriting) + - form parsing + - `bind` shim + - ko.utils.parseJson + - getFormFields + - fieldsIncludedWithJsonPost + - postJson diff --git a/tko.io/src/CNAME b/tko.io/src/CNAME new file mode 100644 index 000000000..b091eb46d --- /dev/null +++ b/tko.io/src/CNAME @@ -0,0 +1 @@ +tko.io \ No newline at end of file diff --git a/tko.io/src/_layouts/base.njk b/tko.io/src/_layouts/base.njk new file mode 100644 index 000000000..4acbdd35b --- /dev/null +++ b/tko.io/src/_layouts/base.njk @@ -0,0 +1,59 @@ + + + + + + {{ title }} - TKO + + + + + + + +
+ {{ content | safe }} +
+ + + + diff --git a/tko.io/src/css/tko.css b/tko.io/src/css/tko.css new file mode 100644 index 000000000..402dfc9b8 --- /dev/null +++ b/tko.io/src/css/tko.css @@ -0,0 +1,659 @@ +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap'); + +/* CSS Reset and Base Styles */ +* { + box-sizing: border-box; +} + +html { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +html, +body { + margin: 0; + padding: 0; + overflow-x: hidden; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif; + font-size: 16px; + line-height: 1.6; + color: #1a1a1a; + background-color: #ffffff; +} + +body { + display: grid; + margin-top: 64px; + height: calc(100vh - 64px); + grid-template-columns: 280px 1fr; + grid-template-areas: 'sidebar main'; + position: relative; +} + +@media screen and (max-width: 991px) { + body { + grid-template-columns: 1fr; + grid-template-areas: + 'sidebar' + 'main'; + height: auto; + } +} + +/* Typography */ +h1, h2, h3, h4, h5, h6 { + font-weight: 600; + line-height: 1.25; + margin-top: 1.5em; + margin-bottom: 0.5em; + color: #111827; +} + +h1 { + font-size: 2.25rem; + font-weight: 700; + margin-top: 0; + margin-bottom: 1rem; + letter-spacing: -0.025em; +} + +h2 { + font-size: 1.875rem; + margin-top: 2em; + padding-bottom: 0.3em; + border-bottom: 1px solid #e5e7eb; +} + +h3 { + font-size: 1.5rem; + margin-top: 1.6em; +} + +h4 { + font-size: 1.25rem; +} + +p { + margin: 1em 0; + line-height: 1.7; +} + +/* Links */ +a { + color: #2563eb; + text-decoration: none; + transition: color 0.15s ease; +} + +a:hover { + color: #1d4ed8; +} + +a:focus { + outline: 2px solid #3b82f6; + outline-offset: 2px; + border-radius: 2px; +} + +main a { + text-decoration: underline; + text-decoration-color: #93c5fd; + text-underline-offset: 2px; +} + +main a:hover { + text-decoration-color: #2563eb; +} + +/* Tables */ +table { + width: 100%; + border-collapse: collapse; + margin: 1.5em 0; + font-size: 0.9375rem; +} + +th { + padding: 0.75rem 1rem; + text-align: left; + font-weight: 600; + background-color: #f9fafb; + border-bottom: 2px solid #e5e7eb; + color: #374151; +} + +td { + padding: 0.75rem 1rem; + border-bottom: 1px solid #e5e7eb; +} + +tr:hover { + background-color: #f9fafb; +} + +/* Lists */ +ul, ol { + margin: 1em 0; + padding-left: 1.5em; +} + +li { + margin: 0.5em 0; + line-height: 1.7; +} + +/* Blockquotes */ +blockquote { + margin: 1.5em 0; + padding: 1em 1.5em; + border-left: 4px solid #3b82f6; + background-color: #eff6ff; + color: #1e40af; +} + +/* + * TOP BAR + */ +.top-bar { + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; + gap: 2rem; + padding: 0 2rem; + top: 0; + left: 0; + position: fixed; + z-index: 1200; + height: 64px; + background-color: #ffffff; + border-bottom: 1px solid #e5e7eb; + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1); +} + +.top-bar .tko { + font-size: 1.5rem; + font-weight: 700; + color: #2563eb; + letter-spacing: -0.025em; +} + +.top-bar a { + padding: 0.5rem 1rem; + color: #4b5563; + font-size: 0.9375rem; + font-weight: 500; + border-radius: 6px; + transition: all 0.15s ease; +} + +.top-bar a:hover { + color: #2563eb; + background-color: #eff6ff; +} + +.top-bar a.external::after { + content: '↗'; + margin-left: 0.25rem; + font-size: 0.875rem; +} + +.current-page { + color: #2563eb !important; + background-color: #eff6ff; +} + +@media screen and (max-width: 768px) { + .top-bar { + padding: 0 1rem; + gap: 0.5rem; + } + + .top-bar a { + padding: 0.5rem; + font-size: 0.875rem; + } +} + +/** + * SIDEBAR + */ +.sidebar { + grid-area: sidebar; + height: calc(100vh - 64px); + overflow-y: auto; + overflow-x: hidden; + background-color: #f9fafb; + border-right: 1px solid #e5e7eb; + padding: 1rem 0; +} + +/* Custom scrollbar for sidebar */ +.sidebar::-webkit-scrollbar { + width: 6px; +} + +.sidebar::-webkit-scrollbar-track { + background: transparent; +} + +.sidebar::-webkit-scrollbar-thumb { + background-color: #d1d5db; + border-radius: 3px; +} + +.sidebar::-webkit-scrollbar-thumb:hover { + background-color: #9ca3af; +} + +.toc { + display: flex; + flex-direction: column; + gap: 0.125rem; + padding: 0 1rem; +} + +.sidebar a { + display: block; + padding: 0.375rem 0.75rem; + color: #4b5563; + font-size: 0.875rem; + border-radius: 6px; + transition: all 0.15s ease; + text-decoration: none; +} + +.sidebar a:hover { + color: #111827; + background-color: #e5e7eb; +} + +.sidebar .section { + font-size: 0.875rem; + font-weight: 600; + color: #111827; + padding: 0.5rem 0.75rem 0.25rem; + margin-top: 1rem; + text-transform: uppercase; + letter-spacing: 0.05em; + font-size: 0.75rem; +} + +.sidebar .section:first-child { + margin-top: 0; +} + +.sidebar .subheading { + padding-left: 1.5rem; + font-weight: 400; + position: relative; +} + +.sidebar .subheading::before { + content: ''; + position: absolute; + left: 0.75rem; + top: 50%; + transform: translateY(-50%); + width: 2px; + height: 60%; + background-color: transparent; + transition: background-color 0.15s ease; +} + +.sidebar .subheading:hover::before { + background-color: #3b82f6; +} + +/* Binding name code styling in sidebar */ +.sidebar .binding-name code { + background-color: transparent; + color: inherit; + padding: 0; + border-radius: 0; + font-size: 0.8125rem; + font-weight: 500; +} + +@keyframes slideIn { + from { + opacity: 0; + transform: translateX(-4px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +.sidebar .in-viewport { + color: #2563eb; + background-color: #eff6ff; + font-weight: 500; +} + +.sidebar .in-viewport::before { + background-color: #2563eb; +} + +@media screen and (max-width: 991px) { + .sidebar { + height: auto; + max-height: 400px; + border-right: none; + border-bottom: 1px solid #e5e7eb; + } +} + +/** + * MAIN CONTENT + */ +main { + grid-area: main; + height: calc(100vh - 64px); + background-color: #ffffff; + padding: 3rem 0; + overflow-y: auto; + overflow-x: hidden; + /* Use CSS grid to allow examples to break out while keeping content centered */ + display: grid; + grid-template-columns: minmax(3rem, 1fr) minmax(0, 1000px) minmax(3rem, 1fr); + grid-auto-rows: auto; +} + +main > * { + /* Most content goes in the center column */ + grid-column: 2; +} + +main > *:first-child { + margin-top: 0; +} + +h1 code { + background-color: #eff6ff; + border: 2px solid #3b82f6; + font-size: inherit; + padding: 0.1em 0.3em; + border-radius: 6px; + font-weight: 700; +} + +@media screen and (max-width: 991px) { + main { + padding: 2rem 1.5rem; + height: auto; + } +} + +/** + * CODE BLOCKS + */ + +code { + font-family: 'JetBrains Mono', 'SF Mono', 'Monaco', 'Inconsolata', 'Fira Code', 'Droid Sans Mono', 'Source Code Pro', monospace; + font-size: 0.875em; + font-weight: 400; +} + +/* Inline code */ +:not(pre) > code { + background-color: #f3f4f6; + color: #dc2626; + padding: 0.2em 0.4em; + border-radius: 4px; + font-size: 0.875em; + white-space: nowrap; +} + +/* Code blocks */ +pre { + background-color: #1e293b; + color: #e2e8f0; + padding: 1.25rem 1.5rem; + margin: 1.5em 0; + border-radius: 8px; + overflow-x: auto; + overflow-y: visible; + line-height: 1.6; + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1); + min-height: fit-content; + height: auto; +} + +pre code { + background-color: transparent; + color: #e2e8f0; + padding: 0; + border-radius: 0; + white-space: pre; + font-size: 0.875rem; + line-height: 1.6; +} + +/* Syntax highlighting hints */ +pre code .keyword { + color: #c792ea; +} + +pre code .string { + color: #c3e88d; +} + +pre code .comment { + color: #636e7b; + font-style: italic; +} + +/* Custom scrollbar for code blocks */ +pre::-webkit-scrollbar { + height: 8px; +} + +pre::-webkit-scrollbar-track { + background: #0f172a; + border-radius: 4px; +} + +pre::-webkit-scrollbar-thumb { + background-color: #475569; + border-radius: 4px; +} + +pre::-webkit-scrollbar-thumb:hover { + background-color: #64748b; +} + +/** + * UTILITY CLASSES + */ + +.section-title { + font-size: 2.5rem; + font-weight: 700; + margin-bottom: 1rem; + color: #111827; +} + +/** + * Source Linking + */ +.source { + display: block; + text-align: right; + font-size: 0.875rem; + position: sticky; + top: 0; + margin-bottom: 1rem; +} + +.source a { + display: inline-block; + padding: 0.5rem 1rem; + background-color: #f3f4f6; + color: #4b5563; + border: 1px solid #d1d5db; + border-radius: 6px; + transition: all 0.15s ease; +} + +.source a:hover { + background-color: #e5e7eb; + border-color: #9ca3af; +} + +/** + * BOOK GRID + */ +.book-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 1.5rem; + margin: 2rem 0; +} + +.book-grid .card { + background: #ffffff; + border: 1px solid #e5e7eb; + border-radius: 8px; + padding: 1.5rem; + transition: all 0.2s ease; +} + +.book-grid .card:hover { + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + transform: translateY(-2px); +} + +/** + * INTERACTIVE EXAMPLES + */ +.example-container { + /* Span all 3 columns of the main grid */ + grid-column: 1 / -1; + margin: 1.5em 3rem; + height: 400px; + border: 1px solid #e5e7eb; + border-radius: 8px; + overflow: hidden; + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1); + display: flex; + flex-direction: row; + position: relative; +} + +.example-editor { + flex: 1; + min-width: 0; + height: 100%; + border-right: 2px solid #3b82f6; + overflow: auto; +} + +.example-editor .cm-editor { + height: 100%; + font-family: 'JetBrains Mono', 'SF Mono', 'Monaco', 'Inconsolata', monospace; + font-size: 0.875rem; +} + +.example-editor .cm-scroller { + overflow: auto; +} + +.example-editor .cm-focused { + outline: none !important; +} + +.example-editor:focus-within { + border-right-color: #2563eb; +} + +.example-result { + flex: 1; + min-width: 0; + height: 100%; + border: none; + background-color: #ffffff; + overflow: hidden; +} + +.example-error { + position: absolute; + bottom: 0; + left: 50%; + right: 0; + padding: 1rem 1.5rem; + background-color: #fef2f2; + color: #991b1b; + border-top: 2px solid #dc2626; + font-family: 'JetBrains Mono', monospace; + font-size: 0.875rem; + line-height: 1.5; + z-index: 10; +} + +/* Responsive: stack vertically on mobile */ +@media (max-width: 768px) { + .example-container { + flex-direction: column; + margin: 1.5em 1rem; + height: 600px; + } + + .example-editor { + border-right: none; + border-bottom: 2px solid #3b82f6; + max-height: 50%; + } + + .example-editor:focus-within { + border-bottom-color: #2563eb; + } + + .example-result { + max-height: 50%; + } + + .example-error { + left: 0; + } +} + +/** + * ACCESSIBILITY & FOCUS STATES + */ +*:focus-visible { + outline: 2px solid #3b82f6; + outline-offset: 2px; +} + +/** + * PRINT STYLES + */ +@media print { + .top-bar, + .sidebar { + display: none; + } + + main { + max-width: 100%; + padding: 1rem; + } + + body { + grid-template-columns: 1fr; + margin-top: 0; + } + + a { + text-decoration: underline; + } + + a[href^="http"]::after { + content: " (" attr(href) ")"; + font-size: 0.875em; + color: #6b7280; + } +} diff --git a/packages/provider.databind/docs/databind-parser.md b/tko.io/src/docs/advanced/databind-parser.md similarity index 99% rename from packages/provider.databind/docs/databind-parser.md rename to tko.io/src/docs/advanced/databind-parser.md index db9df61cd..9b7405602 100644 --- a/packages/provider.databind/docs/databind-parser.md +++ b/tko.io/src/docs/advanced/databind-parser.md @@ -1,3 +1,9 @@ +--- +layout: base.njk +title: DataBind Parser +--- + +# DataBind Parser tko.provider is a binding provider for [Knockout](http://knockoutjs.com), namely it parses HTML attributes and converts them to handlers of bidirectional updates. diff --git a/packages/lifecycle/docs/life-cycle.md b/tko.io/src/docs/advanced/life-cycle.md similarity index 98% rename from packages/lifecycle/docs/life-cycle.md rename to tko.io/src/docs/advanced/life-cycle.md index 565e95a2e..7cdecab87 100644 --- a/packages/lifecycle/docs/life-cycle.md +++ b/tko.io/src/docs/advanced/life-cycle.md @@ -1,4 +1,9 @@ -# tko.lifecycle +--- +layout: base.njk +title: Lifecycle +--- + +# Lifecycle The `tko.lifecycle` package exports one class, `LifeCycle`, which is intended to make tracking and disposing of temporary computations, subscriptions, and DOM event handlers simpler. diff --git a/packages/provider/docs/provider.md b/tko.io/src/docs/advanced/provider.md similarity index 83% rename from packages/provider/docs/provider.md rename to tko.io/src/docs/advanced/provider.md index adcb20017..4f5e8591e 100644 --- a/packages/provider/docs/provider.md +++ b/tko.io/src/docs/advanced/provider.md @@ -1,3 +1,7 @@ +--- +layout: base.njk +title: Provider +--- # Provider @@ -9,8 +13,8 @@ The `Provider` is a class that is responsible for linking nodes to binding handl | `VirtualProvider` | `` | `ComponentProvider` | `` | `AttributeProvider` | `` -| `TextMustacheProvider` | `{{ x_text }}`
`{{{ x_html }}}`
`{{# text: thing /}}` -| `AttributeMustacheProvider` | `` +| `TextMustacheProvider` | {% raw %}`{{ x_text }}`{% endraw %}
{% raw %}`{{{ x_html }}}`{% endraw %}
{% raw %}`{{# text: thing /}}`{% endraw %} +| `AttributeMustacheProvider` | {% raw %}``{% endraw %} | `MultiProvider` | Combines more than one provider together. When building custom versions of tko, one can choose to use one or more binding providers, or to create a custom binding provider. diff --git a/packages/bind/docs/binding-context.md b/tko.io/src/docs/binding-context/binding-context.md similarity index 94% rename from packages/bind/docs/binding-context.md rename to tko.io/src/docs/binding-context/binding-context.md index 14c342c05..c453d7249 100644 --- a/packages/bind/docs/binding-context.md +++ b/tko.io/src/docs/binding-context/binding-context.md @@ -1,7 +1,12 @@ +--- +layout: base.njk +title: Binding Context +--- + # Binding Context -A *binding context* is an object that holds data that you can reference from your bindings. While applying bindings, Knockout automatically creates and manages a hierarchy of binding contexts. The root level of the hierarchy refers to the `viewModel` parameter you supplied to `ko.applyBindings(viewModel)`. Then, each time you use a control flow binding such as [`with`](with-binding.html) or [`foreach`](foreach-binding.html), that creates a child binding context that refers to the nested view model data. +A *binding context* is an object that holds data that you can reference from your bindings. While applying bindings, Knockout automatically creates and manages a hierarchy of binding contexts. The root level of the hierarchy refers to the `viewModel` parameter you supplied to `ko.applyBindings(viewModel)`. Then, each time you use a control flow binding such as [`with`](../with-binding/) or [`foreach`](../foreach-binding/), that creates a child binding context that refers to the nested view model data. Bindings contexts offer the following special properties that you can reference in any binding: diff --git a/packages/bind/docs/binding-preprocessing.md b/tko.io/src/docs/binding-context/binding-preprocessing.md similarity index 97% rename from packages/bind/docs/binding-preprocessing.md rename to tko.io/src/docs/binding-context/binding-preprocessing.md index bf6392858..2b0b76851 100644 --- a/packages/bind/docs/binding-preprocessing.md +++ b/tko.io/src/docs/binding-context/binding-preprocessing.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: Binding Preprocessing +--- + # Binding Preprocessing @@ -7,7 +12,7 @@ Starting with Knockout 3.0, developers can define custom syntaxes by providing c ## Preprocessing binding strings -You can hook into Knockout's logic for interpreting `data-bind` attributes by providing a *binding preprocessor* for a specific binding handler (such as `click`, `visible`, or any [custom binding handler](custom-bindings.html)). +You can hook into Knockout's logic for interpreting `data-bind` attributes by providing a *binding preprocessor* for a specific binding handler (such as `click`, `visible`, or any [custom binding handler](../../binding-context/custom-bindings/)). To do this, attach a `preprocess` function to the binding handler: @@ -77,7 +82,7 @@ Now you can bind `click` like this: ## Preprocessing DOM nodes -You can hook into Knockout's logic for traversing the DOM by providing a *node preprocessor*. This is a function that Knockout will call once for each DOM node that it walks over, both when the UI is first bound, and later when any new DOM subtrees are injected (e.g., via a [`foreach` binding](foreach-binding.html)). +You can hook into Knockout's logic for traversing the DOM by providing a *node preprocessor*. This is a function that Knockout will call once for each DOM node that it walks over, both when the UI is first bound, and later when any new DOM subtrees are injected (e.g., via a [`foreach` binding](../foreach-binding/)). To do this, define a `preprocessNode` function on your binding provider: diff --git a/packages/bind/docs/binding-syntax.md b/tko.io/src/docs/binding-context/binding-syntax.md similarity index 91% rename from packages/bind/docs/binding-syntax.md rename to tko.io/src/docs/binding-context/binding-syntax.md index 192c19360..5da2b5c4b 100644 --- a/packages/bind/docs/binding-syntax.md +++ b/tko.io/src/docs/binding-context/binding-syntax.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: Binding Syntax +--- + # The `data-bind` Syntax @@ -21,7 +26,7 @@ Your value: Cellphone: ``` -The binding *name* should generally match a registered binding handler (either built-in or [custom](custom-bindings.html)) or be a parameter for another binding. If the name matches neither of those, Knockout will ignore it (without any error or warning). So if a binding doesn't appear to work, first check that the name is correct. +The binding *name* should generally match a registered binding handler (either built-in or [custom](../../binding-context/custom-bindings/)) or be a parameter for another binding. If the name matches neither of those, Knockout will ignore it (without any error or warning). So if a binding doesn't appear to work, first check that the name is correct. #### Binding values diff --git a/packages/bind/docs/custom-bindings-controlling-descendant-bindings.md b/tko.io/src/docs/binding-context/custom-bindings-controlling-descendant-bindings.md similarity index 94% rename from packages/bind/docs/custom-bindings-controlling-descendant-bindings.md rename to tko.io/src/docs/binding-context/custom-bindings-controlling-descendant-bindings.md index c1187ae7f..d4c931643 100644 --- a/packages/bind/docs/custom-bindings-controlling-descendant-bindings.md +++ b/tko.io/src/docs/binding-context/custom-bindings-controlling-descendant-bindings.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: Custom Bindings Controlling Descendant Bindings +--- + # Controlling Descendant Bindnings *Note: Creating custom bindings that control descendant binding is an advanced technique, typically used only when creating libraries of reusable bindings. It's not something you'll normally need to do when building applications with Knockout.* @@ -36,7 +41,7 @@ To see this take effect, here's a sample usage: ### Example: Supplying additional values to descendant bindings -Normally, bindings that use `controlsDescendantBindings` will also call `ko.applyBindingsToDescendants(someBindingContext, element)` to apply the descendant bindings against some modified [binding context](binding-context.html). For example, you could have a binding called `withProperties` that attaches some extra properties to the binding context that will then be available to all descendant bindings: +Normally, bindings that use `controlsDescendantBindings` will also call `ko.applyBindingsToDescendants(someBindingContext, element)` to apply the descendant bindings against some modified [binding context](../../binding-context/binding-context/). For example, you could have a binding called `withProperties` that attaches some extra properties to the binding context that will then be available to all descendant bindings: ```javascript ko.bindingHandlers.withProperties = { diff --git a/packages/bind/docs/custom-bindings-disposal.md b/tko.io/src/docs/binding-context/custom-bindings-disposal.md similarity index 82% rename from packages/bind/docs/custom-bindings-disposal.md rename to tko.io/src/docs/binding-context/custom-bindings-disposal.md index fdcc7e607..23f1a4307 100644 --- a/packages/bind/docs/custom-bindings-disposal.md +++ b/tko.io/src/docs/binding-context/custom-bindings-disposal.md @@ -1,6 +1,11 @@ +--- +layout: base.njk +title: Custom Bindings Disposal +--- + # Custom Disposal Logic -In a typical Knockout application, DOM elements are dynamically added and removed, for example using the [`template`](template-binding.html) binding or via control-flow bindings ([`if`](if-binding.html), [`ifnot`](ifnot-binding.html), [`with`](with-binding.html), and [`foreach`](foreach-binding.html)). When creating a custom binding, it is often desirable to add clean-up logic that runs when an element associated with your custom binding is removed by Knockout. +In a typical Knockout application, DOM elements are dynamically added and removed, for example using the [`template`](template-binding.html) binding or via control-flow bindings ([`if`](../if-binding/), [`ifnot`](ifnot-binding.html), [`with`](../with-binding/), and [`foreach`](../foreach-binding/)). When creating a custom binding, it is often desirable to add clean-up logic that runs when an element associated with your custom binding is removed by Knockout. ### Registering a callback on the disposal of an element diff --git a/packages/bind/docs/custom-bindings-for-virtual-elements.md b/tko.io/src/docs/binding-context/custom-bindings-for-virtual-elements.md similarity index 95% rename from packages/bind/docs/custom-bindings-for-virtual-elements.md rename to tko.io/src/docs/binding-context/custom-bindings-for-virtual-elements.md index 0a6fbdf26..a7aa1024c 100644 --- a/packages/bind/docs/custom-bindings-for-virtual-elements.md +++ b/tko.io/src/docs/binding-context/custom-bindings-for-virtual-elements.md @@ -1,9 +1,14 @@ +--- +layout: base.njk +title: Custom Bindings For Virtual Elements +--- + # Custom Bindings and Virtual Elements *Note: Creating custom bindings that support virtual elements is an advanced technique, typically used only when creating libraries of reusable bindings. It's not something you'll normally need to do when building applications with Knockout.* -Knockout's *control flow bindings* (e.g., [`if`](if-binding.html) and [`foreach`](foreach-binding.html)) can be applied not only to regular DOM elements, but also to "virtual" DOM elements defined by a special comment-based syntax. For example: +Knockout's *control flow bindings* (e.g., [`if`](../if-binding/) and [`foreach`](../foreach-binding/)) can be applied not only to regular DOM elements, but also to "virtual" DOM elements defined by a special comment-based syntax. For example: ```html ``` -For more information about `$index` and other context properties such as `$parent`, see documentation for [binding context properties](binding-context.html). +For more information about `$index` and other context properties such as `$parent`, see documentation for [binding context properties](../../binding-context/binding-context/). ### Note 3: Using "as" to give an alias to "foreach" items -As described in Note 1, you can refer to each array entry using the `$data` [context variable](binding-context.html). In some cases though, it may be useful to give the current item a more descriptive name using the `as` option like: +As described in Note 1, you can refer to each array entry using the `$data` [context variable](../../binding-context/binding-context/). In some cases though, it may be useful to give the current item a more descriptive name using the `as` option like: ```html @@ -137,7 +142,7 @@ By default, the `foreach` binding will skip over (i.e., hide) any array entries If you need to run some further custom logic on the generated DOM elements, you can use any of the `afterRender`/`afterAdd`/`beforeRemove`/`beforeMove`/`afterMove` callbacks described below. -> **Note:** These callbacks are *only* intended for triggering animations related to changes in a list. If your goal is actually to attach other behaviors to new DOM elements when they have been added (e.g., event handlers, or to activate third-party UI controls), then your work will be much easier if you implement that new behavior as a [custom binding](custom-bindings.html) instead, because then you can use that behavior anywhere, independently of the `foreach` binding. +> **Note:** These callbacks are *only* intended for triggering animations related to changes in a list. If your goal is actually to attach other behaviors to new DOM elements when they have been added (e.g., event handlers, or to activate third-party UI controls), then your work will be much easier if you implement that new behavior as a [custom binding](../../binding-context/custom-bindings/) instead, because then you can use that behavior anywhere, independently of the `foreach` binding. Here's a trivial example that uses `afterAdd` to apply the classic "yellow fade" effect to newly-added items. It requires the [jQuery Color plugin](https://github.com/jquery/jquery-color) to enable animation of background colors. diff --git a/packages/binding.core/docs/hasfocus-binding.md b/tko.io/src/docs/bindings/hasfocus-binding.md similarity index 97% rename from packages/binding.core/docs/hasfocus-binding.md rename to tko.io/src/docs/bindings/hasfocus-binding.md index 995aafabe..ddacd2e29 100644 --- a/packages/binding.core/docs/hasfocus-binding.md +++ b/tko.io/src/docs/bindings/hasfocus-binding.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: Hasfocus Binding +--- + # `hasFocus` ### Purpose diff --git a/packages/binding.core/docs/html-binding.md b/tko.io/src/docs/bindings/html-binding.md similarity index 92% rename from packages/binding.core/docs/html-binding.md rename to tko.io/src/docs/bindings/html-binding.md index 08438f8c8..5a0bc9432 100644 --- a/packages/binding.core/docs/html-binding.md +++ b/tko.io/src/docs/bindings/html-binding.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: Html Binding +--- + # `html` @@ -42,4 +47,4 @@ viewModel.details("For further details, view the report ` element will then display one item for each item in your array. -Note: For a multi-select list, to set which of the options are selected, or to read which of the options are selected, use [the `selectedOptions` binding](selectedOptions-binding.html). For a single-select list, you can also read and write the selected option using [the `value` binding](value-binding.html). +Note: For a multi-select list, to set which of the options are selected, or to read which of the options are selected, use [the `selectedOptions` binding](../selectedOptions-binding/). For a single-select list, you can also read and write the selected option using [the `value` binding](../value-binding/). ### Example 1: Drop-down list @@ -136,7 +141,7 @@ Note that the only difference between examples 3 and 4 is the `optionsText` valu * `selectedOptions` - For a multi-select list, you can read and write the selection state using `selectedOptions`. Technically this is a separate binding, so it has [its own documentation](selectedOptions-binding.html). + For a multi-select list, you can read and write the selection state using `selectedOptions`. Technically this is a separate binding, so it has [its own documentation](../selectedOptions-binding/). * `valueAllowUnset` diff --git a/packages/binding.core/docs/selectedOptions-binding.md b/tko.io/src/docs/bindings/selectedOptions-binding.md similarity index 83% rename from packages/binding.core/docs/selectedOptions-binding.md rename to tko.io/src/docs/bindings/selectedOptions-binding.md index aa176d389..f9719712f 100644 --- a/packages/binding.core/docs/selectedOptions-binding.md +++ b/tko.io/src/docs/bindings/selectedOptions-binding.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: SelectedOptions Binding +--- + # `selectedOptions` @@ -7,7 +12,7 @@ The `selectedOptions` binding controls which elements in a multi-select list are When the user selects or de-selects an item in the multi-select list, this adds or removes the corresponding value to an array on your view model. Likewise, assuming it's an *observable* array on your view model, then whenever you add or remove (e.g., via `push` or `splice`) items to this array, the corresponding items in the UI become selected or deselected. It's a 2-way binding. -Note: To control which element in a single-select drop-down list is selected, you can use [the `value` binding](value-binding.html) instead. +Note: To control which element in a single-select drop-down list is selected, you can use [the `value` binding](../value-binding/) instead. ### Example ```html @@ -33,7 +38,7 @@ viewModel.chosenCountries.push('France'); // Now France is selected too This should be an array (or an observable array). KO sets the element's selected options to match the contents of the array. Any previous selection state will be overwritten. - If your parameter is an observable array, the binding will update the element's selection whenever the array changes (e.g., via `push`, `pop` or [other observable array methods](observableArrays.html)). If the parameter isn't observable, it will only set the element's selection state once and will not update it again later. + If your parameter is an observable array, the binding will update the element's selection whenever the array changes (e.g., via `push`, `pop` or [other observable array methods](../../observables/observableArrays/)). If the parameter isn't observable, it will only set the element's selection state once and will not update it again later. Whether or not the parameter is an observable array, KO will detect when the user selects or deselects an item in the multi-select list, and will update the array to match. This is how you can read which of the options is selected. @@ -43,6 +48,6 @@ viewModel.chosenCountries.push('France'); // Now France is selected too ### Note: Letting the user select from arbitrary JavaScript objects -In the example code above, the user can choose from an array of string values. You're *not* limited to providing strings - your `options` array can contain arbitrary JavaScript objects if you wish. See [the `options` binding](options-binding.html) for details on how to control how arbitrary objects should be displayed in the list. +In the example code above, the user can choose from an array of string values. You're *not* limited to providing strings - your `options` array can contain arbitrary JavaScript objects if you wish. See [the `options` binding](../options-binding/) for details on how to control how arbitrary objects should be displayed in the list. In this scenario, the values you can read and write using `selectedOptions` are those objects themselves, *not* their textual representations. This leads to much cleaner and more elegant code in most cases. Your view model can imagine that the user chooses from an array of arbitrary objects, without having to care how those objects are mapped to an on-screen representation. diff --git a/packages/binding.core/docs/style-binding.md b/tko.io/src/docs/bindings/style-binding.md similarity index 95% rename from packages/binding.core/docs/style-binding.md rename to tko.io/src/docs/bindings/style-binding.md index 51c4fd48d..7ffffe413 100644 --- a/packages/binding.core/docs/style-binding.md +++ b/tko.io/src/docs/bindings/style-binding.md @@ -1,9 +1,14 @@ +--- +layout: base.njk +title: Style Binding +--- + # `style` ### Purpose The `style` binding adds or removes one or more style values to the associated DOM element. This is useful, for example, to highlight some value in red if it becomes negative, or to set the width of a bar to match a numerical value that changes. -(Note: If you don't want to apply an explicit style value but instead want to assign a CSS class, see [the css binding](css-binding.html).) +(Note: If you don't want to apply an explicit style value but instead want to assign a CSS class, see [the css binding](../css-binding/).) ### Example diff --git a/packages/binding.core/docs/submit-binding.md b/tko.io/src/docs/bindings/submit-binding.md similarity index 98% rename from packages/binding.core/docs/submit-binding.md rename to tko.io/src/docs/bindings/submit-binding.md index e6a5769f4..290ff0586 100644 --- a/packages/binding.core/docs/submit-binding.md +++ b/tko.io/src/docs/bindings/submit-binding.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: Submit Binding +--- + # `submit` diff --git a/packages/binding.template/docs/template-binding.md b/tko.io/src/docs/bindings/template-binding.md similarity index 94% rename from packages/binding.template/docs/template-binding.md rename to tko.io/src/docs/bindings/template-binding.md index 10bcdbafc..ba3ccf4cd 100644 --- a/packages/binding.template/docs/template-binding.md +++ b/tko.io/src/docs/bindings/template-binding.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: Template Binding +--- + # `template` Binding @@ -93,7 +98,7 @@ This gives the same result as embedding an anonymous template directly inside th ### Note 3: Using "as" to give an alias to "foreach" items -When nesting `foreach` templates, it's often useful to refer to items at higher levels in the hierarchy. One way to do this is to refer to `$parent` or other [binding context](binding-context.html) variables in your bindings. +When nesting `foreach` templates, it's often useful to refer to items at higher levels in the hierarchy. One way to do this is to refer to `$parent` or other [binding context](../../binding-context/binding-context/) variables in your bindings. A simpler and more elegant option, however, is to use `as` to declare a name for your iteration variables. For example: @@ -143,7 +148,7 @@ Tip: Remember to pass a *string literal value* to as (e.g., `as: 'season'`, *not Sometimes you might want to run custom post-processing logic on the DOM elements generated by your templates. For example, if you're using a JavaScript widgets library such as jQuery UI, you might want to intercept your templates' output so that you can run jQuery UI commands on it to transform some of the rendered elements into date pickers, sliders, or anything else. -Generally, the best way to perform such post-processing on DOM elements is to write a [custom binding](custom-bindings.html), but if you really just want to access the raw DOM elements emitted by a template, you can use `afterRender`. +Generally, the best way to perform such post-processing on DOM elements is to write a [custom binding](../../binding-context/custom-bindings/), but if you really just want to access the raw DOM elements emitted by a template, you can use `afterRender`. Pass a function reference (either a function literal, or give the name of a function on your view model), and Knockout will invoke it immediately after rendering or re-rendering your template. If you're using `foreach`, Knockout will invoke your `afterRender` callback for each item added to your observable array. For example, @@ -162,7 +167,7 @@ viewModel.myPostProcessingLogic = function(elements) { } ``` -If you are using `foreach` and only want to be notified about elements that are specifically being added or are being removed, you can use `afterAdd` and `beforeRemove` instead. For details, see documentation for the [`foreach` binding](foreach-binding.html). +If you are using `foreach` and only want to be notified about elements that are specifically being added or are being removed, you can use `afterAdd` and `beforeRemove` instead. For details, see documentation for the [`foreach` binding](../foreach-binding/). ### Note 5: Dynamically choosing which template is used @@ -193,7 +198,7 @@ javascript: |- If your function references observable values, then the binding will update whenever any of those values change. This will cause the data to be re-rendered using the appropriate template. -If your function accepts a second parameter, then it will receive the entire [binding context](binding-context.html). You can then access `$parent` or any other [binding context](binding-context.html) variable when dynamically choosing a template. For example, you could amend the preceding code snippet as follows: +If your function accepts a second parameter, then it will receive the entire [binding context](../../binding-context/binding-context/). You can then access `$parent` or any other [binding context](../../binding-context/binding-context/) variable when dynamically choosing a template. For example, you could amend the preceding code snippet as follows: ```javascript displayMode: function(employee, bindingContext) { @@ -253,7 +258,7 @@ The [Underscore.js template engine](http://documentcloud.github.com/underscore/# ``` -Here's [a simple implementation of integrating Underscore templates with Knockout](http://jsfiddle.net/rniemeyer/NW5Vn/). The integration code is just 16 lines long, but it's enough to support Knockout `data-bind` attributes (and hence nested templates) and Knockout [binding context](binding-context.html) variables (`$parent`, `$root`, etc.). +Here's [a simple implementation of integrating Underscore templates with Knockout](http://jsfiddle.net/rniemeyer/NW5Vn/). The integration code is just 16 lines long, but it's enough to support Knockout `data-bind` attributes (and hence nested templates) and Knockout [binding context](../../binding-context/binding-context/) variables (`$parent`, `$root`, etc.). If you're not a fan of the `<%= ... %>` delimiters, you can configure the Underscore template engine to use any other delimiter characters of your choice. diff --git a/packages/binding.core/docs/text-binding.md b/tko.io/src/docs/bindings/text-binding.md similarity index 93% rename from packages/binding.core/docs/text-binding.md rename to tko.io/src/docs/bindings/text-binding.md index f4a69fbde..3de24465a 100644 --- a/packages/binding.core/docs/text-binding.md +++ b/tko.io/src/docs/bindings/text-binding.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: Text Binding +--- + # `text` @@ -26,7 +31,7 @@ Typically this is useful with elements like `` or `` that traditionall ### Note 1: Using functions and expressions to detemine text values -If you want to detemine text programmatically, one option is to create a [computed observable](computedObservables.html), and use its evaluator function as a place for your code that works out what text to display. +If you want to detemine text programmatically, one option is to create a [computed observable](../../computed/computedObservables/), and use its evaluator function as a place for your code that works out what text to display. For example, @@ -54,7 +59,7 @@ viewModel.myMessage("Hello, world!"); ... this would *not* render as italic text, but would render as literal text with visible angle brackets. -If you need to set HTML content in this manner, see [the html binding](html-binding.html). +If you need to set HTML content in this manner, see [the html binding](../html-binding/). ### Note 3: Using "text" without a container element diff --git a/packages/binding.core/docs/textInput-binding.md b/tko.io/src/docs/bindings/textInput-binding.md similarity index 98% rename from packages/binding.core/docs/textInput-binding.md rename to tko.io/src/docs/bindings/textInput-binding.md index 2950148a3..31c879bfe 100644 --- a/packages/binding.core/docs/textInput-binding.md +++ b/tko.io/src/docs/bindings/textInput-binding.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: TextInput Binding +--- + # `textInput` diff --git a/packages/binding.core/docs/uniqueName-binding.md b/tko.io/src/docs/bindings/uniqueName-binding.md similarity index 96% rename from packages/binding.core/docs/uniqueName-binding.md rename to tko.io/src/docs/bindings/uniqueName-binding.md index 0765425ca..d8c0d5023 100644 --- a/packages/binding.core/docs/uniqueName-binding.md +++ b/tko.io/src/docs/bindings/uniqueName-binding.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: UniqueName Binding +--- + # `uniqueName` diff --git a/packages/binding.core/docs/value-binding.md b/tko.io/src/docs/bindings/value-binding.md similarity index 95% rename from packages/binding.core/docs/value-binding.md rename to tko.io/src/docs/bindings/value-binding.md index 23f1627e6..248219f3f 100644 --- a/packages/binding.core/docs/value-binding.md +++ b/tko.io/src/docs/bindings/value-binding.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: Value Binding +--- + # `value` @@ -9,7 +14,7 @@ The `value` binding links the associated DOM element's value with a property on When the user edits the value in the associated form control, it updates the value on your view model. Likewise, when you update the value in your view model, this updates the value of the form control on screen. -Note: If you're working with checkboxes or radio buttons, use [the `checked` binding](checked-binding.html) to read and write your element's checked state, not the `value` binding. +Note: If you're working with checkboxes or radio buttons, use [the `checked` binding](../checked-binding/) to read and write your element's checked state, not the `value` binding. ### Example @@ -57,7 +62,7 @@ Note: If you're working with checkboxes or radio buttons, use [the `checked` bin ### Note 1: Working with drop-down lists (i.e., `` elements). The `value` binding works in conjunction with the `options` binding to let you read and write values that are arbitrary JavaScript objects, not just string values. This is very useful if you want to let the user select from a set of model objects. For examples of this, see [the `options` binding](options-binding.html) or for handling multi-select lists, see the documentation for [the `selectedOptions` binding](selectedOptions-binding.html). +Knockout has special support for drop-down lists (i.e., `` element that does not use the `options` binding. In this case, you can choose to specify your `` elements and Knockout will set the selected value appropriately. diff --git a/packages/binding.core/docs/visible-binding.md b/tko.io/src/docs/bindings/visible-binding.md similarity index 97% rename from packages/binding.core/docs/visible-binding.md rename to tko.io/src/docs/bindings/visible-binding.md index 85388b11b..ce8db7ac7 100644 --- a/packages/binding.core/docs/visible-binding.md +++ b/tko.io/src/docs/bindings/visible-binding.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: Visible Binding +--- + # `visible` diff --git a/packages/binding.if/docs/with-binding.md b/tko.io/src/docs/bindings/with-binding.md similarity index 81% rename from packages/binding.if/docs/with-binding.md rename to tko.io/src/docs/bindings/with-binding.md index 7aac52bae..69ac082d3 100644 --- a/packages/binding.if/docs/with-binding.md +++ b/tko.io/src/docs/bindings/with-binding.md @@ -1,10 +1,15 @@ +--- +layout: base.njk +title: With Binding +--- + # `with` Binding ### Purpose -The `with` binding creates a new [binding context](binding-context.html), so that descendant elements are bound in the context of a specified object. +The `with` binding creates a new [binding context](../../binding-context/binding-context/), so that descendant elements are bound in the context of a specified object. -Of course, you can arbitrarily nest `with` bindings along with the other control-flow bindings such as [`if`](if-binding.html) and [`foreach`](foreach-binding.html). +Of course, you can arbitrarily nest `with` bindings along with the other control-flow bindings such as [`if`](../if-binding/) and [`foreach`](../foreach-binding/). ### Example 1 @@ -33,7 +38,7 @@ javascript: |- This interactive example demonstrates that: * The `with` binding will dynamically add or remove descendant elements depending on whether the associated value is `null`/`undefined` or not - * If you want to access data/functions from parent binding contexts, you can use [special context properties such as `$parent` and `root`](binding-context.html). + * If you want to access data/functions from parent binding contexts, you can use [special context properties such as `$parent` and `root`](../../binding-context/binding-context/). ```example html: |- @@ -92,7 +97,7 @@ javascript: |- ### Note 1: Using "with" without a container element -Just like other control flow elements such as [`if`](if-binding.html) and [`foreach`](foreach-binding.html), you can use `with` without any container element to host it. This is useful if you need to use `with` in a place where it would not be legal to introduce a new container element just to hold the `with` binding. See the documentation for [`if`](if-binding.html) or [`foreach`](foreach-binding.html) for more details. +Just like other control flow elements such as [`if`](../if-binding/) and [`foreach`](../foreach-binding/), you can use `with` without any container element to host it. This is useful if you need to use `with` in a place where it would not be legal to introduce a new container element just to hold the `with` binding. See the documentation for [`if`](../if-binding/) or [`foreach`](../foreach-binding/) for more details. Example: diff --git a/packages/utils.component/docs/component-binding.md b/tko.io/src/docs/components/component-binding.md similarity index 99% rename from packages/utils.component/docs/component-binding.md rename to tko.io/src/docs/components/component-binding.md index f153c2f9b..c264bf883 100644 --- a/packages/utils.component/docs/component-binding.md +++ b/tko.io/src/docs/components/component-binding.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: Component Binding +--- + # `component` diff --git a/packages/utils.component/docs/component-custom-elements.md b/tko.io/src/docs/components/component-custom-elements.md similarity index 95% rename from packages/utils.component/docs/component-custom-elements.md rename to tko.io/src/docs/components/component-custom-elements.md index 7e23fb93c..7ed9872bb 100644 --- a/packages/utils.component/docs/component-custom-elements.md +++ b/tko.io/src/docs/components/component-custom-elements.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: Component Custom Elements +--- + # Custom Component Elements @@ -76,7 +81,7 @@ In the following example, In general, if a parameter's evaluation does not involve evaluating an observable (in this case, the value did not involve observables at all), then the value is passed literally. If the value was an object, then the child component could mutate it, but since it's not observable the parent would not know the child had done so. * `simpleObservable` - * This will be the [`ko.observable`](observables.html) instance declared on the parent viewmodel as `myObservable`. It is not a wrapper --- it's the actual same instance as referenced by the parent. So if the child viewmodel writes to this observable, the parent viewmodel will receive that change. + * This will be the [`ko.observable`](../../observables/observables/) instance declared on the parent viewmodel as `myObservable`. It is not a wrapper --- it's the actual same instance as referenced by the parent. So if the child viewmodel writes to this observable, the parent viewmodel will receive that change. In general, if a parameter's evaluation does not involve evaluating an observable (in this case, the observable was simply passed without evaluating it), then the value is passed literally. @@ -108,7 +113,7 @@ Consider a special list component that can be invoked as follows: By default, the DOM nodes inside `` will be stripped out (without being bound to any viewmodel) and replaced by the component's output. However, those DOM nodes aren't lost: they are remembered, and are supplied to the component in two ways: - * As an array, `$componentTemplateNodes`, available to any binding expression in the component's template (i.e., as a [binding context](binding-context.html) property). Usually this is the most convenient way to use the supplied markup. See the example below. + * As an array, `$componentTemplateNodes`, available to any binding expression in the component's template (i.e., as a [binding context](../../binding-context/binding-context/) property). Usually this is the most convenient way to use the supplied markup. See the example below. * As an array, `componentInfo.templateNodes`, passed to its [`createViewModel` function](component-registration.html#a-createviewmodel-factory-function) The component can then choose to use the supplied DOM nodes as part of its output however it wishes, such as by using `template: { nodes: $componentTemplateNodes }` on any element in the component's template. @@ -148,7 +153,7 @@ ko.components.getComponentNameForNode = function(node) { You can use this technique if, for example, you want to control which subset of registered components may be used as custom elements. -### Registering custom elements {#registering-custom-elements} +### Registering custom elements {% raw %}{#registering-custom-elements}{% endraw %} If you are using the default component loader, and hence are registering your components using `ko.components.register`, then there is nothing extra you need to do. Components registered this way are immediately available for use as custom elements. @@ -170,7 +175,7 @@ A custom element can have a regular `data-bind` attribute (in addition to any `p ``` -However, it does not make sense to use bindings that would modify the element's contents, such as the [`text`](text-binding.html) or [`template`](template-binding.html) bindings, since they would overwrite the template injected by your component. +However, it does not make sense to use bindings that would modify the element's contents, such as the [`text`](../text-binding/) or [`template`](template-binding.html) bindings, since they would overwrite the template injected by your component. Knockout will prevent the use of any bindings that use [`controlsDescendantBindings`](custom-bindings-controlling-descendant-bindings.html), because this also would clash with the component when trying to bind its viewmodel to the injected template. Therefore if you want to use a control flow binding such as `if` or `foreach`, then you must wrap it around your custom element rather than using it directly on the custom element, e.g.,: diff --git a/packages/utils.component/docs/component-loaders.md b/tko.io/src/docs/components/component-loaders.md similarity index 98% rename from packages/utils.component/docs/component-loaders.md rename to tko.io/src/docs/components/component-loaders.md index 06993b6d1..39f5d371d 100644 --- a/packages/utils.component/docs/component-loaders.md +++ b/tko.io/src/docs/components/component-loaders.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: Component Loaders +--- + # Component Loaders @@ -6,7 +11,7 @@ Whenever you inject a [component](component-overview.html) using the [`component * [Table of contents injected here] {:toc} -# The default component loader {#default-component-loader} +# The default component loader {% raw %}{#default-component-loader}{% endraw %} The built-in default component loader, `ko.components.defaultLoader`, is based around a central "registry" of component definitions. It relies on you explicitly registering a configuration for each component before you can use that component. @@ -42,7 +47,7 @@ Also, since `ko.components.defaultLoader` is a component loader, it implements t For documentation on these standard component loader functions, see [implementing a custom component loader](#custom-component-loader). -# Implementing a custom component loader {#custom-component-loader} +# Implementing a custom component loader {% raw %}{#custom-component-loader}{% endraw %} You might want to implement a custom component loader if you want to use naming conventions, rather than explicit registration, to load components. Or, if you want to use a third-party "loader" library to fetch component viewmodels or templates from external locations. diff --git a/packages/utils.component/docs/component-overview.md b/tko.io/src/docs/components/component-overview.md similarity index 98% rename from packages/utils.component/docs/component-overview.md rename to tko.io/src/docs/components/component-overview.md index 76b6707da..377c13800 100644 --- a/packages/utils.component/docs/component-overview.md +++ b/tko.io/src/docs/components/component-overview.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: Component Overview +--- + # Component Overview diff --git a/packages/utils.component/docs/component-registration.md b/tko.io/src/docs/components/component-registration.md similarity index 96% rename from packages/utils.component/docs/component-registration.md rename to tko.io/src/docs/components/component-registration.md index 02cdb3e46..f5cbe3887 100644 --- a/packages/utils.component/docs/component-registration.md +++ b/tko.io/src/docs/components/component-registration.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: Component Registration +--- + # Component Registration @@ -87,7 +92,7 @@ ko.components.register('my-component', { }); ``` -Note that, typically, it's best to perform direct DOM manipulation only through [custom bindings](custom-bindings.html) rather than acting on `componentInfo.element` from inside `createViewModel`. This leads to more modular, reusable code. +Note that, typically, it's best to perform direct DOM manipulation only through [custom bindings](../../binding-context/custom-bindings/) rather than acting on `componentInfo.element` from inside `createViewModel`. This leads to more modular, reusable code. The `componentInfo.templateNodes` array is useful if you want to build a component that accepts arbitrary markup to influence its output (for example, a grid, list, dialog, or tab set that injects supplied markup into itself). For a complete example, see [passing markup into components](component-custom-elements.html#passing-markup-into-components). @@ -307,7 +312,7 @@ ko.components.register('my-component', { Knockout does not call `require([moduleName], ...)` until your component is being instantiated. This is how components get loaded on demand, not up front. -For example, if your component is inside some other element with an [`if` binding](if-binding.html) (or another control flow binding), then it will not cause the AMD module to be loaded until the `if` condition is true. Of course, if the AMD module was already loaded (e.g., in a preloaded bundle) then the `require` call will not trigger any additional HTTP requests, so you can control what is preloaded and what is loaded on demand. +For example, if your component is inside some other element with an [`if` binding](../if-binding/) (or another control flow binding), then it will not cause the AMD module to be loaded until the `if` condition is true. Of course, if the AMD module was already loaded (e.g., in a preloaded bundle) then the `require` call will not trigger any additional HTTP requests, so you can control what is preloaded and what is loaded on demand. ## Registering components as a single AMD module diff --git a/packages/computed/docs/computed-dependency-tracking.md b/tko.io/src/docs/computed/computed-dependency-tracking.md similarity index 96% rename from packages/computed/docs/computed-dependency-tracking.md rename to tko.io/src/docs/computed/computed-dependency-tracking.md index ab730e79f..42282eb5e 100644 --- a/packages/computed/docs/computed-dependency-tracking.md +++ b/tko.io/src/docs/computed/computed-dependency-tracking.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: Computed Dependency Tracking +--- + # Dependency Tracking @@ -13,7 +18,7 @@ So, Knockout doesn't just detect dependencies the first time the evaluator runs The other neat trick is that declarative bindings are simply implemented as computed observables. So, if a binding reads the value of an observable, that binding becomes dependent on that observable, which causes that binding to be re-evaluated if the observable changes. -*Pure* computed observables work slightly differently. For more details, see the documentation for [*pure* computed observables](computed-pure.html). +*Pure* computed observables work slightly differently. For more details, see the documentation for [*pure* computed observables](../computed-pure/). ## Controlling dependencies using peek @@ -31,7 +36,7 @@ ko.computed(function() { }, this); ``` -Note: If you just want to prevent a computed observable from updating too often, see the [`rateLimit` extender](rateLimit-observable.html). +Note: If you just want to prevent a computed observable from updating too often, see the [`rateLimit` extender](../../observables/rateLimit-observable/). ## Ignoring dependencies within a computed diff --git a/packages/computed/docs/computed-pure.md b/tko.io/src/docs/computed/computed-pure.md similarity index 96% rename from packages/computed/docs/computed-pure.md rename to tko.io/src/docs/computed/computed-pure.md index 6f4eab938..a7e8ea64b 100644 --- a/packages/computed/docs/computed-pure.md +++ b/tko.io/src/docs/computed/computed-pure.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: Computed Pure +--- + # Pure Computed Observables @@ -12,7 +17,7 @@ A *pure* computed observable automatically switches between two states based on 2. Whenever it has *any* `change` subscribers, it is awake and ***listening***. When entering the *listening* state, it immediately subscribes to any dependencies. In this state, it operates just like a regular computed observable, as described in [how dependency tracking works](computed-dependency-tracking.md). -#### Why "pure"? {#pure-computed-function-defined} +#### Why "pure"? {% raw %}{#pure-computed-function-defined}{% endraw %} We've borrowed the term from [pure functions](http://en.wikipedia.org/wiki/Pure_function) because this feature is generally only applicable for computed observables whose evaluator is a *pure function* as follows: @@ -73,7 +78,7 @@ You should not use the *pure* feature for a computed observable that is meant to }); ``` -The reason you shouldn't use a *pure* computed if the evaluator has important side effects is simply that the evaluator will not run whenever the computed has no active subscribers (and so is sleeping). If it's important for the evaluator to always run when dependencies change, use a [regular computed](computedObservables.html) instead. +The reason you shouldn't use a *pure* computed if the evaluator has important side effects is simply that the evaluator will not run whenever the computed has no active subscribers (and so is sleeping). If it's important for the evaluator to always run when dependencies change, use a [regular computed](../../computed/computedObservables/) instead. ### State-change notifications diff --git a/packages/computed/docs/computed-reference.md b/tko.io/src/docs/computed/computed-reference.md similarity index 91% rename from packages/computed/docs/computed-reference.md rename to tko.io/src/docs/computed/computed-reference.md index 5bb7ea860..20898994e 100644 --- a/packages/computed/docs/computed-reference.md +++ b/tko.io/src/docs/computed/computed-reference.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: Computed Reference +--- + # Computed Observable Reference @@ -16,12 +21,12 @@ A computed observable can be constructed using one of the following forms: * `read` --- Required. A function that is used to evaluate the computed observable's current value. * `write` --- Optional. If given, makes the computed observable writable. This is a function that receives values that other code is trying to write to your computed observable. It's up to you to supply custom logic to handle the incoming values, typically by writing the values to some underlying observable(s). * `owner` --- Optional. If given, defines the value of `this` whenever KO invokes your `read` or `write` callbacks. - * `pure` --- Optional. If this option is `true`, the computed observable will be set up as a [*pure* computed observable](computed-pure.html). This option is an alternative to the `ko.pureComputed` constructor. + * `pure` --- Optional. If this option is `true`, the computed observable will be set up as a [*pure* computed observable](../computed-pure/). This option is an alternative to the `ko.pureComputed` constructor. * `deferEvaluation` --- Optional. If this option is `true`, then the value of the computed observable will not be evaluated until something actually attempts to access its value or manually subscribes to it. By default, a computed observable has its value determined immediately during creation. * `disposeWhen` --- Optional. If given, this function is executed before each re-evaluation to determine if the computed observable should be disposed. A `true`-ish result will trigger disposal of the computed observable. * `disposeWhenNodeIsRemoved` --- Optional. If given, disposal of the computed observable will be triggered when the specified DOM node is removed by KO. This feature is used to dispose computed observables used in bindings when nodes are removed by the `template` and control-flow bindings. -1. `ko.pureComputed( evaluator [, targetObject] )` --- Constructs a [*pure* computed observable](computed-pure.html) using the given evaluator function and optional object to use for `this`. Unlike `ko.computed`, this method doesn't accept an `options` parameter. +1. `ko.pureComputed( evaluator [, targetObject] )` --- Constructs a [*pure* computed observable](../computed-pure/) using the given evaluator function and optional object to use for `this`. Unlike `ko.computed`, this method doesn't accept an `options` parameter. 1. `ko.pureComputed( options )` --- Constructs a *pure* computed observable using an `options` object. This accepts the `read`, `write`, and `owner` options described above. @@ -30,7 +35,7 @@ A computed observable can be constructed using one of the following forms: A computed observable provides the following functions: * `dispose()` --- Manually disposes the computed observable, clearing all subscriptions to dependencies. This function is useful if you want to stop a computed observable from being updated or want to clean up memory for a computed observable that has dependencies on observables that won't be cleaned. -* `extend(extenders)` --- Applies the given [extenders](extenders.html) to the computed observable. +* `extend(extenders)` --- Applies the given [extenders](../../observables/extenders/) to the computed observable. * `getDependenciesCount()` --- Returns the current number of dependencies of the computed observable. * `getSubscriptionsCount( [event] )` --- Returns the current number of subscriptions (either from other computed observables or manual subscriptions) of the computed observable. Optionally, pass an event name (like `"change"`) to return just the count of subscriptions for that event. * `isActive()` --- Returns whether the computed observable may be updated in the future. A computed observable is inactive if it has no dependencies. diff --git a/packages/computed/docs/computed-writable.md b/tko.io/src/docs/computed/computed-writable.md similarity index 97% rename from packages/computed/docs/computed-writable.md rename to tko.io/src/docs/computed/computed-writable.md index 1aadb28ad..4c5b0ccb7 100644 --- a/packages/computed/docs/computed-writable.md +++ b/tko.io/src/docs/computed/computed-writable.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: Computed Writable +--- + # Writeable Computeds @@ -17,7 +22,7 @@ Going back to the classic "first name + last name = full name" example, you can This is the exact opposite of the [Hello World](../examples/helloWorld.html) example, in that here the first and last names are not editable, but the combined full name is editable. -The preceding view model code demonstrates the *single parameter syntax* for initializing computed observables. See the [computed observable reference](computed-reference.html) for the full list of available options. +The preceding view model code demonstrates the *single parameter syntax* for initializing computed observables. See the [computed observable reference](../computed-reference/) for the full list of available options. ### Example 2: Selecting/deselecting all items diff --git a/packages/computed/docs/computedObservables.md b/tko.io/src/docs/computed/computedObservables.md similarity index 95% rename from packages/computed/docs/computedObservables.md rename to tko.io/src/docs/computed/computedObservables.md index 26edb9354..6360126e5 100644 --- a/packages/computed/docs/computedObservables.md +++ b/tko.io/src/docs/computed/computedObservables.md @@ -1,6 +1,11 @@ +--- +layout: base.njk +title: ComputedObservables +--- + # Computed Observables Overview -What if you've got an [observable](observables.html) for `firstName`, and another for `lastName`, and you want to display the full name? That's where *computed observables* come in - these are functions that are dependent on one or more other observables, and will automatically update whenever any of these dependencies change. +What if you've got an [observable](../../observables/observables/) for `firstName`, and another for `lastName`, and you want to display the full name? That's where *computed observables* come in - these are functions that are dependent on one or more other observables, and will automatically update whenever any of these dependencies change. For example, given the following view model class, @@ -69,7 +74,7 @@ Then, changes to `items` or `selectedIndexes` will ripple through the chain of c ### Forcing computed observables to always notify subscribers -When a computed observable returns a primitive value (a number, string, boolean, or null), the dependencies of the observable are normally only notified if the value actually changed. However, it is possible to use the built-in `notify` [extender](extenders.html) to ensure that a computed observable's subscribers are always notified on an update, even if the value is the same. You would apply the extender like this: +When a computed observable returns a primitive value (a number, string, boolean, or null), the dependencies of the observable are normally only notified if the value actually changed. However, it is possible to use the built-in `notify` [extender](../../observables/extenders/) to ensure that a computed observable's subscribers are always notified on an update, even if the value is the same. You would apply the extender like this: ```javascript myViewModel.fullName = ko.computed(function() { @@ -79,7 +84,7 @@ myViewModel.fullName = ko.computed(function() { ### Delaying and/or suppressing change notifications -Normally, a computed observable updates and notifies its subscribers immediately, as soon as its dependencies change. But if a computed observable has many dependencies or involves expensive updates, you may get better performance by limiting or delaying the computed observable's updates and notifications. This is accomplished using the [`rateLimit` extender](rateLimit-observable.html) like this: +Normally, a computed observable updates and notifies its subscribers immediately, as soon as its dependencies change. But if a computed observable has many dependencies or involves expensive updates, you may get better performance by limiting or delaying the computed observable's updates and notifications. This is accomplished using the [`rateLimit` extender](../../observables/rateLimit-observable/) like this: ```javascript // Ensure updates no more than once per 50-millisecond period @@ -235,7 +240,7 @@ ko.computed(function() { }, this); ``` -Note: If you just want to prevent a computed observable from updating too often, see the [`rateLimit` extender](rateLimit-observable.html). +Note: If you just want to prevent a computed observable from updating too often, see the [`rateLimit` extender](../../observables/rateLimit-observable/). ### Note: Why circular dependencies aren't meaningful @@ -286,7 +291,7 @@ A computed observable can be constructed using one of the following forms: A computed observable provides the following functions: * `dispose()` --- Manually disposes the computed observable, clearing all subscriptions to dependencies. This function is useful if you want to stop a computed observable from being updated or want to clean up memory for a computed observable that has dependencies on observables that won't be cleaned. -* `extend(extenders)` --- Applies the given [extenders](extenders.html) to the computed observable. +* `extend(extenders)` --- Applies the given [extenders](../../observables/extenders/) to the computed observable. * `getDependenciesCount()` --- Returns the current number of dependencies of the computed observable. * `getSubscriptionsCount()` --- Returns the current number of subscriptions (either from other computed observables or manual subscriptions) of the computed observable. * `isActive()` --- Returns whether the computed observable may be updated in the future. A computed observable is inactive if it has no dependencies. diff --git a/packages/computed/docs/proxy.md b/tko.io/src/docs/computed/proxy.md similarity index 96% rename from packages/computed/docs/proxy.md rename to tko.io/src/docs/computed/proxy.md index 3aa38c5c7..7806c1303 100644 --- a/packages/computed/docs/proxy.md +++ b/tko.io/src/docs/computed/proxy.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: Proxy +--- + # Proxy Where the [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) object is [supported](https://caniuse.com/#search=Proxy), TKO can wrap objects to make them observable. diff --git a/packages/observable/docs/arraychange.md b/tko.io/src/docs/observables/arraychange.md similarity index 96% rename from packages/observable/docs/arraychange.md rename to tko.io/src/docs/observables/arraychange.md index eaba1b3fe..6841b2d29 100644 --- a/packages/observable/docs/arraychange.md +++ b/tko.io/src/docs/observables/arraychange.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: Arraychange +--- + # Tracking Array Changes diff --git a/packages/observable/docs/extenders.md b/tko.io/src/docs/observables/extenders.md similarity index 98% rename from packages/observable/docs/extenders.md rename to tko.io/src/docs/observables/extenders.md index 9e0935cc5..979f96f28 100644 --- a/packages/observable/docs/extenders.md +++ b/tko.io/src/docs/observables/extenders.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: Extenders +--- + # Observable Extenders diff --git a/packages/observable/docs/observableArrays.md b/tko.io/src/docs/observables/observableArrays.md similarity index 99% rename from packages/observable/docs/observableArrays.md rename to tko.io/src/docs/observables/observableArrays.md index 1c793a552..99466eba6 100644 --- a/packages/observable/docs/observableArrays.md +++ b/tko.io/src/docs/observables/observableArrays.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: ObservableArrays +--- + # Observable Arrays diff --git a/packages/observable/docs/observables.md b/tko.io/src/docs/observables/observables.md similarity index 97% rename from packages/observable/docs/observables.md rename to tko.io/src/docs/observables/observables.md index 0b2359d1b..e4c621090 100644 --- a/packages/observable/docs/observables.md +++ b/tko.io/src/docs/observables/observables.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: Observables +--- + # Observables Overview @@ -142,7 +147,7 @@ Observables implement a variety of functions useful for working in an asynchrono ## Forcing observables to always notify subscribers -When writing to an observable that contains a primitive value (a number, string, boolean, or null), the dependencies of the observable are normally only notified if the value actually changed. However, it is possible to use the built-in `notify` [extender](extenders.html) to ensure that an observable's subscribers are always notified on a write, even if the value is the same. You would apply the extender to an observable like this: +When writing to an observable that contains a primitive value (a number, string, boolean, or null), the dependencies of the observable are normally only notified if the value actually changed. However, it is possible to use the built-in `notify` [extender](../../observables/extenders/) to ensure that an observable's subscribers are always notified on a write, even if the value is the same. You would apply the extender to an observable like this: ```javascript myViewModel.personName.extend({ notify: 'always' }); @@ -150,7 +155,7 @@ myViewModel.personName.extend({ notify: 'always' }); ## Delaying and/or suppressing change notifications -Normally, an observable notifies its subscribers immediately, as soon as it's changed. But if an observable is changed repeatedly or triggers expensive updates, you may get better performance by limiting or delaying the observable's change notifications. This is accomplished using the [`rateLimit` extender](rateLimit-observable.html) like this: +Normally, an observable notifies its subscribers immediately, as soon as it's changed. But if an observable is changed repeatedly or triggers expensive updates, you may get better performance by limiting or delaying the observable's change notifications. This is accomplished using the [`rateLimit` extender](../../observables/rateLimit-observable/) like this: ```javascript // Ensure it notifies about changes no more than once per 50-millisecond period diff --git a/packages/observable/docs/rateLimit-observable.md b/tko.io/src/docs/observables/rateLimit-observable.md similarity index 92% rename from packages/observable/docs/rateLimit-observable.md rename to tko.io/src/docs/observables/rateLimit-observable.md index 16c2ec088..304609f13 100644 --- a/packages/observable/docs/rateLimit-observable.md +++ b/tko.io/src/docs/observables/rateLimit-observable.md @@ -1,11 +1,16 @@ +--- +layout: base.njk +title: RateLimit Observable +--- + # Extender: `rateLimit` *Note: This rate-limit API was added in Knockout 3.1.0. For previous versions, the [`throttle` extender](throttle-extender.html) provides similar functionality.* -Normally, an [observable](observables.html) that is changed notifies its subscribers immediately, so that any computed observables or bindings that depend on the observable are updated synchronously. The `rateLimit` extender, however, causes an observable to suppress and delay change notifications for a specified period of time. A rate-limited observable therefore updates dependencies asynchronously. +Normally, an [observable](../../observables/observables/) that is changed notifies its subscribers immediately, so that any computed observables or bindings that depend on the observable are updated synchronously. The `rateLimit` extender, however, causes an observable to suppress and delay change notifications for a specified period of time. A rate-limited observable therefore updates dependencies asynchronously. -The `rateLimit` extender can be applied to any type of observable, including [observable arrays](observableArrays.html) and [computed observables](computedObservables.html). The main use cases for rate-limiting are: +The `rateLimit` extender can be applied to any type of observable, including [observable arrays](../../observables/observableArrays/) and [computed observables](../../computed/computedObservables/). The main use cases for rate-limiting are: * Making things respond after a certain delay * Combining multiple changes into a single update diff --git a/packages/observable/docs/throttle-extender.md b/tko.io/src/docs/observables/throttle-extender.md similarity index 98% rename from packages/observable/docs/throttle-extender.md rename to tko.io/src/docs/observables/throttle-extender.md index 562631ee5..ed63362d0 100644 --- a/packages/observable/docs/throttle-extender.md +++ b/tko.io/src/docs/observables/throttle-extender.md @@ -1,3 +1,8 @@ +--- +layout: base.njk +title: Throttle Extender +--- + # Throttle extender *Note: This throttle API is deprecated as of Knockout 3.1.0. Please use the [`rateLimit` extender](#rateLimit-observable) for similar functionality.* diff --git a/tko.io/src/index.md b/tko.io/src/index.md new file mode 100644 index 000000000..0278dd9ed --- /dev/null +++ b/tko.io/src/index.md @@ -0,0 +1,87 @@ +--- +layout: base.njk +title: Introduction +--- + +# What is TKO? + +TKO is a Javascript web framework, and the foundation for Knockout 4. + +Knockout helps you create rich, responsive, maintainable applications built on a clean underlying data model. + +- **Simple data-html bindings** + Easily associate DOM elements with model data using a concise, readable syntax, like this: `` +- **Two-way observables** + Data model and DOM stay in sync, updating the UI whenever the data changes. +- **Computed dependencies** + Create chains of calculated variables dependencies. +- **Templating** + Create reusable components and sophisticated web applications. +- **Extensible** + Implement custom behaviors and compartmentalized code. + +TKO has a comprehensive suite of tests that ensure its correct functioning and allow easy verification on different Javascript browsers and platforms. + + +## First Example + +```jsx +const viewModel = { + firstName: ko.observable('John'), + lastName: ko.observable('Doe') +}; + +viewModel.fullName = ko.computed(() => { + return viewModel.firstName() + ' ' + viewModel.lastName(); +}); + +const { node } = ko.jsx.render( +
+

First name:

+

Last name:

+

Hello, !

+
+); + +document.getElementById('root').appendChild(node); + +ko.applyBindings(viewModel); +``` + +## Supported Platforms + +TKO & Knockout should work on all modern browsers, as well as Javascript engines such as Node.js. + +## Getting started + +Include the latest version with this ` +``` + +or install it locally with: + +```bash +npm install tko +# or +yarn add tko +# or +bun add tko +``` + +Clone the code with: + +```bash +git clone git@github.com:knockout/tko +``` + +## Community + +Find Knockout online at: + +- [Gitter knockout/tko](https://gitter.im/knockout/tko) +- [Gitter knockout/knockout](https://gitter.im/knockout/knockout) +- [Reddit /r/knockoutjs](https://www.reddit.com/r/knockoutjs/) +- [Google Groups](https://groups.google.com/forum/#!forum/knockoutjs) +- [StackOverflow [knockout.js]](http://stackoverflow.com/tags/knockout.js/info) diff --git a/tko.io/src/index.pug b/tko.io/src/index.pug deleted file mode 100644 index 50cfa52ca..000000000 --- a/tko.io/src/index.pug +++ /dev/null @@ -1,31 +0,0 @@ -doctype html -html(lang="en") - head - title= "TKO" - meta(charset="UTF-8") - - each link in links - link(rel='stylesheet' href=link.href integrity=link.integrity crossorigin='anonymous') - - each script in scripts - script(src=script.src integrity=script.integrity crossorigin=script.crossorigin type=script.type || "application/javascript" async=script.async) - - style(type='text/css') - | #{styles} - - body - nav.top-bar(data-bind='highlightIfCurrent') - .tko TKO - a(href='/') Introduction - a(href='/3to4') Knockout 3 to 4 Guide - a.external(href='https://github.com/knockout/tko') Github - - nav.sidebar - #toc.toc(data-bind='each: contents') - a(href='#\{{ navId }}' class='nav flex-column' data-bind='template: { nodes: nodes }, class: css, click: click') - - main - each section in sections - .section - .section-title #{section.title} - .section-body !{section.html} diff --git a/tko.io/src/js/examples.js b/tko.io/src/js/examples.js new file mode 100644 index 000000000..f385b20e3 --- /dev/null +++ b/tko.io/src/js/examples.js @@ -0,0 +1,146 @@ +import * as esbuild from 'https://cdn.jsdelivr.net/npm/esbuild-wasm@0.24.0/esm/browser.min.js'; +import { EditorView, basicSetup } from 'https://esm.sh/codemirror@6.0.1'; +import { javascript } from 'https://esm.sh/@codemirror/lang-javascript@6.2.2'; +import { oneDark } from 'https://esm.sh/@codemirror/theme-one-dark@6.1.2'; + +let esbuildInitialized = false; + +async function initEsbuild() { + if (!esbuildInitialized) { + await esbuild.initialize({ + wasmURL: 'https://cdn.jsdelivr.net/npm/esbuild-wasm@0.24.0/esbuild.wasm' + }); + esbuildInitialized = true; + } +} + +async function transformJSX(code) { + try { + await initEsbuild(); + + const result = await esbuild.transform(code, { + loader: 'jsx', + jsx: 'transform', + jsxFactory: 'ko.jsx.createElement', + jsxFragment: 'ko.jsx.Fragment' + }); + return { success: true, code: result.code }; + } catch (error) { + return { success: false, error: error.message }; + } +} + +function createExampleContainer(codeBlock) { + const container = document.createElement('div'); + container.className = 'example-container'; + + // Create editor wrapper + const editorWrapper = document.createElement('div'); + editorWrapper.className = 'example-editor'; + + const iframe = document.createElement('iframe'); + iframe.className = 'example-result'; + + container.appendChild(editorWrapper); + container.appendChild(iframe); + + // Replace the code block with our interactive container + const pre = codeBlock.parentElement; + pre.parentNode.replaceChild(container, pre); + + // Create CodeMirror editor + const initialCode = codeBlock.textContent.trim(); + let timeout; + + const editor = new EditorView({ + doc: initialCode, + extensions: [ + basicSetup, + javascript({ jsx: true }), + oneDark, + EditorView.updateListener.of((update) => { + if (update.docChanged) { + // Re-run on change (debounced) + clearTimeout(timeout); + timeout = setTimeout(() => { + const code = editor.state.doc.toString(); + runExample(code, iframe, container); + }, 500); + } + }) + ], + parent: editorWrapper + }); + + // Run the code initially + runExample(initialCode, iframe, container); +} + +async function runExample(code, iframe, container) { + const result = await transformJSX(code); + + if (result.success) { + // Create a complete HTML document for the iframe + const html = ` + + + + + + +
+ + + + + `; + + // Use srcdoc for better iframe content handling + iframe.srcdoc = html; + + // Remove any error display + const existingError = container.querySelector('.example-error'); + if (existingError) { + existingError.remove(); + } + } else { + // Display error overlaying the preview panel + let errorDiv = container.querySelector('.example-error'); + if (!errorDiv) { + errorDiv = document.createElement('div'); + errorDiv.className = 'example-error'; + container.appendChild(errorDiv); + } + errorDiv.textContent = `Error: ${result.error}`; + } +} + +// Initialize examples when DOM is ready +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', initExamples); +} else { + initExamples(); +} + +function initExamples() { + // Find all code blocks with language 'jsx' + const codeBlocks = document.querySelectorAll('pre code.language-jsx'); + codeBlocks.forEach(createExampleContainer); +} diff --git a/tko.io/src/tko-io.js b/tko.io/src/tko-io.js deleted file mode 100644 index af7c2601d..000000000 --- a/tko.io/src/tko-io.js +++ /dev/null @@ -1,118 +0,0 @@ -const {ko} = window - -const GITHUB_ROOT = 'https://github.com/knockout/tko/blob/master/packages/' -const TITLE_QS = '.section-title, h1, h2' - -const titleNodeMap = new Map() - -ko.options.deferUpdates = true - -const titleObserver = new IntersectionObserver(entries => { - entries.forEach(e => titleNodeMap.get(e.target)(e.isIntersecting)) -}) - - -class Title { - constructor ({element, navIdNumber}) { - const navId = `toc-${navIdNumber}` - const depth = this.getDepth(element) - Object.assign(this, {element, navId, depth}) - element.setAttribute('id', this.navId) - - const viewportObservables = ko.observableArray([]) - - for (const node of this.generateSiblingNodes()) { - const nodeInViewport = ko.observable(false) - if (titleNodeMap.has(node)) { - viewportObservables.push(titleNodeMap.get(node)) - } else { - titleNodeMap.set(node, nodeInViewport) - titleObserver.observe(node) - } - viewportObservables.push(nodeInViewport) - } - - this.inViewport = ko.computed(() => viewportObservables().some(o => o())) - } - - * generateSiblingNodes () { - let atNode = this.element - yield atNode - while (atNode = atNode.nextSibling) { - if (atNode.nodeType !== atNode.ELEMENT_NODE) { continue } - if (this.getDepth(atNode) <= this.depth) { return } - yield atNode - } - } - - getDepth (node) { - if (node.classList.contains('section-title')) { return 0 } - if (node.tagName === 'H1') { return 1 } - if (node.tagName === 'H2') { return 2 } - return 3 - } - - get css () { - const css = { 'in-viewport': this.inViewport } - switch (this.element.tagName) { - case 'DIV': Object.assign(css, { section: true }); break - case 'H2': Object.assign(css, { subheading: true }); break - case 'H1': Object.assign(css, { heading: true }); break - } - return css - } - - get nodes () { - const node = document.createElement('span') - node.innerHTML = this.element.innerHTML - return [node] - } - - click (vm, evt) { - this.element.scrollIntoView({ behavior: 'smooth', block: 'start' }) - return false - } -} - -function * generateTitles () { - let navIdNumber = 0 - for (const element of document.querySelectorAll(TITLE_QS)) { - navIdNumber++ - yield new Title({element, navIdNumber}) - } -} - - -/** - * Rely on some convention to map the source file to its parts / github origin. - */ -ko.bindingHandlers.set({ - source (element) { - const origin = this.value // e.g. "../packages/tko/docs/intro.md" - const link = GITHUB_ROOT + origin - const [pkg, file] = origin.split('/docs/') - - element.classList.add('source') - element.setAttribute('title', `This part of the documentation comes from ${origin} on GitHub/knockout/tko`) - element.innerHTML = - `
- - ${pkg} - - ${file} - ` - }, - - highlightIfCurrent (element) { - for (const anchor of element.querySelectorAll('a[href]')) { - if (anchor.href === location.href) { - anchor.classList.add('current-page') - } - } - } -}) - -window.addEventListener("load", () => { - const contents = ko.observableArray(Array.from(generateTitles())) - ko.applyBindings({ contents }) -}) diff --git a/tko.io/src/tko.css b/tko.io/src/tko.css deleted file mode 100644 index b9fe13435..000000000 --- a/tko.io/src/tko.css +++ /dev/null @@ -1,285 +0,0 @@ -@import url('https://fonts.googleapis.com/css?family=Nunito|Pacifico|Source+Code+Pro'); - -html, -body { - /* Prevent scroll on narrow devices */ - overflow-x: hidden; - font-family: 'Nunito', sans-serif; -} - -body { - display: grid; - margin-top: 75px; - height: calc(100vh - 75px); - - grid-template-columns: minmax(200px, max-content) auto; - grid-template-areas: - 'sidebar main'; -} - -@media screen and (max-width: 991px) { - body { - grid-template-columns: auto; - grid-template-areas: - 'sidebar' - 'main'; - } -} - -a { - color: #590c12; - transition: 0.1s ease-in-out; -} - -a:focus, a:hover, a:active { - color: #8e383c; - cursor: pointer; - text-decoration: none; -} - -main a { - border-bottom: 1px dashed #590c12; -} - -td { - padding: 5px 1em; - border-bottom: 1px solid gray; -} - -th { - padding: 5px 1em; - border-bottom: 1px solid black; -} - - -/* Codepen iFrames */ -iframe { - padding: 0px 1em; -} - - -/* - * TOP - BAR - */ -.top-bar { - width: 100%; - display: grid; - grid-template-columns: auto; - grid-auto-flow: column; - justify-content: center; - grid-column-gap: 24px; - - top: 0; - left: 0; - position: fixed; - z-index: 1200; - padding: 12px; - - background-color: #931d0d; - font-family: Pacifico; -} - -.top-bar a { - border-radius: 12px; - text-align: center; - padding: 0.25em 0.4em; - color: white; - font-size: 1.4rem; - text-shadow: 0 0 5px black; - line-height: 2.4rem; - transition: 0.4s background-color ease-in-out; -} - -.top-bar a:hover { - background-color: #00000080; - text-shadow: 0 0 5px #931d0d, 0 0 10px #931d0d; - transition: 0.4s background-color ease-in-out; -} - -.top-bar .tko { - color: white; - font-size: 1.6rem; - padding: 0.25em 0.4em; - text-shadow: 0 0 5px #efff6c, 0 0 10px #efff6c; -} - -.current-page { - background-color: #00000040; -} - -/** - * SIDE-BAR - */ -.sidebar { - grid-area: sidebar; - - height: calc(100vh - 75px); - /* Scrollable contents if viewport is shorter than content */ - overflow-y: auto; - overflow-x: hidden; - left: 0; - bottom: 0; - z-index: 1000; - padding: 0; - background-color: #efebe9; - border-right: 1px solid #efebe9; - - padding: 4px 0.75em; -} - -.toc { - position: sticky; -} - -.sidebar a { - padding: 1ex 0.25rem; - color: #931d0d; - border-radius: 4px; -} - -.sidebar a:hover { - color: black; - background-color: #FFaFaFB0; - transition: 0.4s background-color ease-in-out; -} - -.sidebar .section { - font-size: 1.2rem; -} - -.sidebar .subheading { - padding: 0.6ex 8px; - font-weight: normal; - margin-left: 1rem; -} - - @keyframes popin { - from { transform: translateX(50%); } - to { transform: translateX(0%); } - } - -.sidebar .in-viewport::after { - position: absolute; - right: -22px; - background-color: #8F3F4F90; - width: 20px; - height: 20px; - border-radius: 12px; - content: ' '; - animation: 0.25s ease-in 0s popin; -} - -/** - * MAIN - */ -main { - grid-area: main; - height: calc(100vh - 75px); - background-color: #fcd4d4; - padding: 16px; - overflow: scroll; -} - -h2, h3, h4 { - margin-top: 1.3em; - margin-bottom: 0.6em; -} - -h2 { - font-weight: 800; -} - -h3, h4, h2 time { - font-weight: 400; -} - -h1 { - margin-top: 1.5em; -} - -h1 code { - background-color: transparent; - border: 3px solid #E8D8D8; - font-size: inherit; -} - -/** - * CODE - */ - -pre { - font-family: 'Source Code Pro', monospace; - background-color: #0a0909; - padding: 1ex 1em; - margin-left: 1em; - border-radius: 1px; - border: 1px black inset; -} - -code { - background-color: #080707; - color: #e6c07b; - font-size: 0.9rem; -} - -main code { - font-family: 'Source Code Pro', monospace; -} - -code, td code { - white-space: nowrap; - padding: 2px 8px; -} - -pre code { - color: #e6c07b; - white-space: pre; /* We want newlines to be newlines in code blocks */ -} - -/** - * - * TITLES - * - */ - -.section-title { - font-size: 3rem; - font-weight: bold; -} - - - - - -/** - * Source linking - */ -.source { - display: block; - text-align: right; - font-size: 0.9rem; - position: sticky; - top: 0px; -} - -.source a { - padding: 2px 0.62em; - background-color: #E8D8D8; - border: 1px solid gray; -} - -/** - * - * BOOKS - * - */ -.book-grid { - display: grid; - grid-template-columns: repeat(auto-fit, 250px); - grid-gap: 10px; - justify-content: space-around; -} - -.book-grid .card { - width: 250px; -} diff --git a/tko.io/yarn.lock b/tko.io/yarn.lock deleted file mode 100644 index 999ef5924..000000000 --- a/tko.io/yarn.lock +++ /dev/null @@ -1,698 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/helper-string-parser@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c" - -"@babel/helper-validator-identifier@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" - -"@babel/parser@^7.6.0", "@babel/parser@^7.9.6": - version "7.26.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.3.tgz#8c51c5db6ddf08134af1ddbacf16aaab48bac234" - dependencies: - "@babel/types" "^7.26.3" - -"@babel/types@^7.26.3", "@babel/types@^7.6.1", "@babel/types@^7.9.6": - version "7.26.3" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.3.tgz#37e79830f04c2b5687acc77db97fbc75fb81f3c0" - dependencies: - "@babel/helper-string-parser" "^7.25.9" - "@babel/helper-validator-identifier" "^7.25.9" - -acorn@^7.1.1: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - -anymatch@^1.3.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a" - dependencies: - micromatch "^2.1.5" - normalize-path "^2.0.0" - -argparse@^1.0.7: - version "1.0.9" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" - dependencies: - sprintf-js "~1.0.2" - -arr-diff@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" - dependencies: - arr-flatten "^1.0.1" - -arr-flatten@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - -array-unique@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" - -asap@~2.0.3: - version "2.0.6" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - -assert-never@^1.2.1: - version "1.4.0" - resolved "https://registry.yarnpkg.com/assert-never/-/assert-never-1.4.0.tgz#b0d4988628c87f35eb94716cc54422a63927e175" - -async-each@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" - -babel-walk@3.0.0-canary-5: - version "3.0.0-canary-5" - resolved "https://registry.yarnpkg.com/babel-walk/-/babel-walk-3.0.0-canary-5.tgz#f66ecd7298357aee44955f235a6ef54219104b11" - dependencies: - "@babel/types" "^7.9.6" - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - -binary-extensions@^1.0.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.10.0.tgz#9aeb9a6c5e88638aad171e167f5900abe24835d0" - -bindings@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - dependencies: - file-uri-to-path "1.0.0" - -brace-expansion@^1.1.7: - version "1.1.8" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^1.8.2: - version "1.8.5" - resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" - dependencies: - expand-range "^1.8.1" - preserve "^0.2.0" - repeat-element "^1.1.2" - -character-parser@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/character-parser/-/character-parser-2.2.0.tgz#c7ce28f36d4bcd9744e5ffc2c5fcde1c73261fc0" - dependencies: - is-regex "^1.0.3" - -chokidar@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" - dependencies: - anymatch "^1.3.0" - async-each "^1.0.0" - glob-parent "^2.0.0" - inherits "^2.0.1" - is-binary-path "^1.0.0" - is-glob "^2.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.0.0" - optionalDependencies: - fsevents "^1.0.0" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - -constantinople@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/constantinople/-/constantinople-4.0.1.tgz#0def113fa0e4dc8de83331a5cf79c8b325213151" - dependencies: - "@babel/parser" "^7.6.0" - "@babel/types" "^7.6.1" - -core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - -doctypes@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/doctypes/-/doctypes-1.1.0.tgz#ea80b106a87538774e8a3a4a5afe293de489e0a9" - -entities@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" - -esprima@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" - -expand-brackets@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" - dependencies: - is-posix-bracket "^0.1.0" - -expand-range@^1.8.1: - version "1.8.2" - resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" - dependencies: - fill-range "^2.1.0" - -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - dependencies: - is-extendable "^0.1.0" - -extglob@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" - dependencies: - is-extglob "^1.0.0" - -file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - -filename-regex@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" - -fill-range@^2.1.0: - version "2.2.3" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" - dependencies: - is-number "^2.1.0" - isobject "^2.0.0" - randomatic "^1.1.3" - repeat-element "^1.1.2" - repeat-string "^1.5.2" - -for-in@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - -for-own@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" - dependencies: - for-in "^1.0.1" - -fs-extra@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.2.tgz#f91704c53d1b461f893452b0c307d9997647ab6b" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fsevents@^1.0.0: - version "1.2.13" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" - dependencies: - bindings "^1.5.0" - nan "^2.12.1" - -function-bind@^1.0.2: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - -function-bind@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" - -glob-base@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" - dependencies: - glob-parent "^2.0.0" - is-glob "^2.0.0" - -glob-parent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" - dependencies: - is-glob "^2.0.0" - -graceful-fs@^4.1.2, graceful-fs@^4.1.6: - version "4.1.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" - -gray-matter@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/gray-matter/-/gray-matter-3.1.1.tgz#101f80d9e69eeca6765cdce437705b18f40876ac" - dependencies: - extend-shallow "^2.0.1" - js-yaml "^3.10.0" - kind-of "^5.0.2" - strip-bom-string "^1.0.0" - -has@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" - dependencies: - function-bind "^1.0.2" - -hasown@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" - dependencies: - function-bind "^1.1.2" - -highlight.js@^9.12.0: - version "9.12.0" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.12.0.tgz#e6d9dbe57cbefe60751f02af336195870c90c01e" - -inherits@^2.0.1, inherits@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - -is-binary-path@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" - dependencies: - binary-extensions "^1.0.0" - -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - -is-core-module@^2.16.0: - version "2.16.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" - dependencies: - hasown "^2.0.2" - -is-dotfile@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" - -is-equal-shallow@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" - dependencies: - is-primitive "^2.0.0" - -is-expression@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-expression/-/is-expression-4.0.0.tgz#c33155962abf21d0afd2552514d67d2ec16fd2ab" - dependencies: - acorn "^7.1.1" - object-assign "^4.1.1" - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - -is-extglob@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" - -is-glob@^2.0.0, is-glob@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" - dependencies: - is-extglob "^1.0.0" - -is-number@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" - dependencies: - kind-of "^3.0.2" - -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - dependencies: - kind-of "^3.0.2" - -is-posix-bracket@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" - -is-primitive@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" - -is-promise@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" - -is-regex@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" - dependencies: - has "^1.0.1" - -isarray@1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - dependencies: - isarray "1.0.0" - -js-stringify@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/js-stringify/-/js-stringify-1.0.2.tgz#1736fddfd9724f28a3682adc6230ae7e4e9679db" - -js-yaml@^3.10.0: - version "3.10.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - optionalDependencies: - graceful-fs "^4.1.6" - -jstransformer@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/jstransformer/-/jstransformer-1.0.0.tgz#ed8bf0921e2f3f1ed4d5c1a44f68709ed24722c3" - dependencies: - is-promise "^2.0.0" - promise "^7.0.1" - -kind-of@^3.0.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - dependencies: - is-buffer "^1.1.5" - -kind-of@^5.0.2: - version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - -linkify-it@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" - dependencies: - uc.micro "^1.0.1" - -lodash.debounce@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" - -markdown-it@^8.4.0: - version "8.4.0" - resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.0.tgz#e2400881bf171f7018ed1bd9da441dac8af6306d" - dependencies: - argparse "^1.0.7" - entities "~1.1.1" - linkify-it "^2.0.0" - mdurl "^1.0.1" - uc.micro "^1.0.3" - -mdurl@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" - -micromatch@^2.1.5: - version "2.3.11" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" - dependencies: - arr-diff "^2.0.0" - array-unique "^0.2.1" - braces "^1.8.2" - expand-brackets "^0.1.4" - extglob "^0.3.1" - filename-regex "^2.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.1" - kind-of "^3.0.2" - normalize-path "^2.0.1" - object.omit "^2.0.0" - parse-glob "^3.0.4" - regex-cache "^0.4.2" - -minimatch@^3.0.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - dependencies: - brace-expansion "^1.1.7" - -nan@^2.12.1: - version "2.22.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.22.0.tgz#31bc433fc33213c97bad36404bb68063de604de3" - -normalize-path@^2.0.0, normalize-path@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - dependencies: - remove-trailing-separator "^1.0.1" - -object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - -object.omit@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" - dependencies: - for-own "^0.1.4" - is-extendable "^0.1.1" - -parse-glob@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" - dependencies: - glob-base "^0.3.0" - is-dotfile "^1.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.0" - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - -path-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - -preserve@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" - -process-nextick-args@~1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" - -promise@^7.0.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" - dependencies: - asap "~2.0.3" - -pug-attrs@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pug-attrs/-/pug-attrs-3.0.0.tgz#b10451e0348165e31fad1cc23ebddd9dc7347c41" - dependencies: - constantinople "^4.0.1" - js-stringify "^1.0.2" - pug-runtime "^3.0.0" - -pug-code-gen@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/pug-code-gen/-/pug-code-gen-3.0.3.tgz#58133178cb423fe1716aece1c1da392a75251520" - dependencies: - constantinople "^4.0.1" - doctypes "^1.1.0" - js-stringify "^1.0.2" - pug-attrs "^3.0.0" - pug-error "^2.1.0" - pug-runtime "^3.0.1" - void-elements "^3.1.0" - with "^7.0.0" - -pug-error@^2.0.0, pug-error@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/pug-error/-/pug-error-2.1.0.tgz#17ea37b587b6443d4b8f148374ec27b54b406e55" - -pug-filters@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/pug-filters/-/pug-filters-4.0.0.tgz#d3e49af5ba8472e9b7a66d980e707ce9d2cc9b5e" - dependencies: - constantinople "^4.0.1" - jstransformer "1.0.0" - pug-error "^2.0.0" - pug-walk "^2.0.0" - resolve "^1.15.1" - -pug-lexer@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/pug-lexer/-/pug-lexer-5.0.1.tgz#ae44628c5bef9b190b665683b288ca9024b8b0d5" - dependencies: - character-parser "^2.2.0" - is-expression "^4.0.0" - pug-error "^2.0.0" - -pug-linker@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/pug-linker/-/pug-linker-4.0.0.tgz#12cbc0594fc5a3e06b9fc59e6f93c146962a7708" - dependencies: - pug-error "^2.0.0" - pug-walk "^2.0.0" - -pug-load@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pug-load/-/pug-load-3.0.0.tgz#9fd9cda52202b08adb11d25681fb9f34bd41b662" - dependencies: - object-assign "^4.1.1" - pug-walk "^2.0.0" - -pug-parser@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/pug-parser/-/pug-parser-6.0.0.tgz#a8fdc035863a95b2c1dc5ebf4ecf80b4e76a1260" - dependencies: - pug-error "^2.0.0" - token-stream "1.0.0" - -pug-runtime@^3.0.0, pug-runtime@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/pug-runtime/-/pug-runtime-3.0.1.tgz#f636976204723f35a8c5f6fad6acda2a191b83d7" - -pug-strip-comments@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz#f94b07fd6b495523330f490a7f554b4ff876303e" - dependencies: - pug-error "^2.0.0" - -pug-walk@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/pug-walk/-/pug-walk-2.0.0.tgz#417aabc29232bb4499b5b5069a2b2d2a24d5f5fe" - -pug@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/pug/-/pug-3.0.3.tgz#e18324a314cd022883b1e0372b8af3a1a99f7597" - dependencies: - pug-code-gen "^3.0.3" - pug-filters "^4.0.0" - pug-lexer "^5.0.1" - pug-linker "^4.0.0" - pug-load "^3.0.0" - pug-parser "^6.0.0" - pug-runtime "^3.0.1" - pug-strip-comments "^2.0.0" - -randomatic@^1.1.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - -readable-stream@^2.0.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - safe-buffer "~5.1.1" - string_decoder "~1.0.3" - util-deprecate "~1.0.1" - -readdirp@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" - dependencies: - graceful-fs "^4.1.2" - minimatch "^3.0.2" - readable-stream "^2.0.2" - set-immediate-shim "^1.0.1" - -regex-cache@^0.4.2: - version "0.4.4" - resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" - dependencies: - is-equal-shallow "^0.1.3" - -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - -repeat-element@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" - -repeat-string@^1.5.2: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - -resolve@^1.15.1: - version "1.22.10" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" - dependencies: - is-core-module "^2.16.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" - -set-immediate-shim@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - -string_decoder@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" - dependencies: - safe-buffer "~5.1.0" - -strip-bom-string@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92" - -supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" - -token-stream@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/token-stream/-/token-stream-1.0.0.tgz#cc200eab2613f4166d27ff9afc7ca56d49df6eb4" - -uc.micro@^1.0.1, uc.micro@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" - -universalify@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7" - -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - -void-elements@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09" - -with@^7.0.0: - version "7.0.2" - resolved "https://registry.yarnpkg.com/with/-/with-7.0.2.tgz#ccee3ad542d25538a7a7a80aad212b9828495bac" - dependencies: - "@babel/parser" "^7.9.6" - "@babel/types" "^7.9.6" - assert-never "^1.2.1" - babel-walk "3.0.0-canary-5"