From 3c05b4cc72d443fe22f94f22f4c9f85d41a0e04f Mon Sep 17 00:00:00 2001 From: Hans Fast Date: Wed, 11 Mar 2026 14:58:31 +0100 Subject: [PATCH] initial: working demo --- .gitignore | 1 + README.md | 47 +++++++ css/style.css | 5 + getLinkedFilesFromHtml.js | 19 +++ images/bird.webp | Bin 0 -> 5458 bytes images/cat.webp | Bin 0 -> 5132 bytes images/monkey.webp | Bin 0 -> 3044 bytes linked-image.html | 18 +++ linked-stylesheet.html | 19 +++ package-lock.json | 283 ++++++++++++++++++++++++++++++++++++++ package.json | 17 +++ page.ori.html | 17 +++ pathsToObjs.js | 36 +++++ site.ori | 26 ++++ 14 files changed, 488 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 css/style.css create mode 100644 getLinkedFilesFromHtml.js create mode 100644 images/bird.webp create mode 100644 images/cat.webp create mode 100644 images/monkey.webp create mode 100644 linked-image.html create mode 100644 linked-stylesheet.html create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 page.ori.html create mode 100644 pathsToObjs.js create mode 100644 site.ori diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/README.md b/README.md new file mode 100644 index 0000000..6ae5bb2 --- /dev/null +++ b/README.md @@ -0,0 +1,47 @@ +# Find linked Files in HTML and Include Them in Build Output + +`getLinkedFilesFromHtml.js` parses html input to an [abstract syntax tree](https://github.com/syntax-tree/hast) and extracts the `href`/`src` attributes from `link` and `img` nodes. + +We now have a list of slash-separated paths as strings. + +``` +[ + 'css/style.css', + 'about/bird.webp', + 'about/monkey.webp' +] + +``` + +But Origami doesn't work with paths, it works with trees. So to get Origami to copy the files' contents for us, we need a nested tree that Origami can traverse. + + +``` +{ + images: { + 'bird.webp': (binary image data), + 'monkey.webp': (binary image data), + }, + css: { + 'style.css': 'body { font-family: ...}' + } +} + +``` + +So `pathsToObjs.js` creates such an object from the slash-separated paths. + +The resulting object can be applied as a [mask](https://weborigami.org/builtins/tree/mask) to the tree of all files in the source directory. The result is a tree with only the files which the html files link to. We include the contents of this tree in the final top-level tree. + +## Demo +This file and the following two linked pages all reference `css/style.css`. The two pages also each reference an image from the `image/` directory. + +* [linked-image](linked-image.html) +* [linked-stylesheet](linked-stylesheet.html) + +Here's the full `site.ori` defining the files to copy to the output. + + +``` +${site.ori} +``` diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..704d0b0 --- /dev/null +++ b/css/style.css @@ -0,0 +1,5 @@ +body { + font-family: "Jost*", sans-serif; + max-width: 60ch; + margin: 0 auto; +} diff --git a/getLinkedFilesFromHtml.js b/getLinkedFilesFromHtml.js new file mode 100644 index 0000000..97ae245 --- /dev/null +++ b/getLinkedFilesFromHtml.js @@ -0,0 +1,19 @@ +import {fromHtml} from 'hast-util-from-html'; +import {visit} from 'unist-util-visit'; + +export default async function(value) { + const tree = fromHtml(value); + const links = []; + + //take tree; + //visit nodes matching one of the test patterns; + //apply function to those nodes. + visit(tree, [ + {tagName: 'link'}, + {tagName: 'img'} + ], function(node) { + links.push(node); + }) + + return links.map(link => link.properties.href || link.properties.src) +} diff --git a/images/bird.webp b/images/bird.webp new file mode 100644 index 0000000000000000000000000000000000000000..6db86aa3e7501e591918ea6f4b8ccef7f7cb91c7 GIT binary patch literal 5458 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 I{uSW?05{9U2mk;8 literal 0 HcmV?d00001 diff --git a/images/cat.webp b/images/cat.webp new file mode 100644 index 0000000000000000000000000000000000000000..1060f43f1ea8864954dd4a73d6d2ec863086730f GIT binary patch literal 5132 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 literal 0 HcmV?d00001 diff --git a/images/monkey.webp b/images/monkey.webp new file mode 100644 index 0000000000000000000000000000000000000000..b69b32fcdd56768e7b507ad8dbbb8c6bae244fc5 GIT binary patch literal 3044 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 literal 0 HcmV?d00001 diff --git a/linked-image.html b/linked-image.html new file mode 100644 index 0000000..a1a96aa --- /dev/null +++ b/linked-image.html @@ -0,0 +1,18 @@ + + + + + + Copying Linked Image + + + +

Copying Linked Stylesheet

+

Find the files.

+

The image below appears if the mechanism we're testing found the img tag and managed to resolve it's src attribute.

+ origami bird + +

But if you look in the images/ directory, you won't see cat.webp even though it's in the source tree, because that file isn't linked to from any of the html pages.

+ + + diff --git a/linked-stylesheet.html b/linked-stylesheet.html new file mode 100644 index 0000000..ec202a5 --- /dev/null +++ b/linked-stylesheet.html @@ -0,0 +1,19 @@ + + + + + + Copying Linked Stylesheet + + + +

Copying Linked Stylesheet

+

Find the files.

+

This link to the Stylesheet will only work if the mechanism we're testing found the link in this page's head. + +

Just for fun, this file also links to an image:

+ a friendly origami monkey + + + + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..f55195d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,283 @@ +{ + "name": "ori-include-linked-paths", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ori-include-linked-paths", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "hast-util-from-html": "^2.0.3", + "unist-util-visit": "^5.1.0" + } + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/hast-util-from-html": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", + "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "devlop": "^1.1.0", + "hast-util-from-parse5": "^8.0.0", + "parse5": "^7.0.0", + "vfile": "^6.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-from-parse5": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", + "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "hastscript": "^9.0.0", + "property-information": "^7.0.0", + "vfile": "^6.0.0", + "vfile-location": "^5.0.0", + "web-namespaces": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-location": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..b329fa0 --- /dev/null +++ b/package.json @@ -0,0 +1,17 @@ +{ + "name": "ori-include-linked-paths", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "module", + "dependencies": { + "hast-util-from-html": "^2.0.3", + "unist-util-visit": "^5.1.0" + } +} diff --git a/page.ori.html b/page.ori.html new file mode 100644 index 0000000..9fb9dc6 --- /dev/null +++ b/page.ori.html @@ -0,0 +1,17 @@ +--- +(body) => _template() +--- + + + + + + + README + + + + ${body} + + + diff --git a/pathsToObjs.js b/pathsToObjs.js new file mode 100644 index 0000000..c48d471 --- /dev/null +++ b/pathsToObjs.js @@ -0,0 +1,36 @@ +// Original source - https://stackoverflow.com/a/44681235 +// Posted by le_m +// Retrieved 2026-03-11, License - CC BY-SA 3.0 +// Insert path into directory tree structure: +// +//modified to construct an object instead of an array. + +function insert(tree = {}, [head, ...tail]) { + + if (tail.length > 0) { + tree[head] = insert(tree[head], tail) + } else { + tree[head] = true + } + + return tree; +} + +// Example: +let examplepaths = [ + 'css/style.css', + 'about/bird.svg', +]; + +//naive! assumes relative path like in example. +//A more robust implementation would need to resolve paths first, but to what. +export default function process(paths) { + return paths + .map(path => path.split('/') + //.slice(1) //if path starts with / or ./ + ) + .reduce((tree, path) => insert(tree, path), {}); +} + +//test: +// console.log(process(examplepaths)); diff --git a/site.ori b/site.ori new file mode 100644 index 0000000..6797bbf --- /dev/null +++ b/site.ori @@ -0,0 +1,26 @@ +{ + + (pages): { + ./linked-image.html + ./linked-stylesheet.html + } + ...pages/ + + /* + spread the final result of this closure into the parent tree. + */ + ...{ + hast = Tree.map(pages, getLinkedFilesFromHtml.js) + //the [...new Set()] construct filters out duplicates + links: Tree.flat(hast, 2) → (a) => [...new Set(a)] + + //linksAsTree is a nested object representation of the paths. + //can use that object as a mask on all to get a 'filtered' tree. + linksAsTree: pathsToObjs.js(links) + onlyLinkedFiles: Tree.mask(<.>, linksAsTree) + }.onlyLinkedFiles + + index.html: page.ori.html(Origami.mdHtml(Origami.inline(README.md))) + +} +