@dogsbay/serialize-core 0.2.0-beta.98

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.
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Shape-tolerant TreeNode reads — the single place that knows WHERE a value
3
+ * lives on a node.
4
+ *
5
+ * Different importers produce different TreeNode shapes for the same content:
6
+ * text arrives as flat `node.inline` (the dogsbay-md parser) or wrapped as
7
+ * `node.children[{ type: "prose", inline }]` (the Starlight importer); code
8
+ * text as `props.code` or `node.html`; language as `props.lang` or
9
+ * `props.language`; a tab title as `props.title`, `props.label`, or
10
+ * `props.value`.
11
+ *
12
+ * Every serializer used to re-derive these independently, and every serializer
13
+ * that got one wrong emitted SILENTLY EMPTY output — the entire
14
+ * "format-obsidian serializer field-drift" bug class
15
+ * (plans/format-obsidian-serializer-realign.md), where six separate reads had
16
+ * drifted from what the parser actually emits.
17
+ *
18
+ * These functions are deliberately DATA-ONLY: they return values and nodes,
19
+ * never rendered text, so every format can render them its own way while
20
+ * agreeing on where to look. Extracted from the canonical reads in
21
+ * `format-astro/src/serialize.ts`; the operator asymmetries below are
22
+ * behavioural and deliberate — read the comments before "simplifying" them.
23
+ */
24
+ import type { TreeNode, InlineNode } from "@dogsbay/types";
25
+ /**
26
+ * A node's inline content, handling BOTH shapes:
27
+ * flat `node.inline`, or a single wrapped `prose` child carrying `inline`.
28
+ *
29
+ * Mirrors `paragraphToAstro`'s dual-shape read. Note it does NOT fall back to
30
+ * arbitrary children — only the single-`prose`-child wrapper, matching the
31
+ * importer shape it exists for.
32
+ */
33
+ export declare function leafInline(node: TreeNode): InlineNode[] | undefined;
34
+ /** True when the node carries inline content in either shape. */
35
+ export declare function hasInline(node: TreeNode): boolean;
36
+ /**
37
+ * A node's pre-rendered HTML content, handling both the flat and the
38
+ * wrapped-`prose` shapes.
39
+ *
40
+ * THIRD shape, and the one that bites: several importers (MDX, Starlight,
41
+ * MkDocs) emit `prose` nodes carrying `html` with NO `inline` array at all.
42
+ * A serializer that reads only `inline`/`children` renders those nodes as
43
+ * EMPTY — silently dropping every paragraph and list-item body on a real
44
+ * page. (Found by dogfooding this very package on a real Mintlify → Docusaurus
45
+ * conversion: two paragraphs vanished and every bullet came out bare.)
46
+ */
47
+ export declare function leafHtml(node: TreeNode): string | undefined;
48
+ /** True when the node has content in ANY of the three shapes. */
49
+ export declare function hasContent(node: TreeNode): boolean;
50
+ /**
51
+ * A code node's text.
52
+ *
53
+ * Uses `??` (NOT `||`) deliberately: an explicitly empty `props.code` (`""`)
54
+ * is a real, intentional empty code block and must win over `node.html`.
55
+ * Switching this to `||` silently changes behaviour for empty code blocks.
56
+ */
57
+ export declare function codeText(node: TreeNode): string;
58
+ /**
59
+ * A code node's language.
60
+ *
61
+ * Uses `||` (NOT `??`) deliberately: an empty-string language is meaningless
62
+ * and must fall through to the next candidate, then to `fallback`.
63
+ */
64
+ export declare function codeLang(node: TreeNode, fallback?: string): string;
65
+ /**
66
+ * A tab's display title.
67
+ *
68
+ * Cascade order is `title || label || value`, then an index-based default —
69
+ * which is why the index must be passed rather than this being a plain
70
+ * property pick. (The dogsbay-md parser emits `label`; MDX importers emit
71
+ * `title`; reading only one of them renders every tab as the literal fallback.)
72
+ */
73
+ export declare function tabTitle(tab: TreeNode, index?: number): string;
74
+ /** A tab's stable value/key, falling back to its title. */
75
+ export declare function tabValue(tab: TreeNode, index?: number): string;
76
+ /** The non-content fields of a card / link-card. */
77
+ export interface CardFields {
78
+ title: string;
79
+ href: string;
80
+ icon?: string;
81
+ /** Only the `props.description` fallback — NOT the node's body content. */
82
+ description?: string;
83
+ }
84
+ /**
85
+ * A card's scalar fields.
86
+ *
87
+ * Body content is deliberately NOT resolved here: cards use
88
+ * children-before-inline precedence (the opposite of {@link leafInline}'s
89
+ * inline-first order) and each format escapes the `props.description`
90
+ * fallback differently. Resolve the body with {@link cardBodySources}.
91
+ */
92
+ export declare function cardFields(node: TreeNode): CardFields;
93
+ /**
94
+ * The ordered candidate sources for a card's body, most-preferred first:
95
+ * children → inline → `props.description`.
96
+ *
97
+ * Returned as a discriminated list (rather than a rendered string) because the
98
+ * last source needs format-specific escaping while the first two are rendered
99
+ * through the format's normal paths.
100
+ */
101
+ export declare function cardBodySources(node: TreeNode): Array<{
102
+ kind: "children";
103
+ children: TreeNode[];
104
+ } | {
105
+ kind: "inline";
106
+ inline: InlineNode[];
107
+ } | {
108
+ kind: "text";
109
+ text: string;
110
+ }>;
111
+ /** A heading's level, defaulting to 1. */
112
+ export declare function headingLevel(node: TreeNode): number;
113
+ /**
114
+ * THE Dogsbay heading slug rule — lowercase, drop non-word chars (keeping
115
+ * `_` and `-`), spaces → `-`. This is what the site build assigns as anchor
116
+ * ids (`format-dogsbay-md/src/headings.ts` re-exports it), what
117
+ * `format-dogsbay-md`'s TOC emits, and what every exporter that writes a
118
+ * heading link must use — one rule, so a link and its target cannot
119
+ * disagree. Dedupe (`-1`, `-2`) is the CALLER's job over its own heading
120
+ * set; an explicit `{#id}` replaces the text slug (see `headingFragment`).
121
+ */
122
+ export declare function slugifyHeadingText(text: string): string;
123
+ /** The plain text of a heading across the three TreeNode shapes. */
124
+ export declare function headingText(node: TreeNode): string;
125
+ /**
126
+ * The fragment a link to this heading uses on a Dogsbay site: the explicit
127
+ * `props.slug` (backfilled by the parser's `extractHeadings`, or an author's
128
+ * `{#id}`), else the slug of the text.
129
+ */
130
+ export declare function headingFragment(node: TreeNode): string;
131
+ /**
132
+ * A callout/details variant (`note`, `warning`, …), lower-cased, default
133
+ * `note`. Importers spell this `variant` or `type` depending on source syntax.
134
+ */
135
+ export declare function calloutVariant(node: TreeNode, fallback?: string): string;
136
+ /**
137
+ * An explicit callout title, or undefined when the format should derive one
138
+ * from the variant. `null` is preserved by callers that distinguish
139
+ * "deliberately untitled" from "absent".
140
+ */
141
+ export declare function calloutTitle(node: TreeNode): string | undefined;
142
+ /** An ordered list's start number, or undefined when it starts at 1. */
143
+ export declare function listStart(node: TreeNode): number | undefined;
144
+ /** An image/media source, tolerating `props.src` and `props.url`. */
145
+ export declare function mediaSrc(node: TreeNode): string;
146
+ /**
147
+ * Render a "leaf" node's content (list-item, table cell, step, dt, dd) in the
148
+ * canonical order: inline content first, then block children.
149
+ *
150
+ * This is the ordering `format-astro`'s `leafContent` established and the one
151
+ * the obsidian field-drift fix adopted. Formats supply their own renderers;
152
+ * only the ORDER and the empty-part filtering are shared.
153
+ */
154
+ export declare function renderLeaf(node: TreeNode, renderers: {
155
+ inline: (nodes: InlineNode[]) => string;
156
+ children: (nodes: TreeNode[]) => string;
157
+ /**
158
+ * Render pre-rendered HTML content. Supply this or nodes carrying only
159
+ * `html` (the MDX/Starlight/MkDocs `prose` shape) render as EMPTY —
160
+ * see {@link leafHtml}.
161
+ */
162
+ html?: (html: string) => string;
163
+ join?: string;
164
+ }): string;
165
+ //# sourceMappingURL=reads.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reads.d.ts","sourceRoot":"","sources":["../src/reads.ts"],"names":[],"mappings":"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"}
package/dist/reads.js ADDED
@@ -0,0 +1,268 @@
1
+ /**
2
+ * A node's inline content, handling BOTH shapes:
3
+ * flat `node.inline`, or a single wrapped `prose` child carrying `inline`.
4
+ *
5
+ * Mirrors `paragraphToAstro`'s dual-shape read. Note it does NOT fall back to
6
+ * arbitrary children — only the single-`prose`-child wrapper, matching the
7
+ * importer shape it exists for.
8
+ */
9
+ export function leafInline(node) {
10
+ if (node.inline)
11
+ return node.inline;
12
+ if (node.children?.length === 1 &&
13
+ node.children[0].type === "prose" &&
14
+ node.children[0].inline) {
15
+ return node.children[0].inline;
16
+ }
17
+ return undefined;
18
+ }
19
+ /** True when the node carries inline content in either shape. */
20
+ export function hasInline(node) {
21
+ const inline = leafInline(node);
22
+ return Boolean(inline && inline.length > 0);
23
+ }
24
+ /**
25
+ * A node's pre-rendered HTML content, handling both the flat and the
26
+ * wrapped-`prose` shapes.
27
+ *
28
+ * THIRD shape, and the one that bites: several importers (MDX, Starlight,
29
+ * MkDocs) emit `prose` nodes carrying `html` with NO `inline` array at all.
30
+ * A serializer that reads only `inline`/`children` renders those nodes as
31
+ * EMPTY — silently dropping every paragraph and list-item body on a real
32
+ * page. (Found by dogfooding this very package on a real Mintlify → Docusaurus
33
+ * conversion: two paragraphs vanished and every bullet came out bare.)
34
+ */
35
+ export function leafHtml(node) {
36
+ // Symmetry matters: inline wins over html in BOTH shapes. Returning
37
+ // `node.html` while `node.inline` also exists gave callers writing the
38
+ // natural `leafHtml(n) ?? render(leafInline(n))` opposite precedence on flat
39
+ // vs wrapped nodes.
40
+ if (node.inline && node.inline.length > 0)
41
+ return undefined;
42
+ if (node.html)
43
+ return node.html;
44
+ if (node.children?.length === 1 &&
45
+ node.children[0].type === "prose" &&
46
+ !node.children[0].inline &&
47
+ node.children[0].html) {
48
+ return node.children[0].html;
49
+ }
50
+ return undefined;
51
+ }
52
+ /** True when the node has content in ANY of the three shapes. */
53
+ export function hasContent(node) {
54
+ return (hasInline(node) ||
55
+ Boolean(leafHtml(node)) ||
56
+ Boolean(node.children && node.children.length > 0));
57
+ }
58
+ /**
59
+ * A code node's text.
60
+ *
61
+ * Uses `??` (NOT `||`) deliberately: an explicitly empty `props.code` (`""`)
62
+ * is a real, intentional empty code block and must win over `node.html`.
63
+ * Switching this to `||` silently changes behaviour for empty code blocks.
64
+ */
65
+ export function codeText(node) {
66
+ return (node.props?.code ?? node.html ?? "");
67
+ }
68
+ /**
69
+ * A code node's language.
70
+ *
71
+ * Uses `||` (NOT `??`) deliberately: an empty-string language is meaningless
72
+ * and must fall through to the next candidate, then to `fallback`.
73
+ */
74
+ export function codeLang(node, fallback = "") {
75
+ return ((node.props?.lang || node.props?.language || fallback));
76
+ }
77
+ /**
78
+ * A tab's display title.
79
+ *
80
+ * Cascade order is `title || label || value`, then an index-based default —
81
+ * which is why the index must be passed rather than this being a plain
82
+ * property pick. (The dogsbay-md parser emits `label`; MDX importers emit
83
+ * `title`; reading only one of them renders every tab as the literal fallback.)
84
+ */
85
+ export function tabTitle(tab, index = 0) {
86
+ return (tab.props?.title ||
87
+ tab.props?.label ||
88
+ tab.props?.value ||
89
+ `Tab ${index + 1}`);
90
+ }
91
+ /** A tab's stable value/key, falling back to its title. */
92
+ export function tabValue(tab, index = 0) {
93
+ return tab.props?.value || tabTitle(tab, index);
94
+ }
95
+ /**
96
+ * A card's scalar fields.
97
+ *
98
+ * Body content is deliberately NOT resolved here: cards use
99
+ * children-before-inline precedence (the opposite of {@link leafInline}'s
100
+ * inline-first order) and each format escapes the `props.description`
101
+ * fallback differently. Resolve the body with {@link cardBodySources}.
102
+ */
103
+ export function cardFields(node) {
104
+ return {
105
+ title: node.props?.title ?? "",
106
+ href: node.props?.href ?? "",
107
+ icon: node.props?.icon,
108
+ description: node.props?.description,
109
+ };
110
+ }
111
+ /**
112
+ * The ordered candidate sources for a card's body, most-preferred first:
113
+ * children → inline → `props.description`.
114
+ *
115
+ * Returned as a discriminated list (rather than a rendered string) because the
116
+ * last source needs format-specific escaping while the first two are rendered
117
+ * through the format's normal paths.
118
+ */
119
+ export function cardBodySources(node) {
120
+ const out = [];
121
+ if (node.children && node.children.length > 0) {
122
+ out.push({ kind: "children", children: node.children });
123
+ }
124
+ if (node.inline && node.inline.length > 0) {
125
+ out.push({ kind: "inline", inline: node.inline });
126
+ }
127
+ const description = node.props?.description;
128
+ if (description)
129
+ out.push({ kind: "text", text: description });
130
+ return out;
131
+ }
132
+ /** A heading's level, defaulting to 1. */
133
+ export function headingLevel(node) {
134
+ return node.props?.level ?? 1;
135
+ }
136
+ /**
137
+ * THE Dogsbay heading slug rule — lowercase, drop non-word chars (keeping
138
+ * `_` and `-`), spaces → `-`. This is what the site build assigns as anchor
139
+ * ids (`format-dogsbay-md/src/headings.ts` re-exports it), what
140
+ * `format-dogsbay-md`'s TOC emits, and what every exporter that writes a
141
+ * heading link must use — one rule, so a link and its target cannot
142
+ * disagree. Dedupe (`-1`, `-2`) is the CALLER's job over its own heading
143
+ * set; an explicit `{#id}` replaces the text slug (see `headingFragment`).
144
+ */
145
+ export function slugifyHeadingText(text) {
146
+ return text
147
+ .toLowerCase()
148
+ .replace(/[^\w\s-]/g, "")
149
+ .trim()
150
+ .replace(/\s+/g, "-");
151
+ }
152
+ /** The plain text of a heading across the three TreeNode shapes. */
153
+ export function headingText(node) {
154
+ const fromInline = (nodes) => {
155
+ let out = "";
156
+ for (const n of nodes) {
157
+ if (!n || typeof n !== "object")
158
+ continue;
159
+ const x = n;
160
+ if (typeof x.text === "string")
161
+ out += x.text;
162
+ else if (typeof x.alt === "string")
163
+ out += x.alt;
164
+ if (Array.isArray(x.children))
165
+ out += fromInline(x.children);
166
+ }
167
+ return out;
168
+ };
169
+ if (Array.isArray(node.inline) && node.inline.length)
170
+ return fromInline(node.inline);
171
+ if (typeof node.props?.text === "string" && node.props.text)
172
+ return node.props.text;
173
+ // the wrapped shape: children:[{type:"prose", inline}] (fluidtopics/html importers)
174
+ if (Array.isArray(node.children) && node.children.length) {
175
+ const inner = node.children.map((c) => headingText(c)).join("");
176
+ if (inner)
177
+ return inner;
178
+ }
179
+ if (typeof node.html === "string")
180
+ return node.html.replace(/<[^>]+>/g, "");
181
+ return "";
182
+ }
183
+ /**
184
+ * The fragment a link to this heading uses on a Dogsbay site: the explicit
185
+ * `props.slug` (backfilled by the parser's `extractHeadings`, or an author's
186
+ * `{#id}`), else the slug of the text.
187
+ */
188
+ export function headingFragment(node) {
189
+ const explicit = node.props?.slug;
190
+ if (typeof explicit === "string" && explicit)
191
+ return explicit;
192
+ return slugifyHeadingText(headingText(node));
193
+ }
194
+ /**
195
+ * A callout/details variant (`note`, `warning`, …), lower-cased, default
196
+ * `note`. Importers spell this `variant` or `type` depending on source syntax.
197
+ */
198
+ export function calloutVariant(node, fallback = "note") {
199
+ const raw = node.props?.variant || node.props?.type || fallback;
200
+ return raw.toLowerCase();
201
+ }
202
+ /**
203
+ * An explicit callout title, or undefined when the format should derive one
204
+ * from the variant. `null` is preserved by callers that distinguish
205
+ * "deliberately untitled" from "absent".
206
+ */
207
+ export function calloutTitle(node) {
208
+ const title = node.props?.title;
209
+ // An explicit `title=""` is the author suppressing the auto-title. Mapping it
210
+ // to undefined means "derive one from the variant" and the exporter puts the
211
+ // title back — so the empty string is preserved and only absence is undefined.
212
+ return typeof title === "string" ? title : undefined;
213
+ }
214
+ /** An ordered list's start number, or undefined when it starts at 1. */
215
+ export function listStart(node) {
216
+ const raw = node.props?.start;
217
+ if (raw == null)
218
+ return undefined;
219
+ const n = typeof raw === "number" ? raw : parseInt(String(raw), 10);
220
+ return Number.isNaN(n) ? undefined : n;
221
+ }
222
+ /** An image/media source, tolerating `props.src` and `props.url`. */
223
+ export function mediaSrc(node) {
224
+ return (node.props?.src || node.props?.url || "");
225
+ }
226
+ /**
227
+ * Render a "leaf" node's content (list-item, table cell, step, dt, dd) in the
228
+ * canonical order: inline content first, then block children.
229
+ *
230
+ * This is the ordering `format-astro`'s `leafContent` established and the one
231
+ * the obsidian field-drift fix adopted. Formats supply their own renderers;
232
+ * only the ORDER and the empty-part filtering are shared.
233
+ */
234
+ export function renderLeaf(node, renderers) {
235
+ const parts = [];
236
+ // Go through the TOLERANT reads, not the raw fields. Reading `node.inline` /
237
+ // `node.html` directly meant the wrapped `children:[{prose, html}]` shape
238
+ // never reached the html renderer and rendered EMPTY — the exact field-drift
239
+ // failure this package exists to prevent.
240
+ const inline = leafInline(node);
241
+ const html = leafHtml(node);
242
+ // Provenance is established by IDENTITY against the wrapper child, not by
243
+ // re-deriving it from `node.inline === undefined`. That inference was wrong
244
+ // for a falsy-but-present field: `{ html: "", children:[{prose, html:"H"}] }`
245
+ // read the wrapper, concluded the value was flat, and then descended into
246
+ // children — emitting the same paragraph twice.
247
+ const wrapper = node.children?.length === 1 && node.children[0].type === "prose"
248
+ ? node.children[0]
249
+ : undefined;
250
+ let consumedWrapper = false;
251
+ if (inline && inline.length > 0) {
252
+ parts.push(renderers.inline(inline));
253
+ consumedWrapper = wrapper !== undefined && inline === wrapper.inline;
254
+ }
255
+ else if (html && renderers.html) {
256
+ parts.push(renderers.html(html));
257
+ consumedWrapper = wrapper !== undefined && html === wrapper.html;
258
+ }
259
+ // When the content came from the single wrapped `prose` child, that child is
260
+ // already rendered — descending into children would duplicate it.
261
+ if (!consumedWrapper && node.children && node.children.length > 0) {
262
+ const rendered = renderers.children(node.children);
263
+ if (rendered)
264
+ parts.push(rendered);
265
+ }
266
+ return parts.filter(Boolean).join(renderers.join ?? "\n");
267
+ }
268
+ //# sourceMappingURL=reads.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reads.js","sourceRoot":"","sources":["../src/reads.ts"],"names":[],"mappings":"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"}
package/dist/text.d.ts ADDED
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Format-agnostic text utilities.
3
+ *
4
+ * These are byte-identical (or strictly stronger) versions of helpers
5
+ * currently duplicated across serializers: `indent` exists three times
6
+ * (format-dogsbay-md, format-obsidian, format-astro's `indentStr`), and
7
+ * format-obsidian's `chooseFence` is a weaker `pickCodeFence` (hardcoded
8
+ * backtick, `match` instead of `matchAll`).
9
+ *
10
+ * Only genuinely universal helpers live here. Per-dialect escaping
11
+ * (CommonMark text escaping, Astro brace-neutralising, dogsbay-md attribute
12
+ * syntax) stays in its own package — those profiles are not interchangeable.
13
+ */
14
+ /**
15
+ * Choose a fence long enough to wrap `content` without being terminated early.
16
+ *
17
+ * Scans for the longest run of the fence character and returns one longer,
18
+ * with a minimum of three.
19
+ */
20
+ export declare function pickCodeFence(content: string, fenceChar?: "`" | "~"): string;
21
+ /**
22
+ * Choose a `:::` directive fence long enough to wrap `content`.
23
+ * Used by markdown dialects with container directives (Docusaurus
24
+ * admonitions, MyST, dogsbay-md).
25
+ */
26
+ export declare function pickDirectiveFence(content: string): string;
27
+ /** Indent every non-empty line by `spaces`. Empty lines stay empty. */
28
+ export declare function indent(content: string, spaces: number): string;
29
+ /** Prefix every line, using a trimmed prefix for empty lines (blockquotes). */
30
+ export declare function prefixLines(content: string, prefix: string): string;
31
+ /** Collapse 3+ blank lines to 2 and strip trailing whitespace on each line. */
32
+ export declare function normalizeTrailingWhitespace(content: string): string;
33
+ /**
34
+ * Strip HTML tags, keeping text content — the lossy fallback markdown targets
35
+ * use for HTML they cannot represent. Callers should record the degradation.
36
+ */
37
+ export declare function stripHtml(html: string): string;
38
+ /**
39
+ * Convert common INLINE HTML back to markdown.
40
+ *
41
+ * Importers frequently hand serializers pre-rendered HTML for prose
42
+ * (`<code>x</code>`, `<strong>y</strong>`). Passing it through works in
43
+ * MDX-ish targets but produces source no human wants to maintain — and the
44
+ * point of a migration is clean, editable markdown.
45
+ *
46
+ * Deliberately conservative: only unambiguous inline tags, non-greedy, and
47
+ * block-level markup is left completely alone (a regex cannot restructure
48
+ * tables or lists safely). Anything not listed here survives as raw HTML.
49
+ */
50
+ export declare function inlineHtmlToMarkdown(html: string): string;
51
+ /** Serialize a value as YAML frontmatter scalar, quoting when required. */
52
+ export declare function yamlScalar(value: string): string;
53
+ /** Build a YAML frontmatter block from ordered entries. Empty → "". */
54
+ export declare function frontmatterBlock(entries: Array<[string, string | number | boolean | undefined]>): string;
55
+ //# sourceMappingURL=text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../src/text.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,GAAE,GAAG,GAAG,GAAS,GAAG,MAAM,CAOjF;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAM1D;AAED,uEAAuE;AACvE,wBAAgB,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAM9D;AAED,+EAA+E;AAC/E,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAKnE;AAED,+EAA+E;AAC/E,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAMnE;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAkC9C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAwBzD;AAkBD,2EAA2E;AAC3E,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CA8BhD;AAED,uEAAuE;AACvE,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC,GAC9D,MAAM,CAQR"}