@zvndev/darkmown 2.1.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 +22 -0
- package/README.md +65 -0
- package/docs/cli.md +8 -0
- package/docs/spec-alignment.md +18 -0
- package/grammar/wd-directives.gbnf +58 -0
- package/package.json +17 -10
- package/site/pages/docs/index.wd +29 -0
- package/site/pages/playground/index.js +47 -46
- package/src/builder.js +5 -0
- package/src/catalog.js +601 -0
- package/src/cli.js +8 -0
- package/src/compiler/actions.js +87 -34
- package/src/compiler/body.js +36 -14
- package/src/compiler/collections.js +16 -10
- package/src/compiler/context.js +70 -1
- package/src/compiler/fetch.js +51 -19
- package/src/compiler/format.js +5 -2
- package/src/compiler/forms.js +169 -50
- 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 +78 -39
- package/src/compiler/markdown.js +4 -3
- package/src/compiler/media.js +38 -10
- package/src/compiler/page.js +8 -6
- package/src/compiler/predicates.js +74 -30
- package/src/compiler/reader.js +12 -2
- package/src/compiler/state.js +83 -18
- package/src/compiler/structure.js +57 -24
- package/src/deploy.js +8 -4
- package/src/errors.js +1156 -0
- package/src/grammar.js +131 -0
- package/src/index.js +1 -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,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compile a page source file into a full HTML document plus its assets.
|
|
3
|
+
* @param {string} file Absolute path to the source `.md`/`.wd` file.
|
|
4
|
+
* @param {Paths} context Resolved project paths.
|
|
5
|
+
* @param {{ feed?: { href: string, title: string }, collections?: Map<string, import("./collections.js").CollectionRow[]>, vars?: Record<string, unknown>, reader?: import("./reader.js").Reader }} [options]
|
|
6
|
+
* When a site-wide RSS feed is emitted (the home page set `site_url` and the
|
|
7
|
+
* site has dated posts), `feed` carries its absolute href + title so every page
|
|
8
|
+
* links it. `collections` is the build-time collection index a bare-name
|
|
9
|
+
* `@loop` resolves against; `vars` seeds the document scope (the pager `page`
|
|
10
|
+
* object on a paginated route). `reader` is the source reader (fs-backed by
|
|
11
|
+
* default via `src/compiler.js`; in-memory for `compileFromMemory`).
|
|
12
|
+
* @returns {CompiledPage}
|
|
13
|
+
*/
|
|
14
|
+
export function compilePage(file: string, context: Paths, options?: {
|
|
15
|
+
feed?: {
|
|
16
|
+
href: string;
|
|
17
|
+
title: string;
|
|
18
|
+
};
|
|
19
|
+
collections?: Map<string, import("./collections.js").CollectionRow[]>;
|
|
20
|
+
vars?: Record<string, unknown>;
|
|
21
|
+
reader?: import("./reader.js").Reader;
|
|
22
|
+
}): CompiledPage;
|
|
23
|
+
/**
|
|
24
|
+
* Harden every `<img>` in the assembled page body — compile-time only, zero
|
|
25
|
+
* runtime JS. Bare markdown images reflow the page as they decode (cumulative
|
|
26
|
+
* layout shift — the literal "jump" on navigation) and load eagerly. This
|
|
27
|
+
* stamps intrinsic `width`/`height` (read from the file on disk so the browser
|
|
28
|
+
* reserves space), `decoding="async"` on all, and a load-priority split: the
|
|
29
|
+
* first image is the LCP candidate (eager + `fetchpriority="high"`), the rest
|
|
30
|
+
* lazy-load. Author-set attributes are never overwritten.
|
|
31
|
+
* @param {string} html Assembled page body HTML.
|
|
32
|
+
* @param {Paths} paths Resolved project paths.
|
|
33
|
+
* @param {import("./reader.js").Reader} reader Source reader for the image bytes.
|
|
34
|
+
* @returns {string}
|
|
35
|
+
*/
|
|
36
|
+
export function enhanceImages(html: string, paths: Paths, reader: import("./reader.js").Reader): string;
|
|
37
|
+
/**
|
|
38
|
+
* Compile a source file into its body HTML, frontmatter, and assets (no page shell).
|
|
39
|
+
* @param {string} file Absolute path to the source file.
|
|
40
|
+
* @param {Paths} context Resolved project paths.
|
|
41
|
+
* @param {string[]} [stack] Include stack for cycle detection.
|
|
42
|
+
* @param {Record<string, unknown>} [vars] Initial static scope variables.
|
|
43
|
+
* @param {Map<string, import("./collections.js").CollectionRow[]>} [collections]
|
|
44
|
+
* Build-time collection index a bare-name `@loop` resolves against.
|
|
45
|
+
* @param {import("./reader.js").Reader} [reader] Source reader (fs-backed when
|
|
46
|
+
* omitted via `src/compiler.js`; in-memory for `compileFromMemory`).
|
|
47
|
+
* @returns {CompiledDocument}
|
|
48
|
+
*/
|
|
49
|
+
export function compileDocument(file: string, context: Paths, stack?: string[], vars?: Record<string, unknown>, collections?: Map<string, import("./collections.js").CollectionRow[]>, reader?: import("./reader.js").Reader): CompiledDocument;
|
|
50
|
+
/**
|
|
51
|
+
* Compile a single file: parse frontmatter, collect assets, render body.
|
|
52
|
+
* @param {string} file
|
|
53
|
+
* @param {Paths} context
|
|
54
|
+
* @param {string[]} stack
|
|
55
|
+
* @param {Scope} scope
|
|
56
|
+
* @param {Compilation} comp
|
|
57
|
+
* @param {string[]} sections
|
|
58
|
+
* @param {string | null} loopItem
|
|
59
|
+
* @param {number} [reactiveDepth] Enclosing REACTIVE `@loop` levels, threaded in
|
|
60
|
+
* from the including page so an include's body can't bypass the two-level
|
|
61
|
+
* reactive-nesting limit at the `@include` boundary.
|
|
62
|
+
* @param {{ at: string, line: string } | null} [loopOpener] The enclosing `@loop`
|
|
63
|
+
* opener, threaded in so a depth error inside the include names the right opener.
|
|
64
|
+
* @returns {{ meta: Meta, html: string }}
|
|
65
|
+
*/
|
|
66
|
+
export function compileFile(file: string, context: Paths, stack: string[], scope: Scope, comp: Compilation, sections: string[], loopItem: string | null, reactiveDepth?: number, loopOpener?: {
|
|
67
|
+
at: string;
|
|
68
|
+
line: string;
|
|
69
|
+
} | null): {
|
|
70
|
+
meta: Meta;
|
|
71
|
+
html: string;
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Compile a page entirely from an in-memory file map — no filesystem, no
|
|
75
|
+
* `node:fs`. `files` maps PROJECT-RELATIVE POSIX paths (`site/pages/index.wd`,
|
|
76
|
+
* `site/_/nav.wd`) to their source strings; `entryPath` is the project-relative
|
|
77
|
+
* path of the page to compile. Includes, colocated `.skin`/`.js` detection, and
|
|
78
|
+
* `@loop` JSON-data reads all resolve against the same map (anything not in it
|
|
79
|
+
* is simply "absent"), so `@include`s work as long as their targets are present.
|
|
80
|
+
*
|
|
81
|
+
* This is the strategic fs-free entry point the browser playground and a planned
|
|
82
|
+
* mobile host use: the entire module graph reachable from here is free of
|
|
83
|
+
* `node:fs`, so it bundles for the browser. It returns the same
|
|
84
|
+
* {@link CompiledPage} shape as {@link compilePage} and throws the same
|
|
85
|
+
* `file:line` compile errors, so the error DX is identical in-browser.
|
|
86
|
+
* @param {Record<string, string> | Map<string, string>} files Project-relative
|
|
87
|
+
* path → source content.
|
|
88
|
+
* @param {string} entryPath Project-relative path of the page to compile.
|
|
89
|
+
* @param {{ feed?: { href: string, title: string }, collections?: Map<string, import("./collections.js").CollectionRow[]>, vars?: Record<string, unknown>, cwd?: string }} [options]
|
|
90
|
+
* Same shell options as {@link compilePage}; `cwd` overrides the virtual
|
|
91
|
+
* project root the relative keys resolve against (defaults to `/`).
|
|
92
|
+
* @returns {CompiledPage}
|
|
93
|
+
*/
|
|
94
|
+
export function compileFromMemory(files: Record<string, string> | Map<string, string>, entryPath: string, options?: {
|
|
95
|
+
feed?: {
|
|
96
|
+
href: string;
|
|
97
|
+
title: string;
|
|
98
|
+
};
|
|
99
|
+
collections?: Map<string, import("./collections.js").CollectionRow[]>;
|
|
100
|
+
vars?: Record<string, unknown>;
|
|
101
|
+
cwd?: string;
|
|
102
|
+
}): CompiledPage;
|
|
103
|
+
export type Paths = import("./context.js").Paths;
|
|
104
|
+
export type Meta = import("./context.js").Meta;
|
|
105
|
+
export type Scope = import("./context.js").Scope;
|
|
106
|
+
export type Compilation = import("./context.js").Compilation;
|
|
107
|
+
export type Ctx = import("./context.js").Ctx;
|
|
108
|
+
export type CompiledDocument = import("./context.js").CompiledDocument;
|
|
109
|
+
export type CompiledPage = import("./context.js").CompiledPage;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {string} raw
|
|
3
|
+
* @param {string} itemName
|
|
4
|
+
* @param {Ctx} ctx
|
|
5
|
+
* @returns {Predicate}
|
|
6
|
+
*/
|
|
7
|
+
export function compilePredicate(raw: string, itemName: string, ctx: Ctx): Predicate;
|
|
8
|
+
/**
|
|
9
|
+
* Evaluate a compiled predicate against a row at build time by walking its AST —
|
|
10
|
+
* the same closed evaluator the runtime uses, so the fold matches. No eval.
|
|
11
|
+
* @param {string} body
|
|
12
|
+
* @param {unknown} item
|
|
13
|
+
* @param {Ctx} ctx
|
|
14
|
+
* @returns {boolean}
|
|
15
|
+
*/
|
|
16
|
+
export function evalPredicate(body: string, item: unknown, ctx: Ctx): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Compile a `::: … .class when <predicate>`. Allows `:if`-style bare truthy
|
|
19
|
+
* paths and `where`-style `left <op> right` conditions joined by `and`/`or`.
|
|
20
|
+
* Folds to a static verdict when every operand is build-known, else returns a
|
|
21
|
+
* runtime body over I()/S()/C() plus whether it reads the reactive loop item
|
|
22
|
+
* (which decides data-wd-each-class vs the global data-wd-class).
|
|
23
|
+
* @param {string} raw
|
|
24
|
+
* @param {Ctx} ctx
|
|
25
|
+
* @param {string} [what] Directive label for error messages.
|
|
26
|
+
* @returns {{ static: true, value: boolean } | { static: false, body: string, item: boolean }}
|
|
27
|
+
*/
|
|
28
|
+
export function compileWhen(raw: string, ctx: Ctx, what?: string): {
|
|
29
|
+
static: true;
|
|
30
|
+
value: boolean;
|
|
31
|
+
} | {
|
|
32
|
+
static: false;
|
|
33
|
+
body: string;
|
|
34
|
+
item: boolean;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Compile a `:computed` expression into safe JS over the `S(key, path)` reader.
|
|
38
|
+
* @param {string} raw
|
|
39
|
+
* @param {Ctx} ctx
|
|
40
|
+
* @returns {string}
|
|
41
|
+
*/
|
|
42
|
+
export function compileComputedExpr(raw: string, ctx: Ctx): string;
|
|
43
|
+
/**
|
|
44
|
+
* @typedef {import("./context.js").Ctx} Ctx
|
|
45
|
+
* @typedef {import("./context.js").Predicate} Predicate
|
|
46
|
+
*/
|
|
47
|
+
export const PREDICATE_OPS: string[];
|
|
48
|
+
export const PREDICATE_JOINERS: string[];
|
|
49
|
+
export type Ctx = import("./context.js").Ctx;
|
|
50
|
+
export type Predicate = import("./context.js").Predicate;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The narrow filesystem surface the compiler needs. Every method takes an
|
|
3
|
+
* ABSOLUTE path (the compiler resolves includes/assets to absolute paths before
|
|
4
|
+
* reading), so a reader only has to map absolute paths to bytes/existence.
|
|
5
|
+
* @typedef {object} Reader
|
|
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.
|
|
11
|
+
* @property {(absPath: string) => Uint8Array} readBinary Read raw bytes (images).
|
|
12
|
+
* @property {(absPath: string) => boolean} exists Whether the path exists.
|
|
13
|
+
* @property {(absPath: string) => string} realpath Canonical path (symlinks
|
|
14
|
+
* resolved on a real fs; a no-op normalize in memory) — used for cycle keys.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* A reader backed by an in-memory map of PROJECT-RELATIVE path → content. Keys
|
|
18
|
+
* are POSIX, project-relative (e.g. `site/pages/index.wd`, `site/_/nav.wd`);
|
|
19
|
+
* lookups translate an absolute compile path back to its key via `cwd`. There
|
|
20
|
+
* are no symlinks in memory, so `realpath` just normalizes. Binary reads are
|
|
21
|
+
* unsupported (the playground has no image files, and image measuring degrades
|
|
22
|
+
* to "no dimensions" on a throw), so `readBinary` throws — callers already
|
|
23
|
+
* try/catch it.
|
|
24
|
+
* @param {Record<string, string> | Map<string, string>} files
|
|
25
|
+
* @param {string} [cwd] Virtual project root the keys are relative to.
|
|
26
|
+
* @returns {Reader}
|
|
27
|
+
*/
|
|
28
|
+
export function memoryReader(files: Record<string, string> | Map<string, string>, cwd?: string): Reader;
|
|
29
|
+
/**
|
|
30
|
+
* The narrow filesystem surface the compiler needs. Every method takes an
|
|
31
|
+
* ABSOLUTE path (the compiler resolves includes/assets to absolute paths before
|
|
32
|
+
* reading), so a reader only has to map absolute paths to bytes/existence.
|
|
33
|
+
*/
|
|
34
|
+
export type Reader = {
|
|
35
|
+
/**
|
|
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.
|
|
41
|
+
*/
|
|
42
|
+
readText: (absPath: string) => string;
|
|
43
|
+
/**
|
|
44
|
+
* Read raw bytes (images).
|
|
45
|
+
*/
|
|
46
|
+
readBinary: (absPath: string) => Uint8Array;
|
|
47
|
+
/**
|
|
48
|
+
* Whether the path exists.
|
|
49
|
+
*/
|
|
50
|
+
exists: (absPath: string) => boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Canonical path (symlinks
|
|
53
|
+
* resolved on a real fs; a no-op normalize in memory) — used for cycle keys.
|
|
54
|
+
*/
|
|
55
|
+
realpath: (absPath: string) => string;
|
|
56
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
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 handleState(line: string, ctx: Ctx, index: number): string;
|
|
8
|
+
/**
|
|
9
|
+
* Register a state key in the current section scope, enabling the runtime.
|
|
10
|
+
* @param {string} name
|
|
11
|
+
* @param {unknown} value
|
|
12
|
+
* @param {Ctx} ctx
|
|
13
|
+
* @returns {string} The fully-qualified state key.
|
|
14
|
+
*/
|
|
15
|
+
export function declareState(name: string, value: unknown, ctx: Ctx): string;
|
|
16
|
+
/**
|
|
17
|
+
* @param {string} line
|
|
18
|
+
* @param {Ctx} ctx
|
|
19
|
+
* @param {number} index 0-based line index for `file:line` errors.
|
|
20
|
+
* @returns {string}
|
|
21
|
+
*/
|
|
22
|
+
export function handleStore(line: string, ctx: Ctx, index: number): string;
|
|
23
|
+
/**
|
|
24
|
+
* Register a page-global store. The bare name is added to `comp.state` so every
|
|
25
|
+
* resolver (interpolation, :if, @loop, :computed, actions) sees it, and tracked
|
|
26
|
+
* in `comp.stores` for collision checks. Never section-scoped.
|
|
27
|
+
* @param {string} name
|
|
28
|
+
* @param {unknown} value
|
|
29
|
+
* @param {Ctx} ctx
|
|
30
|
+
* @returns {string} The store name (also its bare state key).
|
|
31
|
+
*/
|
|
32
|
+
export function declareStore(name: string, value: unknown, ctx: Ctx): string;
|
|
33
|
+
/**
|
|
34
|
+
* Seed a `<name>_error` state key (null) if absent. Shared by :fetch and the
|
|
35
|
+
* round-trip :form so error fallbacks have a key to bind.
|
|
36
|
+
* @param {string} key
|
|
37
|
+
* @param {Ctx} ctx
|
|
38
|
+
* @returns {void}
|
|
39
|
+
*/
|
|
40
|
+
export function declareErrorState(key: string, ctx: Ctx): void;
|
|
41
|
+
/**
|
|
42
|
+
* @param {string} line
|
|
43
|
+
* @param {Ctx} ctx
|
|
44
|
+
* @param {number} index 0-based line index for `file:line` errors.
|
|
45
|
+
* @returns {string}
|
|
46
|
+
*/
|
|
47
|
+
export function handleComputed(line: string, ctx: Ctx, index: number): string;
|
|
48
|
+
/**
|
|
49
|
+
* `:theme [name] [= "auto"]` declares a durable `:store` (default name `theme`,
|
|
50
|
+
* seed `"auto"`) and reflects its value onto `<html data-theme>`. This layers a
|
|
51
|
+
* manual light/dark switch over the OS preference: `"auto"` follows the skin's
|
|
52
|
+
* `tokens dark` media query, while `"light"`/`"dark"` force the matching
|
|
53
|
+
* `:root[data-theme]` scope. Wire a switch with ordinary store actions —
|
|
54
|
+
* `:button "Dark" -> theme = "dark"`. Durable, so the choice survives reloads.
|
|
55
|
+
* @param {string} line
|
|
56
|
+
* @param {Ctx} ctx
|
|
57
|
+
* @param {number} index 0-based line index for `file:line` errors.
|
|
58
|
+
* @returns {string}
|
|
59
|
+
*/
|
|
60
|
+
export function handleTheme(line: string, ctx: Ctx, index: number): string;
|
|
61
|
+
/**
|
|
62
|
+
* @typedef {import("./context.js").Ctx} Ctx
|
|
63
|
+
*/
|
|
64
|
+
export const STATE_EXAMPLE: ":state count = 0";
|
|
65
|
+
export const STORE_EXAMPLE: ":store cart = []";
|
|
66
|
+
export const COMPUTED_EXAMPLE: ":computed total = items.length * 4";
|
|
67
|
+
export const THEME_EXAMPLE: ":theme";
|
|
68
|
+
export type Ctx = import("./context.js").Ctx;
|
|
@@ -0,0 +1,56 @@
|
|
|
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 handleInclude(line: string, ctx: Ctx, index: number): string;
|
|
8
|
+
/**
|
|
9
|
+
* @param {string} header
|
|
10
|
+
* @param {string[]} bodyLines
|
|
11
|
+
* @param {Ctx} ctx
|
|
12
|
+
* @param {number} index 0-based line index for `file:line` errors.
|
|
13
|
+
* @returns {string}
|
|
14
|
+
*/
|
|
15
|
+
export function handleContainer(header: string, bodyLines: string[], ctx: Ctx, index: number): string;
|
|
16
|
+
/**
|
|
17
|
+
* `:carousel [autoplay=N]` … `:endcarousel` — a horizontally scroll-snapping
|
|
18
|
+
* carousel. Contract: each DIRECT child element of the track is one slide, so put
|
|
19
|
+
* each slide in its own block (e.g. a `::: slide` container) and give that block
|
|
20
|
+
* the slide sizing in your skin — loose prose lines would each count as a slide.
|
|
21
|
+
* Registers the `carousel` behavior (prev/next, dot nav, optional autoplay, mouse
|
|
22
|
+
* drag); native CSS scroll-snap + the page skin handle layout and touch swipe.
|
|
23
|
+
* `autoplay` is suppressed under `prefers-reduced-motion`. No runtime required.
|
|
24
|
+
* @param {string} line
|
|
25
|
+
* @param {string[]} bodyLines
|
|
26
|
+
* @param {Ctx} ctx
|
|
27
|
+
* @param {number} index 0-based line index for `file:line` errors.
|
|
28
|
+
* @returns {string}
|
|
29
|
+
*/
|
|
30
|
+
export function handleCarousel(line: string, bodyLines: string[], ctx: Ctx, index: number): string;
|
|
31
|
+
/**
|
|
32
|
+
* @param {string} line
|
|
33
|
+
* @param {string[]} truthyLines
|
|
34
|
+
* @param {string[]} falsyLines
|
|
35
|
+
* @param {Ctx} ctx
|
|
36
|
+
* @param {number} index 0-based line index for `file:line` errors.
|
|
37
|
+
* @param {number} [falsyStart] 0-based index the falsy body starts at in the
|
|
38
|
+
* current slice, so nested errors in that branch report the true file line.
|
|
39
|
+
* @returns {string}
|
|
40
|
+
*/
|
|
41
|
+
export function handleIf(line: string, truthyLines: string[], falsyLines: string[], ctx: Ctx, index: number, falsyStart?: number): string;
|
|
42
|
+
/**
|
|
43
|
+
* Render the documentation-demo directives (`:try`, `:note`, `:sprint`).
|
|
44
|
+
* @param {string} line
|
|
45
|
+
* @param {Ctx} ctx
|
|
46
|
+
* @returns {string}
|
|
47
|
+
*/
|
|
48
|
+
export function renderDemoDirective(line: string, ctx: Ctx): string;
|
|
49
|
+
/**
|
|
50
|
+
* @typedef {import("./context.js").Ctx} Ctx
|
|
51
|
+
*/
|
|
52
|
+
export const INCLUDE_EXAMPLE: "@include /header.wd";
|
|
53
|
+
export const CONTAINER_EXAMPLE: "::: card .featured";
|
|
54
|
+
export const IF_EXAMPLE: ":if count > 0";
|
|
55
|
+
export const CAROUSEL_EXAMPLE: ":carousel autoplay=3000";
|
|
56
|
+
export type Ctx = import("./context.js").Ctx;
|
package/types/compiler.d.ts
CHANGED
|
@@ -1,236 +1,48 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Compile a page source file into a full HTML document plus its assets
|
|
2
|
+
* Compile a page source file into a full HTML document plus its assets, reading
|
|
3
|
+
* from the real filesystem by default. Pass `options.reader` to compile against
|
|
4
|
+
* a different source (see `compileFromMemory`).
|
|
3
5
|
* @param {string} file Absolute path to the source `.md`/`.wd` file.
|
|
4
|
-
* @param {Paths} context Resolved project paths.
|
|
6
|
+
* @param {import("./config.js").Paths} context Resolved project paths.
|
|
7
|
+
* @param {{ feed?: { href: string, title: string }, collections?: Map<string, import("./compiler/collections.js").CollectionRow[]>, vars?: Record<string, unknown>, reader?: import("./compiler/reader.js").Reader }} [options]
|
|
5
8
|
* @returns {CompiledPage}
|
|
6
9
|
*/
|
|
7
|
-
export function compilePage(file: string, context: Paths
|
|
10
|
+
export function compilePage(file: string, context: import("./config.js").Paths, options?: {
|
|
11
|
+
feed?: {
|
|
12
|
+
href: string;
|
|
13
|
+
title: string;
|
|
14
|
+
};
|
|
15
|
+
collections?: Map<string, import("./compiler/collections.js").CollectionRow[]>;
|
|
16
|
+
vars?: Record<string, unknown>;
|
|
17
|
+
reader?: import("./compiler/reader.js").Reader;
|
|
18
|
+
}): CompiledPage;
|
|
8
19
|
/**
|
|
9
|
-
* Compile a source file into its body HTML, frontmatter, and assets (no page
|
|
20
|
+
* Compile a source file into its body HTML, frontmatter, and assets (no page
|
|
21
|
+
* shell), reading from the real filesystem by default.
|
|
10
22
|
* @param {string} file Absolute path to the source file.
|
|
11
|
-
* @param {Paths} context Resolved project paths.
|
|
23
|
+
* @param {import("./config.js").Paths} context Resolved project paths.
|
|
12
24
|
* @param {string[]} [stack] Include stack for cycle detection.
|
|
13
25
|
* @param {Record<string, unknown>} [vars] Initial static scope variables.
|
|
26
|
+
* @param {Map<string, import("./compiler/collections.js").CollectionRow[]>} [collections]
|
|
27
|
+
* @param {import("./compiler/reader.js").Reader} [reader] Source reader.
|
|
14
28
|
* @returns {CompiledDocument}
|
|
15
29
|
*/
|
|
16
|
-
export function compileDocument(file: string, context: Paths, stack?: string[], vars?: Record<string, unknown
|
|
17
|
-
/**
|
|
18
|
-
* Compile a page from an in-memory map of project-relative path → source, with
|
|
19
|
-
* no filesystem access. `entryPath` is the project-relative path of the page to
|
|
20
|
-
* compile; includes and `@loop` data resolve against the same map.
|
|
21
|
-
* @param {Record<string, string> | Map<string, string>} files
|
|
22
|
-
* @param {string} entryPath
|
|
23
|
-
* @param {{ vars?: Record<string, unknown>, cwd?: string }} [options]
|
|
24
|
-
* @returns {CompiledPage}
|
|
25
|
-
*/
|
|
26
|
-
export function compileFromMemory(files: Record<string, string> | Map<string, string>, entryPath: string, options?: {
|
|
27
|
-
vars?: Record<string, unknown>;
|
|
28
|
-
cwd?: string;
|
|
29
|
-
}): CompiledPage;
|
|
30
|
-
/**
|
|
31
|
-
* Split a raw file into its frontmatter `meta` and `body`.
|
|
32
|
-
* @param {string} raw Full file contents.
|
|
33
|
-
* @param {string} [file] Source path, used only for error messages.
|
|
34
|
-
* @returns {{ meta: Meta, body: string }}
|
|
35
|
-
*/
|
|
36
|
-
export function parseFrontmatter(raw: string, file?: string): {
|
|
37
|
-
meta: Meta;
|
|
38
|
-
body: string;
|
|
39
|
-
};
|
|
30
|
+
export function compileDocument(file: string, context: import("./config.js").Paths, stack?: string[], vars?: Record<string, unknown>, collections?: Map<string, import("./compiler/collections.js").CollectionRow[]>, reader?: import("./compiler/reader.js").Reader): CompiledDocument;
|
|
40
31
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* @param {
|
|
32
|
+
* Harden every `<img>` in an assembled page body, reading intrinsic dimensions
|
|
33
|
+
* from the real filesystem by default.
|
|
34
|
+
* @param {string} html Assembled page body HTML.
|
|
35
|
+
* @param {import("./config.js").Paths} paths Resolved project paths.
|
|
36
|
+
* @param {import("./compiler/reader.js").Reader} [reader] Source reader for image bytes.
|
|
44
37
|
* @returns {string}
|
|
45
38
|
*/
|
|
46
|
-
export function
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
export
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
export type NumArg = {
|
|
57
|
-
kind: "literal";
|
|
58
|
-
value: number;
|
|
59
|
-
} | {
|
|
60
|
-
kind: "key";
|
|
61
|
-
value: string;
|
|
62
|
-
};
|
|
63
|
-
/**
|
|
64
|
-
* A compiled `@loop … where` predicate.
|
|
65
|
-
*/
|
|
66
|
-
export type Predicate = {
|
|
67
|
-
/**
|
|
68
|
-
* Safe JS boolean expression over `I()`/`S()`/`C()`.
|
|
69
|
-
*/
|
|
70
|
-
body: string;
|
|
71
|
-
/**
|
|
72
|
-
* Whether the predicate reads declared state.
|
|
73
|
-
*/
|
|
74
|
-
refsState: boolean;
|
|
75
|
-
};
|
|
76
|
-
/**
|
|
77
|
-
* Loop clause configuration shared by the static and reactive paths.
|
|
78
|
-
*/
|
|
79
|
-
export type LoopOpts = {
|
|
80
|
-
where: Predicate | null;
|
|
81
|
-
sort: {
|
|
82
|
-
key: string;
|
|
83
|
-
dir: string;
|
|
84
|
-
} | null;
|
|
85
|
-
reverse: boolean;
|
|
86
|
-
offset: NumArg | null;
|
|
87
|
-
limit: NumArg | null;
|
|
88
|
-
/**
|
|
89
|
-
* Empty-branch body lines, if any.
|
|
90
|
-
*/
|
|
91
|
-
empty: string[] | null;
|
|
92
|
-
/**
|
|
93
|
-
* Whether offset/limit reference state.
|
|
94
|
-
*/
|
|
95
|
-
clauseRefsState: boolean;
|
|
96
|
-
};
|
|
97
|
-
export type Paths = import("./config.js").Paths;
|
|
98
|
-
/**
|
|
99
|
-
* Frontmatter values are scalars or inline arrays of scalars.
|
|
100
|
-
*/
|
|
101
|
-
export type FrontmatterValue = string | number | boolean | null | Array<string | number | boolean | null>;
|
|
102
|
-
/**
|
|
103
|
-
* Parsed page frontmatter, keyed by field name.
|
|
104
|
-
*/
|
|
105
|
-
export type Meta = Record<string, FrontmatterValue>;
|
|
106
|
-
/**
|
|
107
|
-
* Collected output assets for a compiled document.
|
|
108
|
-
*/
|
|
109
|
-
export type Assets = {
|
|
110
|
-
/**
|
|
111
|
-
* Public hrefs of compiled skin stylesheets.
|
|
112
|
-
*/
|
|
113
|
-
skins: Set<string>;
|
|
114
|
-
/**
|
|
115
|
-
* Public hrefs of colocated page scripts.
|
|
116
|
-
*/
|
|
117
|
-
scripts: Set<string>;
|
|
118
|
-
/**
|
|
119
|
-
* Source path → public href for emitted assets.
|
|
120
|
-
*/
|
|
121
|
-
files: Map<string, string>;
|
|
122
|
-
/**
|
|
123
|
-
* Whether the reactive runtime is required.
|
|
124
|
-
*/
|
|
125
|
-
runtime: boolean;
|
|
126
|
-
};
|
|
127
|
-
/**
|
|
128
|
-
* Per-document compilation accumulator shared across includes/sections.
|
|
129
|
-
*/
|
|
130
|
-
export type Compilation = {
|
|
131
|
-
assets: Assets;
|
|
132
|
-
/**
|
|
133
|
-
* Declared state keys → initial values.
|
|
134
|
-
*/
|
|
135
|
-
state: Map<string, unknown>;
|
|
136
|
-
/**
|
|
137
|
-
* Page-global store names (a subset of state keys).
|
|
138
|
-
*/
|
|
139
|
-
stores: Set<string>;
|
|
140
|
-
/**
|
|
141
|
-
* Non-fatal authoring hints.
|
|
142
|
-
*/
|
|
143
|
-
warnings: string[];
|
|
144
|
-
/**
|
|
145
|
-
* Counter for auto-generated section ids.
|
|
146
|
-
*/
|
|
147
|
-
sectionCounter: number;
|
|
148
|
-
};
|
|
149
|
-
/**
|
|
150
|
-
* A lexical scope chain for static interpolation values (include args, loop vars).
|
|
151
|
-
*/
|
|
152
|
-
export type Scope = {
|
|
153
|
-
parent: Scope | null;
|
|
154
|
-
vars: Record<string, unknown>;
|
|
155
|
-
};
|
|
156
|
-
/**
|
|
157
|
-
* Per-file compile context threaded through the directive handlers.
|
|
158
|
-
*/
|
|
159
|
-
export type Ctx = {
|
|
160
|
-
/**
|
|
161
|
-
* Absolute path to the file being compiled.
|
|
162
|
-
*/
|
|
163
|
-
file: string;
|
|
164
|
-
/**
|
|
165
|
-
* Resolved project paths.
|
|
166
|
-
*/
|
|
167
|
-
context: Paths;
|
|
168
|
-
/**
|
|
169
|
-
* Include stack (real paths) for cycle detection.
|
|
170
|
-
*/
|
|
171
|
-
stack: string[];
|
|
172
|
-
/**
|
|
173
|
-
* Static value scope chain.
|
|
174
|
-
*/
|
|
175
|
-
scope: Scope;
|
|
176
|
-
/**
|
|
177
|
-
* Shared compilation accumulator.
|
|
178
|
-
*/
|
|
179
|
-
comp: Compilation;
|
|
180
|
-
/**
|
|
181
|
-
* Active section-id scope chain.
|
|
182
|
-
*/
|
|
183
|
-
sections: string[];
|
|
184
|
-
/**
|
|
185
|
-
* Name of the current reactive loop item, if any.
|
|
186
|
-
*/
|
|
187
|
-
loopItem: string | null;
|
|
188
|
-
/**
|
|
189
|
-
* State key of the list being looped, if any.
|
|
190
|
-
*/
|
|
191
|
-
loopKey?: string | undefined;
|
|
192
|
-
/**
|
|
193
|
-
* Inside a loop body, so `$index`/`$first`/… are valid.
|
|
194
|
-
*/
|
|
195
|
-
loopMeta?: boolean | undefined;
|
|
196
|
-
/**
|
|
197
|
-
* Markdown-it instance selected for this file.
|
|
198
|
-
*/
|
|
199
|
-
md?: MarkdownIt | undefined;
|
|
200
|
-
};
|
|
201
|
-
/**
|
|
202
|
-
* A compiled page document.
|
|
203
|
-
*/
|
|
204
|
-
export type CompiledDocument = {
|
|
205
|
-
meta: Meta;
|
|
206
|
-
html: string;
|
|
207
|
-
assets: Assets;
|
|
208
|
-
warnings: string[];
|
|
209
|
-
};
|
|
210
|
-
/**
|
|
211
|
-
* A compiled page: the document plus its full HTML shell.
|
|
212
|
-
*/
|
|
213
|
-
export type CompiledPage = {
|
|
214
|
-
meta: Meta;
|
|
215
|
-
html: string;
|
|
216
|
-
assets: Assets;
|
|
217
|
-
warnings: string[];
|
|
218
|
-
};
|
|
219
|
-
/**
|
|
220
|
-
* A parsed `:button` action.
|
|
221
|
-
*/
|
|
222
|
-
export type Action = {
|
|
223
|
-
/**
|
|
224
|
-
* Runtime operation (inc/dec/add/sub/append/prepend/set/toggle/member-toggle/remove/remove-value/clear/merge/delete/reset/append-row).
|
|
225
|
-
*/
|
|
226
|
-
op: string;
|
|
227
|
-
/**
|
|
228
|
-
* State key (possibly dotted) the action mutates.
|
|
229
|
-
*/
|
|
230
|
-
target: string;
|
|
231
|
-
/**
|
|
232
|
-
* Literal value for value-carrying ops.
|
|
233
|
-
*/
|
|
234
|
-
value?: unknown;
|
|
235
|
-
};
|
|
236
|
-
import MarkdownIt from "markdown-it";
|
|
39
|
+
export function enhanceImages(html: string, paths: import("./config.js").Paths, reader?: import("./compiler/reader.js").Reader): string;
|
|
40
|
+
export type Meta = import("./compiler/context.js").Meta;
|
|
41
|
+
export type FrontmatterValue = import("./compiler/context.js").FrontmatterValue;
|
|
42
|
+
export type Assets = import("./compiler/context.js").Assets;
|
|
43
|
+
export type Compilation = import("./compiler/context.js").Compilation;
|
|
44
|
+
export type Scope = import("./compiler/context.js").Scope;
|
|
45
|
+
export type Ctx = import("./compiler/context.js").Ctx;
|
|
46
|
+
export type CompiledDocument = import("./compiler/context.js").CompiledDocument;
|
|
47
|
+
export type CompiledPage = import("./compiler/context.js").CompiledPage;
|
|
48
|
+
export { compileFromMemory, escapeHtml, loopKeyOf, parseFrontmatter, stampScope } from "./compiler/index.js";
|
package/types/dev.d.ts
CHANGED
|
@@ -1,9 +1,54 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Serialize the dev server's rebuilds: at most ONE child build runs at a time.
|
|
3
|
+
* Every build read-modify-writes the dependency map (`dist/.wd-dev-deps.json`),
|
|
4
|
+
* so overlapping children could persist a stale map missing deps a concurrent
|
|
5
|
+
* build just recorded — after which the affected routes silently stop
|
|
6
|
+
* rebuilding. Changes debounce into a batch; changes arriving MID-build
|
|
7
|
+
* accumulate into the next batch (duplicate paths coalesce via the Set, and a
|
|
8
|
+
* `null` — a `src/` change or an unattributable event, forcing a full rebuild —
|
|
9
|
+
* swallows the whole batch into one full build).
|
|
10
|
+
* @param {(changed: string[]) => Promise<void> | void} runBuild Runs one child
|
|
11
|
+
* build over the changed `site/` paths (`[]` = full rebuild). Build failures
|
|
12
|
+
* are its own concern (report + resolve); a rejection still frees the queue.
|
|
13
|
+
* @param {number} [debounceMs] Debounce window for batching change events.
|
|
14
|
+
* @returns {{ change: (path: string | null) => void, close: () => void }}
|
|
15
|
+
*/
|
|
16
|
+
export function createRebuildQueue(runBuild: (changed: string[]) => Promise<void> | void, debounceMs?: number): {
|
|
17
|
+
change: (path: string | null) => void;
|
|
18
|
+
close: () => void;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Inject the dev-client `<script>` before `</body>` (or append it if absent),
|
|
22
|
+
* plus — for a `draft: true` page — an inline draft-banner script. Both are
|
|
23
|
+
* injected at dev-SERVE time only, so neither ever touches the shipped HTML on
|
|
24
|
+
* disk (a production build excludes drafts entirely; a `build --drafts` staging
|
|
25
|
+
* build emits clean HTML with no banner).
|
|
3
26
|
* @param {string} html Page HTML to augment.
|
|
27
|
+
* @param {{ draft?: boolean }} [options] `draft: true` adds the visible banner.
|
|
28
|
+
* @returns {string}
|
|
29
|
+
*/
|
|
30
|
+
export function injectDevClient(html: string, options?: {
|
|
31
|
+
draft?: boolean;
|
|
32
|
+
}): string;
|
|
33
|
+
/**
|
|
34
|
+
* The inline dev-only draft banner: a fixed bar marking the page as an unpublished
|
|
35
|
+
* draft, so it's unmistakable in `darkmown dev` that this content is excluded from
|
|
36
|
+
* a production build. Inert (`pointer-events:none`) and high-z so it never blocks
|
|
37
|
+
* the page; dev-serve-injected, so it's never in shipped output.
|
|
38
|
+
* @returns {string}
|
|
39
|
+
*/
|
|
40
|
+
export function draftBannerScript(): string;
|
|
41
|
+
/**
|
|
42
|
+
* The page the dev server serves for a route with no dist output while the last
|
|
43
|
+
* build is FAILED — the honest alternative to the production 404 copy, which
|
|
44
|
+
* would claim the route "is hidden or has not been created" when the real cause
|
|
45
|
+
* is a compile error. The message renders inline (works without JS) and the
|
|
46
|
+
* injected dev client replays the `builderror` overlay on connect, then reloads
|
|
47
|
+
* the real page on the next successful build.
|
|
48
|
+
* @param {string} message The recorded build failure.
|
|
4
49
|
* @returns {string}
|
|
5
50
|
*/
|
|
6
|
-
export function
|
|
51
|
+
export function buildFailedPage(message: string): string;
|
|
7
52
|
/**
|
|
8
53
|
* The dev-client browser script that opens the SSE channel for live reload.
|
|
9
54
|
* @returns {string}
|