@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.
- package/dist/capability.d.ts +142 -0
- package/dist/capability.d.ts.map +1 -0
- package/dist/capability.js +189 -0
- package/dist/capability.js.map +1 -0
- package/dist/includes.d.ts +68 -0
- package/dist/includes.d.ts.map +1 -0
- package/dist/includes.js +94 -0
- package/dist/includes.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/inline.d.ts +141 -0
- package/dist/inline.d.ts.map +1 -0
- package/dist/inline.js +183 -0
- package/dist/inline.js.map +1 -0
- package/dist/plugins.d.ts +99 -0
- package/dist/plugins.d.ts.map +1 -0
- package/dist/plugins.js +119 -0
- package/dist/plugins.js.map +1 -0
- package/dist/reads.d.ts +165 -0
- package/dist/reads.d.ts.map +1 -0
- package/dist/reads.js +268 -0
- package/dist/reads.js.map +1 -0
- package/dist/text.d.ts +55 -0
- package/dist/text.d.ts.map +1 -0
- package/dist/text.js +191 -0
- package/dist/text.js.map +1 -0
- package/dist/unknown.d.ts +39 -0
- package/dist/unknown.d.ts.map +1 -0
- package/dist/unknown.js +34 -0
- package/dist/unknown.js.map +1 -0
- package/package.json +42 -0
package/dist/inline.d.ts
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic inline walker.
|
|
3
|
+
*
|
|
4
|
+
* The 11-variant `InlineNode` switch used to be written FOUR times
|
|
5
|
+
* (`format-astro` twice — template and html modes — plus `format-obsidian` and
|
|
6
|
+
* `format-dogsbay-md`'s HTML-table fallback). All four were the same
|
|
7
|
+
* `nodes.map(...).join("")` walk differing only in what each leaf emits, and
|
|
8
|
+
* the duplication is why `format-astro` silently DROPPED `highlight`: adding an
|
|
9
|
+
* arm meant remembering four places, so `:highlight[…]` rendered as nothing in
|
|
10
|
+
* both of its renderers. All four now go through this walk (retrofit
|
|
11
|
+
* 2026-08-04), so a variant is handled once per format instead of once per
|
|
12
|
+
* copy — and an omission degrades to plain text via `onUnsupported` rather
|
|
13
|
+
* than vanishing.
|
|
14
|
+
*
|
|
15
|
+
* This module provides the walk once. A format supplies an {@link InlineEmitters}
|
|
16
|
+
* map; anything it omits falls back to a safe default, and — critically —
|
|
17
|
+
* omissions can be *recorded* rather than silently dropped, via `onUnsupported`.
|
|
18
|
+
*
|
|
19
|
+
* Not unified here: `format-dogsbay-md`'s inline renderer is a format-stack
|
|
20
|
+
* machine (it emits delta open/close marks across consecutive text nodes so
|
|
21
|
+
* `*a\nb*` round-trips as one emphasis run). That is a genuinely different
|
|
22
|
+
* traversal and is deliberately left alone.
|
|
23
|
+
*/
|
|
24
|
+
import type { InlineNode } from "@dogsbay/types";
|
|
25
|
+
/** Callbacks available to every emitter. */
|
|
26
|
+
export interface InlineContext {
|
|
27
|
+
/** Render nested inline children (link text, highlight content). */
|
|
28
|
+
recurse: (nodes: InlineNode[]) => string;
|
|
29
|
+
/** Escape literal text for the target format. */
|
|
30
|
+
escape: (text: string) => string;
|
|
31
|
+
/** Record that a construct could not be represented faithfully. */
|
|
32
|
+
report: (feature: string, detail?: string) => void;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Per-variant emitters. Every key is optional; a missing key means "this
|
|
36
|
+
* format cannot represent this inline type", which routes through
|
|
37
|
+
* {@link InlineWalkOptions.onUnsupported} instead of vanishing.
|
|
38
|
+
*/
|
|
39
|
+
export interface InlineEmitters {
|
|
40
|
+
text?: (node: Extract<InlineNode, {
|
|
41
|
+
type: "text";
|
|
42
|
+
}>, ctx: InlineContext) => string;
|
|
43
|
+
link?: (node: Extract<InlineNode, {
|
|
44
|
+
type: "link";
|
|
45
|
+
}>, ctx: InlineContext) => string;
|
|
46
|
+
image?: (node: Extract<InlineNode, {
|
|
47
|
+
type: "image";
|
|
48
|
+
}>, ctx: InlineContext) => string;
|
|
49
|
+
code?: (node: Extract<InlineNode, {
|
|
50
|
+
type: "code";
|
|
51
|
+
}>, ctx: InlineContext) => string;
|
|
52
|
+
highlight?: (node: Extract<InlineNode, {
|
|
53
|
+
type: "highlight";
|
|
54
|
+
}>, ctx: InlineContext) => string;
|
|
55
|
+
"footnote-ref"?: (node: Extract<InlineNode, {
|
|
56
|
+
type: "footnote-ref";
|
|
57
|
+
}>, ctx: InlineContext) => string;
|
|
58
|
+
kbd?: (node: Extract<InlineNode, {
|
|
59
|
+
type: "kbd";
|
|
60
|
+
}>, ctx: InlineContext) => string;
|
|
61
|
+
icon?: (node: Extract<InlineNode, {
|
|
62
|
+
type: "icon";
|
|
63
|
+
}>, ctx: InlineContext) => string;
|
|
64
|
+
math?: (node: Extract<InlineNode, {
|
|
65
|
+
type: "math";
|
|
66
|
+
}>, ctx: InlineContext) => string;
|
|
67
|
+
"html-inline"?: (node: Extract<InlineNode, {
|
|
68
|
+
type: "html-inline";
|
|
69
|
+
}>, ctx: InlineContext) => string;
|
|
70
|
+
break?: (node: Extract<InlineNode, {
|
|
71
|
+
type: "break";
|
|
72
|
+
}>, ctx: InlineContext) => string;
|
|
73
|
+
}
|
|
74
|
+
export interface InlineWalkOptions {
|
|
75
|
+
emitters: InlineEmitters;
|
|
76
|
+
/** Text escaping for the target format. Defaults to identity. */
|
|
77
|
+
escape?: (text: string) => string;
|
|
78
|
+
/**
|
|
79
|
+
* Called when no emitter exists for a variant. Return the fallback string
|
|
80
|
+
* (often a plain-text degradation). Default: best-effort plain text.
|
|
81
|
+
*/
|
|
82
|
+
onUnsupported?: (node: InlineNode, ctx: InlineContext) => string;
|
|
83
|
+
/** Loss recorder — wire this to an `ExportLedger`. */
|
|
84
|
+
report?: (feature: string, detail?: string) => void;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Best-effort plain-text degradation for a variant a format cannot express.
|
|
88
|
+
* Always prefer losing formatting over losing CONTENT.
|
|
89
|
+
*/
|
|
90
|
+
export declare function inlinePlainText(node: InlineNode, escape: (s: string) => string): string;
|
|
91
|
+
/** Render a list of inline nodes with the supplied emitters. */
|
|
92
|
+
export declare function walkInline(nodes: InlineNode[], options: InlineWalkOptions): string;
|
|
93
|
+
/**
|
|
94
|
+
* Apply bold/italic/strikethrough in the canonical order.
|
|
95
|
+
*
|
|
96
|
+
* Order matters and is shared by every existing renderer: bold innermost,
|
|
97
|
+
* then italic, then strikethrough outermost.
|
|
98
|
+
*/
|
|
99
|
+
export declare function applyTextFlags(text: string, node: Extract<InlineNode, {
|
|
100
|
+
type: "text";
|
|
101
|
+
}>, wrap: {
|
|
102
|
+
bold: (s: string) => string;
|
|
103
|
+
italic: (s: string) => string;
|
|
104
|
+
strike: (s: string) => string;
|
|
105
|
+
}): string;
|
|
106
|
+
/**
|
|
107
|
+
* Markdown inline emitters — the common baseline for any markdown-family
|
|
108
|
+
* target (Docusaurus, GitBook, MyST, plain CommonMark).
|
|
109
|
+
*
|
|
110
|
+
* Formats override individual arms for their own syntax (e.g. Obsidian's
|
|
111
|
+
* `==highlight==` is already the markdown default; Docusaurus needs `<kbd>`).
|
|
112
|
+
* Code spans widen their backtick run so content containing backticks survives
|
|
113
|
+
* — the bug `format-obsidian`'s naive `` `${text}` `` still has.
|
|
114
|
+
*/
|
|
115
|
+
export declare function markdownInlineEmitters(): InlineEmitters;
|
|
116
|
+
/**
|
|
117
|
+
* A CommonMark code span that survives a round trip.
|
|
118
|
+
*
|
|
119
|
+
* Widens the backtick fence past any run inside the content, and pads when the
|
|
120
|
+
* content begins/ends with a backtick OR A SPACE — CommonMark strips one space
|
|
121
|
+
* from each side of a padded span, so ` x ` would come back as `x`. Empty
|
|
122
|
+
* content needs the pad too, or `` renders as two literal backticks.
|
|
123
|
+
*/
|
|
124
|
+
export declare function codeSpan(text: string): string;
|
|
125
|
+
/** Escape HTML special characters in TEXT content. */
|
|
126
|
+
export declare function escapeHtml(s: string): string;
|
|
127
|
+
/**
|
|
128
|
+
* Escape a value destined for a double-quoted HTML ATTRIBUTE.
|
|
129
|
+
*
|
|
130
|
+
* Distinct from {@link escapeHtml} because it must also escape `"` — without
|
|
131
|
+
* it an href like `/a" onmouseover="x` breaks out of the attribute. format-astro
|
|
132
|
+
* keeps these separate for the same reason.
|
|
133
|
+
*/
|
|
134
|
+
export declare function escapeAttr(s: string): string;
|
|
135
|
+
/**
|
|
136
|
+
* HTML inline emitters — the baseline for HTML-ish targets.
|
|
137
|
+
* Includes the `highlight` arm (`<mark>`) whose absence from format-astro's
|
|
138
|
+
* two hand-written switches is what motivated this preset.
|
|
139
|
+
*/
|
|
140
|
+
export declare function htmlInlineEmitters(): InlineEmitters;
|
|
141
|
+
//# sourceMappingURL=inline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inline.d.ts","sourceRoot":"","sources":["../src/inline.ts"],"names":[],"mappings":"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"}
|
package/dist/inline.js
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Best-effort plain-text degradation for a variant a format cannot express.
|
|
3
|
+
* Always prefer losing formatting over losing CONTENT.
|
|
4
|
+
*/
|
|
5
|
+
export function inlinePlainText(node, escape) {
|
|
6
|
+
switch (node.type) {
|
|
7
|
+
case "text":
|
|
8
|
+
return escape(node.text);
|
|
9
|
+
case "code":
|
|
10
|
+
return escape(node.text);
|
|
11
|
+
case "math":
|
|
12
|
+
return escape(node.latex);
|
|
13
|
+
case "kbd":
|
|
14
|
+
return escape(node.keys.join("+"));
|
|
15
|
+
case "icon":
|
|
16
|
+
return escape(node.library ? `${node.library}:${node.name}` : node.name);
|
|
17
|
+
case "break":
|
|
18
|
+
return "\n";
|
|
19
|
+
case "html-inline":
|
|
20
|
+
// Keep the markup rather than nothing — losing formatting beats losing content.
|
|
21
|
+
return node.html;
|
|
22
|
+
case "footnote-ref":
|
|
23
|
+
return escape(`[^${node.label}]`);
|
|
24
|
+
case "image":
|
|
25
|
+
return escape(node.alt ?? "");
|
|
26
|
+
case "link":
|
|
27
|
+
case "highlight":
|
|
28
|
+
return node.children.map((c) => inlinePlainText(c, escape)).join("");
|
|
29
|
+
default:
|
|
30
|
+
return "";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** Render a list of inline nodes with the supplied emitters. */
|
|
34
|
+
export function walkInline(nodes, options) {
|
|
35
|
+
const escape = options.escape ?? ((s) => s);
|
|
36
|
+
const report = options.report ?? (() => { });
|
|
37
|
+
const ctx = {
|
|
38
|
+
recurse: (children) => walkInline(children, options),
|
|
39
|
+
escape,
|
|
40
|
+
report,
|
|
41
|
+
};
|
|
42
|
+
const onUnsupported = options.onUnsupported ??
|
|
43
|
+
((node, c) => {
|
|
44
|
+
c.report(`inline:${node.type}`, "no emitter for this inline type");
|
|
45
|
+
return inlinePlainText(node, c.escape);
|
|
46
|
+
});
|
|
47
|
+
return nodes
|
|
48
|
+
.map((node) => {
|
|
49
|
+
const emitter = options.emitters[node.type];
|
|
50
|
+
if (!emitter)
|
|
51
|
+
return onUnsupported(node, ctx);
|
|
52
|
+
return emitter(node, ctx);
|
|
53
|
+
})
|
|
54
|
+
.join("");
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Apply bold/italic/strikethrough in the canonical order.
|
|
58
|
+
*
|
|
59
|
+
* Order matters and is shared by every existing renderer: bold innermost,
|
|
60
|
+
* then italic, then strikethrough outermost.
|
|
61
|
+
*/
|
|
62
|
+
export function applyTextFlags(text, node, wrap) {
|
|
63
|
+
let out = text;
|
|
64
|
+
if (node.bold)
|
|
65
|
+
out = wrap.bold(out);
|
|
66
|
+
if (node.italic)
|
|
67
|
+
out = wrap.italic(out);
|
|
68
|
+
if (node.strikethrough)
|
|
69
|
+
out = wrap.strike(out);
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Markdown inline emitters — the common baseline for any markdown-family
|
|
74
|
+
* target (Docusaurus, GitBook, MyST, plain CommonMark).
|
|
75
|
+
*
|
|
76
|
+
* Formats override individual arms for their own syntax (e.g. Obsidian's
|
|
77
|
+
* `==highlight==` is already the markdown default; Docusaurus needs `<kbd>`).
|
|
78
|
+
* Code spans widen their backtick run so content containing backticks survives
|
|
79
|
+
* — the bug `format-obsidian`'s naive `` `${text}` `` still has.
|
|
80
|
+
*/
|
|
81
|
+
export function markdownInlineEmitters() {
|
|
82
|
+
return {
|
|
83
|
+
text: (node, ctx) => applyTextFlags(ctx.escape(node.text), node, {
|
|
84
|
+
bold: (s) => `**${s}**`,
|
|
85
|
+
italic: (s) => `*${s}*`,
|
|
86
|
+
strike: (s) => `~~${s}~~`,
|
|
87
|
+
}),
|
|
88
|
+
link: (node, ctx) => {
|
|
89
|
+
const title = node.title ? ` "${node.title}"` : "";
|
|
90
|
+
return `[${ctx.recurse(node.children)}](${node.href}${title})`;
|
|
91
|
+
},
|
|
92
|
+
image: (node) => {
|
|
93
|
+
const title = node.title ? ` "${node.title}"` : "";
|
|
94
|
+
return ``;
|
|
95
|
+
},
|
|
96
|
+
code: (node) => codeSpan(node.text),
|
|
97
|
+
highlight: (node, ctx) => `==${ctx.recurse(node.children)}==`,
|
|
98
|
+
"footnote-ref": (node) => `[^${node.label}]`,
|
|
99
|
+
kbd: (node) => node.keys.map((k) => `<kbd>${k}</kbd>`).join("+"),
|
|
100
|
+
math: (node) => `$${node.latex}$`,
|
|
101
|
+
// The presets MUST cover all 11 variants — omitting one is the bug this
|
|
102
|
+
// module was written to stop (format-astro silently dropped `highlight`
|
|
103
|
+
// for exactly this reason, until the retrofit put it on this walk).
|
|
104
|
+
// `:icon[…]` is DOGSBAY-MD-ONLY syntax. Emitting it from the shared
|
|
105
|
+
// markdown preset put a literal `:icon[lucide:check]` on the page of every
|
|
106
|
+
// other markdown target — and, because an emitter now existed, silenced
|
|
107
|
+
// the `onUnsupported` ledger entry that used to record the drop. A visible
|
|
108
|
+
// artefact that nothing reports is strictly worse than a recorded drop, so
|
|
109
|
+
// the baseline emits the readable name and REPORTS. Formats with real icon
|
|
110
|
+
// syntax (dogsbay-md) override this key.
|
|
111
|
+
icon: (node, ctx) => {
|
|
112
|
+
const full = node.library ? `${node.library}:${node.name}` : node.name;
|
|
113
|
+
ctx.report("icon", `no icon syntax in this format — emitted as the name "${full}"`);
|
|
114
|
+
return node.name;
|
|
115
|
+
},
|
|
116
|
+
"html-inline": (node) => node.html,
|
|
117
|
+
break: () => " \n",
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* A CommonMark code span that survives a round trip.
|
|
122
|
+
*
|
|
123
|
+
* Widens the backtick fence past any run inside the content, and pads when the
|
|
124
|
+
* content begins/ends with a backtick OR A SPACE — CommonMark strips one space
|
|
125
|
+
* from each side of a padded span, so ` x ` would come back as `x`. Empty
|
|
126
|
+
* content needs the pad too, or `` renders as two literal backticks.
|
|
127
|
+
*/
|
|
128
|
+
export function codeSpan(text) {
|
|
129
|
+
const longest = (text.match(/`+/g) ?? []).reduce((max, run) => Math.max(max, run.length), 0);
|
|
130
|
+
const fence = "`".repeat(longest + 1);
|
|
131
|
+
const needsPad = text.length === 0 ||
|
|
132
|
+
text.startsWith("`") ||
|
|
133
|
+
text.endsWith("`") ||
|
|
134
|
+
text.startsWith(" ") ||
|
|
135
|
+
text.endsWith(" ");
|
|
136
|
+
const pad = needsPad ? " " : "";
|
|
137
|
+
return `${fence}${pad}${text}${pad}${fence}`;
|
|
138
|
+
}
|
|
139
|
+
/** Escape HTML special characters in TEXT content. */
|
|
140
|
+
export function escapeHtml(s) {
|
|
141
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Escape a value destined for a double-quoted HTML ATTRIBUTE.
|
|
145
|
+
*
|
|
146
|
+
* Distinct from {@link escapeHtml} because it must also escape `"` — without
|
|
147
|
+
* it an href like `/a" onmouseover="x` breaks out of the attribute. format-astro
|
|
148
|
+
* keeps these separate for the same reason.
|
|
149
|
+
*/
|
|
150
|
+
export function escapeAttr(s) {
|
|
151
|
+
return escapeHtml(s).replace(/"/g, """);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* HTML inline emitters — the baseline for HTML-ish targets.
|
|
155
|
+
* Includes the `highlight` arm (`<mark>`) whose absence from format-astro's
|
|
156
|
+
* two hand-written switches is what motivated this preset.
|
|
157
|
+
*/
|
|
158
|
+
export function htmlInlineEmitters() {
|
|
159
|
+
return {
|
|
160
|
+
text: (node, ctx) => applyTextFlags(ctx.escape(node.text), node, {
|
|
161
|
+
bold: (s) => `<strong>${s}</strong>`,
|
|
162
|
+
italic: (s) => `<em>${s}</em>`,
|
|
163
|
+
strike: (s) => `<s>${s}</s>`,
|
|
164
|
+
}),
|
|
165
|
+
link: (node, ctx) => {
|
|
166
|
+
const title = node.title ? ` title="${escapeAttr(node.title)}"` : "";
|
|
167
|
+
return `<a href="${escapeAttr(node.href)}"${title}>${ctx.recurse(node.children)}</a>`;
|
|
168
|
+
},
|
|
169
|
+
image: (node) => `<img src="${escapeAttr(node.src)}" alt="${escapeAttr(node.alt ?? "")}" />`,
|
|
170
|
+
code: (node, ctx) => `<code>${ctx.escape(node.text)}</code>`,
|
|
171
|
+
highlight: (node, ctx) => `<mark>${ctx.recurse(node.children)}</mark>`,
|
|
172
|
+
"footnote-ref": (node) => `<sup><a href="#fn-${node.label}" id="fnref-${node.label}">[${node.label}]</a></sup>`,
|
|
173
|
+
kbd: (node) => node.keys.map((k) => `<kbd>${escapeHtml(k)}</kbd>`).join("+"),
|
|
174
|
+
math: (node, ctx) => `<code class="math-inline">${ctx.escape(node.latex)}</code>`,
|
|
175
|
+
icon: (node) => {
|
|
176
|
+
const full = node.library ? `${node.library}:${node.name}` : node.name;
|
|
177
|
+
return `<span class="dogsbay-icon" data-icon="${escapeAttr(full)}"></span>`;
|
|
178
|
+
},
|
|
179
|
+
"html-inline": (node) => node.html,
|
|
180
|
+
break: () => "<br />",
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=inline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inline.js","sourceRoot":"","sources":["../src/inline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Export plugin composition.
|
|
3
|
+
*
|
|
4
|
+
* A target format's capability is NOT a fixed property of the format — it is a
|
|
5
|
+
* property of the format **plus the plugins the emitted project will use**.
|
|
6
|
+
* Vanilla Docusaurus cannot represent an API endpoint; Docusaurus *with*
|
|
7
|
+
* `docusaurus-plugin-openapi-docs` can. So the capability declaration must be
|
|
8
|
+
* composed, not constant.
|
|
9
|
+
*
|
|
10
|
+
* This module holds the format-agnostic half: plugin metadata, per-feature
|
|
11
|
+
* provider resolution, and capability composition. The emission hooks
|
|
12
|
+
* themselves are format-specific (a Docusaurus plugin mutates
|
|
13
|
+
* `docusaurus.config.js`; an MkDocs one mutates `mkdocs.yml`), so each format
|
|
14
|
+
* extends {@link ExportPluginMeta} with its own hook signatures.
|
|
15
|
+
*
|
|
16
|
+
* Two rules, both inherited from the no-silent-loss doctrine:
|
|
17
|
+
*
|
|
18
|
+
* - A plugin that claims a feature must say at what level, and (via
|
|
19
|
+
* {@link CapabilityDeclaration}) what is still lost.
|
|
20
|
+
* - When two plugins claim the same feature it is an ERROR, not a silent
|
|
21
|
+
* pick. Resolution order is explicit override → declaration order, and an
|
|
22
|
+
* unresolved clash is surfaced to the user.
|
|
23
|
+
*/
|
|
24
|
+
import type { CapabilityDeclaration, SupportLevel } from "./capability.js";
|
|
25
|
+
/** Format-agnostic plugin metadata. Formats extend this with emission hooks. */
|
|
26
|
+
export interface ExportPluginMeta {
|
|
27
|
+
/** Stable id used for `--plugins` selection and conflict messages. */
|
|
28
|
+
id: string;
|
|
29
|
+
/** One-line description shown when listing available plugins. */
|
|
30
|
+
description?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Features this plugin takes ownership of, and the support level it raises
|
|
33
|
+
* them to. Keys match `CapabilityDeclaration.feature` / TreeNode types.
|
|
34
|
+
*/
|
|
35
|
+
provides: Record<string, SupportLevel>;
|
|
36
|
+
/**
|
|
37
|
+
* Capability declarations that REPLACE the base format's entry for the
|
|
38
|
+
* features above — including what is still lost at the higher level.
|
|
39
|
+
*/
|
|
40
|
+
capabilities?: CapabilityDeclaration[];
|
|
41
|
+
/** Plugin ids that cannot be used alongside this one. */
|
|
42
|
+
conflictsWith?: string[];
|
|
43
|
+
/** Extra steps the user must run after export (e.g. a codegen command). */
|
|
44
|
+
postExportSteps?: string[];
|
|
45
|
+
}
|
|
46
|
+
export interface ProviderConflict {
|
|
47
|
+
feature: string;
|
|
48
|
+
/** Plugin ids competing for the feature. */
|
|
49
|
+
candidates: string[];
|
|
50
|
+
}
|
|
51
|
+
/** An explicit `--provider feature=plugin` that cannot be honoured. */
|
|
52
|
+
export interface InvalidOverride {
|
|
53
|
+
feature: string;
|
|
54
|
+
plugin: string;
|
|
55
|
+
reason: string;
|
|
56
|
+
/** Plugins that DO provide the feature — the usable choices. */
|
|
57
|
+
candidates: string[];
|
|
58
|
+
}
|
|
59
|
+
export interface ResolvedPlugins<P extends ExportPluginMeta> {
|
|
60
|
+
/** Selected plugins, in declaration order. */
|
|
61
|
+
plugins: P[];
|
|
62
|
+
/** feature → the plugin that owns emitting it. */
|
|
63
|
+
byFeature: Map<string, P>;
|
|
64
|
+
/** Unresolved clashes — the caller must surface these, never ignore them. */
|
|
65
|
+
conflicts: ProviderConflict[];
|
|
66
|
+
/** Overrides that name a plugin which cannot provide the feature. */
|
|
67
|
+
invalidOverrides: InvalidOverride[];
|
|
68
|
+
/** Mutual-exclusion violations (`conflictsWith`). */
|
|
69
|
+
incompatible: Array<{
|
|
70
|
+
plugin: string;
|
|
71
|
+
conflictsWith: string;
|
|
72
|
+
}>;
|
|
73
|
+
}
|
|
74
|
+
export interface ResolveOptions {
|
|
75
|
+
/**
|
|
76
|
+
* Explicit per-feature winner: `{ endpoint: "openapi-docs" }`. Beats
|
|
77
|
+
* declaration order and silences the conflict for that feature.
|
|
78
|
+
*/
|
|
79
|
+
overrides?: Record<string, string>;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Resolve which plugin owns each feature.
|
|
83
|
+
*
|
|
84
|
+
* Precedence: explicit override → declaration order (earlier wins).
|
|
85
|
+
* A later plugin claiming an already-owned feature produces a conflict rather
|
|
86
|
+
* than quietly losing or quietly winning.
|
|
87
|
+
*/
|
|
88
|
+
export declare function resolvePlugins<P extends ExportPluginMeta>(plugins: P[], options?: ResolveOptions): ResolvedPlugins<P>;
|
|
89
|
+
/**
|
|
90
|
+
* Compose the effective capability declaration: the base format's, with each
|
|
91
|
+
* resolved plugin's entries replacing the features it owns.
|
|
92
|
+
*
|
|
93
|
+
* The result is what the user should be shown — "with THIS profile, here is
|
|
94
|
+
* what you lose" — rather than the format's worst case.
|
|
95
|
+
*/
|
|
96
|
+
export declare function composeCapabilities<P extends ExportPluginMeta>(base: readonly CapabilityDeclaration[], resolved: ResolvedPlugins<P>): CapabilityDeclaration[];
|
|
97
|
+
/** Human-readable explanation of any unresolved clash. */
|
|
98
|
+
export declare function formatPluginConflicts<P extends ExportPluginMeta>(resolved: ResolvedPlugins<P>): string[];
|
|
99
|
+
//# sourceMappingURL=plugins.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugins.d.ts","sourceRoot":"","sources":["../src/plugins.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,KAAK,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE3E,gFAAgF;AAChF,MAAM,WAAW,gBAAgB;IAC/B,sEAAsE;IACtE,EAAE,EAAE,MAAM,CAAC;IACX,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACvC;;;OAGG;IACH,YAAY,CAAC,EAAE,qBAAqB,EAAE,CAAC;IACvC,yDAAyD;IACzD,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,2EAA2E;IAC3E,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,4CAA4C;IAC5C,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,uEAAuE;AACvE,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,gBAAgB;IACzD,8CAA8C;IAC9C,OAAO,EAAE,CAAC,EAAE,CAAC;IACb,kDAAkD;IAClD,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC1B,6EAA6E;IAC7E,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,qEAAqE;IACrE,gBAAgB,EAAE,eAAe,EAAE,CAAC;IACpC,qDAAqD;IACrD,YAAY,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChE;AAED,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,gBAAgB,EACvD,OAAO,EAAE,CAAC,EAAE,EACZ,OAAO,GAAE,cAAmB,GAC3B,eAAe,CAAC,CAAC,CAAC,CA0DpB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,gBAAgB,EAC5D,IAAI,EAAE,SAAS,qBAAqB,EAAE,EACtC,QAAQ,EAAE,eAAe,CAAC,CAAC,CAAC,GAC3B,qBAAqB,EAAE,CA+BzB;AAED,0DAA0D;AAC1D,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,gBAAgB,EAC9D,QAAQ,EAAE,eAAe,CAAC,CAAC,CAAC,GAC3B,MAAM,EAAE,CAqBV"}
|
package/dist/plugins.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve which plugin owns each feature.
|
|
3
|
+
*
|
|
4
|
+
* Precedence: explicit override → declaration order (earlier wins).
|
|
5
|
+
* A later plugin claiming an already-owned feature produces a conflict rather
|
|
6
|
+
* than quietly losing or quietly winning.
|
|
7
|
+
*/
|
|
8
|
+
export function resolvePlugins(plugins, options = {}) {
|
|
9
|
+
const byFeature = new Map();
|
|
10
|
+
const claims = new Map();
|
|
11
|
+
const conflicts = [];
|
|
12
|
+
const invalidOverrides = [];
|
|
13
|
+
const incompatible = [];
|
|
14
|
+
const overrides = options.overrides ?? {};
|
|
15
|
+
const selected = new Set(plugins.map((p) => p.id));
|
|
16
|
+
for (const plugin of plugins) {
|
|
17
|
+
for (const other of plugin.conflictsWith ?? []) {
|
|
18
|
+
if (selected.has(other)) {
|
|
19
|
+
incompatible.push({ plugin: plugin.id, conflictsWith: other });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
for (const plugin of plugins) {
|
|
24
|
+
for (const feature of Object.keys(plugin.provides)) {
|
|
25
|
+
const seen = claims.get(feature) ?? [];
|
|
26
|
+
seen.push(plugin.id);
|
|
27
|
+
claims.set(feature, seen);
|
|
28
|
+
const override = overrides[feature];
|
|
29
|
+
if (override) {
|
|
30
|
+
if (plugin.id === override)
|
|
31
|
+
byFeature.set(feature, plugin);
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (!byFeature.has(feature))
|
|
35
|
+
byFeature.set(feature, plugin);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
for (const [feature, candidates] of claims) {
|
|
39
|
+
if (candidates.length > 1 && !overrides[feature]) {
|
|
40
|
+
conflicts.push({ feature, candidates });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// An override must actually resolve the feature. Without this check a typo
|
|
44
|
+
// (`--provider endpoint=mermaid`) silently SWALLOWED a real a/b conflict and
|
|
45
|
+
// left the feature with no owner — the exporter then emitted a project whose
|
|
46
|
+
// content and capability report disagreed, with no error.
|
|
47
|
+
for (const [feature, id] of Object.entries(overrides)) {
|
|
48
|
+
if (byFeature.has(feature))
|
|
49
|
+
continue;
|
|
50
|
+
const candidates = claims.get(feature) ?? [];
|
|
51
|
+
invalidOverrides.push({
|
|
52
|
+
feature,
|
|
53
|
+
plugin: id,
|
|
54
|
+
reason: !selected.has(id)
|
|
55
|
+
? "not selected"
|
|
56
|
+
: candidates.length === 0
|
|
57
|
+
? "no plugin provides this feature"
|
|
58
|
+
: `does not provide it (providers: ${candidates.join(", ")})`,
|
|
59
|
+
candidates,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
return { plugins, byFeature, conflicts, invalidOverrides, incompatible };
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Compose the effective capability declaration: the base format's, with each
|
|
66
|
+
* resolved plugin's entries replacing the features it owns.
|
|
67
|
+
*
|
|
68
|
+
* The result is what the user should be shown — "with THIS profile, here is
|
|
69
|
+
* what you lose" — rather than the format's worst case.
|
|
70
|
+
*/
|
|
71
|
+
export function composeCapabilities(base, resolved) {
|
|
72
|
+
const out = new Map();
|
|
73
|
+
for (const cap of base)
|
|
74
|
+
out.set(cap.feature, cap);
|
|
75
|
+
for (const [feature, plugin] of resolved.byFeature) {
|
|
76
|
+
const declared = plugin.capabilities?.find((c) => c.feature === feature);
|
|
77
|
+
if (declared && declared.support !== "full" && !declared.note) {
|
|
78
|
+
throw new Error(`Plugin "${plugin.id}" declares "${feature}" as ${declared.support} ` +
|
|
79
|
+
`with no note explaining the loss.`);
|
|
80
|
+
}
|
|
81
|
+
if (declared) {
|
|
82
|
+
out.set(feature, declared);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
// No explicit declaration — raise the support level and name the provider.
|
|
86
|
+
const level = plugin.provides[feature];
|
|
87
|
+
const existing = out.get(feature);
|
|
88
|
+
// Do NOT reuse the base note OR rendersAs: both describe the un-plugged
|
|
89
|
+
// level. Keeping `rendersAs` published rows like
|
|
90
|
+
// `| endpoint | partial | omitted entirely | provided by openapi-docs |`
|
|
91
|
+
// — the same self-contradiction the note rule above exists to prevent.
|
|
92
|
+
void existing;
|
|
93
|
+
out.set(feature, {
|
|
94
|
+
feature,
|
|
95
|
+
support: level,
|
|
96
|
+
note: level === "full" ? undefined : `provided by ${plugin.id}`,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return [...out.values()];
|
|
100
|
+
}
|
|
101
|
+
/** Human-readable explanation of any unresolved clash. */
|
|
102
|
+
export function formatPluginConflicts(resolved) {
|
|
103
|
+
const lines = [];
|
|
104
|
+
for (const c of resolved.incompatible) {
|
|
105
|
+
lines.push(`plugins "${c.plugin}" and "${c.conflictsWith}" cannot be used together`);
|
|
106
|
+
}
|
|
107
|
+
for (const c of resolved.conflicts) {
|
|
108
|
+
lines.push(`feature "${c.feature}" is claimed by ${c.candidates.length} plugins ` +
|
|
109
|
+
`(${c.candidates.join(", ")}) — choose one, e.g. --provider ${c.feature}=${c.candidates[0]}`);
|
|
110
|
+
}
|
|
111
|
+
for (const o of resolved.invalidOverrides) {
|
|
112
|
+
const fix = o.candidates.length > 0
|
|
113
|
+
? ` — use one of: ${o.candidates.join(", ")}`
|
|
114
|
+
: "";
|
|
115
|
+
lines.push(`--provider ${o.feature}=${o.plugin} cannot be honoured: ${o.reason}${fix}`);
|
|
116
|
+
}
|
|
117
|
+
return lines;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=plugins.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugins.js","sourceRoot":"","sources":["../src/plugins.ts"],"names":[],"mappings":"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"}
|