@nuasite/cli 0.54.0 → 0.56.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -7295,7 +7295,7 @@ var init_check_shape = __esm(() => {
7295
7295
  function isBlankFieldValue(value) {
7296
7296
  return value === undefined || value === null || value === "";
7297
7297
  }
7298
- function defaultValueForNewEntry(field, today = () => new Date) {
7298
+ function seedValueForRequiredField(field, today = () => new Date) {
7299
7299
  if (field.defaultValue !== undefined)
7300
7300
  return field.defaultValue;
7301
7301
  switch (field.type) {
@@ -7311,23 +7311,71 @@ function defaultValueForNewEntry(field, today = () => new Date) {
7311
7311
  return "";
7312
7312
  }
7313
7313
  }
7314
+ function blankFieldValue(field) {
7315
+ if (field.defaultValue !== undefined)
7316
+ return field.defaultValue;
7317
+ switch (field.type) {
7318
+ case "boolean":
7319
+ return false;
7320
+ case "array":
7321
+ return [];
7322
+ case "object":
7323
+ return {};
7324
+ case "date":
7325
+ case "datetime":
7326
+ case "time":
7327
+ case "month":
7328
+ case "number":
7329
+ case "year":
7330
+ case "select":
7331
+ case "reference":
7332
+ return;
7333
+ default:
7334
+ return "";
7335
+ }
7336
+ }
7314
7337
  function newRepeaterItem(fields, today) {
7315
7338
  const item = {};
7316
7339
  for (const field of fields) {
7317
7340
  if (!field.required || field.hidden)
7318
7341
  continue;
7319
- item[field.name] = defaultValueForNewEntry(field, today);
7342
+ item[field.name] = seedValueForRequiredField(field, today);
7320
7343
  }
7321
7344
  return item;
7322
7345
  }
7346
+ function isDeclaredDerived(field) {
7347
+ return field.derivedDeclared === true || field.layout?.derivedFrom !== undefined;
7348
+ }
7323
7349
  function blankRequiredFields(fields, frontmatter) {
7324
- return fields.filter((field) => field.required && !(field.hidden ?? field.layout?.hidden) && isBlankFieldValue(frontmatter[field.name])).map((field) => field.name);
7350
+ return fields.filter((field) => field.required && !(field.hidden ?? field.layout?.hidden) && !isDeclaredDerived(field) && isBlankFieldValue(frontmatter[field.name])).map((field) => field.name);
7351
+ }
7352
+ function isPlainRecord(value) {
7353
+ if (typeof value !== "object" || value === null || Array.isArray(value))
7354
+ return false;
7355
+ const prototype = Object.getPrototypeOf(value);
7356
+ return prototype === Object.prototype || prototype === null;
7357
+ }
7358
+ function prunedValue(value) {
7359
+ if (Array.isArray(value))
7360
+ return value.map(prunedValue).filter((item) => !isBlankFieldValue(item));
7361
+ if (isPlainRecord(value))
7362
+ return withoutBlankArrayItems(value);
7363
+ return value;
7364
+ }
7365
+ function withoutBlankArrayItems(frontmatter) {
7366
+ const out = {};
7367
+ for (const [key, value] of Object.entries(frontmatter))
7368
+ out[key] = prunedValue(value);
7369
+ return out;
7325
7370
  }
7326
7371
  // ../cms-types/src/index.ts
7327
7372
  function isFieldType(value) {
7328
7373
  return FIELD_TYPES.includes(value);
7329
7374
  }
7330
- var FIELD_TYPES;
7375
+ function isDerivedTransform(value) {
7376
+ return DERIVED_TRANSFORMS.includes(value);
7377
+ }
7378
+ var FIELD_TYPES, DERIVED_TRANSFORMS;
7331
7379
  var init_src = __esm(() => {
7332
7380
  FIELD_TYPES = [
7333
7381
  "text",
@@ -7351,15 +7399,16 @@ var init_src = __esm(() => {
7351
7399
  "object",
7352
7400
  "reference"
7353
7401
  ];
7402
+ DERIVED_TRANSFORMS = ["slugifyHref", "slug", "copy"];
7354
7403
  });
7355
7404
 
7356
7405
  // ../cms-core/src/editor-write-model.ts
7357
- function newEntryFrontmatter(fields, today) {
7406
+ function newEntryFrontmatter(fields) {
7358
7407
  const frontmatter = {};
7359
7408
  for (const field of fields) {
7360
7409
  if (field.name === "title" || field.hidden)
7361
7410
  continue;
7362
- frontmatter[field.name] = defaultValueForNewEntry(field, today);
7411
+ frontmatter[field.name] = blankFieldValue(field);
7363
7412
  }
7364
7413
  return frontmatter;
7365
7414
  }
@@ -7432,16 +7481,27 @@ function rejectionFinding(action, issue, kind, written) {
7432
7481
  finding.hint = hintFor(kind, valueAt(written, issue.path));
7433
7482
  return finding;
7434
7483
  }
7484
+ function scalarItemType(field) {
7485
+ if (field.reference?.isArray)
7486
+ return "reference";
7487
+ if (field.type !== "array")
7488
+ return;
7489
+ return field.itemType === undefined || field.itemType === "object" ? undefined : field.itemType;
7490
+ }
7435
7491
  function blankItemsFor(field, current, today) {
7492
+ const scalar = scalarItemType(field);
7493
+ if (scalar !== undefined)
7494
+ return [blankFieldValue({ name: field.name, type: scalar })];
7436
7495
  const itemFields = field.fields ?? [];
7437
7496
  if (itemFields.length > 0) {
7438
7497
  return [newRepeaterItem(itemFields.map((item) => ({ ...toWriteModelField(item), required: item.required })), today)];
7439
7498
  }
7440
- if (current.length === 0)
7441
- return [{}, { name: "" }];
7442
7499
  const first = current[0];
7443
- const template = isPlainObject(first) ? Object.fromEntries(Object.keys(first).map((key) => [key, ""])) : {};
7444
- return [{}, template];
7500
+ if (isPlainObject(first))
7501
+ return [{}, Object.fromEntries(Object.keys(first).map((key) => [key, ""]))];
7502
+ if (field.itemType !== "object")
7503
+ return [];
7504
+ return current.length === 0 ? [{}, { name: "" }] : [{}];
7445
7505
  }
7446
7506
  async function checkEditorWrites(input) {
7447
7507
  const findings = [];
@@ -7472,7 +7532,7 @@ async function checkEditorWrites(input) {
7472
7532
  const loaded = input.collections.get(name);
7473
7533
  const entries = loaded?.entries ?? [];
7474
7534
  const kind = loaded ? collectionKind(loaded, collection.loaderPattern) : "markdown";
7475
- const created = applyCreateRouteFields(omitEmptyOnCreate(newEntryFrontmatter(collection.fields.map(toWriteModelField), input.today)), kind, input.today);
7535
+ const created = withoutBlankArrayItems(applyCreateRouteFields(omitEmptyOnCreate(newEntryFrontmatter(collection.fields.map(toWriteModelField))), kind, input.today));
7476
7536
  const guarded = new Set(blankRequiredFields(collection.fields, created));
7477
7537
  const createAction = `Creating a new entry in "${name}"`;
7478
7538
  const createVerdict = await parseWrite(schema, created);
@@ -7486,11 +7546,11 @@ async function checkEditorWrites(input) {
7486
7546
  report(createKey, rejectionFinding(createAction, issue, "create", created));
7487
7547
  }
7488
7548
  }
7489
- const repeaters = collection.fields.filter((field) => field.type === "array" && field.itemType === "object");
7490
- if (repeaters.length === 0)
7549
+ const lists = collection.fields.filter(isListField);
7550
+ if (lists.length === 0)
7491
7551
  continue;
7492
7552
  const seed = await firstAcceptedEntry(schema, entries);
7493
- for (const field of repeaters) {
7553
+ for (const field of lists) {
7494
7554
  const key = `${name} add:${field.name}`;
7495
7555
  if (!seed) {
7496
7556
  const hasEntries = entries.some((entry) => entry.frontmatter !== undefined);
@@ -7509,7 +7569,7 @@ async function checkEditorWrites(input) {
7509
7569
  const existing = Array.isArray(current) ? current : [];
7510
7570
  const action = `Clicking "+ Add" on "${name}.${field.name}"`;
7511
7571
  for (const item of blankItemsFor(field, existing, input.today)) {
7512
- const written = { ...seed, [field.name]: [...existing, item] };
7572
+ const written = withoutBlankArrayItems({ ...seed, [field.name]: [...existing, item] });
7513
7573
  const verdict = await parseWrite(schema, written);
7514
7574
  if ("threw" in verdict) {
7515
7575
  report(key, throwFinding(action, verdict.threw));
@@ -7528,7 +7588,7 @@ var CONFIG_FILE2 = "src/content.config.ts", toWriteModelField = (field) => ({ na
7528
7588
  file: CONFIG_FILE2,
7529
7589
  message: `${action} produces a write the schema throws on: ${threw}`,
7530
7590
  hint: "A schema that throws instead of returning an issue is usually a refinement reading a field this write does not carry. Guard it against a missing value \u2014 `astro sync` runs the same schema over the same record."
7531
- });
7591
+ }), isListField = (field) => field.type === "array" || field.reference?.isArray === true;
7532
7592
  var init_check_write = __esm(() => {
7533
7593
  init_check_entries();
7534
7594
  init_editor_write_model();
@@ -22546,9 +22606,11 @@ function parseConfigSource(source, _sourcePath) {
22546
22606
  });
22547
22607
  continue;
22548
22608
  }
22609
+ const fields = parseSchemaFields(schemaObject, bindings);
22610
+ checkDerivedFromDeclarations(collectionName, fields);
22549
22611
  result.set(collectionName, {
22550
22612
  name: collectionName,
22551
- fields: parseSchemaFields(schemaObject, bindings),
22613
+ fields,
22552
22614
  ...hasSkippedMembers(schemaObject) ? { partialFields: true } : {},
22553
22615
  loaderPattern,
22554
22616
  loaderBase,
@@ -23046,10 +23108,64 @@ function parseFieldLayoutFromObject(obj) {
23046
23108
  if (value.type === "BooleanLiteral")
23047
23109
  layout.hidden = value.value;
23048
23110
  break;
23111
+ case "derivedFrom":
23112
+ parseDerivedFromValue(value, layout);
23113
+ break;
23049
23114
  }
23050
23115
  }
23051
23116
  return Object.keys(layout).length > 0 ? layout : undefined;
23052
23117
  }
23118
+ function parseDerivedFromValue(value, layout) {
23119
+ if (value.type === "StringLiteral") {
23120
+ if (value.value)
23121
+ layout.derivedFrom = value.value;
23122
+ return;
23123
+ }
23124
+ if (value.type !== "ObjectExpression")
23125
+ return;
23126
+ let field;
23127
+ let transform;
23128
+ for (const prop of value.properties) {
23129
+ if (prop.type !== "ObjectProperty")
23130
+ continue;
23131
+ const key = propertyKeyName(prop.key);
23132
+ if (prop.value.type !== "StringLiteral")
23133
+ continue;
23134
+ if (key === "field")
23135
+ field = prop.value.value;
23136
+ else if (key === "transform" && isDerivedTransform(prop.value.value))
23137
+ transform = prop.value.value;
23138
+ }
23139
+ if (!field)
23140
+ return;
23141
+ layout.derivedFrom = field;
23142
+ if (transform)
23143
+ layout.derivedTransform = transform;
23144
+ }
23145
+ function checkDerivedFromDeclarations(collectionName, fields) {
23146
+ const siblingNames = new Set(fields.map((f) => f.name));
23147
+ for (const field of fields) {
23148
+ const source = field.layout?.derivedFrom;
23149
+ if (source !== undefined && !siblingNames.has(source)) {
23150
+ console.warn(`[cms] collection "${collectionName}": field "${field.name}" derives from "${source}", which is not a field of this collection` + ` \u2014 the field is hidden and nothing is ever computed for it`);
23151
+ }
23152
+ dropNestedDerivedFrom(collectionName, field.name, field.fields);
23153
+ }
23154
+ }
23155
+ function dropNestedDerivedFrom(collectionName, path2, fields) {
23156
+ if (!fields)
23157
+ return;
23158
+ for (const field of fields) {
23159
+ const fieldPath = `${path2}.${field.name}`;
23160
+ const layout = field.layout;
23161
+ if (layout?.derivedFrom !== undefined) {
23162
+ console.warn(`[cms] collection "${collectionName}": field "${fieldPath}" declares \`derivedFrom\` on a nested field, which is not supported` + ` \u2014 only top-level fields derive, so the declaration is ignored and the field stays editable`);
23163
+ delete layout.derivedFrom;
23164
+ delete layout.derivedTransform;
23165
+ }
23166
+ dropNestedDerivedFrom(collectionName, fieldPath, field.fields);
23167
+ }
23168
+ }
23053
23169
  var import_parser, FIELD_HELPER_TYPES, VALID_HINT_KEYS, WRAPPER_METHODS;
23054
23170
  var init_content_config_ast = __esm(() => {
23055
23171
  init_src();
@@ -23808,6 +23924,14 @@ function applyParsedFieldLayout(field, pf) {
23808
23924
  field.order = layout.order;
23809
23925
  if (layout.sidebar)
23810
23926
  field.position = "sidebar";
23927
+ if (layout.derivedFrom) {
23928
+ field.derivedFrom = layout.derivedFrom;
23929
+ field.derivedDeclared = true;
23930
+ if (layout.derivedTransform)
23931
+ field.derivedTransform = layout.derivedTransform;
23932
+ field.hidden = layout.hidden ?? true;
23933
+ return;
23934
+ }
23811
23935
  if (layout.hidden)
23812
23936
  field.hidden = true;
23813
23937
  }