docstra 1.7.8 ā 1.7.9
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/cli/commands/init.js +149 -0
- package/cli/templates/docstra-config.js +53 -0
- package/cli/templates/index.js +11 -0
- package/cli/templates/mdx-components.js +8 -0
- package/cli/templates/next-config.js +7 -0
- package/cli/templates/pages.js +63 -0
- package/cli/utils/fs.js +31 -0
- package/package.json +3 -2
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const { safeWrite, createFolder } = require("../utils/fs");
|
|
4
|
+
const {
|
|
5
|
+
DOCSTRA_CONFIG,
|
|
6
|
+
MDX_COMPONENTS,
|
|
7
|
+
NEXT_CONFIG,
|
|
8
|
+
INDEX_MDX,
|
|
9
|
+
PAGE_TSX,
|
|
10
|
+
SOURCE_TS
|
|
11
|
+
} = require("../templates");
|
|
12
|
+
|
|
13
|
+
function initDocstra() {
|
|
14
|
+
console.log("\nš§ Initializing Docstra...\n");
|
|
15
|
+
|
|
16
|
+
const root = process.cwd();
|
|
17
|
+
|
|
18
|
+
// 1. Create structure
|
|
19
|
+
createFolder(path.join(root, "app"));
|
|
20
|
+
|
|
21
|
+
// 2. Create docs content
|
|
22
|
+
const contentDir = path.join(root, "app", "docs", "content");
|
|
23
|
+
const slugDir = path.join(root, "app", "docs", "[[...slug]]");
|
|
24
|
+
|
|
25
|
+
createFolder(contentDir);
|
|
26
|
+
createFolder(slugDir);
|
|
27
|
+
|
|
28
|
+
safeWrite(path.join(contentDir, "index.mdx"), INDEX_MDX);
|
|
29
|
+
safeWrite(path.join(slugDir, "page.tsx"), PAGE_TSX);
|
|
30
|
+
|
|
31
|
+
// 3. Create lib/source.ts
|
|
32
|
+
const libDir = path.join(root, "lib");
|
|
33
|
+
createFolder(libDir);
|
|
34
|
+
safeWrite(path.join(libDir, "source.ts"), SOURCE_TS);
|
|
35
|
+
|
|
36
|
+
// 4. Config files
|
|
37
|
+
safeWrite(path.join(root, "mdx-components.tsx"), MDX_COMPONENTS);
|
|
38
|
+
safeWrite(path.join(root, "docstra.config.ts"), DOCSTRA_CONFIG);
|
|
39
|
+
|
|
40
|
+
// 5. Update next.config
|
|
41
|
+
updateNextConfig(root);
|
|
42
|
+
|
|
43
|
+
// 6. Check/Update Tailwind
|
|
44
|
+
updateTailwindGlobals(root);
|
|
45
|
+
|
|
46
|
+
// 7. Instructions
|
|
47
|
+
console.log(`
|
|
48
|
+
Please install latest version of Docstra by running:
|
|
49
|
+
|
|
50
|
+
Package Manager | Command
|
|
51
|
+
npm | npm install docstra@latest
|
|
52
|
+
yarn | yarn add docstra@latest
|
|
53
|
+
pnpm | pnpm add docstra@latest
|
|
54
|
+
`);
|
|
55
|
+
|
|
56
|
+
console.log("\nš Docstra initialized successfully!\n");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function updateNextConfig(root) {
|
|
60
|
+
const tsPath = path.join(root, "next.config.ts");
|
|
61
|
+
const jsPath = path.join(root, "next.config.js");
|
|
62
|
+
|
|
63
|
+
let nextConfigPath = fs.existsSync(tsPath) ? tsPath :
|
|
64
|
+
fs.existsSync(jsPath) ? jsPath :
|
|
65
|
+
null;
|
|
66
|
+
|
|
67
|
+
if (!nextConfigPath) {
|
|
68
|
+
// Create new if none exists
|
|
69
|
+
safeWrite(tsPath, NEXT_CONFIG);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
let content = fs.readFileSync(nextConfigPath, "utf8");
|
|
74
|
+
|
|
75
|
+
if (content.includes("withDocstra")) {
|
|
76
|
+
console.log("ā next.config already uses withDocstra");
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (!content.includes("withDocstra")) {
|
|
81
|
+
content = `import { withDocstra } from "docstra/server";\n` + content;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const exportRegex = /export\s+default\s+(.+);?/;
|
|
85
|
+
const match = content.match(exportRegex);
|
|
86
|
+
|
|
87
|
+
if (!match) {
|
|
88
|
+
console.log("ā Could not detect export default. Skipped patch.");
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
let exportValue = match[1].trim();
|
|
93
|
+
if (exportValue.endsWith(";")) {
|
|
94
|
+
exportValue = exportValue.slice(0, -1).trim();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const wrapped = `export default withDocstra(${exportValue});`;
|
|
98
|
+
content = content.replace(exportRegex, wrapped);
|
|
99
|
+
|
|
100
|
+
fs.writeFileSync(nextConfigPath, content);
|
|
101
|
+
console.log("ā Updated next.config with withDocstra()");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
function updateTailwindGlobals(root) {
|
|
106
|
+
const globalsPath = path.join(root, "app", "globals.css");
|
|
107
|
+
|
|
108
|
+
if (!fs.existsSync(globalsPath)) {
|
|
109
|
+
console.log("ā app/globals.css not found.");
|
|
110
|
+
console.log("Please ensure Tailwind is installed correctly before running Docstra init.");
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
let css = fs.readFileSync(globalsPath, "utf8");
|
|
115
|
+
|
|
116
|
+
// Simple check for tailwind import/usage would go here if needed,
|
|
117
|
+
// but we'll focus on injecting our styles.
|
|
118
|
+
|
|
119
|
+
if (css.includes('@import "docstra/css";')) {
|
|
120
|
+
console.log("ā docstra/css already imported in globals.css");
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Try to find where to insert
|
|
125
|
+
const tailwindRegex = /@import ['"]tailwindcss[^'"]*['"];?/g;
|
|
126
|
+
let lastMatch = null, match;
|
|
127
|
+
while ((match = tailwindRegex.exec(css)) !== null) {
|
|
128
|
+
lastMatch = match;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (lastMatch) {
|
|
132
|
+
const insertPos = lastMatch.index + lastMatch[0].length;
|
|
133
|
+
const updatedCSS = css.slice(0, insertPos) + `\n@import "docstra/css";\n` + css.slice(insertPos);
|
|
134
|
+
fs.writeFileSync(globalsPath, updatedCSS, "utf8");
|
|
135
|
+
console.log("ā Injected @import \"docstra/css\" into app/globals.css");
|
|
136
|
+
} else {
|
|
137
|
+
// If no explicit tailwind import found (e.g. using @tailwind directives or v4), just append or warn?
|
|
138
|
+
// For now, let's just append appropriately or warn.
|
|
139
|
+
// The original code warned if no tailwind imports were found.
|
|
140
|
+
// Let's keep it simple:
|
|
141
|
+
console.log(`
|
|
142
|
+
ā Tailwind imports not detected (or using different format).
|
|
143
|
+
Add manually:
|
|
144
|
+
@import "docstra/css";
|
|
145
|
+
`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
module.exports = { initDocstra };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module.exports = `import { defineDocstraConfig } from "docstra/config";
|
|
2
|
+
|
|
3
|
+
export default defineDocstraConfig({
|
|
4
|
+
siteName: "Docstra",
|
|
5
|
+
githubRepo: "https://github.com/sudhucodes/docstra",
|
|
6
|
+
contentDir: "app/docs/content",
|
|
7
|
+
editOnGithub: {
|
|
8
|
+
owner: "sudhucodes",
|
|
9
|
+
repo: "docstra",
|
|
10
|
+
path: "docs/content",
|
|
11
|
+
},
|
|
12
|
+
feedback: {
|
|
13
|
+
enabled: true,
|
|
14
|
+
formSyncFormID: "69c728a1-ccd2-4dab-a9f7-bb52baeb4d31",
|
|
15
|
+
},
|
|
16
|
+
navbar: {
|
|
17
|
+
logo: {
|
|
18
|
+
link: "/",
|
|
19
|
+
src: "/brand/logo.svg",
|
|
20
|
+
alt: "Logo",
|
|
21
|
+
className: "h-8 w-auto",
|
|
22
|
+
},
|
|
23
|
+
links: [
|
|
24
|
+
{ name: "Guides", href: "/docs/guides" },
|
|
25
|
+
{ name: "Examples", href: "/docs/examples" },
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
sidebar: {
|
|
29
|
+
links: [
|
|
30
|
+
{
|
|
31
|
+
section: 'Section 1',
|
|
32
|
+
items: [
|
|
33
|
+
{
|
|
34
|
+
name: 'Docs',
|
|
35
|
+
href: '/docs',
|
|
36
|
+
icon: '<Any-Lucide-Icon>'
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'Link 2',
|
|
40
|
+
href: '/docs/link-2',
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
section: 'Section 2',
|
|
46
|
+
items: [
|
|
47
|
+
{ name: 'Link 3', href: '/docs/link-3' },
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
`;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const docstraConfig = require("./docstra-config");
|
|
2
|
+
const mdxComponents = require("./mdx-components");
|
|
3
|
+
const nextConfig = require("./next-config");
|
|
4
|
+
const pages = require("./pages");
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
DOCSTRA_CONFIG: docstraConfig,
|
|
8
|
+
MDX_COMPONENTS: mdxComponents,
|
|
9
|
+
NEXT_CONFIG: nextConfig,
|
|
10
|
+
...pages,
|
|
11
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
exports.INDEX_MDX = `# Welcome to Docstra
|
|
2
|
+
|
|
3
|
+
Your documentation starts inside \`app/docs\`!
|
|
4
|
+
|
|
5
|
+
Start editing this file or add more MDX pages.
|
|
6
|
+
|
|
7
|
+
## Tips
|
|
8
|
+
- Pages in \`app/docs/content\` render automatically.
|
|
9
|
+
- \`[[...slug]]\` handles dynamic routing.
|
|
10
|
+
`;
|
|
11
|
+
|
|
12
|
+
exports.PAGE_TSX = `import docstraConfig from "@/docstra.config";
|
|
13
|
+
import { mdxComponents } from "@/mdx-components";
|
|
14
|
+
import {
|
|
15
|
+
DocstraBody,
|
|
16
|
+
DocstraHeader,
|
|
17
|
+
DocstraPage,
|
|
18
|
+
DocstraProvider,
|
|
19
|
+
} from "docstra";
|
|
20
|
+
|
|
21
|
+
import { source } from "@/lib/source";
|
|
22
|
+
import { notFound } from "next/navigation";
|
|
23
|
+
|
|
24
|
+
export default async function Page({ params }: { params: Promise<{ slug?: string[] }> }) {
|
|
25
|
+
const { slug } = await params
|
|
26
|
+
const page = source.getPage(slug);
|
|
27
|
+
if (!page) return notFound();
|
|
28
|
+
|
|
29
|
+
const MDX = page.body;
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<DocstraProvider docstraConfig={docstraConfig} docs={source.files} pageData={page.info}>
|
|
33
|
+
<DocstraHeader />
|
|
34
|
+
<DocstraPage>
|
|
35
|
+
<DocstraBody>
|
|
36
|
+
<MDX components={mdxComponents} />
|
|
37
|
+
</DocstraBody>
|
|
38
|
+
</DocstraPage>
|
|
39
|
+
</DocstraProvider>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function generateStaticParams() {
|
|
44
|
+
return source.generateStaticParams();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function generateMetadata({ params }: { params: Promise<{ slug?: string[] }> }) {
|
|
48
|
+
const { slug } = await params
|
|
49
|
+
const page = source.getPage(slug);
|
|
50
|
+
if (!page) return notFound();
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
title: page.info.data.metadata.title,
|
|
54
|
+
description: page.info.data.metadata.description,
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
`;
|
|
58
|
+
|
|
59
|
+
exports.SOURCE_TS = `import { docs } from "@/.docstra/index";
|
|
60
|
+
import { createSource } from "docstra/server";
|
|
61
|
+
|
|
62
|
+
export const source = createSource(docs);
|
|
63
|
+
`;
|
package/cli/utils/fs.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
|
|
4
|
+
function safeWrite(filePath, content) {
|
|
5
|
+
if (!fs.existsSync(filePath)) {
|
|
6
|
+
// Ensure directory exists
|
|
7
|
+
const dir = path.dirname(filePath);
|
|
8
|
+
if (!fs.existsSync(dir)) {
|
|
9
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
fs.writeFileSync(filePath, content);
|
|
13
|
+
console.log(`ā Created ${filePath.replace(process.cwd() + path.sep, "")}`);
|
|
14
|
+
} else {
|
|
15
|
+
console.log(`ā Already exists: ${filePath.replace(process.cwd() + path.sep, "")}`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function createFolder(folderPath) {
|
|
20
|
+
if (!fs.existsSync(folderPath)) {
|
|
21
|
+
fs.mkdirSync(folderPath, { recursive: true });
|
|
22
|
+
console.log(`ā Created /${path.relative(process.cwd(), folderPath).replace(/\\/g, "/")}`);
|
|
23
|
+
} else {
|
|
24
|
+
console.log(`ā /${path.relative(process.cwd(), folderPath).replace(/\\/g, "/")} already exists`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports = {
|
|
29
|
+
safeWrite,
|
|
30
|
+
createFolder
|
|
31
|
+
};
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "docstra",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.9",
|
|
4
4
|
"bin": {
|
|
5
5
|
"docstra": "cli/index.js"
|
|
6
6
|
},
|
|
7
7
|
"description": "The Modern Documentation Framework for Next.js",
|
|
8
8
|
"files": [
|
|
9
|
-
"dist"
|
|
9
|
+
"dist",
|
|
10
|
+
"cli"
|
|
10
11
|
],
|
|
11
12
|
"exports": {
|
|
12
13
|
".": {
|