@jini-ai/cms 0.5.2 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/README.md +14 -8
- package/dist/comments/errors.d.ts +23 -0
- package/dist/comments/errors.js +25 -0
- package/dist/comments/express/index.d.ts +2 -0
- package/dist/comments/express/index.js +2 -0
- package/dist/comments/express/submit-handler.d.ts +30 -0
- package/dist/comments/express/submit-handler.js +85 -0
- package/dist/comments/hooks.d.ts +39 -0
- package/dist/comments/hooks.js +41 -0
- package/dist/comments/index.d.ts +11 -0
- package/dist/comments/index.js +11 -0
- package/dist/comments/ingress.d.ts +57 -0
- package/dist/comments/ingress.js +173 -0
- package/dist/comments/module.d.ts +94 -0
- package/dist/comments/module.js +73 -0
- package/dist/comments/ports.d.ts +184 -0
- package/dist/comments/ports.js +2 -0
- package/dist/comments/repo.memory.d.ts +70 -0
- package/dist/comments/repo.memory.js +120 -0
- package/dist/comments/sanitize.d.ts +15 -0
- package/dist/comments/sanitize.js +31 -0
- package/dist/comments/spam.heuristic.d.ts +8 -0
- package/dist/comments/spam.heuristic.js +54 -0
- package/dist/comments/sql/index.d.ts +3 -0
- package/dist/comments/sql/index.js +3 -0
- package/dist/comments/sql/repo.d.ts +77 -0
- package/dist/comments/sql/repo.js +190 -0
- package/dist/comments/sql/repo.rows.d.ts +49 -0
- package/dist/comments/sql/repo.rows.js +71 -0
- package/dist/comments/types.d.ts +187 -0
- package/dist/comments/types.js +39 -0
- package/dist/comments/write-service.d.ts +121 -0
- package/dist/comments/write-service.js +144 -0
- package/dist/core/commands/command.d.ts +2 -9
- package/dist/core/commands/command.js +2 -9
- package/dist/core/index.d.ts +2 -1
- package/dist/core/index.js +1 -0
- package/dist/core/keyset-cursor.d.ts +25 -0
- package/dist/core/keyset-cursor.js +20 -0
- package/dist/core/ports.d.ts +30 -0
- package/dist/core/ports.js +0 -1
- package/dist/core/tools/args.d.ts +1 -46
- package/dist/core/tools/args.js +1 -44
- package/dist/forms/delete-submission.d.ts +38 -0
- package/dist/forms/delete-submission.js +25 -0
- package/dist/forms/duplicate-slug.d.ts +81 -0
- package/dist/forms/duplicate-slug.js +115 -0
- package/dist/forms/errors.d.ts +53 -0
- package/dist/forms/errors.js +25 -0
- package/dist/forms/express/handler.d.ts +59 -0
- package/dist/forms/express/handler.js +217 -0
- package/dist/forms/express/index.d.ts +2 -0
- package/dist/forms/express/index.js +2 -0
- package/dist/forms/fields-json.d.ts +14 -0
- package/dist/forms/fields-json.js +11 -0
- package/dist/forms/forms.d.ts +59 -0
- package/dist/forms/forms.js +213 -0
- package/dist/forms/html/authoring-adapter.d.ts +34 -0
- package/dist/forms/html/authoring-adapter.js +48 -0
- package/dist/forms/html/html-authoring.d.ts +12 -0
- package/dist/forms/html/html-authoring.js +133 -0
- package/dist/forms/html/html-submission-adapter.d.ts +10 -0
- package/dist/forms/html/html-submission-adapter.js +15 -0
- package/dist/forms/html/index.d.ts +4 -0
- package/dist/forms/html/index.js +4 -0
- package/dist/forms/html-render.d.ts +33 -0
- package/dist/forms/html-render.js +31 -0
- package/dist/forms/index.d.ts +17 -0
- package/dist/forms/index.js +17 -0
- package/dist/forms/notify-subscriber.d.ts +32 -0
- package/dist/forms/notify-subscriber.js +60 -0
- package/dist/forms/ports.d.ts +168 -0
- package/dist/forms/ports.js +2 -0
- package/dist/forms/rate-limit-key.d.ts +8 -0
- package/dist/forms/rate-limit-key.js +7 -0
- package/dist/forms/repo.memory.d.ts +120 -0
- package/dist/forms/repo.memory.js +188 -0
- package/dist/forms/sql/index.d.ts +5 -0
- package/dist/forms/sql/index.js +5 -0
- package/dist/forms/sql/repo.d.ts +94 -0
- package/dist/forms/sql/repo.js +175 -0
- package/dist/forms/sql/repo.rows.d.ts +33 -0
- package/dist/forms/sql/repo.rows.js +64 -0
- package/dist/forms/sql/submission-ip-retention-repo.d.ts +9 -0
- package/dist/forms/sql/submission-ip-retention-repo.js +40 -0
- package/dist/forms/sql/tables.d.ts +32 -0
- package/dist/forms/sql/tables.js +2 -0
- package/dist/forms/submission-attempts.d.ts +70 -0
- package/dist/forms/submission-attempts.js +70 -0
- package/dist/forms/submission-email-validation.d.ts +8 -0
- package/dist/forms/submission-email-validation.js +34 -0
- package/dist/forms/submission-ip-retention.d.ts +30 -0
- package/dist/forms/submission-ip-retention.js +27 -0
- package/dist/forms/submit-service.d.ts +78 -0
- package/dist/forms/submit-service.js +109 -0
- package/dist/forms/types.d.ts +49 -0
- package/dist/forms/types.js +2 -0
- package/dist/forms/write-service.d.ts +83 -0
- package/dist/forms/write-service.js +271 -0
- package/dist/media/index.d.ts +0 -3
- package/dist/media/index.js +1 -4
- package/dist/media/node.d.ts +5 -0
- package/dist/media/node.js +6 -0
- package/dist/redirects/capture.d.ts +80 -0
- package/dist/redirects/capture.js +66 -0
- package/dist/redirects/express/index.d.ts +27 -0
- package/dist/redirects/express/index.js +40 -0
- package/dist/redirects/hit-sink.d.ts +56 -0
- package/dist/redirects/hit-sink.js +44 -0
- package/dist/redirects/host-config/index.d.ts +40 -0
- package/dist/redirects/host-config/index.js +145 -0
- package/dist/redirects/index.d.ts +14 -0
- package/dist/redirects/index.js +14 -0
- package/dist/redirects/matcher.d.ts +58 -0
- package/dist/redirects/matcher.js +144 -0
- package/dist/redirects/order.d.ts +30 -0
- package/dist/redirects/order.js +26 -0
- package/dist/redirects/ports.d.ts +242 -0
- package/dist/redirects/ports.internal.d.ts +57 -0
- package/dist/redirects/ports.internal.js +14 -0
- package/dist/redirects/ports.js +2 -0
- package/dist/redirects/redirects.d.ts +226 -0
- package/dist/redirects/redirects.js +590 -0
- package/dist/redirects/referrer-alias.d.ts +31 -0
- package/dist/redirects/referrer-alias.js +33 -0
- package/dist/redirects/repo.memory.d.ts +51 -0
- package/dist/redirects/repo.memory.js +98 -0
- package/dist/redirects/reserved-destination.d.ts +58 -0
- package/dist/redirects/reserved-destination.js +59 -0
- package/dist/redirects/resolver.d.ts +100 -0
- package/dist/redirects/resolver.js +87 -0
- package/dist/redirects/spa/index.d.ts +30 -0
- package/dist/redirects/spa/index.js +27 -0
- package/dist/redirects/sql/index.d.ts +4 -0
- package/dist/redirects/sql/index.js +4 -0
- package/dist/redirects/sql/repo.d.ts +82 -0
- package/dist/redirects/sql/repo.js +143 -0
- package/dist/redirects/sql/repo.rows.d.ts +49 -0
- package/dist/redirects/sql/repo.rows.js +79 -0
- package/dist/redirects/sql/row-types.d.ts +34 -0
- package/dist/redirects/sql/row-types.js +2 -0
- package/dist/redirects/target-gate.d.ts +30 -0
- package/dist/redirects/target-gate.js +85 -0
- package/dist/redirects/types.d.ts +213 -0
- package/dist/redirects/types.js +42 -0
- package/dist/seo/absolute-url.d.ts +58 -0
- package/dist/seo/absolute-url.js +117 -0
- package/dist/seo/dom/index.d.ts +14 -0
- package/dist/seo/dom/index.js +52 -0
- package/dist/seo/errors.d.ts +35 -0
- package/dist/seo/errors.js +35 -0
- package/dist/seo/feed.d.ts +49 -0
- package/dist/seo/feed.js +61 -0
- package/dist/seo/index.d.ts +13 -0
- package/dist/seo/index.js +13 -0
- package/dist/seo/media.d.ts +57 -0
- package/dist/seo/media.js +134 -0
- package/dist/seo/page-head.d.ts +18 -0
- package/dist/seo/page-head.js +114 -0
- package/dist/seo/ports.d.ts +221 -0
- package/dist/seo/ports.js +27 -0
- package/dist/seo/seo.d.ts +73 -0
- package/dist/seo/seo.js +230 -0
- package/dist/seo/sitemap.d.ts +139 -0
- package/dist/seo/sitemap.js +217 -0
- package/dist/seo/types.d.ts +278 -0
- package/dist/seo/types.js +2 -0
- package/dist/seo/write-service.d.ts +79 -0
- package/dist/seo/write-service.js +273 -0
- package/dist/seo/xml-escape.d.ts +16 -0
- package/dist/seo/xml-escape.js +19 -0
- package/dist/settings/express/cms-adapter.d.ts +20 -0
- package/dist/settings/express/cms-adapter.js +124 -0
- package/dist/settings/express/contracts.d.ts +135 -0
- package/dist/settings/express/contracts.js +2 -0
- package/dist/settings/express/http.d.ts +10 -0
- package/dist/settings/express/http.js +211 -0
- package/dist/settings/express/index.d.ts +5 -0
- package/dist/settings/express/index.js +5 -0
- package/dist/settings/express/shared.d.ts +68 -0
- package/dist/settings/express/shared.js +54 -0
- package/dist/settings/express/stream.d.ts +24 -0
- package/dist/settings/express/stream.js +147 -0
- package/dist/settings/index.d.ts +3 -38
- package/dist/settings/index.js +3 -35
- package/dist/taxonomy/write-service.d.ts +2 -30
- package/dist/widgets/authorize-helper.d.ts +42 -0
- package/dist/widgets/authorize-helper.js +16 -0
- package/dist/widgets/concurrency.d.ts +12 -0
- package/dist/widgets/concurrency.js +44 -0
- package/dist/widgets/config-validation.d.ts +34 -0
- package/dist/widgets/config-validation.js +125 -0
- package/dist/widgets/embed-service.d.ts +133 -0
- package/dist/widgets/embed-service.js +460 -0
- package/dist/widgets/embed-validation.d.ts +23 -0
- package/dist/widgets/embed-validation.js +38 -0
- package/dist/widgets/entry-payload.d.ts +103 -0
- package/dist/widgets/entry-payload.js +160 -0
- package/dist/widgets/errors.d.ts +136 -0
- package/dist/widgets/errors.js +136 -0
- package/dist/widgets/host-ports.d.ts +149 -0
- package/dist/widgets/host-ports.js +2 -0
- package/dist/widgets/html/html-embeds.d.ts +247 -0
- package/dist/widgets/html/html-embeds.js +408 -0
- package/dist/widgets/html/index.d.ts +5 -0
- package/dist/widgets/html/index.js +4 -0
- package/dist/widgets/html/legacy-widget-markers.d.ts +8 -0
- package/dist/widgets/html/legacy-widget-markers.js +45 -0
- package/dist/widgets/html/resolve-html-page-embeds.d.ts +42 -0
- package/dist/widgets/html/resolve-html-page-embeds.js +57 -0
- package/dist/widgets/index.d.ts +20 -0
- package/dist/widgets/index.js +19 -0
- package/dist/widgets/markers/html-attributes.d.ts +98 -0
- package/dist/widgets/markers/html-attributes.js +216 -0
- package/dist/widgets/markers/index.d.ts +3 -0
- package/dist/widgets/markers/index.js +3 -0
- package/dist/widgets/markers/marker.d.ts +496 -0
- package/dist/widgets/markers/marker.js +780 -0
- package/dist/widgets/page-embed-types.d.ts +42 -0
- package/dist/widgets/page-embed-types.js +42 -0
- package/dist/widgets/ports.d.ts +142 -0
- package/dist/widgets/ports.js +2 -0
- package/dist/widgets/read-service.d.ts +81 -0
- package/dist/widgets/read-service.js +79 -0
- package/dist/widgets/region-area-service.d.ts +110 -0
- package/dist/widgets/region-area-service.js +180 -0
- package/dist/widgets/registry.d.ts +217 -0
- package/dist/widgets/registry.js +172 -0
- package/dist/widgets/repo.memory.d.ts +41 -0
- package/dist/widgets/repo.memory.js +48 -0
- package/dist/widgets/resolver-service.d.ts +209 -0
- package/dist/widgets/resolver-service.js +909 -0
- package/dist/widgets/resolvers/contact-form.d.ts +26 -0
- package/dist/widgets/resolvers/contact-form.js +54 -0
- package/dist/widgets/resolvers/create-core-resolvers.d.ts +34 -0
- package/dist/widgets/resolvers/create-core-resolvers.js +11 -0
- package/dist/widgets/resolvers/index.d.ts +65 -0
- package/dist/widgets/resolvers/index.js +155 -0
- package/dist/widgets/resolvers/menu.d.ts +42 -0
- package/dist/widgets/resolvers/menu.js +43 -0
- package/dist/widgets/resolvers/ports.d.ts +82 -0
- package/dist/widgets/resolvers/ports.js +2 -0
- package/dist/widgets/resolvers/recent-entries.d.ts +71 -0
- package/dist/widgets/resolvers/recent-entries.js +165 -0
- package/dist/widgets/resolvers/taxonomy.d.ts +12 -0
- package/dist/widgets/resolvers/taxonomy.js +34 -0
- package/dist/widgets/sql/index.d.ts +3 -0
- package/dist/widgets/sql/index.js +3 -0
- package/dist/widgets/sql/repo.d.ts +41 -0
- package/dist/widgets/sql/repo.js +82 -0
- package/dist/widgets/sql/tables.d.ts +13 -0
- package/dist/widgets/sql/tables.js +2 -0
- package/dist/widgets/types.d.ts +213 -0
- package/dist/widgets/types.js +17 -0
- package/dist/widgets/where-used.d.ts +41 -0
- package/dist/widgets/where-used.js +11 -0
- package/dist/widgets/write-service.d.ts +204 -0
- package/dist/widgets/write-service.js +332 -0
- package/dist/workspace/delete.d.ts +1 -1
- package/package.json +220 -12
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file The ONE parser for embed markers (`data-embed-config`), shared by every consumer.
|
|
3
|
+
*
|
|
4
|
+
* Purpose:
|
|
5
|
+
* Before the 2026-08-10 marker-spine unification there were four independent scanners, each with its
|
|
6
|
+
* own regex, matching two different attribute vocabularies that had drifted apart:
|
|
7
|
+
*
|
|
8
|
+
* - `widgets/html-embeds.ts` — `data-embed-type`/`data-embed-id` in a Page's `body_html`
|
|
9
|
+
* - `features/theme/static-render.ts` — the same pair for menu/post markers, PLUS
|
|
10
|
+
* `data-tovu-slot`/`data-nav-current`/`data-slot-variant` for theme partials
|
|
11
|
+
* - `core/entry-refs/extractor.ts` — the same pair again, for reference extraction
|
|
12
|
+
*
|
|
13
|
+
* Four regexes for one concept is four places a fix has to land and four ways they can disagree
|
|
14
|
+
* (they already did: the widgets pipeline only matched a self-closing `<div></div>`, while the theme
|
|
15
|
+
* path deliberately matched a marker WITH authored fallback content inside it). This module is the
|
|
16
|
+
* single definition. Consumers ask it what a piece of HTML references; none of them owns a pattern.
|
|
17
|
+
*
|
|
18
|
+
* The vocabulary is one attribute carrying JSON:
|
|
19
|
+
*
|
|
20
|
+
* <div data-embed-config='{"type":"partial","id":"nav","current":"index"}'></div>
|
|
21
|
+
* <nav data-embed-config='{"type":"menu","id":"docs-nav","variant":"tree"}'>fallback</nav>
|
|
22
|
+
*
|
|
23
|
+
* Forms may request plain output with `{"type":"form","id":"contact","mode":"html"}`;
|
|
24
|
+
* `mode` is resolver-owned config, so the parser carries it through unchanged.
|
|
25
|
+
*
|
|
26
|
+
* `type` and `id` are ordinary keys, not separate attributes, so a new key never requires a new
|
|
27
|
+
* attribute name. The attribute is single-quoted precisely so the JSON's own double quotes need no
|
|
28
|
+
* escaping.
|
|
29
|
+
*
|
|
30
|
+
* Architectural role:
|
|
31
|
+
* PURE. No I/O, no DOM, no resolution — it reports what a marker *says*, never what it resolves to.
|
|
32
|
+
* Lives in `core/` because all three consumers above sit in different features and `core/entry-refs`
|
|
33
|
+
* (the integrity path) is already here.
|
|
34
|
+
*
|
|
35
|
+
* ## Why regex and not a parser
|
|
36
|
+
*
|
|
37
|
+
* Same reason the code it replaces used one: this runs server-side against theme-authored markup and
|
|
38
|
+
* Page bodies with no DOM available, and every consumer needs the marker's *source offsets* to
|
|
39
|
+
* substitute in place. A real HTML parse would also have to round-trip the document back to a string
|
|
40
|
+
* byte-identically, which is a much harder guarantee than locating one attribute.
|
|
41
|
+
*/
|
|
42
|
+
/** A `data-embed-config` marker located in a piece of HTML. */
|
|
43
|
+
export interface EmbedMarker {
|
|
44
|
+
/** `config.type` — which resolver handles this. Always present; a marker without it is invalid. */
|
|
45
|
+
readonly type: string;
|
|
46
|
+
/**
|
|
47
|
+
* `config.id` — which instance. `undefined` for a type that needs no target (none today, but the
|
|
48
|
+
* shape allows one rather than forcing a meaningless id).
|
|
49
|
+
*/
|
|
50
|
+
readonly id: string | undefined;
|
|
51
|
+
/** The whole parsed object, `type`/`id` included, so a resolver reads its own keys off one place. */
|
|
52
|
+
readonly config: Readonly<Record<string, unknown>>;
|
|
53
|
+
/** The marker element's tag name, for consumers that rebuild the open tag. */
|
|
54
|
+
readonly tag: string;
|
|
55
|
+
/** The marker's attribute string, verbatim, so other authored attributes survive a substitution. */
|
|
56
|
+
readonly attrs: string;
|
|
57
|
+
/** The full matched element including its inner content and closing tag. */
|
|
58
|
+
readonly whole: string;
|
|
59
|
+
/**
|
|
60
|
+
* The marker's own original inner content (between its open and close tag), exactly as authored.
|
|
61
|
+
* The mirror image of {@link withInnerContent}'s parameter: that function takes NEW inner content
|
|
62
|
+
* and keeps the marker's existing tag/attrs; this field is for a caller going the other way —
|
|
63
|
+
* keeping (or transforming) the marker's existing inner content while changing its attrs/config,
|
|
64
|
+
* e.g. {@link withAddedId} filling in a missing `id` without disturbing whatever fallback markup
|
|
65
|
+
* the author put inside the marker.
|
|
66
|
+
*/
|
|
67
|
+
readonly inner: string;
|
|
68
|
+
/** Index of `whole` within the scanned html — substitution without re-searching. */
|
|
69
|
+
readonly index: number;
|
|
70
|
+
/** 1-based position among all markers found, for stable locators (`entry_refs` `fieldPath`). */
|
|
71
|
+
readonly occurrence: number;
|
|
72
|
+
}
|
|
73
|
+
/** Why a marker was rejected. Consumers decide whether to warn, skip, or refuse a write. */
|
|
74
|
+
export type EmbedMarkerProblem = {
|
|
75
|
+
readonly kind: "invalid-json";
|
|
76
|
+
readonly raw: string;
|
|
77
|
+
readonly message: string;
|
|
78
|
+
} | {
|
|
79
|
+
readonly kind: "not-an-object";
|
|
80
|
+
readonly raw: string;
|
|
81
|
+
} | {
|
|
82
|
+
readonly kind: "missing-type";
|
|
83
|
+
readonly raw: string;
|
|
84
|
+
};
|
|
85
|
+
/** One rejected marker, with enough context to name it in an error a human can act on. */
|
|
86
|
+
export interface EmbedMarkerRejection {
|
|
87
|
+
readonly problem: EmbedMarkerProblem;
|
|
88
|
+
readonly occurrence: number;
|
|
89
|
+
readonly index: number;
|
|
90
|
+
}
|
|
91
|
+
export interface ScanEmbedMarkersResult {
|
|
92
|
+
readonly markers: readonly EmbedMarker[];
|
|
93
|
+
/**
|
|
94
|
+
* Markers that carry the attribute but could not be understood. **Never silently empty-on-error**:
|
|
95
|
+
* `entry-refs/extractor.ts` builds the where-used index that safe-delete trusts, and a marker that
|
|
96
|
+
* fails to parse would otherwise drop a reference from that index without a trace — letting a
|
|
97
|
+
* delete proceed against something still in use. Extraction and the write chokepoint must treat a
|
|
98
|
+
* non-empty `rejected` as loud; render-time consumers may degrade quietly.
|
|
99
|
+
*/
|
|
100
|
+
readonly rejected: readonly EmbedMarkerRejection[];
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Produce a same-length copy of `html` with every HTML comment, and the raw-text content of every
|
|
104
|
+
* `<script>`/`<style>` element, replaced by space filler. {@link scanEmbedMarkers} runs
|
|
105
|
+
* {@link MARKER_PATTERN} against this copy — never the original — so a well-formed
|
|
106
|
+
* `data-embed-config` marker written inside an authoring note (`<!-- ... -->`) or inside a
|
|
107
|
+
* `<style>` block's CSS comment can never be matched: neither is ever parsed as an element by a
|
|
108
|
+
* browser, so the scanner must not treat either as one either. A marker outside both is untouched
|
|
109
|
+
* here and matches exactly as before.
|
|
110
|
+
*
|
|
111
|
+
* Same length is load-bearing, not cosmetic: every offset {@link scanEmbedMarkers} reports (and
|
|
112
|
+
* {@link substituteMarkers}'s index-based splice back into the ORIGINAL html) depends on a masked
|
|
113
|
+
* span occupying exactly the same positions as what it replaces. Deleting the comment/raw-text
|
|
114
|
+
* content instead of blanking it would shift every later offset out from under those callers.
|
|
115
|
+
*
|
|
116
|
+
* EXPORTED (2026-09-09) for `features/pages/regions.ts`, which scans the SAME page bodies for
|
|
117
|
+
* `data-agent-element` region elements and needs the identical "text inside a comment or inside a
|
|
118
|
+
* <style> block is not markup" rule with the identical offset-preserving guarantee. A second copy
|
|
119
|
+
* of this masking is exactly the four-scanners-for-one-concept drift this module's own header
|
|
120
|
+
* exists to close: region scanning is a different question about the same bytes, not a second
|
|
121
|
+
* vocabulary.
|
|
122
|
+
*/
|
|
123
|
+
export declare function maskNonRenderableRegions({ html }: {
|
|
124
|
+
html: string;
|
|
125
|
+
}, _optional?: Record<string, never>): string;
|
|
126
|
+
/**
|
|
127
|
+
* Validate one marker's raw attribute text. Split out from {@link scanEmbedMarkers} so the scan stays
|
|
128
|
+
* a plain loop: all three rejection branches live here, and the caller only chooses which list to
|
|
129
|
+
* push onto.
|
|
130
|
+
*
|
|
131
|
+
* EXPORTED (2026-09-23, Bug A / interactive-bugs plan Slice A1) so a consumer that only has the raw
|
|
132
|
+
* `data-embed-config` string in hand — the admin's canvas placeholder describer, which reads an
|
|
133
|
+
* already-authored DOM attribute rather than re-running {@link scanEmbedMarkers} — can apply the exact
|
|
134
|
+
* same parse-and-reject rule `scanEmbedMarkers` itself uses, instead of growing its own copy of it.
|
|
135
|
+
*/
|
|
136
|
+
export declare function parseEmbedMarkerConfig({ raw }: {
|
|
137
|
+
raw: string;
|
|
138
|
+
}, _optional?: Record<string, never>): {
|
|
139
|
+
config: Record<string, unknown>;
|
|
140
|
+
} | {
|
|
141
|
+
problem: EmbedMarkerProblem;
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* Locate and parse every embed marker in `html`. Pure; allocates one result per marker.
|
|
145
|
+
*
|
|
146
|
+
* Scans {@link maskNonRenderableRegions}'s masked copy so a marker sitting inside an HTML comment or
|
|
147
|
+
* a `<script>`/`<style>` element's raw text is never matched, and so tags inside either are invisible
|
|
148
|
+
* to {@link findBalancedClose}'s depth count too. Every field on the resulting {@link EmbedMarker}
|
|
149
|
+
* (`whole`, `tag`, `attrs`, `inner`, the parsed config) is read back out of the ORIGINAL `html` at
|
|
150
|
+
* that match's own offsets — masking only decides which spans are eligible to be a marker or to count
|
|
151
|
+
* toward a close tag's depth, it must never change what an eligible marker's own fields report.
|
|
152
|
+
*
|
|
153
|
+
* Uses a private copy of {@link MARKER_PATTERN} (same source/flags) for the `exec` loop below, rather
|
|
154
|
+
* than mutating the shared module-level regex's `lastIndex` directly — this function is PURE, and a
|
|
155
|
+
* shared mutable scan cursor would corrupt a reentrant or recursive call.
|
|
156
|
+
*/
|
|
157
|
+
export declare function scanEmbedMarkers({ html }: {
|
|
158
|
+
html: string;
|
|
159
|
+
}, _optional?: Record<string, never>): ScanEmbedMarkersResult;
|
|
160
|
+
/**
|
|
161
|
+
* Rewrites every double-quoted, entity-encoded `data-embed-config="{"type":…}"` (what a DOM
|
|
162
|
+
* serializer such as the admin's Interactive canvas emits) back to the authored, readable form
|
|
163
|
+
* `data-embed-config='{"type":…}'`, so the stored page source reads the way it was written. Every
|
|
164
|
+
* Page HTML write runs through this (`PagesHtmlDocumentStore`), and the admin applies it to what the
|
|
165
|
+
* canvas hands back.
|
|
166
|
+
*
|
|
167
|
+
* Exact at the config level: a rewritten marker scans to the same `config`, `attrs` and `inner` it did
|
|
168
|
+
* before. Only the quoted value changes; the tag, other attributes and content are untouched. Left
|
|
169
|
+
* as written: a single-quoted marker, a marker inside a comment or `<script>`/`<style>` (never matched,
|
|
170
|
+
* see {@link maskNonRenderableRegions}), and a value that is not valid JSON, so a broken marker still
|
|
171
|
+
* reaches {@link scanEmbedMarkers}'s rejection with its original text.
|
|
172
|
+
*
|
|
173
|
+
* @complexity O(n) over `html`.
|
|
174
|
+
*/
|
|
175
|
+
export declare function normalizeEmbedMarkerQuoting({ html }: {
|
|
176
|
+
html: string;
|
|
177
|
+
}, _optional?: Record<string, never>): string;
|
|
178
|
+
/** Every marker of one type, in document order. The common "which menus does this theme name" shape. */
|
|
179
|
+
export declare function markersOfType({ html, type }: {
|
|
180
|
+
html: string;
|
|
181
|
+
type: string;
|
|
182
|
+
}, _optional?: Record<string, never>): readonly EmbedMarker[];
|
|
183
|
+
/**
|
|
184
|
+
* The two marker `type` values this module parses but never itself resolves — owned end-to-end by
|
|
185
|
+
* `features/theme/static-render.ts` (`injectMenuEmbeds` for {@link MENU_MARKER_TYPE}, `resolveSlots`
|
|
186
|
+
* for {@link PARTIAL_MARKER_TYPE}), which run AFTER `widgets/resolver-service.ts`'s page-embed stage
|
|
187
|
+
* on every static-tier page render.
|
|
188
|
+
*
|
|
189
|
+
* Hoisted here (2026-08-17) so that ownership fact has exactly one spelling. Before this, it existed
|
|
190
|
+
* only as inline string-literal comparisons inside `static-render.ts` itself
|
|
191
|
+
* (`marker.type !== "menu"`, `marker.type !== "partial"`), and `resolver-service.ts`'s own
|
|
192
|
+
* `THEME_OWNED_MARKER_TYPES` carried an independently-typed copy of the same two strings as a
|
|
193
|
+
* documented stopgap pending this exact hoist (`ADS-memory/reports/
|
|
194
|
+
* 2026-08-16-embed-placeholder-gap.md`, "Reuse decision") — two spellings of one fact is exactly the
|
|
195
|
+
* kind of drift risk this module exists to close for marker *parsing*; these two constants close it
|
|
196
|
+
* for marker *type naming* the same way.
|
|
197
|
+
*
|
|
198
|
+
* Deliberately NOT the same question `isPageEmbedType()` (`widgets/resolver-service.ts`) answers —
|
|
199
|
+
* that function tests registry membership (`Object.hasOwn(HTML_EMBED_RESOLVERS, type)`), which is
|
|
200
|
+
* `false` for these two AND for a genuine unregistered/typo type alike. These constants name the
|
|
201
|
+
* "owned elsewhere, not a typo" fact directly instead; see `isPageEmbedType`'s own doc for why
|
|
202
|
+
* conflating the two would silence a real warning.
|
|
203
|
+
*/
|
|
204
|
+
export declare const MENU_MARKER_TYPE = "menu";
|
|
205
|
+
export declare const PARTIAL_MARKER_TYPE = "partial";
|
|
206
|
+
/**
|
|
207
|
+
* The post-previews marker type (2026-09-03) — a theme/page marker that renders a bounded list of
|
|
208
|
+
* published post previews wherever it appears, so any authored Page (a static theme's own marketing
|
|
209
|
+
* page, or a Page/Post rendered through a `theme.json` `templates` entry) can host a post listing.
|
|
210
|
+
* Same ownership shape as {@link MENU_MARKER_TYPE}/{@link PARTIAL_MARKER_TYPE} immediately above:
|
|
211
|
+
* resolved end-to-end by `features/theme/static-render.ts`'s `injectPostPreviewsEmbeds`, never
|
|
212
|
+
* registered in `widgets/resolver-service.ts`'s `HTML_EMBED_RESOLVERS` — see that file's
|
|
213
|
+
* `THEME_OWNED_MARKER_TYPES`, which carries a matching literal entry for the same disclosed
|
|
214
|
+
* "duplicated, not imported" reason its own doc already states for the other two.
|
|
215
|
+
*
|
|
216
|
+
* Config shape: `{"type":"post-previews","limit":6}` — `limit` is optional (defaults to
|
|
217
|
+
* `DEFAULT_POST_PREVIEWS_LIMIT`, `static-render.ts`) and is always clamped, never trusted verbatim,
|
|
218
|
+
* before it reaches the bounded repo query that feeds this marker.
|
|
219
|
+
*/
|
|
220
|
+
export declare const POST_PREVIEWS_MARKER_TYPE = "post-previews";
|
|
221
|
+
/**
|
|
222
|
+
* The collection marker type (2026-09-23) — a theme/page marker that renders a bounded, filtered,
|
|
223
|
+
* sorted list of entries from one custom content type wherever it appears. Same ownership shape as
|
|
224
|
+
* {@link MENU_MARKER_TYPE}/{@link PARTIAL_MARKER_TYPE}/{@link POST_PREVIEWS_MARKER_TYPE} immediately
|
|
225
|
+
* above: resolved end-to-end by `features/theme/static-render.ts`'s `injectCollectionEmbeds`, never
|
|
226
|
+
* registered in `widgets/resolver-service.ts`'s `HTML_EMBED_RESOLVERS` — see that file's
|
|
227
|
+
* `THEME_OWNED_MARKER_TYPES`, which carries a matching literal entry for the same disclosed
|
|
228
|
+
* "duplicated, not imported" reason its own doc gives for the other three.
|
|
229
|
+
*
|
|
230
|
+
* Config shape (validated by `entries/public-list.ts`'s `parseCollectionListConfig`, not by this
|
|
231
|
+
* module): `{"type":"collection","id":"recipe", …}` (`typeKey` accepted as an alias) plus the type's own filter/sort/limit/layout
|
|
232
|
+
* keys. Unlike {@link POST_PREVIEWS_MARKER_TYPE}, a resolved collection marker's wrapper is stripped
|
|
233
|
+
* of `data-embed-config` on the hit path ({@link withInnerContentFinal}) so a later re-scan of the
|
|
234
|
+
* same output can never rediscover and re-resolve it.
|
|
235
|
+
*/
|
|
236
|
+
export declare const COLLECTION_MARKER_TYPE = "collection";
|
|
237
|
+
/**
|
|
238
|
+
* The featured-image marker type (2026-10-05) — a post template's slot for the current post's
|
|
239
|
+
* featured image. A static-tier theme has no template language to read `post.featuredImage` (the
|
|
240
|
+
* Liquid/Handlebars tiers' theme data), so before this marker a static theme had no way to show the
|
|
241
|
+
* image at all; it only reached `og:image`. Same ownership shape as {@link COLLECTION_MARKER_TYPE}:
|
|
242
|
+
* resolved end-to-end by `features/theme/static-render.ts`'s `injectFeaturedImage`, listed in
|
|
243
|
+
* `resolver-service.ts`'s `THEME_OWNED_MARKER_TYPES`.
|
|
244
|
+
*
|
|
245
|
+
* Config shape: `{"type":"featured-image"}` — no target; it always means the entity the route is
|
|
246
|
+
* rendering. A hit fills the authored element with the `<img>` and strips the marker; no image
|
|
247
|
+
* (none set, unresolved, or a page with no current post) removes the WHOLE element, wrapper and
|
|
248
|
+
* fallback included, so a theme's figure/margins never render around nothing.
|
|
249
|
+
*/
|
|
250
|
+
export declare const FEATURED_IMAGE_MARKER_TYPE = "featured-image";
|
|
251
|
+
/**
|
|
252
|
+
* One marker type's `data-embed-config` keys that can name its resolution target, in the exact
|
|
253
|
+
* precedence order the server tries them — `embedMarkerTarget` returns the FIRST of these keys with a
|
|
254
|
+
* usable string value. This is the "which key names the target" rule Bug A's root cause report
|
|
255
|
+
* (2026-09-23 interactive-bugs plan) found spread across four different resolvers
|
|
256
|
+
* (`resolver-service.ts`'s widget/media/post/content, `routes/site/pages.ts`'s collection) with no
|
|
257
|
+
* single shared table — the admin's own placeholder describer could not reuse it because nothing here
|
|
258
|
+
* exposed it. Hoisting it as data (not a switch statement) is what lets both the server's own resolvers
|
|
259
|
+
* and the admin's UI-only describer read the identical precedence rule.
|
|
260
|
+
*
|
|
261
|
+
* - `widget`/`form`/`media`/`post`/`content`: `id`, else `slug` — registered in
|
|
262
|
+
* `resolver-service.ts`'s `HTML_EMBED_RESOLVERS` (see `marker-target-parity.unit.test.ts`, which fails
|
|
263
|
+
* loudly if a registered type has no matching row or incorrect target keys).
|
|
264
|
+
* - `taxonomy`: `id` only — `widgets/resolvers/taxonomy.ts` reads `ref.id`, accepting a real
|
|
265
|
+
* taxonomy id or a unique taxonomy name through that key; `ref.slug` is never consulted.
|
|
266
|
+
* - {@link COLLECTION_MARKER_TYPE}: `id`, else `typeKey` — `routes/site/pages.ts`'s
|
|
267
|
+
* `collectionMarkerTypeKey` tries `config.id` before `config.typeKey`; `slug` is never consulted.
|
|
268
|
+
* - {@link MENU_MARKER_TYPE} / {@link PARTIAL_MARKER_TYPE}: `id` only — `static-render.ts` resolves
|
|
269
|
+
* both purely by id.
|
|
270
|
+
* - {@link POST_PREVIEWS_MARKER_TYPE}: no keys at all — this marker needs no target
|
|
271
|
+
* ({@link embedMarkerTarget} reports that as its own `{ key: "none" }` outcome, never `undefined`,
|
|
272
|
+
* which means "target missing").
|
|
273
|
+
*
|
|
274
|
+
* An unknown type (not a key of this table) is not a member of it; {@link embedMarkerTarget} falls back
|
|
275
|
+
* to `["id"]` for that case rather than treating an unrecognized type as needing no target — a display
|
|
276
|
+
* must never claim a slug resolves for a type no resolver has ever registered.
|
|
277
|
+
*/
|
|
278
|
+
export declare const EMBED_MARKER_TARGET_KEYS: Readonly<Record<string, readonly ("id" | "slug" | "typeKey")[]>>;
|
|
279
|
+
/**
|
|
280
|
+
* One marker's resolved target, from {@link embedMarkerTarget}: either a key/value pair naming what
|
|
281
|
+
* the marker points at, or the `"none"` marker for a type that needs no target at all. Kept distinct
|
|
282
|
+
* from `undefined` (target missing) — see {@link embedMarkerTarget}'s own doc.
|
|
283
|
+
*/
|
|
284
|
+
export type EmbedMarkerTarget = {
|
|
285
|
+
readonly key: "id" | "slug" | "typeKey";
|
|
286
|
+
readonly value: string;
|
|
287
|
+
} | {
|
|
288
|
+
readonly key: "none";
|
|
289
|
+
};
|
|
290
|
+
/**
|
|
291
|
+
* Which `data-embed-config` key names `type`'s resolution target, and that key's value, per
|
|
292
|
+
* {@link EMBED_MARKER_TARGET_KEYS}'s precedence order. Three distinct outcomes:
|
|
293
|
+
*
|
|
294
|
+
* - `{ key, value }` — the first target key present with a usable string value.
|
|
295
|
+
* - `{ key: "none" }` — this type ({@link POST_PREVIEWS_MARKER_TYPE}) needs no target; a caller must
|
|
296
|
+
* never read this as "target missing".
|
|
297
|
+
* - `undefined` — the type has one or more target keys, but the marker's config supplies none of them
|
|
298
|
+
* (or only with an unusable value per {@link normalizeTargetValue}) — "target missing".
|
|
299
|
+
*
|
|
300
|
+
* `type` is compared lower-cased, matching `toEmbedRef`'s own `marker.type.toLowerCase()` in
|
|
301
|
+
* `resolver-service.ts` — a hand-authored `"Widget"` must resolve exactly as `"widget"` does.
|
|
302
|
+
*
|
|
303
|
+
* @complexity O(k) in the number of candidate keys for `type` (at most 2 today) — independent of the
|
|
304
|
+
* surrounding document's size.
|
|
305
|
+
*/
|
|
306
|
+
export declare function embedMarkerTarget({ type, config }: {
|
|
307
|
+
type: string;
|
|
308
|
+
config: Readonly<Record<string, unknown>>;
|
|
309
|
+
}, _optional?: Record<string, never>): EmbedMarkerTarget | undefined;
|
|
310
|
+
/**
|
|
311
|
+
* The "Copy embed code" snippet for any marker type: the same `<div data-embed-config='{"type":…,
|
|
312
|
+
* "<key>":"<value>"}'></div>` wrapper {@link scanEmbedMarkers}/{@link parseEmbedMarkerConfig} already
|
|
313
|
+
* parse back — generalised (readable-slugs S5b) out of `apps/admin/src/features/collections/rules.ts`'s
|
|
314
|
+
* `collectionEmbedSnippet`, the one admin-generated marker that existed before this: that function is
|
|
315
|
+
* now a one-line call onto this (`embedMarkerSnippet("collection", "id", key)`), byte-for-byte
|
|
316
|
+
* unchanged. `features/media`'s own "Copy embed code" button (S5a) is the second caller, with
|
|
317
|
+
* `("media", "slug", asset.slug)` — see {@link EMBED_MARKER_TARGET_KEYS}'s `media` row for why `slug`
|
|
318
|
+
* is a real, resolvable target key for this type.
|
|
319
|
+
*
|
|
320
|
+
* No escaping beyond the plain template: `key`/`value` are expected to already be validated,
|
|
321
|
+
* quote-free identifiers (a slug, a type key, an id) by the time a caller reaches for a copy button —
|
|
322
|
+
* the same assumption `collectionEmbedSnippet` always made.
|
|
323
|
+
*
|
|
324
|
+
* @complexity O(1) — one template string.
|
|
325
|
+
*/
|
|
326
|
+
export declare function embedMarkerSnippet({ type, key, value }: {
|
|
327
|
+
type: string;
|
|
328
|
+
key: "id" | "slug" | "typeKey";
|
|
329
|
+
value: string;
|
|
330
|
+
}, _optional?: Record<string, never>): string;
|
|
331
|
+
/**
|
|
332
|
+
* Rebuild a marker's element around new inner content, keeping its own tag and every authored
|
|
333
|
+
* attribute (`class`, `aria-label`, …). The counterpart to a wholesale replace: a menu marker keeps
|
|
334
|
+
* its `<nav class="docs-nav">` wrapper and only swaps what's inside, whereas a partial slot marker
|
|
335
|
+
* disappears entirely and is replaced by the partial.
|
|
336
|
+
*
|
|
337
|
+
* Synthesizing the open tag from `config` alone instead of using this is a silent bug — it drops the
|
|
338
|
+
* theme's styling hooks and accessible names with nothing failing.
|
|
339
|
+
*/
|
|
340
|
+
export declare function withInnerContent({ marker, inner }: {
|
|
341
|
+
marker: EmbedMarker;
|
|
342
|
+
inner: string;
|
|
343
|
+
}, _optional?: Record<string, never>): string;
|
|
344
|
+
/**
|
|
345
|
+
* Rebuild a marker's element with `id` added to its `data-embed-config`, keeping every other
|
|
346
|
+
* authored config key, the marker's own tag, its other attributes, and its authored inner content
|
|
347
|
+
* ({@link EmbedMarker.inner}) completely unchanged. The counterpart to {@link withInnerContent} for a
|
|
348
|
+
* caller that needs to SUPPLY a marker's target rather than its content — e.g. the unified `content`
|
|
349
|
+
* marker (2026-08-11): a theme-authored `{"type":"content"}` with no `id` means "the entity the route
|
|
350
|
+
* already resolved", and the route fills that id in here before the marker is ever resolved, so every
|
|
351
|
+
* downstream consumer (the scanner, the resolver, a later re-scan) sees an ordinary id-carrying marker
|
|
352
|
+
* rather than needing its own "no id means current entity" special case.
|
|
353
|
+
*
|
|
354
|
+
* Callers must check `marker.id === undefined` themselves before calling this — an author's own
|
|
355
|
+
* explicit id always wins over a caller-supplied default, and this function does not re-check that
|
|
356
|
+
* (it would silently overwrite an explicit reference otherwise, which is the one thing the unified
|
|
357
|
+
* marker's id-vs-no-id contract must never do).
|
|
358
|
+
*
|
|
359
|
+
* @complexity O(n) over the marker's own attrs length (one JSON stringify of a small object, one
|
|
360
|
+
* regex replace over `attrs`) — independent of the surrounding document's size.
|
|
361
|
+
*/
|
|
362
|
+
export declare function withAddedId({ marker, id }: {
|
|
363
|
+
marker: EmbedMarker;
|
|
364
|
+
id: string;
|
|
365
|
+
}, _optional?: Record<string, never>): string;
|
|
366
|
+
/**
|
|
367
|
+
* Rebuild a marker's element around new inner content, like {@link withInnerContent}, but ALSO strips
|
|
368
|
+
* the marker's own `data-embed-config` attribute from the rebuilt tag — every other authored attribute
|
|
369
|
+
* (`class`, `aria-label`, …) survives, only the marker-ness is removed.
|
|
370
|
+
*
|
|
371
|
+
* For a caller that performs its OWN final resolution outside the shared registry/render pipeline
|
|
372
|
+
* (`pages.ts`'s recursive `content`-marker pre-splice, which fetches and inlines an `"html"`-format
|
|
373
|
+
* entity's own body ahead of the normal `resolveHtmlPageEmbeds`/`renderHtmlPageBody` pass) and must
|
|
374
|
+
* guarantee the result is not rediscovered and re-resolved by a LATER marker scan over the same output
|
|
375
|
+
* — an ordinary {@link withInnerContent} splice would leave `data-embed-config` intact, and the next
|
|
376
|
+
* scan would see what looks like a fresh, unresolved marker and try to resolve it again.
|
|
377
|
+
*
|
|
378
|
+
* @complexity O(n) over the marker's own attrs length (one regex replace) — independent of the
|
|
379
|
+
* surrounding document's size.
|
|
380
|
+
*/
|
|
381
|
+
export declare function withInnerContentFinal({ marker, inner }: {
|
|
382
|
+
marker: EmbedMarker;
|
|
383
|
+
inner: string;
|
|
384
|
+
}, _optional?: Record<string, never>): string;
|
|
385
|
+
/**
|
|
386
|
+
* Replace each marker's WHOLE element with what `resolve` returns for it.
|
|
387
|
+
*
|
|
388
|
+
* Whole-element rather than inner-content because the two consumers genuinely differ: a partial slot
|
|
389
|
+
* marker is scaffolding that vanishes once the partial is spliced in, while a menu marker is real
|
|
390
|
+
* theme markup that must survive with only its contents swapped. Callers in the second camp wrap
|
|
391
|
+
* their output in {@link withInnerContent}; making that explicit at the call site is better than a
|
|
392
|
+
* mode flag, because the choice is a real per-type decision and not a preference.
|
|
393
|
+
*
|
|
394
|
+
* `resolve` returning `undefined` means "leave this marker exactly as authored", and that default is
|
|
395
|
+
* load-bearing: a menu that does not exist, a target that was deleted, or a render that produces
|
|
396
|
+
* nothing must fall back to the theme's authored content rather than blanking a nav. Every consumer
|
|
397
|
+
* wants that rule, so it lives here rather than being re-implemented per call site.
|
|
398
|
+
*
|
|
399
|
+
* Applies right-to-left so each splice leaves the earlier markers' offsets valid.
|
|
400
|
+
*/
|
|
401
|
+
export declare function substituteMarkers({ html, resolve }: {
|
|
402
|
+
html: string;
|
|
403
|
+
resolve: (marker: EmbedMarker) => string | undefined;
|
|
404
|
+
}, _optional?: Record<string, never>): string;
|
|
405
|
+
/**
|
|
406
|
+
* One HTML attribute authored directly on a marker element (2026-09-16 — owner: "regular attributes
|
|
407
|
+
* that somebody puts on a data-embed-config should work on the rendered tag"). Produced by
|
|
408
|
+
* {@link parseMarkerAttributes}, consumed by callers that forward some or all of a marker's authored
|
|
409
|
+
* attributes onto whatever it resolves to.
|
|
410
|
+
*/
|
|
411
|
+
export interface MarkerAttribute {
|
|
412
|
+
readonly name: string;
|
|
413
|
+
/** Source text, exactly as authored — never entity-decoded (see {@link parseMarkerAttributes}'s
|
|
414
|
+
* own doc for why). `null` means the attribute was written with no `="..."` at all (a boolean
|
|
415
|
+
* attribute like a bare `autoplay`), not that it had an empty value. */
|
|
416
|
+
readonly value: string | null;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Parses a marker's verbatim {@link EmbedMarker.attrs} text into structured attributes, in authored
|
|
420
|
+
* order, with `data-embed-config` itself removed (it is the marker, not an attribute a caller would
|
|
421
|
+
* ever want to forward) — the read half of the 2026-09-16 embed-attributes contract:
|
|
422
|
+
* {@link formatMarkerAttributes} is its inverse.
|
|
423
|
+
*
|
|
424
|
+
* - Names are lowercased (HTML attribute names are case-insensitive).
|
|
425
|
+
* - A token whose (lowercased) name is not a valid attribute name per
|
|
426
|
+
* {@link MARKER_ATTRIBUTE_NAME_PATTERN} is skipped, never thrown.
|
|
427
|
+
* - A duplicate name keeps its FIRST occurrence — the same rule a real HTML parser applies, so this
|
|
428
|
+
* parser's result matches what a browser would actually expose on the element.
|
|
429
|
+
* - Every value is kept as SOURCE TEXT: never entity-decoded. Re-decoding `&` here and
|
|
430
|
+
* re-escaping on output (see {@link formatMarkerAttributes}) would double-escape a value like
|
|
431
|
+
* `title="a & b"` into `&amp;` — this module never round-trips through a decoded form.
|
|
432
|
+
*
|
|
433
|
+
* @complexity O(n) in the marker's own attrs length (one regex pass) — independent of the surrounding
|
|
434
|
+
* document's size.
|
|
435
|
+
*/
|
|
436
|
+
export declare function parseMarkerAttributes({ marker }: {
|
|
437
|
+
marker: EmbedMarker;
|
|
438
|
+
}, _optional?: Record<string, never>): MarkerAttribute[];
|
|
439
|
+
/**
|
|
440
|
+
* Formats parsed attributes back into attribute-string text, the inverse of
|
|
441
|
+
* {@link parseMarkerAttributes}: a valueless attribute is emitted as a bare ` name`; a valued one as
|
|
442
|
+
* ` name="value"`. The ONLY transform applied to a value is `"` -> `"` (a value may itself
|
|
443
|
+
* contain a literal `"`, e.g. carried over from a single-quoted authored attribute) — `&` is never
|
|
444
|
+
* touched, so source text that already reads `&` is emitted unchanged rather than
|
|
445
|
+
* double-escaping into `&amp;`.
|
|
446
|
+
*
|
|
447
|
+
* @complexity O(n) in the total length of every attribute's name and value.
|
|
448
|
+
*/
|
|
449
|
+
export declare function formatMarkerAttributes({ attrs }: {
|
|
450
|
+
attrs: readonly MarkerAttribute[];
|
|
451
|
+
}, _optional?: Record<string, never>): string;
|
|
452
|
+
/** Whether a marker carries any authored attribute besides `data-embed-config` itself — the "bare
|
|
453
|
+
* marker" test {@link withElementKeptIfAttributed} uses to decide whether an element survives a
|
|
454
|
+
* whole-marker substitution.
|
|
455
|
+
*
|
|
456
|
+
* @complexity O(n) in the marker's own attrs length (delegates to {@link parseMarkerAttributes}).
|
|
457
|
+
*/
|
|
458
|
+
export declare function hasAuthoredAttributes({ marker }: {
|
|
459
|
+
marker: EmbedMarker;
|
|
460
|
+
}, _optional?: Record<string, never>): boolean;
|
|
461
|
+
/**
|
|
462
|
+
* Rebuild a marker's element around new inner content using an EXPLICIT attribute list (rather than
|
|
463
|
+
* the marker's own verbatim {@link EmbedMarker.attrs}) — for a caller that has partitioned a marker's
|
|
464
|
+
* authored attributes and needs only a subset on the rebuilt wrapper (e.g. {@link substituteHtmlEmbeds}
|
|
465
|
+
* moving media-element attribute names off a non-media wrapper onto the resolved `<video>`/`<img>`,
|
|
466
|
+
* keeping the rest on the wrapper). The counterpart to {@link withInnerContent}, which always keeps
|
|
467
|
+
* every authored attribute verbatim.
|
|
468
|
+
*/
|
|
469
|
+
export declare function withInnerContentAndAttributes({ marker, attrs, inner }: {
|
|
470
|
+
marker: EmbedMarker;
|
|
471
|
+
attrs: readonly MarkerAttribute[];
|
|
472
|
+
inner: string;
|
|
473
|
+
}, _optional?: Record<string, never>): string;
|
|
474
|
+
/**
|
|
475
|
+
* Whole-element replace UNLESS the marker carries authored attributes, in which case its element
|
|
476
|
+
* survives (minus `data-embed-config`) around the resolved content — the 2026-09-16 rule for marker
|
|
477
|
+
* types (`widget`, `partial`) that default to disappearing entirely: a bare marker keeps disappearing,
|
|
478
|
+
* byte-identical to before, while an attributed one keeps whatever styling/accessibility hook the
|
|
479
|
+
* author put on it. Delegates to {@link withInnerContentFinal} for the attributed case so the kept
|
|
480
|
+
* wrapper's attribute text is the marker's own verbatim {@link EmbedMarker.attrs} (not a
|
|
481
|
+
* parse-then-reformat round trip) — the same byte-identical-when-nothing-moves discipline
|
|
482
|
+
* {@link withInnerContentFinal} itself already provides.
|
|
483
|
+
*/
|
|
484
|
+
export declare function withElementKeptIfAttributed({ marker, inner }: {
|
|
485
|
+
marker: EmbedMarker;
|
|
486
|
+
inner: string;
|
|
487
|
+
}, _optional?: Record<string, never>): string;
|
|
488
|
+
/**
|
|
489
|
+
* Human-readable one-liner for a rejection, for a warning line or a write-time validation error.
|
|
490
|
+
* Deliberately quotes the offending JSON: the author needs to see what they typed, and the raw text
|
|
491
|
+
* is theme- or admin-authored, never end-user input.
|
|
492
|
+
*/
|
|
493
|
+
export declare function describeRejection({ rejection }: {
|
|
494
|
+
rejection: EmbedMarkerRejection;
|
|
495
|
+
}, _optional?: Record<string, never>): string;
|
|
496
|
+
//# sourceMappingURL=marker.d.ts.map
|