@zvndev/darkmown 2.2.0 → 2.3.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/CHANGELOG.md +13 -0
- package/README.md +34 -2
- package/docs/spec-alignment.md +10 -0
- package/package.json +16 -11
- package/site/pages/docs/index.wd +14 -0
- package/site/pages/playground/index.js +47 -46
- package/src/catalog.js +16 -1
- package/src/compiler/actions.js +42 -22
- package/src/compiler/body.js +36 -14
- package/src/compiler/collections.js +16 -10
- package/src/compiler/context.js +39 -10
- package/src/compiler/fetch.js +39 -15
- package/src/compiler/format.js +5 -2
- package/src/compiler/forms.js +91 -26
- package/src/compiler/frontmatter.js +11 -2
- package/src/compiler/fs-reader.js +2 -1
- package/src/compiler/image-size.js +340 -0
- package/src/compiler/includes.js +8 -4
- package/src/compiler/interpolation.js +15 -7
- package/src/compiler/loops.js +63 -35
- package/src/compiler/markdown.js +4 -3
- package/src/compiler/media.js +17 -3
- package/src/compiler/page.js +8 -6
- package/src/compiler/predicates.js +49 -24
- package/src/compiler/reader.js +12 -2
- package/src/compiler/state.js +16 -2
- package/src/compiler/structure.js +24 -14
- package/src/deploy.js +8 -4
- package/src/errors.js +1156 -0
- package/src/router.js +7 -4
- package/src/scaffold.js +4 -2
- package/src/skin.js +17 -6
- package/types/api-runner.d.ts +94 -0
- package/types/builder.d.ts +141 -10
- package/types/catalog.d.ts +97 -0
- package/types/compiler/actions.d.ts +41 -0
- package/types/compiler/body.d.ts +11 -0
- package/types/compiler/collections.d.ts +76 -0
- package/types/compiler/context.d.ts +661 -0
- package/types/compiler/directives.d.ts +6 -0
- package/types/compiler/expr-ast.d.ts +20 -0
- package/types/compiler/fetch.d.ts +29 -0
- package/types/compiler/format.d.ts +49 -0
- package/types/compiler/forms.d.ts +94 -0
- package/types/compiler/frontmatter.d.ts +33 -0
- package/types/compiler/fs-reader.d.ts +7 -0
- package/types/compiler/image-size.d.ts +14 -0
- package/types/compiler/includes.d.ts +100 -0
- package/types/compiler/index.d.ts +5 -0
- package/types/compiler/interpolation.d.ts +115 -0
- package/types/compiler/loops.d.ts +36 -0
- package/types/compiler/markdown.d.ts +34 -0
- package/types/compiler/media.d.ts +32 -0
- package/types/compiler/page.d.ts +109 -0
- package/types/compiler/predicates.d.ts +50 -0
- package/types/compiler/reader.d.ts +56 -0
- package/types/compiler/state.d.ts +68 -0
- package/types/compiler/structure.d.ts +56 -0
- package/types/compiler.d.ts +35 -223
- package/types/dev.d.ts +47 -2
- package/types/errors.d.ts +100 -0
- package/types/feeds.d.ts +150 -0
- package/types/headers.d.ts +44 -0
- package/types/highlight.d.ts +24 -0
- package/types/router.d.ts +42 -3
- package/types/scaffold.d.ts +15 -3
- package/types/skin.d.ts +28 -1
- package/types/statics.d.ts +2 -1
|
@@ -0,0 +1,661 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import("../config.js").Paths} Paths
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Frontmatter values are scalars or inline arrays of scalars.
|
|
6
|
+
* @typedef {string | number | boolean | null | Array<string | number | boolean | null>} FrontmatterValue
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Parsed page frontmatter, keyed by field name.
|
|
10
|
+
* @typedef {Record<string, FrontmatterValue>} Meta
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Collected output assets for a compiled document.
|
|
14
|
+
* @typedef {object} Assets
|
|
15
|
+
* @property {Set<string>} skins Public hrefs of compiled skin stylesheets.
|
|
16
|
+
* @property {Set<string>} scripts Public hrefs of colocated page scripts.
|
|
17
|
+
* @property {Map<string, string>} files Source path → public href for emitted assets.
|
|
18
|
+
* @property {boolean} runtime Whether the reactive runtime is required.
|
|
19
|
+
* @property {Set<string>} behaviors Names of framework behavior modules this page
|
|
20
|
+
* needs (`slider` is compile-time only and never appears here; `sortable`,
|
|
21
|
+
* `carousel` each emit a pay-for-what-you-use `/__wd/behaviors/<name>.js`).
|
|
22
|
+
* @property {boolean} hasCode Whether the page has a build-time-highlighted code
|
|
23
|
+
* block, so the framework highlight stylesheet (`/__wd/highlight.css`) is
|
|
24
|
+
* emitted and linked — pay-for-what-you-use, zero JS.
|
|
25
|
+
* @property {Set<string>} scopedSkins Source paths of colocated `.skin` files
|
|
26
|
+
* that opted into scoping (`scoped` first line). The builder emits these with
|
|
27
|
+
* the scope attribute and runs the unused-selector warning against the stamped
|
|
28
|
+
* subtree; the HTML stamp uses them to scope the matching page/include subtree.
|
|
29
|
+
*/
|
|
30
|
+
/**
|
|
31
|
+
* The pagination intent a `@loop … paginate N` records during compile, so the
|
|
32
|
+
* builder can multiply routes (page 1 at the listing route, 2+ at
|
|
33
|
+
* `/<route>/page/<n>/`). `total` is the post-`where`/`sort` page count for the
|
|
34
|
+
* collection the loop drew from.
|
|
35
|
+
* @typedef {object} Pagination
|
|
36
|
+
* @property {number} perPage Rows per page (the `paginate N` value).
|
|
37
|
+
* @property {number} total Total page count (≥ 1).
|
|
38
|
+
* @property {string} collection Collection name the loop paginated.
|
|
39
|
+
*/
|
|
40
|
+
/**
|
|
41
|
+
* Per-document compilation accumulator shared across includes/sections.
|
|
42
|
+
* @typedef {object} Compilation
|
|
43
|
+
* @property {Assets} assets
|
|
44
|
+
* @property {Map<string, unknown>} state Declared state keys → initial values.
|
|
45
|
+
* @property {Set<string>} stores Page-global store names (a subset of state keys).
|
|
46
|
+
* @property {Set<string>} fetchKeys Base state keys declared by `:fetch`, so
|
|
47
|
+
* bare `:if <key>_loading` / `:if <key>_error` regions get compile-time
|
|
48
|
+
* `role`/`aria-live` announcements.
|
|
49
|
+
* @property {string[]} warnings Non-fatal authoring hints.
|
|
50
|
+
* @property {number} sectionCounter Counter for auto-generated section ids.
|
|
51
|
+
* @property {Map<string, number>} headingSlugs Heading-slug occurrence counts,
|
|
52
|
+
* shared across prose chunks and includes so anchor ids dedupe document-wide.
|
|
53
|
+
* @property {Map<string, import("./collections.js").CollectionRow[]>} collections
|
|
54
|
+
* Collection name → entry rows, built from the router's routes and threaded in
|
|
55
|
+
* so a bare-name `@loop blog into post` resolves to its entries at build time.
|
|
56
|
+
* @property {import("./context.js").Pagination | null} pagination The pagination
|
|
57
|
+
* intent a `@loop … paginate N` recorded this compile, or null. The builder
|
|
58
|
+
* reads it to multiply routes; one paginated loop per page is supported.
|
|
59
|
+
* @property {Set<string>} deps Absolute paths of every source file this compile
|
|
60
|
+
* read: the page itself, every `@include` target, and every `@loop` JSON data
|
|
61
|
+
* file. The dev builder unions these (plus colocated assets) into the per-route
|
|
62
|
+
* dependency map that drives incremental rebuilds.
|
|
63
|
+
* @property {Set<string>} collectionsUsed Names of the collections this compile
|
|
64
|
+
* looped, so a change to any entry of a collection rebuilds its consumers.
|
|
65
|
+
* @property {import("./reader.js").Reader} reader The file reader every source
|
|
66
|
+
* read threads through — the real filesystem by default, or an in-memory map
|
|
67
|
+
* for `compileFromMemory`. Set once by `createCompilation` and reached via
|
|
68
|
+
* `ctx.comp.reader` in the directive handlers (includes, loop data).
|
|
69
|
+
*/
|
|
70
|
+
/**
|
|
71
|
+
* A lexical scope chain for static interpolation values (include args, loop vars).
|
|
72
|
+
* @typedef {object} Scope
|
|
73
|
+
* @property {Scope | null} parent
|
|
74
|
+
* @property {Record<string, unknown>} vars
|
|
75
|
+
*/
|
|
76
|
+
/**
|
|
77
|
+
* Per-file compile context threaded through the directive handlers.
|
|
78
|
+
* @typedef {object} Ctx
|
|
79
|
+
* @property {string} file Absolute path to the file being compiled.
|
|
80
|
+
* @property {number} [bodyLine] 0-based file line the compiled body starts on
|
|
81
|
+
* (the frontmatter offset), so `at` reports true file line numbers.
|
|
82
|
+
* @property {number} [lineOffset] 0-based body line the current `compileBody`
|
|
83
|
+
* slice starts on. Block handlers recurse with {@link nestedCtx}, so a line
|
|
84
|
+
* index inside a nested block body still maps to the true file line.
|
|
85
|
+
* @property {Paths} context Resolved project paths.
|
|
86
|
+
* @property {string[]} stack Include stack (real paths) for cycle detection.
|
|
87
|
+
* @property {Scope} scope Static value scope chain.
|
|
88
|
+
* @property {Compilation} comp Shared compilation accumulator.
|
|
89
|
+
* @property {string[]} sections Active section-id scope chain.
|
|
90
|
+
* @property {string | null} loopItem Name of the current reactive loop item, if any.
|
|
91
|
+
* @property {string} [loopKey] State key of the list being looped, if any.
|
|
92
|
+
* @property {number} [reactiveDepth] Number of enclosing REACTIVE `@loop` levels
|
|
93
|
+
* (0 at top level). The runtime reconciles at most two nested `data-wd-loop`
|
|
94
|
+
* levels — a third paints empty — so a third reactive level is rejected at
|
|
95
|
+
* compile time. Static (build-unrolled) loops flatten to markup and don't add
|
|
96
|
+
* a level, so they carry the count through without incrementing it.
|
|
97
|
+
* @property {{ at: string, line: string }} [loopOpener] The current `@loop`
|
|
98
|
+
* opener's `file:line` + raw text, set when descending into a loop body so the
|
|
99
|
+
* reactive-nesting-depth error can point at the offending opener.
|
|
100
|
+
* @property {boolean} [loopMeta] Inside a loop body, so `$index`/`$first`/… are valid.
|
|
101
|
+
* @property {import("markdown-it").default} [md] Markdown-it instance selected for this file.
|
|
102
|
+
* @property {(lines: string[], ctx: Ctx) => string} compileBody The body
|
|
103
|
+
* dispatcher, threaded through the context so block handlers (`:if`, `:::`,
|
|
104
|
+
* `:form`, `@loop`, …) recurse into nested bodies without importing the
|
|
105
|
+
* dispatcher back — the module graph stays an import-cycle-free DAG.
|
|
106
|
+
* @property {(file: string, context: Paths, stack: string[], scope: Scope, comp: Compilation, sections: string[], loopItem: string | null, reactiveDepth?: number, loopOpener?: { at: string, line: string } | null) => { meta: Meta, html: string }} compileFile
|
|
107
|
+
* The per-file compile, threaded for the same reason so `@include` can
|
|
108
|
+
* compile its target file. `reactiveDepth`/`loopOpener` carry the enclosing
|
|
109
|
+
* reactive-loop nesting across the include boundary so the depth guard holds.
|
|
110
|
+
*/
|
|
111
|
+
/**
|
|
112
|
+
* A compiled page document.
|
|
113
|
+
* @typedef {object} CompiledDocument
|
|
114
|
+
* @property {Meta} meta
|
|
115
|
+
* @property {string} html
|
|
116
|
+
* @property {Assets} assets
|
|
117
|
+
* @property {string[]} warnings
|
|
118
|
+
* @property {Pagination | null} pagination The pagination intent a paginated
|
|
119
|
+
* `@loop` recorded, or null. The builder reads it to multiply routes.
|
|
120
|
+
* @property {Set<string>} deps Absolute source-file dependencies of this compile.
|
|
121
|
+
* @property {Set<string>} collectionsUsed Collection names this compile looped.
|
|
122
|
+
*/
|
|
123
|
+
/**
|
|
124
|
+
* A compiled page: the document plus its full HTML shell.
|
|
125
|
+
* @typedef {object} CompiledPage
|
|
126
|
+
* @property {Meta} meta
|
|
127
|
+
* @property {string} html
|
|
128
|
+
* @property {Assets} assets
|
|
129
|
+
* @property {string[]} warnings
|
|
130
|
+
* @property {Pagination | null} pagination The pagination intent a paginated
|
|
131
|
+
* `@loop` recorded, or null. The builder reads it to multiply routes.
|
|
132
|
+
* @property {Set<string>} deps Absolute source-file dependencies of this compile.
|
|
133
|
+
* @property {Set<string>} collectionsUsed Collection names this compile looped.
|
|
134
|
+
*/
|
|
135
|
+
/**
|
|
136
|
+
* Structured, machine-readable companion to a compile error's string message.
|
|
137
|
+
* The string `message` contract is unchanged; `wd` gives an AI edit-loop (or an
|
|
138
|
+
* editor) the same facts without re-parsing the prose: which code, which
|
|
139
|
+
* file/line, the corrective `Use:` template, and one concrete compilable
|
|
140
|
+
* example line.
|
|
141
|
+
* @typedef {object} WdErrorInfo
|
|
142
|
+
* @property {string} code Stable error code (`WD` + three digits, e.g. `WD201`).
|
|
143
|
+
* Every code is registered in `src/errors.js` with a title, cause, and fix,
|
|
144
|
+
* and documented in `docs/errors.md`. {@link wdError} prefixes the string
|
|
145
|
+
* message with `[<code>] `, so the code is greppable from the message too.
|
|
146
|
+
* @property {string} [file] Absolute path of the source file the error is in,
|
|
147
|
+
* when the throwing layer knows one (`compileSkin` is a pure string→string
|
|
148
|
+
* pass and a collection-row check names the entry route instead).
|
|
149
|
+
* @property {number} [line] 1-based file line the error points at, when known
|
|
150
|
+
* (some errors — e.g. a bad `where` operand — are file-scoped only, matching
|
|
151
|
+
* the string message, which likewise omits the line there).
|
|
152
|
+
* @property {string} [hint] The corrective `Use:` template (without the `Use: ` prefix).
|
|
153
|
+
* @property {string} [example] One concrete, compilable directive line.
|
|
154
|
+
*/
|
|
155
|
+
/**
|
|
156
|
+
* A compiled `@loop … where` predicate.
|
|
157
|
+
* @typedef {object} Predicate
|
|
158
|
+
* @property {string} body Safe JS boolean expression over `I()`/`S()`/`C()`.
|
|
159
|
+
* @property {boolean} refsState Whether the predicate reads declared state.
|
|
160
|
+
*/
|
|
161
|
+
/**
|
|
162
|
+
* A loop offset/limit argument: a non-negative integer literal or a state key.
|
|
163
|
+
* @typedef {{ kind: "literal", value: number } | { kind: "key", value: string }} NumArg
|
|
164
|
+
*/
|
|
165
|
+
/**
|
|
166
|
+
* Loop clause configuration shared by the static and reactive paths.
|
|
167
|
+
* @typedef {object} LoopOpts
|
|
168
|
+
* @property {Predicate | null} where
|
|
169
|
+
* @property {{ key: string, keyKind: "literal" | "key", dir: string, dirKind: "literal" | "key" } | null} sort A literal item field + asc/desc, or a `:state`/`:store` key for either (reactive, clickable-header sort).
|
|
170
|
+
* @property {boolean} reverse
|
|
171
|
+
* @property {NumArg | null} offset
|
|
172
|
+
* @property {NumArg | null} limit
|
|
173
|
+
* @property {string[] | null} empty Empty-branch body lines, if any.
|
|
174
|
+
* @property {number} [emptyStart] 0-based index the empty branch starts at
|
|
175
|
+
* within the loop body, so its nested errors report the true file line.
|
|
176
|
+
* @property {boolean} clauseRefsState Whether offset/limit reference state.
|
|
177
|
+
* @property {boolean} sortable Drag-to-reorder the underlying :state/:store list
|
|
178
|
+
* (the `sortable` clause). Only valid on a plain reactive state-key loop.
|
|
179
|
+
* @property {number | null} paginate Rows-per-page for a `paginate N` clause, or
|
|
180
|
+
* null. Only valid on a collection loop; multiplies the listing into static
|
|
181
|
+
* pages (page 1 at the route, 2+ at `/<route>/page/<n>/`) and exposes a `page`
|
|
182
|
+
* pager to the template scope.
|
|
183
|
+
*/
|
|
184
|
+
/**
|
|
185
|
+
* A parsed `:button` action.
|
|
186
|
+
* @typedef {object} Action
|
|
187
|
+
* @property {string} op Runtime operation (inc/dec/add/sub/append/prepend/set/toggle/member-toggle/remove/remove-value/clear/merge/delete/reset/append-row).
|
|
188
|
+
* @property {string} target State key (possibly dotted) the action mutates.
|
|
189
|
+
* @property {unknown} [value] Literal value for value-carrying ops.
|
|
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;
|
|
265
|
+
export const pageIncludeExtensions: string[];
|
|
266
|
+
/** @type {Record<string, string>} */
|
|
267
|
+
export const LOOP_META: Record<string, string>;
|
|
268
|
+
export type Paths = import("../config.js").Paths;
|
|
269
|
+
/**
|
|
270
|
+
* Frontmatter values are scalars or inline arrays of scalars.
|
|
271
|
+
*/
|
|
272
|
+
export type FrontmatterValue = string | number | boolean | null | Array<string | number | boolean | null>;
|
|
273
|
+
/**
|
|
274
|
+
* Parsed page frontmatter, keyed by field name.
|
|
275
|
+
*/
|
|
276
|
+
export type Meta = Record<string, FrontmatterValue>;
|
|
277
|
+
/**
|
|
278
|
+
* Collected output assets for a compiled document.
|
|
279
|
+
*/
|
|
280
|
+
export type Assets = {
|
|
281
|
+
/**
|
|
282
|
+
* Public hrefs of compiled skin stylesheets.
|
|
283
|
+
*/
|
|
284
|
+
skins: Set<string>;
|
|
285
|
+
/**
|
|
286
|
+
* Public hrefs of colocated page scripts.
|
|
287
|
+
*/
|
|
288
|
+
scripts: Set<string>;
|
|
289
|
+
/**
|
|
290
|
+
* Source path → public href for emitted assets.
|
|
291
|
+
*/
|
|
292
|
+
files: Map<string, string>;
|
|
293
|
+
/**
|
|
294
|
+
* Whether the reactive runtime is required.
|
|
295
|
+
*/
|
|
296
|
+
runtime: boolean;
|
|
297
|
+
/**
|
|
298
|
+
* Names of framework behavior modules this page
|
|
299
|
+
* needs (`slider` is compile-time only and never appears here; `sortable`,
|
|
300
|
+
* `carousel` each emit a pay-for-what-you-use `/__wd/behaviors/<name>.js`).
|
|
301
|
+
*/
|
|
302
|
+
behaviors: Set<string>;
|
|
303
|
+
/**
|
|
304
|
+
* Whether the page has a build-time-highlighted code
|
|
305
|
+
* block, so the framework highlight stylesheet (`/__wd/highlight.css`) is
|
|
306
|
+
* emitted and linked — pay-for-what-you-use, zero JS.
|
|
307
|
+
*/
|
|
308
|
+
hasCode: boolean;
|
|
309
|
+
/**
|
|
310
|
+
* Source paths of colocated `.skin` files
|
|
311
|
+
* that opted into scoping (`scoped` first line). The builder emits these with
|
|
312
|
+
* the scope attribute and runs the unused-selector warning against the stamped
|
|
313
|
+
* subtree; the HTML stamp uses them to scope the matching page/include subtree.
|
|
314
|
+
*/
|
|
315
|
+
scopedSkins: Set<string>;
|
|
316
|
+
};
|
|
317
|
+
/**
|
|
318
|
+
* The pagination intent a `@loop … paginate N` records during compile, so the
|
|
319
|
+
* builder can multiply routes (page 1 at the listing route, 2+ at
|
|
320
|
+
* `/<route>/page/<n>/`). `total` is the post-`where`/`sort` page count for the
|
|
321
|
+
* collection the loop drew from.
|
|
322
|
+
*/
|
|
323
|
+
export type Pagination = {
|
|
324
|
+
/**
|
|
325
|
+
* Rows per page (the `paginate N` value).
|
|
326
|
+
*/
|
|
327
|
+
perPage: number;
|
|
328
|
+
/**
|
|
329
|
+
* Total page count (≥ 1).
|
|
330
|
+
*/
|
|
331
|
+
total: number;
|
|
332
|
+
/**
|
|
333
|
+
* Collection name the loop paginated.
|
|
334
|
+
*/
|
|
335
|
+
collection: string;
|
|
336
|
+
};
|
|
337
|
+
/**
|
|
338
|
+
* Per-document compilation accumulator shared across includes/sections.
|
|
339
|
+
*/
|
|
340
|
+
export type Compilation = {
|
|
341
|
+
assets: Assets;
|
|
342
|
+
/**
|
|
343
|
+
* Declared state keys → initial values.
|
|
344
|
+
*/
|
|
345
|
+
state: Map<string, unknown>;
|
|
346
|
+
/**
|
|
347
|
+
* Page-global store names (a subset of state keys).
|
|
348
|
+
*/
|
|
349
|
+
stores: Set<string>;
|
|
350
|
+
/**
|
|
351
|
+
* Base state keys declared by `:fetch`, so
|
|
352
|
+
* bare `:if <key>_loading` / `:if <key>_error` regions get compile-time
|
|
353
|
+
* `role`/`aria-live` announcements.
|
|
354
|
+
*/
|
|
355
|
+
fetchKeys: Set<string>;
|
|
356
|
+
/**
|
|
357
|
+
* Non-fatal authoring hints.
|
|
358
|
+
*/
|
|
359
|
+
warnings: string[];
|
|
360
|
+
/**
|
|
361
|
+
* Counter for auto-generated section ids.
|
|
362
|
+
*/
|
|
363
|
+
sectionCounter: number;
|
|
364
|
+
/**
|
|
365
|
+
* Heading-slug occurrence counts,
|
|
366
|
+
* shared across prose chunks and includes so anchor ids dedupe document-wide.
|
|
367
|
+
*/
|
|
368
|
+
headingSlugs: Map<string, number>;
|
|
369
|
+
/**
|
|
370
|
+
* Collection name → entry rows, built from the router's routes and threaded in
|
|
371
|
+
* so a bare-name `@loop blog into post` resolves to its entries at build time.
|
|
372
|
+
*/
|
|
373
|
+
collections: Map<string, import("./collections.js").CollectionRow[]>;
|
|
374
|
+
/**
|
|
375
|
+
* The pagination
|
|
376
|
+
* intent a `@loop … paginate N` recorded this compile, or null. The builder
|
|
377
|
+
* reads it to multiply routes; one paginated loop per page is supported.
|
|
378
|
+
*/
|
|
379
|
+
pagination: import("./context.js").Pagination | null;
|
|
380
|
+
/**
|
|
381
|
+
* Absolute paths of every source file this compile
|
|
382
|
+
* read: the page itself, every `@include` target, and every `@loop` JSON data
|
|
383
|
+
* file. The dev builder unions these (plus colocated assets) into the per-route
|
|
384
|
+
* dependency map that drives incremental rebuilds.
|
|
385
|
+
*/
|
|
386
|
+
deps: Set<string>;
|
|
387
|
+
/**
|
|
388
|
+
* Names of the collections this compile
|
|
389
|
+
* looped, so a change to any entry of a collection rebuilds its consumers.
|
|
390
|
+
*/
|
|
391
|
+
collectionsUsed: Set<string>;
|
|
392
|
+
/**
|
|
393
|
+
* The file reader every source
|
|
394
|
+
* read threads through — the real filesystem by default, or an in-memory map
|
|
395
|
+
* for `compileFromMemory`. Set once by `createCompilation` and reached via
|
|
396
|
+
* `ctx.comp.reader` in the directive handlers (includes, loop data).
|
|
397
|
+
*/
|
|
398
|
+
reader: import("./reader.js").Reader;
|
|
399
|
+
};
|
|
400
|
+
/**
|
|
401
|
+
* A lexical scope chain for static interpolation values (include args, loop vars).
|
|
402
|
+
*/
|
|
403
|
+
export type Scope = {
|
|
404
|
+
parent: Scope | null;
|
|
405
|
+
vars: Record<string, unknown>;
|
|
406
|
+
};
|
|
407
|
+
/**
|
|
408
|
+
* Per-file compile context threaded through the directive handlers.
|
|
409
|
+
*/
|
|
410
|
+
export type Ctx = {
|
|
411
|
+
/**
|
|
412
|
+
* Absolute path to the file being compiled.
|
|
413
|
+
*/
|
|
414
|
+
file: string;
|
|
415
|
+
/**
|
|
416
|
+
* 0-based file line the compiled body starts on
|
|
417
|
+
* (the frontmatter offset), so `at` reports true file line numbers.
|
|
418
|
+
*/
|
|
419
|
+
bodyLine?: number | undefined;
|
|
420
|
+
/**
|
|
421
|
+
* 0-based body line the current `compileBody`
|
|
422
|
+
* slice starts on. Block handlers recurse with {@link nestedCtx}, so a line
|
|
423
|
+
* index inside a nested block body still maps to the true file line.
|
|
424
|
+
*/
|
|
425
|
+
lineOffset?: number | undefined;
|
|
426
|
+
/**
|
|
427
|
+
* Resolved project paths.
|
|
428
|
+
*/
|
|
429
|
+
context: Paths;
|
|
430
|
+
/**
|
|
431
|
+
* Include stack (real paths) for cycle detection.
|
|
432
|
+
*/
|
|
433
|
+
stack: string[];
|
|
434
|
+
/**
|
|
435
|
+
* Static value scope chain.
|
|
436
|
+
*/
|
|
437
|
+
scope: Scope;
|
|
438
|
+
/**
|
|
439
|
+
* Shared compilation accumulator.
|
|
440
|
+
*/
|
|
441
|
+
comp: Compilation;
|
|
442
|
+
/**
|
|
443
|
+
* Active section-id scope chain.
|
|
444
|
+
*/
|
|
445
|
+
sections: string[];
|
|
446
|
+
/**
|
|
447
|
+
* Name of the current reactive loop item, if any.
|
|
448
|
+
*/
|
|
449
|
+
loopItem: string | null;
|
|
450
|
+
/**
|
|
451
|
+
* State key of the list being looped, if any.
|
|
452
|
+
*/
|
|
453
|
+
loopKey?: string | undefined;
|
|
454
|
+
/**
|
|
455
|
+
* Number of enclosing REACTIVE `@loop` levels
|
|
456
|
+
* (0 at top level). The runtime reconciles at most two nested `data-wd-loop`
|
|
457
|
+
* levels — a third paints empty — so a third reactive level is rejected at
|
|
458
|
+
* compile time. Static (build-unrolled) loops flatten to markup and don't add
|
|
459
|
+
* a level, so they carry the count through without incrementing it.
|
|
460
|
+
*/
|
|
461
|
+
reactiveDepth?: number | undefined;
|
|
462
|
+
/**
|
|
463
|
+
* The current `@loop`
|
|
464
|
+
* opener's `file:line` + raw text, set when descending into a loop body so the
|
|
465
|
+
* reactive-nesting-depth error can point at the offending opener.
|
|
466
|
+
*/
|
|
467
|
+
loopOpener?: {
|
|
468
|
+
at: string;
|
|
469
|
+
line: string;
|
|
470
|
+
} | undefined;
|
|
471
|
+
/**
|
|
472
|
+
* Inside a loop body, so `$index`/`$first`/… are valid.
|
|
473
|
+
*/
|
|
474
|
+
loopMeta?: boolean | undefined;
|
|
475
|
+
/**
|
|
476
|
+
* Markdown-it instance selected for this file.
|
|
477
|
+
*/
|
|
478
|
+
md?: import("markdown-it").default | undefined;
|
|
479
|
+
/**
|
|
480
|
+
* The body
|
|
481
|
+
* dispatcher, threaded through the context so block handlers (`:if`, `:::`,
|
|
482
|
+
* `:form`, `@loop`, …) recurse into nested bodies without importing the
|
|
483
|
+
* dispatcher back — the module graph stays an import-cycle-free DAG.
|
|
484
|
+
*/
|
|
485
|
+
compileBody: (lines: string[], ctx: Ctx) => string;
|
|
486
|
+
/**
|
|
487
|
+
* The per-file compile, threaded for the same reason so `@include` can
|
|
488
|
+
* compile its target file. `reactiveDepth`/`loopOpener` carry the enclosing
|
|
489
|
+
* reactive-loop nesting across the include boundary so the depth guard holds.
|
|
490
|
+
*/
|
|
491
|
+
compileFile: (file: string, context: Paths, stack: string[], scope: Scope, comp: Compilation, sections: string[], loopItem: string | null, reactiveDepth?: number, loopOpener?: {
|
|
492
|
+
at: string;
|
|
493
|
+
line: string;
|
|
494
|
+
} | null) => {
|
|
495
|
+
meta: Meta;
|
|
496
|
+
html: string;
|
|
497
|
+
};
|
|
498
|
+
};
|
|
499
|
+
/**
|
|
500
|
+
* A compiled page document.
|
|
501
|
+
*/
|
|
502
|
+
export type CompiledDocument = {
|
|
503
|
+
meta: Meta;
|
|
504
|
+
html: string;
|
|
505
|
+
assets: Assets;
|
|
506
|
+
warnings: string[];
|
|
507
|
+
/**
|
|
508
|
+
* The pagination intent a paginated
|
|
509
|
+
* `@loop` recorded, or null. The builder reads it to multiply routes.
|
|
510
|
+
*/
|
|
511
|
+
pagination: Pagination | null;
|
|
512
|
+
/**
|
|
513
|
+
* Absolute source-file dependencies of this compile.
|
|
514
|
+
*/
|
|
515
|
+
deps: Set<string>;
|
|
516
|
+
/**
|
|
517
|
+
* Collection names this compile looped.
|
|
518
|
+
*/
|
|
519
|
+
collectionsUsed: Set<string>;
|
|
520
|
+
};
|
|
521
|
+
/**
|
|
522
|
+
* A compiled page: the document plus its full HTML shell.
|
|
523
|
+
*/
|
|
524
|
+
export type CompiledPage = {
|
|
525
|
+
meta: Meta;
|
|
526
|
+
html: string;
|
|
527
|
+
assets: Assets;
|
|
528
|
+
warnings: string[];
|
|
529
|
+
/**
|
|
530
|
+
* The pagination intent a paginated
|
|
531
|
+
* `@loop` recorded, or null. The builder reads it to multiply routes.
|
|
532
|
+
*/
|
|
533
|
+
pagination: Pagination | null;
|
|
534
|
+
/**
|
|
535
|
+
* Absolute source-file dependencies of this compile.
|
|
536
|
+
*/
|
|
537
|
+
deps: Set<string>;
|
|
538
|
+
/**
|
|
539
|
+
* Collection names this compile looped.
|
|
540
|
+
*/
|
|
541
|
+
collectionsUsed: Set<string>;
|
|
542
|
+
};
|
|
543
|
+
/**
|
|
544
|
+
* Structured, machine-readable companion to a compile error's string message.
|
|
545
|
+
* The string `message` contract is unchanged; `wd` gives an AI edit-loop (or an
|
|
546
|
+
* editor) the same facts without re-parsing the prose: which code, which
|
|
547
|
+
* file/line, the corrective `Use:` template, and one concrete compilable
|
|
548
|
+
* example line.
|
|
549
|
+
*/
|
|
550
|
+
export type WdErrorInfo = {
|
|
551
|
+
/**
|
|
552
|
+
* Stable error code (`WD` + three digits, e.g. `WD201`).
|
|
553
|
+
* Every code is registered in `src/errors.js` with a title, cause, and fix,
|
|
554
|
+
* and documented in `docs/errors.md`. {@link wdError} prefixes the string
|
|
555
|
+
* message with `[<code>] `, so the code is greppable from the message too.
|
|
556
|
+
*/
|
|
557
|
+
code: string;
|
|
558
|
+
/**
|
|
559
|
+
* Absolute path of the source file the error is in,
|
|
560
|
+
* when the throwing layer knows one (`compileSkin` is a pure string→string
|
|
561
|
+
* pass and a collection-row check names the entry route instead).
|
|
562
|
+
*/
|
|
563
|
+
file?: string | undefined;
|
|
564
|
+
/**
|
|
565
|
+
* 1-based file line the error points at, when known
|
|
566
|
+
* (some errors — e.g. a bad `where` operand — are file-scoped only, matching
|
|
567
|
+
* the string message, which likewise omits the line there).
|
|
568
|
+
*/
|
|
569
|
+
line?: number | undefined;
|
|
570
|
+
/**
|
|
571
|
+
* The corrective `Use:` template (without the `Use: ` prefix).
|
|
572
|
+
*/
|
|
573
|
+
hint?: string | undefined;
|
|
574
|
+
/**
|
|
575
|
+
* One concrete, compilable directive line.
|
|
576
|
+
*/
|
|
577
|
+
example?: string | undefined;
|
|
578
|
+
};
|
|
579
|
+
/**
|
|
580
|
+
* A compiled `@loop … where` predicate.
|
|
581
|
+
*/
|
|
582
|
+
export type Predicate = {
|
|
583
|
+
/**
|
|
584
|
+
* Safe JS boolean expression over `I()`/`S()`/`C()`.
|
|
585
|
+
*/
|
|
586
|
+
body: string;
|
|
587
|
+
/**
|
|
588
|
+
* Whether the predicate reads declared state.
|
|
589
|
+
*/
|
|
590
|
+
refsState: boolean;
|
|
591
|
+
};
|
|
592
|
+
/**
|
|
593
|
+
* A loop offset/limit argument: a non-negative integer literal or a state key.
|
|
594
|
+
*/
|
|
595
|
+
export type NumArg = {
|
|
596
|
+
kind: "literal";
|
|
597
|
+
value: number;
|
|
598
|
+
} | {
|
|
599
|
+
kind: "key";
|
|
600
|
+
value: string;
|
|
601
|
+
};
|
|
602
|
+
/**
|
|
603
|
+
* Loop clause configuration shared by the static and reactive paths.
|
|
604
|
+
*/
|
|
605
|
+
export type LoopOpts = {
|
|
606
|
+
where: Predicate | null;
|
|
607
|
+
/**
|
|
608
|
+
* A literal item field + asc/desc, or a `:state`/`:store` key for either (reactive, clickable-header sort).
|
|
609
|
+
*/
|
|
610
|
+
sort: {
|
|
611
|
+
key: string;
|
|
612
|
+
keyKind: "literal" | "key";
|
|
613
|
+
dir: string;
|
|
614
|
+
dirKind: "literal" | "key";
|
|
615
|
+
} | null;
|
|
616
|
+
reverse: boolean;
|
|
617
|
+
offset: NumArg | null;
|
|
618
|
+
limit: NumArg | null;
|
|
619
|
+
/**
|
|
620
|
+
* Empty-branch body lines, if any.
|
|
621
|
+
*/
|
|
622
|
+
empty: string[] | null;
|
|
623
|
+
/**
|
|
624
|
+
* 0-based index the empty branch starts at
|
|
625
|
+
* within the loop body, so its nested errors report the true file line.
|
|
626
|
+
*/
|
|
627
|
+
emptyStart?: number | undefined;
|
|
628
|
+
/**
|
|
629
|
+
* Whether offset/limit reference state.
|
|
630
|
+
*/
|
|
631
|
+
clauseRefsState: boolean;
|
|
632
|
+
/**
|
|
633
|
+
* Drag-to-reorder the underlying :state/:store list
|
|
634
|
+
* (the `sortable` clause). Only valid on a plain reactive state-key loop.
|
|
635
|
+
*/
|
|
636
|
+
sortable: boolean;
|
|
637
|
+
/**
|
|
638
|
+
* Rows-per-page for a `paginate N` clause, or
|
|
639
|
+
* null. Only valid on a collection loop; multiplies the listing into static
|
|
640
|
+
* pages (page 1 at the route, 2+ at `/<route>/page/<n>/`) and exposes a `page`
|
|
641
|
+
* pager to the template scope.
|
|
642
|
+
*/
|
|
643
|
+
paginate: number | null;
|
|
644
|
+
};
|
|
645
|
+
/**
|
|
646
|
+
* A parsed `:button` action.
|
|
647
|
+
*/
|
|
648
|
+
export type Action = {
|
|
649
|
+
/**
|
|
650
|
+
* Runtime operation (inc/dec/add/sub/append/prepend/set/toggle/member-toggle/remove/remove-value/clear/merge/delete/reset/append-row).
|
|
651
|
+
*/
|
|
652
|
+
op: string;
|
|
653
|
+
/**
|
|
654
|
+
* State key (possibly dotted) the action mutates.
|
|
655
|
+
*/
|
|
656
|
+
target: string;
|
|
657
|
+
/**
|
|
658
|
+
* Literal value for value-carrying ops.
|
|
659
|
+
*/
|
|
660
|
+
value?: unknown;
|
|
661
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { handleFetch } from "./fetch.js";
|
|
2
|
+
export { handleButton, handleEffect, handleEvery } from "./actions.js";
|
|
3
|
+
export { handleBind, handleChoiceGroup, handleForm, handleInput, handleSelect, handleSlider, handleSubmit, handleTextarea } from "./forms.js";
|
|
4
|
+
export { handleEmbed, handleMedia } from "./media.js";
|
|
5
|
+
export { handleComputed, handleState, handleStore, handleTheme } from "./state.js";
|
|
6
|
+
export { handleCarousel, handleContainer, handleIf, handleInclude, renderDemoDirective } from "./structure.js";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Re-parse a validated compiled expression (JS fragment over I()/S()/C()/A())
|
|
3
|
+
* into a compact AST. Throws on anything outside the closed grammar.
|
|
4
|
+
* @param {string} code
|
|
5
|
+
* @returns {any[]}
|
|
6
|
+
*/
|
|
7
|
+
export function astOf(code: string): any[];
|
|
8
|
+
/**
|
|
9
|
+
* Build-time mirror of the runtime AST walker — same operators, so a `:computed`
|
|
10
|
+
* or `where`/`when` predicate folds to the SAME value the runtime will recompute.
|
|
11
|
+
* `state` reads come from the compilation's declared-state map. No eval.
|
|
12
|
+
* @param {any[]} node
|
|
13
|
+
* @param {unknown} item Loop row for I(); undefined otherwise.
|
|
14
|
+
* @param {{ state: Map<string, unknown> }} comp
|
|
15
|
+
* @returns {any}
|
|
16
|
+
*/
|
|
17
|
+
export function evalAst(node: any[], item: unknown, comp: {
|
|
18
|
+
state: Map<string, unknown>;
|
|
19
|
+
}): any;
|
|
20
|
+
export function serializeExpr(code: string): string;
|