@dr-ishaan/remake-blocks 1.8.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +140 -0
- package/dist/astro.d.ts +1 -1
- package/dist/astro.d.ts.map +1 -1
- package/dist/astro.js +2 -2
- package/dist/astro.js.map +1 -1
- package/dist/css-generator.d.ts +35 -0
- package/dist/css-generator.d.ts.map +1 -1
- package/dist/css-generator.js +147 -0
- package/dist/css-generator.js.map +1 -1
- package/dist/dx.d.ts +139 -0
- package/dist/dx.d.ts.map +1 -0
- package/dist/dx.js +230 -0
- package/dist/dx.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/remark-remake-blocks.d.ts.map +1 -1
- package/dist/remark-remake-blocks.js +129 -7
- package/dist/remark-remake-blocks.js.map +1 -1
- package/dist/types.d.ts +111 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +13 -3
package/dist/dx.js
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v1.10.0: Developer Experience utilities.
|
|
3
|
+
*
|
|
4
|
+
* Exports:
|
|
5
|
+
* - CLASSES: frozen object of CSS class name constants for programmatic use
|
|
6
|
+
* - warn(message, ...args): dev-mode warning emitter (gated on devWarnings option)
|
|
7
|
+
* - validateCustomCallouts(configs, strict): validates customCallouts at init time
|
|
8
|
+
* - suggestSimilarType(type, knownTypes): Levenshtein-based "did you mean" suggester
|
|
9
|
+
*
|
|
10
|
+
* @module dx
|
|
11
|
+
*/
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// CLASSES — exported CSS class name constants
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
/**
|
|
16
|
+
* v1.10.0+: Frozen object of CSS class names used by the plugin. Use these
|
|
17
|
+
* in CSS-in-JS, tests, or any code that needs to reference callout classes
|
|
18
|
+
* programmatically without hardcoding strings.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* import { CLASSES } from '@dr-ishaan/remake-blocks';
|
|
23
|
+
*
|
|
24
|
+
* document.querySelector(`.${CLASSES.CALLOUT_NOTE}`) // '.callout-note'
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export const CLASSES = Object.freeze({
|
|
28
|
+
// Container classes
|
|
29
|
+
CALLOUT: "callout",
|
|
30
|
+
CALLOUT_NOTE: "callout-note",
|
|
31
|
+
CALLOUT_TIP: "callout-tip",
|
|
32
|
+
CALLOUT_IMPORTANT: "callout-important",
|
|
33
|
+
CALLOUT_WARNING: "callout-warning",
|
|
34
|
+
CALLOUT_CAUTION: "callout-caution",
|
|
35
|
+
CALLOUT_ABSTRACT: "callout-abstract",
|
|
36
|
+
CALLOUT_INFO: "callout-info",
|
|
37
|
+
CALLOUT_SUCCESS: "callout-success",
|
|
38
|
+
CALLOUT_QUESTION: "callout-question",
|
|
39
|
+
CALLOUT_FAILURE: "callout-failure",
|
|
40
|
+
CALLOUT_DANGER: "callout-danger",
|
|
41
|
+
CALLOUT_QUOTE: "callout-quote",
|
|
42
|
+
CALLOUT_BUG: "callout-bug",
|
|
43
|
+
CALLOUT_EXAMPLE: "callout-example",
|
|
44
|
+
CALLOUT_TODO: "callout-todo",
|
|
45
|
+
CALLOUT_SUMMARY: "callout-summary",
|
|
46
|
+
CALLOUT_TLDR: "callout-tldr",
|
|
47
|
+
CALLOUT_HINT: "callout-hint",
|
|
48
|
+
CALLOUT_CHECK: "callout-check",
|
|
49
|
+
CALLOUT_DONE: "callout-done",
|
|
50
|
+
CALLOUT_HELP: "callout-help",
|
|
51
|
+
CALLOUT_FAQ: "callout-faq",
|
|
52
|
+
CALLOUT_ATTENTION: "callout-attention",
|
|
53
|
+
CALLOUT_FAIL: "callout-fail",
|
|
54
|
+
CALLOUT_MISSING: "callout-missing",
|
|
55
|
+
CALLOUT_ERROR: "callout-error",
|
|
56
|
+
CALLOUT_CITE: "callout-cite",
|
|
57
|
+
// v1.6.0 types
|
|
58
|
+
CALLOUT_DEFINITION: "callout-definition",
|
|
59
|
+
CALLOUT_ASIDE: "callout-aside",
|
|
60
|
+
CALLOUT_CORRECTION: "callout-correction",
|
|
61
|
+
CALLOUT_UPDATE: "callout-update",
|
|
62
|
+
CALLOUT_FIGURE: "callout-figure",
|
|
63
|
+
CALLOUT_FURTHER_READING: "callout-further-reading",
|
|
64
|
+
CALLOUT_PREREQUISITE: "callout-prerequisite",
|
|
65
|
+
CALLOUT_EXERCISE: "callout-exercise",
|
|
66
|
+
CALLOUT_SIDENOTE: "callout-sidenote",
|
|
67
|
+
CALLOUT_TIMELINE: "callout-timeline",
|
|
68
|
+
CALLOUT_ANNOUNCEMENT: "callout-announcement",
|
|
69
|
+
CALLOUT_BIBLIOGRAPHY: "callout-bibliography",
|
|
70
|
+
CALLOUT_DRAFT: "callout-draft",
|
|
71
|
+
CALLOUT_TRANSLATION: "callout-translation",
|
|
72
|
+
CALLOUT_DISCUSSION: "callout-discussion",
|
|
73
|
+
CALLOUT_RETRO: "callout-retro",
|
|
74
|
+
// Sub-element classes
|
|
75
|
+
CALLOUT_TITLE: "callout-title",
|
|
76
|
+
CALLOUT_TITLE_TEXT: "callout-title-text",
|
|
77
|
+
CALLOUT_ICON: "callout-icon",
|
|
78
|
+
CALLOUT_BODY: "callout-body",
|
|
79
|
+
CALLOUT_COLLAPSIBLE: "collapsible",
|
|
80
|
+
// Disclosure / accordion
|
|
81
|
+
DISCLOSURE: "disclosure",
|
|
82
|
+
DISCLOSURE_TITLE: "disclosure-title",
|
|
83
|
+
DISCLOSURE_BODY: "disclosure-body",
|
|
84
|
+
DISCLOSURE_ACCORDION: "disclosure-accordion",
|
|
85
|
+
DISCLOSURE_TREE: "disclosure-tree",
|
|
86
|
+
// Pull quote / epigraph
|
|
87
|
+
PULL_QUOTE: "pull-quote",
|
|
88
|
+
PULL_QUOTE_TEXT: "pull-quote-text",
|
|
89
|
+
PULL_QUOTE_ATTRIBUTION: "pull-quote-attribution",
|
|
90
|
+
EPIGRAPH: "epigraph",
|
|
91
|
+
EPIGRAPH_TEXT: "epigraph-text",
|
|
92
|
+
EPIGRAPH_ATTRIBUTION: "epigraph-attribution",
|
|
93
|
+
// Blockquote enhancement
|
|
94
|
+
BLOCKQUOTE_ENHANCED: "blockquote-enhanced",
|
|
95
|
+
});
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
// warn — dev-mode warning emitter
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
/**
|
|
100
|
+
* v1.10.0+: Emit a developer-mode warning via `console.warn`.
|
|
101
|
+
*
|
|
102
|
+
* The warning is prefixed with `[remake-blocks]` for easy identification
|
|
103
|
+
* and filtering. No-op when `devWarnings` is false OR when running in
|
|
104
|
+
* production (`process.env.NODE_ENV === 'production'`).
|
|
105
|
+
*
|
|
106
|
+
* @param enabled — whether devWarnings is enabled (from plugin options)
|
|
107
|
+
* @param message — warning message (without prefix)
|
|
108
|
+
* @param args — additional context args
|
|
109
|
+
*/
|
|
110
|
+
export function warn(enabled, message, ...args) {
|
|
111
|
+
if (!enabled)
|
|
112
|
+
return;
|
|
113
|
+
if (typeof process !== "undefined" && process.env && process.env.NODE_ENV === "production" && enabled !== true) {
|
|
114
|
+
// Auto-disable in production unless explicitly enabled
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
console.warn(`[remake-blocks] ${message}`, ...args);
|
|
118
|
+
}
|
|
119
|
+
// ---------------------------------------------------------------------------
|
|
120
|
+
// suggestSimilarType — Levenshtein-based "did you mean" suggester
|
|
121
|
+
// ---------------------------------------------------------------------------
|
|
122
|
+
/**
|
|
123
|
+
* Compute Levenshtein edit distance between two strings.
|
|
124
|
+
* Used by `suggestSimilarType` to find the closest match.
|
|
125
|
+
*/
|
|
126
|
+
function levenshtein(a, b) {
|
|
127
|
+
const m = a.length;
|
|
128
|
+
const n = b.length;
|
|
129
|
+
if (m === 0)
|
|
130
|
+
return n;
|
|
131
|
+
if (n === 0)
|
|
132
|
+
return m;
|
|
133
|
+
const dp = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
|
|
134
|
+
for (let i = 0; i <= m; i++)
|
|
135
|
+
dp[i][0] = i;
|
|
136
|
+
for (let j = 0; j <= n; j++)
|
|
137
|
+
dp[0][j] = j;
|
|
138
|
+
for (let i = 1; i <= m; i++) {
|
|
139
|
+
for (let j = 1; j <= n; j++) {
|
|
140
|
+
const cost = a[i - 1].toLowerCase() === b[j - 1].toLowerCase() ? 0 : 1;
|
|
141
|
+
dp[i][j] = Math.min(dp[i - 1][j] + 1, // deletion
|
|
142
|
+
dp[i][j - 1] + 1, // insertion
|
|
143
|
+
dp[i - 1][j - 1] + cost);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return dp[m][n];
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Find the closest matching type from a list of known types.
|
|
150
|
+
* Returns the best match if its edit distance is ≤ 3 (reasonable threshold
|
|
151
|
+
* for typo detection), or null if no close match exists.
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```ts
|
|
155
|
+
* suggestSimilarType('TYPO', ['note', 'tip', 'warning']) // → 'tip'
|
|
156
|
+
* suggestSimilarType('XYZ', ['note', 'tip']) // → null
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
export function suggestSimilarType(input, knownTypes) {
|
|
160
|
+
let bestMatch = null;
|
|
161
|
+
let bestDistance = Infinity;
|
|
162
|
+
for (const candidate of knownTypes) {
|
|
163
|
+
const dist = levenshtein(input, candidate);
|
|
164
|
+
if (dist < bestDistance) {
|
|
165
|
+
bestDistance = dist;
|
|
166
|
+
bestMatch = candidate;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// Only suggest if the edit distance is reasonable (≤ 3 edits, or ≤ half
|
|
170
|
+
// the input length for longer type names like 'further-reading').
|
|
171
|
+
const threshold = Math.max(3, Math.floor(input.length / 2));
|
|
172
|
+
return bestDistance <= threshold ? bestMatch : null;
|
|
173
|
+
}
|
|
174
|
+
// ---------------------------------------------------------------------------
|
|
175
|
+
// validateCustomCallouts — strict config validation
|
|
176
|
+
// ---------------------------------------------------------------------------
|
|
177
|
+
const REQUIRED_CALLOUT_FIELDS = ["type", "icon", "className", "defaultTitle", "color", "backgroundColor"];
|
|
178
|
+
/**
|
|
179
|
+
* v1.10.0+: Validate `customCallouts` config entries.
|
|
180
|
+
*
|
|
181
|
+
* When `strict` is true, throws a descriptive Error for the first config
|
|
182
|
+
* entry that's missing a required field. When `strict` is false, returns
|
|
183
|
+
* an array of validation errors without throwing (caller decides what to do).
|
|
184
|
+
*
|
|
185
|
+
* Required fields per CalloutConfig:
|
|
186
|
+
* - type (non-empty string)
|
|
187
|
+
* - icon (string, may be empty for icon-less callouts)
|
|
188
|
+
* - className (non-empty string, used for CSS targeting)
|
|
189
|
+
* - defaultTitle (non-empty string)
|
|
190
|
+
* - color (valid CSS color)
|
|
191
|
+
* - backgroundColor (valid CSS color)
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```ts
|
|
195
|
+
* validateCustomCallouts([
|
|
196
|
+
* { type: 'x', icon: '🔥', className: 'callout-x', defaultTitle: 'X', color: '#f00', backgroundColor: '#fee' }
|
|
197
|
+
* ], true); // OK — no throw
|
|
198
|
+
*
|
|
199
|
+
* validateCustomCallouts([
|
|
200
|
+
* { type: 'x', icon: '🔥' /* missing className, defaultTitle, color, backgroundColor *\/ }
|
|
201
|
+
* ], true); // throws: "Custom callout config[0] ('x') is missing required fields: className, defaultTitle, color, backgroundColor"
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
export function validateCustomCallouts(configs, strict) {
|
|
205
|
+
const errors = [];
|
|
206
|
+
for (let i = 0; i < configs.length; i++) {
|
|
207
|
+
const c = configs[i];
|
|
208
|
+
if (!c || typeof c !== "object") {
|
|
209
|
+
errors.push(`Custom callout config[${i}] is not an object`);
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
const missing = [];
|
|
213
|
+
for (const field of REQUIRED_CALLOUT_FIELDS) {
|
|
214
|
+
const val = c[field];
|
|
215
|
+
if (val === undefined || val === null || (typeof val === "string" && val.trim() === "" && field !== "icon")) {
|
|
216
|
+
missing.push(field);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (missing.length > 0) {
|
|
220
|
+
const name = typeof c.type === "string" ? `'${c.type}'` : `at index ${i}`;
|
|
221
|
+
const msg = `Custom callout config[${i}] (${name}) is missing required fields: ${missing.join(", ")}`;
|
|
222
|
+
errors.push(msg);
|
|
223
|
+
if (strict) {
|
|
224
|
+
throw new Error(`[remake-blocks] ${msg}`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return errors;
|
|
229
|
+
}
|
|
230
|
+
//# sourceMappingURL=dx.js.map
|
package/dist/dx.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dx.js","sourceRoot":"","sources":["../src/dx.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
*/
|
|
9
9
|
export { remarkRemakeBlocks, remarkCalloutBlocks, BUILTIN_CALLOUTS } from "./remark-remake-blocks.js";
|
|
10
10
|
export { escapeHtml, escapeAttribute, sanitizeColor } from "./remark-remake-blocks.js";
|
|
11
|
-
export { generateCss } from "./css-generator.js";
|
|
11
|
+
export { generateCss, generateMinimalThemeCss } from "./css-generator.js";
|
|
12
|
+
export { CLASSES, validateCustomCallouts, suggestSimilarType } from "./dx.js";
|
|
13
|
+
export type { CalloutClassName } from "./dx.js";
|
|
12
14
|
export { default } from "./astro.js";
|
|
13
|
-
export type { RemakeBlocksOptions, AstroRemakeBlocksOptions, CalloutConfig, CalloutType, BuiltinCalloutType, ParsedCallout, CustomCalloutType, CalloutConfigMap, } from "./types.js";
|
|
15
|
+
export type { RemakeBlocksOptions, AstroRemakeBlocksOptions, CalloutConfig, CalloutType, BuiltinCalloutType, LucideIconName, ParsedCallout, CustomCalloutType, CalloutConfigMap, } from "./types.js";
|
|
14
16
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAEtG,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAEtG,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAIvF,OAAO,EAAE,WAAW,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAG1E,OAAO,EAAE,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAC9E,YAAY,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAGhD,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAGrC,YAAY,EACV,mBAAmB,EACnB,wBAAwB,EACxB,aAAa,EACb,WAAW,EACX,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -11,7 +11,10 @@ export { remarkRemakeBlocks, remarkCalloutBlocks, BUILTIN_CALLOUTS } from "./rem
|
|
|
11
11
|
// Helpers (for users who supply a custom `build` render function)
|
|
12
12
|
export { escapeHtml, escapeAttribute, sanitizeColor } from "./remark-remake-blocks.js";
|
|
13
13
|
// v1.7.0+: CSS generator (for advanced usage outside Astro)
|
|
14
|
-
|
|
14
|
+
// v1.9.0+: also exports generateMinimalThemeCss for tree-shaken theme CSS
|
|
15
|
+
export { generateCss, generateMinimalThemeCss } from "./css-generator.js";
|
|
16
|
+
// v1.10.0+: DX utilities — CSS class constants, validation, "did you mean" suggester
|
|
17
|
+
export { CLASSES, validateCustomCallouts, suggestSimilarType } from "./dx.js";
|
|
15
18
|
// Astro integration (default export, re-exported for backward compatibility)
|
|
16
19
|
export { default } from "./astro.js";
|
|
17
20
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,qBAAqB;AACrB,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACtG,kEAAkE;AAClE,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAEvF,4DAA4D;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,qBAAqB;AACrB,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACtG,kEAAkE;AAClE,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAEvF,4DAA4D;AAC5D,0EAA0E;AAC1E,OAAO,EAAE,WAAW,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAE1E,qFAAqF;AACrF,OAAO,EAAE,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAG9E,6EAA6E;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remark-remake-blocks.d.ts","sourceRoot":"","sources":["../src/remark-remake-blocks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAqC,MAAM,OAAO,CAAC;AACrE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEtC,OAAO,KAAK,EACV,mBAAmB,EACnB,aAAa,EAId,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"remark-remake-blocks.d.ts","sourceRoot":"","sources":["../src/remark-remake-blocks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAqC,MAAM,OAAO,CAAC;AACrE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEtC,OAAO,KAAK,EACV,mBAAmB,EACnB,aAAa,EAId,MAAM,YAAY,CAAC;AAQpB,QAAA,MAAM,gBAAgB,EAAE,aAAa,EAyQpC,CAAC;AAkOF,iBAAS,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE5C;AAUD,iBAAS,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAW9D;AA6TD,iBAAS,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAOvC;AA08BD,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,CAAC,mBAAmB,CAAC,CAAC,EAAE,IAAI,CAgMnE,CAAC;AAiFF,eAAO,MAAM,mBAAmB,oDAAqB,CAAC;AAItD,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAE,CAAC;AAEtD,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
|
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
* `allowDangerousHtml: true` in plugin options to disable escaping —
|
|
15
15
|
* only do this if you fully trust your markdown source.
|
|
16
16
|
*/
|
|
17
|
+
import { visit } from "unist-util-visit";
|
|
18
|
+
// v1.10.0: DX utilities — warnings, validation, "did you mean" suggester
|
|
19
|
+
import { warn, validateCustomCallouts, suggestSimilarType } from "./dx.js";
|
|
17
20
|
// ---------------------------------------------------------------------------
|
|
18
21
|
// 27 Built-in callout configurations
|
|
19
22
|
// ---------------------------------------------------------------------------
|
|
@@ -443,6 +446,12 @@ const DEFAULT_OPTIONS = {
|
|
|
443
446
|
types: undefined,
|
|
444
447
|
defaultCollapse: undefined,
|
|
445
448
|
syntax: undefined,
|
|
449
|
+
// v1.9.0 defaults — all opt-in
|
|
450
|
+
icons: undefined,
|
|
451
|
+
cssMinimalTheme: false,
|
|
452
|
+
// v1.10.0 defaults — devWarnings auto-resolves (undefined = auto), strict off
|
|
453
|
+
devWarnings: undefined,
|
|
454
|
+
strictConfigValidation: false,
|
|
446
455
|
};
|
|
447
456
|
// ---------------------------------------------------------------------------
|
|
448
457
|
// Helper: Validate + normalize a single custom callout config.
|
|
@@ -690,7 +699,7 @@ function parseDirectiveAttrs(attrsBlock) {
|
|
|
690
699
|
// ---------------------------------------------------------------------------
|
|
691
700
|
// Helper: Parse the first paragraph of a blockquote to detect a callout
|
|
692
701
|
// ---------------------------------------------------------------------------
|
|
693
|
-
function parseCalloutDirective(blockquote, calloutPattern, configMap, enableDisclosures, defaultCollapse) {
|
|
702
|
+
function parseCalloutDirective(blockquote, calloutPattern, configMap, enableDisclosures, defaultCollapse, options) {
|
|
694
703
|
const firstChild = blockquote.children[0];
|
|
695
704
|
if (!firstChild || firstChild.type !== "paragraph")
|
|
696
705
|
return null;
|
|
@@ -705,8 +714,19 @@ function parseCalloutDirective(blockquote, calloutPattern, configMap, enableDisc
|
|
|
705
714
|
const lowerType = rawType.toLowerCase();
|
|
706
715
|
const isPullQuote = lowerType === "pull";
|
|
707
716
|
const isEpigraph = lowerType === "epigraph";
|
|
708
|
-
if (!isDisclosure && !isPullQuote && !isEpigraph && !configMap.has(lowerType))
|
|
717
|
+
if (!isDisclosure && !isPullQuote && !isEpigraph && !configMap.has(lowerType)) {
|
|
718
|
+
// v1.10.0: dev warning for unknown callout types with "did you mean" suggestion
|
|
719
|
+
const devWarn = options?._devWarnings;
|
|
720
|
+
if (devWarn) {
|
|
721
|
+
const known = options?._knownTypes;
|
|
722
|
+
const suggestion = known && known.length > 0 ? suggestSimilarType(rawType, known) : null;
|
|
723
|
+
const msg = suggestion
|
|
724
|
+
? `Unknown callout type '${rawType}'. Did you mean '${suggestion}'?`
|
|
725
|
+
: `Unknown callout type '${rawType}'. It will render as a plain blockquote.`;
|
|
726
|
+
warn(true, msg);
|
|
727
|
+
}
|
|
709
728
|
return null;
|
|
729
|
+
}
|
|
710
730
|
const type = isDisclosure ? "disclosure"
|
|
711
731
|
: isPullQuote ? "pull"
|
|
712
732
|
: isEpigraph ? "epigraph"
|
|
@@ -969,8 +989,36 @@ function buildCalloutHtml(parsed, blockquote, calloutPattern, configMap, options
|
|
|
969
989
|
}
|
|
970
990
|
}
|
|
971
991
|
const effectiveRenderIcon = renderIcon && resolvedIcon.length > 0;
|
|
972
|
-
|
|
973
|
-
|
|
992
|
+
// v1.9.0: icon sprite strategy. When icons.strategy === 'sprite', extract
|
|
993
|
+
// the inner SVG content (paths, circles, etc.) and register a <symbol> in
|
|
994
|
+
// the document-level sprite collector. The callout then references the
|
|
995
|
+
// symbol via <use href="#rb-icon-{key}"/> instead of inlining the full SVG.
|
|
996
|
+
//
|
|
997
|
+
// This dramatically reduces HTML size for callout-heavy pages: N callouts
|
|
998
|
+
// of the same type share ONE <symbol> definition instead of N inline SVGs.
|
|
999
|
+
const _iconStrategy = options._iconStrategy;
|
|
1000
|
+
const _spriteCollector = options._spriteCollector;
|
|
1001
|
+
let effectiveIconHtml = resolvedIcon;
|
|
1002
|
+
if (_iconStrategy === "none") {
|
|
1003
|
+
effectiveIconHtml = "";
|
|
1004
|
+
}
|
|
1005
|
+
else if (_iconStrategy === "sprite" && _spriteCollector && effectiveRenderIcon) {
|
|
1006
|
+
// Build a stable symbol ID from the callout type or icon name.
|
|
1007
|
+
// Per-callout {icon="rocket"} overrides get their own symbol; otherwise
|
|
1008
|
+
// the type name is the key (so all [!NOTE] callouts share one symbol).
|
|
1009
|
+
const symbolKey = parsed.overrides?.iconName
|
|
1010
|
+
? `rb-icon-${parsed.overrides.iconName.replace(/[^a-zA-Z0-9-]/g, "-")}`
|
|
1011
|
+
: `rb-icon-${parsed.type.replace(/[^a-zA-Z0-9-]/g, "-")}`;
|
|
1012
|
+
// Extract inner SVG content: everything between <svg ...> and </svg>.
|
|
1013
|
+
const innerMatch = resolvedIcon.match(/<svg[^>]*>([\s\S]*)<\/svg>/i);
|
|
1014
|
+
const inner = innerMatch ? innerMatch[1].trim() : resolvedIcon;
|
|
1015
|
+
if (!_spriteCollector.has(symbolKey)) {
|
|
1016
|
+
_spriteCollector.set(symbolKey, inner);
|
|
1017
|
+
}
|
|
1018
|
+
effectiveIconHtml = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><use href="#${symbolKey}"/></svg>`;
|
|
1019
|
+
}
|
|
1020
|
+
const iconHtml = effectiveRenderIcon && effectiveIconHtml
|
|
1021
|
+
? `<span class="callout-icon" style="color:${safeIconColor}" aria-hidden="true">${effectiveIconHtml}</span>`
|
|
974
1022
|
: "";
|
|
975
1023
|
// v1.2.0: title-text always rendered (unless appearance="hidden")
|
|
976
1024
|
const renderTitle = appearance !== "hidden";
|
|
@@ -985,8 +1033,9 @@ function buildCalloutHtml(parsed, blockquote, calloutPattern, configMap, options
|
|
|
985
1033
|
const titleTextTag = tags.titleText || "span";
|
|
986
1034
|
const bodyTag = tags.body || "div";
|
|
987
1035
|
// Build icon span with custom tag if provided
|
|
988
|
-
|
|
989
|
-
|
|
1036
|
+
// v1.9.0: uses effectiveIconHtml (sprite <use> reference when sprite mode)
|
|
1037
|
+
const iconSpan = effectiveRenderIcon && effectiveIconHtml
|
|
1038
|
+
? `<${iconTag} class="callout-icon" style="color:${safeIconColor}" aria-hidden="true">${effectiveIconHtml}</${iconTag}>`
|
|
990
1039
|
: "";
|
|
991
1040
|
// Build the title block (or skip for "hidden" appearance)
|
|
992
1041
|
const titleBlock = renderTitle
|
|
@@ -1592,6 +1641,19 @@ export const remarkRemakeBlocks = (userOptions) => {
|
|
|
1592
1641
|
...DEFAULT_OPTIONS,
|
|
1593
1642
|
...userOptions,
|
|
1594
1643
|
};
|
|
1644
|
+
// v1.10.0: resolve devWarnings. undefined → auto (true in dev, false in prod).
|
|
1645
|
+
const isProd = typeof process !== "undefined" && process.env && process.env.NODE_ENV === "production";
|
|
1646
|
+
const devWarningsEnabled = options.devWarnings === undefined ? !isProd : options.devWarnings;
|
|
1647
|
+
// v1.10.0: strict customCallouts validation. Throws at init time when
|
|
1648
|
+
// strictConfigValidation is true and any config entry is missing required
|
|
1649
|
+
// fields. In non-strict mode, emits a dev warning instead.
|
|
1650
|
+
if (options.customCallouts && options.customCallouts.length > 0) {
|
|
1651
|
+
const errors = validateCustomCallouts(options.customCallouts, options.strictConfigValidation);
|
|
1652
|
+
if (errors.length > 0 && !options.strictConfigValidation) {
|
|
1653
|
+
for (const e of errors)
|
|
1654
|
+
warn(devWarningsEnabled, e);
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1595
1657
|
// v1.8.0: resolve `syntax` into enableDirectiveSyntax / enableMkDocsSyntax.
|
|
1596
1658
|
// Explicit `enableDirectiveSyntax` / `enableMkDocsSyntax` (v1.3.0 / v1.4.0
|
|
1597
1659
|
// API) take precedence over `syntax` for backward compatibility.
|
|
@@ -1611,11 +1673,24 @@ export const remarkRemakeBlocks = (userOptions) => {
|
|
|
1611
1673
|
}
|
|
1612
1674
|
const configMap = buildCalloutConfigMap(options);
|
|
1613
1675
|
const calloutPattern = options.calloutPattern || buildCalloutPattern(configMap, options.enableDisclosures);
|
|
1676
|
+
// v1.10.0: stash devWarnings flag + known types list on options so
|
|
1677
|
+
// buildCalloutHtml / parseCalloutDirective can emit warnings.
|
|
1678
|
+
options._devWarnings = devWarningsEnabled;
|
|
1679
|
+
options._knownTypes = Array.from(configMap.keys());
|
|
1680
|
+
// v1.9.0: sprite collector — accumulates { symbolId: svgInnerHtml } entries
|
|
1681
|
+
// across all callouts in this document. Populated by buildCalloutHtml when
|
|
1682
|
+
// icons.strategy === 'sprite'. Emitted as a single <svg> sprite at the top
|
|
1683
|
+
// of the document after Pass 1 completes.
|
|
1684
|
+
const iconStrategy = options.icons?.strategy ?? "inline";
|
|
1685
|
+
const spriteCollector = new Map();
|
|
1614
1686
|
return (tree) => {
|
|
1615
1687
|
// v1.2.0: reset per-tree counter for idempotent output (same markdown →
|
|
1616
1688
|
// same HTML, including same ids). This is important for snapshot tests
|
|
1617
1689
|
// and for SSR/deterministic rendering.
|
|
1618
1690
|
resetCalloutIdCounter();
|
|
1691
|
+
// v1.9.0: reset sprite collector per-tree so repeated process() calls
|
|
1692
|
+
// don't accumulate stale entries.
|
|
1693
|
+
spriteCollector.clear();
|
|
1619
1694
|
// v1.3.0: Pass 0 — Transform :::type[Title]{overrides} ... ::: directive syntax
|
|
1620
1695
|
// into callouts (Starlight/Docusaurus/MkDocs content portability).
|
|
1621
1696
|
if (options.enableDirectiveSyntax) {
|
|
@@ -1626,6 +1701,37 @@ export const remarkRemakeBlocks = (userOptions) => {
|
|
|
1626
1701
|
if (options.enableMkDocsSyntax) {
|
|
1627
1702
|
transformMkDocsSyntax(tree, configMap, options);
|
|
1628
1703
|
}
|
|
1704
|
+
// v1.10.0: Pass 0c — Scan for unknown callout directives and emit dev warnings.
|
|
1705
|
+
// The calloutPattern only matches KNOWN types, so unknown types like
|
|
1706
|
+
// [!TYPO] fall through to plain blockquotes WITHOUT entering parseCalloutDirective.
|
|
1707
|
+
// This pre-scan catches them so users get a "did you mean" hint.
|
|
1708
|
+
if (devWarningsEnabled) {
|
|
1709
|
+
const knownTypes = options._knownTypes;
|
|
1710
|
+
const anyDirectiveRe = /^\[!([A-Za-z][A-Za-z0-9-]*)\]/;
|
|
1711
|
+
visit(tree, "blockquote", (bq) => {
|
|
1712
|
+
const first = bq.children[0];
|
|
1713
|
+
if (!first || first.type !== "paragraph")
|
|
1714
|
+
return;
|
|
1715
|
+
const text = extractTextContent(first);
|
|
1716
|
+
if (!text)
|
|
1717
|
+
return;
|
|
1718
|
+
const m = text.match(anyDirectiveRe);
|
|
1719
|
+
if (!m)
|
|
1720
|
+
return;
|
|
1721
|
+
const rawType = m[1];
|
|
1722
|
+
const lowerType = rawType.toLowerCase();
|
|
1723
|
+
// Skip disclosures (empty type), pull quotes, epigraphs, and known types
|
|
1724
|
+
if (lowerType === "" || lowerType === "pull" || lowerType === "epigraph")
|
|
1725
|
+
return;
|
|
1726
|
+
if (configMap.has(lowerType))
|
|
1727
|
+
return;
|
|
1728
|
+
const suggestion = suggestSimilarType(rawType, knownTypes);
|
|
1729
|
+
const msg = suggestion
|
|
1730
|
+
? `Unknown callout type '${rawType}'. Did you mean '${suggestion}'?`
|
|
1731
|
+
: `Unknown callout type '${rawType}'. It will render as a plain blockquote.`;
|
|
1732
|
+
warn(true, msg);
|
|
1733
|
+
});
|
|
1734
|
+
}
|
|
1629
1735
|
// ── Pass 1: Transform blockquotes → callouts / disclosures ──────
|
|
1630
1736
|
// We must process DEEPEST blockquotes first (inside-out) so that
|
|
1631
1737
|
// nested [!] directives are converted before their parents read them.
|
|
@@ -1662,11 +1768,14 @@ export const remarkRemakeBlocks = (userOptions) => {
|
|
|
1662
1768
|
if (foundIdx === -1)
|
|
1663
1769
|
continue; // Already replaced
|
|
1664
1770
|
}
|
|
1665
|
-
const parsed = parseCalloutDirective(bq, calloutPattern, configMap, options.enableDisclosures, options.defaultCollapse);
|
|
1771
|
+
const parsed = parseCalloutDirective(bq, calloutPattern, configMap, options.enableDisclosures, options.defaultCollapse, options);
|
|
1666
1772
|
if (parsed) {
|
|
1667
1773
|
// For disclosures: depth > 0 means it's nested inside another blockquote
|
|
1668
1774
|
// (which is likely another disclosure or callout) → tree view
|
|
1669
1775
|
const disclosureDepth = parsed.isDisclosure ? depth : 0;
|
|
1776
|
+
// v1.9.0: attach sprite collector + strategy to options for buildCalloutHtml
|
|
1777
|
+
options._iconStrategy = iconStrategy;
|
|
1778
|
+
options._spriteCollector = spriteCollector;
|
|
1670
1779
|
const calloutNode = buildCalloutHtml(parsed, bq, calloutPattern, configMap, options, disclosureDepth);
|
|
1671
1780
|
// Replace using the actual current index
|
|
1672
1781
|
const actualIdx = parent.children.indexOf(bq);
|
|
@@ -1691,6 +1800,19 @@ export const remarkRemakeBlocks = (userOptions) => {
|
|
|
1691
1800
|
if (options.enableAccordion && options.enableDisclosures) {
|
|
1692
1801
|
groupAccordions(tree, options.accordionClass);
|
|
1693
1802
|
}
|
|
1803
|
+
// v1.9.0: Pass 3 — Emit icon sprite at the top of the document.
|
|
1804
|
+
// Only when icons.strategy === 'sprite' AND at least one callout
|
|
1805
|
+
// registered an icon. The sprite uses display:none so it doesn't
|
|
1806
|
+
// affect layout; <use href="#rb-icon-{key}"/> references resolve
|
|
1807
|
+
// against it.
|
|
1808
|
+
if (iconStrategy === "sprite" && spriteCollector.size > 0) {
|
|
1809
|
+
const symbols = Array.from(spriteCollector.entries())
|
|
1810
|
+
.map(([id, inner]) => `<symbol id="${id}" viewBox="0 0 24 24">${inner}</symbol>`)
|
|
1811
|
+
.join("");
|
|
1812
|
+
const spriteHtml = `<svg xmlns="http://www.w3.org/2000/svg" style="display:none" aria-hidden="true">${symbols}</svg>`;
|
|
1813
|
+
// Prepend to the document tree as a raw HTML node
|
|
1814
|
+
tree.children.unshift(html(spriteHtml));
|
|
1815
|
+
}
|
|
1694
1816
|
};
|
|
1695
1817
|
};
|
|
1696
1818
|
// ---------------------------------------------------------------------------
|