@writedocs/generator 0.1.0 → 0.2.1

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,17 +1,28 @@
1
- # Writedocs
2
-
3
- A static site generator for documentation: a `writedocs.json` config + a folder of MDX/Markdown in, a fully static site out. Built on [Astro](https://astro.build), in the spirit of Docusaurus/Mintlify.
4
-
5
- ## Quickstart
6
-
7
- ```bash
8
- npm install -g @writedocs/generator
9
-
10
- cd my-docs # any folder containing writedocs.json + docs/
11
- writedocs dev
12
- writedocs build
13
- ```
14
-
15
- The npm package is `@writedocs/generator`; the CLI command it installs is still `writedocs` (see the `bin` field in `package.json`).
16
-
17
- `npx @writedocs/generator init/dev/build` still works too, for a one-off run with no install at all.
1
+ # Writedocs
2
+
3
+ A static site generator for documentation: a `writedocs.json` config + a folder of MDX/Markdown in, a fully static site out. Built on [Astro](https://astro.build), in the spirit of Docusaurus/Mintlify.
4
+
5
+ ## Quickstart
6
+
7
+ ```bash
8
+ npm install -g @writedocs/generator
9
+
10
+ cd my-docs # any folder containing writedocs.json + docs/
11
+ writedocs dev
12
+ writedocs validate
13
+ writedocs build
14
+ ```
15
+
16
+ ## Commands
17
+
18
+ | Command | What it does |
19
+ |---|---|
20
+ | `writedocs init [dir]` | Scaffolds a `writedocs.json` and a starter `docs/` folder. |
21
+ | `writedocs dev [dir]` | Starts a local dev server with hot reload. |
22
+ | `writedocs validate [dir]` | Checks `<dir>/writedocs.json` against the schema. Exits `0` when it is valid and `1` when it is not, so it can gate a CI job; prints one line per problem, in the same words the build uses. Runs entirely locally — no key, no network. Configuration only: it does not resolve OpenAPI specs, and it does not check that the pages named in `navigation` exist. |
23
+
24
+ `[dir]` defaults to the current directory in every command.
25
+
26
+ The npm package is `@writedocs/generator`; the CLI command it installs is still `writedocs` (see the `bin` field in `package.json`).
27
+
28
+ `npx @writedocs/generator init/dev/build` still works too, for a one-off run with no install at all.
package/bin/writedocs.js CHANGED
@@ -1,73 +1,119 @@
1
- #!/usr/bin/env node
2
- import { Command } from 'commander';
3
- import fs from 'node:fs';
4
- import path from 'node:path';
5
- import { fileURLToPath } from 'node:url';
6
- import dotenv from 'dotenv';
7
- import { runDev } from '../src/cli/dev.js';
8
- import { runBuild } from '../src/cli/build.js';
9
- import { runInit } from '../src/cli/init.js';
10
- import { requireBuildKey } from '../src/cli/build-auth.js';
11
-
12
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
13
- const packageRoot = path.resolve(__dirname, '..');
14
- // Read rather than hardcode - a literal version string here silently drifts
15
- // from package.json's own "version" the moment either one is bumped without
16
- // the other (exactly what `npm version <bump>` does: it only touches
17
- // package.json). `writedocs --version` should always reflect what actually
18
- // got published, not whatever this string happened to say at the time this
19
- // line was last hand-edited.
20
- const { version } = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf-8'));
21
-
22
- const program = new Command();
23
- program
24
- .name('writedocs')
25
- .description('Static site generator for writedocs.json + MDX')
26
- .version(version);
27
-
28
- program
29
- .command('dev')
30
- .description('Start a local dev server with hot reload')
31
- .argument('[dir]', 'content directory (contains writedocs.json and docs/)', '.')
32
- .option('-p, --port <port>', 'port to run on')
33
- .action(async (dir, opts) => {
34
- await runDev({
35
- contentDir: path.resolve(process.cwd(), dir),
36
- packageRoot,
37
- port: opts.port,
38
- });
39
- });
40
-
41
- program
42
- // { hidden: true } keeps `build` out of `writedocs --help` - it's not a
43
- // command ordinary users are meant to discover or run themselves. See
44
- // src/cli/build-auth.js for the second layer: even someone who knows the
45
- // command exists still can't run it without the right key.
46
- .command('build', { hidden: true })
47
- .description('Build a static site into <dir>/dist')
48
- .argument('[dir]', 'content directory (contains writedocs.json and docs/)', '.')
49
- .option('-k, --key <key>', 'build authorization key (or set WRITEDOCS_API_KEY)')
50
- .action(async (dir, opts) => {
51
- const contentDir = path.resolve(process.cwd(), dir);
52
- // Project-scoped, not global: a .env sitting next to this project's own
53
- // writedocs.json (WRITEDOCS_KEY_SERVER_URL, WRITEDOCS_API_KEY) is picked
54
- // up automatically, so build doesn't need those exported by hand every
55
- // session. dotenv never overwrites a var already set in the real
56
- // environment - an explicit `export`/CI secret still wins over the file.
57
- dotenv.config({ path: path.join(contentDir, '.env'), quiet: true });
58
- await requireBuildKey(opts.key || process.env.WRITEDOCS_API_KEY);
59
- await runBuild({ contentDir, packageRoot });
60
- });
61
-
62
- program
63
- .command('init')
64
- .description('Scaffold a writedocs.json and starter docs/ folder')
65
- .argument('[dir]', 'directory to scaffold into', '.')
66
- .action(async (dir) => {
67
- await runInit({ targetDir: path.resolve(process.cwd(), dir) });
68
- });
69
-
70
- program.parseAsync(process.argv).catch((err) => {
71
- console.error(`[writedocs] ${err.message}`);
72
- process.exit(1);
73
- });
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import dotenv from 'dotenv';
7
+ import { runDev } from '../src/cli/dev.js';
8
+ import { runBuild } from '../src/cli/build.js';
9
+ import { runInit } from '../src/cli/init.js';
10
+ import { requireBuildKey } from '../src/cli/build-auth.js';
11
+ // O MESMO modulo que o build usa (via loadDocsConfig, que reexporta daqui) e
12
+ // que a plataforma importa por `@writedocs/generator/config-schema` - e o que
13
+ // faz os tres reportarem os mesmos problemas com as mesmas palavras, em vez de
14
+ // cada um manter a sua copia do schema.
15
+ //
16
+ // `.js`, e nao o `.ts` que e a fonte de verdade: este arquivo e carregado por
17
+ // node puro, sem o transform do Astro/Vite, e o Node RECUSA type stripping para
18
+ // qualquer arquivo sob node_modules - por desenho, em qualquer versao
19
+ // (ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING). Ou seja: importar o `.ts` aqui
20
+ // funciona a partir do checkout e falha 100% das vezes para quem instala o
21
+ // pacote, que foi exatamente o que quebrou o `validate` no 0.2.0. O `.js` e
22
+ // gerado do `.ts` pelo script `prepare` (package.json), entao ele existe tanto
23
+ // no checkout quanto dentro do tarball, e o consumidor nao roda build nenhum.
24
+ // Ver a mesma regra ja escrita em src/cli/write-redirects-file.js.
25
+ import { validateDocsConfig, formatValidationIssues } from '../src/lib/config-schema.js';
26
+
27
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
28
+ const packageRoot = path.resolve(__dirname, '..');
29
+ // Read rather than hardcode - a literal version string here silently drifts
30
+ // from package.json's own "version" the moment either one is bumped without
31
+ // the other (exactly what `npm version <bump>` does: it only touches
32
+ // package.json). `writedocs --version` should always reflect what actually
33
+ // got published, not whatever this string happened to say at the time this
34
+ // line was last hand-edited.
35
+ const { version } = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf-8'));
36
+
37
+ const program = new Command();
38
+ program
39
+ .name('writedocs')
40
+ .description('Static site generator for writedocs.json + MDX')
41
+ .version(version);
42
+
43
+ program
44
+ .command('dev')
45
+ .description('Start a local dev server with hot reload')
46
+ .argument('[dir]', 'content directory (contains writedocs.json and docs/)', '.')
47
+ .option('-p, --port <port>', 'port to run on')
48
+ .action(async (dir, opts) => {
49
+ await runDev({
50
+ contentDir: path.resolve(process.cwd(), dir),
51
+ packageRoot,
52
+ port: opts.port,
53
+ });
54
+ });
55
+
56
+ program
57
+ // { hidden: true } keeps `build` out of `writedocs --help` - it's not a
58
+ // command ordinary users are meant to discover or run themselves. See
59
+ // src/cli/build-auth.js for the second layer: even someone who knows the
60
+ // command exists still can't run it without the right key.
61
+ .command('build', { hidden: true })
62
+ .description('Build a static site into <dir>/dist')
63
+ .argument('[dir]', 'content directory (contains writedocs.json and docs/)', '.')
64
+ .option('-k, --key <key>', 'build authorization key (or set WRITEDOCS_API_KEY)')
65
+ .action(async (dir, opts) => {
66
+ const contentDir = path.resolve(process.cwd(), dir);
67
+ // Project-scoped, not global: a .env sitting next to this project's own
68
+ // writedocs.json (WRITEDOCS_KEY_SERVER_URL, WRITEDOCS_API_KEY) is picked
69
+ // up automatically, so build doesn't need those exported by hand every
70
+ // session. dotenv never overwrites a var already set in the real
71
+ // environment - an explicit `export`/CI secret still wins over the file.
72
+ dotenv.config({ path: path.join(contentDir, '.env'), quiet: true });
73
+ await requireBuildKey(opts.key || process.env.WRITEDOCS_API_KEY);
74
+ await runBuild({ contentDir, packageRoot });
75
+ });
76
+
77
+ program
78
+ // Visivel, ao contrario do `build`: validar a propria configuracao e
79
+ // exatamente o tipo de coisa que um usuario deve poder rodar sozinho, no CI
80
+ // inclusive. Sem chave, sem dotenv, sem rede - le um arquivo e sai 0 ou 1.
81
+ .command('validate')
82
+ .description('Validate writedocs.json against the schema')
83
+ .argument('[dir]', 'content directory (contains writedocs.json)', '.')
84
+ .action(async (dir) => {
85
+ const contentDir = path.resolve(process.cwd(), dir);
86
+ const configPath = path.join(contentDir, 'writedocs.json');
87
+ if (!fs.existsSync(configPath)) {
88
+ // Mesma mensagem que loadDocsConfig() ja da pro mesmo caso.
89
+ console.error(
90
+ `[writedocs] writedocs.json not found at ${configPath}. Run "writedocs init" to scaffold one.`
91
+ );
92
+ process.exit(1);
93
+ }
94
+
95
+ const result = validateDocsConfig(fs.readFileSync(configPath, 'utf-8'));
96
+ if (result.ok) {
97
+ console.log(`[writedocs] ${configPath} is valid.`);
98
+ return;
99
+ }
100
+
101
+ // Mesmo formato que o build imprime num config invalido - mesmo texto,
102
+ // mesma ordem, montado pelo mesmo formatador.
103
+ console.error('[writedocs] writedocs.json failed validation:');
104
+ console.error(formatValidationIssues(result.issues));
105
+ process.exit(1);
106
+ });
107
+
108
+ program
109
+ .command('init')
110
+ .description('Scaffold a writedocs.json and starter docs/ folder')
111
+ .argument('[dir]', 'directory to scaffold into', '.')
112
+ .action(async (dir) => {
113
+ await runInit({ targetDir: path.resolve(process.cwd(), dir) });
114
+ });
115
+
116
+ program.parseAsync(process.argv).catch((err) => {
117
+ console.error(`[writedocs] ${err.message}`);
118
+ process.exit(1);
119
+ });
package/package.json CHANGED
@@ -1,79 +1,85 @@
1
- {
2
- "name": "@writedocs/generator",
3
- "version": "0.1.0",
4
- "description": "Static site generator for docs — a writedocs.json + MDX folder in, a static site out.",
5
- "type": "module",
6
- "bin": {
7
- "writedocs": "./bin/writedocs.js"
8
- },
9
- "exports": {
10
- "./components": "./src/components/index.ts"
11
- },
12
- "files": [
13
- "bin",
14
- "src",
15
- "astro.config.mjs"
16
- ],
17
- "scripts": {
18
- "dev": "node bin/writedocs.js dev",
19
- "build": "node bin/writedocs.js build",
20
- "init": "node bin/writedocs.js init"
21
- },
22
- "keywords": [
23
- "docs",
24
- "documentation",
25
- "static-site-generator",
26
- "mdx",
27
- "astro"
28
- ],
29
- "homepage": "https://github.com/writedocs/writedocs#readme",
30
- "repository": {
31
- "type": "git",
32
- "url": "git+https://github.com/writedocs/writedocs.git"
33
- },
34
- "bugs": {
35
- "url": "https://github.com/writedocs/writedocs/issues"
36
- },
37
- "author": "Gabriel Raeder",
38
- "license": "ISC",
39
- "publishConfig": {
40
- "access": "public"
41
- },
42
- "dependencies": {
43
- "@apidevtools/swagger-parser": "^12.1.0",
44
- "@astrojs/markdown-remark": "7.2.2",
45
- "@astrojs/mdx": "^7.0.5",
46
- "@astrojs/react": "^6.0.2",
47
- "@astrojs/sitemap": "^3.7.3",
48
- "@iconify-json/bi": "^1.2.7",
49
- "@iconify-json/fa6-brands": "^1.2.6",
50
- "@iconify-json/fa6-solid": "^1.2.4",
51
- "@iconify-json/heroicons": "^1.2.3",
52
- "@iconify-json/ion": "^1.2.7",
53
- "@iconify-json/lucide": "^1.2.116",
54
- "@iconify-json/mdi": "^1.2.3",
55
- "@iconify-json/ri": "^1.2.10",
56
- "@iconify-json/simple-icons": "^1.2.89",
57
- "@iconify-json/tabler": "^1.2.35",
58
- "@shikijs/transformers": "^4.3.1",
59
- "@tailwindcss/vite": "^4.3.2",
60
- "astro": "^7.2.2",
61
- "astro-icon": "^1.1.5",
62
- "commander": "^15.0.0",
63
- "dotenv": "^17.4.2",
64
- "gray-matter": "^4.0.3",
65
- "katex": "^0.16.47",
66
- "mermaid": "^11.16.0",
67
- "pagefind": "^1.5.2",
68
- "react": "^19.2.8",
69
- "react-dom": "^19.2.8",
70
- "rehype-katex": "^7.0.1",
71
- "remark-math": "^6.0.0",
72
- "shiki": "^4.3.1",
73
- "tailwindcss": "^4.3.2",
74
- "zod": "^4.4.3"
75
- },
76
- "engines": {
77
- "node": ">=20.3.0"
78
- }
79
- }
1
+ {
2
+ "name": "@writedocs/generator",
3
+ "version": "0.2.1",
4
+ "description": "Static site generator for docs — a writedocs.json + MDX folder in, a static site out.",
5
+ "type": "module",
6
+ "bin": {
7
+ "writedocs": "./bin/writedocs.js"
8
+ },
9
+ "exports": {
10
+ "./components": "./src/components/index.ts",
11
+ "./config-schema": "./src/lib/config-schema.js"
12
+ },
13
+ "files": [
14
+ "bin",
15
+ "src",
16
+ "astro.config.mjs"
17
+ ],
18
+ "scripts": {
19
+ "dev": "node bin/writedocs.js dev",
20
+ "build": "node bin/writedocs.js build",
21
+ "init": "node bin/writedocs.js init",
22
+ "build:schema": "esbuild src/lib/config-schema.ts --format=esm --target=node22 --outfile=src/lib/config-schema.js",
23
+ "prepare": "npm run build:schema"
24
+ },
25
+ "keywords": [
26
+ "docs",
27
+ "documentation",
28
+ "static-site-generator",
29
+ "mdx",
30
+ "astro"
31
+ ],
32
+ "homepage": "https://github.com/writedocs/writedocs#readme",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/writedocs/writedocs.git"
36
+ },
37
+ "bugs": {
38
+ "url": "https://github.com/writedocs/writedocs/issues"
39
+ },
40
+ "author": "Gabriel Raeder",
41
+ "license": "ISC",
42
+ "publishConfig": {
43
+ "access": "public"
44
+ },
45
+ "dependencies": {
46
+ "@apidevtools/swagger-parser": "^12.1.0",
47
+ "@astrojs/markdown-remark": "7.2.2",
48
+ "@astrojs/mdx": "^7.0.5",
49
+ "@astrojs/react": "^6.0.2",
50
+ "@astrojs/sitemap": "^3.7.3",
51
+ "@iconify-json/bi": "^1.2.7",
52
+ "@iconify-json/fa6-brands": "^1.2.6",
53
+ "@iconify-json/fa6-solid": "^1.2.4",
54
+ "@iconify-json/heroicons": "^1.2.3",
55
+ "@iconify-json/ion": "^1.2.7",
56
+ "@iconify-json/lucide": "^1.2.116",
57
+ "@iconify-json/mdi": "^1.2.3",
58
+ "@iconify-json/ri": "^1.2.10",
59
+ "@iconify-json/simple-icons": "^1.2.89",
60
+ "@iconify-json/tabler": "^1.2.35",
61
+ "@shikijs/transformers": "^4.3.1",
62
+ "@tailwindcss/vite": "^4.3.2",
63
+ "astro": "7.2.2",
64
+ "astro-icon": "^1.1.5",
65
+ "commander": "^15.0.0",
66
+ "dotenv": "^17.4.2",
67
+ "gray-matter": "^4.0.3",
68
+ "katex": "^0.16.47",
69
+ "mermaid": "^11.16.0",
70
+ "pagefind": "^1.5.2",
71
+ "react": "^19.2.8",
72
+ "react-dom": "^19.2.8",
73
+ "rehype-katex": "^7.0.1",
74
+ "remark-math": "^6.0.0",
75
+ "shiki": "^4.3.1",
76
+ "tailwindcss": "^4.3.2",
77
+ "zod": "^4.4.3"
78
+ },
79
+ "engines": {
80
+ "node": ">=22.12.0"
81
+ },
82
+ "devDependencies": {
83
+ "esbuild": "0.28.2"
84
+ }
85
+ }