@stonecrop/schema 0.16.2 → 0.16.4
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/dist/cli.js +1 -1
- package/dist/index.js +9 -8
- package/dist/index.js.map +1 -1
- package/dist/schema.d.ts +1 -3
- package/dist/src/component-meta.d.ts +1 -1
- package/dist/src/component-meta.d.ts.map +1 -1
- package/dist/src/component-meta.js +1 -0
- package/dist/src/field.d.ts +0 -2
- package/dist/src/field.d.ts.map +1 -1
- package/dist/tsdoc-metadata.json +1 -1
- package/dist/{index-rozX0Luh.js → validation-Dyxjvaio.js} +249 -249
- package/dist/validation-Dyxjvaio.js.map +1 -0
- package/package.json +3 -3
- package/dist/index-rozX0Luh.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import { readFileSync as u, existsSync as S, mkdirSync as w, writeFileSync as x
|
|
|
3
3
|
import { resolve as c, join as O } from "node:path";
|
|
4
4
|
import { parseArgs as $ } from "node:util";
|
|
5
5
|
import { getIntrospectionQuery as N } from "graphql";
|
|
6
|
-
import {
|
|
6
|
+
import { c as P, v as j } from "./validation-Dyxjvaio.js";
|
|
7
7
|
async function C(e, m) {
|
|
8
8
|
const t = await fetch(e, {
|
|
9
9
|
method: "POST",
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as d, D as A, F as u, G as p, I as S, T, a as m, b as
|
|
1
|
+
import { A as d, D as A, F as u, G as p, I as S, T, a as m, b as y, V as L, W as C, d as N, e as F, f as b, g as f, h as k, i as O, c as D, j as I, k as x, l as E, n as h, p as _, m as M, o as g, s as v, q as P, t as R, r as w, v as W, u as G } from "./validation-Dyxjvaio.js";
|
|
2
2
|
const a = {
|
|
3
3
|
ATextInput: "text",
|
|
4
4
|
ATextboxInput: "text",
|
|
@@ -14,7 +14,8 @@ const a = {
|
|
|
14
14
|
ACodeEditor: "code",
|
|
15
15
|
AFormLink: "link",
|
|
16
16
|
AFileAttach: "attach",
|
|
17
|
-
AQuantityInput: "quantity"
|
|
17
|
+
AQuantityInput: "quantity",
|
|
18
|
+
ACurrencyInput: "currency"
|
|
18
19
|
};
|
|
19
20
|
function o(e) {
|
|
20
21
|
return e ? a[e] : void 0;
|
|
@@ -44,10 +45,10 @@ export {
|
|
|
44
45
|
S as INTERNAL_SCALARS,
|
|
45
46
|
T as TableFieldSchema,
|
|
46
47
|
m as TableViewConfig,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
y as TriggerDefinition,
|
|
49
|
+
L as ValueFieldSchema,
|
|
50
|
+
C as WELL_KNOWN_SCALARS,
|
|
51
|
+
N as WorkflowLayout,
|
|
51
52
|
F as WorkflowMeta,
|
|
52
53
|
b as buildScalarMap,
|
|
53
54
|
f as camelToLabel,
|
|
@@ -56,8 +57,8 @@ export {
|
|
|
56
57
|
o as componentCategory,
|
|
57
58
|
i as componentLinkExpansion,
|
|
58
59
|
D as convertGraphQLSchema,
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
I as defaultIsEntityField,
|
|
61
|
+
x as defaultIsEntityType,
|
|
61
62
|
E as isActionAllowedInState,
|
|
62
63
|
h as normalizeFieldKind,
|
|
63
64
|
_ as parseDoctype,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/component-meta.ts"],"sourcesContent":["/**\n * Semantic category for a rendering component.\n *\n * `component` is the primary field axis, so the runtime consumers that need to know what a field\n * *means* (atable cell formatting / filter widgets, record-default init) derive it from here. This\n * is the single source of \"what kind of value does this component render\", keyed by the canonical\n * registered component names — each consumer maps the category to its own concern (filter widget,\n * default value, …).\n *\n * @public\n */\nexport type ComponentCategory =\n\t'text' | 'number' | 'boolean' | 'date' | 'datetime' | 'select' | 'code' | 'link' | 'attach' | 'quantity'\n\n/**\n * Canonical component → semantic category. Only the components Stonecrop ships with appear here;\n * custom/unknown component names have no category and consumers fall back to their default.\n * @public\n */\nexport const COMPONENT_CATEGORY: Record<string, ComponentCategory> = {\n\tATextInput: 'text',\n\tATextboxInput: 'text',\n\tANumericInput: 'number',\n\tACheckbox: 'boolean',\n\tADate: 'date',\n\tADatePicker: 'date',\n\tADateSelection: 'date',\n\tADateTime: 'datetime',\n\tADuration: 'text',\n\tADateRange: 'date',\n\tADropdown: 'select',\n\tACodeEditor: 'code',\n\tAFormLink: 'link',\n\tAFileAttach: 'attach',\n\tAQuantityInput: 'quantity',\n}\n\n/**\n * Resolve a component's semantic category, or `undefined` for an unknown (custom) component —\n * callers treat that as \"no opinion\" and use their own default.\n * @public\n */\nexport function componentCategory(component?: string): ComponentCategory | undefined {\n\treturn component ? COMPONENT_CATEGORY[component] : undefined\n}\n\n/**\n * Whether a link component expands its target doctype, or renders the link inline.\n *\n * This is the *only* axis the component decides. It deliberately does not choose between an\n * embedded record and an embedded table: `cardinality` states whether the value is a scalar or\n * an array, which is a fact about the data rather than a rendering preference, so a component\n * must not be able to override it (an `AForm` over a `noneOrMany` link would be handed an array\n * it cannot render). Component names encode both axes — `AFormLink`/`ATableLink` are the inline\n * pair, `AForm`/`ATable` the expanding pair — but only the inline/expand half is authoritative.\n *\n * @public\n */\nexport type LinkExpansion = 'inline' | 'expand'\n\n/**\n * Canonical link component → expansion. Only components Stonecrop ships with appear here; an\n * unmapped (custom) component has none, and callers treat that as `expand` — the behaviour that\n * predates this map, so a custom component can never silently collapse a link to a picker.\n * @public\n */\nexport const COMPONENT_LINK_EXPANSION: Record<string, LinkExpansion> = {\n\tAFormLink: 'inline',\n\tAForm: 'expand',\n\tATable: 'expand',\n}\n\n/**\n * Resolve a component's link expansion, or `undefined` for an absent/unmapped component.\n * @public\n */\nexport function componentLinkExpansion(component?: string): LinkExpansion | undefined {\n\treturn component ? COMPONENT_LINK_EXPANSION[component] : undefined\n}\n\n/**\n * How a link field renders.\n *\n * - `inline` — a scalar id-picker; the target is *not* expanded (the field keeps its own value\n * and carries a `doctype` prop for async display-text resolution and navigation).\n * - `record` — the target doctype is resolved and embedded as a nested form.\n * - `table` — the target doctype is resolved and embedded as a child table.\n *\n * @public\n */\nexport type LinkRenderMode = 'inline' | 'record' | 'table'\n\n/**\n * Decide how a *declared* link (one with a `LinkDeclaration`) renders.\n *\n * Two independent axes: the **component** picks inline vs expand, and when expanding the\n * **cardinality** picks record vs table (many → table). The declaration's component wins over the\n * field's, matching the precedence the resolver already uses for the rendered component.\n *\n * This is the single definition of \"does this link expand\" — it is consumed by both the client\n * resolver (which builds the nested schema) and the server column builder (which must still\n * SELECT an `inline` link's FK column). Call it; never re-derive the rule at the call site, or\n * the two will drift and the client will render a table for a column the server never selected.\n *\n * @param link - the link declaration (only `component` and `cardinality` are consulted)\n * @param fieldComponent - the linked field's own `component`, used when the declaration names none\n * @public\n */\nexport function resolveLinkRenderMode(\n\tlink: { component?: string; cardinality?: string },\n\tfieldComponent?: string\n): LinkRenderMode {\n\tif (componentLinkExpansion(link.component ?? fieldComponent) === 'inline') return 'inline'\n\treturn link.cardinality === 'noneOrMany' || link.cardinality === 'atLeastOne' ? 'table' : 'record'\n}\n\n/**\n * Every component Stonecrop ships with that can render a value field, sorted by name.\n *\n * The union of the two maps above is the definition, not a copy of it: a shipped component either\n * categorises a value ({@link COMPONENT_CATEGORY}) or is one of the link containers that has no\n * value of its own ({@link COMPONENT_LINK_EXPANSION}'s `AForm`/`ATable`). `AFieldset` is absent by\n * the same rule — it is a `kind: 'fieldset'` container, so it is never a value field's component.\n *\n * `component` is an **open** axis: any string is valid, and naming a custom component is how an app\n * renders a field Stonecrop ships no widget for. This list is therefore the set to *suggest* to an\n * author, and to check first-party data against — never a set to validate arbitrary input against.\n *\n * @public\n */\nexport const CANONICAL_COMPONENTS: readonly string[] = [\n\t...new Set([...Object.keys(COMPONENT_CATEGORY), ...Object.keys(COMPONENT_LINK_EXPANSION)]),\n].toSorted()\n"],"names":["COMPONENT_CATEGORY","componentCategory","component","COMPONENT_LINK_EXPANSION","componentLinkExpansion","resolveLinkRenderMode","link","fieldComponent","CANONICAL_COMPONENTS"],"mappings":";AAmBO,MAAMA,IAAwD;AAAA,EACpE,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,eAAe;AAAA,EACf,WAAW;AAAA,EACX,OAAO;AAAA,EACP,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,WAAW;AAAA,EACX,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,aAAa;AAAA,EACb,WAAW;AAAA,EACX,aAAa;AAAA,EACb,gBAAgB;AACjB;AAOO,SAASC,EAAkBC,GAAmD;AACpF,SAAOA,IAAYF,EAAmBE,CAAS,IAAI;AACpD;AAsBO,MAAMC,IAA0D;AAAA,EACtE,WAAW;AAAA,EACX,OAAO;AAAA,EACP,QAAQ;AACT;AAMO,SAASC,EAAuBF,GAA+C;AACrF,SAAOA,IAAYC,EAAyBD,CAAS,IAAI;AAC1D;AA8BO,SAASG,EACfC,GACAC,GACiB;AACjB,SAAIH,EAAuBE,EAAK,aAAaC,CAAc,MAAM,WAAiB,WAC3ED,EAAK,gBAAgB,gBAAgBA,EAAK,gBAAgB,eAAe,UAAU;AAC3F;AAgBO,MAAME,IAA0C;AAAA,EACtD,GAAG,oBAAI,IAAI,CAAC,GAAG,OAAO,KAAKR,CAAkB,GAAG,GAAG,OAAO,KAAKG,CAAwB,CAAC,CAAC;AAC1F,EAAE,SAAA;"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/component-meta.ts"],"sourcesContent":["/**\n * Semantic category for a rendering component.\n *\n * `component` is the primary field axis, so the runtime consumers that need to know what a field\n * *means* (atable cell formatting / filter widgets, record-default init) derive it from here. This\n * is the single source of \"what kind of value does this component render\", keyed by the canonical\n * registered component names — each consumer maps the category to its own concern (filter widget,\n * default value, …).\n *\n * @public\n */\nexport type ComponentCategory =\n\t'text' | 'number' | 'boolean' | 'date' | 'datetime' | 'select' | 'code' | 'link' | 'attach' | 'quantity' | 'currency'\n\n/**\n * Canonical component → semantic category. Only the components Stonecrop ships with appear here;\n * custom/unknown component names have no category and consumers fall back to their default.\n * @public\n */\nexport const COMPONENT_CATEGORY: Record<string, ComponentCategory> = {\n\tATextInput: 'text',\n\tATextboxInput: 'text',\n\tANumericInput: 'number',\n\tACheckbox: 'boolean',\n\tADate: 'date',\n\tADatePicker: 'date',\n\tADateSelection: 'date',\n\tADateTime: 'datetime',\n\tADuration: 'text',\n\tADateRange: 'date',\n\tADropdown: 'select',\n\tACodeEditor: 'code',\n\tAFormLink: 'link',\n\tAFileAttach: 'attach',\n\tAQuantityInput: 'quantity',\n\tACurrencyInput: 'currency',\n}\n\n/**\n * Resolve a component's semantic category, or `undefined` for an unknown (custom) component —\n * callers treat that as \"no opinion\" and use their own default.\n * @public\n */\nexport function componentCategory(component?: string): ComponentCategory | undefined {\n\treturn component ? COMPONENT_CATEGORY[component] : undefined\n}\n\n/**\n * Whether a link component expands its target doctype, or renders the link inline.\n *\n * This is the *only* axis the component decides. It deliberately does not choose between an\n * embedded record and an embedded table: `cardinality` states whether the value is a scalar or\n * an array, which is a fact about the data rather than a rendering preference, so a component\n * must not be able to override it (an `AForm` over a `noneOrMany` link would be handed an array\n * it cannot render). Component names encode both axes — `AFormLink`/`ATableLink` are the inline\n * pair, `AForm`/`ATable` the expanding pair — but only the inline/expand half is authoritative.\n *\n * @public\n */\nexport type LinkExpansion = 'inline' | 'expand'\n\n/**\n * Canonical link component → expansion. Only components Stonecrop ships with appear here; an\n * unmapped (custom) component has none, and callers treat that as `expand` — the behaviour that\n * predates this map, so a custom component can never silently collapse a link to a picker.\n * @public\n */\nexport const COMPONENT_LINK_EXPANSION: Record<string, LinkExpansion> = {\n\tAFormLink: 'inline',\n\tAForm: 'expand',\n\tATable: 'expand',\n}\n\n/**\n * Resolve a component's link expansion, or `undefined` for an absent/unmapped component.\n * @public\n */\nexport function componentLinkExpansion(component?: string): LinkExpansion | undefined {\n\treturn component ? COMPONENT_LINK_EXPANSION[component] : undefined\n}\n\n/**\n * How a link field renders.\n *\n * - `inline` — a scalar id-picker; the target is *not* expanded (the field keeps its own value\n * and carries a `doctype` prop for async display-text resolution and navigation).\n * - `record` — the target doctype is resolved and embedded as a nested form.\n * - `table` — the target doctype is resolved and embedded as a child table.\n *\n * @public\n */\nexport type LinkRenderMode = 'inline' | 'record' | 'table'\n\n/**\n * Decide how a *declared* link (one with a `LinkDeclaration`) renders.\n *\n * Two independent axes: the **component** picks inline vs expand, and when expanding the\n * **cardinality** picks record vs table (many → table). The declaration's component wins over the\n * field's, matching the precedence the resolver already uses for the rendered component.\n *\n * This is the single definition of \"does this link expand\" — it is consumed by both the client\n * resolver (which builds the nested schema) and the server column builder (which must still\n * SELECT an `inline` link's FK column). Call it; never re-derive the rule at the call site, or\n * the two will drift and the client will render a table for a column the server never selected.\n *\n * @param link - the link declaration (only `component` and `cardinality` are consulted)\n * @param fieldComponent - the linked field's own `component`, used when the declaration names none\n * @public\n */\nexport function resolveLinkRenderMode(\n\tlink: { component?: string; cardinality?: string },\n\tfieldComponent?: string\n): LinkRenderMode {\n\tif (componentLinkExpansion(link.component ?? fieldComponent) === 'inline') return 'inline'\n\treturn link.cardinality === 'noneOrMany' || link.cardinality === 'atLeastOne' ? 'table' : 'record'\n}\n\n/**\n * Every component Stonecrop ships with that can render a value field, sorted by name.\n *\n * The union of the two maps above is the definition, not a copy of it: a shipped component either\n * categorises a value ({@link COMPONENT_CATEGORY}) or is one of the link containers that has no\n * value of its own ({@link COMPONENT_LINK_EXPANSION}'s `AForm`/`ATable`). `AFieldset` is absent by\n * the same rule — it is a `kind: 'fieldset'` container, so it is never a value field's component.\n *\n * `component` is an **open** axis: any string is valid, and naming a custom component is how an app\n * renders a field Stonecrop ships no widget for. This list is therefore the set to *suggest* to an\n * author, and to check first-party data against — never a set to validate arbitrary input against.\n *\n * @public\n */\nexport const CANONICAL_COMPONENTS: readonly string[] = [\n\t...new Set([...Object.keys(COMPONENT_CATEGORY), ...Object.keys(COMPONENT_LINK_EXPANSION)]),\n].toSorted()\n"],"names":["COMPONENT_CATEGORY","componentCategory","component","COMPONENT_LINK_EXPANSION","componentLinkExpansion","resolveLinkRenderMode","link","fieldComponent","CANONICAL_COMPONENTS"],"mappings":";AAmBO,MAAMA,IAAwD;AAAA,EACpE,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,eAAe;AAAA,EACf,WAAW;AAAA,EACX,OAAO;AAAA,EACP,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,WAAW;AAAA,EACX,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,aAAa;AAAA,EACb,WAAW;AAAA,EACX,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,gBAAgB;AACjB;AAOO,SAASC,EAAkBC,GAAmD;AACpF,SAAOA,IAAYF,EAAmBE,CAAS,IAAI;AACpD;AAsBO,MAAMC,IAA0D;AAAA,EACtE,WAAW;AAAA,EACX,OAAO;AAAA,EACP,QAAQ;AACT;AAMO,SAASC,EAAuBF,GAA+C;AACrF,SAAOA,IAAYC,EAAyBD,CAAS,IAAI;AAC1D;AA8BO,SAASG,EACfC,GACAC,GACiB;AACjB,SAAIH,EAAuBE,EAAK,aAAaC,CAAc,MAAM,WAAiB,WAC3ED,EAAK,gBAAgB,gBAAgBA,EAAK,gBAAgB,eAAe,UAAU;AAC3F;AAgBO,MAAME,IAA0C;AAAA,EACtD,GAAG,oBAAI,IAAI,CAAC,GAAG,OAAO,KAAKR,CAAkB,GAAG,GAAG,OAAO,KAAKG,CAAwB,CAAC,CAAC;AAC1F,EAAE,SAAA;"}
|
package/dist/schema.d.ts
CHANGED
|
@@ -295,7 +295,7 @@ export declare const COMPONENT_LINK_EXPANSION: Record<string, LinkExpansion>;
|
|
|
295
295
|
*
|
|
296
296
|
* @public
|
|
297
297
|
*/
|
|
298
|
-
export declare type ComponentCategory = 'text' | 'number' | 'boolean' | 'date' | 'datetime' | 'select' | 'code' | 'link' | 'attach' | 'quantity';
|
|
298
|
+
export declare type ComponentCategory = 'text' | 'number' | 'boolean' | 'date' | 'datetime' | 'select' | 'code' | 'link' | 'attach' | 'quantity' | 'currency';
|
|
299
299
|
|
|
300
300
|
/**
|
|
301
301
|
* Resolve a component's semantic category, or `undefined` for an unknown (custom) component —
|
|
@@ -667,7 +667,6 @@ declare interface FieldTemplate {
|
|
|
667
667
|
* @public
|
|
668
668
|
*/
|
|
669
669
|
export declare const FieldValidation: z.ZodObject<{
|
|
670
|
-
/** Error message to display when validation fails */
|
|
671
670
|
errorMessage: z.ZodString;
|
|
672
671
|
}, z.core.$loose>;
|
|
673
672
|
|
|
@@ -1354,7 +1353,6 @@ export declare const ValueFieldSchema: z.ZodObject<{
|
|
|
1354
1353
|
hidden: z.ZodOptional<z.ZodBoolean>;
|
|
1355
1354
|
default: z.ZodOptional<z.ZodUnknown>;
|
|
1356
1355
|
validation: z.ZodOptional<z.ZodObject<{
|
|
1357
|
-
/** Error message to display when validation fails */
|
|
1358
1356
|
errorMessage: z.ZodString;
|
|
1359
1357
|
}, z.core.$loose>>;
|
|
1360
1358
|
cardinality: z.ZodOptional<z.ZodEnum<{
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @public
|
|
11
11
|
*/
|
|
12
|
-
export type ComponentCategory = 'text' | 'number' | 'boolean' | 'date' | 'datetime' | 'select' | 'code' | 'link' | 'attach' | 'quantity';
|
|
12
|
+
export type ComponentCategory = 'text' | 'number' | 'boolean' | 'date' | 'datetime' | 'select' | 'code' | 'link' | 'attach' | 'quantity' | 'currency';
|
|
13
13
|
/**
|
|
14
14
|
* Canonical component → semantic category. Only the components Stonecrop ships with appear here;
|
|
15
15
|
* custom/unknown component names have no category and consumers fall back to their default.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component-meta.d.ts","sourceRoot":"","sources":["../../src/component-meta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,MAAM,iBAAiB,GAC5B,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"component-meta.d.ts","sourceRoot":"","sources":["../../src/component-meta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,MAAM,iBAAiB,GAC5B,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,CAAA;AAEtH;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAiBhE,CAAA;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAEnF;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAE/C;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAIlE,CAAA;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAEpF;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAA;AAE1D;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CACpC,IAAI,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,EAClD,cAAc,CAAC,EAAE,MAAM,GACrB,cAAc,CAGhB;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EAEtC,CAAA"}
|
package/dist/src/field.d.ts
CHANGED
|
@@ -27,7 +27,6 @@ export type FieldOptions = z.infer<typeof FieldOptions>;
|
|
|
27
27
|
* @public
|
|
28
28
|
*/
|
|
29
29
|
export declare const FieldValidation: z.ZodObject<{
|
|
30
|
-
/** Error message to display when validation fails */
|
|
31
30
|
errorMessage: z.ZodString;
|
|
32
31
|
}, z.core.$loose>;
|
|
33
32
|
/**
|
|
@@ -207,7 +206,6 @@ export declare const ValueFieldSchema: z.ZodObject<{
|
|
|
207
206
|
hidden: z.ZodOptional<z.ZodBoolean>;
|
|
208
207
|
default: z.ZodOptional<z.ZodUnknown>;
|
|
209
208
|
validation: z.ZodOptional<z.ZodObject<{
|
|
210
|
-
/** Error message to display when validation fails */
|
|
211
209
|
errorMessage: z.ZodString;
|
|
212
210
|
}, z.core.$loose>>;
|
|
213
211
|
cardinality: z.ZodOptional<z.ZodEnum<{
|
package/dist/src/field.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field.d.ts","sourceRoot":"","sources":["../../src/field.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAEzC;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,YAAY,wFAQtB,CAAA;AAEH;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AAEvD;;;GAGG;AACH,eAAO,MAAM,eAAe
|
|
1
|
+
{"version":3,"file":"field.d.ts","sourceRoot":"","sources":["../../src/field.ts"],"names":[],"mappings":"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"}
|
package/dist/tsdoc-metadata.json
CHANGED
|
@@ -1,6 +1,194 @@
|
|
|
1
|
-
import { z as e } from "zod";
|
|
2
1
|
import { isScalarType as x, isEnumType as N, isObjectType as b, isNonNullType as j, isListType as U, isNamedType as q, buildSchema as V, buildClientSchema as R } from "graphql";
|
|
3
|
-
|
|
2
|
+
import { z as e } from "zod";
|
|
3
|
+
function Se(n) {
|
|
4
|
+
return n.replace(/_([a-z])/g, (t, i) => i.toUpperCase());
|
|
5
|
+
}
|
|
6
|
+
function Ae(n) {
|
|
7
|
+
return n.replace(/[A-Z]/g, (t) => `_${t.toLowerCase()}`);
|
|
8
|
+
}
|
|
9
|
+
function ke(n) {
|
|
10
|
+
return n.split("_").map((t) => t.charAt(0).toUpperCase() + t.slice(1).toLowerCase()).join(" ");
|
|
11
|
+
}
|
|
12
|
+
function W(n) {
|
|
13
|
+
const t = n.replace(/([A-Z])/g, " $1").trim();
|
|
14
|
+
return t.charAt(0).toUpperCase() + t.slice(1);
|
|
15
|
+
}
|
|
16
|
+
function z(n) {
|
|
17
|
+
return n.split(/[-_\s]+/).map((t) => t.charAt(0).toUpperCase() + t.slice(1).toLowerCase()).join("");
|
|
18
|
+
}
|
|
19
|
+
function h(n) {
|
|
20
|
+
return n.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
|
|
21
|
+
}
|
|
22
|
+
function we(n) {
|
|
23
|
+
return n.replace(/([a-z])([A-Z])/g, "$1_$2").replace(/[\s-]+/g, "_").toLowerCase();
|
|
24
|
+
}
|
|
25
|
+
const P = {
|
|
26
|
+
String: { component: "ATextInput" },
|
|
27
|
+
Int: { component: "ANumericInput" },
|
|
28
|
+
Float: { component: "ANumericInput" },
|
|
29
|
+
Boolean: { component: "ACheckbox" },
|
|
30
|
+
ID: { component: "ATextInput" }
|
|
31
|
+
}, $ = {
|
|
32
|
+
// Arbitrary precision / large numbers — all numeric variants render with ANumericInput.
|
|
33
|
+
BigFloat: { component: "ANumericInput" },
|
|
34
|
+
BigDecimal: { component: "ANumericInput" },
|
|
35
|
+
Decimal: { component: "ANumericInput" },
|
|
36
|
+
BigInt: { component: "ANumericInput" },
|
|
37
|
+
Long: { component: "ANumericInput" },
|
|
38
|
+
// Identifiers
|
|
39
|
+
UUID: { component: "ATextInput" },
|
|
40
|
+
// Date / Time — no dedicated Time SFC exists; Time falls back to a plain text input.
|
|
41
|
+
DateTime: { component: "ADateTime" },
|
|
42
|
+
Datetime: { component: "ADateTime" },
|
|
43
|
+
Date: { component: "ADate" },
|
|
44
|
+
Time: { component: "ATextInput" },
|
|
45
|
+
Interval: { component: "ADuration" },
|
|
46
|
+
Duration: { component: "ADuration" },
|
|
47
|
+
// Structured data
|
|
48
|
+
JSON: { component: "ACodeEditor" },
|
|
49
|
+
JSONObject: { component: "ACodeEditor" },
|
|
50
|
+
JsonNode: { component: "ACodeEditor" }
|
|
51
|
+
}, G = /* @__PURE__ */ new Set(["Cursor"]);
|
|
52
|
+
function Q(n) {
|
|
53
|
+
const t = { ...$ };
|
|
54
|
+
for (const [i, a] of Object.entries(P))
|
|
55
|
+
t[i] = a;
|
|
56
|
+
if (n)
|
|
57
|
+
for (const [i, a] of Object.entries(n))
|
|
58
|
+
t[i] = { component: a.component ?? "ATextInput" };
|
|
59
|
+
return t;
|
|
60
|
+
}
|
|
61
|
+
const B = [
|
|
62
|
+
"Connection",
|
|
63
|
+
"Edge",
|
|
64
|
+
"Input",
|
|
65
|
+
"Patch",
|
|
66
|
+
"Payload",
|
|
67
|
+
"Condition",
|
|
68
|
+
"Filter",
|
|
69
|
+
"OrderBy",
|
|
70
|
+
"Aggregate",
|
|
71
|
+
"AggregateResult",
|
|
72
|
+
"AggregateFilter",
|
|
73
|
+
"DeleteResponse",
|
|
74
|
+
"InsertResponse",
|
|
75
|
+
"UpdateResponse",
|
|
76
|
+
"MutationResponse"
|
|
77
|
+
], K = /* @__PURE__ */ new Set(["Query", "Mutation", "Subscription"]);
|
|
78
|
+
function J(n, t) {
|
|
79
|
+
if (n.startsWith("__") || K.has(n) || n === "Node")
|
|
80
|
+
return !1;
|
|
81
|
+
for (const a of B)
|
|
82
|
+
if (n.endsWith(a))
|
|
83
|
+
return !1;
|
|
84
|
+
const i = t.getFields();
|
|
85
|
+
return Object.keys(i).length !== 0;
|
|
86
|
+
}
|
|
87
|
+
const Z = /* @__PURE__ */ new Set(["nodeId", "__typename", "clientMutationId"]);
|
|
88
|
+
function H(n, t, i) {
|
|
89
|
+
return !Z.has(n);
|
|
90
|
+
}
|
|
91
|
+
function k(n) {
|
|
92
|
+
let t = !1, i = !1, a = n;
|
|
93
|
+
if (j(a) && (t = !0, a = a.ofType), U(a) && (i = !0, a = a.ofType, j(a) && (a = a.ofType)), !q(a))
|
|
94
|
+
throw new Error(`Expected a named GraphQL type, got: ${String(a)}`);
|
|
95
|
+
return { namedType: a, required: t, isList: i };
|
|
96
|
+
}
|
|
97
|
+
function Y(n) {
|
|
98
|
+
const i = n.getFields().edges;
|
|
99
|
+
if (!i) return;
|
|
100
|
+
const { namedType: a, isList: r } = k(i.type);
|
|
101
|
+
if (!r || !b(a)) return;
|
|
102
|
+
const d = a.getFields().node;
|
|
103
|
+
if (!d) return;
|
|
104
|
+
const { namedType: u } = k(d.type);
|
|
105
|
+
if (b(u))
|
|
106
|
+
return u.name;
|
|
107
|
+
}
|
|
108
|
+
function X(n, t, i, a = {}) {
|
|
109
|
+
const { namedType: r, required: y, isList: d } = k(t.type), u = Q(a.customScalars), o = {
|
|
110
|
+
kind: "field",
|
|
111
|
+
fieldname: n,
|
|
112
|
+
label: W(n),
|
|
113
|
+
component: "ATextInput"
|
|
114
|
+
};
|
|
115
|
+
if (y && (o.required = !0), x(r)) {
|
|
116
|
+
if (G.has(r.name))
|
|
117
|
+
return o._unmapped = !0, a.includeUnmappedMeta && (o._graphqlType = r.name), o;
|
|
118
|
+
if (r.name === "ID") {
|
|
119
|
+
const m = z(n);
|
|
120
|
+
if (i.has(m))
|
|
121
|
+
return o.component = "AFormLink", o.doctype = h(m), o;
|
|
122
|
+
}
|
|
123
|
+
const l = u[r.name];
|
|
124
|
+
return l ? o.component = l.component : (o._unmapped = !0, a.includeUnmappedMeta && (o._graphqlType = r.name)), o;
|
|
125
|
+
}
|
|
126
|
+
if (N(r))
|
|
127
|
+
return o.component = "ADropdown", o.options = r.getValues().map((l) => l.name), o;
|
|
128
|
+
if (b(r)) {
|
|
129
|
+
if (!d && i.has(r.name))
|
|
130
|
+
return o.component = "AFormLink", o.doctype = h(r.name), o;
|
|
131
|
+
const l = Y(r);
|
|
132
|
+
return l && i.has(l) ? (o.component = "ATable", o._isLink = !0, o.doctype = h(l), o.cardinality = "noneOrMany", o) : d && i.has(r.name) ? (o.component = "ATable", o._isLink = !0, o.doctype = h(r.name), o.cardinality = "noneOrMany", o) : (o._unmapped = !0, a.includeUnmappedMeta && (o._graphqlType = r.name), o);
|
|
133
|
+
}
|
|
134
|
+
return o._unmapped = !0, a.includeUnmappedMeta && (o._graphqlType = r.name), o;
|
|
135
|
+
}
|
|
136
|
+
function Le(n, t = {}) {
|
|
137
|
+
const i = ee(n), a = i.getTypeMap(), r = /* @__PURE__ */ new Set(), y = i.getQueryType(), d = i.getMutationType(), u = i.getSubscriptionType();
|
|
138
|
+
y && r.add(y.name), d && r.add(d.name), u && r.add(u.name);
|
|
139
|
+
const o = t.isEntityType ?? J, l = /* @__PURE__ */ new Set();
|
|
140
|
+
for (const [c, p] of Object.entries(a))
|
|
141
|
+
b(p) && (r.has(c) || o(c, p) && l.add(c));
|
|
142
|
+
let m = l;
|
|
143
|
+
if (t.include) {
|
|
144
|
+
const c = new Set(t.include);
|
|
145
|
+
m = new Set([...l].filter((p) => c.has(p)));
|
|
146
|
+
}
|
|
147
|
+
if (t.exclude) {
|
|
148
|
+
const c = new Set(t.exclude);
|
|
149
|
+
m = new Set([...m].filter((p) => !c.has(p)));
|
|
150
|
+
}
|
|
151
|
+
const C = t.isEntityField ?? H, L = [];
|
|
152
|
+
for (const c of m) {
|
|
153
|
+
const p = a[c];
|
|
154
|
+
if (!b(p)) continue;
|
|
155
|
+
const O = p.getFields(), _ = t.typeOverrides?.[c], M = Object.entries(O).filter(([s, g]) => C(s, g, p)).map(([s, g]) => {
|
|
156
|
+
if (t.classifyField) {
|
|
157
|
+
const f = t.classifyField(s, g, p);
|
|
158
|
+
if (f != null)
|
|
159
|
+
return {
|
|
160
|
+
kind: "field",
|
|
161
|
+
fieldname: s,
|
|
162
|
+
label: f.label ?? s,
|
|
163
|
+
component: f.component ?? "ATextInput",
|
|
164
|
+
...f
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
const T = X(s, g, l, t);
|
|
168
|
+
return _?.[s] ? Object.assign(T, _[s]) : T;
|
|
169
|
+
}), S = {}, v = M.filter((s) => s._isLink && s.doctype && s.cardinality ? (S[s.fieldname] = {
|
|
170
|
+
target: s.doctype,
|
|
171
|
+
cardinality: s.cardinality
|
|
172
|
+
}, !1) : !0).map((s) => {
|
|
173
|
+
if (!t.includeUnmappedMeta) {
|
|
174
|
+
const { _graphqlType: f, _unmapped: he, _isLink: be, ...E } = s;
|
|
175
|
+
return Object.assign(E, { source: "introspected" });
|
|
176
|
+
}
|
|
177
|
+
const { _isLink: g, ...T } = s;
|
|
178
|
+
return Object.assign(T, { source: "introspected" });
|
|
179
|
+
}), A = {
|
|
180
|
+
name: c,
|
|
181
|
+
slug: h(c),
|
|
182
|
+
fields: v
|
|
183
|
+
};
|
|
184
|
+
Object.keys(S).length > 0 && (A.links = S), t.includeUnmappedMeta && (A._graphqlTypeName = c), L.push(A);
|
|
185
|
+
}
|
|
186
|
+
return L;
|
|
187
|
+
}
|
|
188
|
+
function ee(n) {
|
|
189
|
+
return typeof n == "string" ? V(n) : R(n);
|
|
190
|
+
}
|
|
191
|
+
const te = e.object({
|
|
4
192
|
/** The table view type */
|
|
5
193
|
view: e.enum(["list", "uncounted", "list-expansion", "tree", "gantt", "tree-gantt"]).optional(),
|
|
6
194
|
/** Allow the table to use the full width of its container */
|
|
@@ -12,7 +200,7 @@ const W = e.object({
|
|
|
12
200
|
}).meta({
|
|
13
201
|
title: "TableViewConfig",
|
|
14
202
|
description: "JSON-safe view configuration for table fields in doctype authoring"
|
|
15
|
-
}),
|
|
203
|
+
}), ne = e.union([
|
|
16
204
|
e.array(e.string()),
|
|
17
205
|
// Select choices: ["A", "B", "C"]
|
|
18
206
|
e.record(e.string(), e.unknown())
|
|
@@ -20,7 +208,7 @@ const W = e.object({
|
|
|
20
208
|
]).meta({
|
|
21
209
|
title: "FieldOptions",
|
|
22
210
|
description: "Field options - flexible bag for type-specific configuration"
|
|
23
|
-
}),
|
|
211
|
+
}), ie = e.looseObject({
|
|
24
212
|
/** Error message to display when validation fails */
|
|
25
213
|
errorMessage: e.string()
|
|
26
214
|
}).meta({
|
|
@@ -32,13 +220,13 @@ function D(n) {
|
|
|
32
220
|
const t = n;
|
|
33
221
|
return "kind" in t ? n : "schema" in t ? { kind: "fieldset", ...t } : "columns" in t ? { kind: "table", ...t } : { kind: "field", ...t };
|
|
34
222
|
}
|
|
35
|
-
function
|
|
223
|
+
function oe(n) {
|
|
36
224
|
const t = D(n);
|
|
37
225
|
if (typeof t != "object" || t === null) return t;
|
|
38
226
|
const i = t;
|
|
39
|
-
return i.kind === "fieldset" && Array.isArray(i.schema) ? { ...i, schema: i.schema.map(
|
|
227
|
+
return i.kind === "fieldset" && Array.isArray(i.schema) ? { ...i, schema: i.schema.map(oe) } : t;
|
|
40
228
|
}
|
|
41
|
-
function
|
|
229
|
+
function ae() {
|
|
42
230
|
const n = e.object({
|
|
43
231
|
kind: e.literal("field"),
|
|
44
232
|
fieldname: e.string().min(1),
|
|
@@ -54,12 +242,12 @@ function G() {
|
|
|
54
242
|
mask: e.string().optional(),
|
|
55
243
|
format: e.string().optional(),
|
|
56
244
|
mode: e.enum(["edit", "read", "display"]).optional(),
|
|
57
|
-
options:
|
|
245
|
+
options: ne.optional(),
|
|
58
246
|
required: e.boolean().optional(),
|
|
59
247
|
readOnly: e.boolean().optional(),
|
|
60
248
|
hidden: e.boolean().optional(),
|
|
61
249
|
default: e.unknown().optional(),
|
|
62
|
-
validation:
|
|
250
|
+
validation: ie.optional(),
|
|
63
251
|
cardinality: e.enum(["atMostOne", "one", "noneOrMany", "atLeastOne"]).optional(),
|
|
64
252
|
source: e.literal("introspected").optional()
|
|
65
253
|
}).meta({ title: "ValueField" }), t = e.object({
|
|
@@ -69,7 +257,7 @@ function G() {
|
|
|
69
257
|
label: e.string().optional(),
|
|
70
258
|
// Validates that each column has fieldname; allows all other ColumnSchema properties
|
|
71
259
|
columns: e.array(e.object({ fieldname: e.string().min(1) }).passthrough()),
|
|
72
|
-
config:
|
|
260
|
+
config: te.optional(),
|
|
73
261
|
mode: e.enum(["edit", "read", "display"]).optional()
|
|
74
262
|
}).meta({ title: "TableField" });
|
|
75
263
|
let i = e.never();
|
|
@@ -84,10 +272,10 @@ function G() {
|
|
|
84
272
|
}).meta({ title: "FieldsetField" }), r = e.discriminatedUnion("kind", [n, a, t]);
|
|
85
273
|
return i = e.preprocess(D, r), { ValueFieldSchema: n, TableFieldSchema: t, FieldsetFieldSchema: a, DoctypeFieldSchema: i };
|
|
86
274
|
}
|
|
87
|
-
const F =
|
|
275
|
+
const F = ae(), _e = F.ValueFieldSchema, je = F.FieldsetFieldSchema, De = F.TableFieldSchema, w = F.DoctypeFieldSchema, re = e.enum(["atMostOne", "one", "noneOrMany", "atLeastOne"]).meta({
|
|
88
276
|
title: "Cardinality",
|
|
89
277
|
description: "Cardinality for relationship links between doctypes"
|
|
90
|
-
}),
|
|
278
|
+
}), se = e.object({
|
|
91
279
|
/** Fetch method type */
|
|
92
280
|
method: e.literal("sync"),
|
|
93
281
|
/** Optional limit on number of records to fetch */
|
|
@@ -95,13 +283,13 @@ const F = G(), Se = F.ValueFieldSchema, Ae = F.FieldsetFieldSchema, ke = F.Table
|
|
|
95
283
|
}).meta({
|
|
96
284
|
title: "SyncFetch",
|
|
97
285
|
description: "Sync fetch strategy - data is fetched in the initial query"
|
|
98
|
-
}),
|
|
286
|
+
}), le = e.object({
|
|
99
287
|
/** Fetch method type */
|
|
100
288
|
method: e.literal("lazy")
|
|
101
289
|
}).meta({
|
|
102
290
|
title: "LazyFetch",
|
|
103
291
|
description: "Lazy fetch strategy - data is fetched on demand in a separate query"
|
|
104
|
-
}),
|
|
292
|
+
}), ce = e.object({
|
|
105
293
|
/** Fetch method type */
|
|
106
294
|
method: e.literal("custom"),
|
|
107
295
|
/** Serialized handler function to invoke */
|
|
@@ -109,14 +297,14 @@ const F = G(), Se = F.ValueFieldSchema, Ae = F.FieldsetFieldSchema, ke = F.Table
|
|
|
109
297
|
}).meta({
|
|
110
298
|
title: "CustomFetch",
|
|
111
299
|
description: "Custom fetch strategy - uses a custom handler function"
|
|
112
|
-
}),
|
|
300
|
+
}), pe = e.discriminatedUnion("method", [se, le, ce]).meta({
|
|
113
301
|
title: "FetchStrategy",
|
|
114
302
|
description: "Fetch strategy for link data loading"
|
|
115
|
-
}),
|
|
303
|
+
}), de = e.object({
|
|
116
304
|
/** Target doctype slug */
|
|
117
305
|
target: e.string().min(1),
|
|
118
306
|
/** Cardinality of the relationship */
|
|
119
|
-
cardinality:
|
|
307
|
+
cardinality: re,
|
|
120
308
|
/** Backlink fieldname on the target doctype that points back to this link */
|
|
121
309
|
backlink: e.string().optional(),
|
|
122
310
|
/** Override default rendering component (AForm for 1:1, ATable for 1:many) */
|
|
@@ -124,13 +312,13 @@ const F = G(), Se = F.ValueFieldSchema, Ae = F.FieldsetFieldSchema, ke = F.Table
|
|
|
124
312
|
/** Fieldname of the corresponding Link field in the fields array */
|
|
125
313
|
fieldname: e.string().min(1).optional(),
|
|
126
314
|
/** Fetch strategy for loading nested data */
|
|
127
|
-
fetch:
|
|
315
|
+
fetch: pe.optional(),
|
|
128
316
|
/** Whether to block workflow actions until nested data is loaded (default: true) */
|
|
129
317
|
blockWorkflows: e.boolean().optional()
|
|
130
318
|
}).meta({
|
|
131
319
|
title: "LinkDeclaration",
|
|
132
320
|
description: "Declares a relationship from one doctype to another"
|
|
133
|
-
}),
|
|
321
|
+
}), ue = e.object({
|
|
134
322
|
/** Display label for the action */
|
|
135
323
|
label: e.string().min(1),
|
|
136
324
|
/** Fields that must have values before action can execute */
|
|
@@ -154,7 +342,7 @@ const F = G(), Se = F.ValueFieldSchema, Ae = F.FieldsetFieldSchema, ke = F.Table
|
|
|
154
342
|
}).meta({
|
|
155
343
|
title: "ActionDefinition",
|
|
156
344
|
description: "Action definition within a workflow"
|
|
157
|
-
}),
|
|
345
|
+
}), me = e.object({
|
|
158
346
|
/** Optional display label; the map key is the trigger's identity */
|
|
159
347
|
label: e.string().optional(),
|
|
160
348
|
/** Fieldnames whose edits fire this trigger (fires when any listed field changes) */
|
|
@@ -165,30 +353,30 @@ const F = G(), Se = F.ValueFieldSchema, Ae = F.FieldsetFieldSchema, ke = F.Table
|
|
|
165
353
|
title: "TriggerDefinition",
|
|
166
354
|
description: "Reactive field-validation trigger — advisory client-side"
|
|
167
355
|
});
|
|
168
|
-
function
|
|
356
|
+
function Ie(n, t) {
|
|
169
357
|
const i = n.allowedStates;
|
|
170
358
|
return !i || i.length === 0 ? !0 : i.includes(t);
|
|
171
359
|
}
|
|
172
|
-
const
|
|
360
|
+
const fe = e.record(
|
|
173
361
|
e.string(),
|
|
174
362
|
e.object({
|
|
175
363
|
position: e.object({ x: e.number(), y: e.number() }).optional(),
|
|
176
364
|
targetPosition: e.enum(["left", "top", "right", "bottom"]).optional(),
|
|
177
365
|
sourcePosition: e.enum(["left", "top", "right", "bottom"]).optional()
|
|
178
366
|
})
|
|
179
|
-
),
|
|
367
|
+
), ye = e.object({
|
|
180
368
|
/** List of workflow states */
|
|
181
369
|
states: e.array(e.string()).optional(),
|
|
182
370
|
/** Actions available in this workflow */
|
|
183
|
-
actions: e.record(e.string(),
|
|
371
|
+
actions: e.record(e.string(), ue).optional(),
|
|
184
372
|
/** Reactive field-validation triggers (advisory, client-side), keyed by trigger name */
|
|
185
|
-
triggers: e.record(e.string(),
|
|
373
|
+
triggers: e.record(e.string(), me).optional(),
|
|
186
374
|
/**
|
|
187
375
|
* DocBuilder node positions keyed by state name — authoring view-state. Persisted here so a
|
|
188
376
|
* doctype author's manual graph arrangement survives reloads; like `triggers`, it is client-only
|
|
189
377
|
* and never enters the runtime GraphQL SDL. See {@link (WorkflowLayout:variable)}.
|
|
190
378
|
*/
|
|
191
|
-
layout:
|
|
379
|
+
layout: fe.optional()
|
|
192
380
|
}).meta({
|
|
193
381
|
title: "WorkflowMeta",
|
|
194
382
|
description: "Workflow metadata - states and actions for a doctype"
|
|
@@ -200,16 +388,16 @@ const ee = e.record(
|
|
|
200
388
|
/** Field definitions (a link field is one carrying `doctype`) */
|
|
201
389
|
fields: e.array(w),
|
|
202
390
|
/** Relationship links to other doctypes */
|
|
203
|
-
links: e.record(e.string(),
|
|
391
|
+
links: e.record(e.string(), de).optional(),
|
|
204
392
|
/** Workflow configuration */
|
|
205
|
-
workflow:
|
|
393
|
+
workflow: ye.optional(),
|
|
206
394
|
/** Parent doctype for inheritance */
|
|
207
395
|
inherits: e.string().optional()
|
|
208
396
|
}).meta({
|
|
209
397
|
title: "DoctypeMeta",
|
|
210
398
|
description: "Doctype metadata - complete definition of a doctype"
|
|
211
399
|
});
|
|
212
|
-
function
|
|
400
|
+
function Ce(n) {
|
|
213
401
|
const t = w.safeParse(n);
|
|
214
402
|
return t.success ? { success: !0, errors: [] } : {
|
|
215
403
|
success: !1,
|
|
@@ -219,7 +407,7 @@ function Le(n) {
|
|
|
219
407
|
}))
|
|
220
408
|
};
|
|
221
409
|
}
|
|
222
|
-
function
|
|
410
|
+
function Oe(n) {
|
|
223
411
|
const t = I.safeParse(n);
|
|
224
412
|
return t.success ? { success: !0, errors: [] } : {
|
|
225
413
|
success: !1,
|
|
@@ -229,230 +417,42 @@ function _e(n) {
|
|
|
229
417
|
}))
|
|
230
418
|
};
|
|
231
419
|
}
|
|
232
|
-
function
|
|
420
|
+
function Me(n) {
|
|
233
421
|
return w.parse(n);
|
|
234
422
|
}
|
|
235
|
-
function
|
|
423
|
+
function ve(n) {
|
|
236
424
|
return I.parse(n);
|
|
237
425
|
}
|
|
238
|
-
function Ie(n) {
|
|
239
|
-
return n.replace(/_([a-z])/g, (t, i) => i.toUpperCase());
|
|
240
|
-
}
|
|
241
|
-
function Ce(n) {
|
|
242
|
-
return n.replace(/[A-Z]/g, (t) => `_${t.toLowerCase()}`);
|
|
243
|
-
}
|
|
244
|
-
function Oe(n) {
|
|
245
|
-
return n.split("_").map((t) => t.charAt(0).toUpperCase() + t.slice(1).toLowerCase()).join(" ");
|
|
246
|
-
}
|
|
247
|
-
function ne(n) {
|
|
248
|
-
const t = n.replace(/([A-Z])/g, " $1").trim();
|
|
249
|
-
return t.charAt(0).toUpperCase() + t.slice(1);
|
|
250
|
-
}
|
|
251
|
-
function ie(n) {
|
|
252
|
-
return n.split(/[-_\s]+/).map((t) => t.charAt(0).toUpperCase() + t.slice(1).toLowerCase()).join("");
|
|
253
|
-
}
|
|
254
|
-
function h(n) {
|
|
255
|
-
return n.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
|
|
256
|
-
}
|
|
257
|
-
function Me(n) {
|
|
258
|
-
return n.replace(/([a-z])([A-Z])/g, "$1_$2").replace(/[\s-]+/g, "_").toLowerCase();
|
|
259
|
-
}
|
|
260
|
-
const oe = {
|
|
261
|
-
String: { component: "ATextInput" },
|
|
262
|
-
Int: { component: "ANumericInput" },
|
|
263
|
-
Float: { component: "ANumericInput" },
|
|
264
|
-
Boolean: { component: "ACheckbox" },
|
|
265
|
-
ID: { component: "ATextInput" }
|
|
266
|
-
}, ae = {
|
|
267
|
-
// Arbitrary precision / large numbers — all numeric variants render with ANumericInput.
|
|
268
|
-
BigFloat: { component: "ANumericInput" },
|
|
269
|
-
BigDecimal: { component: "ANumericInput" },
|
|
270
|
-
Decimal: { component: "ANumericInput" },
|
|
271
|
-
BigInt: { component: "ANumericInput" },
|
|
272
|
-
Long: { component: "ANumericInput" },
|
|
273
|
-
// Identifiers
|
|
274
|
-
UUID: { component: "ATextInput" },
|
|
275
|
-
// Date / Time — no dedicated Time SFC exists; Time falls back to a plain text input.
|
|
276
|
-
DateTime: { component: "ADateTime" },
|
|
277
|
-
Datetime: { component: "ADateTime" },
|
|
278
|
-
Date: { component: "ADate" },
|
|
279
|
-
Time: { component: "ATextInput" },
|
|
280
|
-
Interval: { component: "ADuration" },
|
|
281
|
-
Duration: { component: "ADuration" },
|
|
282
|
-
// Structured data
|
|
283
|
-
JSON: { component: "ACodeEditor" },
|
|
284
|
-
JSONObject: { component: "ACodeEditor" },
|
|
285
|
-
JsonNode: { component: "ACodeEditor" }
|
|
286
|
-
}, re = /* @__PURE__ */ new Set(["Cursor"]);
|
|
287
|
-
function se(n) {
|
|
288
|
-
const t = { ...ae };
|
|
289
|
-
for (const [i, a] of Object.entries(oe))
|
|
290
|
-
t[i] = a;
|
|
291
|
-
if (n)
|
|
292
|
-
for (const [i, a] of Object.entries(n))
|
|
293
|
-
t[i] = { component: a.component ?? "ATextInput" };
|
|
294
|
-
return t;
|
|
295
|
-
}
|
|
296
|
-
const le = [
|
|
297
|
-
"Connection",
|
|
298
|
-
"Edge",
|
|
299
|
-
"Input",
|
|
300
|
-
"Patch",
|
|
301
|
-
"Payload",
|
|
302
|
-
"Condition",
|
|
303
|
-
"Filter",
|
|
304
|
-
"OrderBy",
|
|
305
|
-
"Aggregate",
|
|
306
|
-
"AggregateResult",
|
|
307
|
-
"AggregateFilter",
|
|
308
|
-
"DeleteResponse",
|
|
309
|
-
"InsertResponse",
|
|
310
|
-
"UpdateResponse",
|
|
311
|
-
"MutationResponse"
|
|
312
|
-
], ce = /* @__PURE__ */ new Set(["Query", "Mutation", "Subscription"]);
|
|
313
|
-
function pe(n, t) {
|
|
314
|
-
if (n.startsWith("__") || ce.has(n) || n === "Node")
|
|
315
|
-
return !1;
|
|
316
|
-
for (const a of le)
|
|
317
|
-
if (n.endsWith(a))
|
|
318
|
-
return !1;
|
|
319
|
-
const i = t.getFields();
|
|
320
|
-
return Object.keys(i).length !== 0;
|
|
321
|
-
}
|
|
322
|
-
const de = /* @__PURE__ */ new Set(["nodeId", "__typename", "clientMutationId"]);
|
|
323
|
-
function ue(n, t, i) {
|
|
324
|
-
return !de.has(n);
|
|
325
|
-
}
|
|
326
|
-
function k(n) {
|
|
327
|
-
let t = !1, i = !1, a = n;
|
|
328
|
-
if (j(a) && (t = !0, a = a.ofType), U(a) && (i = !0, a = a.ofType, j(a) && (a = a.ofType)), !q(a))
|
|
329
|
-
throw new Error(`Expected a named GraphQL type, got: ${String(a)}`);
|
|
330
|
-
return { namedType: a, required: t, isList: i };
|
|
331
|
-
}
|
|
332
|
-
function me(n) {
|
|
333
|
-
const i = n.getFields().edges;
|
|
334
|
-
if (!i) return;
|
|
335
|
-
const { namedType: a, isList: r } = k(i.type);
|
|
336
|
-
if (!r || !b(a)) return;
|
|
337
|
-
const d = a.getFields().node;
|
|
338
|
-
if (!d) return;
|
|
339
|
-
const { namedType: u } = k(d.type);
|
|
340
|
-
if (b(u))
|
|
341
|
-
return u.name;
|
|
342
|
-
}
|
|
343
|
-
function fe(n, t, i, a = {}) {
|
|
344
|
-
const { namedType: r, required: y, isList: d } = k(t.type), u = se(a.customScalars), o = {
|
|
345
|
-
kind: "field",
|
|
346
|
-
fieldname: n,
|
|
347
|
-
label: ne(n),
|
|
348
|
-
component: "ATextInput"
|
|
349
|
-
};
|
|
350
|
-
if (y && (o.required = !0), x(r)) {
|
|
351
|
-
if (re.has(r.name))
|
|
352
|
-
return o._unmapped = !0, a.includeUnmappedMeta && (o._graphqlType = r.name), o;
|
|
353
|
-
if (r.name === "ID") {
|
|
354
|
-
const m = ie(n);
|
|
355
|
-
if (i.has(m))
|
|
356
|
-
return o.component = "AFormLink", o.doctype = h(m), o;
|
|
357
|
-
}
|
|
358
|
-
const l = u[r.name];
|
|
359
|
-
return l ? o.component = l.component : (o._unmapped = !0, a.includeUnmappedMeta && (o._graphqlType = r.name)), o;
|
|
360
|
-
}
|
|
361
|
-
if (N(r))
|
|
362
|
-
return o.component = "ADropdown", o.options = r.getValues().map((l) => l.name), o;
|
|
363
|
-
if (b(r)) {
|
|
364
|
-
if (!d && i.has(r.name))
|
|
365
|
-
return o.component = "AFormLink", o.doctype = h(r.name), o;
|
|
366
|
-
const l = me(r);
|
|
367
|
-
return l && i.has(l) ? (o.component = "ATable", o._isLink = !0, o.doctype = h(l), o.cardinality = "noneOrMany", o) : d && i.has(r.name) ? (o.component = "ATable", o._isLink = !0, o.doctype = h(r.name), o.cardinality = "noneOrMany", o) : (o._unmapped = !0, a.includeUnmappedMeta && (o._graphqlType = r.name), o);
|
|
368
|
-
}
|
|
369
|
-
return o._unmapped = !0, a.includeUnmappedMeta && (o._graphqlType = r.name), o;
|
|
370
|
-
}
|
|
371
|
-
function ve(n, t = {}) {
|
|
372
|
-
const i = ye(n), a = i.getTypeMap(), r = /* @__PURE__ */ new Set(), y = i.getQueryType(), d = i.getMutationType(), u = i.getSubscriptionType();
|
|
373
|
-
y && r.add(y.name), d && r.add(d.name), u && r.add(u.name);
|
|
374
|
-
const o = t.isEntityType ?? pe, l = /* @__PURE__ */ new Set();
|
|
375
|
-
for (const [c, p] of Object.entries(a))
|
|
376
|
-
b(p) && (r.has(c) || o(c, p) && l.add(c));
|
|
377
|
-
let m = l;
|
|
378
|
-
if (t.include) {
|
|
379
|
-
const c = new Set(t.include);
|
|
380
|
-
m = new Set([...l].filter((p) => c.has(p)));
|
|
381
|
-
}
|
|
382
|
-
if (t.exclude) {
|
|
383
|
-
const c = new Set(t.exclude);
|
|
384
|
-
m = new Set([...m].filter((p) => !c.has(p)));
|
|
385
|
-
}
|
|
386
|
-
const C = t.isEntityField ?? ue, L = [];
|
|
387
|
-
for (const c of m) {
|
|
388
|
-
const p = a[c];
|
|
389
|
-
if (!b(p)) continue;
|
|
390
|
-
const O = p.getFields(), _ = t.typeOverrides?.[c], M = Object.entries(O).filter(([s, g]) => C(s, g, p)).map(([s, g]) => {
|
|
391
|
-
if (t.classifyField) {
|
|
392
|
-
const f = t.classifyField(s, g, p);
|
|
393
|
-
if (f != null)
|
|
394
|
-
return {
|
|
395
|
-
kind: "field",
|
|
396
|
-
fieldname: s,
|
|
397
|
-
label: f.label ?? s,
|
|
398
|
-
component: f.component ?? "ATextInput",
|
|
399
|
-
...f
|
|
400
|
-
};
|
|
401
|
-
}
|
|
402
|
-
const T = fe(s, g, l, t);
|
|
403
|
-
return _?.[s] ? Object.assign(T, _[s]) : T;
|
|
404
|
-
}), S = {}, v = M.filter((s) => s._isLink && s.doctype && s.cardinality ? (S[s.fieldname] = {
|
|
405
|
-
target: s.doctype,
|
|
406
|
-
cardinality: s.cardinality
|
|
407
|
-
}, !1) : !0).map((s) => {
|
|
408
|
-
if (!t.includeUnmappedMeta) {
|
|
409
|
-
const { _graphqlType: f, _unmapped: he, _isLink: be, ...E } = s;
|
|
410
|
-
return Object.assign(E, { source: "introspected" });
|
|
411
|
-
}
|
|
412
|
-
const { _isLink: g, ...T } = s;
|
|
413
|
-
return Object.assign(T, { source: "introspected" });
|
|
414
|
-
}), A = {
|
|
415
|
-
name: c,
|
|
416
|
-
slug: h(c),
|
|
417
|
-
fields: v
|
|
418
|
-
};
|
|
419
|
-
Object.keys(S).length > 0 && (A.links = S), t.includeUnmappedMeta && (A._graphqlTypeName = c), L.push(A);
|
|
420
|
-
}
|
|
421
|
-
return L;
|
|
422
|
-
}
|
|
423
|
-
function ye(n) {
|
|
424
|
-
return typeof n == "string" ? V(n) : R(n);
|
|
425
|
-
}
|
|
426
426
|
export {
|
|
427
|
-
|
|
427
|
+
ue as A,
|
|
428
428
|
w as D,
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
429
|
+
je as F,
|
|
430
|
+
P as G,
|
|
431
|
+
G as I,
|
|
432
|
+
De as T,
|
|
433
|
+
_e as V,
|
|
434
|
+
$ as W,
|
|
435
|
+
te as a,
|
|
436
|
+
me as b,
|
|
437
|
+
Le as c,
|
|
438
|
+
fe as d,
|
|
439
|
+
ye as e,
|
|
440
|
+
Q as f,
|
|
441
|
+
W as g,
|
|
442
|
+
Ae as h,
|
|
443
|
+
X as i,
|
|
444
|
+
H as j,
|
|
445
|
+
J as k,
|
|
446
|
+
Ie as l,
|
|
447
|
+
Me as m,
|
|
448
|
+
oe as n,
|
|
449
|
+
we as o,
|
|
450
|
+
ve as p,
|
|
451
|
+
ke as q,
|
|
452
452
|
h as r,
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
453
|
+
Se as s,
|
|
454
|
+
z as t,
|
|
455
|
+
Ce as u,
|
|
456
|
+
Oe as v
|
|
457
457
|
};
|
|
458
|
-
//# sourceMappingURL=
|
|
458
|
+
//# sourceMappingURL=validation-Dyxjvaio.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation-Dyxjvaio.js","sources":["../src/naming.ts","../src/converter/scalars.ts","../src/converter/heuristics.ts","../src/converter/index.ts","../src/table.ts","../src/field.ts","../src/doctype.ts","../src/validation.ts"],"sourcesContent":["/**\n * Naming Convention Utilities\n * Converts between various naming conventions (snake_case, camelCase, PascalCase, kebab-case)\n * @packageDocumentation\n */\n\n/**\n * Converts snake_case to camelCase\n * @param snakeCase - Snake case string\n * @returns Camel case string\n * @public\n * @example\n * ```typescript\n * snakeToCamel('user_email') // 'userEmail'\n * snakeToCamel('created_at') // 'createdAt'\n * ```\n */\nexport function snakeToCamel(snakeCase: string): string {\n\treturn snakeCase.replace(/_([a-z])/g, (_: string, letter: string) => letter.toUpperCase())\n}\n\n/**\n * Converts camelCase to snake_case\n * @param camelCase - Camel case string\n * @returns Snake case string\n * @public\n * @example\n * ```typescript\n * camelToSnake('userEmail') // 'user_email'\n * camelToSnake('createdAt') // 'created_at'\n * ```\n */\nexport function camelToSnake(camelCase: string): string {\n\treturn camelCase.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`)\n}\n\n/**\n * Converts snake_case to Title Case label\n * @param snakeCase - Snake case string\n * @returns Title case label\n * @public\n * @example\n * ```typescript\n * snakeToLabel('user_email') // 'User Email'\n * snakeToLabel('first_name') // 'First Name'\n * ```\n */\nexport function snakeToLabel(snakeCase: string): string {\n\treturn snakeCase\n\t\t.split('_')\n\t\t.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n\t\t.join(' ')\n}\n\n/**\n * Converts camelCase to Title Case label\n * @param camelCase - Camel case string\n * @returns Title case label\n * @public\n * @example\n * ```typescript\n * camelToLabel('userEmail') // 'User Email'\n * camelToLabel('firstName') // 'First Name'\n * ```\n */\nexport function camelToLabel(camelCase: string): string {\n\tconst withSpaces = camelCase.replace(/([A-Z])/g, ' $1').trim()\n\treturn withSpaces.charAt(0).toUpperCase() + withSpaces.slice(1)\n}\n\n/**\n * Convert table name to PascalCase doctype name\n * @param tableName - SQL table name (snake_case)\n * @returns PascalCase name\n * @public\n */\nexport function toPascalCase(tableName: string): string {\n\treturn tableName\n\t\t.split(/[-_\\s]+/)\n\t\t.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n\t\t.join('')\n}\n\n/**\n * Convert to kebab-case slug\n * @param name - Name to convert\n * @returns kebab-case slug\n * @public\n */\nexport function toSlug(name: string): string {\n\treturn name\n\t\t.replace(/([a-z])([A-Z])/g, '$1-$2')\n\t\t.replace(/[\\s_]+/g, '-')\n\t\t.toLowerCase()\n}\n\n/**\n * Convert PascalCase to snake_case (e.g., for deriving table names from type names)\n * @param pascal - PascalCase string\n * @returns snake_case string\n * @public\n * @example\n * ```typescript\n * pascalToSnake('SalesOrder') // 'sales_order'\n * pascalToSnake('SalesOrderItem') // 'sales_order_item'\n * ```\n */\nexport function pascalToSnake(pascal: string): string {\n\treturn pascal\n\t\t.replace(/([a-z])([A-Z])/g, '$1_$2')\n\t\t.replace(/[\\s-]+/g, '_')\n\t\t.toLowerCase()\n}\n","/**\n * GraphQL Scalar Type Mappings\n *\n * Maps standard GraphQL scalars and well-known custom scalars to Stonecrop field types.\n * Source-agnostic — covers scalars commonly emitted by PostGraphile, Hasura, Apollo, etc.\n *\n * Users can extend these via the `customScalars` option in `GraphQLConversionOptions`.\n *\n * @packageDocumentation\n */\n\nimport type { FieldTemplate } from './types'\n\n/**\n * Mapping from standard GraphQL scalar types to Stonecrop field types.\n * These are defined by the GraphQL specification and are always available.\n *\n * @public\n */\nexport const GQL_SCALAR_MAP: Record<string, FieldTemplate> = {\n\tString: { component: 'ATextInput' },\n\tInt: { component: 'ANumericInput' },\n\tFloat: { component: 'ANumericInput' },\n\tBoolean: { component: 'ACheckbox' },\n\tID: { component: 'ATextInput' },\n}\n\n/**\n * Mapping from well-known custom GraphQL scalars to Stonecrop field types.\n * These cover scalars commonly used across GraphQL servers (PostGraphile, Hasura, etc.)\n * without baking in knowledge of any specific server.\n *\n * Entries here have lower precedence than `customScalars` from options, but higher\n * precedence than unknown/unmapped scalars.\n *\n * @public\n */\nexport const WELL_KNOWN_SCALARS: Record<string, FieldTemplate> = {\n\t// Arbitrary precision / large numbers — all numeric variants render with ANumericInput.\n\tBigFloat: { component: 'ANumericInput' },\n\tBigDecimal: { component: 'ANumericInput' },\n\tDecimal: { component: 'ANumericInput' },\n\tBigInt: { component: 'ANumericInput' },\n\tLong: { component: 'ANumericInput' },\n\n\t// Identifiers\n\tUUID: { component: 'ATextInput' },\n\n\t// Date / Time — no dedicated Time SFC exists; Time falls back to a plain text input.\n\tDateTime: { component: 'ADateTime' },\n\tDatetime: { component: 'ADateTime' },\n\tDate: { component: 'ADate' },\n\tTime: { component: 'ATextInput' },\n\tInterval: { component: 'ADuration' },\n\tDuration: { component: 'ADuration' },\n\n\t// Structured data\n\tJSON: { component: 'ACodeEditor' },\n\tJSONObject: { component: 'ACodeEditor' },\n\tJsonNode: { component: 'ACodeEditor' },\n}\n\n/**\n * Set of scalar type names that are internal to GraphQL servers and should be skipped\n * during field conversion (they don't represent meaningful data fields).\n *\n * @public\n */\nexport const INTERNAL_SCALARS = new Set(['Cursor'])\n\n/**\n * Build a merged scalar map from the built-in maps and user-provided custom scalars.\n * Precedence (highest to lowest): customScalars → GQL_SCALAR_MAP → WELL_KNOWN_SCALARS\n *\n * @param customScalars - User-provided scalar overrides\n * @returns Merged scalar map\n * @public\n */\nexport function buildScalarMap(customScalars?: Record<string, Partial<FieldTemplate>>): Record<string, FieldTemplate> {\n\tconst merged: Record<string, FieldTemplate> = { ...WELL_KNOWN_SCALARS }\n\n\t// Standard scalars override well-known\n\tfor (const [key, value] of Object.entries(GQL_SCALAR_MAP)) {\n\t\tmerged[key] = value\n\t}\n\n\t// Custom scalars override everything\n\tif (customScalars) {\n\t\tfor (const [key, value] of Object.entries(customScalars)) {\n\t\t\tmerged[key] = { component: value.component ?? 'ATextInput' }\n\t\t}\n\t}\n\n\treturn merged\n}\n","/**\n * Default heuristics for identifying entity types and fields in a GraphQL schema.\n *\n * These heuristics work across common GraphQL servers (PostGraphile, Hasura, Apollo, etc.)\n * by detecting widely-adopted conventions like the Relay connection pattern.\n *\n * All heuristics can be overridden via the `isEntityType`, `isEntityField`, and\n * `classifyField` options in `GraphQLConversionOptions`.\n *\n * @packageDocumentation\n */\n\nimport {\n\tisScalarType,\n\tisEnumType,\n\tisObjectType,\n\tisListType,\n\tisNonNullType,\n\tisNamedType,\n\ttype GraphQLObjectType,\n\ttype GraphQLField,\n\ttype GraphQLOutputType,\n\ttype GraphQLNamedType,\n} from 'graphql'\n\nimport type { FieldTemplate } from './types'\nimport type { GraphQLConversionFieldMeta, GraphQLConversionOptions } from './types'\nimport { buildScalarMap, INTERNAL_SCALARS } from './scalars'\nimport { toSlug, camelToLabel, toPascalCase } from '../naming'\n\n/**\n * Suffixes that identify synthetic/framework types generated by GraphQL servers.\n * Types ending with these suffixes are typically not entities.\n */\nconst SYNTHETIC_SUFFIXES = [\n\t'Connection',\n\t'Edge',\n\t'Input',\n\t'Patch',\n\t'Payload',\n\t'Condition',\n\t'Filter',\n\t'OrderBy',\n\t'Aggregate',\n\t'AggregateResult',\n\t'AggregateFilter',\n\t'DeleteResponse',\n\t'InsertResponse',\n\t'UpdateResponse',\n\t'MutationResponse',\n]\n\n/**\n * Root operation type names that are never entities.\n */\nconst ROOT_TYPE_NAMES = new Set(['Query', 'Mutation', 'Subscription'])\n\n/**\n * Default heuristic to determine if a GraphQL object type represents an entity.\n * An entity type becomes a Stonecrop doctype.\n *\n * This heuristic excludes:\n * - Introspection types (`__*`)\n * - Root operation types (`Query`, `Mutation`, `Subscription`)\n * - Types with synthetic suffixes (e.g., `*Connection`, `*Edge`, `*Input`)\n * - Types starting with `Node` interface marker (exact match only)\n *\n * @param typeName - The GraphQL type name\n * @param type - The GraphQL object type definition\n * @returns `true` if this type should become a Stonecrop doctype\n * @public\n */\nexport function defaultIsEntityType(typeName: string, type: GraphQLObjectType): boolean {\n\t// Exclude introspection types\n\tif (typeName.startsWith('__')) {\n\t\treturn false\n\t}\n\n\t// Exclude root operation types\n\tif (ROOT_TYPE_NAMES.has(typeName)) {\n\t\treturn false\n\t}\n\n\t// Exclude the Node interface marker type\n\tif (typeName === 'Node') {\n\t\treturn false\n\t}\n\n\t// Exclude types matching synthetic suffixes\n\tfor (const suffix of SYNTHETIC_SUFFIXES) {\n\t\tif (typeName.endsWith(suffix)) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\t// Must have at least one field\n\tconst fields = type.getFields()\n\tif (Object.keys(fields).length === 0) {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n/**\n * Fields to skip by default on entity types.\n * These are internal to GraphQL servers and don't represent semantic data.\n */\nconst SKIP_FIELDS = new Set(['nodeId', '__typename', 'clientMutationId'])\n\n/**\n * Default heuristic to filter fields on entity types.\n * Skips internal fields that don't represent meaningful data.\n *\n * @param fieldName - The GraphQL field name\n * @param _field - The GraphQL field definition (unused in default implementation)\n * @param _parentType - The parent entity type (unused in default implementation)\n * @returns `true` if this field should be included\n * @public\n */\nexport function defaultIsEntityField(\n\tfieldName: string,\n\t_field: GraphQLField<unknown, unknown>,\n\t_parentType: GraphQLObjectType\n): boolean {\n\treturn !SKIP_FIELDS.has(fieldName)\n}\n\n/**\n * Unwrap NonNull and List wrappers from a GraphQL type, tracking nullability.\n *\n * @param type - The GraphQL output type\n * @returns The unwrapped named type, whether it's required, and whether it's a list\n * @internal\n */\nfunction unwrapType(type: GraphQLOutputType): {\n\tnamedType: GraphQLNamedType\n\trequired: boolean\n\tisList: boolean\n} {\n\tlet required = false\n\tlet isList = false\n\tlet current: GraphQLOutputType = type\n\n\t// Unwrap outer NonNull\n\tif (isNonNullType(current)) {\n\t\trequired = true\n\t\tcurrent = current.ofType\n\t}\n\n\t// Unwrap List\n\tif (isListType(current)) {\n\t\tisList = true\n\t\tcurrent = current.ofType\n\n\t\t// Unwrap inner NonNull (e.g., [Type!])\n\t\tif (isNonNullType(current)) {\n\t\t\tcurrent = current.ofType\n\t\t}\n\t}\n\n\t// At this point, current should be a named type (scalar, enum, or object)\n\tif (!isNamedType(current)) {\n\t\tthrow new Error(`Expected a named GraphQL type, got: ${String(current)}`)\n\t}\n\treturn { namedType: current, required, isList }\n}\n\n/**\n * Check if a GraphQL object type looks like a Relay Connection type.\n * A connection type has an `edges` field returning a list of edge types,\n * where each edge has a `node` field.\n *\n * @param type - The GraphQL object type to check\n * @returns The node type name if this is a connection, or `undefined`\n * @internal\n */\nfunction getConnectionNodeType(type: GraphQLObjectType): string | undefined {\n\tconst fields = type.getFields()\n\n\t// Must have an 'edges' field\n\tconst edgesField = fields['edges']\n\tif (!edgesField) return undefined\n\n\t// edges must be a list\n\tconst { namedType: edgesType, isList: edgesIsList } = unwrapType(edgesField.type)\n\tif (!edgesIsList || !isObjectType(edgesType)) return undefined\n\n\t// Each edge must have a 'node' field\n\tconst edgeFields = edgesType.getFields()\n\tconst nodeField = edgeFields['node']\n\tif (!nodeField) return undefined\n\n\tconst { namedType: nodeType } = unwrapType(nodeField.type)\n\tif (!isObjectType(nodeType)) return undefined\n\n\treturn nodeType.name\n}\n\n/**\n * Classify a single GraphQL field into a Stonecrop field definition.\n *\n * Classification rules (in order):\n * 1. Scalar types → look up in merged scalar map\n * 2. Enum types → `Select` with enum values as options\n * 3. Object types that are entities → `Link` with slug as options\n * 4. Object types that are Connections → `Doctype` with node type slug as options\n * 5. List of entity type → `Doctype` with item type slug as options\n * 6. Anything else → `Data` with `_unmapped: true`\n *\n * @param fieldName - The GraphQL field name\n * @param field - The GraphQL field definition\n * @param entityTypes - Set of type names classified as entities\n * @param options - Conversion options (for custom scalars, unmapped meta, etc.)\n * @returns The Stonecrop field definition\n * @public\n */\nexport function classifyFieldType(\n\tfieldName: string,\n\tfield: GraphQLField<unknown, unknown>,\n\tentityTypes: Set<string>,\n\toptions: GraphQLConversionOptions = {}\n): GraphQLConversionFieldMeta {\n\tconst { namedType, required, isList } = unwrapType(field.type)\n\tconst scalarMap = buildScalarMap(options.customScalars)\n\n\tconst base: GraphQLConversionFieldMeta = {\n\t\tkind: 'field',\n\t\tfieldname: fieldName,\n\t\tlabel: camelToLabel(fieldName),\n\t\tcomponent: 'ATextInput',\n\t}\n\n\tif (required) {\n\t\tbase.required = true\n\t}\n\n\t// 1. Scalar types\n\tif (isScalarType(namedType)) {\n\t\t// Skip internal scalars (e.g., Cursor)\n\t\tif (INTERNAL_SCALARS.has(namedType.name)) {\n\t\t\tbase._unmapped = true\n\t\t\tif (options.includeUnmappedMeta) {\n\t\t\t\tbase._graphqlType = namedType.name\n\t\t\t}\n\t\t\treturn base\n\t\t}\n\n\t\t// Special case: ID fields that reference an entity type → Link\n\t\tif (namedType.name === 'ID') {\n\t\t\tconst candidateTypeName = toPascalCase(fieldName)\n\t\t\tif (entityTypes.has(candidateTypeName)) {\n\t\t\t\tbase.component = 'AFormLink'\n\t\t\t\tbase.doctype = toSlug(candidateTypeName)\n\t\t\t\treturn base\n\t\t\t}\n\t\t}\n\n\t\tconst template: FieldTemplate | undefined = scalarMap[namedType.name]\n\t\tif (template) {\n\t\t\tbase.component = template.component\n\t\t} else {\n\t\t\t// Unknown scalar — default to Data with unmapped marker\n\t\t\tbase._unmapped = true\n\t\t\tif (options.includeUnmappedMeta) {\n\t\t\t\tbase._graphqlType = namedType.name\n\t\t\t}\n\t\t}\n\t\treturn base\n\t}\n\n\t// 2. Enum types → Select\n\tif (isEnumType(namedType)) {\n\t\tbase.component = 'ADropdown'\n\t\tbase.options = namedType.getValues().map(v => v.name)\n\t\treturn base\n\t}\n\n\t// 3–5. Object types\n\tif (isObjectType(namedType)) {\n\t\t// 3. Direct reference to an entity type → Link\n\t\tif (!isList && entityTypes.has(namedType.name)) {\n\t\t\tbase.component = 'AFormLink'\n\t\t\tbase.doctype = toSlug(namedType.name)\n\t\t\treturn base\n\t\t}\n\n\t\t// 4. Connection type → link (child table)\n\t\tconst connectionNodeTypeName = getConnectionNodeType(namedType)\n\t\tif (connectionNodeTypeName && entityTypes.has(connectionNodeTypeName)) {\n\t\t\tbase.component = 'ATable'\n\t\t\tbase._isLink = true\n\t\t\tbase.doctype = toSlug(connectionNodeTypeName)\n\t\t\tbase.cardinality = 'noneOrMany'\n\t\t\treturn base\n\t\t}\n\n\t\t// 5. List of entity type → link\n\t\tif (isList && entityTypes.has(namedType.name)) {\n\t\t\tbase.component = 'ATable'\n\t\t\tbase._isLink = true\n\t\t\tbase.doctype = toSlug(namedType.name)\n\t\t\tbase.cardinality = 'noneOrMany'\n\t\t\treturn base\n\t\t}\n\n\t\t// Unknown object type — mark as unmapped\n\t\tbase._unmapped = true\n\t\tif (options.includeUnmappedMeta) {\n\t\t\tbase._graphqlType = namedType.name\n\t\t}\n\t\treturn base\n\t}\n\n\t// Fallback — shouldn't normally be reached\n\tbase._unmapped = true\n\tif (options.includeUnmappedMeta) {\n\t\tbase._graphqlType = namedType.name\n\t}\n\treturn base\n}\n","/**\n * GraphQL Introspection to Stonecrop Schema Converter\n *\n * Converts a standard GraphQL introspection result (or SDL string) into\n * Stonecrop doctype schemas. Source-agnostic — works with any GraphQL server.\n *\n * @packageDocumentation\n */\n\nimport { buildClientSchema, buildSchema, isObjectType, type GraphQLSchema } from 'graphql'\n\nimport type { LinkDeclaration } from '../doctype'\nimport { toSlug } from '../naming'\nimport type { IntrospectionSource, GraphQLConversionOptions, ConvertedGraphQLDoctype } from './types'\nimport type { ValueField } from '../field'\nimport { defaultIsEntityType, defaultIsEntityField, classifyFieldType } from './heuristics'\n\n/**\n * Convert a GraphQL schema to Stonecrop doctype schemas.\n *\n * Accepts either an `IntrospectionQuery` result object or an SDL string.\n * Entity types are identified using heuristics (or a custom `isEntityType` function)\n * and converted to `DoctypeMeta`-compatible JSON objects.\n *\n * @param source - GraphQL introspection result or SDL string\n * @param options - Conversion options for controlling output format and behavior\n * @returns Array of converted Stonecrop doctype definitions\n *\n * @example\n * ```typescript\n * // From introspection result (fetched from any GraphQL server)\n * const introspection = await fetchIntrospection('http://localhost:5000/graphql')\n * const doctypes = convertGraphQLSchema(introspection)\n *\n * // From SDL string\n * const sdl = fs.readFileSync('schema.graphql', 'utf-8')\n * const doctypes = convertGraphQLSchema(sdl)\n *\n * // With PostGraphile custom scalars\n * const doctypes = convertGraphQLSchema(introspection, {\n * customScalars: {\n * BigFloat: { component: 'ANumericInput' }\n * }\n * })\n * ```\n *\n * @public\n */\nexport function convertGraphQLSchema(\n\tsource: IntrospectionSource,\n\toptions: GraphQLConversionOptions = {}\n): ConvertedGraphQLDoctype[] {\n\tconst schema = buildGraphQLSchema(source)\n\tconst typeMap = schema.getTypeMap()\n\n\t// Determine the root operation type names to exclude\n\tconst rootTypeNames = new Set<string>()\n\tconst queryType = schema.getQueryType()\n\tconst mutationType = schema.getMutationType()\n\tconst subscriptionType = schema.getSubscriptionType()\n\tif (queryType) rootTypeNames.add(queryType.name)\n\tif (mutationType) rootTypeNames.add(mutationType.name)\n\tif (subscriptionType) rootTypeNames.add(subscriptionType.name)\n\n\t// Use custom or default entity type detector\n\tconst isEntityType = options.isEntityType ?? defaultIsEntityType\n\n\t// Phase 1: Identify all entity types\n\tconst entityTypes = new Set<string>()\n\tfor (const [typeName, type] of Object.entries(typeMap)) {\n\t\tif (!isObjectType(type)) continue\n\n\t\t// Always skip root operation types (even if custom isEntityType doesn't)\n\t\tif (rootTypeNames.has(typeName)) continue\n\n\t\tif (isEntityType(typeName, type)) {\n\t\t\tentityTypes.add(typeName)\n\t\t}\n\t}\n\n\t// Phase 2: Apply include/exclude filters\n\tlet filteredEntityTypes = entityTypes\n\n\tif (options.include) {\n\t\tconst includeSet = new Set(options.include)\n\t\tfilteredEntityTypes = new Set([...entityTypes].filter(t => includeSet.has(t)))\n\t}\n\n\tif (options.exclude) {\n\t\tconst excludeSet = new Set(options.exclude)\n\t\tfilteredEntityTypes = new Set([...filteredEntityTypes].filter(t => !excludeSet.has(t)))\n\t}\n\n\t// Phase 3: Convert each entity type to a doctype\n\tconst isEntityField = options.isEntityField ?? defaultIsEntityField\n\n\tconst doctypes: ConvertedGraphQLDoctype[] = []\n\n\tfor (const typeName of filteredEntityTypes) {\n\t\tconst type = typeMap[typeName]\n\t\tif (!isObjectType(type)) continue\n\n\t\tconst fields = type.getFields()\n\t\tconst typeOverrides = options.typeOverrides?.[typeName]\n\n\t\tconst entityFields = Object.entries(fields).filter(([fieldName, field]) => isEntityField(fieldName, field, type))\n\n\t\t// oxlint-disable-next-line oxc/no-map-spread -- ...custom spread required; Object.assign cannot preserve the metadata-carrying inferred union type from classifyField\n\t\tconst allClassifiedFields = entityFields.map(([fieldName, field]) => {\n\t\t\t// Check for full custom classification first\n\t\t\tif (options.classifyField) {\n\t\t\t\tconst custom = options.classifyField(fieldName, field, type)\n\t\t\t\tif (custom !== null && custom !== undefined) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'field' as const,\n\t\t\t\t\t\tfieldname: fieldName,\n\t\t\t\t\t\tlabel: custom.label ?? fieldName,\n\t\t\t\t\t\tcomponent: custom.component ?? 'ATextInput',\n\t\t\t\t\t\t...custom,\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Default classification\n\t\t\tconst classified = classifyFieldType(fieldName, field, entityTypes, options)\n\n\t\t\t// Apply per-field overrides\n\t\t\tif (typeOverrides?.[fieldName]) {\n\t\t\t\treturn Object.assign(classified, typeOverrides[fieldName])\n\t\t\t}\n\n\t\t\treturn classified\n\t\t})\n\n\t\t// Separate scalar fields from link fields\n\t\tconst links: Record<string, LinkDeclaration> = {}\n\t\tconst convertedFields = allClassifiedFields\n\t\t\t.filter(field => {\n\t\t\t\tif (field._isLink && field.doctype && field.cardinality) {\n\t\t\t\t\tlinks[field.fieldname] = {\n\t\t\t\t\t\ttarget: field.doctype,\n\t\t\t\t\t\tcardinality: field.cardinality,\n\t\t\t\t\t}\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\treturn true\n\t\t\t})\n\t\t\t// Clean up internal metadata unless requested, and stamp provenance.\n\t\t\t// Stamped last so every classification path (default, classifyField,\n\t\t\t// typeOverrides) carries the marker — the docbuilder's identity lock\n\t\t\t// keys off it, and an override must not be able to unset it.\n\t\t\t.map(field => {\n\t\t\t\tif (!options.includeUnmappedMeta) {\n\t\t\t\t\tconst { _graphqlType, _unmapped, _isLink, ...clean } = field\n\t\t\t\t\treturn Object.assign(clean, { source: 'introspected' as const })\n\t\t\t\t}\n\t\t\t\tconst { _isLink, ...rest } = field\n\t\t\t\treturn Object.assign(rest, { source: 'introspected' as const })\n\t\t\t})\n\n\t\tconst doctype: ConvertedGraphQLDoctype = {\n\t\t\tname: typeName,\n\t\t\tslug: toSlug(typeName),\n\t\t\tfields: convertedFields as ValueField[],\n\t\t}\n\n\t\tif (Object.keys(links).length > 0) {\n\t\t\tdoctype.links = links\n\t\t}\n\n\t\tif (options.includeUnmappedMeta) {\n\t\t\tdoctype._graphqlTypeName = typeName\n\t\t}\n\n\t\tdoctypes.push(doctype)\n\t}\n\n\treturn doctypes\n}\n\n/**\n * Build a GraphQLSchema from either an introspection result or SDL string.\n *\n * @param source - IntrospectionQuery object or SDL string\n * @returns A complete GraphQLSchema\n * @internal\n */\nfunction buildGraphQLSchema(source: IntrospectionSource): GraphQLSchema {\n\tif (typeof source === 'string') {\n\t\t// SDL string\n\t\treturn buildSchema(source)\n\t}\n\n\t// IntrospectionQuery result\n\treturn buildClientSchema(source)\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Re-exports\n// ═══════════════════════════════════════════════════════════════\n\n// Main converter (this file)\nexport { convertGraphQLSchema as default }\n\n// Types\nexport type {\n\tIntrospectionSource,\n\tGraphQLConversionOptions,\n\tGraphQLConversionFieldMeta,\n\tConvertedGraphQLDoctype,\n} from './types'\n\n// Scalar maps\nexport { GQL_SCALAR_MAP, WELL_KNOWN_SCALARS, INTERNAL_SCALARS, buildScalarMap } from './scalars'\n\n// Heuristics\nexport { defaultIsEntityType, defaultIsEntityField, classifyFieldType } from './heuristics'\n\n// Naming utilities\nexport { toSlug, toPascalCase, pascalToSnake, snakeToCamel, camelToSnake, snakeToLabel, camelToLabel } from '../naming'\n","import { z } from 'zod'\n\n/**\n * JSON-safe view configuration for table fields in doctype authoring.\n *\n * This is the authoring-time subset of `@stonecrop/atable`'s `TableConfig`. It covers\n * the view discriminator and structural options that can be expressed in static JSON.\n * `rowActions` (which requires function-typed handlers) stays in the runtime `TableConfig`.\n *\n * @public\n */\nexport const TableViewConfig = z\n\t.object({\n\t\t/** The table view type */\n\t\tview: z.enum(['list', 'uncounted', 'list-expansion', 'tree', 'gantt', 'tree-gantt']).optional(),\n\n\t\t/** Allow the table to use the full width of its container */\n\t\tfullWidth: z.boolean().optional(),\n\n\t\t/** Default expansion state for tree views */\n\t\tdefaultTreeExpansion: z.enum(['root', 'branch', 'leaf']).optional(),\n\n\t\t/** Enable dependency graph connections for Gantt views */\n\t\tdependencyGraph: z.boolean().optional(),\n\t})\n\t.meta({\n\t\ttitle: 'TableViewConfig',\n\t\tdescription: 'JSON-safe view configuration for table fields in doctype authoring',\n\t})\n\n/**\n * Table view configuration type inferred from Zod schema\n * @public\n */\nexport type TableViewConfig = z.infer<typeof TableViewConfig>\n","import { z } from 'zod'\n\nimport type { ColumnSchema } from './column-schema'\nimport type { InteractionMode } from './mode'\nimport { TableViewConfig } from './table'\n\n/**\n * Field options - flexible bag for type-specific configuration.\n *\n * Usage:\n * - Select: array of choices ([\"Draft\", \"Submitted\", \"Cancelled\"])\n * - Decimal: config object (\\{ precision: 10, scale: 2 \\})\n * - Code: config object (\\{ language: \"python\" \\})\n *\n * Deliberately *not* a bare string: a string once meant \"link target\", which made the value's\n * shape encode its meaning. That job belongs to `ValueField.doctype`, leaving this a plain\n * choices-or-config bag.\n *\n * @public\n */\nexport const FieldOptions = z\n\t.union([\n\t\tz.array(z.string()), // Select choices: [\"A\", \"B\", \"C\"]\n\t\tz.record(z.string(), z.unknown()), // Config: \\{ precision: 10, scale: 2 \\}\n\t])\n\t.meta({\n\t\ttitle: 'FieldOptions',\n\t\tdescription: 'Field options - flexible bag for type-specific configuration',\n\t})\n\n/**\n * Field options type inferred from Zod schema\n * @public\n */\nexport type FieldOptions = z.infer<typeof FieldOptions>\n\n/**\n * Validation configuration for form fields\n * @public\n */\nexport const FieldValidation = z\n\t.looseObject({\n\t\t/** Error message to display when validation fails */\n\t\terrorMessage: z.string(),\n\t})\n\t.meta({\n\t\ttitle: 'FieldValidation',\n\t\tdescription: 'Validation configuration for form fields',\n\t})\n\n/**\n * Field validation type inferred from Zod schema\n * @public\n */\nexport type FieldValidation = z.infer<typeof FieldValidation>\n\n// ---------------------------------------------------------------------------\n// DoctypeField — the discriminated union of authoring-time field variants\n// ---------------------------------------------------------------------------\n\n/**\n * A field that holds a scalar value, a link to another record, or a select choice.\n * The most common kind of field. `component` determines how it renders; the attributes below\n * carry everything else that is not a rendering concern.\n * @public\n */\nexport interface ValueField {\n\t/** Discriminator — identifies this as a value-holding field */\n\tkind: 'field'\n\t/** Unique identifier for this field within its doctype */\n\tfieldname: string\n\t/**\n\t * Vue component that renders this field — the primary (and only) rendering axis. Required:\n\t * there is nothing left to derive it from, and a field without one has nothing to render it.\n\t * Any string is valid; naming a custom component is how an app renders a field Stonecrop\n\t * ships no widget for. See `CANONICAL_COMPONENTS` for the set Stonecrop provides.\n\t */\n\tcomponent: string\n\t/** True for the field that identifies the record's primary-key column. */\n\tprimaryKey?: boolean\n\t/** True for a computed/display field with no backing DB column — excluded from SQL SELECT. */\n\tcomputed?: boolean\n\t/** Editor language for code fields (e.g. `'json'`, `'typescript'`) — the only thing distinguishing\n\t * a JSON editor from a code editor, since both render with `ACodeEditor`. */\n\tlanguage?: string\n\t/**\n\t * Target doctype slug. Presence is what makes a field a link.\n\t *\n\t * How it renders is decided by `component`, not by this: `AFormLink` renders an\n\t * inline id-picker, while `AForm`/`ATable` expand the target (see `linkRenderMode`). Expansion\n\t * metadata — backlink, fetch strategy, authoritative cardinality — lives in the doctype's\n\t * `links` map, which is additive and never required for a plain foreign key.\n\t */\n\tdoctype?: string\n\t/** Human-readable label */\n\tlabel?: string\n\t/** CSS width (e.g. `\"40ch\"`, `\"200px\"`) */\n\twidth?: string\n\t/** Text alignment */\n\talign?: 'left' | 'center' | 'right' | 'start' | 'end'\n\t/** Whether the field is editable in table cell context */\n\tedit?: boolean\n\t/** Input mask pattern or serialized function */\n\tmask?: string\n\t/** Serialized `(value) => string` function for display formatting — distinct from `mask` (input).\n\t * Spreads through `schemaToColumns` to `ColumnSchema.format`; deserialized at render time by\n\t * ATable's `getFormattedValue`. */\n\tformat?: string\n\t/** Per-field interaction mode override */\n\tmode?: InteractionMode\n\t/** Type-specific options: Select choices, Decimal precision config, etc. A link's target is not\n\t * here — it is `doctype`. */\n\toptions?: FieldOptions\n\t/** Whether the field is required */\n\trequired?: boolean\n\t/** Whether the field is read-only */\n\treadOnly?: boolean\n\t/** Whether the field is hidden from the UI */\n\thidden?: boolean\n\t/** Default value for new records */\n\tdefault?: unknown\n\t/** Validation configuration */\n\tvalidation?: FieldValidation\n\t/** Cardinality for Link fields — authoritative value on LinkDeclaration takes precedence */\n\tcardinality?: 'atMostOne' | 'one' | 'noneOrMany' | 'atLeastOne'\n\t/**\n\t * Provenance marker — stamped only by the GraphQL converter; absence means hand-authored.\n\t * When present, the docbuilder freezes the field's identity set (`fieldname`, `primaryKey`,\n\t * `required`, `options`, `cardinality`, `doctype`), since `fieldname` is the GraphQL/column\n\t * binding and `doctype` is the FK's target. `component` is deliberately **not** frozen: it\n\t * chooses the widget, which is an authoring decision the database has no opinion about.\n\t */\n\tsource?: 'introspected'\n}\n\n/**\n * A layout container that groups other fields. Resolves to a nested AForm.\n * @public\n */\nexport interface FieldsetField {\n\t/** Discriminator — identifies this as a fieldset container */\n\tkind: 'fieldset'\n\t/** Unique identifier for this fieldset within its doctype */\n\tfieldname: string\n\t/** Vue component to render this fieldset. Defaults to `'AFieldset'` in resolveSchema. */\n\tcomponent?: string\n\t/** Human-readable label for the fieldset legend */\n\tlabel?: string\n\t/** Whether the fieldset can be collapsed */\n\tcollapsible?: boolean\n\t/** Interaction mode for all children inside this fieldset */\n\tmode?: InteractionMode\n\t/** Nested field definitions — resolved recursively by resolveSchema */\n\tschema: DoctypeField[]\n}\n\n/**\n * An inline table whose columns are defined directly in the schema (no linked doctype).\n * Use when the table data does not warrant a separate doctype.\n * @public\n */\nexport interface TableField {\n\t/** Discriminator — identifies this as an inline table */\n\tkind: 'table'\n\t/** Unique identifier for this table within its doctype */\n\tfieldname: string\n\t/** Vue component to render this table. Defaults to `'ATable'` in resolveSchema. */\n\tcomponent?: string\n\t/** Human-readable label */\n\tlabel?: string\n\t/** Column definitions — use ColumnSchema (fieldname key) from \\@stonecrop/schema */\n\tcolumns: ColumnSchema[]\n\t/** View configuration — defaults to `{ view: 'list' }` in resolveSchema when absent */\n\tconfig?: TableViewConfig\n\t/** Interaction mode for all cells inside this table */\n\tmode?: InteractionMode\n}\n\n/**\n * Union of all authoring-time field variants.\n * Use `kind` to discriminate: `'field'` | `'fieldset'` | `'table'`.\n * @public\n */\nexport type DoctypeField = ValueField | FieldsetField | TableField\n\n// ---------------------------------------------------------------------------\n// Zod runtime validation schemas\n// ---------------------------------------------------------------------------\n\n/**\n * Infers the `kind` discriminant from the structural properties of a raw field\n * object, then injects it if absent. This allows authored JSON to omit `kind`\n * entirely — a `schema` key means fieldset, `columns` means table, anything else\n * is a value field.\n *\n * Rules (applied in order):\n * has `schema` → fieldset\n * has `columns` → table\n * otherwise → field (value-holding scalar or link)\n *\n * Objects that already carry `kind` pass through unchanged (backward-compatible).\n *\n * Single-node only. Zod applies this at every level of the discriminated union (via the\n * `z.lazy` in the fieldset schema), so nested fieldset children are normalized during a\n * parse. Callers that bypass Zod — notably `Doctype.fromObject` — must use the exported\n * {@link normalizeFieldKind} instead, which replicates that recursion.\n */\nfunction injectKind(data: unknown): unknown {\n\tif (typeof data !== 'object' || data === null || Array.isArray(data)) return data\n\t// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- safe: non-null, non-array object verified by guards above\n\tconst obj = data as Record<string, unknown>\n\tif ('kind' in obj) return data\n\tif ('schema' in obj) return { kind: 'fieldset', ...obj }\n\tif ('columns' in obj) return { kind: 'table', ...obj }\n\treturn { kind: 'field', ...obj }\n}\n\n/**\n * Recursively injects the `kind` discriminant into a raw field object and, for fieldsets,\n * into each of its nested `schema` children — mirroring exactly what Zod's `preprocess`\n * does at every level of the discriminated union.\n *\n * Table `columns` are {@link ColumnSchema} entries, not `DoctypeField`s, so they are left\n * untouched — the Zod table schema validates them with a plain passthrough and never injects\n * `kind` there either.\n *\n * Needed because `Doctype.fromObject` constructs a Doctype without running Zod, yet the\n * registry's `resolveFields` gates link and fieldset handling on `field.kind`. Without this,\n * a JSON-authored link resolves to a flat scalar and a fieldset's children are dropped.\n *\n * @public\n */\nexport function normalizeFieldKind(field: unknown): unknown {\n\tconst injected = injectKind(field)\n\tif (typeof injected !== 'object' || injected === null) return injected\n\t// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- injectKind returns a non-null object for object input; guarded above\n\tconst obj = injected as Record<string, unknown>\n\tif (obj.kind === 'fieldset' && Array.isArray(obj.schema)) {\n\t\treturn { ...obj, schema: obj.schema.map(normalizeFieldKind) }\n\t}\n\treturn injected\n}\n\nfunction createDoctypeFieldSchemas() {\n\tconst ValueFieldSchema = z\n\t\t.object({\n\t\t\tkind: z.literal('field'),\n\t\t\tfieldname: z.string().min(1),\n\t\t\tcomponent: z.string().min(1),\n\t\t\tprimaryKey: z.boolean().optional(),\n\t\t\tcomputed: z.boolean().optional(),\n\t\t\tlanguage: z.string().optional(),\n\t\t\tdoctype: z.string().min(1).optional(),\n\t\t\tlabel: z.string().optional(),\n\t\t\twidth: z.string().optional(),\n\t\t\talign: z.enum(['left', 'center', 'right', 'start', 'end']).optional(),\n\t\t\tedit: z.boolean().optional(),\n\t\t\tmask: z.string().optional(),\n\t\t\tformat: z.string().optional(),\n\t\t\tmode: z.enum(['edit', 'read', 'display']).optional(),\n\t\t\toptions: FieldOptions.optional(),\n\t\t\trequired: z.boolean().optional(),\n\t\t\treadOnly: z.boolean().optional(),\n\t\t\thidden: z.boolean().optional(),\n\t\t\tdefault: z.unknown().optional(),\n\t\t\tvalidation: FieldValidation.optional(),\n\t\t\tcardinality: z.enum(['atMostOne', 'one', 'noneOrMany', 'atLeastOne']).optional(),\n\t\t\tsource: z.literal('introspected').optional(),\n\t\t})\n\t\t.meta({ title: 'ValueField' })\n\n\tconst TableFieldSchema = z\n\t\t.object({\n\t\t\tkind: z.literal('table'),\n\t\t\tfieldname: z.string().min(1),\n\t\t\tcomponent: z.string().optional(),\n\t\t\tlabel: z.string().optional(),\n\t\t\t// Validates that each column has fieldname; allows all other ColumnSchema properties\n\t\t\tcolumns: z.array(z.object({ fieldname: z.string().min(1) }).passthrough()),\n\t\t\tconfig: TableViewConfig.optional(),\n\t\t\tmode: z.enum(['edit', 'read', 'display']).optional(),\n\t\t})\n\t\t.meta({ title: 'TableField' })\n\n\t// DoctypeFieldSchema must be declared before FieldsetFieldSchema so the z.lazy\n\t// callback can close over it. The placeholder is overwritten below; the callback\n\t// only runs at parse time, after the real discriminated union is assigned.\n\t// See: https://zod.dev/api?id=discriminated-unions#discriminated-unions\n\t// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- required by Zod's recursive schema pattern; z.never() placeholder is overwritten before any parse call\n\tlet DoctypeFieldSchema: z.ZodType<DoctypeField> = z.never() as unknown as z.ZodType<DoctypeField>\n\n\t// FieldsetFieldSchema stays as a plain ZodObject (not z.ZodType<T>) so that\n\t// z.discriminatedUnion can inspect its 'kind' discriminant property.\n\tconst FieldsetFieldSchema = z\n\t\t.object({\n\t\t\tkind: z.literal('fieldset'),\n\t\t\tfieldname: z.string().min(1),\n\t\t\tcomponent: z.string().optional(),\n\t\t\tlabel: z.string().optional(),\n\t\t\tcollapsible: z.boolean().optional(),\n\t\t\tmode: z.enum(['edit', 'read', 'display']).optional(),\n\t\t\tschema: z.lazy(() => DoctypeFieldSchema.array()),\n\t\t})\n\t\t.meta({ title: 'FieldsetField' })\n\n\tconst rawUnion = z.discriminatedUnion('kind', [ValueFieldSchema, FieldsetFieldSchema, TableFieldSchema])\n\n\t// Overwrite the placeholder with the preprocessed schema. Because z.lazy captures\n\t// DoctypeFieldSchema by closure reference, the lazy callback in FieldsetFieldSchema\n\t// will resolve to this preprocessed version — so nested fieldsets also inject `kind`.\n\t// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- ZodPipe output is DoctypeField; same pattern as the z.never() placeholder above\n\tDoctypeFieldSchema = z.preprocess(injectKind, rawUnion) as unknown as z.ZodType<DoctypeField>\n\n\treturn { ValueFieldSchema, TableFieldSchema, FieldsetFieldSchema, DoctypeFieldSchema }\n}\n\nconst schemas = createDoctypeFieldSchemas()\n\n/**\n * Zod runtime validation schema for ValueField.\n * @public\n */\nexport const ValueFieldSchema = schemas.ValueFieldSchema\n\n/**\n * Zod runtime validation schema for FieldsetField.\n * Recursive — FieldsetField.schema is validated against DoctypeFieldSchema.\n * @public\n */\nexport const FieldsetFieldSchema = schemas.FieldsetFieldSchema\n\n/**\n * Zod runtime validation schema for TableField.\n * @public\n */\nexport const TableFieldSchema = schemas.TableFieldSchema\n\n/**\n * Zod runtime validation schema for the DoctypeField discriminated union.\n * Validates all three field variants: `'field'`, `'fieldset'`, `'table'`.\n * @public\n */\nexport const DoctypeFieldSchema = schemas.DoctypeFieldSchema\n","import { z } from 'zod'\n\nimport { DoctypeFieldSchema } from './field'\n\n/**\n * Cardinality for relationship links.\n * @public\n */\nexport const Cardinality = z.enum(['atMostOne', 'one', 'noneOrMany', 'atLeastOne']).meta({\n\ttitle: 'Cardinality',\n\tdescription: 'Cardinality for relationship links between doctypes',\n})\n\n/**\n * Cardinality type inferred from Zod schema\n * @public\n */\nexport type Cardinality = z.infer<typeof Cardinality>\n\n/**\n * Serialized function type - a function serialized to a string.\n * Used for custom fetch handlers.\n * @public\n */\nexport type SerializedFunction = string\n\n/**\n * Sync fetch strategy - data is fetched in the initial query.\n * @public\n */\nexport const SyncFetch = z\n\t.object({\n\t\t/** Fetch method type */\n\t\tmethod: z.literal('sync'),\n\t\t/** Optional limit on number of records to fetch */\n\t\tlimit: z.number().int().positive().optional(),\n\t})\n\t.meta({\n\t\ttitle: 'SyncFetch',\n\t\tdescription: 'Sync fetch strategy - data is fetched in the initial query',\n\t})\n\n/**\n * Sync fetch strategy type\n * @public\n */\nexport type SyncFetch = z.infer<typeof SyncFetch>\n\n/**\n * Lazy fetch strategy - data is fetched on demand in a separate query.\n * @public\n */\nexport const LazyFetch = z\n\t.object({\n\t\t/** Fetch method type */\n\t\tmethod: z.literal('lazy'),\n\t})\n\t.meta({\n\t\ttitle: 'LazyFetch',\n\t\tdescription: 'Lazy fetch strategy - data is fetched on demand in a separate query',\n\t})\n\n/**\n * Lazy fetch strategy type\n * @public\n */\nexport type LazyFetch = z.infer<typeof LazyFetch>\n\n/**\n * Custom fetch strategy - uses a custom handler function.\n * @public\n */\nexport const CustomFetch = z\n\t.object({\n\t\t/** Fetch method type */\n\t\tmethod: z.literal('custom'),\n\t\t/** Serialized handler function to invoke */\n\t\thandler: z.string(),\n\t})\n\t.meta({\n\t\ttitle: 'CustomFetch',\n\t\tdescription: 'Custom fetch strategy - uses a custom handler function',\n\t})\n\n/**\n * Custom fetch strategy type\n * @public\n */\nexport type CustomFetch = z.infer<typeof CustomFetch>\n\n/**\n * Fetch strategy for link data loading.\n * - sync: fetched in the initial query\n * - lazy: fetched on demand in a separate query\n * - custom: uses a custom handler function\n * @public\n */\nexport const FetchStrategy = z.discriminatedUnion('method', [SyncFetch, LazyFetch, CustomFetch]).meta({\n\ttitle: 'FetchStrategy',\n\tdescription: 'Fetch strategy for link data loading',\n})\n\n/**\n * Fetch strategy type\n * @public\n */\nexport type FetchStrategy = z.infer<typeof FetchStrategy>\n\n/**\n * Link declaration - describes a relationship from one doctype to another.\n * @public\n */\nexport const LinkDeclaration = z\n\t.object({\n\t\t/** Target doctype slug */\n\t\ttarget: z.string().min(1),\n\n\t\t/** Cardinality of the relationship */\n\t\tcardinality: Cardinality,\n\n\t\t/** Backlink fieldname on the target doctype that points back to this link */\n\t\tbacklink: z.string().optional(),\n\n\t\t/** Override default rendering component (AForm for 1:1, ATable for 1:many) */\n\t\tcomponent: z.string().optional(),\n\n\t\t/** Fieldname of the corresponding Link field in the fields array */\n\t\tfieldname: z.string().min(1).optional(),\n\n\t\t/** Fetch strategy for loading nested data */\n\t\tfetch: FetchStrategy.optional(),\n\n\t\t/** Whether to block workflow actions until nested data is loaded (default: true) */\n\t\tblockWorkflows: z.boolean().optional(),\n\t})\n\t.meta({\n\t\ttitle: 'LinkDeclaration',\n\t\tdescription: 'Declares a relationship from one doctype to another',\n\t})\n\n/**\n * Link declaration type inferred from Zod schema\n * @public\n */\nexport type LinkDeclaration = z.infer<typeof LinkDeclaration>\n\n/**\n * Action definition within a workflow\n * @public\n */\nexport const ActionDefinition = z\n\t.object({\n\t\t/** Display label for the action */\n\t\tlabel: z.string().min(1),\n\n\t\t/** Fields that must have values before action can execute */\n\t\trequiredFields: z.array(z.string()).optional(),\n\n\t\t/** Workflow states where this action is available */\n\t\tallowedStates: z.array(z.string()).optional(),\n\n\t\t/** The state the record transitions to after this action executes */\n\t\tnextState: z.string().optional(),\n\n\t\t/** True for stateless command actions with no workflow effect at all (print, email, etc.) */\n\t\tstateless: z.boolean().optional(),\n\n\t\t/**\n\t\t * True for an internal self-transition: the action runs within the current state without\n\t\t * advancing the workflow (e.g. `save`, which mutates record data but stays put). Scoped by\n\t\t * `allowedStates`, rendered as a self-loop in the graph, and has no `nextState`. Distinct from\n\t\t * `stateless` (which has no workflow presence at all): a self-transition is graph-owned and,\n\t\t * unlike a stateless command, persists record data on dispatch.\n\t\t */\n\t\tselfTransition: z.boolean().optional(),\n\n\t\t/** JS function body stored as a string; executed client-side via AsyncFunction with injected API surface */\n\t\tclientHandler: z.string().optional(),\n\t})\n\t.meta({\n\t\ttitle: 'ActionDefinition',\n\t\tdescription: 'Action definition within a workflow',\n\t})\n\n/**\n * Action definition type inferred from Zod schema\n * @public\n */\nexport type ActionDefinition = z.infer<typeof ActionDefinition>\n\n/**\n * Reactive field-validation trigger — advisory, client-side only.\n *\n * A Trigger is a docbuilder-authored validator: when any field in `on` is edited, its\n * `clientHandler` runs (client-side, no rollback) and may flag a field inline to block save\n * in the UI. It is deliberately a **sibling** to {@link (ActionDefinition:type)}, not a member of it —\n * a reactive validator is not a user-invoked action, so it lives in the `triggers` map on\n * {@link (WorkflowMeta:type)} and never appears to action readers (transition/command dropdowns, the FSM graph).\n *\n * The two bindings are independent: `on` is the fire-set (which fields' edits run it), while the\n * `setError(field, msg)` call inside `clientHandler` chooses which field displays the error.\n * @public\n */\nexport const TriggerDefinition = z\n\t.object({\n\t\t/** Optional display label; the map key is the trigger's identity */\n\t\tlabel: z.string().optional(),\n\n\t\t/** Fieldnames whose edits fire this trigger (fires when any listed field changes) */\n\t\ton: z.array(z.string()),\n\n\t\t/** JS function body stored as a string; run client-side with `{ record, value, setError }`. Advisory. */\n\t\tclientHandler: z.string(),\n\t})\n\t.meta({\n\t\ttitle: 'TriggerDefinition',\n\t\tdescription: 'Reactive field-validation trigger — advisory client-side',\n\t})\n\n/**\n * Trigger definition type inferred from Zod schema\n * @public\n */\nexport type TriggerDefinition = z.infer<typeof TriggerDefinition>\n\n/**\n * Whether a workflow action may run from `currentState`.\n *\n * Single source of truth for the \"is this action available here\" rule, shared by\n * the frontend (`getAvailableTransitions`) and the server-side dispatch guard so\n * the two can never disagree. Empty or absent `allowedStates` means the action is\n * available in ALL states — a plain `allowedStates.includes(currentState)` would\n * wrongly block such actions everywhere.\n *\n * @public\n */\nexport function isActionAllowedInState(action: { allowedStates?: string[] | null }, currentState: string): boolean {\n\tconst allowedStates = action.allowedStates\n\tif (!allowedStates || allowedStates.length === 0) return true\n\treturn allowedStates.includes(currentState)\n}\n\n/**\n * DocBuilder graph layout — node positions for the workflow-state graph, keyed by state name.\n * Pure authoring view-state: persisted in the doctype JSON so an author's manual arrangement\n * survives reloads, but — exactly like {@link (WorkflowMeta:type)}'s `triggers` — it is client-only\n * and never mirrored into the runtime GraphQL SDL (see the WorkflowMeta type in the host SDLs, which\n * expose only `states`/`actions`). The shape mirrors VueFlow's node fields; `position` is the node's\n * canvas coordinate and `targetPosition`/`sourcePosition` are the handle sides.\n * @public\n */\nexport const WorkflowLayout = z.record(\n\tz.string(),\n\tz.object({\n\t\tposition: z.object({ x: z.number(), y: z.number() }).optional(),\n\t\ttargetPosition: z.enum(['left', 'top', 'right', 'bottom']).optional(),\n\t\tsourcePosition: z.enum(['left', 'top', 'right', 'bottom']).optional(),\n\t})\n)\n\n/**\n * Workflow layout type inferred from Zod schema\n * @public\n */\nexport type WorkflowLayout = z.infer<typeof WorkflowLayout>\n\n/**\n * Workflow metadata - states and actions for a doctype\n * @public\n */\nexport const WorkflowMeta = z\n\t.object({\n\t\t/** List of workflow states */\n\t\tstates: z.array(z.string()).optional(),\n\n\t\t/** Actions available in this workflow */\n\t\tactions: z.record(z.string(), ActionDefinition).optional(),\n\n\t\t/** Reactive field-validation triggers (advisory, client-side), keyed by trigger name */\n\t\ttriggers: z.record(z.string(), TriggerDefinition).optional(),\n\n\t\t/**\n\t\t * DocBuilder node positions keyed by state name — authoring view-state. Persisted here so a\n\t\t * doctype author's manual graph arrangement survives reloads; like `triggers`, it is client-only\n\t\t * and never enters the runtime GraphQL SDL. See {@link (WorkflowLayout:variable)}.\n\t\t */\n\t\tlayout: WorkflowLayout.optional(),\n\t})\n\t.meta({\n\t\ttitle: 'WorkflowMeta',\n\t\tdescription: 'Workflow metadata - states and actions for a doctype',\n\t})\n\n/**\n * Workflow metadata type inferred from Zod schema\n * @public\n */\nexport type WorkflowMeta = z.infer<typeof WorkflowMeta>\n\n/**\n * Doctype metadata - complete definition of a doctype\n * @public\n */\nexport const DoctypeMeta = z\n\t.object({\n\t\t/** Display name of the doctype */\n\t\tname: z.string().min(1),\n\n\t\t/** URL-friendly slug (kebab-case) */\n\t\tslug: z.string().min(1).optional(),\n\n\t\t/** Field definitions (a link field is one carrying `doctype`) */\n\t\tfields: z.array(DoctypeFieldSchema),\n\n\t\t/** Relationship links to other doctypes */\n\t\tlinks: z.record(z.string(), LinkDeclaration).optional(),\n\n\t\t/** Workflow configuration */\n\t\tworkflow: WorkflowMeta.optional(),\n\n\t\t/** Parent doctype for inheritance */\n\t\tinherits: z.string().optional(),\n\t})\n\t.meta({\n\t\ttitle: 'DoctypeMeta',\n\t\tdescription: 'Doctype metadata - complete definition of a doctype',\n\t})\n\n/**\n * Doctype metadata type inferred from Zod schema\n * @public\n */\nexport type DoctypeMeta = z.infer<typeof DoctypeMeta>\n\n/**\n * Context for identifying what doctype/record we're working with.\n * Used by graphql-middleware and graphql-client to resolve schema metadata.\n * @public\n */\nexport interface DoctypeContext {\n\t/** Doctype name (e.g., 'Task', 'Customer') */\n\tdoctype: string\n\t/** Optional record ID for viewing/editing a specific record */\n\trecordId?: string\n\t/** Additional context properties */\n\t[key: string]: unknown\n}\n\n/**\n * Base interface for doctype metadata passed to DataClient methods.\n * Only requires properties needed for record fetching.\n * @public\n */\nexport interface DoctypeRef {\n\t/** Doctype name (e.g., 'Task', 'Customer') */\n\tname: string\n\t/** URL-friendly slug (e.g., 'task', 'customer') */\n\tslug?: string\n}\n\n/**\n * Options for fetching a single record\n * @public\n */\nexport interface GetRecordOptions {\n\t/**\n\t * Include nested link sub-selections.\n\t * - `true`: include all descendant links\n\t * - `string[]`: include only named links\n\t * - `false` / omitted: scalar fields only (default)\n\t */\n\tincludeNested?: boolean | string[]\n\n\t/**\n\t * Maximum depth for recursive sub-selections.\n\t * No default — unlimited when omitted.\n\t */\n\tmaxDepth?: number\n}\n\n/**\n * Options for fetching multiple records\n * @public\n */\nexport interface GetRecordsOptions {\n\t/** Filter expression (field-value pairs) */\n\tfilters?: Record<string, unknown>\n\t/** Order by expression (e.g. 'NAME_ASC') */\n\torderBy?: string\n\t/** Maximum number of records to return */\n\tlimit?: number\n\t/** Number of records to skip */\n\toffset?: number\n}\n\n/**\n * Result from getRecord - includes the record data\n * @public\n */\nexport interface GetRecordResult {\n\t/** The record data, or null if not found */\n\trecord: Record<string, unknown> | null\n}\n\n/**\n * Interface for data clients that fetch doctype metadata and records.\n * Implemented by \\@stonecrop/graphql-client's StonecropClient.\n * Custom implementations can use any backend (REST, local storage, etc.).\n *\n * @typeParam T - Doctype reference type for record operations (defaults to DoctypeRef)\n * @typeParam M - Doctype metadata return type for getMeta (defaults to DoctypeMeta)\n * @public\n */\nexport interface DataClient<T extends DoctypeRef = DoctypeRef, M = DoctypeMeta> {\n\t/**\n\t * Fetch doctype metadata\n\t * @param context - Doctype context identifying the doctype\n\t * @returns Doctype metadata or null if not found\n\t */\n\tgetMeta(context: DoctypeContext): Promise<M | null>\n\n\t/**\n\t * Fetch a single record by ID\n\t *\n\t * When `includeNested` is set, builds a query with sub-selections for descendant\n\t * links and returns ancestor + merged descendants. When omitted, returns flat scalar data.\n\t *\n\t * @param doctype - Doctype reference (name and optional slug)\n\t * @param recordId - Record ID to fetch\n\t * @param options - Query options\n\t * @returns Record data wrapped in GetRecordResult\n\t */\n\tgetRecord(doctype: T, recordId: string, options?: GetRecordOptions): Promise<GetRecordResult>\n\n\t/**\n\t * Fetch multiple records\n\t * @param doctype - Doctype reference (name and optional slug)\n\t * @param options - Query options\n\t * @returns Array of record data\n\t */\n\tgetRecords(doctype: T, options?: GetRecordsOptions): Promise<Record<string, unknown>[]>\n\n\t/**\n\t * Execute a doctype action (e.g., SUBMIT, APPROVE, save).\n\t * All state changes flow through this single mutation endpoint.\n\t *\n\t * @param doctype - Doctype reference (name and optional slug)\n\t * @param action - Action name to execute (e.g., 'SUBMIT', 'APPROVE', 'save')\n\t * @param args - Action arguments (typically record ID and/or form data)\n\t * @returns Action result with success status, response data, and any error\n\t */\n\trunAction(\n\t\tdoctype: T,\n\t\taction: string,\n\t\targs?: unknown[]\n\t): Promise<{ success: boolean; data: unknown; error: string | null }>\n}\n","import { DoctypeFieldSchema } from './field'\nimport { DoctypeMeta } from './doctype'\n\n/**\n * Validation error with path information\n * @public\n */\nexport interface ValidationError {\n\t/** Path to the invalid property */\n\tpath: PropertyKey[]\n\n\t/** Error message */\n\tmessage: string\n}\n\n/**\n * Result of a validation operation\n * @public\n */\nexport interface ValidationResult {\n\t/** Whether validation passed */\n\tsuccess: boolean\n\n\t/** List of validation errors (empty if success) */\n\terrors: ValidationError[]\n}\n\n/**\n * Validate a field definition against the DoctypeField discriminated union\n * @param data - Data to validate\n * @returns Validation result\n * @public\n */\nexport function validateField(data: unknown): ValidationResult {\n\tconst result = DoctypeFieldSchema.safeParse(data)\n\n\tif (result.success) {\n\t\treturn { success: true, errors: [] }\n\t}\n\n\treturn {\n\t\tsuccess: false,\n\t\terrors: result.error.issues.map(issue => ({\n\t\t\tpath: issue.path,\n\t\t\tmessage: issue.message,\n\t\t})),\n\t}\n}\n\n/**\n * Validate a doctype definition\n * @param data - Data to validate\n * @returns Validation result\n * @public\n */\nexport function validateDoctype(data: unknown): ValidationResult {\n\tconst result = DoctypeMeta.safeParse(data)\n\n\tif (result.success) {\n\t\treturn { success: true, errors: [] }\n\t}\n\n\treturn {\n\t\tsuccess: false,\n\t\terrors: result.error.issues.map(issue => ({\n\t\t\tpath: issue.path,\n\t\t\tmessage: issue.message,\n\t\t})),\n\t}\n}\n\n/**\n * Parse and validate a field, throwing on failure\n * @param data - Data to parse\n * @returns Validated DoctypeField\n * @throws ZodError if validation fails\n * @public\n */\nexport function parseField(data: unknown): import('./field').DoctypeField {\n\treturn DoctypeFieldSchema.parse(data)\n}\n\n/**\n * Parse and validate a doctype, throwing on failure\n * @param data - Data to parse\n * @returns Validated DoctypeMeta\n * @throws ZodError if validation fails\n * @public\n */\nexport function parseDoctype(data: unknown): DoctypeMeta {\n\treturn DoctypeMeta.parse(data)\n}\n\n// Re-export types for convenience\nexport type { DoctypeField, ValueField, FieldsetField, TableField } from './field'\nexport type { DoctypeMeta } from './doctype'\n"],"names":["snakeToCamel","snakeCase","_","letter","camelToSnake","camelCase","snakeToLabel","word","camelToLabel","withSpaces","toPascalCase","tableName","toSlug","name","pascalToSnake","pascal","GQL_SCALAR_MAP","WELL_KNOWN_SCALARS","INTERNAL_SCALARS","buildScalarMap","customScalars","merged","key","value","SYNTHETIC_SUFFIXES","ROOT_TYPE_NAMES","defaultIsEntityType","typeName","type","suffix","fields","SKIP_FIELDS","defaultIsEntityField","fieldName","_field","_parentType","unwrapType","required","isList","current","isNonNullType","isListType","isNamedType","getConnectionNodeType","edgesField","edgesType","edgesIsList","isObjectType","nodeField","nodeType","classifyFieldType","field","entityTypes","options","namedType","scalarMap","base","isScalarType","candidateTypeName","template","isEnumType","v","connectionNodeTypeName","convertGraphQLSchema","source","schema","buildGraphQLSchema","typeMap","rootTypeNames","queryType","mutationType","subscriptionType","isEntityType","filteredEntityTypes","includeSet","t","excludeSet","isEntityField","doctypes","typeOverrides","allClassifiedFields","custom","classified","links","convertedFields","_graphqlType","_unmapped","_isLink","clean","rest","doctype","buildSchema","buildClientSchema","TableViewConfig","z","FieldOptions","FieldValidation","injectKind","data","obj","normalizeFieldKind","injected","createDoctypeFieldSchemas","ValueFieldSchema","TableFieldSchema","DoctypeFieldSchema","FieldsetFieldSchema","rawUnion","schemas","Cardinality","SyncFetch","LazyFetch","CustomFetch","FetchStrategy","LinkDeclaration","ActionDefinition","TriggerDefinition","isActionAllowedInState","action","currentState","allowedStates","WorkflowLayout","WorkflowMeta","DoctypeMeta","validateField","result","issue","validateDoctype","parseField","parseDoctype"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stonecrop/schema",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.4",
|
|
4
4
|
"description": "Stonecrop schema definitions and validation tooling",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"stonecrop-rig": "0.7.0"
|
|
41
41
|
},
|
|
42
42
|
"scripts": {
|
|
43
|
-
"_phase:build": "heft build && vite build && rushx docs",
|
|
44
|
-
"build": "heft build && vite build && rushx docs",
|
|
43
|
+
"_phase:build": "heft build --clean && vite build && rushx docs",
|
|
44
|
+
"build": "heft build --clean && vite build && rushx docs",
|
|
45
45
|
"docs": "bash ../common/scripts/run-docs.sh schema",
|
|
46
46
|
"lint": "oxlint",
|
|
47
47
|
"lint:fix": "oxlint --fix",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-rozX0Luh.js","sources":["../src/table.ts","../src/field.ts","../src/doctype.ts","../src/validation.ts","../src/naming.ts","../src/converter/scalars.ts","../src/converter/heuristics.ts","../src/converter/index.ts"],"sourcesContent":["import { z } from 'zod'\n\n/**\n * JSON-safe view configuration for table fields in doctype authoring.\n *\n * This is the authoring-time subset of `@stonecrop/atable`'s `TableConfig`. It covers\n * the view discriminator and structural options that can be expressed in static JSON.\n * `rowActions` (which requires function-typed handlers) stays in the runtime `TableConfig`.\n *\n * @public\n */\nexport const TableViewConfig = z\n\t.object({\n\t\t/** The table view type */\n\t\tview: z.enum(['list', 'uncounted', 'list-expansion', 'tree', 'gantt', 'tree-gantt']).optional(),\n\n\t\t/** Allow the table to use the full width of its container */\n\t\tfullWidth: z.boolean().optional(),\n\n\t\t/** Default expansion state for tree views */\n\t\tdefaultTreeExpansion: z.enum(['root', 'branch', 'leaf']).optional(),\n\n\t\t/** Enable dependency graph connections for Gantt views */\n\t\tdependencyGraph: z.boolean().optional(),\n\t})\n\t.meta({\n\t\ttitle: 'TableViewConfig',\n\t\tdescription: 'JSON-safe view configuration for table fields in doctype authoring',\n\t})\n\n/**\n * Table view configuration type inferred from Zod schema\n * @public\n */\nexport type TableViewConfig = z.infer<typeof TableViewConfig>\n","import { z } from 'zod'\n\nimport type { ColumnSchema } from './column-schema'\nimport type { InteractionMode } from './mode'\nimport { TableViewConfig } from './table'\n\n/**\n * Field options - flexible bag for type-specific configuration.\n *\n * Usage:\n * - Select: array of choices ([\"Draft\", \"Submitted\", \"Cancelled\"])\n * - Decimal: config object (\\{ precision: 10, scale: 2 \\})\n * - Code: config object (\\{ language: \"python\" \\})\n *\n * Deliberately *not* a bare string: a string once meant \"link target\", which made the value's\n * shape encode its meaning. That job belongs to `ValueField.doctype`, leaving this a plain\n * choices-or-config bag.\n *\n * @public\n */\nexport const FieldOptions = z\n\t.union([\n\t\tz.array(z.string()), // Select choices: [\"A\", \"B\", \"C\"]\n\t\tz.record(z.string(), z.unknown()), // Config: \\{ precision: 10, scale: 2 \\}\n\t])\n\t.meta({\n\t\ttitle: 'FieldOptions',\n\t\tdescription: 'Field options - flexible bag for type-specific configuration',\n\t})\n\n/**\n * Field options type inferred from Zod schema\n * @public\n */\nexport type FieldOptions = z.infer<typeof FieldOptions>\n\n/**\n * Validation configuration for form fields\n * @public\n */\nexport const FieldValidation = z\n\t.looseObject({\n\t\t/** Error message to display when validation fails */\n\t\terrorMessage: z.string(),\n\t})\n\t.meta({\n\t\ttitle: 'FieldValidation',\n\t\tdescription: 'Validation configuration for form fields',\n\t})\n\n/**\n * Field validation type inferred from Zod schema\n * @public\n */\nexport type FieldValidation = z.infer<typeof FieldValidation>\n\n// ---------------------------------------------------------------------------\n// DoctypeField — the discriminated union of authoring-time field variants\n// ---------------------------------------------------------------------------\n\n/**\n * A field that holds a scalar value, a link to another record, or a select choice.\n * The most common kind of field. `component` determines how it renders; the attributes below\n * carry everything else that is not a rendering concern.\n * @public\n */\nexport interface ValueField {\n\t/** Discriminator — identifies this as a value-holding field */\n\tkind: 'field'\n\t/** Unique identifier for this field within its doctype */\n\tfieldname: string\n\t/**\n\t * Vue component that renders this field — the primary (and only) rendering axis. Required:\n\t * there is nothing left to derive it from, and a field without one has nothing to render it.\n\t * Any string is valid; naming a custom component is how an app renders a field Stonecrop\n\t * ships no widget for. See `CANONICAL_COMPONENTS` for the set Stonecrop provides.\n\t */\n\tcomponent: string\n\t/** True for the field that identifies the record's primary-key column. */\n\tprimaryKey?: boolean\n\t/** True for a computed/display field with no backing DB column — excluded from SQL SELECT. */\n\tcomputed?: boolean\n\t/** Editor language for code fields (e.g. `'json'`, `'typescript'`) — the only thing distinguishing\n\t * a JSON editor from a code editor, since both render with `ACodeEditor`. */\n\tlanguage?: string\n\t/**\n\t * Target doctype slug. Presence is what makes a field a link.\n\t *\n\t * How it renders is decided by `component`, not by this: `AFormLink` renders an\n\t * inline id-picker, while `AForm`/`ATable` expand the target (see `linkRenderMode`). Expansion\n\t * metadata — backlink, fetch strategy, authoritative cardinality — lives in the doctype's\n\t * `links` map, which is additive and never required for a plain foreign key.\n\t */\n\tdoctype?: string\n\t/** Human-readable label */\n\tlabel?: string\n\t/** CSS width (e.g. `\"40ch\"`, `\"200px\"`) */\n\twidth?: string\n\t/** Text alignment */\n\talign?: 'left' | 'center' | 'right' | 'start' | 'end'\n\t/** Whether the field is editable in table cell context */\n\tedit?: boolean\n\t/** Input mask pattern or serialized function */\n\tmask?: string\n\t/** Serialized `(value) => string` function for display formatting — distinct from `mask` (input).\n\t * Spreads through `schemaToColumns` to `ColumnSchema.format`; deserialized at render time by\n\t * ATable's `getFormattedValue`. */\n\tformat?: string\n\t/** Per-field interaction mode override */\n\tmode?: InteractionMode\n\t/** Type-specific options: Select choices, Decimal precision config, etc. A link's target is not\n\t * here — it is `doctype`. */\n\toptions?: FieldOptions\n\t/** Whether the field is required */\n\trequired?: boolean\n\t/** Whether the field is read-only */\n\treadOnly?: boolean\n\t/** Whether the field is hidden from the UI */\n\thidden?: boolean\n\t/** Default value for new records */\n\tdefault?: unknown\n\t/** Validation configuration */\n\tvalidation?: FieldValidation\n\t/** Cardinality for Link fields — authoritative value on LinkDeclaration takes precedence */\n\tcardinality?: 'atMostOne' | 'one' | 'noneOrMany' | 'atLeastOne'\n\t/**\n\t * Provenance marker — stamped only by the GraphQL converter; absence means hand-authored.\n\t * When present, the docbuilder freezes the field's identity set (`fieldname`, `primaryKey`,\n\t * `required`, `options`, `cardinality`, `doctype`), since `fieldname` is the GraphQL/column\n\t * binding and `doctype` is the FK's target. `component` is deliberately **not** frozen: it\n\t * chooses the widget, which is an authoring decision the database has no opinion about.\n\t */\n\tsource?: 'introspected'\n}\n\n/**\n * A layout container that groups other fields. Resolves to a nested AForm.\n * @public\n */\nexport interface FieldsetField {\n\t/** Discriminator — identifies this as a fieldset container */\n\tkind: 'fieldset'\n\t/** Unique identifier for this fieldset within its doctype */\n\tfieldname: string\n\t/** Vue component to render this fieldset. Defaults to `'AFieldset'` in resolveSchema. */\n\tcomponent?: string\n\t/** Human-readable label for the fieldset legend */\n\tlabel?: string\n\t/** Whether the fieldset can be collapsed */\n\tcollapsible?: boolean\n\t/** Interaction mode for all children inside this fieldset */\n\tmode?: InteractionMode\n\t/** Nested field definitions — resolved recursively by resolveSchema */\n\tschema: DoctypeField[]\n}\n\n/**\n * An inline table whose columns are defined directly in the schema (no linked doctype).\n * Use when the table data does not warrant a separate doctype.\n * @public\n */\nexport interface TableField {\n\t/** Discriminator — identifies this as an inline table */\n\tkind: 'table'\n\t/** Unique identifier for this table within its doctype */\n\tfieldname: string\n\t/** Vue component to render this table. Defaults to `'ATable'` in resolveSchema. */\n\tcomponent?: string\n\t/** Human-readable label */\n\tlabel?: string\n\t/** Column definitions — use ColumnSchema (fieldname key) from \\@stonecrop/schema */\n\tcolumns: ColumnSchema[]\n\t/** View configuration — defaults to `{ view: 'list' }` in resolveSchema when absent */\n\tconfig?: TableViewConfig\n\t/** Interaction mode for all cells inside this table */\n\tmode?: InteractionMode\n}\n\n/**\n * Union of all authoring-time field variants.\n * Use `kind` to discriminate: `'field'` | `'fieldset'` | `'table'`.\n * @public\n */\nexport type DoctypeField = ValueField | FieldsetField | TableField\n\n// ---------------------------------------------------------------------------\n// Zod runtime validation schemas\n// ---------------------------------------------------------------------------\n\n/**\n * Infers the `kind` discriminant from the structural properties of a raw field\n * object, then injects it if absent. This allows authored JSON to omit `kind`\n * entirely — a `schema` key means fieldset, `columns` means table, anything else\n * is a value field.\n *\n * Rules (applied in order):\n * has `schema` → fieldset\n * has `columns` → table\n * otherwise → field (value-holding scalar or link)\n *\n * Objects that already carry `kind` pass through unchanged (backward-compatible).\n *\n * Single-node only. Zod applies this at every level of the discriminated union (via the\n * `z.lazy` in the fieldset schema), so nested fieldset children are normalized during a\n * parse. Callers that bypass Zod — notably `Doctype.fromObject` — must use the exported\n * {@link normalizeFieldKind} instead, which replicates that recursion.\n */\nfunction injectKind(data: unknown): unknown {\n\tif (typeof data !== 'object' || data === null || Array.isArray(data)) return data\n\t// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- safe: non-null, non-array object verified by guards above\n\tconst obj = data as Record<string, unknown>\n\tif ('kind' in obj) return data\n\tif ('schema' in obj) return { kind: 'fieldset', ...obj }\n\tif ('columns' in obj) return { kind: 'table', ...obj }\n\treturn { kind: 'field', ...obj }\n}\n\n/**\n * Recursively injects the `kind` discriminant into a raw field object and, for fieldsets,\n * into each of its nested `schema` children — mirroring exactly what Zod's `preprocess`\n * does at every level of the discriminated union.\n *\n * Table `columns` are {@link ColumnSchema} entries, not `DoctypeField`s, so they are left\n * untouched — the Zod table schema validates them with a plain passthrough and never injects\n * `kind` there either.\n *\n * Needed because `Doctype.fromObject` constructs a Doctype without running Zod, yet the\n * registry's `resolveFields` gates link and fieldset handling on `field.kind`. Without this,\n * a JSON-authored link resolves to a flat scalar and a fieldset's children are dropped.\n *\n * @public\n */\nexport function normalizeFieldKind(field: unknown): unknown {\n\tconst injected = injectKind(field)\n\tif (typeof injected !== 'object' || injected === null) return injected\n\t// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- injectKind returns a non-null object for object input; guarded above\n\tconst obj = injected as Record<string, unknown>\n\tif (obj.kind === 'fieldset' && Array.isArray(obj.schema)) {\n\t\treturn { ...obj, schema: obj.schema.map(normalizeFieldKind) }\n\t}\n\treturn injected\n}\n\nfunction createDoctypeFieldSchemas() {\n\tconst ValueFieldSchema = z\n\t\t.object({\n\t\t\tkind: z.literal('field'),\n\t\t\tfieldname: z.string().min(1),\n\t\t\tcomponent: z.string().min(1),\n\t\t\tprimaryKey: z.boolean().optional(),\n\t\t\tcomputed: z.boolean().optional(),\n\t\t\tlanguage: z.string().optional(),\n\t\t\tdoctype: z.string().min(1).optional(),\n\t\t\tlabel: z.string().optional(),\n\t\t\twidth: z.string().optional(),\n\t\t\talign: z.enum(['left', 'center', 'right', 'start', 'end']).optional(),\n\t\t\tedit: z.boolean().optional(),\n\t\t\tmask: z.string().optional(),\n\t\t\tformat: z.string().optional(),\n\t\t\tmode: z.enum(['edit', 'read', 'display']).optional(),\n\t\t\toptions: FieldOptions.optional(),\n\t\t\trequired: z.boolean().optional(),\n\t\t\treadOnly: z.boolean().optional(),\n\t\t\thidden: z.boolean().optional(),\n\t\t\tdefault: z.unknown().optional(),\n\t\t\tvalidation: FieldValidation.optional(),\n\t\t\tcardinality: z.enum(['atMostOne', 'one', 'noneOrMany', 'atLeastOne']).optional(),\n\t\t\tsource: z.literal('introspected').optional(),\n\t\t})\n\t\t.meta({ title: 'ValueField' })\n\n\tconst TableFieldSchema = z\n\t\t.object({\n\t\t\tkind: z.literal('table'),\n\t\t\tfieldname: z.string().min(1),\n\t\t\tcomponent: z.string().optional(),\n\t\t\tlabel: z.string().optional(),\n\t\t\t// Validates that each column has fieldname; allows all other ColumnSchema properties\n\t\t\tcolumns: z.array(z.object({ fieldname: z.string().min(1) }).passthrough()),\n\t\t\tconfig: TableViewConfig.optional(),\n\t\t\tmode: z.enum(['edit', 'read', 'display']).optional(),\n\t\t})\n\t\t.meta({ title: 'TableField' })\n\n\t// DoctypeFieldSchema must be declared before FieldsetFieldSchema so the z.lazy\n\t// callback can close over it. The placeholder is overwritten below; the callback\n\t// only runs at parse time, after the real discriminated union is assigned.\n\t// See: https://zod.dev/api?id=discriminated-unions#discriminated-unions\n\t// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- required by Zod's recursive schema pattern; z.never() placeholder is overwritten before any parse call\n\tlet DoctypeFieldSchema: z.ZodType<DoctypeField> = z.never() as unknown as z.ZodType<DoctypeField>\n\n\t// FieldsetFieldSchema stays as a plain ZodObject (not z.ZodType<T>) so that\n\t// z.discriminatedUnion can inspect its 'kind' discriminant property.\n\tconst FieldsetFieldSchema = z\n\t\t.object({\n\t\t\tkind: z.literal('fieldset'),\n\t\t\tfieldname: z.string().min(1),\n\t\t\tcomponent: z.string().optional(),\n\t\t\tlabel: z.string().optional(),\n\t\t\tcollapsible: z.boolean().optional(),\n\t\t\tmode: z.enum(['edit', 'read', 'display']).optional(),\n\t\t\tschema: z.lazy(() => DoctypeFieldSchema.array()),\n\t\t})\n\t\t.meta({ title: 'FieldsetField' })\n\n\tconst rawUnion = z.discriminatedUnion('kind', [ValueFieldSchema, FieldsetFieldSchema, TableFieldSchema])\n\n\t// Overwrite the placeholder with the preprocessed schema. Because z.lazy captures\n\t// DoctypeFieldSchema by closure reference, the lazy callback in FieldsetFieldSchema\n\t// will resolve to this preprocessed version — so nested fieldsets also inject `kind`.\n\t// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- ZodPipe output is DoctypeField; same pattern as the z.never() placeholder above\n\tDoctypeFieldSchema = z.preprocess(injectKind, rawUnion) as unknown as z.ZodType<DoctypeField>\n\n\treturn { ValueFieldSchema, TableFieldSchema, FieldsetFieldSchema, DoctypeFieldSchema }\n}\n\nconst schemas = createDoctypeFieldSchemas()\n\n/**\n * Zod runtime validation schema for ValueField.\n * @public\n */\nexport const ValueFieldSchema = schemas.ValueFieldSchema\n\n/**\n * Zod runtime validation schema for FieldsetField.\n * Recursive — FieldsetField.schema is validated against DoctypeFieldSchema.\n * @public\n */\nexport const FieldsetFieldSchema = schemas.FieldsetFieldSchema\n\n/**\n * Zod runtime validation schema for TableField.\n * @public\n */\nexport const TableFieldSchema = schemas.TableFieldSchema\n\n/**\n * Zod runtime validation schema for the DoctypeField discriminated union.\n * Validates all three field variants: `'field'`, `'fieldset'`, `'table'`.\n * @public\n */\nexport const DoctypeFieldSchema = schemas.DoctypeFieldSchema\n","import { z } from 'zod'\n\nimport { DoctypeFieldSchema } from './field'\n\n/**\n * Cardinality for relationship links.\n * @public\n */\nexport const Cardinality = z.enum(['atMostOne', 'one', 'noneOrMany', 'atLeastOne']).meta({\n\ttitle: 'Cardinality',\n\tdescription: 'Cardinality for relationship links between doctypes',\n})\n\n/**\n * Cardinality type inferred from Zod schema\n * @public\n */\nexport type Cardinality = z.infer<typeof Cardinality>\n\n/**\n * Serialized function type - a function serialized to a string.\n * Used for custom fetch handlers.\n * @public\n */\nexport type SerializedFunction = string\n\n/**\n * Sync fetch strategy - data is fetched in the initial query.\n * @public\n */\nexport const SyncFetch = z\n\t.object({\n\t\t/** Fetch method type */\n\t\tmethod: z.literal('sync'),\n\t\t/** Optional limit on number of records to fetch */\n\t\tlimit: z.number().int().positive().optional(),\n\t})\n\t.meta({\n\t\ttitle: 'SyncFetch',\n\t\tdescription: 'Sync fetch strategy - data is fetched in the initial query',\n\t})\n\n/**\n * Sync fetch strategy type\n * @public\n */\nexport type SyncFetch = z.infer<typeof SyncFetch>\n\n/**\n * Lazy fetch strategy - data is fetched on demand in a separate query.\n * @public\n */\nexport const LazyFetch = z\n\t.object({\n\t\t/** Fetch method type */\n\t\tmethod: z.literal('lazy'),\n\t})\n\t.meta({\n\t\ttitle: 'LazyFetch',\n\t\tdescription: 'Lazy fetch strategy - data is fetched on demand in a separate query',\n\t})\n\n/**\n * Lazy fetch strategy type\n * @public\n */\nexport type LazyFetch = z.infer<typeof LazyFetch>\n\n/**\n * Custom fetch strategy - uses a custom handler function.\n * @public\n */\nexport const CustomFetch = z\n\t.object({\n\t\t/** Fetch method type */\n\t\tmethod: z.literal('custom'),\n\t\t/** Serialized handler function to invoke */\n\t\thandler: z.string(),\n\t})\n\t.meta({\n\t\ttitle: 'CustomFetch',\n\t\tdescription: 'Custom fetch strategy - uses a custom handler function',\n\t})\n\n/**\n * Custom fetch strategy type\n * @public\n */\nexport type CustomFetch = z.infer<typeof CustomFetch>\n\n/**\n * Fetch strategy for link data loading.\n * - sync: fetched in the initial query\n * - lazy: fetched on demand in a separate query\n * - custom: uses a custom handler function\n * @public\n */\nexport const FetchStrategy = z.discriminatedUnion('method', [SyncFetch, LazyFetch, CustomFetch]).meta({\n\ttitle: 'FetchStrategy',\n\tdescription: 'Fetch strategy for link data loading',\n})\n\n/**\n * Fetch strategy type\n * @public\n */\nexport type FetchStrategy = z.infer<typeof FetchStrategy>\n\n/**\n * Link declaration - describes a relationship from one doctype to another.\n * @public\n */\nexport const LinkDeclaration = z\n\t.object({\n\t\t/** Target doctype slug */\n\t\ttarget: z.string().min(1),\n\n\t\t/** Cardinality of the relationship */\n\t\tcardinality: Cardinality,\n\n\t\t/** Backlink fieldname on the target doctype that points back to this link */\n\t\tbacklink: z.string().optional(),\n\n\t\t/** Override default rendering component (AForm for 1:1, ATable for 1:many) */\n\t\tcomponent: z.string().optional(),\n\n\t\t/** Fieldname of the corresponding Link field in the fields array */\n\t\tfieldname: z.string().min(1).optional(),\n\n\t\t/** Fetch strategy for loading nested data */\n\t\tfetch: FetchStrategy.optional(),\n\n\t\t/** Whether to block workflow actions until nested data is loaded (default: true) */\n\t\tblockWorkflows: z.boolean().optional(),\n\t})\n\t.meta({\n\t\ttitle: 'LinkDeclaration',\n\t\tdescription: 'Declares a relationship from one doctype to another',\n\t})\n\n/**\n * Link declaration type inferred from Zod schema\n * @public\n */\nexport type LinkDeclaration = z.infer<typeof LinkDeclaration>\n\n/**\n * Action definition within a workflow\n * @public\n */\nexport const ActionDefinition = z\n\t.object({\n\t\t/** Display label for the action */\n\t\tlabel: z.string().min(1),\n\n\t\t/** Fields that must have values before action can execute */\n\t\trequiredFields: z.array(z.string()).optional(),\n\n\t\t/** Workflow states where this action is available */\n\t\tallowedStates: z.array(z.string()).optional(),\n\n\t\t/** The state the record transitions to after this action executes */\n\t\tnextState: z.string().optional(),\n\n\t\t/** True for stateless command actions with no workflow effect at all (print, email, etc.) */\n\t\tstateless: z.boolean().optional(),\n\n\t\t/**\n\t\t * True for an internal self-transition: the action runs within the current state without\n\t\t * advancing the workflow (e.g. `save`, which mutates record data but stays put). Scoped by\n\t\t * `allowedStates`, rendered as a self-loop in the graph, and has no `nextState`. Distinct from\n\t\t * `stateless` (which has no workflow presence at all): a self-transition is graph-owned and,\n\t\t * unlike a stateless command, persists record data on dispatch.\n\t\t */\n\t\tselfTransition: z.boolean().optional(),\n\n\t\t/** JS function body stored as a string; executed client-side via AsyncFunction with injected API surface */\n\t\tclientHandler: z.string().optional(),\n\t})\n\t.meta({\n\t\ttitle: 'ActionDefinition',\n\t\tdescription: 'Action definition within a workflow',\n\t})\n\n/**\n * Action definition type inferred from Zod schema\n * @public\n */\nexport type ActionDefinition = z.infer<typeof ActionDefinition>\n\n/**\n * Reactive field-validation trigger — advisory, client-side only.\n *\n * A Trigger is a docbuilder-authored validator: when any field in `on` is edited, its\n * `clientHandler` runs (client-side, no rollback) and may flag a field inline to block save\n * in the UI. It is deliberately a **sibling** to {@link (ActionDefinition:type)}, not a member of it —\n * a reactive validator is not a user-invoked action, so it lives in the `triggers` map on\n * {@link (WorkflowMeta:type)} and never appears to action readers (transition/command dropdowns, the FSM graph).\n *\n * The two bindings are independent: `on` is the fire-set (which fields' edits run it), while the\n * `setError(field, msg)` call inside `clientHandler` chooses which field displays the error.\n * @public\n */\nexport const TriggerDefinition = z\n\t.object({\n\t\t/** Optional display label; the map key is the trigger's identity */\n\t\tlabel: z.string().optional(),\n\n\t\t/** Fieldnames whose edits fire this trigger (fires when any listed field changes) */\n\t\ton: z.array(z.string()),\n\n\t\t/** JS function body stored as a string; run client-side with `{ record, value, setError }`. Advisory. */\n\t\tclientHandler: z.string(),\n\t})\n\t.meta({\n\t\ttitle: 'TriggerDefinition',\n\t\tdescription: 'Reactive field-validation trigger — advisory client-side',\n\t})\n\n/**\n * Trigger definition type inferred from Zod schema\n * @public\n */\nexport type TriggerDefinition = z.infer<typeof TriggerDefinition>\n\n/**\n * Whether a workflow action may run from `currentState`.\n *\n * Single source of truth for the \"is this action available here\" rule, shared by\n * the frontend (`getAvailableTransitions`) and the server-side dispatch guard so\n * the two can never disagree. Empty or absent `allowedStates` means the action is\n * available in ALL states — a plain `allowedStates.includes(currentState)` would\n * wrongly block such actions everywhere.\n *\n * @public\n */\nexport function isActionAllowedInState(action: { allowedStates?: string[] | null }, currentState: string): boolean {\n\tconst allowedStates = action.allowedStates\n\tif (!allowedStates || allowedStates.length === 0) return true\n\treturn allowedStates.includes(currentState)\n}\n\n/**\n * DocBuilder graph layout — node positions for the workflow-state graph, keyed by state name.\n * Pure authoring view-state: persisted in the doctype JSON so an author's manual arrangement\n * survives reloads, but — exactly like {@link (WorkflowMeta:type)}'s `triggers` — it is client-only\n * and never mirrored into the runtime GraphQL SDL (see the WorkflowMeta type in the host SDLs, which\n * expose only `states`/`actions`). The shape mirrors VueFlow's node fields; `position` is the node's\n * canvas coordinate and `targetPosition`/`sourcePosition` are the handle sides.\n * @public\n */\nexport const WorkflowLayout = z.record(\n\tz.string(),\n\tz.object({\n\t\tposition: z.object({ x: z.number(), y: z.number() }).optional(),\n\t\ttargetPosition: z.enum(['left', 'top', 'right', 'bottom']).optional(),\n\t\tsourcePosition: z.enum(['left', 'top', 'right', 'bottom']).optional(),\n\t})\n)\n\n/**\n * Workflow layout type inferred from Zod schema\n * @public\n */\nexport type WorkflowLayout = z.infer<typeof WorkflowLayout>\n\n/**\n * Workflow metadata - states and actions for a doctype\n * @public\n */\nexport const WorkflowMeta = z\n\t.object({\n\t\t/** List of workflow states */\n\t\tstates: z.array(z.string()).optional(),\n\n\t\t/** Actions available in this workflow */\n\t\tactions: z.record(z.string(), ActionDefinition).optional(),\n\n\t\t/** Reactive field-validation triggers (advisory, client-side), keyed by trigger name */\n\t\ttriggers: z.record(z.string(), TriggerDefinition).optional(),\n\n\t\t/**\n\t\t * DocBuilder node positions keyed by state name — authoring view-state. Persisted here so a\n\t\t * doctype author's manual graph arrangement survives reloads; like `triggers`, it is client-only\n\t\t * and never enters the runtime GraphQL SDL. See {@link (WorkflowLayout:variable)}.\n\t\t */\n\t\tlayout: WorkflowLayout.optional(),\n\t})\n\t.meta({\n\t\ttitle: 'WorkflowMeta',\n\t\tdescription: 'Workflow metadata - states and actions for a doctype',\n\t})\n\n/**\n * Workflow metadata type inferred from Zod schema\n * @public\n */\nexport type WorkflowMeta = z.infer<typeof WorkflowMeta>\n\n/**\n * Doctype metadata - complete definition of a doctype\n * @public\n */\nexport const DoctypeMeta = z\n\t.object({\n\t\t/** Display name of the doctype */\n\t\tname: z.string().min(1),\n\n\t\t/** URL-friendly slug (kebab-case) */\n\t\tslug: z.string().min(1).optional(),\n\n\t\t/** Field definitions (a link field is one carrying `doctype`) */\n\t\tfields: z.array(DoctypeFieldSchema),\n\n\t\t/** Relationship links to other doctypes */\n\t\tlinks: z.record(z.string(), LinkDeclaration).optional(),\n\n\t\t/** Workflow configuration */\n\t\tworkflow: WorkflowMeta.optional(),\n\n\t\t/** Parent doctype for inheritance */\n\t\tinherits: z.string().optional(),\n\t})\n\t.meta({\n\t\ttitle: 'DoctypeMeta',\n\t\tdescription: 'Doctype metadata - complete definition of a doctype',\n\t})\n\n/**\n * Doctype metadata type inferred from Zod schema\n * @public\n */\nexport type DoctypeMeta = z.infer<typeof DoctypeMeta>\n\n/**\n * Context for identifying what doctype/record we're working with.\n * Used by graphql-middleware and graphql-client to resolve schema metadata.\n * @public\n */\nexport interface DoctypeContext {\n\t/** Doctype name (e.g., 'Task', 'Customer') */\n\tdoctype: string\n\t/** Optional record ID for viewing/editing a specific record */\n\trecordId?: string\n\t/** Additional context properties */\n\t[key: string]: unknown\n}\n\n/**\n * Base interface for doctype metadata passed to DataClient methods.\n * Only requires properties needed for record fetching.\n * @public\n */\nexport interface DoctypeRef {\n\t/** Doctype name (e.g., 'Task', 'Customer') */\n\tname: string\n\t/** URL-friendly slug (e.g., 'task', 'customer') */\n\tslug?: string\n}\n\n/**\n * Options for fetching a single record\n * @public\n */\nexport interface GetRecordOptions {\n\t/**\n\t * Include nested link sub-selections.\n\t * - `true`: include all descendant links\n\t * - `string[]`: include only named links\n\t * - `false` / omitted: scalar fields only (default)\n\t */\n\tincludeNested?: boolean | string[]\n\n\t/**\n\t * Maximum depth for recursive sub-selections.\n\t * No default — unlimited when omitted.\n\t */\n\tmaxDepth?: number\n}\n\n/**\n * Options for fetching multiple records\n * @public\n */\nexport interface GetRecordsOptions {\n\t/** Filter expression (field-value pairs) */\n\tfilters?: Record<string, unknown>\n\t/** Order by expression (e.g. 'NAME_ASC') */\n\torderBy?: string\n\t/** Maximum number of records to return */\n\tlimit?: number\n\t/** Number of records to skip */\n\toffset?: number\n}\n\n/**\n * Result from getRecord - includes the record data\n * @public\n */\nexport interface GetRecordResult {\n\t/** The record data, or null if not found */\n\trecord: Record<string, unknown> | null\n}\n\n/**\n * Interface for data clients that fetch doctype metadata and records.\n * Implemented by \\@stonecrop/graphql-client's StonecropClient.\n * Custom implementations can use any backend (REST, local storage, etc.).\n *\n * @typeParam T - Doctype reference type for record operations (defaults to DoctypeRef)\n * @typeParam M - Doctype metadata return type for getMeta (defaults to DoctypeMeta)\n * @public\n */\nexport interface DataClient<T extends DoctypeRef = DoctypeRef, M = DoctypeMeta> {\n\t/**\n\t * Fetch doctype metadata\n\t * @param context - Doctype context identifying the doctype\n\t * @returns Doctype metadata or null if not found\n\t */\n\tgetMeta(context: DoctypeContext): Promise<M | null>\n\n\t/**\n\t * Fetch a single record by ID\n\t *\n\t * When `includeNested` is set, builds a query with sub-selections for descendant\n\t * links and returns ancestor + merged descendants. When omitted, returns flat scalar data.\n\t *\n\t * @param doctype - Doctype reference (name and optional slug)\n\t * @param recordId - Record ID to fetch\n\t * @param options - Query options\n\t * @returns Record data wrapped in GetRecordResult\n\t */\n\tgetRecord(doctype: T, recordId: string, options?: GetRecordOptions): Promise<GetRecordResult>\n\n\t/**\n\t * Fetch multiple records\n\t * @param doctype - Doctype reference (name and optional slug)\n\t * @param options - Query options\n\t * @returns Array of record data\n\t */\n\tgetRecords(doctype: T, options?: GetRecordsOptions): Promise<Record<string, unknown>[]>\n\n\t/**\n\t * Execute a doctype action (e.g., SUBMIT, APPROVE, save).\n\t * All state changes flow through this single mutation endpoint.\n\t *\n\t * @param doctype - Doctype reference (name and optional slug)\n\t * @param action - Action name to execute (e.g., 'SUBMIT', 'APPROVE', 'save')\n\t * @param args - Action arguments (typically record ID and/or form data)\n\t * @returns Action result with success status, response data, and any error\n\t */\n\trunAction(\n\t\tdoctype: T,\n\t\taction: string,\n\t\targs?: unknown[]\n\t): Promise<{ success: boolean; data: unknown; error: string | null }>\n}\n","import { DoctypeFieldSchema } from './field'\nimport { DoctypeMeta } from './doctype'\n\n/**\n * Validation error with path information\n * @public\n */\nexport interface ValidationError {\n\t/** Path to the invalid property */\n\tpath: PropertyKey[]\n\n\t/** Error message */\n\tmessage: string\n}\n\n/**\n * Result of a validation operation\n * @public\n */\nexport interface ValidationResult {\n\t/** Whether validation passed */\n\tsuccess: boolean\n\n\t/** List of validation errors (empty if success) */\n\terrors: ValidationError[]\n}\n\n/**\n * Validate a field definition against the DoctypeField discriminated union\n * @param data - Data to validate\n * @returns Validation result\n * @public\n */\nexport function validateField(data: unknown): ValidationResult {\n\tconst result = DoctypeFieldSchema.safeParse(data)\n\n\tif (result.success) {\n\t\treturn { success: true, errors: [] }\n\t}\n\n\treturn {\n\t\tsuccess: false,\n\t\terrors: result.error.issues.map(issue => ({\n\t\t\tpath: issue.path,\n\t\t\tmessage: issue.message,\n\t\t})),\n\t}\n}\n\n/**\n * Validate a doctype definition\n * @param data - Data to validate\n * @returns Validation result\n * @public\n */\nexport function validateDoctype(data: unknown): ValidationResult {\n\tconst result = DoctypeMeta.safeParse(data)\n\n\tif (result.success) {\n\t\treturn { success: true, errors: [] }\n\t}\n\n\treturn {\n\t\tsuccess: false,\n\t\terrors: result.error.issues.map(issue => ({\n\t\t\tpath: issue.path,\n\t\t\tmessage: issue.message,\n\t\t})),\n\t}\n}\n\n/**\n * Parse and validate a field, throwing on failure\n * @param data - Data to parse\n * @returns Validated DoctypeField\n * @throws ZodError if validation fails\n * @public\n */\nexport function parseField(data: unknown): import('./field').DoctypeField {\n\treturn DoctypeFieldSchema.parse(data)\n}\n\n/**\n * Parse and validate a doctype, throwing on failure\n * @param data - Data to parse\n * @returns Validated DoctypeMeta\n * @throws ZodError if validation fails\n * @public\n */\nexport function parseDoctype(data: unknown): DoctypeMeta {\n\treturn DoctypeMeta.parse(data)\n}\n\n// Re-export types for convenience\nexport type { DoctypeField, ValueField, FieldsetField, TableField } from './field'\nexport type { DoctypeMeta } from './doctype'\n","/**\n * Naming Convention Utilities\n * Converts between various naming conventions (snake_case, camelCase, PascalCase, kebab-case)\n * @packageDocumentation\n */\n\n/**\n * Converts snake_case to camelCase\n * @param snakeCase - Snake case string\n * @returns Camel case string\n * @public\n * @example\n * ```typescript\n * snakeToCamel('user_email') // 'userEmail'\n * snakeToCamel('created_at') // 'createdAt'\n * ```\n */\nexport function snakeToCamel(snakeCase: string): string {\n\treturn snakeCase.replace(/_([a-z])/g, (_: string, letter: string) => letter.toUpperCase())\n}\n\n/**\n * Converts camelCase to snake_case\n * @param camelCase - Camel case string\n * @returns Snake case string\n * @public\n * @example\n * ```typescript\n * camelToSnake('userEmail') // 'user_email'\n * camelToSnake('createdAt') // 'created_at'\n * ```\n */\nexport function camelToSnake(camelCase: string): string {\n\treturn camelCase.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`)\n}\n\n/**\n * Converts snake_case to Title Case label\n * @param snakeCase - Snake case string\n * @returns Title case label\n * @public\n * @example\n * ```typescript\n * snakeToLabel('user_email') // 'User Email'\n * snakeToLabel('first_name') // 'First Name'\n * ```\n */\nexport function snakeToLabel(snakeCase: string): string {\n\treturn snakeCase\n\t\t.split('_')\n\t\t.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n\t\t.join(' ')\n}\n\n/**\n * Converts camelCase to Title Case label\n * @param camelCase - Camel case string\n * @returns Title case label\n * @public\n * @example\n * ```typescript\n * camelToLabel('userEmail') // 'User Email'\n * camelToLabel('firstName') // 'First Name'\n * ```\n */\nexport function camelToLabel(camelCase: string): string {\n\tconst withSpaces = camelCase.replace(/([A-Z])/g, ' $1').trim()\n\treturn withSpaces.charAt(0).toUpperCase() + withSpaces.slice(1)\n}\n\n/**\n * Convert table name to PascalCase doctype name\n * @param tableName - SQL table name (snake_case)\n * @returns PascalCase name\n * @public\n */\nexport function toPascalCase(tableName: string): string {\n\treturn tableName\n\t\t.split(/[-_\\s]+/)\n\t\t.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n\t\t.join('')\n}\n\n/**\n * Convert to kebab-case slug\n * @param name - Name to convert\n * @returns kebab-case slug\n * @public\n */\nexport function toSlug(name: string): string {\n\treturn name\n\t\t.replace(/([a-z])([A-Z])/g, '$1-$2')\n\t\t.replace(/[\\s_]+/g, '-')\n\t\t.toLowerCase()\n}\n\n/**\n * Convert PascalCase to snake_case (e.g., for deriving table names from type names)\n * @param pascal - PascalCase string\n * @returns snake_case string\n * @public\n * @example\n * ```typescript\n * pascalToSnake('SalesOrder') // 'sales_order'\n * pascalToSnake('SalesOrderItem') // 'sales_order_item'\n * ```\n */\nexport function pascalToSnake(pascal: string): string {\n\treturn pascal\n\t\t.replace(/([a-z])([A-Z])/g, '$1_$2')\n\t\t.replace(/[\\s-]+/g, '_')\n\t\t.toLowerCase()\n}\n","/**\n * GraphQL Scalar Type Mappings\n *\n * Maps standard GraphQL scalars and well-known custom scalars to Stonecrop field types.\n * Source-agnostic — covers scalars commonly emitted by PostGraphile, Hasura, Apollo, etc.\n *\n * Users can extend these via the `customScalars` option in `GraphQLConversionOptions`.\n *\n * @packageDocumentation\n */\n\nimport type { FieldTemplate } from './types'\n\n/**\n * Mapping from standard GraphQL scalar types to Stonecrop field types.\n * These are defined by the GraphQL specification and are always available.\n *\n * @public\n */\nexport const GQL_SCALAR_MAP: Record<string, FieldTemplate> = {\n\tString: { component: 'ATextInput' },\n\tInt: { component: 'ANumericInput' },\n\tFloat: { component: 'ANumericInput' },\n\tBoolean: { component: 'ACheckbox' },\n\tID: { component: 'ATextInput' },\n}\n\n/**\n * Mapping from well-known custom GraphQL scalars to Stonecrop field types.\n * These cover scalars commonly used across GraphQL servers (PostGraphile, Hasura, etc.)\n * without baking in knowledge of any specific server.\n *\n * Entries here have lower precedence than `customScalars` from options, but higher\n * precedence than unknown/unmapped scalars.\n *\n * @public\n */\nexport const WELL_KNOWN_SCALARS: Record<string, FieldTemplate> = {\n\t// Arbitrary precision / large numbers — all numeric variants render with ANumericInput.\n\tBigFloat: { component: 'ANumericInput' },\n\tBigDecimal: { component: 'ANumericInput' },\n\tDecimal: { component: 'ANumericInput' },\n\tBigInt: { component: 'ANumericInput' },\n\tLong: { component: 'ANumericInput' },\n\n\t// Identifiers\n\tUUID: { component: 'ATextInput' },\n\n\t// Date / Time — no dedicated Time SFC exists; Time falls back to a plain text input.\n\tDateTime: { component: 'ADateTime' },\n\tDatetime: { component: 'ADateTime' },\n\tDate: { component: 'ADate' },\n\tTime: { component: 'ATextInput' },\n\tInterval: { component: 'ADuration' },\n\tDuration: { component: 'ADuration' },\n\n\t// Structured data\n\tJSON: { component: 'ACodeEditor' },\n\tJSONObject: { component: 'ACodeEditor' },\n\tJsonNode: { component: 'ACodeEditor' },\n}\n\n/**\n * Set of scalar type names that are internal to GraphQL servers and should be skipped\n * during field conversion (they don't represent meaningful data fields).\n *\n * @public\n */\nexport const INTERNAL_SCALARS = new Set(['Cursor'])\n\n/**\n * Build a merged scalar map from the built-in maps and user-provided custom scalars.\n * Precedence (highest to lowest): customScalars → GQL_SCALAR_MAP → WELL_KNOWN_SCALARS\n *\n * @param customScalars - User-provided scalar overrides\n * @returns Merged scalar map\n * @public\n */\nexport function buildScalarMap(customScalars?: Record<string, Partial<FieldTemplate>>): Record<string, FieldTemplate> {\n\tconst merged: Record<string, FieldTemplate> = { ...WELL_KNOWN_SCALARS }\n\n\t// Standard scalars override well-known\n\tfor (const [key, value] of Object.entries(GQL_SCALAR_MAP)) {\n\t\tmerged[key] = value\n\t}\n\n\t// Custom scalars override everything\n\tif (customScalars) {\n\t\tfor (const [key, value] of Object.entries(customScalars)) {\n\t\t\tmerged[key] = { component: value.component ?? 'ATextInput' }\n\t\t}\n\t}\n\n\treturn merged\n}\n","/**\n * Default heuristics for identifying entity types and fields in a GraphQL schema.\n *\n * These heuristics work across common GraphQL servers (PostGraphile, Hasura, Apollo, etc.)\n * by detecting widely-adopted conventions like the Relay connection pattern.\n *\n * All heuristics can be overridden via the `isEntityType`, `isEntityField`, and\n * `classifyField` options in `GraphQLConversionOptions`.\n *\n * @packageDocumentation\n */\n\nimport {\n\tisScalarType,\n\tisEnumType,\n\tisObjectType,\n\tisListType,\n\tisNonNullType,\n\tisNamedType,\n\ttype GraphQLObjectType,\n\ttype GraphQLField,\n\ttype GraphQLOutputType,\n\ttype GraphQLNamedType,\n} from 'graphql'\n\nimport type { FieldTemplate } from './types'\nimport type { GraphQLConversionFieldMeta, GraphQLConversionOptions } from './types'\nimport { buildScalarMap, INTERNAL_SCALARS } from './scalars'\nimport { toSlug, camelToLabel, toPascalCase } from '../naming'\n\n/**\n * Suffixes that identify synthetic/framework types generated by GraphQL servers.\n * Types ending with these suffixes are typically not entities.\n */\nconst SYNTHETIC_SUFFIXES = [\n\t'Connection',\n\t'Edge',\n\t'Input',\n\t'Patch',\n\t'Payload',\n\t'Condition',\n\t'Filter',\n\t'OrderBy',\n\t'Aggregate',\n\t'AggregateResult',\n\t'AggregateFilter',\n\t'DeleteResponse',\n\t'InsertResponse',\n\t'UpdateResponse',\n\t'MutationResponse',\n]\n\n/**\n * Root operation type names that are never entities.\n */\nconst ROOT_TYPE_NAMES = new Set(['Query', 'Mutation', 'Subscription'])\n\n/**\n * Default heuristic to determine if a GraphQL object type represents an entity.\n * An entity type becomes a Stonecrop doctype.\n *\n * This heuristic excludes:\n * - Introspection types (`__*`)\n * - Root operation types (`Query`, `Mutation`, `Subscription`)\n * - Types with synthetic suffixes (e.g., `*Connection`, `*Edge`, `*Input`)\n * - Types starting with `Node` interface marker (exact match only)\n *\n * @param typeName - The GraphQL type name\n * @param type - The GraphQL object type definition\n * @returns `true` if this type should become a Stonecrop doctype\n * @public\n */\nexport function defaultIsEntityType(typeName: string, type: GraphQLObjectType): boolean {\n\t// Exclude introspection types\n\tif (typeName.startsWith('__')) {\n\t\treturn false\n\t}\n\n\t// Exclude root operation types\n\tif (ROOT_TYPE_NAMES.has(typeName)) {\n\t\treturn false\n\t}\n\n\t// Exclude the Node interface marker type\n\tif (typeName === 'Node') {\n\t\treturn false\n\t}\n\n\t// Exclude types matching synthetic suffixes\n\tfor (const suffix of SYNTHETIC_SUFFIXES) {\n\t\tif (typeName.endsWith(suffix)) {\n\t\t\treturn false\n\t\t}\n\t}\n\n\t// Must have at least one field\n\tconst fields = type.getFields()\n\tif (Object.keys(fields).length === 0) {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n/**\n * Fields to skip by default on entity types.\n * These are internal to GraphQL servers and don't represent semantic data.\n */\nconst SKIP_FIELDS = new Set(['nodeId', '__typename', 'clientMutationId'])\n\n/**\n * Default heuristic to filter fields on entity types.\n * Skips internal fields that don't represent meaningful data.\n *\n * @param fieldName - The GraphQL field name\n * @param _field - The GraphQL field definition (unused in default implementation)\n * @param _parentType - The parent entity type (unused in default implementation)\n * @returns `true` if this field should be included\n * @public\n */\nexport function defaultIsEntityField(\n\tfieldName: string,\n\t_field: GraphQLField<unknown, unknown>,\n\t_parentType: GraphQLObjectType\n): boolean {\n\treturn !SKIP_FIELDS.has(fieldName)\n}\n\n/**\n * Unwrap NonNull and List wrappers from a GraphQL type, tracking nullability.\n *\n * @param type - The GraphQL output type\n * @returns The unwrapped named type, whether it's required, and whether it's a list\n * @internal\n */\nfunction unwrapType(type: GraphQLOutputType): {\n\tnamedType: GraphQLNamedType\n\trequired: boolean\n\tisList: boolean\n} {\n\tlet required = false\n\tlet isList = false\n\tlet current: GraphQLOutputType = type\n\n\t// Unwrap outer NonNull\n\tif (isNonNullType(current)) {\n\t\trequired = true\n\t\tcurrent = current.ofType\n\t}\n\n\t// Unwrap List\n\tif (isListType(current)) {\n\t\tisList = true\n\t\tcurrent = current.ofType\n\n\t\t// Unwrap inner NonNull (e.g., [Type!])\n\t\tif (isNonNullType(current)) {\n\t\t\tcurrent = current.ofType\n\t\t}\n\t}\n\n\t// At this point, current should be a named type (scalar, enum, or object)\n\tif (!isNamedType(current)) {\n\t\tthrow new Error(`Expected a named GraphQL type, got: ${String(current)}`)\n\t}\n\treturn { namedType: current, required, isList }\n}\n\n/**\n * Check if a GraphQL object type looks like a Relay Connection type.\n * A connection type has an `edges` field returning a list of edge types,\n * where each edge has a `node` field.\n *\n * @param type - The GraphQL object type to check\n * @returns The node type name if this is a connection, or `undefined`\n * @internal\n */\nfunction getConnectionNodeType(type: GraphQLObjectType): string | undefined {\n\tconst fields = type.getFields()\n\n\t// Must have an 'edges' field\n\tconst edgesField = fields['edges']\n\tif (!edgesField) return undefined\n\n\t// edges must be a list\n\tconst { namedType: edgesType, isList: edgesIsList } = unwrapType(edgesField.type)\n\tif (!edgesIsList || !isObjectType(edgesType)) return undefined\n\n\t// Each edge must have a 'node' field\n\tconst edgeFields = edgesType.getFields()\n\tconst nodeField = edgeFields['node']\n\tif (!nodeField) return undefined\n\n\tconst { namedType: nodeType } = unwrapType(nodeField.type)\n\tif (!isObjectType(nodeType)) return undefined\n\n\treturn nodeType.name\n}\n\n/**\n * Classify a single GraphQL field into a Stonecrop field definition.\n *\n * Classification rules (in order):\n * 1. Scalar types → look up in merged scalar map\n * 2. Enum types → `Select` with enum values as options\n * 3. Object types that are entities → `Link` with slug as options\n * 4. Object types that are Connections → `Doctype` with node type slug as options\n * 5. List of entity type → `Doctype` with item type slug as options\n * 6. Anything else → `Data` with `_unmapped: true`\n *\n * @param fieldName - The GraphQL field name\n * @param field - The GraphQL field definition\n * @param entityTypes - Set of type names classified as entities\n * @param options - Conversion options (for custom scalars, unmapped meta, etc.)\n * @returns The Stonecrop field definition\n * @public\n */\nexport function classifyFieldType(\n\tfieldName: string,\n\tfield: GraphQLField<unknown, unknown>,\n\tentityTypes: Set<string>,\n\toptions: GraphQLConversionOptions = {}\n): GraphQLConversionFieldMeta {\n\tconst { namedType, required, isList } = unwrapType(field.type)\n\tconst scalarMap = buildScalarMap(options.customScalars)\n\n\tconst base: GraphQLConversionFieldMeta = {\n\t\tkind: 'field',\n\t\tfieldname: fieldName,\n\t\tlabel: camelToLabel(fieldName),\n\t\tcomponent: 'ATextInput',\n\t}\n\n\tif (required) {\n\t\tbase.required = true\n\t}\n\n\t// 1. Scalar types\n\tif (isScalarType(namedType)) {\n\t\t// Skip internal scalars (e.g., Cursor)\n\t\tif (INTERNAL_SCALARS.has(namedType.name)) {\n\t\t\tbase._unmapped = true\n\t\t\tif (options.includeUnmappedMeta) {\n\t\t\t\tbase._graphqlType = namedType.name\n\t\t\t}\n\t\t\treturn base\n\t\t}\n\n\t\t// Special case: ID fields that reference an entity type → Link\n\t\tif (namedType.name === 'ID') {\n\t\t\tconst candidateTypeName = toPascalCase(fieldName)\n\t\t\tif (entityTypes.has(candidateTypeName)) {\n\t\t\t\tbase.component = 'AFormLink'\n\t\t\t\tbase.doctype = toSlug(candidateTypeName)\n\t\t\t\treturn base\n\t\t\t}\n\t\t}\n\n\t\tconst template: FieldTemplate | undefined = scalarMap[namedType.name]\n\t\tif (template) {\n\t\t\tbase.component = template.component\n\t\t} else {\n\t\t\t// Unknown scalar — default to Data with unmapped marker\n\t\t\tbase._unmapped = true\n\t\t\tif (options.includeUnmappedMeta) {\n\t\t\t\tbase._graphqlType = namedType.name\n\t\t\t}\n\t\t}\n\t\treturn base\n\t}\n\n\t// 2. Enum types → Select\n\tif (isEnumType(namedType)) {\n\t\tbase.component = 'ADropdown'\n\t\tbase.options = namedType.getValues().map(v => v.name)\n\t\treturn base\n\t}\n\n\t// 3–5. Object types\n\tif (isObjectType(namedType)) {\n\t\t// 3. Direct reference to an entity type → Link\n\t\tif (!isList && entityTypes.has(namedType.name)) {\n\t\t\tbase.component = 'AFormLink'\n\t\t\tbase.doctype = toSlug(namedType.name)\n\t\t\treturn base\n\t\t}\n\n\t\t// 4. Connection type → link (child table)\n\t\tconst connectionNodeTypeName = getConnectionNodeType(namedType)\n\t\tif (connectionNodeTypeName && entityTypes.has(connectionNodeTypeName)) {\n\t\t\tbase.component = 'ATable'\n\t\t\tbase._isLink = true\n\t\t\tbase.doctype = toSlug(connectionNodeTypeName)\n\t\t\tbase.cardinality = 'noneOrMany'\n\t\t\treturn base\n\t\t}\n\n\t\t// 5. List of entity type → link\n\t\tif (isList && entityTypes.has(namedType.name)) {\n\t\t\tbase.component = 'ATable'\n\t\t\tbase._isLink = true\n\t\t\tbase.doctype = toSlug(namedType.name)\n\t\t\tbase.cardinality = 'noneOrMany'\n\t\t\treturn base\n\t\t}\n\n\t\t// Unknown object type — mark as unmapped\n\t\tbase._unmapped = true\n\t\tif (options.includeUnmappedMeta) {\n\t\t\tbase._graphqlType = namedType.name\n\t\t}\n\t\treturn base\n\t}\n\n\t// Fallback — shouldn't normally be reached\n\tbase._unmapped = true\n\tif (options.includeUnmappedMeta) {\n\t\tbase._graphqlType = namedType.name\n\t}\n\treturn base\n}\n","/**\n * GraphQL Introspection to Stonecrop Schema Converter\n *\n * Converts a standard GraphQL introspection result (or SDL string) into\n * Stonecrop doctype schemas. Source-agnostic — works with any GraphQL server.\n *\n * @packageDocumentation\n */\n\nimport { buildClientSchema, buildSchema, isObjectType, type GraphQLSchema } from 'graphql'\n\nimport type { LinkDeclaration } from '../doctype'\nimport { toSlug } from '../naming'\nimport type { IntrospectionSource, GraphQLConversionOptions, ConvertedGraphQLDoctype } from './types'\nimport type { ValueField } from '../field'\nimport { defaultIsEntityType, defaultIsEntityField, classifyFieldType } from './heuristics'\n\n/**\n * Convert a GraphQL schema to Stonecrop doctype schemas.\n *\n * Accepts either an `IntrospectionQuery` result object or an SDL string.\n * Entity types are identified using heuristics (or a custom `isEntityType` function)\n * and converted to `DoctypeMeta`-compatible JSON objects.\n *\n * @param source - GraphQL introspection result or SDL string\n * @param options - Conversion options for controlling output format and behavior\n * @returns Array of converted Stonecrop doctype definitions\n *\n * @example\n * ```typescript\n * // From introspection result (fetched from any GraphQL server)\n * const introspection = await fetchIntrospection('http://localhost:5000/graphql')\n * const doctypes = convertGraphQLSchema(introspection)\n *\n * // From SDL string\n * const sdl = fs.readFileSync('schema.graphql', 'utf-8')\n * const doctypes = convertGraphQLSchema(sdl)\n *\n * // With PostGraphile custom scalars\n * const doctypes = convertGraphQLSchema(introspection, {\n * customScalars: {\n * BigFloat: { component: 'ANumericInput' }\n * }\n * })\n * ```\n *\n * @public\n */\nexport function convertGraphQLSchema(\n\tsource: IntrospectionSource,\n\toptions: GraphQLConversionOptions = {}\n): ConvertedGraphQLDoctype[] {\n\tconst schema = buildGraphQLSchema(source)\n\tconst typeMap = schema.getTypeMap()\n\n\t// Determine the root operation type names to exclude\n\tconst rootTypeNames = new Set<string>()\n\tconst queryType = schema.getQueryType()\n\tconst mutationType = schema.getMutationType()\n\tconst subscriptionType = schema.getSubscriptionType()\n\tif (queryType) rootTypeNames.add(queryType.name)\n\tif (mutationType) rootTypeNames.add(mutationType.name)\n\tif (subscriptionType) rootTypeNames.add(subscriptionType.name)\n\n\t// Use custom or default entity type detector\n\tconst isEntityType = options.isEntityType ?? defaultIsEntityType\n\n\t// Phase 1: Identify all entity types\n\tconst entityTypes = new Set<string>()\n\tfor (const [typeName, type] of Object.entries(typeMap)) {\n\t\tif (!isObjectType(type)) continue\n\n\t\t// Always skip root operation types (even if custom isEntityType doesn't)\n\t\tif (rootTypeNames.has(typeName)) continue\n\n\t\tif (isEntityType(typeName, type)) {\n\t\t\tentityTypes.add(typeName)\n\t\t}\n\t}\n\n\t// Phase 2: Apply include/exclude filters\n\tlet filteredEntityTypes = entityTypes\n\n\tif (options.include) {\n\t\tconst includeSet = new Set(options.include)\n\t\tfilteredEntityTypes = new Set([...entityTypes].filter(t => includeSet.has(t)))\n\t}\n\n\tif (options.exclude) {\n\t\tconst excludeSet = new Set(options.exclude)\n\t\tfilteredEntityTypes = new Set([...filteredEntityTypes].filter(t => !excludeSet.has(t)))\n\t}\n\n\t// Phase 3: Convert each entity type to a doctype\n\tconst isEntityField = options.isEntityField ?? defaultIsEntityField\n\n\tconst doctypes: ConvertedGraphQLDoctype[] = []\n\n\tfor (const typeName of filteredEntityTypes) {\n\t\tconst type = typeMap[typeName]\n\t\tif (!isObjectType(type)) continue\n\n\t\tconst fields = type.getFields()\n\t\tconst typeOverrides = options.typeOverrides?.[typeName]\n\n\t\tconst entityFields = Object.entries(fields).filter(([fieldName, field]) => isEntityField(fieldName, field, type))\n\n\t\t// oxlint-disable-next-line oxc/no-map-spread -- ...custom spread required; Object.assign cannot preserve the metadata-carrying inferred union type from classifyField\n\t\tconst allClassifiedFields = entityFields.map(([fieldName, field]) => {\n\t\t\t// Check for full custom classification first\n\t\t\tif (options.classifyField) {\n\t\t\t\tconst custom = options.classifyField(fieldName, field, type)\n\t\t\t\tif (custom !== null && custom !== undefined) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tkind: 'field' as const,\n\t\t\t\t\t\tfieldname: fieldName,\n\t\t\t\t\t\tlabel: custom.label ?? fieldName,\n\t\t\t\t\t\tcomponent: custom.component ?? 'ATextInput',\n\t\t\t\t\t\t...custom,\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Default classification\n\t\t\tconst classified = classifyFieldType(fieldName, field, entityTypes, options)\n\n\t\t\t// Apply per-field overrides\n\t\t\tif (typeOverrides?.[fieldName]) {\n\t\t\t\treturn Object.assign(classified, typeOverrides[fieldName])\n\t\t\t}\n\n\t\t\treturn classified\n\t\t})\n\n\t\t// Separate scalar fields from link fields\n\t\tconst links: Record<string, LinkDeclaration> = {}\n\t\tconst convertedFields = allClassifiedFields\n\t\t\t.filter(field => {\n\t\t\t\tif (field._isLink && field.doctype && field.cardinality) {\n\t\t\t\t\tlinks[field.fieldname] = {\n\t\t\t\t\t\ttarget: field.doctype,\n\t\t\t\t\t\tcardinality: field.cardinality,\n\t\t\t\t\t}\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\treturn true\n\t\t\t})\n\t\t\t// Clean up internal metadata unless requested, and stamp provenance.\n\t\t\t// Stamped last so every classification path (default, classifyField,\n\t\t\t// typeOverrides) carries the marker — the docbuilder's identity lock\n\t\t\t// keys off it, and an override must not be able to unset it.\n\t\t\t.map(field => {\n\t\t\t\tif (!options.includeUnmappedMeta) {\n\t\t\t\t\tconst { _graphqlType, _unmapped, _isLink, ...clean } = field\n\t\t\t\t\treturn Object.assign(clean, { source: 'introspected' as const })\n\t\t\t\t}\n\t\t\t\tconst { _isLink, ...rest } = field\n\t\t\t\treturn Object.assign(rest, { source: 'introspected' as const })\n\t\t\t})\n\n\t\tconst doctype: ConvertedGraphQLDoctype = {\n\t\t\tname: typeName,\n\t\t\tslug: toSlug(typeName),\n\t\t\tfields: convertedFields as ValueField[],\n\t\t}\n\n\t\tif (Object.keys(links).length > 0) {\n\t\t\tdoctype.links = links\n\t\t}\n\n\t\tif (options.includeUnmappedMeta) {\n\t\t\tdoctype._graphqlTypeName = typeName\n\t\t}\n\n\t\tdoctypes.push(doctype)\n\t}\n\n\treturn doctypes\n}\n\n/**\n * Build a GraphQLSchema from either an introspection result or SDL string.\n *\n * @param source - IntrospectionQuery object or SDL string\n * @returns A complete GraphQLSchema\n * @internal\n */\nfunction buildGraphQLSchema(source: IntrospectionSource): GraphQLSchema {\n\tif (typeof source === 'string') {\n\t\t// SDL string\n\t\treturn buildSchema(source)\n\t}\n\n\t// IntrospectionQuery result\n\treturn buildClientSchema(source)\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Re-exports\n// ═══════════════════════════════════════════════════════════════\n\n// Main converter (this file)\nexport { convertGraphQLSchema as default }\n\n// Types\nexport type {\n\tIntrospectionSource,\n\tGraphQLConversionOptions,\n\tGraphQLConversionFieldMeta,\n\tConvertedGraphQLDoctype,\n} from './types'\n\n// Scalar maps\nexport { GQL_SCALAR_MAP, WELL_KNOWN_SCALARS, INTERNAL_SCALARS, buildScalarMap } from './scalars'\n\n// Heuristics\nexport { defaultIsEntityType, defaultIsEntityField, classifyFieldType } from './heuristics'\n\n// Naming utilities\nexport { toSlug, toPascalCase, pascalToSnake, snakeToCamel, camelToSnake, snakeToLabel, camelToLabel } from '../naming'\n"],"names":["TableViewConfig","z","FieldOptions","FieldValidation","injectKind","data","obj","normalizeFieldKind","field","injected","createDoctypeFieldSchemas","ValueFieldSchema","TableFieldSchema","DoctypeFieldSchema","FieldsetFieldSchema","rawUnion","schemas","Cardinality","SyncFetch","LazyFetch","CustomFetch","FetchStrategy","LinkDeclaration","ActionDefinition","TriggerDefinition","isActionAllowedInState","action","currentState","allowedStates","WorkflowLayout","WorkflowMeta","DoctypeMeta","validateField","result","issue","validateDoctype","parseField","parseDoctype","snakeToCamel","snakeCase","_","letter","camelToSnake","camelCase","snakeToLabel","word","camelToLabel","withSpaces","toPascalCase","tableName","toSlug","name","pascalToSnake","pascal","GQL_SCALAR_MAP","WELL_KNOWN_SCALARS","INTERNAL_SCALARS","buildScalarMap","customScalars","merged","key","value","SYNTHETIC_SUFFIXES","ROOT_TYPE_NAMES","defaultIsEntityType","typeName","type","suffix","fields","SKIP_FIELDS","defaultIsEntityField","fieldName","_field","_parentType","unwrapType","required","isList","current","isNonNullType","isListType","isNamedType","getConnectionNodeType","edgesField","edgesType","edgesIsList","isObjectType","nodeField","nodeType","classifyFieldType","entityTypes","options","namedType","scalarMap","base","isScalarType","candidateTypeName","template","isEnumType","v","connectionNodeTypeName","convertGraphQLSchema","source","schema","buildGraphQLSchema","typeMap","rootTypeNames","queryType","mutationType","subscriptionType","isEntityType","filteredEntityTypes","includeSet","t","excludeSet","isEntityField","doctypes","typeOverrides","allClassifiedFields","custom","classified","links","convertedFields","_graphqlType","_unmapped","_isLink","clean","rest","doctype","buildSchema","buildClientSchema"],"mappings":"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"}
|