@axerity/cli 0.1.0 → 0.1.2

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 +1,97 @@
1
1
  # Axerity
2
+
3
+ A documentation site generator built with SvelteKit. Write Markdown, configure
4
+ one JSON file, and ship a fast static site.
5
+
6
+ ## Quick start
7
+
8
+ ```sh
9
+ pnpm dlx @axerity/cli init mydocs
10
+ cd mydocs
11
+ pnpm dlx @axerity/cli dev
12
+ ```
13
+
14
+ That scaffolds a content-only project and starts a live dev server at
15
+ `http://localhost:5173`.
16
+
17
+ ```
18
+ mydocs/
19
+ axerity.json # all configuration
20
+ docs/ # your Markdown
21
+ meta.json # ordering and icons per folder
22
+ index.md
23
+ quickstart.md
24
+ ```
25
+
26
+ ## Install
27
+
28
+ Run it without installing:
29
+
30
+ ```sh
31
+ pnpm dlx @axerity/cli <command>
32
+ ```
33
+
34
+ Or add it to a project so the version is pinned and reproducible:
35
+
36
+ ```sh
37
+ pnpm add -D @axerity/cli
38
+ ```
39
+
40
+ ```json
41
+ {
42
+ "scripts": {
43
+ "dev": "axerity dev",
44
+ "build": "axerity build",
45
+ "preview": "axerity preview"
46
+ }
47
+ }
48
+ ```
49
+
50
+ ## Commands
51
+
52
+ | Command | What it does |
53
+ | ----------------- | ------------------------------------- |
54
+ | `axerity init` | Scaffold a new docs site |
55
+ | `axerity dev` | Start the dev server with live reload |
56
+ | `axerity build` | Build a static site into `./build` |
57
+ | `axerity preview` | Serve the production build locally |
58
+
59
+ The build output is a plain static site you can host anywhere: Vercel, Netlify,
60
+ Cloudflare, GitHub Pages, nginx, or any static host.
61
+
62
+ ## Features
63
+
64
+ - Markdown with a built in component kit: callouts, cards, tabs, steps,
65
+ accordions, code groups, badges, trees, frames, and more
66
+ - API references generated from an OpenAPI spec, plus webhook and WebSocket
67
+ components
68
+ - Versioned content with a switcher that follows the reader across versions
69
+ - Themes, custom brand colors, and full white labelling from `axerity.json`
70
+ - Build time search, an RSS feed, sitemap, `llms.txt`, and dynamic OpenGraph
71
+ images
72
+ - Mermaid diagrams, Twoslash type hovers, and syntax highlighting
73
+
74
+ ## Configuration
75
+
76
+ Everything global lives in `axerity.json`. A few of the common keys:
77
+
78
+ ```json
79
+ {
80
+ "$schema": "https://axerity.com/axerity.schema.json",
81
+ "name": "My Docs",
82
+ "theme": "neutral",
83
+ "openapi": "./openapi.json",
84
+ "topNav": [{ "title": "Docs", "href": "/" }]
85
+ }
86
+ ```
87
+
88
+ Point `$schema` at the bundled JSON schema for autocomplete and validation in
89
+ your editor.
90
+
91
+ ## Requirements
92
+
93
+ Node.js 24 or newer.
94
+
95
+ ## License
96
+
97
+ MIT
package/bin/axerity.js CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { spawn, spawnSync } from 'node:child_process';
3
+ import { createRequire } from 'node:module';
3
4
  import { fileURLToPath } from 'node:url';
4
5
  import {
5
6
  cpSync,
@@ -20,9 +21,14 @@ const isEngineRepo = userRoot === engineRoot;
20
21
 
21
22
  const symlinkType = process.platform === 'win32' ? 'junction' : 'dir';
22
23
 
23
- // The engine runs in place, from its own install with its real node_modules. The
24
- // user's project is mounted into a handful of gitignored paths for a single run,
25
- // so nothing the engine tracks is ever touched — clean exit, Ctrl-C, or crash.
24
+ const require = createRequire(import.meta.url);
25
+ function viteBin() {
26
+ const pkgPath = require.resolve('vite/package.json');
27
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
28
+ const rel = typeof pkg.bin === 'string' ? pkg.bin : pkg.bin.vite;
29
+ return resolve(dirname(pkgPath), rel);
30
+ }
31
+
26
32
  const ENGINE_DOCS = join(engineRoot, 'src', 'content', 'docs');
27
33
  const ENGINE_CONFIG = join(engineRoot, 'axerity.json');
28
34
  const ENGINE_STATIC = join(engineRoot, 'static');
@@ -38,16 +44,12 @@ function findContentDir() {
38
44
  return null;
39
45
  }
40
46
 
41
- /** Reset the engine's own demo site into the mount points (for `axerity` runs
42
- * from inside the engine repo). `pnpm dev` does this via its pre-scripts. */
43
47
  function prepareEngine() {
44
48
  spawnSync(process.execPath, [join(engineRoot, 'scripts', 'prepare-engine.mjs')], {
45
49
  stdio: 'inherit'
46
50
  });
47
51
  }
48
52
 
49
- /** Copy local specs into a gitignored folder and rewrite the config to point at
50
- * them, so the user's spec paths resolve without touching the engine tree. */
51
53
  function mountSpecs(config) {
52
54
  const rewrite = (source) => {
53
55
  const spec = typeof source === 'string' ? source : source.spec;
@@ -66,19 +68,15 @@ function mountSpecs(config) {
66
68
  }
67
69
 
68
70
  function mount(contentDir) {
69
- // Content -> the path the engine globs, as symlinks so generated pages (an API
70
- // reference) can sit alongside without touching the user's repo.
71
71
  rmSync(ENGINE_DOCS, { recursive: true, force: true });
72
72
  mkdirSync(ENGINE_DOCS, { recursive: true });
73
73
  for (const entry of readdirSync(contentDir)) {
74
74
  symlinkSync(join(contentDir, entry), join(ENGINE_DOCS, entry), symlinkType);
75
75
  }
76
76
 
77
- // Config (with local spec paths rewritten into the gitignored specs folder).
78
77
  const config = JSON.parse(readFileSync(join(userRoot, 'axerity.json'), 'utf8'));
79
78
  writeFileSync(ENGINE_CONFIG, JSON.stringify(mountSpecs(config), null, '\t'));
80
79
 
81
- // Assets: engine defaults overlaid with the user's public/ folder.
82
80
  rmSync(ASSETS_DIR, { recursive: true, force: true });
83
81
  cpSync(ENGINE_STATIC, ASSETS_DIR, { recursive: true });
84
82
  const userPublic = join(userRoot, 'public');
@@ -106,7 +104,7 @@ const banner = (sub) => process.stdout.write(`\n ${mark} ${bold('axerity')} ${d
106
104
  const NOISE =
107
105
  /^\s*(VITE v|➜|press h|ready in|Local:|Network:|\[vite\].*(optimiz|dependencies)|\[optimizer\]|Forced re-opt|watching for file changes|use --host)/i;
108
106
 
109
- function streamServer(child, sub) {
107
+ function streamServer(child) {
110
108
  let shown = false;
111
109
  let buffer = '';
112
110
  const onData = (chunk) => {
@@ -130,7 +128,6 @@ function streamServer(child, sub) {
130
128
  child.stderr.on('data', onData);
131
129
  }
132
130
 
133
- /** A build: silent spinner on success, full captured output only on failure. */
134
131
  function streamBuild(child) {
135
132
  const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
136
133
  let i = 0;
@@ -152,8 +149,7 @@ function streamBuild(child) {
152
149
  }
153
150
 
154
151
  function runEngine(sub, extra, { mounted, onSuccess }) {
155
- const viteEntry = join(engineRoot, 'node_modules', 'vite', 'bin', 'vite.js');
156
- const child = spawn(process.execPath, [viteEntry, sub, ...extra], {
152
+ const child = spawn(process.execPath, [viteBin(), sub, ...extra], {
157
153
  cwd: engineRoot,
158
154
  stdio: ['inherit', 'pipe', 'pipe'],
159
155
  env: {
@@ -165,7 +161,7 @@ function runEngine(sub, extra, { mounted, onSuccess }) {
165
161
  });
166
162
 
167
163
  banner(sub);
168
- const build = sub === 'build' ? streamBuild(child) : (streamServer(child, sub), null);
164
+ const build = sub === 'build' ? streamBuild(child) : (streamServer(child), null);
169
165
 
170
166
  let cleaned = false;
171
167
  const cleanup = () => {
@@ -190,7 +186,6 @@ function runEngine(sub, extra, { mounted, onSuccess }) {
190
186
  }
191
187
 
192
188
  function run(sub, extra) {
193
- // Inside the engine repo: serve its own demo site.
194
189
  if (isEngineRepo) {
195
190
  prepareEngine();
196
191
  return runEngine(sub, extra, { mounted: false });
@@ -271,9 +266,11 @@ function init() {
271
266
  console.log(' axerity dev');
272
267
  }
273
268
 
269
+ const pkgVersion = () =>
270
+ JSON.parse(readFileSync(join(engineRoot, 'package.json'), 'utf8')).version;
271
+
274
272
  function help() {
275
- const { version } = JSON.parse(readFileSync(join(engineRoot, 'package.json'), 'utf8'));
276
- console.log(`Axerity ${version} — a documentation site generator\n`);
273
+ console.log(`Axerity ${pkgVersion()} a documentation site generator\n`);
277
274
  console.log('Usage: axerity <command>\n');
278
275
  console.log('Commands:');
279
276
  console.log(' init [dir] Scaffold a new docs site');
@@ -287,6 +284,11 @@ const command = process.argv[2];
287
284
  const extra = process.argv.slice(3);
288
285
 
289
286
  switch (command) {
287
+ case '--version':
288
+ case '-v':
289
+ case 'version':
290
+ console.log(pkgVersion());
291
+ break;
290
292
  case 'init':
291
293
  init();
292
294
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axerity/cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "A documentation site generator built with Svelte.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/vite.config.ts CHANGED
@@ -22,7 +22,7 @@ function openapi() {
22
22
  }
23
23
  await generateApiDocs(openapi, 'src/content/docs');
24
24
  } catch {
25
- // theres nothing
25
+ return;
26
26
  }
27
27
  };
28
28
  return {
@@ -42,5 +42,5 @@ function openapi() {
42
42
 
43
43
  export default defineConfig({
44
44
  plugins: [openapi(), tailwindcss(), sveltekit()],
45
- server: allow ? { fs: { allow: ['.', allow] } } : undefined
45
+ server: allow ? { fs: { strict: false } } : undefined
46
46
  });