nrdocs 0.1.1 → 0.1.3
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/bin.mjs +109 -21
- package/package.json +1 -1
package/dist/bin.mjs
CHANGED
|
@@ -694,6 +694,21 @@ function parseInitArgs(args2) {
|
|
|
694
694
|
}
|
|
695
695
|
return opts;
|
|
696
696
|
}
|
|
697
|
+
function normalizeUrl(url) {
|
|
698
|
+
let normalized = url.trim();
|
|
699
|
+
if (!normalized.startsWith("http://") && !normalized.startsWith("https://")) {
|
|
700
|
+
normalized = `https://${normalized}`;
|
|
701
|
+
}
|
|
702
|
+
normalized = normalized.replace(/\/+$/, "");
|
|
703
|
+
try {
|
|
704
|
+
new URL(normalized);
|
|
705
|
+
} catch {
|
|
706
|
+
console.error(`Error: "${url}" is not a valid URL.`);
|
|
707
|
+
console.error("Expected format: https://docs.example.com");
|
|
708
|
+
process.exit(2);
|
|
709
|
+
}
|
|
710
|
+
return normalized;
|
|
711
|
+
}
|
|
697
712
|
function readExistingConfig(configPath) {
|
|
698
713
|
if (!fs2.existsSync(configPath)) return {};
|
|
699
714
|
try {
|
|
@@ -751,6 +766,7 @@ async function handleInit(args2) {
|
|
|
751
766
|
console.error(" nrdocs init --api-url https://your-docs-url.com");
|
|
752
767
|
process.exit(2);
|
|
753
768
|
}
|
|
769
|
+
apiUrl = normalizeUrl(apiUrl);
|
|
754
770
|
const indexFile = path3.join(docsPath, "index.md");
|
|
755
771
|
const workflowDir = path3.resolve(".github", "workflows");
|
|
756
772
|
const workflowFile = path3.join(workflowDir, "nrdocs.yml");
|
|
@@ -6092,9 +6108,33 @@ function rewriteMdLink(href, basePath, owner, repo) {
|
|
|
6092
6108
|
}
|
|
6093
6109
|
|
|
6094
6110
|
// src/renderer/template.ts
|
|
6111
|
+
function extractToc(html) {
|
|
6112
|
+
const toc = [];
|
|
6113
|
+
const regex = /<h([2-3])[^>]*id="([^"]*)"[^>]*>(.*?)<\/h[2-3]>/gi;
|
|
6114
|
+
let match2;
|
|
6115
|
+
while ((match2 = regex.exec(html)) !== null) {
|
|
6116
|
+
toc.push({
|
|
6117
|
+
level: parseInt(match2[1], 10),
|
|
6118
|
+
id: match2[2],
|
|
6119
|
+
text: match2[3].replace(/<[^>]*>/g, "")
|
|
6120
|
+
});
|
|
6121
|
+
}
|
|
6122
|
+
return toc;
|
|
6123
|
+
}
|
|
6124
|
+
function addHeadingIds(html) {
|
|
6125
|
+
return html.replace(/<h([2-3])([^>]*)>(.*?)<\/h[2-3]>/gi, (_match, level, attrs, text2) => {
|
|
6126
|
+
if (attrs.includes("id=")) return _match;
|
|
6127
|
+
const plainText = text2.replace(/<[^>]*>/g, "");
|
|
6128
|
+
const id = plainText.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
6129
|
+
return `<h${level} id="${id}"${attrs}>${text2}</h${level}>`;
|
|
6130
|
+
});
|
|
6131
|
+
}
|
|
6095
6132
|
function wrapInTemplate(options) {
|
|
6096
6133
|
const { title, siteTitle, content, nav, canonicalUrl, baseUrl } = options;
|
|
6097
6134
|
const pageTitle = title === siteTitle ? siteTitle : `${title} - ${siteTitle}`;
|
|
6135
|
+
const contentWithIds = addHeadingIds(content);
|
|
6136
|
+
const toc = extractToc(contentWithIds);
|
|
6137
|
+
const hasToc = toc.length > 1;
|
|
6098
6138
|
return `<!DOCTYPE html>
|
|
6099
6139
|
<html lang="en">
|
|
6100
6140
|
<head>
|
|
@@ -6103,34 +6143,46 @@ function wrapInTemplate(options) {
|
|
|
6103
6143
|
<meta http-equiv="X-Content-Type-Options" content="nosniff">
|
|
6104
6144
|
<meta http-equiv="X-Frame-Options" content="DENY">
|
|
6105
6145
|
<meta name="referrer" content="no-referrer">
|
|
6146
|
+
<meta name="generator" content="nrdocs">
|
|
6106
6147
|
<title>${escapeHtml2(pageTitle)}</title>
|
|
6107
6148
|
<link rel="canonical" href="${escapeHtml2(canonicalUrl)}">
|
|
6108
6149
|
<style>
|
|
6109
6150
|
*{margin:0;padding:0;box-sizing:border-box}
|
|
6110
|
-
body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;line-height:1.
|
|
6111
|
-
nav.sidebar{width:260px;padding:1.5rem;border-right:1px solid #e0e0e0;background:#fafafa;overflow-y:auto;flex-shrink:0}
|
|
6151
|
+
body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;font-size:1.0625rem;line-height:1.7;color:#1a1a1a;display:flex;min-height:100vh}
|
|
6152
|
+
nav.sidebar{width:260px;padding:1.5rem;border-right:1px solid #e0e0e0;background:#fafafa;overflow-y:auto;flex-shrink:0;position:sticky;top:0;height:100vh}
|
|
6112
6153
|
nav.sidebar .site-title{font-weight:700;font-size:1.1rem;margin-bottom:1rem;color:#111}
|
|
6113
6154
|
nav.sidebar ul{list-style:none}
|
|
6114
6155
|
nav.sidebar li{margin-bottom:0.25rem}
|
|
6115
|
-
nav.sidebar a{color:#333;text-decoration:none;padding:0.
|
|
6156
|
+
nav.sidebar a{color:#333;text-decoration:none;padding:0.3rem 0.6rem;display:block;border-radius:4px;font-size:0.95rem}
|
|
6116
6157
|
nav.sidebar a:hover{background:#e8e8e8}
|
|
6117
6158
|
nav.sidebar a.active{background:#e0e7ff;color:#1d4ed8;font-weight:500}
|
|
6118
|
-
|
|
6119
|
-
main
|
|
6120
|
-
main
|
|
6121
|
-
main
|
|
6122
|
-
main
|
|
6159
|
+
.content-wrapper{flex:1;display:flex;min-width:0}
|
|
6160
|
+
main{flex:1;padding:2.5rem 3rem;max-width:52rem;min-width:0;overflow-wrap:break-word}
|
|
6161
|
+
main h1{font-size:2.2rem;margin-bottom:1.2rem;border-bottom:1px solid #e0e0e0;padding-bottom:0.5rem;line-height:1.3}
|
|
6162
|
+
main h2{font-size:1.6rem;margin-top:2.5rem;margin-bottom:0.75rem;line-height:1.3}
|
|
6163
|
+
main h3{font-size:1.3rem;margin-top:1.8rem;margin-bottom:0.5rem;line-height:1.4}
|
|
6164
|
+
main p{margin-bottom:1.1rem}
|
|
6123
6165
|
main a{color:#1d4ed8;text-decoration:underline}
|
|
6124
|
-
main code{background:#f3f4f6;padding:0.
|
|
6125
|
-
main pre{background:#1e1e1e;color:#d4d4d4;padding:
|
|
6126
|
-
main pre code{background:none;padding:0;color:inherit}
|
|
6127
|
-
main table{border-collapse:collapse;width:100%;margin-bottom:
|
|
6128
|
-
main th,main td{border:1px solid #d0d0d0;padding:0.
|
|
6166
|
+
main code{background:#f3f4f6;padding:0.2rem 0.4rem;border-radius:3px;font-size:0.88em}
|
|
6167
|
+
main pre{background:#1e1e1e;color:#d4d4d4;padding:1.2rem;border-radius:6px;overflow-x:auto;margin-bottom:1.2rem;font-size:0.9rem;line-height:1.5}
|
|
6168
|
+
main pre code{background:none;padding:0;color:inherit;font-size:inherit}
|
|
6169
|
+
main table{border-collapse:collapse;width:100%;margin-bottom:1.2rem}
|
|
6170
|
+
main th,main td{border:1px solid #d0d0d0;padding:0.6rem 0.85rem;text-align:left}
|
|
6129
6171
|
main th{background:#f5f5f5;font-weight:600}
|
|
6130
|
-
main img{max-width:100%;height:auto}
|
|
6131
|
-
main blockquote{border-left:4px solid #d0d0d0;padding-left:1rem;margin-bottom:1rem;color:#555}
|
|
6132
|
-
main ul,main ol{margin-bottom:1rem;padding-left:1.5rem}
|
|
6133
|
-
|
|
6172
|
+
main img{max-width:100%;height:auto;border-radius:4px}
|
|
6173
|
+
main blockquote{border-left:4px solid #d0d0d0;padding-left:1rem;margin-bottom:1.1rem;color:#555;font-style:italic}
|
|
6174
|
+
main ul,main ol{margin-bottom:1.1rem;padding-left:1.5rem}
|
|
6175
|
+
main li{margin-bottom:0.3rem}
|
|
6176
|
+
aside.toc{width:220px;padding:1.5rem 1rem;position:sticky;top:0;height:100vh;overflow-y:auto;flex-shrink:0;border-left:1px solid #e8e8e8}
|
|
6177
|
+
aside.toc .toc-title{font-size:0.8rem;font-weight:600;text-transform:uppercase;letter-spacing:0.05em;color:#666;margin-bottom:0.75rem}
|
|
6178
|
+
aside.toc ul{list-style:none}
|
|
6179
|
+
aside.toc li{margin-bottom:0.3rem}
|
|
6180
|
+
aside.toc a{color:#555;text-decoration:none;font-size:0.85rem;display:block;padding:0.15rem 0;border-radius:2px}
|
|
6181
|
+
aside.toc a:hover{color:#1d4ed8}
|
|
6182
|
+
aside.toc .toc-h3{padding-left:0.75rem}
|
|
6183
|
+
footer{padding:1.5rem 3rem;border-top:1px solid #e8e8e8;color:#888;font-size:0.8rem;text-align:center}
|
|
6184
|
+
@media(max-width:1100px){aside.toc{display:none}}
|
|
6185
|
+
@media(max-width:768px){body{flex-direction:column}nav.sidebar{width:100%;border-right:none;border-bottom:1px solid #e0e0e0;position:static;height:auto}main{padding:1.5rem}}
|
|
6134
6186
|
</style>
|
|
6135
6187
|
</head>
|
|
6136
6188
|
<body>
|
|
@@ -6140,12 +6192,28 @@ main ul,main ol{margin-bottom:1rem;padding-left:1.5rem}
|
|
|
6140
6192
|
${renderNavItems(nav, baseUrl)}
|
|
6141
6193
|
</ul>
|
|
6142
6194
|
</nav>
|
|
6195
|
+
<div class="content-wrapper">
|
|
6143
6196
|
<main>
|
|
6144
|
-
${
|
|
6197
|
+
${contentWithIds}
|
|
6198
|
+
<footer>Generated with <a href="https://github.com/noam-r/nrdocs">nrdocs</a></footer>
|
|
6145
6199
|
</main>
|
|
6200
|
+
${hasToc ? renderToc(toc) : ""}
|
|
6201
|
+
</div>
|
|
6146
6202
|
</body>
|
|
6147
6203
|
</html>`;
|
|
6148
6204
|
}
|
|
6205
|
+
function renderToc(toc) {
|
|
6206
|
+
const items = toc.map((entry) => {
|
|
6207
|
+
const cls = entry.level === 3 ? ' class="toc-h3"' : "";
|
|
6208
|
+
return `<li${cls}><a href="#${escapeHtml2(entry.id)}">${escapeHtml2(entry.text)}</a></li>`;
|
|
6209
|
+
}).join("\n");
|
|
6210
|
+
return `<aside class="toc">
|
|
6211
|
+
<div class="toc-title">On this page</div>
|
|
6212
|
+
<ul>
|
|
6213
|
+
${items}
|
|
6214
|
+
</ul>
|
|
6215
|
+
</aside>`;
|
|
6216
|
+
}
|
|
6149
6217
|
function renderNavItems(items, baseUrl) {
|
|
6150
6218
|
return items.map((item) => {
|
|
6151
6219
|
const href = baseUrl + item.href;
|
|
@@ -6545,9 +6613,13 @@ async function handlePublish(args2) {
|
|
|
6545
6613
|
console.log("Uploading to nrdocs...");
|
|
6546
6614
|
const client = new ApiClient(apiUrl, token);
|
|
6547
6615
|
const formData = new FormData();
|
|
6548
|
-
formData.append("
|
|
6549
|
-
formData.append("
|
|
6550
|
-
|
|
6616
|
+
formData.append("artifact", new Blob([archive], { type: "application/gzip" }), "docs.tar.gz");
|
|
6617
|
+
formData.append("metadata", JSON.stringify({
|
|
6618
|
+
schema_version: 1,
|
|
6619
|
+
site: { title: siteTitle, requested_access: "password" },
|
|
6620
|
+
artifact: { format: "tar.gz", size_bytes: archive.length },
|
|
6621
|
+
nrdocs: { cli_version: "0.1.1" }
|
|
6622
|
+
}));
|
|
6551
6623
|
const result = await client.publish(formData);
|
|
6552
6624
|
if (result.ok) {
|
|
6553
6625
|
console.log("Published successfully!");
|
|
@@ -6699,6 +6771,21 @@ function checkCloudflareAuth() {
|
|
|
6699
6771
|
const result = runSilent("npx wrangler whoami");
|
|
6700
6772
|
return result.ok && !result.stdout.includes("Not authenticated");
|
|
6701
6773
|
}
|
|
6774
|
+
function normalizeUrl2(url) {
|
|
6775
|
+
let normalized = url.trim();
|
|
6776
|
+
if (!normalized.startsWith("http://") && !normalized.startsWith("https://")) {
|
|
6777
|
+
normalized = `https://${normalized}`;
|
|
6778
|
+
}
|
|
6779
|
+
normalized = normalized.replace(/\/+$/, "");
|
|
6780
|
+
try {
|
|
6781
|
+
new URL(normalized);
|
|
6782
|
+
} catch {
|
|
6783
|
+
console.error(`Error: "${url}" is not a valid URL.`);
|
|
6784
|
+
console.error("Expected format: https://docs.example.com");
|
|
6785
|
+
process.exit(2);
|
|
6786
|
+
}
|
|
6787
|
+
return normalized;
|
|
6788
|
+
}
|
|
6702
6789
|
function findWorkerDir() {
|
|
6703
6790
|
const candidates = [
|
|
6704
6791
|
path9.resolve("packages/worker"),
|
|
@@ -6761,6 +6848,7 @@ async function handleDeploy(args2) {
|
|
|
6761
6848
|
instance = instance || await prompt3("Instance name", "default");
|
|
6762
6849
|
baseUrl = baseUrl || await prompt3("Docs base URL", "https://docs.example.com");
|
|
6763
6850
|
}
|
|
6851
|
+
baseUrl = normalizeUrl2(baseUrl);
|
|
6764
6852
|
const validation = validateInstanceName(instance);
|
|
6765
6853
|
if (!validation.valid) {
|
|
6766
6854
|
console.error(`Error: ${validation.error}`);
|