@barzhsieh/nuxt-content-mermaid 2.2.3 → 3.0.2
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/README.md +47 -502
- package/README.zh-TW.md +46 -509
- package/dist/module.d.mts +39 -53
- package/dist/module.json +3 -3
- package/dist/module.mjs +600 -155
- package/dist/runtime/built-in-renderer/BuiltInRenderer.d.vue.ts +0 -0
- package/dist/runtime/built-in-renderer/BuiltInRenderer.vue +597 -0
- package/dist/runtime/built-in-renderer/BuiltInRenderer.vue.d.ts +0 -0
- package/dist/runtime/component-configuration-error.d.ts +3 -0
- package/dist/runtime/component-configuration-error.js +7 -0
- package/dist/runtime/component-configuration.d.ts +23 -0
- package/dist/runtime/component-configuration.js +78 -0
- package/dist/runtime/components/ContentMermaidTransport.d.vue.ts +10 -0
- package/dist/runtime/components/ContentMermaidTransport.vue +21 -0
- package/dist/runtime/components/ContentMermaidTransport.vue.d.ts +10 -0
- package/dist/runtime/components/Mermaid.d.vue.ts +0 -31
- package/dist/runtime/components/Mermaid.vue +136 -743
- package/dist/runtime/components/Mermaid.vue.d.ts +0 -31
- package/dist/runtime/components/MermaidExpandOverlay.d.vue.ts +13 -16
- package/dist/runtime/components/MermaidExpandOverlay.vue +61 -53
- package/dist/runtime/components/MermaidExpandOverlay.vue.d.ts +13 -16
- package/dist/runtime/components/MermaidFullscreenPresentation.d.vue.ts +18 -0
- package/dist/runtime/components/MermaidFullscreenPresentation.vue +56 -0
- package/dist/runtime/components/MermaidFullscreenPresentation.vue.d.ts +18 -0
- package/dist/runtime/composables/useMermaidExpand.d.ts +16 -32
- package/dist/runtime/composables/useMermaidExpand.js +232 -75
- package/dist/runtime/composables/useMermaidFullscreen.d.ts +18 -0
- package/dist/runtime/composables/useMermaidFullscreen.js +242 -0
- package/dist/runtime/composables/useMermaidZoom.d.ts +5 -1
- package/dist/runtime/composables/useMermaidZoom.js +54 -28
- package/dist/runtime/configuration/core.d.ts +27 -0
- package/dist/runtime/configuration/core.js +340 -0
- package/dist/runtime/configuration/module.d.ts +17 -0
- package/dist/runtime/configuration/module.js +233 -0
- package/dist/runtime/configuration/runtime-options.d.ts +4 -0
- package/dist/runtime/configuration/runtime-options.js +57 -0
- package/dist/runtime/constants.d.ts +24 -0
- package/dist/runtime/constants.js +60 -2
- package/dist/runtime/direct-mermaid-config.d.ts +5 -0
- package/dist/runtime/direct-mermaid-config.js +216 -0
- package/dist/runtime/mermaid-config.d.ts +9 -5
- package/dist/runtime/mermaid-config.js +30 -19
- package/dist/runtime/mermaid-rendering.d.ts +28 -0
- package/dist/runtime/mermaid-rendering.js +140 -0
- package/dist/runtime/plugins/content-mermaid-transport.d.ts +2 -0
- package/dist/runtime/plugins/content-mermaid-transport.js +5 -0
- package/dist/runtime/plugins/mermaid.client.d.ts +0 -3
- package/dist/runtime/plugins/mermaid.client.js +14 -32
- package/dist/runtime/plugins/runtime-config.d.ts +2 -0
- package/dist/runtime/plugins/runtime-config.js +9 -0
- package/dist/runtime/rendererSelection.d.ts +43 -0
- package/dist/runtime/rendererSelection.js +36 -0
- package/dist/runtime/rendererSelectionOrchestration.d.ts +12 -0
- package/dist/runtime/rendererSelectionOrchestration.js +13 -0
- package/dist/runtime/runtime-snapshot.d.ts +3 -0
- package/dist/runtime/runtime-snapshot.js +26 -0
- package/dist/runtime/utils/index.d.ts +0 -4
- package/dist/runtime/utils/index.js +0 -37
- package/dist/types.d.mts +2 -2
- package/package.json +38 -32
- package/dist/runtime/utils/mermaid-transform.d.ts +0 -18
- package/dist/runtime/utils/mermaid-transform.js +0 -345
package/dist/module.mjs
CHANGED
|
@@ -1,152 +1,448 @@
|
|
|
1
|
-
import { defineNuxtModule,
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
1
|
+
import { defineNuxtModule, createResolver, addVitePlugin, addPlugin, addComponent, addImports, addTypeTemplate } from '@nuxt/kit';
|
|
2
|
+
import { cloneOwnedData, mergeByPresence, assertStrictData, ContentMermaidConfigurationError } from '../dist/runtime/configuration/core.js';
|
|
3
|
+
import { resolveModuleConfiguration } from '../dist/runtime/configuration/module.js';
|
|
4
|
+
import destr from 'destr';
|
|
5
|
+
import { parse, stringify } from 'yaml';
|
|
6
|
+
import { isRecord, isNonEmptyRecord } from '../dist/runtime/utils/is.js';
|
|
6
7
|
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const MERMAID_FENCE_RE = /^[ \t]*(?:`{3,}|~{3,})[ \t]*mermaid(?:$|[ \t{[])/im;
|
|
18
|
-
const DEFAULTS = {
|
|
19
|
-
enabled: true,
|
|
20
|
-
loader: {
|
|
21
|
-
init: { ...DEFAULT_MERMAID_CONFIG },
|
|
22
|
-
lazy: true
|
|
23
|
-
},
|
|
24
|
-
theme: {
|
|
25
|
-
light: DEFAULT_LIGHT_THEME,
|
|
26
|
-
dark: DEFAULT_DARK_THEME
|
|
27
|
-
},
|
|
28
|
-
components: {
|
|
29
|
-
renderer: void 0,
|
|
30
|
-
spinner: void 0,
|
|
31
|
-
error: void 0
|
|
32
|
-
},
|
|
33
|
-
expand: DEFAULT_EXPAND_OPTIONS,
|
|
34
|
-
toolbar: DEFAULT_TOOLBAR_OPTIONS
|
|
35
|
-
};
|
|
36
|
-
const module$1 = defineNuxtModule({
|
|
37
|
-
meta: {
|
|
38
|
-
name: MODULE_NAME,
|
|
39
|
-
configKey: "contentMermaid",
|
|
40
|
-
compatibility: {
|
|
41
|
-
nuxt: "^3.20.1 || ^4.1.0"
|
|
8
|
+
const UNSAFE_INLINE_KEYS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
|
|
9
|
+
function inspectMermaidFrontmatter(rawCode, newline) {
|
|
10
|
+
const lines = rawCode.split(newline);
|
|
11
|
+
let startIndex = 0;
|
|
12
|
+
while (startIndex < lines.length) {
|
|
13
|
+
const line = lines[startIndex];
|
|
14
|
+
const trimmed = line.trim();
|
|
15
|
+
if (!trimmed) {
|
|
16
|
+
startIndex += 1;
|
|
17
|
+
continue;
|
|
42
18
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
config.optimizeDeps ||= {};
|
|
83
|
-
config.optimizeDeps.include ||= [];
|
|
84
|
-
config.optimizeDeps.include.push(
|
|
85
|
-
...MERMAID_OPTIMIZE_DEPS.map((dep) => `${MODULE_NAME} > ${dep}`)
|
|
86
|
-
);
|
|
87
|
-
}
|
|
19
|
+
if (isMermaidDirectiveStart(line)) {
|
|
20
|
+
startIndex = skipMermaidDirective(lines, startIndex);
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (isMermaidCommentLine(line)) {
|
|
24
|
+
startIndex += 1;
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
if (startIndex >= lines.length)
|
|
30
|
+
return { kind: "absent" };
|
|
31
|
+
const startLine = lines[startIndex];
|
|
32
|
+
if (startLine.trim() !== "---")
|
|
33
|
+
return { kind: "absent" };
|
|
34
|
+
const indentMatch = startLine.match(/^\s*/);
|
|
35
|
+
const indent = indentMatch ? indentMatch[0] : "";
|
|
36
|
+
let endIndex = -1;
|
|
37
|
+
for (let i = startIndex + 1; i < lines.length; i++) {
|
|
38
|
+
if (lines[i].trim() === "---") {
|
|
39
|
+
endIndex = i;
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (endIndex === -1)
|
|
44
|
+
return { kind: "invalid" };
|
|
45
|
+
const yamlLines = lines.slice(startIndex + 1, endIndex).map((line) => line.startsWith(indent) ? line.slice(indent.length) : line);
|
|
46
|
+
const yamlRaw = yamlLines.join("\n").trim();
|
|
47
|
+
try {
|
|
48
|
+
const data = yamlRaw ? parse(yamlRaw) : {};
|
|
49
|
+
if (!isRecord(data))
|
|
50
|
+
return { kind: "invalid" };
|
|
51
|
+
return {
|
|
52
|
+
kind: "valid",
|
|
53
|
+
info: {
|
|
54
|
+
data,
|
|
55
|
+
startIndex,
|
|
56
|
+
endIndex,
|
|
57
|
+
indent
|
|
88
58
|
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
59
|
+
};
|
|
60
|
+
} catch {
|
|
61
|
+
return { kind: "invalid" };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function isMermaidDirectiveStart(line) {
|
|
65
|
+
return line.trim().startsWith("%%{");
|
|
66
|
+
}
|
|
67
|
+
function isMermaidCommentLine(line) {
|
|
68
|
+
const trimmed = line.trim();
|
|
69
|
+
return trimmed.startsWith("%%") && !trimmed.startsWith("%%{");
|
|
70
|
+
}
|
|
71
|
+
function skipMermaidDirective(lines, startIndex) {
|
|
72
|
+
let index = startIndex;
|
|
73
|
+
while (index < lines.length) {
|
|
74
|
+
if (lines[index].includes("}%%"))
|
|
75
|
+
return index + 1;
|
|
76
|
+
index += 1;
|
|
77
|
+
}
|
|
78
|
+
return lines.length;
|
|
79
|
+
}
|
|
80
|
+
function parseInlineAttrs(info) {
|
|
81
|
+
const attrsBlock = extractInlineAttrsBlock(info);
|
|
82
|
+
if (attrsBlock === null)
|
|
83
|
+
return null;
|
|
84
|
+
return parseInlineAttrsBlock(attrsBlock);
|
|
85
|
+
}
|
|
86
|
+
function extractInlineAttrsBlock(info) {
|
|
87
|
+
const startIndex = info.indexOf("{");
|
|
88
|
+
if (startIndex === -1)
|
|
89
|
+
return null;
|
|
90
|
+
let depth = 0;
|
|
91
|
+
let quote = null;
|
|
92
|
+
for (let i = startIndex; i < info.length; i++) {
|
|
93
|
+
const char = info[i];
|
|
94
|
+
if (quote) {
|
|
95
|
+
if (char === quote && info[i - 1] !== "\\")
|
|
96
|
+
quote = null;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if (char === '"' || char === "'") {
|
|
100
|
+
quote = char;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (char === "{") {
|
|
104
|
+
depth += 1;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (char === "}") {
|
|
108
|
+
depth -= 1;
|
|
109
|
+
if (depth === 0)
|
|
110
|
+
return info.slice(startIndex + 1, i);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
function parseInlineAttrsBlock(raw) {
|
|
116
|
+
const result = {};
|
|
117
|
+
let index = 0;
|
|
118
|
+
while (index < raw.length) {
|
|
119
|
+
index = skipSeparators(raw, index);
|
|
120
|
+
if (index >= raw.length)
|
|
121
|
+
break;
|
|
122
|
+
const keyStart = index;
|
|
123
|
+
while (index < raw.length && isAttrKeyChar(raw[index]))
|
|
124
|
+
index += 1;
|
|
125
|
+
const key = raw.slice(keyStart, index).trim();
|
|
126
|
+
if (!key)
|
|
127
|
+
break;
|
|
128
|
+
index = skipWhitespace(raw, index);
|
|
129
|
+
let value = true;
|
|
130
|
+
if (index < raw.length && (raw[index] === "=" || raw[index] === ":")) {
|
|
131
|
+
index += 1;
|
|
132
|
+
index = skipWhitespace(raw, index);
|
|
133
|
+
const { value: rawValue, nextIndex, quoted } = readAttributeValue(raw, index);
|
|
134
|
+
index = nextIndex;
|
|
135
|
+
value = parseAttributeValue(rawValue, quoted);
|
|
136
|
+
}
|
|
137
|
+
if (!setNestedValue(result, key, value))
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
function skipWhitespace(input, index) {
|
|
143
|
+
let cursor = index;
|
|
144
|
+
while (cursor < input.length) {
|
|
145
|
+
const char = input[cursor];
|
|
146
|
+
if (char !== " " && char !== " " && char !== "\n" && char !== "\r")
|
|
147
|
+
break;
|
|
148
|
+
cursor += 1;
|
|
149
|
+
}
|
|
150
|
+
return cursor;
|
|
151
|
+
}
|
|
152
|
+
function skipSeparators(input, index) {
|
|
153
|
+
let cursor = index;
|
|
154
|
+
while (cursor < input.length) {
|
|
155
|
+
const char = input[cursor];
|
|
156
|
+
if (char !== " " && char !== " " && char !== "\n" && char !== "\r" && char !== ";")
|
|
157
|
+
break;
|
|
158
|
+
cursor += 1;
|
|
159
|
+
}
|
|
160
|
+
return cursor;
|
|
161
|
+
}
|
|
162
|
+
function isAttrKeyChar(char) {
|
|
163
|
+
return /[\w.-]/.test(char);
|
|
164
|
+
}
|
|
165
|
+
function readAttributeValue(input, start) {
|
|
166
|
+
const char = input[start];
|
|
167
|
+
if (char === '"' || char === "'")
|
|
168
|
+
return readQuotedValue(input, start);
|
|
169
|
+
if (char === "{" || char === "[")
|
|
170
|
+
return readBalancedValue(input, start);
|
|
171
|
+
let end = start;
|
|
172
|
+
while (end < input.length) {
|
|
173
|
+
const current = input[end];
|
|
174
|
+
if (current === ";" || current === " " || current === " " || current === "\n" || current === "\r")
|
|
175
|
+
break;
|
|
176
|
+
end += 1;
|
|
177
|
+
}
|
|
178
|
+
return { value: input.slice(start, end), nextIndex: end, quoted: false };
|
|
179
|
+
}
|
|
180
|
+
function readQuotedValue(input, start) {
|
|
181
|
+
const quote = input[start];
|
|
182
|
+
let cursor = start + 1;
|
|
183
|
+
let result = "";
|
|
184
|
+
while (cursor < input.length) {
|
|
185
|
+
const char = input[cursor];
|
|
186
|
+
if (char === "\\" && cursor + 1 < input.length) {
|
|
187
|
+
result += input[cursor + 1];
|
|
188
|
+
cursor += 2;
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (char === quote) {
|
|
192
|
+
return { value: result, nextIndex: cursor + 1, quoted: true };
|
|
193
|
+
}
|
|
194
|
+
result += char;
|
|
195
|
+
cursor += 1;
|
|
196
|
+
}
|
|
197
|
+
return { value: result, nextIndex: cursor, quoted: true };
|
|
198
|
+
}
|
|
199
|
+
function readBalancedValue(input, start) {
|
|
200
|
+
const open = input[start];
|
|
201
|
+
const close = open === "{" ? "}" : "]";
|
|
202
|
+
let depth = 0;
|
|
203
|
+
let quote = null;
|
|
204
|
+
for (let i = start; i < input.length; i++) {
|
|
205
|
+
const char = input[i];
|
|
206
|
+
if (quote) {
|
|
207
|
+
if (char === quote && input[i - 1] !== "\\")
|
|
208
|
+
quote = null;
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
if (char === '"' || char === "'") {
|
|
212
|
+
quote = char;
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
if (char === open) {
|
|
216
|
+
depth += 1;
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
if (char === close) {
|
|
220
|
+
depth -= 1;
|
|
221
|
+
if (depth === 0) {
|
|
222
|
+
return { value: input.slice(start, i + 1), nextIndex: i + 1, quoted: false };
|
|
103
223
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return { value: input.slice(start), nextIndex: input.length, quoted: false };
|
|
227
|
+
}
|
|
228
|
+
function parseAttributeValue(raw, quoted) {
|
|
229
|
+
const value = raw.trim();
|
|
230
|
+
if (!value)
|
|
231
|
+
return "";
|
|
232
|
+
const isStructured = value.startsWith("{") || value.startsWith("[");
|
|
233
|
+
if (quoted) {
|
|
234
|
+
if (!isStructured)
|
|
235
|
+
return value;
|
|
236
|
+
return parseStructuredValue(value);
|
|
237
|
+
}
|
|
238
|
+
if (isStructured)
|
|
239
|
+
return parseStructuredValue(value);
|
|
240
|
+
return destr(value);
|
|
241
|
+
}
|
|
242
|
+
function parseStructuredValue(value) {
|
|
243
|
+
const parsed = destr(value);
|
|
244
|
+
if (parsed !== value)
|
|
245
|
+
return parsed;
|
|
246
|
+
try {
|
|
247
|
+
const yamlParsed = parse(value);
|
|
248
|
+
if (isRecord(yamlParsed) || Array.isArray(yamlParsed))
|
|
249
|
+
return yamlParsed;
|
|
250
|
+
} catch {
|
|
251
|
+
}
|
|
252
|
+
return value;
|
|
253
|
+
}
|
|
254
|
+
function setNestedValue(target, path, value) {
|
|
255
|
+
const keys = path.split(".").filter(Boolean);
|
|
256
|
+
if (!keys.length)
|
|
257
|
+
return false;
|
|
258
|
+
let current = target;
|
|
259
|
+
for (let i = 0; i < keys.length; i++) {
|
|
260
|
+
const key = keys[i];
|
|
261
|
+
if (UNSAFE_INLINE_KEYS.has(key))
|
|
262
|
+
return false;
|
|
263
|
+
if (i === keys.length - 1) {
|
|
264
|
+
current[key] = value;
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
const existing = current[key];
|
|
268
|
+
if (!isRecord(existing)) {
|
|
269
|
+
current[key] = {};
|
|
270
|
+
}
|
|
271
|
+
current = current[key];
|
|
272
|
+
}
|
|
273
|
+
return true;
|
|
274
|
+
}
|
|
275
|
+
function applyResolvedMermaidFrontmatter(rawCode, newline, frontmatterInfo, frontmatter, fallbackIndent) {
|
|
276
|
+
const frontmatterLines = serializeMermaidFrontmatter(
|
|
277
|
+
frontmatter,
|
|
278
|
+
frontmatterInfo?.indent ?? fallbackIndent
|
|
279
|
+
);
|
|
280
|
+
const lines = rawCode.split(newline);
|
|
281
|
+
if (frontmatterInfo) {
|
|
282
|
+
const before = lines.slice(0, frontmatterInfo.startIndex);
|
|
283
|
+
const after = lines.slice(frontmatterInfo.endIndex + 1);
|
|
284
|
+
return [...frontmatterLines, ...before, ...after].join(newline);
|
|
285
|
+
}
|
|
286
|
+
return [
|
|
287
|
+
...frontmatterLines,
|
|
288
|
+
...lines
|
|
289
|
+
].join(newline);
|
|
290
|
+
}
|
|
291
|
+
function serializeMermaidFrontmatter(frontmatter, indent) {
|
|
292
|
+
const yaml = stringify(frontmatter).trim();
|
|
293
|
+
const yamlLines = yaml ? yaml.split("\n").map((line) => `${indent}${line}`) : [];
|
|
294
|
+
const delimiter = `${indent}---`;
|
|
295
|
+
return [
|
|
296
|
+
delimiter,
|
|
297
|
+
...yamlLines,
|
|
298
|
+
delimiter
|
|
299
|
+
];
|
|
300
|
+
}
|
|
109
301
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
302
|
+
const MARKDOWN_METADATA_PHASE = {
|
|
303
|
+
name: "Markdown Mermaid Metadata",
|
|
304
|
+
root: "mermaid"
|
|
305
|
+
};
|
|
306
|
+
const UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
307
|
+
const INLINE_ATTRIBUTE_KEYS = /* @__PURE__ */ new Set(["title", "config", "toolbar"]);
|
|
308
|
+
const TOOLBAR_KEYS = /* @__PURE__ */ new Set(["title", "fontSize", "fullscreenToolbarScale", "buttons"]);
|
|
309
|
+
const TOOLBAR_BUTTON_KEYS = /* @__PURE__ */ new Set(["copy", "fullscreen", "expand"]);
|
|
310
|
+
function hasOwn(value, key) {
|
|
311
|
+
return Object.prototype.hasOwnProperty.call(value, key);
|
|
312
|
+
}
|
|
313
|
+
function valueAt(value, key) {
|
|
314
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
315
|
+
return descriptor && "value" in descriptor ? descriptor.value : void 0;
|
|
316
|
+
}
|
|
317
|
+
function isPlainRecord(value) {
|
|
318
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
319
|
+
const prototype = Object.getPrototypeOf(value);
|
|
320
|
+
return prototype === Object.prototype || prototype === null;
|
|
321
|
+
}
|
|
322
|
+
function hasUnsafeKeys(value) {
|
|
323
|
+
if (value === null || typeof value !== "object") return false;
|
|
324
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
325
|
+
for (const key of Object.keys(descriptors)) {
|
|
326
|
+
if (UNSAFE_KEYS.has(key)) return true;
|
|
327
|
+
const descriptor = descriptors[key];
|
|
328
|
+
if (descriptor && "value" in descriptor && hasUnsafeKeys(descriptor.value))
|
|
329
|
+
return true;
|
|
113
330
|
}
|
|
331
|
+
return false;
|
|
114
332
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
333
|
+
function normalizeRecord(value) {
|
|
334
|
+
try {
|
|
335
|
+
assertStrictData(value, MARKDOWN_METADATA_PHASE);
|
|
336
|
+
} catch (error) {
|
|
337
|
+
if (error instanceof ContentMermaidConfigurationError) return null;
|
|
338
|
+
throw error;
|
|
118
339
|
}
|
|
340
|
+
if (!isPlainRecord(value) || hasUnsafeKeys(value)) return null;
|
|
341
|
+
return cloneOwnedData(value);
|
|
119
342
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
343
|
+
function hasOnlyKeys(value, allowedKeys) {
|
|
344
|
+
return Object.keys(Object.getOwnPropertyDescriptors(value)).every((key) => allowedKeys.has(key));
|
|
345
|
+
}
|
|
346
|
+
function isStringifiableScalar(value) {
|
|
347
|
+
return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
348
|
+
}
|
|
349
|
+
function normalizeToolbar(value) {
|
|
350
|
+
const toolbar = normalizeRecord(value);
|
|
351
|
+
if (!toolbar || !hasOnlyKeys(toolbar, TOOLBAR_KEYS)) return null;
|
|
352
|
+
const title = valueAt(toolbar, "title");
|
|
353
|
+
if (title !== void 0 && typeof title !== "string") return null;
|
|
354
|
+
const fontSize = valueAt(toolbar, "fontSize");
|
|
355
|
+
if (fontSize !== void 0 && typeof fontSize !== "string" && typeof fontSize !== "number") return null;
|
|
356
|
+
const fullscreenToolbarScale = valueAt(toolbar, "fullscreenToolbarScale");
|
|
357
|
+
if (fullscreenToolbarScale !== void 0 && typeof fullscreenToolbarScale !== "number") return null;
|
|
358
|
+
const buttons = valueAt(toolbar, "buttons");
|
|
359
|
+
if (buttons !== void 0) {
|
|
360
|
+
if (!isPlainRecord(buttons) || !hasOnlyKeys(buttons, TOOLBAR_BUTTON_KEYS)) return null;
|
|
361
|
+
for (const key of TOOLBAR_BUTTON_KEYS) {
|
|
362
|
+
const button = valueAt(buttons, key);
|
|
363
|
+
if (button !== void 0 && typeof button !== "boolean") return null;
|
|
364
|
+
}
|
|
132
365
|
}
|
|
133
|
-
|
|
134
|
-
|
|
366
|
+
return toolbar;
|
|
367
|
+
}
|
|
368
|
+
function resolveDiagramMermaidConfig(value) {
|
|
369
|
+
return normalizeRecord(value);
|
|
370
|
+
}
|
|
371
|
+
function resolveFenceInlineAttributes(value) {
|
|
372
|
+
if (value === null) return null;
|
|
373
|
+
const attrs = normalizeRecord(value);
|
|
374
|
+
if (!attrs || !hasOnlyKeys(attrs, INLINE_ATTRIBUTE_KEYS)) return null;
|
|
375
|
+
const normalized = cloneOwnedData(attrs);
|
|
376
|
+
for (const key of ["title"]) {
|
|
377
|
+
if (!hasOwn(attrs, key)) continue;
|
|
378
|
+
const attribute = valueAt(attrs, key);
|
|
379
|
+
if (attribute === void 0 || !isStringifiableScalar(attribute)) return null;
|
|
380
|
+
normalized[key] = String(attribute);
|
|
381
|
+
}
|
|
382
|
+
if (hasOwn(attrs, "config")) {
|
|
383
|
+
const config = resolveDiagramMermaidConfig(valueAt(attrs, "config"));
|
|
384
|
+
if (!config) return null;
|
|
385
|
+
normalized.config = config;
|
|
386
|
+
}
|
|
387
|
+
if (hasOwn(attrs, "toolbar")) {
|
|
388
|
+
const toolbar = resolveMarkdownToolbar([valueAt(attrs, "toolbar")]);
|
|
389
|
+
if (toolbar === null || toolbar === void 0) return null;
|
|
390
|
+
normalized.toolbar = toolbar;
|
|
391
|
+
}
|
|
392
|
+
return normalized;
|
|
393
|
+
}
|
|
394
|
+
function resolveMarkdownFrontmatter(layers) {
|
|
395
|
+
const normalizedLayers = [];
|
|
396
|
+
for (const layer of layers) {
|
|
397
|
+
if (layer === void 0) continue;
|
|
398
|
+
const normalized = normalizeRecord(layer);
|
|
399
|
+
if (!normalized) return null;
|
|
400
|
+
if (hasOwn(normalized, "config")) {
|
|
401
|
+
const config = resolveDiagramMermaidConfig(valueAt(normalized, "config"));
|
|
402
|
+
if (!config) return null;
|
|
403
|
+
normalized.config = config;
|
|
404
|
+
}
|
|
405
|
+
if (hasOwn(normalized, "toolbar")) {
|
|
406
|
+
const toolbar = resolveMarkdownToolbar([valueAt(normalized, "toolbar")]);
|
|
407
|
+
if (toolbar === null || toolbar === void 0) return null;
|
|
408
|
+
normalized.toolbar = toolbar;
|
|
409
|
+
}
|
|
410
|
+
normalizedLayers.push(normalized);
|
|
411
|
+
}
|
|
412
|
+
return mergeByPresence(normalizedLayers);
|
|
413
|
+
}
|
|
414
|
+
function resolveMarkdownToolbar(layers) {
|
|
415
|
+
const normalizedLayers = [];
|
|
416
|
+
for (const layer of layers) {
|
|
417
|
+
if (layer === void 0) continue;
|
|
418
|
+
const toolbar = normalizeToolbar(layer);
|
|
419
|
+
if (!toolbar) return null;
|
|
420
|
+
normalizedLayers.push(toolbar);
|
|
421
|
+
}
|
|
422
|
+
if (!normalizedLayers.length) return void 0;
|
|
423
|
+
return mergeByPresence(normalizedLayers);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const MERMAID_COMPONENT_NAME = "ContentMermaidTransport";
|
|
427
|
+
const PAGE_MERMAID_CONFIG_EXPRESSION = "config";
|
|
428
|
+
function serializeInlineAttributeRecord(value) {
|
|
429
|
+
return JSON.stringify(value).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/'/g, "'");
|
|
430
|
+
}
|
|
431
|
+
function isClosingFence(line, markerChar, markerLength) {
|
|
432
|
+
const trimmed = line.trim();
|
|
433
|
+
if (trimmed.length < markerLength) return false;
|
|
434
|
+
for (const char of trimmed) {
|
|
435
|
+
if (char !== markerChar) return false;
|
|
436
|
+
}
|
|
437
|
+
return true;
|
|
438
|
+
}
|
|
439
|
+
function transformMarkdownDiagrams(body) {
|
|
135
440
|
const newline = body.includes("\r\n") ? "\r\n" : "\n";
|
|
136
441
|
const lines = body.split(newline);
|
|
137
442
|
const output = [];
|
|
138
443
|
let inFence = false;
|
|
139
444
|
let fenceChar = null;
|
|
140
445
|
let fenceLength = 0;
|
|
141
|
-
const isClosingFence = (line) => {
|
|
142
|
-
if (!fenceChar) return false;
|
|
143
|
-
const trimmed = line.trim();
|
|
144
|
-
if (trimmed.length < fenceLength) return false;
|
|
145
|
-
for (const char of trimmed) {
|
|
146
|
-
if (char !== fenceChar) return false;
|
|
147
|
-
}
|
|
148
|
-
return true;
|
|
149
|
-
};
|
|
150
446
|
const isFenceMarkerChar = (char) => char === "`" || char === "~";
|
|
151
447
|
const parseFence = (line) => {
|
|
152
448
|
let index = 0;
|
|
@@ -178,19 +474,19 @@ function transformMermaidCodeBlocks(body, componentName, frontmatterConfigKey =
|
|
|
178
474
|
};
|
|
179
475
|
const buildComponentTag = (encoded, toolbar) => {
|
|
180
476
|
const attrs = [
|
|
181
|
-
`:config="${
|
|
477
|
+
`:page-config="${PAGE_MERMAID_CONFIG_EXPRESSION}"`
|
|
182
478
|
];
|
|
183
479
|
if (toolbar && isNonEmptyRecord(toolbar)) {
|
|
184
|
-
attrs.push(`:toolbar='${
|
|
480
|
+
attrs.push(`:toolbar='${serializeInlineAttributeRecord(toolbar)}'`);
|
|
185
481
|
}
|
|
186
482
|
attrs.push(`code="${encoded}"`);
|
|
187
|
-
return `<${
|
|
483
|
+
return `<${MERMAID_COMPONENT_NAME} ${attrs.join(" ")}></${MERMAID_COMPONENT_NAME}>`;
|
|
188
484
|
};
|
|
189
485
|
for (let index = 0; index < lines.length; index++) {
|
|
190
486
|
const line = lines[index];
|
|
191
487
|
if (inFence) {
|
|
192
488
|
output.push(line);
|
|
193
|
-
if (isClosingFence(line)) {
|
|
489
|
+
if (fenceChar && isClosingFence(line, fenceChar, fenceLength)) {
|
|
194
490
|
inFence = false;
|
|
195
491
|
fenceChar = null;
|
|
196
492
|
fenceLength = 0;
|
|
@@ -211,16 +507,7 @@ function transformMermaidCodeBlocks(body, componentName, frontmatterConfigKey =
|
|
|
211
507
|
}
|
|
212
508
|
let closingIndex = -1;
|
|
213
509
|
for (let j = index + 1; j < lines.length; j++) {
|
|
214
|
-
|
|
215
|
-
if (trimmed.length < fence.markerLength) continue;
|
|
216
|
-
let isFence = true;
|
|
217
|
-
for (const char of trimmed) {
|
|
218
|
-
if (char !== fence.markerChar) {
|
|
219
|
-
isFence = false;
|
|
220
|
-
break;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
if (isFence) {
|
|
510
|
+
if (isClosingFence(lines[j], fence.markerChar, fence.markerLength)) {
|
|
224
511
|
closingIndex = j;
|
|
225
512
|
break;
|
|
226
513
|
}
|
|
@@ -237,13 +524,39 @@ function transformMermaidCodeBlocks(body, componentName, frontmatterConfigKey =
|
|
|
237
524
|
continue;
|
|
238
525
|
}
|
|
239
526
|
const inlineAttrs = parseInlineAttrs(fence.info);
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
)
|
|
527
|
+
if (fence.info.includes("{") && !inlineAttrs) {
|
|
528
|
+
output.push(...lines.slice(index, closingIndex + 1));
|
|
529
|
+
index = closingIndex;
|
|
530
|
+
continue;
|
|
531
|
+
}
|
|
532
|
+
const frontmatterResult = inspectMermaidFrontmatter(rawCode, newline);
|
|
533
|
+
if (frontmatterResult.kind === "invalid") {
|
|
534
|
+
output.push(...lines.slice(index, closingIndex + 1));
|
|
535
|
+
index = closingIndex;
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
const frontmatterInfo = frontmatterResult.kind === "valid" ? frontmatterResult.info : null;
|
|
539
|
+
const inlineOverrides = resolveFenceInlineAttributes(inlineAttrs);
|
|
540
|
+
if (inlineAttrs && !inlineOverrides) {
|
|
541
|
+
output.push(...lines.slice(index, closingIndex + 1));
|
|
542
|
+
index = closingIndex;
|
|
543
|
+
continue;
|
|
544
|
+
}
|
|
545
|
+
const resolvedFrontmatter = resolveMarkdownFrontmatter([
|
|
546
|
+
frontmatterInfo?.data,
|
|
547
|
+
inlineOverrides ?? void 0
|
|
548
|
+
]);
|
|
549
|
+
const toolbarProps = resolveMarkdownToolbar([
|
|
550
|
+
frontmatterInfo?.data.toolbar,
|
|
551
|
+
inlineOverrides?.toolbar
|
|
552
|
+
]);
|
|
553
|
+
if (resolvedFrontmatter === null || toolbarProps === null) {
|
|
554
|
+
output.push(...lines.slice(index, closingIndex + 1));
|
|
555
|
+
index = closingIndex;
|
|
556
|
+
continue;
|
|
557
|
+
}
|
|
558
|
+
const hasInlineOverrides = inlineOverrides && Object.keys(inlineOverrides).length > 0;
|
|
559
|
+
const mergedCode = frontmatterInfo || hasInlineOverrides ? applyResolvedMermaidFrontmatter(rawCode, newline, frontmatterInfo, resolvedFrontmatter, fence.indent) : rawCode;
|
|
247
560
|
const encoded = encodeURIComponent(mergedCode.trim());
|
|
248
561
|
output.push(`${fence.indent}${buildComponentTag(encoded, toolbarProps)}`);
|
|
249
562
|
index = closingIndex;
|
|
@@ -251,4 +564,136 @@ function transformMermaidCodeBlocks(body, componentName, frontmatterConfigKey =
|
|
|
251
564
|
return output.join(newline);
|
|
252
565
|
}
|
|
253
566
|
|
|
254
|
-
|
|
567
|
+
const MODULE_NAME = "@barzhsieh/nuxt-content-mermaid";
|
|
568
|
+
const MERMAID_OPTIMIZE_DEPS = [
|
|
569
|
+
"mermaid",
|
|
570
|
+
"@braintree/sanitize-url",
|
|
571
|
+
"dayjs",
|
|
572
|
+
"dayjs/plugin/isoWeek.js",
|
|
573
|
+
"dayjs/plugin/customParseFormat.js",
|
|
574
|
+
"dayjs/plugin/advancedFormat.js",
|
|
575
|
+
"dayjs/plugin/duration.js"
|
|
576
|
+
];
|
|
577
|
+
const LEGACY_ALIAS_PHASE = {
|
|
578
|
+
name: "Nuxt Module Configuration",
|
|
579
|
+
root: "nuxt.options"
|
|
580
|
+
};
|
|
581
|
+
function throwMigrationError(path, expected, received) {
|
|
582
|
+
throw new ContentMermaidConfigurationError(LEGACY_ALIAS_PHASE, [{
|
|
583
|
+
path,
|
|
584
|
+
code: "UNEXPECTED_PROPERTY",
|
|
585
|
+
expected,
|
|
586
|
+
received
|
|
587
|
+
}], false);
|
|
588
|
+
}
|
|
589
|
+
function assertNoLegacyModuleAlias(nuxtOptions) {
|
|
590
|
+
if (Object.getOwnPropertyDescriptor(nuxtOptions, "mermaidContent")) {
|
|
591
|
+
throwMigrationError(["mermaidContent"], "the supported contentMermaid key", "removed legacy alias");
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
function readRuntimeOverrides(publicRuntimeConfig) {
|
|
595
|
+
const descriptor = Object.getOwnPropertyDescriptor(publicRuntimeConfig, "contentMermaid");
|
|
596
|
+
if (!descriptor) return void 0;
|
|
597
|
+
if (!("value" in descriptor)) {
|
|
598
|
+
throwMigrationError(
|
|
599
|
+
["runtimeConfig", "public", "contentMermaid"],
|
|
600
|
+
"an enumerable data property",
|
|
601
|
+
"accessor"
|
|
602
|
+
);
|
|
603
|
+
}
|
|
604
|
+
if (!descriptor.enumerable) {
|
|
605
|
+
throwMigrationError(
|
|
606
|
+
["runtimeConfig", "public", "contentMermaid"],
|
|
607
|
+
"an enumerable data property",
|
|
608
|
+
"non-enumerable-property"
|
|
609
|
+
);
|
|
610
|
+
}
|
|
611
|
+
return descriptor.value;
|
|
612
|
+
}
|
|
613
|
+
const module$1 = defineNuxtModule({
|
|
614
|
+
meta: {
|
|
615
|
+
name: MODULE_NAME,
|
|
616
|
+
configKey: "contentMermaid",
|
|
617
|
+
compatibility: {
|
|
618
|
+
nuxt: "^4.1.0"
|
|
619
|
+
}
|
|
620
|
+
},
|
|
621
|
+
moduleDependencies: {
|
|
622
|
+
"@nuxt/content": {
|
|
623
|
+
version: ">=3.5.0 <4.0.0"
|
|
624
|
+
}
|
|
625
|
+
},
|
|
626
|
+
setup(options, nuxt) {
|
|
627
|
+
assertNoLegacyModuleAlias(nuxt.options);
|
|
628
|
+
const publicRuntimeConfig = nuxt.options.runtimeConfig.public;
|
|
629
|
+
const resolved = resolveModuleConfiguration({
|
|
630
|
+
nuxtResolvedOptions: options,
|
|
631
|
+
runtimeOverrides: readRuntimeOverrides(publicRuntimeConfig)
|
|
632
|
+
});
|
|
633
|
+
if (!resolved.enabled) return;
|
|
634
|
+
publicRuntimeConfig.contentMermaid = resolved.runtimeOptions;
|
|
635
|
+
const resolver = createResolver(import.meta.url);
|
|
636
|
+
const runtimeDir = resolver.resolve("./runtime");
|
|
637
|
+
const baseMermaidComponentName = "Mermaid";
|
|
638
|
+
nuxt.options.css ||= [];
|
|
639
|
+
nuxt.options.css.push(resolver.resolve("./runtime/styles.css"));
|
|
640
|
+
addVitePlugin(() => ({
|
|
641
|
+
name: "nuxt-content-mermaid:optimize-deps",
|
|
642
|
+
configEnvironment(name, config) {
|
|
643
|
+
if (name === "client") {
|
|
644
|
+
config.optimizeDeps ||= {};
|
|
645
|
+
config.optimizeDeps.include ||= [];
|
|
646
|
+
config.optimizeDeps.include.push(
|
|
647
|
+
...MERMAID_OPTIMIZE_DEPS.map((dep) => `${MODULE_NAME} > ${dep}`)
|
|
648
|
+
);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}));
|
|
652
|
+
addPlugin({
|
|
653
|
+
src: resolver.resolve(runtimeDir, "plugins/mermaid.client"),
|
|
654
|
+
mode: "client"
|
|
655
|
+
});
|
|
656
|
+
addPlugin({
|
|
657
|
+
src: resolver.resolve(runtimeDir, "plugins/content-mermaid-transport")
|
|
658
|
+
});
|
|
659
|
+
addPlugin({
|
|
660
|
+
src: resolver.resolve(runtimeDir, "plugins/runtime-config")
|
|
661
|
+
});
|
|
662
|
+
addComponent({
|
|
663
|
+
name: baseMermaidComponentName,
|
|
664
|
+
filePath: resolver.resolve(runtimeDir, "components/Mermaid.vue")
|
|
665
|
+
});
|
|
666
|
+
addImports([
|
|
667
|
+
{
|
|
668
|
+
name: "useMermaidTheme",
|
|
669
|
+
as: "useMermaidTheme",
|
|
670
|
+
from: resolver.resolve(runtimeDir, "composables/useMermaidTheme")
|
|
671
|
+
}
|
|
672
|
+
]);
|
|
673
|
+
addTypeTemplate({
|
|
674
|
+
filename: "types/mermaid-content.d.ts",
|
|
675
|
+
getContents: () => `
|
|
676
|
+
import type { Mermaid } from 'mermaid'
|
|
677
|
+
|
|
678
|
+
declare module '#app' {
|
|
679
|
+
interface NuxtApp {
|
|
680
|
+
$mermaid: () => Promise<Mermaid>
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
declare module 'vue' {
|
|
684
|
+
interface ComponentCustomProperties {
|
|
685
|
+
$mermaid: () => Promise<Mermaid>
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
export {}
|
|
689
|
+
`
|
|
690
|
+
});
|
|
691
|
+
nuxt.hook("content:file:beforeParse", ((ctx) => {
|
|
692
|
+
const { file } = ctx;
|
|
693
|
+
if (!file.id?.endsWith(".md")) return;
|
|
694
|
+
file.body = transformMarkdownDiagrams(file.body);
|
|
695
|
+
}));
|
|
696
|
+
}
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
export { module$1 as default };
|