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