@jskit-ai/crud-server-generator 0.1.63 → 0.1.64

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.
@@ -5,29 +5,14 @@ import { toCamelCase } from "@jskit-ai/kernel/shared/support/stringCase";
5
5
  import {
6
6
  resolveGenerationSnapshot,
7
7
  resolveScaffoldColumns,
8
- renderPropertyAccess,
9
- renderResourceFieldSchema,
10
- renderInputNormalizer,
11
- renderOutputNormalizerExpression,
12
- buildFieldMetaEntries
8
+ renderCanonicalResourceFieldSchema,
9
+ buildFieldContractEntries
13
10
  } from "../buildTemplateContext.js";
14
11
  import {
15
12
  resolveCrudResourceDefaults,
16
13
  applyCrudResourceFieldPatch
17
14
  } from "./resourceAst.js";
18
15
 
19
- const NORMALIZE_SUPPORT_IMPORTS = new Set([
20
- "normalizeText",
21
- "normalizeBoolean",
22
- "normalizeFiniteNumber",
23
- "normalizeFiniteInteger",
24
- "normalizeIfInSource",
25
- "normalizeIfPresent",
26
- "normalizeOrNull"
27
- ]);
28
- const DATABASE_RUNTIME_IMPORTS = new Set(["toIsoString", "toDatabaseDateTimeUtc"]);
29
- const DATABASE_RUNTIME_REPOSITORY_IMPORTS = new Set(["parseJsonValue"]);
30
-
31
16
  function toPosixPath(value = "") {
32
17
  return String(value || "").replaceAll(path.sep, "/");
33
18
  }
@@ -114,8 +99,8 @@ function resolveColumnForField(snapshot = {}, fieldKey = "", { idColumn = "id" }
114
99
  );
115
100
  }
116
101
 
117
- function buildFieldMetaEntry(snapshot = {}, column = {}) {
118
- const entries = buildFieldMetaEntries({
102
+ function buildFieldContractEntry(snapshot = {}, column = {}) {
103
+ const entries = buildFieldContractEntries({
119
104
  outputColumns: [column],
120
105
  writableColumns: [column],
121
106
  snapshot
@@ -124,51 +109,6 @@ function buildFieldMetaEntry(snapshot = {}, column = {}) {
124
109
  return entries.find((entry) => normalizeText(entry?.key) === key) || null;
125
110
  }
126
111
 
127
- function collectKnownIdentifiers(expression = "") {
128
- return new Set(String(expression || "").match(/[A-Za-z_$][A-Za-z0-9_$]*/g) || []);
129
- }
130
-
131
- function resolveImportsForField({ inputNormalizationExpression = "", outputNormalizationExpression = "" } = {}) {
132
- const normalizeImports = new Set(["normalizeIfInSource"]);
133
- const databaseRuntimeImports = new Set();
134
- const databaseRuntimeRepositoryImports = new Set();
135
-
136
- const identifiers = new Set([
137
- ...collectKnownIdentifiers(inputNormalizationExpression),
138
- ...collectKnownIdentifiers(outputNormalizationExpression)
139
- ]);
140
-
141
- for (const identifier of identifiers) {
142
- if (NORMALIZE_SUPPORT_IMPORTS.has(identifier)) {
143
- normalizeImports.add(identifier);
144
- continue;
145
- }
146
- if (DATABASE_RUNTIME_IMPORTS.has(identifier)) {
147
- databaseRuntimeImports.add(identifier);
148
- continue;
149
- }
150
- if (DATABASE_RUNTIME_REPOSITORY_IMPORTS.has(identifier)) {
151
- databaseRuntimeRepositoryImports.add(identifier);
152
- }
153
- }
154
-
155
- return {
156
- normalizeImports: [...normalizeImports],
157
- databaseRuntimeImports: [...databaseRuntimeImports],
158
- databaseRuntimeRepositoryImports: [...databaseRuntimeRepositoryImports]
159
- };
160
- }
161
-
162
- function resolveOutputNormalizationExpression(column = {}) {
163
- const outputNormalizer = renderOutputNormalizerExpression(column);
164
- const sourceAccess = renderPropertyAccess("source", column.key);
165
- if (!outputNormalizer) {
166
- return sourceAccess;
167
- }
168
- const wrapper = column?.nullable === true ? "normalizeOrNull" : "normalizeIfPresent";
169
- return `${wrapper}(${sourceAccess}, ${outputNormalizer})`;
170
- }
171
-
172
112
  async function runGeneratorSubcommand({
173
113
  appRoot,
174
114
  subcommand = "",
@@ -201,26 +141,14 @@ async function runGeneratorSubcommand({
201
141
  );
202
142
  }
203
143
 
204
- const createSchemaExpression = renderResourceFieldSchema(column, { forOutput: false });
205
- const outputSchemaExpression = renderResourceFieldSchema(column, { forOutput: true });
206
- const inputNormalizationExpression = renderInputNormalizer(column);
207
- const outputNormalizationExpression = resolveOutputNormalizationExpression(column);
208
- const fieldMetaEntry = buildFieldMetaEntry(snapshot, column);
209
- const imports = resolveImportsForField({
210
- inputNormalizationExpression,
211
- outputNormalizationExpression
144
+ const fieldContractEntry = buildFieldContractEntry(snapshot, column);
145
+ const resourceSchemaExpression = renderCanonicalResourceFieldSchema(column, {
146
+ fieldContractEntry
212
147
  });
213
148
 
214
149
  const applied = applyCrudResourceFieldPatch(originalSource, {
215
150
  fieldKey,
216
- createSchemaExpression,
217
- outputSchemaExpression,
218
- inputNormalizationExpression,
219
- outputNormalizationExpression,
220
- fieldMetaEntry,
221
- normalizeImportNames: imports.normalizeImports,
222
- databaseRuntimeImportNames: imports.databaseRuntimeImports,
223
- databaseRuntimeRepositoryOptionsImportNames: imports.databaseRuntimeRepositoryImports
151
+ resourceSchemaExpression
224
152
  });
225
153
 
226
154
  if (applied.changed && dryRun !== true) {
@@ -1,7 +1,6 @@
1
1
  import * as recast from "recast";
2
2
  import { parse as parseBabel } from "@babel/parser";
3
3
  import { normalizeText } from "@jskit-ai/database-runtime/shared";
4
- import { normalizeCrudLookupNamespace } from "@jskit-ai/kernel/shared/support/crudLookup";
5
4
 
6
5
  const { namedTypes: n, builders: b } = recast.types;
7
6
 
@@ -61,15 +60,6 @@ function parseExpression(source = "", context = "crud-server-generator scaffold-
61
60
  return declaration.init;
62
61
  }
63
62
 
64
- function parseStatement(source = "", context = "crud-server-generator scaffold-field") {
65
- const ast = parseModule(String(source || ""), context);
66
- const statement = ast?.program?.body?.[0];
67
- if (!statement) {
68
- throw new Error(`${context} could not parse statement.`);
69
- }
70
- return statement;
71
- }
72
-
73
63
  function resolveNodeKeyName(keyNode, { computed = false } = {}) {
74
64
  if (!keyNode) {
75
65
  return "";
@@ -122,58 +112,40 @@ function requireVariableDeclarator(programNode, variableName = "", context = "cr
122
112
  throw new Error(`${context} could not find const ${variableName}.`);
123
113
  }
124
114
 
125
- function requireSchemaPropertiesObject(programNode, variableName = "", context = "crud-server-generator scaffold-field") {
126
- const declaration = requireVariableDeclarator(programNode, variableName, context);
115
+ function requireCrudResourceConfigObject(programNode, context = "crud-server-generator scaffold-field") {
116
+ const declaration = requireVariableDeclarator(programNode, "resource", context);
127
117
  const initExpression = declaration.init;
128
118
  if (!n.CallExpression.check(initExpression)) {
129
- throw new Error(`${context} expected ${variableName} to be initialized with Type.Object(...).`);
119
+ throw new Error(
120
+ `${context} requires resource files authored as const resource = defineCrudResource({ ... }).`
121
+ );
130
122
  }
131
-
132
- const callee = initExpression.callee;
133
- const isTypeObjectCall =
134
- n.MemberExpression.check(callee) &&
135
- !callee.computed &&
136
- n.Identifier.check(callee.object) &&
137
- callee.object.name === "Type" &&
138
- n.Identifier.check(callee.property) &&
139
- callee.property.name === "Object";
140
- if (!isTypeObjectCall) {
141
- throw new Error(`${context} expected ${variableName} to call Type.Object(...).`);
123
+ if (!n.Identifier.check(initExpression.callee) || initExpression.callee.name !== "defineCrudResource") {
124
+ throw new Error(
125
+ `${context} requires resource files authored as const resource = defineCrudResource({ ... }).`
126
+ );
142
127
  }
143
128
 
144
129
  const firstArgument = initExpression.arguments?.[0];
145
130
  if (!n.ObjectExpression.check(firstArgument)) {
146
- throw new Error(`${context} expected ${variableName} Type.Object first argument to be an object literal.`);
131
+ throw new Error(
132
+ `${context} requires defineCrudResource(...) to receive an inline object literal.`
133
+ );
147
134
  }
148
135
 
149
136
  return firstArgument;
150
137
  }
151
138
 
152
- function requireObjectFreezePayloadObject(programNode, variableName = "", context = "crud-server-generator scaffold-field") {
153
- const declaration = requireVariableDeclarator(programNode, variableName, context);
154
- const initExpression = declaration.init;
155
- if (!n.CallExpression.check(initExpression)) {
156
- throw new Error(`${context} expected ${variableName} to be initialized with Object.freeze(...).`);
157
- }
158
-
159
- const callee = initExpression.callee;
160
- const isObjectFreezeCall =
161
- n.MemberExpression.check(callee) &&
162
- !callee.computed &&
163
- n.Identifier.check(callee.object) &&
164
- callee.object.name === "Object" &&
165
- n.Identifier.check(callee.property) &&
166
- callee.property.name === "freeze";
167
- if (!isObjectFreezeCall) {
168
- throw new Error(`${context} expected ${variableName} to call Object.freeze(...).`);
169
- }
170
-
171
- const payload = initExpression.arguments?.[0];
172
- if (!n.ObjectExpression.check(payload)) {
173
- throw new Error(`${context} expected ${variableName} Object.freeze payload to be an object literal.`);
139
+ function requireResourceSchemaObject(programNode, context = "crud-server-generator scaffold-field") {
140
+ const resourceObject = requireCrudResourceConfigObject(programNode, context);
141
+ const schemaProperty = findObjectPropertyByName(resourceObject, "schema");
142
+ if (!schemaProperty || !n.ObjectExpression.check(schemaProperty.value)) {
143
+ throw new Error(
144
+ `${context} requires defineCrudResource({ ..., schema: { ... } }) with an inline schema object literal.`
145
+ );
174
146
  }
175
147
 
176
- return payload;
148
+ return schemaProperty.value;
177
149
  }
178
150
 
179
151
  function findObjectPropertyByName(objectNode, propertyName = "") {
@@ -197,48 +169,6 @@ function findObjectPropertyByName(objectNode, propertyName = "") {
197
169
  return null;
198
170
  }
199
171
 
200
- function requireNormalizeFunctionBody(programNode, variableName = "", context = "crud-server-generator scaffold-field") {
201
- const validatorObject = requireObjectFreezePayloadObject(programNode, variableName, context);
202
- const normalizeProperty = findObjectPropertyByName(validatorObject, "normalize");
203
- if (!normalizeProperty) {
204
- throw new Error(`${context} expected ${variableName}.normalize(...) to exist.`);
205
- }
206
-
207
- if (n.ObjectMethod.check(normalizeProperty)) {
208
- return normalizeProperty.body;
209
- }
210
-
211
- const propertyValue = normalizeProperty.value;
212
- if (n.FunctionExpression.check(propertyValue) || n.ArrowFunctionExpression.check(propertyValue)) {
213
- if (n.BlockStatement.check(propertyValue.body)) {
214
- return propertyValue.body;
215
- }
216
- }
217
-
218
- throw new Error(`${context} expected ${variableName}.normalize to be a function with a block body.`);
219
- }
220
-
221
- function requireNormalizedObjectLiteral(functionBody, context = "crud-server-generator scaffold-field") {
222
- for (const statement of functionBody.body || []) {
223
- if (!n.VariableDeclaration.check(statement)) {
224
- continue;
225
- }
226
- for (const declaration of statement.declarations || []) {
227
- if (!n.VariableDeclarator.check(declaration) || !n.Identifier.check(declaration.id)) {
228
- continue;
229
- }
230
- if (declaration.id.name !== "normalized") {
231
- continue;
232
- }
233
- if (!n.ObjectExpression.check(declaration.init)) {
234
- throw new Error(`${context} expected normalized to be initialized as an object literal.`);
235
- }
236
- return declaration.init;
237
- }
238
- }
239
- throw new Error(`${context} could not find "const normalized = { ... }".`);
240
- }
241
-
242
172
  function hasObjectProperty(objectNode, propertyName = "") {
243
173
  return Boolean(findObjectPropertyByName(objectNode, propertyName));
244
174
  }
@@ -284,155 +214,6 @@ function insertObjectProperty(
284
214
  return true;
285
215
  }
286
216
 
287
- function hasNormalizeIfInSourceCall(functionBody, fieldKey = "") {
288
- const targetFieldKey = normalizeText(fieldKey);
289
- if (!targetFieldKey) {
290
- return false;
291
- }
292
-
293
- for (const statement of functionBody.body || []) {
294
- if (!n.ExpressionStatement.check(statement) || !n.CallExpression.check(statement.expression)) {
295
- continue;
296
- }
297
- const callExpression = statement.expression;
298
- if (!n.Identifier.check(callExpression.callee) || callExpression.callee.name !== "normalizeIfInSource") {
299
- continue;
300
- }
301
- const keyArgument = callExpression.arguments?.[2];
302
- if (n.StringLiteral.check(keyArgument) && normalizeText(keyArgument.value) === targetFieldKey) {
303
- return true;
304
- }
305
- if (n.Literal.check(keyArgument) && typeof keyArgument.value === "string" && normalizeText(keyArgument.value) === targetFieldKey) {
306
- return true;
307
- }
308
- }
309
-
310
- return false;
311
- }
312
-
313
- function resolveReturnNormalizedIndex(functionBody) {
314
- const statements = Array.isArray(functionBody?.body) ? functionBody.body : [];
315
- for (const [index, statement] of statements.entries()) {
316
- if (!n.ReturnStatement.check(statement)) {
317
- continue;
318
- }
319
- if (n.Identifier.check(statement.argument) && statement.argument.name === "normalized") {
320
- return index;
321
- }
322
- }
323
- return statements.length;
324
- }
325
-
326
- function hasResourceFieldMetaEntry(programNode, fieldKey = "") {
327
- const targetKey = normalizeText(fieldKey);
328
- if (!targetKey || !programNode || !Array.isArray(programNode.body)) {
329
- return false;
330
- }
331
-
332
- for (const statement of programNode.body) {
333
- if (!n.ExpressionStatement.check(statement) || !n.CallExpression.check(statement.expression)) {
334
- continue;
335
- }
336
- const callExpression = statement.expression;
337
- if (!n.MemberExpression.check(callExpression.callee) || callExpression.callee.computed) {
338
- continue;
339
- }
340
- if (!n.Identifier.check(callExpression.callee.object) || callExpression.callee.object.name !== "RESOURCE_FIELD_META") {
341
- continue;
342
- }
343
- if (!n.Identifier.check(callExpression.callee.property) || callExpression.callee.property.name !== "push") {
344
- continue;
345
- }
346
-
347
- const firstArgument = callExpression.arguments?.[0];
348
- if (!n.ObjectExpression.check(firstArgument)) {
349
- continue;
350
- }
351
- const keyProperty = findObjectPropertyByName(firstArgument, "key");
352
- if (!keyProperty) {
353
- continue;
354
- }
355
- const keyValue = keyProperty.value;
356
- if (n.StringLiteral.check(keyValue) && normalizeText(keyValue.value) === targetKey) {
357
- return true;
358
- }
359
- if (n.Literal.check(keyValue) && typeof keyValue.value === "string" && normalizeText(keyValue.value) === targetKey) {
360
- return true;
361
- }
362
- }
363
-
364
- return false;
365
- }
366
-
367
- function sortImportSpecifiers(importDeclaration) {
368
- const sourceSpecifiers = Array.isArray(importDeclaration?.specifiers) ? importDeclaration.specifiers : [];
369
- const named = sourceSpecifiers
370
- .filter((specifier) => n.ImportSpecifier.check(specifier))
371
- .sort((left, right) => {
372
- const leftName = String(left?.imported?.name || left?.imported?.value || "");
373
- const rightName = String(right?.imported?.name || right?.imported?.value || "");
374
- return leftName.localeCompare(rightName);
375
- });
376
- const nonNamed = sourceSpecifiers.filter((specifier) => !n.ImportSpecifier.check(specifier));
377
- importDeclaration.specifiers = [...nonNamed, ...named];
378
- }
379
-
380
- function ensureNamedImport(programNode, modulePath = "", importName = "") {
381
- const normalizedModulePath = normalizeText(modulePath);
382
- const normalizedImportName = normalizeText(importName);
383
- if (!normalizedModulePath || !normalizedImportName) {
384
- return false;
385
- }
386
-
387
- const importDeclarations = (programNode.body || []).filter((statement) => n.ImportDeclaration.check(statement));
388
- let declaration = importDeclarations.find((statement) => {
389
- const source = statement.source;
390
- if (n.StringLiteral.check(source)) {
391
- return source.value === normalizedModulePath;
392
- }
393
- if (n.Literal.check(source)) {
394
- return source.value === normalizedModulePath;
395
- }
396
- return false;
397
- });
398
-
399
- if (!declaration) {
400
- declaration = b.importDeclaration(
401
- [b.importSpecifier(b.identifier(normalizedImportName), b.identifier(normalizedImportName))],
402
- b.stringLiteral(normalizedModulePath)
403
- );
404
- const insertionIndex = (() => {
405
- const body = Array.isArray(programNode.body) ? programNode.body : [];
406
- let index = 0;
407
- while (index < body.length && n.ImportDeclaration.check(body[index])) {
408
- index += 1;
409
- }
410
- return index;
411
- })();
412
- programNode.body.splice(insertionIndex, 0, declaration);
413
- return true;
414
- }
415
-
416
- const hasSpecifier = (declaration.specifiers || []).some((specifier) => {
417
- if (!n.ImportSpecifier.check(specifier)) {
418
- return false;
419
- }
420
- const importedName = String(specifier.imported?.name || specifier.imported?.value || "");
421
- const localName = String(specifier.local?.name || "");
422
- return importedName === normalizedImportName || localName === normalizedImportName;
423
- });
424
- if (hasSpecifier) {
425
- return false;
426
- }
427
-
428
- declaration.specifiers = [
429
- ...(declaration.specifiers || []),
430
- b.importSpecifier(b.identifier(normalizedImportName), b.identifier(normalizedImportName))
431
- ];
432
- sortImportSpecifiers(declaration);
433
- return true;
434
- }
435
-
436
217
  function resolveObjectPropertyStringValue(objectNode, propertyName = "") {
437
218
  const propertyNode = findObjectPropertyByName(objectNode, propertyName);
438
219
  if (!propertyNode) {
@@ -450,88 +231,23 @@ function resolveObjectPropertyStringValue(objectNode, propertyName = "") {
450
231
 
451
232
  function resolveCrudResourceDefaults(source = "", context = "crud-server-generator scaffold-field") {
452
233
  const ast = parseModule(source, context);
453
- const statements = Array.isArray(ast?.program?.body) ? ast.program.body : [];
454
-
455
- for (const statement of statements) {
456
- if (!n.VariableDeclaration.check(statement)) {
457
- continue;
458
- }
459
- for (const declaration of statement.declarations || []) {
460
- if (!n.VariableDeclarator.check(declaration) || !n.ObjectExpression.check(declaration.init)) {
461
- continue;
462
- }
463
- const tableName = resolveObjectPropertyStringValue(declaration.init, "tableName");
464
- if (!tableName) {
465
- continue;
466
- }
467
- const idColumn = resolveObjectPropertyStringValue(declaration.init, "idColumn");
468
- return Object.freeze({
469
- tableName,
470
- idColumn: idColumn || "id"
471
- });
472
- }
473
- }
474
-
475
- throw new Error(`${context} could not resolve resource tableName/idColumn from resource object literal.`);
476
- }
477
-
478
- function renderResourceFieldMetaPushStatement(entry = {}) {
479
- const key = normalizeText(entry?.key);
480
- if (!key) {
481
- throw new Error("crud-server-generator scaffold-field fieldMeta entry requires key.");
482
- }
483
-
484
- const lines = ["RESOURCE_FIELD_META.push({"];
485
- lines.push(` key: ${JSON.stringify(key)},`);
486
-
487
- const repositoryColumn = normalizeText(entry?.repository?.column);
488
- if (repositoryColumn) {
489
- lines.push(" repository: {");
490
- lines.push(` column: ${JSON.stringify(repositoryColumn)}`);
491
- lines.push(" },");
492
- }
493
-
494
- const relation = entry?.relation && typeof entry.relation === "object" ? entry.relation : null;
495
- if (relation) {
496
- const relationNamespace =
497
- normalizeCrudLookupNamespace(relation.namespace) ||
498
- normalizeCrudLookupNamespace(relation.apiPath);
499
- if (!relationNamespace) {
500
- throw new Error("crud-server-generator scaffold-field fieldMeta relation requires namespace.");
501
- }
502
- lines.push(" relation: {");
503
- lines.push(` kind: ${JSON.stringify(normalizeText(relation.kind) || "lookup")},`);
504
- lines.push(` namespace: ${JSON.stringify(relationNamespace)},`);
505
- lines.push(` valueKey: ${JSON.stringify(normalizeText(relation.valueKey) || "id")}`);
506
- lines.push(" },");
507
- }
508
-
509
- const formControl = normalizeText(entry?.ui?.formControl);
510
- if (formControl) {
511
- lines.push(" ui: {");
512
- lines.push(` formControl: ${JSON.stringify(formControl)} // or "select"`);
513
- lines.push(" }");
514
- } else {
515
- const lastIndex = lines.length - 1;
516
- lines[lastIndex] = lines[lastIndex].replace(/,$/, "");
517
- }
518
-
519
- lines.push("});");
520
- return lines.join("\n");
234
+ const resourceObject = requireCrudResourceConfigObject(ast.program, context);
235
+ const tableName = resolveObjectPropertyStringValue(resourceObject, "tableName");
236
+ if (!tableName) {
237
+ throw new Error(`${context} could not resolve resource tableName from resource object literal.`);
238
+ }
239
+ const idColumn = resolveObjectPropertyStringValue(resourceObject, "idColumn") || "id";
240
+ return Object.freeze({
241
+ tableName,
242
+ idColumn
243
+ });
521
244
  }
522
245
 
523
246
  function applyCrudResourceFieldPatch(
524
247
  source = "",
525
248
  {
526
249
  fieldKey = "",
527
- outputSchemaExpression = "",
528
- createSchemaExpression = "",
529
- outputNormalizationExpression = "",
530
- inputNormalizationExpression = "",
531
- fieldMetaEntry = null,
532
- normalizeImportNames = [],
533
- databaseRuntimeImportNames = [],
534
- databaseRuntimeRepositoryOptionsImportNames = [],
250
+ resourceSchemaExpression = "",
535
251
  context = "crud-server-generator scaffold-field"
536
252
  } = {}
537
253
  ) {
@@ -539,88 +255,19 @@ function applyCrudResourceFieldPatch(
539
255
  if (!normalizedFieldKey) {
540
256
  throw new Error(`${context} apply patch requires fieldKey.`);
541
257
  }
542
- if (!normalizeText(outputSchemaExpression)) {
543
- throw new Error(`${context} apply patch requires outputSchemaExpression.`);
544
- }
545
- if (!normalizeText(createSchemaExpression)) {
546
- throw new Error(`${context} apply patch requires createSchemaExpression.`);
547
- }
548
- if (!normalizeText(outputNormalizationExpression)) {
549
- throw new Error(`${context} apply patch requires outputNormalizationExpression.`);
550
- }
551
- if (!normalizeText(inputNormalizationExpression)) {
552
- throw new Error(`${context} apply patch requires inputNormalizationExpression.`);
258
+ const hasCanonicalFieldExpression = Boolean(normalizeText(resourceSchemaExpression));
259
+ if (!hasCanonicalFieldExpression) {
260
+ throw new Error(
261
+ `${context} apply patch requires resourceSchemaExpression.`
262
+ );
553
263
  }
554
264
 
555
265
  const ast = parseModule(source, context);
556
266
  const programNode = ast.program;
557
- let changed = false;
558
-
559
- const recordOutputSchemaObject = requireSchemaPropertiesObject(programNode, "recordOutputSchema", context);
560
- changed =
561
- insertObjectProperty(recordOutputSchemaObject, normalizedFieldKey, outputSchemaExpression, {
562
- context,
563
- insertBeforeComputed: true
564
- }) || changed;
565
-
566
- const createBodySchemaObject = requireSchemaPropertiesObject(programNode, "createBodySchema", context);
567
- changed =
568
- insertObjectProperty(createBodySchemaObject, normalizedFieldKey, createSchemaExpression, {
569
- context
570
- }) || changed;
571
-
572
- const recordNormalizeFunctionBody = requireNormalizeFunctionBody(programNode, "recordOutputValidator", context);
573
- const recordNormalizedObject = requireNormalizedObjectLiteral(recordNormalizeFunctionBody, context);
574
- changed =
575
- insertObjectProperty(recordNormalizedObject, normalizedFieldKey, outputNormalizationExpression, {
576
- context
577
- }) || changed;
578
-
579
- const createNormalizeFunctionBody = requireNormalizeFunctionBody(programNode, "createBodyValidator", context);
580
- if (!hasNormalizeIfInSourceCall(createNormalizeFunctionBody, normalizedFieldKey)) {
581
- const insertionStatement = parseStatement(
582
- `normalizeIfInSource(source, normalized, ${JSON.stringify(normalizedFieldKey)}, ${inputNormalizationExpression});`,
583
- context
584
- );
585
- const insertionIndex = resolveReturnNormalizedIndex(createNormalizeFunctionBody);
586
- createNormalizeFunctionBody.body.splice(insertionIndex, 0, insertionStatement);
587
- changed = true;
588
- }
589
-
590
- const validFieldMetaEntry =
591
- fieldMetaEntry &&
592
- typeof fieldMetaEntry === "object" &&
593
- normalizeText(fieldMetaEntry.key) === normalizedFieldKey
594
- ? fieldMetaEntry
595
- : null;
596
- if (validFieldMetaEntry && !hasResourceFieldMetaEntry(programNode, normalizedFieldKey)) {
597
- const fieldMetaStatement = parseStatement(renderResourceFieldMetaPushStatement(validFieldMetaEntry), context);
598
- programNode.body.push(fieldMetaStatement);
599
- changed = true;
600
- }
601
-
602
- const normalizeImports = Array.isArray(normalizeImportNames) ? normalizeImportNames : [];
603
- for (const importName of normalizeImports) {
604
- changed =
605
- ensureNamedImport(programNode, "@jskit-ai/kernel/shared/support/normalize", importName) || changed;
606
- }
607
-
608
- const databaseRuntimeImports = Array.isArray(databaseRuntimeImportNames) ? databaseRuntimeImportNames : [];
609
- for (const importName of databaseRuntimeImports) {
610
- changed = ensureNamedImport(programNode, "@jskit-ai/database-runtime/shared", importName) || changed;
611
- }
612
-
613
- const databaseRuntimeRepositoryOptionsImports = Array.isArray(databaseRuntimeRepositoryOptionsImportNames)
614
- ? databaseRuntimeRepositoryOptionsImportNames
615
- : [];
616
- for (const importName of databaseRuntimeRepositoryOptionsImports) {
617
- changed =
618
- ensureNamedImport(
619
- programNode,
620
- "@jskit-ai/database-runtime/shared/repositoryOptions",
621
- importName
622
- ) || changed;
623
- }
267
+ const resourceSchemaObject = requireResourceSchemaObject(programNode, context);
268
+ const changed = insertObjectProperty(resourceSchemaObject, normalizedFieldKey, resourceSchemaExpression, {
269
+ context
270
+ });
624
271
 
625
272
  return {
626
273
  changed,