@nuasite/cli 0.46.5 → 0.47.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
@@ -22383,15 +22383,21 @@ var require_lib = __commonJS((exports) => {
22383
22383
  });
22384
22384
 
22385
22385
  // ../cms-types/src/index.ts
22386
- var init_src = () => {};
22387
-
22388
- // ../cms-core/src/content-config-ast.ts
22389
- var import_parser, FIELD_HELPER_TYPES, VALID_HINT_KEYS, WRAPPER_METHODS;
22390
- var init_content_config_ast = __esm(() => {
22391
- init_src();
22392
- import_parser = __toESM(require_lib(), 1);
22393
- FIELD_HELPER_TYPES = new Set([
22386
+ function isFieldType(value) {
22387
+ return FIELD_TYPES.includes(value);
22388
+ }
22389
+ var FIELD_TYPES;
22390
+ var init_src = __esm(() => {
22391
+ FIELD_TYPES = [
22394
22392
  "text",
22393
+ "textarea",
22394
+ "markdown",
22395
+ "date",
22396
+ "datetime",
22397
+ "time",
22398
+ "year",
22399
+ "month",
22400
+ "boolean",
22395
22401
  "number",
22396
22402
  "image",
22397
22403
  "file",
@@ -22399,323 +22405,14 @@ var init_content_config_ast = __esm(() => {
22399
22405
  "email",
22400
22406
  "tel",
22401
22407
  "color",
22402
- "date",
22403
- "datetime",
22404
- "time",
22405
- "year",
22406
- "month",
22407
- "textarea",
22408
- "markdown"
22409
- ]);
22410
- VALID_HINT_KEYS = new Set([
22411
- "min",
22412
- "max",
22413
- "step",
22414
- "placeholder",
22415
- "maxLength",
22416
- "minLength",
22417
- "rows",
22418
- "accept"
22419
- ]);
22420
- WRAPPER_METHODS = new Set(["optional", "nullable", "nullish", "default"]);
22421
- });
22422
- // ../cms-core/src/collection-scanner.ts
22423
- var import_yaml, SIDEBAR_FIELD_NAMES, FREE_TEXT_FIELD_NAMES, PUBLISH_TOGGLE_NAMES, PUBLISH_DATE_NAMES;
22424
- var init_collection_scanner = __esm(() => {
22425
- init_content_config_ast();
22426
- import_yaml = __toESM(require_dist(), 1);
22427
- SIDEBAR_FIELD_NAMES = new Set([
22428
- "title",
22429
- "date",
22430
- "pubdate",
22431
- "publishdate",
22432
- "draft",
22433
- "image",
22434
- "featuredimage",
22435
- "cover",
22436
- "coverimage",
22437
- "thumbnail",
22438
- "author"
22439
- ]);
22440
- FREE_TEXT_FIELD_NAMES = new Set([
22441
- "title",
22442
- "name",
22443
- "description",
22444
- "summary",
22445
- "excerpt",
22446
- "subtitle",
22447
- "heading",
22448
- "headline",
22449
- "slug",
22450
- "alt",
22451
- "caption"
22452
- ]);
22453
- PUBLISH_TOGGLE_NAMES = new Set(["draft", "isdraft", "published", "ispublished", "unpublished"]);
22454
- PUBLISH_DATE_NAMES = new Set([
22455
- "date",
22456
- "pubdate",
22457
- "publishdate",
22458
- "publisheddate",
22459
- "publishedate",
22460
- "publishedat",
22461
- "datepublished"
22462
- ]);
22463
- });
22464
-
22465
- // ../cms-core/src/component-registry.ts
22466
- var import_parser2;
22467
- var init_component_registry = __esm(() => {
22468
- import_parser2 = __toESM(require_lib(), 1);
22469
- });
22470
-
22471
- // ../cms-core/src/media/local.ts
22472
- function mimeFromExt(ext) {
22473
- return MIME_BY_EXT[ext] ?? "application/octet-stream";
22474
- }
22475
- var MIME_BY_EXT;
22476
- var init_local = __esm(() => {
22477
- MIME_BY_EXT = {
22478
- ".jpg": "image/jpeg",
22479
- ".jpeg": "image/jpeg",
22480
- ".png": "image/png",
22481
- ".gif": "image/gif",
22482
- ".webp": "image/webp",
22483
- ".avif": "image/avif",
22484
- ".svg": "image/svg+xml",
22485
- ".ico": "image/x-icon",
22486
- ".mp4": "video/mp4",
22487
- ".webm": "video/webm",
22488
- ".pdf": "application/pdf"
22489
- };
22490
- });
22491
-
22492
- // ../cms-core/src/handlers/entry-ops.ts
22493
- var import_yaml2;
22494
- var init_entry_ops = __esm(() => {
22495
- init_collection_scanner();
22496
- init_content_config_ast();
22497
- init_local();
22498
- import_yaml2 = __toESM(require_dist(), 1);
22499
- });
22500
-
22501
- // ../cms-core/src/handlers/page-ops.ts
22502
- var init_page_ops = () => {};
22503
- // ../cms-core/src/core.ts
22504
- var init_core = __esm(() => {
22505
- init_collection_scanner();
22506
- init_component_registry();
22507
- init_entry_ops();
22508
- init_page_ops();
22509
- });
22510
- // ../cms-core/src/fs/node-fs.ts
22511
- var init_node_fs = () => {};
22512
- // ../cms-core/src/media/project-images.ts
22513
- async function listProjectImages(fs, options) {
22514
- const excludeDir = options?.excludeDir ? normalizeDir(options.excludeDir) : null;
22515
- const scanDirs = [
22516
- { dir: "public", relativeToRoot: false },
22517
- { dir: "src", relativeToRoot: true }
22408
+ "select",
22409
+ "array",
22410
+ "object",
22411
+ "reference"
22518
22412
  ];
22519
- const results = await Promise.all(scanDirs.map(async ({ dir, relativeToRoot }) => {
22520
- const items2 = [];
22521
- await scanDirectory(fs, dir, dir, relativeToRoot, excludeDir, items2);
22522
- return items2;
22523
- }));
22524
- const items = results.flat();
22525
- items.sort((a, b) => a.filename.localeCompare(b.filename));
22526
- return items;
22527
- }
22528
- function normalizeDir(dir) {
22529
- return dir.replace(/^\/+/, "").replace(/\/+$/, "");
22530
- }
22531
- async function scanDirectory(fs, currentDir, baseDir, relativeToRoot, excludeDir, items) {
22532
- if (excludeDir && normalizeDir(currentDir) === excludeDir)
22533
- return;
22534
- const entries = await fs.list(currentDir);
22535
- const subdirs = [];
22536
- for (const entry of entries) {
22537
- if (entry.name.startsWith(".") || entry.name === "node_modules")
22538
- continue;
22539
- const fullPath = `${currentDir}/${entry.name}`;
22540
- if (entry.isDirectory) {
22541
- subdirs.push(scanDirectory(fs, fullPath, baseDir, relativeToRoot, excludeDir, items));
22542
- } else {
22543
- const dotIdx = entry.name.lastIndexOf(".");
22544
- const ext = dotIdx >= 0 ? entry.name.slice(dotIdx).toLowerCase() : "";
22545
- if (!IMAGE_EXTENSIONS.has(ext))
22546
- continue;
22547
- const url = relativeToRoot ? `/${fullPath}` : `/${fullPath.slice(baseDir.length + 1)}`;
22548
- items.push({
22549
- id: `project:${url}`,
22550
- url,
22551
- filename: entry.name,
22552
- contentType: mimeFromExt(ext)
22553
- });
22554
- }
22555
- }
22556
- await Promise.all(subdirs);
22557
- }
22558
- var IMAGE_EXTENSIONS;
22559
- var init_project_images = __esm(() => {
22560
- init_local();
22561
- IMAGE_EXTENSIONS = new Set(Object.entries(MIME_BY_EXT).filter(([, mime]) => mime.startsWith("image/")).map(([ext]) => ext));
22562
- });
22563
-
22564
- // ../cms-core/src/media/s3.ts
22565
- var init_s3 = __esm(() => {
22566
- init_local();
22567
- });
22568
-
22569
- // ../cms-core/src/media/index.ts
22570
- var init_media = __esm(() => {
22571
- init_local();
22572
- init_project_images();
22573
- init_s3();
22574
- });
22575
-
22576
- // ../cms-core/src/project-config-ast.ts
22577
- var import_parser3;
22578
- var init_project_config_ast = __esm(() => {
22579
- import_parser3 = __toESM(require_lib(), 1);
22580
- });
22581
-
22582
- // ../cms-core/src/index.ts
22583
- var init_src2 = __esm(() => {
22584
- init_collection_scanner();
22585
- init_component_registry();
22586
- init_content_config_ast();
22587
- init_core();
22588
- init_node_fs();
22589
- init_entry_ops();
22590
- init_media();
22591
- init_project_config_ast();
22592
- });
22593
-
22594
- // ../cms/src/config.ts
22595
- function getProjectRoot() {
22596
- return projectRootOverride ?? process.cwd();
22597
- }
22598
- var projectRootOverride = null;
22599
- var init_config = () => {};
22600
-
22601
- // ../../node_modules/@astrojs/compiler/dist/chunk-W5DTLHV4.js
22602
- import g from "crypto";
22603
- import _ from "fs";
22604
- import { TextDecoder as b, TextEncoder as v } from "util";
22605
- var y, w;
22606
- var init_chunk_W5DTLHV4 = __esm(() => {
22607
- globalThis.fs || Object.defineProperty(globalThis, "fs", { value: _ });
22608
- globalThis.process || Object.defineProperties(globalThis, "process", { value: process });
22609
- globalThis.crypto || Object.defineProperty(globalThis, "crypto", { value: g.webcrypto ? g.webcrypto : { getRandomValues(m) {
22610
- return g.randomFillSync(m);
22611
- } } });
22612
- globalThis.performance || Object.defineProperty(globalThis, "performance", { value: { now() {
22613
- let [m, o] = process.hrtime();
22614
- return m * 1000 + o / 1e6;
22615
- } } });
22616
- y = new v("utf-8");
22617
- w = new b("utf-8");
22618
- });
22619
-
22620
- // ../../node_modules/@astrojs/compiler/dist/node/index.js
22621
- var init_node = __esm(() => {
22622
- init_chunk_W5DTLHV4();
22623
- });
22624
-
22625
- // ../cms/src/error-collector.ts
22626
- class ErrorCollector {
22627
- errors = [];
22628
- warnings = [];
22629
- addError(context, error) {
22630
- this.errors.push({ context, error });
22631
- }
22632
- addWarning(context, message) {
22633
- this.warnings.push({ context, message });
22634
- }
22635
- hasErrors() {
22636
- return this.errors.length > 0;
22637
- }
22638
- hasWarnings() {
22639
- return this.warnings.length > 0;
22640
- }
22641
- getErrors() {
22642
- return this.errors;
22643
- }
22644
- getWarnings() {
22645
- return this.warnings;
22646
- }
22647
- getSummary() {
22648
- const lines = [];
22649
- if (this.errors.length > 0) {
22650
- lines.push(`${this.errors.length} error(s):`);
22651
- for (const { context, error } of this.errors) {
22652
- lines.push(` - ${context}: ${error.message}`);
22653
- }
22654
- }
22655
- if (this.warnings.length > 0) {
22656
- lines.push(`${this.warnings.length} warning(s):`);
22657
- for (const { context, message } of this.warnings) {
22658
- lines.push(` - ${context}: ${message}`);
22659
- }
22660
- }
22661
- return lines.join(`
22662
- `);
22663
- }
22664
- clear() {
22665
- this.errors = [];
22666
- this.warnings = [];
22667
- }
22668
- }
22669
- function getErrorCollector() {
22670
- if (!globalErrorCollector) {
22671
- globalErrorCollector = new ErrorCollector;
22672
- }
22673
- return globalErrorCollector;
22674
- }
22675
- var globalErrorCollector = null;
22676
-
22677
- // ../cms/src/source-finder/cache.ts
22678
- var parsedFileCache, directoryCache, markdownFileCache, declaredUrlIndexCache, dirtyFiles;
22679
- var init_cache = __esm(() => {
22680
- parsedFileCache = new Map;
22681
- directoryCache = new Map;
22682
- markdownFileCache = new Map;
22683
- declaredUrlIndexCache = new Map;
22684
- dirtyFiles = new Set;
22685
- });
22686
- // ../cms/src/source-finder/variable-extraction.ts
22687
- var import_parser4;
22688
- var init_variable_extraction = __esm(() => {
22689
- import_parser4 = __toESM(require_lib(), 1);
22690
- });
22691
-
22692
- // ../cms/src/source-finder/ast-parser.ts
22693
- function parseFrontmatter2(content, filePath) {
22694
- try {
22695
- return import_parser5.parse(content, {
22696
- sourceType: "module",
22697
- plugins: ["typescript"],
22698
- errorRecovery: true
22699
- });
22700
- } catch (error) {
22701
- if (filePath) {
22702
- getErrorCollector().addWarning(`Frontmatter parse: ${filePath}`, error instanceof Error ? error.message : String(error));
22703
- }
22704
- return null;
22705
- }
22706
- }
22707
- var import_parser5, inFlightParsing;
22708
- var init_ast_parser = __esm(() => {
22709
- init_node();
22710
- init_cache();
22711
- init_variable_extraction();
22712
- import_parser5 = __toESM(require_lib(), 1);
22713
- inFlightParsing = new Map;
22714
22413
  });
22715
22414
 
22716
- // ../cms/src/content-config-ast.ts
22717
- import fs from "fs/promises";
22718
- import path from "path";
22415
+ // ../cms-core/src/content-config-ast.ts
22719
22416
  function resolveExpression(node, bindings, visited = new Set) {
22720
22417
  let current = node;
22721
22418
  while (current.type === "Identifier") {
@@ -22729,33 +22426,42 @@ function resolveExpression(node, bindings, visited = new Set) {
22729
22426
  }
22730
22427
  return current;
22731
22428
  }
22732
- async function parseContentConfig2() {
22733
- const projectRoot = getProjectRoot();
22429
+ function parseSource(source) {
22430
+ try {
22431
+ return import_parser.parse(source, {
22432
+ sourceType: "module",
22433
+ plugins: ["typescript"],
22434
+ errorRecovery: true
22435
+ });
22436
+ } catch {
22437
+ return null;
22438
+ }
22439
+ }
22440
+ async function parseContentConfig(fs, cache) {
22734
22441
  for (const configPath of ["src/content/config.ts", "src/content.config.ts"]) {
22735
- const fullPath = path.join(projectRoot, configPath);
22736
22442
  let stat;
22737
22443
  try {
22738
- stat = await fs.stat(fullPath);
22444
+ stat = await fs.stat(configPath);
22739
22445
  } catch {
22740
22446
  continue;
22741
22447
  }
22742
- const cached = parseCache.get(fullPath);
22448
+ const cached = cache.get(configPath);
22743
22449
  if (cached && cached.mtimeMs === stat.mtimeMs) {
22744
22450
  if (cached.parsed.size > 0)
22745
22451
  return cached.parsed;
22746
22452
  continue;
22747
22453
  }
22748
- const content = await fs.readFile(fullPath, "utf-8");
22749
- const parsed = parseConfigSource2(content, configPath);
22750
- parseCache.set(fullPath, { mtimeMs: stat.mtimeMs, parsed });
22454
+ const content = await fs.readFile(configPath);
22455
+ const parsed = parseConfigSource(content, configPath);
22456
+ cache.set(configPath, { mtimeMs: stat.mtimeMs, parsed });
22751
22457
  if (parsed.size > 0)
22752
22458
  return parsed;
22753
22459
  }
22754
22460
  return new Map;
22755
22461
  }
22756
- function parseConfigSource2(source, sourcePath) {
22462
+ function parseConfigSource(source, _sourcePath) {
22757
22463
  const result = new Map;
22758
- const ast = parseFrontmatter2(source, sourcePath);
22464
+ const ast = parseSource(source);
22759
22465
  if (!ast)
22760
22466
  return result;
22761
22467
  const bindings = new Map;
@@ -22806,18 +22512,23 @@ function parseConfigSource2(source, sourcePath) {
22806
22512
  }
22807
22513
  for (const [collectionName, decl] of collectionObjects) {
22808
22514
  const loaderProperty = decl.properties.find((p) => p.type === "ObjectProperty" && propertyKeyName(p.key) === "loader");
22809
- const loaderOptions = loaderProperty ? extractGlobLoaderOptions(loaderProperty.value, bindings) : {};
22515
+ const loaderOptions = loaderProperty?.type === "ObjectProperty" ? extractGlobLoaderOptions(loaderProperty.value, bindings) : {};
22810
22516
  const loaderPattern = loaderOptions.pattern;
22811
22517
  const loaderBase = loaderOptions.base;
22518
+ const cmsProperty = decl.properties.find((p) => p.type === "ObjectProperty" && propertyKeyName(p.key) === "cms");
22519
+ const layout = cmsProperty?.type === "ObjectProperty" ? parseCmsLayout(cmsProperty.value, bindings) : undefined;
22520
+ const pathname = cmsProperty?.type === "ObjectProperty" ? parseCmsPathname(cmsProperty.value, bindings) : undefined;
22812
22521
  const schemaProperty = decl.properties.find((p) => p.type === "ObjectProperty" && propertyKeyName(p.key) === "schema");
22813
- if (!schemaProperty) {
22522
+ if (!schemaProperty || schemaProperty.type !== "ObjectProperty") {
22814
22523
  if (!loaderPattern)
22815
22524
  continue;
22816
22525
  result.set(collectionName, {
22817
22526
  name: collectionName,
22818
22527
  fields: [],
22819
22528
  loaderPattern,
22820
- loaderBase
22529
+ loaderBase,
22530
+ layout,
22531
+ pathname
22821
22532
  });
22822
22533
  continue;
22823
22534
  }
@@ -22829,7 +22540,9 @@ function parseConfigSource2(source, sourcePath) {
22829
22540
  name: collectionName,
22830
22541
  fields: [],
22831
22542
  loaderPattern,
22832
- loaderBase
22543
+ loaderBase,
22544
+ layout,
22545
+ pathname
22833
22546
  });
22834
22547
  continue;
22835
22548
  }
@@ -22837,13 +22550,126 @@ function parseConfigSource2(source, sourcePath) {
22837
22550
  name: collectionName,
22838
22551
  fields: parseSchemaFields(schemaObject, bindings),
22839
22552
  loaderPattern,
22840
- loaderBase
22553
+ loaderBase,
22554
+ layout,
22555
+ pathname
22841
22556
  });
22842
22557
  }
22843
22558
  return result;
22844
22559
  }
22560
+ function parseCmsLayout(node, bindings) {
22561
+ const resolved = resolveExpression(node, bindings);
22562
+ if (resolved.type !== "ObjectExpression")
22563
+ return;
22564
+ const layout = {};
22565
+ for (const prop of resolved.properties) {
22566
+ if (prop.type !== "ObjectProperty")
22567
+ continue;
22568
+ const key = propertyKeyName(prop.key);
22569
+ const value = resolveExpression(prop.value, bindings);
22570
+ if (key === "display") {
22571
+ if (value.type === "StringLiteral" && (value.value === "tabs" || value.value === "sections"))
22572
+ layout.display = value.value;
22573
+ } else if (key === "sidebar") {
22574
+ if (value.type === "ArrayExpression")
22575
+ layout.sidebar = stringArray(value);
22576
+ } else if (key === "sections") {
22577
+ if (value.type === "ArrayExpression") {
22578
+ const sections = value.elements.map((el) => el && el.type !== "SpreadElement" ? parseLayoutSection(resolveExpression(el, bindings)) : null).filter((s) => s !== null);
22579
+ if (sections.length > 0)
22580
+ layout.sections = sections;
22581
+ }
22582
+ }
22583
+ }
22584
+ return Object.keys(layout).length > 0 ? layout : undefined;
22585
+ }
22586
+ function parseLayoutSection(node) {
22587
+ if (node.type !== "ObjectExpression")
22588
+ return null;
22589
+ let title;
22590
+ let fields = [];
22591
+ let collapsed = false;
22592
+ for (const prop of node.properties) {
22593
+ if (prop.type !== "ObjectProperty")
22594
+ continue;
22595
+ const key = propertyKeyName(prop.key);
22596
+ if (key === "title" && prop.value.type === "StringLiteral")
22597
+ title = prop.value.value;
22598
+ else if (key === "fields" && prop.value.type === "ArrayExpression")
22599
+ fields = stringArray(prop.value);
22600
+ else if (key === "collapsed" && prop.value.type === "BooleanLiteral")
22601
+ collapsed = prop.value.value;
22602
+ }
22603
+ if (title === undefined || fields.length === 0)
22604
+ return null;
22605
+ return collapsed ? { title, fields, collapsed } : { title, fields };
22606
+ }
22607
+ function stringArray(node) {
22608
+ const out = [];
22609
+ for (const el of node.elements) {
22610
+ if (el?.type === "StringLiteral")
22611
+ out.push(el.value);
22612
+ }
22613
+ return out;
22614
+ }
22845
22615
  function isDefineCollectionCallee(callee) {
22846
- return callee.type === "Identifier" && callee.name === "defineCollection";
22616
+ return callee.type === "Identifier" && (callee.name === "defineCollection" || callee.name === "defineCmsCollection");
22617
+ }
22618
+ function parseCmsPathname(node, bindings) {
22619
+ const resolved = resolveExpression(node, bindings);
22620
+ if (resolved.type !== "ObjectExpression")
22621
+ return;
22622
+ const pathnameProp = resolved.properties.find((p) => p.type === "ObjectProperty" && propertyKeyName(p.key) === "pathname");
22623
+ if (!pathnameProp || pathnameProp.type !== "ObjectProperty")
22624
+ return;
22625
+ const arr = resolveExpression(pathnameProp.value, bindings);
22626
+ if (arr.type !== "ArrayExpression")
22627
+ return;
22628
+ const spec = [];
22629
+ for (const el of arr.elements) {
22630
+ if (!el || el.type === "SpreadElement")
22631
+ continue;
22632
+ const segment = parsePathnameSegment(resolveExpression(el, bindings));
22633
+ if (segment)
22634
+ spec.push(segment);
22635
+ }
22636
+ return spec.length > 0 ? spec : undefined;
22637
+ }
22638
+ function parsePathnameSegment(node) {
22639
+ if (node.type !== "ObjectExpression")
22640
+ return null;
22641
+ let field;
22642
+ let literal;
22643
+ let map;
22644
+ for (const prop of node.properties) {
22645
+ if (prop.type !== "ObjectProperty")
22646
+ continue;
22647
+ const key = propertyKeyName(prop.key);
22648
+ if (key === "field" && prop.value.type === "StringLiteral")
22649
+ field = prop.value.value;
22650
+ else if (key === "literal" && prop.value.type === "StringLiteral")
22651
+ literal = prop.value.value;
22652
+ else if (key === "map" && prop.value.type === "ObjectExpression")
22653
+ map = parseStringRecord(prop.value);
22654
+ }
22655
+ if (literal !== undefined)
22656
+ return { literal };
22657
+ if (field !== undefined)
22658
+ return map ? { field, map } : { field };
22659
+ return null;
22660
+ }
22661
+ function parseStringRecord(node) {
22662
+ const out = {};
22663
+ for (const prop of node.properties) {
22664
+ if (prop.type !== "ObjectProperty")
22665
+ continue;
22666
+ const key = propertyKeyName(prop.key);
22667
+ if (key === null)
22668
+ continue;
22669
+ if (prop.value.type === "StringLiteral")
22670
+ out[key] = prop.value.value;
22671
+ }
22672
+ return Object.keys(out).length > 0 ? out : undefined;
22847
22673
  }
22848
22674
  function propertyKeyName(key) {
22849
22675
  if (key.type === "Identifier")
@@ -22943,7 +22769,7 @@ function analyzeFieldExpression(node, field, bindings) {
22943
22769
  return;
22944
22770
  const property = current.callee.property;
22945
22771
  const methodName = property.type === "Identifier" ? property.name : "";
22946
- if (WRAPPER_METHODS2.has(methodName)) {
22772
+ if (WRAPPER_METHODS.has(methodName)) {
22947
22773
  field.required = false;
22948
22774
  } else if (methodName === "orderBy") {
22949
22775
  const arg = current.arguments[0];
@@ -22986,13 +22812,16 @@ function analyzeBaseCall(node, field, bindings) {
22986
22812
  return;
22987
22813
  const ns = callee.object.name;
22988
22814
  const fn = callee.property.name;
22989
- if (ns === "n" && FIELD_HELPER_TYPES2.has(fn)) {
22815
+ if (ns === "n" && FIELD_HELPER_TYPES.has(fn) && isFieldType(fn)) {
22990
22816
  field.type = fn;
22991
22817
  const firstArg = node.arguments[0];
22992
22818
  if (firstArg?.type === "ObjectExpression") {
22993
22819
  const hints = parseHintsFromObject(firstArg);
22994
22820
  if (hints)
22995
22821
  field.hints = hints;
22822
+ const layout = parseFieldLayoutFromObject(firstArg);
22823
+ if (layout)
22824
+ field.layout = layout;
22996
22825
  }
22997
22826
  return;
22998
22827
  }
@@ -23050,26 +22879,89 @@ function parseHintsFromObject(obj) {
23050
22879
  if (prop.type !== "ObjectProperty")
23051
22880
  continue;
23052
22881
  const key = propertyKeyName(prop.key);
23053
- if (!key || !VALID_HINT_KEYS2.has(key))
22882
+ if (!key || !VALID_HINT_KEYS.has(key))
23054
22883
  continue;
23055
22884
  const value = prop.value;
23056
22885
  if (value.type === "NumericLiteral") {
23057
- raw[key] = value.value;
22886
+ assignHint(raw, key, value.value);
23058
22887
  } else if (value.type === "UnaryExpression" && value.operator === "-" && value.argument.type === "NumericLiteral") {
23059
- raw[key] = -value.argument.value;
22888
+ assignHint(raw, key, -value.argument.value);
23060
22889
  } else if (value.type === "StringLiteral") {
23061
- raw[key] = value.value;
22890
+ assignHint(raw, key, value.value);
23062
22891
  }
23063
22892
  }
23064
22893
  if (Object.keys(raw).length === 0)
23065
22894
  return;
23066
22895
  return raw;
23067
22896
  }
23068
- var FIELD_HELPER_TYPES2, VALID_HINT_KEYS2, WRAPPER_METHODS2, parseCache;
23069
- var init_content_config_ast2 = __esm(() => {
23070
- init_config();
23071
- init_ast_parser();
23072
- FIELD_HELPER_TYPES2 = new Set([
22897
+ function assignHint(hints, key, value) {
22898
+ switch (key) {
22899
+ case "min":
22900
+ case "max":
22901
+ hints[key] = value;
22902
+ return;
22903
+ case "step":
22904
+ case "maxLength":
22905
+ case "minLength":
22906
+ case "rows":
22907
+ if (typeof value === "number")
22908
+ hints[key] = value;
22909
+ return;
22910
+ case "placeholder":
22911
+ case "accept":
22912
+ if (typeof value === "string")
22913
+ hints[key] = value;
22914
+ return;
22915
+ }
22916
+ }
22917
+ function parseFieldLayoutFromObject(obj) {
22918
+ const layout = {};
22919
+ for (const prop of obj.properties) {
22920
+ if (prop.type !== "ObjectProperty")
22921
+ continue;
22922
+ const key = propertyKeyName(prop.key);
22923
+ const value = prop.value;
22924
+ switch (key) {
22925
+ case "label":
22926
+ if (value.type === "StringLiteral")
22927
+ layout.label = value.value;
22928
+ break;
22929
+ case "help":
22930
+ if (value.type === "StringLiteral")
22931
+ layout.help = value.value;
22932
+ break;
22933
+ case "group":
22934
+ if (value.type === "StringLiteral")
22935
+ layout.group = value.value;
22936
+ break;
22937
+ case "width":
22938
+ if (value.type === "StringLiteral" && (value.value === "full" || value.value === "half"))
22939
+ layout.width = value.value;
22940
+ break;
22941
+ case "order":
22942
+ if (value.type === "NumericLiteral") {
22943
+ layout.order = value.value;
22944
+ } else if (value.type === "UnaryExpression" && value.operator === "-" && value.argument.type === "NumericLiteral") {
22945
+ layout.order = -value.argument.value;
22946
+ }
22947
+ break;
22948
+ case "sidebar":
22949
+ if (value.type === "BooleanLiteral")
22950
+ layout.sidebar = value.value;
22951
+ break;
22952
+ case "hidden":
22953
+ if (value.type === "BooleanLiteral")
22954
+ layout.hidden = value.value;
22955
+ break;
22956
+ }
22957
+ }
22958
+ return Object.keys(layout).length > 0 ? layout : undefined;
22959
+ }
22960
+ var import_parser, FIELD_HELPER_TYPES, VALID_HINT_KEYS, WRAPPER_METHODS;
22961
+ var init_content_config_ast = __esm(() => {
22962
+ init_src();
22963
+ import_parser = __toESM(require_lib(), 1);
22964
+ FIELD_HELPER_TYPES = new Set([
23073
22965
  "text",
23074
22966
  "number",
23075
22967
  "image",
@@ -23083,9 +22975,10 @@ var init_content_config_ast2 = __esm(() => {
23083
22975
  "time",
23084
22976
  "year",
23085
22977
  "month",
23086
- "textarea"
22978
+ "textarea",
22979
+ "markdown"
23087
22980
  ]);
23088
- VALID_HINT_KEYS2 = new Set([
22981
+ VALID_HINT_KEYS = new Set([
23089
22982
  "min",
23090
22983
  "max",
23091
22984
  "step",
@@ -23095,21 +22988,45 @@ var init_content_config_ast2 = __esm(() => {
23095
22988
  "rows",
23096
22989
  "accept"
23097
22990
  ]);
23098
- WRAPPER_METHODS2 = new Set(["optional", "nullable", "nullish", "default"]);
23099
- parseCache = new Map;
22991
+ WRAPPER_METHODS = new Set(["optional", "nullable", "nullish", "default"]);
23100
22992
  });
23101
22993
 
23102
- // ../cms/src/shared.ts
23103
- function slugify2(text) {
23104
- return text.toLowerCase().trim().replace(/[^\w\s\-/]/g, "").replace(/[\s_]+/g, "-").replace(/^[-/]+|[-/]+$/g, "");
22994
+ // ../cms-core/src/shared.ts
22995
+ function pathSegmentValue(raw) {
22996
+ if (typeof raw === "string")
22997
+ return raw;
22998
+ if (typeof raw === "number" || typeof raw === "boolean")
22999
+ return String(raw);
23000
+ if (raw instanceof Date)
23001
+ return raw.toISOString().slice(0, 10);
23002
+ return;
23003
+ }
23004
+ function computePathnameFromSpec(spec, data) {
23005
+ const segments = [];
23006
+ for (const seg of spec) {
23007
+ if ("literal" in seg) {
23008
+ segments.push(seg.literal);
23009
+ continue;
23010
+ }
23011
+ const value = pathSegmentValue(data[seg.field]);
23012
+ if (value === undefined)
23013
+ return;
23014
+ segments.push(seg.map && Object.hasOwn(seg.map, value) ? seg.map[value] : value);
23015
+ }
23016
+ const path = ("/" + segments.join("/")).replace(/\/{2,}/g, "/").replace(/\/+$/, "");
23017
+ return path === "" ? "/" : path;
23018
+ }
23019
+ function resolvePathnameFromSpec(def, data) {
23020
+ if (!def.pathname)
23021
+ return;
23022
+ return computePathnameFromSpec(def.pathname, data ?? {});
23105
23023
  }
23106
- function slugifyHref2(text) {
23024
+ function slugifyHref(text) {
23107
23025
  return "/" + text.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_]+/g, "-").replace(/^-+|-+$/g, "");
23108
23026
  }
23109
23027
 
23110
- // ../cms/src/collection-scanner.ts
23111
- import fs2 from "fs/promises";
23112
- import path2 from "path";
23028
+ // ../cms-core/src/collection-scanner.ts
23029
+ import path from "path";
23113
23030
  function normalizeFieldName(name) {
23114
23031
  return name.toLowerCase().replace(/[_-]/g, "");
23115
23032
  }
@@ -23117,22 +23034,22 @@ function extractFrontmatterBlock(content) {
23117
23034
  const match = content.match(FRONTMATTER_PATTERN);
23118
23035
  return match?.[1] ?? null;
23119
23036
  }
23120
- function parseFrontmatter3(content) {
23037
+ function parseFrontmatter(content) {
23121
23038
  const block = extractFrontmatterBlock(content);
23122
23039
  if (!block)
23123
23040
  return null;
23124
- return import_yaml3.parse(block);
23041
+ return import_yaml.parse(block);
23125
23042
  }
23126
23043
  function parseFieldDirectives(content) {
23127
23044
  const block = extractFrontmatterBlock(content);
23128
23045
  if (!block)
23129
23046
  return {};
23130
- const doc = import_yaml3.parseDocument(block);
23131
- if (!import_yaml3.isMap(doc.contents))
23047
+ const doc = import_yaml.parseDocument(block);
23048
+ if (!import_yaml.isMap(doc.contents))
23132
23049
  return {};
23133
23050
  const result = {};
23134
23051
  for (const pair of doc.contents.items) {
23135
- if (!import_yaml3.isPair(pair) || !import_yaml3.isScalar(pair.key))
23052
+ if (!import_yaml.isPair(pair) || !import_yaml.isScalar(pair.key))
23136
23053
  continue;
23137
23054
  const comment = pair.key.commentBefore;
23138
23055
  if (!comment)
@@ -23158,7 +23075,7 @@ function parseFieldDirectives(content) {
23158
23075
  }
23159
23076
  function assignFieldMetadata(fields, directives) {
23160
23077
  for (const field of fields) {
23161
- if (SIDEBAR_FIELD_NAMES2.has(normalizeFieldName(field.name)) || field.type === "image" || field.type === "boolean") {
23078
+ if (SIDEBAR_FIELD_NAMES.has(normalizeFieldName(field.name)) || field.type === "image" || field.type === "boolean") {
23162
23079
  field.position = "sidebar";
23163
23080
  } else {
23164
23081
  field.position = "header";
@@ -23192,7 +23109,7 @@ function inferFieldType(value, key) {
23192
23109
  if (DATE_PATTERN.test(value)) {
23193
23110
  return "date";
23194
23111
  }
23195
- if (IMAGE_EXTENSIONS2.test(value)) {
23112
+ if (IMAGE_EXTENSIONS.test(value)) {
23196
23113
  return "image";
23197
23114
  }
23198
23115
  const lowerKey = key.toLowerCase();
@@ -23215,7 +23132,7 @@ function mergeFieldObservations(observations, depth = 0) {
23215
23132
  return [];
23216
23133
  const fields = [];
23217
23134
  for (const obs of observations) {
23218
- const nonNullValues = obs.values.filter((v2) => v2 !== null && v2 !== undefined);
23135
+ const nonNullValues = obs.values.filter((v) => v !== null && v !== undefined);
23219
23136
  if (nonNullValues.length === 0)
23220
23137
  continue;
23221
23138
  const typeCounts = new Map;
@@ -23237,8 +23154,8 @@ function mergeFieldObservations(observations, depth = 0) {
23237
23154
  required: obs.presentCount === obs.totalEntries,
23238
23155
  examples: nonNullValues.slice(0, 3)
23239
23156
  };
23240
- if (fieldType === "text" && !FREE_TEXT_FIELD_NAMES2.has(normalizeFieldName(obs.name))) {
23241
- const uniqueValues = [...new Set(nonNullValues.map((v2) => String(v2)))];
23157
+ if (fieldType === "text" && !FREE_TEXT_FIELD_NAMES.has(normalizeFieldName(obs.name))) {
23158
+ const uniqueValues = [...new Set(nonNullValues.map((v) => String(v)))];
23242
23159
  const uniqueRatio = uniqueValues.length / nonNullValues.length;
23243
23160
  if (uniqueValues.length > 0 && uniqueValues.length <= MAX_SELECT_OPTIONS && nonNullValues.length >= 2 && uniqueRatio <= 0.8) {
23244
23161
  field.type = "select";
@@ -23246,18 +23163,18 @@ function mergeFieldObservations(observations, depth = 0) {
23246
23163
  }
23247
23164
  }
23248
23165
  if (fieldType === "array") {
23249
- const allItems = nonNullValues.flatMap((v2) => Array.isArray(v2) ? v2 : []);
23166
+ const allItems = nonNullValues.flatMap((v) => Array.isArray(v) ? v : []);
23250
23167
  if (allItems.length > 0) {
23251
23168
  const itemType = inferFieldType(allItems[0], obs.name);
23252
23169
  field.itemType = itemType;
23253
23170
  if (itemType === "text") {
23254
- const uniqueItems = [...new Set(allItems.map((v2) => String(v2)))];
23171
+ const uniqueItems = [...new Set(allItems.map((v) => String(v)))];
23255
23172
  if (uniqueItems.length <= MAX_SELECT_OPTIONS * 2) {
23256
23173
  field.options = uniqueItems.sort();
23257
23174
  }
23258
23175
  }
23259
23176
  if (itemType === "object") {
23260
- const objectItems = allItems.filter((v2) => typeof v2 === "object" && v2 !== null && !Array.isArray(v2));
23177
+ const objectItems = allItems.filter((v) => typeof v === "object" && v !== null && !Array.isArray(v));
23261
23178
  if (objectItems.length > 0) {
23262
23179
  const subFieldMap = new Map;
23263
23180
  for (const item of objectItems) {
@@ -23269,7 +23186,7 @@ function mergeFieldObservations(observations, depth = 0) {
23269
23186
  }
23270
23187
  }
23271
23188
  if (fieldType === "object") {
23272
- const objectValues = nonNullValues.filter((v2) => typeof v2 === "object" && v2 !== null && !Array.isArray(v2));
23189
+ const objectValues = nonNullValues.filter((v) => typeof v === "object" && v !== null && !Array.isArray(v));
23273
23190
  if (objectValues.length > 0) {
23274
23191
  const subFieldMap = new Map;
23275
23192
  for (const item of objectValues) {
@@ -23297,13 +23214,13 @@ function assembleCollectionDefinition(collectionName, contentDir, fieldMap, entr
23297
23214
  for (const obs of fieldMap.values()) {
23298
23215
  obs.totalEntries = entryCount;
23299
23216
  }
23300
- entryInfos.sort((a, b2) => (a.title ?? a.slug).localeCompare(b2.title ?? b2.slug));
23217
+ entryInfos.sort((a, b) => (a.title ?? a.slug).localeCompare(b.title ?? b.slug));
23301
23218
  const fields = mergeFieldObservations(Array.from(fieldMap.values()));
23302
23219
  const label = collectionName.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
23303
23220
  return {
23304
23221
  name: collectionName,
23305
23222
  label,
23306
- path: path2.join(contentDir, collectionName),
23223
+ path: path.join(contentDir, collectionName),
23307
23224
  entryCount,
23308
23225
  fields,
23309
23226
  fileExtension: "md",
@@ -23312,19 +23229,13 @@ function assembleCollectionDefinition(collectionName, contentDir, fieldMap, entr
23312
23229
  };
23313
23230
  }
23314
23231
  function getCollectionSourceBasePath(basePath, collectionName, contentDir) {
23315
- const projectRoot = getProjectRoot();
23316
- const defaultContentDir = path2.isAbsolute(contentDir) ? contentDir : path2.join(projectRoot, contentDir);
23317
- const defaultCollectionPath = path2.join(defaultContentDir, collectionName);
23318
- if (path2.resolve(basePath) === path2.resolve(defaultCollectionPath)) {
23319
- return path2.join(contentDir, collectionName);
23320
- }
23321
- const relativeBase = path2.relative(projectRoot, basePath);
23322
- if (relativeBase && !relativeBase.startsWith("..") && !path2.isAbsolute(relativeBase)) {
23323
- return relativeBase;
23232
+ const defaultCollectionPath = path.join(contentDir, collectionName);
23233
+ if (path.normalize(basePath) === path.normalize(defaultCollectionPath)) {
23234
+ return path.join(contentDir, collectionName);
23324
23235
  }
23325
23236
  return basePath;
23326
23237
  }
23327
- async function buildCollectionDefinition(basePath, sources, collectionName, contentDir) {
23238
+ async function buildCollectionDefinition(fs, basePath, sources, collectionName, contentDir) {
23328
23239
  if (sources.length === 0)
23329
23240
  return null;
23330
23241
  const sourceBasePath = getCollectionSourceBasePath(basePath, collectionName, contentDir);
@@ -23334,11 +23245,13 @@ async function buildCollectionDefinition(basePath, sources, collectionName, cont
23334
23245
  const allDirectives = {};
23335
23246
  const entryInfos = [];
23336
23247
  let hasDraft = false;
23337
- const fileContents = await Promise.all(sources.map((s) => fs2.readFile(path2.join(basePath, s.relPath), "utf-8")));
23248
+ const fileContents = await Promise.all(sources.map((s) => fs.readFile(path.join(basePath, s.relPath)).catch(() => null)));
23338
23249
  for (let i = 0;i < sources.length; i++) {
23339
23250
  const source = sources[i];
23340
23251
  const content = fileContents[i];
23341
- const frontmatter = parseFrontmatter3(content);
23252
+ if (content === null)
23253
+ continue;
23254
+ const frontmatter = parseFrontmatter(content);
23342
23255
  const directives = parseFieldDirectives(content);
23343
23256
  for (const [key, value] of Object.entries(directives)) {
23344
23257
  if (!allDirectives[key]) {
@@ -23347,7 +23260,7 @@ async function buildCollectionDefinition(basePath, sources, collectionName, cont
23347
23260
  }
23348
23261
  const entryInfo = {
23349
23262
  slug: source.slug,
23350
- sourcePath: path2.join(sourceBasePath, source.relPath)
23263
+ sourcePath: path.join(sourceBasePath, source.relPath)
23351
23264
  };
23352
23265
  if (frontmatter) {
23353
23266
  if (typeof frontmatter.title === "string") {
@@ -23373,107 +23286,88 @@ async function buildCollectionDefinition(basePath, sources, collectionName, cont
23373
23286
  assignFieldMetadata(def.fields, allDirectives);
23374
23287
  return def;
23375
23288
  }
23376
- async function scanCollection(collectionPath, collectionName, contentDir) {
23377
- try {
23378
- const dirEntries = await fs2.readdir(collectionPath, { withFileTypes: true });
23379
- const sources = [];
23380
- const takenSlugs = new Set;
23381
- for (const entry of dirEntries) {
23382
- if (!entry.isFile())
23383
- continue;
23384
- if (!entry.name.endsWith(".md") && !entry.name.endsWith(".mdx"))
23385
- continue;
23386
- const slug = entry.name.replace(/\.(md|mdx)$/, "");
23387
- sources.push({ slug, relPath: entry.name });
23388
- takenSlugs.add(slug);
23389
- }
23390
- const subdirs = dirEntries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith("."));
23391
- const indexLookups = await Promise.all(subdirs.map(async (dir) => {
23392
- if (takenSlugs.has(dir.name))
23393
- return null;
23394
- for (const ext of ["md", "mdx"]) {
23395
- const relPath = path2.join(dir.name, `index.${ext}`);
23396
- try {
23397
- await fs2.access(path2.join(collectionPath, relPath));
23398
- return { slug: dir.name, relPath };
23399
- } catch {}
23400
- }
23401
- return null;
23402
- }));
23403
- for (const entry of indexLookups) {
23404
- if (entry)
23405
- sources.push(entry);
23406
- }
23407
- if (sources.length === 0)
23408
- return null;
23409
- return await buildCollectionDefinition(collectionPath, sources, collectionName, contentDir);
23410
- } catch {
23289
+ async function buildDataCollectionDefinition(fs, basePath, sources, collectionName, contentDir) {
23290
+ if (sources.length === 0)
23411
23291
  return null;
23412
- }
23413
- }
23414
- function globToRegExp2(glob) {
23415
- let re = "";
23416
- for (let i = 0;i < glob.length; i++) {
23417
- const c = glob[i];
23418
- if (c === "*") {
23419
- if (glob[i + 1] === "*") {
23420
- re += ".*";
23421
- i++;
23422
- if (glob[i + 1] === "/")
23423
- i++;
23424
- } else {
23425
- re += "[^/]*";
23426
- }
23427
- } else if (c === "?") {
23428
- re += "[^/]";
23429
- } else if (c === "{") {
23430
- const end = glob.indexOf("}", i);
23431
- if (end === -1) {
23432
- re += "\\{";
23433
- } else {
23434
- const opts = glob.slice(i + 1, end).split(",").map((s) => s.replace(/[.+^${}()|[\]\\]/g, "\\$&"));
23435
- re += `(?:${opts.join("|")})`;
23436
- i = end;
23437
- }
23438
- } else if (".+^$()|[]\\".includes(c)) {
23439
- re += `\\${c}`;
23440
- } else {
23441
- re += c;
23292
+ const sourceBasePath = getCollectionSourceBasePath(basePath, collectionName, contentDir);
23293
+ const fieldMap = new Map;
23294
+ const entryInfos = [];
23295
+ const ext = sources.some((s) => s.relPath.endsWith(".json")) ? "json" : sources.some((s) => s.relPath.endsWith(".yaml")) ? "yaml" : "yml";
23296
+ const fileContents = await Promise.all(sources.map((s) => fs.readFile(path.join(basePath, s.relPath)).catch(() => null)));
23297
+ for (let i = 0;i < sources.length; i++) {
23298
+ const source = sources[i];
23299
+ const raw = fileContents[i];
23300
+ if (raw === null)
23301
+ continue;
23302
+ let data = null;
23303
+ try {
23304
+ data = source.relPath.endsWith(".json") ? JSON.parse(raw) : import_yaml.parse(raw);
23305
+ } catch {
23306
+ continue;
23442
23307
  }
23308
+ if (!data || typeof data !== "object")
23309
+ continue;
23310
+ const title = typeof data.name === "string" ? data.name : typeof data.title === "string" ? data.title : undefined;
23311
+ entryInfos.push({
23312
+ slug: source.slug,
23313
+ title,
23314
+ sourcePath: path.join(sourceBasePath, source.relPath),
23315
+ data
23316
+ });
23317
+ collectFieldObservations(fieldMap, data, sources.length);
23443
23318
  }
23444
- return new RegExp(`^${re}$`);
23319
+ return assembleCollectionDefinition(collectionName, contentDir, fieldMap, entryInfos, sources.length, {
23320
+ type: "data",
23321
+ fileExtension: ext
23322
+ });
23445
23323
  }
23446
- async function walkFiles(dir, prefix = "") {
23447
- let dirEntries;
23448
- try {
23449
- dirEntries = await fs2.readdir(dir, { withFileTypes: true });
23450
- } catch {
23451
- return [];
23452
- }
23453
- const out = [];
23324
+ async function scanCollection(fs, collectionPath, collectionName, contentDir) {
23325
+ const dirEntries = await fs.list(collectionPath);
23326
+ if (dirEntries.length === 0)
23327
+ return null;
23328
+ const sources = [];
23329
+ const takenSlugs = new Set;
23454
23330
  for (const entry of dirEntries) {
23455
- if (entry.name.startsWith("_") || entry.name.startsWith("."))
23331
+ if (entry.isDirectory)
23456
23332
  continue;
23457
- const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
23458
- if (entry.isDirectory()) {
23459
- out.push(...await walkFiles(path2.join(dir, entry.name), rel));
23460
- } else if (entry.isFile()) {
23461
- out.push(rel);
23462
- }
23333
+ if (!entry.name.endsWith(".md") && !entry.name.endsWith(".mdx"))
23334
+ continue;
23335
+ const slug = entry.name.replace(/\.(md|mdx)$/, "");
23336
+ sources.push({ slug, relPath: entry.name });
23337
+ takenSlugs.add(slug);
23463
23338
  }
23464
- return out;
23465
- }
23466
- async function scanGlobCollection(collectionName, baseRel, pattern, contentDir) {
23467
- try {
23468
- const absBase = path2.join(getProjectRoot(), baseRel);
23469
- const matcher = globToRegExp2(pattern);
23470
- const sources = (await walkFiles(absBase)).filter((rel) => (rel.endsWith(".md") || rel.endsWith(".mdx")) && matcher.test(rel)).map((rel) => ({ slug: rel.replace(/\.(md|mdx)$/, ""), relPath: rel }));
23471
- if (sources.length === 0)
23339
+ const subdirs = dirEntries.filter((e) => e.isDirectory && !e.name.startsWith("_") && !e.name.startsWith("."));
23340
+ const indexLookups = await Promise.all(subdirs.map(async (dir) => {
23341
+ if (takenSlugs.has(dir.name))
23472
23342
  return null;
23473
- return await buildCollectionDefinition(absBase, sources, collectionName, contentDir);
23474
- } catch {
23343
+ for (const ext of ["md", "mdx"]) {
23344
+ const relPath = path.join(dir.name, `index.${ext}`);
23345
+ if (await fs.exists(path.join(collectionPath, relPath))) {
23346
+ return { slug: dir.name, relPath };
23347
+ }
23348
+ }
23349
+ return null;
23350
+ }));
23351
+ for (const entry of indexLookups) {
23352
+ if (entry)
23353
+ sources.push(entry);
23354
+ }
23355
+ if (sources.length === 0)
23475
23356
  return null;
23357
+ return await buildCollectionDefinition(fs, collectionPath, sources, collectionName, contentDir);
23358
+ }
23359
+ async function scanGlobCollection(fs, collectionName, baseRel, pattern, contentDir) {
23360
+ const matches = await fs.glob(path.join(baseRel, pattern));
23361
+ const rels = matches.map((rel) => path.relative(baseRel, rel)).filter((relToBase) => !relToBase.split("/").some((seg) => seg.startsWith("_") || seg.startsWith(".")));
23362
+ const mdSources = rels.filter((relToBase) => relToBase.endsWith(".md") || relToBase.endsWith(".mdx")).map((relToBase) => ({ slug: relToBase.replace(/\.(md|mdx)$/, ""), relPath: relToBase }));
23363
+ if (mdSources.length > 0) {
23364
+ return await buildCollectionDefinition(fs, baseRel, mdSources, collectionName, contentDir);
23476
23365
  }
23366
+ const dataSources = rels.filter((relToBase) => /\.(ya?ml|json)$/.test(relToBase)).map((relToBase) => ({ slug: relToBase.replace(/\.(ya?ml|json)$/, ""), relPath: relToBase }));
23367
+ if (dataSources.length > 0) {
23368
+ return await buildDataCollectionDefinition(fs, baseRel, dataSources, collectionName, contentDir);
23369
+ }
23370
+ return null;
23477
23371
  }
23478
23372
  function applyParsedConfig(collections, parsed) {
23479
23373
  for (const [collectionName, parsedColl] of parsed) {
@@ -23491,8 +23385,31 @@ function applyParsedConfig(collections, parsed) {
23491
23385
  continue;
23492
23386
  applyParsedFieldOverrides(field, pf);
23493
23387
  }
23388
+ if (parsedColl.layout)
23389
+ def.layout = parsedColl.layout;
23390
+ if (parsedColl.pathname)
23391
+ def.pathname = parsedColl.pathname;
23494
23392
  }
23495
23393
  }
23394
+ function applyParsedFieldLayout(field, pf) {
23395
+ const layout = pf.layout;
23396
+ if (!layout)
23397
+ return;
23398
+ if (layout.label !== undefined)
23399
+ field.label = layout.label;
23400
+ if (layout.help !== undefined)
23401
+ field.help = layout.help;
23402
+ if (layout.group !== undefined)
23403
+ field.group = layout.group;
23404
+ if (layout.width !== undefined)
23405
+ field.width = layout.width;
23406
+ if (layout.order !== undefined)
23407
+ field.order = layout.order;
23408
+ if (layout.sidebar)
23409
+ field.position = "sidebar";
23410
+ if (layout.hidden)
23411
+ field.hidden = true;
23412
+ }
23496
23413
  function applyParsedFieldOverrides(field, pf) {
23497
23414
  if (pf.type) {
23498
23415
  field.type = pf.type;
@@ -23506,6 +23423,7 @@ function applyParsedFieldOverrides(field, pf) {
23506
23423
  if (pf.astroImage)
23507
23424
  field.astroImage = true;
23508
23425
  field.required = pf.required;
23426
+ applyParsedFieldLayout(field, pf);
23509
23427
  if (pf.fields) {
23510
23428
  const existingByName = new Map((field.fields ?? []).map((f) => [f.name, f]));
23511
23429
  field.fields = pf.fields.map((subPf) => {
@@ -23534,6 +23452,7 @@ function parsedFieldToFieldDefinition(pf) {
23534
23452
  fd.astroImage = true;
23535
23453
  if (pf.fields)
23536
23454
  fd.fields = pf.fields.map(parsedFieldToFieldDefinition);
23455
+ applyParsedFieldLayout(fd, pf);
23537
23456
  return fd;
23538
23457
  }
23539
23458
  function applyCollectionOrderBy(collections, parsed) {
@@ -23550,9 +23469,9 @@ function applyCollectionOrderBy(collections, parsed) {
23550
23469
  def.orderDirection = direction;
23551
23470
  if (def.entries && def.entries.length > 1) {
23552
23471
  const dir = direction === "desc" ? -1 : 1;
23553
- def.entries.sort((a, b2) => {
23472
+ def.entries.sort((a, b) => {
23554
23473
  const aVal = a.data?.[fieldName];
23555
- const bVal = b2.data?.[fieldName];
23474
+ const bVal = b.data?.[fieldName];
23556
23475
  if (aVal == null && bVal == null)
23557
23476
  return 0;
23558
23477
  if (aVal == null)
@@ -23604,14 +23523,14 @@ function detectReferenceFieldsBySlugMatch(collections) {
23604
23523
  for (const [collectionName, def] of Object.entries(collections)) {
23605
23524
  for (const field of def.fields) {
23606
23525
  if ((field.type === "text" || field.type === "select") && field.examples) {
23607
- const stringExamples = field.examples.filter((v2) => typeof v2 === "string");
23526
+ const stringExamples = field.examples.filter((v) => typeof v === "string");
23608
23527
  if (stringExamples.length === 0)
23609
23528
  continue;
23610
23529
  const candidates = [];
23611
23530
  for (const [targetName, slugs] of collectionSlugs) {
23612
23531
  if (targetName === collectionName)
23613
23532
  continue;
23614
- const matchCount = stringExamples.filter((v2) => slugs.has(v2)).length;
23533
+ const matchCount = stringExamples.filter((v) => slugs.has(v)).length;
23615
23534
  if (matchCount > 0 && matchCount === stringExamples.length) {
23616
23535
  candidates.push({ name: targetName, slugs });
23617
23536
  }
@@ -23621,12 +23540,12 @@ function detectReferenceFieldsBySlugMatch(collections) {
23621
23540
  bestTarget = candidates[0].name;
23622
23541
  } else if (candidates.length > 1) {
23623
23542
  const allValues = def.entries?.flatMap((e) => {
23624
- const v2 = e.data?.[field.name];
23625
- return typeof v2 === "string" ? [v2] : [];
23543
+ const v = e.data?.[field.name];
23544
+ return typeof v === "string" ? [v] : [];
23626
23545
  }) ?? stringExamples;
23627
23546
  let bestOverlap = 0;
23628
23547
  for (const c of candidates) {
23629
- const overlap = allValues.filter((v2) => c.slugs.has(v2)).length;
23548
+ const overlap = allValues.filter((v) => c.slugs.has(v)).length;
23630
23549
  if (overlap > bestOverlap) {
23631
23550
  bestOverlap = overlap;
23632
23551
  bestTarget = c.name;
@@ -23645,7 +23564,7 @@ function detectReferenceFieldsBySlugMatch(collections) {
23645
23564
  for (const [targetName, slugs] of collectionSlugs) {
23646
23565
  if (targetName === collectionName)
23647
23566
  continue;
23648
- const matchCount = field.options.filter((v2) => slugs.has(v2)).length;
23567
+ const matchCount = field.options.filter((v) => slugs.has(v)).length;
23649
23568
  if (matchCount > 0 && matchCount >= field.options.length * 0.5) {
23650
23569
  if (matchCount > bestOverlap) {
23651
23570
  bestOverlap = matchCount;
@@ -23672,9 +23591,9 @@ function assignSemanticRoles(collections) {
23672
23591
  if (field.hidden || field.role)
23673
23592
  continue;
23674
23593
  const normalized = normalizeFieldName(field.name);
23675
- if (!toggle && field.type === "boolean" && PUBLISH_TOGGLE_NAMES2.has(normalized)) {
23594
+ if (!toggle && field.type === "boolean" && PUBLISH_TOGGLE_NAMES.has(normalized)) {
23676
23595
  toggle = field;
23677
- } else if (!dateByName && PUBLISH_DATE_NAMES2.has(normalized)) {
23596
+ } else if (!dateByName && PUBLISH_DATE_NAMES.has(normalized)) {
23678
23597
  dateByName = field;
23679
23598
  } else if (!dateByType && (field.type === "date" || field.type === "datetime")) {
23680
23599
  dateByType = field;
@@ -23712,12 +23631,12 @@ function detectDerivedHrefFields(collections) {
23712
23631
  }
23713
23632
  if (!sourceField || !sourceField.examples || !field.examples)
23714
23633
  continue;
23715
- const sourceExamples = sourceField.examples.filter((v2) => typeof v2 === "string");
23716
- const derivedExamples = field.examples.filter((v2) => typeof v2 === "string");
23634
+ const sourceExamples = sourceField.examples.filter((v) => typeof v === "string");
23635
+ const derivedExamples = field.examples.filter((v) => typeof v === "string");
23717
23636
  if (sourceExamples.length === 0 || derivedExamples.length === 0)
23718
23637
  continue;
23719
- const expectedHrefs = new Set(sourceExamples.map(slugifyHref2));
23720
- const allMatch = derivedExamples.every((v2) => expectedHrefs.has(v2));
23638
+ const expectedHrefs = new Set(sourceExamples.map(slugifyHref));
23639
+ const allMatch = derivedExamples.every((v) => expectedHrefs.has(v));
23721
23640
  if (allMatch) {
23722
23641
  field.hidden = true;
23723
23642
  field.derivedFrom = sourceField.name;
@@ -23727,161 +23646,429 @@ function detectDerivedHrefFields(collections) {
23727
23646
  }
23728
23647
  }
23729
23648
  }
23730
- async function scanDataCollection(collectionPath, collectionName, contentDir) {
23731
- try {
23732
- const dirEntries = await fs2.readdir(collectionPath, { withFileTypes: true });
23733
- const sources = [];
23734
- const takenSlugs = new Set;
23735
- for (const entry of dirEntries) {
23736
- if (!entry.isFile())
23737
- continue;
23738
- if (!entry.name.endsWith(".json") && !entry.name.endsWith(".yaml") && !entry.name.endsWith(".yml"))
23739
- continue;
23740
- const slug = entry.name.replace(/\.(json|ya?ml)$/, "");
23741
- sources.push({ slug, relPath: entry.name });
23742
- takenSlugs.add(slug);
23649
+ async function scanDataCollection(fs, collectionPath, collectionName, contentDir) {
23650
+ const dirEntries = await fs.list(collectionPath);
23651
+ if (dirEntries.length === 0)
23652
+ return null;
23653
+ const sources = [];
23654
+ const takenSlugs = new Set;
23655
+ for (const entry of dirEntries) {
23656
+ if (entry.isDirectory)
23657
+ continue;
23658
+ if (!entry.name.endsWith(".json") && !entry.name.endsWith(".yaml") && !entry.name.endsWith(".yml"))
23659
+ continue;
23660
+ const slug = entry.name.replace(/\.(json|ya?ml)$/, "");
23661
+ sources.push({ slug, relPath: entry.name });
23662
+ takenSlugs.add(slug);
23663
+ }
23664
+ const subdirs = dirEntries.filter((e) => e.isDirectory && !e.name.startsWith("_") && !e.name.startsWith("."));
23665
+ const indexLookups = await Promise.all(subdirs.map(async (dir) => {
23666
+ if (takenSlugs.has(dir.name))
23667
+ return null;
23668
+ for (const indexExt of ["json", "yaml", "yml"]) {
23669
+ const relPath = path.join(dir.name, `index.${indexExt}`);
23670
+ if (await fs.exists(path.join(collectionPath, relPath))) {
23671
+ return { slug: dir.name, relPath };
23672
+ }
23743
23673
  }
23744
- const subdirs = dirEntries.filter((e) => e.isDirectory() && !e.name.startsWith("_") && !e.name.startsWith("."));
23745
- const indexLookups = await Promise.all(subdirs.map(async (dir) => {
23746
- if (takenSlugs.has(dir.name))
23747
- return null;
23748
- for (const indexExt of ["json", "yaml", "yml"]) {
23749
- const relPath = path2.join(dir.name, `index.${indexExt}`);
23750
- try {
23751
- await fs2.access(path2.join(collectionPath, relPath));
23752
- return { slug: dir.name, relPath };
23753
- } catch {}
23674
+ return null;
23675
+ }));
23676
+ for (const entry of indexLookups) {
23677
+ if (entry)
23678
+ sources.push(entry);
23679
+ }
23680
+ return await buildDataCollectionDefinition(fs, collectionPath, sources, collectionName, contentDir);
23681
+ }
23682
+ async function scanCollections(fs, contentDir = "src/content", parseCache = new Map) {
23683
+ const collections = {};
23684
+ const entries = await fs.list(contentDir);
23685
+ const scanPromises = entries.filter((entry) => entry.isDirectory && !entry.name.startsWith("_") && !entry.name.startsWith(".")).map(async (entry) => {
23686
+ try {
23687
+ const collectionPath = path.join(contentDir, entry.name);
23688
+ const definition = await scanCollection(fs, collectionPath, entry.name, contentDir) ?? await scanDataCollection(fs, collectionPath, entry.name, contentDir);
23689
+ if (definition) {
23690
+ collections[entry.name] = definition;
23754
23691
  }
23755
- return null;
23756
- }));
23757
- for (const entry of indexLookups) {
23758
- if (entry)
23759
- sources.push(entry);
23692
+ } catch (error) {
23693
+ console.warn(`[cms] Skipping collection "${entry.name}" \u2014 scan failed:`, error);
23760
23694
  }
23761
- if (sources.length === 0)
23762
- return null;
23763
- const fieldMap = new Map;
23764
- const entryInfos = [];
23765
- const ext = sources.some((s) => s.relPath.endsWith(".json")) ? "json" : sources.some((s) => s.relPath.endsWith(".yaml")) ? "yaml" : "yml";
23766
- const fileContents = await Promise.all(sources.map((s) => fs2.readFile(path2.join(collectionPath, s.relPath), "utf-8").catch(() => null)));
23767
- for (let i = 0;i < sources.length; i++) {
23768
- const source = sources[i];
23769
- const raw = fileContents[i];
23770
- if (raw === null)
23695
+ });
23696
+ await Promise.all(scanPromises);
23697
+ const parsed = await parseContentConfig(fs, parseCache);
23698
+ for (const [collectionName, parsedCollection] of parsed) {
23699
+ if (collections[collectionName])
23700
+ continue;
23701
+ if (!parsedCollection.loaderBase || !parsedCollection.loaderPattern)
23702
+ continue;
23703
+ let definition;
23704
+ try {
23705
+ definition = await scanGlobCollection(fs, collectionName, parsedCollection.loaderBase, parsedCollection.loaderPattern, contentDir);
23706
+ } catch (error) {
23707
+ console.warn(`[cms] Skipping glob collection "${collectionName}" \u2014 scan failed:`, error);
23708
+ continue;
23709
+ }
23710
+ if (!definition)
23711
+ continue;
23712
+ const baseName = parsedCollection.loaderBase.replace(/[/\\]+$/, "").split(/[/\\]/).pop();
23713
+ if (baseName && baseName !== collectionName && collections[baseName]) {
23714
+ definition.parentCollection = baseName;
23715
+ }
23716
+ collections[collectionName] = definition;
23717
+ }
23718
+ applyParsedConfig(collections, parsed);
23719
+ detectReferenceFields(collections, parsed);
23720
+ detectDerivedHrefFields(collections);
23721
+ assignSemanticRoles(collections);
23722
+ applyCollectionOrderBy(collections, parsed);
23723
+ warnOnPathnameCollisions(collections);
23724
+ return collections;
23725
+ }
23726
+ function warnOnPathnameCollisions(collections) {
23727
+ for (const def of Object.values(collections)) {
23728
+ if (!def.pathname || !def.entries)
23729
+ continue;
23730
+ const bySlug = new Map;
23731
+ for (const entry of def.entries) {
23732
+ const pathname = resolvePathnameFromSpec(def, entry.data);
23733
+ if (!pathname)
23771
23734
  continue;
23772
- let data = null;
23735
+ const prev = bySlug.get(pathname);
23736
+ if (prev) {
23737
+ console.warn(`[cms] collection "${def.name}": pathname rule maps both "${prev}" and "${entry.slug}" to "${pathname}" \u2014 these entries will collide on one URL`);
23738
+ } else {
23739
+ bySlug.set(pathname, entry.slug);
23740
+ }
23741
+ }
23742
+ }
23743
+ }
23744
+ var import_yaml, DATE_PATTERN, URL_PATTERN, IMAGE_EXTENSIONS, MAX_SELECT_OPTIONS = 10, TEXTAREA_MIN_LENGTH = 200, SIDEBAR_FIELD_NAMES, DIRECTIVE_PATTERN, FREE_TEXT_FIELD_NAMES, PUBLISH_TOGGLE_NAMES, PUBLISH_DATE_NAMES, FRONTMATTER_PATTERN, MAX_NESTED_FIELD_DEPTH = 16, HREF_SUFFIXES;
23745
+ var init_collection_scanner = __esm(() => {
23746
+ init_content_config_ast();
23747
+ import_yaml = __toESM(require_dist(), 1);
23748
+ DATE_PATTERN = /^\d{4}-\d{2}-\d{2}/;
23749
+ URL_PATTERN = /^(https?:\/\/|\/)/;
23750
+ IMAGE_EXTENSIONS = /\.(jpg|jpeg|png|gif|webp|svg|avif)$/i;
23751
+ SIDEBAR_FIELD_NAMES = new Set([
23752
+ "title",
23753
+ "date",
23754
+ "pubdate",
23755
+ "publishdate",
23756
+ "draft",
23757
+ "image",
23758
+ "featuredimage",
23759
+ "cover",
23760
+ "coverimage",
23761
+ "thumbnail",
23762
+ "author"
23763
+ ]);
23764
+ DIRECTIVE_PATTERN = /^\s*@(position|group)\s+(.+)$/;
23765
+ FREE_TEXT_FIELD_NAMES = new Set([
23766
+ "title",
23767
+ "name",
23768
+ "description",
23769
+ "summary",
23770
+ "excerpt",
23771
+ "subtitle",
23772
+ "heading",
23773
+ "headline",
23774
+ "slug",
23775
+ "alt",
23776
+ "caption"
23777
+ ]);
23778
+ PUBLISH_TOGGLE_NAMES = new Set(["draft", "isdraft", "published", "ispublished", "unpublished"]);
23779
+ PUBLISH_DATE_NAMES = new Set([
23780
+ "date",
23781
+ "pubdate",
23782
+ "publishdate",
23783
+ "publisheddate",
23784
+ "publishedate",
23785
+ "publishedat",
23786
+ "datepublished"
23787
+ ]);
23788
+ FRONTMATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---/;
23789
+ HREF_SUFFIXES = ["href", "url", "link", "slug", "path"];
23790
+ });
23791
+
23792
+ // ../cms-core/src/component-registry.ts
23793
+ var import_parser2;
23794
+ var init_component_registry = __esm(() => {
23795
+ import_parser2 = __toESM(require_lib(), 1);
23796
+ });
23797
+
23798
+ // ../cms-core/src/media/local.ts
23799
+ function mimeFromExt(ext) {
23800
+ return MIME_BY_EXT[ext] ?? "application/octet-stream";
23801
+ }
23802
+ var MIME_BY_EXT;
23803
+ var init_local = __esm(() => {
23804
+ MIME_BY_EXT = {
23805
+ ".jpg": "image/jpeg",
23806
+ ".jpeg": "image/jpeg",
23807
+ ".png": "image/png",
23808
+ ".gif": "image/gif",
23809
+ ".webp": "image/webp",
23810
+ ".avif": "image/avif",
23811
+ ".svg": "image/svg+xml",
23812
+ ".ico": "image/x-icon",
23813
+ ".mp4": "video/mp4",
23814
+ ".webm": "video/webm",
23815
+ ".pdf": "application/pdf"
23816
+ };
23817
+ });
23818
+
23819
+ // ../cms-core/src/handlers/entry-ops.ts
23820
+ var import_yaml2;
23821
+ var init_entry_ops = __esm(() => {
23822
+ init_collection_scanner();
23823
+ init_content_config_ast();
23824
+ init_local();
23825
+ import_yaml2 = __toESM(require_dist(), 1);
23826
+ });
23827
+
23828
+ // ../cms-core/src/handlers/page-ops.ts
23829
+ var init_page_ops = () => {};
23830
+ // ../cms-core/src/core.ts
23831
+ var init_core = __esm(() => {
23832
+ init_collection_scanner();
23833
+ init_component_registry();
23834
+ init_entry_ops();
23835
+ init_page_ops();
23836
+ });
23837
+
23838
+ // ../cms-core/src/fs/glob.ts
23839
+ function globToRegExp(glob) {
23840
+ let re = "";
23841
+ for (let i = 0;i < glob.length; i++) {
23842
+ const c = glob[i];
23843
+ if (c === "*") {
23844
+ if (glob[i + 1] === "*") {
23845
+ re += ".*";
23846
+ i++;
23847
+ if (glob[i + 1] === "/")
23848
+ i++;
23849
+ } else {
23850
+ re += "[^/]*";
23851
+ }
23852
+ } else if (c === "?") {
23853
+ re += "[^/]";
23854
+ } else if (c === "{") {
23855
+ const end = glob.indexOf("}", i);
23856
+ if (end === -1) {
23857
+ re += "\\{";
23858
+ } else {
23859
+ const opts = glob.slice(i + 1, end).split(",").map((s) => s.replace(/[.+^${}()|[\]\\]/g, "\\$&"));
23860
+ re += `(?:${opts.join("|")})`;
23861
+ i = end;
23862
+ }
23863
+ } else if (".+^$()|[]\\".includes(c)) {
23864
+ re += `\\${c}`;
23865
+ } else {
23866
+ re += c;
23867
+ }
23868
+ }
23869
+ return new RegExp(`^${re}$`);
23870
+ }
23871
+
23872
+ // ../cms-core/src/fs/node-fs.ts
23873
+ import fs from "fs/promises";
23874
+ import path2 from "path";
23875
+ function resolveWithinRoot(root, filePath) {
23876
+ const resolvedRoot = path2.resolve(root);
23877
+ const isAbsoluteFs = filePath.startsWith(resolvedRoot);
23878
+ const normalizedPath = !isAbsoluteFs && filePath.startsWith("/") ? filePath.slice(1) : filePath;
23879
+ const fullPath = path2.isAbsolute(normalizedPath) ? path2.resolve(normalizedPath) : path2.resolve(resolvedRoot, normalizedPath);
23880
+ if (!fullPath.startsWith(resolvedRoot + path2.sep) && fullPath !== resolvedRoot) {
23881
+ throw new Error(`Path traversal detected: ${filePath}`);
23882
+ }
23883
+ return fullPath;
23884
+ }
23885
+ function isNodeError(error) {
23886
+ return error instanceof Error && "code" in error;
23887
+ }
23888
+ async function walkFiles(absRoot, absDir) {
23889
+ let dirEntries;
23890
+ try {
23891
+ dirEntries = await fs.readdir(absDir, { withFileTypes: true });
23892
+ } catch {
23893
+ return [];
23894
+ }
23895
+ const out = [];
23896
+ for (const entry of dirEntries) {
23897
+ const abs = path2.join(absDir, entry.name);
23898
+ if (entry.isDirectory()) {
23899
+ out.push(...await walkFiles(absRoot, abs));
23900
+ } else if (entry.isFile()) {
23901
+ out.push(path2.relative(absRoot, abs).split(path2.sep).join("/"));
23902
+ }
23903
+ }
23904
+ return out;
23905
+ }
23906
+ function staticPrefixDir(pattern) {
23907
+ const segments = pattern.split("/");
23908
+ const staticSegments = [];
23909
+ for (const segment of segments) {
23910
+ if (/[*?{}[\]]/.test(segment))
23911
+ break;
23912
+ staticSegments.push(segment);
23913
+ }
23914
+ if (staticSegments.length === segments.length) {
23915
+ staticSegments.pop();
23916
+ }
23917
+ return staticSegments.join("/");
23918
+ }
23919
+ function createNodeFs(root) {
23920
+ const resolvedRoot = path2.resolve(root);
23921
+ const resolve = (p) => resolveWithinRoot(resolvedRoot, p);
23922
+ return {
23923
+ async readFile(filePath) {
23924
+ return fs.readFile(resolve(filePath), "utf-8");
23925
+ },
23926
+ async readBytes(filePath) {
23927
+ return fs.readFile(resolve(filePath));
23928
+ },
23929
+ async writeFile(filePath, content) {
23930
+ const fullPath = resolve(filePath);
23931
+ await fs.mkdir(path2.dirname(fullPath), { recursive: true });
23932
+ const tempPath = `${fullPath}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`;
23773
23933
  try {
23774
- data = source.relPath.endsWith(".json") ? JSON.parse(raw) : import_yaml3.parse(raw);
23934
+ await fs.writeFile(tempPath, content, "utf-8");
23935
+ await fs.rename(tempPath, fullPath);
23936
+ } catch (error) {
23937
+ await fs.rm(tempPath, { force: true });
23938
+ throw error;
23939
+ }
23940
+ },
23941
+ async rename(from, to) {
23942
+ const fullTo = resolve(to);
23943
+ await fs.mkdir(path2.dirname(fullTo), { recursive: true });
23944
+ await fs.rename(resolve(from), fullTo);
23945
+ },
23946
+ async remove(filePath) {
23947
+ await fs.rm(resolve(filePath), { force: true });
23948
+ },
23949
+ async exists(filePath) {
23950
+ try {
23951
+ await fs.access(resolve(filePath));
23952
+ return true;
23775
23953
  } catch {
23776
- continue;
23954
+ return false;
23777
23955
  }
23778
- if (!data || typeof data !== "object")
23779
- continue;
23780
- const title = typeof data.name === "string" ? data.name : typeof data.title === "string" ? data.title : undefined;
23781
- entryInfos.push({
23782
- slug: source.slug,
23783
- title,
23784
- sourcePath: path2.join(contentDir, collectionName, source.relPath),
23785
- data
23786
- });
23787
- collectFieldObservations(fieldMap, data, sources.length);
23956
+ },
23957
+ async list(dir) {
23958
+ try {
23959
+ const entries = await fs.readdir(resolve(dir), { withFileTypes: true });
23960
+ return entries.map((entry) => ({ name: entry.name, isDirectory: entry.isDirectory() }));
23961
+ } catch (error) {
23962
+ if (isNodeError(error) && error.code === "ENOENT")
23963
+ return [];
23964
+ throw error;
23965
+ }
23966
+ },
23967
+ async glob(pattern) {
23968
+ const baseRel = staticPrefixDir(pattern);
23969
+ const absBase = resolve(baseRel);
23970
+ const matcher = globToRegExp(pattern);
23971
+ const files = await walkFiles(resolvedRoot, absBase);
23972
+ return files.filter((rel) => matcher.test(rel));
23973
+ },
23974
+ async stat(filePath) {
23975
+ const s = await fs.stat(resolve(filePath));
23976
+ return { mtimeMs: s.mtimeMs, size: s.size };
23788
23977
  }
23789
- return assembleCollectionDefinition(collectionName, contentDir, fieldMap, entryInfos, sources.length, {
23790
- type: "data",
23791
- fileExtension: ext
23792
- });
23793
- } catch {
23794
- return null;
23795
- }
23978
+ };
23796
23979
  }
23797
- async function scanCollections2(contentDir = "src/content") {
23798
- const projectRoot = getProjectRoot();
23799
- const fullContentDir = path2.isAbsolute(contentDir) ? contentDir : path2.join(projectRoot, contentDir);
23800
- const collections = {};
23801
- try {
23802
- const entries = await fs2.readdir(fullContentDir, { withFileTypes: true });
23803
- const scanPromises = entries.filter((entry) => entry.isDirectory() && !entry.name.startsWith("_") && !entry.name.startsWith(".")).map(async (entry) => {
23804
- const collectionPath = path2.join(fullContentDir, entry.name);
23805
- const definition = await scanCollection(collectionPath, entry.name, contentDir) ?? await scanDataCollection(collectionPath, entry.name, contentDir);
23806
- if (definition) {
23807
- collections[entry.name] = definition;
23808
- }
23809
- });
23810
- await Promise.all(scanPromises);
23811
- } catch {}
23812
- const parsed = await parseContentConfig2();
23813
- for (const [collectionName, parsedCollection] of parsed) {
23814
- if (collections[collectionName])
23815
- continue;
23816
- if (!parsedCollection.loaderBase || !parsedCollection.loaderPattern)
23817
- continue;
23818
- const definition = await scanGlobCollection(collectionName, parsedCollection.loaderBase, parsedCollection.loaderPattern, contentDir);
23819
- if (!definition)
23980
+ var init_node_fs = () => {};
23981
+ // ../cms-core/src/media/project-images.ts
23982
+ async function listProjectImages(fs2, options) {
23983
+ const excludeDir = options?.excludeDir ? normalizeDir(options.excludeDir) : null;
23984
+ const scanDirs = [
23985
+ { dir: "public", relativeToRoot: false },
23986
+ { dir: "src", relativeToRoot: true }
23987
+ ];
23988
+ const results = await Promise.all(scanDirs.map(async ({ dir, relativeToRoot }) => {
23989
+ const items2 = [];
23990
+ await scanDirectory(fs2, dir, dir, relativeToRoot, excludeDir, items2);
23991
+ return items2;
23992
+ }));
23993
+ const items = results.flat();
23994
+ items.sort((a, b) => a.filename.localeCompare(b.filename));
23995
+ return items;
23996
+ }
23997
+ function normalizeDir(dir) {
23998
+ return dir.replace(/^\/+/, "").replace(/\/+$/, "");
23999
+ }
24000
+ async function scanDirectory(fs2, currentDir, baseDir, relativeToRoot, excludeDir, items) {
24001
+ if (excludeDir && normalizeDir(currentDir) === excludeDir)
24002
+ return;
24003
+ const entries = await fs2.list(currentDir);
24004
+ const subdirs = [];
24005
+ for (const entry of entries) {
24006
+ if (entry.name.startsWith(".") || entry.name === "node_modules")
23820
24007
  continue;
23821
- const baseName = parsedCollection.loaderBase.replace(/[/\\]+$/, "").split(/[/\\]/).pop();
23822
- if (baseName && baseName !== collectionName && collections[baseName]) {
23823
- definition.parentCollection = baseName;
24008
+ const fullPath = `${currentDir}/${entry.name}`;
24009
+ if (entry.isDirectory) {
24010
+ subdirs.push(scanDirectory(fs2, fullPath, baseDir, relativeToRoot, excludeDir, items));
24011
+ } else {
24012
+ const dotIdx = entry.name.lastIndexOf(".");
24013
+ const ext = dotIdx >= 0 ? entry.name.slice(dotIdx).toLowerCase() : "";
24014
+ if (!IMAGE_EXTENSIONS2.has(ext))
24015
+ continue;
24016
+ const url = relativeToRoot ? `/${fullPath}` : `/${fullPath.slice(baseDir.length + 1)}`;
24017
+ items.push({
24018
+ id: `project:${url}`,
24019
+ url,
24020
+ filename: entry.name,
24021
+ contentType: mimeFromExt(ext)
24022
+ });
23824
24023
  }
23825
- collections[collectionName] = definition;
23826
24024
  }
23827
- applyParsedConfig(collections, parsed);
23828
- detectReferenceFields(collections, parsed);
23829
- detectDerivedHrefFields(collections);
23830
- assignSemanticRoles(collections);
23831
- applyCollectionOrderBy(collections, parsed);
23832
- return collections;
24025
+ await Promise.all(subdirs);
23833
24026
  }
23834
- var import_yaml3, DATE_PATTERN, URL_PATTERN, IMAGE_EXTENSIONS2, MAX_SELECT_OPTIONS = 10, TEXTAREA_MIN_LENGTH = 200, SIDEBAR_FIELD_NAMES2, DIRECTIVE_PATTERN, FREE_TEXT_FIELD_NAMES2, PUBLISH_TOGGLE_NAMES2, PUBLISH_DATE_NAMES2, FRONTMATTER_PATTERN, MAX_NESTED_FIELD_DEPTH = 16, HREF_SUFFIXES;
23835
- var init_collection_scanner2 = __esm(() => {
23836
- init_config();
23837
- init_content_config_ast2();
23838
- import_yaml3 = __toESM(require_dist(), 1);
23839
- DATE_PATTERN = /^\d{4}-\d{2}-\d{2}/;
23840
- URL_PATTERN = /^(https?:\/\/|\/)/;
23841
- IMAGE_EXTENSIONS2 = /\.(jpg|jpeg|png|gif|webp|svg|avif)$/i;
23842
- SIDEBAR_FIELD_NAMES2 = new Set([
23843
- "title",
23844
- "date",
23845
- "pubdate",
23846
- "publishdate",
23847
- "draft",
23848
- "image",
23849
- "featuredimage",
23850
- "cover",
23851
- "coverimage",
23852
- "thumbnail",
23853
- "author"
23854
- ]);
23855
- DIRECTIVE_PATTERN = /^\s*@(position|group)\s+(.+)$/;
23856
- FREE_TEXT_FIELD_NAMES2 = new Set([
23857
- "title",
23858
- "name",
23859
- "description",
23860
- "summary",
23861
- "excerpt",
23862
- "subtitle",
23863
- "heading",
23864
- "headline",
23865
- "slug",
23866
- "alt",
23867
- "caption"
23868
- ]);
23869
- PUBLISH_TOGGLE_NAMES2 = new Set(["draft", "isdraft", "published", "ispublished", "unpublished"]);
23870
- PUBLISH_DATE_NAMES2 = new Set([
23871
- "date",
23872
- "pubdate",
23873
- "publishdate",
23874
- "publisheddate",
23875
- "publishedate",
23876
- "publishedat",
23877
- "datepublished"
23878
- ]);
23879
- FRONTMATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---/;
23880
- HREF_SUFFIXES = ["href", "url", "link", "slug", "path"];
24027
+ var IMAGE_EXTENSIONS2;
24028
+ var init_project_images = __esm(() => {
24029
+ init_local();
24030
+ IMAGE_EXTENSIONS2 = new Set(Object.entries(MIME_BY_EXT).filter(([, mime]) => mime.startsWith("image/")).map(([ext]) => ext));
24031
+ });
24032
+
24033
+ // ../cms-core/src/media/s3.ts
24034
+ var init_s3 = __esm(() => {
24035
+ init_local();
24036
+ });
24037
+
24038
+ // ../cms-core/src/media/index.ts
24039
+ var init_media = __esm(() => {
24040
+ init_local();
24041
+ init_project_images();
24042
+ init_s3();
24043
+ });
24044
+
24045
+ // ../cms-core/src/project-config-ast.ts
24046
+ var import_parser3;
24047
+ var init_project_config_ast = __esm(() => {
24048
+ import_parser3 = __toESM(require_lib(), 1);
24049
+ });
24050
+
24051
+ // ../cms-core/src/index.ts
24052
+ var init_src2 = __esm(() => {
24053
+ init_collection_scanner();
24054
+ init_component_registry();
24055
+ init_content_config_ast();
24056
+ init_core();
24057
+ init_node_fs();
24058
+ init_entry_ops();
24059
+ init_media();
24060
+ init_project_config_ast();
23881
24061
  });
23882
24062
 
24063
+ // ../cms/src/config.ts
24064
+ function getProjectRoot() {
24065
+ return projectRootOverride ?? process.cwd();
24066
+ }
24067
+ var projectRootOverride = null;
24068
+ var init_config = () => {};
24069
+
23883
24070
  // ../cms/src/component-registry.ts
23884
- import fs3 from "fs/promises";
24071
+ import fs2 from "fs/promises";
23885
24072
  import path3 from "path";
23886
24073
 
23887
24074
  class ComponentRegistry {
@@ -23905,7 +24092,7 @@ class ComponentRegistry {
23905
24092
  return this.components.get(name);
23906
24093
  }
23907
24094
  async scanDirectory(dir, relativePath) {
23908
- const entries = await fs3.readdir(dir, { withFileTypes: true });
24095
+ const entries = await fs2.readdir(dir, { withFileTypes: true });
23909
24096
  for (const entry of entries) {
23910
24097
  const fullPath = path3.join(dir, entry.name);
23911
24098
  const relPath = path3.join(relativePath, entry.name);
@@ -23918,7 +24105,7 @@ class ComponentRegistry {
23918
24105
  }
23919
24106
  async parseComponent(filePath, relativePath) {
23920
24107
  try {
23921
- const content = await fs3.readFile(filePath, "utf-8");
24108
+ const content = await fs2.readFile(filePath, "utf-8");
23922
24109
  const componentName = path3.basename(filePath, ".astro");
23923
24110
  const props = await this.extractProps(content);
23924
24111
  const slots = this.extractSlots(content);
@@ -23943,7 +24130,7 @@ ${propsContent}
23943
24130
  }`;
23944
24131
  let ast;
23945
24132
  try {
23946
- ast = import_parser6.parse(synthetic, {
24133
+ ast = import_parser4.parse(synthetic, {
23947
24134
  sourceType: "module",
23948
24135
  plugins: ["typescript"],
23949
24136
  errorRecovery: true
@@ -23973,13 +24160,13 @@ ${propsContent}
23973
24160
  type = lines[startLine].slice(ta.loc.start.column, ta.loc.end.column).trim();
23974
24161
  } else {
23975
24162
  const parts = [];
23976
- for (let l2 = startLine;l2 <= endLine; l2++) {
23977
- if (l2 === startLine)
23978
- parts.push(lines[l2].slice(ta.loc.start.column));
23979
- else if (l2 === endLine)
23980
- parts.push(lines[l2].slice(0, ta.loc.end.column));
24163
+ for (let l = startLine;l <= endLine; l++) {
24164
+ if (l === startLine)
24165
+ parts.push(lines[l].slice(ta.loc.start.column));
24166
+ else if (l === endLine)
24167
+ parts.push(lines[l].slice(0, ta.loc.end.column));
23981
24168
  else
23982
- parts.push(lines[l2]);
24169
+ parts.push(lines[l]);
23983
24170
  }
23984
24171
  type = parts.join(`
23985
24172
  `).trim();
@@ -24003,7 +24190,7 @@ ${propsContent}
24003
24190
  const last = member.leadingComments[member.leadingComments.length - 1];
24004
24191
  if (last.type === "CommentBlock") {
24005
24192
  description = last.value.split(`
24006
- `).map((l2) => l2.replace(/^\s*\*\s?/, "").trim()).filter(Boolean).join(" ");
24193
+ `).map((l) => l.replace(/^\s*\*\s?/, "").trim()).filter(Boolean).join(" ");
24007
24194
  } else if (last.type === "CommentLine" && last.loc && member.loc) {
24008
24195
  const commentLineContent = lines[last.loc.start.line - 1]?.trim();
24009
24196
  if (commentLineContent?.startsWith("//")) {
@@ -24150,12 +24337,28 @@ ${propsContent}
24150
24337
  return;
24151
24338
  }
24152
24339
  }
24153
- var import_parser6;
24340
+ var import_parser4;
24154
24341
  var init_component_registry2 = __esm(() => {
24155
24342
  init_config();
24156
- import_parser6 = __toESM(require_lib(), 1);
24343
+ import_parser4 = __toESM(require_lib(), 1);
24344
+ });
24345
+
24346
+ // ../cms/src/scan-cache.ts
24347
+ function scanCollections2(contentDir) {
24348
+ return scanCollections(createNodeFs(getProjectRoot()), contentDir, parseCache);
24349
+ }
24350
+ var parseCache;
24351
+ var init_scan_cache = __esm(() => {
24352
+ init_src2();
24353
+ init_config();
24354
+ parseCache = new Map;
24157
24355
  });
24158
24356
 
24357
+ // ../cms/src/shared.ts
24358
+ function slugify2(text) {
24359
+ return text.toLowerCase().trim().replace(/[^\w\s\-/]/g, "").replace(/[\s_]+/g, "-").replace(/^[-/]+|[-/]+$/g, "");
24360
+ }
24361
+
24159
24362
  // ../cms/src/utils.ts
24160
24363
  import { createHash } from "crypto";
24161
24364
  import path4 from "path";
@@ -24197,7 +24400,7 @@ function generateSourceFileHashes(entries) {
24197
24400
  }
24198
24401
  const hashes = {};
24199
24402
  for (const [filePath, fileEntries] of Object.entries(entriesByFile)) {
24200
- const sorted = fileEntries.sort((a, b2) => (a.sourceLine || 0) - (b2.sourceLine || 0));
24403
+ const sorted = fileEntries.sort((a, b) => (a.sourceLine || 0) - (b.sourceLine || 0));
24201
24404
  const content = sorted.map((e) => `${e.sourceLine || 0}|${e.text}|${e.sourceSnippet || ""}`).join(`
24202
24405
  `);
24203
24406
  hashes[filePath] = sha256(content);
@@ -24256,7 +24459,7 @@ var init_utils2 = __esm(() => {
24256
24459
  });
24257
24460
 
24258
24461
  // ../cms/src/handlers/component-ops.ts
24259
- import fs4 from "fs/promises";
24462
+ import fs3 from "fs/promises";
24260
24463
  import path5 from "path";
24261
24464
  async function handleInsertComponent(request, manifestWriter) {
24262
24465
  const { position, referenceComponentId, componentName, props, meta } = request;
@@ -24290,7 +24493,7 @@ async function handleInsertComponent(request, manifestWriter) {
24290
24493
  try {
24291
24494
  let currentContent;
24292
24495
  try {
24293
- currentContent = await fs4.readFile(fullPath, "utf-8");
24496
+ currentContent = await fs3.readFile(fullPath, "utf-8");
24294
24497
  } catch {
24295
24498
  return { success: false, error: `Source file not found: ${filePath}` };
24296
24499
  }
@@ -24315,7 +24518,7 @@ async function handleInsertComponent(request, manifestWriter) {
24315
24518
  `);
24316
24519
  lines.splice(insertIndex, 0, indentedJsx);
24317
24520
  ensureComponentImport(lines, componentName, componentDef.file, filePath);
24318
- await fs4.writeFile(fullPath, lines.join(`
24521
+ await fs3.writeFile(fullPath, lines.join(`
24319
24522
  `), "utf-8");
24320
24523
  return {
24321
24524
  success: true,
@@ -24358,7 +24561,7 @@ async function handleRemoveComponent(request, manifestWriter) {
24358
24561
  try {
24359
24562
  let currentContent;
24360
24563
  try {
24361
- currentContent = await fs4.readFile(fullPath, "utf-8");
24564
+ currentContent = await fs3.readFile(fullPath, "utf-8");
24362
24565
  } catch {
24363
24566
  return { success: false, error: `Source file not found: ${filePath}` };
24364
24567
  }
@@ -24380,7 +24583,7 @@ async function handleRemoveComponent(request, manifestWriter) {
24380
24583
  removeCount++;
24381
24584
  }
24382
24585
  lines.splice(startLine, removeCount);
24383
- await fs4.writeFile(fullPath, lines.join(`
24586
+ await fs3.writeFile(fullPath, lines.join(`
24384
24587
  `), "utf-8");
24385
24588
  return {
24386
24589
  success: true,
@@ -24477,7 +24680,7 @@ async function findComponentInvocationFile(projectRoot, pageUrl, manifest, refer
24477
24680
  const filePath = normalizeFilePath(referenceComponent.invocationSourcePath);
24478
24681
  const fullPath = path5.resolve(projectRoot, filePath);
24479
24682
  try {
24480
- const content = await fs4.readFile(fullPath, "utf-8");
24683
+ const content = await fs3.readFile(fullPath, "utf-8");
24481
24684
  const lines = content.split(`
24482
24685
  `);
24483
24686
  const lineIndex = findComponentInvocationLine(lines, referenceComponent.componentName, referenceComponent.invocationIndex ?? 0);
@@ -24491,7 +24694,7 @@ async function findComponentInvocationFile(projectRoot, pageUrl, manifest, refer
24491
24694
  for (const candidate of candidates) {
24492
24695
  const fullPath = path5.resolve(projectRoot, candidate);
24493
24696
  try {
24494
- const content = await fs4.readFile(fullPath, "utf-8");
24697
+ const content = await fs3.readFile(fullPath, "utf-8");
24495
24698
  const lines = content.split(`
24496
24699
  `);
24497
24700
  const lineIndex = findComponentInvocationLine(lines, referenceComponent.componentName, occurrenceIndex);
@@ -24581,7 +24784,7 @@ var init_component_ops = __esm(() => {
24581
24784
  });
24582
24785
 
24583
24786
  // ../cms/src/handlers/array-ops.ts
24584
- import fs5 from "fs/promises";
24787
+ import fs4 from "fs/promises";
24585
24788
  function parseInlineArrayName(componentName) {
24586
24789
  if (!componentName.startsWith("__array:"))
24587
24790
  return null;
@@ -24616,7 +24819,7 @@ function detectArrayPattern(lines, invocationLineIndex) {
24616
24819
  function findArrayDeclaration(frontmatterContent, frontmatterStartLine, arrayVarName) {
24617
24820
  let ast;
24618
24821
  try {
24619
- ast = import_parser7.parse(frontmatterContent, {
24822
+ ast = import_parser5.parse(frontmatterContent, {
24620
24823
  sourceType: "module",
24621
24824
  plugins: ["typescript"],
24622
24825
  errorRecovery: true
@@ -24661,7 +24864,7 @@ async function resolveArrayContext(component, manifest, pageUrl) {
24661
24864
  const { arrayVarName, mapOccurrence } = parsed;
24662
24865
  const filePath2 = normalizeFilePath(component.invocationSourcePath ?? component.sourcePath);
24663
24866
  const fullPath2 = resolveAndValidatePath(filePath2);
24664
- const content2 = await fs5.readFile(fullPath2, "utf-8");
24867
+ const content2 = await fs4.readFile(fullPath2, "utf-8");
24665
24868
  const lines2 = content2.split(`
24666
24869
  `);
24667
24870
  const fmEnd2 = findFrontmatterEnd(lines2);
@@ -24687,7 +24890,7 @@ async function resolveArrayContext(component, manifest, pageUrl) {
24687
24890
  const elementBounds2 = findArrayDeclaration(frontmatterContent2, frontmatterStartLine2, arrayVarName);
24688
24891
  if (!elementBounds2 || elementBounds2.length === 0)
24689
24892
  return null;
24690
- const sameSourceComponents2 = Object.values(manifest.components).filter((c) => c.componentName === component.componentName && c.invocationSourcePath === component.invocationSourcePath).sort((a, b2) => (a.invocationIndex ?? 0) - (b2.invocationIndex ?? 0));
24893
+ const sameSourceComponents2 = Object.values(manifest.components).filter((c) => c.componentName === component.componentName && c.invocationSourcePath === component.invocationSourcePath).sort((a, b) => (a.invocationIndex ?? 0) - (b.invocationIndex ?? 0));
24691
24894
  const arrayIndex2 = sameSourceComponents2.findIndex((c) => c.id === component.id);
24692
24895
  if (arrayIndex2 < 0 || arrayIndex2 >= elementBounds2.length)
24693
24896
  return null;
@@ -24706,7 +24909,7 @@ async function resolveArrayContext(component, manifest, pageUrl) {
24706
24909
  const invocation = await findComponentInvocationFile(projectRoot, pageUrl, manifest, component);
24707
24910
  const filePath = invocation?.filePath ?? normalizeFilePath(component.invocationSourcePath ?? component.sourcePath);
24708
24911
  const fullPath = resolveAndValidatePath(filePath);
24709
- const content = await fs5.readFile(fullPath, "utf-8");
24912
+ const content = await fs4.readFile(fullPath, "utf-8");
24710
24913
  const lines = content.split(`
24711
24914
  `);
24712
24915
  let refLineIndex;
@@ -24734,7 +24937,7 @@ async function resolveArrayContext(component, manifest, pageUrl) {
24734
24937
  return null;
24735
24938
  }
24736
24939
  const occurrenceIndex = getComponentOccurrenceIndex(manifest, component);
24737
- const sameSourceComponents = Object.values(manifest.components).filter((c) => c.componentName === component.componentName && c.invocationSourcePath === component.invocationSourcePath).sort((a, b2) => (a.invocationIndex ?? 0) - (b2.invocationIndex ?? 0));
24940
+ const sameSourceComponents = Object.values(manifest.components).filter((c) => c.componentName === component.componentName && c.invocationSourcePath === component.invocationSourcePath).sort((a, b) => (a.invocationIndex ?? 0) - (b.invocationIndex ?? 0));
24738
24941
  const arrayIndex = sameSourceComponents.findIndex((c) => c.id === component.id);
24739
24942
  if (arrayIndex < 0 || arrayIndex >= elementBounds.length) {
24740
24943
  return null;
@@ -24778,7 +24981,7 @@ async function handleRemoveArrayItem(request, manifestWriter) {
24778
24981
  const { fullPath, arrayIndex } = ctx;
24779
24982
  const release = await acquireFileLock(fullPath);
24780
24983
  try {
24781
- const freshContent = await fs5.readFile(fullPath, "utf-8");
24984
+ const freshContent = await fs4.readFile(fullPath, "utf-8");
24782
24985
  const freshLines = freshContent.split(`
24783
24986
  `);
24784
24987
  const freshFmEnd = findFrontmatterEnd(freshLines);
@@ -24807,7 +25010,7 @@ async function handleRemoveArrayItem(request, manifestWriter) {
24807
25010
  freshLines[removeStart - 1] = prevLine.replace(/,\s*$/, "");
24808
25011
  }
24809
25012
  }
24810
- await fs5.writeFile(fullPath, freshLines.join(`
25013
+ await fs4.writeFile(fullPath, freshLines.join(`
24811
25014
  `), "utf-8");
24812
25015
  return {
24813
25016
  success: true,
@@ -24849,7 +25052,7 @@ async function handleAddArrayItem(request, manifestWriter) {
24849
25052
  const { fullPath, arrayIndex } = ctx;
24850
25053
  const release = await acquireFileLock(fullPath);
24851
25054
  try {
24852
- const freshContent = await fs5.readFile(fullPath, "utf-8");
25055
+ const freshContent = await fs4.readFile(fullPath, "utf-8");
24853
25056
  const freshLines = freshContent.split(`
24854
25057
  `);
24855
25058
  const freshFmEnd = findFrontmatterEnd(freshLines);
@@ -24900,7 +25103,7 @@ async function handleAddArrayItem(request, manifestWriter) {
24900
25103
  break;
24901
25104
  }
24902
25105
  }
24903
- await fs5.writeFile(fullPath, freshLines.join(`
25106
+ await fs4.writeFile(fullPath, freshLines.join(`
24904
25107
  `), "utf-8");
24905
25108
  return {
24906
25109
  success: true,
@@ -24946,17 +25149,17 @@ function formatValue(value) {
24946
25149
  return generateObjectLiteral(value);
24947
25150
  return String(value);
24948
25151
  }
24949
- var import_parser7;
25152
+ var import_parser5;
24950
25153
  var init_array_ops = __esm(() => {
24951
25154
  init_config();
24952
25155
  init_utils2();
24953
25156
  init_component_ops();
24954
- import_parser7 = __toESM(require_lib(), 1);
25157
+ import_parser5 = __toESM(require_lib(), 1);
24955
25158
  });
24956
25159
 
24957
25160
  // ../cms/src/astro-image-paths.ts
24958
25161
  import { createHash as createHash2 } from "crypto";
24959
- import fs6 from "fs/promises";
25162
+ import fs5 from "fs/promises";
24960
25163
  import path6 from "path";
24961
25164
  function isHugoStyleEntry(entryAbsPath) {
24962
25165
  return HUGO_INDEX_RE.test(path6.basename(entryAbsPath));
@@ -25003,10 +25206,10 @@ async function pickHashedSibling(dir, baseName, buf) {
25003
25206
  }
25004
25207
  async function isFreeOrMatching(absPath, compareBuffer) {
25005
25208
  try {
25006
- const stat = await fs6.stat(absPath);
25209
+ const stat = await fs5.stat(absPath);
25007
25210
  if (stat.size !== compareBuffer.length)
25008
25211
  return false;
25009
- const existing = await fs6.readFile(absPath);
25212
+ const existing = await fs5.readFile(absPath);
25010
25213
  return compareBuffer.equals(existing);
25011
25214
  } catch {
25012
25215
  return true;
@@ -25018,7 +25221,7 @@ var init_astro_image_paths = __esm(() => {
25018
25221
  });
25019
25222
 
25020
25223
  // ../cms/src/handlers/astro-image-upload.ts
25021
- import fs7 from "fs/promises";
25224
+ import fs6 from "fs/promises";
25022
25225
  import path7 from "path";
25023
25226
  async function tryAstroImageUpload(args) {
25024
25227
  const { collection, entry, field } = args.context;
@@ -25041,8 +25244,8 @@ async function tryAstroImageUpload(args) {
25041
25244
  originalFilename: args.originalFilename,
25042
25245
  compareBuffer: args.fileBuffer
25043
25246
  });
25044
- await fs7.mkdir(path7.dirname(target.absPath), { recursive: true });
25045
- await fs7.writeFile(target.absPath, args.fileBuffer);
25247
+ await fs6.mkdir(path7.dirname(target.absPath), { recursive: true });
25248
+ await fs6.writeFile(target.absPath, args.fileBuffer);
25046
25249
  return {
25047
25250
  success: true,
25048
25251
  url: target.relPath,
@@ -25055,7 +25258,7 @@ var init_astro_image_upload = __esm(() => {
25055
25258
  });
25056
25259
 
25057
25260
  // ../cms/src/handlers/page-ops.ts
25058
- import fs8 from "fs/promises";
25261
+ import fs7 from "fs/promises";
25059
25262
  async function handleCheckSlugExists(slug) {
25060
25263
  const normalizedSlug = slugify2(slug);
25061
25264
  if (!normalizedSlug)
@@ -25065,7 +25268,7 @@ async function handleCheckSlugExists(slug) {
25065
25268
  }
25066
25269
  async function fileExists(fullPath) {
25067
25270
  try {
25068
- await fs8.access(fullPath);
25271
+ await fs7.access(fullPath);
25069
25272
  return true;
25070
25273
  } catch {
25071
25274
  return false;
@@ -25552,24 +25755,24 @@ var require_lib2 = __commonJS((exports) => {
25552
25755
  // ../../node_modules/domhandler/lib/node.js
25553
25756
  var require_node2 = __commonJS((exports) => {
25554
25757
  var __extends = exports && exports.__extends || function() {
25555
- var extendStatics = function(d2, b2) {
25556
- extendStatics = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function(d3, b3) {
25557
- d3.__proto__ = b3;
25558
- } || function(d3, b3) {
25559
- for (var p in b3)
25560
- if (Object.prototype.hasOwnProperty.call(b3, p))
25561
- d3[p] = b3[p];
25758
+ var extendStatics = function(d, b) {
25759
+ extendStatics = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function(d2, b2) {
25760
+ d2.__proto__ = b2;
25761
+ } || function(d2, b2) {
25762
+ for (var p in b2)
25763
+ if (Object.prototype.hasOwnProperty.call(b2, p))
25764
+ d2[p] = b2[p];
25562
25765
  };
25563
- return extendStatics(d2, b2);
25766
+ return extendStatics(d, b);
25564
25767
  };
25565
- return function(d2, b2) {
25566
- if (typeof b2 !== "function" && b2 !== null)
25567
- throw new TypeError("Class extends value " + String(b2) + " is not a constructor or null");
25568
- extendStatics(d2, b2);
25768
+ return function(d, b) {
25769
+ if (typeof b !== "function" && b !== null)
25770
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
25771
+ extendStatics(d, b);
25569
25772
  function __() {
25570
- this.constructor = d2;
25773
+ this.constructor = d;
25571
25774
  }
25572
- d2.prototype = b2 === null ? Object.create(b2) : (__.prototype = b2.prototype, new __);
25775
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __);
25573
25776
  };
25574
25777
  }();
25575
25778
  var __assign = exports && exports.__assign || function() {
@@ -26176,10 +26379,10 @@ var require_decode = __commonJS((exports) => {
26176
26379
  k2 = k;
26177
26380
  o[k2] = m[k];
26178
26381
  });
26179
- var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? function(o, v2) {
26180
- Object.defineProperty(o, "default", { enumerable: true, value: v2 });
26181
- } : function(o, v2) {
26182
- o["default"] = v2;
26382
+ var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? function(o, v) {
26383
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
26384
+ } : function(o, v) {
26385
+ o["default"] = v;
26183
26386
  });
26184
26387
  var __importStar = exports && exports.__importStar || function(mod) {
26185
26388
  if (mod && mod.__esModule)
@@ -26905,10 +27108,10 @@ var require_lib5 = __commonJS((exports) => {
26905
27108
  k2 = k;
26906
27109
  o[k2] = m[k];
26907
27110
  });
26908
- var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? function(o, v2) {
26909
- Object.defineProperty(o, "default", { enumerable: true, value: v2 });
26910
- } : function(o, v2) {
26911
- o["default"] = v2;
27111
+ var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? function(o, v) {
27112
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
27113
+ } : function(o, v) {
27114
+ o["default"] = v;
26912
27115
  });
26913
27116
  var __importStar = exports && exports.__importStar || function(mod) {
26914
27117
  if (mod && mod.__esModule)
@@ -27438,9 +27641,9 @@ var require_legacy = __commonJS((exports) => {
27438
27641
  return (0, domhandler_1.isTag)(elem) && elem.attribs[attrib] === value;
27439
27642
  };
27440
27643
  }
27441
- function combineFuncs(a, b2) {
27644
+ function combineFuncs(a, b) {
27442
27645
  return function(elem) {
27443
- return a(elem) || b2(elem);
27646
+ return a(elem) || b(elem);
27444
27647
  };
27445
27648
  }
27446
27649
  function compileTest(options) {
@@ -27574,8 +27777,8 @@ var require_helpers = __commonJS((exports) => {
27574
27777
  nodes = nodes.filter(function(node, i, arr) {
27575
27778
  return !arr.includes(node, i + 1);
27576
27779
  });
27577
- nodes.sort(function(a, b2) {
27578
- var relative = compareDocumentPosition(a, b2);
27780
+ nodes.sort(function(a, b) {
27781
+ var relative = compareDocumentPosition(a, b);
27579
27782
  if (relative & DocumentPosition.PRECEDING) {
27580
27783
  return -1;
27581
27784
  } else if (relative & DocumentPosition.FOLLOWING) {
@@ -27864,7 +28067,7 @@ var require_parse = __commonJS((exports) => {
27864
28067
  }
27865
28068
  exports.isTraversal = isTraversal;
27866
28069
  var stripQuotesFromPseudos = new Set(["contains", "icontains"]);
27867
- function funescape(_2, escaped, escapedWhitespace) {
28070
+ function funescape(_, escaped, escapedWhitespace) {
27868
28071
  var high = parseInt(escaped, 16) - 65536;
27869
28072
  return high !== high || escapedWhitespace ? escaped : high < 0 ? String.fromCharCode(high + 65536) : String.fromCharCode(high >> 10 | 55296, high & 1023 | 56320);
27870
28073
  }
@@ -28173,7 +28376,7 @@ var require_parse = __commonJS((exports) => {
28173
28376
  var require_stringify3 = __commonJS((exports) => {
28174
28377
  var __spreadArray = exports && exports.__spreadArray || function(to, from, pack) {
28175
28378
  if (pack || arguments.length === 2)
28176
- for (var i = 0, l2 = from.length, ar;i < l2; i++) {
28379
+ for (var i = 0, l = from.length, ar;i < l; i++) {
28177
28380
  if (ar || !(i in from)) {
28178
28381
  if (!ar)
28179
28382
  ar = Array.prototype.slice.call(from, 0, i);
@@ -28385,8 +28588,8 @@ var require_sort = __commonJS((exports) => {
28385
28588
  } else if (token.name === "has" || token.name === "contains") {
28386
28589
  proc = 0;
28387
28590
  } else if (Array.isArray(token.data)) {
28388
- proc = Math.min.apply(Math, token.data.map(function(d2) {
28389
- return Math.min.apply(Math, d2.map(getProcedure));
28591
+ proc = Math.min.apply(Math, token.data.map(function(d) {
28592
+ return Math.min.apply(Math, d.map(getProcedure));
28390
28593
  }));
28391
28594
  if (proc < 0) {
28392
28595
  proc = 0;
@@ -28666,53 +28869,53 @@ var require_compile = __commonJS((exports) => {
28666
28869
  var boolbase_1 = __importDefault(require_boolbase());
28667
28870
  function compile(parsed) {
28668
28871
  var a = parsed[0];
28669
- var b2 = parsed[1] - 1;
28670
- if (b2 < 0 && a <= 0)
28872
+ var b = parsed[1] - 1;
28873
+ if (b < 0 && a <= 0)
28671
28874
  return boolbase_1.default.falseFunc;
28672
28875
  if (a === -1)
28673
28876
  return function(index) {
28674
- return index <= b2;
28877
+ return index <= b;
28675
28878
  };
28676
28879
  if (a === 0)
28677
28880
  return function(index) {
28678
- return index === b2;
28881
+ return index === b;
28679
28882
  };
28680
28883
  if (a === 1)
28681
- return b2 < 0 ? boolbase_1.default.trueFunc : function(index) {
28682
- return index >= b2;
28884
+ return b < 0 ? boolbase_1.default.trueFunc : function(index) {
28885
+ return index >= b;
28683
28886
  };
28684
28887
  var absA = Math.abs(a);
28685
- var bMod = (b2 % absA + absA) % absA;
28888
+ var bMod = (b % absA + absA) % absA;
28686
28889
  return a > 1 ? function(index) {
28687
- return index >= b2 && index % absA === bMod;
28890
+ return index >= b && index % absA === bMod;
28688
28891
  } : function(index) {
28689
- return index <= b2 && index % absA === bMod;
28892
+ return index <= b && index % absA === bMod;
28690
28893
  };
28691
28894
  }
28692
28895
  exports.compile = compile;
28693
28896
  function generate(parsed) {
28694
28897
  var a = parsed[0];
28695
- var b2 = parsed[1] - 1;
28898
+ var b = parsed[1] - 1;
28696
28899
  var n = 0;
28697
28900
  if (a < 0) {
28698
28901
  var aPos_1 = -a;
28699
- var minValue_1 = (b2 % aPos_1 + aPos_1) % aPos_1;
28902
+ var minValue_1 = (b % aPos_1 + aPos_1) % aPos_1;
28700
28903
  return function() {
28701
28904
  var val = minValue_1 + aPos_1 * n++;
28702
- return val > b2 ? null : val;
28905
+ return val > b ? null : val;
28703
28906
  };
28704
28907
  }
28705
28908
  if (a === 0)
28706
- return b2 < 0 ? function() {
28909
+ return b < 0 ? function() {
28707
28910
  return null;
28708
28911
  } : function() {
28709
- return n++ === 0 ? b2 : null;
28912
+ return n++ === 0 ? b : null;
28710
28913
  };
28711
- if (b2 < 0) {
28712
- b2 += a * Math.ceil(-b2 / a);
28914
+ if (b < 0) {
28915
+ b += a * Math.ceil(-b / a);
28713
28916
  }
28714
28917
  return function() {
28715
- return a * n++ + b2;
28918
+ return a * n++ + b;
28716
28919
  };
28717
28920
  }
28718
28921
  exports.generate = generate;
@@ -29015,7 +29218,7 @@ var require_aliases = __commonJS((exports) => {
29015
29218
  var require_subselects = __commonJS((exports) => {
29016
29219
  var __spreadArray = exports && exports.__spreadArray || function(to, from, pack) {
29017
29220
  if (pack || arguments.length === 2)
29018
- for (var i = 0, l2 = from.length, ar;i < l2; i++) {
29221
+ for (var i = 0, l = from.length, ar;i < l; i++) {
29019
29222
  if (ar || !(i in from)) {
29020
29223
  if (!ar)
29021
29224
  ar = Array.prototype.slice.call(from, 0, i);
@@ -29323,10 +29526,10 @@ var require_compile2 = __commonJS((exports) => {
29323
29526
  k2 = k;
29324
29527
  o[k2] = m[k];
29325
29528
  });
29326
- var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? function(o, v2) {
29327
- Object.defineProperty(o, "default", { enumerable: true, value: v2 });
29328
- } : function(o, v2) {
29329
- o["default"] = v2;
29529
+ var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? function(o, v) {
29530
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
29531
+ } : function(o, v) {
29532
+ o["default"] = v;
29330
29533
  });
29331
29534
  var __importStar = exports && exports.__importStar || function(mod) {
29332
29535
  if (mod && mod.__esModule)
@@ -29425,15 +29628,15 @@ var require_compile2 = __commonJS((exports) => {
29425
29628
  return previous === boolbase_1.default.falseFunc ? boolbase_1.default.falseFunc : (0, general_js_1.compileGeneralSelector)(previous, rule, options, context, compileToken);
29426
29629
  }, (_a = options.rootFunc) !== null && _a !== undefined ? _a : boolbase_1.default.trueFunc);
29427
29630
  }
29428
- function reduceRules(a, b2) {
29429
- if (b2 === boolbase_1.default.falseFunc || a === boolbase_1.default.trueFunc) {
29631
+ function reduceRules(a, b) {
29632
+ if (b === boolbase_1.default.falseFunc || a === boolbase_1.default.trueFunc) {
29430
29633
  return a;
29431
29634
  }
29432
- if (a === boolbase_1.default.falseFunc || b2 === boolbase_1.default.trueFunc) {
29433
- return b2;
29635
+ if (a === boolbase_1.default.falseFunc || b === boolbase_1.default.trueFunc) {
29636
+ return b;
29434
29637
  }
29435
29638
  return function combine(elem) {
29436
- return a(elem) || b2(elem);
29639
+ return a(elem) || b(elem);
29437
29640
  };
29438
29641
  }
29439
29642
  });
@@ -29455,10 +29658,10 @@ var require_lib8 = __commonJS((exports) => {
29455
29658
  k2 = k;
29456
29659
  o[k2] = m[k];
29457
29660
  });
29458
- var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? function(o, v2) {
29459
- Object.defineProperty(o, "default", { enumerable: true, value: v2 });
29460
- } : function(o, v2) {
29461
- o["default"] = v2;
29661
+ var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? function(o, v) {
29662
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
29663
+ } : function(o, v) {
29664
+ o["default"] = v;
29462
29665
  });
29463
29666
  var __importStar = exports && exports.__importStar || function(mod) {
29464
29667
  if (mod && mod.__esModule)
@@ -29481,8 +29684,8 @@ var require_lib8 = __commonJS((exports) => {
29481
29684
  var boolbase_1 = __importDefault(require_boolbase());
29482
29685
  var compile_js_1 = require_compile2();
29483
29686
  var subselects_js_1 = require_subselects();
29484
- var defaultEquals = function(a, b2) {
29485
- return a === b2;
29687
+ var defaultEquals = function(a, b) {
29688
+ return a === b;
29486
29689
  };
29487
29690
  var defaultOptions = {
29488
29691
  adapter: DomUtils,
@@ -29628,7 +29831,7 @@ var require_matcher = __commonJS((exports) => {
29628
29831
  }
29629
29832
  function findOne(test, elems) {
29630
29833
  let elem = null;
29631
- for (let i = 0, l2 = elems === null || elems === undefined ? undefined : elems.length;i < l2 && !elem; i++) {
29834
+ for (let i = 0, l = elems === null || elems === undefined ? undefined : elems.length;i < l && !elem; i++) {
29632
29835
  const el = elems[i];
29633
29836
  if (test(el)) {
29634
29837
  elem = el;
@@ -30186,7 +30389,7 @@ var require_html = __commonJS((exports) => {
30186
30389
  let old = null;
30187
30390
  function findOne(test, elems) {
30188
30391
  let elem = null;
30189
- for (let i = 0, l2 = elems.length;i < l2 && !elem; i++) {
30392
+ for (let i = 0, l = elems.length;i < l && !elem; i++) {
30190
30393
  const el2 = elems[i];
30191
30394
  if (test(el2)) {
30192
30395
  elem = el2;
@@ -30767,14 +30970,64 @@ var require_dist2 = __commonJS((exports) => {
30767
30970
  parse2.TextNode = text_1.default;
30768
30971
  parse2.NodeType = type_1.default;
30769
30972
  });
30973
+ // ../../node_modules/@astrojs/compiler/dist/chunk-W5DTLHV4.js
30974
+ import g from "crypto";
30975
+ import _ from "fs";
30976
+ import { TextDecoder as b, TextEncoder as v } from "util";
30977
+ var y, w;
30978
+ var init_chunk_W5DTLHV4 = __esm(() => {
30979
+ globalThis.fs || Object.defineProperty(globalThis, "fs", { value: _ });
30980
+ globalThis.process || Object.defineProperties(globalThis, "process", { value: process });
30981
+ globalThis.crypto || Object.defineProperty(globalThis, "crypto", { value: g.webcrypto ? g.webcrypto : { getRandomValues(m) {
30982
+ return g.randomFillSync(m);
30983
+ } } });
30984
+ globalThis.performance || Object.defineProperty(globalThis, "performance", { value: { now() {
30985
+ let [m, o] = process.hrtime();
30986
+ return m * 1000 + o / 1e6;
30987
+ } } });
30988
+ y = new v("utf-8");
30989
+ w = new b("utf-8");
30990
+ });
30991
+
30992
+ // ../../node_modules/@astrojs/compiler/dist/node/index.js
30993
+ var init_node = __esm(() => {
30994
+ init_chunk_W5DTLHV4();
30995
+ });
30996
+ // ../cms/src/source-finder/cache.ts
30997
+ var parsedFileCache, directoryCache, markdownFileCache, declaredUrlIndexCache, dirtyFiles;
30998
+ var init_cache = __esm(() => {
30999
+ parsedFileCache = new Map;
31000
+ directoryCache = new Map;
31001
+ markdownFileCache = new Map;
31002
+ declaredUrlIndexCache = new Map;
31003
+ dirtyFiles = new Set;
31004
+ });
31005
+ // ../cms/src/source-finder/variable-extraction.ts
31006
+ var import_parser6;
31007
+ var init_variable_extraction = __esm(() => {
31008
+ import_parser6 = __toESM(require_lib(), 1);
31009
+ });
31010
+
31011
+ // ../cms/src/source-finder/ast-parser.ts
31012
+ var import_parser7, inFlightParsing;
31013
+ var init_ast_parser = __esm(() => {
31014
+ init_node();
31015
+ init_cache();
31016
+ init_variable_extraction();
31017
+ import_parser7 = __toESM(require_lib(), 1);
31018
+ inFlightParsing = new Map;
31019
+ });
30770
31020
 
30771
31021
  // ../cms/src/source-finder/collection-finder.ts
30772
- var import_yaml4;
31022
+ var import_yaml3, specPathnameIndexCache;
30773
31023
  var init_collection_finder = __esm(() => {
31024
+ init_src2();
30774
31025
  init_config();
31026
+ init_scan_cache();
30775
31027
  init_cache();
30776
31028
  init_snippet_utils();
30777
- import_yaml4 = __toESM(require_dist(), 1);
31029
+ import_yaml3 = __toESM(require_dist(), 1);
31030
+ specPathnameIndexCache = new WeakMap;
30778
31031
  });
30779
31032
 
30780
31033
  // ../cms/src/source-finder/search-index.ts
@@ -30832,7 +31085,7 @@ function extractAstroImageOriginalUrl(src) {
30832
31085
  } catch {}
30833
31086
  return;
30834
31087
  }
30835
- var import_yaml5;
31088
+ var import_yaml4;
30836
31089
  var init_snippet_utils = __esm(() => {
30837
31090
  init_astro_image_paths();
30838
31091
  init_config();
@@ -30842,11 +31095,11 @@ var init_snippet_utils = __esm(() => {
30842
31095
  init_cross_file_tracker();
30843
31096
  init_image_finder();
30844
31097
  init_search_index();
30845
- import_yaml5 = __toESM(require_dist(), 1);
31098
+ import_yaml4 = __toESM(require_dist(), 1);
30846
31099
  });
30847
31100
 
30848
31101
  // ../cms/src/handlers/source-writer.ts
30849
- import fs9 from "fs/promises";
31102
+ import fs8 from "fs/promises";
30850
31103
  import path8 from "path";
30851
31104
  async function handleUpdate(request, manifestWriter) {
30852
31105
  const { changes, meta } = request;
@@ -30877,17 +31130,17 @@ async function handleUpdate(request, manifestWriter) {
30877
31130
  const fullPath = resolveAndValidatePath(filePath);
30878
31131
  const release = await acquireFileLock(fullPath);
30879
31132
  try {
30880
- const currentContent = await fs9.readFile(fullPath, "utf-8");
31133
+ const currentContent = await fs8.readFile(fullPath, "utf-8");
30881
31134
  const { newContent, appliedCount, failedChanges, fileOps } = await applyChanges(currentContent, fileChanges, manifest, fullPath, meta.url);
30882
31135
  if (failedChanges.length > 0) {
30883
31136
  errors.push(...failedChanges);
30884
31137
  }
30885
31138
  if (appliedCount > 0 && newContent !== currentContent) {
30886
31139
  for (const op of fileOps) {
30887
- await fs9.mkdir(path8.dirname(op.target), { recursive: true });
30888
- await fs9.writeFile(op.target, op.bytes);
31140
+ await fs8.mkdir(path8.dirname(op.target), { recursive: true });
31141
+ await fs8.writeFile(op.target, op.bytes);
30889
31142
  }
30890
- await fs9.writeFile(fullPath, newContent, "utf-8");
31143
+ await fs8.writeFile(fullPath, newContent, "utf-8");
30891
31144
  updated += appliedCount;
30892
31145
  }
30893
31146
  } finally {
@@ -30980,7 +31233,7 @@ async function applyImageChange(content, change, absFilePath, originUrl) {
30980
31233
  const yamlKeyMatch = change.sourceSnippet.match(/^\s*([\w][\w-]*):\s*/);
30981
31234
  if (yamlKeyMatch?.[1]) {
30982
31235
  try {
30983
- const parsed = import_yaml6.parse(change.sourceSnippet);
31236
+ const parsed = import_yaml5.parse(change.sourceSnippet);
30984
31237
  if (parsed && typeof parsed === "object") {
30985
31238
  const value = parsed[yamlKeyMatch[1]];
30986
31239
  if (typeof value === "string" && !srcCandidates.includes(value)) {
@@ -31165,7 +31418,7 @@ async function resolveNewSrcBytes(newSrc, originUrl) {
31165
31418
  const diskPath = newSrc.startsWith("/src/") ? path8.join(getProjectRoot(), newSrc.slice(1)) : newSrc.startsWith("/") && !newSrc.startsWith("//") ? path8.join(getProjectRoot(), "public", newSrc.replace(/^\/+/, "")) : null;
31166
31419
  if (diskPath) {
31167
31420
  try {
31168
- return { bytes: await fs9.readFile(diskPath), filename: filenameFromPath(newSrc) };
31421
+ return { bytes: await fs8.readFile(diskPath), filename: filenameFromPath(newSrc) };
31169
31422
  } catch {}
31170
31423
  }
31171
31424
  try {
@@ -31597,7 +31850,7 @@ function tryYamlValueReplacement(sourceSnippet, resolvedOriginal, resolvedNewTex
31597
31850
  if (!keyMatch)
31598
31851
  return null;
31599
31852
  try {
31600
- const parsed = import_yaml6.parse(sourceSnippet);
31853
+ const parsed = import_yaml5.parse(sourceSnippet);
31601
31854
  if (parsed == null || typeof parsed !== "object")
31602
31855
  return null;
31603
31856
  const value = parsed[keyMatch[2]];
@@ -31608,7 +31861,7 @@ function tryYamlValueReplacement(sourceSnippet, resolvedOriginal, resolvedNewTex
31608
31861
  } catch {
31609
31862
  return null;
31610
31863
  }
31611
- const serialized = import_yaml6.stringify(resolvedNewText, { lineWidth: 0 }).trimEnd();
31864
+ const serialized = import_yaml5.stringify(resolvedNewText, { lineWidth: 0 }).trimEnd();
31612
31865
  return `${keyMatch[1]}${serialized}`;
31613
31866
  }
31614
31867
  function tryDataFileValueReplacement(content, sourceSnippet, originalValue, newValue, sourceLine) {
@@ -31696,14 +31949,14 @@ function tryBrNormalizedChange(sourceSnippet, resolvedOriginal, resolvedNewText)
31696
31949
  }
31697
31950
  return result !== sourceSnippet ? result : null;
31698
31951
  }
31699
- var import_node_html_parser, import_yaml6, ASSET_IMPORT_EXT_RE, REMOTE_FETCH_TIMEOUT_MS = 15000, REMOTE_FETCH_MAX_BYTES, QUOTED_LITERAL_DELIMITERS;
31952
+ var import_node_html_parser, import_yaml5, ASSET_IMPORT_EXT_RE, REMOTE_FETCH_TIMEOUT_MS = 15000, REMOTE_FETCH_MAX_BYTES, QUOTED_LITERAL_DELIMITERS;
31700
31953
  var init_source_writer = __esm(() => {
31701
31954
  init_astro_image_paths();
31702
31955
  init_config();
31703
31956
  init_snippet_utils();
31704
31957
  init_utils2();
31705
31958
  import_node_html_parser = __toESM(require_dist2(), 1);
31706
- import_yaml6 = __toESM(require_dist(), 1);
31959
+ import_yaml5 = __toESM(require_dist(), 1);
31707
31960
  ASSET_IMPORT_EXT_RE = /\.(jpe?g|png|gif|webp|avif|svg|ico|bmp|tiff?)$/i;
31708
31961
  REMOTE_FETCH_MAX_BYTES = 50 * 1024 * 1024;
31709
31962
  QUOTED_LITERAL_DELIMITERS = [`'`, `"`, "`"];
@@ -31774,9 +32027,9 @@ function lastSlug(sourcePath) {
31774
32027
  var ALLOWED_UPLOAD_TYPES, DATA_EXTENSIONS, routeMap;
31775
32028
  var init_api_routes = __esm(() => {
31776
32029
  init_src2();
31777
- init_collection_scanner2();
31778
32030
  init_config();
31779
32031
  init_dev_middleware();
32032
+ init_scan_cache();
31780
32033
  init_array_ops();
31781
32034
  init_astro_image_upload();
31782
32035
  init_component_ops();
@@ -32085,7 +32338,7 @@ var init_color_patterns = __esm(() => {
32085
32338
  });
32086
32339
 
32087
32340
  // ../cms/src/tailwind-colors.ts
32088
- import fs10 from "fs/promises";
32341
+ import fs9 from "fs/promises";
32089
32342
  import path10 from "path";
32090
32343
  async function parseTailwindConfig(projectRoot = getProjectRoot()) {
32091
32344
  const cssFiles = [
@@ -32102,7 +32355,7 @@ async function parseTailwindConfig(projectRoot = getProjectRoot()) {
32102
32355
  for (const cssFile of cssFiles) {
32103
32356
  const fullPath = path10.join(projectRoot, cssFile);
32104
32357
  try {
32105
- const content = await fs10.readFile(fullPath, "utf-8");
32358
+ const content = await fs9.readFile(fullPath, "utf-8");
32106
32359
  customColors = extractColorsFromCss(content);
32107
32360
  if (customColors.length > 0) {
32108
32361
  break;
@@ -32175,7 +32428,7 @@ async function parseTextStyles(projectRoot = getProjectRoot()) {
32175
32428
  for (const cssFile of cssFiles) {
32176
32429
  const fullPath = path10.join(projectRoot, cssFile);
32177
32430
  try {
32178
- const content = await fs10.readFile(fullPath, "utf-8");
32431
+ const content = await fs9.readFile(fullPath, "utf-8");
32179
32432
  customTextStyles = extractTextStylesFromCss(content);
32180
32433
  if (Object.values(customTextStyles).some((arr) => arr && arr.length > 0)) {
32181
32434
  break;
@@ -32640,7 +32893,7 @@ var init_local_admin = __esm(() => {
32640
32893
  });
32641
32894
 
32642
32895
  // ../cms/src/manifest-writer.ts
32643
- import fs11 from "fs/promises";
32896
+ import fs10 from "fs/promises";
32644
32897
  import path11 from "path";
32645
32898
 
32646
32899
  class ManifestWriter {
@@ -32742,7 +32995,7 @@ class ManifestWriter {
32742
32995
  async writePageManifest(pagePath, entries, components, collection, seo) {
32743
32996
  const manifestPath = this.getPageManifestPath(pagePath);
32744
32997
  const manifestDir = path11.dirname(manifestPath);
32745
- await fs11.mkdir(manifestDir, { recursive: true });
32998
+ await fs10.mkdir(manifestDir, { recursive: true });
32746
32999
  const metadata = {
32747
33000
  version: MANIFEST_VERSION,
32748
33001
  generatedAt: new Date().toISOString(),
@@ -32763,7 +33016,7 @@ class ManifestWriter {
32763
33016
  if (seo) {
32764
33017
  pageManifest.seo = seo;
32765
33018
  }
32766
- await fs11.writeFile(manifestPath, JSON.stringify(pageManifest, null, 2), "utf-8");
33019
+ await fs10.writeFile(manifestPath, JSON.stringify(pageManifest, null, 2), "utf-8");
32767
33020
  }
32768
33021
  async finalize() {
32769
33022
  await this.writeQueue;
@@ -32782,12 +33035,17 @@ class ManifestWriter {
32782
33035
  }
32783
33036
  }
32784
33037
  for (const def of Object.values(this.collectionDefinitions)) {
32785
- if (def.entries) {
32786
- for (const entry of def.entries) {
32787
- const pathname = collectionPathMap.get(`${def.name}/${entry.slug}`);
32788
- if (pathname) {
32789
- entry.pathname = pathname;
32790
- }
33038
+ if (!def.entries)
33039
+ continue;
33040
+ for (const entry of def.entries) {
33041
+ const fromSpec = resolvePathnameFromSpec(def, entry.data);
33042
+ if (fromSpec) {
33043
+ entry.pathname = fromSpec;
33044
+ continue;
33045
+ }
33046
+ const pathname = collectionPathMap.get(`${def.name}/${entry.slug}`);
33047
+ if (pathname) {
33048
+ entry.pathname = pathname;
32791
33049
  }
32792
33050
  }
32793
33051
  }
@@ -32806,7 +33064,7 @@ class ManifestWriter {
32806
33064
  if (this.availableTextStyles) {
32807
33065
  globalSettings.availableTextStyles = this.availableTextStyles;
32808
33066
  }
32809
- await fs11.writeFile(globalManifestPath, JSON.stringify(globalSettings, null, 2), "utf-8");
33067
+ await fs10.writeFile(globalManifestPath, JSON.stringify(globalSettings, null, 2), "utf-8");
32810
33068
  }
32811
33069
  return {
32812
33070
  totalEntries: Object.keys(this.globalManifest.entries).length,
@@ -32855,6 +33113,7 @@ class ManifestWriter {
32855
33113
  }
32856
33114
  var MANIFEST_VERSION = "1.0";
32857
33115
  var init_manifest_writer = __esm(() => {
33116
+ init_src2();
32858
33117
  init_config();
32859
33118
  init_tailwind_colors();
32860
33119
  init_utils2();
@@ -33402,12 +33661,12 @@ var init_field_types = __esm(() => {
33402
33661
  });
33403
33662
 
33404
33663
  // ../cms/src/migrate-astro-image.ts
33405
- import fs12 from "fs/promises";
33664
+ import fs11 from "fs/promises";
33406
33665
  import path12 from "path";
33407
33666
  async function migrateAstroImages(options = {}) {
33408
33667
  const projectRoot = options.projectRoot ?? getProjectRoot();
33409
33668
  const dryRun = options.dryRun ?? false;
33410
- const collections = await scanCollections2();
33669
+ const collections = await scanCollections(createNodeFs(projectRoot));
33411
33670
  const migrations = [];
33412
33671
  const skipped = [];
33413
33672
  for (const def of Object.values(collections)) {
@@ -33418,7 +33677,7 @@ async function migrateAstroImages(options = {}) {
33418
33677
  const entryAbs = path12.isAbsolute(entry.sourcePath) ? entry.sourcePath : path12.join(projectRoot, entry.sourcePath);
33419
33678
  let raw;
33420
33679
  try {
33421
- raw = await fs12.readFile(entryAbs, "utf-8");
33680
+ raw = await fs11.readFile(entryAbs, "utf-8");
33422
33681
  } catch {
33423
33682
  skipped.push({ entrySourcePath: entry.sourcePath, fieldName: "*", reason: "read failed" });
33424
33683
  continue;
@@ -33429,7 +33688,7 @@ async function migrateAstroImages(options = {}) {
33429
33688
  continue;
33430
33689
  }
33431
33690
  const [fullFm, fmStart, yamlBody, fmEnd] = fmMatch;
33432
- const doc2 = import_yaml7.parseDocument(yamlBody);
33691
+ const doc2 = import_yaml6.parseDocument(yamlBody);
33433
33692
  let mutated = false;
33434
33693
  for (const field of astroFields) {
33435
33694
  const current = doc2.get(field.name);
@@ -33443,7 +33702,7 @@ async function migrateAstroImages(options = {}) {
33443
33702
  const sourceAbs = path12.join(projectRoot, "public", current.replace(/^\/+/, ""));
33444
33703
  let sourceBuf;
33445
33704
  try {
33446
- sourceBuf = await fs12.readFile(sourceAbs);
33705
+ sourceBuf = await fs11.readFile(sourceAbs);
33447
33706
  } catch {
33448
33707
  skipped.push({ entrySourcePath: entry.sourcePath, fieldName: field.name, reason: `source missing: ${sourceAbs}` });
33449
33708
  continue;
@@ -33455,8 +33714,8 @@ async function migrateAstroImages(options = {}) {
33455
33714
  compareBuffer: sourceBuf
33456
33715
  });
33457
33716
  if (!dryRun) {
33458
- await fs12.mkdir(path12.dirname(target.absPath), { recursive: true });
33459
- await fs12.writeFile(target.absPath, sourceBuf);
33717
+ await fs11.mkdir(path12.dirname(target.absPath), { recursive: true });
33718
+ await fs11.writeFile(target.absPath, sourceBuf);
33460
33719
  }
33461
33720
  doc2.set(field.name, target.relPath);
33462
33721
  mutated = true;
@@ -33472,18 +33731,18 @@ async function migrateAstroImages(options = {}) {
33472
33731
  if (mutated && !dryRun) {
33473
33732
  const newYaml = doc2.toString().replace(/\n$/, "");
33474
33733
  const newRaw = raw.replace(fullFm, `${fmStart}${newYaml}${fmEnd}`);
33475
- await fs12.writeFile(entryAbs, newRaw, "utf-8");
33734
+ await fs11.writeFile(entryAbs, newRaw, "utf-8");
33476
33735
  }
33477
33736
  }
33478
33737
  }
33479
33738
  return { migrations, skipped };
33480
33739
  }
33481
- var import_yaml7, FRONTMATTER_RE;
33740
+ var import_yaml6, FRONTMATTER_RE;
33482
33741
  var init_migrate_astro_image = __esm(() => {
33742
+ init_src2();
33483
33743
  init_astro_image_paths();
33484
- init_collection_scanner2();
33485
33744
  init_config();
33486
- import_yaml7 = __toESM(require_dist(), 1);
33745
+ import_yaml6 = __toESM(require_dist(), 1);
33487
33746
  FRONTMATTER_RE = /^(---\r?\n)([\s\S]*?)(\r?\n---\r?\n?)/;
33488
33747
  });
33489
33748
 
@@ -33491,7 +33750,6 @@ var init_migrate_astro_image = __esm(() => {
33491
33750
  var DEFAULT_MAX_UPLOAD_SIZE;
33492
33751
  var init_src3 = __esm(() => {
33493
33752
  init_src2();
33494
- init_collection_scanner2();
33495
33753
  init_component_registry2();
33496
33754
  init_config();
33497
33755
  init_dev_middleware();
@@ -33499,13 +33757,14 @@ var init_src3 = __esm(() => {
33499
33757
  init_manifest_writer();
33500
33758
  init_mode();
33501
33759
  init_remark_list_directive();
33760
+ init_scan_cache();
33502
33761
  init_utils2();
33503
33762
  init_vite_plugin();
33504
33763
  init_src2();
33505
33764
  init_src();
33506
33765
  init_field_types();
33507
33766
  init_mode();
33508
- init_collection_scanner2();
33767
+ init_src2();
33509
33768
  init_config();
33510
33769
  init_migrate_astro_image();
33511
33770
  init_source_finder();