betterstart-cli 0.0.4 → 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/assets/adapters/next/templates/init/components/shared/dev-mode/copyable-code-block.tsx +2 -2
- package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/dev-mode-code-mirror.tsx +11 -5
- package/dist/assets/adapters/next/templates/init/lib/actions/media/types.ts +9 -1
- package/dist/assets/adapters/next/templates/init/types/index.ts +2 -0
- package/dist/cli.js +558 -47
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
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`);
|
|
@@ -3892,12 +3947,17 @@ function buildResultMapping(allDbFields, relationshipFields, Plural, camelPlural
|
|
|
3892
3947
|
` const createdByUser = row.createdByUser as { id?: string | null; name?: string | null; email?: string | null } | null | undefined`,
|
|
3893
3948
|
` const updatedByUser = row.updatedByUser as { id?: string | null; name?: string | null; email?: string | null } | null | undefined`
|
|
3894
3949
|
].filter(Boolean).join("\n");
|
|
3950
|
+
const mappedTimestampFields = allDbFields.some((f) => f.name === "createdAtFormatted") ? [] : [
|
|
3951
|
+
` createdAtFormatted: formatActionDate(row.createdAt)`,
|
|
3952
|
+
` updatedAtFormatted: formatActionDate(row.updatedAt)`
|
|
3953
|
+
];
|
|
3895
3954
|
const rowMappings = allDbFields.map((f) => {
|
|
3896
3955
|
if (f.type === "relationship" && !f.multiple) {
|
|
3897
3956
|
return ` ${f.name}: ${f.name}?.id ? { id: ${f.name}.id, name: ${f.name}.name ?? undefined, title: ${f.name}.title ?? undefined, slug: ${f.name}.slug ?? undefined, label: ${f.name}.label ?? undefined } : null`;
|
|
3898
3957
|
}
|
|
3899
3958
|
return ` ${f.name}: row.${f.name}`;
|
|
3900
3959
|
}).concat([
|
|
3960
|
+
...mappedTimestampFields,
|
|
3901
3961
|
` createdByUser: createdByUser?.id ? { id: createdByUser.id, name: createdByUser.name ?? '', email: createdByUser.email ?? '' } : null`,
|
|
3902
3962
|
` updatedByUser: updatedByUser?.id ? { id: updatedByUser.id, name: updatedByUser.name ?? '', email: updatedByUser.email ?? '' } : null`
|
|
3903
3963
|
]).join(",\n");
|
|
@@ -3926,7 +3986,7 @@ ${rowMappings}
|
|
|
3926
3986
|
return `${mapBlock}
|
|
3927
3987
|
|
|
3928
3988
|
return {
|
|
3929
|
-
${camelPlural}: mapped${Plural} as ${Singular}[],
|
|
3989
|
+
${camelPlural}: mapped${Plural} as unknown as ${Singular}[],
|
|
3930
3990
|
total
|
|
3931
3991
|
}`;
|
|
3932
3992
|
}
|
|
@@ -3938,15 +3998,20 @@ function buildSingleRowMapping(allDbFields, _relationshipFields, typeName, htmlF
|
|
|
3938
3998
|
return ` ${f.name}: row.${f.name}`;
|
|
3939
3999
|
});
|
|
3940
4000
|
const htmlMappings = htmlFields.map((f) => ` ${f.name}Html: row.${f.name}Html`);
|
|
4001
|
+
const singleTimestampFields = allDbFields.some((f) => f.name === "createdAtFormatted") ? [] : [
|
|
4002
|
+
` createdAtFormatted: formatActionDate(row.createdAt)`,
|
|
4003
|
+
` updatedAtFormatted: formatActionDate(row.updatedAt)`
|
|
4004
|
+
];
|
|
3941
4005
|
const mappings = [
|
|
3942
4006
|
...fieldMappings,
|
|
3943
4007
|
...htmlMappings,
|
|
4008
|
+
...singleTimestampFields,
|
|
3944
4009
|
` createdByUser: row.createdByUser?.id ? { id: row.createdByUser.id, name: row.createdByUser.name, email: row.createdByUser.email } : null`,
|
|
3945
4010
|
` updatedByUser: row.updatedByUser?.id ? { id: row.updatedByUser.id, name: row.updatedByUser.name, email: row.updatedByUser.email } : null`
|
|
3946
4011
|
].join(",\n");
|
|
3947
4012
|
return `{
|
|
3948
4013
|
${mappings}
|
|
3949
|
-
} as ${typeName}`;
|
|
4014
|
+
} as unknown as ${typeName}`;
|
|
3950
4015
|
}
|
|
3951
4016
|
function buildExplicitSelect(fields, tableVar, htmlFields = [], extraSelects = [], extraJoins = "") {
|
|
3952
4017
|
const fieldSelects = fields.map((f) => ` ${f.name}: ${tableVar}.${f.name}`);
|
|
@@ -4172,6 +4237,7 @@ var SINGLE_ACTION_FIELD_EXCLUSIONS = /* @__PURE__ */ new Set(["id", "createdAt",
|
|
|
4172
4237
|
var DEFAULT_ADMIN_IMPORT_ALIAS = "@admin";
|
|
4173
4238
|
var SAMPLE_UUID = "00000000-0000-4000-8000-000000000001";
|
|
4174
4239
|
var SINGLETON_ID = "00000000-0000-0000-0000-000000000001";
|
|
4240
|
+
var SAMPLE_FORMATTED_TIMESTAMP = "Jan 01, 2026";
|
|
4175
4241
|
function isActionField(field, exclusions) {
|
|
4176
4242
|
return !field.primaryKey && !exclusions.has(field.name) && !isAuthorshipFieldName(field.name) && !isLayoutField(field.type);
|
|
4177
4243
|
}
|
|
@@ -4354,6 +4420,8 @@ function sampleAdminMedia() {
|
|
|
4354
4420
|
tags: ["example"],
|
|
4355
4421
|
createdAt: "2026-01-01T00:00:00.000Z",
|
|
4356
4422
|
updatedAt: "2026-01-01T00:00:00.000Z",
|
|
4423
|
+
createdAtFormatted: SAMPLE_FORMATTED_TIMESTAMP,
|
|
4424
|
+
updatedAtFormatted: SAMPLE_FORMATTED_TIMESTAMP,
|
|
4357
4425
|
createdBy: "user-id",
|
|
4358
4426
|
updatedBy: "user-id"
|
|
4359
4427
|
};
|
|
@@ -4369,6 +4437,14 @@ function sampleSchemaOutputValue(field) {
|
|
|
4369
4437
|
if (field.name === "id") return SAMPLE_UUID;
|
|
4370
4438
|
if (field.name === "createdAt" || field.name === "updatedAt") return "2026-01-01T00:00:00.000Z";
|
|
4371
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
|
+
}
|
|
4372
4448
|
if (field.type === "relationship" && field.relationship && !field.multiple) {
|
|
4373
4449
|
return {
|
|
4374
4450
|
id: SAMPLE_UUID,
|
|
@@ -4378,6 +4454,18 @@ function sampleSchemaOutputValue(field) {
|
|
|
4378
4454
|
label: "Example related record"
|
|
4379
4455
|
};
|
|
4380
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
|
+
}
|
|
4381
4469
|
return sampleSchemaFieldValue(field);
|
|
4382
4470
|
}
|
|
4383
4471
|
function sampleSingleOutputValue(field) {
|
|
@@ -4392,7 +4480,7 @@ function createEntityDataObject(schema) {
|
|
|
4392
4480
|
return field.type === "image" || field.type === "video" || field.type === "media";
|
|
4393
4481
|
});
|
|
4394
4482
|
const galleryFields = regularDbFields.filter((field) => field.type === "gallery");
|
|
4395
|
-
return {
|
|
4483
|
+
return addFormattedTimestamps({
|
|
4396
4484
|
...Object.fromEntries(allDbFields.map((field) => [field.name, sampleSchemaOutputValue(field)])),
|
|
4397
4485
|
...Object.fromEntries(
|
|
4398
4486
|
htmlOutputFields.map((field) => [
|
|
@@ -4407,7 +4495,17 @@ function createEntityDataObject(schema) {
|
|
|
4407
4495
|
),
|
|
4408
4496
|
createdByUser: sampleAdminUserSummary(),
|
|
4409
4497
|
updatedByUser: sampleAdminUserSummary()
|
|
4410
|
-
};
|
|
4498
|
+
});
|
|
4499
|
+
}
|
|
4500
|
+
function addFormattedTimestamps(data) {
|
|
4501
|
+
const output = { ...data };
|
|
4502
|
+
if (typeof output.createdAt === "string") {
|
|
4503
|
+
output.createdAtFormatted = SAMPLE_FORMATTED_TIMESTAMP;
|
|
4504
|
+
}
|
|
4505
|
+
if (typeof output.updatedAt === "string") {
|
|
4506
|
+
output.updatedAtFormatted = SAMPLE_FORMATTED_TIMESTAMP;
|
|
4507
|
+
}
|
|
4508
|
+
return output;
|
|
4411
4509
|
}
|
|
4412
4510
|
function getSingleAllDbFields(schema) {
|
|
4413
4511
|
const dbFields = flattenFields(schema.fields).filter(
|
|
@@ -4430,7 +4528,7 @@ function getSingleAllDbFields(schema) {
|
|
|
4430
4528
|
function createSingleDataObject(schema) {
|
|
4431
4529
|
const dbFields = getSingleAllDbFields(schema);
|
|
4432
4530
|
const htmlOutputFields = getHtmlOutputFields(dbFields);
|
|
4433
|
-
return {
|
|
4531
|
+
return addFormattedTimestamps({
|
|
4434
4532
|
...Object.fromEntries(dbFields.map((field) => [field.name, sampleSingleOutputValue(field)])),
|
|
4435
4533
|
...Object.fromEntries(
|
|
4436
4534
|
htmlOutputFields.map((field) => [
|
|
@@ -4440,7 +4538,7 @@ function createSingleDataObject(schema) {
|
|
|
4440
4538
|
),
|
|
4441
4539
|
createdByUser: sampleAdminUserSummary(),
|
|
4442
4540
|
updatedByUser: sampleAdminUserSummary()
|
|
4443
|
-
};
|
|
4541
|
+
});
|
|
4444
4542
|
}
|
|
4445
4543
|
function createFormSubmissionObject(fields) {
|
|
4446
4544
|
return {
|
|
@@ -8007,7 +8105,10 @@ function genHelpersContent(ctx) {
|
|
|
8007
8105
|
drizzleImports.add("inArray");
|
|
8008
8106
|
schemaImports.add("adminMedia");
|
|
8009
8107
|
}
|
|
8010
|
-
if (ctx.
|
|
8108
|
+
if (ctx.hasCreatableSelectFields) {
|
|
8109
|
+
schemaImports.add(ctx.selectOptionsTableVar);
|
|
8110
|
+
}
|
|
8111
|
+
if (ctx.hasM2M || ctx.hasListRels || ctx.hasMediaFields || ctx.hasCreatableSelectFields) {
|
|
8011
8112
|
lines.push(`import db from '@admin/db'`);
|
|
8012
8113
|
}
|
|
8013
8114
|
const tables = [...schemaImports].sort();
|
|
@@ -8020,7 +8121,21 @@ function genHelpersContent(ctx) {
|
|
|
8020
8121
|
if (ctx.hasMediaFields) {
|
|
8021
8122
|
lines.push(`import type { AdminMedia } from '@admin/types'`);
|
|
8022
8123
|
}
|
|
8023
|
-
|
|
8124
|
+
const typeImports = ctx.hasSelectFields ? `${ctx.Singular}, SelectOptionValue` : ctx.Singular;
|
|
8125
|
+
lines.push(`import type { ${typeImports} } from './types'`);
|
|
8126
|
+
lines.push("");
|
|
8127
|
+
lines.push(`export function formatActionDate(value: unknown): string {
|
|
8128
|
+
if (typeof value !== 'string') return ''
|
|
8129
|
+
const date = new Date(value)
|
|
8130
|
+
if (Number.isNaN(date.getTime())) return ''
|
|
8131
|
+
|
|
8132
|
+
return date.toLocaleDateString('en-US', {
|
|
8133
|
+
month: 'short',
|
|
8134
|
+
day: '2-digit',
|
|
8135
|
+
year: 'numeric',
|
|
8136
|
+
timeZone: 'UTC'
|
|
8137
|
+
})
|
|
8138
|
+
}`);
|
|
8024
8139
|
lines.push("");
|
|
8025
8140
|
if (ctx.hasListRels) {
|
|
8026
8141
|
const exportedFn = ctx.populateListRelsFn.replace("async function", "export async function").trim();
|
|
@@ -8031,6 +8146,10 @@ function genHelpersContent(ctx) {
|
|
|
8031
8146
|
lines.push(generateResolveMediaFunction(ctx));
|
|
8032
8147
|
lines.push("");
|
|
8033
8148
|
}
|
|
8149
|
+
if (ctx.hasSelectFields) {
|
|
8150
|
+
lines.push(generateResolveSelectFieldsFunction(ctx));
|
|
8151
|
+
lines.push("");
|
|
8152
|
+
}
|
|
8034
8153
|
lines.push(generateVersionSnapshotHelpers(ctx));
|
|
8035
8154
|
lines.push("");
|
|
8036
8155
|
return lines.join("\n");
|
|
@@ -8081,7 +8200,7 @@ const VERSION_RESTORE_KEYS = [${restoreKeys}] as const
|
|
|
8081
8200
|
const VERSION_M2M_KEYS = [${m2mKeys}] as const
|
|
8082
8201
|
|
|
8083
8202
|
export function build${ctx.Singular}VersionSnapshot(row: Partial<${ctx.Singular}> | Record<string, unknown>): Record<string, unknown> {
|
|
8084
|
-
const source = row as Record<string, unknown>
|
|
8203
|
+
const source = row as unknown as Record<string, unknown>
|
|
8085
8204
|
const snapshot: Record<string, unknown> = {}
|
|
8086
8205
|
|
|
8087
8206
|
for (const key of VERSION_SNAPSHOT_KEYS) {
|
|
@@ -8133,10 +8252,32 @@ function generateResolveMediaFunction(ctx) {
|
|
|
8133
8252
|
}`
|
|
8134
8253
|
).join("\n");
|
|
8135
8254
|
const assignSingle = singleFields.map(
|
|
8136
|
-
(name) => ` row.${name}Media =
|
|
8255
|
+
(name) => ` row.${name}Media = row.${name} && !row.${name}.startsWith('http')
|
|
8256
|
+
? (() => {
|
|
8257
|
+
const media = mediaMap.get(row.${name})
|
|
8258
|
+
if (!media) return null
|
|
8259
|
+
return {
|
|
8260
|
+
...media,
|
|
8261
|
+
createdAtFormatted: formatActionDate(media.createdAt),
|
|
8262
|
+
updatedAtFormatted: formatActionDate(media.updatedAt)
|
|
8263
|
+
}
|
|
8264
|
+
})()
|
|
8265
|
+
: null`
|
|
8137
8266
|
).join("\n");
|
|
8138
8267
|
const assignArray = arrayFields.map(
|
|
8139
|
-
(name) => ` row.${name}Media = Array.isArray(row.${name})
|
|
8268
|
+
(name) => ` row.${name}Media = Array.isArray(row.${name})
|
|
8269
|
+
? row.${name}
|
|
8270
|
+
.map((id: string) => {
|
|
8271
|
+
const media = mediaMap.get(id)
|
|
8272
|
+
if (!media) return null
|
|
8273
|
+
return {
|
|
8274
|
+
...media,
|
|
8275
|
+
createdAtFormatted: formatActionDate(media.createdAt),
|
|
8276
|
+
updatedAtFormatted: formatActionDate(media.updatedAt)
|
|
8277
|
+
}
|
|
8278
|
+
})
|
|
8279
|
+
.filter(Boolean) as AdminMedia[]
|
|
8280
|
+
: []`
|
|
8140
8281
|
).join("\n");
|
|
8141
8282
|
return `export async function resolve${ctx.Singular}MediaFields(rows: ${ctx.Singular}[]): Promise<${ctx.Singular}[]> {
|
|
8142
8283
|
if (rows.length === 0) return rows
|
|
@@ -8164,6 +8305,95 @@ ${assignArray}` : ""}
|
|
|
8164
8305
|
return rows
|
|
8165
8306
|
}`;
|
|
8166
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
|
+
}
|
|
8167
8397
|
function genGetPluralContent(ctx) {
|
|
8168
8398
|
const dbImports = [ctx.tableVar, "user", ...ctx.relTableImports].sort();
|
|
8169
8399
|
const drizzle = ["asc", "desc"];
|
|
@@ -8176,7 +8406,8 @@ function genGetPluralContent(ctx) {
|
|
|
8176
8406
|
if (ctx.hasRelationships) drizzle.push("eq");
|
|
8177
8407
|
const sortedDrizzle = [...new Set(drizzle)].sort();
|
|
8178
8408
|
const typeImports = [`${ctx.Plural}Page`, `${ctx.Plural}Query`, `${ctx.Singular}`];
|
|
8179
|
-
const helperImports = [];
|
|
8409
|
+
const helperImports = ["formatActionDate"];
|
|
8410
|
+
if (ctx.hasSelectFields) helperImports.push(`resolve${ctx.Singular}SelectFields`);
|
|
8180
8411
|
if (ctx.hasListRels) helperImports.push(`populate${ctx.Singular}ListRelationships`);
|
|
8181
8412
|
if (ctx.hasMediaFields) helperImports.push(`resolve${ctx.Singular}MediaFields`);
|
|
8182
8413
|
const populateImport = helperImports.length > 0 ? `
|
|
@@ -8266,7 +8497,8 @@ function genGetByIdContent(ctx) {
|
|
|
8266
8497
|
const dbImports = [ctx.tableVar, "user", ...ctx.relTableImports].sort();
|
|
8267
8498
|
const drizzle = ["eq"];
|
|
8268
8499
|
const sortedDrizzle = [...new Set(drizzle)].sort();
|
|
8269
|
-
const byIdHelperImports = [];
|
|
8500
|
+
const byIdHelperImports = ["formatActionDate"];
|
|
8501
|
+
if (ctx.hasSelectFields) byIdHelperImports.push(`resolve${ctx.Singular}SelectFields`);
|
|
8270
8502
|
if (ctx.hasListRels) byIdHelperImports.push(`populate${ctx.Singular}ListRelationships`);
|
|
8271
8503
|
if (ctx.hasMediaFields) byIdHelperImports.push(`resolve${ctx.Singular}MediaFields`);
|
|
8272
8504
|
const populateImport = byIdHelperImports.length > 0 ? `
|
|
@@ -8304,7 +8536,8 @@ function genGetBySlugContent(ctx) {
|
|
|
8304
8536
|
const dbImports = [ctx.tableVar, "user", ...ctx.relTableImports].sort();
|
|
8305
8537
|
const drizzle = ["eq"];
|
|
8306
8538
|
const sortedDrizzle = [...new Set(drizzle)].sort();
|
|
8307
|
-
const bySlugHelperImports = [];
|
|
8539
|
+
const bySlugHelperImports = ["formatActionDate"];
|
|
8540
|
+
if (ctx.hasSelectFields) bySlugHelperImports.push(`resolve${ctx.Singular}SelectFields`);
|
|
8308
8541
|
if (ctx.hasListRels) bySlugHelperImports.push(`populate${ctx.Singular}ListRelationships`);
|
|
8309
8542
|
if (ctx.hasMediaFields) bySlugHelperImports.push(`resolve${ctx.Singular}MediaFields`);
|
|
8310
8543
|
const populateImport = bySlugHelperImports.length > 0 ? `
|
|
@@ -8340,7 +8573,7 @@ export async function get${ctx.Singular}BySlug(slug: string): Promise<${ctx.Sing
|
|
|
8340
8573
|
function genCreateContent(ctx) {
|
|
8341
8574
|
const kebabSingular = toKebabCase(ctx.singular);
|
|
8342
8575
|
const snapshotImport = ctx.hasM2M ? `build${ctx.Singular}VersionSnapshotWithRelationships` : `build${ctx.Singular}VersionSnapshot`;
|
|
8343
|
-
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})`;
|
|
8344
8577
|
const slugImport = ctx.hasAutoSlug ? `
|
|
8345
8578
|
import { slugify } from '@admin/utils/validation/validation'` : "";
|
|
8346
8579
|
const markdownImport = ctx.hasHtmlOutput ? `
|
|
@@ -8434,7 +8667,7 @@ ${ctx.htmlCreateMappings},` : ""}${ctx.hasDraft ? `
|
|
|
8434
8667
|
typeof created${ctx.Singular}Id === 'string'
|
|
8435
8668
|
? await get${ctx.Singular}ById(created${ctx.Singular}Id)
|
|
8436
8669
|
: null
|
|
8437
|
-
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})
|
|
8438
8671
|
const created${ctx.Singular}Context = ${createResultContext}
|
|
8439
8672
|
${afterHook("afterCreate", `created${ctx.Singular}Context`)}
|
|
8440
8673
|
${createAfterPublishBlock}
|
|
@@ -8453,7 +8686,7 @@ ${createAfterPublishBlock}
|
|
|
8453
8686
|
function genUpdateContent(ctx) {
|
|
8454
8687
|
const kebabSingular = toKebabCase(ctx.singular);
|
|
8455
8688
|
const snapshotImport = ctx.hasM2M ? `build${ctx.Singular}VersionSnapshotWithRelationships` : `build${ctx.Singular}VersionSnapshot`;
|
|
8456
|
-
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})`;
|
|
8457
8690
|
const slugImport = ctx.hasAutoSlug ? `
|
|
8458
8691
|
import { slugify } from '@admin/utils/validation/validation'` : "";
|
|
8459
8692
|
const markdownImport = ctx.hasHtmlOutput ? `
|
|
@@ -8577,7 +8810,7 @@ ${htmlUpdateBlock}
|
|
|
8577
8810
|
${ctx.cacheInvalidationFn}(${ctx.camelPlural}CacheTags.byId(id))
|
|
8578
8811
|
${ctx.cacheInvalidationFn}(entityVersionsCacheTags.for('${ctx.plural}', id))
|
|
8579
8812
|
const updated${ctx.Singular} = await get${ctx.Singular}ById(id)
|
|
8580
|
-
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})
|
|
8581
8814
|
const updated${ctx.Singular}Context = ${updateResultContext}
|
|
8582
8815
|
${updateAfterPublishBlock}
|
|
8583
8816
|
${afterHook("afterUpdate", `updated${ctx.Singular}Context`)}
|
|
@@ -8632,7 +8865,7 @@ function buildRestoreManyToManyStatements(ctx) {
|
|
|
8632
8865
|
function genRestoreContent(ctx) {
|
|
8633
8866
|
const kebabSingular = toKebabCase(ctx.singular);
|
|
8634
8867
|
const snapshotImport = ctx.hasM2M ? `build${ctx.Singular}VersionSnapshotWithRelationships` : `build${ctx.Singular}VersionSnapshot`;
|
|
8635
|
-
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})`;
|
|
8636
8869
|
const dbImports = [
|
|
8637
8870
|
"entityVersions",
|
|
8638
8871
|
ctx.tableVar,
|
|
@@ -8711,7 +8944,7 @@ ${restoreM2M}
|
|
|
8711
8944
|
|
|
8712
8945
|
return {
|
|
8713
8946
|
success: true,
|
|
8714
|
-
${ctx.camelSingular}: restored${ctx.Singular} ?? (result[0] as ${ctx.Singular})
|
|
8947
|
+
${ctx.camelSingular}: restored${ctx.Singular} ?? (result[0] as unknown as ${ctx.Singular})
|
|
8715
8948
|
}
|
|
8716
8949
|
} catch (error) {
|
|
8717
8950
|
console.error('Error restoring ${ctx.singular} version:', error)
|
|
@@ -9754,6 +9987,8 @@ function buildEntityContext(schema, nextMajorVersion) {
|
|
|
9754
9987
|
(f) => f.type === "select" && f.creatable === true
|
|
9755
9988
|
);
|
|
9756
9989
|
const hasCreatableSelectFields = creatableSelectFields.length > 0;
|
|
9990
|
+
const selectFields = collectReadSelectFields(allDbFields);
|
|
9991
|
+
const hasSelectFields = selectFields.length > 0;
|
|
9757
9992
|
const dateRangeFilterFields = new Set(
|
|
9758
9993
|
resolvedFilters.filter((filter) => filter.type === "date-range").map((filter) => filter.field)
|
|
9759
9994
|
);
|
|
@@ -9777,7 +10012,7 @@ function buildEntityContext(schema, nextMajorVersion) {
|
|
|
9777
10012
|
const relTableImports = relationshipFields.map((f) => toCamelCase(f.relationship));
|
|
9778
10013
|
const listRelTableImports = allListRelQueries.map((q) => q.relTable);
|
|
9779
10014
|
const dataFields = allDbFields.map(
|
|
9780
|
-
(f) => ` ${quotePropertyName(f.name)}: ${
|
|
10015
|
+
(f) => ` ${quotePropertyName(f.name)}: ${getReadFieldType(f)}${f.type === "select" || f.required || f.primaryKey ? "" : " | null"}`
|
|
9781
10016
|
).join("\n");
|
|
9782
10017
|
const m2mFieldTypes = m2mFields.map((f) => ` ${quotePropertyName(f.name)}: string[]`).join("\n");
|
|
9783
10018
|
const htmlFieldTypes = htmlOutputFields.map((f) => ` ${f.name}Html: string`).join("\n");
|
|
@@ -9788,13 +10023,19 @@ function buildEntityContext(schema, nextMajorVersion) {
|
|
|
9788
10023
|
const mediaTypeImport = hasMediaFields ? `
|
|
9789
10024
|
import type { AdminMedia } from '@admin/types'
|
|
9790
10025
|
` : "";
|
|
9791
|
-
const
|
|
10026
|
+
const hasTimestampFields = allDbFields.some((f) => f.name === "createdAt") && allDbFields.some((f) => f.name === "updatedAt");
|
|
10027
|
+
const hasFormattedTimestampFields = allDbFields.some((f) => f.name === "createdAtFormatted");
|
|
10028
|
+
const timestampFields = hasTimestampFields && !hasFormattedTimestampFields ? "\n createdAtFormatted: string\n updatedAtFormatted: string" : "";
|
|
10029
|
+
const readSelectOptionType = buildReadSelectOptionType(selectFields);
|
|
10030
|
+
const dataInterface = `${mediaTypeImport}${buildAuthorshipUserType()}${readSelectOptionType ? `
|
|
10031
|
+
|
|
10032
|
+
${readSelectOptionType}` : ""}
|
|
9792
10033
|
|
|
9793
10034
|
export interface ${Singular} {
|
|
9794
10035
|
${dataFields}${htmlFieldTypes ? `
|
|
9795
10036
|
${htmlFieldTypes}` : ""}${m2mFieldTypes ? `
|
|
9796
10037
|
${m2mFieldTypes}` : ""}${mediaCompanionTypes ? `
|
|
9797
|
-
${mediaCompanionTypes}` : ""}
|
|
10038
|
+
${mediaCompanionTypes}` : ""}${timestampFields}
|
|
9798
10039
|
${buildAuthorshipDataFields()}
|
|
9799
10040
|
}`;
|
|
9800
10041
|
const responseInterface = `export interface ${Plural}Page {
|
|
@@ -9893,7 +10134,8 @@ ${searchFields.map((f) => ` ilike(${tableVar}.${f}, searchTerm)`).join(
|
|
|
9893
10134
|
Singular,
|
|
9894
10135
|
hasListRels
|
|
9895
10136
|
);
|
|
9896
|
-
const
|
|
10137
|
+
const selectResultMapping = hasSelectFields ? wrapWithSelectResolution(baseResultMapping, camelPlural, Singular) : baseResultMapping;
|
|
10138
|
+
const resultMapping = hasMediaFields ? wrapWithMediaResolution(selectResultMapping, camelPlural, Singular) : selectResultMapping;
|
|
9897
10139
|
const baseListResultMapping = hasHtmlOutput ? buildResultMapping(
|
|
9898
10140
|
listDbFields,
|
|
9899
10141
|
relationshipFields,
|
|
@@ -9902,7 +10144,8 @@ ${searchFields.map((f) => ` ilike(${tableVar}.${f}, searchTerm)`).join(
|
|
|
9902
10144
|
Singular,
|
|
9903
10145
|
hasListRels
|
|
9904
10146
|
) : baseResultMapping;
|
|
9905
|
-
const
|
|
10147
|
+
const selectListResultMapping = hasSelectFields ? wrapWithSelectResolution(baseListResultMapping, camelPlural, Singular) : baseListResultMapping;
|
|
10148
|
+
const listResultMapping = hasMediaFields ? wrapWithMediaResolution(selectListResultMapping, camelPlural, Singular) : selectListResultMapping;
|
|
9906
10149
|
const fieldMeta = createFields.map((f) => `{ name: '${f.name}', type: '${f.type}', required: ${f.required ?? false} }`).join(",\n ");
|
|
9907
10150
|
const createMappings = createFields.map((f) => ` ${f.name}: ${generateFieldMapping(f)}`).join(",\n");
|
|
9908
10151
|
const htmlCreateBlock = hasHtmlOutput ? `
|
|
@@ -9943,9 +10186,11 @@ ${searchFields.map((f) => ` ilike(${tableVar}.${f}, searchTerm)`).join(
|
|
|
9943
10186
|
return `const row = result[0]
|
|
9944
10187
|
return ${singleRowMapping}`;
|
|
9945
10188
|
})();
|
|
9946
|
-
const
|
|
9947
|
-
|
|
9948
|
-
|
|
10189
|
+
const singleRowResolvers = [
|
|
10190
|
+
...hasSelectFields ? [`resolve${Singular}SelectFields`] : [],
|
|
10191
|
+
...hasMediaFields ? [`resolve${Singular}MediaFields`] : []
|
|
10192
|
+
];
|
|
10193
|
+
const singleRowReturn = singleRowResolvers.length > 0 ? wrapSingleRowReturnWithResolvers(baseSingleRowReturn, singleRowResolvers) : baseSingleRowReturn;
|
|
9949
10194
|
const nextMajor = nextMajorVersion ?? 16;
|
|
9950
10195
|
const cacheInvalidationFn = nextMajor >= 16 ? "updateTag" : "revalidateTag";
|
|
9951
10196
|
const cacheReadImport = nextMajor >= 16 ? `import { cacheLife, cacheTag } from 'next/cache'` : `import { unstable_cacheTag as cacheTag } from 'next/cache'`;
|
|
@@ -9975,9 +10220,11 @@ ${searchFields.map((f) => ` ilike(${tableVar}.${f}, searchTerm)`).join(
|
|
|
9975
10220
|
hasSearch,
|
|
9976
10221
|
hasFilters,
|
|
9977
10222
|
hasAutoSlug,
|
|
10223
|
+
hasSelectFields,
|
|
9978
10224
|
hasCreatableSelectFields,
|
|
9979
10225
|
searchFields,
|
|
9980
10226
|
htmlOutputFields,
|
|
10227
|
+
selectFields,
|
|
9981
10228
|
creatableSelectFields,
|
|
9982
10229
|
m2mFields,
|
|
9983
10230
|
filterableFields,
|
|
@@ -10028,11 +10275,135 @@ function wrapWithMediaResolution(mapping, camelPlural, Singular) {
|
|
|
10028
10275
|
}
|
|
10029
10276
|
return mapping.replace(
|
|
10030
10277
|
new RegExp(`${camelPlural}: (results as ${Singular}\\[\\])`),
|
|
10031
|
-
`${camelPlural}: await resolve${Singular}MediaFields($1)`
|
|
10278
|
+
`${camelPlural}: await resolve${Singular}MediaFields($1 as unknown as ${Singular}[])`
|
|
10279
|
+
);
|
|
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}[])`
|
|
10032
10301
|
);
|
|
10033
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
|
+
}
|
|
10034
10316
|
|
|
10035
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
|
+
}
|
|
10036
10407
|
function generateSingleActions(schema, actionsDir, options = {}) {
|
|
10037
10408
|
const singular = singularize(schema.name);
|
|
10038
10409
|
const plural = pluralize(schema.name);
|
|
@@ -10052,6 +10423,8 @@ function generateSingleActions(schema, actionsDir, options = {}) {
|
|
|
10052
10423
|
(field) => field.type === "select" && field.creatable === true
|
|
10053
10424
|
);
|
|
10054
10425
|
const hasCreatableSelectFields = creatableSelectFields.length > 0;
|
|
10426
|
+
const selectFields = collectReadSelectFields(dbFields);
|
|
10427
|
+
const hasSelectFields = selectFields.length > 0;
|
|
10055
10428
|
const allDbFields = [...dbFields];
|
|
10056
10429
|
if (!dbFields.some((f) => f.name === "createdAt")) {
|
|
10057
10430
|
allDbFields.push({ name: "createdAt", type: "timestamp", required: true });
|
|
@@ -10068,9 +10441,12 @@ function generateSingleActions(schema, actionsDir, options = {}) {
|
|
|
10068
10441
|
(f) => !f.primaryKey && f.name !== "createdAt" && f.name !== "updatedAt" && !isAuthorshipFieldName(f.name)
|
|
10069
10442
|
);
|
|
10070
10443
|
const dataFields = allDbFields.map(
|
|
10071
|
-
(f) => ` ${quotePropertyName(f.name)}: ${
|
|
10444
|
+
(f) => ` ${quotePropertyName(f.name)}: ${getReadFieldType(f)}${f.type === "select" || f.required || f.primaryKey ? "" : " | null"}`
|
|
10072
10445
|
).join("\n");
|
|
10073
10446
|
const htmlFieldTypes = htmlOutputFields.map((f) => ` ${f.name}Html: string`).join("\n");
|
|
10447
|
+
const hasTimestampFields = allDbFields.some((f) => f.name === "createdAt") && allDbFields.some((f) => f.name === "updatedAt");
|
|
10448
|
+
const hasFormattedTimestampFields = allDbFields.some((f) => f.name === "createdAtFormatted");
|
|
10449
|
+
const timestampFields = hasTimestampFields && !hasFormattedTimestampFields ? "\n createdAtFormatted: string\n updatedAtFormatted: string" : "";
|
|
10074
10450
|
const upsertInterfaceFields = upsertFields.map((f) => ` ${quotePropertyName(f.name)}?: ${getFieldType(f, "input")}`).join("\n");
|
|
10075
10451
|
const fieldMeta = upsertFields.map((f) => `{ name: '${f.name}', type: '${f.type}', required: ${f.required ?? false} }`).join(",\n ");
|
|
10076
10452
|
const cacheTag = `${schema.name}:all`;
|
|
@@ -10094,9 +10470,10 @@ function generateSingleActions(schema, actionsDir, options = {}) {
|
|
|
10094
10470
|
};
|
|
10095
10471
|
const typesContent = `${[
|
|
10096
10472
|
buildAuthorshipUserType(),
|
|
10473
|
+
buildReadSelectOptionType(selectFields),
|
|
10097
10474
|
`export interface ${Singular} {
|
|
10098
10475
|
${dataFields}${htmlFieldTypes ? `
|
|
10099
|
-
${htmlFieldTypes}` : ""}
|
|
10476
|
+
${htmlFieldTypes}` : ""}${timestampFields}
|
|
10100
10477
|
${buildAuthorshipDataFields()}
|
|
10101
10478
|
}`,
|
|
10102
10479
|
`export interface ${Singular}UpsertInput {
|
|
@@ -10122,22 +10499,47 @@ ${upsertInterfaceFields}
|
|
|
10122
10499
|
authorshipSelects,
|
|
10123
10500
|
authorshipJoins
|
|
10124
10501
|
);
|
|
10125
|
-
const
|
|
10126
|
-
|
|
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
|
+
` : "";
|
|
10127
10516
|
const getContent = `'use server'
|
|
10128
10517
|
|
|
10129
10518
|
import db from '@admin/db'
|
|
10130
|
-
import { ${
|
|
10519
|
+
import { ${getDbImports.join(", ")} } from '@admin/db/schema'
|
|
10131
10520
|
import { eq } from 'drizzle-orm'
|
|
10132
10521
|
import { alias } from 'drizzle-orm/pg-core'
|
|
10133
10522
|
${cacheReadImport}
|
|
10134
10523
|
import { ${cacheTagsVar} } from './types'
|
|
10135
|
-
import type { ${Singular} } from './types'
|
|
10524
|
+
import type { ${Singular}${hasSelectFields ? ", SelectOptionValue" : ""} } from './types'
|
|
10136
10525
|
|
|
10137
10526
|
${buildAuthorshipAliasBlock()}
|
|
10138
10527
|
|
|
10139
10528
|
const SINGLETON_ID = '${singletonId}'
|
|
10140
10529
|
|
|
10530
|
+
function formatActionDate(value: unknown): string {
|
|
10531
|
+
if (typeof value !== 'string') return ''
|
|
10532
|
+
const date = new Date(value)
|
|
10533
|
+
if (Number.isNaN(date.getTime())) return ''
|
|
10534
|
+
|
|
10535
|
+
return date.toLocaleDateString('en-US', {
|
|
10536
|
+
month: 'short',
|
|
10537
|
+
day: '2-digit',
|
|
10538
|
+
year: 'numeric',
|
|
10539
|
+
timeZone: 'UTC'
|
|
10540
|
+
})
|
|
10541
|
+
}
|
|
10542
|
+
${selectResolutionFunctions}
|
|
10141
10543
|
export async function get${Singular}(): Promise<${Singular} | null> {
|
|
10142
10544
|
'use cache'${cacheLifeLine}
|
|
10143
10545
|
cacheTag(${cacheTagsVar}.all)
|
|
@@ -10217,7 +10619,7 @@ ${htmlUpsertBlock}
|
|
|
10217
10619
|
|
|
10218
10620
|
return {
|
|
10219
10621
|
success: true,
|
|
10220
|
-
${camelSingular}: saved${Singular} ?? (result[0] as ${Singular})
|
|
10622
|
+
${camelSingular}: saved${Singular} ?? (result[0] as unknown as ${Singular})
|
|
10221
10623
|
}
|
|
10222
10624
|
} catch (error) {
|
|
10223
10625
|
console.error('Error upserting ${singular}:', error)
|
|
@@ -10446,6 +10848,22 @@ function fieldHasMediaCompanion(column, fields) {
|
|
|
10446
10848
|
const field = fields.find((item) => item.name === column.accessorKey);
|
|
10447
10849
|
return field?.type === "image" || field?.type === "media" || field?.type === "video";
|
|
10448
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
|
+
}
|
|
10449
10867
|
function buildImageUrlExpression(column, fields, fallbackExpression) {
|
|
10450
10868
|
const fallback = `(${fallbackExpression} as string | null | undefined)`;
|
|
10451
10869
|
if (!fieldHasMediaCompanion(column, fields)) {
|
|
@@ -10526,6 +10944,7 @@ function generateColumnDef2(column, fields) {
|
|
|
10526
10944
|
}` : `header: '${column.header}'`;
|
|
10527
10945
|
let cellDef = "";
|
|
10528
10946
|
const authorshipUserAccessor = getAuthorshipUserAccessor(column.accessorKey);
|
|
10947
|
+
const isSelectColumn = fieldIsSelect(column, fields);
|
|
10529
10948
|
if (authorshipUserAccessor) {
|
|
10530
10949
|
cellDef = `cell: ({ row }) => {
|
|
10531
10950
|
${generateAuthorshipValue(authorshipUserAccessor)}
|
|
@@ -10546,7 +10965,15 @@ function generateColumnDef2(column, fields) {
|
|
|
10546
10965
|
}`;
|
|
10547
10966
|
break;
|
|
10548
10967
|
case "badge":
|
|
10549
|
-
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 }) => {
|
|
10550
10977
|
const value = row.getValue('${column.accessorKey}')
|
|
10551
10978
|
return (
|
|
10552
10979
|
<Badge variant="outline">
|
|
@@ -10628,14 +11055,22 @@ function generateColumnDef2(column, fields) {
|
|
|
10628
11055
|
return <${column.component} data={row.original} />
|
|
10629
11056
|
}`;
|
|
10630
11057
|
} else {
|
|
10631
|
-
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 }) => {
|
|
10632
11063
|
const value = row.getValue('${column.accessorKey}')
|
|
10633
11064
|
return <div>{value === null || value === undefined ? 'Unavailable' : String(value)}</div>
|
|
10634
11065
|
}`;
|
|
10635
11066
|
}
|
|
10636
11067
|
break;
|
|
10637
11068
|
default:
|
|
10638
|
-
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 }) => {
|
|
10639
11074
|
const value = row.getValue('${column.accessorKey}')
|
|
10640
11075
|
return <div>{value === null || value === undefined ? 'Unavailable' : String(value)}</div>
|
|
10641
11076
|
}`;
|
|
@@ -10677,6 +11112,7 @@ function generateFirstColumnDef(column, fields, options = {}) {
|
|
|
10677
11112
|
)`;
|
|
10678
11113
|
let cellDef = "";
|
|
10679
11114
|
const authorshipUserAccessor = getAuthorshipUserAccessor(column.accessorKey);
|
|
11115
|
+
const isSelectColumn = fieldIsSelect(column, fields);
|
|
10680
11116
|
if (authorshipUserAccessor) {
|
|
10681
11117
|
cellDef = `cell: ({ row }) => {
|
|
10682
11118
|
${generateAuthorshipValue(authorshipUserAccessor)}
|
|
@@ -10708,7 +11144,22 @@ function generateFirstColumnDef(column, fields, options = {}) {
|
|
|
10708
11144
|
}`;
|
|
10709
11145
|
break;
|
|
10710
11146
|
case "badge":
|
|
10711
|
-
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 }) => {
|
|
10712
11163
|
const value = row.original.${column.accessorKey}
|
|
10713
11164
|
return (
|
|
10714
11165
|
<div className="flex items-center gap-4 h-full pl-1">
|
|
@@ -10831,7 +11282,22 @@ function generateFirstColumnDef(column, fields, options = {}) {
|
|
|
10831
11282
|
)
|
|
10832
11283
|
}`;
|
|
10833
11284
|
} else {
|
|
10834
|
-
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 }) => {
|
|
10835
11301
|
const value = row.original.${column.accessorKey}
|
|
10836
11302
|
return (
|
|
10837
11303
|
<div className="flex items-center gap-4 h-full pl-1">
|
|
@@ -10877,7 +11343,22 @@ function generateFirstColumnDef(column, fields, options = {}) {
|
|
|
10877
11343
|
}`;
|
|
10878
11344
|
break;
|
|
10879
11345
|
default:
|
|
10880
|
-
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 }) => {
|
|
10881
11362
|
const value = row.original.${column.accessorKey}
|
|
10882
11363
|
return (
|
|
10883
11364
|
<div className="flex items-center gap-4 h-full pl-1">
|
|
@@ -11549,9 +12030,38 @@ function defaultFallbackValue(f) {
|
|
|
11549
12030
|
function hasInitialValueExpression(fieldName, dataSource = "initialData") {
|
|
11550
12031
|
return `${dataSource}?.${fieldName} !== undefined && ${dataSource}?.${fieldName} !== null && ${dataSource}?.${fieldName} !== ''`;
|
|
11551
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
|
+
}
|
|
11552
12048
|
function generateDefaultValue(f, fieldMap, dataSource = "initialData") {
|
|
11553
12049
|
if (f.defaultValueFrom && f.defaultValueFrom.trim() !== f.name && fieldMap?.has(f.defaultValueFrom.trim())) {
|
|
11554
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
|
+
}
|
|
11555
12065
|
return ` ${f.name}: ${hasInitialValueExpression(f.name, dataSource)}
|
|
11556
12066
|
? ${dataSource}.${f.name}
|
|
11557
12067
|
: ${hasInitialValueExpression(sourceName, dataSource)}
|
|
@@ -11581,22 +12091,23 @@ function generateDefaultValue(f, fieldMap, dataSource = "initialData") {
|
|
|
11581
12091
|
return ` ${f.name}: ${dataSource}?.${f.name} ?? undefined`;
|
|
11582
12092
|
}
|
|
11583
12093
|
if (f.type === "select") {
|
|
12094
|
+
const selectedValuesExpression = selectReadValuesExpression(f.name, dataSource);
|
|
11584
12095
|
if (f.multiple) {
|
|
11585
12096
|
const fallback2 = JSON.stringify(selectDefaultValues(f));
|
|
11586
12097
|
if (f.creatable) {
|
|
11587
|
-
return ` ${f.name}:
|
|
12098
|
+
return ` ${f.name}: ${selectedValuesExpression}.length > 0 ? ${selectedValuesExpression} : ${fallback2}`;
|
|
11588
12099
|
}
|
|
11589
12100
|
const validValuesExpression2 = `([${(f.options || []).map((option) => JSON.stringify(option.value)).join(", ")}] as const as readonly string[])`;
|
|
11590
|
-
return ` ${f.name}:
|
|
11591
|
-
? ${
|
|
12101
|
+
return ` ${f.name}: ${selectedValuesExpression}.length > 0
|
|
12102
|
+
? ${selectedValuesExpression}.filter((value) => ${validValuesExpression2}.includes(value))
|
|
11592
12103
|
: ${fallback2}`;
|
|
11593
12104
|
}
|
|
11594
12105
|
const fallback = f.default !== void 0 && f.default !== null ? JSON.stringify(f.default) : "''";
|
|
11595
12106
|
if (f.creatable) {
|
|
11596
|
-
return ` ${f.name}:
|
|
12107
|
+
return ` ${f.name}: ${selectedValuesExpression}[0] ?? ${fallback}`;
|
|
11597
12108
|
}
|
|
11598
12109
|
const validValuesExpression = `([${(f.options || []).map((option) => JSON.stringify(option.value)).join(", ")}] as const as readonly string[])`;
|
|
11599
|
-
return ` ${f.name}:
|
|
12110
|
+
return ` ${f.name}: ${selectedValuesExpression}[0] && ${validValuesExpression}.includes(${selectedValuesExpression}[0]) ? ${selectedValuesExpression}[0] : ${fallback}`;
|
|
11600
12111
|
}
|
|
11601
12112
|
if (f.default !== void 0 && f.default !== null) {
|
|
11602
12113
|
const def = typeof f.default === "string" ? `'${f.default}'` : f.default;
|