docmedown 0.1.5 → 0.1.7
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/cli.js +103 -6
- package/dist/docmedown.cjs +58 -58
- package/dist/docmedown.iife.js +327 -327
- package/dist/docmedown.mjs +4916 -4603
- package/dist/types/runtime/components/OfflineNotice.d.ts +6 -0
- package/dist/types/runtime/config-schema.d.ts +11 -0
- package/dist/types/runtime/home.d.ts +47 -0
- package/dist/types/runtime/markdown/inline-text.d.ts +11 -0
- package/dist/types/runtime/offline-export.d.ts +25 -0
- package/dist/types/runtime/provider/DocProvider.d.ts +2 -0
- package/dist/types/runtime/types.d.ts +3 -0
- package/package.json +2 -2
- package/schemas/docs.schema.json +16 -0
- package/templates/docs.json +4 -0
package/dist/cli.js
CHANGED
|
@@ -31,7 +31,7 @@ var import_commander = require("commander");
|
|
|
31
31
|
// package.json
|
|
32
32
|
var package_default = {
|
|
33
33
|
name: "docmedown",
|
|
34
|
-
version: "0.1.
|
|
34
|
+
version: "0.1.7",
|
|
35
35
|
description: "The simplest MarkDown documenter yet. CLI & Web Script React SPA documentation engine.",
|
|
36
36
|
main: "./dist/docmedown.cjs",
|
|
37
37
|
module: "./dist/docmedown.mjs",
|
|
@@ -77,7 +77,7 @@ var package_default = {
|
|
|
77
77
|
"build:docs:watch": "node ./bin/docmedown.js build ./docs --watch",
|
|
78
78
|
"build:offline": "node ./bin/docmedown.js build ./docs",
|
|
79
79
|
"config:docs": "node ./bin/docmedown.js config ./docs/docs.json",
|
|
80
|
-
test: "npx tsx --test tests/parser.test.ts tests/scanner.test.ts tests/theme-schema.test.ts tests/runtime-integration.test.ts tests/package-smoke.test.ts tests/hosting.test.ts tests/deploy.test.ts",
|
|
80
|
+
test: "npx tsx --test tests/parser.test.ts tests/scanner.test.ts tests/theme-schema.test.ts tests/runtime-integration.test.ts tests/package-smoke.test.ts tests/hosting.test.ts tests/deploy.test.ts tests/home.test.ts",
|
|
81
81
|
"test:artifacts": "npx tsx --test tests/offline-artifact.test.ts",
|
|
82
82
|
"test:release": "npm run typecheck && npm run lint && npm run test && npm run build && npm run build:docs && npm run test:artifacts && npm pack --dry-run",
|
|
83
83
|
deploy: "node ./scripts/deploy.mjs",
|
|
@@ -240,6 +240,9 @@ var docSearchConfigSchema = import_zod.z.object({
|
|
|
240
240
|
placeholder: import_zod.z.string().optional(),
|
|
241
241
|
maxResults: import_zod.z.number().int().positive().max(100).optional()
|
|
242
242
|
}).strict();
|
|
243
|
+
var docOfflineConfigSchema = import_zod.z.object({
|
|
244
|
+
embedNestedDocs: import_zod.z.boolean().optional()
|
|
245
|
+
}).strict();
|
|
243
246
|
var docConfigSchema = import_zod.z.object({
|
|
244
247
|
$schema: import_zod.z.string().url("Must be an absolute URL.").optional(),
|
|
245
248
|
name: nonEmptyString.optional(),
|
|
@@ -247,6 +250,7 @@ var docConfigSchema = import_zod.z.object({
|
|
|
247
250
|
description: import_zod.z.string().optional(),
|
|
248
251
|
version: import_zod.z.string().optional(),
|
|
249
252
|
rootDoc: nonEmptyString.optional(),
|
|
253
|
+
home: nonEmptyString.optional(),
|
|
250
254
|
source: remoteSourceSchema.optional(),
|
|
251
255
|
theme: docThemeConfigSchema.optional(),
|
|
252
256
|
nav: import_zod.z.array(navLinkSchema).optional(),
|
|
@@ -259,6 +263,7 @@ var docConfigSchema = import_zod.z.object({
|
|
|
259
263
|
defaultCollapsed: import_zod.z.boolean().optional()
|
|
260
264
|
}).strict().optional(),
|
|
261
265
|
search: docSearchConfigSchema.optional(),
|
|
266
|
+
offline: docOfflineConfigSchema.optional(),
|
|
262
267
|
footer: import_zod.z.object({
|
|
263
268
|
copyright: import_zod.z.string().optional(),
|
|
264
269
|
links: import_zod.z.array(navLinkSchema).optional(),
|
|
@@ -313,6 +318,9 @@ var DEFAULT_CONFIG = {
|
|
|
313
318
|
placeholder: "Search documentation...",
|
|
314
319
|
maxResults: 10
|
|
315
320
|
},
|
|
321
|
+
offline: {
|
|
322
|
+
embedNestedDocs: true
|
|
323
|
+
},
|
|
316
324
|
footer: {
|
|
317
325
|
copyright: `\xA9 ${(/* @__PURE__ */ new Date()).getFullYear()} DocMeDown. All rights reserved.`,
|
|
318
326
|
showBuiltWith: true
|
|
@@ -344,6 +352,10 @@ function normalizeConfig(userConfig = {}) {
|
|
|
344
352
|
...DEFAULT_CONFIG.search,
|
|
345
353
|
...parsedConfig.search
|
|
346
354
|
},
|
|
355
|
+
offline: {
|
|
356
|
+
...DEFAULT_CONFIG.offline,
|
|
357
|
+
...parsedConfig.offline
|
|
358
|
+
},
|
|
347
359
|
footer: {
|
|
348
360
|
...DEFAULT_CONFIG.footer,
|
|
349
361
|
...parsedConfig.footer
|
|
@@ -365,7 +377,7 @@ function escapeHtml(value) {
|
|
|
365
377
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
366
378
|
}
|
|
367
379
|
function createCompressedOfflineHtml(encodedGzip, title) {
|
|
368
|
-
const bootstrap = `(async()=>{try{const b=Uint8Array.from(atob(document.getElementById("d").textContent.trim()),c=>c.charCodeAt(0)),s=await new Response(new Blob([b]).stream().pipeThrough(new DecompressionStream("gzip"))).text(),e=JSON.parse(s);if(e.version!==${OFFLINE_FORMAT_VERSION})throw new Error("Unsupported offline format");window.__DOCMEDOWN_OFFLINE__=true;window.__DOCMEDOWN_DATA__=e.data;window.__DOCMEDOWN_CONFIG__=e.data.manifest.config;const u=URL.createObjectURL(new Blob([e.runtime],{type:"text/javascript"}))
|
|
380
|
+
const bootstrap = `(async()=>{try{const b=Uint8Array.from(atob(document.getElementById("d").textContent.trim()),c=>c.charCodeAt(0)),s=await new Response(new Blob([b]).stream().pipeThrough(new DecompressionStream("gzip"))).text(),e=JSON.parse(s);if(e.version!==${OFFLINE_FORMAT_VERSION})throw new Error("Unsupported offline format");window.__DOCMEDOWN_OFFLINE__=true;window.__DOCMEDOWN_DATA__=e.data;window.__DOCMEDOWN_CONFIG__=e.data.manifest.config;const u=URL.createObjectURL(new Blob([e.runtime],{type:"text/javascript"}));window.__DOCMEDOWN_RUNTIME_URL__=u;const j=document.createElement("script");j.src=u;j.onerror=()=>{URL.revokeObjectURL(u);throw new Error("Runtime bootstrap failed")};document.head.appendChild(j)}catch(e){document.getElementById("dmd-app").textContent="Could not open this offline documentation copy: "+e.message}})();`;
|
|
369
381
|
return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="data:,"><title>${escapeHtml(title)}</title></head><body><div id="dmd-app">Opening offline documentation\u2026</div><script id="d" type="application/octet-stream">${encodedGzip}</script><script>${bootstrap}</script></body></html>`;
|
|
370
382
|
}
|
|
371
383
|
|
|
@@ -484,6 +496,49 @@ function mapManualSidebar(items) {
|
|
|
484
496
|
});
|
|
485
497
|
}
|
|
486
498
|
|
|
499
|
+
// src/runtime/markdown/inline-text.ts
|
|
500
|
+
var NAMED_HTML_ENTITIES = {
|
|
501
|
+
amp: "&",
|
|
502
|
+
lt: "<",
|
|
503
|
+
gt: ">",
|
|
504
|
+
quot: '"',
|
|
505
|
+
apos: "'",
|
|
506
|
+
nbsp: " ",
|
|
507
|
+
copy: "\xA9",
|
|
508
|
+
reg: "\xAE",
|
|
509
|
+
trade: "\u2122",
|
|
510
|
+
middot: "\xB7",
|
|
511
|
+
hellip: "\u2026",
|
|
512
|
+
mdash: "\u2014",
|
|
513
|
+
ndash: "\u2013",
|
|
514
|
+
bull: "\u2022",
|
|
515
|
+
deg: "\xB0",
|
|
516
|
+
times: "\xD7",
|
|
517
|
+
plusmn: "\xB1",
|
|
518
|
+
laquo: "\xAB",
|
|
519
|
+
raquo: "\xBB",
|
|
520
|
+
sect: "\xA7",
|
|
521
|
+
para: "\xB6"
|
|
522
|
+
};
|
|
523
|
+
function codePointToChar(code) {
|
|
524
|
+
return Number.isInteger(code) && code > 0 && code <= 1114111 ? String.fromCodePoint(code) : "";
|
|
525
|
+
}
|
|
526
|
+
function decodeHtmlEntities(value) {
|
|
527
|
+
return value.replace(/&#x([0-9a-f]+);/gi, (_match, hex) => codePointToChar(parseInt(hex, 16))).replace(/&#([0-9]+);/g, (_match, dec) => codePointToChar(Number(dec))).replace(/&([a-z][a-z0-9]*);/gi, (match, name) => NAMED_HTML_ENTITIES[name.toLowerCase()] ?? match);
|
|
528
|
+
}
|
|
529
|
+
var IMAGE_PATTERN = /!\[([^\]]*)\]\([^)]*\)/g;
|
|
530
|
+
var LINK_PATTERN = /\[([^\]]+)\]\([^)]*\)/g;
|
|
531
|
+
var CODE_PATTERN = /`([^`]+)`/g;
|
|
532
|
+
var BOLD_PATTERN = /\*\*([^*\n]+)\*\*/g;
|
|
533
|
+
var UNDERSCORE_BOLD_PATTERN = /__([^_\n]+)__/g;
|
|
534
|
+
var ITALIC_PATTERN = /\*([^*\n]+)\*/g;
|
|
535
|
+
var STRIKETHROUGH_PATTERN = /~~([^~\n]+)~~/g;
|
|
536
|
+
function inlineHeadingToPlainText(raw) {
|
|
537
|
+
return decodeHtmlEntities(
|
|
538
|
+
raw.replace(IMAGE_PATTERN, "$1").replace(LINK_PATTERN, "$1").replace(CODE_PATTERN, "$1").replace(BOLD_PATTERN, "$1").replace(UNDERSCORE_BOLD_PATTERN, "$1").replace(ITALIC_PATTERN, "$1").replace(STRIKETHROUGH_PATTERN, "$1")
|
|
539
|
+
).replace(/\s+/g, " ").trim();
|
|
540
|
+
}
|
|
541
|
+
|
|
487
542
|
// src/cli/utils/scanner.ts
|
|
488
543
|
function extractHeadings(content) {
|
|
489
544
|
const headings = [];
|
|
@@ -492,8 +547,9 @@ function extractHeadings(content) {
|
|
|
492
547
|
const match = line.match(/^(#{1,4})\s+(.+)$/);
|
|
493
548
|
if (match) {
|
|
494
549
|
const level = match[1].length;
|
|
495
|
-
const
|
|
496
|
-
const
|
|
550
|
+
const rawHeading = match[2].trim();
|
|
551
|
+
const text = inlineHeadingToPlainText(rawHeading);
|
|
552
|
+
const id = rawHeading.replace(/[#*`_]/g, "").toLowerCase().replace(/[^\w\s-]/g, "").trim().replace(/[\s_-]+/g, "-");
|
|
497
553
|
headings.push({ level, text, id });
|
|
498
554
|
}
|
|
499
555
|
}
|
|
@@ -614,6 +670,32 @@ function findNestedDocumentationRoots(targetDir) {
|
|
|
614
670
|
visit(targetDir);
|
|
615
671
|
return roots;
|
|
616
672
|
}
|
|
673
|
+
function collectNestedOfflineSites(targetDir) {
|
|
674
|
+
const sites = {};
|
|
675
|
+
for (const nestedRoot of findNestedDocumentationRoots(targetDir)) {
|
|
676
|
+
const key = import_node_path2.default.relative(targetDir, nestedRoot).replace(/\\/g, "/");
|
|
677
|
+
const nestedConfigPath = import_node_path2.default.join(nestedRoot, "docs.json");
|
|
678
|
+
let nestedConfig = normalizeConfig();
|
|
679
|
+
if (import_node_fs2.default.existsSync(nestedConfigPath)) {
|
|
680
|
+
nestedConfig = normalizeConfig(parseDocConfigJson(import_node_fs2.default.readFileSync(nestedConfigPath, "utf-8"), nestedConfigPath));
|
|
681
|
+
}
|
|
682
|
+
const nestedDocs = {};
|
|
683
|
+
for (const file of scanDirectory(nestedRoot)) {
|
|
684
|
+
const raw = import_node_fs2.default.readFileSync(import_node_path2.default.join(nestedRoot, file), "utf-8");
|
|
685
|
+
const slug = file.replace(/\.(md|mdx)$/i, "");
|
|
686
|
+
const cleanSlug = slug.toLowerCase() === "readme" || slug.toLowerCase() === "index" ? "README" : slug;
|
|
687
|
+
nestedDocs[cleanSlug] = raw;
|
|
688
|
+
nestedDocs[file] = raw;
|
|
689
|
+
}
|
|
690
|
+
sites[key] = {
|
|
691
|
+
name: nestedConfig.name || key,
|
|
692
|
+
manifest: generateManifest(nestedRoot, nestedConfig),
|
|
693
|
+
docs: nestedDocs,
|
|
694
|
+
componentsSource: bundleCustomComponents(import_node_path2.default.join(nestedRoot, ".dmd", "components.js"))
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
return sites;
|
|
698
|
+
}
|
|
617
699
|
function shouldWatchDocumentationSource(rootDir, changedPath) {
|
|
618
700
|
const relativePath = import_node_path2.default.relative(rootDir, changedPath).replace(/\\/g, "/");
|
|
619
701
|
const firstSegment = relativePath.split("/")[0];
|
|
@@ -681,9 +763,24 @@ async function buildCommand(targetDirArg = "./docs", options = {}) {
|
|
|
681
763
|
} else {
|
|
682
764
|
console.warn(import_chalk.default.yellow(" \u26A0 Local runtime bundle not found, linking CDN script."));
|
|
683
765
|
}
|
|
766
|
+
const embedNestedDocs = config.offline?.embedNestedDocs !== false;
|
|
767
|
+
const nestedSites = embedNestedDocs && options.buildNested !== false ? collectNestedOfflineSites(targetDir) : void 0;
|
|
768
|
+
const nestedCount = nestedSites ? Object.keys(nestedSites).length : 0;
|
|
769
|
+
if (nestedCount > 0) {
|
|
770
|
+
console.log(
|
|
771
|
+
import_chalk.default.green(
|
|
772
|
+
` \u2714 Embedded ${nestedCount} nested documentation site${nestedCount === 1 ? "" : "s"} into the offline bundle`
|
|
773
|
+
)
|
|
774
|
+
);
|
|
775
|
+
}
|
|
684
776
|
const envelope = {
|
|
685
777
|
version: OFFLINE_FORMAT_VERSION,
|
|
686
|
-
data: {
|
|
778
|
+
data: {
|
|
779
|
+
manifest,
|
|
780
|
+
docs: docsMap,
|
|
781
|
+
componentsSource,
|
|
782
|
+
...nestedSites && nestedCount > 0 ? { nestedSites } : {}
|
|
783
|
+
},
|
|
687
784
|
runtime: bundleJs
|
|
688
785
|
};
|
|
689
786
|
const encodedEnvelope = encodeCompressedOfflineEnvelope(envelope);
|