@stonecrop/schema 0.25.0 → 0.27.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 +23 -0
- package/dist/cli.js +85 -59
- package/dist/cli.js.map +1 -1
- package/dist/index.js +68 -61
- package/dist/index.js.map +1 -1
- package/dist/schema.d.ts +256 -13
- package/dist/src/cli.js +53 -6
- package/dist/src/component-meta.d.ts.map +1 -1
- package/dist/src/component-meta.js +1 -0
- package/dist/src/converter/aggregate.d.ts +127 -0
- package/dist/src/converter/aggregate.d.ts.map +1 -0
- package/dist/src/converter/aggregate.js +235 -0
- package/dist/src/converter/authored.d.ts +43 -0
- package/dist/src/converter/authored.d.ts.map +1 -0
- package/dist/src/converter/authored.js +52 -0
- package/dist/src/converter/heuristics.d.ts +2 -2
- package/dist/src/converter/heuristics.d.ts.map +1 -1
- package/dist/src/converter/heuristics.js +43 -4
- package/dist/src/converter/index.d.ts +3 -1
- package/dist/src/converter/index.d.ts.map +1 -1
- package/dist/src/converter/index.js +2 -0
- package/dist/src/converter/merge.d.ts +25 -10
- package/dist/src/converter/merge.d.ts.map +1 -1
- package/dist/src/converter/merge.js +17 -26
- package/dist/src/doctype.d.ts +38 -0
- package/dist/src/doctype.d.ts.map +1 -1
- package/dist/src/doctype.js +55 -1
- package/dist/src/field.d.ts +59 -8
- package/dist/src/field.d.ts.map +1 -1
- package/dist/src/field.js +84 -14
- package/dist/src/index.d.ts +3 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -3
- package/dist/validation-BjRDR6sh.js +1000 -0
- package/dist/validation-BjRDR6sh.js.map +1 -0
- package/package.json +3 -1
- package/dist/validation-CQtfIFHQ.js +0 -583
- package/dist/validation-CQtfIFHQ.js.map +0 -1
package/dist/src/doctype.d.ts
CHANGED
|
@@ -249,6 +249,7 @@ export declare const DoctypeMeta: z.ZodObject<{
|
|
|
249
249
|
name: z.ZodString;
|
|
250
250
|
slug: z.ZodOptional<z.ZodString>;
|
|
251
251
|
displayField: z.ZodOptional<z.ZodString>;
|
|
252
|
+
route: z.ZodOptional<z.ZodString>;
|
|
252
253
|
fields: z.ZodArray<z.ZodType<import("./field").DoctypeField, unknown, z.core.$ZodTypeInternals<import("./field").DoctypeField, unknown>>>;
|
|
253
254
|
links: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
254
255
|
target: z.ZodString;
|
|
@@ -314,6 +315,43 @@ export declare const DoctypeMeta: z.ZodObject<{
|
|
|
314
315
|
* @public
|
|
315
316
|
*/
|
|
316
317
|
export type DoctypeMeta = z.infer<typeof DoctypeMeta>;
|
|
318
|
+
/**
|
|
319
|
+
* The one string a doctype is addressed by.
|
|
320
|
+
*
|
|
321
|
+
* A doctype carries two names — `name` (`OrderItem`) and `slug` (`order-item`) — and every registry
|
|
322
|
+
* must agree on which one keys it. Three implementations had drifted apart: the adapter's registry is
|
|
323
|
+
* keyed by `name` and its `getMeta` also scans for a matching `slug`, so it accepts **either**; the
|
|
324
|
+
* client's registry is keyed by a slug it derives itself and accepts **only** that; and
|
|
325
|
+
* `Doctype.fromObject` dropped an authored `slug` on the floor and re-derived one regardless. The
|
|
326
|
+
* adapter's accepted set was therefore a strict superset of the client's, and a link target written
|
|
327
|
+
* as the Name booted the server, passed its reference check, served rows over GraphQL, and was
|
|
328
|
+
* silently dropped by the client — an expanding child table rendering as one empty text input, with
|
|
329
|
+
* nothing logged.
|
|
330
|
+
*
|
|
331
|
+
* Resolving through this in both runtimes is what makes the two answers the same answer. It is the
|
|
332
|
+
* derivation only; a *lookup* still belongs to whichever registry owns the corpus, because the two
|
|
333
|
+
* corpora legitimately differ (a client registers lazily, and a client-only host has no adapter at
|
|
334
|
+
* all).
|
|
335
|
+
*
|
|
336
|
+
* An authored `slug` wins over the derived one because the authored doctype is the source of truth:
|
|
337
|
+
* generation verifies a file and never overwrites it, so a doctype that states its own slug means it.
|
|
338
|
+
* Deriving unconditionally is what `fromObject` did, and it made an authored `slug` a silent no-op on
|
|
339
|
+
* one side of the wire while the other honoured it.
|
|
340
|
+
*
|
|
341
|
+
* @param doctype - anything carrying a doctype's `name` and optional authored `slug`
|
|
342
|
+
* @returns the canonical slug
|
|
343
|
+
* @public
|
|
344
|
+
*
|
|
345
|
+
* @example
|
|
346
|
+
* ```typescript
|
|
347
|
+
* getDoctypeSlug({ name: 'OrderItem' }) // 'order-item'
|
|
348
|
+
* getDoctypeSlug({ name: 'Planner', slug: 'planner-board' }) // 'planner-board'
|
|
349
|
+
* ```
|
|
350
|
+
*/
|
|
351
|
+
export declare function getDoctypeSlug(doctype: {
|
|
352
|
+
name: string;
|
|
353
|
+
slug?: string;
|
|
354
|
+
}): string;
|
|
317
355
|
/**
|
|
318
356
|
* Suffix appended to a link fieldname for its pre-resolved display text in record payloads.
|
|
319
357
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctype.d.ts","sourceRoot":"","sources":["../../src/doctype.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;
|
|
1
|
+
{"version":3,"file":"doctype.d.ts","sourceRoot":"","sources":["../../src/doctype.ts"],"names":[],"mappings":"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"}
|
package/dist/src/doctype.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { DoctypeFieldSchema, flattenFields, getDisplayField } from './field';
|
|
3
|
+
import { toSlug } from './naming';
|
|
3
4
|
/**
|
|
4
5
|
* Cardinality for relationship links.
|
|
5
6
|
* @public
|
|
@@ -214,6 +215,16 @@ export const DoctypeMeta = z
|
|
|
214
215
|
* returns that field as `{ id, displayText }`, reading `displayText` from this field.
|
|
215
216
|
*/
|
|
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(),
|
|
217
228
|
/** Field definitions (a link field is one carrying `doctype`) */
|
|
218
229
|
fields: z.array(DoctypeFieldSchema),
|
|
219
230
|
/** Relationship links to other doctypes */
|
|
@@ -239,9 +250,13 @@ export const DoctypeMeta = z
|
|
|
239
250
|
// need not be unique — `stonecropRecord`'s row map then keeps whichever row comes last.
|
|
240
251
|
// Refusing at the gate is what makes it say so.
|
|
241
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
|
+
//
|
|
242
257
|
// Zero keys stays legal and is not an omission: a surrogate-key doctype declares none and
|
|
243
258
|
// resolves through `getRecordIdField`'s documented `id` fallback.
|
|
244
|
-
const declared = doctype.fields.filter(f => f.kind === 'field' && f.primaryKey);
|
|
259
|
+
const declared = flattenFields(doctype.fields).filter(f => f.kind === 'field' && f.primaryKey);
|
|
245
260
|
if (declared.length > 1) {
|
|
246
261
|
ctx.addIssue({
|
|
247
262
|
code: 'custom',
|
|
@@ -267,6 +282,45 @@ export const DoctypeMeta = z
|
|
|
267
282
|
});
|
|
268
283
|
}
|
|
269
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
|
+
}
|
|
270
324
|
/**
|
|
271
325
|
* Suffix appended to a link fieldname for its pre-resolved display text in record payloads.
|
|
272
326
|
*
|
package/dist/src/field.d.ts
CHANGED
|
@@ -73,6 +73,8 @@ export interface ValueField {
|
|
|
73
73
|
label?: string;
|
|
74
74
|
/** CSS width (e.g. `"40ch"`, `"200px"`) */
|
|
75
75
|
width?: string;
|
|
76
|
+
/** CSS height (e.g. `"100%"`, `"40vh"`) — used by full-viewport fields such as Planner */
|
|
77
|
+
height?: string;
|
|
76
78
|
/** Text alignment */
|
|
77
79
|
align?: 'left' | 'center' | 'right' | 'start' | 'end';
|
|
78
80
|
/** Whether the field is editable in table cell context */
|
|
@@ -157,6 +159,29 @@ export interface TableField {
|
|
|
157
159
|
* @public
|
|
158
160
|
*/
|
|
159
161
|
export type DoctypeField = ValueField | FieldsetField | TableField;
|
|
162
|
+
/**
|
|
163
|
+
* Which of the three field shapes an entry has, read from the entry's own structure.
|
|
164
|
+
*
|
|
165
|
+
* The single definition of that question. It had three copies before this — the parser's
|
|
166
|
+
* `injectKind`, {@link stripFieldKind}'s agreement check, and the docbuilder's own
|
|
167
|
+
* `isValueField` in another package — each free to drift, and drift here re-types a field rather
|
|
168
|
+
* than throwing: a value field read as a fieldset loses its column, a fieldset read as a value
|
|
169
|
+
* field loses every child.
|
|
170
|
+
*
|
|
171
|
+
* Deliberately **shape-only**: a declared `kind` is ignored. Two callers depend on that. The
|
|
172
|
+
* stripper compares this against the declaration to decide whether removing it is lossless, which
|
|
173
|
+
* it cannot do if this honours it. The docbuilder reads raw JSON off disk and classifies entries to
|
|
174
|
+
* decide which to render as editable rows — and `kind` is Stonecrop's own discriminant, not
|
|
175
|
+
* something a doctype author writes, so a tool reading a file has no business consulting it.
|
|
176
|
+
*
|
|
177
|
+
* `injectKind` is the one place a declaration still wins, and only to leave an already-parsed
|
|
178
|
+
* object untouched on its way back through.
|
|
179
|
+
*
|
|
180
|
+
* @param field - a field entry, authored or parsed
|
|
181
|
+
* @returns the kind its shape implies
|
|
182
|
+
* @public
|
|
183
|
+
*/
|
|
184
|
+
export declare function inferFieldKind(field: unknown): DoctypeField['kind'];
|
|
160
185
|
/**
|
|
161
186
|
* Recursively injects the `kind` discriminant into a raw field object and, for fieldsets,
|
|
162
187
|
* into each of its nested `schema` children — mirroring exactly what Zod's `preprocess`
|
|
@@ -173,6 +198,27 @@ export type DoctypeField = ValueField | FieldsetField | TableField;
|
|
|
173
198
|
* @public
|
|
174
199
|
*/
|
|
175
200
|
export declare function normalizeFieldKind(field: unknown): unknown;
|
|
201
|
+
/**
|
|
202
|
+
* Remove the `kind` discriminant from a field, recursing into a fieldset's children.
|
|
203
|
+
*
|
|
204
|
+
* The outbound half of the boundary {@link normalizeFieldKind} owns inbound. `kind` is a
|
|
205
|
+
* discriminated-union tag the parser synthesizes, not something an author writes, so nothing that
|
|
206
|
+
* *writes* a doctype should put it on disk — the generator and the docbuilder's save both call
|
|
207
|
+
* this. Without it the two round-trip asymmetrically: every save adds a key the file never had.
|
|
208
|
+
*
|
|
209
|
+
* Strips only when `injectKind` would restore exactly what was removed. A fieldset carrying no
|
|
210
|
+
* `schema` re-infers as a plain field, so its `kind` is kept rather than silently re-typing the
|
|
211
|
+
* document; `DoctypeMeta` requires `schema` on a fieldset, so that shape is already invalid and
|
|
212
|
+
* belongs to the load gate, not here.
|
|
213
|
+
*
|
|
214
|
+
* Table `columns` are {@link ColumnSchema} entries rather than `DoctypeField`s and never carry an
|
|
215
|
+
* injected `kind`, so they are passed through untouched — the same asymmetry `injectKind` has.
|
|
216
|
+
*
|
|
217
|
+
* @param field - a field object, as held in memory after parsing
|
|
218
|
+
* @returns the field without `kind`, safe to serialize
|
|
219
|
+
* @public
|
|
220
|
+
*/
|
|
221
|
+
export declare function stripFieldKind(field: unknown): unknown;
|
|
176
222
|
/**
|
|
177
223
|
* The field properties a `source: 'introspected'` marker freezes — the ones the database owns.
|
|
178
224
|
*
|
|
@@ -194,15 +240,19 @@ export declare const INTROSPECTED_IDENTITY_PROPS: readonly ["fieldname", "primar
|
|
|
194
240
|
* route/store key from it. Call this; never re-derive the rule at the call site, or the two will
|
|
195
241
|
* drift and the client will key records by a column the server never queried.
|
|
196
242
|
*
|
|
197
|
-
* Two deliberate
|
|
198
|
-
* -
|
|
199
|
-
* children are
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
243
|
+
* Two deliberate rules, both matching the shape `primaryKey` actually has:
|
|
244
|
+
* - Fieldset children are **included**, via {@link flattenFields}. A fieldset is layout, not
|
|
245
|
+
* scope: its children are fields of the doctype with columns of their own, which is why the
|
|
246
|
+
* adapter's SELECT already descends and why `getDisplayField` does too. Scanning top level only
|
|
247
|
+
* did not *refuse* a nested declaration — it ignored one, so an author marked identity and
|
|
248
|
+
* nothing honoured it and nothing said so.
|
|
249
|
+
* - The **first** match in document order wins. Identity is single-valued by design — a doctype
|
|
250
|
+
* describes the API surface, and mapping a composite database key onto one identity there is the
|
|
251
|
+
* adapter's job — so a doctype declaring several is malformed rather than composite.
|
|
252
|
+
* `DoctypeMeta` rejects that at the load gate; this stays total for callers holding fields that
|
|
253
|
+
* never went through it.
|
|
204
254
|
*
|
|
205
|
-
* @param fields - the doctype's
|
|
255
|
+
* @param fields - the doctype's fields; fieldset children are descended into
|
|
206
256
|
* @returns the primary-key field, or `undefined` for a PK-less doctype
|
|
207
257
|
* @public
|
|
208
258
|
*/
|
|
@@ -298,6 +348,7 @@ export declare const ValueFieldSchema: z.ZodObject<{
|
|
|
298
348
|
doctype: z.ZodOptional<z.ZodString>;
|
|
299
349
|
label: z.ZodOptional<z.ZodString>;
|
|
300
350
|
width: z.ZodOptional<z.ZodString>;
|
|
351
|
+
height: z.ZodOptional<z.ZodString>;
|
|
301
352
|
align: z.ZodOptional<z.ZodEnum<{
|
|
302
353
|
left: "left";
|
|
303
354
|
right: "right";
|
package/dist/src/field.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"field.d.ts","sourceRoot":"","sources":["../../src/field.ts"],"names":[],"mappings":"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
|
|
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;;;;;;;;;;;;;;GAcG;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;;iBAQzB,CAAA;AAEH;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAA;AAM7D;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IAC1B,+DAA+D;IAC/D,IAAI,EAAE,OAAO,CAAA;IACb,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAA;IACjB;;;;;OAKG;IACH,SAAS,EAAE,MAAM,CAAA;IACjB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;kFAC8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,0FAA0F;IAC1F,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,KAAK,CAAA;IACrD,0DAA0D;IAC1D,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;wFAGoF;IACpF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,0CAA0C;IAC1C,IAAI,CAAC,EAAE,eAAe,CAAA;IACtB;kCAC8B;IAC9B,OAAO,CAAC,EAAE,YAAY,CAAA;IACtB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,qCAAqC;IACrC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,oCAAoC;IACpC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,+BAA+B;IAC/B,UAAU,CAAC,EAAE,eAAe,CAAA;IAC5B,4FAA4F;IAC5F,WAAW,CAAC,EAAE,WAAW,GAAG,KAAK,GAAG,YAAY,GAAG,YAAY,CAAA;IAC/D;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,cAAc,CAAA;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC7B,8DAA8D;IAC9D,IAAI,EAAE,UAAU,CAAA;IAChB,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAA;IACjB,yFAAyF;IACzF,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,4CAA4C;IAC5C,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,6DAA6D;IAC7D,IAAI,CAAC,EAAE,eAAe,CAAA;IACtB,uEAAuE;IACvE,MAAM,EAAE,YAAY,EAAE,CAAA;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,UAAU;IAC1B,yDAAyD;IACzD,IAAI,EAAE,OAAO,CAAA;IACb,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAA;IACjB,mFAAmF;IACnF,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,oFAAoF;IACpF,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,uFAAuF;IACvF,MAAM,CAAC,EAAE,eAAe,CAAA;IACxB,uDAAuD;IACvD,IAAI,CAAC,EAAE,eAAe,CAAA;CACtB;AAED;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,aAAa,GAAG,UAAU,CAAA;AAMlE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,CAKnE;AAiCD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAS1D;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAYtD;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,2BAA2B,uFAO9B,CAAA;AAEV;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,GAAG,UAAU,GAAG,SAAS,CAE1F;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,GAAG,CAAC,UAAU,GAAG,UAAU,CAAC,EAAE,CAU1F;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,eAAe,CAC9B,MAAM,EAAE,SAAS,YAAY,EAAE,EAC/B,YAAY,EAAE,MAAM,GAAG,SAAS,GAC9B,UAAU,GAAG,SAAS,CAKxB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,GAAG,MAAM,CAExE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAChC,MAAM,EAAE,SAAS,YAAY,EAAE,EAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,MAAM,GAAG,SAAS,CAUpB;AA8ED;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAA2B,CAAA;AAExD;;;;GAIG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;iBAA8B,CAAA;AAE9D;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAA2B,CAAA;AAExD;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,mFAA6B,CAAA"}
|
package/dist/src/field.js
CHANGED
|
@@ -40,6 +40,37 @@ export const FieldValidation = z
|
|
|
40
40
|
// ---------------------------------------------------------------------------
|
|
41
41
|
// Zod runtime validation schemas
|
|
42
42
|
// ---------------------------------------------------------------------------
|
|
43
|
+
/**
|
|
44
|
+
* Which of the three field shapes an entry has, read from the entry's own structure.
|
|
45
|
+
*
|
|
46
|
+
* The single definition of that question. It had three copies before this — the parser's
|
|
47
|
+
* `injectKind`, {@link stripFieldKind}'s agreement check, and the docbuilder's own
|
|
48
|
+
* `isValueField` in another package — each free to drift, and drift here re-types a field rather
|
|
49
|
+
* than throwing: a value field read as a fieldset loses its column, a fieldset read as a value
|
|
50
|
+
* field loses every child.
|
|
51
|
+
*
|
|
52
|
+
* Deliberately **shape-only**: a declared `kind` is ignored. Two callers depend on that. The
|
|
53
|
+
* stripper compares this against the declaration to decide whether removing it is lossless, which
|
|
54
|
+
* it cannot do if this honours it. The docbuilder reads raw JSON off disk and classifies entries to
|
|
55
|
+
* decide which to render as editable rows — and `kind` is Stonecrop's own discriminant, not
|
|
56
|
+
* something a doctype author writes, so a tool reading a file has no business consulting it.
|
|
57
|
+
*
|
|
58
|
+
* `injectKind` is the one place a declaration still wins, and only to leave an already-parsed
|
|
59
|
+
* object untouched on its way back through.
|
|
60
|
+
*
|
|
61
|
+
* @param field - a field entry, authored or parsed
|
|
62
|
+
* @returns the kind its shape implies
|
|
63
|
+
* @public
|
|
64
|
+
*/
|
|
65
|
+
export function inferFieldKind(field) {
|
|
66
|
+
if (typeof field !== 'object' || field === null || Array.isArray(field))
|
|
67
|
+
return 'field';
|
|
68
|
+
if ('schema' in field)
|
|
69
|
+
return 'fieldset';
|
|
70
|
+
if ('columns' in field)
|
|
71
|
+
return 'table';
|
|
72
|
+
return 'field';
|
|
73
|
+
}
|
|
43
74
|
/**
|
|
44
75
|
* Infers the `kind` discriminant from the structural properties of a raw field
|
|
45
76
|
* object, then injects it if absent. This allows authored JSON to omit `kind`
|
|
@@ -63,13 +94,14 @@ function injectKind(data) {
|
|
|
63
94
|
return data;
|
|
64
95
|
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- safe: non-null, non-array object verified by guards above
|
|
65
96
|
const obj = data;
|
|
97
|
+
// An explicit `kind` is left exactly as it was found: this is the one place a declaration still
|
|
98
|
+
// beats the shape, and only so an already-parsed object survives a second pass unchanged.
|
|
99
|
+
// Returning `data` itself rather than rebuilding it also preserves identity and key order.
|
|
100
|
+
// Nothing outside this function shares that precedence — a reader classifying a file on disk
|
|
101
|
+
// wants `inferFieldKind`, because `kind` is ours and no author writes it.
|
|
66
102
|
if ('kind' in obj)
|
|
67
103
|
return data;
|
|
68
|
-
|
|
69
|
-
return { kind: 'fieldset', ...obj };
|
|
70
|
-
if ('columns' in obj)
|
|
71
|
-
return { kind: 'table', ...obj };
|
|
72
|
-
return { kind: 'field', ...obj };
|
|
104
|
+
return { kind: inferFieldKind(obj), ...obj };
|
|
73
105
|
}
|
|
74
106
|
/**
|
|
75
107
|
* Recursively injects the `kind` discriminant into a raw field object and, for fieldsets,
|
|
@@ -97,6 +129,39 @@ export function normalizeFieldKind(field) {
|
|
|
97
129
|
}
|
|
98
130
|
return injected;
|
|
99
131
|
}
|
|
132
|
+
/**
|
|
133
|
+
* Remove the `kind` discriminant from a field, recursing into a fieldset's children.
|
|
134
|
+
*
|
|
135
|
+
* The outbound half of the boundary {@link normalizeFieldKind} owns inbound. `kind` is a
|
|
136
|
+
* discriminated-union tag the parser synthesizes, not something an author writes, so nothing that
|
|
137
|
+
* *writes* a doctype should put it on disk — the generator and the docbuilder's save both call
|
|
138
|
+
* this. Without it the two round-trip asymmetrically: every save adds a key the file never had.
|
|
139
|
+
*
|
|
140
|
+
* Strips only when `injectKind` would restore exactly what was removed. A fieldset carrying no
|
|
141
|
+
* `schema` re-infers as a plain field, so its `kind` is kept rather than silently re-typing the
|
|
142
|
+
* document; `DoctypeMeta` requires `schema` on a fieldset, so that shape is already invalid and
|
|
143
|
+
* belongs to the load gate, not here.
|
|
144
|
+
*
|
|
145
|
+
* Table `columns` are {@link ColumnSchema} entries rather than `DoctypeField`s and never carry an
|
|
146
|
+
* injected `kind`, so they are passed through untouched — the same asymmetry `injectKind` has.
|
|
147
|
+
*
|
|
148
|
+
* @param field - a field object, as held in memory after parsing
|
|
149
|
+
* @returns the field without `kind`, safe to serialize
|
|
150
|
+
* @public
|
|
151
|
+
*/
|
|
152
|
+
export function stripFieldKind(field) {
|
|
153
|
+
if (typeof field !== 'object' || field === null || Array.isArray(field))
|
|
154
|
+
return field;
|
|
155
|
+
// oxlint-disable-next-line typescript/no-unsafe-type-assertion -- safe: non-null, non-array object verified by the guard above
|
|
156
|
+
const obj = field;
|
|
157
|
+
if (obj.kind !== undefined && obj.kind !== inferFieldKind(obj))
|
|
158
|
+
return field;
|
|
159
|
+
const { kind: _kind, ...rest } = obj;
|
|
160
|
+
if (Array.isArray(rest.schema)) {
|
|
161
|
+
return { ...rest, schema: rest.schema.map(stripFieldKind) };
|
|
162
|
+
}
|
|
163
|
+
return rest;
|
|
164
|
+
}
|
|
100
165
|
/**
|
|
101
166
|
* The field properties a `source: 'introspected'` marker freezes — the ones the database owns.
|
|
102
167
|
*
|
|
@@ -125,20 +190,24 @@ export const INTROSPECTED_IDENTITY_PROPS = [
|
|
|
125
190
|
* route/store key from it. Call this; never re-derive the rule at the call site, or the two will
|
|
126
191
|
* drift and the client will key records by a column the server never queried.
|
|
127
192
|
*
|
|
128
|
-
* Two deliberate
|
|
129
|
-
* -
|
|
130
|
-
* children are
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
193
|
+
* Two deliberate rules, both matching the shape `primaryKey` actually has:
|
|
194
|
+
* - Fieldset children are **included**, via {@link flattenFields}. A fieldset is layout, not
|
|
195
|
+
* scope: its children are fields of the doctype with columns of their own, which is why the
|
|
196
|
+
* adapter's SELECT already descends and why `getDisplayField` does too. Scanning top level only
|
|
197
|
+
* did not *refuse* a nested declaration — it ignored one, so an author marked identity and
|
|
198
|
+
* nothing honoured it and nothing said so.
|
|
199
|
+
* - The **first** match in document order wins. Identity is single-valued by design — a doctype
|
|
200
|
+
* describes the API surface, and mapping a composite database key onto one identity there is the
|
|
201
|
+
* adapter's job — so a doctype declaring several is malformed rather than composite.
|
|
202
|
+
* `DoctypeMeta` rejects that at the load gate; this stays total for callers holding fields that
|
|
203
|
+
* never went through it.
|
|
135
204
|
*
|
|
136
|
-
* @param fields - the doctype's
|
|
205
|
+
* @param fields - the doctype's fields; fieldset children are descended into
|
|
137
206
|
* @returns the primary-key field, or `undefined` for a PK-less doctype
|
|
138
207
|
* @public
|
|
139
208
|
*/
|
|
140
209
|
export function getPrimaryKeyField(fields) {
|
|
141
|
-
return fields.find((f) => f.kind === 'field' && Boolean(f.primaryKey));
|
|
210
|
+
return flattenFields(fields).find((f) => f.kind === 'field' && Boolean(f.primaryKey));
|
|
142
211
|
}
|
|
143
212
|
/**
|
|
144
213
|
* Recursively flatten Fieldset containers into a flat array of non-container fields.
|
|
@@ -257,6 +326,7 @@ function createDoctypeFieldSchemas() {
|
|
|
257
326
|
doctype: z.string().min(1).optional(),
|
|
258
327
|
label: z.string().optional(),
|
|
259
328
|
width: z.string().optional(),
|
|
329
|
+
height: z.string().optional(),
|
|
260
330
|
align: z.enum(['left', 'center', 'right', 'start', 'end']).optional(),
|
|
261
331
|
edit: z.boolean().optional(),
|
|
262
332
|
mask: z.string().optional(),
|
package/dist/src/index.d.ts
CHANGED
|
@@ -2,11 +2,11 @@ export type { InteractionMode } from './mode';
|
|
|
2
2
|
export { TableViewConfig } from './table';
|
|
3
3
|
export { CANONICAL_COMPONENTS, COMPONENT_CATEGORY, COMPONENT_LINK_EXPANSION, componentCategory, componentLinkExpansion, resolveLinkRenderMode, type ComponentCategory, type LinkExpansion, type LinkRenderMode, } from './component-meta';
|
|
4
4
|
export type { DoctypeField, FieldOptions, FieldValidation, FieldsetField, TableField, ValueField } from './field';
|
|
5
|
-
export { DoctypeFieldSchema, FieldsetFieldSchema, flattenFields, getDisplayField, getPrimaryKeyField, getRecordIdentity, getRecordIdField, INTROSPECTED_IDENTITY_PROPS, normalizeFieldKind, TableFieldSchema, ValueFieldSchema, } from './field';
|
|
6
|
-
export { ActionDefinition, TriggerDefinition, WorkflowLayout, WorkflowMeta, isActionAllowedInState, LINK_DISPLAY_SUFFIX, linkDisplayFieldname, } from './doctype';
|
|
5
|
+
export { DoctypeFieldSchema, FieldsetFieldSchema, flattenFields, getDisplayField, getPrimaryKeyField, getRecordIdentity, getRecordIdField, INTROSPECTED_IDENTITY_PROPS, normalizeFieldKind, inferFieldKind, stripFieldKind, TableFieldSchema, ValueFieldSchema, } from './field';
|
|
6
|
+
export { ActionDefinition, TriggerDefinition, WorkflowLayout, WorkflowMeta, getDoctypeSlug, isActionAllowedInState, LINK_DISPLAY_SUFFIX, linkDisplayFieldname, } from './doctype';
|
|
7
7
|
export type { Cardinality, CustomFetch, DataClient, DoctypeContext, DoctypeMeta, DoctypeRef, FetchStrategy, GetRecordOptions, GetRecordResult, GetRecordsOptions, GetRecordsResult, LazyFetch, LinkDeclaration, SerializedFunction, SyncFetch, } from './doctype';
|
|
8
8
|
export { parseDoctype, parseField, validateDoctype, validateField, type ValidationError, type ValidationResult, } from './validation';
|
|
9
|
-
export { buildScalarMap, classifyFieldType, convertGraphQLSchema, defaultIsEntityField, defaultIsEntityType, formatDoctypeDrift, GQL_SCALAR_MAP, INTERNAL_SCALARS, mergeIntrospectedDoctype, WELL_KNOWN_SCALARS, type AuthoredDoctype, type ConvertedGraphQLDoctype, type DoctypeDrift, type GraphQLConversionFieldMeta, type GraphQLConversionOptions, type IntrospectionSource, type MergeResult, } from './converter';
|
|
9
|
+
export { aggregateDoctypeName, buildAggregateDoctype, buildScalarMap, classifyFieldType, convertGraphQLSchema, defaultIsEntityField, defaultIsEntityType, formatDoctypeDrift, GQL_SCALAR_MAP, INTERNAL_SCALARS, mergeIntrospectedDoctype, planGeneration, WELL_KNOWN_SCALARS, type AuthoredDoctype, type ConvertedGraphQLDoctype, type DoctypeDrift, type GraphQLConversionFieldMeta, type GenerationPlanEntry, type GenerationPlanOptions, type GraphQLConversionOptions, type IntrospectionSource, type MergeOptions, type MergeResult, } from './converter';
|
|
10
10
|
export { toSlug, toPascalCase, pascalToSnake, snakeToCamel, camelToSnake, snakeToLabel, camelToLabel } from './naming';
|
|
11
11
|
export type { ColumnSchema } from './column-schema';
|
|
12
12
|
export type { BadgeDescriptor, BadgePresentation, BadgeSpec, BadgeSpecObject, BadgeVariant, SelectOptions, } from './badge';
|
package/dist/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAA;AAG7C,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAGzC,OAAO,EACN,oBAAoB,EACpB,kBAAkB,EAClB,wBAAwB,EACxB,iBAAiB,EACjB,sBAAsB,EACtB,qBAAqB,EACrB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,cAAc,GACnB,MAAM,kBAAkB,CAAA;AAGzB,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACjH,OAAO,EACN,kBAAkB,EAClB,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,2BAA2B,EAC3B,kBAAkB,EAClB,gBAAgB,EAChB,gBAAgB,GAChB,MAAM,SAAS,CAAA;AAKhB,OAAO,EACN,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,YAAY,EACZ,sBAAsB,EACtB,mBAAmB,EACnB,oBAAoB,GACpB,MAAM,WAAW,CAAA;AAClB,YAAY,EACX,WAAW,EACX,WAAW,EACX,UAAU,EACV,cAAc,EACd,WAAW,EACX,UAAU,EACV,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,SAAS,EACT,eAAe,EACf,kBAAkB,EAClB,SAAS,GACT,MAAM,WAAW,CAAA;AAGlB,OAAO,EACN,YAAY,EACZ,UAAU,EACV,eAAe,EACf,aAAa,EACb,KAAK,eAAe,EACpB,KAAK,gBAAgB,GACrB,MAAM,cAAc,CAAA;AAGrB,OAAO,EACN,cAAc,EACd,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,wBAAwB,EACxB,kBAAkB,EAClB,KAAK,eAAe,EACpB,KAAK,uBAAuB,EAC5B,KAAK,YAAY,EACjB,KAAK,0BAA0B,EAC/B,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EACxB,KAAK,WAAW,GAChB,MAAM,aAAa,CAAA;AAGpB,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAGtH,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAGnD,YAAY,EACX,eAAe,EACf,iBAAiB,EACjB,SAAS,EACT,eAAe,EACf,YAAY,EACZ,aAAa,GACb,MAAM,SAAS,CAAA;AAChB,OAAO,EACN,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,WAAW,EACX,aAAa,GACb,MAAM,SAAS,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAA;AAG7C,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAGzC,OAAO,EACN,oBAAoB,EACpB,kBAAkB,EAClB,wBAAwB,EACxB,iBAAiB,EACjB,sBAAsB,EACtB,qBAAqB,EACrB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,cAAc,GACnB,MAAM,kBAAkB,CAAA;AAGzB,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACjH,OAAO,EACN,kBAAkB,EAClB,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,2BAA2B,EAC3B,kBAAkB,EAClB,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,gBAAgB,GAChB,MAAM,SAAS,CAAA;AAKhB,OAAO,EACN,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,YAAY,EACZ,cAAc,EACd,sBAAsB,EACtB,mBAAmB,EACnB,oBAAoB,GACpB,MAAM,WAAW,CAAA;AAClB,YAAY,EACX,WAAW,EACX,WAAW,EACX,UAAU,EACV,cAAc,EACd,WAAW,EACX,UAAU,EACV,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,SAAS,EACT,eAAe,EACf,kBAAkB,EAClB,SAAS,GACT,MAAM,WAAW,CAAA;AAGlB,OAAO,EACN,YAAY,EACZ,UAAU,EACV,eAAe,EACf,aAAa,EACb,KAAK,eAAe,EACpB,KAAK,gBAAgB,GACrB,MAAM,cAAc,CAAA;AAGrB,OAAO,EACN,oBAAoB,EACpB,qBAAqB,EACrB,cAAc,EACd,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,wBAAwB,EACxB,cAAc,EACd,kBAAkB,EAClB,KAAK,eAAe,EACpB,KAAK,uBAAuB,EAC5B,KAAK,YAAY,EACjB,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,WAAW,GAChB,MAAM,aAAa,CAAA;AAGpB,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAGtH,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAGnD,YAAY,EACX,eAAe,EACf,iBAAiB,EACjB,SAAS,EACT,eAAe,EACf,YAAY,EACZ,aAAa,GACb,MAAM,SAAS,CAAA;AAChB,OAAO,EACN,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,WAAW,EACX,aAAa,GACb,MAAM,SAAS,CAAA"}
|
package/dist/src/index.js
CHANGED
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
export { TableViewConfig } from './table';
|
|
3
3
|
// Component → semantic category — the single source of "what kind of value does this component render"
|
|
4
4
|
export { CANONICAL_COMPONENTS, COMPONENT_CATEGORY, COMPONENT_LINK_EXPANSION, componentCategory, componentLinkExpansion, resolveLinkRenderMode, } from './component-meta';
|
|
5
|
-
export { DoctypeFieldSchema, FieldsetFieldSchema, flattenFields, getDisplayField, getPrimaryKeyField, getRecordIdentity, getRecordIdField, INTROSPECTED_IDENTITY_PROPS, normalizeFieldKind, TableFieldSchema, ValueFieldSchema, } from './field';
|
|
5
|
+
export { DoctypeFieldSchema, FieldsetFieldSchema, flattenFields, getDisplayField, getPrimaryKeyField, getRecordIdentity, getRecordIdField, INTROSPECTED_IDENTITY_PROPS, normalizeFieldKind, inferFieldKind, stripFieldKind, TableFieldSchema, ValueFieldSchema, } from './field';
|
|
6
6
|
// Doctype schema
|
|
7
7
|
// ActionDefinition and WorkflowMeta are exported as values (Zod schemas) so consumers can use
|
|
8
8
|
// .safeParse(), .shape, etc. at runtime. TypeScript types are inferred from the same exports.
|
|
9
|
-
export { ActionDefinition, TriggerDefinition, WorkflowLayout, WorkflowMeta, isActionAllowedInState, LINK_DISPLAY_SUFFIX, linkDisplayFieldname, } from './doctype';
|
|
9
|
+
export { ActionDefinition, TriggerDefinition, WorkflowLayout, WorkflowMeta, getDoctypeSlug, isActionAllowedInState, LINK_DISPLAY_SUFFIX, linkDisplayFieldname, } from './doctype';
|
|
10
10
|
// Validation helpers
|
|
11
11
|
export { parseDoctype, parseField, validateDoctype, validateField, } from './validation';
|
|
12
12
|
// GraphQL to Doctype conversion
|
|
13
|
-
export { buildScalarMap, classifyFieldType, convertGraphQLSchema, defaultIsEntityField, defaultIsEntityType, formatDoctypeDrift, GQL_SCALAR_MAP, INTERNAL_SCALARS, mergeIntrospectedDoctype, WELL_KNOWN_SCALARS, } from './converter';
|
|
13
|
+
export { aggregateDoctypeName, buildAggregateDoctype, buildScalarMap, classifyFieldType, convertGraphQLSchema, defaultIsEntityField, defaultIsEntityType, formatDoctypeDrift, GQL_SCALAR_MAP, INTERNAL_SCALARS, mergeIntrospectedDoctype, planGeneration, WELL_KNOWN_SCALARS, } from './converter';
|
|
14
14
|
// Naming utilities
|
|
15
15
|
export { toSlug, toPascalCase, pascalToSnake, snakeToCamel, camelToSnake, snakeToLabel, camelToLabel } from './naming';
|
|
16
16
|
export { hasBadgeOptions, isBadgeDescriptor, isSelectChoiceMap, isSelectOptions, lookupBadge, selectChoices, } from './badge';
|