@zvndev/darkmown 2.3.1-next.1.g3a4a8dc → 2.3.1-next.2.ga0699da

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.
Files changed (40) hide show
  1. package/package.json +1 -1
  2. package/types/compiler/context.d.ts +74 -60
  3. package/types/compiler/reader.d.ts +10 -2
  4. package/types/src/api-runner.d.ts +0 -94
  5. package/types/src/builder.d.ts +0 -170
  6. package/types/src/catalog.d.ts +0 -97
  7. package/types/src/compiler/actions.d.ts +0 -41
  8. package/types/src/compiler/body.d.ts +0 -11
  9. package/types/src/compiler/collections.d.ts +0 -76
  10. package/types/src/compiler/context.d.ts +0 -647
  11. package/types/src/compiler/directives.d.ts +0 -6
  12. package/types/src/compiler/expr-ast.d.ts +0 -20
  13. package/types/src/compiler/fetch.d.ts +0 -29
  14. package/types/src/compiler/format.d.ts +0 -49
  15. package/types/src/compiler/forms.d.ts +0 -94
  16. package/types/src/compiler/frontmatter.d.ts +0 -33
  17. package/types/src/compiler/fs-reader.d.ts +0 -7
  18. package/types/src/compiler/image-size.d.ts +0 -14
  19. package/types/src/compiler/includes.d.ts +0 -100
  20. package/types/src/compiler/index.d.ts +0 -5
  21. package/types/src/compiler/interpolation.d.ts +0 -115
  22. package/types/src/compiler/loops.d.ts +0 -36
  23. package/types/src/compiler/markdown.d.ts +0 -34
  24. package/types/src/compiler/media.d.ts +0 -32
  25. package/types/src/compiler/page.d.ts +0 -109
  26. package/types/src/compiler/predicates.d.ts +0 -50
  27. package/types/src/compiler/reader.d.ts +0 -48
  28. package/types/src/compiler/state.d.ts +0 -68
  29. package/types/src/compiler/structure.d.ts +0 -56
  30. package/types/src/compiler.d.ts +0 -48
  31. package/types/src/config.d.ts +0 -45
  32. package/types/src/dev.d.ts +0 -58
  33. package/types/src/errors.d.ts +0 -100
  34. package/types/src/feeds.d.ts +0 -150
  35. package/types/src/headers.d.ts +0 -44
  36. package/types/src/highlight.d.ts +0 -24
  37. package/types/src/router.d.ts +0 -78
  38. package/types/src/scaffold.d.ts +0 -20
  39. package/types/src/skin.d.ts +0 -48
  40. package/types/src/statics.d.ts +0 -24
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zvndev/darkmown",
3
- "version": "2.3.1-next.1.g3a4a8dc",
3
+ "version": "2.3.1-next.2.ga0699da",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -1,63 +1,3 @@
1
- /**
2
- * @param {import("./reader.js").Reader} reader The source reader for this
3
- * compile (fs-backed by default; in-memory for `compileFromMemory`).
4
- * @returns {Compilation}
5
- */
6
- export function createCompilation(reader: import("./reader.js").Reader): Compilation;
7
- /**
8
- * @param {Scope | null} parent
9
- * @param {Record<string, unknown>} [vars]
10
- * @returns {Scope}
11
- */
12
- export function createScope(parent: Scope | null, vars?: Record<string, unknown>): Scope;
13
- /**
14
- * Format a source location as `file:line` (1-based) for compile errors. Keeps the
15
- * file path intact so existing message matchers still pass, while pointing at the
16
- * directive's (or unclosed opener's) line. `index` is 0-based into the current
17
- * `compileBody` slice; `ctx.lineOffset` (where that slice starts in the body,
18
- * accumulated by {@link nestedCtx} as block handlers recurse) and `ctx.bodyLine`
19
- * (the frontmatter offset) shift it back to the true file line.
20
- * @param {Pick<Ctx, "file" | "bodyLine" | "lineOffset">} ctx
21
- * @param {number} index 0-based line index into the current body slice.
22
- * @returns {string}
23
- */
24
- export function at(ctx: Pick<Ctx, "file" | "bodyLine" | "lineOffset">, index: number): string;
25
- /**
26
- * The 1-based true file line for a body-slice `index` — the numeric half of
27
- * {@link at}, exposed so {@link wdError} can populate the structured `wd.line`.
28
- * @param {Pick<Ctx, "bodyLine" | "lineOffset">} ctx
29
- * @param {number} index 0-based line index into the current body slice.
30
- * @returns {number}
31
- */
32
- export function lineOf(ctx: Pick<Ctx, "bodyLine" | "lineOffset">, index: number): number;
33
- /**
34
- * Build a compile `Error` carrying a structured {@link WdErrorInfo} on `err.wd`
35
- * — so an AI edit-loop (or an editor) gets code/file/line/hint/example without
36
- * re-parsing the prose. The string message is the caller's text prefixed with
37
- * the stable `[WDxxx]` code, so a user can search the code straight out of the
38
- * terminal; everything after the prefix (the `file:line`, the corrective `Use:`
39
- * template, the concrete `e.g.` example) is unchanged.
40
- *
41
- * Every author-facing compile error is built here, so no error can ship without
42
- * a code. See `src/errors.js` for the registry and the numbering scheme.
43
- * @param {string} message The user-facing error text, without the code prefix.
44
- * @param {WdErrorInfo} wd The structured mirror (its `code` becomes the prefix).
45
- * @returns {Error & { wd: WdErrorInfo }}
46
- */
47
- export function wdError(message: string, wd: WdErrorInfo): Error & {
48
- wd: WdErrorInfo;
49
- };
50
- /**
51
- * The compile context for a nested block body that starts `start` lines into the
52
- * current slice. The offset accumulates, so errors inside arbitrarily nested
53
- * blocks (`::: container`, `:form`, `@loop`, `:if`, `:carousel`) still report
54
- * the true file line through {@link at}.
55
- * @template {Pick<Ctx, "lineOffset">} T
56
- * @param {T} ctx
57
- * @param {number} start 0-based index the nested body starts at in the current slice.
58
- * @returns {T}
59
- */
60
- export function nestedCtx<T extends Pick<Ctx, "lineOffset">>(ctx: T, start: number): T;
61
1
  /**
62
2
  * @typedef {import("../config.js").Paths} Paths
63
3
  */
@@ -248,6 +188,80 @@ export function nestedCtx<T extends Pick<Ctx, "lineOffset">>(ctx: T, start: numb
248
188
  * @property {string} target State key (possibly dotted) the action mutates.
249
189
  * @property {unknown} [value] Literal value for value-carrying ops.
250
190
  */
191
+ /**
192
+ * Normalize CRLF/CR line endings to LF.
193
+ *
194
+ * Every line-structured parser in the project (frontmatter delimiters, the `.wd`
195
+ * directive dispatcher, `.skin` indentation) tests LF-shaped text. Source files
196
+ * authored on Windows — or checked out anywhere with git's `core.autocrlf`, the
197
+ * default on Windows — arrive CRLF-terminated, and an un-normalized `\r` turns
198
+ * `---` into `---\r` and silently defeats those tests. Applied at the reader
199
+ * boundary and again at the two entry points that accept raw strings from
200
+ * callers that bypass the reader; it is idempotent, so doubling up is free.
201
+ * @param {string} text
202
+ * @returns {string}
203
+ */
204
+ export function normalizeNewlines(text: string): string;
205
+ /**
206
+ * @param {import("./reader.js").Reader} reader The source reader for this
207
+ * compile (fs-backed by default; in-memory for `compileFromMemory`).
208
+ * @returns {Compilation}
209
+ */
210
+ export function createCompilation(reader: import("./reader.js").Reader): Compilation;
211
+ /**
212
+ * @param {Scope | null} parent
213
+ * @param {Record<string, unknown>} [vars]
214
+ * @returns {Scope}
215
+ */
216
+ export function createScope(parent: Scope | null, vars?: Record<string, unknown>): Scope;
217
+ /**
218
+ * Format a source location as `file:line` (1-based) for compile errors. Keeps the
219
+ * file path intact so existing message matchers still pass, while pointing at the
220
+ * directive's (or unclosed opener's) line. `index` is 0-based into the current
221
+ * `compileBody` slice; `ctx.lineOffset` (where that slice starts in the body,
222
+ * accumulated by {@link nestedCtx} as block handlers recurse) and `ctx.bodyLine`
223
+ * (the frontmatter offset) shift it back to the true file line.
224
+ * @param {Pick<Ctx, "file" | "bodyLine" | "lineOffset">} ctx
225
+ * @param {number} index 0-based line index into the current body slice.
226
+ * @returns {string}
227
+ */
228
+ export function at(ctx: Pick<Ctx, "file" | "bodyLine" | "lineOffset">, index: number): string;
229
+ /**
230
+ * The 1-based true file line for a body-slice `index` — the numeric half of
231
+ * {@link at}, exposed so {@link wdError} can populate the structured `wd.line`.
232
+ * @param {Pick<Ctx, "bodyLine" | "lineOffset">} ctx
233
+ * @param {number} index 0-based line index into the current body slice.
234
+ * @returns {number}
235
+ */
236
+ export function lineOf(ctx: Pick<Ctx, "bodyLine" | "lineOffset">, index: number): number;
237
+ /**
238
+ * Build a compile `Error` carrying a structured {@link WdErrorInfo} on `err.wd`
239
+ * — so an AI edit-loop (or an editor) gets code/file/line/hint/example without
240
+ * re-parsing the prose. The string message is the caller's text prefixed with
241
+ * the stable `[WDxxx]` code, so a user can search the code straight out of the
242
+ * terminal; everything after the prefix (the `file:line`, the corrective `Use:`
243
+ * template, the concrete `e.g.` example) is unchanged.
244
+ *
245
+ * Every author-facing compile error is built here, so no error can ship without
246
+ * a code. See `src/errors.js` for the registry and the numbering scheme.
247
+ * @param {string} message The user-facing error text, without the code prefix.
248
+ * @param {WdErrorInfo} wd The structured mirror (its `code` becomes the prefix).
249
+ * @returns {Error & { wd: WdErrorInfo }}
250
+ */
251
+ export function wdError(message: string, wd: WdErrorInfo): Error & {
252
+ wd: WdErrorInfo;
253
+ };
254
+ /**
255
+ * The compile context for a nested block body that starts `start` lines into the
256
+ * current slice. The offset accumulates, so errors inside arbitrarily nested
257
+ * blocks (`::: container`, `:form`, `@loop`, `:if`, `:carousel`) still report
258
+ * the true file line through {@link at}.
259
+ * @template {Pick<Ctx, "lineOffset">} T
260
+ * @param {T} ctx
261
+ * @param {number} start 0-based index the nested body starts at in the current slice.
262
+ * @returns {T}
263
+ */
264
+ export function nestedCtx<T extends Pick<Ctx, "lineOffset">>(ctx: T, start: number): T;
251
265
  export const pageIncludeExtensions: string[];
252
266
  /** @type {Record<string, string>} */
253
267
  export const LOOP_META: Record<string, string>;
@@ -3,7 +3,11 @@
3
3
  * ABSOLUTE path (the compiler resolves includes/assets to absolute paths before
4
4
  * reading), so a reader only has to map absolute paths to bytes/existence.
5
5
  * @typedef {object} Reader
6
- * @property {(absPath: string) => string} readText Read a UTF-8 text file.
6
+ * @property {(absPath: string) => string} readText Read a UTF-8 text file. The
7
+ * result is ALWAYS LF-normalized: every parser downstream is line-structured
8
+ * and LF-shaped, so a CRLF source (Windows, or any `core.autocrlf` checkout)
9
+ * would otherwise fail to match delimiters like `---`. A custom reader must
10
+ * uphold this.
7
11
  * @property {(absPath: string) => Uint8Array} readBinary Read raw bytes (images).
8
12
  * @property {(absPath: string) => boolean} exists Whether the path exists.
9
13
  * @property {(absPath: string) => string} realpath Canonical path (symlinks
@@ -29,7 +33,11 @@ export function memoryReader(files: Record<string, string> | Map<string, string>
29
33
  */
30
34
  export type Reader = {
31
35
  /**
32
- * Read a UTF-8 text file.
36
+ * Read a UTF-8 text file. The
37
+ * result is ALWAYS LF-normalized: every parser downstream is line-structured
38
+ * and LF-shaped, so a CRLF source (Windows, or any `core.autocrlf` checkout)
39
+ * would otherwise fail to match delimiters like `---`. A custom reader must
40
+ * uphold this.
33
41
  */
34
42
  readText: (absPath: string) => string;
35
43
  /**
@@ -1,94 +0,0 @@
1
- /**
2
- * The local-dev serverless API runner. Gives `darkmown dev` the SAME `/api/*`
3
- * behavior a project gets on Vercel / Cloudflare in production, so a `:fetch
4
- * /api/x` or a form POST works identically before you ever deploy.
5
- *
6
- * The convention is deliberately plain: a backend endpoint is a plain-JS file
7
- * under the project's top-level `api/` directory that default-exports a
8
- * Web-standard handler `(request: Request, context) => Response | Promise<Response>`.
9
- * That is the exact signature Vercel Edge, Cloudflare Pages, Netlify Edge and
10
- * Deno already run — Darkmown owns no server, it just emulates the host locally.
11
- *
12
- * File → route, rooted at the `/api` URL prefix (matching Vercel's `api/`):
13
- * api/echo.js → /api/echo
14
- * api/users/index.js → /api/users
15
- * api/users/list.js → /api/users/list
16
- * api/users/[id].js → /api/users/:id (context.params.id)
17
- *
18
- * Nothing here mutates module state: routes are discovered per call so a newly
19
- * added function is picked up without a restart, and each handler is imported
20
- * with an mtime cache-buster so edits hot-reload.
21
- */
22
- /**
23
- * A discovered API route.
24
- * @typedef {object} ApiRoute
25
- * @property {string} file Absolute path to the handler module.
26
- * @property {string[]} segments Route segments after `/api`; a dynamic segment
27
- * is stored as `[name]` (e.g. `["users", "[id]"]`).
28
- */
29
- /**
30
- * Walk `apiDir` and return every `.js`/`.mjs` handler as an {@link ApiRoute}.
31
- * Files/dirs whose name starts with `.`, `_`, or `-` are treated as private
32
- * (helpers, fixtures) and never routed, matching the router's hidden-path rule.
33
- * Returns `[]` when `apiDir` does not exist.
34
- * @param {string} apiDir Absolute path to the project's `api/` directory.
35
- * @returns {ApiRoute[]}
36
- */
37
- export function discoverApiRoutes(apiDir: string): ApiRoute[];
38
- /**
39
- * Match a request pathname against discovered routes. The pathname is expected
40
- * to start with `/api`; anything else returns `null` (caller serves static).
41
- * @param {ApiRoute[]} routes
42
- * @param {string} pathname Request pathname (no query string).
43
- * @returns {{ file: string, params: Record<string, string> } | null}
44
- */
45
- export function matchApiRoute(routes: ApiRoute[], pathname: string): {
46
- file: string;
47
- params: Record<string, string>;
48
- } | null;
49
- /**
50
- * Build a Web-standard `Request` from a Node `IncomingMessage`. The body (for
51
- * methods that carry one) is buffered fully — dev endpoints are small and this
52
- * avoids the `duplex: "half"` streaming dance.
53
- * @param {import("node:http").IncomingMessage} req
54
- * @returns {Promise<Request>}
55
- */
56
- export function nodeRequestToWeb(req: import("node:http").IncomingMessage): Promise<Request>;
57
- /**
58
- * Write a Web-standard `Response` back onto a Node `ServerResponse`.
59
- * @param {Response} response
60
- * @param {import("node:http").ServerResponse} res
61
- * @returns {Promise<void>}
62
- */
63
- export function writeWebResponse(response: Response, res: import("node:http").ServerResponse): Promise<void>;
64
- /**
65
- * Handle a request as an API call if its pathname matches a function under
66
- * `apiDir`. Returns `true` when it owned the request (a route matched, whether
67
- * the handler succeeded or threw), `false` when nothing matched so the caller
68
- * should fall through to static serving.
69
- *
70
- * @param {object} io
71
- * @param {string} io.apiDir Absolute path to the project's `api/` directory.
72
- * @param {import("node:http").IncomingMessage} io.req
73
- * @param {import("node:http").ServerResponse} io.res
74
- * @returns {Promise<boolean>}
75
- */
76
- export function handleApiRequest({ apiDir, req, res }: {
77
- apiDir: string;
78
- req: import("node:http").IncomingMessage;
79
- res: import("node:http").ServerResponse;
80
- }): Promise<boolean>;
81
- /**
82
- * A discovered API route.
83
- */
84
- export type ApiRoute = {
85
- /**
86
- * Absolute path to the handler module.
87
- */
88
- file: string;
89
- /**
90
- * Route segments after `/api`; a dynamic segment
91
- * is stored as `[name]` (e.g. `["users", "[id]"]`).
92
- */
93
- segments: string[];
94
- };
@@ -1,170 +0,0 @@
1
- /**
2
- * Compile the whole site under `cwd` into `dist`, returning the route manifest.
3
- *
4
- * The build is always 100% static, CDN-cacheable HTML. Backend `api/*.js`
5
- * functions are NOT compiled — they are the host's concern. `target` only
6
- * decides the small amount of host glue Darkmown emits alongside the static
7
- * output: the default (`vercel`/anything) leaves `api/` for the platform to pick
8
- * up natively; `cloudflare` emits a `dist/_worker.js/` module that routes
9
- * `/api/*` to those same functions and serves everything else as a static asset.
10
- *
11
- * @param {string} [cwd] Project working directory (defaults to `process.cwd()`).
12
- * @param {{ target?: string, includeDrafts?: boolean, depMap?: boolean, changed?: string[], quietFeedHints?: boolean }} [options]
13
- * `target: "cloudflare"` emits the Pages worker. `includeDrafts: true` keeps
14
- * `draft: true` pages in the build + feeds (dev / `build --drafts`); default
15
- * excludes them at route discovery so feeds never see a draft. `depMap: true`
16
- * (dev builds) writes the per-route dependency map to `dist/.wd-dev-deps.json`.
17
- * `changed` (project-relative paths, dev only; implies `depMap`) attempts an
18
- * incremental rebuild of just the affected routes, falling back to a full
19
- * rebuild on ANY uncertainty — a stale page is worse than a slow rebuild.
20
- * @returns {BuildResult}
21
- */
22
- export function buildSite(cwd?: string, options?: {
23
- target?: string;
24
- includeDrafts?: boolean;
25
- depMap?: boolean;
26
- changed?: string[];
27
- quietFeedHints?: boolean;
28
- }): BuildResult;
29
- /**
30
- * Strip developer comments from the runtime before it ships. The source keeps
31
- * full JSDoc type annotations (for `checkJs` + `.d.ts`) and explanatory comments
32
- * so it stays readable; the browser downloads neither. This keeps the shipped
33
- * runtime lean and the gzip budget honest (measured against what users receive),
34
- * WITHOUT minifying — identifiers, structure, and whitespace are all preserved.
35
- *
36
- * Two passes, each conservative: `/** ... *\/` JSDoc blocks, then whole-line
37
- * `//` comments (a line that is nothing but a comment). Trailing `//` after code
38
- * and `//` inside strings/URLs are deliberately left untouched, so no string
39
- * literal is ever harmed.
40
- * @param {string} source
41
- * @returns {string}
42
- */
43
- export function stripRuntimeComments(source: string): string;
44
- /**
45
- * Render the Cloudflare Pages `_headers` file from the route manifest.
46
- *
47
- * Cloudflare applies every matching block in order; when blocks set the same
48
- * header, the later block wins. So we emit the catch-all `/*` first (baseline
49
- * security headers + the reactive CSP, which since 2.1 is eval-free and satisfies
50
- * every page), then one block per static route that re-states the same eval-free
51
- * CSP as defense-in-depth. Reactive routes need no override — the catch-all
52
- * already carries the eval-free CSP.
53
- *
54
- * Clean URLs mean a route like `/docs/` is served at both `/docs` and `/docs/`,
55
- * so each static route emits a path glob (`/docs`, `/docs/*`) that covers both.
56
- * @param {RouteManifestEntry[]} manifest
57
- * @returns {string}
58
- */
59
- export function renderCloudflareHeaders(manifest: RouteManifestEntry[]): string;
60
- /**
61
- * @typedef {import("./config.js").Paths} Paths
62
- * @typedef {import("./compiler.js").Assets} Assets
63
- * @typedef {import("./compiler.js").Meta} Meta
64
- * @typedef {import("./router.js").Route} Route
65
- */
66
- /**
67
- * A built route entry written to `dist/routes.json`.
68
- * @typedef {object} RouteManifestEntry
69
- * @property {string} route Public route path.
70
- * @property {string} file Source file path, relative to cwd, POSIX-separated.
71
- * @property {{ skins: string[], scripts: string[], runtime: boolean }} assets
72
- */
73
- /**
74
- * One source route's record in the dev dependency map (`dist/.wd-dev-deps.json`),
75
- * written by dev builds so a later `--changed` build can rebuild only the routes
76
- * whose dependency graph contains the changed file.
77
- * @typedef {object} DepMapEntry
78
- * @property {string} file Source file, project-relative, POSIX-separated.
79
- * @property {string[]} deps Every source file this route's compile read (the page
80
- * itself, includes, loop JSON data files, colocated `.skin`/`.js`) —
81
- * project-relative, POSIX-separated, sorted.
82
- * @property {string[]} collections Collection names the route loops, so a change
83
- * to any entry of the collection rebuilds this route.
84
- * @property {RouteManifestEntry[]} pages The manifest entries this route emitted
85
- * (one, or one per pagination page), so `routes.json`/`_headers`/the sitemap
86
- * can be reassembled globally without recompiling untouched routes.
87
- */
88
- /** The dev dependency map's filename under `dist/`. */
89
- export const DEP_MAP_FILE: ".wd-dev-deps.json";
90
- /**
91
- * The value `buildSite` returns. `incremental` is present only when a `changed`
92
- * build actually rebuilt a subset of routes (absent on every full rebuild).
93
- */
94
- export type BuildResult = {
95
- routes: RouteManifestEntry[];
96
- distRoot: string;
97
- feeds: {
98
- sitemap: number | null;
99
- rss: number | null;
100
- };
101
- incremental?: {
102
- changed: string[];
103
- rebuilt: string[];
104
- total: number;
105
- } | undefined;
106
- };
107
- /**
108
- * A compiled page bound for a concrete output route. Mirrors `CompiledPage` plus
109
- * the public `route` it's written to — for a paginated listing, page 1 keeps the
110
- * listing route and pages 2+ get `/<route>/page/<n>/`.
111
- */
112
- export type EmittedPage = {
113
- /**
114
- * Public route path this page is written to.
115
- */
116
- route: string;
117
- html: string;
118
- assets: import("./compiler.js").Assets;
119
- warnings: string[];
120
- };
121
- export type Paths = import("./config.js").Paths;
122
- export type Assets = import("./compiler.js").Assets;
123
- export type Meta = import("./compiler.js").Meta;
124
- export type Route = import("./router.js").Route;
125
- /**
126
- * A built route entry written to `dist/routes.json`.
127
- */
128
- export type RouteManifestEntry = {
129
- /**
130
- * Public route path.
131
- */
132
- route: string;
133
- /**
134
- * Source file path, relative to cwd, POSIX-separated.
135
- */
136
- file: string;
137
- assets: {
138
- skins: string[];
139
- scripts: string[];
140
- runtime: boolean;
141
- };
142
- };
143
- /**
144
- * One source route's record in the dev dependency map (`dist/.wd-dev-deps.json`),
145
- * written by dev builds so a later `--changed` build can rebuild only the routes
146
- * whose dependency graph contains the changed file.
147
- */
148
- export type DepMapEntry = {
149
- /**
150
- * Source file, project-relative, POSIX-separated.
151
- */
152
- file: string;
153
- /**
154
- * Every source file this route's compile read (the page
155
- * itself, includes, loop JSON data files, colocated `.skin`/`.js`) —
156
- * project-relative, POSIX-separated, sorted.
157
- */
158
- deps: string[];
159
- /**
160
- * Collection names the route loops, so a change
161
- * to any entry of the collection rebuilds this route.
162
- */
163
- collections: string[];
164
- /**
165
- * The manifest entries this route emitted
166
- * (one, or one per pagination page), so `routes.json`/`_headers`/the sitemap
167
- * can be reassembled globally without recompiling untouched routes.
168
- */
169
- pages: RouteManifestEntry[];
170
- };
@@ -1,97 +0,0 @@
1
- /**
2
- * The structured, machine-readable catalog of the whole `.wd` authoring surface.
3
- * @returns {DirectiveCatalog}
4
- */
5
- export function directiveCatalog(): DirectiveCatalog;
6
- /**
7
- * Render the catalog as a compact llms.txt-style markdown cheatsheet — the
8
- * artifact an app pastes into a small model's system prompt. Generated entirely
9
- * from {@link directiveCatalog}, so it can never disagree with what compiles.
10
- * @returns {string}
11
- */
12
- export function llmsText(): string;
13
- /** The action tokens the catalog exposes — used by the drift guard. */
14
- export const CATALOG_ACTION_TOKENS: string[];
15
- /**
16
- * Whether the directive
17
- * ships zero JS (static), needs the reactive runtime (reactive), or can be
18
- * either depending on whether it reads `:state`/`:store` (either).
19
- */
20
- export type Reactivity = "static" | "reactive" | "either";
21
- export type DirectiveEntry = {
22
- /**
23
- * The directive token (`@loop`, `:state`, `:::`, …).
24
- */
25
- name: string;
26
- /**
27
- * A single line, or an opener with a closer.
28
- */
29
- kind: "line" | "block";
30
- /**
31
- * One-line schematic (`[…]` = optional, `<…>` = slot).
32
- */
33
- syntax: string;
34
- /**
35
- * One-line, plain-language summary.
36
- */
37
- description: string;
38
- /**
39
- * One concrete, compilable line.
40
- */
41
- example: string;
42
- reactive: Reactivity;
43
- };
44
- /**
45
- * A clause / action-op / pipe / operator entry.
46
- */
47
- export type CatalogEntry = {
48
- name: string;
49
- syntax?: string | undefined;
50
- description: string;
51
- example?: string | undefined;
52
- };
53
- export type DirectiveCatalog = {
54
- /**
55
- * The installed Darkmown version.
56
- */
57
- version: string;
58
- /**
59
- * Always `.wd` — the file extension that gates directives.
60
- */
61
- format: string;
62
- directives: DirectiveEntry[];
63
- /**
64
- * Clauses of the `@loop` header (fixed order).
65
- */
66
- loopClauses: CatalogEntry[];
67
- /**
68
- * Per-row meta variables valid in a loop body.
69
- */
70
- loopVariables: CatalogEntry[];
71
- /**
72
- * The `:button`/`:effect`/`:every` action vocabulary.
73
- */
74
- actionOps: CatalogEntry[];
75
- /**
76
- * The `{ value | pipe }` formatter whitelist.
77
- */
78
- formatPipes: CatalogEntry[];
79
- /**
80
- * Comparison operators for `where`/`:if`/`when`.
81
- */
82
- predicateOps: CatalogEntry[];
83
- /**
84
- * Logical joiners (`and`/`or`/`not`).
85
- */
86
- predicateJoiners: string[];
87
- /**
88
- * The `WDxxx` code blocks.
89
- */
90
- errorAreas: import("./errors.js").ErrorArea[];
91
- /**
92
- * Every stable compile-error
93
- * code, with its cause and fix. A thrown error's message starts with its code
94
- * (`[WD201] …`) and mirrors it on `err.wd.code`.
95
- */
96
- errors: import("./errors.js").ErrorEntry[];
97
- };
@@ -1,41 +0,0 @@
1
- /**
2
- * @param {string} line
3
- * @param {Ctx} ctx
4
- * @param {number} index 0-based line index for `file:line` errors.
5
- * @returns {string}
6
- */
7
- export function handleButton(line: string, ctx: Ctx, index: number): string;
8
- /**
9
- * Parse `:effect <watched> -> <actions>` into a zero-output marker the runtime
10
- * watches: when `<watched>` state changes, it runs `<actions>` (the same `:button`
11
- * action vocabulary, `;`-chained). For arbitrary side effects beyond `:computed`
12
- * (derive state) and fetch deps (auto-refetch).
13
- * @param {string} line
14
- * @param {Ctx} ctx
15
- * @param {number} index 0-based line index for `file:line` errors.
16
- * @returns {string}
17
- */
18
- export function handleEffect(line: string, ctx: Ctx, index: number): string;
19
- /**
20
- * Parse `:every <duration> -> <actions>` into a marker the runtime drives on a
21
- * timer: every `<duration>` it runs `<actions>` (the same `:button` vocabulary,
22
- * `;`-chained), and the interval auto-pauses while the tab is hidden. The one time
23
- * primitive — behind live polling (`:every 5s -> board refetch`), clocks and
24
- * countdowns (`:every 1s -> seconds++`), and slideshow autoplay (`:every 4s -> slide++`).
25
- * @param {string} line
26
- * @param {Ctx} ctx
27
- * @param {number} index 0-based line index for `file:line` errors.
28
- * @returns {string}
29
- */
30
- export function handleEvery(line: string, ctx: Ctx, index: number): string;
31
- /**
32
- * @typedef {import("./context.js").Ctx} Ctx
33
- * @typedef {import("./context.js").Action} Action
34
- */
35
- export const BUTTON_EXAMPLE: ":button \"Add one\" -> count++";
36
- export const EFFECT_EXAMPLE: ":effect query -> searches++";
37
- export const EVERY_EXAMPLE: ":every 5s -> seconds++";
38
- export const ACTION_EXAMPLE: "count++";
39
- export const ACTION_USE: "Use: name++, name--, n += k, n -= k, name = v, flag toggle, list append/prepend v, list toggle v, list remove v, x clear, obj merge other, obj delete key, name reset — chain with \";\" — e.g. count++";
40
- export type Ctx = import("./context.js").Ctx;
41
- export type Action = import("./context.js").Action;
@@ -1,11 +0,0 @@
1
- /**
2
- * @typedef {import("./context.js").Ctx} Ctx
3
- */
4
- /**
5
- * Parse a `.wd` body line-by-line into HTML, mixing directives and prose.
6
- * @param {string[]} lines
7
- * @param {Ctx} ctx
8
- * @returns {string}
9
- */
10
- export function compileBody(lines: string[], ctx: Ctx): string;
11
- export type Ctx = import("./context.js").Ctx;
@@ -1,76 +0,0 @@
1
- /**
2
- * Build the collection index from the router's discovered routes: one entry per
3
- * `site/pages/<name>/…` route, grouped under the FIRST path segment (the
4
- * collection name). The home route, top-level pages, and the synthetic `/404/`
5
- * route are not entries. Reuses each route's already-parsed `meta` (no re-parse)
6
- * and reads the `.md` body only for the excerpt fallback. When a collection has
7
- * a `_schema.wd`, every entry is validated against it here (throwing on the
8
- * first violation), so a malformed entry fails the build with a `file:line`.
9
- *
10
- * @param {Route[]} routes Post-draft-filter routes from `discoverRoutes`.
11
- * @param {Paths} paths Resolved project paths (`routesRoot` for `_schema.wd`).
12
- * @param {import("./reader.js").Reader} [reader] Source reader (fs-backed by
13
- * default; pass an in-memory reader to build collections without a filesystem).
14
- * @returns {Map<string, CollectionRow[]>} Collection name → entry rows.
15
- */
16
- export function buildCollections(routes: Route[], paths: Paths, reader?: import("./reader.js").Reader): Map<string, CollectionRow[]>;
17
- /**
18
- * A parsed `_schema.wd` field rule.
19
- * @typedef {object} SchemaField
20
- * @property {string} name Field name.
21
- * @property {string} type One of {@link SCHEMA_TYPES}.
22
- * @property {boolean} optional Whether the field may be absent (`?` modifier).
23
- */
24
- /**
25
- * Read + parse a collection's `_schema.wd`, or null when the file is absent
26
- * (validation is opt-in). The schema is frontmatter-shaped — one `field: type`
27
- * line per rule inside the `---` block — so authors write it exactly like the
28
- * frontmatter it validates. Each type must be in the closed {@link SCHEMA_TYPES}
29
- * vocabulary (`?` suffix = optional); an unknown token is a compile error in the
30
- * schema file itself, pointing at the offending line.
31
- * @param {string} name Collection name.
32
- * @param {Paths} paths
33
- * @param {import("./reader.js").Reader} [reader] Source reader (fs-backed by default).
34
- * @returns {SchemaField[] | null}
35
- */
36
- export function readSchema(name: string, paths: Paths, reader?: import("./reader.js").Reader): SchemaField[] | null;
37
- /**
38
- * Parse a `_schema.wd` source into field rules. The schema fields live in the
39
- * frontmatter block; the body (if any) is ignored, so a schema file can carry a
40
- * prose note after its `---` fence. Each field line is `name: type` where type
41
- * is a closed token with an optional trailing `?`.
42
- * @param {string} raw `_schema.wd` file contents.
43
- * @param {string} file Absolute path, for `file:line` errors.
44
- * @returns {SchemaField[]}
45
- */
46
- export function parseSchema(raw: string, file: string): SchemaField[];
47
- /**
48
- * A parsed `_schema.wd` field rule.
49
- */
50
- export type SchemaField = {
51
- /**
52
- * Field name.
53
- */
54
- name: string;
55
- /**
56
- * One of {@link SCHEMA_TYPES}.
57
- */
58
- type: string;
59
- /**
60
- * Whether the field may be absent (`?` modifier).
61
- */
62
- optional: boolean;
63
- };
64
- export type Paths = import("./context.js").Paths;
65
- export type Meta = import("./context.js").Meta;
66
- export type Route = import("../router.js").Route;
67
- /**
68
- * A collection entry row: every frontmatter field, plus derived `url`/`slug`/
69
- * `excerpt`. Keyed loosely so authors' custom frontmatter keys pass through to
70
- * `{ post.whatever }` and `where`/`sort` without a closed schema here.
71
- */
72
- export type CollectionRow = Record<string, unknown> & {
73
- url: string;
74
- slug: string;
75
- excerpt: string;
76
- };