@micacms/editor 0.5.0-rc.2 → 0.5.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.
@@ -1 +1 @@
1
- {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../src/check.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA2BH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3B,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,2EAA2E;IAC3E,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,uFAAuF;AACvF,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAkErE;AAoJD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAexD;AAiED,mDAAmD;AACnD,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAkBtE"}
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../src/check.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA2BH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3B,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,2EAA2E;IAC3E,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,uFAAuF;AACvF,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAwErE;AAoJD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAexD;AAiED,mDAAmD;AACnD,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAkBtE"}
package/dist/check.js CHANGED
@@ -7,7 +7,7 @@ import { existsSync } from "node:fs";
7
7
  import { relative } from "node:path";
8
8
  import { DOCUMENT_EXTENSION, documentPath, entryLayout, INDEX_FILE, isValidSlug, MANIFEST_PATH, ORDER_FILE, readCollectionEntry, readSingleton, resolveSlugField, singletonPath, validateFields, } from "@micacms/core";
9
9
  import { within } from "@micacms/core/node";
10
- import { contentFiles, loadSchema } from "@micacms/runtime";
10
+ import { contentFiles, loadSchema, readOnlyParts } from "@micacms/runtime";
11
11
  /** Checks the content under `root` against the model in `<root>/.mica/schema.json`. */
12
12
  export async function checkContent(root) {
13
13
  const files = contentFiles({ root });
@@ -28,6 +28,10 @@ export async function checkContent(root) {
28
28
  return report;
29
29
  }
30
30
  report.model = true;
31
+ // A model from a newer @micacms/astro: this check cannot judge those entries.
32
+ const readOnly = readOnlyParts(site);
33
+ for (const reason of readOnly.values())
34
+ error(MANIFEST_PATH, `Not checked. ${reason}`);
31
35
  const slugs = new Map();
32
36
  for (const [name, def] of Object.entries(site.collections)) {
33
37
  slugs.set(name, new Set(await entrySlugs(files, def.fields, name, error, warning)));
@@ -35,6 +39,8 @@ export async function checkContent(root) {
35
39
  const context = { root, files, site, slugs, error, warning };
36
40
  for (const [name, def] of Object.entries(site.collections)) {
37
41
  report.collections++;
42
+ if (readOnly.has(`collections.${name}`))
43
+ continue;
38
44
  const slugField = resolveSlugField(def);
39
45
  for (const slug of slugs.get(name)) {
40
46
  report.entries++;
@@ -53,6 +59,8 @@ export async function checkContent(root) {
53
59
  }
54
60
  for (const [name, def] of Object.entries(site.singletons)) {
55
61
  report.singletons++;
62
+ if (readOnly.has(`singletons.${name}`))
63
+ continue;
56
64
  const directory = entryLayout(def.fields) === "directory";
57
65
  const base = singletonPath(def.fields, name);
58
66
  const dataPath = directory ? `${base}/${INDEX_FILE}` : base;
package/dist/check.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"check.js","sourceRoot":"","sources":["../src/check.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `mica check` — reads every entry the way Mica and the website read it, and\n * reports what they would skip, refuse or render as a gap. It never opens a\n * browser and exits with 1 when it finds an error, for CI and coding agents.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { relative } from \"node:path\";\n\nimport {\n DOCUMENT_EXTENSION,\n documentPath,\n entryLayout,\n INDEX_FILE,\n isValidSlug,\n MANIFEST_PATH,\n ORDER_FILE,\n readCollectionEntry,\n readSingleton,\n resolveSlugField,\n singletonPath,\n validateFields,\n type AnyField,\n type ContentSource,\n type FieldMap,\n type PathSegment,\n type Site,\n} from \"@micacms/core\";\nimport { within } from \"@micacms/core/node\";\nimport { contentFiles, loadSchema } from \"@micacms/runtime\";\n\nexport interface CheckProblem {\n level: \"error\" | \"warning\";\n /** The file, relative to the content root. */\n path: string;\n message: string;\n}\n\nexport interface CheckReport {\n problems: CheckProblem[];\n /** False when the model could not be read, so nothing else was checked. */\n model: boolean;\n collections: number;\n entries: number;\n singletons: number;\n}\n\n/** Checks the content under `root` against the model in `<root>/.mica/schema.json`. */\nexport async function checkContent(root: string): Promise<CheckReport> {\n const files = contentFiles({ root });\n const report: CheckReport = { problems: [], model: false, collections: 0, entries: 0, singletons: 0 };\n const error = (path: string, message: string) => report.problems.push({ level: \"error\", path, message });\n const warning = (path: string, message: string) => report.problems.push({ level: \"warning\", path, message });\n\n const manifest = await readText(files, MANIFEST_PATH);\n if (manifest === null || manifest instanceof Error) {\n error(MANIFEST_PATH, manifest?.message ?? \"There is no content model. Run `npx astro sync` in the Astro project to write it.\");\n return report;\n }\n let site: Site;\n try {\n site = await loadSchema(files);\n } catch (cause) {\n error(MANIFEST_PATH, (cause as Error).message);\n return report;\n }\n report.model = true;\n\n const slugs = new Map<string, Set<string>>();\n for (const [name, def] of Object.entries(site.collections)) {\n slugs.set(name, new Set(await entrySlugs(files, def.fields, name, error, warning)));\n }\n\n const context: EntryContext = { root, files, site, slugs, error, warning };\n\n for (const [name, def] of Object.entries(site.collections)) {\n report.collections++;\n const slugField = resolveSlugField(def);\n for (const slug of slugs.get(name)!) {\n report.entries++;\n const directory = entryLayout(def.fields) === \"directory\";\n const base = directory ? `${name}/${slug}` : null;\n const dataPath = directory ? `${base}/${INDEX_FILE}` : `${name}/${slug}.json`;\n\n const data = await readOrReport(() => readCollectionEntry(files, def, name, slug), dataPath, error);\n if (!data) continue;\n const stored = slugField ? data[slugField] : undefined;\n if (typeof stored === \"string\" && stored !== \"\" && stored !== slug) {\n warning(dataPath, `${slugField} is \"${stored}\", but the entry is named \"${slug}\". The next save in the editor renames the entry.`);\n }\n await checkEntry(context, def.fields, data, dataPath, base);\n }\n }\n\n for (const [name, def] of Object.entries(site.singletons)) {\n report.singletons++;\n const directory = entryLayout(def.fields) === \"directory\";\n const base = singletonPath(def.fields, name);\n const dataPath = directory ? `${base}/${INDEX_FILE}` : base;\n const otherLayout = directory ? `${name}.json` : `${name}/${INDEX_FILE}`;\n if ((await readText(files, otherLayout)) !== null) {\n error(otherLayout, `Not read: \"${def.label}\" is stored as ${dataPath}, because ${directory ? \"it has\" : \"it has no\"} rich text or media.`);\n }\n\n const data = await readOrReport(() => readSingleton(files, def, name), dataPath, error);\n if (data === undefined) continue;\n if (data === null) {\n warning(dataPath, `No content for \"${def.label}\" yet.`);\n continue;\n }\n await checkEntry(context, def.fields, data, dataPath, directory ? base : null);\n }\n\n return report;\n}\n\ninterface EntryContext {\n root: string;\n files: ContentSource;\n site: Site;\n slugs: Map<string, Set<string>>;\n error(path: string, message: string): void;\n warning(path: string, message: string): void;\n}\n\n/** The slugs Mica reads in a collection, reporting what it would skip. */\nasync function entrySlugs(\n files: ContentSource,\n fields: FieldMap,\n name: string,\n error: (path: string, message: string) => void,\n warning: (path: string, message: string) => void,\n): Promise<string[]> {\n const directory = entryLayout(fields) === \"directory\";\n const shape = directory ? `a folder with ${INDEX_FILE}` : \"a <slug>.json file\";\n const found: string[] = [];\n\n for (const item of await files.list(name)) {\n const path = `${name}/${item.name}`;\n if (item.name.startsWith(\".\")) continue;\n if (item.name === ORDER_FILE) {\n checkOrder(await readText(files, path), path, error);\n continue;\n }\n\n // An entry in the other layout is lost content, not a stray file: the model gained or lost rich text or media.\n if (directory && item.type === \"file\" && item.name.endsWith(\".json\")) {\n error(path, `Not read: entries of \"${name}\" are folders with ${INDEX_FILE}, because it has rich text or media.`);\n continue;\n }\n if (!directory && item.type === \"directory\" && (await readText(files, `${path}/${INDEX_FILE}`)) !== null) {\n error(path, `Not read: entries of \"${name}\" are <slug>.json files, because it has no rich text or media.`);\n continue;\n }\n\n const slug = directory ? item.name : item.name.replace(/\\.json$/, \"\");\n const looksLikeEntry = directory ? item.type === \"directory\" : item.type === \"file\" && item.name.endsWith(\".json\");\n if (!looksLikeEntry) {\n warning(path, `Not read. Each entry of \"${name}\" is ${shape}.`);\n continue;\n }\n if (!isValidSlug(slug)) {\n error(path, `Not read: \"${slug}\" is not a slug. Use lowercase letters, digits and single hyphens.`);\n continue;\n }\n const index = directory ? await readText(files, `${path}/${INDEX_FILE}`) : \"\";\n if (index === null || index instanceof Error) {\n error(path, `Not read: ${index?.message ?? `the folder has no ${INDEX_FILE}.`}`);\n continue;\n }\n found.push(slug);\n }\n return found;\n}\n\n/** The file's text, null when it is not there, or the error that reading it gave. */\nasync function readText(files: ContentSource, path: string): Promise<string | null | Error> {\n try {\n return await files.read(path);\n } catch (cause) {\n return cause as Error;\n }\n}\n\nfunction checkOrder(text: string | null | Error, path: string, error: (path: string, message: string) => void): void {\n if (text === null) return;\n if (text instanceof Error) return error(path, text.message);\n let order: unknown;\n try {\n order = JSON.parse(text);\n } catch {\n return error(path, \"Not valid JSON. The build fails on it.\");\n }\n if (!Array.isArray(order)) {\n error(path, 'Must be a JSON array of slugs, such as [\"second\", \"first\"]. The build fails on it.');\n }\n}\n\nasync function readOrReport<T>(\n read: () => Promise<T>,\n path: string,\n error: (path: string, message: string) => void,\n): Promise<T | undefined> {\n try {\n return await read();\n } catch (cause) {\n error(path, (cause as Error).message.replace(`${path}: `, \"\"));\n return undefined;\n }\n}\n\nasync function checkEntry(\n context: EntryContext,\n fields: FieldMap,\n data: Record<string, unknown>,\n dataPath: string,\n base: string | null,\n): Promise<void> {\n const { root, files, slugs, error, warning } = context;\n\n const result = validateFields(fields, data, \"storage\");\n if (!result.ok) {\n for (const issue of result.issues) error(dataPath, issue.path ? `${issue.path}: ${issue.message}` : issue.message);\n }\n\n const raw = JSON.parse((await files.read(dataPath))!) as Record<string, unknown>;\n for (const message of unknownKeys(fields, raw, [])) warning(dataPath, message);\n\n visit(fields, data, [], (field, value, path) => {\n const key = path.join(\".\");\n if (field.kind === \"media\") {\n for (const file of list(value)) {\n let exists = false;\n try {\n exists = existsSync(within(root, file));\n } catch {\n // A path outside the content root does not exist for Mica.\n }\n if (!exists) error(dataPath, `${key}: the file \"${file}\" does not exist under the content root.`);\n }\n }\n if (field.kind === \"relation\") {\n for (const slug of list(value)) {\n if (!slugs.get(field.collection)?.has(slug)) {\n error(dataPath, `${key}: there is no \"${slug}\" in \"${field.collection}\".`);\n }\n }\n }\n });\n\n if (base === null) return;\n for (const item of await files.list(base)) {\n if (item.type !== \"file\" || !item.name.endsWith(DOCUMENT_EXTENSION)) continue;\n const path = `${base}/${item.name}`;\n if (!namesRichText(fields, documentPath(item.name))) {\n warning(path, \"Not read: no rich-text field has this name.\");\n continue;\n }\n for (const message of markdocWarnings((await files.read(path)) ?? \"\")) warning(path, message);\n }\n}\n\n/**\n * What Markdoc renders differently from Markdown, found in the text outside\n * code. A scan, not a parse: it can warn about too much, never about too little.\n */\nexport function markdocWarnings(source: string): string[] {\n const prose = source.replace(/^(`{3,}|~{3,})[^\\n]*\\n[\\s\\S]*?^\\1[ \\t]*$/gm, \"\").replace(/`[^`\\n]*`/g, \"\");\n const messages: string[] = [];\n const html = [...new Set([...prose.matchAll(/<\\/?([a-zA-Z][a-zA-Z0-9-]*)(?=[\\s/>])[^>\\n]*>/g)].map((match) => match[1]!.toLowerCase()))];\n if (html.length > 0) {\n messages.push(`Raw HTML (${html.map((tag) => `<${tag}>`).join(\", \")}) is not rendered: Markdoc escapes it.`);\n }\n const tags = [...new Set([...prose.matchAll(/\\{%\\s*([a-zA-Z][\\w-]*)/g)].map((match) => match[1]!))];\n if (tags.length > 0) {\n messages.push(\n `Markdoc tags (${tags.join(\", \")}) render only if the website declares them in renderRichText(source, { config }).`,\n );\n }\n if (/\\[\\^[^\\]]+\\]/.test(prose)) messages.push(\"Footnotes ([^1]) are not Markdoc: they render as plain text.\");\n return messages;\n}\n\nfunction list(value: unknown): string[] {\n const values = Array.isArray(value) ? value : [value];\n return values.filter((item): item is string => typeof item === \"string\" && item !== \"\");\n}\n\n/** Calls `onField` for every field with a value, nested fields included. */\nfunction visit(\n fields: FieldMap,\n data: Record<string, unknown>,\n path: PathSegment[],\n onField: (field: AnyField, value: unknown, path: PathSegment[]) => void,\n): void {\n for (const [key, field] of Object.entries(fields)) {\n const value = data[key];\n if (value === undefined || value === null) continue;\n onField(field, value, [...path, key]);\n if (field.kind === \"object\" && isRecord(value)) visit(field.fields, value, [...path, key], onField);\n if (field.kind === \"repeater\" && Array.isArray(value)) {\n value.forEach((row, index) => {\n if (isRecord(row)) visit(field.fields, row, [...path, key, index], onField);\n });\n }\n }\n}\n\n/** Keys in the stored JSON that the model does not have; Mica drops them on the next save. */\nfunction unknownKeys(fields: FieldMap, raw: Record<string, unknown>, path: PathSegment[]): string[] {\n const messages: string[] = [];\n for (const [key, value] of Object.entries(raw)) {\n const at = [...path, key].join(\".\");\n const field = fields[key];\n if (!field) {\n messages.push(`${at}: the model has no such field. Mica drops it on the next save.`);\n } else if (field.kind === \"richText\") {\n messages.push(`${at}: rich text belongs in ${[...path, key].join(\".\")}${DOCUMENT_EXTENSION}, not in the JSON.`);\n } else if (field.kind === \"object\" && isRecord(value)) {\n messages.push(...unknownKeys(field.fields, value, [...path, key]));\n } else if (field.kind === \"repeater\" && Array.isArray(value)) {\n value.forEach((row, index) => {\n if (isRecord(row)) messages.push(...unknownKeys(field.fields, row, [...path, key, index]));\n });\n }\n }\n return messages;\n}\n\n/** Whether a sidecar's dotted path leads to a rich-text field. */\nfunction namesRichText(fields: FieldMap, path: PathSegment[]): boolean {\n let map: FieldMap | undefined = fields;\n for (const [index, segment] of path.entries()) {\n if (typeof segment === \"number\") continue;\n const field: AnyField | undefined = map?.[segment];\n if (!field) return false;\n if (index === path.length - 1) return field.kind === \"richText\";\n map = field.kind === \"object\" || field.kind === \"repeater\" ? field.fields : undefined;\n }\n return false;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\n/** The report as a person or an agent reads it. */\nexport function formatReport(report: CheckReport, root: string): string {\n const errors = report.problems.filter((problem) => problem.level === \"error\").length;\n const warnings = report.problems.length - errors;\n const lines = [\n report.model\n ? `Checked ${report.entries} ${report.entries === 1 ? \"entry\" : \"entries\"} in ${report.collections} ` +\n `${report.collections === 1 ? \"collection\" : \"collections\"} and ${report.singletons} ` +\n `${report.singletons === 1 ? \"singleton\" : \"singletons\"} in ${relative(process.cwd(), root) || \".\"}.`\n : `Could not read the content model in ${relative(process.cwd(), root) || \".\"}, so no entry was checked.`,\n \"\",\n ];\n for (const problem of report.problems) {\n lines.push(` ${problem.level === \"error\" ? \"error \" : \"warning\"} ${problem.path}`);\n for (const line of problem.message.split(\"\\n\")) lines.push(` ${line.trim()}`);\n }\n if (report.problems.length > 0) lines.push(\"\");\n lines.push(`${errors} ${errors === 1 ? \"error\" : \"errors\"}, ${warnings} ${warnings === 1 ? \"warning\" : \"warnings\"}.`);\n return `${lines.join(\"\\n\")}\\n`;\n}\n"]}
1
+ {"version":3,"file":"check.js","sourceRoot":"","sources":["../src/check.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,WAAW,EACX,UAAU,EACV,WAAW,EACX,aAAa,EACb,UAAU,EACV,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,cAAc,GAMf,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAkB3E,uFAAuF;AACvF,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAY;IAC7C,MAAM,KAAK,GAAG,YAAY,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;IACrC,MAAM,MAAM,GAAgB,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;IACtG,MAAM,KAAK,GAAG,CAAC,IAAY,EAAE,OAAe,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IACzG,MAAM,OAAO,GAAG,CAAC,IAAY,EAAE,OAAe,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAE7G,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;IACtD,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,YAAY,KAAK,EAAE,CAAC;QACnD,KAAK,CAAC,aAAa,EAAE,QAAQ,EAAE,OAAO,IAAI,mFAAmF,CAAC,CAAC;QAC/H,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,IAAU,CAAC;IACf,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,KAAK,CAAC,aAAa,EAAG,KAAe,CAAC,OAAO,CAAC,CAAC;QAC/C,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC;IAEpB,8EAA8E;IAC9E,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACrC,KAAK,MAAM,MAAM,IAAI,QAAQ,CAAC,MAAM,EAAE;QAAE,KAAK,CAAC,aAAa,EAAE,gBAAgB,MAAM,EAAE,CAAC,CAAC;IAEvF,MAAM,KAAK,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC7C,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;QAC3D,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,GAAG,CAAC,MAAM,UAAU,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACtF,CAAC;IAED,MAAM,OAAO,GAAiB,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IAE3E,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;QAC3D,MAAM,CAAC,WAAW,EAAE,CAAC;QACrB,IAAI,QAAQ,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC;YAAE,SAAS;QAClD,MAAM,SAAS,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;QACxC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAE,EAAE,CAAC;YACpC,MAAM,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,WAAW,CAAC;YAC1D,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;YAClD,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,IAAI,OAAO,CAAC;YAE9E,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE,CAAC,mBAAmB,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;YACpG,IAAI,CAAC,IAAI;gBAAE,SAAS;YACpB,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACvD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,EAAE,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBACnE,OAAO,CAAC,QAAQ,EAAE,GAAG,SAAS,QAAQ,MAAM,8BAA8B,IAAI,mDAAmD,CAAC,CAAC;YACrI,CAAC;YACD,MAAM,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QAC1D,MAAM,CAAC,UAAU,EAAE,CAAC;QACpB,IAAI,QAAQ,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC;YAAE,SAAS;QACjD,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,WAAW,CAAC;QAC1D,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC7C,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QAC5D,MAAM,WAAW,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,UAAU,EAAE,CAAC;QACzE,IAAI,CAAC,MAAM,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAClD,KAAK,CAAC,WAAW,EAAE,cAAc,GAAG,CAAC,KAAK,kBAAkB,QAAQ,aAAa,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,sBAAsB,CAAC,CAAC;QAC7I,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QACxF,IAAI,IAAI,KAAK,SAAS;YAAE,SAAS;QACjC,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,OAAO,CAAC,QAAQ,EAAE,mBAAmB,GAAG,CAAC,KAAK,QAAQ,CAAC,CAAC;YACxD,SAAS;QACX,CAAC;QACD,MAAM,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACjF,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAWD,0EAA0E;AAC1E,KAAK,UAAU,UAAU,CACvB,KAAoB,EACpB,MAAgB,EAChB,IAAY,EACZ,KAA8C,EAC9C,OAAgD;IAEhD,MAAM,SAAS,GAAG,WAAW,CAAC,MAAM,CAAC,KAAK,WAAW,CAAC;IACtD,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,iBAAiB,UAAU,EAAE,CAAC,CAAC,CAAC,oBAAoB,CAAC;IAC/E,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,MAAM,IAAI,IAAI,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,GAAG,GAAG,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACpC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QACxC,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC7B,UAAU,CAAC,MAAM,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YACrD,SAAS;QACX,CAAC;QAED,+GAA+G;QAC/G,IAAI,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YACrE,KAAK,CAAC,IAAI,EAAE,yBAAyB,IAAI,sBAAsB,UAAU,sCAAsC,CAAC,CAAC;YACjH,SAAS;QACX,CAAC;QACD,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,MAAM,QAAQ,CAAC,KAAK,EAAE,GAAG,IAAI,IAAI,UAAU,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACzG,KAAK,CAAC,IAAI,EAAE,yBAAyB,IAAI,gEAAgE,CAAC,CAAC;YAC3G,SAAS;QACX,CAAC;QAED,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QACtE,MAAM,cAAc,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACnH,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,OAAO,CAAC,IAAI,EAAE,4BAA4B,IAAI,QAAQ,KAAK,GAAG,CAAC,CAAC;YAChE,SAAS;QACX,CAAC;QACD,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,KAAK,CAAC,IAAI,EAAE,cAAc,IAAI,oEAAoE,CAAC,CAAC;YACpG,SAAS;QACX,CAAC;QACD,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,KAAK,EAAE,GAAG,IAAI,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9E,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC7C,KAAK,CAAC,IAAI,EAAE,aAAa,KAAK,EAAE,OAAO,IAAI,qBAAqB,UAAU,GAAG,EAAE,CAAC,CAAC;YACjF,SAAS;QACX,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,qFAAqF;AACrF,KAAK,UAAU,QAAQ,CAAC,KAAoB,EAAE,IAAY;IACxD,IAAI,CAAC;QACH,OAAO,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,KAAc,CAAC;IACxB,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,IAA2B,EAAE,IAAY,EAAE,KAA8C;IAC3G,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO;IAC1B,IAAI,IAAI,YAAY,KAAK;QAAE,OAAO,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5D,IAAI,KAAc,CAAC;IACnB,IAAI,CAAC;QACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC,IAAI,EAAE,wCAAwC,CAAC,CAAC;IAC/D,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,KAAK,CAAC,IAAI,EAAE,oFAAoF,CAAC,CAAC;IACpG,CAAC;AACH,CAAC;AAED,KAAK,UAAU,YAAY,CACzB,IAAsB,EACtB,IAAY,EACZ,KAA8C;IAE9C,IAAI,CAAC;QACH,OAAO,MAAM,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,KAAK,CAAC,IAAI,EAAG,KAAe,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;QAC/D,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,KAAK,UAAU,UAAU,CACvB,OAAqB,EACrB,MAAgB,EAChB,IAA6B,EAC7B,QAAgB,EAChB,IAAmB;IAEnB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IAEvD,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;IACvD,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QACf,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM;YAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACrH,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAE,CAA4B,CAAC;IACjF,KAAK,MAAM,OAAO,IAAI,WAAW,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;QAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAE/E,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC3B,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC3B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC/B,IAAI,MAAM,GAAG,KAAK,CAAC;gBACnB,IAAI,CAAC;oBACH,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;gBAC1C,CAAC;gBAAC,MAAM,CAAC;oBACP,2DAA2D;gBAC7D,CAAC;gBACD,IAAI,CAAC,MAAM;oBAAE,KAAK,CAAC,QAAQ,EAAE,GAAG,GAAG,eAAe,IAAI,0CAA0C,CAAC,CAAC;YACpG,CAAC;QACH,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC9B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC/B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC5C,KAAK,CAAC,QAAQ,EAAE,GAAG,GAAG,kBAAkB,IAAI,SAAS,KAAK,CAAC,UAAU,IAAI,CAAC,CAAC;gBAC7E,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO;IAC1B,KAAK,MAAM,IAAI,IAAI,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1C,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC;YAAE,SAAS;QAC9E,MAAM,IAAI,GAAG,GAAG,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACpC,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YACpD,OAAO,CAAC,IAAI,EAAE,6CAA6C,CAAC,CAAC;YAC7D,SAAS;QACX,CAAC;QACD,KAAK,MAAM,OAAO,IAAI,eAAe,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YAAE,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAChG,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,4CAA4C,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACzG,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,gDAAgD,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC;IACzI,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpB,QAAQ,CAAC,IAAI,CAAC,aAAa,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;IAC/G,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC;IACpG,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpB,QAAQ,CAAC,IAAI,CACX,iBAAiB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,mFAAmF,CACpH,CAAC;IACJ,CAAC;IACD,IAAI,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,QAAQ,CAAC,IAAI,CAAC,8DAA8D,CAAC,CAAC;IAC9G,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,IAAI,CAAC,KAAc;IAC1B,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACtD,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC;AAC1F,CAAC;AAED,4EAA4E;AAC5E,SAAS,KAAK,CACZ,MAAgB,EAChB,IAA6B,EAC7B,IAAmB,EACnB,OAAuE;IAEvE,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;QACxB,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;YAAE,SAAS;QACpD,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;QACtC,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,QAAQ,CAAC,KAAK,CAAC;YAAE,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC;QACpG,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACtD,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;gBAC3B,IAAI,QAAQ,CAAC,GAAG,CAAC;oBAAE,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC;YAC9E,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC;AAED,8FAA8F;AAC9F,SAAS,WAAW,CAAC,MAAgB,EAAE,GAA4B,EAAE,IAAmB;IACtF,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/C,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC1B,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,gEAAgE,CAAC,CAAC;QACvF,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YACrC,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,0BAA0B,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,kBAAkB,oBAAoB,CAAC,CAAC;QAClH,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACtD,QAAQ,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;QACrE,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7D,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;gBAC3B,IAAI,QAAQ,CAAC,GAAG,CAAC;oBAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;YAC7F,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,kEAAkE;AAClE,SAAS,aAAa,CAAC,MAAgB,EAAE,IAAmB;IAC1D,IAAI,GAAG,GAAyB,MAAM,CAAC;IACvC,KAAK,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;QAC9C,IAAI,OAAO,OAAO,KAAK,QAAQ;YAAE,SAAS;QAC1C,MAAM,KAAK,GAAyB,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC;QACnD,IAAI,CAAC,KAAK;YAAE,OAAO,KAAK,CAAC;QACzB,IAAI,KAAK,KAAK,IAAI,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC,IAAI,KAAK,UAAU,CAAC;QAChE,GAAG,GAAG,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IACxF,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,YAAY,CAAC,MAAmB,EAAE,IAAY;IAC5D,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;IACrF,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,MAAM,CAAC;IACjD,MAAM,KAAK,GAAG;QACZ,MAAM,CAAC,KAAK;YACV,CAAC,CAAC,WAAW,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,OAAO,MAAM,CAAC,WAAW,GAAG;gBACnG,GAAG,MAAM,CAAC,WAAW,KAAK,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,aAAa,QAAQ,MAAM,CAAC,UAAU,GAAG;gBACtF,GAAG,MAAM,CAAC,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,OAAO,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,IAAI,GAAG,GAAG;YACvG,CAAC,CAAC,uCAAuC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,IAAI,GAAG,4BAA4B;QAC3G,EAAE;KACH,CAAC;IACF,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACtC,KAAK,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,KAAK,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QACtF,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,cAAc,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC1F,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/C,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC;IACtH,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACjC,CAAC","sourcesContent":["/**\n * `mica check` — reads every entry the way Mica and the website read it, and\n * reports what they would skip, refuse or render as a gap. It never opens a\n * browser and exits with 1 when it finds an error, for CI and coding agents.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { relative } from \"node:path\";\n\nimport {\n DOCUMENT_EXTENSION,\n documentPath,\n entryLayout,\n INDEX_FILE,\n isValidSlug,\n MANIFEST_PATH,\n ORDER_FILE,\n readCollectionEntry,\n readSingleton,\n resolveSlugField,\n singletonPath,\n validateFields,\n type AnyField,\n type ContentSource,\n type FieldMap,\n type PathSegment,\n type Site,\n} from \"@micacms/core\";\nimport { within } from \"@micacms/core/node\";\nimport { contentFiles, loadSchema, readOnlyParts } from \"@micacms/runtime\";\n\nexport interface CheckProblem {\n level: \"error\" | \"warning\";\n /** The file, relative to the content root. */\n path: string;\n message: string;\n}\n\nexport interface CheckReport {\n problems: CheckProblem[];\n /** False when the model could not be read, so nothing else was checked. */\n model: boolean;\n collections: number;\n entries: number;\n singletons: number;\n}\n\n/** Checks the content under `root` against the model in `<root>/.mica/schema.json`. */\nexport async function checkContent(root: string): Promise<CheckReport> {\n const files = contentFiles({ root });\n const report: CheckReport = { problems: [], model: false, collections: 0, entries: 0, singletons: 0 };\n const error = (path: string, message: string) => report.problems.push({ level: \"error\", path, message });\n const warning = (path: string, message: string) => report.problems.push({ level: \"warning\", path, message });\n\n const manifest = await readText(files, MANIFEST_PATH);\n if (manifest === null || manifest instanceof Error) {\n error(MANIFEST_PATH, manifest?.message ?? \"There is no content model. Run `npx astro sync` in the Astro project to write it.\");\n return report;\n }\n let site: Site;\n try {\n site = await loadSchema(files);\n } catch (cause) {\n error(MANIFEST_PATH, (cause as Error).message);\n return report;\n }\n report.model = true;\n\n // A model from a newer @micacms/astro: this check cannot judge those entries.\n const readOnly = readOnlyParts(site);\n for (const reason of readOnly.values()) error(MANIFEST_PATH, `Not checked. ${reason}`);\n\n const slugs = new Map<string, Set<string>>();\n for (const [name, def] of Object.entries(site.collections)) {\n slugs.set(name, new Set(await entrySlugs(files, def.fields, name, error, warning)));\n }\n\n const context: EntryContext = { root, files, site, slugs, error, warning };\n\n for (const [name, def] of Object.entries(site.collections)) {\n report.collections++;\n if (readOnly.has(`collections.${name}`)) continue;\n const slugField = resolveSlugField(def);\n for (const slug of slugs.get(name)!) {\n report.entries++;\n const directory = entryLayout(def.fields) === \"directory\";\n const base = directory ? `${name}/${slug}` : null;\n const dataPath = directory ? `${base}/${INDEX_FILE}` : `${name}/${slug}.json`;\n\n const data = await readOrReport(() => readCollectionEntry(files, def, name, slug), dataPath, error);\n if (!data) continue;\n const stored = slugField ? data[slugField] : undefined;\n if (typeof stored === \"string\" && stored !== \"\" && stored !== slug) {\n warning(dataPath, `${slugField} is \"${stored}\", but the entry is named \"${slug}\". The next save in the editor renames the entry.`);\n }\n await checkEntry(context, def.fields, data, dataPath, base);\n }\n }\n\n for (const [name, def] of Object.entries(site.singletons)) {\n report.singletons++;\n if (readOnly.has(`singletons.${name}`)) continue;\n const directory = entryLayout(def.fields) === \"directory\";\n const base = singletonPath(def.fields, name);\n const dataPath = directory ? `${base}/${INDEX_FILE}` : base;\n const otherLayout = directory ? `${name}.json` : `${name}/${INDEX_FILE}`;\n if ((await readText(files, otherLayout)) !== null) {\n error(otherLayout, `Not read: \"${def.label}\" is stored as ${dataPath}, because ${directory ? \"it has\" : \"it has no\"} rich text or media.`);\n }\n\n const data = await readOrReport(() => readSingleton(files, def, name), dataPath, error);\n if (data === undefined) continue;\n if (data === null) {\n warning(dataPath, `No content for \"${def.label}\" yet.`);\n continue;\n }\n await checkEntry(context, def.fields, data, dataPath, directory ? base : null);\n }\n\n return report;\n}\n\ninterface EntryContext {\n root: string;\n files: ContentSource;\n site: Site;\n slugs: Map<string, Set<string>>;\n error(path: string, message: string): void;\n warning(path: string, message: string): void;\n}\n\n/** The slugs Mica reads in a collection, reporting what it would skip. */\nasync function entrySlugs(\n files: ContentSource,\n fields: FieldMap,\n name: string,\n error: (path: string, message: string) => void,\n warning: (path: string, message: string) => void,\n): Promise<string[]> {\n const directory = entryLayout(fields) === \"directory\";\n const shape = directory ? `a folder with ${INDEX_FILE}` : \"a <slug>.json file\";\n const found: string[] = [];\n\n for (const item of await files.list(name)) {\n const path = `${name}/${item.name}`;\n if (item.name.startsWith(\".\")) continue;\n if (item.name === ORDER_FILE) {\n checkOrder(await readText(files, path), path, error);\n continue;\n }\n\n // An entry in the other layout is lost content, not a stray file: the model gained or lost rich text or media.\n if (directory && item.type === \"file\" && item.name.endsWith(\".json\")) {\n error(path, `Not read: entries of \"${name}\" are folders with ${INDEX_FILE}, because it has rich text or media.`);\n continue;\n }\n if (!directory && item.type === \"directory\" && (await readText(files, `${path}/${INDEX_FILE}`)) !== null) {\n error(path, `Not read: entries of \"${name}\" are <slug>.json files, because it has no rich text or media.`);\n continue;\n }\n\n const slug = directory ? item.name : item.name.replace(/\\.json$/, \"\");\n const looksLikeEntry = directory ? item.type === \"directory\" : item.type === \"file\" && item.name.endsWith(\".json\");\n if (!looksLikeEntry) {\n warning(path, `Not read. Each entry of \"${name}\" is ${shape}.`);\n continue;\n }\n if (!isValidSlug(slug)) {\n error(path, `Not read: \"${slug}\" is not a slug. Use lowercase letters, digits and single hyphens.`);\n continue;\n }\n const index = directory ? await readText(files, `${path}/${INDEX_FILE}`) : \"\";\n if (index === null || index instanceof Error) {\n error(path, `Not read: ${index?.message ?? `the folder has no ${INDEX_FILE}.`}`);\n continue;\n }\n found.push(slug);\n }\n return found;\n}\n\n/** The file's text, null when it is not there, or the error that reading it gave. */\nasync function readText(files: ContentSource, path: string): Promise<string | null | Error> {\n try {\n return await files.read(path);\n } catch (cause) {\n return cause as Error;\n }\n}\n\nfunction checkOrder(text: string | null | Error, path: string, error: (path: string, message: string) => void): void {\n if (text === null) return;\n if (text instanceof Error) return error(path, text.message);\n let order: unknown;\n try {\n order = JSON.parse(text);\n } catch {\n return error(path, \"Not valid JSON. The build fails on it.\");\n }\n if (!Array.isArray(order)) {\n error(path, 'Must be a JSON array of slugs, such as [\"second\", \"first\"]. The build fails on it.');\n }\n}\n\nasync function readOrReport<T>(\n read: () => Promise<T>,\n path: string,\n error: (path: string, message: string) => void,\n): Promise<T | undefined> {\n try {\n return await read();\n } catch (cause) {\n error(path, (cause as Error).message.replace(`${path}: `, \"\"));\n return undefined;\n }\n}\n\nasync function checkEntry(\n context: EntryContext,\n fields: FieldMap,\n data: Record<string, unknown>,\n dataPath: string,\n base: string | null,\n): Promise<void> {\n const { root, files, slugs, error, warning } = context;\n\n const result = validateFields(fields, data, \"storage\");\n if (!result.ok) {\n for (const issue of result.issues) error(dataPath, issue.path ? `${issue.path}: ${issue.message}` : issue.message);\n }\n\n const raw = JSON.parse((await files.read(dataPath))!) as Record<string, unknown>;\n for (const message of unknownKeys(fields, raw, [])) warning(dataPath, message);\n\n visit(fields, data, [], (field, value, path) => {\n const key = path.join(\".\");\n if (field.kind === \"media\") {\n for (const file of list(value)) {\n let exists = false;\n try {\n exists = existsSync(within(root, file));\n } catch {\n // A path outside the content root does not exist for Mica.\n }\n if (!exists) error(dataPath, `${key}: the file \"${file}\" does not exist under the content root.`);\n }\n }\n if (field.kind === \"relation\") {\n for (const slug of list(value)) {\n if (!slugs.get(field.collection)?.has(slug)) {\n error(dataPath, `${key}: there is no \"${slug}\" in \"${field.collection}\".`);\n }\n }\n }\n });\n\n if (base === null) return;\n for (const item of await files.list(base)) {\n if (item.type !== \"file\" || !item.name.endsWith(DOCUMENT_EXTENSION)) continue;\n const path = `${base}/${item.name}`;\n if (!namesRichText(fields, documentPath(item.name))) {\n warning(path, \"Not read: no rich-text field has this name.\");\n continue;\n }\n for (const message of markdocWarnings((await files.read(path)) ?? \"\")) warning(path, message);\n }\n}\n\n/**\n * What Markdoc renders differently from Markdown, found in the text outside\n * code. A scan, not a parse: it can warn about too much, never about too little.\n */\nexport function markdocWarnings(source: string): string[] {\n const prose = source.replace(/^(`{3,}|~{3,})[^\\n]*\\n[\\s\\S]*?^\\1[ \\t]*$/gm, \"\").replace(/`[^`\\n]*`/g, \"\");\n const messages: string[] = [];\n const html = [...new Set([...prose.matchAll(/<\\/?([a-zA-Z][a-zA-Z0-9-]*)(?=[\\s/>])[^>\\n]*>/g)].map((match) => match[1]!.toLowerCase()))];\n if (html.length > 0) {\n messages.push(`Raw HTML (${html.map((tag) => `<${tag}>`).join(\", \")}) is not rendered: Markdoc escapes it.`);\n }\n const tags = [...new Set([...prose.matchAll(/\\{%\\s*([a-zA-Z][\\w-]*)/g)].map((match) => match[1]!))];\n if (tags.length > 0) {\n messages.push(\n `Markdoc tags (${tags.join(\", \")}) render only if the website declares them in renderRichText(source, { config }).`,\n );\n }\n if (/\\[\\^[^\\]]+\\]/.test(prose)) messages.push(\"Footnotes ([^1]) are not Markdoc: they render as plain text.\");\n return messages;\n}\n\nfunction list(value: unknown): string[] {\n const values = Array.isArray(value) ? value : [value];\n return values.filter((item): item is string => typeof item === \"string\" && item !== \"\");\n}\n\n/** Calls `onField` for every field with a value, nested fields included. */\nfunction visit(\n fields: FieldMap,\n data: Record<string, unknown>,\n path: PathSegment[],\n onField: (field: AnyField, value: unknown, path: PathSegment[]) => void,\n): void {\n for (const [key, field] of Object.entries(fields)) {\n const value = data[key];\n if (value === undefined || value === null) continue;\n onField(field, value, [...path, key]);\n if (field.kind === \"object\" && isRecord(value)) visit(field.fields, value, [...path, key], onField);\n if (field.kind === \"repeater\" && Array.isArray(value)) {\n value.forEach((row, index) => {\n if (isRecord(row)) visit(field.fields, row, [...path, key, index], onField);\n });\n }\n }\n}\n\n/** Keys in the stored JSON that the model does not have; Mica drops them on the next save. */\nfunction unknownKeys(fields: FieldMap, raw: Record<string, unknown>, path: PathSegment[]): string[] {\n const messages: string[] = [];\n for (const [key, value] of Object.entries(raw)) {\n const at = [...path, key].join(\".\");\n const field = fields[key];\n if (!field) {\n messages.push(`${at}: the model has no such field. Mica drops it on the next save.`);\n } else if (field.kind === \"richText\") {\n messages.push(`${at}: rich text belongs in ${[...path, key].join(\".\")}${DOCUMENT_EXTENSION}, not in the JSON.`);\n } else if (field.kind === \"object\" && isRecord(value)) {\n messages.push(...unknownKeys(field.fields, value, [...path, key]));\n } else if (field.kind === \"repeater\" && Array.isArray(value)) {\n value.forEach((row, index) => {\n if (isRecord(row)) messages.push(...unknownKeys(field.fields, row, [...path, key, index]));\n });\n }\n }\n return messages;\n}\n\n/** Whether a sidecar's dotted path leads to a rich-text field. */\nfunction namesRichText(fields: FieldMap, path: PathSegment[]): boolean {\n let map: FieldMap | undefined = fields;\n for (const [index, segment] of path.entries()) {\n if (typeof segment === \"number\") continue;\n const field: AnyField | undefined = map?.[segment];\n if (!field) return false;\n if (index === path.length - 1) return field.kind === \"richText\";\n map = field.kind === \"object\" || field.kind === \"repeater\" ? field.fields : undefined;\n }\n return false;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\n/** The report as a person or an agent reads it. */\nexport function formatReport(report: CheckReport, root: string): string {\n const errors = report.problems.filter((problem) => problem.level === \"error\").length;\n const warnings = report.problems.length - errors;\n const lines = [\n report.model\n ? `Checked ${report.entries} ${report.entries === 1 ? \"entry\" : \"entries\"} in ${report.collections} ` +\n `${report.collections === 1 ? \"collection\" : \"collections\"} and ${report.singletons} ` +\n `${report.singletons === 1 ? \"singleton\" : \"singletons\"} in ${relative(process.cwd(), root) || \".\"}.`\n : `Could not read the content model in ${relative(process.cwd(), root) || \".\"}, so no entry was checked.`,\n \"\",\n ];\n for (const problem of report.problems) {\n lines.push(` ${problem.level === \"error\" ? \"error \" : \"warning\"} ${problem.path}`);\n for (const line of problem.message.split(\"\\n\")) lines.push(` ${line.trim()}`);\n }\n if (report.problems.length > 0) lines.push(\"\");\n lines.push(`${errors} ${errors === 1 ? \"error\" : \"errors\"}, ${warnings} ${warnings === 1 ? \"warning\" : \"warnings\"}.`);\n return `${lines.join(\"\\n\")}\\n`;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@micacms/editor",
3
- "version": "0.5.0-rc.2",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "description": "The local Mica editor — `npx @micacms/editor` against a checkout on your own machine. No authentication, no database, loopback only.",
6
6
  "license": "MIT",
@@ -23,9 +23,9 @@
23
23
  "dependencies": {
24
24
  "hono": "^4.13.7",
25
25
  "zod": "^4.3.6",
26
- "@micacms/core": "0.5.0-rc.2",
27
- "@micacms/editor-ui": "0.5.0-rc.2",
28
- "@micacms/runtime": "0.5.0-rc.2"
26
+ "@micacms/core": "0.5.0",
27
+ "@micacms/editor-ui": "0.5.0",
28
+ "@micacms/runtime": "0.5.0"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@types/node": "^22.20.1",