@dooc-dev/dooc 0.0.0-stage → 0.0.1
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 +26 -2
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +244 -0
- package/dist/code.global.js +285 -0
- package/dist/compiler/bundle-urls.d.ts +3 -0
- package/dist/compiler/bundle-urls.js +294 -0
- package/dist/compiler/bundle.d.ts +2 -0
- package/dist/compiler/bundle.js +100 -0
- package/dist/compiler/check-prose.d.ts +11 -0
- package/dist/compiler/check-prose.js +138 -0
- package/dist/compiler/check-types.d.ts +44 -0
- package/dist/compiler/check-types.js +1 -0
- package/dist/compiler/check.d.ts +5 -0
- package/dist/compiler/check.js +450 -0
- package/dist/compiler/code-blocks.d.ts +17 -0
- package/dist/compiler/code-blocks.js +198 -0
- package/dist/compiler/code-languages.d.ts +10 -0
- package/dist/compiler/code-languages.js +109 -0
- package/dist/compiler/compile.d.ts +95 -0
- package/dist/compiler/compile.js +410 -0
- package/dist/compiler/config.d.ts +7 -0
- package/dist/compiler/config.js +52 -0
- package/dist/compiler/dialect.d.ts +24 -0
- package/dist/compiler/dialect.js +198 -0
- package/dist/compiler/drawio.d.ts +26 -0
- package/dist/compiler/drawio.js +176 -0
- package/dist/compiler/figures.d.ts +14 -0
- package/dist/compiler/figures.js +221 -0
- package/dist/compiler/file-cache.d.ts +14 -0
- package/dist/compiler/file-cache.js +61 -0
- package/dist/compiler/files.d.ts +29 -0
- package/dist/compiler/files.js +431 -0
- package/dist/compiler/fonts.d.ts +10 -0
- package/dist/compiler/fonts.js +54 -0
- package/dist/compiler/format.d.ts +1 -0
- package/dist/compiler/format.js +42 -0
- package/dist/compiler/from-mdast.d.ts +16 -0
- package/dist/compiler/from-mdast.js +142 -0
- package/dist/compiler/icons.d.ts +14 -0
- package/dist/compiler/icons.js +85 -0
- package/dist/compiler/language-codes.d.ts +7 -0
- package/dist/compiler/language-codes.js +17 -0
- package/dist/compiler/locales.d.ts +7 -0
- package/dist/compiler/locales.js +67 -0
- package/dist/compiler/manifest.d.ts +6 -0
- package/dist/compiler/manifest.js +30 -0
- package/dist/compiler/ops.d.ts +44 -0
- package/dist/compiler/ops.js +362 -0
- package/dist/compiler/public-file.d.ts +2 -0
- package/dist/compiler/public-file.js +93 -0
- package/dist/compiler/serialize.d.ts +3 -0
- package/dist/compiler/serialize.js +16 -0
- package/dist/compiler/terms.d.ts +9 -0
- package/dist/compiler/terms.js +44 -0
- package/dist/compiler/textfile-remote.d.ts +12 -0
- package/dist/compiler/textfile-remote.js +124 -0
- package/dist/compiler/textfile.d.ts +9 -0
- package/dist/compiler/textfile.js +113 -0
- package/dist/compiler/theme-variants.d.ts +4 -0
- package/dist/compiler/theme-variants.js +22 -0
- package/dist/compiler/zip.d.ts +6 -0
- package/dist/compiler/zip.js +48 -0
- package/dist/core/blocks.d.ts +99 -0
- package/dist/core/blocks.js +29 -0
- package/dist/core/code-file.d.ts +12 -0
- package/dist/core/code-file.js +68 -0
- package/dist/core/content-metadata.d.ts +48 -0
- package/dist/core/content-metadata.js +264 -0
- package/dist/core/content-types.d.ts +45 -0
- package/dist/core/content-types.js +1 -0
- package/dist/core/figure-frame.d.ts +12 -0
- package/dist/core/figure-frame.js +108 -0
- package/dist/core/file-embed.d.ts +13 -0
- package/dist/core/file-embed.js +43 -0
- package/dist/core/files.d.ts +15 -0
- package/dist/core/files.js +59 -0
- package/dist/core/flow-base-css.generated.d.ts +1 -0
- package/dist/core/flow-base-css.generated.js +4 -0
- package/dist/core/flow-css.d.ts +9 -0
- package/dist/core/flow-css.js +54 -0
- package/dist/core/graph-common.d.ts +32 -0
- package/dist/core/graph-common.js +113 -0
- package/dist/core/graph.d.ts +117 -0
- package/dist/core/graph.js +480 -0
- package/dist/core/html.d.ts +29 -0
- package/dist/core/html.js +444 -0
- package/dist/core/icons.d.ts +1 -0
- package/dist/core/icons.js +1 -0
- package/dist/core/inline.d.ts +27 -0
- package/dist/core/inline.js +42 -0
- package/dist/core/language.d.ts +41 -0
- package/dist/core/language.js +44 -0
- package/dist/core/languages/ja.d.ts +2 -0
- package/dist/core/languages/ja.js +5 -0
- package/dist/core/markdown.d.ts +27 -0
- package/dist/core/markdown.js +154 -0
- package/dist/core/previewers.d.ts +37 -0
- package/dist/core/previewers.js +103 -0
- package/dist/core/routing.d.ts +20 -0
- package/dist/core/routing.js +64 -0
- package/dist/core/schema-comments.d.ts +14 -0
- package/dist/core/schema-comments.js +52 -0
- package/dist/core/schema-graph-flow.d.ts +9 -0
- package/dist/core/schema-graph-flow.js +379 -0
- package/dist/core/schema-graph-mount.d.ts +9 -0
- package/dist/core/schema-graph-mount.js +105 -0
- package/dist/core/schema-graph.d.ts +254 -0
- package/dist/core/schema-graph.js +981 -0
- package/dist/core/table-ui.d.ts +2 -0
- package/dist/core/table-ui.js +180 -0
- package/dist/core/taxonomy.d.ts +12 -0
- package/dist/core/taxonomy.js +49 -0
- package/dist/core/term-reference.d.ts +5 -0
- package/dist/core/term-reference.js +19 -0
- package/dist/core/terms-ui.d.ts +6 -0
- package/dist/core/terms-ui.js +22 -0
- package/dist/core/textfile.d.ts +10 -0
- package/dist/core/textfile.js +39 -0
- package/dist/core/theme-variants.d.ts +3 -0
- package/dist/core/theme-variants.js +37 -0
- package/dist/core/toc-ui.d.ts +2 -0
- package/dist/core/toc-ui.js +161 -0
- package/dist/core/video-ui.d.ts +2 -0
- package/dist/core/video-ui.js +253 -0
- package/dist/core/workspace.d.ts +15 -0
- package/dist/core/workspace.js +28 -0
- package/dist/edit.global.js +305 -0
- package/dist/flow.global.js +4959 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +31 -0
- package/dist/mcp.d.ts +24 -0
- package/dist/mcp.js +467 -0
- package/dist/plugins/actions.d.ts +45 -0
- package/dist/plugins/actions.js +125 -0
- package/dist/plugins/blocks.d.ts +92 -0
- package/dist/plugins/blocks.js +99 -0
- package/dist/plugins/index.d.ts +4 -0
- package/dist/plugins/index.js +1 -0
- package/dist/plugins/oauth.d.ts +14 -0
- package/dist/plugins/oauth.js +164 -0
- package/dist/plugins/runtime.d.ts +24 -0
- package/dist/plugins/runtime.js +339 -0
- package/dist/plugins/types.d.ts +56 -0
- package/dist/plugins/types.js +1 -0
- package/dist/plugins/view.d.ts +29 -0
- package/dist/plugins/view.js +60 -0
- package/dist/ui.global.js +77 -0
- package/dist/viewer/assets.d.ts +2 -0
- package/dist/viewer/assets.js +3 -0
- package/dist/viewer/build.d.ts +12 -0
- package/dist/viewer/build.js +55 -0
- package/dist/viewer/bundle-network.d.ts +2 -0
- package/dist/viewer/bundle-network.js +88 -0
- package/dist/viewer/code-file.d.ts +20 -0
- package/dist/viewer/code-file.js +42 -0
- package/dist/viewer/editor-tools.d.ts +38 -0
- package/dist/viewer/editor-tools.js +211 -0
- package/dist/viewer/file-references.d.ts +14 -0
- package/dist/viewer/file-references.js +38 -0
- package/dist/viewer/font-picker.d.ts +4 -0
- package/dist/viewer/font-picker.js +145 -0
- package/dist/viewer/font-settings.d.ts +11 -0
- package/dist/viewer/font-settings.js +50 -0
- package/dist/viewer/fonts/LICENSE.txt +119 -0
- package/dist/viewer/fonts/udev-gothic-regular.woff2 +0 -0
- package/dist/viewer/fonts.d.ts +2 -0
- package/dist/viewer/fonts.js +13 -0
- package/dist/viewer/git-diff.d.ts +3 -0
- package/dist/viewer/git-diff.js +33 -0
- package/dist/viewer/git-types.d.ts +73 -0
- package/dist/viewer/git-types.js +1 -0
- package/dist/viewer/git.d.ts +5 -0
- package/dist/viewer/git.js +337 -0
- package/dist/viewer/hmr.d.ts +53 -0
- package/dist/viewer/hmr.js +335 -0
- package/dist/viewer/i18n.d.ts +6 -0
- package/dist/viewer/i18n.js +65 -0
- package/dist/viewer/ja-lint.d.ts +3 -0
- package/dist/viewer/ja-lint.js +44 -0
- package/dist/viewer/language-picker.d.ts +2 -0
- package/dist/viewer/language-picker.js +233 -0
- package/dist/viewer/languages.d.ts +11 -0
- package/dist/viewer/languages.js +20 -0
- package/dist/viewer/locales/eng.json +294 -0
- package/dist/viewer/locales/jpn.json +294 -0
- package/dist/viewer/locales/zho.json +294 -0
- package/dist/viewer/nav-focus.d.ts +2 -0
- package/dist/viewer/nav-focus.js +64 -0
- package/dist/viewer/plugin-blocks.d.ts +3 -0
- package/dist/viewer/plugin-blocks.js +115 -0
- package/dist/viewer/plugin-config.d.ts +35 -0
- package/dist/viewer/plugin-config.js +57 -0
- package/dist/viewer/plugin-view.d.ts +3 -0
- package/dist/viewer/plugin-view.js +28 -0
- package/dist/viewer/plugins.d.ts +8 -0
- package/dist/viewer/plugins.js +214 -0
- package/dist/viewer/resize.d.ts +4 -0
- package/dist/viewer/resize.js +238 -0
- package/dist/viewer/resource-library.d.ts +29 -0
- package/dist/viewer/resource-library.js +104 -0
- package/dist/viewer/search.d.ts +16 -0
- package/dist/viewer/search.js +358 -0
- package/dist/viewer/serve.d.ts +206 -0
- package/dist/viewer/serve.js +3233 -0
- package/dist/viewer/site-icon.d.ts +8 -0
- package/dist/viewer/site-icon.js +56 -0
- package/dist/viewer/textfile.d.ts +9 -0
- package/dist/viewer/textfile.js +50 -0
- package/dist/viewer/theme-picker.d.ts +2 -0
- package/dist/viewer/theme-picker.js +135 -0
- package/dist/viewer/workspace.d.ts +4 -0
- package/dist/viewer/workspace.js +47 -0
- package/package.json +127 -5
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { Document, isSeq, parseDocument } from "yaml";
|
|
3
|
+
import { ICONS_DIR, squareSvg } from "../compiler/icons.js";
|
|
4
|
+
import { parseManifestText } from "../compiler/manifest.js";
|
|
5
|
+
import { readTextfile, textfilePath, writeTextfile } from "../compiler/textfile.js";
|
|
6
|
+
import { MANIFEST_FILE } from "../core/content-metadata.js";
|
|
7
|
+
import { defaultFilePath } from "../core/files.js";
|
|
8
|
+
export const siteIconResponse = (root, input) => {
|
|
9
|
+
const svg = typeof input?.data === "string"
|
|
10
|
+
? squareSvg(Buffer.from(input.data, "base64").toString("utf8"))
|
|
11
|
+
: undefined;
|
|
12
|
+
if (!svg)
|
|
13
|
+
return {
|
|
14
|
+
status: 400,
|
|
15
|
+
body: { error: "specify an svg (viewBox or width / height required)" },
|
|
16
|
+
};
|
|
17
|
+
try {
|
|
18
|
+
const raw = existsSync(textfilePath(root, MANIFEST_FILE))
|
|
19
|
+
? readTextfile(root, MANIFEST_FILE)
|
|
20
|
+
: null;
|
|
21
|
+
const manifest = parseManifestText(raw ?? "[]");
|
|
22
|
+
if (manifest.errors.length)
|
|
23
|
+
return { status: 409, body: { error: manifest.errors.join("\n") } };
|
|
24
|
+
const file = manifest.icon ??
|
|
25
|
+
(manifest.files?.defaultLayout !== false
|
|
26
|
+
? defaultFilePath("_site.svg")
|
|
27
|
+
: `${ICONS_DIR}/_site.svg`);
|
|
28
|
+
if (!manifest.icon && existsSync(textfilePath(root, file)))
|
|
29
|
+
return {
|
|
30
|
+
status: 409,
|
|
31
|
+
body: { error: `${file} already exists; set dooc.yaml's icon to use it` },
|
|
32
|
+
};
|
|
33
|
+
const base = existsSync(textfilePath(root, file)) ? readTextfile(root, file) : null;
|
|
34
|
+
if (!writeTextfile(root, file, svg, base))
|
|
35
|
+
return { status: 409, body: { error: "Icon changed externally. Try again." } };
|
|
36
|
+
if (!manifest.icon) {
|
|
37
|
+
const parsed = parseDocument(raw ?? "docs: []\n");
|
|
38
|
+
const document = isSeq(parsed.contents) || parsed.contents == null
|
|
39
|
+
? new Document({ docs: parsed.toJS() ?? [] })
|
|
40
|
+
: parsed;
|
|
41
|
+
document.set("icon", file);
|
|
42
|
+
if (!writeTextfile(root, MANIFEST_FILE, document.toString(), raw))
|
|
43
|
+
return { status: 409, body: { error: "Manifest changed externally. Try again." } };
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
status: 200,
|
|
47
|
+
body: { icon: `data:image/svg+xml;base64,${Buffer.from(svg).toString("base64")}` },
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
return {
|
|
52
|
+
status: 400,
|
|
53
|
+
body: { error: error instanceof Error ? error.message : String(error) },
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const previewTextfiles: (root: string, input: unknown) => ReadonlyMap<string, string>;
|
|
2
|
+
export declare const textfileResponse: (root: string, input: Record<string, unknown> | undefined, domains?: readonly string[]) => Promise<{
|
|
3
|
+
status: number;
|
|
4
|
+
body: {
|
|
5
|
+
content?: string | null;
|
|
6
|
+
error?: string;
|
|
7
|
+
gitBase?: string | null;
|
|
8
|
+
};
|
|
9
|
+
}>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { readTextfileAsync, textfilePath, writeTextfile } from "../compiler/textfile.js";
|
|
2
|
+
import { TextfileUnavailable } from "../compiler/textfile-remote.js";
|
|
3
|
+
import { isRemoteTextfile } from "../core/textfile.js";
|
|
4
|
+
export const previewTextfiles = (root, input) => {
|
|
5
|
+
if (input === undefined)
|
|
6
|
+
return new Map();
|
|
7
|
+
if (!input || typeof input !== "object" || Array.isArray(input))
|
|
8
|
+
throw new Error("Expected text file drafts");
|
|
9
|
+
const files = new Map();
|
|
10
|
+
for (const [file, content] of Object.entries(input)) {
|
|
11
|
+
textfilePath(root, file);
|
|
12
|
+
if (typeof content !== "string" || /[\0\uD800-\uDFFF]/u.test(content))
|
|
13
|
+
throw new Error("Expected UTF-8 text file content");
|
|
14
|
+
files.set(file.replace(/^(\.\/)+/, ""), content);
|
|
15
|
+
}
|
|
16
|
+
return files;
|
|
17
|
+
};
|
|
18
|
+
export const textfileResponse = async (root, input, domains = []) => {
|
|
19
|
+
if (typeof input?.file !== "string" || !["read", "save"].includes(String(input.action)))
|
|
20
|
+
return { status: 400, body: { error: "Invalid text file request" } };
|
|
21
|
+
try {
|
|
22
|
+
if (input.action === "save") {
|
|
23
|
+
if (isRemoteTextfile(input.file))
|
|
24
|
+
return { status: 400, body: { error: "Remote files are read-only" } };
|
|
25
|
+
if (typeof input.content !== "string" ||
|
|
26
|
+
(input.base !== null && typeof input.base !== "string"))
|
|
27
|
+
return { status: 400, body: { error: "Content and original text are required" } };
|
|
28
|
+
if (!writeTextfile(root, input.file, input.content, input.base))
|
|
29
|
+
return {
|
|
30
|
+
status: 409,
|
|
31
|
+
body: { error: "File changed externally. Reload it before saving." },
|
|
32
|
+
};
|
|
33
|
+
return { status: 200, body: { content: input.content } };
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
status: 200,
|
|
37
|
+
body: { content: await readTextfileAsync(root, input.file, true, domains) },
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
if (input.action === "read" &&
|
|
42
|
+
(error.code === "ENOENT" ||
|
|
43
|
+
(error instanceof TextfileUnavailable && error.reason === "missing")))
|
|
44
|
+
return { status: 200, body: { content: null } };
|
|
45
|
+
return {
|
|
46
|
+
status: 400,
|
|
47
|
+
body: { error: error instanceof Error ? error.message : String(error) },
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
};
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/** Self-contained because published viewers embed this function directly. */
|
|
2
|
+
export const mountThemePickers = (icons, themes = ["light", "dark"]) => {
|
|
3
|
+
const root = document.documentElement;
|
|
4
|
+
const documentChoices = themes.length === 1 ? themes : ["auto", ...themes];
|
|
5
|
+
const read = (key) => {
|
|
6
|
+
try {
|
|
7
|
+
const value = localStorage.getItem(key);
|
|
8
|
+
return value === "light" || value === "dark" ? value : "auto";
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return "auto";
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
let documentDefault = read("docs-preview:theme");
|
|
15
|
+
if (!documentChoices.includes(documentDefault))
|
|
16
|
+
documentDefault = documentChoices[0] ?? "auto";
|
|
17
|
+
root.dataset.theme = documentDefault;
|
|
18
|
+
root.dataset.editorTheme = read("docs-editor:theme");
|
|
19
|
+
const t = (key) => window.__docsTranslate?.(key) ??
|
|
20
|
+
key;
|
|
21
|
+
const popup = document.createElement("div");
|
|
22
|
+
popup.className = "theme-picker";
|
|
23
|
+
popup.id = "theme-picker";
|
|
24
|
+
popup.popover = "auto";
|
|
25
|
+
popup.setAttribute("role", "menu");
|
|
26
|
+
document.body.append(popup);
|
|
27
|
+
let trigger;
|
|
28
|
+
const target = (button) => button.dataset.themePicker === "editor"
|
|
29
|
+
? root
|
|
30
|
+
: (button.closest(".preview-pane") ?? root);
|
|
31
|
+
const current = (button) => button.dataset.themePicker === "editor"
|
|
32
|
+
? (root.dataset.editorTheme ?? "auto")
|
|
33
|
+
: (target(button).dataset.theme ?? "auto");
|
|
34
|
+
const sync = () => {
|
|
35
|
+
for (const pane of document.querySelectorAll(".resources-pane"))
|
|
36
|
+
if (pane.dataset.theme !== root.dataset.editorTheme)
|
|
37
|
+
pane.dataset.theme = root.dataset.editorTheme;
|
|
38
|
+
for (const pane of document.querySelectorAll(".preview-pane:not(.resources-pane)"))
|
|
39
|
+
if (!documentChoices.includes(pane.dataset.theme ?? ""))
|
|
40
|
+
pane.dataset.theme = documentDefault;
|
|
41
|
+
for (const button of document.querySelectorAll("[data-theme-picker]")) {
|
|
42
|
+
const value = current(button);
|
|
43
|
+
const markup = icons[value === "auto" ? "" : value] ?? "";
|
|
44
|
+
if (button.dataset.themeIcon !== value) {
|
|
45
|
+
button.innerHTML = markup;
|
|
46
|
+
button.dataset.themeIcon = value;
|
|
47
|
+
}
|
|
48
|
+
const label = t(button.dataset.themePicker === "editor" ? "Editor theme" : "Preview theme");
|
|
49
|
+
button.title = `${label}: ${t(value === "auto" ? "Auto" : value === "light" ? "Light" : "Dark")}`;
|
|
50
|
+
button.setAttribute("aria-label", button.title);
|
|
51
|
+
button.setAttribute("aria-haspopup", "menu");
|
|
52
|
+
button.setAttribute("aria-controls", popup.id);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
document.addEventListener("click", (event) => {
|
|
56
|
+
const button = event.target instanceof Element
|
|
57
|
+
? event.target.closest("[data-theme-picker]")
|
|
58
|
+
: null;
|
|
59
|
+
if (!button)
|
|
60
|
+
return;
|
|
61
|
+
if (trigger === button && popup.matches(":popover-open")) {
|
|
62
|
+
popup.hidePopover();
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (popup.matches(":popover-open"))
|
|
66
|
+
popup.hidePopover();
|
|
67
|
+
trigger = button;
|
|
68
|
+
popup.dataset.theme = current(button);
|
|
69
|
+
popup.replaceChildren();
|
|
70
|
+
for (const value of button.dataset.themePicker === "editor"
|
|
71
|
+
? ["auto", "light", "dark"]
|
|
72
|
+
: documentChoices) {
|
|
73
|
+
const option = document.createElement("button");
|
|
74
|
+
option.type = "button";
|
|
75
|
+
option.dataset.value = value;
|
|
76
|
+
option.setAttribute("role", "menuitemradio");
|
|
77
|
+
option.setAttribute("aria-checked", String(value === current(button)));
|
|
78
|
+
option.innerHTML = icons[value === "auto" ? "" : value] ?? "";
|
|
79
|
+
option.append(document.createTextNode(t(value === "auto" ? "Auto" : value === "light" ? "Light" : "Dark")));
|
|
80
|
+
popup.append(option);
|
|
81
|
+
}
|
|
82
|
+
const rect = button.getBoundingClientRect();
|
|
83
|
+
popup.style.left = `${Math.max(8, Math.min(rect.left, innerWidth - 156))}px`;
|
|
84
|
+
popup.style.top = `${Math.min(rect.bottom + 6, innerHeight - 140)}px`;
|
|
85
|
+
popup.showPopover();
|
|
86
|
+
button.setAttribute("aria-expanded", "true");
|
|
87
|
+
popup.querySelector('[aria-checked="true"]')?.focus();
|
|
88
|
+
});
|
|
89
|
+
popup.addEventListener("click", (event) => {
|
|
90
|
+
const option = event.target instanceof Element
|
|
91
|
+
? event.target.closest("[data-value]")
|
|
92
|
+
: null;
|
|
93
|
+
if (!option || !trigger)
|
|
94
|
+
return;
|
|
95
|
+
const value = option.dataset.value ?? "auto";
|
|
96
|
+
const editor = trigger.dataset.themePicker === "editor";
|
|
97
|
+
if (editor)
|
|
98
|
+
root.dataset.editorTheme = value;
|
|
99
|
+
else {
|
|
100
|
+
target(trigger).dataset.theme = value;
|
|
101
|
+
documentDefault = value;
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
localStorage.setItem(editor ? "docs-editor:theme" : "docs-preview:theme", value);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
/* Theme selection still works without persistence. */
|
|
108
|
+
}
|
|
109
|
+
popup.hidePopover();
|
|
110
|
+
trigger.focus();
|
|
111
|
+
sync();
|
|
112
|
+
});
|
|
113
|
+
popup.addEventListener("keydown", (event) => {
|
|
114
|
+
const options = [...popup.querySelectorAll("button")];
|
|
115
|
+
const index = options.indexOf(document.activeElement);
|
|
116
|
+
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
117
|
+
event.preventDefault();
|
|
118
|
+
options[(index + (event.key === "ArrowDown" ? 1 : options.length - 1)) % options.length]?.focus();
|
|
119
|
+
}
|
|
120
|
+
if (event.key === "Escape")
|
|
121
|
+
trigger?.focus();
|
|
122
|
+
});
|
|
123
|
+
popup.addEventListener("toggle", () => {
|
|
124
|
+
if (!popup.matches(":popover-open"))
|
|
125
|
+
trigger?.setAttribute("aria-expanded", "false");
|
|
126
|
+
});
|
|
127
|
+
document.addEventListener("docs:ui-language", sync);
|
|
128
|
+
new MutationObserver(sync).observe(root, {
|
|
129
|
+
childList: true,
|
|
130
|
+
subtree: true,
|
|
131
|
+
attributes: true,
|
|
132
|
+
attributeFilter: ["data-theme", "data-editor-theme"],
|
|
133
|
+
});
|
|
134
|
+
sync();
|
|
135
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { WorkspaceSource } from "../core/workspace.js";
|
|
2
|
+
export declare const gitHeadFile: (root: string) => string | undefined;
|
|
3
|
+
/** Read only local metadata; no Git commands, credentials or network access are needed. */
|
|
4
|
+
export declare const readWorkspaceSource: (root: string) => WorkspaceSource;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { existsSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
2
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
3
|
+
/** Git worktrees use a .git file pointing at their own metadata directory. */
|
|
4
|
+
const gitMetadata = (root) => {
|
|
5
|
+
let directory = realpathSync(root);
|
|
6
|
+
for (;;) {
|
|
7
|
+
const git = join(directory, ".git");
|
|
8
|
+
try {
|
|
9
|
+
const target = statSync(git).isDirectory()
|
|
10
|
+
? git
|
|
11
|
+
: /^gitdir: (.+)\r?\n?$/.exec(readFileSync(git, "utf8"))?.[1];
|
|
12
|
+
const head = target ? join(resolve(directory, target.trim()), "HEAD") : undefined;
|
|
13
|
+
return head && existsSync(head) ? { head, directory } : undefined;
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
if (error.code !== "ENOENT")
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
const parent = dirname(directory);
|
|
20
|
+
if (parent === directory)
|
|
21
|
+
return undefined;
|
|
22
|
+
directory = parent;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
export const gitHeadFile = (root) => gitMetadata(root)?.head;
|
|
26
|
+
/** Read only local metadata; no Git commands, credentials or network access are needed. */
|
|
27
|
+
export const readWorkspaceSource = (root) => {
|
|
28
|
+
const git = gitMetadata(root);
|
|
29
|
+
if (git) {
|
|
30
|
+
try {
|
|
31
|
+
const common = join(dirname(git.head), "commondir");
|
|
32
|
+
const repo = basename(existsSync(common)
|
|
33
|
+
? dirname(resolve(dirname(git.head), readFileSync(common, "utf8").trim()))
|
|
34
|
+
: git.directory);
|
|
35
|
+
const head = readFileSync(git.head, "utf8").trim();
|
|
36
|
+
const branch = /^ref: refs\/heads\/(.+)$/.exec(head)?.[1];
|
|
37
|
+
if (branch)
|
|
38
|
+
return { protocol: "git", repo, branch };
|
|
39
|
+
if (/^(?:[a-f\d]{40}|[a-f\d]{64})$/i.test(head))
|
|
40
|
+
return { protocol: "git", repo, branch: `HEAD (${head.slice(0, 7)})` };
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// Unreadable Git metadata must not prevent access to the document files.
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return { protocol: "storage", folder: basename(resolve(root)) || root, service: "Local" };
|
|
47
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,128 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
"name": "@dooc-dev/dooc",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "View and edit source files with dooc.yaml configuration, and share them as source ZIPs or standalone HTML.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"bin": {
|
|
10
|
+
"dooc": "./dist/cli.js"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
"./check": {
|
|
14
|
+
"types": "./dist/compiler/check.d.ts",
|
|
15
|
+
"default": "./dist/compiler/check.js"
|
|
16
|
+
},
|
|
17
|
+
"./viewer-plugins": {
|
|
18
|
+
"types": "./dist/viewer/plugins.d.ts",
|
|
19
|
+
"default": "./dist/viewer/plugins.js"
|
|
20
|
+
},
|
|
21
|
+
"./plugins": {
|
|
22
|
+
"types": "./dist/plugins/index.d.ts",
|
|
23
|
+
"default": "./dist/plugins/index.js"
|
|
24
|
+
},
|
|
25
|
+
".": {
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"default": "./dist/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./flow": {
|
|
30
|
+
"types": "./dist/core/schema-graph-mount.d.ts",
|
|
31
|
+
"default": "./dist/core/schema-graph-mount.js"
|
|
32
|
+
},
|
|
33
|
+
"./flow.global.js": "./dist/flow.global.js"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"@xyflow/react": ">=12",
|
|
37
|
+
"react": ">=19",
|
|
38
|
+
"react-dom": ">=19"
|
|
39
|
+
},
|
|
40
|
+
"peerDependenciesMeta": {
|
|
41
|
+
"@xyflow/react": {
|
|
42
|
+
"optional": true
|
|
43
|
+
},
|
|
44
|
+
"react": {
|
|
45
|
+
"optional": true
|
|
46
|
+
},
|
|
47
|
+
"react-dom": {
|
|
48
|
+
"optional": true
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"packageManager": "pnpm@10.28.2",
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=22"
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"build:plugin": "node -e \"require('node:fs').rmSync('packages/dooc-plugin/dist', {recursive:true, force:true})\" && tsc -p tsconfig.plugin.json",
|
|
57
|
+
"test:plugin-package": "node --import tsx scripts/test-plugin-package.mjs",
|
|
58
|
+
"build": "node -e \"require('node:fs').rmSync('dist', {recursive:true, force:true})\" && pnpm run build:css && pnpm run build:fonts && tsc -p tsconfig.build.json && pnpm run build:flow && pnpm run build:edit",
|
|
59
|
+
"build:binary": "bun scripts/build-binary.mjs",
|
|
60
|
+
"build:css": "node --import tsx src/core/build-flow-css.ts",
|
|
61
|
+
"build:flow": "esbuild src/core/schema-graph-global.tsx --bundle --format=iife --target=es2022 --minify --outfile=dist/flow.global.js",
|
|
62
|
+
"build:edit": "esbuild src/viewer/edit-client.ts --bundle --format=iife --target=es2022 --minify --outfile=dist/edit.global.js && esbuild src/viewer/ui-client.ts --bundle --format=iife --target=es2022 --minify --outfile=dist/ui.global.js && esbuild src/viewer/code-highlight.ts --bundle --format=iife --target=es2022 --minify --outfile=dist/code.global.js",
|
|
63
|
+
"test": "vitest run",
|
|
64
|
+
"test:binary": "node scripts/test-binary.mjs",
|
|
65
|
+
"test:install": "node scripts/test-install.mjs",
|
|
66
|
+
"check": "biome check . && tsc --noEmit && pnpm run build && vitest run && pnpm run test:install && pnpm run test:plugin-package",
|
|
67
|
+
"fix": "biome check --write .",
|
|
68
|
+
"build:fonts": "node -e \"require('node:fs').cpSync('src/viewer/fonts', 'dist/viewer/fonts', {recursive:true})\""
|
|
69
|
+
},
|
|
70
|
+
"devDependencies": {
|
|
71
|
+
"@biomejs/biome": "2.4.15",
|
|
72
|
+
"@codemirror/autocomplete": "^6.20.4",
|
|
73
|
+
"@codemirror/commands": "^6.11.1",
|
|
74
|
+
"@codemirror/lang-markdown": "^6.5.2",
|
|
75
|
+
"@codemirror/language": "^6.13.1",
|
|
76
|
+
"@codemirror/lint": "6.9.7",
|
|
77
|
+
"@codemirror/search": "6.7.2",
|
|
78
|
+
"@codemirror/state": "^6.7.6",
|
|
79
|
+
"@codemirror/view": "^6.43.15",
|
|
80
|
+
"@lezer/common": "^1.5.4",
|
|
81
|
+
"@lezer/highlight": "^1.2.5",
|
|
82
|
+
"@shikijs/themes": "^4.5.0",
|
|
83
|
+
"@types/mdast": "^4.0.4",
|
|
84
|
+
"@types/node": "^22.10.0",
|
|
85
|
+
"@types/react": "^19.2.17",
|
|
86
|
+
"@types/react-dom": "^19.2.3",
|
|
87
|
+
"@xyflow/react": "^12.11.2",
|
|
88
|
+
"diff": "8.0.4",
|
|
89
|
+
"esbuild": "^0.28.1",
|
|
90
|
+
"react": "^19.2.8",
|
|
91
|
+
"react-dom": "^19.2.8",
|
|
92
|
+
"textlint": "^15.8.0",
|
|
93
|
+
"tsx": "^4.19.2",
|
|
94
|
+
"typescript": "^5.8.3",
|
|
95
|
+
"vitest": "^2.1.9"
|
|
96
|
+
},
|
|
97
|
+
"dependencies": {
|
|
98
|
+
"@dagrejs/dagre": "^3.0.0",
|
|
99
|
+
"@shikijs/langs": "4.5.0",
|
|
100
|
+
"@textlint/kernel": "^15.8.0",
|
|
101
|
+
"@textlint/module-interop": "^15.8.0",
|
|
102
|
+
"@textlint/textlint-plugin-markdown": "^15.8.0",
|
|
103
|
+
"franc": "^6.2.0",
|
|
104
|
+
"iso-639-3": "^3.0.1",
|
|
105
|
+
"mermaid": "^12.3.0",
|
|
106
|
+
"parse5": "8.0.0",
|
|
107
|
+
"postcss": "8.5.32",
|
|
108
|
+
"postcss-value-parser": "4.2.0",
|
|
109
|
+
"remark-frontmatter": "^5.0.0",
|
|
110
|
+
"remark-gfm": "^4.0.1",
|
|
111
|
+
"remark-parse": "^11.0.0",
|
|
112
|
+
"remark-stringify": "11.0.0",
|
|
113
|
+
"shiki": "^4.5.0",
|
|
114
|
+
"string-width": "4.2.3",
|
|
115
|
+
"textlint-rule-preset-ja-technical-writing": "^12.0.2",
|
|
116
|
+
"unified": "^11.0.5",
|
|
117
|
+
"unist-util-visit": "^5.0.0",
|
|
118
|
+
"yaml": "^2.7.0"
|
|
119
|
+
},
|
|
120
|
+
"repository": {
|
|
121
|
+
"type": "git",
|
|
122
|
+
"url": "git+https://github.com/dooc-dev/dooc.git"
|
|
123
|
+
},
|
|
124
|
+
"publishConfig": {
|
|
125
|
+
"registry": "https://registry.npmjs.org",
|
|
126
|
+
"access": "public"
|
|
127
|
+
}
|
|
128
|
+
}
|