@zvndev/darkmown 2.2.0 → 2.3.1-next.1.g3a4a8dc

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 (105) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +34 -2
  3. package/docs/spec-alignment.md +10 -0
  4. package/package.json +16 -11
  5. package/site/pages/docs/index.wd +14 -0
  6. package/site/pages/playground/index.js +47 -46
  7. package/src/catalog.js +16 -1
  8. package/src/compiler/actions.js +42 -22
  9. package/src/compiler/body.js +36 -14
  10. package/src/compiler/collections.js +16 -10
  11. package/src/compiler/context.js +39 -10
  12. package/src/compiler/fetch.js +39 -15
  13. package/src/compiler/format.js +5 -2
  14. package/src/compiler/forms.js +91 -26
  15. package/src/compiler/frontmatter.js +11 -2
  16. package/src/compiler/fs-reader.js +2 -1
  17. package/src/compiler/image-size.js +340 -0
  18. package/src/compiler/includes.js +8 -4
  19. package/src/compiler/interpolation.js +15 -7
  20. package/src/compiler/loops.js +63 -35
  21. package/src/compiler/markdown.js +4 -3
  22. package/src/compiler/media.js +17 -3
  23. package/src/compiler/page.js +8 -6
  24. package/src/compiler/predicates.js +49 -24
  25. package/src/compiler/reader.js +12 -2
  26. package/src/compiler/state.js +16 -2
  27. package/src/compiler/structure.js +24 -14
  28. package/src/deploy.js +8 -4
  29. package/src/errors.js +1156 -0
  30. package/src/router.js +7 -4
  31. package/src/scaffold.js +4 -2
  32. package/src/skin.js +17 -6
  33. package/types/api-runner.d.ts +94 -0
  34. package/types/builder.d.ts +141 -10
  35. package/types/catalog.d.ts +97 -0
  36. package/types/compiler/actions.d.ts +41 -0
  37. package/types/compiler/body.d.ts +11 -0
  38. package/types/compiler/collections.d.ts +76 -0
  39. package/types/compiler/context.d.ts +647 -0
  40. package/types/compiler/directives.d.ts +6 -0
  41. package/types/compiler/expr-ast.d.ts +20 -0
  42. package/types/compiler/fetch.d.ts +29 -0
  43. package/types/compiler/format.d.ts +49 -0
  44. package/types/compiler/forms.d.ts +94 -0
  45. package/types/compiler/frontmatter.d.ts +33 -0
  46. package/types/compiler/fs-reader.d.ts +7 -0
  47. package/types/compiler/image-size.d.ts +14 -0
  48. package/types/compiler/includes.d.ts +100 -0
  49. package/types/compiler/index.d.ts +5 -0
  50. package/types/compiler/interpolation.d.ts +115 -0
  51. package/types/compiler/loops.d.ts +36 -0
  52. package/types/compiler/markdown.d.ts +34 -0
  53. package/types/compiler/media.d.ts +32 -0
  54. package/types/compiler/page.d.ts +109 -0
  55. package/types/compiler/predicates.d.ts +50 -0
  56. package/types/compiler/reader.d.ts +48 -0
  57. package/types/compiler/state.d.ts +68 -0
  58. package/types/compiler/structure.d.ts +56 -0
  59. package/types/compiler.d.ts +35 -223
  60. package/types/dev.d.ts +47 -2
  61. package/types/errors.d.ts +100 -0
  62. package/types/feeds.d.ts +150 -0
  63. package/types/headers.d.ts +44 -0
  64. package/types/highlight.d.ts +24 -0
  65. package/types/router.d.ts +42 -3
  66. package/types/scaffold.d.ts +15 -3
  67. package/types/skin.d.ts +28 -1
  68. package/types/src/api-runner.d.ts +94 -0
  69. package/types/src/builder.d.ts +170 -0
  70. package/types/src/catalog.d.ts +97 -0
  71. package/types/src/compiler/actions.d.ts +41 -0
  72. package/types/src/compiler/body.d.ts +11 -0
  73. package/types/src/compiler/collections.d.ts +76 -0
  74. package/types/src/compiler/context.d.ts +647 -0
  75. package/types/src/compiler/directives.d.ts +6 -0
  76. package/types/src/compiler/expr-ast.d.ts +20 -0
  77. package/types/src/compiler/fetch.d.ts +29 -0
  78. package/types/src/compiler/format.d.ts +49 -0
  79. package/types/src/compiler/forms.d.ts +94 -0
  80. package/types/src/compiler/frontmatter.d.ts +33 -0
  81. package/types/src/compiler/fs-reader.d.ts +7 -0
  82. package/types/src/compiler/image-size.d.ts +14 -0
  83. package/types/src/compiler/includes.d.ts +100 -0
  84. package/types/src/compiler/index.d.ts +5 -0
  85. package/types/src/compiler/interpolation.d.ts +115 -0
  86. package/types/src/compiler/loops.d.ts +36 -0
  87. package/types/src/compiler/markdown.d.ts +34 -0
  88. package/types/src/compiler/media.d.ts +32 -0
  89. package/types/src/compiler/page.d.ts +109 -0
  90. package/types/src/compiler/predicates.d.ts +50 -0
  91. package/types/src/compiler/reader.d.ts +48 -0
  92. package/types/src/compiler/state.d.ts +68 -0
  93. package/types/src/compiler/structure.d.ts +56 -0
  94. package/types/src/compiler.d.ts +48 -0
  95. package/types/src/config.d.ts +45 -0
  96. package/types/src/dev.d.ts +58 -0
  97. package/types/src/errors.d.ts +100 -0
  98. package/types/src/feeds.d.ts +150 -0
  99. package/types/src/headers.d.ts +44 -0
  100. package/types/src/highlight.d.ts +24 -0
  101. package/types/src/router.d.ts +78 -0
  102. package/types/src/scaffold.d.ts +20 -0
  103. package/types/src/skin.d.ts +48 -0
  104. package/types/src/statics.d.ts +24 -0
  105. package/types/statics.d.ts +2 -1
@@ -0,0 +1,170 @@
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
+ };
@@ -0,0 +1,97 @@
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
+ };
@@ -0,0 +1,41 @@
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;
@@ -0,0 +1,11 @@
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;
@@ -0,0 +1,76 @@
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
+ };