@stonecrop/schema 0.31.0 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -10
- package/dist/cli.js +194 -121
- package/dist/cli.js.map +1 -1
- package/dist/converter-CLwduvT_.js +2102 -0
- package/dist/converter-CLwduvT_.js.map +1 -0
- package/dist/flatten-Bx2cfvw3.js +37 -0
- package/dist/flatten-Bx2cfvw3.js.map +1 -0
- package/dist/index.js +123 -117
- package/dist/index.js.map +1 -1
- package/dist/record-BQOOi83C.js +134 -0
- package/dist/record-BQOOi83C.js.map +1 -0
- package/dist/record.js +2 -6
- package/dist/tsdoc-metadata.json +1 -1
- package/package.json +34 -18
- package/dist/flatten-C1MjkzFh.js +0 -10
- package/dist/flatten-C1MjkzFh.js.map +0 -1
- package/dist/record-Bc0lI9Rq.js +0 -61
- package/dist/record-Bc0lI9Rq.js.map +0 -1
- package/dist/record.js.map +0 -1
- package/dist/schema.tsbuildinfo +0 -1
- package/dist/src/badge.d.ts +0 -74
- package/dist/src/badge.d.ts.map +0 -1
- package/dist/src/badge.js +0 -158
- package/dist/src/cli.d.ts +0 -3
- package/dist/src/cli.d.ts.map +0 -1
- package/dist/src/cli.js +0 -292
- package/dist/src/column-schema.d.ts +0 -163
- package/dist/src/column-schema.d.ts.map +0 -1
- package/dist/src/column-schema.js +0 -0
- package/dist/src/component-meta.d.ts +0 -96
- package/dist/src/component-meta.d.ts.map +0 -1
- package/dist/src/component-meta.js +0 -88
- package/dist/src/converter/aggregate.d.ts +0 -127
- package/dist/src/converter/aggregate.d.ts.map +0 -1
- package/dist/src/converter/aggregate.js +0 -235
- package/dist/src/converter/authored.d.ts +0 -43
- package/dist/src/converter/authored.d.ts.map +0 -1
- package/dist/src/converter/authored.js +0 -52
- package/dist/src/converter/heuristics.d.ts +0 -60
- package/dist/src/converter/heuristics.d.ts.map +0 -1
- package/dist/src/converter/heuristics.js +0 -304
- package/dist/src/converter/index.d.ts +0 -51
- package/dist/src/converter/index.d.ts.map +0 -1
- package/dist/src/converter/index.js +0 -195
- package/dist/src/converter/merge.d.ts +0 -102
- package/dist/src/converter/merge.d.ts.map +0 -1
- package/dist/src/converter/merge.js +0 -136
- package/dist/src/converter/scalars.d.ts +0 -46
- package/dist/src/converter/scalars.d.ts.map +0 -1
- package/dist/src/converter/scalars.js +0 -83
- package/dist/src/converter/types.d.ts +0 -157
- package/dist/src/converter/types.d.ts.map +0 -1
- package/dist/src/converter/types.js +0 -5
- package/dist/src/doctype.d.ts +0 -516
- package/dist/src/doctype.d.ts.map +0 -1
- package/dist/src/doctype.js +0 -343
- package/dist/src/field.d.ts +0 -423
- package/dist/src/field.d.ts.map +0 -1
- package/dist/src/field.js +0 -378
- package/dist/src/flatten.d.ts +0 -29
- package/dist/src/flatten.d.ts.map +0 -1
- package/dist/src/flatten.js +0 -38
- package/dist/src/index.d.ts +0 -16
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/index.js +0 -20
- package/dist/src/mode.d.ts +0 -15
- package/dist/src/mode.d.ts.map +0 -1
- package/dist/src/mode.js +0 -0
- package/dist/src/naming.d.ts +0 -80
- package/dist/src/naming.d.ts.map +0 -1
- package/dist/src/naming.js +0 -106
- package/dist/src/record.d.ts +0 -29
- package/dist/src/record.d.ts.map +0 -1
- package/dist/src/record.js +0 -55
- package/dist/src/table.d.ts +0 -33
- package/dist/src/table.d.ts.map +0 -1
- package/dist/src/table.js +0 -25
- package/dist/src/validation.d.ts +0 -54
- package/dist/src/validation.d.ts.map +0 -1
- package/dist/src/validation.js +0 -60
- package/dist/validation-C9P__pRF.js +0 -994
- package/dist/validation-C9P__pRF.js.map +0 -1
package/dist/src/doctype.js
DELETED
|
@@ -1,343 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { DoctypeFieldSchema, flattenFields, getDisplayField } from './field';
|
|
3
|
-
import { toSlug } from './naming';
|
|
4
|
-
/**
|
|
5
|
-
* Cardinality for relationship links.
|
|
6
|
-
* @public
|
|
7
|
-
*/
|
|
8
|
-
export const Cardinality = z.enum(['atMostOne', 'one', 'noneOrMany', 'atLeastOne']).meta({
|
|
9
|
-
title: 'Cardinality',
|
|
10
|
-
description: 'Cardinality for relationship links between doctypes',
|
|
11
|
-
});
|
|
12
|
-
/**
|
|
13
|
-
* Sync fetch strategy - data is fetched in the initial query.
|
|
14
|
-
* @public
|
|
15
|
-
*/
|
|
16
|
-
export const SyncFetch = z
|
|
17
|
-
.object({
|
|
18
|
-
/** Fetch method type */
|
|
19
|
-
method: z.literal('sync'),
|
|
20
|
-
/** Optional limit on number of records to fetch */
|
|
21
|
-
limit: z.number().int().positive().optional(),
|
|
22
|
-
})
|
|
23
|
-
.meta({
|
|
24
|
-
title: 'SyncFetch',
|
|
25
|
-
description: 'Sync fetch strategy - data is fetched in the initial query',
|
|
26
|
-
});
|
|
27
|
-
/**
|
|
28
|
-
* Lazy fetch strategy - data is fetched on demand in a separate query.
|
|
29
|
-
* @public
|
|
30
|
-
*/
|
|
31
|
-
export const LazyFetch = z
|
|
32
|
-
.object({
|
|
33
|
-
/** Fetch method type */
|
|
34
|
-
method: z.literal('lazy'),
|
|
35
|
-
})
|
|
36
|
-
.meta({
|
|
37
|
-
title: 'LazyFetch',
|
|
38
|
-
description: 'Lazy fetch strategy - data is fetched on demand in a separate query',
|
|
39
|
-
});
|
|
40
|
-
/**
|
|
41
|
-
* Custom fetch strategy - uses a custom handler function.
|
|
42
|
-
* @public
|
|
43
|
-
*/
|
|
44
|
-
export const CustomFetch = z
|
|
45
|
-
.object({
|
|
46
|
-
/** Fetch method type */
|
|
47
|
-
method: z.literal('custom'),
|
|
48
|
-
/** Serialized handler function to invoke */
|
|
49
|
-
handler: z.string(),
|
|
50
|
-
})
|
|
51
|
-
.meta({
|
|
52
|
-
title: 'CustomFetch',
|
|
53
|
-
description: 'Custom fetch strategy - uses a custom handler function',
|
|
54
|
-
});
|
|
55
|
-
/**
|
|
56
|
-
* Fetch strategy for link data loading.
|
|
57
|
-
* - sync: fetched in the initial query
|
|
58
|
-
* - lazy: fetched on demand in a separate query
|
|
59
|
-
* - custom: uses a custom handler function
|
|
60
|
-
* @public
|
|
61
|
-
*/
|
|
62
|
-
export const FetchStrategy = z.discriminatedUnion('method', [SyncFetch, LazyFetch, CustomFetch]).meta({
|
|
63
|
-
title: 'FetchStrategy',
|
|
64
|
-
description: 'Fetch strategy for link data loading',
|
|
65
|
-
});
|
|
66
|
-
/**
|
|
67
|
-
* Link declaration - describes a relationship from one doctype to another.
|
|
68
|
-
* @public
|
|
69
|
-
*/
|
|
70
|
-
export const LinkDeclaration = z
|
|
71
|
-
.object({
|
|
72
|
-
/** Target doctype slug */
|
|
73
|
-
target: z.string().min(1),
|
|
74
|
-
/** Cardinality of the relationship */
|
|
75
|
-
cardinality: Cardinality,
|
|
76
|
-
/** Backlink fieldname on the target doctype that points back to this link */
|
|
77
|
-
backlink: z.string().optional(),
|
|
78
|
-
/** Override default rendering component (AForm for 1:1, ATable for 1:many) */
|
|
79
|
-
component: z.string().optional(),
|
|
80
|
-
/** Fieldname of the corresponding Link field in the fields array */
|
|
81
|
-
fieldname: z.string().min(1).optional(),
|
|
82
|
-
/** Fetch strategy for loading nested data */
|
|
83
|
-
fetch: FetchStrategy.optional(),
|
|
84
|
-
/** Whether to block workflow actions until nested data is loaded (default: true) */
|
|
85
|
-
blockWorkflows: z.boolean().optional(),
|
|
86
|
-
})
|
|
87
|
-
.meta({
|
|
88
|
-
title: 'LinkDeclaration',
|
|
89
|
-
description: 'Declares a relationship from one doctype to another',
|
|
90
|
-
});
|
|
91
|
-
/**
|
|
92
|
-
* Action definition within a workflow
|
|
93
|
-
* @public
|
|
94
|
-
*/
|
|
95
|
-
export const ActionDefinition = z
|
|
96
|
-
.object({
|
|
97
|
-
/** Display label for the action */
|
|
98
|
-
label: z.string().min(1),
|
|
99
|
-
/** Fields that must have values before action can execute */
|
|
100
|
-
requiredFields: z.array(z.string()).optional(),
|
|
101
|
-
/** Workflow states where this action is available */
|
|
102
|
-
allowedStates: z.array(z.string()).optional(),
|
|
103
|
-
/** The state the record transitions to after this action executes */
|
|
104
|
-
nextState: z.string().optional(),
|
|
105
|
-
/** True for stateless command actions with no workflow effect at all (print, email, etc.) */
|
|
106
|
-
stateless: z.boolean().optional(),
|
|
107
|
-
/**
|
|
108
|
-
* True for an internal self-transition: the action runs within the current state without
|
|
109
|
-
* advancing the workflow (e.g. `save`, which mutates record data but stays put). Scoped by
|
|
110
|
-
* `allowedStates`, rendered as a self-loop in the graph, and has no `nextState`. Distinct from
|
|
111
|
-
* `stateless` (which has no workflow presence at all): a self-transition is graph-owned and,
|
|
112
|
-
* unlike a stateless command, persists record data on dispatch.
|
|
113
|
-
*/
|
|
114
|
-
selfTransition: z.boolean().optional(),
|
|
115
|
-
/** JS function body stored as a string; executed client-side via AsyncFunction with injected API surface */
|
|
116
|
-
clientHandler: z.string().optional(),
|
|
117
|
-
})
|
|
118
|
-
.meta({
|
|
119
|
-
title: 'ActionDefinition',
|
|
120
|
-
description: 'Action definition within a workflow',
|
|
121
|
-
});
|
|
122
|
-
/**
|
|
123
|
-
* Reactive field-validation trigger — advisory, client-side only.
|
|
124
|
-
*
|
|
125
|
-
* A Trigger is a docbuilder-authored validator: when any field in `on` is edited, its
|
|
126
|
-
* `clientHandler` runs (client-side, no rollback) and may flag a field inline to block save
|
|
127
|
-
* in the UI. It is deliberately a **sibling** to {@link (ActionDefinition:type)}, not a member of it —
|
|
128
|
-
* a reactive validator is not a user-invoked action, so it lives in the `triggers` map on
|
|
129
|
-
* {@link (WorkflowMeta:type)} and never appears to action readers (transition/command dropdowns, the FSM graph).
|
|
130
|
-
*
|
|
131
|
-
* The two bindings are independent: `on` is the fire-set (which fields' edits run it), while the
|
|
132
|
-
* `setError(field, msg)` call inside `clientHandler` chooses which field displays the error.
|
|
133
|
-
* @public
|
|
134
|
-
*/
|
|
135
|
-
export const TriggerDefinition = z
|
|
136
|
-
.object({
|
|
137
|
-
/** Optional display label; the map key is the trigger's identity */
|
|
138
|
-
label: z.string().optional(),
|
|
139
|
-
/** Fieldnames whose edits fire this trigger (fires when any listed field changes) */
|
|
140
|
-
on: z.array(z.string()),
|
|
141
|
-
/** JS function body stored as a string; run client-side with `{ record, value, setError }`. Advisory. */
|
|
142
|
-
clientHandler: z.string(),
|
|
143
|
-
})
|
|
144
|
-
.meta({
|
|
145
|
-
title: 'TriggerDefinition',
|
|
146
|
-
description: 'Reactive field-validation trigger — advisory client-side',
|
|
147
|
-
});
|
|
148
|
-
/**
|
|
149
|
-
* Whether a workflow action may run from `currentState`.
|
|
150
|
-
*
|
|
151
|
-
* Single source of truth for the "is this action available here" rule, shared by
|
|
152
|
-
* the frontend (`getAvailableTransitions`) and the server-side dispatch guard so
|
|
153
|
-
* the two can never disagree. Empty or absent `allowedStates` means the action is
|
|
154
|
-
* available in ALL states — a plain `allowedStates.includes(currentState)` would
|
|
155
|
-
* wrongly block such actions everywhere.
|
|
156
|
-
*
|
|
157
|
-
* @public
|
|
158
|
-
*/
|
|
159
|
-
export function isActionAllowedInState(action, currentState) {
|
|
160
|
-
const allowedStates = action.allowedStates;
|
|
161
|
-
if (!allowedStates || allowedStates.length === 0)
|
|
162
|
-
return true;
|
|
163
|
-
return allowedStates.includes(currentState);
|
|
164
|
-
}
|
|
165
|
-
/**
|
|
166
|
-
* DocBuilder graph layout — node positions for the workflow-state graph, keyed by state name.
|
|
167
|
-
* Pure authoring view-state: persisted in the doctype JSON so an author's manual arrangement
|
|
168
|
-
* survives reloads, but — exactly like {@link (WorkflowMeta:type)}'s `triggers` — it is client-only
|
|
169
|
-
* and never mirrored into the runtime GraphQL SDL (see the WorkflowMeta type in the host SDLs, which
|
|
170
|
-
* expose only `states`/`actions`). The shape mirrors VueFlow's node fields; `position` is the node's
|
|
171
|
-
* canvas coordinate and `targetPosition`/`sourcePosition` are the handle sides.
|
|
172
|
-
* @public
|
|
173
|
-
*/
|
|
174
|
-
export const WorkflowLayout = z.record(z.string(), z.object({
|
|
175
|
-
position: z.object({ x: z.number(), y: z.number() }).optional(),
|
|
176
|
-
targetPosition: z.enum(['left', 'top', 'right', 'bottom']).optional(),
|
|
177
|
-
sourcePosition: z.enum(['left', 'top', 'right', 'bottom']).optional(),
|
|
178
|
-
}));
|
|
179
|
-
/**
|
|
180
|
-
* Workflow metadata - states and actions for a doctype
|
|
181
|
-
* @public
|
|
182
|
-
*/
|
|
183
|
-
export const WorkflowMeta = z
|
|
184
|
-
.object({
|
|
185
|
-
/** List of workflow states */
|
|
186
|
-
states: z.array(z.string()).optional(),
|
|
187
|
-
/** Actions available in this workflow */
|
|
188
|
-
actions: z.record(z.string(), ActionDefinition).optional(),
|
|
189
|
-
/** Reactive field-validation triggers (advisory, client-side), keyed by trigger name */
|
|
190
|
-
triggers: z.record(z.string(), TriggerDefinition).optional(),
|
|
191
|
-
/**
|
|
192
|
-
* DocBuilder node positions keyed by state name — authoring view-state. Persisted here so a
|
|
193
|
-
* doctype author's manual graph arrangement survives reloads; like `triggers`, it is client-only
|
|
194
|
-
* and never enters the runtime GraphQL SDL. See {@link (WorkflowLayout:variable)}.
|
|
195
|
-
*/
|
|
196
|
-
layout: WorkflowLayout.optional(),
|
|
197
|
-
})
|
|
198
|
-
.meta({
|
|
199
|
-
title: 'WorkflowMeta',
|
|
200
|
-
description: 'Workflow metadata - states and actions for a doctype',
|
|
201
|
-
});
|
|
202
|
-
/**
|
|
203
|
-
* Doctype metadata - complete definition of a doctype
|
|
204
|
-
* @public
|
|
205
|
-
*/
|
|
206
|
-
export const DoctypeMeta = z
|
|
207
|
-
.object({
|
|
208
|
-
/** Display name of the doctype */
|
|
209
|
-
name: z.string().min(1),
|
|
210
|
-
/** URL-friendly slug (kebab-case) */
|
|
211
|
-
slug: z.string().min(1).optional(),
|
|
212
|
-
/**
|
|
213
|
-
* Field on this doctype used when displaying a reference to one of its records.
|
|
214
|
-
* When a record elsewhere holds an inline foreign key to this doctype, the middleware
|
|
215
|
-
* returns that field as `{ id, displayText }`, reading `displayText` from this field.
|
|
216
|
-
*/
|
|
217
|
-
displayField: z.string().min(1).optional(),
|
|
218
|
-
/**
|
|
219
|
-
* URL path this doctype registers at, written literally — `/order` for a collection,
|
|
220
|
-
* `/order/:id` for a record. Absent means the doctype has no page of its own, which is the
|
|
221
|
-
* common case: a child table is reached inside its parent, never at a URL.
|
|
222
|
-
*
|
|
223
|
-
* A path rather than a segment because the record parameter has to be somewhere, and a host
|
|
224
|
-
* that reads a bare segment has to know which kind of doctype it is holding to decide where
|
|
225
|
-
* to put it. Writing it out means nothing downstream re-derives it.
|
|
226
|
-
*/
|
|
227
|
-
route: z.string().startsWith('/').optional(),
|
|
228
|
-
/** Field definitions (a link field is one carrying `doctype`) */
|
|
229
|
-
fields: z.array(DoctypeFieldSchema),
|
|
230
|
-
/** Relationship links to other doctypes */
|
|
231
|
-
links: z.record(z.string(), LinkDeclaration).optional(),
|
|
232
|
-
/** Workflow configuration */
|
|
233
|
-
workflow: WorkflowMeta.optional(),
|
|
234
|
-
/** Parent doctype for inheritance */
|
|
235
|
-
inherits: z.string().optional(),
|
|
236
|
-
})
|
|
237
|
-
.meta({
|
|
238
|
-
title: 'DoctypeMeta',
|
|
239
|
-
description: 'Doctype metadata - complete definition of a doctype',
|
|
240
|
-
})
|
|
241
|
-
.superRefine((doctype, ctx) => {
|
|
242
|
-
// A record is identified by exactly one field here, and that is the design rather than a
|
|
243
|
-
// limitation awaiting composite support. A doctype describes the **API surface** a client
|
|
244
|
-
// interacts with, not the table behind it; how a composite database key maps onto a single
|
|
245
|
-
// identity on that surface is the server's business, and the client neither sees nor
|
|
246
|
-
// encodes the parts. So there is nothing for a doctype-level composite key to express.
|
|
247
|
-
//
|
|
248
|
-
// Declaring several is therefore malformed, and silently so: `getPrimaryKeyField` takes the
|
|
249
|
-
// first match and the rest are ignored, leaving an adapter to key records on a column that
|
|
250
|
-
// need not be unique — `stonecropRecord`'s row map then keeps whichever row comes last.
|
|
251
|
-
// Refusing at the gate is what makes it say so.
|
|
252
|
-
//
|
|
253
|
-
// Counts the flattened set, because that is the set `getPrimaryKeyField` resolves over. The
|
|
254
|
-
// two asked different questions while this scanned top level only: a doctype with one key
|
|
255
|
-
// declared at each level passed the gate and then had one of them silently dropped.
|
|
256
|
-
//
|
|
257
|
-
// Zero keys stays legal and is not an omission: a surrogate-key doctype declares none and
|
|
258
|
-
// resolves through `getRecordIdField`'s documented `id` fallback.
|
|
259
|
-
const declared = flattenFields(doctype.fields).filter(f => f.kind === 'field' && f.primaryKey);
|
|
260
|
-
if (declared.length > 1) {
|
|
261
|
-
ctx.addIssue({
|
|
262
|
-
code: 'custom',
|
|
263
|
-
path: ['fields'],
|
|
264
|
-
message: `Doctype declares ${declared.length} primaryKey fields (${declared
|
|
265
|
-
.map(f => (f.kind === 'field' ? f.fieldname : ''))
|
|
266
|
-
.join(', ')}); a record is identified by exactly one field. A composite database key is mapped to a single identity by the adapter, so a doctype never declares its parts`,
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
// Through `getDisplayField` rather than a scan written here, because the adapter builds its
|
|
270
|
-
// SELECT from that same call. The two hand-rolled versions disagreed in both directions at
|
|
271
|
-
// once: this gate scanned top-level only, so it rejected a fieldset-nested field that would
|
|
272
|
-
// have worked, while neither side excluded `computed` fields, so a nomination naming one
|
|
273
|
-
// passed the gate and then failed as a missing column at query time.
|
|
274
|
-
if (doctype.displayField && !getDisplayField(doctype.fields, doctype.displayField)) {
|
|
275
|
-
const named = flattenFields(doctype.fields).find(f => f.fieldname === doctype.displayField);
|
|
276
|
-
ctx.addIssue({
|
|
277
|
-
code: 'custom',
|
|
278
|
-
path: ['displayField'],
|
|
279
|
-
message: named
|
|
280
|
-
? `displayField "${doctype.displayField}" names a computed field, which has no column to read a display value from`
|
|
281
|
-
: `displayField "${doctype.displayField}" is not declared on this doctype`,
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
});
|
|
285
|
-
/**
|
|
286
|
-
* The one string a doctype is addressed by.
|
|
287
|
-
*
|
|
288
|
-
* A doctype carries two names — `name` (`OrderItem`) and `slug` (`order-item`) — and every registry
|
|
289
|
-
* must agree on which one keys it. Three implementations had drifted apart: the adapter's registry is
|
|
290
|
-
* keyed by `name` and its `getMeta` also scans for a matching `slug`, so it accepts **either**; the
|
|
291
|
-
* client's registry is keyed by a slug it derives itself and accepts **only** that; and
|
|
292
|
-
* `Doctype.fromObject` dropped an authored `slug` on the floor and re-derived one regardless. The
|
|
293
|
-
* adapter's accepted set was therefore a strict superset of the client's, and a link target written
|
|
294
|
-
* as the Name booted the server, passed its reference check, served rows over GraphQL, and was
|
|
295
|
-
* silently dropped by the client — an expanding child table rendering as one empty text input, with
|
|
296
|
-
* nothing logged.
|
|
297
|
-
*
|
|
298
|
-
* Resolving through this in both runtimes is what makes the two answers the same answer. It is the
|
|
299
|
-
* derivation only; a *lookup* still belongs to whichever registry owns the corpus, because the two
|
|
300
|
-
* corpora legitimately differ (a client registers lazily, and a client-only host has no adapter at
|
|
301
|
-
* all).
|
|
302
|
-
*
|
|
303
|
-
* An authored `slug` wins over the derived one because the authored doctype is the source of truth:
|
|
304
|
-
* generation verifies a file and never overwrites it, so a doctype that states its own slug means it.
|
|
305
|
-
* Deriving unconditionally is what `fromObject` did, and it made an authored `slug` a silent no-op on
|
|
306
|
-
* one side of the wire while the other honoured it.
|
|
307
|
-
*
|
|
308
|
-
* @param doctype - anything carrying a doctype's `name` and optional authored `slug`
|
|
309
|
-
* @returns the canonical slug
|
|
310
|
-
* @public
|
|
311
|
-
*
|
|
312
|
-
* @example
|
|
313
|
-
* ```typescript
|
|
314
|
-
* getDoctypeSlug({ name: 'OrderItem' }) // 'order-item'
|
|
315
|
-
* getDoctypeSlug({ name: 'Planner', slug: 'planner-board' }) // 'planner-board'
|
|
316
|
-
* ```
|
|
317
|
-
*/
|
|
318
|
-
export function getDoctypeSlug(doctype) {
|
|
319
|
-
// `||` rather than `??`: an empty authored slug is not a usable registry key, and this is
|
|
320
|
-
// reachable — `Doctype.fromObject` builds a doctype without going through the Zod gate, which is
|
|
321
|
-
// where `slug: z.string().min(1)` would have refused it.
|
|
322
|
-
return doctype.slug || toSlug(doctype.name);
|
|
323
|
-
}
|
|
324
|
-
/**
|
|
325
|
-
* Suffix appended to a link fieldname for its pre-resolved display text in record payloads.
|
|
326
|
-
*
|
|
327
|
-
* @deprecated The `__display` suffix pattern is no longer used. Inline link fields are enriched
|
|
328
|
-
* server-side by `@stonecrop/graphql-middleware` as `{ id, displayText }` objects on the link
|
|
329
|
-
* field itself.
|
|
330
|
-
* @public
|
|
331
|
-
*/
|
|
332
|
-
export const LINK_DISPLAY_SUFFIX = '__display';
|
|
333
|
-
/**
|
|
334
|
-
* Build the payload key for a link field's display text (e.g. `customerId__display`).
|
|
335
|
-
*
|
|
336
|
-
* @deprecated The `__display` suffix pattern is no longer used. Inline link fields are enriched
|
|
337
|
-
* server-side by `@stonecrop/graphql-middleware` as `{ id, displayText }` objects on the link
|
|
338
|
-
* field itself.
|
|
339
|
-
* @public
|
|
340
|
-
*/
|
|
341
|
-
export function linkDisplayFieldname(fieldname) {
|
|
342
|
-
return `${fieldname}${LINK_DISPLAY_SUFFIX}`;
|
|
343
|
-
}
|