vantage-md 0.5.6 → 0.5.7

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/react.cjs CHANGED
@@ -39,6 +39,7 @@ let rehype_katex = require("rehype-katex");
39
39
  rehype_katex = __toESM(rehype_katex, 1);
40
40
  let rehype_slug = require("rehype-slug");
41
41
  rehype_slug = __toESM(rehype_slug, 1);
42
+ let unist_util_visit = require("unist-util-visit");
42
43
  let yaml = require("yaml");
43
44
  yaml = __toESM(yaml, 1);
44
45
  let smol_toml = require("smol-toml");
@@ -69,24 +70,145 @@ const BLOCK_TAGS = /* @__PURE__ */ new Set([
69
70
  "hr",
70
71
  "div"
71
72
  ]);
72
- function visit(node, offset) {
73
+ function visit$1(node, offset) {
73
74
  if ("children" in node) {
74
75
  for (const child of node.children) if (child.type === "element") {
75
76
  if (BLOCK_TAGS.has(child.tagName) && child.position?.start?.line) {
76
77
  child.properties = child.properties || {};
77
78
  child.properties["dataSourceLine"] = child.position.start.line + offset;
78
79
  }
79
- visit(child, offset);
80
+ visit$1(child, offset);
80
81
  }
81
82
  }
82
83
  }
83
84
  const rehypeSourceLines = (options) => {
84
85
  const offset = options?.offset ?? 0;
85
86
  return (tree) => {
86
- visit(tree, offset);
87
+ visit$1(tree, offset);
87
88
  };
88
89
  };
89
90
  //#endregion
91
+ //#region src/rehypeVantageAlerts.ts
92
+ /**
93
+ * GFM alerts — `> [!WARNING]` — compiled into `data-vantage-alert`.
94
+ *
95
+ * `remark-gfm` does not implement alerts, so until this plugin existed a
96
+ * `> [!WARNING]` rendered as an ordinary blockquote with the literal marker
97
+ * visible as its first words. Worse than merely unstyled: `@tailwindcss/typography`
98
+ * italicises blockquotes and draws `open-quote`/`close-quote` around the first
99
+ * paragraph, so a callout came out as an italic *quotation* whose opening words
100
+ * were `"[!WARNING]`. That was the "Known gaps" entry in
101
+ * `docs/reference/inline-markup.md` and OQ-10, filed rather than fixed, while
102
+ * `styleGuide.ts` went on telling every agent to write them.
103
+ *
104
+ * The tokens are deliberately the ones the `tone` vocabulary already resolves —
105
+ * an alert *is* the six-colour light/dark treatment `tone` shipped, which is
106
+ * exactly what the gap entry said whoever fixed this should do rather than
107
+ * building a second palette. `[!WARNING]` and `<!-- vantage: block tone=warning -->`
108
+ * therefore agree by construction, and adding a theme still touches one
109
+ * custom-property block.
110
+ *
111
+ * **This runs in the shared pipeline, so all four renderers get it** — the live
112
+ * viewer, the package's exported viewer, the static export and the CLI checker's
113
+ * `renderMarkdown`. That is what makes an injected title element acceptable here
114
+ * where the collapse caret's glyph had to be drawn in CSS: the caret is injected
115
+ * by app JS that may never run, and this is not (D5).
116
+ *
117
+ * ## What it does not do
118
+ *
119
+ * It does not touch a blockquote that carries no marker, and an unrecognised
120
+ * marker (`[!HINT]`) is left exactly as it was — visible literal text, which is
121
+ * the honest rendering of something GitHub also would not style. Silently
122
+ * swallowing it would hide a typo that reads as a callout on neither renderer.
123
+ */
124
+ /**
125
+ * The five GFM alert kinds, lowercased.
126
+ *
127
+ * Deliberately *not* re-derived from `VANTAGE_TONES`: that list carries a sixth
128
+ * token, `muted`, which is ours and is not an alert word. The overlap is the
129
+ * point — the five that coincide share a palette — but the two vocabularies are
130
+ * closed by different authorities and a change to one must not silently move the
131
+ * other. A test asserts the five are a subset of the tones.
132
+ */
133
+ const VANTAGE_ALERTS = [
134
+ "note",
135
+ "tip",
136
+ "important",
137
+ "warning",
138
+ "caution"
139
+ ];
140
+ /** The visible label per kind. Title case, as GitHub renders it. */
141
+ const ALERT_TITLES = {
142
+ note: "Note",
143
+ tip: "Tip",
144
+ important: "Important",
145
+ warning: "Warning",
146
+ caution: "Caution"
147
+ };
148
+ /**
149
+ * The marker, anchored and requiring the rest of its line to be empty.
150
+ *
151
+ * GFM puts the marker alone on the blockquote's first line, and holding to that
152
+ * is what keeps a paragraph that merely *begins* with bracketed text from being
153
+ * eaten. The trailing newline is optional only for the degenerate blockquote
154
+ * whose entire content is the marker.
155
+ *
156
+ * Measured against the real chain rather than assumed: `remark-parse` reads
157
+ * `[!TIP]` as a shortcut link reference, and because no definition matches,
158
+ * `mdast-util-to-hast` puts it back as **one** leading text node —
159
+ * `"[!TIP]\nThe generalization: "` — not as a `[`/label/`]` triple. So a single
160
+ * anchored test on the first text node is enough, and the plugin does not have
161
+ * to reassemble the marker across siblings.
162
+ */
163
+ const MARKER = /^\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\][ \t]*(?:\r?\n|$)/;
164
+ /** The first child, if it is an element. */
165
+ function firstElement(node) {
166
+ const child = node.children.find((c) => c.type === "element" || c.type === "text" && c.value.trim() !== "");
167
+ return child?.type === "element" ? child : void 0;
168
+ }
169
+ /**
170
+ * Compile `> [!KIND]` blockquotes into `data-vantage-alert="kind"`.
171
+ *
172
+ * Order in the chain matters twice, and both are stated in `pipeline.ts`:
173
+ *
174
+ * - **after `rehypeSourceLines`**, so the injected title carries no
175
+ * `data-source-line`. That is what keeps it out of `anchorBlockWithin`, which
176
+ * filters candidates to those with a finite line — otherwise a review comment
177
+ * on an alert would anchor to the word "Warning" instead of to the prose.
178
+ * - **before `rehypeSanitize`**, so nothing reaches the DOM the schema has not
179
+ * passed. `dataVantageAlert` is allowlisted there by name *and* value, like
180
+ * every other `data-vantage-*` attribute.
181
+ */
182
+ function rehypeVantageAlerts() {
183
+ return (tree) => {
184
+ (0, unist_util_visit.visit)(tree, "element", (node) => {
185
+ if (node.tagName !== "blockquote") return;
186
+ const paragraph = firstElement(node);
187
+ if (paragraph === void 0 || paragraph.tagName !== "p") return;
188
+ const lead = paragraph.children[0];
189
+ if (lead === void 0 || lead.type !== "text") return;
190
+ const match = MARKER.exec(lead.value);
191
+ if (match === null) return;
192
+ const kind = match[1].toLowerCase();
193
+ lead.value = lead.value.slice(match[0].length);
194
+ if (lead.value === "" && paragraph.children.length === 1) node.children = node.children.filter((c) => c !== paragraph);
195
+ node.properties = {
196
+ ...node.properties,
197
+ dataVantageAlert: kind
198
+ };
199
+ node.children.unshift({
200
+ type: "element",
201
+ tagName: "div",
202
+ properties: { className: ["vantage-alert-title"] },
203
+ children: [{
204
+ type: "text",
205
+ value: ALERT_TITLES[kind]
206
+ }]
207
+ });
208
+ });
209
+ };
210
+ }
211
+ //#endregion
90
212
  //#region src/vantageDirectives.ts
91
213
  /**
92
214
  * The `tone` vocabulary: GitHub's alert words plus `muted`.
@@ -827,6 +949,7 @@ const sanitizeSchema = {
827
949
  ["dataVantageCollapseToggle", COLLAPSE_GROUP_ID],
828
950
  ["dataVantageRun", ...VANTAGE_RUNS],
829
951
  ["dataVantageOq", "true"],
952
+ ["dataVantageAlert", ...VANTAGE_ALERTS],
830
953
  "dataVantageLeaning"
831
954
  ],
832
955
  code: [...rehype_sanitize.defaultSchema.attributes?.code || [], "className"],
@@ -872,6 +995,7 @@ function buildRehypePlugins(options = {}) {
872
995
  const { math = true, highlight = true, sourceLines = true, sanitize = true, bodyLineOffset = 0 } = options;
873
996
  const plugins = [rehype_raw.default];
874
997
  if (sourceLines) plugins.push([rehypeSourceLines, { offset: bodyLineOffset }]);
998
+ plugins.push(rehypeVantageAlerts);
875
999
  plugins.push(rehypeVantageDirectives);
876
1000
  if (sanitize) plugins.push([rehype_sanitize.default, sanitizeSchema]);
877
1001
  plugins.push(rehype_slug.default);