@nodegx/export 0.0.0-stage → 0.2.5

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 (49) hide show
  1. package/README.md +59 -2
  2. package/dist/analyze/appState.d.ts +296 -0
  3. package/dist/analyze/plan.d.ts +3757 -0
  4. package/dist/analyze/querySettings.d.ts +75 -0
  5. package/dist/analyze/reach.d.ts +41 -0
  6. package/dist/analyze/scriptUses.d.ts +29 -0
  7. package/dist/catalog.d.ts +129 -0
  8. package/dist/cli/args.d.ts +90 -0
  9. package/dist/cli/exitCodes.d.ts +125 -0
  10. package/dist/cli/run.d.ts +30 -0
  11. package/dist/cli.inputs.json +174 -0
  12. package/dist/cli.mjs +53746 -0
  13. package/dist/cli.mjs.map +7 -0
  14. package/dist/emit/animateLib.d.ts +43 -0
  15. package/dist/emit/component.d.ts +144 -0
  16. package/dist/emit/dateLib.d.ts +45 -0
  17. package/dist/emit/emitApp.d.ts +38 -0
  18. package/dist/emit/idLib.d.ts +68 -0
  19. package/dist/emit/kits.d.ts +85 -0
  20. package/dist/emit/mediaLib.d.ts +75 -0
  21. package/dist/emit/naming.d.ts +76 -0
  22. package/dist/emit/parseLib.d.ts +106 -0
  23. package/dist/emit/preflight.d.ts +174 -0
  24. package/dist/emit/readme.d.ts +51 -0
  25. package/dist/emit/report.d.ts +309 -0
  26. package/dist/emit/scaffold.d.ts +67 -0
  27. package/dist/emit/statesLib.d.ts +52 -0
  28. package/dist/emit/style.d.ts +165 -0
  29. package/dist/emit/utilLib.d.ts +78 -0
  30. package/dist/errorMessage.d.ts +28 -0
  31. package/dist/index.cjs +52848 -0
  32. package/dist/index.cjs.map +7 -0
  33. package/dist/index.d.ts +37 -0
  34. package/dist/index.mjs +52769 -0
  35. package/dist/index.mjs.map +7 -0
  36. package/dist/ir/types.d.ts +567 -0
  37. package/dist/ledger.cjs +971 -0
  38. package/dist/ledger.cjs.map +7 -0
  39. package/dist/ledger.d.ts +75 -0
  40. package/dist/ledger.mjs +948 -0
  41. package/dist/ledger.mjs.map +7 -0
  42. package/dist/node-catalog.json +65333 -0
  43. package/dist/parse/kitSource.d.ts +135 -0
  44. package/dist/parse/parseModules.d.ts +42 -0
  45. package/dist/parse/parseProject.d.ts +13 -0
  46. package/dist/scriptFiles.d.ts +30 -0
  47. package/dist/structurePorts.d.ts +70 -0
  48. package/dist/write/writeExport.d.ts +67 -0
  49. package/package.json +53 -4
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Scaffolding generator — EXP-002 implementation step 3: "a project that builds with an empty
3
+ * component proves the pipeline end to end."
4
+ *
5
+ * Emits everything around the components: package.json, Vite/TS config, entry point, the route
6
+ * table derived from the project's Router node(s) + each page's `Page` node urlPath, the design
7
+ * tokens as tokens.css, and a placeholder page per routed component so the output builds before
8
+ * the visual generator exists. Placeholders are explicitly marked and are replaced file-for-file
9
+ * as later generators land.
10
+ *
11
+ * Pure: ExportIR in, sorted { path → content } out. No filesystem access here — writing (and
12
+ * EXP-007's provenance headers/hashes, which need the final bytes) happens in a separate step.
13
+ */
14
+ import { ExportIR } from '../ir/types';
15
+ /**
16
+ * EXP-011 §54. The router shell kept as a component file for the logic beside its Router — an `On App Error`
17
+ * boundary — which `App.tsx` renders as the first child of the router, alive for the app's life.
18
+ */
19
+ export interface ScaffoldShell {
20
+ symbol: string;
21
+ fileBase: string;
22
+ }
23
+ export interface ScaffoldPage {
24
+ /** Component path form: "Pages/Landing". */
25
+ componentPath: string;
26
+ /** "ThankYou" — PascalCased last path segment, deduplicated. */
27
+ fileBase: string;
28
+ /** "ThankYouPage". */
29
+ symbol: string;
30
+ /** "/thank-you", or "/product/{id}" — the component's Page node urlPath, verbatim. */
31
+ urlPath: string;
32
+ /**
33
+ * The same path as a react-router pattern: "/product/{id}" → "/product/:id".
34
+ *
35
+ * 🔴 **Not cosmetic — a braced segment matches nothing in react-router.** The runtime's own
36
+ * matcher splits on "/" and treats a `{name}` part as a capture (`router.tsx:746`); react-router
37
+ * spells the same thing `:name`. Emitting the authored path into `<Route path=…>` produced a
38
+ * route that only ever matched the literal text "{id}", so every detail page 404'd to the
39
+ * start page and the parameters this slice reads were never populated at all.
40
+ */
41
+ routePath: string;
42
+ /** The braced segment names, in path order — "/product/{id}/{tab}" → ["id", "tab"]. */
43
+ pathParams: string[];
44
+ isStart: boolean;
45
+ }
46
+ /**
47
+ * The braced segments of an authored urlPath, in order.
48
+ *
49
+ * ⚠️ Deliberately the runtime's own regex (`router.tsx:614`), not a stricter one. `Navigate To
50
+ * Path` uses `/\{[A-Za-z0-9_]*\}/g` — a narrower alphabet — and the two disagreeing is a
51
+ * runtime fact this export is not the place to resolve: a Page whose urlPath is `/x/{a-b}` has a
52
+ * parameter as far as the Router is concerned, so it has one here.
53
+ */
54
+ export declare function bracedParams(urlPath: string): string[];
55
+ export declare function emitScaffold(ir: ExportIR, shell?: ScaffoldShell): Record<string, string>;
56
+ /**
57
+ * The route table: the first Router node's `routes` in source order, joined with each target
58
+ * component's `Page` node `urlPath`. Components a router lists but the project lacks are
59
+ * skipped here — analysis reports them (nothing in emit is allowed to throw on content).
60
+ */
61
+ export declare function routedPages(ir: ExportIR): ScaffoldPage[];
62
+ /**
63
+ * P18-S110-ROUTERSELF. What the export does not do with a Router's own ports, one sentence each. The Router collapses
64
+ * into `App.tsx` (`plan.ts` `routerShellDisposition`), which renders the pages straight into the route table: there
65
+ * is no Router element to paint, clip or class, and no Router to unmount.
66
+ */
67
+ export declare function routerNotes(ir: ExportIR): string[];
@@ -0,0 +1,52 @@
1
+ /**
2
+ * `src/lib/states.ts` — the `States` node, emitted into the app (EXP-011 §49).
3
+ *
4
+ * {@link ./animateLib.ts}'s shape, one module over, and a module of its own because an app that
5
+ * fades a number should not ship a state machine. It imports `./animate` for the run engine, the
6
+ * bezier solver and the linear curve.
7
+ *
8
+ * It is a transcription of `noodl-viewer-react/src/nodes/std-library/states.ts`:
9
+ *
10
+ * - **Requests are queued per pass and drained after it** (`scheduleGoToState` over
11
+ * `scheduleAfterInputsHaveUpdated`): a request for where the pass is already heading answers
12
+ * Unchanged at once; otherwise all but the last request are *settled immediately* and the last
13
+ * one animates. The drain here is a microtask — the handler that asked is the pass.
14
+ * - **`goToState`**: a falsy state is the first state; the current state is Unchanged; a name not
15
+ * in the list is Failure, with the node's own `Error` text (`nearestName` transcribed for the
16
+ * "Did you mean" clause); the first ever request jumps (no State Changed); after that booleans and
17
+ * strings jump, numbers and colours tween along `transition-<state>-<value>`, else
18
+ * `transitiondef-<state>`, else `{[0, 0, 0.58, 1], 300, 0}`, and settle at once when both are 0,
19
+ * when Use Transitions is off, or when the state is one the pass only passed through. `State`,
20
+ * `At <state>` and State Changed move at the request; `Has Reached <state>` at the tween's end
21
+ * (at once when there is none); Done after State Changed.
22
+ * - **Colours** go through `resolveColor`, then `readColor` (the viewer's `color-reader.ts`,
23
+ * transcribed), interpolate per channel with `Math.floor`, come back as `rgbaToHex`, and land on
24
+ * the value the state names. Before GAM-006 (P88) the interpreter read every colour as hex, so a
25
+ * `var(--token)` tweened through `#0aNaNNaNNaN`; it now reads the token off the document, as this
26
+ * module always did. A colour unreadable at either end holds the colour on screen until the end,
27
+ * in both worlds. The one departure left: this `resolveColor` also resolves a named colour
28
+ * (`red`) through a probe element, so here it glides where the interpreter holds.
29
+ * - **A colour with a per-value delay holds the colour on screen for the delay.** Before GAM-006
30
+ * (P88) both worlds published the tween's parsed RGBA array there (`currentValues[v] =
31
+ * this.startValues[v]`), which no style sink accepts. Both now publish the start colour string.
32
+ * - **Boot** (`states`'s setter, then an authored `currentState`): the node jumps to the first
33
+ * state, and an authored State that is not the first is a queued request — so it *animates* from
34
+ * the first state at boot and fires State Changed. Reproduced.
35
+ */
36
+ /** Where the module lands in the exported app. */
37
+ export declare const STATES_LIB_PATH = "src/lib/states.ts";
38
+ /** The exported helpers a component imports. Sorted — the import list is sorted too. */
39
+ export declare const STATES_HELPERS: readonly ["defineStates", "useStates"];
40
+ /** The value types this slice translates — `textStyle` is refused by name. */
41
+ export declare const STATES_VALUE_TYPES: readonly ["number", "string", "boolean", "color"];
42
+ export type StatesValueType = (typeof STATES_VALUE_TYPES)[number];
43
+ /** The interpreter's default transition, `goToState`'s own literal. */
44
+ export declare const DEFAULT_TRANSITION: {
45
+ readonly curve: readonly [0, 0, 0.58, 1];
46
+ readonly dur: 300;
47
+ readonly delay: 0;
48
+ };
49
+ /**
50
+ * The module's source — a plain string, for `dateLib.ts`'s stated reason.
51
+ */
52
+ export declare function statesLibSource(): string;
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Style extraction — the per-node content-vs-style parameter split and the parameter → CSS
3
+ * mapping (EXP-002 step 4, semantics settled in EXP-002-TARGET-OUTPUT.md §1):
4
+ *
5
+ * - A node's parameters split into two piles: content/behaviour (text, src, alt, label, …) go to
6
+ * JSX; layout and style go to one CSS-module class per visual node. The split is an explicit
7
+ * table per visual type, never a guess.
8
+ * - Runtime style semantics become their CSS equivalents by table: `clip: true` →
9
+ * `overflow: hidden`; `sizeMode` gates whether width/height are emitted; the `boxShadow*`
10
+ * params fold into one `box-shadow` (missing pieces fall back to the catalog's port defaults,
11
+ * because the interpreter falls back to the same); per-corner radii fold when uniform;
12
+ * padding/margin use shorthands when the sides agree.
13
+ * - Token references (`var(--space-5)`) pass through verbatim; literals pass through literally;
14
+ * `{value, unit}` dimensions join into CSS lengths (`0` stays unitless).
15
+ * - `Text` renders with `margin: 0`; flex containers state `display: flex` and their
16
+ * `flex-direction` explicitly rather than relying on a global reset.
17
+ *
18
+ * Parameters that are neither content nor style (variant, cssClassName, mounted, …) are returned
19
+ * as `unhandled` — analysis reports them; nothing is silently dropped.
20
+ */
21
+ import { CatalogIndex } from '../catalog';
22
+ import { NodeIR, ParamValue, StylesIR } from '../ir/types';
23
+ /** How a rendered node behaves for style purposes. */
24
+ export type StyleRole = 'group' | 'text' | 'image' | 'button' | 'input' | 'page' | 'columns' | 'icon' | 'checkbox' | 'radio' | 'radiogroup' | 'select' | 'range' | 'video' | 'circle' | 'drag'
25
+ /** EXP-011 §61. A Component Stack — a flex column that fills its parent and clips, as its `defaultCss` states. */
26
+ | 'stack';
27
+ export interface Decl {
28
+ prop: string;
29
+ value: string;
30
+ }
31
+ export interface NodeStyle {
32
+ /** Ordered, ready to print. */
33
+ decls: Decl[];
34
+ /** Parameter names the style tables know nothing about — report, never guess. */
35
+ unhandled: string[];
36
+ /** Anything the tables dropped knowingly (unusable layout tokens, …) — report verbatim. */
37
+ notes: string[];
38
+ }
39
+ /** Pseudo/companion CSS a role owns beyond its one class (VISUALS-TARGET). */
40
+ export interface RoleCss {
41
+ /** Printed as `.cls<suffix> { … }` right after the node's own block, decls hand-ordered. */
42
+ blocks: Array<{
43
+ suffix: string;
44
+ decls: Decl[];
45
+ }>;
46
+ /** A companion class beside the node's own: the control's label wrapper, the columns query container. */
47
+ wrapper?: {
48
+ role: 'label' | 'container';
49
+ decls: Decl[];
50
+ };
51
+ /** `@container (max-width: …)` overrides of the node's own class (columns breakpoints). */
52
+ containerQueries: Array<{
53
+ maxWidth: string;
54
+ decls: Decl[];
55
+ }>;
56
+ notes: string[];
57
+ }
58
+ /**
59
+ * The content/behaviour half of the split: parameters that bind into JSX rather than CSS,
60
+ * per visual type. `children` renders as the element's text child; `attr:<name>` as a JSX
61
+ * attribute; `head` as a hoisted document tag; `routing` is consumed by the route table.
62
+ */
63
+ export declare const CONTENT_PARAMS: Record<string, Record<string, string>>;
64
+ /** JSX attribute order per element, so generated attribute lists are stable and readable. */
65
+ export declare const CONTENT_ATTR_ORDER: string[];
66
+ /**
67
+ * The style parameters a **wire** may land on (EXP-011 §49) — printed as an inline `style={{…}}`
68
+ * on the element, which wins over the module class exactly as a wired value replaces the
69
+ * authored parameter in the runtime. `sink` is what the position holds, for the untyped-source
70
+ * table in `component.ts`; `css` is the React style key.
71
+ *
72
+ * Three, chosen by what the animation pair drives and by what needs no unit: `opacity` is
73
+ * unitless, the two colours are strings. A wired `width` would need the port's `defaultUnit`
74
+ * appended and a wired `transformX` a `transform` the static style has no rule for — both
75
+ * refused by name until a fixture asks. Keys in emit order.
76
+ *
77
+ * 🔴 **"Refused by name" was the intent and not the behaviour, for as long as this table existed
78
+ * (HLS-005).** Nothing here refuses anything: this is a lookup table, and `styleAttrs` iterates
79
+ * *it* rather than the bindings, so a wire onto a port that is not a key was never visited and so
80
+ * never named. The wire was dropped in silence and the component could still be filed under
81
+ * "Translated with nothing left over" — issue #23. The mechanism that makes this sentence true is
82
+ * the claim ledger and its sweep in `component.ts`, which reports every binding no builder took.
83
+ * `tests/fixtures/status-rail` is the fixture that asked.
84
+ */
85
+ /**
86
+ * EXP-011 §63. A `Drag`'s own ports — the hook's options, printed by the component emitter and neither style nor
87
+ * content. ⚠️ `plan.ts`'s `DRAG_OPTION_PORTS` is the authority (it carries the keys and labels); this list must name the
88
+ * same ports, and `drag.test.ts` pins that it does. style.ts cannot import plan.ts (plan.ts imports this module).
89
+ */
90
+ export declare const DRAG_OWN_PORTS: readonly string[];
91
+ export declare const WIRED_STYLE_SINKS: Record<string, {
92
+ css: string;
93
+ sink: 'number' | 'string';
94
+ }>;
95
+ export declare function computeNodeStyle(node: NodeIR, role: StyleRole, catalog: CatalogIndex,
96
+ /**
97
+ * STY-004. The project's style dictionary, when it has one. Optional because 48 of this package's
98
+ * 48 fixtures and all seven shipped templates have none, and because every existing caller
99
+ * predates it — a node with no Look and no text style must compute byte-identically without it.
100
+ */
101
+ styles?: StylesIR): NodeStyle;
102
+ /**
103
+ * The layout string as grid tracks — `readLayoutToken`'s own rule (Columns.tsx): entries that
104
+ * are not positive finite numbers are dropped (reported here, where the runtime's validator
105
+ * cannot run), and a wholly unusable string renders one full-width column. An authored non-zero
106
+ * minWidth wraps each track in minmax(), the fold's floor spelled in CSS.
107
+ */
108
+ export declare function layoutTracks(layoutString: string, minWidth: string | undefined, notes: string[]): string;
109
+ /** Auto Fit's tracks; a zero/absent minimum degrades to one column, the runtime's own floor. */
110
+ export declare function autoFitTracks(minWidth: string | undefined): string;
111
+ /** The three `Noodl.Icon` shapes plus image sources, resolved from static parameters. */
112
+ export type IconSource = {
113
+ kind: 'font';
114
+ classes: string[];
115
+ text?: string;
116
+ } | {
117
+ kind: 'sprite';
118
+ url: string;
119
+ symbolId: string;
120
+ } | {
121
+ kind: 'image';
122
+ src: string;
123
+ } | {
124
+ kind: 'inline';
125
+ } | {
126
+ kind: 'none';
127
+ };
128
+ export declare function iconSourceOf(node: NodeIR, catalog: CatalogIndex): IconSource;
129
+ /**
130
+ * The CSS a role owns beyond its single class: control marks (::before), label wrappers, and
131
+ * the columns breakpoints' @container rules. Kept beside computeNodeStyle because the two must
132
+ * agree on effective values (border colour feeds both the box and the mark).
133
+ */
134
+ export declare function computeRoleCss(node: NodeIR, role: StyleRole, catalog: CatalogIndex,
135
+ /**
136
+ * STY-004. The same dictionary `computeNodeStyle` gets, for the same reason this function sits
137
+ * beside it: a Look's `borderColor` has to reach the checkbox's mark as well as its box. Resolve
138
+ * it in one of the two and they disagree, which is the defect this pairing exists to prevent.
139
+ */
140
+ styles?: StylesIR): RoleCss;
141
+ /** Tokens and literals pass through verbatim; dimensions join value and unit; zero drops its unit. */
142
+ export declare function cssValue(value: ParamValue): string;
143
+ /**
144
+ * EXP-014. A `backgroundImage` port value as it must read inside `url(…)` in a generated CSS
145
+ * module.
146
+ *
147
+ * 🔴 **The leading slash is the whole function.** The port holds a project-relative path
148
+ * (`noodl_modules/starter-imagery/people-coffee-shop.webp`) and the asset travels through the
149
+ * `copies` channel to `public/<same path>`, which the bundler serves from the site root. A
150
+ * *relative* `url()` in CSS resolves against the stylesheet's own URL, not the document's, so the
151
+ * verbatim value would be resolved at build time against `src/pages/` and fail there. Root-
152
+ * absolute is the same shape `scaffold.ts` gives a module stylesheet's `<link href>`, and for the
153
+ * same reason.
154
+ *
155
+ * Anything already absolute — an http(s) URL, a protocol-relative one, a `data:` URI, or a path
156
+ * that already starts at the root — passes through untouched.
157
+ */
158
+ export declare function cssUrl(value: string): string;
159
+ /**
160
+ * EXP-014. `backdropBlur` as a CSS length, or `undefined` where the filter must not be emitted at
161
+ * all — the runtime's `cssLength` followed by its zero gate, transcribed. A `{value, unit}` from
162
+ * the editor and a bare number from a parameter are both lengths in px; a token reference is a
163
+ * string that is not a number, is not zero, and paints.
164
+ */
165
+ export declare function blurLength(value: ParamValue | undefined): string | undefined;
@@ -0,0 +1,78 @@
1
+ /**
2
+ * `src/lib/util.ts` — the small string/math utilities, emitted into the app (EXP-011 Tier 2.7).
3
+ *
4
+ * The same shape as {@link ./dateLib.ts}, and for the same reason: `Substring`, `Number Remapper`
5
+ * and `String Mapper` are one pure function each, so what varies between two projects using them
6
+ * is only the arguments at the call site. Constant text here, shipped only where something calls
7
+ * into it.
8
+ *
9
+ * It is a transcription of three runtime files, and the transcription is the whole job:
10
+ *
11
+ * - `noodl-runtime/src/nodes/std-library/substring.ts` — the `-1` sentinel and the `substr` call.
12
+ * - `noodl-runtime/src/nodes/std-library/numberremapper.ts` — `_calculateNewOutputValue`, whose
13
+ * degenerate branch (`maxInput === minInput ⇒ 0`) is reproduced rather than repaired. NDA-012
14
+ * already decided that question in the interpreter, by moving the *default* off the degenerate
15
+ * configuration; an export that silently answered something else would disagree with the node
16
+ * an author has already watched run.
17
+ * - `noodl-runtime/src/nodes/std-library/stringmapper.ts` — `doMapping`, which is an `indexOf`
18
+ * over two index-aligned lists.
19
+ *
20
+ * 🔴 **Two of the three take `unknown` where the runtime takes whatever arrived, and one place
21
+ * they deliberately disagree.** `Substring`'s `string` setter is `value.toString()`, which
22
+ * **throws** on `null`/`undefined` rather than yielding an empty result — the node's own port
23
+ * description says so. Reproducing that would put an uncaught exception in somebody's page, which
24
+ * is the trade the date family already refused (`dateLib.ts`, the enum paragraph). So the helper
25
+ * answers `''` there, and the planner files a note wherever a wire into that port can actually
26
+ * deliver an empty. For every value the interpreter survives, `String(v)` and `v.toString()` are
27
+ * the same string.
28
+ *
29
+ * ⚠️ **`Number()` rather than the raw arithmetic, and they agree.** The interpreter stores what
30
+ * arrives and lets `-` and `/` coerce. `Number(x)` and `x - 0` produce the same result for every
31
+ * primitive a port can carry — `''` and `null` to `0`, `undefined` and unparseable text to `NaN`
32
+ * — so the conversion is a typing device here and not a behaviour change.
33
+ */
34
+ import { ParseHelper } from './parseLib';
35
+ /** Where the module lands in the exported app. */
36
+ export declare const UTIL_LIB_PATH = "src/lib/util.ts";
37
+ /** The exported helpers, one per translated node. Sorted — the import list is sorted too. */
38
+ export declare const UTIL_HELPERS: readonly ["blendColor", "blendColorKept", "booleanToString", "log", "mapString", "pickFile", "remapNumber", "substring"];
39
+ /**
40
+ * A `util-call`'s verb. EXP-011 §75 widens it by the four parse helpers, which live in `src/lib/parse.ts`
41
+ * ({@link ./parseLib.ts}) and NOT in this module's source: the plan and the emitter treat the two families
42
+ * as one kind (a pure call, arguments in port order), and the import line is split by module at emit.
43
+ */
44
+ export type UtilHelper = (typeof UTIL_HELPERS)[number] | ParseHelper;
45
+ /**
46
+ * Which helpers can answer `undefined`, and it is exactly one.
47
+ *
48
+ * `substring` always returns a string and `remapNumber` always returns a number (`NaN` is a
49
+ * number, and `NaN` is what the interpreter publishes too). `mapString` publishes `Default` when
50
+ * nothing matched, and `Default` is unset on a node whose panel the author never opened — so it
51
+ * is the one read in this family a sink has to guard.
52
+ *
53
+ * 🔴 Must agree with `maybeUndefinedExpr` in `plan.ts` and `maybeUndefined` in `component.ts`;
54
+ * both read this table rather than restating it, which is the only spelling under which three
55
+ * copies of one fact cannot drift.
56
+ */
57
+ export declare const UTIL_HELPER_MAY_BE_UNDEFINED: Record<UtilHelper, boolean>;
58
+ /**
59
+ * Whether a `util-call` can answer `undefined` — {@link UTIL_HELPER_MAY_BE_UNDEFINED} for the utilities,
60
+ * and the parse module's per-output table for a parse helper (EXP-011 §75: `count` is never undefined,
61
+ * `items` is until the text arrives). 🔴 The one function both `maybeUndefinedExpr` (plan.ts) and
62
+ * `maybeUndefined` (component.ts) call, so the two cannot drift.
63
+ */
64
+ export declare function utilCallMayBeUndefined(expr: {
65
+ fn: UtilHelper;
66
+ args: ReadonlyArray<{
67
+ kind: string;
68
+ value?: unknown;
69
+ }>;
70
+ }): boolean;
71
+ /**
72
+ * The module's source.
73
+ *
74
+ * ⚠️ A plain string rather than a template literal, for `dateLib.ts`'s stated reason: the emitted
75
+ * body needs no interpolation, and keeping it out of an interpolation context means a future edit
76
+ * cannot accidentally interpolate the generator's own scope into the exported app.
77
+ */
78
+ export declare function utilLibSource(): string;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The message out of a thrown value, without asking which realm it was thrown in.
3
+ *
4
+ * ## 🔴 Why `instanceof Error` is not the way to do this (register row C41)
5
+ *
6
+ * `error instanceof Error ? error.message : String(error)` is the idiom everywhere, and it is
7
+ * **false for an error that crossed a realm boundary** — a different `vm` context, a jest sandbox,
8
+ * an Electron preload. When it is false the fallback runs, and `String(error)` is not
9
+ * `error.message`: it is `"SyntaxError: Unexpected token 'export'"` where the message alone is
10
+ * `"Unexpected token 'export'"`. So the *same* failure is reported to the *same* user in two
11
+ * different wordings, and which one they get depends on where the error was constructed.
12
+ *
13
+ * This was not a hypothesis. HLS-001 found it as an unexplained disagreement between two test
14
+ * runners over three hashes in the `kits` corpus project, and filed it as C41. HLS-002 hit it
15
+ * again from the other end: the editor's export and `nodegx export` produced byte-identical trees
16
+ * **except** `EXPORT-REPORT.md`, whose kit-loading lines differed by exactly this prefix. A
17
+ * defect that presents as "the two front doors disagree" is worth more than a defect that
18
+ * presents as a wording preference, which is why AC1 is written as a byte comparison.
19
+ *
20
+ * ⚠️ It is also load-bearing beyond the wording. `kitSource.ts` **pattern-matches** the string it
21
+ * gets here to decide whether a kit is an ES-module build. Those regexes happen to survive the
22
+ * prefix; the next one written might not, and it would fail by silently classifying a kit as
23
+ * something else rather than by throwing.
24
+ *
25
+ * The duck test below is realm-safe because it asks the value what it has rather than which
26
+ * constructor made it — which is the only question that has the same answer in every realm.
27
+ */
28
+ export declare function errorMessage(error: unknown): string;