@ghentcdh/crouton-core 0.0.1-alpha.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,1280 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ BooleanCellBuilder: () => BooleanCellBuilder,
34
+ Builder: () => Builder,
35
+ BuilderWithElements: () => BuilderWithElements,
36
+ CONFIG_FILES: () => CONFIG_FILES,
37
+ CalculatedColumnSchema: () => CalculatedColumnSchema,
38
+ CategoryBuilder: () => CategoryBuilder,
39
+ ControlBuilder: () => ControlBuilder,
40
+ ControlType: () => ControlType,
41
+ CroutonConfigSchema: () => CroutonConfigSchema,
42
+ DataSourceSchema: () => DataSourceSchema,
43
+ DataSourceShape: () => DataSourceShape,
44
+ DetailConfigSchema: () => DetailConfigSchema,
45
+ DetailControlSchema: () => DetailControlSchema,
46
+ FieldInputSchema: () => FieldInputSchema,
47
+ FieldVariantSchema: () => FieldVariantSchema,
48
+ GroupBuilder: () => GroupBuilder,
49
+ JsonActionSchema: () => JsonActionSchema,
50
+ JsonColumnSchema: () => JsonColumnSchema,
51
+ JsonIncludeEntrySchema: () => JsonIncludeEntrySchema,
52
+ JsonLinkActionSchema: () => JsonLinkActionSchema,
53
+ JsonOperationsSchema: () => JsonOperationsSchema,
54
+ JsonProcedureActionSchema: () => JsonProcedureActionSchema,
55
+ LayoutBuilder: () => LayoutBuilder,
56
+ LayoutTypes: () => LayoutTypes,
57
+ ModalSize: () => ModalSize,
58
+ Operator: () => Operator,
59
+ OperatorLabel: () => OperatorLabel,
60
+ OperatorNoValue: () => OperatorNoValue,
61
+ OperatorOptions: () => OperatorOptions,
62
+ OperatorsByType: () => OperatorsByType,
63
+ PositiveRequestNumber: () => PositiveRequestNumber,
64
+ RelationFieldInputOptionsSchema: () => RelationFieldInputOptionsSchema,
65
+ RelationType: () => RelationType,
66
+ RequestSchema: () => RequestSchema,
67
+ RequestSchemaWithOffset: () => RequestSchemaWithOffset,
68
+ ResourceJsonSchema: () => ResourceJsonSchema,
69
+ ResourceJsonShape: () => ResourceJsonShape,
70
+ ResponseRequestSchema: () => ResponseRequestSchema,
71
+ ResponseSchema: () => ResponseSchema,
72
+ RulesetSchema: () => RulesetSchema,
73
+ SidebarGroupSchema: () => SidebarGroupSchema,
74
+ SidebarSchema: () => SidebarSchema,
75
+ Size: () => ModalSize,
76
+ SortDirEnum: () => SortDirEnum,
77
+ StringOrArray: () => StringOrArray,
78
+ TableBuilder: () => TableBuilder,
79
+ TextCellBuilder: () => TextCellBuilder,
80
+ WhenConditionSchema: () => WhenConditionSchema,
81
+ buildFilter: () => buildFilter,
82
+ buildSort: () => buildSort,
83
+ buildSortKey: () => buildSortKey,
84
+ createSchema: () => createSchema,
85
+ dropNullableFromRequired: () => dropNullableFromRequired,
86
+ enforceRequiredStringMinLength: () => enforceRequiredStringMinLength,
87
+ extractFilters: () => extractFilters,
88
+ filterToString: () => filterToString,
89
+ findColumnDef: () => findColumnDef,
90
+ findProperty: () => findProperty,
91
+ fromValueLabel: () => fromValueLabel,
92
+ labelFromId: () => labelFromId,
93
+ mergeFieldVariant: () => mergeFieldVariant,
94
+ normalizeLabel: () => normalizeLabel,
95
+ resolveFormField: () => resolveFormField,
96
+ resolveTableField: () => resolveTableField,
97
+ resolveViewField: () => resolveViewField,
98
+ stringToFilter: () => stringToFilter,
99
+ toValueLabel: () => toValueLabel,
100
+ transformDataSource: () => transformDataSource,
101
+ uiFromJsonSchema: () => uiFromJsonSchema
102
+ });
103
+ module.exports = __toCommonJS(index_exports);
104
+
105
+ // src/lib/request.model.ts
106
+ var import_zod2 = require("zod");
107
+
108
+ // src/lib/zod.types.ts
109
+ var import_zod = require("zod");
110
+ var PositiveRequestNumber = () => import_zod.z.coerce.number().int().positive().nonnegative();
111
+ var StringOrArray = () => import_zod.z.string().or(import_zod.z.array(import_zod.z.string())).transform((val) => {
112
+ if (Array.isArray(val)) return val;
113
+ return [val];
114
+ });
115
+
116
+ // src/lib/request.model.ts
117
+ var SortDirEnum = import_zod2.z.enum(["asc", "desc"]);
118
+ var RequestSchema = import_zod2.z.object({
119
+ page: PositiveRequestNumber().optional().default(1),
120
+ pageSize: PositiveRequestNumber().optional().default(20),
121
+ sort: import_zod2.z.string().optional().default("id"),
122
+ sortDir: SortDirEnum.optional().default("asc"),
123
+ // Filter is of the format key:value:operator (e.g. name:john:eq) operator is optional
124
+ filter: StringOrArray().optional().default([])
125
+ });
126
+ var RequestSchemaWithOffset = RequestSchema.transform((schema) => {
127
+ const { page, pageSize, sort } = schema;
128
+ return {
129
+ ...schema,
130
+ sort: sort || "id",
131
+ offset: (page - 1) * pageSize
132
+ };
133
+ });
134
+
135
+ // src/lib/filter.ts
136
+ var Operator = [
137
+ "contains",
138
+ "not_contains",
139
+ "equals",
140
+ "not_equals",
141
+ "gt",
142
+ "lt",
143
+ "isnull",
144
+ "isnotnull"
145
+ ];
146
+ var OperatorLabel = {
147
+ contains: "contains",
148
+ not_contains: "not contains",
149
+ equals: "equals",
150
+ not_equals: "not equals",
151
+ gt: ">",
152
+ lt: "<",
153
+ isnull: "is empty",
154
+ isnotnull: "is not empty"
155
+ };
156
+ var OperatorOptions = Operator.map((k) => ({
157
+ value: k,
158
+ label: OperatorLabel[k]
159
+ }));
160
+ var OperatorNoValue = /* @__PURE__ */ new Set(["isnull", "isnotnull"]);
161
+ var OperatorsByType = {
162
+ string: ["contains", "not_contains", "equals", "not_equals", "isnull", "isnotnull"],
163
+ number: ["equals", "not_equals", "gt", "lt", "isnull", "isnotnull"],
164
+ date: ["equals", "not_equals", "gt", "lt", "isnull", "isnotnull"],
165
+ boolean: ["equals", "not_equals", "isnull", "isnotnull"],
166
+ enum: ["equals", "not_equals", "isnull", "isnotnull"]
167
+ };
168
+ var getFilterValues = (filter) => {
169
+ const parts = filter.split(":");
170
+ const key = parts[0] ?? "";
171
+ const lastPart = parts[parts.length - 1];
172
+ const hasOp = parts.length >= 3 && Operator.includes(lastPart);
173
+ const operator = hasOp ? lastPart : "contains";
174
+ const value = hasOp ? parts.slice(1, -1).join(":") : parts.slice(1).join(":");
175
+ return { key, value, operator };
176
+ };
177
+ var buildFilterKey = (keys, filterObj) => {
178
+ if (keys.length === 1) return { key: keys[0], filterObj };
179
+ const buildKey = keys.pop();
180
+ return buildFilterKey(keys, { [buildKey]: filterObj });
181
+ };
182
+ var buildSort = (key, sortDir) => buildSortKey(key.split("."), SortDirEnum.safeParse(sortDir).data ?? "asc");
183
+ var buildSortKey = (keys, sortDir) => {
184
+ if (keys.length === 1) return { [keys[0]]: sortDir };
185
+ const buildKey = keys.pop();
186
+ return buildSortKey(keys, { [buildKey]: sortDir });
187
+ };
188
+ var buildFilter = (filters) => {
189
+ const filter = {};
190
+ filters?.forEach((f) => {
191
+ const { key, value, operator } = getFilterValues(f);
192
+ if (!key) return;
193
+ const op = operator || "contains";
194
+ const filterObj = { [operator || "contains"]: value.toLowerCase() };
195
+ if (op === "contains") filterObj["mode"] = "insensitive";
196
+ const build = buildFilterKey(key.split("."), filterObj);
197
+ filter[build.key] = build.filterObj;
198
+ });
199
+ return filter;
200
+ };
201
+ var extractFilters = (filters) => {
202
+ const result = [];
203
+ filters.forEach((f) => {
204
+ const { key, value, operator } = getFilterValues(f);
205
+ if (!key) return;
206
+ result.push({ label: key, key, value, operator });
207
+ });
208
+ return result;
209
+ };
210
+ var filterToString = (filter) => `${filter.key}:${filter.value}:${filter.operator}`;
211
+ var stringToFilter = (s) => getFilterValues(s);
212
+
213
+ // src/lib/response.model.ts
214
+ var import_zod4 = require("zod");
215
+ var ResponseRequestSchema = RequestSchema.extend({
216
+ count: PositiveRequestNumber(),
217
+ totalPages: PositiveRequestNumber()
218
+ });
219
+ var ResponseSchema = import_zod4.z.object({
220
+ data: import_zod4.z.array(import_zod4.z.unknown()),
221
+ request: ResponseRequestSchema
222
+ });
223
+
224
+ // src/lib/create-schema.ts
225
+ var import_zod6 = require("zod");
226
+ var ModalSize = /* @__PURE__ */ ((ModalSize2) => {
227
+ ModalSize2["xs"] = "xs";
228
+ ModalSize2["sm"] = "sm";
229
+ ModalSize2["lg"] = "lg";
230
+ ModalSize2["xl"] = "xl";
231
+ return ModalSize2;
232
+ })(ModalSize || {});
233
+ var simplifyNullableAnyOf = (property) => {
234
+ const anyOf = property["anyOf"];
235
+ if (!Array.isArray(anyOf) || anyOf.length !== 2) return false;
236
+ const nonNull = anyOf.find((s) => s["type"] !== "null");
237
+ const hasNull = anyOf.some((s) => s["type"] === "null");
238
+ if (nonNull && hasNull) {
239
+ delete property["anyOf"];
240
+ Object.assign(property, nonNull);
241
+ return true;
242
+ }
243
+ return false;
244
+ };
245
+ var transformToJsonSchema = (schema) => {
246
+ const jsonSchema = (0, import_zod6.toJSONSchema)(schema, { unrepresentable: "any", target: "draft-07" });
247
+ jsonSchema.additionalProperties = true;
248
+ const properties = jsonSchema.properties;
249
+ if (properties) {
250
+ const nullableKeys = /* @__PURE__ */ new Set();
251
+ for (const key of Object.keys(properties)) {
252
+ if (simplifyNullableAnyOf(properties[key])) nullableKeys.add(key);
253
+ }
254
+ const required = jsonSchema.required;
255
+ if (Array.isArray(required)) {
256
+ jsonSchema.required = required.filter((key) => !nullableKeys.has(key));
257
+ }
258
+ }
259
+ return jsonSchema;
260
+ };
261
+ var createSchema = (props) => {
262
+ if (!props.schema) throw new Error("no schema provided");
263
+ const schema = props.schema;
264
+ const dtoSchema = props.dtoSchema;
265
+ const formSchema = transformToJsonSchema(dtoSchema);
266
+ const optionalSchema = transformToJsonSchema(schema.partial());
267
+ return {
268
+ dtoSchema,
269
+ responseSchema: props.responseSchema ?? dtoSchema,
270
+ schema: {
271
+ form: { uiSchema: props.uiSchema, schema: formSchema, modalSize: props.modalSize ?? "sm" },
272
+ table: props.tableSchema ? { uiSchema: props.tableSchema, schema: optionalSchema } : void 0,
273
+ filter: props.filterSchema ? { uiSchema: props.filterSchema, schema: optionalSchema } : void 0,
274
+ uri: props.uri,
275
+ searchUri: props.searchUri ?? `${props.uri}?filter=`
276
+ }
277
+ };
278
+ };
279
+
280
+ // src/lib/schema.utils.ts
281
+ var dropNullableFromRequired = (schema) => {
282
+ if (!schema?.properties) return schema;
283
+ const required = schema.required;
284
+ if (!Array.isArray(required) || required.length === 0) return schema;
285
+ const filteredRequired = required.filter((key) => {
286
+ const prop = schema.properties[key];
287
+ if (!prop || typeof prop !== "object") return true;
288
+ const anyOf = prop["anyOf"];
289
+ return !(Array.isArray(anyOf) && anyOf.some((s) => s?.["type"] === "null"));
290
+ });
291
+ if (filteredRequired.length === required.length) return schema;
292
+ return { ...schema, required: filteredRequired };
293
+ };
294
+ var enforceRequiredStringMinLength = (schema) => {
295
+ if (!schema?.properties) return schema;
296
+ const patchedProperties = { ...schema.properties };
297
+ let changed = false;
298
+ for (const key of Object.keys(patchedProperties)) {
299
+ const prop = patchedProperties[key];
300
+ if (!prop || typeof prop !== "object") continue;
301
+ if (prop.type === "string" && prop.minLength === void 0) {
302
+ patchedProperties[key] = { ...prop, minLength: 1 };
303
+ changed = true;
304
+ } else if (prop.type === "object") {
305
+ const patched = enforceRequiredStringMinLength(prop);
306
+ if (patched !== prop) {
307
+ patchedProperties[key] = patched;
308
+ changed = true;
309
+ }
310
+ }
311
+ }
312
+ return changed ? { ...schema, properties: patchedProperties } : schema;
313
+ };
314
+ var findProperty = (column, schema) => {
315
+ if (!column.scope) return { id: null, property: null };
316
+ const id = column.scope?.substring("#/properties/".length);
317
+ const property = schema?.properties?.[id] ?? {};
318
+ return { id, property };
319
+ };
320
+
321
+ // src/lib/layout/base.builder.ts
322
+ var Builder = class {
323
+ constructor(type) {
324
+ this.type = type;
325
+ }
326
+ type;
327
+ };
328
+ var BuilderWithElements = class extends Builder {
329
+ elements = [];
330
+ addControl(control) {
331
+ this.elements.push(control);
332
+ return this;
333
+ }
334
+ addControls(...controls) {
335
+ this.elements.push(...controls);
336
+ return this;
337
+ }
338
+ buildElements() {
339
+ return this.elements.map((e) => e.build());
340
+ }
341
+ };
342
+
343
+ // src/lib/layout/control.builder.ts
344
+ var ControlType = {
345
+ number: "number",
346
+ string: "string",
347
+ integer: "Integer",
348
+ autocomplete: "autocomplete",
349
+ textArea: "textarea",
350
+ markdown: "markdown",
351
+ array: "array",
352
+ custom: "custom",
353
+ select: "select",
354
+ mutliSelect: "mutliSelect",
355
+ boolean: "boolean",
356
+ link: "link",
357
+ relation: "relation",
358
+ date: "date",
359
+ dateTime: "dateTime",
360
+ dateRange: "date-range"
361
+ };
362
+ var ControlBuilder = class _ControlBuilder extends Builder {
363
+ constructor(scope, type = "Control") {
364
+ super(type);
365
+ this.scope = scope;
366
+ }
367
+ scope;
368
+ options = {
369
+ format: "Control",
370
+ styles: {}
371
+ };
372
+ _detail;
373
+ static asObject(property) {
374
+ return new _ControlBuilder(
375
+ `#/properties/${property}`,
376
+ "Object"
377
+ );
378
+ }
379
+ static properties(property) {
380
+ return new _ControlBuilder(`#/properties/${property}`);
381
+ }
382
+ static asCustom(property, type) {
383
+ const builder = new _ControlBuilder(
384
+ `#/properties/${property}`
385
+ );
386
+ builder.addOptions({
387
+ format: ControlType.custom,
388
+ type
389
+ });
390
+ return builder;
391
+ }
392
+ setCustomRender(customRender) {
393
+ this.addOptions({ customRender });
394
+ return this;
395
+ }
396
+ detail(layoutBuilder, label) {
397
+ this._detail = layoutBuilder;
398
+ this.addOptions({
399
+ format: ControlType.array,
400
+ elementLabelProp: label
401
+ });
402
+ return this;
403
+ }
404
+ addAction(action) {
405
+ const actions = this.options?.actions ?? [];
406
+ actions.push(action);
407
+ return this.addOptions({ actions });
408
+ }
409
+ detailFixed(layoutBuilder, options = {}) {
410
+ this._detail = layoutBuilder;
411
+ return this.addOptions({
412
+ hideActions: true,
413
+ format: ControlType.array,
414
+ layout: options.layout ?? "column",
415
+ elementLabelProp: options.label
416
+ });
417
+ }
418
+ labelKey(labelKey) {
419
+ return this.addOptions({ labelKey });
420
+ }
421
+ readonly() {
422
+ return this.addOptions({
423
+ format: ControlType.string,
424
+ readonly: true
425
+ });
426
+ }
427
+ link() {
428
+ return this.addOptions({
429
+ format: ControlType.link
430
+ });
431
+ }
432
+ markdown(options) {
433
+ return this.addOptions({
434
+ format: ControlType.markdown,
435
+ ...options ?? {}
436
+ });
437
+ }
438
+ textArea(options) {
439
+ return this.addOptions({
440
+ format: ControlType.textArea,
441
+ ...options ?? {}
442
+ });
443
+ }
444
+ autocomplete(options) {
445
+ return this.addOptions({
446
+ format: ControlType.autocomplete,
447
+ dataField: "data",
448
+ ...options ?? {}
449
+ });
450
+ }
451
+ control(format, options) {
452
+ return this.addOptions({
453
+ format,
454
+ ...options
455
+ });
456
+ }
457
+ select(options) {
458
+ return this.addOptions({
459
+ format: ControlType.select,
460
+ ...options
461
+ });
462
+ }
463
+ mutliSelect(options) {
464
+ return this.addOptions({
465
+ format: ControlType.mutliSelect,
466
+ ...options
467
+ });
468
+ }
469
+ width(width) {
470
+ return this.addOptions({
471
+ styles: {
472
+ ...this.options?.styles,
473
+ width,
474
+ control: {
475
+ wrapper: `input-${width}`
476
+ }
477
+ }
478
+ });
479
+ }
480
+ customLabel(label) {
481
+ return this.addOptions({ label });
482
+ }
483
+ placeHolder(placeholder) {
484
+ return this.addOptions({ placeholder });
485
+ }
486
+ hideLabel() {
487
+ return this.addOptions({ hideLabel: true });
488
+ }
489
+ addOptions(options) {
490
+ this.options = {
491
+ ...this.options,
492
+ ...options
493
+ };
494
+ return this;
495
+ }
496
+ build() {
497
+ return {
498
+ type: this.type,
499
+ scope: this.scope,
500
+ options: {
501
+ ...this.options,
502
+ detail: this._detail ? this._detail?.build() : void 0
503
+ }
504
+ };
505
+ }
506
+ };
507
+
508
+ // src/lib/layout/layout.builder.ts
509
+ var LayoutTypes = {
510
+ HorizontalLayout: "HorizontalLayout",
511
+ VerticalLayout: "VerticalLayout",
512
+ CollapseLayout: "CollapseLayout",
513
+ GridLayout: "GridLayout"
514
+ };
515
+ var LayoutBuilder = class _LayoutBuilder extends BuilderWithElements {
516
+ options;
517
+ constructor(type, options = {}) {
518
+ super(type);
519
+ this.options = options;
520
+ }
521
+ static horizontal() {
522
+ return new _LayoutBuilder(LayoutTypes.HorizontalLayout);
523
+ }
524
+ static collapse() {
525
+ return new _LayoutBuilder(LayoutTypes.CollapseLayout);
526
+ }
527
+ static vertical() {
528
+ return new _LayoutBuilder(LayoutTypes.VerticalLayout);
529
+ }
530
+ static grid() {
531
+ return new _LayoutBuilder(LayoutTypes.GridLayout);
532
+ }
533
+ titleKey(titleKey) {
534
+ return this.addOptions({ titleKey });
535
+ }
536
+ title(title) {
537
+ return this.addOptions({ title });
538
+ }
539
+ addOptions(options) {
540
+ this.options = {
541
+ ...this.options,
542
+ ...options
543
+ };
544
+ return this;
545
+ }
546
+ build() {
547
+ return {
548
+ type: this.type,
549
+ elements: this.buildElements(),
550
+ options: this.options
551
+ };
552
+ }
553
+ };
554
+
555
+ // src/lib/from-json.builder.ts
556
+ var uiFromJsonSchema = (jsonSchema) => {
557
+ const properties = jsonSchema.properties ?? {};
558
+ const layout = LayoutBuilder.grid();
559
+ for (const key of Object.keys(properties)) {
560
+ layout.addControl(ControlBuilder.properties(key));
561
+ }
562
+ return layout.build();
563
+ };
564
+
565
+ // src/lib/value-label.ts
566
+ var wrapOne = (value, values) => {
567
+ const match = values.find((o) => o.value === value);
568
+ return { value, label: match ? match.label : String(value) };
569
+ };
570
+ var toValueLabel = (value, values) => {
571
+ if (value === null || value === void 0) return value;
572
+ if (Array.isArray(value)) return value.map((v) => wrapOne(v, values));
573
+ return wrapOne(value, values);
574
+ };
575
+ var fromValueLabel = (input) => {
576
+ if (Array.isArray(input)) return input.map(fromValueLabel);
577
+ if (input && typeof input === "object" && "value" in input) {
578
+ return input.value;
579
+ }
580
+ return input;
581
+ };
582
+
583
+ // src/lib/layout/category.builder.ts
584
+ var CategoryBuilder = class _CategoryBuilder extends BuilderWithElements {
585
+ constructor(label) {
586
+ super(label);
587
+ this.label = label;
588
+ }
589
+ label;
590
+ rule = {
591
+ effect: "SHOW",
592
+ condition: {}
593
+ };
594
+ static label(label) {
595
+ return new _CategoryBuilder(label);
596
+ }
597
+ build() {
598
+ return {
599
+ type: "Category",
600
+ label: this.label,
601
+ rule: this.rule,
602
+ elements: this.buildElements()
603
+ };
604
+ }
605
+ };
606
+
607
+ // src/lib/layout/group.builder.ts
608
+ var GroupBuilder = class _GroupBuilder extends BuilderWithElements {
609
+ constructor(label) {
610
+ super(label);
611
+ this.label = label;
612
+ }
613
+ label;
614
+ static label(label) {
615
+ return new _GroupBuilder(label);
616
+ }
617
+ build() {
618
+ return {
619
+ type: "Group",
620
+ label: this.label,
621
+ elements: this.buildElements()
622
+ };
623
+ }
624
+ };
625
+
626
+ // src/lib/table/table.builder.ts
627
+ var TextCellBuilder = class _TextCellBuilder extends Builder {
628
+ constructor(scope, type = "TextCell") {
629
+ super(type);
630
+ this.scope = scope;
631
+ }
632
+ scope;
633
+ options;
634
+ static properties(property) {
635
+ return new _TextCellBuilder(`#/properties/${property}`);
636
+ }
637
+ key(key) {
638
+ this.options = {
639
+ format: "keyValue",
640
+ key
641
+ };
642
+ return this;
643
+ }
644
+ setSortId(sortId) {
645
+ this.options = {
646
+ ...this.options ?? { format: this.type },
647
+ sortId
648
+ };
649
+ return this;
650
+ }
651
+ build() {
652
+ return {
653
+ type: this.type,
654
+ scope: this.scope,
655
+ options: this.options
656
+ };
657
+ }
658
+ };
659
+ var BooleanCellBuilder = class _BooleanCellBuilder extends TextCellBuilder {
660
+ constructor(scope) {
661
+ super(scope, "BooleanCell");
662
+ }
663
+ static properties(property) {
664
+ return new _BooleanCellBuilder(`#/properties/${property}`);
665
+ }
666
+ };
667
+ var TableBuilder = class _TableBuilder {
668
+ builder;
669
+ constructor() {
670
+ this.builder = LayoutBuilder.horizontal();
671
+ }
672
+ static init() {
673
+ return new _TableBuilder();
674
+ }
675
+ addControl(control) {
676
+ this.builder.addControls(control);
677
+ return this;
678
+ }
679
+ addControls(...controls) {
680
+ this.builder.addControls(...controls);
681
+ return this;
682
+ }
683
+ build() {
684
+ return this.builder.build();
685
+ }
686
+ };
687
+
688
+ // src/lib/table/table.utils.ts
689
+ var findColumnDef = (column, schema) => {
690
+ const { id, property } = findProperty(column, schema);
691
+ return { ...column, id, ...property };
692
+ };
693
+
694
+ // src/lib/data-source/DataSourceSchema.ts
695
+ var import_zod7 = __toESM(require("zod"), 1);
696
+ var DataSourceShape = import_zod7.default.object({
697
+ /** Datasource name (folder + `name` in data-source.json). */
698
+ name: import_zod7.default.string(),
699
+ /** Env var holding the connection URL. */
700
+ urlEnv: import_zod7.default.string(),
701
+ /** Import path for this datasource's generated Zod types (for resource `schema.ts`). */
702
+ generatedTypesImport: import_zod7.default.string().optional(),
703
+ /** Datasource type tag. Default `postgres`. */
704
+ type: import_zod7.default.string().default("postgres"),
705
+ /** Mark this as the default datasource. Default `false`. */
706
+ default: import_zod7.default.boolean().default(false),
707
+ /** Prisma schema path, relative to project root. Default `prisma/<name>/schema.prisma`. */
708
+ prismaSchema: import_zod7.default.string().optional(),
709
+ /** Prisma config path, relative to project root. Default `prisma/<name>/prisma.config.ts`. */
710
+ prismaConfig: import_zod7.default.string().optional(),
711
+ /** zod-prisma-types output dir, relative to project root. Default `generated/<name>/src`. */
712
+ zodOutput: import_zod7.default.string().optional(),
713
+ /** Prisma client output dir, relative to project root. Default `generated/<name>/client`. */
714
+ clientOutput: import_zod7.default.string().optional()
715
+ });
716
+ var transformDataSource = (data) => {
717
+ const name = data.name ?? "name";
718
+ return {
719
+ ...data,
720
+ generatedTypesImport: data.generatedTypesImport ?? `@your-scope/generated/${name}`,
721
+ prismaSchema: data.prismaSchema ?? `prisma/${name}/schema.prisma`,
722
+ prismaConfig: data.prismaConfig ?? `prisma/${name}/prisma.config.ts`,
723
+ zodOutput: data.zodOutput ?? `generated/${name}/src`,
724
+ clientOutput: data.clientOutput ?? `generated/${name}/client`
725
+ };
726
+ };
727
+ var DataSourceSchema = DataSourceShape.transform(transformDataSource);
728
+
729
+ // src/lib/data-source/Operations.schema.ts
730
+ var import_zod8 = require("zod");
731
+ var BoolOrUpsertSchema = import_zod8.z.union([
732
+ import_zod8.z.boolean(),
733
+ import_zod8.z.object({ upsertOn: import_zod8.z.union([import_zod8.z.string(), import_zod8.z.array(import_zod8.z.string())]) })
734
+ ]);
735
+ var JsonOperationsSchema = import_zod8.z.object({
736
+ findAll: import_zod8.z.boolean().default(true),
737
+ // default: true — only explicit `false` disables it
738
+ findOne: import_zod8.z.boolean().default(true),
739
+ // default: true
740
+ create: import_zod8.z.boolean().default(true),
741
+ // default: true
742
+ update: import_zod8.z.boolean().default(true),
743
+ // default: true
744
+ patch: import_zod8.z.boolean().default(true),
745
+ // default: true
746
+ upsert: BoolOrUpsertSchema.default(false),
747
+ // default: disabled; `true` throws at load time — must be `{ upsertOn }`
748
+ delete: import_zod8.z.boolean().default(true)
749
+ // default: true
750
+ });
751
+
752
+ // src/lib/resource/ResourceJson.schema.ts
753
+ var import_zod15 = require("zod");
754
+
755
+ // src/lib/resource/CalculatedColumn.schema.ts
756
+ var import_zod10 = require("zod");
757
+
758
+ // src/lib/resource/FieldInput.schema.ts
759
+ var import_zod9 = require("zod");
760
+ var RelationType = import_zod9.z.enum([
761
+ "oneToOne",
762
+ "manyToOne",
763
+ "oneToMany",
764
+ "manyToMany"
765
+ ]);
766
+ var DetailControlSchema = import_zod9.z.object({
767
+ property: import_zod9.z.string(),
768
+ // required
769
+ type: import_zod9.z.string().optional(),
770
+ // default: 'text'
771
+ options: import_zod9.z.record(import_zod9.z.string(), import_zod9.z.unknown()).optional(),
772
+ hideLabel: import_zod9.z.boolean().optional(),
773
+ // default: false
774
+ width: import_zod9.z.string().optional()
775
+ });
776
+ var DetailConfigSchema = import_zod9.z.object({
777
+ layout: import_zod9.z.enum(["collapse", "row"]),
778
+ // required
779
+ titleKey: import_zod9.z.string().optional(),
780
+ controls: import_zod9.z.array(DetailControlSchema)
781
+ // required
782
+ });
783
+ var RelationFieldInputOptionsSchema = import_zod9.z.object({
784
+ colspan: import_zod9.z.number().optional().default(12),
785
+ /** Field to sort related records by, e.g. `"title"` or `"author.name"`. */
786
+ sort: import_zod9.z.string().optional(),
787
+ /** Sort direction. Defaults to `"asc"` when omitted. */
788
+ sortDir: import_zod9.z.enum(["asc", "desc"]).optional(),
789
+ // default: 'asc'
790
+ /** CSS flex direction for the relation control button layout. */
791
+ direction: import_zod9.z.string().optional(),
792
+ /** Key used as the display label in the relation control. */
793
+ displayKey: import_zod9.z.string().optional(),
794
+ /** Path to the related resource (resolved to a URI at load time). */
795
+ resource: import_zod9.z.string().optional()
796
+ }).catchall(import_zod9.z.unknown());
797
+ var FieldInputSchema = import_zod9.z.object({
798
+ type: import_zod9.z.string().optional(),
799
+ customRender: import_zod9.z.string().optional(),
800
+ /**
801
+ * Render format hint for the frontend (e.g. `"relation"` for sub-resource
802
+ * relations). When `format` is `"relation"`, `resource` must also be set.
803
+ */
804
+ format: import_zod9.z.string().optional(),
805
+ // 'relation' triggers relation handling; requires `resource`
806
+ /**
807
+ * Relative path to the child resource definition, e.g. `"./author.resource"`.
808
+ * Only used when `format` is `"relation"`. Resolved at load time to inject
809
+ * sub-resource URIs into `options`.
810
+ */
811
+ resource: import_zod9.z.string().optional(),
812
+ // required when format === 'relation'
813
+ /**
814
+ * Cardinality of the relation. Used by the frontend to determine the correct
815
+ * renderer and behaviour (e.g. single-select vs multi-select).
816
+ * - `manyToOne` / `oneToOne` — single FK reference (autocomplete / relation control)
817
+ * - `oneToMany` / `manyToMany` — collection (sub-resource table / multi-select)
818
+ */
819
+ relationType: RelationType.optional(),
820
+ // auto-derived from the Zod model/sibling FK column if omitted
821
+ /** Override the display order in form views. Lower values come first. */
822
+ position: import_zod9.z.number().optional(),
823
+ // default: source order
824
+ options: import_zod9.z.union([RelationFieldInputOptionsSchema, import_zod9.z.unknown()]).optional(),
825
+ /** Nested array detail layout (renders via `detailFixed`). */
826
+ detail: DetailConfigSchema.optional()
827
+ });
828
+ var FieldVariantSchema = FieldInputSchema;
829
+ var stripNull = (obj) => {
830
+ const out = {};
831
+ for (const [k, v] of Object.entries(obj)) if (v !== null) out[k] = v;
832
+ return out;
833
+ };
834
+ var mergeFieldVariant = (base, override) => {
835
+ if (!base) return override;
836
+ if (!override) return base;
837
+ const merged = stripNull({ ...base, ...override });
838
+ if (base.options || override.options) {
839
+ const mergedOptions = stripNull({
840
+ ...base.options,
841
+ ...override.options
842
+ });
843
+ merged.options = mergedOptions;
844
+ }
845
+ return merged;
846
+ };
847
+
848
+ // src/lib/schema/label.helper.ts
849
+ var labelFromId = (id) => {
850
+ const words = id.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").trim();
851
+ return words.charAt(0).toUpperCase() + words.slice(1).toLowerCase();
852
+ };
853
+ var normalizeLabel = (obj) => {
854
+ return { label: labelFromId(obj.id), ...obj };
855
+ };
856
+
857
+ // src/lib/resource/CalculatedColumn.schema.ts
858
+ var CalculatedColumnSchema = import_zod10.z.object({
859
+ /** Column identifier used in the response payload and UI schema. */
860
+ id: import_zod10.z.string(),
861
+ // required
862
+ /** SQL alias — must match `id`. */
863
+ alias: import_zod10.z.string(),
864
+ // required — must match `id`
865
+ /** Human-readable label shown in the table header. */
866
+ label: import_zod10.z.string().optional(),
867
+ sqlExpression: import_zod10.z.string(),
868
+ // required
869
+ /** JSON schema / cast type for the computed value. Defaults to `"number"`. `"string"` skips CAST. */
870
+ type: import_zod10.z.enum(["number", "boolean", "string"]).optional(),
871
+ // default: 'number'
872
+ /**
873
+ * Insertion position relative to the other visible columns.
874
+ * Uses the same semantics as `fieldInput.position` on regular columns:
875
+ * `position: N` places this column before the element currently at index N.
876
+ * Can also be set via `fieldInput.position` (takes precedence).
877
+ */
878
+ position: import_zod10.z.number().optional(),
879
+ hiddenInTable: import_zod10.z.boolean().optional(),
880
+ // default: false
881
+ hiddenInView: import_zod10.z.boolean().optional(),
882
+ // default: false
883
+ /**
884
+ * Field input options for rendering in form / view schemas.
885
+ * Supports `colspan`, `format`, and any other options passed to the Control renderer.
886
+ * `position` here takes precedence over the top-level `position`.
887
+ */
888
+ fieldInput: FieldInputSchema.optional()
889
+ }).transform(normalizeLabel);
890
+
891
+ // src/lib/resource/Column.ts
892
+ var import_zod11 = require("zod");
893
+ var WhenConditionSchema = import_zod11.z.object({
894
+ field: import_zod11.z.string(),
895
+ // required
896
+ eq: import_zod11.z.unknown().optional(),
897
+ neq: import_zod11.z.unknown().optional(),
898
+ exists: import_zod11.z.boolean().optional(),
899
+ notExists: import_zod11.z.boolean().optional()
900
+ });
901
+ var JsonColumnSchema = import_zod11.z.object({
902
+ id: import_zod11.z.string(),
903
+ // required in array form; implied by the map key in map form
904
+ column: import_zod11.z.string().optional(),
905
+ // default: same as `id`
906
+ label: import_zod11.z.string().optional(),
907
+ // default: title-cased version of `id`
908
+ hiddenInTable: import_zod11.z.boolean().default(false),
909
+ // default: false
910
+ hiddenInForm: import_zod11.z.boolean().default(false),
911
+ // default: false
912
+ hiddenInView: import_zod11.z.boolean().default(false),
913
+ // default: false
914
+ sortable: import_zod11.z.boolean().default(false),
915
+ // default: false
916
+ defaultSort: import_zod11.z.boolean().default(false),
917
+ // default: false
918
+ searchable: import_zod11.z.boolean().default(false),
919
+ // default: false
920
+ filterable: import_zod11.z.boolean().default(false),
921
+ // default: false
922
+ createable: import_zod11.z.boolean().default(true),
923
+ // default: true (only `false` excludes it)
924
+ updateable: import_zod11.z.boolean().default(true),
925
+ // default: true (only `false` excludes it)
926
+ hideLabel: import_zod11.z.boolean().default(false),
927
+ // default: false
928
+ showWhen: WhenConditionSchema.optional(),
929
+ hideWhen: WhenConditionSchema.optional(),
930
+ disabledWhen: WhenConditionSchema.optional(),
931
+ displayKey: import_zod11.z.string().optional(),
932
+ // e.g. "author.name" for nested display
933
+ sortId: import_zod11.z.string().optional(),
934
+ // overrides the sort
935
+ /**
936
+ * Name of a shared enum in the project enum registry (`crouton.enums.json`).
937
+ * At load time the loader injects that enum's `{ value, label }[]` into
938
+ * `fieldInput.options.values`, so columns don't duplicate the option list.
939
+ */
940
+ enum: import_zod11.z.string().optional(),
941
+ // name of a shared enum in crouton.enums.json
942
+ idField: import_zod11.z.boolean().default(false),
943
+ // default: false — exactly one column should set this
944
+ showInLookup: import_zod11.z.boolean().default(false),
945
+ // default: false
946
+ columnType: import_zod11.z.string().default("string"),
947
+ // default: 'string'
948
+ fieldInput: FieldInputSchema.optional(),
949
+ /**
950
+ * Optional per-context override for the read-only VIEW ui. Same shape as
951
+ * `fieldInput`; every key optional. Falls back to `fieldInput` (deep-merged
952
+ * one level into `options`). Resolved at read time by the transformer.
953
+ */
954
+ fieldView: FieldVariantSchema.optional(),
955
+ /**
956
+ * Optional per-context override for the TABLE ui. Same shape as `fieldInput`;
957
+ * every key optional. Falls back to `fieldView`, then `fieldInput`.
958
+ * Resolved at read time by the transformer.
959
+ */
960
+ fieldTable: FieldVariantSchema.optional(),
961
+ /**
962
+ * Path to another `resource.json` whose columns are expanded as nested sub-columns
963
+ * under this column's object key.
964
+ *
965
+ * Example: `"extend": "../internalAuthor/resource.json"` on a column `author`
966
+ * auto-generates virtual sub-columns like `author_name` (column: "author", displayKey: "name").
967
+ *
968
+ * Visibility (`hiddenInTable/Form/View`) on this column is inherited by all sub-columns as a
969
+ * default; the referenced resource's own column visibility further restricts it.
970
+ */
971
+ extend: import_zod11.z.string().optional(),
972
+ // path to another resource.json expanded as virtual sub-columns
973
+ /**
974
+ * Per-sub-column overrides when using `extend`.
975
+ * Key: the virtual column id (`"{extendId}_{refColId}"`) or just the referenced column id.
976
+ * Value: any `JsonColumn` fields to merge over the generated virtual column.
977
+ */
978
+ columns: import_zod11.z.record(import_zod11.z.string(), import_zod11.z.record(import_zod11.z.string(), import_zod11.z.unknown())).optional()
979
+ // per-sub-column overrides, only used with `extend`
980
+ });
981
+
982
+ // src/lib/resource/Sidebar.schema.ts
983
+ var import_zod12 = __toESM(require("zod"), 1);
984
+ var SidebarGroupSchema = import_zod12.default.object({
985
+ /** Human-readable heading shown in the sidebar. Defaults to a title-cased version of the slug. */
986
+ label: import_zod12.default.string().optional(),
987
+ /** Controls the order of this group among top-level sidebar items. */
988
+ position: import_zod12.default.number().optional()
989
+ });
990
+ var SidebarSchema = import_zod12.default.object({
991
+ hide: import_zod12.default.boolean().default(false),
992
+ // default: false
993
+ position: import_zod12.default.number().optional(),
994
+ // default: sorted alphabetically after positioned entries
995
+ label: import_zod12.default.string().optional(),
996
+ // default: resource `title`
997
+ /**
998
+ * Slug of the group this resource belongs to.
999
+ * Must match a key in `sidebarGroups` in `crouton.json`.
1000
+ * Resources with the same `group` are nested under a shared collapsible section.
1001
+ */
1002
+ group: import_zod12.default.string().optional()
1003
+ // must match a key in `sidebarGroups` (crouton.json)
1004
+ });
1005
+
1006
+ // src/lib/resource/TableAction.schema.ts
1007
+ var import_zod13 = require("zod");
1008
+ var ActionConditionSchema = import_zod13.z.object({
1009
+ /** Row field to evaluate. */
1010
+ field: import_zod13.z.string(),
1011
+ //
1012
+ /**
1013
+ * Comparison operator. Defaults to `"eq"`.
1014
+ * - `eq` / `neq` — strict equality
1015
+ * - `gt` / `gte` / `lt` / `lte` — numeric or date comparison
1016
+ * - `exists` — field is not null / undefined / empty string
1017
+ * - `notExists` — field is null / undefined / empty string
1018
+ */
1019
+ op: import_zod13.z.enum(["eq", "neq", "gt", "gte", "lt", "lte", "exists", "notExists"]).default("eq"),
1020
+ // default: 'eq'
1021
+ /** Comparison value. Not required for `exists` / `notExists`. */
1022
+ value: import_zod13.z.unknown().optional()
1023
+ // not required for exists/notExists
1024
+ });
1025
+ var ActionSchema = import_zod13.z.object({
1026
+ type: import_zod13.z.string(),
1027
+ /** Unique identifier for the action. */
1028
+ id: import_zod13.z.string(),
1029
+ // required
1030
+ /** Human-readable button label. */
1031
+ label: import_zod13.z.string(),
1032
+ /** MDI icon name, e.g. `"mdi:open-in-new"`. */
1033
+ icon: import_zod13.z.string().optional(),
1034
+ /** Tooltip text. Falls back to `label` when omitted. */
1035
+ tooltip: import_zod13.z.string().optional(),
1036
+ // default: falls back to `label`
1037
+ condition: ActionConditionSchema.optional()
1038
+ });
1039
+ var JsonProcedureActionSchema = ActionSchema.extend({
1040
+ type: import_zod13.z.literal("procedure").default("procedure"),
1041
+ // default: 'procedure'
1042
+ /**
1043
+ * Filename (without extension) inside the resource's `actions/` directory
1044
+ * that exports the table-action procedure, e.g. `"syncZotero"`.
1045
+ */
1046
+ procedure: import_zod13.z.string(),
1047
+ // required
1048
+ /** HTTP method for the frontend. Defaults to `"post"`. */
1049
+ method: import_zod13.z.string().optional().default("post"),
1050
+ // default: 'post'
1051
+ /** Static query / body params passed to the endpoint. */
1052
+ data: import_zod13.z.record(import_zod13.z.string(), import_zod13.z.unknown()).optional()
1053
+ });
1054
+ var JsonLinkActionSchema = ActionSchema.extend({
1055
+ /** Optional condition evaluated per row. Button is hidden when the condition is false. */
1056
+ type: import_zod13.z.literal("link").default("link"),
1057
+ // required
1058
+ /** URL to open. May contain `{env.VAR}` placeholders. */
1059
+ href: import_zod13.z.string()
1060
+ // required
1061
+ });
1062
+ var transformAction = (action) => {
1063
+ const label = action.label;
1064
+ return {
1065
+ tooltip: label,
1066
+ ...action
1067
+ };
1068
+ };
1069
+ var JsonActionSchema = import_zod13.z.union([JsonProcedureActionSchema, JsonLinkActionSchema]).transform(transformAction);
1070
+
1071
+ // src/lib/resource/include.schema.ts
1072
+ var import_zod14 = require("zod");
1073
+ var JsonIncludeEntrySchema = import_zod14.z.lazy(
1074
+ () => import_zod14.z.union([
1075
+ import_zod14.z.string(),
1076
+ // plain relation name → `{ [name]: true }`
1077
+ import_zod14.z.object({
1078
+ relation: import_zod14.z.string(),
1079
+ // required
1080
+ include: import_zod14.z.array(JsonIncludeEntrySchema).optional(),
1081
+ // nested includes;
1082
+ /** Prisma-format orderBy clause applied to the included records. */
1083
+ orderBy: import_zod14.z.record(import_zod14.z.string(), import_zod14.z.unknown()).optional()
1084
+ })
1085
+ ])
1086
+ );
1087
+
1088
+ // src/lib/resource/ResourceJson.schema.ts
1089
+ var JsonColumnsMapSchema = import_zod15.z.record(
1090
+ import_zod15.z.string(),
1091
+ JsonColumnSchema.omit({ id: true }).catchall(import_zod15.z.unknown())
1092
+ );
1093
+ var ColumnsSchema = JsonColumnsMapSchema;
1094
+ var JsonDisplaySchema = import_zod15.z.object({
1095
+ mode: import_zod15.z.enum(["page", "modal"]).default("modal"),
1096
+ // default: 'modal'
1097
+ customComponent: import_zod15.z.string().nullable().optional().default(null)
1098
+ // default: null
1099
+ });
1100
+ var normalizeColumns = (columns) => {
1101
+ if (!columns) return void 0;
1102
+ const raw = Array.isArray(columns) ? columns : Object.entries(columns).map(([id, col]) => ({ id, ...col }));
1103
+ return raw.map((col) => ({
1104
+ ...col,
1105
+ label: col.label ?? labelFromId(col.id)
1106
+ }));
1107
+ };
1108
+ var ResourceJsonShape = import_zod15.z.object({
1109
+ name: import_zod15.z.string(),
1110
+ // required — unique id, used as the frontend form id
1111
+ route: import_zod15.z.string(),
1112
+ // required — URL segment for generated endpoints
1113
+ model: import_zod15.z.string(),
1114
+ // required — Prisma model name
1115
+ tag: import_zod15.z.string(),
1116
+ // required — OpenAPI tag
1117
+ title: import_zod15.z.string().optional(),
1118
+ // no computed default — used as UI display title
1119
+ table: import_zod15.z.string().optional(),
1120
+ // default: same as `model`
1121
+ database: import_zod15.z.string().optional(),
1122
+ // default: project's default data source
1123
+ sidebar: SidebarSchema.default(SidebarSchema.parse({})),
1124
+ // default: shown, alphabetically ordered, ungrouped
1125
+ display: JsonDisplaySchema.default(JsonDisplaySchema.parse({})),
1126
+ // default: { mode: 'modal', customComponent: null }
1127
+ operations: JsonOperationsSchema,
1128
+ // required key — but every sub-field defaults to enabled
1129
+ columns: ColumnsSchema.default(ColumnsSchema.parse({})),
1130
+ // id-keyed map; omit for a columnless resource
1131
+ calculatedColumns: import_zod15.z.array(CalculatedColumnSchema).default([]),
1132
+ actions: import_zod15.z.array(JsonActionSchema).default([]),
1133
+ /** Global table-level actions (no record id). Shown as toolbar buttons. */
1134
+ tableActions: import_zod15.z.array(JsonActionSchema).default([]),
1135
+ /** Modal width when opening a form for this resource. */
1136
+ modalSize: import_zod15.z.enum(["xs", "sm", "lg", "xl"]).default("sm"),
1137
+ // default: 'sm' for create/edit modal
1138
+ /**
1139
+ * Relations to include when querying this resource.
1140
+ * Each entry is either a plain relation name (`"author"` → `include: { author: true }`)
1141
+ * or an object for nested includes:
1142
+ * `{ "relation": "text_author", "include": ["author"] }` →
1143
+ * `include: { text_author: { include: { author: true } } }`
1144
+ */
1145
+ include: import_zod15.z.array(JsonIncludeEntrySchema).default([])
1146
+ });
1147
+ var ResourceJsonSchema = ResourceJsonShape.transform((obj) => {
1148
+ const title = obj.title ?? labelFromId(obj.name);
1149
+ return { title, ...obj, columns: normalizeColumns(obj.columns) };
1150
+ });
1151
+
1152
+ // src/lib/resource/fieldVariants.ts
1153
+ var resolveFormField = (c) => c.fieldInput;
1154
+ var resolveViewField = (c) => mergeFieldVariant(c.fieldInput, c.fieldView);
1155
+ var resolveTableField = (c) => mergeFieldVariant(resolveViewField(c), c.fieldTable);
1156
+
1157
+ // src/lib/config/CroutonConfig.schema.ts
1158
+ var import_zod16 = require("zod");
1159
+ var RulesetSchema = import_zod16.z.object({
1160
+ hideIdInTable: import_zod16.z.boolean().default(true),
1161
+ hideIdInForm: import_zod16.z.boolean().default(true),
1162
+ hideIdInView: import_zod16.z.boolean().default(true),
1163
+ hideTimestamps: import_zod16.z.boolean().default(true),
1164
+ hideForeignKeys: import_zod16.z.boolean().default(true),
1165
+ includeRelations: import_zod16.z.boolean().default(false),
1166
+ hideRelationsInTable: import_zod16.z.boolean().default(true),
1167
+ showRelationsInForm: import_zod16.z.boolean().default(true),
1168
+ enumValueLabel: import_zod16.z.boolean().default(true),
1169
+ sharedEnums: import_zod16.z.boolean().default(true),
1170
+ defaultOperations: JsonOperationsSchema.default(
1171
+ JsonOperationsSchema.parse({})
1172
+ )
1173
+ });
1174
+ var CroutonConfigSchema = import_zod16.z.object({
1175
+ /**
1176
+ * Application title served to the frontend via `GET /_app/layout`.
1177
+ * Displayed in the admin sidebar header.
1178
+ */
1179
+ title: import_zod16.z.string(),
1180
+ /** Where resource directories live, relative to the project root. */
1181
+ resourcesDir: import_zod16.z.string(),
1182
+ /** Where datasource folders live (each with a `data-source.json`). */
1183
+ dataSourcesDir: import_zod16.z.string(),
1184
+ /**
1185
+ * Template for a model's Zod export name. `{Model}` → Prisma model name.
1186
+ * Defaults to `{Model}WithRelationsSchema` (the relations-aware schema
1187
+ * emitted by zod-prisma-types when `createRelationValuesTypes` is on).
1188
+ */
1189
+ schemaExportName: import_zod16.z.string().default("{Model}WithRelationsSchema"),
1190
+ /** Path to the shared enum registry, relative to project root. Default `crouton.enums.json`. */
1191
+ enumsFile: import_zod16.z.string().default("crouton.enums.json"),
1192
+ /** Optional overrides of the default visibility ruleset. */
1193
+ rules: RulesetSchema.default(RulesetSchema.parse({})),
1194
+ /**
1195
+ * Sidebar group definitions, keyed by group slug (e.g. `"metadata"`).
1196
+ * Resources reference a group via `sidebar.group` in their `resource.json`.
1197
+ */
1198
+ sidebarGroups: import_zod16.z.record(import_zod16.z.string(), SidebarGroupSchema).default({}),
1199
+ /**
1200
+ * Whether form fields are saved automatically as the user edits them.
1201
+ * @default true
1202
+ */
1203
+ autoSave: import_zod16.z.boolean().default(true)
1204
+ });
1205
+
1206
+ // src/lib/config/readConfig.ts
1207
+ var CONFIG_FILES = ["crouton.json", "crouton.mjs", "crouton.js"];
1208
+ // Annotate the CommonJS export names for ESM import in node:
1209
+ 0 && (module.exports = {
1210
+ BooleanCellBuilder,
1211
+ Builder,
1212
+ BuilderWithElements,
1213
+ CONFIG_FILES,
1214
+ CalculatedColumnSchema,
1215
+ CategoryBuilder,
1216
+ ControlBuilder,
1217
+ ControlType,
1218
+ CroutonConfigSchema,
1219
+ DataSourceSchema,
1220
+ DataSourceShape,
1221
+ DetailConfigSchema,
1222
+ DetailControlSchema,
1223
+ FieldInputSchema,
1224
+ FieldVariantSchema,
1225
+ GroupBuilder,
1226
+ JsonActionSchema,
1227
+ JsonColumnSchema,
1228
+ JsonIncludeEntrySchema,
1229
+ JsonLinkActionSchema,
1230
+ JsonOperationsSchema,
1231
+ JsonProcedureActionSchema,
1232
+ LayoutBuilder,
1233
+ LayoutTypes,
1234
+ ModalSize,
1235
+ Operator,
1236
+ OperatorLabel,
1237
+ OperatorNoValue,
1238
+ OperatorOptions,
1239
+ OperatorsByType,
1240
+ PositiveRequestNumber,
1241
+ RelationFieldInputOptionsSchema,
1242
+ RelationType,
1243
+ RequestSchema,
1244
+ RequestSchemaWithOffset,
1245
+ ResourceJsonSchema,
1246
+ ResourceJsonShape,
1247
+ ResponseRequestSchema,
1248
+ ResponseSchema,
1249
+ RulesetSchema,
1250
+ SidebarGroupSchema,
1251
+ SidebarSchema,
1252
+ Size,
1253
+ SortDirEnum,
1254
+ StringOrArray,
1255
+ TableBuilder,
1256
+ TextCellBuilder,
1257
+ WhenConditionSchema,
1258
+ buildFilter,
1259
+ buildSort,
1260
+ buildSortKey,
1261
+ createSchema,
1262
+ dropNullableFromRequired,
1263
+ enforceRequiredStringMinLength,
1264
+ extractFilters,
1265
+ filterToString,
1266
+ findColumnDef,
1267
+ findProperty,
1268
+ fromValueLabel,
1269
+ labelFromId,
1270
+ mergeFieldVariant,
1271
+ normalizeLabel,
1272
+ resolveFormField,
1273
+ resolveTableField,
1274
+ resolveViewField,
1275
+ stringToFilter,
1276
+ toValueLabel,
1277
+ transformDataSource,
1278
+ uiFromJsonSchema
1279
+ });
1280
+ //# sourceMappingURL=index.cjs.map