betterstart-cli 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -3867,6 +3867,61 @@ function generateFieldMapping(field, source = "input") {
3867
3867
  function getFieldType(field, mode = "output") {
3868
3868
  return toTypeScriptType(field, mode);
3869
3869
  }
3870
+ function getReadFieldType(field) {
3871
+ if (field.type === "select") return "SelectOptionValue[]";
3872
+ if (field.type === "group" && field.fields && field.fields.length > 0) {
3873
+ const groupType = field.fields.map(
3874
+ (nestedField) => `${quotePropertyName(nestedField.name)}?: ${getReadFieldType(nestedField)}`
3875
+ ).join("; ");
3876
+ return `{ ${groupType} }`;
3877
+ }
3878
+ if (field.type === "list" && field.fields && field.fields.length > 0) {
3879
+ const nestedType = field.fields.flatMap((nestedField) => {
3880
+ const fields = [`${quotePropertyName(nestedField.name)}?: ${getReadFieldType(nestedField)}`];
3881
+ if (nestedField.hasIcon) {
3882
+ fields.push(`${quotePropertyName(`${nestedField.name}Icon`)}?: string`);
3883
+ }
3884
+ return fields;
3885
+ }).join("; ");
3886
+ return `Array<{ ${nestedType} }>`;
3887
+ }
3888
+ return getFieldType(field, "output");
3889
+ }
3890
+ function collectReadSelectFields(fields, path52 = []) {
3891
+ const matches = fields.flatMap((field) => {
3892
+ const currentPath = [...path52, field.name];
3893
+ const matches2 = field.type === "select" ? [{ field, path: currentPath }] : [];
3894
+ if (field.fields) {
3895
+ matches2.push(...collectReadSelectFields(field.fields, currentPath));
3896
+ }
3897
+ if (field.tabs) {
3898
+ for (const tab of field.tabs) {
3899
+ matches2.push(...collectReadSelectFields(tab.fields ?? [], currentPath));
3900
+ if (tab.slot?.main?.fields) {
3901
+ matches2.push(...collectReadSelectFields(tab.slot.main.fields, currentPath));
3902
+ }
3903
+ if (tab.slot?.sidebar?.fields) {
3904
+ matches2.push(...collectReadSelectFields(tab.slot.sidebar.fields, currentPath));
3905
+ }
3906
+ }
3907
+ }
3908
+ return matches2;
3909
+ });
3910
+ const seen = /* @__PURE__ */ new Set();
3911
+ return matches.filter((match) => {
3912
+ const key = match.path.join(".");
3913
+ if (seen.has(key)) return false;
3914
+ seen.add(key);
3915
+ return true;
3916
+ });
3917
+ }
3918
+ function buildReadSelectOptionType(selectFields) {
3919
+ if (selectFields.length === 0) return null;
3920
+ return `export interface SelectOptionValue {
3921
+ label: string
3922
+ value: string
3923
+ }`;
3924
+ }
3870
3925
  function buildRelationshipSelect(allDbFields, relationshipFields, tableVar, htmlFields = [], extraSelects = [], extraJoins = "") {
3871
3926
  const fieldSelects = allDbFields.filter((f) => f.type !== "relationship").map((f) => ` ${f.name}: ${tableVar}.${f.name}`);
3872
3927
  const htmlSelects = htmlFields.map((f) => ` ${f.name}Html: ${tableVar}.${f.name}Html`);
@@ -3931,7 +3986,7 @@ ${rowMappings}
3931
3986
  return `${mapBlock}
3932
3987
 
3933
3988
  return {
3934
- ${camelPlural}: mapped${Plural} as ${Singular}[],
3989
+ ${camelPlural}: mapped${Plural} as unknown as ${Singular}[],
3935
3990
  total
3936
3991
  }`;
3937
3992
  }
@@ -3956,7 +4011,7 @@ function buildSingleRowMapping(allDbFields, _relationshipFields, typeName, htmlF
3956
4011
  ].join(",\n");
3957
4012
  return `{
3958
4013
  ${mappings}
3959
- } as ${typeName}`;
4014
+ } as unknown as ${typeName}`;
3960
4015
  }
3961
4016
  function buildExplicitSelect(fields, tableVar, htmlFields = [], extraSelects = [], extraJoins = "") {
3962
4017
  const fieldSelects = fields.map((f) => ` ${f.name}: ${tableVar}.${f.name}`);
@@ -4382,6 +4437,14 @@ function sampleSchemaOutputValue(field) {
4382
4437
  if (field.name === "id") return SAMPLE_UUID;
4383
4438
  if (field.name === "createdAt" || field.name === "updatedAt") return "2026-01-01T00:00:00.000Z";
4384
4439
  if (field.name === "createdBy" || field.name === "updatedBy") return "user-id";
4440
+ if (field.type === "select") {
4441
+ const sampleValue = sampleSchemaFieldValue(field);
4442
+ const values = Array.isArray(sampleValue) ? sampleValue : sampleValue ? [sampleValue] : [];
4443
+ return values.filter((value) => typeof value === "string" && value.length > 0).map((value) => ({
4444
+ label: field.options?.find((option) => option.value === value)?.label ?? value,
4445
+ value
4446
+ }));
4447
+ }
4385
4448
  if (field.type === "relationship" && field.relationship && !field.multiple) {
4386
4449
  return {
4387
4450
  id: SAMPLE_UUID,
@@ -4391,6 +4454,18 @@ function sampleSchemaOutputValue(field) {
4391
4454
  label: "Example related record"
4392
4455
  };
4393
4456
  }
4457
+ if (field.type === "group" && field.fields && field.fields.length > 0) {
4458
+ return Object.fromEntries(
4459
+ field.fields.filter((nestedField) => nestedField.name && !isLayoutField(nestedField.type)).map((nestedField) => [nestedField.name, sampleSchemaOutputValue(nestedField)])
4460
+ );
4461
+ }
4462
+ if (field.type === "list" && field.fields && field.fields.length > 0) {
4463
+ return [
4464
+ Object.fromEntries(
4465
+ field.fields.filter((nestedField) => nestedField.name && !isLayoutField(nestedField.type)).map((nestedField) => [nestedField.name, sampleSchemaOutputValue(nestedField)])
4466
+ )
4467
+ ];
4468
+ }
4394
4469
  return sampleSchemaFieldValue(field);
4395
4470
  }
4396
4471
  function sampleSingleOutputValue(field) {
@@ -8030,7 +8105,10 @@ function genHelpersContent(ctx) {
8030
8105
  drizzleImports.add("inArray");
8031
8106
  schemaImports.add("adminMedia");
8032
8107
  }
8033
- if (ctx.hasM2M || ctx.hasListRels || ctx.hasMediaFields) {
8108
+ if (ctx.hasCreatableSelectFields) {
8109
+ schemaImports.add(ctx.selectOptionsTableVar);
8110
+ }
8111
+ if (ctx.hasM2M || ctx.hasListRels || ctx.hasMediaFields || ctx.hasCreatableSelectFields) {
8034
8112
  lines.push(`import db from '@admin/db'`);
8035
8113
  }
8036
8114
  const tables = [...schemaImports].sort();
@@ -8043,7 +8121,8 @@ function genHelpersContent(ctx) {
8043
8121
  if (ctx.hasMediaFields) {
8044
8122
  lines.push(`import type { AdminMedia } from '@admin/types'`);
8045
8123
  }
8046
- lines.push(`import type { ${ctx.Singular} } from './types'`);
8124
+ const typeImports = ctx.hasSelectFields ? `${ctx.Singular}, SelectOptionValue` : ctx.Singular;
8125
+ lines.push(`import type { ${typeImports} } from './types'`);
8047
8126
  lines.push("");
8048
8127
  lines.push(`export function formatActionDate(value: unknown): string {
8049
8128
  if (typeof value !== 'string') return ''
@@ -8067,6 +8146,10 @@ function genHelpersContent(ctx) {
8067
8146
  lines.push(generateResolveMediaFunction(ctx));
8068
8147
  lines.push("");
8069
8148
  }
8149
+ if (ctx.hasSelectFields) {
8150
+ lines.push(generateResolveSelectFieldsFunction(ctx));
8151
+ lines.push("");
8152
+ }
8070
8153
  lines.push(generateVersionSnapshotHelpers(ctx));
8071
8154
  lines.push("");
8072
8155
  return lines.join("\n");
@@ -8117,7 +8200,7 @@ const VERSION_RESTORE_KEYS = [${restoreKeys}] as const
8117
8200
  const VERSION_M2M_KEYS = [${m2mKeys}] as const
8118
8201
 
8119
8202
  export function build${ctx.Singular}VersionSnapshot(row: Partial<${ctx.Singular}> | Record<string, unknown>): Record<string, unknown> {
8120
- const source = row as Record<string, unknown>
8203
+ const source = row as unknown as Record<string, unknown>
8121
8204
  const snapshot: Record<string, unknown> = {}
8122
8205
 
8123
8206
  for (const key of VERSION_SNAPSHOT_KEYS) {
@@ -8222,6 +8305,95 @@ ${assignArray}` : ""}
8222
8305
  return rows
8223
8306
  }`;
8224
8307
  }
8308
+ function generateResolveSelectFieldsFunction(ctx) {
8309
+ const staticLabelMaps = ctx.selectFields.map((readField) => {
8310
+ const key = readField.path.join(".");
8311
+ const entries = (readField.field.options ?? []).map((option) => `${JSON.stringify(option.value)}: ${JSON.stringify(option.label)}`).join(", ");
8312
+ return ` ${JSON.stringify(key)}: { ${entries} }`;
8313
+ }).join(",\n");
8314
+ const dynamicRowsBlock = ctx.hasCreatableSelectFields ? `
8315
+ const dynamicRows = await db
8316
+ .select({
8317
+ fieldName: ${ctx.selectOptionsTableVar}.fieldName,
8318
+ label: ${ctx.selectOptionsTableVar}.label,
8319
+ value: ${ctx.selectOptionsTableVar}.value
8320
+ })
8321
+ .from(${ctx.selectOptionsTableVar})
8322
+
8323
+ for (const row of dynamicRows) {
8324
+ labelMaps[row.fieldName] ??= {}
8325
+ labelMaps[row.fieldName][row.value] = row.label
8326
+ }
8327
+ ` : "";
8328
+ const assignments = ctx.selectFields.map((readField) => {
8329
+ const key = readField.path.join(".");
8330
+ return ` resolveSelectFieldPath(source, ${JSON.stringify(readField.path)}, labelMaps[${JSON.stringify(key)}] ?? {})`;
8331
+ }).join("\n");
8332
+ return `const STATIC_SELECT_OPTION_LABELS = {
8333
+ ${staticLabelMaps}
8334
+ } satisfies Record<string, Record<string, string>>
8335
+
8336
+ function cloneSelectOptionLabelMaps(): Record<string, Record<string, string>> {
8337
+ return Object.fromEntries(
8338
+ Object.entries(STATIC_SELECT_OPTION_LABELS).map(([fieldName, labels]) => [
8339
+ fieldName,
8340
+ { ...labels }
8341
+ ])
8342
+ )
8343
+ }
8344
+
8345
+ function toSelectOptionValues(value: unknown, labels: Record<string, string>): SelectOptionValue[] {
8346
+ const values = Array.isArray(value) ? value : value ? [value] : []
8347
+
8348
+ return values
8349
+ .filter((item): item is string => typeof item === 'string' && item.length > 0)
8350
+ .map((item) => ({
8351
+ label: labels[item] ?? item,
8352
+ value: item
8353
+ }))
8354
+ }
8355
+
8356
+ function resolveSelectFieldPath(
8357
+ source: Record<string, unknown>,
8358
+ path: readonly string[],
8359
+ labels: Record<string, string>
8360
+ ): void {
8361
+ const [fieldName, ...rest] = path
8362
+ if (!fieldName) return
8363
+
8364
+ if (rest.length === 0) {
8365
+ source[fieldName] = toSelectOptionValues(source[fieldName], labels)
8366
+ return
8367
+ }
8368
+
8369
+ const value = source[fieldName]
8370
+ if (Array.isArray(value)) {
8371
+ for (const item of value) {
8372
+ if (item && typeof item === 'object') {
8373
+ resolveSelectFieldPath(item as Record<string, unknown>, rest, labels)
8374
+ }
8375
+ }
8376
+ return
8377
+ }
8378
+
8379
+ if (value && typeof value === 'object') {
8380
+ resolveSelectFieldPath(value as Record<string, unknown>, rest, labels)
8381
+ }
8382
+ }
8383
+
8384
+ export async function resolve${ctx.Singular}SelectFields(rows: ${ctx.Singular}[]): Promise<${ctx.Singular}[]> {
8385
+ if (rows.length === 0) return rows
8386
+
8387
+ const labelMaps = cloneSelectOptionLabelMaps()
8388
+ ${dynamicRowsBlock}
8389
+ for (const row of rows) {
8390
+ const source = row as unknown as Record<string, unknown>
8391
+ ${assignments}
8392
+ }
8393
+
8394
+ return rows
8395
+ }`;
8396
+ }
8225
8397
  function genGetPluralContent(ctx) {
8226
8398
  const dbImports = [ctx.tableVar, "user", ...ctx.relTableImports].sort();
8227
8399
  const drizzle = ["asc", "desc"];
@@ -8235,6 +8407,7 @@ function genGetPluralContent(ctx) {
8235
8407
  const sortedDrizzle = [...new Set(drizzle)].sort();
8236
8408
  const typeImports = [`${ctx.Plural}Page`, `${ctx.Plural}Query`, `${ctx.Singular}`];
8237
8409
  const helperImports = ["formatActionDate"];
8410
+ if (ctx.hasSelectFields) helperImports.push(`resolve${ctx.Singular}SelectFields`);
8238
8411
  if (ctx.hasListRels) helperImports.push(`populate${ctx.Singular}ListRelationships`);
8239
8412
  if (ctx.hasMediaFields) helperImports.push(`resolve${ctx.Singular}MediaFields`);
8240
8413
  const populateImport = helperImports.length > 0 ? `
@@ -8325,6 +8498,7 @@ function genGetByIdContent(ctx) {
8325
8498
  const drizzle = ["eq"];
8326
8499
  const sortedDrizzle = [...new Set(drizzle)].sort();
8327
8500
  const byIdHelperImports = ["formatActionDate"];
8501
+ if (ctx.hasSelectFields) byIdHelperImports.push(`resolve${ctx.Singular}SelectFields`);
8328
8502
  if (ctx.hasListRels) byIdHelperImports.push(`populate${ctx.Singular}ListRelationships`);
8329
8503
  if (ctx.hasMediaFields) byIdHelperImports.push(`resolve${ctx.Singular}MediaFields`);
8330
8504
  const populateImport = byIdHelperImports.length > 0 ? `
@@ -8363,6 +8537,7 @@ function genGetBySlugContent(ctx) {
8363
8537
  const drizzle = ["eq"];
8364
8538
  const sortedDrizzle = [...new Set(drizzle)].sort();
8365
8539
  const bySlugHelperImports = ["formatActionDate"];
8540
+ if (ctx.hasSelectFields) bySlugHelperImports.push(`resolve${ctx.Singular}SelectFields`);
8366
8541
  if (ctx.hasListRels) bySlugHelperImports.push(`populate${ctx.Singular}ListRelationships`);
8367
8542
  if (ctx.hasMediaFields) bySlugHelperImports.push(`resolve${ctx.Singular}MediaFields`);
8368
8543
  const populateImport = bySlugHelperImports.length > 0 ? `
@@ -8398,7 +8573,7 @@ export async function get${ctx.Singular}BySlug(slug: string): Promise<${ctx.Sing
8398
8573
  function genCreateContent(ctx) {
8399
8574
  const kebabSingular = toKebabCase(ctx.singular);
8400
8575
  const snapshotImport = ctx.hasM2M ? `build${ctx.Singular}VersionSnapshotWithRelationships` : `build${ctx.Singular}VersionSnapshot`;
8401
- const snapshotData = ctx.hasM2M ? `await build${ctx.Singular}VersionSnapshotWithRelationships(createdRow as ${ctx.Singular}, tx)` : `build${ctx.Singular}VersionSnapshot(createdRow as ${ctx.Singular})`;
8576
+ const snapshotData = ctx.hasM2M ? `await build${ctx.Singular}VersionSnapshotWithRelationships(createdRow as unknown as ${ctx.Singular}, tx)` : `build${ctx.Singular}VersionSnapshot(createdRow as unknown as ${ctx.Singular})`;
8402
8577
  const slugImport = ctx.hasAutoSlug ? `
8403
8578
  import { slugify } from '@admin/utils/validation/validation'` : "";
8404
8579
  const markdownImport = ctx.hasHtmlOutput ? `
@@ -8492,7 +8667,7 @@ ${ctx.htmlCreateMappings},` : ""}${ctx.hasDraft ? `
8492
8667
  typeof created${ctx.Singular}Id === 'string'
8493
8668
  ? await get${ctx.Singular}ById(created${ctx.Singular}Id)
8494
8669
  : null
8495
- const created${ctx.Singular}Data = created${ctx.Singular} ?? (result[0] as ${ctx.Singular})
8670
+ const created${ctx.Singular}Data = created${ctx.Singular} ?? (result[0] as unknown as ${ctx.Singular})
8496
8671
  const created${ctx.Singular}Context = ${createResultContext}
8497
8672
  ${afterHook("afterCreate", `created${ctx.Singular}Context`)}
8498
8673
  ${createAfterPublishBlock}
@@ -8511,7 +8686,7 @@ ${createAfterPublishBlock}
8511
8686
  function genUpdateContent(ctx) {
8512
8687
  const kebabSingular = toKebabCase(ctx.singular);
8513
8688
  const snapshotImport = ctx.hasM2M ? `build${ctx.Singular}VersionSnapshotWithRelationships` : `build${ctx.Singular}VersionSnapshot`;
8514
- const previousSnapshot = ctx.hasM2M ? `await build${ctx.Singular}VersionSnapshotWithRelationships(previousRow as ${ctx.Singular}, tx)` : `build${ctx.Singular}VersionSnapshot(previousRow as ${ctx.Singular})`;
8689
+ const previousSnapshot = ctx.hasM2M ? `await build${ctx.Singular}VersionSnapshotWithRelationships(previousRow as unknown as ${ctx.Singular}, tx)` : `build${ctx.Singular}VersionSnapshot(previousRow as unknown as ${ctx.Singular})`;
8515
8690
  const slugImport = ctx.hasAutoSlug ? `
8516
8691
  import { slugify } from '@admin/utils/validation/validation'` : "";
8517
8692
  const markdownImport = ctx.hasHtmlOutput ? `
@@ -8635,7 +8810,7 @@ ${htmlUpdateBlock}
8635
8810
  ${ctx.cacheInvalidationFn}(${ctx.camelPlural}CacheTags.byId(id))
8636
8811
  ${ctx.cacheInvalidationFn}(entityVersionsCacheTags.for('${ctx.plural}', id))
8637
8812
  const updated${ctx.Singular} = await get${ctx.Singular}ById(id)
8638
- const updated${ctx.Singular}Data = updated${ctx.Singular} ?? (result[0] as ${ctx.Singular})
8813
+ const updated${ctx.Singular}Data = updated${ctx.Singular} ?? (result[0] as unknown as ${ctx.Singular})
8639
8814
  const updated${ctx.Singular}Context = ${updateResultContext}
8640
8815
  ${updateAfterPublishBlock}
8641
8816
  ${afterHook("afterUpdate", `updated${ctx.Singular}Context`)}
@@ -8690,7 +8865,7 @@ function buildRestoreManyToManyStatements(ctx) {
8690
8865
  function genRestoreContent(ctx) {
8691
8866
  const kebabSingular = toKebabCase(ctx.singular);
8692
8867
  const snapshotImport = ctx.hasM2M ? `build${ctx.Singular}VersionSnapshotWithRelationships` : `build${ctx.Singular}VersionSnapshot`;
8693
- const currentSnapshot = ctx.hasM2M ? `await build${ctx.Singular}VersionSnapshotWithRelationships(currentRow as ${ctx.Singular}, tx)` : `build${ctx.Singular}VersionSnapshot(currentRow as ${ctx.Singular})`;
8868
+ const currentSnapshot = ctx.hasM2M ? `await build${ctx.Singular}VersionSnapshotWithRelationships(currentRow as unknown as ${ctx.Singular}, tx)` : `build${ctx.Singular}VersionSnapshot(currentRow as unknown as ${ctx.Singular})`;
8694
8869
  const dbImports = [
8695
8870
  "entityVersions",
8696
8871
  ctx.tableVar,
@@ -8769,7 +8944,7 @@ ${restoreM2M}
8769
8944
 
8770
8945
  return {
8771
8946
  success: true,
8772
- ${ctx.camelSingular}: restored${ctx.Singular} ?? (result[0] as ${ctx.Singular})
8947
+ ${ctx.camelSingular}: restored${ctx.Singular} ?? (result[0] as unknown as ${ctx.Singular})
8773
8948
  }
8774
8949
  } catch (error) {
8775
8950
  console.error('Error restoring ${ctx.singular} version:', error)
@@ -9812,6 +9987,8 @@ function buildEntityContext(schema, nextMajorVersion) {
9812
9987
  (f) => f.type === "select" && f.creatable === true
9813
9988
  );
9814
9989
  const hasCreatableSelectFields = creatableSelectFields.length > 0;
9990
+ const selectFields = collectReadSelectFields(allDbFields);
9991
+ const hasSelectFields = selectFields.length > 0;
9815
9992
  const dateRangeFilterFields = new Set(
9816
9993
  resolvedFilters.filter((filter) => filter.type === "date-range").map((filter) => filter.field)
9817
9994
  );
@@ -9835,7 +10012,7 @@ function buildEntityContext(schema, nextMajorVersion) {
9835
10012
  const relTableImports = relationshipFields.map((f) => toCamelCase(f.relationship));
9836
10013
  const listRelTableImports = allListRelQueries.map((q) => q.relTable);
9837
10014
  const dataFields = allDbFields.map(
9838
- (f) => ` ${quotePropertyName(f.name)}: ${getFieldType(f, "output")}${f.required || f.primaryKey ? "" : " | null"}`
10015
+ (f) => ` ${quotePropertyName(f.name)}: ${getReadFieldType(f)}${f.type === "select" || f.required || f.primaryKey ? "" : " | null"}`
9839
10016
  ).join("\n");
9840
10017
  const m2mFieldTypes = m2mFields.map((f) => ` ${quotePropertyName(f.name)}: string[]`).join("\n");
9841
10018
  const htmlFieldTypes = htmlOutputFields.map((f) => ` ${f.name}Html: string`).join("\n");
@@ -9849,7 +10026,10 @@ import type { AdminMedia } from '@admin/types'
9849
10026
  const hasTimestampFields = allDbFields.some((f) => f.name === "createdAt") && allDbFields.some((f) => f.name === "updatedAt");
9850
10027
  const hasFormattedTimestampFields = allDbFields.some((f) => f.name === "createdAtFormatted");
9851
10028
  const timestampFields = hasTimestampFields && !hasFormattedTimestampFields ? "\n createdAtFormatted: string\n updatedAtFormatted: string" : "";
9852
- const dataInterface = `${mediaTypeImport}${buildAuthorshipUserType()}
10029
+ const readSelectOptionType = buildReadSelectOptionType(selectFields);
10030
+ const dataInterface = `${mediaTypeImport}${buildAuthorshipUserType()}${readSelectOptionType ? `
10031
+
10032
+ ${readSelectOptionType}` : ""}
9853
10033
 
9854
10034
  export interface ${Singular} {
9855
10035
  ${dataFields}${htmlFieldTypes ? `
@@ -9954,7 +10134,8 @@ ${searchFields.map((f) => ` ilike(${tableVar}.${f}, searchTerm)`).join(
9954
10134
  Singular,
9955
10135
  hasListRels
9956
10136
  );
9957
- const resultMapping = hasMediaFields ? wrapWithMediaResolution(baseResultMapping, camelPlural, Singular) : baseResultMapping;
10137
+ const selectResultMapping = hasSelectFields ? wrapWithSelectResolution(baseResultMapping, camelPlural, Singular) : baseResultMapping;
10138
+ const resultMapping = hasMediaFields ? wrapWithMediaResolution(selectResultMapping, camelPlural, Singular) : selectResultMapping;
9958
10139
  const baseListResultMapping = hasHtmlOutput ? buildResultMapping(
9959
10140
  listDbFields,
9960
10141
  relationshipFields,
@@ -9963,7 +10144,8 @@ ${searchFields.map((f) => ` ilike(${tableVar}.${f}, searchTerm)`).join(
9963
10144
  Singular,
9964
10145
  hasListRels
9965
10146
  ) : baseResultMapping;
9966
- const listResultMapping = hasMediaFields ? wrapWithMediaResolution(baseListResultMapping, camelPlural, Singular) : baseListResultMapping;
10147
+ const selectListResultMapping = hasSelectFields ? wrapWithSelectResolution(baseListResultMapping, camelPlural, Singular) : baseListResultMapping;
10148
+ const listResultMapping = hasMediaFields ? wrapWithMediaResolution(selectListResultMapping, camelPlural, Singular) : selectListResultMapping;
9967
10149
  const fieldMeta = createFields.map((f) => `{ name: '${f.name}', type: '${f.type}', required: ${f.required ?? false} }`).join(",\n ");
9968
10150
  const createMappings = createFields.map((f) => ` ${f.name}: ${generateFieldMapping(f)}`).join(",\n");
9969
10151
  const htmlCreateBlock = hasHtmlOutput ? `
@@ -10004,9 +10186,11 @@ ${searchFields.map((f) => ` ilike(${tableVar}.${f}, searchTerm)`).join(
10004
10186
  return `const row = result[0]
10005
10187
  return ${singleRowMapping}`;
10006
10188
  })();
10007
- const singleRowReturn = hasMediaFields ? `${baseSingleRowReturn.replace(/return ([\s\S]+)$/, `const singleRow = $1
10008
- const [resolved] = await resolve${Singular}MediaFields([singleRow])
10009
- return resolved`)}` : baseSingleRowReturn;
10189
+ const singleRowResolvers = [
10190
+ ...hasSelectFields ? [`resolve${Singular}SelectFields`] : [],
10191
+ ...hasMediaFields ? [`resolve${Singular}MediaFields`] : []
10192
+ ];
10193
+ const singleRowReturn = singleRowResolvers.length > 0 ? wrapSingleRowReturnWithResolvers(baseSingleRowReturn, singleRowResolvers) : baseSingleRowReturn;
10010
10194
  const nextMajor = nextMajorVersion ?? 16;
10011
10195
  const cacheInvalidationFn = nextMajor >= 16 ? "updateTag" : "revalidateTag";
10012
10196
  const cacheReadImport = nextMajor >= 16 ? `import { cacheLife, cacheTag } from 'next/cache'` : `import { unstable_cacheTag as cacheTag } from 'next/cache'`;
@@ -10036,9 +10220,11 @@ ${searchFields.map((f) => ` ilike(${tableVar}.${f}, searchTerm)`).join(
10036
10220
  hasSearch,
10037
10221
  hasFilters,
10038
10222
  hasAutoSlug,
10223
+ hasSelectFields,
10039
10224
  hasCreatableSelectFields,
10040
10225
  searchFields,
10041
10226
  htmlOutputFields,
10227
+ selectFields,
10042
10228
  creatableSelectFields,
10043
10229
  m2mFields,
10044
10230
  filterableFields,
@@ -10089,11 +10275,135 @@ function wrapWithMediaResolution(mapping, camelPlural, Singular) {
10089
10275
  }
10090
10276
  return mapping.replace(
10091
10277
  new RegExp(`${camelPlural}: (results as ${Singular}\\[\\])`),
10092
- `${camelPlural}: await resolve${Singular}MediaFields($1)`
10278
+ `${camelPlural}: await resolve${Singular}MediaFields($1 as unknown as ${Singular}[])`
10093
10279
  );
10094
10280
  }
10281
+ function wrapWithSelectResolution(mapping, camelPlural, Singular) {
10282
+ const returnPattern = new RegExp(
10283
+ `return \\{\\n\\s+${camelPlural}: ([^,]+),\\n\\s+total\\n\\s+\\}`
10284
+ );
10285
+ const match = mapping.match(returnPattern);
10286
+ if (match) {
10287
+ const arrayExpr = match[1].trim();
10288
+ return mapping.replace(
10289
+ match[0],
10290
+ `const resolved${Singular}SelectFields = await resolve${Singular}SelectFields(${arrayExpr})
10291
+
10292
+ return {
10293
+ ${camelPlural}: resolved${Singular}SelectFields,
10294
+ total
10295
+ }`
10296
+ );
10297
+ }
10298
+ return mapping.replace(
10299
+ new RegExp(`${camelPlural}: (results as ${Singular}\\[\\])`),
10300
+ `${camelPlural}: await resolve${Singular}SelectFields($1 as unknown as ${Singular}[])`
10301
+ );
10302
+ }
10303
+ function wrapSingleRowReturnWithResolvers(singleRowReturn, resolvers) {
10304
+ return singleRowReturn.replace(/return ([\s\S]+)$/, (_, expression) => {
10305
+ const lines = [`const singleRow = ${expression}`];
10306
+ let current = "singleRow";
10307
+ for (const resolver of resolvers) {
10308
+ const resolvedName = resolver.replace(/^resolve/, "resolved").replace(/Fields$/, "Row");
10309
+ lines.push(` const [${resolvedName}] = await ${resolver}([${current}])`);
10310
+ current = resolvedName;
10311
+ }
10312
+ lines.push(` return ${current}`);
10313
+ return lines.join("\n");
10314
+ });
10315
+ }
10095
10316
 
10096
10317
  // adapters/next/generators/actions/single-actions.ts
10318
+ function generateSingleResolveSelectFieldsFunction(Singular, selectFields, selectOptionsTableVar, hasCreatableSelectFields) {
10319
+ const staticLabelMaps = selectFields.map((readField) => {
10320
+ const key = readField.path.join(".");
10321
+ const entries = (readField.field.options ?? []).map((option) => `${JSON.stringify(option.value)}: ${JSON.stringify(option.label)}`).join(", ");
10322
+ return ` ${JSON.stringify(key)}: { ${entries} }`;
10323
+ }).join(",\n");
10324
+ const dynamicRowsBlock = hasCreatableSelectFields ? `
10325
+ const dynamicRows = await db
10326
+ .select({
10327
+ fieldName: ${selectOptionsTableVar}.fieldName,
10328
+ label: ${selectOptionsTableVar}.label,
10329
+ value: ${selectOptionsTableVar}.value
10330
+ })
10331
+ .from(${selectOptionsTableVar})
10332
+
10333
+ for (const row of dynamicRows) {
10334
+ labelMaps[row.fieldName] ??= {}
10335
+ labelMaps[row.fieldName][row.value] = row.label
10336
+ }
10337
+ ` : "";
10338
+ const assignments = selectFields.map((readField) => {
10339
+ const key = readField.path.join(".");
10340
+ return ` resolveSelectFieldPath(source, ${JSON.stringify(readField.path)}, labelMaps[${JSON.stringify(key)}] ?? {})`;
10341
+ }).join("\n");
10342
+ return `const STATIC_SELECT_OPTION_LABELS = {
10343
+ ${staticLabelMaps}
10344
+ } satisfies Record<string, Record<string, string>>
10345
+
10346
+ function cloneSelectOptionLabelMaps(): Record<string, Record<string, string>> {
10347
+ return Object.fromEntries(
10348
+ Object.entries(STATIC_SELECT_OPTION_LABELS).map(([fieldName, labels]) => [
10349
+ fieldName,
10350
+ { ...labels }
10351
+ ])
10352
+ )
10353
+ }
10354
+
10355
+ function toSelectOptionValues(value: unknown, labels: Record<string, string>): SelectOptionValue[] {
10356
+ const values = Array.isArray(value) ? value : value ? [value] : []
10357
+
10358
+ return values
10359
+ .filter((item): item is string => typeof item === 'string' && item.length > 0)
10360
+ .map((item) => ({
10361
+ label: labels[item] ?? item,
10362
+ value: item
10363
+ }))
10364
+ }
10365
+
10366
+ function resolveSelectFieldPath(
10367
+ source: Record<string, unknown>,
10368
+ path: readonly string[],
10369
+ labels: Record<string, string>
10370
+ ): void {
10371
+ const [fieldName, ...rest] = path
10372
+ if (!fieldName) return
10373
+
10374
+ if (rest.length === 0) {
10375
+ source[fieldName] = toSelectOptionValues(source[fieldName], labels)
10376
+ return
10377
+ }
10378
+
10379
+ const value = source[fieldName]
10380
+ if (Array.isArray(value)) {
10381
+ for (const item of value) {
10382
+ if (item && typeof item === 'object') {
10383
+ resolveSelectFieldPath(item as Record<string, unknown>, rest, labels)
10384
+ }
10385
+ }
10386
+ return
10387
+ }
10388
+
10389
+ if (value && typeof value === 'object') {
10390
+ resolveSelectFieldPath(value as Record<string, unknown>, rest, labels)
10391
+ }
10392
+ }
10393
+
10394
+ async function resolve${Singular}SelectFields(rows: ${Singular}[]): Promise<${Singular}[]> {
10395
+ if (rows.length === 0) return rows
10396
+
10397
+ const labelMaps = cloneSelectOptionLabelMaps()
10398
+ ${dynamicRowsBlock}
10399
+ for (const row of rows) {
10400
+ const source = row as unknown as Record<string, unknown>
10401
+ ${assignments}
10402
+ }
10403
+
10404
+ return rows
10405
+ }`;
10406
+ }
10097
10407
  function generateSingleActions(schema, actionsDir, options = {}) {
10098
10408
  const singular = singularize(schema.name);
10099
10409
  const plural = pluralize(schema.name);
@@ -10113,6 +10423,8 @@ function generateSingleActions(schema, actionsDir, options = {}) {
10113
10423
  (field) => field.type === "select" && field.creatable === true
10114
10424
  );
10115
10425
  const hasCreatableSelectFields = creatableSelectFields.length > 0;
10426
+ const selectFields = collectReadSelectFields(dbFields);
10427
+ const hasSelectFields = selectFields.length > 0;
10116
10428
  const allDbFields = [...dbFields];
10117
10429
  if (!dbFields.some((f) => f.name === "createdAt")) {
10118
10430
  allDbFields.push({ name: "createdAt", type: "timestamp", required: true });
@@ -10129,7 +10441,7 @@ function generateSingleActions(schema, actionsDir, options = {}) {
10129
10441
  (f) => !f.primaryKey && f.name !== "createdAt" && f.name !== "updatedAt" && !isAuthorshipFieldName(f.name)
10130
10442
  );
10131
10443
  const dataFields = allDbFields.map(
10132
- (f) => ` ${quotePropertyName(f.name)}: ${getFieldType(f, "output")}${f.required || f.primaryKey ? "" : " | null"}`
10444
+ (f) => ` ${quotePropertyName(f.name)}: ${getReadFieldType(f)}${f.type === "select" || f.required || f.primaryKey ? "" : " | null"}`
10133
10445
  ).join("\n");
10134
10446
  const htmlFieldTypes = htmlOutputFields.map((f) => ` ${f.name}Html: string`).join("\n");
10135
10447
  const hasTimestampFields = allDbFields.some((f) => f.name === "createdAt") && allDbFields.some((f) => f.name === "updatedAt");
@@ -10158,6 +10470,7 @@ function generateSingleActions(schema, actionsDir, options = {}) {
10158
10470
  };
10159
10471
  const typesContent = `${[
10160
10472
  buildAuthorshipUserType(),
10473
+ buildReadSelectOptionType(selectFields),
10161
10474
  `export interface ${Singular} {
10162
10475
  ${dataFields}${htmlFieldTypes ? `
10163
10476
  ${htmlFieldTypes}` : ""}${timestampFields}
@@ -10186,17 +10499,29 @@ ${upsertInterfaceFields}
10186
10499
  authorshipSelects,
10187
10500
  authorshipJoins
10188
10501
  );
10189
- const singleRowReturn = `const row = result[0]
10190
- return ${buildSingleRowMapping(allDbFields, [], `${Singular}`, htmlOutputFields)}`;
10502
+ const singleRowMapping = buildSingleRowMapping(allDbFields, [], `${Singular}`, htmlOutputFields);
10503
+ const singleRowReturn = hasSelectFields ? `const row = result[0]
10504
+ const singleRow = ${singleRowMapping}
10505
+ const [resolvedSelectRow] = await resolve${Singular}SelectFields([singleRow])
10506
+ return resolvedSelectRow` : `const row = result[0]
10507
+ return ${singleRowMapping}`;
10508
+ const getDbImports = [
10509
+ tableVar,
10510
+ "user",
10511
+ ...hasCreatableSelectFields ? [`${tableVar}SelectOptions`] : []
10512
+ ].sort();
10513
+ const selectResolutionFunctions = hasSelectFields ? `
10514
+ ${generateSingleResolveSelectFieldsFunction(Singular, selectFields, `${tableVar}SelectOptions`, hasCreatableSelectFields)}
10515
+ ` : "";
10191
10516
  const getContent = `'use server'
10192
10517
 
10193
10518
  import db from '@admin/db'
10194
- import { ${tableVar}, user } from '@admin/db/schema'
10519
+ import { ${getDbImports.join(", ")} } from '@admin/db/schema'
10195
10520
  import { eq } from 'drizzle-orm'
10196
10521
  import { alias } from 'drizzle-orm/pg-core'
10197
10522
  ${cacheReadImport}
10198
10523
  import { ${cacheTagsVar} } from './types'
10199
- import type { ${Singular} } from './types'
10524
+ import type { ${Singular}${hasSelectFields ? ", SelectOptionValue" : ""} } from './types'
10200
10525
 
10201
10526
  ${buildAuthorshipAliasBlock()}
10202
10527
 
@@ -10214,7 +10539,7 @@ function formatActionDate(value: unknown): string {
10214
10539
  timeZone: 'UTC'
10215
10540
  })
10216
10541
  }
10217
-
10542
+ ${selectResolutionFunctions}
10218
10543
  export async function get${Singular}(): Promise<${Singular} | null> {
10219
10544
  'use cache'${cacheLifeLine}
10220
10545
  cacheTag(${cacheTagsVar}.all)
@@ -10294,7 +10619,7 @@ ${htmlUpsertBlock}
10294
10619
 
10295
10620
  return {
10296
10621
  success: true,
10297
- ${camelSingular}: saved${Singular} ?? (result[0] as ${Singular})
10622
+ ${camelSingular}: saved${Singular} ?? (result[0] as unknown as ${Singular})
10298
10623
  }
10299
10624
  } catch (error) {
10300
10625
  console.error('Error upserting ${singular}:', error)
@@ -10523,6 +10848,22 @@ function fieldHasMediaCompanion(column, fields) {
10523
10848
  const field = fields.find((item) => item.name === column.accessorKey);
10524
10849
  return field?.type === "image" || field?.type === "media" || field?.type === "video";
10525
10850
  }
10851
+ function fieldIsSelect(column, fields) {
10852
+ return fields.find((item) => item.name === column.accessorKey)?.type === "select";
10853
+ }
10854
+ function generateSelectLabel(valueExpression) {
10855
+ return `const label = Array.isArray(${valueExpression})
10856
+ ? ${valueExpression}
10857
+ .map((option) =>
10858
+ typeof option === 'object' && option !== null && 'label' in option
10859
+ ? String(option.label)
10860
+ : String(option)
10861
+ )
10862
+ .join(', ')
10863
+ : ${valueExpression} === null || ${valueExpression} === undefined
10864
+ ? null
10865
+ : String(${valueExpression})`;
10866
+ }
10526
10867
  function buildImageUrlExpression(column, fields, fallbackExpression) {
10527
10868
  const fallback = `(${fallbackExpression} as string | null | undefined)`;
10528
10869
  if (!fieldHasMediaCompanion(column, fields)) {
@@ -10603,6 +10944,7 @@ function generateColumnDef2(column, fields) {
10603
10944
  }` : `header: '${column.header}'`;
10604
10945
  let cellDef = "";
10605
10946
  const authorshipUserAccessor = getAuthorshipUserAccessor(column.accessorKey);
10947
+ const isSelectColumn = fieldIsSelect(column, fields);
10606
10948
  if (authorshipUserAccessor) {
10607
10949
  cellDef = `cell: ({ row }) => {
10608
10950
  ${generateAuthorshipValue(authorshipUserAccessor)}
@@ -10623,7 +10965,15 @@ function generateColumnDef2(column, fields) {
10623
10965
  }`;
10624
10966
  break;
10625
10967
  case "badge":
10626
- cellDef = `cell: ({ row }) => {
10968
+ cellDef = isSelectColumn ? `cell: ({ row }) => {
10969
+ const value = row.getValue('${column.accessorKey}')
10970
+ ${generateSelectLabel("value")}
10971
+ return (
10972
+ <Badge variant="outline">
10973
+ {label || 'Unavailable'}
10974
+ </Badge>
10975
+ )
10976
+ }` : `cell: ({ row }) => {
10627
10977
  const value = row.getValue('${column.accessorKey}')
10628
10978
  return (
10629
10979
  <Badge variant="outline">
@@ -10705,14 +11055,22 @@ function generateColumnDef2(column, fields) {
10705
11055
  return <${column.component} data={row.original} />
10706
11056
  }`;
10707
11057
  } else {
10708
- cellDef = `cell: ({ row }) => {
11058
+ cellDef = isSelectColumn ? `cell: ({ row }) => {
11059
+ const value = row.getValue('${column.accessorKey}')
11060
+ ${generateSelectLabel("value")}
11061
+ return <div>{label || 'Unavailable'}</div>
11062
+ }` : `cell: ({ row }) => {
10709
11063
  const value = row.getValue('${column.accessorKey}')
10710
11064
  return <div>{value === null || value === undefined ? 'Unavailable' : String(value)}</div>
10711
11065
  }`;
10712
11066
  }
10713
11067
  break;
10714
11068
  default:
10715
- cellDef = `cell: ({ row }) => {
11069
+ cellDef = isSelectColumn ? `cell: ({ row }) => {
11070
+ const value = row.getValue('${column.accessorKey}')
11071
+ ${generateSelectLabel("value")}
11072
+ return <div>{label || 'Unavailable'}</div>
11073
+ }` : `cell: ({ row }) => {
10716
11074
  const value = row.getValue('${column.accessorKey}')
10717
11075
  return <div>{value === null || value === undefined ? 'Unavailable' : String(value)}</div>
10718
11076
  }`;
@@ -10754,6 +11112,7 @@ function generateFirstColumnDef(column, fields, options = {}) {
10754
11112
  )`;
10755
11113
  let cellDef = "";
10756
11114
  const authorshipUserAccessor = getAuthorshipUserAccessor(column.accessorKey);
11115
+ const isSelectColumn = fieldIsSelect(column, fields);
10757
11116
  if (authorshipUserAccessor) {
10758
11117
  cellDef = `cell: ({ row }) => {
10759
11118
  ${generateAuthorshipValue(authorshipUserAccessor)}
@@ -10785,7 +11144,22 @@ function generateFirstColumnDef(column, fields, options = {}) {
10785
11144
  }`;
10786
11145
  break;
10787
11146
  case "badge":
10788
- cellDef = `cell: ({ row }) => {
11147
+ cellDef = isSelectColumn ? `cell: ({ row }) => {
11148
+ const value = row.original.${column.accessorKey}
11149
+ ${generateSelectLabel("value")}
11150
+ return (
11151
+ <div className="flex items-center gap-4 h-full pl-1">
11152
+ <Checkbox
11153
+ checked={row.getIsSelected()}
11154
+ onCheckedChange={(value) => row.toggleSelected(!!value)}
11155
+ aria-label="Select row"
11156
+ />
11157
+ <Badge variant="outline">
11158
+ {label || 'Unavailable'}
11159
+ </Badge>
11160
+ </div>
11161
+ )
11162
+ }` : `cell: ({ row }) => {
10789
11163
  const value = row.original.${column.accessorKey}
10790
11164
  return (
10791
11165
  <div className="flex items-center gap-4 h-full pl-1">
@@ -10908,7 +11282,22 @@ function generateFirstColumnDef(column, fields, options = {}) {
10908
11282
  )
10909
11283
  }`;
10910
11284
  } else {
10911
- cellDef = `cell: ({ row }) => {
11285
+ cellDef = isSelectColumn ? `cell: ({ row }) => {
11286
+ const value = row.original.${column.accessorKey}
11287
+ ${generateSelectLabel("value")}
11288
+ return (
11289
+ <div className="flex items-center gap-4 h-full pl-1">
11290
+ <Checkbox
11291
+ checked={row.getIsSelected()}
11292
+ onCheckedChange={(value) => row.toggleSelected(!!value)}
11293
+ aria-label="Select row"
11294
+ />
11295
+ <span className="truncate max-w-[300px]">
11296
+ {label || 'Unavailable'}
11297
+ </span>
11298
+ </div>
11299
+ )
11300
+ }` : `cell: ({ row }) => {
10912
11301
  const value = row.original.${column.accessorKey}
10913
11302
  return (
10914
11303
  <div className="flex items-center gap-4 h-full pl-1">
@@ -10954,7 +11343,22 @@ function generateFirstColumnDef(column, fields, options = {}) {
10954
11343
  }`;
10955
11344
  break;
10956
11345
  default:
10957
- cellDef = `cell: ({ row }) => {
11346
+ cellDef = isSelectColumn ? `cell: ({ row }) => {
11347
+ const value = row.original.${column.accessorKey}
11348
+ ${generateSelectLabel("value")}
11349
+ return (
11350
+ <div className="flex items-center gap-4 h-full pl-1">
11351
+ <Checkbox
11352
+ checked={row.getIsSelected()}
11353
+ onCheckedChange={(value) => row.toggleSelected(!!value)}
11354
+ aria-label="Select row"
11355
+ />
11356
+ <span className="truncate max-w-[300px]">
11357
+ {label || 'Unavailable'}
11358
+ </span>
11359
+ </div>
11360
+ )
11361
+ }` : `cell: ({ row }) => {
10958
11362
  const value = row.original.${column.accessorKey}
10959
11363
  return (
10960
11364
  <div className="flex items-center gap-4 h-full pl-1">
@@ -11626,9 +12030,38 @@ function defaultFallbackValue(f) {
11626
12030
  function hasInitialValueExpression(fieldName, dataSource = "initialData") {
11627
12031
  return `${dataSource}?.${fieldName} !== undefined && ${dataSource}?.${fieldName} !== null && ${dataSource}?.${fieldName} !== ''`;
11628
12032
  }
12033
+ function selectReadValuesExpression(fieldName, dataSource = "initialData") {
12034
+ return `(() => {
12035
+ const selectValue = ${dataSource}?.${fieldName} as unknown
12036
+ const values = Array.isArray(selectValue) ? selectValue : [selectValue]
12037
+ return values
12038
+ .map((option) => {
12039
+ if (typeof option === 'string') return option
12040
+ if (option && typeof option === 'object' && 'value' in option) {
12041
+ return String(option.value)
12042
+ }
12043
+ return null
12044
+ })
12045
+ .filter((value): value is string => typeof value === 'string' && value.length > 0)
12046
+ })()`;
12047
+ }
11629
12048
  function generateDefaultValue(f, fieldMap, dataSource = "initialData") {
11630
12049
  if (f.defaultValueFrom && f.defaultValueFrom.trim() !== f.name && fieldMap?.has(f.defaultValueFrom.trim())) {
11631
12050
  const sourceName = f.defaultValueFrom.trim();
12051
+ if (f.type === "select") {
12052
+ const targetValuesExpression = selectReadValuesExpression(f.name, dataSource);
12053
+ const sourceValuesExpression = selectReadValuesExpression(sourceName, dataSource);
12054
+ if (f.multiple) {
12055
+ const fallback2 = JSON.stringify(selectDefaultValues(f));
12056
+ return ` ${f.name}: ${targetValuesExpression}.length > 0
12057
+ ? ${targetValuesExpression}
12058
+ : ${sourceValuesExpression}.length > 0
12059
+ ? ${sourceValuesExpression}
12060
+ : ${fallback2}`;
12061
+ }
12062
+ const fallback = f.default !== void 0 && f.default !== null ? JSON.stringify(f.default) : "''";
12063
+ return ` ${f.name}: ${targetValuesExpression}[0] ?? ${sourceValuesExpression}[0] ?? ${fallback}`;
12064
+ }
11632
12065
  return ` ${f.name}: ${hasInitialValueExpression(f.name, dataSource)}
11633
12066
  ? ${dataSource}.${f.name}
11634
12067
  : ${hasInitialValueExpression(sourceName, dataSource)}
@@ -11658,22 +12091,23 @@ function generateDefaultValue(f, fieldMap, dataSource = "initialData") {
11658
12091
  return ` ${f.name}: ${dataSource}?.${f.name} ?? undefined`;
11659
12092
  }
11660
12093
  if (f.type === "select") {
12094
+ const selectedValuesExpression = selectReadValuesExpression(f.name, dataSource);
11661
12095
  if (f.multiple) {
11662
12096
  const fallback2 = JSON.stringify(selectDefaultValues(f));
11663
12097
  if (f.creatable) {
11664
- return ` ${f.name}: Array.isArray(${dataSource}?.${f.name}) ? ${dataSource}?.${f.name} : ${fallback2}`;
12098
+ return ` ${f.name}: ${selectedValuesExpression}.length > 0 ? ${selectedValuesExpression} : ${fallback2}`;
11665
12099
  }
11666
12100
  const validValuesExpression2 = `([${(f.options || []).map((option) => JSON.stringify(option.value)).join(", ")}] as const as readonly string[])`;
11667
- return ` ${f.name}: Array.isArray(${dataSource}?.${f.name})
11668
- ? ${dataSource}?.${f.name}.filter((value) => ${validValuesExpression2}.includes(value))
12101
+ return ` ${f.name}: ${selectedValuesExpression}.length > 0
12102
+ ? ${selectedValuesExpression}.filter((value) => ${validValuesExpression2}.includes(value))
11669
12103
  : ${fallback2}`;
11670
12104
  }
11671
12105
  const fallback = f.default !== void 0 && f.default !== null ? JSON.stringify(f.default) : "''";
11672
12106
  if (f.creatable) {
11673
- return ` ${f.name}: typeof ${dataSource}?.${f.name} === 'string' ? ${dataSource}?.${f.name} : ${fallback}`;
12107
+ return ` ${f.name}: ${selectedValuesExpression}[0] ?? ${fallback}`;
11674
12108
  }
11675
12109
  const validValuesExpression = `([${(f.options || []).map((option) => JSON.stringify(option.value)).join(", ")}] as const as readonly string[])`;
11676
- return ` ${f.name}: typeof ${dataSource}?.${f.name} === 'string' && ${validValuesExpression}.includes(${dataSource}?.${f.name}) ? ${dataSource}?.${f.name} : ${fallback}`;
12110
+ return ` ${f.name}: ${selectedValuesExpression}[0] && ${validValuesExpression}.includes(${selectedValuesExpression}[0]) ? ${selectedValuesExpression}[0] : ${fallback}`;
11677
12111
  }
11678
12112
  if (f.default !== void 0 && f.default !== null) {
11679
12113
  const def = typeof f.default === "string" ? `'${f.default}'` : f.default;