@abraca/nuxt 2.0.11 → 2.4.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/dist/module.d.mts +68 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +99 -4
- package/dist/runtime/components/ACodeEditor.d.vue.ts +26 -0
- package/dist/runtime/components/ACodeEditor.vue +268 -0
- package/dist/runtime/components/ACodeEditor.vue.d.ts +26 -0
- package/dist/runtime/components/ADocumentTree.vue +52 -20
- package/dist/runtime/components/AEditor.d.vue.ts +20 -13
- package/dist/runtime/components/AEditor.vue +55 -2
- package/dist/runtime/components/AEditor.vue.d.ts +20 -13
- package/dist/runtime/components/ANodePanel.vue +64 -60
- package/dist/runtime/components/ANotificationBell.d.vue.ts +1 -1
- package/dist/runtime/components/ANotificationBell.vue.d.ts +1 -1
- package/dist/runtime/components/ASpaceFormModal.d.vue.ts +2 -2
- package/dist/runtime/components/ASpaceFormModal.vue.d.ts +2 -2
- package/dist/runtime/components/aware/AMedia.d.vue.ts +1 -1
- package/dist/runtime/components/aware/AMedia.vue.d.ts +1 -1
- package/dist/runtime/components/aware/APresenceBlobs.d.vue.ts +29 -1
- package/dist/runtime/components/aware/APresenceBlobs.vue +54 -8
- package/dist/runtime/components/aware/APresenceBlobs.vue.d.ts +29 -1
- package/dist/runtime/components/aware/APresenceCursors.d.vue.ts +11 -0
- package/dist/runtime/components/aware/APresenceCursors.vue +74 -9
- package/dist/runtime/components/aware/APresenceCursors.vue.d.ts +11 -0
- package/dist/runtime/components/aware/AToggleGroup.d.vue.ts +28 -13
- package/dist/runtime/components/aware/AToggleGroup.vue +56 -20
- package/dist/runtime/components/aware/AToggleGroup.vue.d.ts +28 -13
- package/dist/runtime/components/docs/ADocsNavigation.d.vue.ts +1 -1
- package/dist/runtime/components/docs/ADocsNavigation.vue.d.ts +1 -1
- package/dist/runtime/components/docs/ADocsSearch.d.vue.ts +1 -1
- package/dist/runtime/components/docs/ADocsSearch.vue.d.ts +1 -1
- package/dist/runtime/components/docs/ADocsSearchButton.d.vue.ts +1 -1
- package/dist/runtime/components/docs/ADocsSearchButton.vue.d.ts +1 -1
- package/dist/runtime/components/docs/ADocsToc.d.vue.ts +2 -2
- package/dist/runtime/components/docs/ADocsToc.vue.d.ts +2 -2
- package/dist/runtime/components/editor/AEditorRedoButton.d.vue.ts +1 -1
- package/dist/runtime/components/editor/AEditorRedoButton.vue.d.ts +1 -1
- package/dist/runtime/components/editor/AEditorUndoButton.d.vue.ts +1 -1
- package/dist/runtime/components/editor/AEditorUndoButton.vue.d.ts +1 -1
- package/dist/runtime/components/editor/AFileGlbViewer.vue +27 -10
- package/dist/runtime/components/editor/ANodeInlineLabel.d.vue.ts +1 -1
- package/dist/runtime/components/editor/ANodeInlineLabel.vue.d.ts +1 -1
- package/dist/runtime/components/registry/APluginBrowser.d.vue.ts +23 -0
- package/dist/runtime/components/registry/APluginBrowser.vue +155 -0
- package/dist/runtime/components/registry/APluginBrowser.vue.d.ts +23 -0
- package/dist/runtime/components/registry/APluginCapabilityDialog.d.vue.ts +17 -0
- package/dist/runtime/components/registry/APluginCapabilityDialog.vue +159 -0
- package/dist/runtime/components/registry/APluginCapabilityDialog.vue.d.ts +17 -0
- package/dist/runtime/components/registry/APluginCard.d.vue.ts +20 -0
- package/dist/runtime/components/registry/APluginCard.vue +91 -0
- package/dist/runtime/components/registry/APluginCard.vue.d.ts +20 -0
- package/dist/runtime/components/registry/APluginDetail.d.vue.ts +18 -0
- package/dist/runtime/components/registry/APluginDetail.vue +252 -0
- package/dist/runtime/components/registry/APluginDetail.vue.d.ts +18 -0
- package/dist/runtime/components/renderers/ACodeRenderer.d.vue.ts +15 -0
- package/dist/runtime/components/renderers/ACodeRenderer.vue +68 -0
- package/dist/runtime/components/renderers/ACodeRenderer.vue.d.ts +15 -0
- package/dist/runtime/components/renderers/AGraphRenderer.vue +416 -120
- package/dist/runtime/components/renderers/AProseRenderer.d.vue.ts +2 -2
- package/dist/runtime/components/renderers/AProseRenderer.vue.d.ts +2 -2
- package/dist/runtime/components/renderers/sheets/ASheetsToolbar.d.vue.ts +4 -4
- package/dist/runtime/components/renderers/sheets/ASheetsToolbar.vue.d.ts +4 -4
- package/dist/runtime/components/shell/ABreadcrumbForDoc.d.vue.ts +11 -0
- package/dist/runtime/components/shell/ABreadcrumbForDoc.vue +16 -0
- package/dist/runtime/components/shell/ABreadcrumbForDoc.vue.d.ts +11 -0
- package/dist/runtime/components/shell/ASettingsSection.d.vue.ts +35 -0
- package/dist/runtime/components/shell/ASettingsSection.vue +26 -0
- package/dist/runtime/components/shell/ASettingsSection.vue.d.ts +35 -0
- package/dist/runtime/components/shell/ASidebar.d.vue.ts +1 -1
- package/dist/runtime/components/shell/ASidebar.vue.d.ts +1 -1
- package/dist/runtime/components/shell/AUserMenu.d.vue.ts +3 -0
- package/dist/runtime/components/shell/AUserMenu.vue +4 -0
- package/dist/runtime/components/shell/AUserMenu.vue.d.ts +3 -0
- package/dist/runtime/composables/useAbracadabraSchema.d.ts +83 -0
- package/dist/runtime/composables/useAbracadabraSchema.js +52 -0
- package/dist/runtime/composables/useAggregatedPresence.d.ts +1 -6
- package/dist/runtime/composables/useCalendarView.d.ts +1 -1
- package/dist/runtime/composables/useChat.js +1 -0
- package/dist/runtime/composables/useDocBreadcrumb.d.ts +21 -0
- package/dist/runtime/composables/useDocBreadcrumb.js +33 -0
- package/dist/runtime/composables/useDocEntryTyped.d.ts +60 -0
- package/dist/runtime/composables/useDocEntryTyped.js +70 -0
- package/dist/runtime/composables/useEditorDragHandle.js +18 -0
- package/dist/runtime/composables/useEditorSuggestions.js +2 -1
- package/dist/runtime/composables/useInstalledPlugins.d.ts +3 -21
- package/dist/runtime/composables/useInstalledPlugins.js +2 -12
- package/dist/runtime/composables/useMetaMenuItems.d.ts +21 -0
- package/dist/runtime/composables/useMetaMenuItems.js +115 -0
- package/dist/runtime/composables/useMetaValidator.d.ts +27 -0
- package/dist/runtime/composables/useMetaValidator.js +10 -0
- package/dist/runtime/composables/usePluginCatalog.d.ts +161 -0
- package/dist/runtime/composables/usePluginCatalog.js +234 -0
- package/dist/runtime/composables/useQuery.d.ts +79 -0
- package/dist/runtime/composables/useQuery.js +97 -0
- package/dist/runtime/composables/useSpaces.js +4 -5
- package/dist/runtime/composables/useTableView.d.ts +3 -3
- package/dist/runtime/composables/useTypedDoc.d.ts +97 -0
- package/dist/runtime/composables/useTypedDoc.js +114 -0
- package/dist/runtime/composables/useWebRTC.js +44 -5
- package/dist/runtime/extensions/document-meta.js +5 -0
- package/dist/runtime/extensions/timeline.d.ts +11 -0
- package/dist/runtime/extensions/timeline.js +52 -0
- package/dist/runtime/extensions/views/DocumentMetaView.d.vue.ts +4 -0
- package/dist/runtime/extensions/views/DocumentMetaView.vue +63 -0
- package/dist/runtime/extensions/views/DocumentMetaView.vue.d.ts +4 -0
- package/dist/runtime/extensions/views/TimelineItemView.d.vue.ts +4 -0
- package/dist/runtime/extensions/views/TimelineItemView.vue +131 -0
- package/dist/runtime/extensions/views/TimelineItemView.vue.d.ts +4 -0
- package/dist/runtime/extensions/views/TimelineView.d.vue.ts +9 -0
- package/dist/runtime/extensions/views/TimelineView.vue +29 -0
- package/dist/runtime/extensions/views/TimelineView.vue.d.ts +9 -0
- package/dist/runtime/locale.d.ts +2 -0
- package/dist/runtime/locale.js +2 -0
- package/dist/runtime/plugin-abracadabra.client.js +107 -6
- package/dist/runtime/plugin-registry.d.ts +11 -30
- package/dist/runtime/plugin-registry.js +2 -82
- package/dist/runtime/plugins/core.plugin.js +10 -4
- package/dist/runtime/server/api/_abracadabra/spaces.get.d.ts +1 -1
- package/dist/runtime/server/plugins/abracadabra-service.js +28 -0
- package/dist/runtime/server/utils/docCache.js +24 -3
- package/dist/runtime/server/utils/schemaServerSupport.d.ts +52 -0
- package/dist/runtime/server/utils/schemaServerSupport.js +51 -0
- package/dist/runtime/types.d.ts +63 -46
- package/dist/runtime/utils/docTypes.d.ts +15 -0
- package/dist/runtime/utils/docTypes.js +20 -0
- package/dist/runtime/utils/loadCodeMirror.d.ts +32 -0
- package/dist/runtime/utils/loadCodeMirror.js +65 -0
- package/dist/runtime/utils/loadThree.d.ts +18 -0
- package/dist/runtime/utils/loadThree.js +46 -0
- package/dist/runtime/utils/markdownToYjs.d.ts +1 -23
- package/dist/runtime/utils/markdownToYjs.js +5 -440
- package/dist/runtime/utils/schemaSupport.d.ts +60 -0
- package/dist/runtime/utils/schemaSupport.js +40 -0
- package/dist/runtime/utils/yjsConvert.d.ts +1 -14
- package/dist/runtime/utils/yjsConvert.js +5 -331
- package/package.json +86 -21
|
@@ -1,440 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
return clean.charAt(0).toUpperCase() + clean.slice(1);
|
|
7
|
-
}
|
|
8
|
-
function coerceScalar(raw) {
|
|
9
|
-
const trimmed = raw.trim();
|
|
10
|
-
if (trimmed === "true") return true;
|
|
11
|
-
if (trimmed === "false") return false;
|
|
12
|
-
const num = Number(trimmed);
|
|
13
|
-
if (!Number.isNaN(num) && trimmed !== "") return num;
|
|
14
|
-
if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
15
|
-
return trimmed.slice(1, -1);
|
|
16
|
-
}
|
|
17
|
-
return trimmed;
|
|
18
|
-
}
|
|
19
|
-
void coerceScalar;
|
|
20
|
-
function parseInlineArray(raw) {
|
|
21
|
-
return raw.slice(1, -1).split(",").map((s) => s.trim()).filter(Boolean);
|
|
22
|
-
}
|
|
23
|
-
export function parseFrontmatter(markdown) {
|
|
24
|
-
const noResult = { meta: {}, body: markdown };
|
|
25
|
-
const match = markdown.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
|
|
26
|
-
if (!match) return noResult;
|
|
27
|
-
const yamlBlock = match[1];
|
|
28
|
-
const body = markdown.slice(match[0].length);
|
|
29
|
-
const raw = {};
|
|
30
|
-
const lines = yamlBlock.split("\n");
|
|
31
|
-
let i = 0;
|
|
32
|
-
while (i < lines.length) {
|
|
33
|
-
const line = lines[i];
|
|
34
|
-
const blockSeqKey = line.match(/^(\w[\w-]*):\s*$/);
|
|
35
|
-
if (blockSeqKey && i + 1 < lines.length && /^\s+-\s/.test(lines[i + 1])) {
|
|
36
|
-
const key = blockSeqKey[1];
|
|
37
|
-
const items = [];
|
|
38
|
-
i++;
|
|
39
|
-
while (i < lines.length && /^\s+-\s/.test(lines[i])) {
|
|
40
|
-
items.push(lines[i].replace(/^\s+-\s/, "").trim());
|
|
41
|
-
i++;
|
|
42
|
-
}
|
|
43
|
-
raw[key] = items;
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
const kvMatch = line.match(/^(\w[\w-]*):\s*(.*)$/);
|
|
47
|
-
if (kvMatch) {
|
|
48
|
-
const key = kvMatch[1];
|
|
49
|
-
const val = kvMatch[2].trim();
|
|
50
|
-
if (val.startsWith("[") && val.endsWith("]")) {
|
|
51
|
-
raw[key] = parseInlineArray(val);
|
|
52
|
-
} else {
|
|
53
|
-
raw[key] = val;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
i++;
|
|
57
|
-
}
|
|
58
|
-
const meta = {};
|
|
59
|
-
const getStr = (keys) => {
|
|
60
|
-
for (const k of keys) {
|
|
61
|
-
const v = raw[k];
|
|
62
|
-
if (typeof v === "string" && v) return v;
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
const getArr = (keys) => {
|
|
66
|
-
for (const k of keys) {
|
|
67
|
-
const v = raw[k];
|
|
68
|
-
if (Array.isArray(v)) return v;
|
|
69
|
-
if (typeof v === "string" && v) return [v];
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
if (raw["tags"]) meta.tags = Array.isArray(raw["tags"]) ? raw["tags"] : [raw["tags"]];
|
|
73
|
-
const color = getStr(["color"]);
|
|
74
|
-
if (color) meta.color = color;
|
|
75
|
-
const icon = getStr(["icon"]);
|
|
76
|
-
if (icon) meta.icon = icon;
|
|
77
|
-
const status = getStr(["status"]);
|
|
78
|
-
if (status) meta.status = status;
|
|
79
|
-
const priorityRaw = getStr(["priority"]);
|
|
80
|
-
if (priorityRaw !== void 0) {
|
|
81
|
-
const map = { low: 1, medium: 2, high: 3, urgent: 4 };
|
|
82
|
-
meta.priority = map[priorityRaw.toLowerCase()] ?? (Number(priorityRaw) || 0);
|
|
83
|
-
}
|
|
84
|
-
const checkedRaw = raw["checked"] ?? raw["done"];
|
|
85
|
-
if (checkedRaw !== void 0) meta.checked = checkedRaw === "true" || checkedRaw === true;
|
|
86
|
-
const dateStart = getStr(["date", "created"]);
|
|
87
|
-
if (dateStart) meta.dateStart = dateStart;
|
|
88
|
-
const dateEnd = getStr(["due"]);
|
|
89
|
-
if (dateEnd) meta.dateEnd = dateEnd;
|
|
90
|
-
const subtitle = getStr(["description", "subtitle"]);
|
|
91
|
-
if (subtitle) meta.subtitle = subtitle;
|
|
92
|
-
const url = getStr(["url"]);
|
|
93
|
-
if (url) meta.url = url;
|
|
94
|
-
const ratingRaw = getStr(["rating"]);
|
|
95
|
-
if (ratingRaw !== void 0) {
|
|
96
|
-
const n = Number(ratingRaw);
|
|
97
|
-
if (!Number.isNaN(n)) meta.rating = Math.min(5, Math.max(0, n));
|
|
98
|
-
}
|
|
99
|
-
const tagsResult = getArr(["tags"]);
|
|
100
|
-
if (tagsResult) meta.tags = tagsResult;
|
|
101
|
-
const title = typeof raw["title"] === "string" ? raw["title"] : void 0;
|
|
102
|
-
const type = getStr(["type"]);
|
|
103
|
-
return { title, type, meta, body };
|
|
104
|
-
}
|
|
105
|
-
function parseMdcProps(propsStr) {
|
|
106
|
-
if (!propsStr) return {};
|
|
107
|
-
const result = {};
|
|
108
|
-
const re = /(\w[\w-]*)="([^"]*)"/g;
|
|
109
|
-
let m;
|
|
110
|
-
while ((m = re.exec(propsStr)) !== null) {
|
|
111
|
-
result[m[1]] = m[2];
|
|
112
|
-
}
|
|
113
|
-
return result;
|
|
114
|
-
}
|
|
115
|
-
function parseInline(text) {
|
|
116
|
-
const stripped = text.replace(/\{lang="[^"]*"\}/g, "").replace(/:(?!badge|icon|kbd)(\w[\w-]*)\[([^\]]*)\](\{[^}]*\})?/g, "$2").replace(/:(?!badge|icon|kbd)(\w[\w-]*)(\{[^}]*\})/g, "");
|
|
117
|
-
const tokens = [];
|
|
118
|
-
const re = /:badge\[([^\]]*)\](\{[^}]*\})?|:icon\{([^}]*)\}|:kbd\{([^}]*)\}|!?\[\[([^\]|]+)(?:\|([^\]]+))?\]\]|~~(.+?)~~|\*\*(.+?)\*\*|\*(.+?)\*|_(.+?)_|`(.+?)`|\[(.+?)\]\((.+?)\)/g;
|
|
119
|
-
let lastIndex = 0;
|
|
120
|
-
let match;
|
|
121
|
-
while ((match = re.exec(stripped)) !== null) {
|
|
122
|
-
if (match.index > lastIndex) {
|
|
123
|
-
tokens.push({ text: stripped.slice(lastIndex, match.index) });
|
|
124
|
-
}
|
|
125
|
-
if (match[1] !== void 0) {
|
|
126
|
-
const badgeProps = parseMdcProps(match[2]);
|
|
127
|
-
tokens.push({ text: match[1] || "Badge", attrs: { badge: { label: match[1] || "Badge", color: badgeProps["color"] || "neutral", variant: badgeProps["variant"] || "subtle" } } });
|
|
128
|
-
} else if (match[3] !== void 0) {
|
|
129
|
-
const iconProps = parseMdcProps(`{${match[3]}}`);
|
|
130
|
-
tokens.push({ text: "\u200B", attrs: { proseIcon: { name: iconProps["name"] || "i-lucide-star" } } });
|
|
131
|
-
} else if (match[4] !== void 0) {
|
|
132
|
-
const kbdProps = parseMdcProps(`{${match[4]}}`);
|
|
133
|
-
tokens.push({ text: kbdProps["value"] || "", attrs: { kbd: { value: kbdProps["value"] || "" } } });
|
|
134
|
-
} else if (match[5] !== void 0) {
|
|
135
|
-
const displayText = match[6] ?? match[5];
|
|
136
|
-
tokens.push({ text: displayText });
|
|
137
|
-
} else if (match[7] !== void 0) {
|
|
138
|
-
tokens.push({ text: match[7], attrs: { strike: true } });
|
|
139
|
-
} else if (match[8] !== void 0) {
|
|
140
|
-
tokens.push({ text: match[8], attrs: { bold: true } });
|
|
141
|
-
} else if (match[9] !== void 0) {
|
|
142
|
-
tokens.push({ text: match[9], attrs: { italic: true } });
|
|
143
|
-
} else if (match[10] !== void 0) {
|
|
144
|
-
tokens.push({ text: match[10], attrs: { italic: true } });
|
|
145
|
-
} else if (match[11] !== void 0) {
|
|
146
|
-
tokens.push({ text: match[11], attrs: { code: true } });
|
|
147
|
-
} else if (match[12] !== void 0 && match[13] !== void 0) {
|
|
148
|
-
tokens.push({ text: match[12], attrs: { link: { href: match[13] } } });
|
|
149
|
-
}
|
|
150
|
-
lastIndex = match.index + match[0].length;
|
|
151
|
-
}
|
|
152
|
-
if (lastIndex < stripped.length) {
|
|
153
|
-
tokens.push({ text: stripped.slice(lastIndex) });
|
|
154
|
-
}
|
|
155
|
-
return tokens.filter((t) => t.text.length > 0);
|
|
156
|
-
}
|
|
157
|
-
function parseTableRow(line) {
|
|
158
|
-
const parts = line.split("|");
|
|
159
|
-
return parts.slice(1, parts.length - 1).map((c) => c.trim());
|
|
160
|
-
}
|
|
161
|
-
function isTableSeparator(line) {
|
|
162
|
-
return /^\|[\s|:-]+\|$/.test(line.trim());
|
|
163
|
-
}
|
|
164
|
-
const TASK_RE = /^[-*+]\s+\[([ x])\]\s+(.*)/i;
|
|
165
|
-
function parseBlocks(markdown) {
|
|
166
|
-
const rawLines = markdown.split("\n");
|
|
167
|
-
let firstContentLine = 0;
|
|
168
|
-
while (firstContentLine < rawLines.length) {
|
|
169
|
-
const l = rawLines[firstContentLine];
|
|
170
|
-
if (l.trim() === "" || /^import\s/.test(l) || /^export\s/.test(l)) {
|
|
171
|
-
firstContentLine++;
|
|
172
|
-
} else {
|
|
173
|
-
break;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
const stripped = rawLines.slice(firstContentLine).join("\n");
|
|
177
|
-
const blocks = [];
|
|
178
|
-
const lines = stripped.split("\n");
|
|
179
|
-
let i = 0;
|
|
180
|
-
while (i < lines.length) {
|
|
181
|
-
const line = lines[i];
|
|
182
|
-
const fenceBlockMatch = line.match(/^(`{3,})([^`]*)$/);
|
|
183
|
-
if (fenceBlockMatch) {
|
|
184
|
-
const fence = fenceBlockMatch[1];
|
|
185
|
-
const lang = fenceBlockMatch[2].trim().replace(/\{[^}]*\}$/, "").replace(/\s*\[.*\]$/, "").trim();
|
|
186
|
-
const codeLines = [];
|
|
187
|
-
i++;
|
|
188
|
-
while (i < lines.length && !lines[i].startsWith(fence)) {
|
|
189
|
-
codeLines.push(lines[i]);
|
|
190
|
-
i++;
|
|
191
|
-
}
|
|
192
|
-
i++;
|
|
193
|
-
blocks.push({ type: "codeBlock", lang, code: codeLines.join("\n") });
|
|
194
|
-
continue;
|
|
195
|
-
}
|
|
196
|
-
const headingMatch = line.match(/^(#{1,6})\s+(.*)/);
|
|
197
|
-
if (headingMatch) {
|
|
198
|
-
blocks.push({ type: "heading", level: headingMatch[1].length, text: headingMatch[2].trim() });
|
|
199
|
-
i++;
|
|
200
|
-
continue;
|
|
201
|
-
}
|
|
202
|
-
if (/^[-*_]{3,}\s*$/.test(line)) {
|
|
203
|
-
blocks.push({ type: "hr" });
|
|
204
|
-
i++;
|
|
205
|
-
continue;
|
|
206
|
-
}
|
|
207
|
-
const imgMatch = line.match(/^!\[([^\]]*)\]\(([^)]+)\)(\{[^}]*\})?\s*$/);
|
|
208
|
-
if (imgMatch) {
|
|
209
|
-
const alt = imgMatch[1] ?? "";
|
|
210
|
-
const src = imgMatch[2] ?? "";
|
|
211
|
-
const attrs = parseMdcProps(imgMatch[3]);
|
|
212
|
-
blocks.push({ type: "image", src, alt, width: attrs["width"], height: attrs["height"] });
|
|
213
|
-
i++;
|
|
214
|
-
continue;
|
|
215
|
-
}
|
|
216
|
-
if (line.startsWith("> ") || line === ">") {
|
|
217
|
-
const bqLines = [];
|
|
218
|
-
while (i < lines.length && (lines[i].startsWith("> ") || lines[i] === ">")) {
|
|
219
|
-
bqLines.push(lines[i].replace(/^>\s?/, ""));
|
|
220
|
-
i++;
|
|
221
|
-
}
|
|
222
|
-
blocks.push({ type: "blockquote", lines: bqLines });
|
|
223
|
-
continue;
|
|
224
|
-
}
|
|
225
|
-
if (/^\s*\|/.test(line)) {
|
|
226
|
-
const tableLines = [];
|
|
227
|
-
while (i < lines.length && /^\s*\|/.test(lines[i])) {
|
|
228
|
-
tableLines.push(lines[i]);
|
|
229
|
-
i++;
|
|
230
|
-
}
|
|
231
|
-
if (tableLines.length >= 2 && isTableSeparator(tableLines[1])) {
|
|
232
|
-
const headerRow = parseTableRow(tableLines[0]);
|
|
233
|
-
const dataRows = tableLines.slice(2).filter((l) => !isTableSeparator(l)).map(parseTableRow);
|
|
234
|
-
blocks.push({ type: "table", headerRow, dataRows });
|
|
235
|
-
} else {
|
|
236
|
-
for (const l of tableLines) blocks.push({ type: "paragraph", text: l });
|
|
237
|
-
}
|
|
238
|
-
continue;
|
|
239
|
-
}
|
|
240
|
-
const MDC_OPEN = /^\s*:{2,}\w[\w-]*(?:\{[^}]*\})?\s*$/;
|
|
241
|
-
if (MDC_OPEN.test(line)) {
|
|
242
|
-
const colons = line.match(/^\s*(:+)/)?.[1]?.length ?? 2;
|
|
243
|
-
i++;
|
|
244
|
-
while (i < lines.length) {
|
|
245
|
-
const l = lines[i];
|
|
246
|
-
if (new RegExp(`^\\s*:{${colons}}\\s*$`).test(l)) {
|
|
247
|
-
i++;
|
|
248
|
-
break;
|
|
249
|
-
}
|
|
250
|
-
i++;
|
|
251
|
-
}
|
|
252
|
-
continue;
|
|
253
|
-
}
|
|
254
|
-
if (TASK_RE.test(line)) {
|
|
255
|
-
const items = [];
|
|
256
|
-
while (i < lines.length && TASK_RE.test(lines[i])) {
|
|
257
|
-
const m = lines[i].match(TASK_RE);
|
|
258
|
-
items.push({ checked: m[1].toLowerCase() === "x", text: m[2] });
|
|
259
|
-
i++;
|
|
260
|
-
}
|
|
261
|
-
blocks.push({ type: "taskList", items });
|
|
262
|
-
continue;
|
|
263
|
-
}
|
|
264
|
-
if (/^[-*+]\s+/.test(line)) {
|
|
265
|
-
const items = [];
|
|
266
|
-
while (i < lines.length && /^[-*+]\s+/.test(lines[i]) && !TASK_RE.test(lines[i])) {
|
|
267
|
-
items.push(lines[i].replace(/^[-*+]\s+/, ""));
|
|
268
|
-
i++;
|
|
269
|
-
}
|
|
270
|
-
if (items.length) {
|
|
271
|
-
blocks.push({ type: "bulletList", items });
|
|
272
|
-
continue;
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
if (/^\d+\.\s+/.test(line)) {
|
|
276
|
-
const items = [];
|
|
277
|
-
while (i < lines.length && /^\d+\.\s+/.test(lines[i])) {
|
|
278
|
-
items.push(lines[i].replace(/^\d+\.\s+/, ""));
|
|
279
|
-
i++;
|
|
280
|
-
}
|
|
281
|
-
blocks.push({ type: "orderedList", items });
|
|
282
|
-
continue;
|
|
283
|
-
}
|
|
284
|
-
if (line.trim() === "") {
|
|
285
|
-
i++;
|
|
286
|
-
continue;
|
|
287
|
-
}
|
|
288
|
-
const paraLines = [];
|
|
289
|
-
while (i < lines.length && lines[i].trim() !== "" && !/^(?:#{1,6}\s|[-*+]\s|\d+\.\s|>|`{3,}|\s*\||[-*_]{3,}\s*$|\s*:{2,}\w)/.test(lines[i])) {
|
|
290
|
-
paraLines.push(lines[i]);
|
|
291
|
-
i++;
|
|
292
|
-
}
|
|
293
|
-
if (paraLines.length) {
|
|
294
|
-
blocks.push({ type: "paragraph", text: paraLines.join(" ") });
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
return blocks;
|
|
298
|
-
}
|
|
299
|
-
function fillTextInto(el, tokens) {
|
|
300
|
-
const filtered = tokens.filter((t) => t.text.length > 0);
|
|
301
|
-
if (!filtered.length) return;
|
|
302
|
-
const xtNodes = filtered.map(() => new Y.XmlText());
|
|
303
|
-
el.insert(0, xtNodes);
|
|
304
|
-
filtered.forEach((tok, i) => {
|
|
305
|
-
if (tok.attrs) {
|
|
306
|
-
xtNodes[i].insert(0, tok.text, tok.attrs);
|
|
307
|
-
} else {
|
|
308
|
-
xtNodes[i].insert(0, tok.text);
|
|
309
|
-
}
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
function blockElName(b) {
|
|
313
|
-
switch (b.type) {
|
|
314
|
-
case "heading":
|
|
315
|
-
return "heading";
|
|
316
|
-
case "paragraph":
|
|
317
|
-
return "paragraph";
|
|
318
|
-
case "bulletList":
|
|
319
|
-
return "bulletList";
|
|
320
|
-
case "orderedList":
|
|
321
|
-
return "orderedList";
|
|
322
|
-
case "taskList":
|
|
323
|
-
return "taskList";
|
|
324
|
-
case "codeBlock":
|
|
325
|
-
return "codeBlock";
|
|
326
|
-
case "blockquote":
|
|
327
|
-
return "blockquote";
|
|
328
|
-
case "table":
|
|
329
|
-
return "table";
|
|
330
|
-
case "hr":
|
|
331
|
-
return "horizontalRule";
|
|
332
|
-
case "image":
|
|
333
|
-
return "image";
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
function fillBlock(el, block) {
|
|
337
|
-
switch (block.type) {
|
|
338
|
-
case "heading": {
|
|
339
|
-
el.setAttribute("level", block.level);
|
|
340
|
-
fillTextInto(el, parseInline(block.text));
|
|
341
|
-
break;
|
|
342
|
-
}
|
|
343
|
-
case "paragraph": {
|
|
344
|
-
fillTextInto(el, parseInline(block.text));
|
|
345
|
-
break;
|
|
346
|
-
}
|
|
347
|
-
case "bulletList":
|
|
348
|
-
case "orderedList": {
|
|
349
|
-
const listItemEls = block.items.map(() => new Y.XmlElement("listItem"));
|
|
350
|
-
el.insert(0, listItemEls);
|
|
351
|
-
block.items.forEach((text, i) => {
|
|
352
|
-
const paraEl = new Y.XmlElement("paragraph");
|
|
353
|
-
listItemEls[i].insert(0, [paraEl]);
|
|
354
|
-
fillTextInto(paraEl, parseInline(text));
|
|
355
|
-
});
|
|
356
|
-
break;
|
|
357
|
-
}
|
|
358
|
-
case "taskList": {
|
|
359
|
-
const taskItemEls = block.items.map(() => new Y.XmlElement("taskItem"));
|
|
360
|
-
el.insert(0, taskItemEls);
|
|
361
|
-
block.items.forEach((item, i) => {
|
|
362
|
-
taskItemEls[i].setAttribute("checked", item.checked);
|
|
363
|
-
const paraEl = new Y.XmlElement("paragraph");
|
|
364
|
-
taskItemEls[i].insert(0, [paraEl]);
|
|
365
|
-
fillTextInto(paraEl, parseInline(item.text));
|
|
366
|
-
});
|
|
367
|
-
break;
|
|
368
|
-
}
|
|
369
|
-
case "codeBlock": {
|
|
370
|
-
if (block.lang) el.setAttribute("language", block.lang);
|
|
371
|
-
const xt = new Y.XmlText();
|
|
372
|
-
el.insert(0, [xt]);
|
|
373
|
-
xt.insert(0, block.code);
|
|
374
|
-
break;
|
|
375
|
-
}
|
|
376
|
-
case "blockquote": {
|
|
377
|
-
const paraEls = block.lines.map(() => new Y.XmlElement("paragraph"));
|
|
378
|
-
el.insert(0, paraEls);
|
|
379
|
-
block.lines.forEach((line, i) => fillTextInto(paraEls[i], parseInline(line)));
|
|
380
|
-
break;
|
|
381
|
-
}
|
|
382
|
-
case "table": {
|
|
383
|
-
const headerRowEl = new Y.XmlElement("tableRow");
|
|
384
|
-
const dataRowEls = block.dataRows.map(() => new Y.XmlElement("tableRow"));
|
|
385
|
-
el.insert(0, [headerRowEl, ...dataRowEls]);
|
|
386
|
-
const headerCellEls = block.headerRow.map(() => new Y.XmlElement("tableHeader"));
|
|
387
|
-
headerRowEl.insert(0, headerCellEls);
|
|
388
|
-
block.headerRow.forEach((cellText, i) => {
|
|
389
|
-
const paraEl = new Y.XmlElement("paragraph");
|
|
390
|
-
headerCellEls[i].insert(0, [paraEl]);
|
|
391
|
-
fillTextInto(paraEl, parseInline(cellText));
|
|
392
|
-
});
|
|
393
|
-
block.dataRows.forEach((row, ri) => {
|
|
394
|
-
const cellEls = row.map(() => new Y.XmlElement("tableCell"));
|
|
395
|
-
dataRowEls[ri].insert(0, cellEls);
|
|
396
|
-
row.forEach((cellText, ci) => {
|
|
397
|
-
const paraEl = new Y.XmlElement("paragraph");
|
|
398
|
-
cellEls[ci].insert(0, [paraEl]);
|
|
399
|
-
fillTextInto(paraEl, parseInline(cellText));
|
|
400
|
-
});
|
|
401
|
-
});
|
|
402
|
-
break;
|
|
403
|
-
}
|
|
404
|
-
case "hr":
|
|
405
|
-
break;
|
|
406
|
-
case "image": {
|
|
407
|
-
el.setAttribute("src", block.src);
|
|
408
|
-
if (block.alt) el.setAttribute("alt", block.alt);
|
|
409
|
-
if (block.width) el.setAttribute("width", block.width);
|
|
410
|
-
if (block.height) el.setAttribute("height", block.height);
|
|
411
|
-
break;
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
export function populateYDocFromMarkdown(fragment, markdown, fallbackTitle = "Untitled") {
|
|
416
|
-
const ydoc = fragment.doc;
|
|
417
|
-
if (!ydoc) {
|
|
418
|
-
console.warn("[markdownToYjs] fragment has no doc \u2014 skipping population");
|
|
419
|
-
return;
|
|
420
|
-
}
|
|
421
|
-
const blocks = parseBlocks(markdown);
|
|
422
|
-
let title = fallbackTitle;
|
|
423
|
-
let contentBlocks = blocks;
|
|
424
|
-
const h1 = blocks.findIndex((b) => b.type === "heading" && b.level === 1);
|
|
425
|
-
if (h1 !== -1) {
|
|
426
|
-
title = blocks[h1].text;
|
|
427
|
-
contentBlocks = blocks.filter((_, i) => i !== h1);
|
|
428
|
-
}
|
|
429
|
-
if (!contentBlocks.length) contentBlocks = [{ type: "paragraph", text: "" }];
|
|
430
|
-
ydoc.transact(() => {
|
|
431
|
-
const headerEl = new Y.XmlElement("documentHeader");
|
|
432
|
-
const metaEl = new Y.XmlElement("documentMeta");
|
|
433
|
-
const bodyEls = contentBlocks.map((b) => new Y.XmlElement(blockElName(b)));
|
|
434
|
-
fragment.insert(0, [headerEl, metaEl, ...bodyEls]);
|
|
435
|
-
const headerXt = new Y.XmlText();
|
|
436
|
-
headerEl.insert(0, [headerXt]);
|
|
437
|
-
headerXt.insert(0, title);
|
|
438
|
-
contentBlocks.forEach((block, i) => fillBlock(bodyEls[i], block));
|
|
439
|
-
});
|
|
440
|
-
}
|
|
1
|
+
export {
|
|
2
|
+
filenameToLabel,
|
|
3
|
+
parseFrontmatter,
|
|
4
|
+
populateYDocFromMarkdown
|
|
5
|
+
} from "@abraca/convert";
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional `@abraca/schema` integration support.
|
|
3
|
+
*
|
|
4
|
+
* `@abraca/nuxt` works with or without the schema package installed. This
|
|
5
|
+
* helper performs a single dynamic import on first call, caches the
|
|
6
|
+
* resolved module (or the explicit absence sentinel), and returns the
|
|
7
|
+
* cached value on subsequent calls.
|
|
8
|
+
*
|
|
9
|
+
* No code path imports `@abraca/schema` statically — that is the Rule 1
|
|
10
|
+
* (core schema-free) requirement carried into the wrapper. Types here
|
|
11
|
+
* are intentionally structural so this file type-checks with or without
|
|
12
|
+
* the peer installed.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Structural shape of a `@abraca/schema` SchemaRegistry. Mirrors the
|
|
16
|
+
* runtime contract the package exposes, but avoids a static type import
|
|
17
|
+
* so the module compiles without the peer dep.
|
|
18
|
+
*/
|
|
19
|
+
export interface SchemaRegistryLike<TMap = Record<string, unknown>> {
|
|
20
|
+
readonly types: ReadonlyMap<string, unknown>;
|
|
21
|
+
get: (name: string) => unknown;
|
|
22
|
+
validateMeta: (name: string, value: unknown) => ValidationResultLike;
|
|
23
|
+
validateChildType: (parent: string | null, child: string) => ValidationResultLike;
|
|
24
|
+
readonly __metaMap?: TMap;
|
|
25
|
+
}
|
|
26
|
+
export type ValidationResultLike = {
|
|
27
|
+
ok: true;
|
|
28
|
+
value: unknown;
|
|
29
|
+
} | {
|
|
30
|
+
ok: false;
|
|
31
|
+
errors: ReadonlyArray<{
|
|
32
|
+
path: ReadonlyArray<PropertyKey>;
|
|
33
|
+
message: string;
|
|
34
|
+
code?: string;
|
|
35
|
+
}>;
|
|
36
|
+
};
|
|
37
|
+
/** Subset of the `@abraca/schema` public surface the module needs at runtime. */
|
|
38
|
+
export interface SchemaModule {
|
|
39
|
+
defineSchema: (spec: {
|
|
40
|
+
types: ReadonlyArray<unknown>;
|
|
41
|
+
}) => SchemaRegistryLike;
|
|
42
|
+
defineDocType: (spec: unknown) => unknown;
|
|
43
|
+
runMigrations: (registry: SchemaRegistryLike, typeName: string, meta: unknown) => unknown;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Resolve `@abraca/schema` if it is installed.
|
|
47
|
+
*
|
|
48
|
+
* Returns `null` (and warns once) when the package is missing or fails
|
|
49
|
+
* to import. Subsequent calls reuse the cached result; the dynamic
|
|
50
|
+
* `import()` only runs once per process.
|
|
51
|
+
*
|
|
52
|
+
* Safe to call in both browser and SSR contexts — the schema package
|
|
53
|
+
* has no platform-specific side effects.
|
|
54
|
+
*/
|
|
55
|
+
export declare function tryLoadSchemaModule(): Promise<SchemaModule | null>;
|
|
56
|
+
/**
|
|
57
|
+
* Test-only hook: reset the cached resolution so the next call performs
|
|
58
|
+
* a fresh dynamic import. Not exported from the module's public API.
|
|
59
|
+
*/
|
|
60
|
+
export declare function __resetSchemaSupportCacheForTests(): void;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
let cached;
|
|
2
|
+
let loading = null;
|
|
3
|
+
let warned = false;
|
|
4
|
+
export async function tryLoadSchemaModule() {
|
|
5
|
+
if (cached !== void 0) return cached;
|
|
6
|
+
if (loading) return loading;
|
|
7
|
+
loading = (async () => {
|
|
8
|
+
try {
|
|
9
|
+
const mod = await import("@abraca/schema");
|
|
10
|
+
const candidate = {
|
|
11
|
+
defineSchema: mod.defineSchema,
|
|
12
|
+
defineDocType: mod.defineDocType,
|
|
13
|
+
runMigrations: mod.runMigrations
|
|
14
|
+
};
|
|
15
|
+
if (typeof candidate.defineSchema !== "function" || typeof candidate.defineDocType !== "function" || typeof candidate.runMigrations !== "function") {
|
|
16
|
+
throw new TypeError("unexpected @abraca/schema shape \u2014 missing one of defineSchema / defineDocType / runMigrations");
|
|
17
|
+
}
|
|
18
|
+
cached = candidate;
|
|
19
|
+
return cached;
|
|
20
|
+
} catch (err) {
|
|
21
|
+
if (!warned) {
|
|
22
|
+
warned = true;
|
|
23
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
24
|
+
console.warn(
|
|
25
|
+
`[abracadabra] schema integration requested but @abraca/schema could not be loaded \u2014 install it as a peer dependency to enable typed reads / validated writes / migrations (${reason})`
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
cached = null;
|
|
29
|
+
return null;
|
|
30
|
+
} finally {
|
|
31
|
+
loading = null;
|
|
32
|
+
}
|
|
33
|
+
})();
|
|
34
|
+
return loading;
|
|
35
|
+
}
|
|
36
|
+
export function __resetSchemaSupportCacheForTests() {
|
|
37
|
+
cached = void 0;
|
|
38
|
+
loading = null;
|
|
39
|
+
warned = false;
|
|
40
|
+
}
|
|
@@ -1,14 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* yjsConvert.ts
|
|
3
|
-
*
|
|
4
|
-
* Converts Y.XmlFragment content to markdown or HTML text.
|
|
5
|
-
* Used by useDocExport to serialize collaborative documents.
|
|
6
|
-
*
|
|
7
|
-
* Ported from cou-sh/app/utils/yjsToMarkdown.ts
|
|
8
|
-
*/
|
|
9
|
-
import * as Y from 'yjs';
|
|
10
|
-
import type { DocPageMeta } from '../types.js';
|
|
11
|
-
export declare function yjsToMarkdown(fragment: Y.XmlFragment, label: string, meta?: DocPageMeta, type?: string): string;
|
|
12
|
-
export declare function yjsToHtml(fragment: Y.XmlFragment, label: string): string;
|
|
13
|
-
/** Extract plain text from a Y.XmlFragment (for search indexing) */
|
|
14
|
-
export declare function yjsToPlainText(fragment: Y.XmlFragment): string;
|
|
1
|
+
export { yjsToMarkdown, yjsToHtml, yjsToPlainText, } from '@abraca/convert';
|