@micacms/editor 0.5.0 → 0.6.0-rc.2

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import.js","sourceRoot":"","sources":["../src/import.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `mica import`: moves the entries of Astro content collections into Mica.\n *\n * It reads `.astro/data-store.json`, where Astro keeps every entry after its\n * own loader and schema ran, so one importer covers `glob()`, `file()`,\n * Markdown, MDX frontmatter, JSON and YAML alike. Each field of the Mica model\n * takes the field with the same name, unless `--map` names another; values are\n * converted to the stored form and written with the editor's own serializer.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { copyFile, mkdir, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport {\n collectionEntryPath,\n entryFiles,\n serializeEntry,\n singletonPath,\n slugify,\n validateFields,\n type AnyField,\n type FieldMap,\n} from \"@micacms/core\";\nimport { within } from \"@micacms/core/node\";\nimport { contentFiles, loadSchema } from \"@micacms/runtime\";\n\nimport { unflatten } from \"./devalue.js\";\n\n/** The `--map` value for the Markdown body. Not `$body`: a shell would expand it. */\nexport const BODY = \"@body\";\n\n/** Astro's marker for a path that `image()` resolves against the entry's file. */\nconst IMAGE_MARKER = \"__ASTRO_IMAGE_\";\n\nexport interface ImportOptions {\n /** The Mica content root. */\n root: string;\n /** The Astro project, which the entries' file paths are relative to. */\n project: string;\n /** Astro's data store from before Mica replaced the collections: `node_modules/.astro/data-store.json`. */\n store: string;\n /** `collection.targetField` (dots for fields in an object, and `.alt`) → source key; `@body` is the Markdown body. Not inside repeater rows. */\n map?: Record<string, string>;\n /** Collection → the number field that gives the initial manual order. */\n order?: Record<string, string>;\n /** Only these collections and singletons; all that match by name when empty. */\n only?: string[];\n}\n\nexport interface ImportResult {\n imported: Array<{ name: string; entries: number }>;\n problems: string[];\n}\n\ninterface StoredEntry {\n id: string;\n data: Record<string, unknown>;\n body?: string;\n filePath?: string;\n}\n\nexport class ImportError extends Error {\n override name = \"ImportError\";\n}\n\nexport async function importCollections(options: ImportOptions): Promise<ImportResult> {\n try {\n return await importAll(options);\n } catch (error) {\n // Any refusal reads as one, not as a stack trace.\n if (error instanceof ImportError) throw error;\n throw new ImportError((error as Error).message, { cause: error });\n }\n}\n\nasync function importAll(options: ImportOptions): Promise<ImportResult> {\n const site = await loadSchema(contentFiles({ root: options.root }));\n const astro = readStore(options.store);\n const result: ImportResult = { imported: [], problems: [] };\n const map = options.map ?? {};\n\n const names = [...Object.keys(site.collections), ...Object.keys(site.singletons)].filter(\n (name) => astro.has(name) && (!options.only?.length || options.only.includes(name)),\n );\n for (const name of options.only ?? []) {\n if (!astro.has(name)) result.problems.push(`${name}: the data store has no collection with this name.`);\n }\n if (names.length === 0) throw new ImportError(\"No Astro collection has the name of a Mica collection or singleton.\");\n\n // Before the first write, so that a refusal leaves nothing half done.\n for (const name of names) {\n const fields = (site.singletons[name] ?? site.collections[name]!).fields;\n const target = site.singletons[name] ? singletonPath(fields, name) : name;\n if (existsSync(within(options.root, target))) {\n throw new ImportError(`${target} exists in the content root. Delete it to import \"${name}\" again.`);\n }\n if (!site.singletons[name]) {\n const empty = astro.get(name)!.find((entry) => slugify(entry.id.replace(/\\//g, \"-\")) === \"\");\n if (empty) throw new ImportError(`${name}: the id \"${empty.id}\" gives no slug. Rename the entry first.`);\n }\n }\n\n for (const name of names) {\n const entries = astro.get(name)!;\n const singleton = site.singletons[name];\n const fields = (singleton ?? site.collections[name]!).fields;\n if (singleton && entries.length !== 1) {\n result.problems.push(`${name}: a singleton takes one entry, and the collection has ${entries.length}. Not imported.`);\n continue;\n }\n\n const used = new Set<string>();\n let bodyTaken = false;\n const slugs = new Map<string, string>();\n const written: Array<{ slug: string; source: StoredEntry }> = [];\n\n for (const entry of entries) {\n const slug = slugify(entry.id.replace(/\\//g, \"-\"));\n if (!singleton && slugs.has(slug)) {\n result.problems.push(`${name}: \"${entry.id}\" and \"${slugs.get(slug)}\" both become \"${slug}\". Not imported: \"${entry.id}\".`);\n continue;\n }\n slugs.set(slug, entry.id);\n\n const base = singleton ? singletonPath(fields, name) : collectionEntryPath(fields, name, slug);\n const context: Context = { options, map, name, entry, base, slug, used, problems: result.problems, copies: [], body: false };\n const data = convertFields(fields, entry.data, \"\", context, singleton ? undefined : slug);\n bodyTaken ||= context.body;\n\n const check = validateFields(fields, data);\n if (!check.ok) {\n for (const issue of check.issues) result.problems.push(`${name}/${slug}: ${issue.path}: ${issue.message}`);\n }\n for (const [file, contents] of Object.entries(entryFiles(fields, base, serializeEntry(fields, data)))) {\n await mkdir(path.dirname(within(options.root, file)), { recursive: true });\n await writeFile(within(options.root, file), contents);\n }\n for (const { from, to } of context.copies) {\n await mkdir(path.dirname(within(options.root, to)), { recursive: true });\n await copyFile(from, within(options.root, to));\n }\n written.push({ slug, source: entry });\n }\n\n const orderField = options.order?.[name];\n if (orderField) {\n const def = site.collections[name];\n if (!def?.sortable) result.problems.push(`${name}: --order needs a collection with \\`sortable: true\\`.`);\n else {\n const position = (item: { source: StoredEntry }) => {\n const value = Number(item.source.data[orderField]);\n return Number.isFinite(value) ? value : Number.POSITIVE_INFINITY;\n };\n const order = [...written].sort((a, b) => position(a) - position(b)).map((item) => item.slug);\n await writeFile(within(options.root, `${name}/_order.json`), `${JSON.stringify(order, null, 2)}\\n`);\n used.add(orderField);\n }\n }\n\n if (!bodyTaken && entries.some((entry) => entry.body?.trim())) {\n result.problems.push(`${name}: not imported: the Markdown body. The model has no rich-text field \\`body\\`; map one with --map ${name}.<field>=@body.`);\n }\n const left = new Set(entries.flatMap((entry) => Object.keys(entry.data)).filter((key) => !used.has(key)));\n if (left.size > 0) result.problems.push(`${name}: not imported: ${[...left].join(\", \")}. Map them with --map, or leave them out.`);\n result.imported.push({ name, entries: written.length });\n }\n\n return result;\n}\n\ninterface Context {\n options: ImportOptions;\n map: Record<string, string>;\n name: string;\n entry: StoredEntry;\n base: string;\n slug: string;\n /** Top-level source keys that some field took. */\n used: Set<string>;\n problems: string[];\n copies: Array<{ from: string; to: string }>;\n /** Whether a field took the Markdown body. */\n body: boolean;\n}\n\nfunction convertFields(\n fields: FieldMap,\n source: Record<string, unknown>,\n prefix: string,\n context: Context,\n slug?: string,\n): Record<string, unknown> {\n const data: Record<string, unknown> = {};\n for (const [key, field] of Object.entries(fields)) {\n const at = prefix ? `${prefix}.${key}` : key;\n if (field.kind === \"slug\" && prefix === \"\" && slug !== undefined) {\n data[key] = slug;\n continue;\n }\n data[key] = convert(field, read(source, at, key, context), at, context);\n }\n return data;\n}\n\n/** The source value for a target field: mapped, else the key of the same name. */\nfunction read(source: Record<string, unknown>, at: string, key: string, context: Context): unknown {\n const mapped = context.map[`${context.name}.${at}`];\n if (mapped === BODY) {\n context.body = true;\n return context.entry.body?.trim() || null;\n }\n if (mapped !== undefined) {\n context.used.add(mapped.split(\".\")[0]!);\n return mapped.split(\".\").reduce<unknown>((value, part) => (isRecord(value) ? value[part] : undefined), context.entry.data);\n }\n if (!at.includes(\".\")) context.used.add(key);\n return source[key];\n}\n\nfunction convert(field: AnyField, value: unknown, at: string, context: Context): unknown {\n const where = `${context.name}/${context.slug}: ${at}`;\n switch (field.kind) {\n case \"richText\":\n // The body goes to the rich-text field named `body`, unless a map says otherwise.\n if (value == null && at === \"body\" && !(`${context.name}.body` in context.map) && context.entry.body?.trim()) {\n context.body = true;\n return context.entry.body.trim();\n }\n return value ?? null;\n case \"date\":\n return toDate(value, where, context, field.includeTime === true);\n case \"relation\": {\n const one = (item: unknown) => (isRecord(item) ? slugify(String(item[\"id\"] ?? \"\")) : typeof item === \"string\" ? slugify(item) : null);\n return field.multiple ? (Array.isArray(value) ? value.map(one).filter(Boolean) : []) : one(value);\n }\n case \"media\": {\n const one = (item: unknown, index?: number) => {\n const stored = copyMedia(item, `${where}${index === undefined ? \"\" : `.${index}`}`, context);\n if (stored === null || !field.alt) return stored;\n const alt = context.map[`${context.name}.${at}.alt`];\n if (alt !== undefined) context.used.add(alt.split(\".\")[0]!);\n const text = alt === undefined ? null : alt.split(\".\").reduce<unknown>((v, p) => (isRecord(v) ? v[p] : undefined), context.entry.data);\n return { path: stored, alt: typeof text === \"string\" ? text : null };\n };\n if (field.multiple) return Array.isArray(value) ? value.map((item, index) => one(item, index)).filter((item) => item !== null) : [];\n return one(value);\n }\n case \"object\": {\n // A map can fill an object from flat keys, for example `blog.seo.title=metaTitle`.\n const mapped = Object.keys(context.map).some((key) => key.startsWith(`${context.name}.${at}.`));\n return isRecord(value) || mapped ? convertFields(field.fields, isRecord(value) ? value : {}, at, context) : null;\n }\n case \"repeater\":\n return Array.isArray(value)\n ? value.map((row, index) => (isRecord(row) ? convertFields(field.fields, row, `${at}.${index}`, { ...context, map: {} }) : {}))\n : [];\n case \"select\":\n return field.multiple ? (Array.isArray(value) ? value : []) : (value ?? null);\n case \"boolean\":\n return typeof value === \"boolean\" ? value : (field.default ?? false);\n case \"number\":\n return typeof value === \"number\" ? value : value == null ? null : Number(value);\n default:\n return value instanceof Date ? value.toISOString() : (value ?? null);\n }\n}\n\n/**\n * A date as `YYYY-MM-DD` in UTC (a local-time date would give the day before\n * east of UTC), or a full ISO timestamp for `date({ includeTime: true })`.\n */\nfunction toDate(value: unknown, where: string, context: Context, withTime: boolean): string | null {\n if (value == null || value === \"\") return null;\n const parsed =\n value instanceof Date\n ? value\n : typeof value === \"string\" && /^\\d{4}-\\d{2}-\\d{2}/.test(value)\n ? new Date(value.length === 10 ? `${value}T00:00:00Z` : value)\n : new Date(`${String(value)} UTC`);\n if (Number.isNaN(parsed.getTime())) {\n context.problems.push(`${where}: \"${String(value)}\" is not a date.`);\n return null;\n }\n return withTime ? parsed.toISOString() : parsed.toISOString().slice(0, 10);\n}\n\n/** Copies a media file into the entry's `media/` folder, and gives the stored path. */\nfunction copyMedia(value: unknown, where: string, context: Context): string | null {\n if (typeof value !== \"string\" || value === \"\") return null;\n const raw = value.startsWith(IMAGE_MARKER) ? value.slice(IMAGE_MARKER.length) : value;\n if (/^[a-z]+:\\/\\//i.test(raw)) {\n context.problems.push(`${where}: \"${raw}\" is a URL. Download the file and add it in the editor.`);\n return null;\n }\n const from = raw.startsWith(\"/\")\n ? path.join(context.options.project, raw)\n : path.resolve(context.options.project, path.dirname(context.entry.filePath ?? \".\"), raw);\n if (!existsSync(from)) {\n context.problems.push(`${where}: the file \"${raw}\" does not exist.`);\n return null;\n }\n const taken = new Set(context.copies.map((copy) => path.posix.basename(copy.to)));\n let name = path.basename(from);\n for (let n = 2; taken.has(name); n++) name = `${path.parse(from).name}-${n}${path.extname(from)}`;\n context.copies.push({ from, to: `${context.base}/media/${name}` });\n return `media/${name}`;\n}\n\n/** Collection name → its entries, from Astro's data store. */\nfunction readStore(file: string): Map<string, StoredEntry[]> {\n if (!existsSync(file)) {\n throw new ImportError(`There is no data store at ${file}. Run \\`npx astro sync\\` before Mica replaces the collections, and keep a copy.`);\n }\n const root = unflatten(JSON.parse(readFileSync(file, \"utf8\")) as unknown[]);\n if (!(root instanceof Map)) throw new ImportError(`${file} is not an Astro data store.`);\n const collections = new Map<string, StoredEntry[]>();\n for (const [name, entries] of root) {\n if (typeof name !== \"string\" || name.includes(\"::\") || !(entries instanceof Map)) continue;\n collections.set(name, [...entries.values()] as StoredEntry[]);\n }\n return collections;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value) && !(value instanceof Date);\n}\n\n/** The result as a person or an agent reads it. */\nexport function formatImport(result: ImportResult): string {\n const lines = result.imported.map(({ name, entries }) => ` imported ${name}: ${entries} ${entries === 1 ? \"entry\" : \"entries\"}`);\n for (const problem of result.problems) lines.push(` check ${problem}`);\n lines.push(\"\", \"Next: run `npx mica check`, and compare the website with the version before.\");\n return `${lines.join(\"\\n\")}\\n`;\n}\n"]}
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * content directory and installs no auth code that can be misconfigured.
5
5
  */
6
6
  import { MANIFEST_PATH } from "@micacms/core";
7
- import { ConfigError, contentFiles, createApp, createLogger, createRuntimeContext, loadSchema, SchemaError, schemaFingerprint, schemaOrigin, startServer, VERSION, } from "@micacms/runtime";
7
+ import { ConfigError, contentFiles, createApp, createLogger, createRuntimeContext, layoutProblems, loadSchema, SchemaError, schemaFingerprint, schemaOrigin, startServer, VERSION, } from "@micacms/runtime";
8
8
  import { editorUiDist } from "./admin-dir.js";
9
9
  import { portInUse, startupBanner, supportsColor } from "./banner.js";
10
10
  import { loadConfig } from "./config.js";
@@ -22,7 +22,7 @@ async function main() {
22
22
  }
23
23
  throw error;
24
24
  }
25
- const logger = createLogger({ level: config.LOG_LEVEL, pretty: true });
25
+ const logger = createLogger({ level: config.MICA_LOG_LEVEL, pretty: true });
26
26
  // A bad or absent model is a project mistake, not a crash: exit like a bad
27
27
  // environment, without a stack trace.
28
28
  const files = contentFiles({ root: config.contentRoot });
@@ -37,6 +37,11 @@ async function main() {
37
37
  }
38
38
  throw error;
39
39
  }
40
+ const misplaced = await layoutProblems(files, model);
41
+ if (misplaced.length > 0) {
42
+ process.stderr.write(`\n${misplaced.join("\n\n")}\n\n`);
43
+ process.exit(78); // EX_CONFIG
44
+ }
40
45
  const schemaRevision = await files.revision(MANIFEST_PATH);
41
46
  const ctx = createRuntimeContext({
42
47
  config,
@@ -50,7 +55,7 @@ async function main() {
50
55
  });
51
56
  const app = createApp(ctx, {
52
57
  guards: [hostGuard()],
53
- adminDir: config.ADMIN_DIR ?? editorUiDist(),
58
+ adminDir: config.MICA_ADMIN_DIR ?? editorUiDist(),
54
59
  });
55
60
  const fingerprint = await schemaFingerprint(model);
56
61
  startServer({
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The local editor's process entry point: the developer's checkout, the\n * auth-neutral runtime and the Host allowlist. It writes nothing outside the\n * content directory and installs no auth code that can be misconfigured.\n */\n\nimport { MANIFEST_PATH } from \"@micacms/core\";\nimport {\n ConfigError,\n contentFiles,\n createApp,\n createLogger,\n createRuntimeContext,\n loadSchema,\n SchemaError,\n schemaFingerprint,\n schemaOrigin,\n startServer,\n VERSION,\n} from \"@micacms/runtime\";\n\nimport { editorUiDist } from \"./admin-dir.js\";\nimport { portInUse, startupBanner, supportsColor } from \"./banner.js\";\nimport { loadConfig } from \"./config.js\";\nimport { hostGuard } from \"./guards.js\";\nimport { openInBrowser } from \"./open.js\";\n\nasync function main(): Promise<void> {\n let config;\n try {\n config = loadConfig();\n } catch (error) {\n if (error instanceof ConfigError) {\n process.stderr.write(`\\n${error.message}\\n\\n`);\n process.exit(78); // EX_CONFIG\n }\n throw error;\n }\n\n const logger = createLogger({ level: config.LOG_LEVEL, pretty: true });\n\n // A bad or absent model is a project mistake, not a crash: exit like a bad\n // environment, without a stack trace.\n const files = contentFiles({ root: config.contentRoot });\n\n let model;\n try {\n model = await loadSchema(files);\n } catch (error) {\n if (error instanceof SchemaError) {\n process.stderr.write(`\\n${error.message}\\n\\n`);\n process.exit(78); // EX_CONFIG\n }\n throw error;\n }\n\n const schemaRevision = await files.revision(MANIFEST_PATH);\n\n const ctx = createRuntimeContext({\n config,\n model,\n files,\n schemaRevision,\n logger,\n operational: () => ({\n auth: \"none — the local editor has no accounts and no sign-in\",\n }),\n });\n\n const app = createApp(ctx, {\n guards: [hostGuard()],\n adminDir: config.ADMIN_DIR ?? editorUiDist(),\n });\n\n const fingerprint = await schemaFingerprint(model);\n\n startServer({\n app,\n host: config.HOST,\n port: config.PORT,\n logger,\n\n onListening() {\n // A person at a terminal gets a short banner; a log collector gets every field.\n if (config.MICA_CLI) {\n const useColor = supportsColor(process.stdout, process.env);\n\n process.stdout.write(\n startupBanner(\n {\n version: VERSION,\n url: config.MICA_PUBLIC_URL,\n contentRoot: files.origin,\n collections: Object.keys(model.collections).length,\n singletons: Object.keys(model.singletons).length,\n },\n useColor,\n ),\n );\n\n if (config.MICA_OPEN) openInBrowser(`${config.MICA_PUBLIC_URL}/admin/`);\n return;\n }\n\n logger.info(\"Mica local editor started\", {\n url: config.MICA_PUBLIC_URL,\n listening: `${config.HOST}:${config.PORT}`,\n auth: \"none (local editor; loopback only)\",\n content: files.origin,\n schema: schemaOrigin(files),\n schemaFingerprint: fingerprint,\n collections: Object.keys(model.collections).length,\n });\n },\n\n portInUseMessage: () =>\n portInUse(config.PORT, config.HOST, supportsColor(process.stderr, process.env)),\n\n shutdown: () => ctx.shutdown(),\n });\n}\n\nmain().catch((error: unknown) => {\n process.stderr.write(`Failed to start: ${error instanceof Error ? error.stack : String(error)}\\n`);\n process.exit(1);\n});\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The local editor's process entry point: the developer's checkout, the\n * auth-neutral runtime and the Host allowlist. It writes nothing outside the\n * content directory and installs no auth code that can be misconfigured.\n */\n\nimport { MANIFEST_PATH } from \"@micacms/core\";\nimport {\n ConfigError,\n contentFiles,\n createApp,\n createLogger,\n createRuntimeContext,\n layoutProblems,\n loadSchema,\n SchemaError,\n schemaFingerprint,\n schemaOrigin,\n startServer,\n VERSION,\n} from \"@micacms/runtime\";\n\nimport { editorUiDist } from \"./admin-dir.js\";\nimport { portInUse, startupBanner, supportsColor } from \"./banner.js\";\nimport { loadConfig } from \"./config.js\";\nimport { hostGuard } from \"./guards.js\";\nimport { openInBrowser } from \"./open.js\";\n\nasync function main(): Promise<void> {\n let config;\n try {\n config = loadConfig();\n } catch (error) {\n if (error instanceof ConfigError) {\n process.stderr.write(`\\n${error.message}\\n\\n`);\n process.exit(78); // EX_CONFIG\n }\n throw error;\n }\n\n const logger = createLogger({ level: config.MICA_LOG_LEVEL, pretty: true });\n\n // A bad or absent model is a project mistake, not a crash: exit like a bad\n // environment, without a stack trace.\n const files = contentFiles({ root: config.contentRoot });\n\n let model;\n try {\n model = await loadSchema(files);\n } catch (error) {\n if (error instanceof SchemaError) {\n process.stderr.write(`\\n${error.message}\\n\\n`);\n process.exit(78); // EX_CONFIG\n }\n throw error;\n }\n\n const misplaced = await layoutProblems(files, model);\n if (misplaced.length > 0) {\n process.stderr.write(`\\n${misplaced.join(\"\\n\\n\")}\\n\\n`);\n process.exit(78); // EX_CONFIG\n }\n\n const schemaRevision = await files.revision(MANIFEST_PATH);\n\n const ctx = createRuntimeContext({\n config,\n model,\n files,\n schemaRevision,\n logger,\n operational: () => ({\n auth: \"none — the local editor has no accounts and no sign-in\",\n }),\n });\n\n const app = createApp(ctx, {\n guards: [hostGuard()],\n adminDir: config.MICA_ADMIN_DIR ?? editorUiDist(),\n });\n\n const fingerprint = await schemaFingerprint(model);\n\n startServer({\n app,\n host: config.HOST,\n port: config.PORT,\n logger,\n\n onListening() {\n // A person at a terminal gets a short banner; a log collector gets every field.\n if (config.MICA_CLI) {\n const useColor = supportsColor(process.stdout, process.env);\n\n process.stdout.write(\n startupBanner(\n {\n version: VERSION,\n url: config.MICA_PUBLIC_URL,\n contentRoot: files.origin,\n collections: Object.keys(model.collections).length,\n singletons: Object.keys(model.singletons).length,\n },\n useColor,\n ),\n );\n\n if (config.MICA_OPEN) openInBrowser(`${config.MICA_PUBLIC_URL}/admin/`);\n return;\n }\n\n logger.info(\"Mica local editor started\", {\n url: config.MICA_PUBLIC_URL,\n listening: `${config.HOST}:${config.PORT}`,\n auth: \"none (local editor; loopback only)\",\n content: files.origin,\n schema: schemaOrigin(files),\n schemaFingerprint: fingerprint,\n collections: Object.keys(model.collections).length,\n });\n },\n\n portInUseMessage: () =>\n portInUse(config.PORT, config.HOST, supportsColor(process.stderr, process.env)),\n\n shutdown: () => ctx.shutdown(),\n });\n}\n\nmain().catch((error: unknown) => {\n process.stderr.write(`Failed to start: ${error instanceof Error ? error.stack : String(error)}\\n`);\n process.exit(1);\n});\n"]}
package/dist/init.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * `mica init` — adds Mica to an Astro project: a starter model and the content
3
3
  * collections. It never overwrites a file.
4
4
  */
5
- export declare const MODEL = "import {\n collection,\n date,\n defineSite,\n media,\n richText,\n singleton,\n slug,\n text,\n} from \"@micacms/core\";\n\nexport const site = defineSite({\n root: \"./content\",\n\n collections: {\n news: collection({\n label: \"News\",\n labelSingular: \"Article\",\n fields: {\n title: text({ label: \"Title\", required: true, maxLength: 120, listed: true }),\n slug: slug({ from: \"title\" }),\n publishedOn: date({ label: \"Published on\", listed: true }),\n cover: media({ accept: \"image\" }),\n body: richText(),\n },\n }),\n },\n\n singletons: {\n settings: singleton({\n label: \"Website\",\n fields: {\n siteName: text({ label: \"Site name\", required: true }),\n tagline: text({ label: \"Tagline\" }),\n },\n }),\n },\n});\n";
5
+ export declare const MODEL = "import {\n collection,\n date,\n defineSite,\n media,\n richText,\n singleton,\n slug,\n text,\n} from \"@micacms/core\";\n\nexport const site = defineSite({\n root: \"./content\",\n\n collections: {\n news: collection({\n label: \"News\",\n labelSingular: \"Article\",\n fields: {\n title: text({ label: \"Title\", required: true, maxLength: 120, listed: true }),\n slug: slug({ from: \"title\" }),\n publishedOn: date({ label: \"Published on\", listed: true }),\n cover: media({ accept: \"image\", alt: \"required\" }),\n body: richText(),\n },\n }),\n },\n\n singletons: {\n settings: singleton({\n label: \"Website\",\n fields: {\n siteName: text({ label: \"Site name\", required: true }),\n tagline: text({ label: \"Tagline\" }),\n },\n }),\n },\n});\n";
6
6
  export interface InitResult {
7
7
  /** Files and directories made, relative to the project. */
8
8
  created: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,eAAO,MAAM,KAAK,o1BAsCjB,CAAC;AAcF,MAAM,WAAW,UAAU;IACzB,2DAA2D;IAC3D,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,sDAAsD;IACtD,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,0CAA0C;IAC1C,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,qBAAa,SAAU,SAAQ,KAAK;IACzB,IAAI,SAAe;CAC7B;AAED,mDAAmD;AACnD,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAqDvD;AAYD,mDAAmD;AACnD,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAOrD"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,eAAO,MAAM,KAAK,u2BAsCjB,CAAC;AAcF,MAAM,WAAW,UAAU;IACzB,2DAA2D;IAC3D,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,sDAAsD;IACtD,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,0CAA0C;IAC1C,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,qBAAa,SAAU,SAAQ,KAAK;IACzB,IAAI,SAAe;CAC7B;AAED,mDAAmD;AACnD,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CA2DvD;AAuBD,mDAAmD;AACnD,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAOrD"}
package/dist/init.js CHANGED
@@ -26,7 +26,7 @@ export const site = defineSite({
26
26
  title: text({ label: "Title", required: true, maxLength: 120, listed: true }),
27
27
  slug: slug({ from: "title" }),
28
28
  publishedOn: date({ label: "Published on", listed: true }),
29
- cover: media({ accept: "image" }),
29
+ cover: media({ accept: "image", alt: "required" }),
30
30
  body: richText(),
31
31
  },
32
32
  }),
@@ -103,11 +103,27 @@ export function initProject(project) {
103
103
  result.next.push(`Install the packages: npm install ${missing.join(" ")}`);
104
104
  if (!dependencies["@micacms/editor"])
105
105
  result.next.push("Install the editor: npm install --save-dev @micacms/editor");
106
+ const scripts = scriptsToSet(pkg.scripts ?? {}, Boolean(dependencies["@astrojs/check"]));
107
+ if (scripts.length > 0)
108
+ result.next.push(`Set in "scripts" in package.json:\n\n${scripts.map((line) => ` ${line}`).join(",\n")}`);
106
109
  result.next.push(model
107
110
  ? "Add the website's collections and singletons to the model in src/mica.ts."
108
- : "Replace the starter model in src/mica.ts (news, settings) with the website's model.", "Write the model to content/.mica/schema.json: npx astro sync", "Check the content: npx mica check", "When the content is in place, open the editor in a browser: npx mica");
111
+ : "Replace the starter model in src/mica.ts (news, settings) with the website's model.", "Write the model to content/.mica/schema.json: npx astro sync", "Check the content: npx mica check", "When the content is in place, open the editor in a browser: npx mica start");
109
112
  return result;
110
113
  }
114
+ /** `npm run mica` opens the editor (`mica start`); `npm run check` checks the content, and the types when `@astrojs/check` is there. */
115
+ function scriptsToSet(scripts, astroCheck) {
116
+ const missing = [];
117
+ if (!scripts["mica"])
118
+ missing.push(`"mica": "mica start"`);
119
+ // Without @astrojs/check, `astro check` asks to install it, and a script cannot answer.
120
+ const check = scripts["check"];
121
+ if (!check)
122
+ missing.push(`"check": "${astroCheck ? "mica check && astro check" : "mica check"}"`);
123
+ else if (!check.includes("mica check"))
124
+ missing.push(`"check": ${JSON.stringify(`mica check && ${check}`)}`);
125
+ return missing;
126
+ }
111
127
  function existingFile(project, candidates) {
112
128
  return candidates.find((candidate) => existsSync(path.join(project, candidate)));
113
129
  }
package/dist/init.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `mica init` — adds Mica to an Astro project: a starter model and the content\n * collections. It never overwrites a file.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\n\nexport const MODEL = `import {\n collection,\n date,\n defineSite,\n media,\n richText,\n singleton,\n slug,\n text,\n} from \"@micacms/core\";\n\nexport const site = defineSite({\n root: \"./content\",\n\n collections: {\n news: collection({\n label: \"News\",\n labelSingular: \"Article\",\n fields: {\n title: text({ label: \"Title\", required: true, maxLength: 120, listed: true }),\n slug: slug({ from: \"title\" }),\n publishedOn: date({ label: \"Published on\", listed: true }),\n cover: media({ accept: \"image\" }),\n body: richText(),\n },\n }),\n },\n\n singletons: {\n settings: singleton({\n label: \"Website\",\n fields: {\n siteName: text({ label: \"Site name\", required: true }),\n tagline: text({ label: \"Tagline\" }),\n },\n }),\n },\n});\n`;\n\nconst COLLECTIONS = `import { micaCollections } from \"@micacms/astro\";\n\nimport { site } from \"./mica\";\n\nexport const collections = micaCollections(site);\n`;\n\nconst MERGE = ` import { micaCollections } from \"@micacms/astro\";\n import { site } from \"./mica\";\n\n export const collections = { ...micaCollections(site), /* your collections */ };`;\n\nexport interface InitResult {\n /** Files and directories made, relative to the project. */\n created: string[];\n /** Files that already existed and were left alone. */\n kept: string[];\n /** What the person or agent does next. */\n next: string[];\n}\n\nexport class InitError extends Error {\n override name = \"InitError\";\n}\n\n/** Adds Mica to the Astro project in `project`. */\nexport function initProject(project: string): InitResult {\n const manifest = path.join(project, \"package.json\");\n if (!existsSync(manifest)) {\n throw new InitError(`There is no package.json in ${project}. Create an Astro project first: npm create astro@latest`);\n }\n let pkg: { dependencies?: Record<string, string>; devDependencies?: Record<string, string> };\n try {\n pkg = JSON.parse(readFileSync(manifest, \"utf8\")) as typeof pkg;\n } catch (cause) {\n throw new InitError(`${manifest} is not valid JSON: ${(cause as Error).message}`);\n }\n const dependencies = { ...pkg.dependencies, ...pkg.devDependencies };\n if (!dependencies[\"astro\"]) {\n throw new InitError(`${manifest} has no \"astro\" dependency. Run mica init in an Astro project.`);\n }\n\n const result: InitResult = { created: [], kept: [], next: [] };\n\n const model = existingFile(project, [\"src/mica.ts\", \"src/mica.mts\", \"src/mica.js\", \"src/mica.mjs\"]);\n if (model) result.kept.push(model);\n else write(project, \"src/mica.ts\", MODEL, result);\n\n const config = existingFile(project, [\n \"src/content.config.ts\",\n \"src/content.config.mts\",\n \"src/content.config.js\",\n \"src/content.config.mjs\",\n \"src/content/config.ts\",\n \"src/content/config.mts\",\n \"src/content/config.js\",\n \"src/content/config.mjs\",\n ]);\n if (config) {\n result.kept.push(config);\n if (!readFileSync(path.join(project, config), \"utf8\").includes(\"micaCollections\")) {\n result.next.push(`Add the Mica collections to ${config}:\\n\\n${MERGE}`);\n }\n } else {\n write(project, \"src/content.config.ts\", COLLECTIONS, result);\n }\n\n const missing = [\"@micacms/astro\", \"@micacms/core\"].filter((name) => !dependencies[name]);\n if (missing.length > 0) result.next.push(`Install the packages: npm install ${missing.join(\" \")}`);\n if (!dependencies[\"@micacms/editor\"]) result.next.push(\"Install the editor: npm install --save-dev @micacms/editor\");\n result.next.push(\n model\n ? \"Add the website's collections and singletons to the model in src/mica.ts.\"\n : \"Replace the starter model in src/mica.ts (news, settings) with the website's model.\",\n \"Write the model to content/.mica/schema.json: npx astro sync\",\n \"Check the content: npx mica check\",\n \"When the content is in place, open the editor in a browser: npx mica\",\n );\n return result;\n}\n\nfunction existingFile(project: string, candidates: string[]): string | undefined {\n return candidates.find((candidate) => existsSync(path.join(project, candidate)));\n}\n\nfunction write(project: string, file: string, contents: string, result: InitResult): void {\n mkdirSync(path.dirname(path.join(project, file)), { recursive: true });\n writeFileSync(path.join(project, file), contents, { flag: \"wx\" });\n result.created.push(file);\n}\n\n/** The result as a person or an agent reads it. */\nexport function formatInit(result: InitResult): string {\n const lines: string[] = [];\n for (const file of result.created) lines.push(` created ${file}`);\n for (const file of result.kept) lines.push(` kept ${file}`);\n lines.push(\"\", \"Next:\", \"\");\n result.next.forEach((step, index) => lines.push(` ${index + 1}. ${step}`, ...(step.includes(\"\\n\") ? [\"\"] : [])));\n return `${lines.join(\"\\n\")}\\n`;\n}\n"]}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `mica init` — adds Mica to an Astro project: a starter model and the content\n * collections. It never overwrites a file.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\n\nexport const MODEL = `import {\n collection,\n date,\n defineSite,\n media,\n richText,\n singleton,\n slug,\n text,\n} from \"@micacms/core\";\n\nexport const site = defineSite({\n root: \"./content\",\n\n collections: {\n news: collection({\n label: \"News\",\n labelSingular: \"Article\",\n fields: {\n title: text({ label: \"Title\", required: true, maxLength: 120, listed: true }),\n slug: slug({ from: \"title\" }),\n publishedOn: date({ label: \"Published on\", listed: true }),\n cover: media({ accept: \"image\", alt: \"required\" }),\n body: richText(),\n },\n }),\n },\n\n singletons: {\n settings: singleton({\n label: \"Website\",\n fields: {\n siteName: text({ label: \"Site name\", required: true }),\n tagline: text({ label: \"Tagline\" }),\n },\n }),\n },\n});\n`;\n\nconst COLLECTIONS = `import { micaCollections } from \"@micacms/astro\";\n\nimport { site } from \"./mica\";\n\nexport const collections = micaCollections(site);\n`;\n\nconst MERGE = ` import { micaCollections } from \"@micacms/astro\";\n import { site } from \"./mica\";\n\n export const collections = { ...micaCollections(site), /* your collections */ };`;\n\nexport interface InitResult {\n /** Files and directories made, relative to the project. */\n created: string[];\n /** Files that already existed and were left alone. */\n kept: string[];\n /** What the person or agent does next. */\n next: string[];\n}\n\nexport class InitError extends Error {\n override name = \"InitError\";\n}\n\n/** Adds Mica to the Astro project in `project`. */\nexport function initProject(project: string): InitResult {\n const manifest = path.join(project, \"package.json\");\n if (!existsSync(manifest)) {\n throw new InitError(`There is no package.json in ${project}. Create an Astro project first: npm create astro@latest`);\n }\n let pkg: {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n scripts?: Record<string, string>;\n };\n try {\n pkg = JSON.parse(readFileSync(manifest, \"utf8\")) as typeof pkg;\n } catch (cause) {\n throw new InitError(`${manifest} is not valid JSON: ${(cause as Error).message}`);\n }\n const dependencies = { ...pkg.dependencies, ...pkg.devDependencies };\n if (!dependencies[\"astro\"]) {\n throw new InitError(`${manifest} has no \"astro\" dependency. Run mica init in an Astro project.`);\n }\n\n const result: InitResult = { created: [], kept: [], next: [] };\n\n const model = existingFile(project, [\"src/mica.ts\", \"src/mica.mts\", \"src/mica.js\", \"src/mica.mjs\"]);\n if (model) result.kept.push(model);\n else write(project, \"src/mica.ts\", MODEL, result);\n\n const config = existingFile(project, [\n \"src/content.config.ts\",\n \"src/content.config.mts\",\n \"src/content.config.js\",\n \"src/content.config.mjs\",\n \"src/content/config.ts\",\n \"src/content/config.mts\",\n \"src/content/config.js\",\n \"src/content/config.mjs\",\n ]);\n if (config) {\n result.kept.push(config);\n if (!readFileSync(path.join(project, config), \"utf8\").includes(\"micaCollections\")) {\n result.next.push(`Add the Mica collections to ${config}:\\n\\n${MERGE}`);\n }\n } else {\n write(project, \"src/content.config.ts\", COLLECTIONS, result);\n }\n\n const missing = [\"@micacms/astro\", \"@micacms/core\"].filter((name) => !dependencies[name]);\n if (missing.length > 0) result.next.push(`Install the packages: npm install ${missing.join(\" \")}`);\n if (!dependencies[\"@micacms/editor\"]) result.next.push(\"Install the editor: npm install --save-dev @micacms/editor\");\n const scripts = scriptsToSet(pkg.scripts ?? {}, Boolean(dependencies[\"@astrojs/check\"]));\n if (scripts.length > 0) result.next.push(`Set in \"scripts\" in package.json:\\n\\n${scripts.map((line) => ` ${line}`).join(\",\\n\")}`);\n result.next.push(\n model\n ? \"Add the website's collections and singletons to the model in src/mica.ts.\"\n : \"Replace the starter model in src/mica.ts (news, settings) with the website's model.\",\n \"Write the model to content/.mica/schema.json: npx astro sync\",\n \"Check the content: npx mica check\",\n \"When the content is in place, open the editor in a browser: npx mica start\",\n );\n return result;\n}\n\n/** `npm run mica` opens the editor (`mica start`); `npm run check` checks the content, and the types when `@astrojs/check` is there. */\nfunction scriptsToSet(scripts: Record<string, string>, astroCheck: boolean): string[] {\n const missing: string[] = [];\n if (!scripts[\"mica\"]) missing.push(`\"mica\": \"mica start\"`);\n // Without @astrojs/check, `astro check` asks to install it, and a script cannot answer.\n const check = scripts[\"check\"];\n if (!check) missing.push(`\"check\": \"${astroCheck ? \"mica check && astro check\" : \"mica check\"}\"`);\n else if (!check.includes(\"mica check\")) missing.push(`\"check\": ${JSON.stringify(`mica check && ${check}`)}`);\n return missing;\n}\n\nfunction existingFile(project: string, candidates: string[]): string | undefined {\n return candidates.find((candidate) => existsSync(path.join(project, candidate)));\n}\n\nfunction write(project: string, file: string, contents: string, result: InitResult): void {\n mkdirSync(path.dirname(path.join(project, file)), { recursive: true });\n writeFileSync(path.join(project, file), contents, { flag: \"wx\" });\n result.created.push(file);\n}\n\n/** The result as a person or an agent reads it. */\nexport function formatInit(result: InitResult): string {\n const lines: string[] = [];\n for (const file of result.created) lines.push(` created ${file}`);\n for (const file of result.kept) lines.push(` kept ${file}`);\n lines.push(\"\", \"Next:\", \"\");\n result.next.forEach((step, index) => lines.push(` ${index + 1}. ${step}`, ...(step.includes(\"\\n\") ? [\"\"] : [])));\n return `${lines.join(\"\\n\")}\\n`;\n}\n"]}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * `mica migrate-layout`: moves the entries that a model change left in the
3
+ * other layout. The developer runs it in the working tree and commits the
4
+ * result with the model change; Git is the undo.
5
+ */
6
+ export interface LayoutMigration {
7
+ /** Each entry moved, as content-root paths. */
8
+ moved: Array<{
9
+ from: string;
10
+ to: string;
11
+ }>;
12
+ /** Rich text and media of an entry that became a file: no field reads them now. */
13
+ removed: string[];
14
+ /** Files that Mica did not write, left in the old folder. */
15
+ kept: string[];
16
+ /** Entries not moved, because the target already exists. */
17
+ conflicts: string[];
18
+ }
19
+ /** Moves every entry in the other layout into the layout that the model gives. */
20
+ export declare function migrateLayout(root: string): Promise<LayoutMigration>;
21
+ /** The result as a person or an agent reads it. */
22
+ export declare function formatMigration(result: LayoutMigration): string;
23
+ //# sourceMappingURL=migrate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAsBH,MAAM,WAAW,eAAe;IAC9B,+CAA+C;IAC/C,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3C,mFAAmF;IACnF,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,6DAA6D;IAC7D,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,4DAA4D;IAC5D,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,kFAAkF;AAClF,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAgC1E;AAmDD,mDAAmD;AACnD,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAS/D"}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * `mica migrate-layout`: moves the entries that a model change left in the
3
+ * other layout. The developer runs it in the working tree and commits the
4
+ * result with the model change; Git is the undo.
5
+ */
6
+ import { existsSync } from "node:fs";
7
+ import { mkdir, readdir, rename, rm, rmdir } from "node:fs/promises";
8
+ import path from "node:path";
9
+ import { collectReferences, DOCUMENT_EXTENSION, entryLayout, INDEX_FILE, MEDIA_DIR, misplacedFiles, readCollection, readSingleton, } from "@micacms/core";
10
+ import { within } from "@micacms/core/node";
11
+ import { contentFiles, loadSchema } from "@micacms/runtime";
12
+ /** Moves every entry in the other layout into the layout that the model gives. */
13
+ export async function migrateLayout(root) {
14
+ const files = contentFiles({ root });
15
+ const site = await loadSchema(files);
16
+ const result = { moved: [], removed: [], kept: [], conflicts: [] };
17
+ const parts = [
18
+ ...Object.entries(site.collections).map(([name, def]) => [name, def.fields, "collection"]),
19
+ ...Object.entries(site.singletons).map(([name, def]) => [name, def.fields, "singleton"]),
20
+ ];
21
+ const formerFolders = [];
22
+ for (const [name, fields, kind] of parts) {
23
+ // The model decides the direction: `pages/index.json` is an entry named `index` in a file collection.
24
+ const toFolder = entryLayout(fields) === "directory";
25
+ for (const from of await misplacedFiles(files, fields, name, kind)) {
26
+ const to = toFolder ? `${from.slice(0, -".json".length)}/${INDEX_FILE}` : `${path.posix.dirname(from)}.json`;
27
+ if (existsSync(within(root, to))) {
28
+ result.conflicts.push(`${from}: ${to} exists too. Merge the two by hand.`);
29
+ continue;
30
+ }
31
+ await mkdir(path.dirname(within(root, to)), { recursive: true });
32
+ await rename(within(root, from), within(root, to));
33
+ if (!toFolder)
34
+ formerFolders.push(path.posix.dirname(from));
35
+ result.moved.push({ from, to });
36
+ }
37
+ }
38
+ const used = await usedMedia(files, site);
39
+ for (const folder of formerFolders)
40
+ await emptyFolder(root, folder, used, result);
41
+ return result;
42
+ }
43
+ /**
44
+ * Every media path that an entry uses, after the moves. Null when a collection
45
+ * cannot be read: then no media file is removed.
46
+ */
47
+ async function usedMedia(files, site) {
48
+ const used = new Set();
49
+ const note = (fields, data) => {
50
+ for (const reference of collectReferences(fields, data))
51
+ if (reference.kind === "media")
52
+ used.add(reference.path);
53
+ };
54
+ try {
55
+ for (const [name, def] of Object.entries(site.collections)) {
56
+ for (const entry of await readCollection(files, def, name))
57
+ note(def.fields, entry.data);
58
+ }
59
+ for (const [name, def] of Object.entries(site.singletons)) {
60
+ const data = await readSingleton(files, def, name);
61
+ if (data)
62
+ note(def.fields, data);
63
+ }
64
+ }
65
+ catch {
66
+ return null;
67
+ }
68
+ return used;
69
+ }
70
+ /** Removes the sidecars and the unused media of a former folder entry; keeps anything else. */
71
+ async function emptyFolder(root, folder, used, result) {
72
+ for (const item of await readdir(within(root, folder), { withFileTypes: true, recursive: true })) {
73
+ if (!item.isFile())
74
+ continue;
75
+ const file = path.relative(path.resolve(root), path.join(item.parentPath, item.name)).split(path.sep).join("/");
76
+ const inMedia = file.startsWith(`${folder}/${MEDIA_DIR}/`);
77
+ const sidecar = path.posix.dirname(file) === folder && file.endsWith(DOCUMENT_EXTENSION);
78
+ if (inMedia && (used === null || used.has(file))) {
79
+ result.kept.push(`${file} (${used ? "another entry uses it" : "a collection could not be read"})`);
80
+ }
81
+ else if (inMedia || sidecar) {
82
+ await rm(within(root, file));
83
+ result.removed.push(file);
84
+ }
85
+ else {
86
+ result.kept.push(`${file} (not written by Mica)`);
87
+ }
88
+ }
89
+ await removeEmpty(within(root, folder));
90
+ }
91
+ async function removeEmpty(directory) {
92
+ for (const item of await readdir(directory, { withFileTypes: true })) {
93
+ if (item.isDirectory())
94
+ await removeEmpty(path.join(directory, item.name));
95
+ }
96
+ if ((await readdir(directory)).length === 0)
97
+ await rmdir(directory);
98
+ }
99
+ /** The result as a person or an agent reads it. */
100
+ export function formatMigration(result) {
101
+ const lines = [];
102
+ for (const { from, to } of result.moved)
103
+ lines.push(` moved ${from} -> ${to}`);
104
+ for (const file of result.removed)
105
+ lines.push(` removed ${file}`);
106
+ for (const file of result.kept)
107
+ lines.push(` kept ${file}`);
108
+ for (const conflict of result.conflicts)
109
+ lines.push(` error ${conflict}`);
110
+ if (lines.length === 0)
111
+ return "Every entry is in the layout of the model. Nothing to move.\n";
112
+ lines.push("", "Next: run `npx mica check`, look at `git status`, and commit the result with the model change.");
113
+ return `${lines.join("\n")}\n`;
114
+ }
115
+ //# sourceMappingURL=migrate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `mica migrate-layout`: moves the entries that a model change left in the\n * other layout. The developer runs it in the working tree and commits the\n * result with the model change; Git is the undo.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { mkdir, readdir, rename, rm, rmdir } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport {\n collectReferences,\n DOCUMENT_EXTENSION,\n entryLayout,\n INDEX_FILE,\n MEDIA_DIR,\n misplacedFiles,\n readCollection,\n readSingleton,\n type ContentSource,\n type FieldMap,\n type Site,\n} from \"@micacms/core\";\nimport { within } from \"@micacms/core/node\";\nimport { contentFiles, loadSchema } from \"@micacms/runtime\";\n\nexport interface LayoutMigration {\n /** Each entry moved, as content-root paths. */\n moved: Array<{ from: string; to: string }>;\n /** Rich text and media of an entry that became a file: no field reads them now. */\n removed: string[];\n /** Files that Mica did not write, left in the old folder. */\n kept: string[];\n /** Entries not moved, because the target already exists. */\n conflicts: string[];\n}\n\n/** Moves every entry in the other layout into the layout that the model gives. */\nexport async function migrateLayout(root: string): Promise<LayoutMigration> {\n const files = contentFiles({ root });\n const site = await loadSchema(files);\n const result: LayoutMigration = { moved: [], removed: [], kept: [], conflicts: [] };\n\n const parts: Array<[string, FieldMap, \"collection\" | \"singleton\"]> = [\n ...Object.entries(site.collections).map(([name, def]) => [name, def.fields, \"collection\"] as [string, FieldMap, \"collection\"]),\n ...Object.entries(site.singletons).map(([name, def]) => [name, def.fields, \"singleton\"] as [string, FieldMap, \"singleton\"]),\n ];\n\n const formerFolders: string[] = [];\n for (const [name, fields, kind] of parts) {\n // The model decides the direction: `pages/index.json` is an entry named `index` in a file collection.\n const toFolder = entryLayout(fields) === \"directory\";\n for (const from of await misplacedFiles(files, fields, name, kind)) {\n const to = toFolder ? `${from.slice(0, -\".json\".length)}/${INDEX_FILE}` : `${path.posix.dirname(from)}.json`;\n\n if (existsSync(within(root, to))) {\n result.conflicts.push(`${from}: ${to} exists too. Merge the two by hand.`);\n continue;\n }\n\n await mkdir(path.dirname(within(root, to)), { recursive: true });\n await rename(within(root, from), within(root, to));\n if (!toFolder) formerFolders.push(path.posix.dirname(from));\n result.moved.push({ from, to });\n }\n }\n\n const used = await usedMedia(files, site);\n for (const folder of formerFolders) await emptyFolder(root, folder, used, result);\n return result;\n}\n\n/**\n * Every media path that an entry uses, after the moves. Null when a collection\n * cannot be read: then no media file is removed.\n */\nasync function usedMedia(files: ContentSource, site: Site): Promise<Set<string> | null> {\n const used = new Set<string>();\n const note = (fields: FieldMap, data: Record<string, unknown>) => {\n for (const reference of collectReferences(fields, data)) if (reference.kind === \"media\") used.add(reference.path);\n };\n try {\n for (const [name, def] of Object.entries(site.collections)) {\n for (const entry of await readCollection(files, def, name)) note(def.fields, entry.data);\n }\n for (const [name, def] of Object.entries(site.singletons)) {\n const data = await readSingleton(files, def, name);\n if (data) note(def.fields, data);\n }\n } catch {\n return null;\n }\n return used;\n}\n\n/** Removes the sidecars and the unused media of a former folder entry; keeps anything else. */\nasync function emptyFolder(root: string, folder: string, used: Set<string> | null, result: LayoutMigration): Promise<void> {\n for (const item of await readdir(within(root, folder), { withFileTypes: true, recursive: true })) {\n if (!item.isFile()) continue;\n const file = path.relative(path.resolve(root), path.join(item.parentPath, item.name)).split(path.sep).join(\"/\");\n const inMedia = file.startsWith(`${folder}/${MEDIA_DIR}/`);\n const sidecar = path.posix.dirname(file) === folder && file.endsWith(DOCUMENT_EXTENSION);\n if (inMedia && (used === null || used.has(file))) {\n result.kept.push(`${file} (${used ? \"another entry uses it\" : \"a collection could not be read\"})`);\n } else if (inMedia || sidecar) {\n await rm(within(root, file));\n result.removed.push(file);\n } else {\n result.kept.push(`${file} (not written by Mica)`);\n }\n }\n await removeEmpty(within(root, folder));\n}\n\nasync function removeEmpty(directory: string): Promise<void> {\n for (const item of await readdir(directory, { withFileTypes: true })) {\n if (item.isDirectory()) await removeEmpty(path.join(directory, item.name));\n }\n if ((await readdir(directory)).length === 0) await rmdir(directory);\n}\n\n/** The result as a person or an agent reads it. */\nexport function formatMigration(result: LayoutMigration): string {\n const lines: string[] = [];\n for (const { from, to } of result.moved) lines.push(` moved ${from} -> ${to}`);\n for (const file of result.removed) lines.push(` removed ${file}`);\n for (const file of result.kept) lines.push(` kept ${file}`);\n for (const conflict of result.conflicts) lines.push(` error ${conflict}`);\n if (lines.length === 0) return \"Every entry is in the layout of the model. Nothing to move.\\n\";\n lines.push(\"\", \"Next: run `npx mica check`, look at `git status`, and commit the result with the model change.\");\n return `${lines.join(\"\\n\")}\\n`;\n}\n"]}
package/package.json CHANGED
@@ -1,9 +1,16 @@
1
1
  {
2
2
  "name": "@micacms/editor",
3
- "version": "0.5.0",
3
+ "version": "0.6.0-rc.2",
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",
7
+ "homepage": "https://micacms.com",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/micacms/mica.git",
11
+ "directory": "apps/local-editor"
12
+ },
13
+ "bugs": "https://github.com/micacms/mica/issues",
7
14
  "author": "Alexander Müdespacher",
8
15
  "keywords": [
9
16
  "mica",
@@ -23,9 +30,9 @@
23
30
  "dependencies": {
24
31
  "hono": "^4.13.7",
25
32
  "zod": "^4.3.6",
26
- "@micacms/core": "0.5.0",
27
- "@micacms/editor-ui": "0.5.0",
28
- "@micacms/runtime": "0.5.0"
33
+ "@micacms/core": "0.6.0-rc.2",
34
+ "@micacms/editor-ui": "0.6.0-rc.2",
35
+ "@micacms/runtime": "0.6.0-rc.2"
29
36
  },
30
37
  "devDependencies": {
31
38
  "@types/node": "^22.20.1",
@@ -33,14 +40,14 @@
33
40
  "typescript": "^5.7.3"
34
41
  },
35
42
  "engines": {
36
- "node": ">=22.12.0"
43
+ "node": ">=24"
37
44
  },
38
45
  "publishConfig": {
39
46
  "access": "public"
40
47
  },
41
48
  "scripts": {
42
49
  "build": "tsc -p tsconfig.json",
43
- "dev": "tsx watch --clear-screen=false --include ../../examples/muster-consulting/content/.mica/schema.json src/index.ts",
50
+ "dev": "tsx watch --env-file=dev.env --clear-screen=false --include ../../examples/muster-consulting/content/.mica/schema.json src/index.ts",
44
51
  "start": "node dist/index.js",
45
52
  "typecheck": "tsc -p tsconfig.test.json",
46
53
  "test": "tsc -p tsconfig.test.json && node --test --import tsx test/*.test.ts"