@knowcode/doc-builder 1.0.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/lib/deploy.js ADDED
@@ -0,0 +1,158 @@
1
+ const chalk = require('chalk');
2
+ const prompts = require('prompts');
3
+ const { execSync } = require('child_process');
4
+ const fs = require('fs-extra');
5
+ const path = require('path');
6
+
7
+ /**
8
+ * Setup Vercel project for first-time deployment
9
+ */
10
+ async function setupVercelProject(config) {
11
+ console.log(chalk.blue('\nšŸ“‹ Setting up Vercel project...\n'));
12
+
13
+ // Check if Vercel CLI is installed
14
+ try {
15
+ execSync('vercel --version', { stdio: 'ignore' });
16
+ } catch (error) {
17
+ console.log(chalk.red('āŒ Vercel CLI not found!'));
18
+ console.log(chalk.gray('Install it with: npm install -g vercel'));
19
+ process.exit(1);
20
+ }
21
+
22
+ // Project setup questions
23
+ const answers = await prompts([
24
+ {
25
+ type: 'text',
26
+ name: 'projectName',
27
+ message: 'What is your project name?',
28
+ initial: config.siteName || 'my-docs'
29
+ },
30
+ {
31
+ type: 'select',
32
+ name: 'framework',
33
+ message: 'Which framework preset?',
34
+ choices: [
35
+ { title: 'Other (Static HTML)', value: 'other' },
36
+ { title: 'Next.js', value: 'nextjs' },
37
+ { title: 'Vite', value: 'vite' }
38
+ ],
39
+ initial: 0
40
+ },
41
+ {
42
+ type: 'confirm',
43
+ name: 'publicAccess',
44
+ message: 'Make the deployment publicly accessible?',
45
+ initial: true
46
+ }
47
+ ]);
48
+
49
+ // Create vercel.json if it doesn't exist
50
+ const vercelConfigPath = path.join(process.cwd(), 'vercel.json');
51
+ if (!fs.existsSync(vercelConfigPath)) {
52
+ const vercelConfig = {
53
+ outputDirectory: config.outputDir || 'html',
54
+ framework: answers.framework === 'other' ? null : answers.framework,
55
+ buildCommand: "npm run build:docs",
56
+ devCommand: "npm run dev:docs",
57
+ installCommand: "npm install",
58
+ public: answers.publicAccess
59
+ };
60
+
61
+ fs.writeJsonSync(vercelConfigPath, vercelConfig, { spaces: 2 });
62
+ console.log(chalk.green('āœ… Created vercel.json'));
63
+ }
64
+
65
+ // Run Vercel setup
66
+ console.log(chalk.blue('\nšŸ”— Linking to Vercel...\n'));
67
+
68
+ try {
69
+ execSync('vercel link', { stdio: 'inherit' });
70
+ } catch (error) {
71
+ console.error(chalk.red('Failed to link Vercel project'));
72
+ process.exit(1);
73
+ }
74
+
75
+ // Important reminders for Vercel settings
76
+ console.log(chalk.yellow('\nāš ļø IMPORTANT: Vercel Project Settings\n'));
77
+ console.log(chalk.white('After deployment, go to your Vercel dashboard and:'));
78
+ console.log(chalk.gray('1. Navigate to Project Settings > General'));
79
+ console.log(chalk.gray('2. Under "Security", find "Deployment Protection"'));
80
+ console.log(chalk.gray('3. Set "Deployment Protection" to "Disabled" for public access'));
81
+ console.log(chalk.gray('4. Or configure authentication if you want to keep it private'));
82
+ console.log();
83
+ console.log(chalk.cyan('Dashboard URL: https://vercel.com/dashboard'));
84
+ console.log();
85
+
86
+ // Add .vercel to .gitignore if not already there
87
+ const gitignorePath = path.join(process.cwd(), '.gitignore');
88
+ if (fs.existsSync(gitignorePath)) {
89
+ const gitignore = fs.readFileSync(gitignorePath, 'utf8');
90
+ if (!gitignore.includes('.vercel')) {
91
+ fs.appendFileSync(gitignorePath, '\n# Vercel\n.vercel\n');
92
+ console.log(chalk.green('āœ… Added .vercel to .gitignore'));
93
+ }
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Deploy to Vercel
99
+ */
100
+ async function deployToVercel(config, isProd = false) {
101
+ // Ensure the build output exists
102
+ const outputPath = path.join(process.cwd(), config.outputDir || 'html');
103
+ if (!fs.existsSync(outputPath)) {
104
+ throw new Error(`Output directory ${outputPath} does not exist. Run 'doc-builder build' first.`);
105
+ }
106
+
107
+ // Deploy command
108
+ const deployCmd = isProd ? 'vercel --prod' : 'vercel';
109
+
110
+ try {
111
+ // Run deployment and capture output
112
+ const output = execSync(deployCmd, {
113
+ cwd: process.cwd(),
114
+ encoding: 'utf8'
115
+ });
116
+
117
+ // Extract URL from output
118
+ const urlMatch = output.match(/https:\/\/[^\s]+/);
119
+ const deployUrl = urlMatch ? urlMatch[0] : 'Check Vercel dashboard';
120
+
121
+ return deployUrl;
122
+ } catch (error) {
123
+ throw new Error(`Vercel deployment failed: ${error.message}`);
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Create deployment-specific files
129
+ */
130
+ async function prepareDeployment(config) {
131
+ const outputDir = path.join(process.cwd(), config.outputDir || 'html');
132
+
133
+ // Create a simple index redirect if needed
134
+ const indexPath = path.join(outputDir, 'index.html');
135
+ if (!fs.existsSync(indexPath)) {
136
+ const readmePath = path.join(outputDir, 'README.html');
137
+ if (fs.existsSync(readmePath)) {
138
+ // Create redirect
139
+ const redirectHtml = `<!DOCTYPE html>
140
+ <html>
141
+ <head>
142
+ <meta http-equiv="refresh" content="0; url=README.html">
143
+ <title>Redirecting...</title>
144
+ </head>
145
+ <body>
146
+ <p>Redirecting to <a href="README.html">documentation</a>...</p>
147
+ </body>
148
+ </html>`;
149
+ fs.writeFileSync(indexPath, redirectHtml);
150
+ }
151
+ }
152
+ }
153
+
154
+ module.exports = {
155
+ setupVercelProject,
156
+ deployToVercel,
157
+ prepareDeployment
158
+ };
@@ -0,0 +1,96 @@
1
+ const http = require('http');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const chalk = require('chalk');
5
+
6
+ /**
7
+ * Simple development server
8
+ */
9
+ async function startDevServer(config, port = 3000) {
10
+ const outputDir = path.join(process.cwd(), config.outputDir);
11
+
12
+ if (!fs.existsSync(outputDir)) {
13
+ console.log(chalk.yellow('Output directory not found. Building first...'));
14
+ const { build } = require('./builder');
15
+ await build(config);
16
+ }
17
+
18
+ const server = http.createServer((req, res) => {
19
+ let filePath = path.join(outputDir, req.url === '/' ? 'index.html' : req.url);
20
+
21
+ // Add .html extension if not present and not a file with extension
22
+ if (!path.extname(filePath) && !filePath.endsWith('/')) {
23
+ filePath += '.html';
24
+ }
25
+
26
+ // Serve index.html for directories
27
+ if (filePath.endsWith('/')) {
28
+ filePath += 'index.html';
29
+ }
30
+
31
+ fs.readFile(filePath, (err, content) => {
32
+ if (err) {
33
+ if (err.code === 'ENOENT') {
34
+ res.writeHead(404);
35
+ res.end('404 Not Found');
36
+ } else {
37
+ res.writeHead(500);
38
+ res.end(`Server Error: ${err.code}`);
39
+ }
40
+ } else {
41
+ // Determine content type
42
+ const ext = path.extname(filePath);
43
+ let contentType = 'text/html';
44
+ switch (ext) {
45
+ case '.js':
46
+ contentType = 'text/javascript';
47
+ break;
48
+ case '.css':
49
+ contentType = 'text/css';
50
+ break;
51
+ case '.json':
52
+ contentType = 'application/json';
53
+ break;
54
+ case '.png':
55
+ contentType = 'image/png';
56
+ break;
57
+ case '.jpg':
58
+ contentType = 'image/jpg';
59
+ break;
60
+ }
61
+
62
+ res.writeHead(200, { 'Content-Type': contentType });
63
+ res.end(content, 'utf-8');
64
+ }
65
+ });
66
+ });
67
+
68
+ server.listen(port, () => {
69
+ console.log(chalk.green(`\nšŸ“” Development server running at: ${chalk.cyan(`http://localhost:${port}`)}\n`));
70
+ console.log(chalk.gray('Press Ctrl+C to stop'));
71
+ });
72
+
73
+ // Watch for changes (basic implementation)
74
+ if (config.watch !== false) {
75
+ const docsDir = path.join(process.cwd(), config.docsDir);
76
+ console.log(chalk.gray(`Watching for changes in ${config.docsDir}...`));
77
+
78
+ // Simple file watcher - in production, use chokidar
79
+ fs.watch(docsDir, { recursive: true }, async (eventType, filename) => {
80
+ if (filename && filename.endsWith('.md')) {
81
+ console.log(chalk.yellow(`\nšŸ”„ ${filename} changed, rebuilding...`));
82
+ try {
83
+ const { build } = require('./builder');
84
+ await build(config);
85
+ console.log(chalk.green('āœ… Rebuild complete'));
86
+ } catch (error) {
87
+ console.error(chalk.red(`āŒ Rebuild failed: ${error.message}`));
88
+ }
89
+ }
90
+ });
91
+ }
92
+ }
93
+
94
+ module.exports = {
95
+ startDevServer
96
+ };
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@knowcode/doc-builder",
3
+ "version": "1.0.0",
4
+ "description": "Reusable documentation builder for markdown-based sites with Vercel deployment support",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "doc-builder": "./cli.js",
8
+ "juno-docs": "./cli.js",
9
+ "@knowcode/doc-builder": "./scripts/npx-runner.js"
10
+ },
11
+ "scripts": {
12
+ "postinstall": "node scripts/setup.js || true",
13
+ "test": "echo \"Error: no test specified\" && exit 1"
14
+ },
15
+ "keywords": [
16
+ "documentation",
17
+ "markdown",
18
+ "static-site-generator",
19
+ "vercel",
20
+ "juno"
21
+ ],
22
+ "author": "KnowCode",
23
+ "license": "MIT",
24
+ "dependencies": {
25
+ "marked": "^15.0.12",
26
+ "commander": "^11.0.0",
27
+ "chalk": "^4.1.2",
28
+ "prompts": "^2.4.2",
29
+ "ora": "5.4.1",
30
+ "fs-extra": "^11.2.0"
31
+ },
32
+ "engines": {
33
+ "node": ">=14.0.0"
34
+ }
35
+ }
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * NPX runner script for @knowcode/doc-builder
5
+ * This script enables zero-configuration usage via npx
6
+ */
7
+
8
+ const { execSync } = require('child_process');
9
+ const path = require('path');
10
+ const fs = require('fs');
11
+
12
+ // Get the command from arguments
13
+ const [,, command = 'build', ...args] = process.argv;
14
+
15
+ // Path to the actual CLI
16
+ const cliPath = path.join(__dirname, '..', 'cli.js');
17
+
18
+ // Build the command
19
+ const fullCommand = `node "${cliPath}" ${command} ${args.join(' ')}`;
20
+
21
+ try {
22
+ // Execute the CLI with stdio inherited to preserve colors and interactivity
23
+ execSync(fullCommand, { stdio: 'inherit' });
24
+ } catch (error) {
25
+ // Exit with the same code as the CLI
26
+ process.exit(error.status || 1);
27
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Post-install setup script for @juno/doc-builder
3
+ * This script runs after npm install to help users get started
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+ const chalk = require('chalk');
9
+
10
+ // Check if we're in the doc-builder package itself (skip setup)
11
+ const packagePath = path.join(process.cwd(), 'package.json');
12
+ if (fs.existsSync(packagePath)) {
13
+ const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
14
+ if (pkg.name === '@knowcode/doc-builder') {
15
+ // We're in the doc-builder package itself, skip setup
16
+ process.exit(0);
17
+ }
18
+ }
19
+
20
+ console.log(chalk.cyan('\nšŸš€ Welcome to @knowcode/doc-builder!\n'));
21
+
22
+ console.log('You can use doc-builder in several ways:\n');
23
+
24
+ console.log(chalk.yellow('1. Using npx (no installation required):'));
25
+ console.log(' npx @knowcode/doc-builder build');
26
+ console.log(' npx @knowcode/doc-builder dev');
27
+ console.log(' npx @knowcode/doc-builder deploy\n');
28
+
29
+ console.log(chalk.yellow('2. After installing as a dependency:'));
30
+ console.log(' doc-builder build');
31
+ console.log(' doc-builder dev');
32
+ console.log(' doc-builder deploy\n');
33
+
34
+ console.log(chalk.yellow('3. In your package.json scripts:'));
35
+ console.log(chalk.gray(' "scripts": {'));
36
+ console.log(chalk.gray(' "docs:build": "doc-builder build",'));
37
+ console.log(chalk.gray(' "docs:dev": "doc-builder dev",'));
38
+ console.log(chalk.gray(' "docs:deploy": "doc-builder deploy --prod"'));
39
+ console.log(chalk.gray(' }\n'));
40
+
41
+ console.log(chalk.yellow('4. Programmatically in your code:'));
42
+ console.log(chalk.gray(' const { build } = require("@knowcode/doc-builder");'));
43
+ console.log(chalk.gray(' await build();\n'));
44
+
45
+ // Check for common doc directories
46
+ const commonDirs = ['docs', 'documentation', 'doc'];
47
+ const foundDir = commonDirs.find(dir => fs.existsSync(path.join(process.cwd(), dir)));
48
+
49
+ if (foundDir) {
50
+ console.log(chalk.green(`āœ… Found ${foundDir}/ directory - doc-builder will use this by default\n`));
51
+ } else {
52
+ console.log(chalk.yellow(`ā„¹ļø No docs directory found. Create a 'docs' folder with markdown files to get started.\n`));
53
+ }
54
+
55
+ console.log(chalk.gray('For more information, visit: https://github.com/juno-platform/doc-builder'));
56
+ console.log(chalk.gray('To create a config file, run: doc-builder init --config\n'));