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.
@@ -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,8 @@
1
+ module.exports = `import { defaultMdxComponents } from "docstra/server";
2
+ import { DocstraCodeBlock } from "docstra";
3
+
4
+ export const mdxComponents = {
5
+ ...defaultMdxComponents,
6
+ code: DocstraCodeBlock
7
+ };
8
+ `;
@@ -0,0 +1,7 @@
1
+ module.exports = `import type { NextConfig } from "next";
2
+ import { withDocstra } from "docstra/server";
3
+
4
+ const nextConfig: NextConfig = {};
5
+
6
+ export default withDocstra(nextConfig);
7
+ `;
@@ -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
+ `;
@@ -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.8",
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
  ".": {