@dooc-dev/dooc 0.0.0-stage → 0.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.
Files changed (221) hide show
  1. package/README.md +26 -2
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.js +311 -0
  4. package/dist/code.global.js +285 -0
  5. package/dist/compiler/bundle-urls.d.ts +3 -0
  6. package/dist/compiler/bundle-urls.js +294 -0
  7. package/dist/compiler/bundle.d.ts +2 -0
  8. package/dist/compiler/bundle.js +100 -0
  9. package/dist/compiler/check-prose.d.ts +11 -0
  10. package/dist/compiler/check-prose.js +138 -0
  11. package/dist/compiler/check-types.d.ts +44 -0
  12. package/dist/compiler/check-types.js +1 -0
  13. package/dist/compiler/check.d.ts +5 -0
  14. package/dist/compiler/check.js +450 -0
  15. package/dist/compiler/code-blocks.d.ts +17 -0
  16. package/dist/compiler/code-blocks.js +198 -0
  17. package/dist/compiler/code-languages.d.ts +10 -0
  18. package/dist/compiler/code-languages.js +109 -0
  19. package/dist/compiler/compile.d.ts +95 -0
  20. package/dist/compiler/compile.js +410 -0
  21. package/dist/compiler/config.d.ts +7 -0
  22. package/dist/compiler/config.js +52 -0
  23. package/dist/compiler/dialect.d.ts +24 -0
  24. package/dist/compiler/dialect.js +198 -0
  25. package/dist/compiler/drawio.d.ts +26 -0
  26. package/dist/compiler/drawio.js +176 -0
  27. package/dist/compiler/figures.d.ts +14 -0
  28. package/dist/compiler/figures.js +221 -0
  29. package/dist/compiler/file-cache.d.ts +14 -0
  30. package/dist/compiler/file-cache.js +61 -0
  31. package/dist/compiler/files.d.ts +29 -0
  32. package/dist/compiler/files.js +431 -0
  33. package/dist/compiler/fonts.d.ts +10 -0
  34. package/dist/compiler/fonts.js +54 -0
  35. package/dist/compiler/format.d.ts +1 -0
  36. package/dist/compiler/format.js +42 -0
  37. package/dist/compiler/from-mdast.d.ts +16 -0
  38. package/dist/compiler/from-mdast.js +142 -0
  39. package/dist/compiler/icons.d.ts +14 -0
  40. package/dist/compiler/icons.js +85 -0
  41. package/dist/compiler/language-codes.d.ts +7 -0
  42. package/dist/compiler/language-codes.js +17 -0
  43. package/dist/compiler/locales.d.ts +7 -0
  44. package/dist/compiler/locales.js +67 -0
  45. package/dist/compiler/manifest.d.ts +6 -0
  46. package/dist/compiler/manifest.js +30 -0
  47. package/dist/compiler/ops.d.ts +44 -0
  48. package/dist/compiler/ops.js +362 -0
  49. package/dist/compiler/public-file.d.ts +2 -0
  50. package/dist/compiler/public-file.js +93 -0
  51. package/dist/compiler/serialize.d.ts +3 -0
  52. package/dist/compiler/serialize.js +16 -0
  53. package/dist/compiler/terms.d.ts +9 -0
  54. package/dist/compiler/terms.js +44 -0
  55. package/dist/compiler/textfile-remote.d.ts +12 -0
  56. package/dist/compiler/textfile-remote.js +124 -0
  57. package/dist/compiler/textfile.d.ts +9 -0
  58. package/dist/compiler/textfile.js +113 -0
  59. package/dist/compiler/theme-variants.d.ts +4 -0
  60. package/dist/compiler/theme-variants.js +22 -0
  61. package/dist/compiler/zip.d.ts +6 -0
  62. package/dist/compiler/zip.js +48 -0
  63. package/dist/core/blocks.d.ts +99 -0
  64. package/dist/core/blocks.js +29 -0
  65. package/dist/core/code-file.d.ts +12 -0
  66. package/dist/core/code-file.js +68 -0
  67. package/dist/core/content-metadata.d.ts +48 -0
  68. package/dist/core/content-metadata.js +264 -0
  69. package/dist/core/content-types.d.ts +45 -0
  70. package/dist/core/content-types.js +1 -0
  71. package/dist/core/extension-package.d.ts +34 -0
  72. package/dist/core/extension-package.js +147 -0
  73. package/dist/core/figure-frame.d.ts +12 -0
  74. package/dist/core/figure-frame.js +108 -0
  75. package/dist/core/file-embed.d.ts +13 -0
  76. package/dist/core/file-embed.js +43 -0
  77. package/dist/core/files.d.ts +15 -0
  78. package/dist/core/files.js +59 -0
  79. package/dist/core/flow-base-css.generated.d.ts +1 -0
  80. package/dist/core/flow-base-css.generated.js +4 -0
  81. package/dist/core/flow-css.d.ts +9 -0
  82. package/dist/core/flow-css.js +54 -0
  83. package/dist/core/graph-common.d.ts +32 -0
  84. package/dist/core/graph-common.js +113 -0
  85. package/dist/core/graph.d.ts +117 -0
  86. package/dist/core/graph.js +480 -0
  87. package/dist/core/html.d.ts +29 -0
  88. package/dist/core/html.js +444 -0
  89. package/dist/core/icons.d.ts +2 -0
  90. package/dist/core/icons.js +2 -0
  91. package/dist/core/inline.d.ts +27 -0
  92. package/dist/core/inline.js +42 -0
  93. package/dist/core/language.d.ts +41 -0
  94. package/dist/core/language.js +44 -0
  95. package/dist/core/languages/ja.d.ts +2 -0
  96. package/dist/core/languages/ja.js +5 -0
  97. package/dist/core/markdown.d.ts +27 -0
  98. package/dist/core/markdown.js +154 -0
  99. package/dist/core/previewers.d.ts +37 -0
  100. package/dist/core/previewers.js +103 -0
  101. package/dist/core/routing.d.ts +20 -0
  102. package/dist/core/routing.js +64 -0
  103. package/dist/core/schema-comments.d.ts +14 -0
  104. package/dist/core/schema-comments.js +52 -0
  105. package/dist/core/schema-graph-flow.d.ts +9 -0
  106. package/dist/core/schema-graph-flow.js +379 -0
  107. package/dist/core/schema-graph-mount.d.ts +9 -0
  108. package/dist/core/schema-graph-mount.js +105 -0
  109. package/dist/core/schema-graph.d.ts +254 -0
  110. package/dist/core/schema-graph.js +981 -0
  111. package/dist/core/table-ui.d.ts +2 -0
  112. package/dist/core/table-ui.js +180 -0
  113. package/dist/core/taxonomy.d.ts +12 -0
  114. package/dist/core/taxonomy.js +49 -0
  115. package/dist/core/term-reference.d.ts +5 -0
  116. package/dist/core/term-reference.js +19 -0
  117. package/dist/core/terms-ui.d.ts +6 -0
  118. package/dist/core/terms-ui.js +22 -0
  119. package/dist/core/textfile.d.ts +10 -0
  120. package/dist/core/textfile.js +39 -0
  121. package/dist/core/theme-variants.d.ts +3 -0
  122. package/dist/core/theme-variants.js +37 -0
  123. package/dist/core/toc-ui.d.ts +2 -0
  124. package/dist/core/toc-ui.js +161 -0
  125. package/dist/core/video-ui.d.ts +2 -0
  126. package/dist/core/video-ui.js +253 -0
  127. package/dist/core/workspace.d.ts +15 -0
  128. package/dist/core/workspace.js +28 -0
  129. package/dist/edit.global.js +306 -0
  130. package/dist/flow.global.js +4959 -0
  131. package/dist/index.d.ts +17 -0
  132. package/dist/index.js +31 -0
  133. package/dist/mcp.d.ts +24 -0
  134. package/dist/mcp.js +467 -0
  135. package/dist/plugins/actions.d.ts +45 -0
  136. package/dist/plugins/actions.js +125 -0
  137. package/dist/plugins/blocks.d.ts +93 -0
  138. package/dist/plugins/blocks.js +100 -0
  139. package/dist/plugins/index.d.ts +4 -0
  140. package/dist/plugins/index.js +1 -0
  141. package/dist/plugins/local-storage.d.ts +18 -0
  142. package/dist/plugins/local-storage.js +115 -0
  143. package/dist/plugins/oauth.d.ts +14 -0
  144. package/dist/plugins/oauth.js +170 -0
  145. package/dist/plugins/runtime.d.ts +26 -0
  146. package/dist/plugins/runtime.js +395 -0
  147. package/dist/plugins/types.d.ts +59 -0
  148. package/dist/plugins/types.js +1 -0
  149. package/dist/plugins/view.d.ts +7 -0
  150. package/dist/plugins/view.js +21 -0
  151. package/dist/ui.global.js +78 -0
  152. package/dist/viewer/assets.d.ts +2 -0
  153. package/dist/viewer/assets.js +3 -0
  154. package/dist/viewer/build.d.ts +12 -0
  155. package/dist/viewer/build.js +55 -0
  156. package/dist/viewer/bundle-network.d.ts +2 -0
  157. package/dist/viewer/bundle-network.js +88 -0
  158. package/dist/viewer/code-file.d.ts +20 -0
  159. package/dist/viewer/code-file.js +42 -0
  160. package/dist/viewer/editor-tools.d.ts +38 -0
  161. package/dist/viewer/editor-tools.js +211 -0
  162. package/dist/viewer/extension-pack.d.ts +2 -0
  163. package/dist/viewer/extension-pack.js +36 -0
  164. package/dist/viewer/extensions.d.ts +10 -0
  165. package/dist/viewer/extensions.js +302 -0
  166. package/dist/viewer/file-references.d.ts +14 -0
  167. package/dist/viewer/file-references.js +38 -0
  168. package/dist/viewer/font-picker.d.ts +4 -0
  169. package/dist/viewer/font-picker.js +145 -0
  170. package/dist/viewer/font-settings.d.ts +11 -0
  171. package/dist/viewer/font-settings.js +50 -0
  172. package/dist/viewer/fonts/LICENSE.txt +119 -0
  173. package/dist/viewer/fonts/udev-gothic-regular.woff2 +0 -0
  174. package/dist/viewer/fonts.d.ts +2 -0
  175. package/dist/viewer/fonts.js +13 -0
  176. package/dist/viewer/git-diff.d.ts +3 -0
  177. package/dist/viewer/git-diff.js +33 -0
  178. package/dist/viewer/git-types.d.ts +73 -0
  179. package/dist/viewer/git-types.js +1 -0
  180. package/dist/viewer/git.d.ts +5 -0
  181. package/dist/viewer/git.js +337 -0
  182. package/dist/viewer/hmr.d.ts +53 -0
  183. package/dist/viewer/hmr.js +337 -0
  184. package/dist/viewer/i18n.d.ts +6 -0
  185. package/dist/viewer/i18n.js +65 -0
  186. package/dist/viewer/ja-lint.d.ts +3 -0
  187. package/dist/viewer/ja-lint.js +44 -0
  188. package/dist/viewer/language-picker.d.ts +2 -0
  189. package/dist/viewer/language-picker.js +233 -0
  190. package/dist/viewer/languages.d.ts +11 -0
  191. package/dist/viewer/languages.js +20 -0
  192. package/dist/viewer/locales/eng.json +317 -0
  193. package/dist/viewer/locales/jpn.json +317 -0
  194. package/dist/viewer/locales/zho.json +317 -0
  195. package/dist/viewer/nav-focus.d.ts +2 -0
  196. package/dist/viewer/nav-focus.js +64 -0
  197. package/dist/viewer/plugin-blocks.d.ts +3 -0
  198. package/dist/viewer/plugin-blocks.js +115 -0
  199. package/dist/viewer/plugin-config.d.ts +35 -0
  200. package/dist/viewer/plugin-config.js +57 -0
  201. package/dist/viewer/plugin-view.d.ts +2 -0
  202. package/dist/viewer/plugin-view.js +6 -0
  203. package/dist/viewer/plugins.d.ts +12 -0
  204. package/dist/viewer/plugins.js +267 -0
  205. package/dist/viewer/resize.d.ts +4 -0
  206. package/dist/viewer/resize.js +238 -0
  207. package/dist/viewer/resource-library.d.ts +29 -0
  208. package/dist/viewer/resource-library.js +104 -0
  209. package/dist/viewer/search.d.ts +16 -0
  210. package/dist/viewer/search.js +358 -0
  211. package/dist/viewer/serve.d.ts +210 -0
  212. package/dist/viewer/serve.js +3312 -0
  213. package/dist/viewer/site-icon.d.ts +8 -0
  214. package/dist/viewer/site-icon.js +56 -0
  215. package/dist/viewer/textfile.d.ts +9 -0
  216. package/dist/viewer/textfile.js +50 -0
  217. package/dist/viewer/theme-picker.d.ts +2 -0
  218. package/dist/viewer/theme-picker.js +135 -0
  219. package/dist/viewer/workspace.d.ts +4 -0
  220. package/dist/viewer/workspace.js +47 -0
  221. package/package.json +128 -5
@@ -0,0 +1,8 @@
1
+ export declare const siteIconResponse: (root: string, input: Record<string, unknown> | undefined) => {
2
+ status: number;
3
+ body: {
4
+ icon: string;
5
+ } | {
6
+ error: string;
7
+ };
8
+ };
@@ -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,2 @@
1
+ /** Self-contained because published viewers embed this function directly. */
2
+ export declare const mountThemePickers: (icons: Record<string, string>, themes?: string[]) => void;
@@ -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,129 @@
1
1
  {
2
- "name": "@dooc-dev/dooc",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
2
+ "name": "@dooc-dev/dooc",
3
+ "version": "0.0.2",
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
+ "build:sample-extension": "node --import tsx scripts/build-sample-extension.mjs"
70
+ },
71
+ "devDependencies": {
72
+ "@biomejs/biome": "2.4.15",
73
+ "@codemirror/autocomplete": "^6.20.4",
74
+ "@codemirror/commands": "^6.11.1",
75
+ "@codemirror/lang-markdown": "^6.5.2",
76
+ "@codemirror/language": "^6.13.1",
77
+ "@codemirror/lint": "6.9.7",
78
+ "@codemirror/search": "6.7.2",
79
+ "@codemirror/state": "^6.7.6",
80
+ "@codemirror/view": "^6.43.15",
81
+ "@lezer/common": "^1.5.4",
82
+ "@lezer/highlight": "^1.2.5",
83
+ "@shikijs/themes": "^4.5.0",
84
+ "@types/mdast": "^4.0.4",
85
+ "@types/node": "^22.10.0",
86
+ "@types/react": "^19.2.17",
87
+ "@types/react-dom": "^19.2.3",
88
+ "@xyflow/react": "^12.11.2",
89
+ "diff": "8.0.4",
90
+ "esbuild": "^0.28.1",
91
+ "react": "^19.2.8",
92
+ "react-dom": "^19.2.8",
93
+ "textlint": "^15.8.0",
94
+ "tsx": "^4.19.2",
95
+ "typescript": "^5.8.3",
96
+ "vitest": "^2.1.9"
97
+ },
98
+ "dependencies": {
99
+ "@dagrejs/dagre": "^3.0.0",
100
+ "@shikijs/langs": "4.5.0",
101
+ "@textlint/kernel": "^15.8.0",
102
+ "@textlint/module-interop": "^15.8.0",
103
+ "@textlint/textlint-plugin-markdown": "^15.8.0",
104
+ "franc": "^6.2.0",
105
+ "iso-639-3": "^3.0.1",
106
+ "mermaid": "^12.3.0",
107
+ "parse5": "8.0.0",
108
+ "postcss": "8.5.32",
109
+ "postcss-value-parser": "4.2.0",
110
+ "remark-frontmatter": "^5.0.0",
111
+ "remark-gfm": "^4.0.1",
112
+ "remark-parse": "^11.0.0",
113
+ "remark-stringify": "11.0.0",
114
+ "shiki": "^4.5.0",
115
+ "string-width": "4.2.3",
116
+ "textlint-rule-preset-ja-technical-writing": "^12.0.2",
117
+ "unified": "^11.0.5",
118
+ "unist-util-visit": "^5.0.0",
119
+ "yaml": "^2.7.0"
120
+ },
121
+ "repository": {
122
+ "type": "git",
123
+ "url": "git+https://github.com/dooc-dev/dooc.git"
124
+ },
125
+ "publishConfig": {
126
+ "registry": "https://registry.npmjs.org",
127
+ "access": "public"
128
+ }
129
+ }