@developerportalsg/docportal-cli 0.0.0-stage → 0.1.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/README.md CHANGED
@@ -1,3 +1,109 @@
1
- # Temporary Holding Version
1
+ # @developerportalsg/docportal-cli
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ CLI tools for Documentation Portal publishers. Validates links against the platform's custom Docsify link resolution rules.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install -g @developerportalsg/docportal-cli
9
+ ```
10
+
11
+ Or run without installing:
12
+
13
+ ```bash
14
+ npx @developerportalsg/docportal-cli check-links .
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ### Local check (filesystem)
20
+
21
+ ```bash
22
+ docportal check-links .
23
+ docportal check-links . --base-path docs
24
+ docportal check-links . --verbose
25
+ docportal check-links . --json
26
+ ```
27
+
28
+ ### Remote check (HTTP)
29
+
30
+ ```bash
31
+ docportal check-links --url https://docs.developer.tech.gov.sg --slug my-doc
32
+ docportal check-links --url https://docs.developer.tech.gov.sg --slug my-doc --base-path docs
33
+ ```
34
+
35
+ ### Options
36
+
37
+ | Flag | Description |
38
+ |---|---|
39
+ | `--base-path <path>` | Subdirectory serving as docs root (matches docsify `basePath`) |
40
+ | `--url <url>` | Base URL for remote checking (requires `--slug`) |
41
+ | `--slug <slug>` | Document slug for remote checking |
42
+ | `--json` | Output results as JSONL (one JSON object per line) |
43
+ | `--verbose`, `-v` | Show OK links in addition to broken ones |
44
+
45
+ ### Exit codes
46
+
47
+ | Code | Meaning |
48
+ |---|---|
49
+ | 0 | All links OK (or all EXPECT annotations match) |
50
+ | 1 | Mismatches found between actual status and EXPECT annotations |
51
+
52
+ ## What it checks
53
+
54
+ The Documentation Portal uses a custom Docsify fork with non-standard link resolution. This tool encodes those rules:
55
+
56
+ | Link type | Resolution rule | `../` | `/path` |
57
+ |---|---|---|---|
58
+ | Document links | From doc root | **Broken** | Doc root |
59
+ | Sidebar links | From doc root | **Broken** | Doc root |
60
+ | Images | From current page directory | Works | Doc root |
61
+ | Embeds (`:include`) | From current file directory | Works | **Broken** |
62
+
63
+ ### Checks performed
64
+
65
+ - Document and sidebar links resolve from doc root (not current file)
66
+ - `../` in document/sidebar links flagged as broken
67
+ - `/path` in `:include` embeds flagged as broken
68
+ - All link targets verified to exist (filesystem or HTTP)
69
+ - Image paths resolve from current page directory
70
+ - Embed paths resolve from current file directory
71
+ - `:disabled` links skipped
72
+
73
+ ## EXPECT annotations
74
+
75
+ Test documents can annotate links with expected outcomes:
76
+
77
+ ```markdown
78
+ [Link](page-a) <!-- EXPECT:ok -->
79
+ [Link](../page) <!-- EXPECT:broken:dotdot-unsupported -->
80
+ ```
81
+
82
+ The tool reports **mismatches** when actual results differ from annotations — useful for verifying test cases.
83
+
84
+ ## Development
85
+
86
+ ```bash
87
+ cd tools/docportal-cli
88
+ npm install
89
+ npm run build
90
+ npm test
91
+ ```
92
+
93
+ ### Project structure
94
+
95
+ ```
96
+ src/
97
+ cli.ts # CLI entry point and subcommand dispatcher
98
+ commands/
99
+ check-links.ts # check-links command (local + remote modes)
100
+ lib/
101
+ resolve.ts # Docsify link resolution rules
102
+ parse.ts # Markdown and sidebar link extraction
103
+ check-local.ts # Filesystem-based link checking
104
+ check-remote.ts # HTTP-based link checking
105
+ tests/
106
+ resolve.test.ts # Unit tests for resolution rules
107
+ ```
108
+
109
+ Zero runtime dependencies — uses only Node.js built-ins and native `fetch`.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env node
2
+ import { runCheckLinks } from "./commands/check-links.js";
3
+ const VERSION = "0.1.0";
4
+ const HELP = `
5
+ docportal — CLI tools for Documentation Portal publishers
6
+
7
+ Usage:
8
+ docportal <command> [options]
9
+
10
+ Commands:
11
+ check-links <path> Check links against Doc Portal resolution rules
12
+ check-links --url Check links against a live published doc
13
+
14
+ Options:
15
+ --help, -h Show this help
16
+ --version Show version
17
+
18
+ Examples:
19
+ docportal check-links .
20
+ docportal check-links . --base-path docs
21
+ docportal check-links . --verbose --json
22
+ docportal check-links --url https://docs.developer.tech.gov.sg --slug my-doc
23
+ `.trim();
24
+ async function main() {
25
+ const args = process.argv.slice(2);
26
+ const command = args[0];
27
+ if (!command || command === "--help" || command === "-h") {
28
+ console.log(HELP);
29
+ process.exit(0);
30
+ }
31
+ if (command === "--version") {
32
+ console.log(VERSION);
33
+ process.exit(0);
34
+ }
35
+ if (command === "check-links") {
36
+ const exitCode = await runCheckLinks(args.slice(1));
37
+ process.exit(exitCode);
38
+ }
39
+ console.error(`Unknown command: ${command}`);
40
+ console.error(`Run 'docportal --help' for usage.`);
41
+ process.exit(1);
42
+ }
43
+ main().catch((err) => {
44
+ console.error(err);
45
+ process.exit(1);
46
+ });
47
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE1D,MAAM,OAAO,GAAG,OAAO,CAAC;AAExB,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;;;CAmBZ,CAAC,IAAI,EAAE,CAAC;AAET,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAExB,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;QAC5B,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,OAAO,KAAK,aAAa,EAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACpD,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACzB,CAAC;IAED,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAC;IAC7C,OAAO,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ interface CheckLinksOptions {
2
+ localPath?: string;
3
+ basePath: string;
4
+ url?: string;
5
+ slug?: string;
6
+ json: boolean;
7
+ verbose: boolean;
8
+ }
9
+ export declare function parseCheckLinksArgs(args: string[]): CheckLinksOptions;
10
+ export declare function runCheckLinks(args: string[]): Promise<number>;
11
+ export {};
12
+ //# sourceMappingURL=check-links.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-links.d.ts","sourceRoot":"","sources":["../../src/commands/check-links.ts"],"names":[],"mappings":"AAKA,UAAU,iBAAiB;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB;AA6DD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,iBAAiB,CAwBrE;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAmCnE"}
@@ -0,0 +1,121 @@
1
+ import * as path from "node:path";
2
+ import * as fs from "node:fs";
3
+ import { checkLocal } from "../lib/check-local.js";
4
+ import { checkRemote } from "../lib/check-remote.js";
5
+ function printResults(results, verbose, json) {
6
+ if (json) {
7
+ for (const r of results)
8
+ console.log(JSON.stringify(r));
9
+ return;
10
+ }
11
+ const broken = results.filter((r) => r.status === "broken");
12
+ const ok = results.filter((r) => r.status === "ok");
13
+ const mismatches = results.filter((r) => r.mismatch);
14
+ console.log(`\n${"=".repeat(70)}`);
15
+ console.log(`Link Check Results`);
16
+ console.log(`${"=".repeat(70)}\n`);
17
+ if (broken.length > 0) {
18
+ console.log(`BROKEN LINKS (${broken.length}):\n`);
19
+ for (const r of broken) {
20
+ const expectTag = r.expect ? ` [EXPECT:${r.expect}]` : "";
21
+ console.log(` BROKEN ${r.file}:${r.line} [${r.linkText}](${r.href})${expectTag}`);
22
+ console.log(` → resolves to: ${r.resolved}`);
23
+ if (r.reason)
24
+ console.log(` → reason: ${r.reason}`);
25
+ console.log();
26
+ }
27
+ }
28
+ if (verbose && ok.length > 0) {
29
+ console.log(`OK LINKS (${ok.length}):\n`);
30
+ for (const r of ok) {
31
+ const expectTag = r.expect ? ` [EXPECT:${r.expect}]` : "";
32
+ console.log(` OK ${r.file}:${r.line} [${r.linkText}](${r.href})${expectTag}`);
33
+ console.log(` → resolves to: ${r.resolved}`);
34
+ console.log();
35
+ }
36
+ }
37
+ if (mismatches.length > 0) {
38
+ console.log(`\nMISMATCHES (${mismatches.length}) — link status doesn't match EXPECT annotation:\n`);
39
+ for (const r of mismatches) {
40
+ console.log(` ${r.status.toUpperCase().padEnd(7)} ${r.file}:${r.line} [${r.linkText}](${r.href})`);
41
+ console.log(` → expected: ${r.expect}${r.expectReason ? ` (${r.expectReason})` : ""}`);
42
+ console.log(` → actual: ${r.status}${r.reason ? ` — ${r.reason}` : ""}`);
43
+ console.log();
44
+ }
45
+ }
46
+ console.log(`${"─".repeat(70)}`);
47
+ console.log(`Total: ${results.length} links checked`);
48
+ console.log(` OK: ${ok.length}`);
49
+ console.log(` Broken: ${broken.length}`);
50
+ if (mismatches.length > 0)
51
+ console.log(` Mismatches: ${mismatches.length}`);
52
+ const annotated = results.filter((r) => r.expect);
53
+ if (annotated.length > 0) {
54
+ const correct = annotated.filter((r) => !r.mismatch);
55
+ console.log(` Annotations: ${correct.length}/${annotated.length} correct`);
56
+ }
57
+ console.log();
58
+ }
59
+ export function parseCheckLinksArgs(args) {
60
+ let localPath;
61
+ let basePath = "";
62
+ let url;
63
+ let slug;
64
+ let json = false;
65
+ let verbose = false;
66
+ for (let i = 0; i < args.length; i++) {
67
+ if (args[i] === "--base-path" && args[i + 1]) {
68
+ basePath = args[++i];
69
+ }
70
+ else if (args[i] === "--url" && args[i + 1]) {
71
+ url = args[++i];
72
+ }
73
+ else if (args[i] === "--slug" && args[i + 1]) {
74
+ slug = args[++i];
75
+ }
76
+ else if (args[i] === "--json") {
77
+ json = true;
78
+ }
79
+ else if (args[i] === "--verbose" || args[i] === "-v") {
80
+ verbose = true;
81
+ }
82
+ else if (!args[i].startsWith("-")) {
83
+ localPath = args[i];
84
+ }
85
+ }
86
+ return { localPath, basePath, url, slug, json, verbose };
87
+ }
88
+ export async function runCheckLinks(args) {
89
+ const { localPath, basePath, url, slug, json, verbose } = parseCheckLinksArgs(args);
90
+ if (url) {
91
+ if (!slug) {
92
+ console.error("Error: --slug required with --url");
93
+ return 1;
94
+ }
95
+ console.log(`Checking remote: ${url}/docs/${slug}/ (basePath: "${basePath || "(none)"}")`);
96
+ const results = await checkRemote(url, slug, basePath);
97
+ printResults(results, verbose, json);
98
+ return results.some((r) => r.mismatch) ? 1 : 0;
99
+ }
100
+ if (!localPath) {
101
+ console.error("Usage:");
102
+ console.error(" docportal check-links <path> [--base-path <bp>] [--verbose] [--json]");
103
+ console.error(" docportal check-links --url <url> --slug <slug> [--base-path <bp>]");
104
+ return 1;
105
+ }
106
+ const absPath = path.resolve(localPath);
107
+ if (!fs.existsSync(absPath)) {
108
+ console.error(`Path not found: ${absPath}`);
109
+ return 1;
110
+ }
111
+ if (json) {
112
+ process.stderr.write(`Checking local: ${absPath} (basePath: "${basePath || "(none)"}")\n`);
113
+ }
114
+ else {
115
+ console.log(`Checking local: ${absPath} (basePath: "${basePath || "(none)"}")`);
116
+ }
117
+ const results = checkLocal(absPath, basePath);
118
+ printResults(results, verbose, json);
119
+ return results.some((r) => r.mismatch) ? 1 : 0;
120
+ }
121
+ //# sourceMappingURL=check-links.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-links.js","sourceRoot":"","sources":["../../src/commands/check-links.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export interface CheckResult {
2
+ file: string;
3
+ line: number;
4
+ href: string;
5
+ linkText: string;
6
+ kind: string;
7
+ resolved: string;
8
+ status: "ok" | "broken";
9
+ reason: string;
10
+ expect?: "ok" | "broken";
11
+ expectReason?: string;
12
+ mismatch?: boolean;
13
+ }
14
+ export declare function checkLocal(docRootDir: string, basePath: string): CheckResult[];
15
+ //# sourceMappingURL=check-local.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-local.d.ts","sourceRoot":"","sources":["../../src/lib/check-local.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,IAAI,GAAG,QAAQ,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,IAAI,GAAG,QAAQ,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAgDD,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,WAAW,EAAE,CAuF9E"}
@@ -0,0 +1,134 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { resolveDocLink, resolveImageLink, resolveEmbedLink, resolveSidebarLink } from "./resolve.js";
4
+ import { extractLinks, parseSidebar } from "./parse.js";
5
+ function walkMdFiles(dir) {
6
+ const results = [];
7
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
8
+ const full = path.join(dir, entry.name);
9
+ if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules" && entry.name !== "tools") {
10
+ results.push(...walkMdFiles(full));
11
+ }
12
+ else if (entry.isFile() && entry.name.endsWith(".md")) {
13
+ results.push(full);
14
+ }
15
+ }
16
+ return results;
17
+ }
18
+ function findSidebars(dir) {
19
+ const results = [];
20
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
21
+ const full = path.join(dir, entry.name);
22
+ if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules" && entry.name !== "tools" && entry.name !== "assets") {
23
+ results.push(...findSidebars(full));
24
+ }
25
+ else if (entry.isFile() && entry.name === "_sidebar.md") {
26
+ results.push(full);
27
+ }
28
+ }
29
+ return results;
30
+ }
31
+ function fileExists(docRootAbs, relativePath) {
32
+ const full = path.join(docRootAbs, relativePath);
33
+ if (fs.existsSync(full))
34
+ return true;
35
+ if (!relativePath.endsWith(".md")) {
36
+ return fs.existsSync(full + ".md");
37
+ }
38
+ return false;
39
+ }
40
+ const EXPECT_RE = /<!--\s*EXPECT:(ok|broken)(?::([^\s>]+))?\s*-->/;
41
+ function findSidebarExpect(content, targetLine) {
42
+ const lines = content.split("\n");
43
+ const idx = targetLine - 1;
44
+ if (idx < 0 || idx >= lines.length)
45
+ return undefined;
46
+ const match = lines[idx].match(EXPECT_RE);
47
+ if (match)
48
+ return { expect: match[1], expectReason: match[2] };
49
+ return undefined;
50
+ }
51
+ export function checkLocal(docRootDir, basePath) {
52
+ const rootAbs = basePath ? path.join(docRootDir, basePath) : docRootDir;
53
+ if (!fs.existsSync(rootAbs)) {
54
+ console.error(`Doc root not found: ${rootAbs}`);
55
+ return [];
56
+ }
57
+ const results = [];
58
+ const sidebars = findSidebars(rootAbs);
59
+ for (const sidebarPath of sidebars) {
60
+ const content = fs.readFileSync(sidebarPath, "utf-8");
61
+ const links = parseSidebar(content);
62
+ for (const link of links) {
63
+ const resolved = resolveSidebarLink(link.href, "");
64
+ const exists = fileExists(rootAbs, resolved.resolved);
65
+ const broken = resolved.broken || !exists;
66
+ const expectMatch = findSidebarExpect(content, link.line);
67
+ results.push({
68
+ file: path.relative(docRootDir, sidebarPath),
69
+ line: link.line,
70
+ href: link.href,
71
+ linkText: link.text,
72
+ kind: "sidebar",
73
+ resolved: resolved.resolved,
74
+ status: broken ? "broken" : "ok",
75
+ reason: resolved.reason || (exists ? "" : `file not found: ${resolved.resolved}`),
76
+ expect: expectMatch?.expect,
77
+ expectReason: expectMatch?.expectReason,
78
+ mismatch: expectMatch?.expect ? (broken ? expectMatch.expect === "ok" : expectMatch.expect === "broken") : undefined,
79
+ });
80
+ }
81
+ }
82
+ const mdFiles = walkMdFiles(rootAbs);
83
+ for (const filePath of mdFiles) {
84
+ if (path.basename(filePath) === "_sidebar.md")
85
+ continue;
86
+ const content = fs.readFileSync(filePath, "utf-8");
87
+ const relFile = path.relative(rootAbs, filePath);
88
+ const relDir = path.dirname(relFile);
89
+ const links = extractLinks(content, content);
90
+ for (const link of links) {
91
+ let resolved;
92
+ let exists = false;
93
+ if (link.kind === "doc") {
94
+ resolved = resolveDocLink(link.href, "");
95
+ if (resolved.type === "external" || resolved.type === "anchor" || resolved.type === "mailto")
96
+ continue;
97
+ if (resolved.type === "asset")
98
+ continue;
99
+ exists = !resolved.broken && fileExists(rootAbs, resolved.resolved);
100
+ }
101
+ else if (link.kind === "image") {
102
+ resolved = resolveImageLink(link.href, relDir, "");
103
+ if (resolved.type === "external")
104
+ continue;
105
+ const imgPath = path.join(rootAbs, resolved.resolved);
106
+ exists = fs.existsSync(imgPath);
107
+ }
108
+ else {
109
+ resolved = resolveEmbedLink(link.href, relDir);
110
+ if (resolved.type === "external")
111
+ continue;
112
+ const embedPath = path.join(rootAbs, resolved.resolved);
113
+ exists = !resolved.broken && fs.existsSync(embedPath);
114
+ }
115
+ const broken = resolved.broken || !exists;
116
+ const reason = resolved.reason || (exists ? "" : `file not found: ${resolved.resolved}`);
117
+ results.push({
118
+ file: basePath ? path.join(basePath, relFile) : relFile,
119
+ line: link.line,
120
+ href: link.href,
121
+ linkText: link.text,
122
+ kind: link.kind,
123
+ resolved: resolved.resolved,
124
+ status: broken ? "broken" : "ok",
125
+ reason,
126
+ expect: link.expect,
127
+ expectReason: link.expectReason,
128
+ mismatch: link.expect ? (broken ? link.expect === "ok" : link.expect === "broken") : undefined,
129
+ });
130
+ }
131
+ }
132
+ return results;
133
+ }
134
+ //# sourceMappingURL=check-local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-local.js","sourceRoot":"","sources":["../../src/lib/check-local.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { CheckResult } from "./check-local.js";
2
+ export declare function checkRemote(baseUrl: string, slug: string, basePath: string): Promise<CheckResult[]>;
3
+ //# sourceMappingURL=check-remote.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-remote.d.ts","sourceRoot":"","sources":["../../src/lib/check-remote.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AA2BpD,wBAAsB,WAAW,CAC/B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,WAAW,EAAE,CAAC,CAuGxB"}
@@ -0,0 +1,121 @@
1
+ import { resolveDocLink, resolveSidebarLink } from "./resolve.js";
2
+ import { parseSidebar, extractLinks } from "./parse.js";
3
+ async function fetchText(url) {
4
+ try {
5
+ const resp = await fetch(url, { redirect: "follow" });
6
+ if (!resp.ok)
7
+ return { text: null, status: resp.status };
8
+ const text = await resp.text();
9
+ return { text, status: resp.status };
10
+ }
11
+ catch {
12
+ return { text: null, status: 0 };
13
+ }
14
+ }
15
+ async function headCheck(url) {
16
+ try {
17
+ const resp = await fetch(url, { method: "HEAD", redirect: "follow" });
18
+ return resp.status;
19
+ }
20
+ catch {
21
+ return 0;
22
+ }
23
+ }
24
+ function isHtml(text) {
25
+ const s = text.trimStart().slice(0, 10).toLowerCase();
26
+ return s.startsWith("<!") || s.startsWith("<html");
27
+ }
28
+ export async function checkRemote(baseUrl, slug, basePath) {
29
+ const contentRoot = basePath
30
+ ? `${baseUrl}/docs/${slug}/${basePath}`
31
+ : `${baseUrl}/docs/${slug}`;
32
+ const sidebarUrl = `${contentRoot}/_sidebar.md`;
33
+ console.log(`Fetching sidebar: ${sidebarUrl}`);
34
+ const { text: sidebarContent, status: sidebarStatus } = await fetchText(sidebarUrl);
35
+ if (!sidebarContent || isHtml(sidebarContent)) {
36
+ console.error(`Failed to fetch sidebar (status ${sidebarStatus})`);
37
+ return [];
38
+ }
39
+ const sidebarLinks = parseSidebar(sidebarContent);
40
+ const results = [];
41
+ for (const link of sidebarLinks) {
42
+ const resolved = resolveSidebarLink(link.href, "");
43
+ if (resolved.broken) {
44
+ results.push({
45
+ file: "_sidebar.md",
46
+ line: link.line,
47
+ href: link.href,
48
+ linkText: link.text,
49
+ kind: "sidebar",
50
+ resolved: resolved.resolved,
51
+ status: "broken",
52
+ reason: resolved.reason || "",
53
+ });
54
+ continue;
55
+ }
56
+ const pageUrl = `${contentRoot}/${resolved.resolved}`;
57
+ const status = await headCheck(pageUrl);
58
+ const ok = status >= 200 && status < 400;
59
+ results.push({
60
+ file: "_sidebar.md",
61
+ line: link.line,
62
+ href: link.href,
63
+ linkText: link.text,
64
+ kind: "sidebar",
65
+ resolved: resolved.resolved,
66
+ status: ok ? "ok" : "broken",
67
+ reason: ok ? "" : `HTTP ${status}`,
68
+ });
69
+ }
70
+ const pageUrls = sidebarLinks
71
+ .map((l) => {
72
+ const r = resolveSidebarLink(l.href, "");
73
+ return r.broken ? null : `${contentRoot}/${r.resolved}`;
74
+ })
75
+ .filter(Boolean);
76
+ const homepageUrl = `${contentRoot}/README.md`;
77
+ if (!pageUrls.includes(homepageUrl))
78
+ pageUrls.unshift(homepageUrl);
79
+ for (const pageUrl of pageUrls) {
80
+ const { text: pageContent } = await fetchText(pageUrl);
81
+ if (!pageContent || isHtml(pageContent))
82
+ continue;
83
+ const relPath = pageUrl.replace(contentRoot + "/", "");
84
+ const links = extractLinks(pageContent, pageContent);
85
+ for (const link of links) {
86
+ if (link.kind !== "doc")
87
+ continue;
88
+ const resolved = resolveDocLink(link.href, "");
89
+ if (resolved.type === "external" || resolved.type === "anchor" || resolved.type === "mailto" || resolved.type === "asset")
90
+ continue;
91
+ if (resolved.broken) {
92
+ results.push({
93
+ file: relPath,
94
+ line: link.line,
95
+ href: link.href,
96
+ linkText: link.text,
97
+ kind: "doc",
98
+ resolved: resolved.resolved,
99
+ status: "broken",
100
+ reason: resolved.reason || "",
101
+ });
102
+ continue;
103
+ }
104
+ const targetUrl = `${contentRoot}/${resolved.resolved}`;
105
+ const status = await headCheck(targetUrl);
106
+ const ok = status >= 200 && status < 400;
107
+ results.push({
108
+ file: relPath,
109
+ line: link.line,
110
+ href: link.href,
111
+ linkText: link.text,
112
+ kind: "doc",
113
+ resolved: resolved.resolved,
114
+ status: ok ? "ok" : "broken",
115
+ reason: ok ? "" : `HTTP ${status}`,
116
+ });
117
+ }
118
+ }
119
+ return results;
120
+ }
121
+ //# sourceMappingURL=check-remote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-remote.js","sourceRoot":"","sources":["../../src/lib/check-remote.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ export interface SidebarLink {
2
+ text: string;
3
+ href: string;
4
+ line: number;
5
+ depth: number;
6
+ section: string | null;
7
+ }
8
+ export interface PageLink {
9
+ text: string;
10
+ href: string;
11
+ line: number;
12
+ kind: "doc" | "image" | "embed";
13
+ expect?: "ok" | "broken";
14
+ expectReason?: string;
15
+ }
16
+ export declare function parseSidebar(content: string): SidebarLink[];
17
+ export declare function extractLinks(content: string, originalContent: string): PageLink[];
18
+ //# sourceMappingURL=parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/lib/parse.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,KAAK,GAAG,OAAO,GAAG,OAAO,CAAC;IAChC,MAAM,CAAC,EAAE,IAAI,GAAG,QAAQ,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAwCD,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,CAoB3D;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,QAAQ,EAAE,CAgCjF"}
@@ -0,0 +1,110 @@
1
+ const MD_LINK_RE = /\[([^\]]*)\]\(([^)]+)\)/g;
2
+ const IMG_LINK_RE = /!\[([^\]]*)\]\(([^)]+)\)/g;
3
+ const HTML_COMMENT_RE = /<!--.*?-->/gs;
4
+ const FENCED_CODE_RE = /^```[^\n]*\n.*?^```/gms;
5
+ const INDENTED_CODE_RE = /^(?: {4}|\t)[^\n]*$/gm;
6
+ const INLINE_CODE_RE = /`[^`\n]+`/g;
7
+ const EXPECT_RE = /<!--\s*EXPECT:(ok|broken)(?::([^\s>]+))?\s*-->/;
8
+ function stripCodeBlocks(content) {
9
+ return content
10
+ .replace(FENCED_CODE_RE, (m) => "\n".repeat(countNewlines(m)))
11
+ .replace(INDENTED_CODE_RE, "")
12
+ .replace(INLINE_CODE_RE, "");
13
+ }
14
+ function stripHtmlComments(content) {
15
+ return content.replace(HTML_COMMENT_RE, (m) => "\n".repeat(countNewlines(m)));
16
+ }
17
+ function countNewlines(s) {
18
+ let n = 0;
19
+ for (const c of s)
20
+ if (c === "\n")
21
+ n++;
22
+ return n;
23
+ }
24
+ function cleanHref(href) {
25
+ const i = href.indexOf(" ");
26
+ return i >= 0 ? href.slice(0, i) : href;
27
+ }
28
+ function lineAt(content, offset) {
29
+ let n = 1;
30
+ for (let i = 0; i < offset && i < content.length; i++) {
31
+ if (content[i] === "\n")
32
+ n++;
33
+ }
34
+ return n;
35
+ }
36
+ export function parseSidebar(content) {
37
+ const cleaned = content.replace(HTML_COMMENT_RE, (m) => "\n".repeat(countNewlines(m)));
38
+ const links = [];
39
+ let currentSection = null;
40
+ for (const [lineno, line] of cleaned.split("\n").entries()) {
41
+ const bold = line.match(/\*\*(.+?)\*\*/);
42
+ if (bold)
43
+ currentSection = bold[1];
44
+ for (const m of line.matchAll(MD_LINK_RE)) {
45
+ const href = cleanHref(m[2].trim());
46
+ if (href.startsWith("#") || href.startsWith("http://") || href.startsWith("https://"))
47
+ continue;
48
+ const stripped = href.split("#")[0].split("?")[0];
49
+ if (!stripped)
50
+ continue;
51
+ const depth = Math.floor((line.length - line.trimStart().length) / 2);
52
+ links.push({ text: m[1], href: stripped, line: lineno + 1, depth, section: currentSection });
53
+ }
54
+ }
55
+ return links;
56
+ }
57
+ export function extractLinks(content, originalContent) {
58
+ const forParsing = stripHtmlComments(stripCodeBlocks(content));
59
+ const links = [];
60
+ for (const m of forParsing.matchAll(IMG_LINK_RE)) {
61
+ const href = cleanHref(m[2].trim());
62
+ if (href.startsWith("http://") || href.startsWith("https://"))
63
+ continue;
64
+ const line = lineAt(forParsing, m.index);
65
+ const expect = findExpect(originalContent, line);
66
+ links.push({ text: m[1], href, line, kind: "image", ...expect });
67
+ }
68
+ for (const m of forParsing.matchAll(MD_LINK_RE)) {
69
+ if (forParsing[m.index - 1] === "!")
70
+ continue;
71
+ const fullHref = m[2].trim();
72
+ const href = cleanHref(fullHref);
73
+ if (href.startsWith("#") || href.startsWith("http://") || href.startsWith("https://"))
74
+ continue;
75
+ if (href.startsWith("mailto:") || href.startsWith("tel:"))
76
+ continue;
77
+ if (fullHref.includes(":disabled"))
78
+ continue;
79
+ const line = lineAt(forParsing, m.index);
80
+ const expect = findExpect(originalContent, line);
81
+ if (fullHref.includes("':include'") || fullHref.includes('":include"') || fullHref.includes(":include")) {
82
+ const cleanedHref = href.split("#")[0].split("?")[0];
83
+ links.push({ text: m[1], href: cleanedHref, line, kind: "embed", ...expect });
84
+ }
85
+ else {
86
+ links.push({ text: m[1], href, line, kind: "doc", ...expect });
87
+ }
88
+ }
89
+ return links;
90
+ }
91
+ function findExpect(originalContent, targetLine) {
92
+ const lines = originalContent.split("\n");
93
+ const lineIdx = targetLine - 1;
94
+ if (lineIdx < 0 || lineIdx >= lines.length)
95
+ return {};
96
+ const lineText = lines[lineIdx];
97
+ const match = lineText.match(EXPECT_RE);
98
+ if (!match) {
99
+ if (lineIdx + 1 < lines.length) {
100
+ const nextLine = lines[lineIdx + 1];
101
+ const nextMatch = nextLine.match(EXPECT_RE);
102
+ if (nextMatch) {
103
+ return { expect: nextMatch[1], expectReason: nextMatch[2] };
104
+ }
105
+ }
106
+ return {};
107
+ }
108
+ return { expect: match[1], expectReason: match[2] };
109
+ }
110
+ //# sourceMappingURL=parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/lib/parse.ts"],"names":[],"mappings":"AAiBA,MAAM,UAAU,GAAG,0BAA0B,CAAC;AAC9C,MAAM,WAAW,GAAG,2BAA2B,CAAC;AAChD,MAAM,eAAe,GAAG,cAAc,CAAC;AACvC,MAAM,cAAc,GAAG,wBAAwB,CAAC;AAChD,MAAM,gBAAgB,GAAG,uBAAuB,CAAC;AACjD,MAAM,cAAc,GAAG,YAAY,CAAC;AACpC,MAAM,SAAS,GAAG,gDAAgD,CAAC;AAEnE,SAAS,eAAe,CAAC,OAAe;IACtC,OAAO,OAAO;SACX,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;SAC7D,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC;SAC7B,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,iBAAiB,CAAC,OAAe;IACxC,OAAO,OAAO,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChF,CAAC;AAED,SAAS,aAAa,CAAC,CAAS;IAC9B,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,KAAK,MAAM,CAAC,IAAI,CAAC;QAAE,IAAI,CAAC,KAAK,IAAI;YAAE,CAAC,EAAE,CAAC;IACvC,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,SAAS,CAAC,IAAY;IAC7B,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC5B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1C,CAAC;AAED,SAAS,MAAM,CAAC,OAAe,EAAE,MAAc;IAC7C,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtD,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI;YAAE,CAAC,EAAE,CAAC;IAC/B,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACvF,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,IAAI,cAAc,GAAkB,IAAI,CAAC;IAEzC,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;QAC3D,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;QACzC,IAAI,IAAI;YAAE,cAAc,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAEnC,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YAC1C,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YACpC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;gBAAE,SAAS;YAChG,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAClD,IAAI,CAAC,QAAQ;gBAAE,SAAS;YAExB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YACtE,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;QAC/F,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,eAAuB;IACnE,MAAM,UAAU,GAAG,iBAAiB,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAe,EAAE,CAAC;IAE7B,KAAK,MAAM,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACpC,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;YAAE,SAAS;QACxE,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,KAAM,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,UAAU,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;QACjD,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAChD,IAAI,UAAU,CAAC,CAAC,CAAC,KAAM,GAAG,CAAC,CAAC,KAAK,GAAG;YAAE,SAAS;QAC/C,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;QACjC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;YAAE,SAAS;QAChG,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,SAAS;QACpE,IAAI,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC;YAAE,SAAS;QAE7C,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,KAAM,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,UAAU,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;QAEjD,IAAI,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YACxG,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACrD,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;QAChF,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,UAAU,CAAC,eAAuB,EAAE,UAAkB;IAC7D,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,UAAU,GAAG,CAAC,CAAC;IAC/B,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,IAAI,KAAK,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IAEtD,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;IAChC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACxC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,IAAI,OAAO,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YAC/B,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;YACpC,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YAC5C,IAAI,SAAS,EAAE,CAAC;gBACd,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAoB,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;YACjF,CAAC;QACH,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAoB,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AACzE,CAAC"}
@@ -0,0 +1,14 @@
1
+ export type LinkType = "doc" | "image" | "embed" | "sidebar" | "external" | "anchor" | "asset" | "mailto";
2
+ export interface ResolvedLink {
3
+ href: string;
4
+ resolved: string;
5
+ type: LinkType;
6
+ exists?: boolean;
7
+ broken?: boolean;
8
+ reason?: string;
9
+ }
10
+ export declare function resolveDocLink(href: string, basePath: string): ResolvedLink;
11
+ export declare function resolveSidebarLink(href: string, basePath: string): ResolvedLink;
12
+ export declare function resolveImageLink(href: string, currentPageDir: string, docRoot: string): ResolvedLink;
13
+ export declare function resolveEmbedLink(href: string, currentFileDir: string): ResolvedLink;
14
+ //# sourceMappingURL=resolve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/lib/resolve.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE1G,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAyBD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,CAoC3E;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,CAG/E;AAED,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,MAAM,GACd,YAAY,CAgBd;AAED,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,cAAc,EAAE,MAAM,GACrB,YAAY,CAiBd"}
@@ -0,0 +1,98 @@
1
+ import * as path from "node:path";
2
+ const ASSET_EXTENSIONS = new Set([
3
+ ".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp", ".ico", ".bmp",
4
+ ".pdf", ".zip", ".tar", ".gz",
5
+ ".css", ".js", ".json", ".xml", ".yaml", ".yml",
6
+ ".woff", ".woff2", ".ttf", ".eot",
7
+ ".mp4", ".webm", ".mp3",
8
+ ".xls", ".xlsx", ".html", ".txt",
9
+ ]);
10
+ function extOf(p) {
11
+ const dot = p.lastIndexOf(".");
12
+ return dot >= 0 ? p.slice(dot).toLowerCase() : "";
13
+ }
14
+ function isAsset(href) {
15
+ return ASSET_EXTENSIONS.has(extOf(href));
16
+ }
17
+ function ensureMd(p) {
18
+ if (!p.endsWith(".md") && !p.endsWith(".txt"))
19
+ return p + ".md";
20
+ return p;
21
+ }
22
+ function cleanHref(href) {
23
+ const spaceIdx = href.indexOf(" ");
24
+ return spaceIdx >= 0 ? href.slice(0, spaceIdx) : href;
25
+ }
26
+ function stripFragmentAndQuery(href) {
27
+ return href.split("#")[0].split("?")[0];
28
+ }
29
+ export function resolveDocLink(href, basePath) {
30
+ const cleaned = stripFragmentAndQuery(cleanHref(href.trim()));
31
+ if (!cleaned)
32
+ return { href, resolved: "", type: "anchor", reason: "empty after strip" };
33
+ if (cleaned.startsWith("http://") || cleaned.startsWith("https://")) {
34
+ return { href, resolved: cleaned, type: "external" };
35
+ }
36
+ if (cleaned.startsWith("#")) {
37
+ return { href, resolved: cleaned, type: "anchor" };
38
+ }
39
+ if (cleaned.startsWith("mailto:") || cleaned.startsWith("tel:")) {
40
+ return { href, resolved: cleaned, type: "mailto" };
41
+ }
42
+ if (isAsset(cleaned)) {
43
+ return { href, resolved: cleaned, type: "asset" };
44
+ }
45
+ if (cleaned.startsWith("../")) {
46
+ return {
47
+ href,
48
+ resolved: cleaned,
49
+ type: "doc",
50
+ broken: true,
51
+ reason: "../ is not supported by the custom renderer for document links",
52
+ };
53
+ }
54
+ const stripped = cleaned.replace(/^\.\//, "").replace(/^\//, "");
55
+ if (!stripped) {
56
+ const resolved = basePath ? path.posix.join(basePath, "README.md") : "README.md";
57
+ return { href, resolved, type: "doc" };
58
+ }
59
+ const withMd = ensureMd(stripped);
60
+ const resolved = basePath ? path.posix.join(basePath, withMd) : withMd;
61
+ return { href, resolved, type: "doc" };
62
+ }
63
+ export function resolveSidebarLink(href, basePath) {
64
+ const result = resolveDocLink(href, basePath);
65
+ return { ...result, type: result.type === "doc" ? "sidebar" : result.type };
66
+ }
67
+ export function resolveImageLink(href, currentPageDir, docRoot) {
68
+ const cleaned = stripFragmentAndQuery(cleanHref(href.trim()));
69
+ if (!cleaned)
70
+ return { href, resolved: "", type: "image" };
71
+ if (cleaned.startsWith("http://") || cleaned.startsWith("https://")) {
72
+ return { href, resolved: cleaned, type: "external" };
73
+ }
74
+ if (cleaned.startsWith("/")) {
75
+ const stripped = cleaned.slice(1);
76
+ const resolved = docRoot ? path.posix.join(docRoot, stripped) : stripped;
77
+ return { href, resolved, type: "image" };
78
+ }
79
+ const resolved = path.posix.normalize(path.posix.join(currentPageDir, cleaned));
80
+ return { href, resolved, type: "image" };
81
+ }
82
+ export function resolveEmbedLink(href, currentFileDir) {
83
+ const cleaned = stripFragmentAndQuery(cleanHref(href.trim()));
84
+ if (!cleaned)
85
+ return { href, resolved: "", type: "embed" };
86
+ if (cleaned.startsWith("/")) {
87
+ return {
88
+ href,
89
+ resolved: cleaned,
90
+ type: "embed",
91
+ broken: true,
92
+ reason: "absolute paths are broken for :include embeds",
93
+ };
94
+ }
95
+ const resolved = path.posix.normalize(path.posix.join(currentFileDir, cleaned));
96
+ return { href, resolved, type: "embed" };
97
+ }
98
+ //# sourceMappingURL=resolve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/lib/resolve.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,35 @@
1
1
  {
2
2
  "name": "@developerportalsg/docportal-cli",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "CLI tools for Documentation Portal publishers — link checking, validation, and more",
5
+ "type": "module",
6
+ "bin": {
7
+ "docportal": "dist/cli.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "test": "node --import tsx --test tests/**/*.test.ts",
15
+ "prepublishOnly": "npm run build"
16
+ },
17
+ "engines": {
18
+ "node": ">=18.0.0"
19
+ },
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "keywords": [
24
+ "documentation-portal",
25
+ "docsify",
26
+ "link-checker",
27
+ "devportal"
28
+ ],
29
+ "author": "Developer Portal Team",
30
+ "license": "MIT",
31
+ "devDependencies": {
32
+ "tsx": "^4.0.0",
33
+ "typescript": "^5.0.0"
34
+ }
35
+ }