@stonecrop/schema 0.10.15 → 0.11.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 +87 -26
- package/dist/cli.cjs +41 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/converter/heuristics.js +8 -6
- package/dist/converter/index.js +20 -3
- package/dist/converter-DNwpowpq.js +459 -0
- package/dist/converter-DNwpowpq.js.map +1 -0
- package/dist/doctype.js +90 -5
- package/dist/field.js +5 -3
- package/dist/fieldtype.js +0 -2
- package/dist/index-0qWNlDQ5.js +450 -0
- package/dist/index-0qWNlDQ5.js.map +1 -0
- package/dist/index-2UVTfbcY.js +448 -0
- package/dist/index-2UVTfbcY.js.map +1 -0
- package/dist/index-9QjWZ_PC.js +449 -0
- package/dist/index-9QjWZ_PC.js.map +1 -0
- package/dist/index-BCADNO5M.js +449 -0
- package/dist/index-BCADNO5M.js.map +1 -0
- package/dist/index-BRQJGVFR.js +453 -0
- package/dist/index-BRQJGVFR.js.map +1 -0
- package/dist/index-BatnoC-J.js +429 -0
- package/dist/index-BatnoC-J.js.map +1 -0
- package/dist/index-BhMd2_xl.js +454 -0
- package/dist/index-BhMd2_xl.js.map +1 -0
- package/dist/index-CLc5mUMQ.js +478 -0
- package/dist/index-CLc5mUMQ.js.map +1 -0
- package/dist/index-COrltkHl.js +401 -0
- package/dist/index-COrltkHl.js.map +1 -0
- package/dist/index-CvN9xK1B.js +453 -0
- package/dist/index-CvN9xK1B.js.map +1 -0
- package/dist/index-CzoRIy1-.js +408 -0
- package/dist/index-CzoRIy1-.js.map +1 -0
- package/dist/index-DIb_Z0wI.js +476 -0
- package/dist/index-DIb_Z0wI.js.map +1 -0
- package/dist/index-DNROIEMe.js +449 -0
- package/dist/index-DNROIEMe.js.map +1 -0
- package/dist/index-DUFcQC-H.js +449 -0
- package/dist/index-DUFcQC-H.js.map +1 -0
- package/dist/index-DmD8vmuB.js +449 -0
- package/dist/index-DmD8vmuB.js.map +1 -0
- package/dist/index-XZZbfFxT.js +434 -0
- package/dist/index-XZZbfFxT.js.map +1 -0
- package/dist/index-aeXXzPET.cjs +2 -0
- package/dist/index-aeXXzPET.cjs.map +1 -0
- package/dist/index-neVkjlgB.js +446 -0
- package/dist/index-neVkjlgB.js.map +1 -0
- package/dist/index-xdlVWldg.js +408 -0
- package/dist/index-xdlVWldg.js.map +1 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +23 -29
- package/dist/jsonschema.js +225 -0
- package/dist/schema.d.ts +206 -35
- package/dist/src/cli.js +210 -0
- package/dist/src/converter/heuristics.d.ts.map +1 -1
- package/dist/src/converter/heuristics.js +256 -0
- package/dist/src/converter/index.d.ts.map +1 -1
- package/dist/src/converter/index.js +164 -0
- package/dist/src/converter/scalars.js +86 -0
- package/dist/src/converter/types.d.ts +2 -0
- package/dist/src/converter/types.d.ts.map +1 -1
- package/dist/src/converter/types.js +5 -0
- package/dist/src/doctype.d.ts +176 -12
- package/dist/src/doctype.d.ts.map +1 -1
- package/dist/src/doctype.js +67 -0
- package/dist/src/field.d.ts +3 -2
- package/dist/src/field.d.ts.map +1 -1
- package/dist/src/field.js +108 -0
- package/dist/src/fieldtype.d.ts +0 -1
- package/dist/src/fieldtype.d.ts.map +1 -1
- package/dist/src/fieldtype.js +75 -0
- package/dist/src/index.d.ts +5 -9
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +12 -0
- package/dist/src/jsonschema.d.ts +95 -0
- package/dist/src/jsonschema.d.ts.map +1 -0
- package/dist/src/naming.js +106 -0
- package/dist/src/tsdoc-metadata.json +11 -0
- package/dist/src/validation.js +60 -0
- package/package.json +1 -1
package/dist/schema.d.ts
CHANGED
|
@@ -58,6 +58,23 @@ export declare function camelToLabel(camelCase: string): string;
|
|
|
58
58
|
*/
|
|
59
59
|
export declare function camelToSnake(camelCase: string): string;
|
|
60
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Cardinality for relationship links.
|
|
63
|
+
* @public
|
|
64
|
+
*/
|
|
65
|
+
export declare const Cardinality: z.ZodEnum<{
|
|
66
|
+
one: "one";
|
|
67
|
+
atMostOne: "atMostOne";
|
|
68
|
+
noneOrMany: "noneOrMany";
|
|
69
|
+
atLeastOne: "atLeastOne";
|
|
70
|
+
}>;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Cardinality type inferred from Zod schema
|
|
74
|
+
* @public
|
|
75
|
+
*/
|
|
76
|
+
export declare type Cardinality = z.infer<typeof Cardinality>;
|
|
77
|
+
|
|
61
78
|
/**
|
|
62
79
|
* Classify a single GraphQL field into a Stonecrop field definition.
|
|
63
80
|
*
|
|
@@ -123,6 +140,21 @@ export declare interface ConvertedGraphQLDoctype extends Omit<DoctypeMeta, 'fiel
|
|
|
123
140
|
*/
|
|
124
141
|
export declare function convertGraphQLSchema(source: IntrospectionSource, options?: GraphQLConversionOptions): ConvertedGraphQLDoctype[];
|
|
125
142
|
|
|
143
|
+
/**
|
|
144
|
+
* Custom fetch strategy - uses a custom handler function.
|
|
145
|
+
* @public
|
|
146
|
+
*/
|
|
147
|
+
export declare const CustomFetch: z.ZodObject<{
|
|
148
|
+
method: z.ZodLiteral<"custom">;
|
|
149
|
+
handler: z.ZodString;
|
|
150
|
+
}, z.core.$strip>;
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Custom fetch strategy type
|
|
154
|
+
* @public
|
|
155
|
+
*/
|
|
156
|
+
export declare type CustomFetch = z.infer<typeof CustomFetch>;
|
|
157
|
+
|
|
126
158
|
/**
|
|
127
159
|
* Interface for data clients that fetch doctype metadata and records.
|
|
128
160
|
* Implemented by \@stonecrop/graphql-client's StonecropClient.
|
|
@@ -141,23 +173,23 @@ export declare interface DataClient<T extends DoctypeRef = DoctypeRef, M = Docty
|
|
|
141
173
|
getMeta(context: DoctypeContext): Promise<M | null>;
|
|
142
174
|
/**
|
|
143
175
|
* Fetch a single record by ID
|
|
176
|
+
*
|
|
177
|
+
* When `includeNested` is set, builds a query with sub-selections for descendant
|
|
178
|
+
* links and returns ancestor + merged descendants. When omitted, returns flat scalar data.
|
|
179
|
+
*
|
|
144
180
|
* @param doctype - Doctype reference (name and optional slug)
|
|
145
181
|
* @param recordId - Record ID to fetch
|
|
182
|
+
* @param options - Query options
|
|
146
183
|
* @returns Record data or null if not found
|
|
147
184
|
*/
|
|
148
|
-
getRecord(doctype: T, recordId: string): Promise<Record<string, unknown> | null>;
|
|
185
|
+
getRecord(doctype: T, recordId: string, options?: GetRecordOptions): Promise<Record<string, unknown> | null>;
|
|
149
186
|
/**
|
|
150
187
|
* Fetch multiple records
|
|
151
188
|
* @param doctype - Doctype reference (name and optional slug)
|
|
152
|
-
* @param options -
|
|
189
|
+
* @param options - Query options
|
|
153
190
|
* @returns Array of record data
|
|
154
191
|
*/
|
|
155
|
-
getRecords(doctype: T, options?:
|
|
156
|
-
filters?: Record<string, unknown>;
|
|
157
|
-
orderBy?: string;
|
|
158
|
-
limit?: number;
|
|
159
|
-
offset?: number;
|
|
160
|
-
}): Promise<Record<string, unknown>[]>;
|
|
192
|
+
getRecords(doctype: T, options?: GetRecordsOptions): Promise<Record<string, unknown>[]>;
|
|
161
193
|
/**
|
|
162
194
|
* Execute a doctype action (e.g., SUBMIT, APPROVE, save).
|
|
163
195
|
* All state changes flow through this single mutation endpoint.
|
|
@@ -221,7 +253,7 @@ export declare interface DoctypeContext {
|
|
|
221
253
|
* Doctype metadata - complete definition of a doctype
|
|
222
254
|
* @public
|
|
223
255
|
*/
|
|
224
|
-
declare const DoctypeMeta: z.ZodObject<{
|
|
256
|
+
export declare const DoctypeMeta: z.ZodObject<{
|
|
225
257
|
name: z.ZodString;
|
|
226
258
|
slug: z.ZodOptional<z.ZodString>;
|
|
227
259
|
tableName: z.ZodOptional<z.ZodString>;
|
|
@@ -242,7 +274,6 @@ declare const DoctypeMeta: z.ZodObject<{
|
|
|
242
274
|
JSON: "JSON";
|
|
243
275
|
Code: "Code";
|
|
244
276
|
Link: "Link";
|
|
245
|
-
Doctype: "Doctype";
|
|
246
277
|
Attach: "Attach";
|
|
247
278
|
Currency: "Currency";
|
|
248
279
|
Quantity: "Quantity";
|
|
@@ -267,13 +298,37 @@ declare const DoctypeMeta: z.ZodObject<{
|
|
|
267
298
|
options: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>;
|
|
268
299
|
cardinality: z.ZodOptional<z.ZodEnum<{
|
|
269
300
|
one: "one";
|
|
270
|
-
|
|
301
|
+
atMostOne: "atMostOne";
|
|
302
|
+
noneOrMany: "noneOrMany";
|
|
303
|
+
atLeastOne: "atLeastOne";
|
|
271
304
|
}>>;
|
|
272
305
|
mask: z.ZodOptional<z.ZodString>;
|
|
273
306
|
validation: z.ZodOptional<z.ZodObject<{
|
|
274
307
|
errorMessage: z.ZodString;
|
|
275
308
|
}, z.core.$loose>>;
|
|
276
309
|
}, z.core.$strip>>;
|
|
310
|
+
links: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
311
|
+
target: z.ZodString;
|
|
312
|
+
cardinality: z.ZodEnum<{
|
|
313
|
+
one: "one";
|
|
314
|
+
atMostOne: "atMostOne";
|
|
315
|
+
noneOrMany: "noneOrMany";
|
|
316
|
+
atLeastOne: "atLeastOne";
|
|
317
|
+
}>;
|
|
318
|
+
backlink: z.ZodOptional<z.ZodString>;
|
|
319
|
+
component: z.ZodOptional<z.ZodString>;
|
|
320
|
+
fieldname: z.ZodOptional<z.ZodString>;
|
|
321
|
+
fetch: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
322
|
+
method: z.ZodLiteral<"sync">;
|
|
323
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
324
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
325
|
+
method: z.ZodLiteral<"lazy">;
|
|
326
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
327
|
+
method: z.ZodLiteral<"custom">;
|
|
328
|
+
handler: z.ZodString;
|
|
329
|
+
}, z.core.$strip>], "method">>;
|
|
330
|
+
blockWorkflows: z.ZodOptional<z.ZodBoolean>;
|
|
331
|
+
}, z.core.$strip>>>;
|
|
277
332
|
workflow: z.ZodOptional<z.ZodObject<{
|
|
278
333
|
states: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
279
334
|
actions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
@@ -286,17 +341,13 @@ declare const DoctypeMeta: z.ZodObject<{
|
|
|
286
341
|
}, z.core.$strip>>>;
|
|
287
342
|
}, z.core.$strip>>;
|
|
288
343
|
inherits: z.ZodOptional<z.ZodString>;
|
|
289
|
-
listDoctype: z.ZodOptional<z.ZodString>;
|
|
290
|
-
parentDoctype: z.ZodOptional<z.ZodString>;
|
|
291
344
|
}, z.core.$strip>;
|
|
292
345
|
|
|
293
346
|
/**
|
|
294
347
|
* Doctype metadata type inferred from Zod schema
|
|
295
348
|
* @public
|
|
296
349
|
*/
|
|
297
|
-
declare type DoctypeMeta = z.infer<typeof DoctypeMeta>;
|
|
298
|
-
export { DoctypeMeta }
|
|
299
|
-
export { DoctypeMeta as DoctypeMetaType }
|
|
350
|
+
export declare type DoctypeMeta = z.infer<typeof DoctypeMeta>;
|
|
300
351
|
|
|
301
352
|
/**
|
|
302
353
|
* Base interface for doctype metadata passed to DataClient methods.
|
|
@@ -310,6 +361,29 @@ export declare interface DoctypeRef {
|
|
|
310
361
|
slug?: string;
|
|
311
362
|
}
|
|
312
363
|
|
|
364
|
+
/**
|
|
365
|
+
* Fetch strategy for link data loading.
|
|
366
|
+
* - sync: fetched in the initial query
|
|
367
|
+
* - lazy: fetched on demand in a separate query
|
|
368
|
+
* - custom: uses a custom handler function
|
|
369
|
+
* @public
|
|
370
|
+
*/
|
|
371
|
+
export declare const FetchStrategy: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
372
|
+
method: z.ZodLiteral<"sync">;
|
|
373
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
374
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
375
|
+
method: z.ZodLiteral<"lazy">;
|
|
376
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
377
|
+
method: z.ZodLiteral<"custom">;
|
|
378
|
+
handler: z.ZodString;
|
|
379
|
+
}, z.core.$strip>], "method">;
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Fetch strategy type
|
|
383
|
+
* @public
|
|
384
|
+
*/
|
|
385
|
+
export declare type FetchStrategy = z.infer<typeof FetchStrategy>;
|
|
386
|
+
|
|
313
387
|
/**
|
|
314
388
|
* Unified field metadata - the single source of truth for field definitions.
|
|
315
389
|
* Works for both forms (AForm) and tables (ATable).
|
|
@@ -318,7 +392,7 @@ export declare interface DoctypeRef {
|
|
|
318
392
|
*
|
|
319
393
|
* @public
|
|
320
394
|
*/
|
|
321
|
-
declare const FieldMeta: z.ZodObject<{
|
|
395
|
+
export declare const FieldMeta: z.ZodObject<{
|
|
322
396
|
fieldname: z.ZodString;
|
|
323
397
|
fieldtype: z.ZodEnum<{
|
|
324
398
|
Data: "Data";
|
|
@@ -335,7 +409,6 @@ declare const FieldMeta: z.ZodObject<{
|
|
|
335
409
|
JSON: "JSON";
|
|
336
410
|
Code: "Code";
|
|
337
411
|
Link: "Link";
|
|
338
|
-
Doctype: "Doctype";
|
|
339
412
|
Attach: "Attach";
|
|
340
413
|
Currency: "Currency";
|
|
341
414
|
Quantity: "Quantity";
|
|
@@ -360,7 +433,9 @@ declare const FieldMeta: z.ZodObject<{
|
|
|
360
433
|
options: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>;
|
|
361
434
|
cardinality: z.ZodOptional<z.ZodEnum<{
|
|
362
435
|
one: "one";
|
|
363
|
-
|
|
436
|
+
atMostOne: "atMostOne";
|
|
437
|
+
noneOrMany: "noneOrMany";
|
|
438
|
+
atLeastOne: "atLeastOne";
|
|
364
439
|
}>>;
|
|
365
440
|
mask: z.ZodOptional<z.ZodString>;
|
|
366
441
|
validation: z.ZodOptional<z.ZodObject<{
|
|
@@ -373,9 +448,7 @@ declare const FieldMeta: z.ZodObject<{
|
|
|
373
448
|
* Field metadata type inferred from Zod schema
|
|
374
449
|
* @public
|
|
375
450
|
*/
|
|
376
|
-
declare type FieldMeta = z.infer<typeof FieldMeta>;
|
|
377
|
-
export { FieldMeta }
|
|
378
|
-
export { FieldMeta as FieldMetaType }
|
|
451
|
+
export declare type FieldMeta = z.infer<typeof FieldMeta>;
|
|
379
452
|
|
|
380
453
|
/**
|
|
381
454
|
* Field options - flexible bag for type-specific configuration.
|
|
@@ -388,15 +461,13 @@ export { FieldMeta as FieldMetaType }
|
|
|
388
461
|
*
|
|
389
462
|
* @public
|
|
390
463
|
*/
|
|
391
|
-
declare const FieldOptions: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>;
|
|
464
|
+
export declare const FieldOptions: z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>;
|
|
392
465
|
|
|
393
466
|
/**
|
|
394
467
|
* Field options type inferred from Zod schema
|
|
395
468
|
* @public
|
|
396
469
|
*/
|
|
397
|
-
declare type FieldOptions = z.infer<typeof FieldOptions>;
|
|
398
|
-
export { FieldOptions }
|
|
399
|
-
export { FieldOptions as FieldOptionsType }
|
|
470
|
+
export declare type FieldOptions = z.infer<typeof FieldOptions>;
|
|
400
471
|
|
|
401
472
|
/**
|
|
402
473
|
* Field template for TYPE_MAP entries.
|
|
@@ -437,6 +508,40 @@ export declare type FieldValidation = z.infer<typeof FieldValidation>;
|
|
|
437
508
|
*/
|
|
438
509
|
export declare function getDefaultComponent(fieldtype: StonecropFieldType): string;
|
|
439
510
|
|
|
511
|
+
/**
|
|
512
|
+
* Options for fetching a single record
|
|
513
|
+
* @public
|
|
514
|
+
*/
|
|
515
|
+
export declare interface GetRecordOptions {
|
|
516
|
+
/**
|
|
517
|
+
* Include nested link sub-selections.
|
|
518
|
+
* - `true`: include all descendant links
|
|
519
|
+
* - `string[]`: include only named links
|
|
520
|
+
* - `false` / omitted: scalar fields only (default)
|
|
521
|
+
*/
|
|
522
|
+
includeNested?: boolean | string[];
|
|
523
|
+
/**
|
|
524
|
+
* Maximum depth for recursive sub-selections.
|
|
525
|
+
* No default — unlimited when omitted.
|
|
526
|
+
*/
|
|
527
|
+
maxDepth?: number;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Options for fetching multiple records
|
|
532
|
+
* @public
|
|
533
|
+
*/
|
|
534
|
+
export declare interface GetRecordsOptions {
|
|
535
|
+
/** Filter expression (field-value pairs) */
|
|
536
|
+
filters?: Record<string, unknown>;
|
|
537
|
+
/** Order by expression (e.g. 'NAME_ASC') */
|
|
538
|
+
orderBy?: string;
|
|
539
|
+
/** Maximum number of records to return */
|
|
540
|
+
limit?: number;
|
|
541
|
+
/** Number of records to skip */
|
|
542
|
+
offset?: number;
|
|
543
|
+
}
|
|
544
|
+
|
|
440
545
|
/**
|
|
441
546
|
* Mapping from standard GraphQL scalar types to Stonecrop field types.
|
|
442
547
|
* These are defined by the GraphQL specification and are always available.
|
|
@@ -456,6 +561,8 @@ export declare interface GraphQLConversionFieldMeta extends FieldMeta {
|
|
|
456
561
|
_graphqlType?: string;
|
|
457
562
|
/** Marks fields that couldn't be automatically mapped */
|
|
458
563
|
_unmapped?: boolean;
|
|
564
|
+
/** Marks relationship fields that belong in `links`, not `fields` */
|
|
565
|
+
_isLink?: boolean;
|
|
459
566
|
}
|
|
460
567
|
|
|
461
568
|
/**
|
|
@@ -579,6 +686,53 @@ export declare const INTERNAL_SCALARS: Set<string>;
|
|
|
579
686
|
*/
|
|
580
687
|
export declare type IntrospectionSource = IntrospectionQuery | string;
|
|
581
688
|
|
|
689
|
+
/**
|
|
690
|
+
* Lazy fetch strategy - data is fetched on demand in a separate query.
|
|
691
|
+
* @public
|
|
692
|
+
*/
|
|
693
|
+
export declare const LazyFetch: z.ZodObject<{
|
|
694
|
+
method: z.ZodLiteral<"lazy">;
|
|
695
|
+
}, z.core.$strip>;
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* Lazy fetch strategy type
|
|
699
|
+
* @public
|
|
700
|
+
*/
|
|
701
|
+
export declare type LazyFetch = z.infer<typeof LazyFetch>;
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* Link declaration - describes a relationship from one doctype to another.
|
|
705
|
+
* @public
|
|
706
|
+
*/
|
|
707
|
+
export declare const LinkDeclaration: z.ZodObject<{
|
|
708
|
+
target: z.ZodString;
|
|
709
|
+
cardinality: z.ZodEnum<{
|
|
710
|
+
one: "one";
|
|
711
|
+
atMostOne: "atMostOne";
|
|
712
|
+
noneOrMany: "noneOrMany";
|
|
713
|
+
atLeastOne: "atLeastOne";
|
|
714
|
+
}>;
|
|
715
|
+
backlink: z.ZodOptional<z.ZodString>;
|
|
716
|
+
component: z.ZodOptional<z.ZodString>;
|
|
717
|
+
fieldname: z.ZodOptional<z.ZodString>;
|
|
718
|
+
fetch: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
719
|
+
method: z.ZodLiteral<"sync">;
|
|
720
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
721
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
722
|
+
method: z.ZodLiteral<"lazy">;
|
|
723
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
724
|
+
method: z.ZodLiteral<"custom">;
|
|
725
|
+
handler: z.ZodString;
|
|
726
|
+
}, z.core.$strip>], "method">>;
|
|
727
|
+
blockWorkflows: z.ZodOptional<z.ZodBoolean>;
|
|
728
|
+
}, z.core.$strip>;
|
|
729
|
+
|
|
730
|
+
/**
|
|
731
|
+
* Link declaration type inferred from Zod schema
|
|
732
|
+
* @public
|
|
733
|
+
*/
|
|
734
|
+
export declare type LinkDeclaration = z.infer<typeof LinkDeclaration>;
|
|
735
|
+
|
|
582
736
|
/**
|
|
583
737
|
* Parse and validate a doctype, throwing on failure
|
|
584
738
|
* @param data - Data to parse
|
|
@@ -610,6 +764,13 @@ export declare function parseField(data: unknown): FieldMeta;
|
|
|
610
764
|
*/
|
|
611
765
|
export declare function pascalToSnake(pascal: string): string;
|
|
612
766
|
|
|
767
|
+
/**
|
|
768
|
+
* Serialized function type - a function serialized to a string.
|
|
769
|
+
* Used for custom fetch handlers.
|
|
770
|
+
* @public
|
|
771
|
+
*/
|
|
772
|
+
export declare type SerializedFunction = string;
|
|
773
|
+
|
|
613
774
|
/**
|
|
614
775
|
* Converts snake_case to camelCase
|
|
615
776
|
* @param snakeCase - Snake case string
|
|
@@ -641,7 +802,7 @@ export declare function snakeToLabel(snakeCase: string): string;
|
|
|
641
802
|
* These are consistent across forms and tables.
|
|
642
803
|
* @public
|
|
643
804
|
*/
|
|
644
|
-
declare const StonecropFieldType: z.ZodEnum<{
|
|
805
|
+
export declare const StonecropFieldType: z.ZodEnum<{
|
|
645
806
|
Data: "Data";
|
|
646
807
|
Text: "Text";
|
|
647
808
|
Int: "Int";
|
|
@@ -656,7 +817,6 @@ declare const StonecropFieldType: z.ZodEnum<{
|
|
|
656
817
|
JSON: "JSON";
|
|
657
818
|
Code: "Code";
|
|
658
819
|
Link: "Link";
|
|
659
|
-
Doctype: "Doctype";
|
|
660
820
|
Attach: "Attach";
|
|
661
821
|
Currency: "Currency";
|
|
662
822
|
Quantity: "Quantity";
|
|
@@ -667,9 +827,22 @@ declare const StonecropFieldType: z.ZodEnum<{
|
|
|
667
827
|
* Stonecrop field type enum inferred from Zod schema
|
|
668
828
|
* @public
|
|
669
829
|
*/
|
|
670
|
-
declare type StonecropFieldType = z.infer<typeof StonecropFieldType>;
|
|
671
|
-
|
|
672
|
-
|
|
830
|
+
export declare type StonecropFieldType = z.infer<typeof StonecropFieldType>;
|
|
831
|
+
|
|
832
|
+
/**
|
|
833
|
+
* Sync fetch strategy - data is fetched in the initial query.
|
|
834
|
+
* @public
|
|
835
|
+
*/
|
|
836
|
+
export declare const SyncFetch: z.ZodObject<{
|
|
837
|
+
method: z.ZodLiteral<"sync">;
|
|
838
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
839
|
+
}, z.core.$strip>;
|
|
840
|
+
|
|
841
|
+
/**
|
|
842
|
+
* Sync fetch strategy type
|
|
843
|
+
* @public
|
|
844
|
+
*/
|
|
845
|
+
export declare type SyncFetch = z.infer<typeof SyncFetch>;
|
|
673
846
|
|
|
674
847
|
/**
|
|
675
848
|
* Convert table name to PascalCase doctype name
|
|
@@ -748,7 +921,7 @@ export declare const WELL_KNOWN_SCALARS: Record<string, FieldTemplate>;
|
|
|
748
921
|
* Workflow metadata - states and actions for a doctype
|
|
749
922
|
* @public
|
|
750
923
|
*/
|
|
751
|
-
declare const WorkflowMeta: z.ZodObject<{
|
|
924
|
+
export declare const WorkflowMeta: z.ZodObject<{
|
|
752
925
|
states: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
753
926
|
actions: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
754
927
|
label: z.ZodString;
|
|
@@ -764,8 +937,6 @@ declare const WorkflowMeta: z.ZodObject<{
|
|
|
764
937
|
* Workflow metadata type inferred from Zod schema
|
|
765
938
|
* @public
|
|
766
939
|
*/
|
|
767
|
-
declare type WorkflowMeta = z.infer<typeof WorkflowMeta>;
|
|
768
|
-
export { WorkflowMeta }
|
|
769
|
-
export { WorkflowMeta as WorkflowMetaType }
|
|
940
|
+
export declare type WorkflowMeta = z.infer<typeof WorkflowMeta>;
|
|
770
941
|
|
|
771
942
|
export { }
|
package/dist/src/cli.js
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Stonecrop Schema CLI
|
|
4
|
+
*
|
|
5
|
+
* Converts GraphQL introspection results to Stonecrop doctype JSON schemas.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* stonecrop-schema generate --endpoint <url> --output <dir>
|
|
9
|
+
* stonecrop-schema generate --introspection <file.json> --output <dir>
|
|
10
|
+
* stonecrop-schema generate --sdl <file.graphql> --output <dir>
|
|
11
|
+
*
|
|
12
|
+
* @packageDocumentation
|
|
13
|
+
*/
|
|
14
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
15
|
+
import { resolve, join } from 'node:path';
|
|
16
|
+
import { parseArgs } from 'node:util';
|
|
17
|
+
import { getIntrospectionQuery } from 'graphql';
|
|
18
|
+
import { convertGraphQLSchema } from './converter/index';
|
|
19
|
+
import { validateDoctype } from './validation';
|
|
20
|
+
/**
|
|
21
|
+
* Fetch an introspection result from a live GraphQL endpoint.
|
|
22
|
+
*
|
|
23
|
+
* @param endpoint - The GraphQL endpoint URL
|
|
24
|
+
* @param headers - Optional HTTP headers
|
|
25
|
+
* @returns The introspection query result
|
|
26
|
+
*/
|
|
27
|
+
async function fetchIntrospection(endpoint, headers) {
|
|
28
|
+
const response = await fetch(endpoint, {
|
|
29
|
+
method: 'POST',
|
|
30
|
+
headers: {
|
|
31
|
+
'Content-Type': 'application/json',
|
|
32
|
+
...headers,
|
|
33
|
+
},
|
|
34
|
+
body: JSON.stringify({
|
|
35
|
+
query: getIntrospectionQuery(),
|
|
36
|
+
}),
|
|
37
|
+
});
|
|
38
|
+
if (!response.ok) {
|
|
39
|
+
throw new Error(`Failed to fetch introspection: ${response.status} ${response.statusText}`);
|
|
40
|
+
}
|
|
41
|
+
const json = (await response.json());
|
|
42
|
+
if (json.errors?.length) {
|
|
43
|
+
throw new Error(`GraphQL errors: ${json.errors.map(e => e.message).join(', ')}`);
|
|
44
|
+
}
|
|
45
|
+
if (!json.data) {
|
|
46
|
+
throw new Error('No data in introspection response');
|
|
47
|
+
}
|
|
48
|
+
return json.data;
|
|
49
|
+
}
|
|
50
|
+
async function main() {
|
|
51
|
+
const { values, positionals } = parseArgs({
|
|
52
|
+
allowPositionals: true,
|
|
53
|
+
options: {
|
|
54
|
+
endpoint: { type: 'string', short: 'e' },
|
|
55
|
+
introspection: { type: 'string', short: 'i' },
|
|
56
|
+
sdl: { type: 'string', short: 's' },
|
|
57
|
+
output: { type: 'string', short: 'o' },
|
|
58
|
+
include: { type: 'string' },
|
|
59
|
+
exclude: { type: 'string' },
|
|
60
|
+
overrides: { type: 'string' },
|
|
61
|
+
'custom-scalars': { type: 'string' },
|
|
62
|
+
'include-unmapped': { type: 'boolean', default: false },
|
|
63
|
+
help: { type: 'boolean', short: 'h' },
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
const command = positionals[0];
|
|
67
|
+
if (values.help || !command) {
|
|
68
|
+
printHelp();
|
|
69
|
+
process.exit(command ? 0 : 1);
|
|
70
|
+
}
|
|
71
|
+
if (command !== 'generate') {
|
|
72
|
+
console.error(`Unknown command: ${command}`);
|
|
73
|
+
console.error('Available commands: generate');
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
// Determine source
|
|
77
|
+
const sourceCount = [values.endpoint, values.introspection, values.sdl].filter(Boolean).length;
|
|
78
|
+
if (sourceCount !== 1) {
|
|
79
|
+
console.error('Exactly one of --endpoint, --introspection, or --sdl must be provided');
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
if (!values.output) {
|
|
83
|
+
console.error('--output <dir> is required');
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
const outputDir = resolve(values.output);
|
|
87
|
+
// Build conversion options
|
|
88
|
+
const options = {
|
|
89
|
+
includeUnmappedMeta: values['include-unmapped'],
|
|
90
|
+
};
|
|
91
|
+
if (values.include) {
|
|
92
|
+
options.include = values.include.split(',').map(s => s.trim());
|
|
93
|
+
}
|
|
94
|
+
if (values.exclude) {
|
|
95
|
+
options.exclude = values.exclude.split(',').map(s => s.trim());
|
|
96
|
+
}
|
|
97
|
+
if (values.overrides) {
|
|
98
|
+
const overridesPath = resolve(values.overrides);
|
|
99
|
+
const overridesContent = readFileSync(overridesPath, 'utf-8');
|
|
100
|
+
options.typeOverrides = JSON.parse(overridesContent);
|
|
101
|
+
}
|
|
102
|
+
if (values['custom-scalars']) {
|
|
103
|
+
const scalarsPath = resolve(values['custom-scalars']);
|
|
104
|
+
const scalarsContent = readFileSync(scalarsPath, 'utf-8');
|
|
105
|
+
options.customScalars = JSON.parse(scalarsContent);
|
|
106
|
+
}
|
|
107
|
+
// Resolve source
|
|
108
|
+
let source;
|
|
109
|
+
if (values.endpoint) {
|
|
110
|
+
console.log(`Fetching introspection from ${values.endpoint}...`);
|
|
111
|
+
source = await fetchIntrospection(values.endpoint);
|
|
112
|
+
}
|
|
113
|
+
else if (values.introspection) {
|
|
114
|
+
const filePath = resolve(values.introspection);
|
|
115
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
116
|
+
const parsed = JSON.parse(content);
|
|
117
|
+
// Handle both { data: { __schema: ... } } and { __schema: ... } formats
|
|
118
|
+
source = parsed.data ?? parsed;
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
const filePath = resolve(values.sdl);
|
|
122
|
+
source = readFileSync(filePath, 'utf-8');
|
|
123
|
+
}
|
|
124
|
+
// Convert
|
|
125
|
+
const doctypes = convertGraphQLSchema(source, options);
|
|
126
|
+
if (doctypes.length === 0) {
|
|
127
|
+
console.warn('No entity types found in the schema. Check your include/exclude filters.');
|
|
128
|
+
process.exit(0);
|
|
129
|
+
}
|
|
130
|
+
// Write output
|
|
131
|
+
if (!existsSync(outputDir)) {
|
|
132
|
+
mkdirSync(outputDir, { recursive: true });
|
|
133
|
+
}
|
|
134
|
+
let warnings = 0;
|
|
135
|
+
let errors = 0;
|
|
136
|
+
for (const doctype of doctypes) {
|
|
137
|
+
const fileName = `${doctype.slug}.json`;
|
|
138
|
+
const filePath = join(outputDir, fileName);
|
|
139
|
+
const json = JSON.stringify(doctype, null, '\t');
|
|
140
|
+
writeFileSync(filePath, json + '\n', 'utf-8');
|
|
141
|
+
// Validate the output
|
|
142
|
+
const validation = validateDoctype(doctype);
|
|
143
|
+
if (!validation.success) {
|
|
144
|
+
errors++;
|
|
145
|
+
console.error(` ERROR: ${fileName} failed validation:`);
|
|
146
|
+
for (const err of validation.errors) {
|
|
147
|
+
console.error(` ${err.path.join('.')}: ${err.message}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
// Check for unmapped fields
|
|
152
|
+
const unmappedFields = doctype.fields.filter((f) => f._unmapped);
|
|
153
|
+
if (unmappedFields.length > 0) {
|
|
154
|
+
warnings++;
|
|
155
|
+
console.warn(` WARN: ${fileName} has ${unmappedFields.length} unmapped field(s): ${unmappedFields
|
|
156
|
+
.map((f) => f.fieldname)
|
|
157
|
+
.join(', ')}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
console.log(`\nGenerated ${doctypes.length} doctype(s) in ${outputDir}` +
|
|
162
|
+
(warnings ? ` (${warnings} with warnings)` : '') +
|
|
163
|
+
(errors ? ` (${errors} with errors)` : ''));
|
|
164
|
+
if (errors > 0) {
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
function printHelp() {
|
|
169
|
+
console.log(`
|
|
170
|
+
stonecrop-schema - Convert GraphQL schemas to Stonecrop doctypes
|
|
171
|
+
|
|
172
|
+
USAGE:
|
|
173
|
+
stonecrop-schema generate [options]
|
|
174
|
+
|
|
175
|
+
SOURCE (exactly one required):
|
|
176
|
+
--endpoint, -e <url> Fetch introspection from a live GraphQL endpoint
|
|
177
|
+
--introspection, -i <file> Read from a saved introspection JSON file
|
|
178
|
+
--sdl, -s <file> Read from a GraphQL SDL (.graphql) file
|
|
179
|
+
|
|
180
|
+
OUTPUT:
|
|
181
|
+
--output, -o <dir> Directory to write doctype JSON files (required)
|
|
182
|
+
|
|
183
|
+
OPTIONS:
|
|
184
|
+
--include <types> Comma-separated list of type names to include
|
|
185
|
+
--exclude <types> Comma-separated list of type names to exclude
|
|
186
|
+
--overrides <file> JSON file with per-type field overrides
|
|
187
|
+
--custom-scalars <file> JSON file mapping custom scalar names to field templates
|
|
188
|
+
--include-unmapped Include _graphqlType metadata on unmapped fields
|
|
189
|
+
--help, -h Show this help message
|
|
190
|
+
|
|
191
|
+
EXAMPLES:
|
|
192
|
+
# From a live PostGraphile server
|
|
193
|
+
stonecrop-schema generate -e http://localhost:5000/graphql -o ./schemas
|
|
194
|
+
|
|
195
|
+
# From a saved introspection result
|
|
196
|
+
stonecrop-schema generate -i introspection.json -o ./schemas
|
|
197
|
+
|
|
198
|
+
# From an SDL file with custom scalars
|
|
199
|
+
stonecrop-schema generate -s schema.graphql -o ./schemas \\
|
|
200
|
+
--custom-scalars custom-scalars.json
|
|
201
|
+
|
|
202
|
+
# Only convert specific types
|
|
203
|
+
stonecrop-schema generate -e http://localhost:5000/graphql -o ./schemas \\
|
|
204
|
+
--include "User,Post,Comment"
|
|
205
|
+
`);
|
|
206
|
+
}
|
|
207
|
+
main().catch(err => {
|
|
208
|
+
console.error('Error:', err.message);
|
|
209
|
+
process.exit(1);
|
|
210
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heuristics.d.ts","sourceRoot":"","sources":["../../../src/converter/heuristics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAMN,KAAK,iBAAiB,EACtB,KAAK,YAAY,EAGjB,MAAM,SAAS,CAAA;AAGhB,OAAO,KAAK,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAA;AA+BnF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CA8BtF;AAQD;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,EACtC,WAAW,EAAE,iBAAiB,GAC5B,OAAO,CAET;AAsED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iBAAiB,CAChC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,EACrC,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EACxB,OAAO,GAAE,wBAA6B,GACpC,0BAA0B,
|
|
1
|
+
{"version":3,"file":"heuristics.d.ts","sourceRoot":"","sources":["../../../src/converter/heuristics.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAMN,KAAK,iBAAiB,EACtB,KAAK,YAAY,EAGjB,MAAM,SAAS,CAAA;AAGhB,OAAO,KAAK,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAA;AA+BnF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CA8BtF;AAQD;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CACnC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,EACtC,WAAW,EAAE,iBAAiB,GAC5B,OAAO,CAET;AAsED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iBAAiB,CAChC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,EACrC,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EACxB,OAAO,GAAE,wBAA6B,GACpC,0BAA0B,CA6F5B"}
|