diff options
| author | (quasar) nebula <qznebula@protonmail.com> | 2025-10-23 18:13:05 -0300 |
|---|---|---|
| committer | (quasar) nebula <qznebula@protonmail.com> | 2025-10-23 18:19:16 -0300 |
| commit | 91214d3e8482e3128f1c7a2d6da240ef0413a59d (patch) | |
| tree | 05f904e761ec42e9b40f3068a563f9f0d75bc8c3 /src | |
| parent | f41f72314b32fd62d940631a310b573d41fd346f (diff) | |
html, infra: html.inside(), html.findInside()
Ooooo
Diffstat (limited to 'src')
| -rw-r--r-- | src/content-function.js | 16 | ||||
| -rw-r--r-- | src/html.js | 126 |
2 files changed, 137 insertions, 5 deletions
diff --git a/src/content-function.js b/src/content-function.js index e141a686..04f2ce90 100644 --- a/src/content-function.js +++ b/src/content-function.js @@ -2,7 +2,7 @@ import {inspect as nodeInspect} from 'node:util'; import {decorateError} from '#aggregate'; import {colors, decorateTime, ENABLE_COLOR} from '#cli'; -import {Template} from '#html'; +import {Tag, Template} from '#html'; import {empty} from '#sugar'; function inspect(value, opts = {}) { @@ -103,6 +103,20 @@ function prepareWorkingGenerateFunction(spec, boundExtraDependencies) { } }; + generate = (baseGenerate => (...args) => { + const result = baseGenerate(...args); + + if (result instanceof Template || result instanceof Tag) { + if (Object.hasOwn(result, Symbol.for('hsmusic.content.via'))) { + result[Symbol.for('hsmusic.contentFunction.via')].push(dependency); + } else { + result[Symbol.for('hsmusic.contentFunction.via')] = [dependency]; + } + } + + return result; + })(generate); + generate = optionalDecorateTime(`generate`, dependency, generate); if (spec.slots) { diff --git a/src/html.js b/src/html.js index 444edd6a..4cac9525 100644 --- a/src/html.js +++ b/src/html.js @@ -1698,6 +1698,61 @@ export function smooth(smoothie) { return tags(helper(smoothie)); } +export function inside(insidee) { + if (insidee instanceof Template) { + return inside(Template.resolve(insidee)); + } + + if (insidee instanceof Tag) { + return Array.from(smooth(tags(insidee.content)).content); + } + + return []; +} + +export function findInside(insidee, query) { + if (typeof query === 'object' && query.slots) { + return findInside(insidee, item => + Template.resolveForSlots(item, query.slots, 'null')); + } + + if (typeof query === 'object' && query.annotation) { + return findInside(insidee, item => + Template.resolveForAnnotation(item, query.annotation, 'null')); + } + + if (typeof query === 'object' && query.tag) { + return findInside(insidee, item => { + const tag = normalize(item); + if (tag.tagName === query) { + return tag; + } else { + return null; + } + }); + } + + if (typeof query === 'string') { + return findInside(insidee, item => + Template.resolveForContentFunction(item, query, 'null')); + } + + if (typeof query !== 'function') { + throw new Error(`Expected {slots}, {annotation}, or query function`); + } + + for (const item of inside(insidee)) { + const result = query(item); + if (result && result === true) { + return item; + } else if (result) { + return result; + } + } + + return null; +} + export function template(description) { return new Template(description); } @@ -2109,7 +2164,7 @@ export class Template { return content; } - static resolveForSlots(content, slots) { + static resolveForSlots(content, slots, without = 'throw') { if (!slots || typeof slots !== 'object') { throw new Error( `Expected slots to be an object or array, ` + @@ -2132,9 +2187,72 @@ export class Template { } } - throw new Error( - `Didn't find slots ${inspect(slots, {compact: true})} ` + - `resolving ${inspect(content, {compact: true})}`); + if (without === 'throw') { + throw new Error( + `Didn't find slots ${inspect(slots, {compact: true})} ` + + `resolving ${inspect(content, {compact: true})}`); + } else { + return null; + } + } + + static resolveForAnnotation(content, annotation, without = 'throw') { + if (!annotation || typeof annotation !== 'string') { + throw new Error( + `Expected annotation to be a string, ` + + `got ${typeAppearance(annotation)}`); + } + + while (content instanceof Template) { + if (content.description.annotation === annotation) { + return content; + } else { + content = content.content; + } + } + + if (without === 'throw') { + throw new Error( + `Didn't find annotation ${inspect(annotation, {compact: true})} ` + + `resolving ${inspect(content, {compact: true})}`); + } else { + return null; + } + } + + static resolveForContentFunction(content, dependency, without = 'throw') { + if (!dependency || typeof dependency !== 'string') { + throw new Error( + `Expected dependency to be a string, ` + + `got ${typeAppearance(dependency)}`); + } + + const considerContentFunction = () => + (content instanceof Tag || content instanceof Template) && + Object.hasOwn(content, Symbol.for('hsmusic.contentFunction.via')) && + content[Symbol.for('hsmusic.contentFunction.via')].includes(dependency); + + while (content instanceof Template) { + if (considerContentFunction()) { + return content; + } else if (content.description.annotation === dependency) { + return content; + } else { + content = content.content; + } + } + + if (considerContentFunction()) { + return content; + } + + if (without === 'throw') { + throw new Error( + `Didn't find dependency ${inspect(dependency, {compact: true})} ` + + `resolving ${inspect(content, {compact: true})}`); + } else { + return null; + } } [inspect.custom]() { |