@pipelex/mthds-form 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -7
- package/dist/chunk-25I6JDIK.js +28 -0
- package/dist/chunk-25I6JDIK.js.map +1 -0
- package/dist/chunk-5Q2W6HBA.js +201 -0
- package/dist/chunk-5Q2W6HBA.js.map +1 -0
- package/dist/chunk-GCXV76WU.js +213 -0
- package/dist/chunk-GCXV76WU.js.map +1 -0
- package/dist/chunk-GKV77RAS.js +46 -0
- package/dist/chunk-GKV77RAS.js.map +1 -0
- package/dist/chunk-IIJRJGZQ.js +128 -0
- package/dist/chunk-IIJRJGZQ.js.map +1 -0
- package/dist/chunk-IM2AHWBR.js +99 -0
- package/dist/chunk-IM2AHWBR.js.map +1 -0
- package/dist/chunk-LBFZXYCY.js +44 -0
- package/dist/chunk-LBFZXYCY.js.map +1 -0
- package/dist/chunk-OD3VYXUY.js +156 -0
- package/dist/chunk-OD3VYXUY.js.map +1 -0
- package/dist/chunk-PM55AHRO.js +52 -0
- package/dist/chunk-PM55AHRO.js.map +1 -0
- package/dist/chunk-RPA7DNSK.js +41 -0
- package/dist/chunk-RPA7DNSK.js.map +1 -0
- package/dist/chunk-V3OV2XQT.js +12 -0
- package/dist/chunk-V3OV2XQT.js.map +1 -0
- package/dist/chunk-VTPUDBSJ.js +61 -0
- package/dist/chunk-VTPUDBSJ.js.map +1 -0
- package/dist/chunk-XYQ7NXQZ.js +31 -0
- package/dist/chunk-XYQ7NXQZ.js.map +1 -0
- package/dist/chunk-YEVVR6FE.js +66 -0
- package/dist/chunk-YEVVR6FE.js.map +1 -0
- package/dist/core/contracts.d.ts +114 -0
- package/dist/core/contracts.js +4 -0
- package/dist/core/contracts.js.map +1 -0
- package/dist/core/date-format.d.ts +87 -0
- package/dist/core/date-format.js +3 -0
- package/dist/core/date-format.js.map +1 -0
- package/dist/core/derive.d.ts +55 -0
- package/dist/core/derive.js +6 -0
- package/dist/core/derive.js.map +1 -0
- package/dist/core/descriptor.d.ts +172 -0
- package/dist/core/descriptor.js +3 -0
- package/dist/core/descriptor.js.map +1 -0
- package/dist/core/gate-validator.d.ts +27 -0
- package/dist/core/gate-validator.js +4 -0
- package/dist/core/gate-validator.js.map +1 -0
- package/dist/core/gate.d.ts +144 -0
- package/dist/core/gate.js +12 -0
- package/dist/core/gate.js.map +1 -0
- package/dist/core/gating-fields.d.ts +38 -0
- package/dist/core/gating-fields.js +6 -0
- package/dist/core/gating-fields.js.map +1 -0
- package/dist/core/index.d.ts +13 -623
- package/dist/core/index.js +14 -1
- package/dist/core/normalize-schema.d.ts +30 -0
- package/dist/core/normalize-schema.js +4 -0
- package/dist/core/normalize-schema.js.map +1 -0
- package/dist/core/own-property.d.ts +46 -0
- package/dist/core/own-property.js +3 -0
- package/dist/core/own-property.js.map +1 -0
- package/dist/core/readiness.d.ts +91 -0
- package/dist/core/readiness.js +4 -0
- package/dist/core/readiness.js.map +1 -0
- package/dist/core/schema-utils.d.ts +86 -0
- package/dist/core/schema-utils.js +3 -0
- package/dist/core/schema-utils.js.map +1 -0
- package/dist/core/validation-message.d.ts +39 -0
- package/dist/core/validation-message.js +4 -0
- package/dist/core/validation-message.js.map +1 -0
- package/dist/core/values.d.ts +98 -0
- package/dist/core/values.js +10 -0
- package/dist/core/values.js.map +1 -0
- package/dist/core/wire-format.d.ts +95 -0
- package/dist/core/wire-format.js +6 -0
- package/dist/core/wire-format.js.map +1 -0
- package/dist/react/index.d.ts +43 -2
- package/dist/react/index.js +166 -64
- package/dist/react/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +7 -1
- package/dist/chunk-S6KOTTGD.js +0 -990
- package/dist/chunk-S6KOTTGD.js.map +0 -1
- package/dist/descriptor-DPrrfAjL.d.ts +0 -101
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @pipelex/mthds-form
|
|
2
2
|
|
|
3
|
-
The input form for MTHDS methods, as a library: a headless kernel that
|
|
3
|
+
The input form for MTHDS methods, as a library: a headless kernel that maps the method's wire-stated input form and contracts onto a renderable descriptor and gates what may be run, plus a themeable React control set that renders that descriptor.
|
|
4
4
|
|
|
5
5
|
It exists because "the form" is one problem that keeps being solved separately. A method declares its inputs; something has to decide what widget each input deserves, whether the Run button may light up, what shape the values take on the wire, and what a validation failure says to a person. That logic belongs in one place with tests around it, not copied into each surface that happens to need a form.
|
|
6
6
|
|
|
@@ -15,15 +15,24 @@ import { FieldRenderer } from '@pipelex/mthds-form/react'; // the controls
|
|
|
15
15
|
|
|
16
16
|
`./react` is the control set — one control per field kind behind a single dispatch point, styled with Tailwind classes over standard shadcn/ui tokens. `react` and `react-dom` are optional peer dependencies, so a consumer that only wants the kernel never installs them.
|
|
17
17
|
|
|
18
|
+
`mthds` is a peer dependency too, and a required one, but it is **types only**: the wire types of `pipe_io_contracts` belong to the MTHDS standard, so this package re-exports the standard's declarations instead of restating them. Every import of it is an `import type` and is erased at build, so it costs an install entry and no shipped bytes. See [docs/dependency-budget.md](docs/dependency-budget.md).
|
|
19
|
+
|
|
18
20
|
## The shape of a form
|
|
19
21
|
|
|
20
22
|
```tsx
|
|
21
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
buildRunFields,
|
|
25
|
+
computeReadiness,
|
|
26
|
+
getPipeInputForm,
|
|
27
|
+
getPipeIOContract,
|
|
28
|
+
} from '@pipelex/mthds-form';
|
|
22
29
|
import { FieldRenderer } from '@pipelex/mthds-form/react';
|
|
23
30
|
|
|
24
|
-
const contract = getPipeIOContract(method.pipe_io_contracts,
|
|
25
|
-
const
|
|
26
|
-
const
|
|
31
|
+
const contract = getPipeIOContract(method.pipe_io_contracts, method.domain, pipeCode);
|
|
32
|
+
const descriptor = getPipeInputForm(method.input_form, method.domain, pipeCode);
|
|
33
|
+
const fields = buildRunFields(descriptor, contract.inputs);
|
|
34
|
+
const { missing } = computeReadiness(fields, values);
|
|
35
|
+
const canRun = missing.length === 0;
|
|
27
36
|
|
|
28
37
|
return fields.map((field) => (
|
|
29
38
|
<FieldRenderer
|
|
@@ -36,7 +45,11 @@ return fields.map((field) => (
|
|
|
36
45
|
));
|
|
37
46
|
```
|
|
38
47
|
|
|
39
|
-
`
|
|
48
|
+
`pipe_io_contracts` is always on a valid validate report; `input_form` is its sibling presentation view, opted into with `views: ["input_form"]` on the validate request. Both lookups take their arguments in wire order — **the map, domain, pipe code** — and the last two are strings, so swapping them typechecks. They resolve anyway against a map keyed by bare pipe code, and fail only against one keyed by namespaced `pipe_ref`, a long way from the call.
|
|
49
|
+
|
|
50
|
+
`computeReadiness` reports `{ total, ready, missing }` — `missing` names the inputs still to fill, so it is both the Run gate and what a form tells the user is left.
|
|
51
|
+
|
|
52
|
+
The wire descriptor states what each field IS; `buildRunFields` maps it structurally, consulting the contract's `json_schema` only for two facts the wire omits (the scalar wrapper key and nested list bounds). Everything downstream — rendering, readiness, validation messaging — reads the `RunField` descriptor it returns. That is the load-bearing rule of the package, and [docs/architecture.md](docs/architecture.md) explains what it buys.
|
|
40
53
|
|
|
41
54
|
Submitting goes through the gate: `buildRunInputsSchema` → `prepareRunInputs` → `validateRunInputs` → `apiInputsFromSchemaData`. The verdict is structured (`RunInputError[]`), and `describeValidationError` renders it for a person.
|
|
42
55
|
|
|
@@ -51,7 +64,8 @@ The controls carry Tailwind classes over the standard shadcn/ui semantic tokens
|
|
|
51
64
|
| [docs/architecture.md](docs/architecture.md) | the descriptor currency, the one-function seam, the module map |
|
|
52
65
|
| [docs/dependency-budget.md](docs/dependency-budget.md) | what each layer may depend on, and how that is enforced |
|
|
53
66
|
| [docs/theming.md](docs/theming.md) | the token contract and host setup |
|
|
54
|
-
| [docs/
|
|
67
|
+
| [docs/wire-correspondence.md](docs/wire-correspondence.md) | the name-for-name wire ↔ `RunField` mapping |
|
|
68
|
+
| [docs/derivation-swap.md](docs/derivation-swap.md) | the record of the swap to the wire descriptor — what changed, what survived |
|
|
55
69
|
|
|
56
70
|
## Development
|
|
57
71
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// src/core/descriptor.ts
|
|
2
|
+
function conceptCategory(field) {
|
|
3
|
+
switch (field.kind) {
|
|
4
|
+
case "text":
|
|
5
|
+
case "prose":
|
|
6
|
+
return "text";
|
|
7
|
+
case "date":
|
|
8
|
+
return "date";
|
|
9
|
+
case "document":
|
|
10
|
+
return "document";
|
|
11
|
+
case "image":
|
|
12
|
+
return "image";
|
|
13
|
+
case "number":
|
|
14
|
+
return "number";
|
|
15
|
+
case "boolean":
|
|
16
|
+
return "boolean";
|
|
17
|
+
case "enum":
|
|
18
|
+
return "choice";
|
|
19
|
+
case "list":
|
|
20
|
+
return "list";
|
|
21
|
+
default:
|
|
22
|
+
return "structured";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { conceptCategory };
|
|
27
|
+
//# sourceMappingURL=chunk-25I6JDIK.js.map
|
|
28
|
+
//# sourceMappingURL=chunk-25I6JDIK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/descriptor.ts"],"names":[],"mappings":";AA6MO,SAAS,gBAAgB,KAAA,EAAkC;AAChE,EAAA,QAAQ,MAAM,IAAA;AAAM,IAClB,KAAK,MAAA;AAAA,IACL,KAAK,OAAA;AACH,MAAA,OAAO,MAAA;AAAA,IACT,KAAK,MAAA;AACH,MAAA,OAAO,MAAA;AAAA,IACT,KAAK,UAAA;AACH,MAAA,OAAO,UAAA;AAAA,IACT,KAAK,OAAA;AACH,MAAA,OAAO,OAAA;AAAA,IACT,KAAK,QAAA;AACH,MAAA,OAAO,QAAA;AAAA,IACT,KAAK,SAAA;AACH,MAAA,OAAO,SAAA;AAAA,IACT,KAAK,MAAA;AACH,MAAA,OAAO,QAAA;AAAA,IACT,KAAK,MAAA;AACH,MAAA,OAAO,MAAA;AAAA,IACT;AACE,MAAA,OAAO,YAAA;AAAA;AAEb","file":"chunk-25I6JDIK.js","sourcesContent":["/**\n * The `RunField` descriptor - the consumer-facing currency of the form kernel.\n *\n * A method's inputs arrive from the API as two sibling artifacts: the wire\n * input-form descriptor (`input_form`, the ordered presentation view the MTHDS\n * standard specifies) and the `pipe_io_contracts` entry whose `json_schema`\n * stays the validation contract. `buildRunFields` (in `derive.ts`) maps the\n * wire descriptor structurally onto this `RunField[]` shape - so the\n * presentational field components never touch either wire artifact directly,\n * and stories can describe any input shape declaratively.\n *\n * Pure module: no React, no API calls. Trivially unit-testable.\n */\n\nimport type { InputPresence } from './contracts';\n\nexport type RunFieldKind =\n | 'text' // short single-line string\n | 'prose' // long free-text (textarea)\n | 'date' // a calendar date (schema `format: date` or `date-time`)\n | 'number' // integer or float\n | 'boolean' // true/false\n | 'enum' // pick one of a fixed set\n | 'document' // a file (PDF, docx…) by upload or URL\n | 'image' // a file rendered with a preview\n | 'object' // a structured concept with nested fields\n | 'list' // an array of one element type\n | 'unknown'; // anything we can't map → raw JSON escape hatch\n\nexport interface RunFieldCommon {\n /** The variable identifier as written in the method (rendered in mono). */\n name: string;\n /** Human label; falls back to `name` when absent. */\n title?: string;\n /** The concept this input carries, e.g. `native.Document`, `demo.Invoice`. */\n conceptRef?: string;\n /**\n * The concept's refinement chain, immediate parent first, walked to its end\n * (`['legal.BaseClause', 'native.Text']`). Straight off the wire descriptor;\n * absent when the concept refines nothing. \"Does this refine `native.X`?\" is\n * a membership test on this list, never shape sniffing.\n */\n refines?: string[];\n /** One-line helper text shown under the label. */\n description?: string;\n /** Required inputs always show; optional ones can collapse. */\n required: boolean;\n /**\n * The authored presence marker of the pipe's input slot, verbatim - set on\n * TOP-LEVEL fields only, like `gating`. `required` is its two-valued\n * projection (`presence !== 'optional'`); the marker itself is carried so a\n * renderer can distinguish the authored `!` assertion from a plain slot.\n */\n presence?: InputPresence;\n /**\n * The value applied when the caller omits the field - present only when a\n * default was AUTHORED, never the `null` a schema projection attaches to an\n * optional field. A defaulted field always arrives `required: false`.\n */\n defaultValue?: unknown;\n /** Example values for the field, when the wire carries any. */\n examples?: unknown[];\n /**\n * The node's effective intent hints - the flat `string → string` merge the\n * language defines, carried verbatim. Non-normative: a renderer that ignores\n * them stays correct, and nothing in the kernel's gating reads them.\n */\n hints?: Record<string, string>;\n /**\n * Whether Run waits for this input - set on TOP-LEVEL fields only, straight\n * from `inputMustBeFilled` (see `mustBeFilled` in `readiness.ts` for why this\n * is not the same question as `required`). Nested fields leave it undefined;\n * they are gated through their parent's `fieldFilled`.\n */\n gating?: boolean;\n /**\n * The single property this field's value sits inside on the wire, when its\n * concept declares a scalar content model: `native.Text` is `TextContent\n * {text}`, `native.Number` is `NumberContent {number}`, `native.YesNo` is\n * `YesNoContent {yes_no}`. The control still holds the plain scalar; the\n * value bridge wraps into this property on the way out and unwraps on the way\n * back in.\n *\n * A property NAME, never a schema - the descriptor stays the only currency\n * and `buildRunFields` stays the only reader of JSON Schema. Absent whenever\n * the value is already the whole content (a structured concept, a file, a\n * child property of a structure): wrapping those would double-nest them.\n */\n contentKey?: string;\n}\n\n/**\n * The constraint slots the two text kinds share, mapped from the wire's\n * `min_length` / `max_length` / `pattern` / `format`. `format` is the open\n * string set carrying schema formats the `date` kind does not absorb\n * (`'time'`, `'uri'`, …); a renderer may hint on it and ignore it safely.\n */\nexport interface TextConstraints {\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n format?: string;\n}\n\nexport interface TextRunField extends RunFieldCommon, TextConstraints {\n kind: 'text';\n placeholder?: string;\n}\n\nexport interface ProseRunField extends RunFieldCommon, TextConstraints {\n kind: 'prose';\n placeholder?: string;\n}\n\nexport interface DateRunField extends RunFieldCommon {\n kind: 'date';\n /**\n * The wire's `datetime` flag - true when the value carries a time of day\n * (the backing schema is `format: date-time`): the stored value is a full\n * RFC 3339 timestamp (`2026-07-06T00:00:00Z`) so it passes the API's\n * `date-time` validation, even though the control only asks for a day. False\n * for a bare calendar date, where the value stays `YYYY-MM-DD`.\n */\n datetime: boolean;\n}\n\nexport interface NumberRunField extends RunFieldCommon {\n kind: 'number';\n integer: boolean;\n min?: number;\n max?: number;\n}\n\nexport interface BooleanRunField extends RunFieldCommon {\n kind: 'boolean';\n}\n\nexport interface EnumRunField extends RunFieldCommon {\n kind: 'enum';\n options: string[];\n}\n\nexport interface FileRunField extends RunFieldCommon {\n kind: 'document' | 'image';\n /** Accept hint shown to the user, e.g. \"PDF, PNG, JPG\". */\n accept?: string;\n}\n\nexport interface ObjectRunField extends RunFieldCommon {\n kind: 'object';\n fields: RunField[];\n}\n\nexport interface ListRunField extends RunFieldCommon {\n kind: 'list';\n /** The element descriptor (its `name` is unused; the index labels items). */\n item: RunField;\n /**\n * The FEWEST items the slot accepts. Absent for a variable `Concept[]` list,\n * which demands none.\n *\n * On a top-level slot this is the wire descriptor's `item_count` (present\n * exactly on a fixed `[N]` slot); an engine emits `minItems`/`maxItems` = N\n * on the same slot's schema, so the number `fieldFilled` gates on and the\n * keyword ajv reads agree by construction.\n *\n * The wire never puts `item_count` on a NESTED list, but the model behind a\n * structured concept may state `minItems` on an array property of its own -\n * so on nested nodes this is read off the schema, which is the direction\n * that cannot leave readiness more permissive than the gate.\n */\n itemCount?: number;\n /**\n * The MOST items the slot accepts, off the schema's `maxItems` (which a\n * fixed `[N]` slot also states as N).\n *\n * A separate field because it is a separate fact, and conflating them is a\n * bug that hides: `itemCount` was read as a minimum by readiness and as a\n * maximum by the control that stops offering `Add`, which agree only while\n * a contract states both bounds equal. A list told \"at least two\" was then\n * presented as a list of exactly two.\n */\n maxItemCount?: number;\n}\n\nexport interface UnknownRunField extends RunFieldCommon {\n kind: 'unknown';\n}\n\nexport type RunField =\n | TextRunField\n | ProseRunField\n | DateRunField\n | NumberRunField\n | BooleanRunField\n | EnumRunField\n | FileRunField\n | ObjectRunField\n | ListRunField\n | UnknownRunField;\n\n/** The short, friendly category label for a concept_ref (drives the pill dot). */\nexport type ConceptCategory =\n 'text' | 'date' | 'document' | 'image' | 'number' | 'boolean' | 'choice' | 'structured' | 'list';\n\nexport function conceptCategory(field: RunField): ConceptCategory {\n switch (field.kind) {\n case 'text':\n case 'prose':\n return 'text';\n case 'date':\n return 'date';\n case 'document':\n return 'document';\n case 'image':\n return 'image';\n case 'number':\n return 'number';\n case 'boolean':\n return 'boolean';\n case 'enum':\n return 'choice';\n case 'list':\n return 'list';\n default:\n return 'structured';\n }\n}\n"]}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { buildRunFields } from './chunk-IIJRJGZQ.js';
|
|
2
|
+
import { inflateAllInputs, deflateAllInputs } from './chunk-GCXV76WU.js';
|
|
3
|
+
import { isFilled } from './chunk-PM55AHRO.js';
|
|
4
|
+
import { isOptionalInput, isPluralInput } from './chunk-XYQ7NXQZ.js';
|
|
5
|
+
import { ownProp } from './chunk-V3OV2XQT.js';
|
|
6
|
+
|
|
7
|
+
// src/core/values.ts
|
|
8
|
+
function wrapContent(field, value) {
|
|
9
|
+
return field.contentKey === void 0 ? value : { [field.contentKey]: value };
|
|
10
|
+
}
|
|
11
|
+
function unwrapContent(field, value) {
|
|
12
|
+
const key = field.contentKey;
|
|
13
|
+
if (key === void 0 || !value || typeof value !== "object" || Array.isArray(value))
|
|
14
|
+
return value;
|
|
15
|
+
return ownProp(value, key);
|
|
16
|
+
}
|
|
17
|
+
var MAX_UNWRAP_DEPTH = 8;
|
|
18
|
+
function textFromStored(value, depth = 0) {
|
|
19
|
+
if (value == null) return void 0;
|
|
20
|
+
if (typeof value === "string") return value;
|
|
21
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
22
|
+
if (typeof value !== "object" || depth >= MAX_UNWRAP_DEPTH) return void 0;
|
|
23
|
+
const envelope = value;
|
|
24
|
+
if ("text" in envelope) return textFromStored(envelope.text, depth + 1);
|
|
25
|
+
if ("content" in envelope) return textFromStored(envelope.content, depth + 1);
|
|
26
|
+
return void 0;
|
|
27
|
+
}
|
|
28
|
+
function fromRjsf(field, value) {
|
|
29
|
+
switch (field.kind) {
|
|
30
|
+
case "text":
|
|
31
|
+
case "prose":
|
|
32
|
+
return textFromStored(unwrapContent(field, value));
|
|
33
|
+
case "number": {
|
|
34
|
+
const raw = unwrapContent(field, value);
|
|
35
|
+
if (typeof raw === "number") return Number.isFinite(raw) ? raw : void 0;
|
|
36
|
+
if (typeof raw === "string" && raw.trim() !== "") {
|
|
37
|
+
const parsed = Number(raw);
|
|
38
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
39
|
+
}
|
|
40
|
+
return void 0;
|
|
41
|
+
}
|
|
42
|
+
case "boolean": {
|
|
43
|
+
const raw = unwrapContent(field, value);
|
|
44
|
+
return typeof raw === "boolean" ? raw : void 0;
|
|
45
|
+
}
|
|
46
|
+
case "unknown":
|
|
47
|
+
if (typeof value === "string") return value;
|
|
48
|
+
if (value == null) return void 0;
|
|
49
|
+
if (typeof value === "object") {
|
|
50
|
+
try {
|
|
51
|
+
return JSON.stringify(value, null, 2);
|
|
52
|
+
} catch {
|
|
53
|
+
return void 0;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return String(value);
|
|
57
|
+
case "document":
|
|
58
|
+
case "image": {
|
|
59
|
+
if (value && typeof value === "object") {
|
|
60
|
+
const o = value;
|
|
61
|
+
return o.url ? { url: String(o.url), filename: o.filename } : void 0;
|
|
62
|
+
}
|
|
63
|
+
return typeof value === "string" && value ? { url: value } : void 0;
|
|
64
|
+
}
|
|
65
|
+
case "object": {
|
|
66
|
+
const obj = value && typeof value === "object" ? value : {};
|
|
67
|
+
const out = {};
|
|
68
|
+
for (const child of field.fields) out[child.name] = fromRjsf(child, ownProp(obj, child.name));
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
71
|
+
case "list": {
|
|
72
|
+
const arr = Array.isArray(value) ? value : [];
|
|
73
|
+
return arr.map((item) => fromRjsf(field.item, item));
|
|
74
|
+
}
|
|
75
|
+
default:
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function toRjsf(field, value, collapseEmpty = true) {
|
|
80
|
+
switch (field.kind) {
|
|
81
|
+
case "text":
|
|
82
|
+
case "prose":
|
|
83
|
+
return wrapContent(field, typeof value === "string" ? value : "");
|
|
84
|
+
case "number":
|
|
85
|
+
return typeof value === "number" && Number.isFinite(value) ? wrapContent(field, value) : void 0;
|
|
86
|
+
case "boolean":
|
|
87
|
+
return typeof value === "boolean" ? wrapContent(field, value) : void 0;
|
|
88
|
+
case "unknown":
|
|
89
|
+
return typeof value === "string" ? value : "";
|
|
90
|
+
case "document":
|
|
91
|
+
case "image": {
|
|
92
|
+
const url = value && typeof value === "object" ? value.url : value;
|
|
93
|
+
const filename = value && typeof value === "object" ? value.filename : void 0;
|
|
94
|
+
return { url: url ? String(url) : "", ...filename ? { filename } : {} };
|
|
95
|
+
}
|
|
96
|
+
case "object": {
|
|
97
|
+
const obj = value && typeof value === "object" ? value : {};
|
|
98
|
+
const out = {};
|
|
99
|
+
for (const child of field.fields) out[child.name] = toRjsf(child, ownProp(obj, child.name));
|
|
100
|
+
return collapseEmpty && !isFilled(out) ? void 0 : out;
|
|
101
|
+
}
|
|
102
|
+
case "list": {
|
|
103
|
+
const arr = Array.isArray(value) ? value : [];
|
|
104
|
+
return arr.map((item) => toRjsf(field.item, item, false));
|
|
105
|
+
}
|
|
106
|
+
default:
|
|
107
|
+
return value;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function runValuesFromStore(inputData, fields, inputSchemas) {
|
|
111
|
+
const full = inflateAllInputs(inputData ?? {}, inputSchemas);
|
|
112
|
+
const out = {};
|
|
113
|
+
for (const field of fields) out[field.name] = fromRjsf(field, ownProp(full, field.name));
|
|
114
|
+
return out;
|
|
115
|
+
}
|
|
116
|
+
function rjsfDataFromRunValues(values, fields) {
|
|
117
|
+
const full = {};
|
|
118
|
+
for (const field of fields) full[field.name] = toRjsf(field, ownProp(values, field.name));
|
|
119
|
+
return full;
|
|
120
|
+
}
|
|
121
|
+
function storeInputDataFromRunValues(values, fields, inputSchemas) {
|
|
122
|
+
return deflateAllInputs(rjsfDataFromRunValues(values, fields), inputSchemas);
|
|
123
|
+
}
|
|
124
|
+
function apiInputsFromRunValues(values, fields, inputSchemas) {
|
|
125
|
+
const out = {};
|
|
126
|
+
for (const field of fields) {
|
|
127
|
+
const schema = ownProp(inputSchemas, field.name);
|
|
128
|
+
if (!schema) continue;
|
|
129
|
+
const value = ownProp(values, field.name);
|
|
130
|
+
if (isOptionalInput(schema) && !isFilled(value)) continue;
|
|
131
|
+
if (isPluralInput(schema) && !isFilled(value)) {
|
|
132
|
+
out[field.name] = [];
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
out[field.name] = { concept: schema.concept_ref, content: toRjsf(field, value) };
|
|
136
|
+
}
|
|
137
|
+
return out;
|
|
138
|
+
}
|
|
139
|
+
function hasWorkingMemoryRoot(value) {
|
|
140
|
+
return !!value && typeof value === "object" && "working_memory" in value && !!value.working_memory && typeof value.working_memory.root === "object";
|
|
141
|
+
}
|
|
142
|
+
function entryConceptRef(data) {
|
|
143
|
+
if (!data || typeof data !== "object") return void 0;
|
|
144
|
+
const raw = data.concept;
|
|
145
|
+
if (raw && typeof raw === "object")
|
|
146
|
+
return (raw.concept_code ?? raw.code) || void 0;
|
|
147
|
+
if (typeof raw === "string") return raw;
|
|
148
|
+
return data.concept_code || void 0;
|
|
149
|
+
}
|
|
150
|
+
function outputsFromPipeOutput(pipeOutput, inputKeys) {
|
|
151
|
+
if (!hasWorkingMemoryRoot(pipeOutput)) return null;
|
|
152
|
+
const wm = pipeOutput.working_memory;
|
|
153
|
+
const entries = Object.entries(wm.root).filter(([key]) => !inputKeys.includes(key));
|
|
154
|
+
if (entries.length === 0) return null;
|
|
155
|
+
const toEntry = ([key, data]) => ({
|
|
156
|
+
key,
|
|
157
|
+
conceptRef: entryConceptRef(data),
|
|
158
|
+
value: data?.content ?? data
|
|
159
|
+
});
|
|
160
|
+
const mainKey = wm.aliases?.["main_stuff"];
|
|
161
|
+
const mainEntry = mainKey && Object.prototype.hasOwnProperty.call(wm.root, mainKey) ? [mainKey, wm.root[mainKey]] : entries[entries.length - 1];
|
|
162
|
+
const intermediates = entries.filter(([key]) => key !== mainEntry[0]).map(toEntry);
|
|
163
|
+
return { main: toEntry(mainEntry), intermediates };
|
|
164
|
+
}
|
|
165
|
+
function inputDataFromWorkingMemory(workingMemory, inputSchemas) {
|
|
166
|
+
const root = workingMemory?.root;
|
|
167
|
+
if (!root || typeof root !== "object") return null;
|
|
168
|
+
const full = {};
|
|
169
|
+
let found = false;
|
|
170
|
+
for (const key of Object.keys(inputSchemas)) {
|
|
171
|
+
const entry = ownProp(root, key);
|
|
172
|
+
if (entry && typeof entry === "object" && "content" in entry) {
|
|
173
|
+
full[key] = entry.content;
|
|
174
|
+
found = true;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (!found) return null;
|
|
178
|
+
return deflateAllInputs(full, inputSchemas);
|
|
179
|
+
}
|
|
180
|
+
function fieldsForContract(contract, descriptor) {
|
|
181
|
+
return contract?.inputs && descriptor ? buildRunFields(descriptor, contract.inputs) : [];
|
|
182
|
+
}
|
|
183
|
+
function setValueAtPath(root, path, value) {
|
|
184
|
+
const head = path[0];
|
|
185
|
+
if (head === void 0) return root;
|
|
186
|
+
const rest = path.slice(1);
|
|
187
|
+
if (rest.length === 0) return { ...root, [head]: value };
|
|
188
|
+
const nextSeg = rest[0];
|
|
189
|
+
const child = root[head];
|
|
190
|
+
if (/^\d+$/.test(nextSeg)) {
|
|
191
|
+
const arr = Array.isArray(child) ? child.slice() : [];
|
|
192
|
+
const idx = Number(nextSeg);
|
|
193
|
+
arr[idx] = rest.length === 1 ? value : setValueAtPath(arr[idx] ?? {}, rest.slice(1), value);
|
|
194
|
+
return { ...root, [head]: arr };
|
|
195
|
+
}
|
|
196
|
+
return { ...root, [head]: setValueAtPath(child ?? {}, rest, value) };
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export { apiInputsFromRunValues, fieldsForContract, inputDataFromWorkingMemory, outputsFromPipeOutput, rjsfDataFromRunValues, runValuesFromStore, setValueAtPath, storeInputDataFromRunValues };
|
|
200
|
+
//# sourceMappingURL=chunk-5Q2W6HBA.js.map
|
|
201
|
+
//# sourceMappingURL=chunk-5Q2W6HBA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/values.ts"],"names":[],"mappings":"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","file":"chunk-5Q2W6HBA.js","sourcesContent":["/**\n * Bridges the `MethodRunner`'s field values to the rest of the host.\n *\n * The method-store keeps inputs in the *simplified* format and runs send the\n * *full* RJSF form shape - both already handled by `inflate/deflateAllInputs`.\n * The only gap is that a few field controls use a friendlier value than RJSF: a\n * scalar is the bare scalar where the full shape is the content model its\n * concept declares (`{ text }`, `{ number }`, `{ yes_no }`), and a file is\n * `{ url, filename }`. `fromRjsf`/`toRjsf` translate just those, so store\n * reads/writes and run payloads stay byte-for-byte compatible with the proven\n * playground path.\n *\n * Which property a scalar wraps into is NOT decided here - it arrives on the\n * descriptor as `contentKey`, derived from the contract by `buildRunFields`.\n *\n * Pure module - no React, unit-tested.\n */\nimport type { PipeInputFormDescriptor } from 'mthds/protocol';\n\nimport type { RunField } from './descriptor';\nimport { buildRunFields } from './derive';\nimport { ownProp } from './own-property';\nimport { isFilled } from './readiness';\nimport { isOptionalInput, isPluralInput } from './contracts';\nimport { deflateAllInputs, inflateAllInputs } from './wire-format';\nimport type { PipeIOContract, PipeInputContract } from './contracts';\n\ntype Dict = Record<string, unknown>;\ntype InputSchemas = Record<string, PipeInputContract>;\n\n// ─── RJSF full shape ↔ RunField value ──────────────────────────────────────\n\n/**\n * Put a scalar back inside the content model its concept declares:\n * `\"hi\"` → `{ text: \"hi\" }`, `2` → `{ number: 2 }`, `false` → `{ yes_no: false }`.\n *\n * The property name comes from the DESCRIPTOR (`contentKey`, stamped by\n * `buildRunFields` - the only reader of JSON Schema). This module holds no\n * taxonomy of its own, which is the point: the version that did held a list of\n * concepts that wrap, `native.Number` was missing from it, and every run\n * carrying a number was rejected by the gate against `NumberContent`.\n *\n * A field with no `contentKey` keeps its value plain. That is not an oversight\n * either - a child property of a structured concept, or a custom concept whose\n * schema is a bare string, IS its value, and wrapping it double-nests it\n * (`{ text: { text } }`) into a payload no schema accepts.\n */\nfunction wrapContent(field: RunField, value: unknown): unknown {\n return field.contentKey === undefined ? value : { [field.contentKey]: value };\n}\n\n/**\n * The inverse. A value that is already bare passes through untouched: persisted\n * `inputData` predates the number and yes/no wrappers, and an inputs.json\n * written by hand or by an agent says `2`, not `{number: 2}`.\n */\nfunction unwrapContent(field: RunField, value: unknown): unknown {\n const key = field.contentKey;\n if (key === undefined || !value || typeof value !== 'object' || Array.isArray(value))\n return value;\n return ownProp(value as Record<string, unknown>, key);\n}\n\n/** How deep a nested `{ text: … }` / `{ content: … }` chain we bother unwrapping. */\nconst MAX_UNWRAP_DEPTH = 8;\n\n/**\n * Pull a plain string out of whatever the store hands a text field.\n *\n * Persisted `inputData` carries historical corruptions - a double-wrapped\n * `{ text: { text } }`, a `{ concept, content }` envelope that was never\n * deflated - and the old fallback ran `String()` over them, which renders the\n * literal `\"[object Object]\"` into the textarea. That is worse than showing\n * nothing: it looks exactly like content the user typed, and one keystroke\n * later it is content the user typed. So unwrap the envelopes we know, and give\n * up with `undefined` (an empty field) rather than displaying garbage.\n *\n * Genuine primitives still stringify - a number or a boolean in a text slot is\n * a value, not a wrapper.\n *\n * The envelope names here are the HISTORICAL corruptions, not the wrapper key:\n * the declared wrapper is stripped by `unwrapContent` first, off the field's\n * `contentKey`, exactly as the number and boolean paths do. A text wrapper\n * whose property is not literally `text` would otherwise read back empty - and\n * one save later, BE empty.\n */\nfunction textFromStored(value: unknown, depth = 0): string | undefined {\n if (value == null) return undefined;\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n if (typeof value !== 'object' || depth >= MAX_UNWRAP_DEPTH) return undefined;\n const envelope = value as { text?: unknown; content?: unknown };\n if ('text' in envelope) return textFromStored(envelope.text, depth + 1);\n if ('content' in envelope) return textFromStored(envelope.content, depth + 1);\n return undefined;\n}\n\n/** RJSF full form value → the runner's field value. */\nfunction fromRjsf(field: RunField, value: unknown): unknown {\n switch (field.kind) {\n case 'text':\n case 'prose':\n return textFromStored(unwrapContent(field, value));\n case 'number': {\n // The control holds `number | undefined`. A numeric STRING is tolerated\n // because that is what a hand-written inputs.json tends to carry; anything\n // else empties the field rather than feeding NaN to a number input.\n const raw = unwrapContent(field, value);\n if (typeof raw === 'number') return Number.isFinite(raw) ? raw : undefined;\n if (typeof raw === 'string' && raw.trim() !== '') {\n const parsed = Number(raw);\n return Number.isFinite(parsed) ? parsed : undefined;\n }\n return undefined;\n }\n case 'boolean': {\n // Strictly a real boolean, deliberately: pipelex declares `YesNoContent.\n // yes_no` with `strict=True` precisely to refuse \"yes\"/1/\"true\", and\n // coercing here would smuggle back in what the runtime closed off.\n const raw = unwrapContent(field, value);\n return typeof raw === 'boolean' ? raw : undefined;\n }\n case 'unknown':\n // The escape hatch is a raw-JSON textarea, so a structured value belongs\n // there as JSON - `String(value)` would have shown \"[object Object]\" and\n // thrown the actual value away.\n if (typeof value === 'string') return value;\n if (value == null) return undefined;\n if (typeof value === 'object') {\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return undefined;\n }\n }\n return String(value);\n case 'document':\n case 'image': {\n if (value && typeof value === 'object') {\n const o = value as { url?: unknown; filename?: unknown };\n return o.url\n ? { url: String(o.url), filename: o.filename as string | undefined }\n : undefined;\n }\n return typeof value === 'string' && value ? { url: value } : undefined;\n }\n case 'object': {\n const obj = (value && typeof value === 'object' ? value : {}) as Dict;\n const out: Dict = {};\n for (const child of field.fields) out[child.name] = fromRjsf(child, ownProp(obj, child.name));\n return out;\n }\n case 'list': {\n const arr = Array.isArray(value) ? value : [];\n return arr.map((item) => fromRjsf(field.item, item));\n }\n default:\n return value;\n }\n}\n\n/**\n * The runner's field value → RJSF full form value (what runs/store expect).\n *\n * `collapseEmpty` is what a SINGULAR slot does and a LIST ITEM must not: an\n * untouched structure in a singular slot is absent, but an item exists only\n * because the user added it, so adding IS the touch. Only the structure case\n * reads the flag.\n */\nfunction toRjsf(field: RunField, value: unknown, collapseEmpty = true): unknown {\n switch (field.kind) {\n case 'text':\n case 'prose':\n return wrapContent(field, typeof value === 'string' ? value : '');\n case 'number':\n // An untouched number stays ABSENT rather than becoming an empty wrapper.\n // The gate then does the right thing on both counts: it prunes an absent\n // optional input, and it reports a required one as missing by name -\n // where `{number: undefined}` would read as a malformed value instead.\n return typeof value === 'number' && Number.isFinite(value)\n ? wrapContent(field, value)\n : undefined;\n case 'boolean':\n // `false` is a value, not an absence - hence the type test rather than a\n // truthiness one.\n return typeof value === 'boolean' ? wrapContent(field, value) : undefined;\n case 'unknown':\n return typeof value === 'string' ? value : '';\n case 'document':\n case 'image': {\n const url = value && typeof value === 'object' ? (value as { url?: unknown }).url : value;\n const filename =\n value && typeof value === 'object' ? (value as { filename?: unknown }).filename : undefined;\n return { url: url ? String(url) : '', ...(filename ? { filename } : {}) };\n }\n case 'object': {\n const obj = (value && typeof value === 'object' ? value : {}) as Dict;\n const out: Dict = {};\n for (const child of field.fields) out[child.name] = toRjsf(child, ownProp(obj, child.name));\n // A structure nobody put anything into stays ABSENT, exactly as an\n // untouched number does above - it does NOT become a shell of empty\n // children. Materializing that shell made an OPTIONAL structured input\n // unrunnable whenever its concept declared a required child: readiness\n // ignored the input (correctly - the method said it may be omitted), Run\n // lit up, and the gate then judged an object the kernel had invented\n // against the concept's full schema and rejected the run for a child the\n // user was never asked to fill.\n //\n // Emptiness is `isFilled`, the SAME predicate readiness and the wire\n // payload use, so the three cannot disagree about whether this input is\n // there. Which also says what the touch is NOT: opening the optional\n // disclosure is local view state the value never sees, so a section\n // opened and left blank collapses exactly like one never opened. What\n // keeps a structure is a VALUE in it - and then the whole shell survives,\n // empty children and all, so a required child left blank still fails, and\n // loudly.\n return collapseEmpty && !isFilled(out) ? undefined : out;\n }\n case 'list': {\n const arr = Array.isArray(value) ? value : [];\n // An item is NEVER absent: it is in the array because the user added it,\n // and `ListField`'s \"Add\" seeds an object item with `{}`. Letting it\n // collapse the way an untouched singular slot does put `undefined` in the\n // array, which ajv rejects as `must be object` - blocking an empty item\n // the item schema allowed, and turning a required-child complaint into a\n // type error that names nothing the user can act on.\n return arr.map((item) => toRjsf(field.item, item, false));\n }\n default:\n return value;\n }\n}\n\n// ─── Store ↔ RunField values ──────────────────────────────────────────────\n\n/** Seed the runner's form values from the method-store's simplified inputData. */\nexport function runValuesFromStore(\n inputData: Dict | undefined,\n fields: RunField[],\n inputSchemas: InputSchemas,\n): Dict {\n const full = inflateAllInputs(inputData ?? {}, inputSchemas);\n const out: Dict = {};\n for (const field of fields) out[field.name] = fromRjsf(field, ownProp(full, field.name));\n return out;\n}\n\n/**\n * The runner's form values in **schema shape** - the same shape an RJSF panel\n * holds, and therefore the shape `gate.ts` validates against the per-input\n * JSON Schemas.\n *\n * Deliberately stops short of `deflateAllInputs`: deflation is the STORE's\n * compact form, and ajv validates the full one.\n */\nexport function rjsfDataFromRunValues(values: Dict, fields: RunField[]): Dict {\n const full: Dict = {};\n for (const field of fields) full[field.name] = toRjsf(field, ownProp(values, field.name));\n return full;\n}\n\n/** Convert the runner's form values back to the store's simplified inputData. */\nexport function storeInputDataFromRunValues(\n values: Dict,\n fields: RunField[],\n inputSchemas: InputSchemas,\n): Dict {\n return deflateAllInputs(rjsfDataFromRunValues(values, fields), inputSchemas);\n}\n\n/**\n * Build the `{ concept, content }` map a run expects from the form values.\n *\n * The two ways a method says \"this may be nothing\" land differently on the wire,\n * and both matter:\n * - an **optional (`?`)** input left blank is OMITTED, so the runtime records a\n * real absence the method can branch on - sending `{ text: \"\" }` would look\n * like the caller supplied an empty string;\n * - a **plural (`[]`)** input keeps its key, because a plural slot is never\n * absent - its empty form IS the empty list, and the runtime requires the key.\n * When that list is EMPTY it is sent BARE, without the envelope: the envelope\n * is the runtime's \"explicit form\", which bypasses the top-down shaper and\n * hands the value to the bottom-up factory, and that factory types a list from\n * its first item - so an empty list there raises \"Cannot create Stuff from\n * empty list in content\". The bare form keeps the shaper, which reads the\n * DECLARED concept and builds the empty list correctly. (pipelex/#1096 makes\n * the envelope agree; the bare form runs today and stays correct after.)\n */\nexport function apiInputsFromRunValues(\n values: Dict,\n fields: RunField[],\n inputSchemas: InputSchemas,\n): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const field of fields) {\n const schema = ownProp(inputSchemas, field.name);\n if (!schema) continue;\n const value = ownProp(values, field.name);\n if (isOptionalInput(schema) && !isFilled(value)) continue;\n if (isPluralInput(schema) && !isFilled(value)) {\n out[field.name] = [];\n continue;\n }\n out[field.name] = { concept: schema.concept_ref, content: toRjsf(field, value) };\n }\n return out;\n}\n\n// ─── Pipe output → result entries ────────────────────────────────────────────\n\n/** One named output pulled out of a run's working memory, ready to render. */\nexport interface OutputEntry {\n /** The output variable key (mono). */\n key: string;\n conceptRef?: string;\n value: unknown;\n}\n\n/**\n * The slice of a serialized pipe output this module actually reads. Structural\n * on purpose: the SDK's `DictPipeOutput` is the host's wire type, and the kernel\n * must not depend on `@pipelex/sdk` - the guard below verifies the shape at\n * runtime anyway.\n */\ninterface PipeOutputWithWorkingMemory {\n working_memory: {\n root: Record<string, unknown>;\n aliases?: Record<string, string>;\n };\n}\n\nfunction hasWorkingMemoryRoot(value: unknown): value is PipeOutputWithWorkingMemory {\n return (\n !!value &&\n typeof value === 'object' &&\n 'working_memory' in value &&\n !!(value as { working_memory?: { root?: unknown } }).working_memory &&\n typeof (value as { working_memory: { root?: unknown } }).working_memory.root === 'object'\n );\n}\n\n/** The concept code of a working-memory entry (`{concept}` may be obj/str/absent). */\nfunction entryConceptRef(data: unknown): string | undefined {\n if (!data || typeof data !== 'object') return undefined;\n const raw = (data as { concept?: unknown; concept_code?: unknown }).concept;\n if (raw && typeof raw === 'object')\n return (\n ((raw as { concept_code?: string }).concept_code ?? (raw as { code?: string }).code) ||\n undefined\n );\n if (typeof raw === 'string') return raw;\n return (data as { concept_code?: string }).concept_code || undefined;\n}\n\n/**\n * Split a run's pipe output into the main result and any intermediate outputs,\n * excluding the inputs. The main output's identity comes from the working\n * memory's `main_stuff` alias (the authoritative pointer to the output variable)\n * - so its label is the REAL stuff name, not a positional guess. Falls back to\n * the last produced stuff only when the alias is absent.\n */\nexport function outputsFromPipeOutput(\n pipeOutput: unknown,\n inputKeys: string[],\n): { main: OutputEntry; intermediates: OutputEntry[] } | null {\n if (!hasWorkingMemoryRoot(pipeOutput)) return null;\n const wm = pipeOutput.working_memory as {\n root: Record<string, unknown>;\n aliases?: Record<string, string>;\n };\n const entries = Object.entries(wm.root).filter(([key]) => !inputKeys.includes(key));\n if (entries.length === 0) return null;\n\n const toEntry = ([key, data]: [string, unknown]): OutputEntry => ({\n key,\n conceptRef: entryConceptRef(data),\n value: (data as { content?: unknown })?.content ?? data,\n });\n\n // The real main-output name: `aliases.main_stuff` → its root key.\n const mainKey = wm.aliases?.['main_stuff'];\n const mainEntry: [string, unknown] =\n mainKey && Object.prototype.hasOwnProperty.call(wm.root, mainKey)\n ? [mainKey, wm.root[mainKey]]\n : entries[entries.length - 1]!;\n const intermediates = entries.filter(([key]) => key !== mainEntry[0]).map(toEntry);\n\n return { main: toEntry(mainEntry), intermediates };\n}\n\n/**\n * Recover the inputs a run was executed with from its working memory. The run's\n * `working_memory.root` holds every named stuff - inputs AND outputs - keyed by\n * variable name; we pull the entries whose keys are declared inputs and deflate\n * their `content` (the full form shape) back into the store's simplified\n * `inputData`. Lets the runner repopulate the form for a past/shared run - the\n * inputs that produced the result. Returns `null` when no inputs are present.\n */\nexport function inputDataFromWorkingMemory(\n workingMemory: unknown,\n inputSchemas: InputSchemas,\n): Dict | null {\n const root = (workingMemory as { root?: Record<string, unknown> } | null | undefined)?.root;\n if (!root || typeof root !== 'object') return null;\n const full: Dict = {};\n let found = false;\n for (const key of Object.keys(inputSchemas)) {\n const entry = ownProp(root, key);\n if (entry && typeof entry === 'object' && 'content' in entry) {\n full[key] = (entry as { content: unknown }).content;\n found = true;\n }\n }\n if (!found) return null;\n return deflateAllInputs(full, inputSchemas);\n}\n\n/**\n * Field descriptors for a method's main pipe - the wire descriptor mapped over\n * the contract, or `[]` while either artifact has not arrived yet. The\n * descriptor comes back from `validate` beside `pipe_io_contracts` when the\n * request opts in with `views: [\"input_form\"]`; `getPipeInputForm` is the\n * lookup that matches `getPipeIOContract`.\n */\nexport function fieldsForContract(\n contract: PipeIOContract | undefined,\n descriptor: PipeInputFormDescriptor | undefined,\n): RunField[] {\n return contract?.inputs && descriptor ? buildRunFields(descriptor, contract.inputs) : [];\n}\n\n/**\n * Immutably set a value at a dotted/indexed path (`a.0.b`). Used to write an\n * uploaded file's URL back to a field anywhere in the (possibly nested) tree.\n */\nexport function setValueAtPath(root: Dict, path: string[], value: unknown): Dict {\n const head = path[0];\n if (head === undefined) return root;\n const rest = path.slice(1);\n if (rest.length === 0) return { ...root, [head]: value };\n\n const nextSeg = rest[0] as string;\n const child = root[head];\n if (/^\\d+$/.test(nextSeg)) {\n const arr = Array.isArray(child) ? child.slice() : [];\n const idx = Number(nextSeg);\n arr[idx] =\n rest.length === 1 ? value : setValueAtPath((arr[idx] as Dict) ?? {}, rest.slice(1), value);\n return { ...root, [head]: arr };\n }\n return { ...root, [head]: setValueAtPath((child as Dict) ?? {}, rest, value) };\n}\n"]}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { asCalendarDate } from './chunk-GKV77RAS.js';
|
|
2
|
+
import { collectSchemaDefs, resolveSchemaIndirection, schemaTypeOf } from './chunk-OD3VYXUY.js';
|
|
3
|
+
import { ownProp, hasOwnProp } from './chunk-V3OV2XQT.js';
|
|
4
|
+
|
|
5
|
+
// src/core/wire-format.ts
|
|
6
|
+
function nativeSet(...names) {
|
|
7
|
+
return new Set(names.flatMap((n) => [n, `native.${n}`]));
|
|
8
|
+
}
|
|
9
|
+
var WIRE_TEXT_CONCEPTS = nativeSet("Text");
|
|
10
|
+
var WIRE_DOCUMENT_LIKE_CONCEPTS = nativeSet("Document", "Image", "Page");
|
|
11
|
+
function isTextConcept(concept) {
|
|
12
|
+
return WIRE_TEXT_CONCEPTS.has(concept);
|
|
13
|
+
}
|
|
14
|
+
function isDocumentLikeConcept(concept) {
|
|
15
|
+
return WIRE_DOCUMENT_LIKE_CONCEPTS.has(concept);
|
|
16
|
+
}
|
|
17
|
+
function isListConcept(conceptCode) {
|
|
18
|
+
if (conceptCode.endsWith("[]")) return { isList: true, baseConcept: conceptCode.slice(0, -2) };
|
|
19
|
+
return { isList: false, baseConcept: conceptCode };
|
|
20
|
+
}
|
|
21
|
+
function deflateInput(value, conceptCode) {
|
|
22
|
+
const { isList, baseConcept } = isListConcept(conceptCode);
|
|
23
|
+
if (isList) {
|
|
24
|
+
const items = Array.isArray(value) ? value : [];
|
|
25
|
+
return items.map((item) => deflateListItem(item, baseConcept));
|
|
26
|
+
}
|
|
27
|
+
return deflateSingleValue(value, baseConcept);
|
|
28
|
+
}
|
|
29
|
+
function deflateListItem(value, concept) {
|
|
30
|
+
if (isTextConcept(concept)) {
|
|
31
|
+
if (value && typeof value === "object" && "text" in value) {
|
|
32
|
+
return value.text;
|
|
33
|
+
}
|
|
34
|
+
return typeof value === "string" ? value : String(value ?? "");
|
|
35
|
+
}
|
|
36
|
+
if (isDocumentLikeConcept(concept)) {
|
|
37
|
+
if (value && typeof value === "object" && "url" in value) {
|
|
38
|
+
return value.url;
|
|
39
|
+
}
|
|
40
|
+
if (typeof value === "string") return value;
|
|
41
|
+
return "";
|
|
42
|
+
}
|
|
43
|
+
return { concept, content: unwrapAllWrappers(value) };
|
|
44
|
+
}
|
|
45
|
+
function deflateSingleValue(value, concept) {
|
|
46
|
+
if (isTextConcept(concept)) {
|
|
47
|
+
if (value && typeof value === "object" && "text" in value) {
|
|
48
|
+
return value.text;
|
|
49
|
+
}
|
|
50
|
+
return typeof value === "string" ? value : String(value ?? "");
|
|
51
|
+
}
|
|
52
|
+
if (isDocumentLikeConcept(concept)) {
|
|
53
|
+
if (value && typeof value === "object" && "url" in value) {
|
|
54
|
+
return value.url;
|
|
55
|
+
}
|
|
56
|
+
if (typeof value === "string") return value;
|
|
57
|
+
return "";
|
|
58
|
+
}
|
|
59
|
+
return { concept, content: unwrapAllWrappers(value) };
|
|
60
|
+
}
|
|
61
|
+
function inflateInput(value, conceptCode) {
|
|
62
|
+
const { isList, baseConcept } = isListConcept(conceptCode);
|
|
63
|
+
if (isList) {
|
|
64
|
+
const unwrapped = isWrappedForm(value) ? value.content : value;
|
|
65
|
+
let items;
|
|
66
|
+
if (Array.isArray(unwrapped)) {
|
|
67
|
+
items = unwrapped;
|
|
68
|
+
} else if (unwrapped != null && typeof unwrapped === "object") {
|
|
69
|
+
items = [unwrapped];
|
|
70
|
+
} else {
|
|
71
|
+
items = [];
|
|
72
|
+
}
|
|
73
|
+
return items.map((item) => inflateSingleValue(item, baseConcept));
|
|
74
|
+
}
|
|
75
|
+
return inflateSingleValue(value, baseConcept);
|
|
76
|
+
}
|
|
77
|
+
var DOCUMENT_FIELDS = /* @__PURE__ */ new Set(["url", "public_url", "mime_type", "filename", "title", "snippet"]);
|
|
78
|
+
function looksLikeDocument(obj) {
|
|
79
|
+
return Object.keys(obj).some((k) => DOCUMENT_FIELDS.has(k));
|
|
80
|
+
}
|
|
81
|
+
function isWrappedForm(value) {
|
|
82
|
+
return !!value && typeof value === "object" && "concept" in value && "content" in value && typeof value.concept === "string";
|
|
83
|
+
}
|
|
84
|
+
function inflateSingleValue(value, concept) {
|
|
85
|
+
if (isWrappedForm(value) && (isTextConcept(concept) || isDocumentLikeConcept(concept))) {
|
|
86
|
+
return inflateSingleValue(value.content, concept);
|
|
87
|
+
}
|
|
88
|
+
if (isTextConcept(concept)) {
|
|
89
|
+
if (typeof value === "string") {
|
|
90
|
+
return { text: value };
|
|
91
|
+
}
|
|
92
|
+
if (value && typeof value === "object" && "text" in value) {
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
return { text: "" };
|
|
96
|
+
}
|
|
97
|
+
if (isDocumentLikeConcept(concept)) {
|
|
98
|
+
if (typeof value === "string") {
|
|
99
|
+
return { url: value };
|
|
100
|
+
}
|
|
101
|
+
if (value && typeof value === "object" && "url" in value) {
|
|
102
|
+
return value;
|
|
103
|
+
}
|
|
104
|
+
if (value && typeof value === "object" && looksLikeDocument(value)) {
|
|
105
|
+
return { ...value, url: "" };
|
|
106
|
+
}
|
|
107
|
+
return { url: "" };
|
|
108
|
+
}
|
|
109
|
+
return unwrapAllWrappers(value);
|
|
110
|
+
}
|
|
111
|
+
function unwrapAllWrappers(value) {
|
|
112
|
+
let current = value;
|
|
113
|
+
while (isWrappedForm(current)) {
|
|
114
|
+
current = current.content;
|
|
115
|
+
}
|
|
116
|
+
if (current && typeof current === "object" && !Array.isArray(current) && "content" in current) {
|
|
117
|
+
return current.content;
|
|
118
|
+
}
|
|
119
|
+
return current;
|
|
120
|
+
}
|
|
121
|
+
function resolveConceptCode(schema) {
|
|
122
|
+
const code = schema.concept_ref;
|
|
123
|
+
if (!code) return "";
|
|
124
|
+
if (!code.endsWith("[]") && schema.json_schema?.type === "array") {
|
|
125
|
+
return code + "[]";
|
|
126
|
+
}
|
|
127
|
+
return code;
|
|
128
|
+
}
|
|
129
|
+
function deflateAllInputs(formData, inputSchemas) {
|
|
130
|
+
const result = {};
|
|
131
|
+
for (const [stuffName, schema] of Object.entries(inputSchemas)) {
|
|
132
|
+
result[stuffName] = deflateInput(ownProp(formData, stuffName), resolveConceptCode(schema));
|
|
133
|
+
}
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
function healStringWrappers(value, rawSchema, defs) {
|
|
137
|
+
if (!rawSchema || value == null) return value;
|
|
138
|
+
const allDefs = defs ?? collectSchemaDefs(rawSchema, {}, { traverseArrays: false });
|
|
139
|
+
const schema = resolveSchemaIndirection(rawSchema, allDefs);
|
|
140
|
+
const type = schemaTypeOf(schema);
|
|
141
|
+
if (type === "string" && schema.format === "date" && typeof value === "string") {
|
|
142
|
+
return asCalendarDate(value) ?? value;
|
|
143
|
+
}
|
|
144
|
+
if (type === "string") {
|
|
145
|
+
if (typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 1 && typeof value.text === "string") {
|
|
146
|
+
return value.text;
|
|
147
|
+
}
|
|
148
|
+
return value;
|
|
149
|
+
}
|
|
150
|
+
if (type === "object" && typeof value === "object" && !Array.isArray(value)) {
|
|
151
|
+
const props = schema.properties;
|
|
152
|
+
if (!props) return value;
|
|
153
|
+
const out = { ...value };
|
|
154
|
+
for (const [key, propSchema] of Object.entries(props)) {
|
|
155
|
+
if (hasOwnProp(out, key)) out[key] = healStringWrappers(out[key], propSchema, allDefs);
|
|
156
|
+
}
|
|
157
|
+
return out;
|
|
158
|
+
}
|
|
159
|
+
if (type === "array" && Array.isArray(value)) {
|
|
160
|
+
const items = schema.items;
|
|
161
|
+
return value.map((item) => healStringWrappers(item, items, allDefs));
|
|
162
|
+
}
|
|
163
|
+
return value;
|
|
164
|
+
}
|
|
165
|
+
function isEmptyAfterPruning(value) {
|
|
166
|
+
if (value === "" || value === null || value === void 0) return true;
|
|
167
|
+
return typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 0;
|
|
168
|
+
}
|
|
169
|
+
function pruneEmptyOptionals(value, rawSchema, defs) {
|
|
170
|
+
if (!rawSchema || value == null) return value;
|
|
171
|
+
const allDefs = defs ?? collectSchemaDefs(rawSchema, {}, { traverseArrays: false });
|
|
172
|
+
const schema = resolveSchemaIndirection(rawSchema, allDefs);
|
|
173
|
+
const type = schemaTypeOf(schema);
|
|
174
|
+
if (type === "array" && Array.isArray(value)) {
|
|
175
|
+
const items = schema.items;
|
|
176
|
+
return value.map((item) => pruneEmptyOptionals(item, items, allDefs));
|
|
177
|
+
}
|
|
178
|
+
if (type !== "object" || typeof value !== "object" || Array.isArray(value)) return value;
|
|
179
|
+
const props = schema.properties;
|
|
180
|
+
if (!props) return value;
|
|
181
|
+
const required = new Set(Array.isArray(schema.required) ? schema.required : []);
|
|
182
|
+
const out = {};
|
|
183
|
+
for (const [key, raw] of Object.entries(value)) {
|
|
184
|
+
const propSchema = ownProp(props, key);
|
|
185
|
+
if (!propSchema) {
|
|
186
|
+
out[key] = raw;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
const pruned = pruneEmptyOptionals(raw, propSchema, allDefs);
|
|
190
|
+
if (isEmptyAfterPruning(pruned) && !required.has(key)) continue;
|
|
191
|
+
out[key] = pruned;
|
|
192
|
+
}
|
|
193
|
+
return out;
|
|
194
|
+
}
|
|
195
|
+
function inflateAllInputs(simplifiedData, inputSchemas) {
|
|
196
|
+
const result = {};
|
|
197
|
+
for (const [stuffName, value] of Object.entries(simplifiedData)) {
|
|
198
|
+
const schema = ownProp(inputSchemas, stuffName);
|
|
199
|
+
if (schema) {
|
|
200
|
+
result[stuffName] = healStringWrappers(
|
|
201
|
+
inflateInput(value, resolveConceptCode(schema)),
|
|
202
|
+
schema.json_schema
|
|
203
|
+
);
|
|
204
|
+
} else {
|
|
205
|
+
result[stuffName] = value;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return result;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export { deflateAllInputs, deflateInput, healStringWrappers, inflateAllInputs, inflateInput, pruneEmptyOptionals, resolveConceptCode };
|
|
212
|
+
//# sourceMappingURL=chunk-GCXV76WU.js.map
|
|
213
|
+
//# sourceMappingURL=chunk-GCXV76WU.js.map
|