@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.
- package/README.md +59 -2
- package/dist/analyze/appState.d.ts +296 -0
- package/dist/analyze/plan.d.ts +3757 -0
- package/dist/analyze/querySettings.d.ts +75 -0
- package/dist/analyze/reach.d.ts +41 -0
- package/dist/analyze/scriptUses.d.ts +29 -0
- package/dist/catalog.d.ts +129 -0
- package/dist/cli/args.d.ts +90 -0
- package/dist/cli/exitCodes.d.ts +125 -0
- package/dist/cli/run.d.ts +30 -0
- package/dist/cli.inputs.json +174 -0
- package/dist/cli.mjs +53746 -0
- package/dist/cli.mjs.map +7 -0
- package/dist/emit/animateLib.d.ts +43 -0
- package/dist/emit/component.d.ts +144 -0
- package/dist/emit/dateLib.d.ts +45 -0
- package/dist/emit/emitApp.d.ts +38 -0
- package/dist/emit/idLib.d.ts +68 -0
- package/dist/emit/kits.d.ts +85 -0
- package/dist/emit/mediaLib.d.ts +75 -0
- package/dist/emit/naming.d.ts +76 -0
- package/dist/emit/parseLib.d.ts +106 -0
- package/dist/emit/preflight.d.ts +174 -0
- package/dist/emit/readme.d.ts +51 -0
- package/dist/emit/report.d.ts +309 -0
- package/dist/emit/scaffold.d.ts +67 -0
- package/dist/emit/statesLib.d.ts +52 -0
- package/dist/emit/style.d.ts +165 -0
- package/dist/emit/utilLib.d.ts +78 -0
- package/dist/errorMessage.d.ts +28 -0
- package/dist/index.cjs +52848 -0
- package/dist/index.cjs.map +7 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.mjs +52769 -0
- package/dist/index.mjs.map +7 -0
- package/dist/ir/types.d.ts +567 -0
- package/dist/ledger.cjs +971 -0
- package/dist/ledger.cjs.map +7 -0
- package/dist/ledger.d.ts +75 -0
- package/dist/ledger.mjs +948 -0
- package/dist/ledger.mjs.map +7 -0
- package/dist/node-catalog.json +65333 -0
- package/dist/parse/kitSource.d.ts +135 -0
- package/dist/parse/parseModules.d.ts +42 -0
- package/dist/parse/parseProject.d.ts +13 -0
- package/dist/scriptFiles.d.ts +30 -0
- package/dist/structurePorts.d.ts +70 -0
- package/dist/write/writeExport.d.ts +67 -0
- 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;
|