{"version":3,"file":"collections-DSBGdPVj.cjs","names":[],"sources":["../../src/content/frontmatter.ts","../../src/content/markdown.ts","../../src/content/schema.ts","../../src/content/collections.ts"],"sourcesContent":["// --- Frontmatter parser (YAML subset, zero dependencies) ---\n//\n// Parses the YAML subset that covers ~95% of real-world frontmatter:\n//   - scalar key/value pairs (strings, numbers, booleans, null)\n//   - dates (ISO 8601)\n//   - inline arrays: [a, b, c]\n//   - block arrays:\n//       tags:\n//         - foo\n//         - bar\n//   - quoted strings (single and double)\n//\n// This is NOT a full YAML parser. It deliberately rejects nested mappings and\n// complex types. If a project needs full YAML, it can install `yaml` as a peer\n// dependency and we can add a fallback later.\n\nexport interface ParsedFrontmatter {\n  data: Record<string, unknown>;\n  body: string;\n}\n\n/**\n * Splits a Markdown document into frontmatter and body. Returns the raw\n * frontmatter string (without the `---` fences) and the body.\n */\nexport function splitFrontmatter(source: string): { raw: string; body: string } {\n  if (!source.startsWith(\"---\")) return { raw: \"\", body: source };\n\n  // Find the closing `---` on its own line.\n  const rest = source.slice(3);\n  const closeMatch = rest.match(/^.*?\\n---[ \\t]*\\r?\\n?/s);\n  if (!closeMatch) return { raw: \"\", body: source };\n\n  const raw = rest.slice(0, closeMatch.index! + closeMatch[0].length - 4).trim();\n  const body = rest.slice(closeMatch.index! + closeMatch[0].length);\n  return { raw, body };\n}\n\n/**\n * Parses a YAML-subset frontmatter string into a JS object.\n */\nexport function parseFrontmatter(raw: string): Record<string, unknown> {\n  const result: Record<string, unknown> = {};\n  const lines = raw.split(/\\r?\\n/);\n\n  let i = 0;\n  while (i < lines.length) {\n    const line = lines[i];\n    // Skip blank lines and comments.\n    if (!line.trim() || line.trim().startsWith(\"#\")) {\n      i++;\n      continue;\n    }\n\n    const kvMatch = line.match(/^(\\S[^:]*):\\s*(.*)$/);\n    if (!kvMatch) {\n      i++;\n      continue;\n    }\n\n    const key = kvMatch[1].trim();\n    const value = kvMatch[2].trim();\n\n    // Block array: value is empty, next lines are indented `- item`.\n    if (value === \"\") {\n      // Check if next lines are indented list items.\n      const items: unknown[] = [];\n      let j = i + 1;\n      while (j < lines.length) {\n        const nextLine = lines[j];\n        if (!nextLine.trim()) {\n          j++;\n          continue;\n        }\n        const listItemMatch = nextLine.match(/^\\s+-\\s+(.*)$/);\n        if (listItemMatch) {\n          items.push(parseScalar(listItemMatch[1].trim()));\n          j++;\n          continue;\n        }\n        // Indented non-list content (nested mapping) — not supported.\n        if (/^\\s+\\S/.test(nextLine) && !listItemMatch) {\n          // Could be a nested map; we skip it gracefully.\n          j++;\n          continue;\n        }\n        break;\n      }\n      if (items.length > 0) {\n        result[key] = items;\n        i = j;\n      } else {\n        // Empty value (null).\n        result[key] = null;\n        i++;\n      }\n      continue;\n    }\n\n    result[key] = parseValue(value);\n    i++;\n  }\n\n  return result;\n}\n\n/**\n * Parses a scalar value, handling inline arrays, quoted strings, numbers,\n * booleans, null and ISO dates.\n */\nfunction parseValue(value: string): unknown {\n  // Inline array: [a, b, c]\n  if (value.startsWith(\"[\") && value.endsWith(\"]\")) {\n    const inner = value.slice(1, -1).trim();\n    if (!inner) return [];\n    return inner.split(\",\").map((item) => parseScalar(item.trim()));\n  }\n  return parseScalar(value);\n}\n\nfunction parseScalar(value: string): unknown {\n  if (!value) return null;\n\n  // Double-quoted string.\n  if (value.startsWith('\"') && value.endsWith('\"')) {\n    return unescapeQuoted(value.slice(1, -1));\n  }\n  // Single-quoted string.\n  if (value.startsWith(\"'\") && value.endsWith(\"'\")) {\n    return value.slice(1, -1).replace(/''/g, \"'\");\n  }\n\n  // Boolean.\n  const lower = value.toLowerCase();\n  if (lower === \"true\") return true;\n  if (lower === \"false\") return false;\n  if (lower === \"null\" || lower === \"~\") return null;\n\n  // Number (int, float, negative, scientific).\n  if (/^-?\\d+$/.test(value)) return parseInt(value, 10);\n  if (/^-?\\d+\\.\\d+$/.test(value)) return parseFloat(value);\n  if (/^-?\\d+(\\.\\d+)?[eE][-+]?\\d+$/.test(value)) return parseFloat(value);\n\n  // ISO date: YYYY-MM-DD or full ISO 8601.\n  if (/^\\d{4}-\\d{2}-\\d{2}(T\\d{2}:\\d{2}(:\\d{2})?(\\.\\d+)?(Z|[+-]\\d{2}:?\\d{2})?)?$/.test(value)) {\n    const date = new Date(value);\n    if (!isNaN(date.getTime())) return date;\n  }\n\n  // Plain string.\n  return value;\n}\n\nfunction unescapeQuoted(value: string): string {\n  return value\n    .replace(/\\\\n/g, \"\\n\")\n    .replace(/\\\\t/g, \"\\t\")\n    .replace(/\\\\\"/g, '\"')\n    .replace(/\\\\\\\\/g, \"\\\\\");\n}\n\n/**\n * Parses a full Markdown document (frontmatter + body) in one call.\n */\nexport function parseDocument(source: string): ParsedFrontmatter {\n  const { raw, body } = splitFrontmatter(source);\n  const data = raw ? parseFrontmatter(raw) : {};\n  return { data, body: body.trimStart() };\n}\n","// --- Markdown → HTML renderer (optional `marked` peer dependency) ---\n//\n// Markdown rendering is delegated to `marked` when available. If `marked` is\n// not installed, a clear error is thrown with installation instructions.\n//\n// The resulting HTML is treated as trusted author content (same model as\n// Astro). If you render user-generated Markdown, sanitize it yourself before\n// passing it to the renderer.\n\ntype MarkedModule = { marked: (src: string) => string };\nlet markedLoader: (() => Promise<MarkedModule>) | null | undefined;\n\n/**\n * Lazily loads `marked` from the user's project. We use a dynamic import so\n * the kit itself has no hard dependency on `marked`.\n */\nasync function loadMarked(): Promise<MarkedModule> {\n  if (markedLoader === null) {\n    throw new Error(\n      \"[nix-js-kit] Markdown rendering requires the `marked` package. Install it with:\\n\" +\n      \"  npm install marked\\n\" +\n      \"  # or\\n\" +\n      \"  bun add marked\",\n    );\n  }\n  if (markedLoader) return await markedLoader();\n\n  // Try to import `marked` from the user's project.\n  try {\n    // @ts-ignore — `marked` is an optional peer dependency.\n    const mod = (await import(\"marked\")) as unknown as { marked?: (src: string) => string; default?: (src: string) => string };\n    const fn = (typeof mod.marked === \"function\" ? mod.marked : mod.default) as (src: string) => string;\n    const wrapped = { marked: fn };\n    markedLoader = async () => wrapped;\n    return wrapped;\n  } catch {\n    markedLoader = null;\n    throw new Error(\n      \"[nix-js-kit] Markdown rendering requires the `marked` package. Install it with:\\n\" +\n      \"  npm install marked\\n\" +\n      \"  # or\\n\" +\n      \"  bun add marked\",\n    );\n  }\n}\n\n/**\n * Renders a Markdown string to HTML using `marked`.\n *\n * @throws If `marked` is not installed.\n */\nexport async function renderMarkdown(source: string): Promise<string> {\n  const { marked } = await loadMarked();\n  return marked(source) as string;\n}\n","// --- Schema validation (optional `zod` peer dependency) ---\n//\n// Collections can define a schema for their frontmatter. When `zod` is\n// installed, schemas are validated at parse time and errors include the file\n// path and field. When `zod` is not installed, schemas are ignored (the data\n// is returned as-is) so the content layer still works without validation.\n\nexport interface SchemaValidator {\n  (data: unknown, filePath: string): Record<string, unknown>;\n}\n\nlet zodLoader: (() => Promise<any>) | null | undefined;\n\nasync function loadZod(): Promise<any | null> {\n  if (zodLoader === null) return null;\n  if (zodLoader) return zodLoader();\n  try {\n    // @ts-ignore — `zod` is an optional peer dependency.\n    const mod = await import(\"zod\");\n    zodLoader = async () => mod;\n    return mod;\n  } catch {\n    zodLoader = null;\n    return null;\n  }\n}\n\n/**\n * Creates a validator function from a schema object. If the schema is a zod\n * schema (has a `.parse` method), it is used directly. If `zod` is not\n * installed but a schema is provided, validation is skipped with a warning.\n */\nexport function createValidator(schema: unknown): SchemaValidator | undefined {\n  if (!schema) return undefined;\n\n  // Check if it's a zod schema (duck-typing).\n  if (schema && typeof schema === \"object\" && typeof (schema as any).parse === \"function\") {\n    return (data: unknown, filePath: string) => {\n      try {\n        return (schema as any).parse(data);\n      } catch (err: any) {\n        const issues = err?.issues ?? err?.errors ?? [];\n        const details = Array.isArray(issues)\n          ? issues.map((i: any) => `  - ${i.path?.join(\".\") ?? \"(root)\"}: ${i.message}`).join(\"\\n\")\n          : String(err);\n        throw new Error(\n          `[nix-js-kit] Schema validation failed for \"${filePath}\":\\n${details}`,\n        );\n      }\n    };\n  }\n\n  // Plain function validator.\n  if (typeof schema === \"function\") {\n    return (data: unknown, filePath: string) => {\n      try {\n        return (schema as Function)(data);\n      } catch (err: any) {\n        throw new Error(`[nix-js-kit] Schema validation failed for \"${filePath}\": ${err?.message ?? err}`);\n      }\n    };\n  }\n\n  return undefined;\n}\n\n/**\n * Ensures `zod` is available and re-exports it. Used by `defineCollection`\n * consumers who want to write `z.object(...)` schemas.\n */\nexport async function getZod(): Promise<any> {\n  const zod = await loadZod();\n  if (!zod) {\n    throw new Error(\n      \"[nix-js-kit] Schema validation requires the `zod` package. Install it with:\\n\" +\n      \"  npm install zod\\n\" +\n      \"  # or\\n\" +\n      \"  bun add zod\",\n    );\n  }\n  return zod;\n}\n","// --- Content collections ---\n//\n// A collection is a directory under `src/content/<name>/` containing `.md`\n// files. Each file has YAML frontmatter (parsed by our own parser) and a\n// Markdown body (rendered via `marked` when requested).\n//\n// Collections are defined in `src/content/config.ts`:\n//\n//   import { defineCollection } from \"@deijose/nix-js-kit/content\";\n//   export const collections = {\n//     blog: defineCollection({ schema: z.object({ title: z.string() }) }),\n//   };\n//\n// At runtime, `getCollection(\"blog\")` scans the directory, parses frontmatter,\n// validates against the schema (if zod is installed), and returns typed\n// entries. `getEntry(\"blog\", \"hello\")` returns a single entry by slug.\n\nimport { readdir, readFile, stat } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\nimport { parseDocument } from \"./frontmatter.js\";\nimport { renderMarkdown } from \"./markdown.js\";\nimport { createValidator, type SchemaValidator } from \"./schema.js\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\nexport interface CollectionDefinition {\n  /** Schema for frontmatter validation (zod schema or plain function). */\n  schema?: unknown;\n}\n\nexport interface ContentEntry<TData = Record<string, unknown>> {\n  /** Collection name, e.g. \"blog\". */\n  collection: string;\n  /** Entry slug (filename without `.md`), e.g. \"hello-world\". */\n  slug: string;\n  /** Parsed and validated frontmatter. */\n  data: TData;\n  /** Raw Markdown body (not yet rendered to HTML). */\n  body: string;\n  /** Rendered HTML body (lazily computed via `renderHTML()`). */\n  html?: string;\n  /** Absolute path to the source `.md` file. */\n  filePath: string;\n}\n\n/**\n * Defines a collection with an optional schema. Used in `src/content/config.ts`.\n */\nexport function defineCollection(def: CollectionDefinition): CollectionDefinition {\n  return def;\n}\n\n/** Type for the `collections` export from `src/content/config.ts`. */\nexport type CollectionsConfig = Record<string, CollectionDefinition>;\n\n// --- Internal cache ---\n\ninterface CachedCollection {\n  entries: ContentEntry[];\n  loadedAt: number;\n}\n\nconst collectionCache = new Map<string, CachedCollection>();\nconst configCache = new Map<string, CollectionsConfig | null>();\n\nconst CACHE_TTL_MS = 5000; // 5 seconds in dev; invalidated on HMR\n\n// Per-request content root via AsyncLocalStorage (plan §11.4).\n// Falls back to the global contentRoot set by setContentRoot().\nconst contentRootALS = new AsyncLocalStorage<string>();\n\n// Global fallback (set by CLI/Vite plugin on startup).\nlet globalContentRoot: string | null = null;\n\n/**\n * Sets the root directory for content. Called by the Vite plugin / CLI on\n * startup so `getCollection` knows where to find `src/content/`.\n */\nexport function setContentRoot(root: string): void {\n  globalContentRoot = root;\n  collectionCache.clear();\n  configCache.clear();\n}\n\n/**\n * Runs a function with a per-request content root (plan §11.4).\n * This prevents global state leakage between concurrent requests.\n */\nexport function withContentRoot<T>(root: string, fn: () => T): T {\n  return contentRootALS.run(root, fn);\n}\n\nfunction resolveContentRoot(): string {\n  // Prefer per-request context.\n  const alsRoot = contentRootALS.getStore();\n  if (alsRoot) return alsRoot;\n  // Fall back to global.\n  if (globalContentRoot) return globalContentRoot;\n  // Final fallback: assume CWD/src/content.\n  return join(process.cwd(), \"src\", \"content\");\n}\n\n/**\n * Loads the user's `src/content/config.ts` (if it exists) and returns the\n * collections config.\n */\nasync function loadCollectionsConfig(root: string): Promise<CollectionsConfig | null> {\n  const cacheKey = root;\n  if (configCache.has(cacheKey)) return configCache.get(cacheKey) ?? null;\n\n  const configPath = join(root, \"config.ts\");\n  try {\n    await stat(configPath);\n  } catch {\n    configCache.set(cacheKey, null);\n    return null;\n  }\n\n  try {\n    const mod = await import(configPath);\n    const config = (mod.collections ?? mod.default) as CollectionsConfig;\n    configCache.set(cacheKey, config);\n    return config;\n  } catch (err) {\n    console.warn(\"[nix-js-kit] Failed to load content config:\", err);\n    configCache.set(cacheKey, null);\n    return null;\n  }\n}\n\n/**\n * Clears the in-memory cache for all collections. Called by the HMR handler\n * when a `.md` file changes.\n */\nexport function clearContentCache(): void {\n  collectionCache.clear();\n  configCache.clear();\n}\n\n/**\n * Scans a collection directory and returns all entries. Nested directories\n * are scanned recursively; the slug of a nested file includes its relative\n * sub-path (e.g. `getting-started/intro` for `getting-started/intro.md`).\n */\nasync function scanCollection(\n  name: string,\n  collectionDir: string,\n  validator: SchemaValidator | undefined,\n): Promise<ContentEntry[]> {\n  let files: string[];\n  try {\n    files = await readdir(collectionDir, { recursive: true });\n  } catch {\n    return [];\n  }\n\n  const mdFiles = files.filter((f) => f.endsWith(\".md\"));\n  const entries: ContentEntry[] = [];\n\n  for (const file of mdFiles) {\n    const filePath = join(collectionDir, file);\n    const slug = file.slice(0, -3).replace(/\\\\/g, \"/\");\n    const source = await readFile(filePath, \"utf8\");\n    const { data: rawData, body } = parseDocument(source);\n\n    const data = validator ? validator(rawData, filePath) : rawData;\n\n    entries.push({\n      collection: name,\n      slug,\n      data,\n      body,\n      filePath,\n    });\n  }\n\n  // Sort by date descending if a `date` field exists, otherwise by slug.\n  entries.sort((a, b) => {\n    const dateA = (a.data as Record<string, unknown>)?.date;\n    const dateB = (b.data as Record<string, unknown>)?.date;\n    if (dateA instanceof Date && dateB instanceof Date) {\n      return dateB.getTime() - dateA.getTime();\n    }\n    return a.slug.localeCompare(b.slug);\n  });\n\n  return entries;\n}\n\n/**\n * Returns all entries in a collection.\n *\n * @param name Collection name (directory under `src/content/`).\n *\n * Per plan §11.4: collection names are validated for containment — no\n * path traversal or escape from the content root is allowed.\n */\nexport async function getCollection<TData = Record<string, unknown>>(\n  name: string,\n): Promise<ContentEntry<TData>[]> {\n  // Containment check: reject names that could escape the content root.\n  if (!isValidCollectionName(name)) {\n    throw new Error(`[nix-js-kit] Invalid collection name: \"${name}\". Collection names must be alphanumeric with hyphens/underscores only.`);\n  }\n\n  const root = resolveContentRoot();\n  const collectionDir = join(root, name);\n\n  // Verify the resolved path is still inside the content root.\n  const resolvedDir = resolve(collectionDir);\n  const resolvedRoot = resolve(root);\n  if (!resolvedDir.startsWith(resolvedRoot + \"/\") && resolvedDir !== resolvedRoot) {\n    throw new Error(`[nix-js-kit] Collection \"${name}\" escapes the content root.`);\n  }\n\n  const cached = collectionCache.get(`${root}:${name}`);\n  if (cached && Date.now() - cached.loadedAt < CACHE_TTL_MS) {\n    return cached.entries as ContentEntry<TData>[];\n  }\n\n  const config = await loadCollectionsConfig(root);\n  const def = config?.[name];\n  const validator = def ? createValidator(def.schema) : undefined;\n\n  const entries = await scanCollection(name, collectionDir, validator);\n  collectionCache.set(`${root}:${name}`, { entries, loadedAt: Date.now() });\n  return entries as ContentEntry<TData>[];\n}\n\n/**\n * Validates that a collection name is safe (no path traversal, no special chars).\n * Per plan §11.4: containment of collection names.\n */\nfunction isValidCollectionName(name: string): boolean {\n  if (!name || typeof name !== \"string\") return false;\n  // Only allow alphanumeric, hyphens, and underscores.\n  if (!/^[a-zA-Z0-9_-]+$/.test(name)) return false;\n  // Reject names that could be path segments (., .., etc).\n  if (name === \".\" || name === \"..\") return false;\n  return true;\n}\n\n/**\n * Returns a single entry by slug, or `undefined` if not found.\n *\n * @param collection Collection name.\n * @param slug Entry slug (filename without `.md`).\n */\nexport async function getEntry<TData = Record<string, unknown>>(\n  collection: string,\n  slug: string,\n): Promise<ContentEntry<TData> | undefined> {\n  const entries = await getCollection<TData>(collection);\n  return entries.find((e) => e.slug === slug);\n}\n\n/**\n * Returns multiple entries by slug.\n *\n * @param collection Collection name.\n * @param slugs Array of slugs.\n */\nexport async function getEntries<TData = Record<string, unknown>>(\n  collection: string,\n  slugs: string[],\n): Promise<ContentEntry<TData>[]> {\n  const entries = await getCollection<TData>(collection);\n  const slugSet = new Set(slugs);\n  return entries.filter((e) => slugSet.has(e.slug));\n}\n\n/**\n * Renders the Markdown body of an entry to HTML. The result is cached on the\n * entry object so repeated calls don't re-render.\n *\n * @throws If `marked` is not installed.\n */\nexport async function renderEntryHTML(entry: ContentEntry): Promise<string> {\n  if (entry.html) return entry.html;\n  const html = await renderMarkdown(entry.body);\n  entry.html = html;\n  return html;\n}\n"],"mappings":"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"}