@axerity/cli 0.1.1 → 0.1.3

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
@@ -29,9 +29,6 @@ function viteBin() {
29
29
  return resolve(dirname(pkgPath), rel);
30
30
  }
31
31
 
32
- // The engine runs in place, from its own install with its real node_modules. The
33
- // user's project is mounted into a handful of gitignored paths for a single run,
34
- // so nothing the engine tracks is ever touched — clean exit, Ctrl-C, or crash.
35
32
  const ENGINE_DOCS = join(engineRoot, 'src', 'content', 'docs');
36
33
  const ENGINE_CONFIG = join(engineRoot, 'axerity.json');
37
34
  const ENGINE_STATIC = join(engineRoot, 'static');
@@ -47,16 +44,12 @@ function findContentDir() {
47
44
  return null;
48
45
  }
49
46
 
50
- /** Reset the engine's own demo site into the mount points (for `axerity` runs
51
- * from inside the engine repo). `pnpm dev` does this via its pre-scripts. */
52
47
  function prepareEngine() {
53
48
  spawnSync(process.execPath, [join(engineRoot, 'scripts', 'prepare-engine.mjs')], {
54
49
  stdio: 'inherit'
55
50
  });
56
51
  }
57
52
 
58
- /** Copy local specs into a gitignored folder and rewrite the config to point at
59
- * them, so the user's spec paths resolve without touching the engine tree. */
60
53
  function mountSpecs(config) {
61
54
  const rewrite = (source) => {
62
55
  const spec = typeof source === 'string' ? source : source.spec;
@@ -75,19 +68,15 @@ function mountSpecs(config) {
75
68
  }
76
69
 
77
70
  function mount(contentDir) {
78
- // Content -> the path the engine globs, as symlinks so generated pages (an API
79
- // reference) can sit alongside without touching the user's repo.
80
71
  rmSync(ENGINE_DOCS, { recursive: true, force: true });
81
72
  mkdirSync(ENGINE_DOCS, { recursive: true });
82
73
  for (const entry of readdirSync(contentDir)) {
83
74
  symlinkSync(join(contentDir, entry), join(ENGINE_DOCS, entry), symlinkType);
84
75
  }
85
76
 
86
- // Config (with local spec paths rewritten into the gitignored specs folder).
87
77
  const config = JSON.parse(readFileSync(join(userRoot, 'axerity.json'), 'utf8'));
88
78
  writeFileSync(ENGINE_CONFIG, JSON.stringify(mountSpecs(config), null, '\t'));
89
79
 
90
- // Assets: engine defaults overlaid with the user's public/ folder.
91
80
  rmSync(ASSETS_DIR, { recursive: true, force: true });
92
81
  cpSync(ENGINE_STATIC, ASSETS_DIR, { recursive: true });
93
82
  const userPublic = join(userRoot, 'public');
@@ -115,7 +104,7 @@ const banner = (sub) => process.stdout.write(`\n ${mark} ${bold('axerity')} ${d
115
104
  const NOISE =
116
105
  /^\s*(VITE v|➜|press h|ready in|Local:|Network:|\[vite\].*(optimiz|dependencies)|\[optimizer\]|Forced re-opt|watching for file changes|use --host)/i;
117
106
 
118
- function streamServer(child, sub) {
107
+ function streamServer(child) {
119
108
  let shown = false;
120
109
  let buffer = '';
121
110
  const onData = (chunk) => {
@@ -139,7 +128,6 @@ function streamServer(child, sub) {
139
128
  child.stderr.on('data', onData);
140
129
  }
141
130
 
142
- /** A build: silent spinner on success, full captured output only on failure. */
143
131
  function streamBuild(child) {
144
132
  const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
145
133
  let i = 0;
@@ -173,7 +161,7 @@ function runEngine(sub, extra, { mounted, onSuccess }) {
173
161
  });
174
162
 
175
163
  banner(sub);
176
- const build = sub === 'build' ? streamBuild(child) : (streamServer(child, sub), null);
164
+ const build = sub === 'build' ? streamBuild(child) : (streamServer(child), null);
177
165
 
178
166
  let cleaned = false;
179
167
  const cleanup = () => {
@@ -198,7 +186,6 @@ function runEngine(sub, extra, { mounted, onSuccess }) {
198
186
  }
199
187
 
200
188
  function run(sub, extra) {
201
- // Inside the engine repo: serve its own demo site.
202
189
  if (isEngineRepo) {
203
190
  prepareEngine();
204
191
  return runEngine(sub, extra, { mounted: false });
@@ -246,7 +233,7 @@ function init() {
246
233
  const files = {
247
234
  'axerity.json': `${JSON.stringify(
248
235
  {
249
- $schema: 'https://axerity.com/axerity.schema.json',
236
+ $schema: 'https://unpkg.com/@axerity/cli/axerity.schema.json',
250
237
  name: 'My Docs',
251
238
  description: 'Documentation built with Axerity.',
252
239
  theme: 'neutral',
@@ -279,9 +266,11 @@ function init() {
279
266
  console.log(' axerity dev');
280
267
  }
281
268
 
269
+ const pkgVersion = () =>
270
+ JSON.parse(readFileSync(join(engineRoot, 'package.json'), 'utf8')).version;
271
+
282
272
  function help() {
283
- const { version } = JSON.parse(readFileSync(join(engineRoot, 'package.json'), 'utf8'));
284
- console.log(`Axerity ${version} — a documentation site generator\n`);
273
+ console.log(`Axerity ${pkgVersion()} a documentation site generator\n`);
285
274
  console.log('Usage: axerity <command>\n');
286
275
  console.log('Commands:');
287
276
  console.log(' init [dir] Scaffold a new docs site');
@@ -295,6 +284,11 @@ const command = process.argv[2];
295
284
  const extra = process.argv.slice(3);
296
285
 
297
286
  switch (command) {
287
+ case '--version':
288
+ case '-v':
289
+ case 'version':
290
+ console.log(pkgVersion());
291
+ break;
298
292
  case 'init':
299
293
  init();
300
294
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axerity/cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "A documentation site generator built with Svelte.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -59,6 +59,7 @@
59
59
  "@tailwindcss/forms": "^0.5.11",
60
60
  "@tailwindcss/typography": "^0.5.19",
61
61
  "@tailwindcss/vite": "^4.3.0",
62
+ "lucide": "^1.17.0",
62
63
  "mdsvex": "^0.12.7",
63
64
  "mermaid": "^11.15.0",
64
65
  "rehype-slug": "^6.0.0",
@@ -18,8 +18,8 @@ axerity build # build the static site
18
18
  axerity preview # preview the production build
19
19
  ```
20
20
 
21
- Run them with `npx axerity <command>`, or install globally with
22
- `npm install -g axerity` and call `axerity` directly.
21
+ Run them with `pnpm dlx @axerity/cli <command>` (or `npx @axerity/cli <command>`),
22
+ or add `@axerity/cli` as a dev dependency and call `axerity` through your scripts.
23
23
 
24
24
  ## init
25
25
 
@@ -35,12 +35,14 @@ example `axerity dev --port 4000`.
35
35
 
36
36
  ## build
37
37
 
38
- `axerity build` produces a static site. Every page is prerendered to HTML, and
39
- the search index, `llms.txt`, sitemap, RSS feed, and OpenGraph images are all
40
- written out, ready to host anywhere.
38
+ `axerity build` produces a static site in `build/`. Every page is prerendered to
39
+ HTML, and the search index, `llms.txt`, sitemap, RSS feed, and OpenGraph images
40
+ are all written out, ready to host anywhere.
41
41
 
42
42
  ## How it works
43
43
 
44
- The CLI never touches your content. It assembles a hidden `.axerity` workspace
45
- that pairs the packaged engine with your `docs/` folder and `axerity.json`, then
46
- runs Vite there. Add `.axerity` to your `.gitignore`; `init` does this for you.
44
+ The engine runs from its own install, not from your repo. When you run a command,
45
+ Axerity reads your `docs/` and `axerity.json` and renders against them, then
46
+ writes the result to `build/` in your project. Your content is the source of
47
+ truth and nothing else in your folder is touched, so there is no workspace to
48
+ gitignore beyond `build/`.
@@ -40,7 +40,7 @@ Settings and set the Framework Preset to **Other**.
40
40
 
41
41
  In the Pages project settings:
42
42
 
43
- - **Build command:** `npx axerity build`
43
+ - **Build command:** `npx @axerity/cli build`
44
44
  - **Build output directory:** `build`
45
45
  - **Framework preset:** None
46
46
 
@@ -50,7 +50,7 @@ Cloudflare serves clean URLs automatically.
50
50
 
51
51
  ```toml title="netlify.toml"
52
52
  [build]
53
- command = "npx axerity build"
53
+ command = "npx @axerity/cli build"
54
54
  publish = "build"
55
55
  ```
56
56
 
@@ -59,7 +59,7 @@ Netlify serves clean URLs (pretty URLs) by default.
59
59
  ## GitHub Pages
60
60
 
61
61
  Build, then publish the `build/` folder (for example with a GitHub Action that
62
- runs `npx axerity build` and uploads `build/` as the Pages artifact).
62
+ runs `npx @axerity/cli build` and uploads `build/` as the Pages artifact).
63
63
 
64
64
  Project sites are served from `https://<user>.github.io/<repo>/`, a sub-path, so
65
65
  set the base in `axerity.json`:
@@ -6,35 +6,52 @@ icon: download
6
6
 
7
7
  # Installation
8
8
 
9
- Axerity is a CLI. You do not clone or fork anything. Install it, scaffold a site,
10
- and start writing Markdown.
9
+ Axerity is a CLI. You do not clone or fork anything. Run it, scaffold a site, and
10
+ start writing Markdown.
11
11
 
12
12
  ## Requirements
13
13
 
14
- - Node.js 20 or newer
14
+ - Node.js 24 or newer
15
15
 
16
16
  ## Create a site
17
17
 
18
18
  Scaffold a new site with `init`, then start the dev server:
19
19
 
20
20
  ```bash
21
- npx axerity init my-docs
21
+ pnpm dlx @axerity/cli init my-docs
22
22
  cd my-docs
23
- npx axerity dev
23
+ pnpm dlx @axerity/cli dev
24
24
  ```
25
25
 
26
- Your site is running at `http://localhost:5173`. Or install it globally and drop
27
- the `npx`:
26
+ Your site is running at `http://localhost:5173`. `pnpm dlx` runs the CLI without
27
+ installing it. `npx @axerity/cli <command>` works the same way.
28
+
29
+ ## Install it
30
+
31
+ For a project you build often, add it as a dev dependency so the version is
32
+ pinned:
28
33
 
29
34
  ```bash
30
- npm install -g axerity
31
- axerity init my-docs
35
+ pnpm add -D @axerity/cli
36
+ ```
37
+
38
+ Then wire up scripts in your `package.json`:
39
+
40
+ ```json
41
+ {
42
+ "scripts": {
43
+ "dev": "axerity dev",
44
+ "build": "axerity build",
45
+ "preview": "axerity preview"
46
+ }
47
+ }
32
48
  ```
33
49
 
50
+ Now `pnpm dev` and `pnpm build` just work, no global install or PATH setup.
51
+
34
52
  ## Project layout
35
53
 
36
- A site is just your content and one config file. Everything else lives in the
37
- package:
54
+ A site is your content and one config file:
38
55
 
39
56
  ```
40
57
  my-docs/
@@ -44,6 +61,6 @@ my-docs/
44
61
  ```
45
62
 
46
63
  Write Markdown in `docs/`, order pages with `meta.json`, and configure the site
47
- in [`axerity.json`](/configuration). The CLI builds a hidden `.axerity`
48
- workspace to run the engine against your content, so add `.axerity` to your
49
- `.gitignore` (the scaffold does this for you).
64
+ in [`axerity.json`](/configuration). The engine runs from its own install, so the
65
+ only thing Axerity ever creates in your project is the `build/` folder. The
66
+ scaffold adds it to your `.gitignore` for you.
@@ -1,8 +1,8 @@
1
1
  <script lang="ts" module>
2
- import type { Component } from 'svelte';
3
- import * as icons from '@lucide/svelte';
2
+ import { icons } from 'lucide';
4
3
 
5
- const registry = icons as unknown as Record<string, Component>;
4
+ type IconNode = [string, Record<string, string | number>][];
5
+ const registry = icons as unknown as Record<string, IconNode>;
6
6
 
7
7
  const pascal = (name: string) =>
8
8
  name
@@ -18,9 +18,24 @@
18
18
  class: className = ''
19
19
  }: { name?: string; size?: number; class?: string } = $props();
20
20
 
21
- const Icon = $derived(name ? registry[pascal(name)] : undefined);
21
+ const node = $derived(name ? registry[pascal(name)] : undefined);
22
22
  </script>
23
23
 
24
- {#if Icon}
25
- <Icon {size} class={className} />
24
+ {#if node}
25
+ <svg
26
+ xmlns="http://www.w3.org/2000/svg"
27
+ width={size}
28
+ height={size}
29
+ viewBox="0 0 24 24"
30
+ fill="none"
31
+ stroke="currentColor"
32
+ stroke-width="2"
33
+ stroke-linecap="round"
34
+ stroke-linejoin="round"
35
+ class={`lucide ${className}`}
36
+ >
37
+ {#each node as [tag, attrs], i (i)}
38
+ <svelte:element this={tag} {...attrs} />
39
+ {/each}
40
+ </svg>
26
41
  {/if}
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
  });