yaakdoc 0.0.0-stage → 0.2.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/dist/cli.js ADDED
@@ -0,0 +1,343 @@
1
+ import { c as VERSION } from "./site-X7q76qYf.js";
2
+ import { a as createDevServer, n as eject, o as build, r as init, t as preview } from "./preview-Ba1BfVZV.js";
3
+ import { ConfigError, mergeConfig } from "@yaakdoc/config";
4
+ import { relative, resolve } from "node:path";
5
+ import { readFileSync } from "node:fs";
6
+ import { consola } from "consola";
7
+ import colors from "picocolors";
8
+ import * as p from "@clack/prompts";
9
+ import { defineCommand, runMain } from "citty";
10
+ //#region src/cli/overrides.ts
11
+ /**
12
+ * Reads the value of `--overrides`: inline JSON (starting with `{`) or the path of a JSON file. The
13
+ * result is merged over the config file and validated together with it.
14
+ */
15
+ function readOverrides(value, cwd = process.cwd()) {
16
+ const inline = value.trimStart().startsWith("{");
17
+ let text = value;
18
+ if (!inline) try {
19
+ text = readFileSync(resolve(cwd, value), "utf8");
20
+ } catch (error) {
21
+ throw new ConfigError(`Could not read overrides ${value}: ${error.message}`);
22
+ }
23
+ let parsed;
24
+ try {
25
+ parsed = JSON.parse(text);
26
+ } catch (error) {
27
+ throw new ConfigError(`Invalid JSON in ${inline ? "--overrides" : `overrides ${value}`}: ${error.message}`);
28
+ }
29
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new ConfigError("--overrides must be a JSON object");
30
+ return parsed;
31
+ }
32
+ //#endregion
33
+ //#region src/cli/index.ts
34
+ const sharedArgs = {
35
+ export: {
36
+ type: "positional",
37
+ required: false,
38
+ description: "Path to the Yaak export (auto-detected by default)"
39
+ },
40
+ config: {
41
+ type: "string",
42
+ alias: "c",
43
+ description: "Path to the config file"
44
+ },
45
+ theme: {
46
+ type: "string",
47
+ alias: "t",
48
+ description: "Theme name, package or local path"
49
+ },
50
+ pages: {
51
+ type: "enum",
52
+ options: ["single", "per-request"],
53
+ description: "Page layout: one page or a page per request"
54
+ },
55
+ base: {
56
+ type: "string",
57
+ description: "Base path the site is served from, e.g. /docs/"
58
+ },
59
+ environment: {
60
+ type: "string",
61
+ alias: "e",
62
+ description: "Environment used to resolve variables"
63
+ },
64
+ workspace: {
65
+ type: "string",
66
+ alias: "w",
67
+ description: "Workspace to document (id or name)"
68
+ },
69
+ overrides: {
70
+ type: "string",
71
+ description: "Config values merged over the config file (a JSON file or inline JSON)"
72
+ }
73
+ };
74
+ function overridesFrom(args) {
75
+ const overrides = {};
76
+ if (args.export) overrides.export = args.export;
77
+ if (args.theme) overrides.theme = args.theme;
78
+ if (args.pages) overrides.pages = args.pages;
79
+ if (args.base) overrides.base = args.base;
80
+ if (args.environment) overrides.environment = args.environment;
81
+ if (args.workspace) overrides.workspace = args.workspace;
82
+ return args.overrides ? mergeConfig(readOverrides(args.overrides), overrides) : overrides;
83
+ }
84
+ const rel = (path) => relative(process.cwd(), path) || ".";
85
+ function summary(context) {
86
+ const requests = Object.keys(context.document.requests).length;
87
+ const folders = Object.keys(context.document.folders).length;
88
+ return [
89
+ `${colors.dim("Export")} ${context.exportPath ? rel(context.exportPath) : "(in memory)"} ${colors.dim(`(Yaak ${context.source.yaakVersion})`)}`,
90
+ `${colors.dim("Workspace")} ${context.document.workspace.name} ${colors.dim(`· ${requests} requests, ${folders} folders`)}`,
91
+ `${colors.dim("Environment")} ${context.document.environment?.name ?? colors.dim("none")}`,
92
+ `${colors.dim("Theme")} ${context.theme.name} ${colors.dim(context.theme.packageName ?? rel(context.theme.root))}`,
93
+ `${colors.dim("Config")} ${context.configFile ? rel(context.configFile) : colors.dim("none (defaults)")}`
94
+ ].map((line) => ` ${line}`).join("\n");
95
+ }
96
+ const banner = () => `\n ${colors.bold(colors.magenta("yaakdoc"))} ${colors.dim(`v${VERSION}`)}\n`;
97
+ const subCommands = {
98
+ dev: defineCommand({
99
+ meta: {
100
+ name: "dev",
101
+ description: "Start the docs dev server (default command)"
102
+ },
103
+ args: {
104
+ ...sharedArgs,
105
+ port: {
106
+ type: "string",
107
+ alias: "p",
108
+ description: "Port (default: 4000)"
109
+ },
110
+ host: {
111
+ type: "string",
112
+ description: "Host to listen on (use --host 0.0.0.0 to expose)"
113
+ },
114
+ open: {
115
+ type: "boolean",
116
+ alias: "o",
117
+ description: "Open the browser"
118
+ },
119
+ watch: {
120
+ type: "boolean",
121
+ default: true,
122
+ negativeDescription: "Don't reload when the export or config changes"
123
+ }
124
+ },
125
+ async run({ args }) {
126
+ const server = await createDevServer({
127
+ ...args.config ? { configFile: args.config } : {},
128
+ overrides: overridesFrom(args),
129
+ ...args.port ? { port: Number(args.port) } : {},
130
+ ...args.host ? { host: args.host === "true" ? true : args.host } : {},
131
+ ...args.open ? { open: true } : {},
132
+ watch: args.watch
133
+ });
134
+ const context = server.getContext();
135
+ console.log(banner());
136
+ console.log(summary(context));
137
+ console.log(`\n ${colors.green("➜")} ${colors.bold("Local")} ${colors.cyan(server.url)}`);
138
+ if (context.config.llms.enabled) console.log(` ${colors.green("➜")} ${colors.bold("LLMs")} ${colors.cyan(`${server.url}llms.txt`)}`);
139
+ console.log(`\n ${colors.dim(args.watch ? "Watching for changes. Press Ctrl+C to stop." : "Press Ctrl+C to stop.")}\n`);
140
+ const shutdown = async () => {
141
+ await server.close();
142
+ process.exit(0);
143
+ };
144
+ process.once("SIGINT", shutdown);
145
+ process.once("SIGTERM", shutdown);
146
+ }
147
+ }),
148
+ build: defineCommand({
149
+ meta: {
150
+ name: "build",
151
+ description: "Build a static site"
152
+ },
153
+ args: {
154
+ ...sharedArgs,
155
+ outDir: {
156
+ type: "string",
157
+ alias: "o",
158
+ description: "Output directory (default: dist)"
159
+ }
160
+ },
161
+ async run({ args }) {
162
+ console.log(banner());
163
+ const started = performance.now();
164
+ const overrides = overridesFrom(args);
165
+ if (args.outDir) overrides.outDir = args.outDir;
166
+ const result = await build({
167
+ ...args.config ? { configFile: args.config } : {},
168
+ overrides
169
+ });
170
+ console.log(summary(result.context));
171
+ const pages = result.files.filter((file) => file.endsWith(".html")).length;
172
+ const markdown = result.files.filter((file) => file.endsWith(".md") || file.endsWith(".txt")).length;
173
+ console.log(`\n ${colors.green("✔")} Built ${pages} page${pages === 1 ? "" : "s"} and ${markdown} Markdown/llms files into ${colors.cyan(rel(result.outDir))} ${colors.dim(`in ${Math.round(performance.now() - started)}ms`)}\n`);
174
+ }
175
+ }),
176
+ preview: defineCommand({
177
+ meta: {
178
+ name: "preview",
179
+ description: "Serve the built site locally"
180
+ },
181
+ args: {
182
+ config: sharedArgs.config,
183
+ outDir: {
184
+ type: "string",
185
+ description: "Directory to serve (default: dist)"
186
+ },
187
+ port: {
188
+ type: "string",
189
+ alias: "p",
190
+ description: "Port (default: 4000)"
191
+ },
192
+ host: {
193
+ type: "string",
194
+ description: "Host to listen on"
195
+ },
196
+ open: {
197
+ type: "boolean",
198
+ alias: "o",
199
+ description: "Open the browser"
200
+ }
201
+ },
202
+ async run({ args }) {
203
+ const server = await preview({
204
+ ...args.config ? { configFile: args.config } : {},
205
+ ...args.outDir ? { outDir: args.outDir } : {},
206
+ ...args.port ? { port: Number(args.port) } : {},
207
+ ...args.host ? { host: args.host } : {},
208
+ ...args.open ? { open: true } : {}
209
+ });
210
+ console.log(banner());
211
+ console.log(` ${colors.green("➜")} ${colors.bold("Preview")} ${colors.cyan(server.url)}\n`);
212
+ }
213
+ }),
214
+ init: defineCommand({
215
+ meta: {
216
+ name: "init",
217
+ description: "Create a yaakdoc.config.json"
218
+ },
219
+ args: {
220
+ yes: {
221
+ type: "boolean",
222
+ alias: "y",
223
+ description: "Use defaults without prompting"
224
+ },
225
+ force: {
226
+ type: "boolean",
227
+ description: "Overwrite an existing config"
228
+ }
229
+ },
230
+ async run({ args }) {
231
+ const config = {};
232
+ if (!args.yes && process.stdin.isTTY) {
233
+ p.intro(colors.bold(colors.magenta(" yaakdoc init ")));
234
+ const answers = await p.group({
235
+ title: () => p.text({
236
+ message: "Site title",
237
+ placeholder: "Defaults to the workspace name"
238
+ }),
239
+ primary: () => p.text({
240
+ message: "Primary brand color",
241
+ placeholder: "#7c3aed",
242
+ defaultValue: ""
243
+ }),
244
+ pages: () => p.select({
245
+ message: "Page layout",
246
+ options: [{
247
+ value: "single",
248
+ label: "Single page",
249
+ hint: "everything on one page, like Insomnia Documenter"
250
+ }, {
251
+ value: "per-request",
252
+ label: "Page per request",
253
+ hint: "better for large APIs"
254
+ }]
255
+ }),
256
+ llms: () => p.confirm({
257
+ message: "Generate llms.txt and Markdown pages for LLMs?",
258
+ initialValue: true
259
+ })
260
+ }, { onCancel: () => process.exit(1) });
261
+ if (answers.title) config.branding = {
262
+ ...config.branding,
263
+ title: answers.title
264
+ };
265
+ if (answers.primary) config.branding = {
266
+ ...config.branding,
267
+ colors: { primary: answers.primary }
268
+ };
269
+ config.pages = answers.pages;
270
+ if (!answers.llms) config.llms = { enabled: false };
271
+ }
272
+ const { file } = await init({
273
+ config,
274
+ force: Boolean(args.force)
275
+ });
276
+ if (!args.yes && process.stdin.isTTY) p.outro(`Created ${colors.cyan(rel(file))}. Run ${colors.bold("npx yaakdoc")} to start.`);
277
+ else consola.success(`Created ${rel(file)}`);
278
+ }
279
+ }),
280
+ eject: defineCommand({
281
+ meta: {
282
+ name: "eject",
283
+ description: "Copy the theme into your project to customize it"
284
+ },
285
+ args: {
286
+ config: sharedArgs.config,
287
+ out: {
288
+ type: "string",
289
+ description: "Destination directory (default: ./theme)"
290
+ },
291
+ force: {
292
+ type: "boolean",
293
+ description: "Overwrite a non-empty destination"
294
+ }
295
+ },
296
+ async run({ args }) {
297
+ const result = await eject({
298
+ ...args.config ? { configFile: args.config } : {},
299
+ ...args.out ? { out: args.out } : {},
300
+ force: Boolean(args.force)
301
+ });
302
+ consola.success(`Ejected theme ${colors.bold(result.theme)} into ${colors.cyan(rel(result.out))} (${result.files.length} files)`);
303
+ if (result.config?.updated) consola.info(`${result.config.created ? "Created" : "Updated"} ${rel(result.config.file)} → "theme": "./${rel(result.out)}"`);
304
+ else if (result.config) consola.warn(`Set \`theme: "./${rel(result.out)}"\` in ${rel(result.config.file)} to use the ejected theme.`);
305
+ if (result.dependencies.length > 0) consola.info(`The theme's dependencies are provided by yaakdoc. To pin your own versions, install:\n npm i -D ${result.dependencies.join(" ")}`);
306
+ }
307
+ })
308
+ };
309
+ const main = defineCommand({
310
+ meta: {
311
+ name: "yaakdoc",
312
+ version: VERSION,
313
+ description: "API documentation sites from Yaak exports"
314
+ },
315
+ default: "dev",
316
+ subCommands
317
+ });
318
+ /** `yaakdoc ./api.json --port 3000` → `yaakdoc dev ./api.json --port 3000` */
319
+ function normalizeArgs(argv) {
320
+ const first = argv.find((arg) => !arg.startsWith("-"));
321
+ if (argv.length > 0 && argv.every((arg) => [
322
+ "-h",
323
+ "--help",
324
+ "-v",
325
+ "--version"
326
+ ].includes(arg))) return argv;
327
+ if (first && first in subCommands) return argv;
328
+ return argv.length === 0 ? argv : ["dev", ...argv];
329
+ }
330
+ async function run(argv = process.argv.slice(2)) {
331
+ process.on("unhandledRejection", (error) => {
332
+ consola.error(error instanceof Error ? error.message : error);
333
+ process.exit(1);
334
+ });
335
+ try {
336
+ await runMain(main, { rawArgs: normalizeArgs(argv) });
337
+ } catch (error) {
338
+ consola.error(error.message);
339
+ process.exit(1);
340
+ }
341
+ }
342
+ //#endregion
343
+ export { normalizeArgs, run };
@@ -0,0 +1,118 @@
1
+ import { _ as themePackageCandidates, a as withBase, c as Route, f as resolveContext, g as themeFromDefinition, h as resolveTheme, i as emptyOutDir, l as YaakdocOptions, m as ThemeError, n as RenderEntry, o as writeSite, p as ResolvedTheme, r as assertSafeOutDir, s as Context, t as VERSION, u as matchRoute } from "./version-Bwv0ibuY.js";
2
+ import { ResolvedConfig, YaakdocConfig, YaakdocConfig as YaakdocConfig$1, defineConfig } from "@yaakdoc/config";
3
+ import { ThemeDefinition, defineTheme } from "@yaakdoc/react/theme";
4
+ import { Snippet, defineSnippet } from "@yaakdoc/snippets";
5
+ import { Plugin, ViteDevServer } from "vite";
6
+ import { Server } from "node:http";
7
+ import { Assets } from "@yaakdoc/react";
8
+ //#region src/node/build.d.ts
9
+ type BuildResult = {
10
+ outDir: string;
11
+ /** Written files, relative to outDir. */
12
+ files: string[];
13
+ context: Context;
14
+ };
15
+ /** Builds the static site: client assets, prerendered HTML for every route, Markdown and llms.txt. */
16
+ export declare function build(options?: YaakdocOptions): Promise<BuildResult>;
17
+ type ThemeBundle = {
18
+ /** Client assets, relative to the output directory. */
19
+ assets: Assets;
20
+ /** The SSR entry (exports `render`), in a temporary directory inside the output directory. */
21
+ ssrEntry: string;
22
+ };
23
+ /**
24
+ * Builds the theme with Vite: the island runtime and CSS into `outDir` (emptied first), and the SSR
25
+ * entry, fully bundled so it runs from anywhere. Pass `base: "./"` for client assets that work
26
+ * under any base path (used to precompile the theme bundled into the Yaak plugin).
27
+ */
28
+ export declare function bundleTheme(context: Context, outDir: string, options?: {
29
+ base?: string;
30
+ }): Promise<ThemeBundle>;
31
+ //#endregion
32
+ //#region src/node/dev.d.ts
33
+ type DevServerOptions = YaakdocOptions & {
34
+ port?: number;
35
+ host?: string | boolean;
36
+ open?: boolean;
37
+ /** Reload when the export/config/assets change (default: true). */
38
+ watch?: boolean;
39
+ /** Called after the context is rebuilt because a watched file changed. */
40
+ onReload?: (context: Context) => void;
41
+ };
42
+ type DevServer = {
43
+ url: string;
44
+ vite: ViteDevServer;
45
+ httpServer: Server;
46
+ getContext: () => Context;
47
+ close: () => Promise<void>;
48
+ };
49
+ /** Starts the development server with SSR, HMR for theme code/CSS and reload on export changes. */
50
+ export declare function createDevServer(options?: DevServerOptions): Promise<DevServer>;
51
+ //#endregion
52
+ //#region src/node/eject.d.ts
53
+ type EjectOptions = {
54
+ cwd?: string;
55
+ configFile?: string;
56
+ /** Destination directory (default: `./theme`). */
57
+ out?: string;
58
+ /** Overwrite a non-empty destination. */
59
+ force?: boolean;
60
+ /** Update (or create) the config to use the ejected theme (default: true). */
61
+ updateConfig?: boolean;
62
+ };
63
+ type EjectResult = {
64
+ out: string;
65
+ files: string[];
66
+ theme: string;
67
+ dependencies: string[];
68
+ config: {
69
+ file: string;
70
+ updated: boolean;
71
+ created: boolean;
72
+ } | null;
73
+ };
74
+ /** Copies the current theme's source into the project so it can be customized freely. */
75
+ export declare function eject(options?: EjectOptions): Promise<EjectResult>;
76
+ //#endregion
77
+ //#region src/node/init.d.ts
78
+ /** `$schema` value for yaakdoc.config.json: local copy when installed, otherwise unpkg. */
79
+ export declare function schemaUrl(cwd: string): string;
80
+ type InitOptions = {
81
+ cwd?: string;
82
+ config?: YaakdocConfig$1;
83
+ force?: boolean;
84
+ };
85
+ /** Writes a yaakdoc.config.json (with `$schema` for editor autocomplete). */
86
+ export declare function init(options?: InitOptions): Promise<{
87
+ file: string;
88
+ config: YaakdocConfig$1;
89
+ }>;
90
+ //#endregion
91
+ //#region src/node/plugin.d.ts
92
+ export declare const VIRTUAL_SERVER = "virtual:yaakdoc/entry-server";
93
+ /** The SSR entry exports `render` (see `RenderEntry`). */
94
+ export declare const VIRTUAL_CLIENT = "virtual:yaakdoc/entry-client";
95
+ /**
96
+ * The yaakdoc Vite plugin: virtual SSR/client entries, theme-scoped `@/` alias, and fallback
97
+ * resolution of theme dependencies from the yaakdoc installation (so ejected themes and `npx` work
98
+ * without installing anything in the project).
99
+ */
100
+ export declare function yaakdocPlugin(getContext: () => Context, onSsrUpdate?: () => void): Plugin;
101
+ //#endregion
102
+ //#region src/node/preview.d.ts
103
+ type PreviewOptions = {
104
+ cwd?: string;
105
+ configFile?: string;
106
+ outDir?: string;
107
+ port?: number;
108
+ host?: string | boolean;
109
+ open?: boolean;
110
+ };
111
+ /** Serves a built site (like a static host would, including 404.html and base path). */
112
+ export declare function preview(options?: PreviewOptions): Promise<{
113
+ url: string;
114
+ server: Server;
115
+ close: () => Promise<void>;
116
+ }>;
117
+ //#endregion
118
+ export { type BuildResult, type Context, type DevServer, type DevServerOptions, type EjectOptions, type EjectResult, type InitOptions, type PreviewOptions, type RenderEntry, type ResolvedConfig, type ResolvedTheme, type Route, type Snippet, type ThemeBundle, type ThemeDefinition, ThemeError, VERSION, type YaakdocConfig, type YaakdocOptions, assertSafeOutDir, defineConfig, defineSnippet, defineTheme, emptyOutDir, matchRoute, resolveContext, resolveTheme, themeFromDefinition, themePackageCandidates, withBase, writeSite };
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ import { a as matchRoute, c as VERSION, d as themeFromDefinition, f as themePackageCandidates, i as writeSite, l as ThemeError, n as emptyOutDir, r as withBase, s as resolveContext, t as assertSafeOutDir, u as resolveTheme } from "./site-X7q76qYf.js";
2
+ import { a as createDevServer, c as VIRTUAL_CLIENT, i as schemaUrl, l as VIRTUAL_SERVER, n as eject, o as build, r as init, s as bundleTheme, t as preview, u as yaakdocPlugin } from "./preview-Ba1BfVZV.js";
3
+ import { defineConfig } from "@yaakdoc/config";
4
+ import { defineTheme } from "@yaakdoc/react/theme";
5
+ import { defineSnippet } from "@yaakdoc/snippets";
6
+ export { ThemeError, VERSION, VIRTUAL_CLIENT, VIRTUAL_SERVER, assertSafeOutDir, build, bundleTheme, createDevServer, defineConfig, defineSnippet, defineTheme, eject, emptyOutDir, init, matchRoute, preview, resolveContext, resolveTheme, schemaUrl, themeFromDefinition, themePackageCandidates, withBase, writeSite, yaakdocPlugin };
@@ -0,0 +1,19 @@
1
+ import { spawn } from "node:child_process";
2
+ //#region src/node/open.ts
3
+ /** Opens a URL in the default browser (best effort). */
4
+ function openBrowser(url) {
5
+ const [command, args] = process.platform === "darwin" ? ["open", [url]] : process.platform === "win32" ? ["cmd", [
6
+ "/c",
7
+ "start",
8
+ "",
9
+ url
10
+ ]] : ["xdg-open", [url]];
11
+ try {
12
+ spawn(command, args, {
13
+ stdio: "ignore",
14
+ detached: true
15
+ }).on("error", () => {}).unref();
16
+ } catch {}
17
+ }
18
+ //#endregion
19
+ export { openBrowser as default };