@refrakt-md/runes 0.26.0 → 0.28.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.
Files changed (57) hide show
  1. package/dist/config.d.ts +4 -1
  2. package/dist/config.d.ts.map +1 -1
  3. package/dist/config.js +17 -2
  4. package/dist/config.js.map +1 -1
  5. package/dist/data-adapters.d.ts +64 -0
  6. package/dist/data-adapters.d.ts.map +1 -0
  7. package/dist/data-adapters.js +281 -0
  8. package/dist/data-adapters.js.map +1 -0
  9. package/dist/data-emit.d.ts +24 -0
  10. package/dist/data-emit.d.ts.map +1 -0
  11. package/dist/data-emit.js +48 -0
  12. package/dist/data-emit.js.map +1 -0
  13. package/dist/data-pipeline.d.ts +24 -0
  14. package/dist/data-pipeline.d.ts.map +1 -0
  15. package/dist/data-pipeline.js +154 -0
  16. package/dist/data-pipeline.js.map +1 -0
  17. package/dist/data-projection.d.ts +79 -0
  18. package/dist/data-projection.d.ts.map +1 -0
  19. package/dist/data-projection.js +212 -0
  20. package/dist/data-projection.js.map +1 -0
  21. package/dist/drawer-pipeline.d.ts +8 -5
  22. package/dist/drawer-pipeline.d.ts.map +1 -1
  23. package/dist/drawer-pipeline.js +2 -2
  24. package/dist/drawer-pipeline.js.map +1 -1
  25. package/dist/expand-pipeline.d.ts +4 -1
  26. package/dist/expand-pipeline.d.ts.map +1 -1
  27. package/dist/expand-pipeline.js +11 -11
  28. package/dist/expand-pipeline.js.map +1 -1
  29. package/dist/field-match.d.ts +4 -0
  30. package/dist/field-match.d.ts.map +1 -1
  31. package/dist/field-match.js +4 -2
  32. package/dist/field-match.js.map +1 -1
  33. package/dist/file-ref-resolve.js +3 -3
  34. package/dist/file-ref-resolve.js.map +1 -1
  35. package/dist/index.d.ts +2 -0
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +11 -1
  38. package/dist/index.js.map +1 -1
  39. package/dist/lib/read-file.d.ts +21 -26
  40. package/dist/lib/read-file.d.ts.map +1 -1
  41. package/dist/lib/read-file.js +25 -77
  42. package/dist/lib/read-file.js.map +1 -1
  43. package/dist/nodes.d.ts +9 -0
  44. package/dist/nodes.d.ts.map +1 -1
  45. package/dist/nodes.js +15 -0
  46. package/dist/nodes.js.map +1 -1
  47. package/dist/snippet-pipeline.d.ts.map +1 -1
  48. package/dist/snippet-pipeline.js +10 -9
  49. package/dist/snippet-pipeline.js.map +1 -1
  50. package/dist/tags/data.d.ts +19 -0
  51. package/dist/tags/data.d.ts.map +1 -0
  52. package/dist/tags/data.js +50 -0
  53. package/dist/tags/data.js.map +1 -0
  54. package/dist/tags/sandbox.d.ts.map +1 -1
  55. package/dist/tags/sandbox.js +11 -6
  56. package/dist/tags/sandbox.js.map +1 -1
  57. package/package.json +3 -3
@@ -0,0 +1,281 @@
1
+ /**
2
+ * Format adapters for the `data` rune (SPEC-103).
3
+ *
4
+ * A format adapter has exactly one job: get raw bytes to the shared
5
+ * intermediate shape `{ headers, rows }`. That is the *only* place
6
+ * format-specific knobs live — everything downstream (projection, typing,
7
+ * table emission) is format-agnostic. This module owns the CSV/TSV adapter;
8
+ * JSON/NDJSON adapters (WORK-486) land here against the same contract.
9
+ */
10
+ /** Thrown by adapters on a malformed source. The preprocess hook catches it
11
+ * and renders an in-page error callout (never a malformed table). */
12
+ export class DataSourceError extends Error {
13
+ constructor(message) {
14
+ super(message);
15
+ this.name = 'DataSourceError';
16
+ }
17
+ }
18
+ /** Infer the format from a file extension, lower-cased. Returns null for an
19
+ * unknown extension so the caller can fall back to an explicit `format`. */
20
+ export function inferFormat(path) {
21
+ const dot = path.lastIndexOf('.');
22
+ if (dot === -1)
23
+ return null;
24
+ const ext = path.slice(dot + 1).toLowerCase();
25
+ switch (ext) {
26
+ case 'csv': return 'csv';
27
+ case 'tsv': return 'tsv';
28
+ case 'json': return 'json';
29
+ case 'ndjson':
30
+ case 'jsonl': return 'ndjson';
31
+ default: return null;
32
+ }
33
+ }
34
+ /**
35
+ * Parse delimited text (CSV/TSV) into a raw grid of string cells, following
36
+ * RFC 4180: double-quoted fields may contain the delimiter, CR/LF, and escaped
37
+ * quotes (`""`). Handles both `\n` and `\r\n` line endings. A trailing newline
38
+ * does not produce a spurious empty final row.
39
+ */
40
+ export function parseDelimited(text, delimiter) {
41
+ const rows = [];
42
+ let row = [];
43
+ let field = '';
44
+ let inQuotes = false;
45
+ let started = false; // any char seen on the current row (so blank lines are kept faithfully)
46
+ const pushField = () => {
47
+ row.push(field);
48
+ field = '';
49
+ };
50
+ const pushRow = () => {
51
+ pushField();
52
+ rows.push(row);
53
+ row = [];
54
+ started = false;
55
+ };
56
+ for (let i = 0; i < text.length; i++) {
57
+ const ch = text[i];
58
+ if (inQuotes) {
59
+ if (ch === '"') {
60
+ if (text[i + 1] === '"') {
61
+ field += '"';
62
+ i++;
63
+ }
64
+ else
65
+ inQuotes = false;
66
+ }
67
+ else {
68
+ field += ch;
69
+ }
70
+ continue;
71
+ }
72
+ if (ch === '"') {
73
+ inQuotes = true;
74
+ started = true;
75
+ continue;
76
+ }
77
+ if (ch === delimiter) {
78
+ pushField();
79
+ started = true;
80
+ continue;
81
+ }
82
+ if (ch === '\r') {
83
+ started = true;
84
+ continue;
85
+ } // CR handled with the following LF
86
+ if (ch === '\n') {
87
+ pushRow();
88
+ continue;
89
+ }
90
+ field += ch;
91
+ started = true;
92
+ }
93
+ // Flush the final field/row unless the input ended exactly on a newline.
94
+ if (started || field.length > 0 || row.length > 0)
95
+ pushRow();
96
+ return rows;
97
+ }
98
+ /**
99
+ * CSV/TSV adapter — reduce delimited text to `{ headers, rows }`. Honors
100
+ * `delimiter` (explicit override or the format default) and `header`
101
+ * (false → synthesized `col1…`). Ragged rows are padded/truncated to the
102
+ * header width so the grid stays rectangular.
103
+ */
104
+ export function delimitedAdapter(raw, opts) {
105
+ const delimiter = opts.delimiter && opts.delimiter.length > 0
106
+ ? opts.delimiter
107
+ : (opts.format === 'tsv' ? '\t' : ',');
108
+ const grid = parseDelimited(raw, delimiter).filter(
109
+ // Drop fully-empty trailing rows (a single empty field from a blank line).
110
+ (r) => !(r.length === 1 && r[0] === ''));
111
+ if (grid.length === 0) {
112
+ throw new DataSourceError('source is empty (no rows)');
113
+ }
114
+ const useHeader = opts.header !== false;
115
+ let headers;
116
+ let bodyStart;
117
+ if (useHeader) {
118
+ headers = grid[0].map((h) => h.trim());
119
+ bodyStart = 1;
120
+ }
121
+ else {
122
+ const width = grid.reduce((max, r) => Math.max(max, r.length), 0);
123
+ headers = Array.from({ length: width }, (_, i) => `col${i + 1}`);
124
+ bodyStart = 0;
125
+ }
126
+ const width = headers.length;
127
+ const rows = [];
128
+ for (let i = bodyStart; i < grid.length; i++) {
129
+ const r = grid[i];
130
+ const cells = [];
131
+ for (let c = 0; c < width; c++)
132
+ cells.push(r[c] ?? '');
133
+ rows.push(cells);
134
+ }
135
+ return { headers, rows };
136
+ }
137
+ // ─────────────────────────────────────────────────────────────────────────
138
+ // JSON / NDJSON adapters (WORK-486)
139
+ // ─────────────────────────────────────────────────────────────────────────
140
+ /** Stringify a leaf value for a cell. Primitives become their string form;
141
+ * arrays of primitives comma-join; anything else JSON-serializes. */
142
+ function cellString(v) {
143
+ if (v === null || v === undefined)
144
+ return '';
145
+ if (Array.isArray(v))
146
+ return v.map((x) => (x === null || x === undefined ? '' : String(x))).join(', ');
147
+ if (typeof v === 'object')
148
+ return JSON.stringify(v);
149
+ return String(v);
150
+ }
151
+ /** Recursively flatten a record's nested plain objects into dotted keys
152
+ * (`{ geo: { country } }` → `geo.country`), so `columns` can pluck nested
153
+ * fields by exact (dotted) header and the intermediate shape stays flat text.
154
+ * Arrays and primitives are leaves. */
155
+ function flattenRecord(obj, prefix = '', out = {}) {
156
+ for (const [k, v] of Object.entries(obj)) {
157
+ const key = prefix ? `${prefix}.${k}` : k;
158
+ if (v !== null && typeof v === 'object' && !Array.isArray(v)) {
159
+ flattenRecord(v, key, out);
160
+ }
161
+ else {
162
+ out[key] = cellString(v);
163
+ }
164
+ }
165
+ return out;
166
+ }
167
+ /** Reduce an array of record objects to `{ headers, rows }` — headers are the
168
+ * union of flattened keys in first-seen order. Shared by JSON `records`/`index`
169
+ * and NDJSON. */
170
+ function recordsToTable(records, leadKey) {
171
+ const flat = records.map((r) => flattenRecord(r));
172
+ const seen = new Set();
173
+ const headers = [];
174
+ if (leadKey) {
175
+ headers.push(leadKey.header);
176
+ seen.add(leadKey.header);
177
+ }
178
+ for (const f of flat) {
179
+ for (const k of Object.keys(f)) {
180
+ if (!seen.has(k)) {
181
+ seen.add(k);
182
+ headers.push(k);
183
+ }
184
+ }
185
+ }
186
+ const rows = flat.map((f, i) => headers.map((h, c) => {
187
+ if (leadKey && c === 0)
188
+ return leadKey.values[i];
189
+ return f[h] ?? '';
190
+ }));
191
+ return { headers, rows };
192
+ }
193
+ /** Resolve a `root` locator (dotted path or JSON Pointer) within a document. */
194
+ function resolveRoot(doc, root) {
195
+ if (!root)
196
+ return doc;
197
+ const parts = root.startsWith('/')
198
+ ? root.slice(1).split('/').map((p) => p.replace(/~1/g, '/').replace(/~0/g, '~'))
199
+ : root.split('.');
200
+ let cur = doc;
201
+ for (const p of parts) {
202
+ if (cur === null || typeof cur !== 'object') {
203
+ throw new DataSourceError(`root path "${root}" does not resolve to a value`);
204
+ }
205
+ cur = cur[p];
206
+ }
207
+ if (cur === undefined)
208
+ throw new DataSourceError(`root path "${root}" not found in the document`);
209
+ return cur;
210
+ }
211
+ /** JSON adapter — reduce a JSON document to `{ headers, rows }` per `root`/`orient`. */
212
+ export function jsonAdapter(raw, opts = {}) {
213
+ let doc;
214
+ try {
215
+ doc = JSON.parse(raw);
216
+ }
217
+ catch (err) {
218
+ throw new DataSourceError(`invalid JSON — ${err.message}`);
219
+ }
220
+ const target = resolveRoot(doc, opts.root ?? '');
221
+ // Determine orientation.
222
+ let orient = opts.orient;
223
+ if (!orient) {
224
+ if (Array.isArray(target)) {
225
+ orient = Array.isArray(target[0]) ? 'values' : 'records';
226
+ }
227
+ else if (target && typeof target === 'object') {
228
+ throw new DataSourceError('source is an object map — set orient="index" (with key-column) to tabulate it');
229
+ }
230
+ else {
231
+ throw new DataSourceError('source is not an array or object of records');
232
+ }
233
+ }
234
+ if (orient === 'values') {
235
+ if (!Array.isArray(target) || target.length === 0) {
236
+ throw new DataSourceError('orient="values" expects a non-empty array of arrays');
237
+ }
238
+ const [headerRow, ...body] = target;
239
+ const headers = headerRow.map(cellString);
240
+ const rows = body.map((inner) => headers.map((_, i) => cellString(inner[i])));
241
+ return { headers, rows };
242
+ }
243
+ if (orient === 'index') {
244
+ if (!target || typeof target !== 'object' || Array.isArray(target)) {
245
+ throw new DataSourceError('orient="index" expects an object map ({ key: record, … })');
246
+ }
247
+ const entries = Object.entries(target);
248
+ const records = entries.map(([, v]) => (v && typeof v === 'object' && !Array.isArray(v) ? v : { value: v }));
249
+ const keys = entries.map(([k]) => k);
250
+ return recordsToTable(records, { header: opts.keyColumn && opts.keyColumn.length > 0 ? opts.keyColumn : 'key', values: keys });
251
+ }
252
+ // records
253
+ if (!Array.isArray(target)) {
254
+ throw new DataSourceError('orient="records" expects an array of objects');
255
+ }
256
+ const records = target.map((r) => (r && typeof r === 'object' && !Array.isArray(r) ? r : { value: r }));
257
+ return recordsToTable(records);
258
+ }
259
+ /** NDJSON adapter — parse line-delimited JSON records to `{ headers, rows }`
260
+ * (the union of record keys becomes the headers). */
261
+ export function ndjsonAdapter(raw) {
262
+ const records = [];
263
+ const lines = raw.split('\n');
264
+ for (let i = 0; i < lines.length; i++) {
265
+ const line = lines[i].trim();
266
+ if (line === '')
267
+ continue;
268
+ let parsed;
269
+ try {
270
+ parsed = JSON.parse(line);
271
+ }
272
+ catch (err) {
273
+ throw new DataSourceError(`invalid NDJSON on line ${i + 1} — ${err.message}`);
274
+ }
275
+ records.push(parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : { value: parsed });
276
+ }
277
+ if (records.length === 0)
278
+ throw new DataSourceError('source is empty (no NDJSON records)');
279
+ return recordsToTable(records);
280
+ }
281
+ //# sourceMappingURL=data-adapters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-adapters.js","sourceRoot":"","sources":["../src/data-adapters.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * AST emission for the `data` rune (SPEC-103).
3
+ *
4
+ * Turns the projected + typed table into a Markdoc `table` AST node — the same
5
+ * shape `Markdoc.parse` produces for a pipe table — so `chart` (`findTable`) and
6
+ * `datatable` (its table/`rf-table-wrapper` lookup) consume it with no
7
+ * structural edits, and it renders as a normal table standalone. Typed-numeric
8
+ * value cells carry a normalized `data-value` (forwarded by the `td` node).
9
+ *
10
+ * The error path emits a visible `hint` callout node instead of a malformed
11
+ * table, so a bad source surfaces on the page without crashing the build.
12
+ */
13
+ import type { Node } from '@markdoc/markdoc';
14
+ import type { TypedTable } from './data-projection.js';
15
+ /** Build a Markdoc `table` AST node from a projected + typed table. */
16
+ export declare function emitTableNode(table: TypedTable): Node;
17
+ /**
18
+ * Build a visible in-page error callout (a `hint` rune node, `type="caution"`)
19
+ * carrying the message — used for sandbox-escape / missing-file / parse-error /
20
+ * empty-result, so the failure is visible and the build continues (the `data`
21
+ * tag never reaches its throwing transform).
22
+ */
23
+ export declare function emitErrorNode(message: string): Node;
24
+ //# sourceMappingURL=data-emit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-emit.d.ts","sourceRoot":"","sources":["../src/data-emit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AASvD,uEAAuE;AACvE,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAmBrD;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAGnD"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * AST emission for the `data` rune (SPEC-103).
3
+ *
4
+ * Turns the projected + typed table into a Markdoc `table` AST node — the same
5
+ * shape `Markdoc.parse` produces for a pipe table — so `chart` (`findTable`) and
6
+ * `datatable` (its table/`rf-table-wrapper` lookup) consume it with no
7
+ * structural edits, and it renders as a normal table standalone. Typed-numeric
8
+ * value cells carry a normalized `data-value` (forwarded by the `td` node).
9
+ *
10
+ * The error path emits a visible `hint` callout node instead of a malformed
11
+ * table, so a bad source surfaces on the page without crashing the build.
12
+ */
13
+ import Markdoc from '@markdoc/markdoc';
14
+ const { Ast } = Markdoc;
15
+ /** Wrap plain text as a Markdoc inline node (the content shape a th/td holds). */
16
+ function inlineText(text) {
17
+ return new Ast.Node('inline', {}, [new Ast.Node('text', { content: text })]);
18
+ }
19
+ /** Build a Markdoc `table` AST node from a projected + typed table. */
20
+ export function emitTableNode(table) {
21
+ const headerCells = table.headers.map((h) => new Ast.Node('th', {}, [inlineText(h)]));
22
+ const thead = new Ast.Node('thead', {}, [new Ast.Node('tr', {}, headerCells)]);
23
+ const bodyRows = table.rows.map((row) => {
24
+ const cells = row.map((cell, c) => {
25
+ // A numeric column with a parseable value carries the normalized number
26
+ // on `data-value`; the cell text stays the original human-formatted
27
+ // string (and the no-JS fallback).
28
+ const attrs = table.columnTypes[c] === 'numeric' && cell.value !== null
29
+ ? { 'data-value': String(cell.value) }
30
+ : {};
31
+ return new Ast.Node('td', attrs, [inlineText(cell.text)]);
32
+ });
33
+ return new Ast.Node('tr', {}, cells);
34
+ });
35
+ const tbody = new Ast.Node('tbody', {}, bodyRows);
36
+ return new Ast.Node('table', {}, [thead, tbody]);
37
+ }
38
+ /**
39
+ * Build a visible in-page error callout (a `hint` rune node, `type="caution"`)
40
+ * carrying the message — used for sandbox-escape / missing-file / parse-error /
41
+ * empty-result, so the failure is visible and the build continues (the `data`
42
+ * tag never reaches its throwing transform).
43
+ */
44
+ export function emitErrorNode(message) {
45
+ const para = new Ast.Node('paragraph', {}, [inlineText(message)]);
46
+ return new Ast.Node('tag', { type: 'caution' }, [para], 'hint');
47
+ }
48
+ //# sourceMappingURL=data-emit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-emit.js","sourceRoot":"","sources":["../src/data-emit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,OAAO,MAAM,kBAAkB,CAAC;AAIvC,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;AAExB,kFAAkF;AAClF,SAAS,UAAU,CAAC,IAAY;IAC/B,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9E,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,aAAa,CAAC,KAAiB;IAC9C,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtF,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IAE/E,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACvC,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;YACjC,wEAAwE;YACxE,oEAAoE;YACpE,mCAAmC;YACnC,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI;gBACtE,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;gBACtC,CAAC,CAAC,EAAE,CAAC;YACN,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC3D,CAAC,CAAC,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC;IAElD,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;AAClD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,OAAe;IAC5C,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAClE,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;AACjE,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Data pipeline hook (SPEC-103).
3
+ *
4
+ * A preprocess sibling to `preprocessSnippets`: walk the parsed AST, and for
5
+ * every `{% data %}` tag resolve its `src` through the SPEC-113 `ProjectFiles`
6
+ * seam (whole-file, project-root bounded), run the format adapter + shared
7
+ * projection + typing, and replace the tag with a Markdoc `table` AST node. The
8
+ * emitted table is consumed by `chart`/`datatable` with no structural edits and
9
+ * is the honest no-JS fallback on a bare page.
10
+ *
11
+ * On any failure (sandbox escape / missing file / parse error / empty result)
12
+ * the tag is replaced with a visible error callout and a build warning is
13
+ * emitted — the build continues and the `data` tag never reaches its throwing
14
+ * transform.
15
+ */
16
+ import type { Node } from '@markdoc/markdoc';
17
+ import type { PreprocessContext, PreprocessPage } from '@refrakt-md/types';
18
+ /**
19
+ * Preprocess: replace every `{% data %}` tag with a resolved `table` node (or an
20
+ * error callout). No-op when no provider is available (tree mode without a wired
21
+ * `ProjectFiles`), matching snippet.
22
+ */
23
+ export declare function preprocessData(ast: Node, page: PreprocessPage, ctx: PreprocessContext): Node | void;
24
+ //# sourceMappingURL=data-pipeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-pipeline.d.ts","sourceRoot":"","sources":["../src/data-pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAgB,iBAAiB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AA4CzF;;;;GAIG;AACH,wBAAgB,cAAc,CAC7B,GAAG,EAAE,IAAI,EACT,IAAI,EAAE,cAAc,EACpB,GAAG,EAAE,iBAAiB,GACpB,IAAI,GAAG,IAAI,CAKb"}
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Data pipeline hook (SPEC-103).
3
+ *
4
+ * A preprocess sibling to `preprocessSnippets`: walk the parsed AST, and for
5
+ * every `{% data %}` tag resolve its `src` through the SPEC-113 `ProjectFiles`
6
+ * seam (whole-file, project-root bounded), run the format adapter + shared
7
+ * projection + typing, and replace the tag with a Markdoc `table` AST node. The
8
+ * emitted table is consumed by `chart`/`datatable` with no structural edits and
9
+ * is the honest no-JS fallback on a bare page.
10
+ *
11
+ * On any failure (sandbox escape / missing file / parse error / empty result)
12
+ * the tag is replaced with a visible error callout and a build warning is
13
+ * emitted — the build continues and the `data` tag never reaches its throwing
14
+ * transform.
15
+ */
16
+ import { delimitedAdapter, jsonAdapter, ndjsonAdapter, inferFormat, DataSourceError, } from './data-adapters.js';
17
+ import { applyWhere, applySort, applyColumns, applyLimitOffset, applyTyping, } from './data-projection.js';
18
+ import { emitTableNode, emitErrorNode } from './data-emit.js';
19
+ /** Resolve a Markdoc attribute value to a string — literal strings and
20
+ * `Variable` AST nodes (e.g. `src=$file.dir`). Mirrors snippet's resolver. */
21
+ function resolveString(value, variables) {
22
+ if (value === undefined || value === null)
23
+ return '';
24
+ if (typeof value === 'string')
25
+ return value;
26
+ if (typeof value === 'number' || typeof value === 'boolean')
27
+ return String(value);
28
+ if (typeof value === 'object' && '$$mdtype' in value) {
29
+ const node = value;
30
+ if (node.$$mdtype === 'Variable' && Array.isArray(node.path)) {
31
+ let current = variables;
32
+ for (const segment of node.path) {
33
+ if (current === null || current === undefined)
34
+ return '';
35
+ current = current[segment];
36
+ }
37
+ return current === null || current === undefined ? '' : String(current);
38
+ }
39
+ }
40
+ return '';
41
+ }
42
+ /** Parse a comma-separated column list into trimmed, non-empty names. */
43
+ function splitList(raw) {
44
+ return raw.split(',').map((s) => s.trim()).filter((s) => s.length > 0);
45
+ }
46
+ /**
47
+ * Preprocess: replace every `{% data %}` tag with a resolved `table` node (or an
48
+ * error callout). No-op when no provider is available (tree mode without a wired
49
+ * `ProjectFiles`), matching snippet.
50
+ */
51
+ export function preprocessData(ast, page, ctx) {
52
+ if (!ctx.sandbox)
53
+ return;
54
+ let mutated = false;
55
+ walkAndReplaceData(ast, page, ctx, ctx.sandbox, () => { mutated = true; });
56
+ return mutated ? ast : undefined;
57
+ }
58
+ function walkAndReplaceData(node, page, ctx, files, onReplaced) {
59
+ if (!node.children)
60
+ return;
61
+ for (let i = 0; i < node.children.length; i++) {
62
+ const child = node.children[i];
63
+ if (child.type === 'tag' && child.tag === 'data') {
64
+ node.children[i] = resolveDataToNode(child, page, ctx, files);
65
+ onReplaced();
66
+ continue;
67
+ }
68
+ walkAndReplaceData(child, page, ctx, files, onReplaced);
69
+ }
70
+ }
71
+ function resolveDataToNode(tag, page, ctx, files) {
72
+ const a = tag.attributes;
73
+ const src = resolveString(a.src, ctx.variables);
74
+ if (!src) {
75
+ const msg = 'data `src` attribute is required (and an unresolvable variable reference resolves to empty)';
76
+ ctx.error(msg, page.url);
77
+ return emitErrorNode(`data error: ${msg}`);
78
+ }
79
+ try {
80
+ const raw = files.read(src);
81
+ if (raw === null) {
82
+ throw new DataSourceError(`source "${src}" cannot be resolved — the file is missing or outside the project root`);
83
+ }
84
+ const format = resolveFormat(src, resolveString(a.format, ctx.variables));
85
+ const table = runAdapter(raw, format, a, ctx);
86
+ // Shared projection: where → sort → columns → limit/offset.
87
+ const { table: filtered, warnings } = applyWhere(table, resolveString(a.where, ctx.variables) || undefined);
88
+ for (const w of warnings)
89
+ ctx.warn(`data "${src}": ${w}`, page.url);
90
+ const sorted = applySort(filtered, resolveString(a.sort, ctx.variables) || undefined);
91
+ const { table: selected, sources } = applyColumns(sorted, resolveString(a.columns, ctx.variables) || undefined);
92
+ const projected = applyLimitOffset(selected, numberAttr(a.limit), numberAttr(a.offset));
93
+ if (projected.rows.length === 0) {
94
+ throw new DataSourceError('result is empty after projection (no rows to render)');
95
+ }
96
+ // Shared typing → data-value channel (`numeric`/`text` may name the
97
+ // source or the renamed column).
98
+ const numericCols = splitList(resolveString(a.numeric, ctx.variables));
99
+ const textCols = splitList(resolveString(a.text, ctx.variables));
100
+ const typed = applyTyping(projected, { numeric: numericCols, text: textCols, sources });
101
+ return emitTableNode(typed);
102
+ }
103
+ catch (err) {
104
+ const msg = err instanceof DataSourceError
105
+ ? err.message
106
+ : `unexpected failure — ${err instanceof Error ? err.message : String(err)}`;
107
+ ctx.error(`data "${src}": ${msg}`, page.url);
108
+ return emitErrorNode(`data error: ${msg}`);
109
+ }
110
+ }
111
+ /** Resolve the effective format: explicit override, else extension-inferred. */
112
+ function resolveFormat(src, explicit) {
113
+ if (explicit)
114
+ return explicit;
115
+ const inferred = inferFormat(src);
116
+ if (inferred)
117
+ return inferred;
118
+ throw new DataSourceError(`could not infer format from "${src}" — add format="csv|tsv|json|ndjson"`);
119
+ }
120
+ /** Dispatch to the format adapter. CSV/TSV land here (WORK-417); JSON/NDJSON
121
+ * adapters arrive in WORK-486 against this same contract. */
122
+ function runAdapter(raw, format, a, ctx) {
123
+ switch (format) {
124
+ case 'csv':
125
+ case 'tsv':
126
+ return delimitedAdapter(raw, {
127
+ format,
128
+ delimiter: resolveString(a.delimiter, ctx.variables) || undefined,
129
+ header: a.header === undefined ? undefined : a.header !== false,
130
+ });
131
+ case 'json': {
132
+ const orient = resolveString(a.orient, ctx.variables);
133
+ return jsonAdapter(raw, {
134
+ root: resolveString(a.root, ctx.variables) || undefined,
135
+ orient: orient ? orient : undefined,
136
+ keyColumn: resolveString(a['key-column'], ctx.variables) || undefined,
137
+ });
138
+ }
139
+ case 'ndjson':
140
+ return ndjsonAdapter(raw);
141
+ default:
142
+ throw new DataSourceError(`unsupported format "${format}"`);
143
+ }
144
+ }
145
+ function numberAttr(value) {
146
+ if (typeof value === 'number' && Number.isFinite(value))
147
+ return value;
148
+ if (typeof value === 'string' && value.trim() !== '') {
149
+ const n = Number(value);
150
+ return Number.isFinite(n) ? n : undefined;
151
+ }
152
+ return undefined;
153
+ }
154
+ //# sourceMappingURL=data-pipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-pipeline.js","sourceRoot":"","sources":["../src/data-pipeline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Shared projection + typing for the `data` rune (SPEC-103).
3
+ *
4
+ * Everything here is format-agnostic: it runs on the intermediate
5
+ * `{ headers, rows }` shape every adapter produces, identically regardless of
6
+ * source. The pipeline is `where → sort → columns → limit/offset` (projection)
7
+ * then `numeric/text` typing, which emits the normalized `data-value` channel
8
+ * that carries a clean number to `chart`'s renderer and `datatable`'s sort.
9
+ */
10
+ import type { DataTable } from './data-adapters.js';
11
+ export type ColumnType = 'numeric' | 'text';
12
+ /** A typed cell: the original (human-formatted) text plus a normalized numeric
13
+ * value when the column is numeric and the text parses. The `value` becomes
14
+ * the cell's `data-value`; the text stays the visible content + no-JS fallback. */
15
+ export interface TypedCell {
16
+ text: string;
17
+ value: number | null;
18
+ }
19
+ /** The fully projected + typed table the emitter turns into a Markdoc node. */
20
+ export interface TypedTable {
21
+ headers: string[];
22
+ columnTypes: ColumnType[];
23
+ rows: TypedCell[][];
24
+ }
25
+ /**
26
+ * Normalize a human-formatted number to a plain JS number, or null when the
27
+ * text isn't numeric. Strips common currency symbols and thousands separators
28
+ * (`"$1,200"` → `1200`); leaves percentages, units, and prose as non-numeric.
29
+ */
30
+ export declare function normalizeNumber(text: string): number | null;
31
+ /** A single `columns` selection: source header + optional rename. */
32
+ interface ColumnSelection {
33
+ source: string;
34
+ as?: string;
35
+ }
36
+ /** Parse a `columns` spec — `"name as Product, revenue as 'Revenue ($)'"` —
37
+ * into ordered selections. Commas inside quotes don't split; aliases may be
38
+ * bare, single-, or double-quoted. */
39
+ export declare function parseColumnsSpec(spec: string): ColumnSelection[];
40
+ /**
41
+ * Apply `where` — filter rows with the SPEC-070 `field:value` grammar, reusing
42
+ * `parseFieldMatch` + `matchValue` with a row-shaped resolver (the column header
43
+ * is the field; the cell text is the single candidate). AND across distinct
44
+ * fields, OR within a repeated field. Returns the (possibly filtered) table plus
45
+ * any parse warnings for the caller to surface.
46
+ */
47
+ export declare function applyWhere(table: DataTable, expr: string | undefined): {
48
+ table: DataTable;
49
+ warnings: string[];
50
+ };
51
+ /** Apply `columns` — select, reorder, and rename. Unknown sources are skipped
52
+ * (a `where`/`sort` may legitimately reference a column the author then drops).
53
+ * Returns the (possibly renamed) table plus `sources` — the original source
54
+ * header for each output column, so typing can match `numeric`/`text` against
55
+ * either the source or the alias. With no spec, the table is unchanged and
56
+ * `sources` mirrors the headers. */
57
+ export declare function applyColumns(table: DataTable, spec: string | undefined): {
58
+ table: DataTable;
59
+ sources: string[];
60
+ };
61
+ /** Apply `sort` — `"revenue"` (asc) or `"-revenue"` (desc). Sorts numerically
62
+ * when every non-empty cell in the column parses as a number, else by natural
63
+ * string collation. A no-op when `spec` is empty or names an unknown column. */
64
+ export declare function applySort(table: DataTable, spec: string | undefined): DataTable;
65
+ /** Apply `limit`/`offset` — a row slice (the `data` analogue of snippet `lines=`). */
66
+ export declare function applyLimitOffset(table: DataTable, limit?: number, offset?: number): DataTable;
67
+ /**
68
+ * Type each column and emit the `data-value` channel. A column is numeric when
69
+ * explicitly listed in `numeric`, or (by default) when every non-empty cell
70
+ * parses as a number; `text` forces a column back to text. Numeric value cells
71
+ * carry the normalized number; text cells carry `null`.
72
+ */
73
+ export declare function applyTyping(table: DataTable, opts?: {
74
+ numeric?: string[];
75
+ text?: string[];
76
+ sources?: string[];
77
+ }): TypedTable;
78
+ export {};
79
+ //# sourceMappingURL=data-projection.d.ts.map