@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,142 @@
1
+ /**
2
+ * Export capability declaration + loss ledger.
3
+ *
4
+ * Every target format can represent only part of the TreeNode vocabulary.
5
+ * Obsidian has no per-element `class`; Docusaurus has no `<Steps>`; plain
6
+ * markdown has no tabs at all. Today that knowledge is scattered — five
7
+ * near-identical ledger shapes exist across packages
8
+ * (`MdxLedgerEntry`, `DitaConversionNote`, `FidelityIssue`,
9
+ * `TranslateLedgerEntry` ×2) with nothing shared, and the one export-side
10
+ * fallback that exists (`format-dogsbay-md`'s `renderUnknown`) records
11
+ * *nothing* — its `skip` mode is silent loss. `format-obsidian`'s attribute
12
+ * dropping is documented in a CLAUDE.md and recorded nowhere.
13
+ *
14
+ * This module gives exporters two complementary, required surfaces:
15
+ *
16
+ * 1. **Static declaration** ({@link CapabilityDeclaration}) — what the format
17
+ * structurally cannot represent, known before any content is seen. It is
18
+ * documentation: publishable, diffable, and answerable up front ("what do
19
+ * I lose migrating to Docusaurus?").
20
+ * 2. **Observed ledger** ({@link ExportLedger}) — what *this* conversion
21
+ * actually dropped or degraded, per page. Answers "what did I lose in MY
22
+ * content?", which is usually a much shorter list than the static one.
23
+ *
24
+ * The discipline, inherited from format-dita: **known loss, never silent
25
+ * loss.**
26
+ */
27
+ /** How completely a target format supports a feature. */
28
+ export type SupportLevel =
29
+ /** Round-trips faithfully. */
30
+ "full"
31
+ /** Representable, but something is lost (styling, semantics, nesting). */
32
+ | "partial"
33
+ /** Cannot be represented at all; content is dropped or flattened. */
34
+ | "none";
35
+ /** A static statement about one feature in one target format. */
36
+ export interface CapabilityDeclaration {
37
+ /**
38
+ * TreeNode type (`"tabs"`, `"callout"`) or a named cross-cutting concern
39
+ * (`"per-element class"`, `"nested tabs"`).
40
+ */
41
+ feature: string;
42
+ support: SupportLevel;
43
+ /**
44
+ * How it degrades and what the reader should expect. REQUIRED whenever
45
+ * support is not "full" — a bare "partial" with no explanation is exactly
46
+ * the silent-loss problem this module exists to prevent.
47
+ */
48
+ note?: string;
49
+ /** What the feature becomes in the output, when it survives in some form. */
50
+ rendersAs?: string;
51
+ }
52
+ /** What happened to a specific piece of content during one export. */
53
+ export type LossAction =
54
+ /** Content was removed entirely. */
55
+ "dropped"
56
+ /** Content survived, but with reduced fidelity (e.g. styling stripped). */
57
+ | "degraded"
58
+ /** Content was mapped onto a near-equivalent construct. */
59
+ | "approximated";
60
+ /** One observed loss event. */
61
+ export interface ExportLedgerEntry {
62
+ /** TreeNode type or named concern — matches a {@link CapabilityDeclaration}. */
63
+ feature: string;
64
+ action: LossAction;
65
+ /** Human-readable specifics for this occurrence. */
66
+ detail?: string;
67
+ /** Page slug where it happened, when known. */
68
+ page?: string;
69
+ }
70
+ /** Aggregated view of a ledger, grouped by feature+action. */
71
+ export interface LedgerSummaryRow {
72
+ feature: string;
73
+ action: LossAction;
74
+ count: number;
75
+ pages: string[];
76
+ /** First detail seen for this group — representative, not exhaustive. */
77
+ detail?: string;
78
+ }
79
+ /**
80
+ * Collects loss events during an export.
81
+ *
82
+ * Exporters create one per run, pass it down, and call {@link record} at every
83
+ * point they drop or degrade something. Cheap by design: recording is a push,
84
+ * and a clean export costs one empty array.
85
+ */
86
+ export declare class ExportLedger {
87
+ private readonly items;
88
+ /** Page slug stamped onto entries recorded without an explicit one. */
89
+ private currentPage?;
90
+ /** Scope subsequent {@link record} calls to a page. */
91
+ setPage(page: string | undefined): void;
92
+ /** Record one loss event. */
93
+ record(entry: ExportLedgerEntry): void;
94
+ /** Convenience: record a dropped feature. */
95
+ drop(feature: string, detail?: string): void;
96
+ /** Convenience: record a degraded feature. */
97
+ degrade(feature: string, detail?: string): void;
98
+ /** Convenience: record an approximated feature. */
99
+ approximate(feature: string, detail?: string): void;
100
+ /** All recorded entries, in order. */
101
+ get entries(): readonly ExportLedgerEntry[];
102
+ get isEmpty(): boolean;
103
+ get size(): number;
104
+ /**
105
+ * Aggregate by feature+action, most frequent first — the shape a report
106
+ * prints. Mirrors `format-mdx`'s `printLedgerReport` grouping.
107
+ */
108
+ summary(): LedgerSummaryRow[];
109
+ }
110
+ /**
111
+ * Render the observed ledger as plain text for the CLI.
112
+ *
113
+ * Empty state is explicit and positive ("nothing was dropped") — the
114
+ * import-dita precedent — so a clean run is visibly clean rather than silent.
115
+ */
116
+ export declare function formatLedgerReport(ledger: ExportLedger, formatName: string): string;
117
+ /**
118
+ * Render a format's static capability declaration as a markdown table, for
119
+ * publishing in the package's docs ("what this exporter cannot support").
120
+ *
121
+ * Sorted worst-first (none → partial → full) so the limitations lead.
122
+ */
123
+ export declare function formatCapabilityTable(capabilities: readonly CapabilityDeclaration[]): string;
124
+ /**
125
+ * Cross-check an OBSERVED ledger against the STATIC declaration.
126
+ *
127
+ * `validateCapabilities` only checks the declaration's internal consistency; it
128
+ * cannot catch a degradation that was never declared. This closes that gap: a
129
+ * feature recorded as lost must be declared, and must not be declared `full`.
130
+ * Exporters assert it in tests so undocumented loss cannot ship.
131
+ */
132
+ export declare function validateLedgerAgainstCapabilities(ledger: ExportLedger, capabilities: readonly CapabilityDeclaration[]): string[];
133
+ /** The features a format cannot represent at all — the headline limitations. */
134
+ export declare function unsupportedFeatures(capabilities: readonly CapabilityDeclaration[]): CapabilityDeclaration[];
135
+ /**
136
+ * Validate a declaration set: every non-full entry must explain itself, and
137
+ * features must not be declared twice. Returns problem strings (empty = valid).
138
+ * Exporters assert this in their tests so an undocumented degradation cannot
139
+ * ship.
140
+ */
141
+ export declare function validateCapabilities(capabilities: readonly CapabilityDeclaration[]): string[];
142
+ //# sourceMappingURL=capability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,yDAAyD;AACzD,MAAM,MAAM,YAAY;AACtB,8BAA8B;AAC5B,MAAM;AACR,0EAA0E;GACxE,SAAS;AACX,qEAAqE;GACnE,MAAM,CAAC;AAEX,iEAAiE;AACjE,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,YAAY,CAAC;IACtB;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,sEAAsE;AACtE,MAAM,MAAM,UAAU;AACpB,oCAAoC;AAClC,SAAS;AACX,2EAA2E;GACzE,UAAU;AACZ,2DAA2D;GACzD,cAAc,CAAC;AAEnB,+BAA+B;AAC/B,MAAM,WAAW,iBAAiB;IAChC,gFAAgF;IAChF,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,UAAU,CAAC;IACnB,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,8DAA8D;AAC9D,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;GAMG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA2B;IACjD,uEAAuE;IACvE,OAAO,CAAC,WAAW,CAAC,CAAS;IAE7B,uDAAuD;IACvD,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAIvC,6BAA6B;IAC7B,MAAM,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI;IAOtC,6CAA6C;IAC7C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAI5C,8CAA8C;IAC9C,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAI/C,mDAAmD;IACnD,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAInD,sCAAsC;IACtC,IAAI,OAAO,IAAI,SAAS,iBAAiB,EAAE,CAE1C;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;OAGG;IACH,OAAO,IAAI,gBAAgB,EAAE;CAoB9B;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,MAAM,GACjB,MAAM,CAgBR;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,SAAS,qBAAqB,EAAE,GAC7C,MAAM,CAmBR;AAED;;;;;;;GAOG;AACH,wBAAgB,iCAAiC,CAC/C,MAAM,EAAE,YAAY,EACpB,YAAY,EAAE,SAAS,qBAAqB,EAAE,GAC7C,MAAM,EAAE,CAmBV;AAED,gFAAgF;AAChF,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,SAAS,qBAAqB,EAAE,GAC7C,qBAAqB,EAAE,CAEzB;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,SAAS,qBAAqB,EAAE,GAC7C,MAAM,EAAE,CAaV"}
@@ -0,0 +1,189 @@
1
+ /**
2
+ * Export capability declaration + loss ledger.
3
+ *
4
+ * Every target format can represent only part of the TreeNode vocabulary.
5
+ * Obsidian has no per-element `class`; Docusaurus has no `<Steps>`; plain
6
+ * markdown has no tabs at all. Today that knowledge is scattered — five
7
+ * near-identical ledger shapes exist across packages
8
+ * (`MdxLedgerEntry`, `DitaConversionNote`, `FidelityIssue`,
9
+ * `TranslateLedgerEntry` ×2) with nothing shared, and the one export-side
10
+ * fallback that exists (`format-dogsbay-md`'s `renderUnknown`) records
11
+ * *nothing* — its `skip` mode is silent loss. `format-obsidian`'s attribute
12
+ * dropping is documented in a CLAUDE.md and recorded nowhere.
13
+ *
14
+ * This module gives exporters two complementary, required surfaces:
15
+ *
16
+ * 1. **Static declaration** ({@link CapabilityDeclaration}) — what the format
17
+ * structurally cannot represent, known before any content is seen. It is
18
+ * documentation: publishable, diffable, and answerable up front ("what do
19
+ * I lose migrating to Docusaurus?").
20
+ * 2. **Observed ledger** ({@link ExportLedger}) — what *this* conversion
21
+ * actually dropped or degraded, per page. Answers "what did I lose in MY
22
+ * content?", which is usually a much shorter list than the static one.
23
+ *
24
+ * The discipline, inherited from format-dita: **known loss, never silent
25
+ * loss.**
26
+ */
27
+ /**
28
+ * Collects loss events during an export.
29
+ *
30
+ * Exporters create one per run, pass it down, and call {@link record} at every
31
+ * point they drop or degrade something. Cheap by design: recording is a push,
32
+ * and a clean export costs one empty array.
33
+ */
34
+ export class ExportLedger {
35
+ items = [];
36
+ /** Page slug stamped onto entries recorded without an explicit one. */
37
+ currentPage;
38
+ /** Scope subsequent {@link record} calls to a page. */
39
+ setPage(page) {
40
+ this.currentPage = page;
41
+ }
42
+ /** Record one loss event. */
43
+ record(entry) {
44
+ this.items.push({
45
+ ...entry,
46
+ page: entry.page ?? this.currentPage,
47
+ });
48
+ }
49
+ /** Convenience: record a dropped feature. */
50
+ drop(feature, detail) {
51
+ this.record({ feature, action: "dropped", detail });
52
+ }
53
+ /** Convenience: record a degraded feature. */
54
+ degrade(feature, detail) {
55
+ this.record({ feature, action: "degraded", detail });
56
+ }
57
+ /** Convenience: record an approximated feature. */
58
+ approximate(feature, detail) {
59
+ this.record({ feature, action: "approximated", detail });
60
+ }
61
+ /** All recorded entries, in order. */
62
+ get entries() {
63
+ return this.items;
64
+ }
65
+ get isEmpty() {
66
+ return this.items.length === 0;
67
+ }
68
+ get size() {
69
+ return this.items.length;
70
+ }
71
+ /**
72
+ * Aggregate by feature+action, most frequent first — the shape a report
73
+ * prints. Mirrors `format-mdx`'s `printLedgerReport` grouping.
74
+ */
75
+ summary() {
76
+ const groups = new Map();
77
+ for (const entry of this.items) {
78
+ const key = `${entry.feature}\t${entry.action}`;
79
+ let row = groups.get(key);
80
+ if (!row) {
81
+ row = {
82
+ feature: entry.feature,
83
+ action: entry.action,
84
+ count: 0,
85
+ pages: [],
86
+ detail: entry.detail,
87
+ };
88
+ groups.set(key, row);
89
+ }
90
+ row.count++;
91
+ if (entry.page && !row.pages.includes(entry.page))
92
+ row.pages.push(entry.page);
93
+ }
94
+ return [...groups.values()].sort((a, b) => b.count - a.count);
95
+ }
96
+ }
97
+ /**
98
+ * Render the observed ledger as plain text for the CLI.
99
+ *
100
+ * Empty state is explicit and positive ("nothing was dropped") — the
101
+ * import-dita precedent — so a clean run is visibly clean rather than silent.
102
+ */
103
+ export function formatLedgerReport(ledger, formatName) {
104
+ if (ledger.isEmpty) {
105
+ return `${formatName} export: nothing was dropped or degraded.`;
106
+ }
107
+ const lines = [
108
+ `${formatName} export — ${ledger.size} fidelity note(s):`,
109
+ ];
110
+ for (const row of ledger.summary()) {
111
+ const where = row.pages.length > 0
112
+ ? ` (${row.pages.length} page${row.pages.length === 1 ? "" : "s"})`
113
+ : "";
114
+ const detail = row.detail ? ` — ${row.detail}` : "";
115
+ lines.push(` ${row.feature} ${row.action} ×${row.count}${where}${detail}`);
116
+ }
117
+ return lines.join("\n");
118
+ }
119
+ /**
120
+ * Render a format's static capability declaration as a markdown table, for
121
+ * publishing in the package's docs ("what this exporter cannot support").
122
+ *
123
+ * Sorted worst-first (none → partial → full) so the limitations lead.
124
+ */
125
+ export function formatCapabilityTable(capabilities) {
126
+ const rank = { none: 0, partial: 1, full: 2 };
127
+ const sorted = [...capabilities].sort((a, b) => rank[a.support] - rank[b.support] || a.feature.localeCompare(b.feature));
128
+ const icon = {
129
+ full: "✅ full",
130
+ partial: "⚠️ partial",
131
+ none: "❌ none",
132
+ };
133
+ const rows = sorted.map((c) => `| ${c.feature} | ${icon[c.support]} | ${c.rendersAs ?? "—"} | ${c.note ?? ""} |`);
134
+ return [
135
+ "| Feature | Support | Renders as | Notes |",
136
+ "|---|---|---|---|",
137
+ ...rows,
138
+ ].join("\n");
139
+ }
140
+ /**
141
+ * Cross-check an OBSERVED ledger against the STATIC declaration.
142
+ *
143
+ * `validateCapabilities` only checks the declaration's internal consistency; it
144
+ * cannot catch a degradation that was never declared. This closes that gap: a
145
+ * feature recorded as lost must be declared, and must not be declared `full`.
146
+ * Exporters assert it in tests so undocumented loss cannot ship.
147
+ */
148
+ export function validateLedgerAgainstCapabilities(ledger, capabilities) {
149
+ const byFeature = new Map(capabilities.map((c) => [c.feature, c]));
150
+ const problems = [];
151
+ const seen = new Set();
152
+ for (const row of ledger.summary()) {
153
+ if (seen.has(row.feature))
154
+ continue;
155
+ seen.add(row.feature);
156
+ const declared = byFeature.get(row.feature);
157
+ if (!declared) {
158
+ problems.push(`"${row.feature}" was ${row.action} at runtime but is not declared in the capability table`);
159
+ }
160
+ else if (declared.support === "full") {
161
+ problems.push(`"${row.feature}" is declared full but was ${row.action} at runtime`);
162
+ }
163
+ }
164
+ return problems;
165
+ }
166
+ /** The features a format cannot represent at all — the headline limitations. */
167
+ export function unsupportedFeatures(capabilities) {
168
+ return capabilities.filter((c) => c.support === "none");
169
+ }
170
+ /**
171
+ * Validate a declaration set: every non-full entry must explain itself, and
172
+ * features must not be declared twice. Returns problem strings (empty = valid).
173
+ * Exporters assert this in their tests so an undocumented degradation cannot
174
+ * ship.
175
+ */
176
+ export function validateCapabilities(capabilities) {
177
+ const problems = [];
178
+ const seen = new Set();
179
+ for (const cap of capabilities) {
180
+ if (seen.has(cap.feature))
181
+ problems.push(`duplicate declaration: ${cap.feature}`);
182
+ seen.add(cap.feature);
183
+ if (cap.support !== "full" && !cap.note) {
184
+ problems.push(`"${cap.feature}" is declared ${cap.support} but has no note explaining the loss`);
185
+ }
186
+ }
187
+ return problems;
188
+ }
189
+ //# sourceMappingURL=capability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capability.js","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AA2DH;;;;;;GAMG;AACH,MAAM,OAAO,YAAY;IACN,KAAK,GAAwB,EAAE,CAAC;IACjD,uEAAuE;IAC/D,WAAW,CAAU;IAE7B,uDAAuD;IACvD,OAAO,CAAC,IAAwB;QAC9B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IAC1B,CAAC;IAED,6BAA6B;IAC7B,MAAM,CAAC,KAAwB;QAC7B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;YACd,GAAG,KAAK;YACR,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,WAAW;SACrC,CAAC,CAAC;IACL,CAAC;IAED,6CAA6C;IAC7C,IAAI,CAAC,OAAe,EAAE,MAAe;QACnC,IAAI,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,8CAA8C;IAC9C,OAAO,CAAC,OAAe,EAAE,MAAe;QACtC,IAAI,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC;IACvD,CAAC;IAED,mDAAmD;IACnD,WAAW,CAAC,OAAe,EAAE,MAAe;QAC1C,IAAI,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,sCAAsC;IACtC,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC;IACjC,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IAC3B,CAAC;IAED;;;OAGG;IACH,OAAO;QACL,MAAM,MAAM,GAAG,IAAI,GAAG,EAA4B,CAAC;QACnD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC/B,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC,OAAO,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC;YAChD,IAAI,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC1B,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,GAAG,GAAG;oBACJ,OAAO,EAAE,KAAK,CAAC,OAAO;oBACtB,MAAM,EAAE,KAAK,CAAC,MAAM;oBACpB,KAAK,EAAE,CAAC;oBACR,KAAK,EAAE,EAAE;oBACT,MAAM,EAAE,KAAK,CAAC,MAAM;iBACrB,CAAC;gBACF,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACvB,CAAC;YACD,GAAG,CAAC,KAAK,EAAE,CAAC;YACZ,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;gBAAE,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAChF,CAAC;QACD,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAChE,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAChC,MAAoB,EACpB,UAAkB;IAElB,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,OAAO,GAAG,UAAU,2CAA2C,CAAC;IAClE,CAAC;IACD,MAAM,KAAK,GAAa;QACtB,GAAG,UAAU,aAAa,MAAM,CAAC,IAAI,oBAAoB;KAC1D,CAAC;IACF,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;QACnC,MAAM,KAAK,GACT,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;YAClB,CAAC,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG;YACnE,CAAC,CAAC,EAAE,CAAC;QACT,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpD,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,KAAK,GAAG,KAAK,GAAG,MAAM,EAAE,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CACnC,YAA8C;IAE9C,MAAM,IAAI,GAAiC,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAC5E,MAAM,MAAM,GAAG,CAAC,GAAG,YAAY,CAAC,CAAC,IAAI,CACnC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAClF,CAAC;IACF,MAAM,IAAI,GAAiC;QACzC,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,YAAY;QACrB,IAAI,EAAE,QAAQ;KACf,CAAC;IACF,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CACrB,CAAC,CAAC,EAAE,EAAE,CACJ,KAAK,CAAC,CAAC,OAAO,MAAM,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,SAAS,IAAI,GAAG,MAAM,CAAC,CAAC,IAAI,IAAI,EAAE,IAAI,CACpF,CAAC;IACF,OAAO;QACL,4CAA4C;QAC5C,mBAAmB;QACnB,GAAG,IAAI;KACR,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iCAAiC,CAC/C,MAAoB,EACpB,YAA8C;IAE9C,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACnE,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;QACnC,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;YAAE,SAAS;QACpC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACtB,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC5C,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,QAAQ,CAAC,IAAI,CACX,IAAI,GAAG,CAAC,OAAO,SAAS,GAAG,CAAC,MAAM,yDAAyD,CAC5F,CAAC;QACJ,CAAC;aAAM,IAAI,QAAQ,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC;YACvC,QAAQ,CAAC,IAAI,CACX,IAAI,GAAG,CAAC,OAAO,8BAA8B,GAAG,CAAC,MAAM,aAAa,CACrE,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,mBAAmB,CACjC,YAA8C;IAE9C,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC;AAC1D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAClC,YAA8C;IAE9C,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAC/B,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,0BAA0B,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QAClF,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACtB,IAAI,GAAG,CAAC,OAAO,KAAK,MAAM,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;YACxC,QAAQ,CAAC,IAAI,CACX,IAAI,GAAG,CAAC,OAAO,iBAAiB,GAAG,CAAC,OAAO,sCAAsC,CAClF,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Include realization — splice transcluded fragments into the tree.
3
+ *
4
+ * An `include` node (`{% include "path" %}`, AsciiDoc `include::`, a DITA
5
+ * conref, an MDX snippet import) is a TRANSCLUSION: the content lives in
6
+ * another file and belongs at that point in this page. Exactly one exporter —
7
+ * `format-dogsbay-md` — has syntax to carry the reference itself. Every other
8
+ * target must put the content IN, or the page ships with a hole in it.
9
+ *
10
+ * Before this existed, they put nothing in:
11
+ *
12
+ * dogsbay-md {% include "_snippets/warn.md" %} ← preserved
13
+ * docusaurus <!-- unsupported: include --> ← recorded, no content
14
+ * astro (nothing) ← silent
15
+ * obsidian (nothing) ← silent
16
+ *
17
+ * That mattered beyond the edge case: `dogsbay site build` resolves includes in
18
+ * a Minja preprocessing pass BEFORE parsing, so the supported publish path was
19
+ * fine — but `dogsbay convert --to astro` on the same corpus emitted `<p></p>`
20
+ * where every include had been. A corpus migrated from AsciiDoc (OpenShift:
21
+ * every `include::` becomes `{% include %}`) lost all of them on any second
22
+ * conversion, with no warning.
23
+ *
24
+ * This module is deliberately I/O-FREE: the caller supplies `resolve`, which
25
+ * maps an include's `src` to the fragment's nodes (reading and parsing however
26
+ * that format does it). Keeps the core pure and testable, and lets the same
27
+ * pass serve a filesystem importer, an in-memory editor, or a hosted runner.
28
+ */
29
+ import type { TreeNode } from "@dogsbay/types";
30
+ export interface RealizeResult {
31
+ tree: TreeNode[];
32
+ /** Include sources successfully spliced, in encounter order. */
33
+ realized: string[];
34
+ /** Include sources the resolver could not supply — reported, never silent. */
35
+ missing: string[];
36
+ /** Sources dropped because including them would recurse forever. */
37
+ cyclic: string[];
38
+ /**
39
+ * Sources dropped for exceeding `maxDepth` — legitimately nested too deep,
40
+ * NOT self-referential. Reporting these as cyclic told operators their
41
+ * content referred to itself when it merely nested.
42
+ */
43
+ tooDeep: string[];
44
+ }
45
+ export interface RealizeOptions {
46
+ /**
47
+ * Fragment lookup. Return the fragment's nodes, or null when it cannot be
48
+ * resolved (missing file, unreadable, outside the corpus).
49
+ */
50
+ resolve: (src: string, node: TreeNode) => TreeNode[] | null;
51
+ /**
52
+ * Depth limit for includes that themselves include. Default 10 — deep enough
53
+ * for real doc sets (OpenShift nests two or three), shallow enough that a
54
+ * pathological chain terminates.
55
+ */
56
+ maxDepth?: number;
57
+ }
58
+ /**
59
+ * Replace every `include` node with the nodes of its fragment.
60
+ *
61
+ * Cycles are detected by the ACTIVE path, not a global seen-set: a fragment
62
+ * legitimately included by twenty pages must resolve twenty times, while
63
+ * `a → b → a` must not recurse. The offending node is dropped and recorded.
64
+ */
65
+ export declare function realizeIncludes(nodes: TreeNode[], options: RealizeOptions): RealizeResult;
66
+ /** True when the tree contains an include anywhere. Cheap pre-check. */
67
+ export declare function hasIncludes(nodes: TreeNode[]): boolean;
68
+ //# sourceMappingURL=includes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"includes.d.ts","sourceRoot":"","sources":["../src/includes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,gEAAgE;IAChE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,8EAA8E;IAC9E,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,oEAAoE;IACpE,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB;;;;OAIG;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,KAAK,QAAQ,EAAE,GAAG,IAAI,CAAC;IAC5D;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,QAAQ,EAAE,EACjB,OAAO,EAAE,cAAc,GACtB,aAAa,CAsDf;AAwBD,wEAAwE;AACxE,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAMtD"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Replace every `include` node with the nodes of its fragment.
3
+ *
4
+ * Cycles are detected by the ACTIVE path, not a global seen-set: a fragment
5
+ * legitimately included by twenty pages must resolve twenty times, while
6
+ * `a → b → a` must not recurse. The offending node is dropped and recorded.
7
+ */
8
+ export function realizeIncludes(nodes, options) {
9
+ const maxDepth = options.maxDepth ?? 10;
10
+ const realized = [];
11
+ const missing = [];
12
+ const cyclic = [];
13
+ const tooDeep = [];
14
+ const walk = (list, active) => {
15
+ const out = [];
16
+ for (const node of list) {
17
+ if (node.type === "include") {
18
+ const src = String(node.props?.src ?? "");
19
+ if (!src) {
20
+ missing.push("(include with no src)");
21
+ continue;
22
+ }
23
+ if (active.includes(src)) {
24
+ cyclic.push(src);
25
+ continue;
26
+ }
27
+ if (active.length >= maxDepth) {
28
+ tooDeep.push(src);
29
+ continue;
30
+ }
31
+ const fragment = options.resolve(src, node);
32
+ if (!fragment) {
33
+ missing.push(src);
34
+ continue;
35
+ }
36
+ realized.push(src);
37
+ // Recurse: a fragment may include further fragments.
38
+ //
39
+ // `cloneTree` is load-bearing. One fragment is spliced into many pages
40
+ // and the resolver may hand back the SAME node objects each time (a
41
+ // cache, or the page set). Rebuilding only the spine left `inline`
42
+ // arrays and `props` objects ALIASED, so any later per-page pass — an
43
+ // href rewrite, a heading-level offset — mutated every other consumer
44
+ // and the cached fragment itself.
45
+ out.push(...walk(cloneTree(fragment), [...active, src]));
46
+ continue;
47
+ }
48
+ if (node.children) {
49
+ // Rebuild the node rather than mutating the caller's tree — the same
50
+ // fragment nodes can be spliced into several pages, and mutating them
51
+ // in place would corrupt every other use.
52
+ out.push({ ...node, children: walk(node.children, active) });
53
+ continue;
54
+ }
55
+ out.push(node);
56
+ }
57
+ return out;
58
+ };
59
+ return { tree: walk(nodes, []), realized, missing, cyclic, tooDeep };
60
+ }
61
+ /** Structural deep copy, so a spliced fragment is never aliased across pages. */
62
+ function cloneTree(nodes) {
63
+ return nodes.map((node) => {
64
+ const copy = { ...node };
65
+ if (node.props)
66
+ copy.props = { ...node.props };
67
+ if (node.inline)
68
+ copy.inline = node.inline.map((i) => cloneInline(i));
69
+ if (node.children)
70
+ copy.children = cloneTree(node.children);
71
+ return copy;
72
+ });
73
+ }
74
+ function cloneInline(node) {
75
+ const copy = { ...node };
76
+ if (Array.isArray(copy.children)) {
77
+ copy.children = copy.children.map((c) => cloneInline(c));
78
+ }
79
+ if (copy.attrs && typeof copy.attrs === "object") {
80
+ copy.attrs = { ...copy.attrs };
81
+ }
82
+ return copy;
83
+ }
84
+ /** True when the tree contains an include anywhere. Cheap pre-check. */
85
+ export function hasIncludes(nodes) {
86
+ for (const node of nodes) {
87
+ if (node.type === "include")
88
+ return true;
89
+ if (node.children && hasIncludes(node.children))
90
+ return true;
91
+ }
92
+ return false;
93
+ }
94
+ //# sourceMappingURL=includes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"includes.js","sourceRoot":"","sources":["../src/includes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @dogsbay/serialize-core — the shared machinery every format exporter builds on.
3
+ *
4
+ * Three layers, in value order:
5
+ *
6
+ * 1. **Shape-tolerant reads** (`reads.ts`) — one place that knows WHERE a value
7
+ * lives on a TreeNode. Eliminates the field-drift bug class where a
8
+ * serializer reads a field the parser doesn't emit and silently emits
9
+ * nothing.
10
+ * 2. **Generic inline walker** (`inline.ts`) — the 11-variant InlineNode switch,
11
+ * written once, with markdown and HTML emitter presets.
12
+ * 3. **Capability + ledger** (`capability.ts`) — every exporter declares what it
13
+ * cannot represent (static) and records what it actually lost (observed).
14
+ * Known loss, never silent loss.
15
+ *
16
+ * Plus format-agnostic text helpers (`text.ts`) and an unknown-node fallback
17
+ * that reports instead of silently dropping (`unknown.ts`).
18
+ */
19
+ export { leafInline, leafHtml, hasInline, hasContent, codeText, codeLang, tabTitle, tabValue, cardFields, cardBodySources, headingLevel, headingText, headingFragment, slugifyHeadingText, calloutVariant, calloutTitle, listStart, mediaSrc, renderLeaf, type CardFields, } from "./reads.js";
20
+ export { walkInline, applyTextFlags, inlinePlainText, markdownInlineEmitters, htmlInlineEmitters, escapeHtml, escapeAttr, codeSpan, type InlineContext, type InlineEmitters, type InlineWalkOptions, } from "./inline.js";
21
+ export { ExportLedger, formatLedgerReport, formatCapabilityTable, unsupportedFeatures, validateCapabilities, validateLedgerAgainstCapabilities, type SupportLevel, type CapabilityDeclaration, type LossAction, type ExportLedgerEntry, type LedgerSummaryRow, } from "./capability.js";
22
+ export { pickCodeFence, pickDirectiveFence, indent, prefixLines, normalizeTrailingWhitespace, stripHtml, inlineHtmlToMarkdown, yamlScalar, frontmatterBlock, } from "./text.js";
23
+ export { resolvePlugins, composeCapabilities, formatPluginConflicts, type ExportPluginMeta, type ResolvedPlugins, type ProviderConflict, type InvalidOverride, type ResolveOptions, } from "./plugins.js";
24
+ export { realizeIncludes, hasIncludes, type RealizeResult, type RealizeOptions, } from "./includes.js";
25
+ export { renderUnknownNode, type UnknownNodePolicy, type UnknownNodeOptions, } from "./unknown.js";
26
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EACL,UAAU,EACV,QAAQ,EACR,SAAS,EACT,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,eAAe,EACf,YAAY,EACZ,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,UAAU,EACV,KAAK,UAAU,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,UAAU,EACV,cAAc,EACd,eAAe,EACf,sBAAsB,EACtB,kBAAkB,EAClB,UAAU,EACV,UAAU,EACV,QAAQ,EACR,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,iBAAiB,GACvB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,iCAAiC,EACjC,KAAK,YAAY,EACjB,KAAK,qBAAqB,EAC1B,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,GACtB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,MAAM,EACN,WAAW,EACX,2BAA2B,EAC3B,SAAS,EACT,oBAAoB,EACpB,UAAU,EACV,gBAAgB,GACjB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,qBAAqB,EACrB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,cAAc,GACpB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,eAAe,EACf,WAAW,EACX,KAAK,aAAa,EAClB,KAAK,cAAc,GACpB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,iBAAiB,EACjB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,GACxB,MAAM,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @dogsbay/serialize-core — the shared machinery every format exporter builds on.
3
+ *
4
+ * Three layers, in value order:
5
+ *
6
+ * 1. **Shape-tolerant reads** (`reads.ts`) — one place that knows WHERE a value
7
+ * lives on a TreeNode. Eliminates the field-drift bug class where a
8
+ * serializer reads a field the parser doesn't emit and silently emits
9
+ * nothing.
10
+ * 2. **Generic inline walker** (`inline.ts`) — the 11-variant InlineNode switch,
11
+ * written once, with markdown and HTML emitter presets.
12
+ * 3. **Capability + ledger** (`capability.ts`) — every exporter declares what it
13
+ * cannot represent (static) and records what it actually lost (observed).
14
+ * Known loss, never silent loss.
15
+ *
16
+ * Plus format-agnostic text helpers (`text.ts`) and an unknown-node fallback
17
+ * that reports instead of silently dropping (`unknown.ts`).
18
+ */
19
+ export { leafInline, leafHtml, hasInline, hasContent, codeText, codeLang, tabTitle, tabValue, cardFields, cardBodySources, headingLevel, headingText, headingFragment, slugifyHeadingText, calloutVariant, calloutTitle, listStart, mediaSrc, renderLeaf, } from "./reads.js";
20
+ export { walkInline, applyTextFlags, inlinePlainText, markdownInlineEmitters, htmlInlineEmitters, escapeHtml, escapeAttr, codeSpan, } from "./inline.js";
21
+ export { ExportLedger, formatLedgerReport, formatCapabilityTable, unsupportedFeatures, validateCapabilities, validateLedgerAgainstCapabilities, } from "./capability.js";
22
+ export { pickCodeFence, pickDirectiveFence, indent, prefixLines, normalizeTrailingWhitespace, stripHtml, inlineHtmlToMarkdown, yamlScalar, frontmatterBlock, } from "./text.js";
23
+ export { resolvePlugins, composeCapabilities, formatPluginConflicts, } from "./plugins.js";
24
+ export { realizeIncludes, hasIncludes, } from "./includes.js";
25
+ export { renderUnknownNode, } from "./unknown.js";
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EACL,UAAU,EACV,QAAQ,EACR,SAAS,EACT,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,eAAe,EACf,YAAY,EACZ,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,UAAU,GAEX,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,UAAU,EACV,cAAc,EACd,eAAe,EACf,sBAAsB,EACtB,kBAAkB,EAClB,UAAU,EACV,UAAU,EACV,QAAQ,GAIT,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,iCAAiC,GAMlC,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,MAAM,EACN,WAAW,EACX,2BAA2B,EAC3B,SAAS,EACT,oBAAoB,EACpB,UAAU,EACV,gBAAgB,GACjB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,qBAAqB,GAMtB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,eAAe,EACf,WAAW,GAGZ,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,iBAAiB,GAGlB,MAAM,cAAc,CAAC"}