@schemic/core 0.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +212 -0
- package/lib/authoring.d.ts +89 -0
- package/lib/authoring.js +187 -0
- package/lib/authoring.js.map +1 -0
- package/lib/chunk-C4D6JWSE.js +54 -0
- package/lib/chunk-C4D6JWSE.js.map +1 -0
- package/lib/chunk-T23RNU7G.js +304 -0
- package/lib/chunk-T23RNU7G.js.map +1 -0
- package/lib/config-TIiKDd9t.d.ts +97 -0
- package/lib/config.d.ts +1 -0
- package/lib/config.js +8 -0
- package/lib/config.js.map +1 -0
- package/lib/driver-Dh5hLKHm.d.ts +736 -0
- package/lib/driver.d.ts +150 -0
- package/lib/driver.js +47 -0
- package/lib/driver.js.map +1 -0
- package/lib/index.d.ts +84 -0
- package/lib/index.js +794 -0
- package/lib/index.js.map +1 -0
- package/lib/testing.d.ts +29 -0
- package/lib/testing.js +111 -0
- package/lib/testing.js.map +1 -0
- package/package.json +93 -0
- package/src/authoring.ts +304 -0
- package/src/cli-kit/config.ts +179 -0
- package/src/cli-kit/diff.ts +230 -0
- package/src/cli-kit/filter.ts +159 -0
- package/src/cli-kit/merge.ts +380 -0
- package/src/cli-kit/meta.ts +123 -0
- package/src/cli-kit/pager.ts +42 -0
- package/src/cli-kit/schema.ts +186 -0
- package/src/cli-kit/style.ts +24 -0
- package/src/config.ts +51 -0
- package/src/connection.ts +78 -0
- package/src/driver/driver.ts +300 -0
- package/src/driver/index.ts +31 -0
- package/src/driver/portable-ir.ts +51 -0
- package/src/driver/portable.ts +124 -0
- package/src/driver/sdk.ts +66 -0
- package/src/index.ts +145 -0
- package/src/kind/index.ts +28 -0
- package/src/kind/plan.ts +390 -0
- package/src/kind/registry.ts +225 -0
- package/src/testing.ts +181 -0
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli-kit/config.ts","../src/cli-kit/style.ts","../src/cli-kit/diff.ts","../src/cli-kit/filter.ts","../src/cli-kit/merge.ts","../src/cli-kit/meta.ts","../src/cli-kit/pager.ts","../src/cli-kit/schema.ts"],"sourcesContent":["import { existsSync, statSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport type { SchemicConfig } from \"@schemic/core/config\";\nimport { createJiti } from \"jiti\";\nimport type { ConnectionConfigBase, ResolveContext } from \"../connection\";\n\nconst CONFIG_NAMES = [\n \"schemic.config.ts\",\n \"schemic.config.mjs\",\n \"schemic.config.js\",\n];\n\nconst DEFAULT_MIGRATIONS = \"./database/migrations\";\n\n/**\n * Is the schema path a single file (vs a directory of schema modules)? Determined by `stat` when\n * it exists, else inferred from a `.ts`/`.js`-ish extension.\n */\nfunction schemaIsFilePath(path: string): boolean {\n if (existsSync(path)) return statSync(path).isFile();\n return /\\.[mc]?[jt]s$/.test(path);\n}\n\n/**\n * Load `.env(.local)` from the project root into `process.env` so the config's own explicit\n * `process.env.X` reads resolve when run under node (bun loads `.env` itself). Does not override\n * already-set variables, so shell env still wins; load `.env.local` first so it beats `.env`.\n */\nfunction loadDotEnv(dir: string): void {\n const proc = process as typeof process & {\n loadEnvFile?: (path: string) => void;\n };\n if (typeof proc.loadEnvFile !== \"function\") return;\n for (const name of [\".env.local\", \".env\"]) {\n const file = resolve(dir, name);\n if (!existsSync(file)) continue;\n try {\n proc.loadEnvFile(file);\n } catch {\n // ignore a malformed .env file\n }\n }\n}\n\n/**\n * A resolved, per-CONNECTION config — the dialect-NEUTRAL shape every command operates on (one\n * connection at a time). `params` are the driver-specific connection params (opaque to core; the\n * driver's `connect` reads them). Built by resolving one entry of `config.connections`.\n */\nexport interface ResolvedConfig {\n /** Resolved connection name (e.g. `default`, or `tenants:abc` within a collection). */\n connection: string;\n /** The driver this connection uses (the package the CLI dynamically loads). */\n driver: string;\n /** Project root (the directory containing the config file). */\n root: string;\n /** Absolute schema path — a single `.ts` module, or a directory of them. */\n schemaPath: string;\n /** Whether `schemaPath` is a single file (vs a directory of schema modules). */\n schemaIsFile: boolean;\n /** Absolute migrations directory (per connection's schema). */\n migrationsDir: string;\n /** Absolute migration meta directory (the snapshot). */\n metaDir: string;\n /** Name of the table that records applied migrations. */\n migrationsTable: string;\n /** Driver-specific connection params (url/namespace/… or whatever the driver defines). Opaque to core. */\n params: Record<string, unknown>;\n /** Optional seed script (project-level). */\n seed?: string;\n}\n\n/**\n * A jiti instance for loading the project's TS/ESM modules. Caches are off so `--watch` re-reads\n * edited schema files. (Bare deps like `@schemic/core` are native-imported, so registries stay shared.)\n */\nexport function makeJiti() {\n return createJiti(import.meta.url, {\n interopDefault: true,\n fsCache: false,\n moduleCache: false,\n });\n}\n\n/** Find + load `schemic.config.ts` into the dialect-neutral {@link SchemicConfig}. */\nexport async function loadProject(opts?: {\n config?: string;\n cwd?: string;\n}): Promise<{ config: SchemicConfig; root: string }> {\n const cwd = opts?.cwd ?? process.cwd();\n const path = opts?.config\n ? resolve(cwd, opts.config)\n : CONFIG_NAMES.map((n) => resolve(cwd, n)).find((p) => existsSync(p));\n if (!path || !existsSync(path)) {\n throw new Error(\"No schemic.config.ts found — run `schemic init` first.\");\n }\n const root = dirname(path);\n loadDotEnv(root); // populate process.env before the config module's explicit reads\n const loaded = (await makeJiti().import(path)) as {\n default?: SchemicConfig;\n } & SchemicConfig;\n const config = loaded.default ?? loaded;\n if (!config?.connections || Object.keys(config.connections).length === 0) {\n throw new Error(`Invalid config at ${path}: expected a \"connections\" map.`);\n }\n return { config, root };\n}\n\n/**\n * Build the {@link ResolvedConfig} for one connection of the project. `ctx` carries the lazy\n * cross-connection proxy + CLI `--arg`s (the CLI provides the real one; a static connection ignores\n * it). A resolver returning a COLLECTION yields one ResolvedConfig per keyed entry.\n *\n * NOTE (WIP — multi-connection): the full resolution engine (lazy proxy DAG, `--connection`/`--all`\n * addressing, collection fan-out) lives in `@schemic/cli`; this builder handles a single resolved\n * connection config. See docs/MULTI-CONNECTION.md.\n */\nexport function resolveConnectionConfig(\n config: SchemicConfig,\n connection: string,\n conn: ConnectionConfigBase,\n driver: string,\n root: string,\n): ResolvedConfig {\n const { schema, migrations, key, ...params } = conn;\n const schemaPath = resolve(root, schema);\n const migrationsDir = resolve(root, migrations ?? DEFAULT_MIGRATIONS);\n return {\n connection: key ? `${connection}:${key}` : connection,\n driver,\n root,\n schemaPath,\n schemaIsFile: schemaIsFilePath(schemaPath),\n migrationsDir,\n metaDir: resolve(migrationsDir, \"meta\"),\n migrationsTable: config.migrationsTable ?? \"_migrations\",\n params: params as Record<string, unknown>,\n seed: config.seed,\n };\n}\n\n/**\n * Load the project and resolve the DEFAULT connection to a {@link ResolvedConfig} — the single-\n * connection convenience path. (Multi-connection addressing + resolver context are added by the CLI;\n * here a static default connection is resolved with an empty context.)\n */\nexport async function loadConfig(opts?: {\n config?: string;\n cwd?: string;\n}): Promise<ResolvedConfig> {\n const { config, root } = await loadProject(opts);\n const names = Object.keys(config.connections);\n const name =\n config.defaultConnection ?? (names.length === 1 ? names[0] : \"default\");\n const entry = config.connections[name];\n if (!entry) {\n throw new Error(\n `No connection named \"${name}\". Set \"defaultConnection\" or pass --connection. Known: ${names.join(\", \")}.`,\n );\n }\n const ctx: ResolveContext = { connections: {}, args: {}, env: process.env };\n const resolved = await entry.resolve(ctx);\n if (resolved.length !== 1) {\n throw new Error(\n `Connection \"${name}\" resolved to ${resolved.length} connections (a collection); pass --connection ${name}:<key>.`,\n );\n }\n return resolveConnectionConfig(config, name, resolved[0], entry.driver, root);\n}\n\n/** Per-command connection flag overrides (CLI args, applied by the driver over `params`). */\nexport interface ConnectionOverrides {\n url?: string;\n namespace?: string;\n database?: string;\n username?: string;\n password?: string;\n authLevel?: string;\n}\n","// Tiny ANSI styling, gated on a TTY and honoring NO_COLOR. No dependency.\n/** Whether colored output is enabled (a TTY and `NO_COLOR` unset). */\nexport const colorEnabled = () =>\n Boolean(process.stdout.isTTY) && !process.env.NO_COLOR;\nconst paint = (code: number, s: string) =>\n colorEnabled() ? `\\x1b[${code}m${s}\\x1b[0m` : s;\n\nexport const style = {\n green: (s: string) => paint(32, s),\n red: (s: string) => paint(31, s),\n yellow: (s: string) => paint(33, s),\n cyan: (s: string) => paint(36, s),\n dim: (s: string) => paint(90, s),\n bold: (s: string) => paint(1, s),\n};\n\n/** A green ✓ success line. */\nexport const ok = (s: string) => `${style.green(\"✓\")} ${s}`;\n/** A red ✗ failure line. */\nexport const fail = (s: string) => `${style.red(\"✗\")} ${s}`;\n\n/** Pluralize `n thing` / `n things`. */\nexport const plural = (n: number, word: string) =>\n `${n} ${word}${n === 1 ? \"\" : \"s\"}`;\n","// The DIALECT-FREE diff DISPLAY + shared types. The SurrealDB statement-diff engine (buildSnapshot/\n// diffSnapshots/renderMigration) lives in `./surreal-diff` and is invoked through the driver; this\n// module is what the CLI shell uses to RENDER any driver's Diff (git-style file groups, word-diff,\n// unified patch, kind summaries). Dialect-free: `kind` is an opaque string, not a Surreal kind union.\nimport type { KindRegistry } from \"../kind\";\nimport { colorEnabled, style } from \"./style\";\n\n/**\n * One object's change, for display. `kind` is the object kind, `table` its owner (a table name,\n * or the object's own name for db-level objects). `add` carries the new DDL; `remove` carries the\n * `REMOVE` statement (`ddl`) plus the dropped object's prior DDL (`old`, for the unified patch);\n * `change` pairs old↔new.\n */\nexport type DiffItem = {\n key: string;\n table: string;\n /** Dialect-defined object kind (e.g. \"table\"/\"field\"/\"index\") — opaque to the display. */\n kind: string;\n /** The source file this object lives in (or lived in, for a removal). Absent if unknown. */\n file?: string;\n} & (\n | { op: \"add\"; ddl: string }\n | { op: \"remove\"; ddl: string; old: string }\n | { op: \"change\"; before: string; after: string }\n);\n\nexport interface Diff {\n up: string[];\n down: string[];\n /** Structured per-object changes for the human display (word-level diff). */\n items?: DiffItem[];\n /** Every desired statement (the `next` schema), for the `--full` context view. */\n full?: { key: string; table: string; ddl: string }[];\n}\n\n/** `true` if the two snapshots define the same objects with identical DDL. */\nexport function isEmptyDiff(diff: Diff): boolean {\n return diff.up.length === 0;\n}\n\n/**\n * Inline word-level diff of two statements: shared tokens dim, removed tokens red, added tokens\n * green (LCS over space-separated tokens). So a changed field shows the whole statement with only\n * the changed words highlighted.\n */\nexport function tokenDiff(before: string, after: string): string {\n const a = before.split(\" \");\n const b = after.split(\" \");\n const m = a.length;\n const n = b.length;\n const dp: number[][] = Array.from({ length: m + 1 }, () =>\n new Array(n + 1).fill(0),\n );\n for (let i = m - 1; i >= 0; i--) {\n for (let j = n - 1; j >= 0; j--) {\n dp[i][j] =\n a[i] === b[j]\n ? dp[i + 1][j + 1] + 1\n : Math.max(dp[i + 1][j], dp[i][j + 1]);\n }\n }\n // With color: red/green/dim. Without (pipe / CI / NO_COLOR): git `--word-diff=plain` markers\n // `[-removed-]`/`{+added+}` so removed-vs-added is unambiguous and assertable.\n const colored = colorEnabled();\n const del = (t: string) => (colored ? style.red(t) : `[-${t}-]`);\n const ins = (t: string) => (colored ? style.green(t) : `{+${t}+}`);\n const eq = (t: string) => (colored ? style.dim(t) : t);\n const out: string[] = [];\n let i = 0;\n let j = 0;\n while (i < m && j < n) {\n if (a[i] === b[j]) {\n out.push(eq(a[i]));\n i++;\n j++;\n } else if (dp[i + 1][j] >= dp[i][j + 1]) {\n out.push(del(a[i++]));\n } else {\n out.push(ins(b[j++]));\n }\n }\n while (i < m) out.push(del(a[i++]));\n while (j < n) out.push(ins(b[j++]));\n return out.join(\" \");\n}\n\n/**\n * Render one display item: `+`/`-` line for add/remove. A change renders as separate red `-` /\n * green `+` lines by default, or as a single inline word-diff when `inline` is set (the A/B toggle).\n */\nfunction renderItem(it: DiffItem, inline = false): string {\n if (it.op === \"add\") return style.green(` + ${it.ddl}`);\n if (it.op === \"remove\") return style.red(` - ${it.ddl}`);\n if (inline) return ` ${tokenDiff(it.before, it.after)}`;\n return `${style.red(` - ${it.before}`)}\\n${style.green(` + ${it.after}`)}`;\n}\n\n/**\n * Group diff items by their source file (git-style), so the display reads like a file diff. Items\n * with no file (an older snapshot, or the live DB) fall back to a per-object group headed by the\n * object's bare name. Returns groups in first-seen order, each with its header.\n */\nfunction groupByFile(\n items: DiffItem[],\n): { header: string; items: DiffItem[] }[] {\n const order: string[] = [];\n const byKey = new Map<string, DiffItem[]>();\n for (const it of items) {\n const key = it.file ?? `\\0${it.table}`; // \\0 can't collide with a real path\n let group = byKey.get(key);\n if (!group) {\n group = [];\n byKey.set(key, group);\n order.push(key);\n }\n group.push(it);\n }\n return order.map((key) => {\n const group = byKey.get(key) ?? [];\n return {\n header: group.find((i) => i.file)?.file ?? group[0].table,\n items: group,\n };\n });\n}\n\n/** Render display items as a git-style file diff: each group headed by its source file path. */\nexport function formatItems(items: DiffItem[], inline = false): string {\n return groupByFile(items)\n .map((g) =>\n [\n style.bold(g.header),\n ...g.items.map((it) => renderItem(it, inline)),\n ].join(\"\\n\"),\n )\n .join(\"\\n\\n\");\n}\n\n/**\n * A standard **unified diff** of the change, grouped one section per source file (git-style) — for\n * piping through a diff viewer (git's pager / delta). Objects with no file fall back to a section\n * headed by the object's bare name. Each object is a single-line DDL statement, so hunks are\n * line-for-line.\n */\nexport function formatPatch(diff: Diff): string {\n const items = diff.items ?? [];\n if (!items.length) return \"\";\n const out: string[] = [];\n for (const { header, items: group } of groupByFile(items)) {\n const lines: string[] = [];\n let dels = 0;\n let adds = 0;\n for (const it of group) {\n if (it.op === \"add\") {\n lines.push(`+${it.ddl}`);\n adds++;\n } else if (it.op === \"remove\") {\n lines.push(`-${it.old}`);\n dels++;\n } else {\n lines.push(`-${it.before}`, `+${it.after}`);\n dels++;\n adds++;\n }\n }\n out.push(\n `diff --git a/${header} b/${header}`,\n `--- a/${header}`,\n `+++ b/${header}`,\n `@@ -${dels ? 1 : 0},${dels} +${adds ? 1 : 0},${adds} @@`,\n ...lines,\n );\n }\n return `${out.join(\"\\n\")}\\n`;\n}\n\n/** `--full`: the whole desired schema — unchanged dim, additions green, changes word-diffed. */\nfunction formatFull(diff: Diff, inline = false): string {\n const byKey = new Map((diff.items ?? []).map((it) => [it.key, it]));\n const out: string[] = [];\n let prev: string | undefined;\n for (const f of diff.full ?? []) {\n if (prev !== undefined && f.table !== prev) out.push(\"\");\n const it = byKey.get(f.key);\n if (it?.op === \"change\") out.push(renderItem(it, inline));\n else if (it?.op === \"add\") out.push(style.green(` + ${f.ddl}`));\n else out.push(style.dim(` ${f.ddl}`));\n prev = f.table;\n }\n const removed = (diff.items ?? []).filter((it) => it.op === \"remove\");\n if (removed.length) {\n out.push(\"\");\n for (const it of removed) out.push(renderItem(it, inline));\n }\n return out.join(\"\\n\");\n}\n\n/** A human-readable view of a diff's forward (and optionally reverse) changes. */\nexport function formatDiff(\n diff: Diff,\n opts: { down?: boolean; full?: boolean; inline?: boolean } = {},\n): string {\n if (!diff.up.length) return \"No changes.\";\n let out = opts.full\n ? formatFull(diff, opts.inline)\n : formatItems(diff.items ?? [], opts.inline);\n if (opts.down) {\n out += `\\n\\n${style.dim(\" rollback (down):\")}\\n${diff.down.map((s) => style.dim(` ${s}`)).join(\"\\n\")}`;\n }\n return out;\n}\n\n/**\n * A per-kind breakdown of a set of changes, e.g. `1 Table, 2 Fields`. Counts each item by its\n * structured `kind` and labels it from the registry's per-kind {@link KindRegistry.display} (singular\n * when the count is one), so the summary is correct for every dialect — no DDL parsing.\n */\nexport function summarizeKinds(\n registry: KindRegistry,\n items: readonly { kind: string }[],\n): string {\n const counts = new Map<string, number>();\n for (const it of items) counts.set(it.kind, (counts.get(it.kind) ?? 0) + 1);\n const parts: string[] = [];\n for (const [kind, n] of counts) {\n const d = registry.display(kind);\n parts.push(`${n} ${n === 1 ? d.label : d.plural}`);\n }\n return parts.join(\", \");\n}\n","import type { Command } from \"commander\";\nimport type { KindRegistry, PortableObject } from \"../kind\";\nimport { snapshotKinds, snapshotObjects } from \"../kind\";\nimport type { StoredSnapshot } from \"./meta\";\n\n/**\n * Per-kind object filter for `pull`/`diff`/`sync`/`generate`. Each kind is independently\n * included (optionally name-restricted). `DEFINE ACCESS` is OPT-IN everywhere — excluded\n * unless `--access` is given — so an introspection (which redacts access signing keys) can't\n * silently rotate them. Table-scoped objects (fields/indexes/events) follow their table.\n */\ninterface Cat {\n on: boolean;\n /** When set, only these names of the kind are included. */\n names?: Set<string>;\n}\n\nexport interface Filter {\n tables: Cat;\n functions: Cat;\n events: Cat;\n access: Cat;\n}\n\n/** Commander's parse of one `--kind [names]` / `--no-kind` flag: `undefined`/`true`/string/`false`. */\ntype FlagValue = string | boolean | undefined;\n\nexport interface FilterOpts {\n tables?: FlagValue;\n functions?: FlagValue;\n events?: FlagValue;\n access?: FlagValue;\n}\n\nfunction cat(v: FlagValue, defaultOn: boolean): Cat {\n if (v === undefined) return { on: defaultOn };\n if (v === false) return { on: false };\n if (v === true) return { on: true };\n const names = new Set(\n v\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean),\n );\n return names.size ? { on: true, names } : { on: true };\n}\n\n/** Build a {@link Filter} from CLI flags. Access is opt-in (`--access`); the rest default to on. */\nexport function parseFilter(o: FilterOpts): Filter {\n return {\n tables: cat(o.tables, true),\n functions: cat(o.functions, true),\n events: cat(o.events, true),\n access: cat(o.access, false), // DEFINE ACCESS is explicit everywhere — see module note.\n };\n}\n\n/** Attach the per-kind `--tables/--functions/--events/--access [names]` (+ `--no-*`) options. */\nexport function kindFlags(cmd: Command): Command {\n return cmd\n .option(\"--tables [names]\", \"only these tables (comma-separated)\")\n .option(\"--no-tables\", \"exclude all tables\")\n .option(\"--functions [names]\", \"only these functions\")\n .option(\"--no-functions\", \"exclude all functions\")\n .option(\"--events [names]\", \"only these events\")\n .option(\"--no-events\", \"exclude all events\")\n .option(\n \"--access [names]\",\n \"include access (off by default; key not pulled)\",\n )\n .option(\"--no-access\", \"exclude all access (the default)\");\n}\n\n/** Whether a name passes a category gate (kind on + name allowed). Shared with the surreal filters. */\nexport const inCat = (c: Cat, name: string): boolean =>\n c.on && (!c.names || c.names.has(name));\n\n// The SurrealDB statement/struct filters (`included`/`filterSnapshot`/`mergeSnapshot`/\n// `filterStructured`) live in `./surreal-filter`. Below are the dialect-free kind-registry filters.\n\n// --- kind-registry filters (the stored-snapshot path) -------------------------------------------\n\nconst objKey = (o: PortableObject) => `${o.kind}:${o.name}`;\n\n/** Which Filter category gates a TOP-LEVEL kind (and whose name-set its name is matched against). */\nfunction category(kind: string): keyof Filter {\n if (kind === \"function\") return \"functions\";\n if (kind === \"access\") return \"access\";\n return \"tables\"; // a table (and any future top-level structural kind)\n}\n\n/**\n * Whether a portable object passes the filter. A TOP-LEVEL object (no owner) is gated by its kind's\n * category + name. An OWNED object (owner set — an index/event/constraint) FOLLOWS its owner table's\n * inclusion; an `event` is ADDITIONALLY gated by the `events` category. (Fields are substrate nested\n * in their table object, never standalone here.)\n */\nexport function passesFilter(\n registry: KindRegistry,\n o: PortableObject,\n f: Filter,\n): boolean {\n const owner = registry.engine(o.kind)?.owner?.(o);\n if (owner) {\n if (!inCat(f.tables, owner.name)) return false;\n return o.kind === \"event\" ? inCat(f.events, o.name) : true;\n }\n return inCat(f[category(o.kind)], o.name);\n}\n\n/** Keep only the portable objects that pass the filter (the {@link filterStructured} analog). */\nexport function filterKinds(\n registry: KindRegistry,\n objects: PortableObject[],\n f: Filter,\n): PortableObject[] {\n return objects.filter((o) => passesFilter(registry, o, f));\n}\n\n/**\n * The stored snapshot to persist after a filtered `generate`: INCLUDED objects take their new state\n * from `next`, EXCLUDED objects keep `prev`'s. Dedup by `kind:name` (an included `next` object wins).\n * `files` overlays next on prev.\n */\nexport function mergeStored(\n registry: KindRegistry,\n prev: StoredSnapshot,\n next: StoredSnapshot,\n f: Filter,\n): StoredSnapshot {\n const merged = new Map<string, PortableObject>();\n for (const o of snapshotObjects(prev.schema))\n if (!passesFilter(registry, o, f)) merged.set(objKey(o), o);\n for (const o of snapshotObjects(next.schema))\n if (passesFilter(registry, o, f)) merged.set(objKey(o), o);\n return {\n version: 3,\n driver: next.driver,\n schema: snapshotKinds([...merged.values()]),\n files: { ...(prev.files ?? {}), ...(next.files ?? {}) },\n };\n}\n\n/**\n * Restrict the `disk` objects to those that ALSO exist `live` (intersect by `kind:name`) AND pass the\n * filter — for `baseline`. Hand-written schema not yet in the DB stays pending; what's really there is\n * captured. Each field/index/event/constraint is its own object, so intersect-by-key handles them.\n */\nexport function intersectKinds(\n registry: KindRegistry,\n disk: PortableObject[],\n live: PortableObject[],\n f: Filter,\n): PortableObject[] {\n const liveKeys = new Set(live.map(objKey));\n return disk.filter(\n (o) => liveKeys.has(objKey(o)) && passesFilter(registry, o, f),\n );\n}\n","// Surgically merge freshly-pulled `s.*` definitions into existing schema files, instead of\n// overwriting them. Uses magicast (recast under the hood), so untouched code — user comments,\n// extra imports, unrelated consts, hand-formatted fields — survives. The live DB wins on any\n// object/field it defines; the only thing at risk is LOCAL-ONLY content (a field or whole const\n// that exists in your files but not in the DB), which the caller resolves via keep/drop.\n\nimport { mkdirSync, rmSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { generateCode, parseModule } from \"magicast\";\nimport { colorEnabled, style } from \"./style\";\n\n/** One rendered object (table / function / access): its const statement + the imports it needs. */\nexport interface RenderedUnit {\n kind: \"table\" | \"function\" | \"access\";\n /** DB object name (drives the file path). */\n name: string;\n /** The exported const identifier (`User`, `math_add`, …). */\n exportName: string;\n /** The `export const … = define…(…);` statement source (no import lines). */\n code: string;\n /** The `import …` lines this unit needs. */\n imports: string[];\n}\n\n/** Local-only content a merge would drop when mirroring the DB. */\nexport interface LocalOnly {\n /** Per existing const: field keys present locally but absent from the DB object. */\n fields: { exportName: string; fields: string[] }[];\n /** Whole consts present locally whose object the DB no longer has. */\n objects: string[];\n}\n\nexport interface MergeResult {\n content: string;\n localOnly: LocalOnly;\n}\n\n/** Options governing what happens to local-only content. */\nexport interface MergeOptions {\n /** Keep local-only fields (graft them back into the merged object). */\n keepLocalFields: boolean;\n /** Keep local-only consts (objects the DB no longer has). */\n keepLocalObjects: boolean;\n}\n\n/** What pulling would do to one schema file. */\nexport interface PullFilePlan {\n /** Path relative to the project root (for display). */\n rel: string;\n /** Absolute path on disk. */\n abs: string;\n /**\n * `create` (new file), `update` (merged edits), `unchanged` (already matches the DB), or `delete`\n * (a file that is purely local-only entities the DB doesn't have — removed when mirroring).\n */\n action: \"create\" | \"update\" | \"unchanged\" | \"delete\";\n /** Current file contents (`\"\"` for a new file). */\n before: string;\n /** Contents after the pull (the merged result). */\n after: string;\n /** Local-only content this file would drop when mirroring the DB. */\n localOnly: LocalOnly;\n}\n\n/** A driver's introspection rendered into a per-file write plan (see a driver's `planPull`). */\nexport interface PullPlan {\n files: PullFilePlan[];\n}\n\n/** Apply a plan: write created/updated files, delete local-only files. Returns the paths touched. */\nexport function applyPull(plan: PullPlan): string[] {\n const touched: string[] = [];\n for (const f of plan.files) {\n if (f.action === \"unchanged\") continue;\n if (f.action === \"delete\") {\n rmSync(f.abs, { force: true });\n } else {\n mkdirSync(dirname(f.abs), { recursive: true });\n writeFileSync(f.abs, f.after);\n }\n touched.push(f.rel);\n }\n return touched;\n}\n\n// --- AST helpers ------------------------------------------------------------------------------\n// A permissive view over the recast/babel nodes we touch — every property we read, all optional,\n// so navigation needs no per-access casts.\ninterface AstNode {\n type: string;\n name?: string;\n callee?: AstNode;\n object?: AstNode;\n body?: AstNode;\n arguments?: AstNode[];\n properties?: AstNode[];\n declaration?: AstNode;\n declarations?: Array<{ id?: { name?: string }; init?: AstNode }>;\n key?: { name?: string; value?: string };\n comments?: Array<{ leading?: boolean }>;\n}\n\ninterface MagicastModule {\n $ast: { body: AstNode[] };\n imports: {\n $add: (s: { from: string; imported: string; local: string }) => void;\n };\n}\n\nconst asMod = (mod: unknown): MagicastModule =>\n mod as unknown as MagicastModule;\n\n/** The exported const's name, or null if this statement isn't an `export const X = …`. */\nfunction exportConstName(node: AstNode): string | null {\n if (node.type !== \"ExportNamedDeclaration\") return null;\n if (node.declaration?.type !== \"VariableDeclaration\") return null;\n return node.declaration.declarations?.[0]?.id?.name ?? null;\n}\n\n/** The init expression of an `export const X = <init>`. */\nfunction exportConstInit(node: AstNode): AstNode | null {\n return node.declaration?.declarations?.[0]?.init ?? null;\n}\n\n/** Walk a `define…(…).a().b()` chain down to the `define…(…)` CallExpression. */\nfunction defineCall(init: AstNode | null): AstNode | null {\n let n: AstNode | null = init;\n while (n) {\n if (n.type === \"CallExpression\") {\n if (\n n.callee?.type === \"Identifier\" &&\n /^define/.test(n.callee.name ?? \"\")\n )\n return n;\n n =\n n.callee?.type === \"MemberExpression\"\n ? (n.callee.object ?? null)\n : (n.callee ?? null);\n } else if (n.type === \"MemberExpression\") {\n n = n.object ?? null;\n } else break;\n }\n return null;\n}\n\n/** The fields ObjectExpression of a `defineTable`/`defineRelation` call (handles the `self` arrow form). */\nfunction fieldsObject(init: AstNode | null): AstNode | null {\n const call = defineCall(init);\n if (!call) return null;\n let obj = call.arguments?.[1] ?? null;\n if (obj?.type === \"ArrowFunctionExpression\") obj = obj.body ?? null;\n return obj?.type === \"ObjectExpression\" ? obj : null;\n}\n\n/** Property key as a string (`name` / `\"weird-key\"`). */\nfunction propKey(p: AstNode): string | undefined {\n return p.key?.name ?? p.key?.value;\n}\n\n/** Whether a node carries a leading comment (so we don't clobber/duplicate it). */\nfunction hasLeadingComment(node: AstNode): boolean {\n return Boolean(node.comments?.some((c) => c.leading));\n}\n\n/** Parse `import { a, b } from \"x\"` lines into `{from, names}` (our generated imports use no aliases). */\nfunction parseImportLine(\n line: string,\n): { from: string; names: string[] } | null {\n const m = /import\\s*\\{([^}]*)\\}\\s*from\\s*[\"']([^\"']+)[\"']/.exec(line);\n if (!m) return null;\n return {\n from: m[2],\n names: m[1]\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean),\n };\n}\n\n/**\n * Merge `units` into `existingSrc`. Each unit replaces the matching `export const` in place (DB wins),\n * preserving everything else in the file. New units are appended; needed imports are unioned in.\n * Local-only fields/objects are reported, and kept or dropped per `opts`.\n */\nexport function mergeUnits(\n existingSrc: string,\n units: RenderedUnit[],\n opts: MergeOptions,\n): MergeResult {\n const mod = parseModule(existingSrc);\n const body = asMod(mod).$ast.body;\n\n // Index existing exported consts by name.\n const existing = new Map<string, AstNode>();\n for (const node of body) {\n const name = exportConstName(node);\n if (name) existing.set(name, node);\n }\n\n const localOnly: LocalOnly = { fields: [], objects: [] };\n const desiredNames = new Set(units.map((u) => u.exportName));\n\n for (const unit of units) {\n // Parse the freshly-rendered unit to lift its statement node.\n const unitBody = asMod(parseModule(unit.code)).$ast.body;\n const desiredNode = unitBody.find(\n (n) => exportConstName(n) === unit.exportName,\n );\n if (!desiredNode) continue; // shouldn't happen — the renderer always emits the const\n\n const prior = existing.get(unit.exportName);\n if (prior) {\n // Table/relation: reconcile fields. Functions/access are atomic (whole-const replace).\n if (unit.kind === \"table\") {\n const priorObj = fieldsObject(exportConstInit(prior));\n const desiredObj = fieldsObject(exportConstInit(desiredNode));\n if (priorObj?.properties && desiredObj?.properties) {\n const desiredKeys = new Set(desiredObj.properties.map(propKey));\n const localFields = priorObj.properties.filter(\n (p) => !desiredKeys.has(propKey(p)),\n );\n if (localFields.length) {\n localOnly.fields.push({\n exportName: unit.exportName,\n fields: localFields.map((p) => propKey(p) ?? \"?\"),\n });\n // Graft the local-only field nodes (with their comments) onto the merged object.\n if (opts.keepLocalFields)\n for (const p of localFields) desiredObj.properties.push(p);\n }\n }\n }\n // Preserve a user's leading comment above the const (the renderer emits none for tables;\n // for access the renderer's own NOTE already lives on desiredNode, so don't double it).\n if (!hasLeadingComment(desiredNode))\n desiredNode.comments = prior.comments;\n body[body.indexOf(prior)] = desiredNode;\n } else {\n body.push(desiredNode);\n }\n addImports(mod, unit.imports);\n }\n\n // Existing consts the DB no longer has → local-only objects.\n for (const [name, node] of existing) {\n if (desiredNames.has(name)) continue;\n localOnly.objects.push(name);\n if (!opts.keepLocalObjects) body.splice(body.indexOf(node), 1);\n }\n\n return { content: ensureTrailingNewline(generateCode(mod).code), localOnly };\n}\n\n/** Union the named imports from `lines` into the module (magicast dedupes against existing). */\nfunction addImports(mod: unknown, lines: string[]): void {\n const imports = asMod(mod).imports;\n for (const line of lines) {\n const parsed = parseImportLine(line);\n if (!parsed) continue;\n for (const name of parsed.names)\n imports.$add({ from: parsed.from, imported: name, local: name });\n }\n}\n\nfunction ensureTrailingNewline(s: string): string {\n return s.endsWith(\"\\n\") ? s : `${s}\\n`;\n}\n\n// --- Line diff (colored preview + git-style patch) -------------------------------------------\n\ntype LineOp = { tag: \" \" | \"-\" | \"+\"; line: string };\n\nconst splitLines = (s: string): string[] =>\n s === \"\" ? [] : s.replace(/\\n$/, \"\").split(\"\\n\");\n\n/** LCS line-level ops between two texts (a trailing newline is ignored). */\nfunction lineOps(before: string, after: string): LineOp[] {\n const a = splitLines(before);\n const b = splitLines(after);\n const m = a.length;\n const n = b.length;\n const dp: number[][] = Array.from({ length: m + 1 }, () =>\n new Array(n + 1).fill(0),\n );\n for (let i = m - 1; i >= 0; i--)\n for (let j = n - 1; j >= 0; j--)\n dp[i][j] =\n a[i] === b[j]\n ? dp[i + 1][j + 1] + 1\n : Math.max(dp[i + 1][j], dp[i][j + 1]);\n const ops: LineOp[] = [];\n let i = 0;\n let j = 0;\n while (i < m && j < n) {\n if (a[i] === b[j]) {\n ops.push({ tag: \" \", line: a[i] });\n i++;\n j++;\n } else if (dp[i + 1][j] >= dp[i][j + 1]) {\n ops.push({ tag: \"-\", line: a[i++] });\n } else {\n ops.push({ tag: \"+\", line: b[j++] });\n }\n }\n while (i < m) ops.push({ tag: \"-\", line: a[i++] });\n while (j < n) ops.push({ tag: \"+\", line: b[j++] });\n return ops;\n}\n\n/**\n * A compact colored line diff for previews. A new file renders as all-green additions; an edit\n * renders removed (red `-`) / added (green `+`) lines with a little surrounding context (long\n * unchanged runs collapse to `…`).\n */\nexport function lineDiff(before: string, after: string): string {\n const ops = lineOps(before, after);\n // Keep changed lines plus up to 2 lines of context around each; collapse long unchanged runs.\n const CONTEXT = 2;\n const keep = new Array(ops.length).fill(false);\n ops.forEach((op, idx) => {\n if (op.tag === \" \") return;\n for (\n let k = Math.max(0, idx - CONTEXT);\n k <= Math.min(ops.length - 1, idx + CONTEXT);\n k++\n )\n keep[k] = true;\n });\n const out: string[] = [];\n let gap = false;\n ops.forEach((op, idx) => {\n if (!keep[idx]) {\n if (!gap) out.push(style.dim(\" …\"));\n gap = true;\n return;\n }\n gap = false;\n if (op.tag === \" \") out.push(style.dim(` ${op.line}`));\n else if (op.tag === \"-\") out.push(style.red(`- ${op.line}`));\n else out.push(style.green(`+ ${op.line}`));\n });\n return out.join(\"\\n\");\n}\n\n/**\n * A git-style unified diff between two texts, headed by `label` as the file path — for piping to a\n * diff viewer (delta / git's pager). Returns \"\" when there's no change.\n */\nexport function unifiedDiff(\n before: string,\n after: string,\n label: string,\n): string {\n const ops = lineOps(before, after);\n if (!ops.some((o) => o.tag !== \" \")) return \"\";\n const oldLen = ops.filter((o) => o.tag !== \"+\").length;\n const newLen = ops.filter((o) => o.tag !== \"-\").length;\n const body = ops.map((o) =>\n o.tag === \" \" ? ` ${o.line}` : `${o.tag}${o.line}`,\n );\n return `${[\n `diff --git a/${label} b/${label}`,\n `--- a/${label}`,\n `+++ b/${label}`,\n `@@ -1,${oldLen} +1,${newLen} @@`,\n ...body,\n ].join(\"\\n\")}\\n`;\n}\n\n/** Colored verb for a pull action (`new` / `update` / `delete` / `unchanged`). */\nexport function actionLabel(\n action: \"create\" | \"update\" | \"unchanged\" | \"delete\",\n): string {\n if (action === \"create\") return colorEnabled() ? style.green(\"new\") : \"new\";\n if (action === \"update\")\n return colorEnabled() ? style.yellow(\"update\") : \"update\";\n if (action === \"delete\")\n return colorEnabled() ? style.red(\"delete\") : \"delete\";\n return style.dim(\"unchanged\");\n}\n","import { createHash } from \"node:crypto\";\nimport {\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n writeFileSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { KindSnapshot } from \"../kind\";\n\n// The legacy STATEMENT snapshot types (Snapshot/SnapshotStatement/EMPTY_SNAPSHOT) now live in\n// cli/structure.ts (the SurrealDB module that produces them) — this file is the NEUTRAL stored-\n// snapshot + migration-file engine.\n\n/**\n * The STORED snapshot (`_snapshot.json`): the canonical schema is portable objects grouped by kind\n * (a {@link KindSnapshot}); DDL is derived generically via the kind registry (`buildKindDiff`/\n * `emitKinds`). Diffed against the next `generate`. `files` maps each object's name to its\n * project-root-relative source file (display-only; attached to diff items by the CLI). Pre-launch:\n * the format is free to change, so there is no on-disk version migration — an unrecognized snapshot\n * is treated as empty (regenerate via `schemic gen --baseline`).\n */\nexport interface StoredSnapshot {\n version: 3;\n /** The driver that authored this snapshot (\"surrealdb\", \"postgres\", …). */\n driver: string;\n /** Portable objects grouped by kind. */\n schema: KindSnapshot;\n files?: Record<string, string>;\n}\n\n/** A migration file on disk. The filename is the source of truth — there's no journal. */\nexport interface Migration {\n /** Filename without the `.surql` extension, e.g. `20260607153045_add_users`. */\n tag: string;\n /** Filename, e.g. `20260607153045_add_users.surql`. */\n file: string;\n}\n\nconst SNAPSHOT_FILE = \"_snapshot.json\";\n/** Fallback migration extension when a caller has no driver to hand (the driver provides the real one). */\nconst DEFAULT_MIGRATION_EXT = \".surql\";\n\n/** A fresh empty STORED snapshot. Fresh each call so callers can't alias shared empty state. */\nfunction emptyStored(): StoredSnapshot {\n return {\n version: 3,\n driver: \"surrealdb\",\n schema: { kinds: {} },\n files: {},\n };\n}\n\n/** The empty STORED snapshot — used as `prev` for a `--baseline` generate (diff against nothing). */\nexport const EMPTY_STORED: StoredSnapshot = emptyStored();\n\n/**\n * Read the stored snapshot. Pre-launch: any snapshot that isn't the current `version: 3` shape (a\n * pre-portable v1/v2, or absent) is treated as EMPTY — regenerate with `schemic gen --baseline`.\n */\nexport function readSnapshot(metaDir: string): StoredSnapshot {\n const path = join(metaDir, SNAPSHOT_FILE);\n if (!existsSync(path)) return emptyStored();\n const raw = JSON.parse(readFileSync(path, \"utf8\")) as Partial<StoredSnapshot>;\n if (raw.version === 3 && raw.driver && raw.schema)\n return { files: {}, ...(raw as StoredSnapshot) };\n return emptyStored();\n}\n\nexport function writeSnapshot(metaDir: string, snapshot: StoredSnapshot): void {\n mkdirSync(metaDir, { recursive: true });\n writeFileSync(\n join(metaDir, SNAPSHOT_FILE),\n `${JSON.stringify(snapshot, null, 2)}\\n`,\n );\n}\n\n/**\n * All migration files in `migrationsDir`, in apply order. Filenames are timestamp-prefixed, so\n * a plain ascending sort is chronological (and legacy `0001_` names sort before timestamped\n * ones). The `meta/` directory and any file not ending in `ext` (the driver's migration extension)\n * are ignored.\n */\nexport function listMigrations(\n migrationsDir: string,\n ext: string = DEFAULT_MIGRATION_EXT,\n): Migration[] {\n if (!existsSync(migrationsDir)) return [];\n return readdirSync(migrationsDir)\n .filter((f) => f.endsWith(ext))\n .sort()\n .map((file) => ({ tag: file.slice(0, -ext.length), file }));\n}\n\n/** A sortable UTC timestamp prefix for a new migration, e.g. `20260607153045`. */\nexport function timestamp(date: Date): string {\n const p = (n: number) => String(n).padStart(2, \"0\");\n return (\n `${date.getUTCFullYear()}` +\n p(date.getUTCMonth() + 1) +\n p(date.getUTCDate()) +\n p(date.getUTCHours()) +\n p(date.getUTCMinutes()) +\n p(date.getUTCSeconds())\n );\n}\n\n/** sha256 of a migration file's contents (drift detection / apply-time bookkeeping). */\nexport function checksum(content: string): string {\n return createHash(\"sha256\").update(content).digest(\"hex\").slice(0, 16);\n}\n\n/** Turn a free-form migration name into a filename-safe slug. */\nexport function slug(name: string): string {\n return (\n name\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\") || \"migration\"\n );\n}\n","import { execFileSync, spawn } from \"node:child_process\";\n\n/** Read a single git config value (global/system included), or undefined. */\nfunction gitConfig(key: string): string | undefined {\n try {\n const v = execFileSync(\"git\", [\"config\", \"--get\", key], {\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }).trim();\n return v || undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * The diff pager, resolved the way git does: `pager.diff` → `core.pager` → `$GIT_PAGER` →\n * `$PAGER`. So a user with `core.pager = delta` gets delta for free, with their own config.\n */\nexport function resolvePager(): string | undefined {\n return (\n gitConfig(\"pager.diff\") ||\n gitConfig(\"core.pager\") ||\n process.env.GIT_PAGER ||\n process.env.PAGER ||\n undefined\n );\n}\n\n/** Pipe `text` through `pager` (a shell command, possibly with args); resolve when it exits. */\nexport function pipeThroughPager(pager: string, text: string): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const child = spawn(\"sh\", [\"-c\", pager], {\n stdio: [\"pipe\", \"inherit\", \"inherit\"],\n });\n child.once(\"error\", reject);\n child.once(\"close\", () => resolve());\n // The pager may quit before reading all input (e.g. `less` on a short diff) — ignore EPIPE.\n child.stdin.on(\"error\", () => {});\n child.stdin.end(text);\n });\n}\n","import { existsSync, readdirSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { Authored, AuthoredDef } from \"@schemic/core\";\nimport { makeJiti } from \"./config\";\n\n/**\n * The NEUTRAL view of a loaded table the engine reads — just `name` plus the `config.relation` flag\n * used for ordering. A driver casts this to its own concrete table builder in `lower`. (The runtime\n * object is the driver's real `TableDef`; the engine never names that type.)\n */\nexport interface AnyTable extends Authored {\n readonly config: { readonly relation?: unknown };\n}\n\n/**\n * Duck-typed `TableDef` check. We avoid `instanceof` on purpose: the user's schema and the\n * CLI may end up with different module instances of `@schemic/core`, so we recognize a table\n * by shape instead. (Structural access into `emitStatements` works regardless.)\n */\nfunction isTableDef(v: unknown): v is AnyTable {\n if (!v || typeof v !== \"object\") return false;\n const t = v as Record<string, unknown>;\n return (\n typeof t.name === \"string\" &&\n typeof t.fields === \"object\" &&\n t.fields !== null &&\n typeof t.config === \"object\" &&\n t.config !== null &&\n typeof t.record === \"function\"\n );\n}\n\n/** Duck-typed standalone-def check (`defineEvent`/`defineFunction`) — see `isTableDef` on why not `instanceof`. */\nfunction isStandaloneDef(v: unknown): v is AuthoredDef {\n if (!v || typeof v !== \"object\") return false;\n const d = v as Record<string, unknown>;\n return (\n (d.kind === \"event\" || d.kind === \"function\" || d.kind === \"access\") &&\n typeof d.name === \"string\"\n );\n}\n\nfunction tsFiles(dir: string): string[] {\n const out: string[] = [];\n for (const entry of readdirSync(dir).sort()) {\n const p = join(dir, entry);\n if (statSync(p).isDirectory()) out.push(...tsFiles(p));\n else if (/\\.(ts|mts|js|mjs)$/.test(entry) && !entry.endsWith(\".d.ts\"))\n out.push(p);\n }\n return out;\n}\n\n/** The schema module file(s) for a path: the file itself, or every module under the directory. */\nfunction schemaFiles(path: string): string[] {\n return statSync(path).isFile() ? [path] : tsFiles(path);\n}\n\n/** Import a schema module file and yield its exported tables/relations, paired with the file. */\nasync function* tablesIn(\n jiti: ReturnType<typeof makeJiti>,\n file: string,\n): AsyncGenerator<AnyTable> {\n const mod = (await jiti.import(file)) as Record<string, unknown>;\n for (const value of Object.values(mod)) if (isTableDef(value)) yield value;\n}\n\n/**\n * Load every schema object from `schemaPath` (a single `.ts` module, or a directory of them): the\n * tables/relations (ordered normal-before-relation, then by name, for stable DDL) and the standalone\n * defs (`defineEvent`/`defineFunction`). One pass over the files.\n */\nexport async function loadDefs(schemaPath: string): Promise<{\n tables: AnyTable[];\n defs: AuthoredDef[];\n /** Absolute source file each table/def was loaded from (for `diff`'s file annotations). */\n fileOf: Map<AnyTable | AuthoredDef, string>;\n}> {\n if (!existsSync(schemaPath)) {\n throw new Error(`Schema path not found: ${schemaPath}`);\n }\n const jiti = makeJiti();\n const tables = new Map<string, AnyTable>();\n const defs: AuthoredDef[] = [];\n const fileOf = new Map<AnyTable | AuthoredDef, string>();\n for (const file of schemaFiles(schemaPath)) {\n const mod = (await jiti.import(file)) as Record<string, unknown>;\n for (const value of Object.values(mod)) {\n if (isTableDef(value)) {\n tables.set(value.name, value); // last def of a name wins\n fileOf.set(value, file);\n } else if (isStandaloneDef(value)) {\n defs.push(value);\n fileOf.set(value, file);\n }\n }\n }\n const rank = (t: AnyTable) => (t.config.relation ? 1 : 0);\n const sorted = [...tables.values()].sort(\n (a, b) => rank(a) - rank(b) || a.name.localeCompare(b.name),\n );\n return { tables: sorted, defs, fileOf };\n}\n\n/** The tables/relations from `schemaPath` (standalone events excluded — see {@link loadDefs}). */\nexport async function loadSchemas(schemaPath: string): Promise<AnyTable[]> {\n return (await loadDefs(schemaPath)).tables;\n}\n\n/** A schema file's exported entities (tables/functions/accesses) and whether it holds ONLY those. */\nexport interface LocalFileEntities {\n /** Each schema entity by its export-const identifier + its DB name (table/function/access name). */\n entities: { exportName: string; name: string; kind: \"table\" | \"def\" }[];\n /** True when EVERY runtime export of the file is a schema entity (no helpers / other exports). */\n pureSchema: boolean;\n}\n\n/**\n * Scan each schema file for the tables/functions/accesses it exports (by export-const name), and\n * whether the file is purely schema. `pull` uses this to find whole-entity local-only schema\n * (entities the live DB doesn't have) and to decide whether a file is safe to delete when mirroring\n * the DB. Standalone events are not whole entities (they attach to a table), so they don't count as\n * entities — a file exporting one is therefore not `pureSchema` and won't be auto-deleted.\n */\nexport async function scanLocalEntities(\n schemaPath: string,\n): Promise<Map<string, LocalFileEntities>> {\n if (!existsSync(schemaPath)) return new Map();\n const jiti = makeJiti();\n const out = new Map<string, LocalFileEntities>();\n for (const file of schemaFiles(schemaPath)) {\n const exports = Object.entries(\n (await jiti.import(file)) as Record<string, unknown>,\n );\n const entities: LocalFileEntities[\"entities\"] = [];\n for (const [exportName, value] of exports) {\n if (isTableDef(value))\n entities.push({ exportName, name: value.name, kind: \"table\" });\n else if (\n isStandaloneDef(value) &&\n (value.kind === \"function\" || value.kind === \"access\")\n )\n entities.push({ exportName, name: value.name, kind: \"def\" });\n }\n if (entities.length)\n out.set(file, {\n entities,\n pureSchema: entities.length === exports.length,\n });\n }\n return out;\n}\n\n/** Map of table name → the file that defines it (for `pull`'s duplicate-definition check). */\nexport async function existingTables(\n schemaPath: string,\n): Promise<Map<string, string>> {\n if (!existsSync(schemaPath)) return new Map();\n const jiti = makeJiti();\n const out = new Map<string, string>();\n for (const file of schemaFiles(schemaPath)) {\n for await (const t of tablesIn(jiti, file)) out.set(t.name, file);\n }\n return out;\n}\n\n/**\n * Names defined in more than one place, mapped to the files that define them (a file repeats if it\n * defines the same name twice). `loadSchemas` silently lets the last definition win, so this is how\n * `doctor` surfaces the otherwise-invisible conflict.\n */\nexport async function duplicateTables(\n schemaPath: string,\n): Promise<Map<string, string[]>> {\n if (!existsSync(schemaPath)) return new Map();\n const jiti = makeJiti();\n const seen = new Map<string, string[]>();\n for (const file of schemaFiles(schemaPath)) {\n for await (const t of tablesIn(jiti, file)) {\n const files = seen.get(t.name);\n if (files) files.push(file);\n else seen.set(t.name, [file]);\n }\n }\n return new Map([...seen].filter(([, files]) => files.length > 1));\n}\n"],"mappings":"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","names":["i","j","dirname","dirname","i","j","existsSync","mkdirSync","writeFileSync","resolve","existsSync","readdirSync","statSync","join","readdirSync","join","statSync","existsSync"]}
|
package/lib/testing.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { D as Driver } from './driver-Dh5hLKHm.js';
|
|
2
|
+
import 'jiti';
|
|
3
|
+
import './config-TIiKDd9t.js';
|
|
4
|
+
import 'commander';
|
|
5
|
+
|
|
6
|
+
/** The driver's authoring namespace (`s`) — a bag of field builders. Loosely typed (cross-driver). */
|
|
7
|
+
type Authoring = Record<string, (...args: any[]) => unknown>;
|
|
8
|
+
interface DriverConformanceOptions {
|
|
9
|
+
/** The driver's registry name (e.g. `"surrealdb"`, `"postgres"`). */
|
|
10
|
+
name: string;
|
|
11
|
+
/** The driver's authoring namespace — the `s` each package exports. */
|
|
12
|
+
s: Authoring;
|
|
13
|
+
/** The driver under test (already registered by importing its package). */
|
|
14
|
+
driver: Driver<unknown>;
|
|
15
|
+
/**
|
|
16
|
+
* Authors the driver's primary fielded definable — a table, collection, node-type, … — from a name
|
|
17
|
+
* and a field shape. Used to lower a probe object through the pipeline. Drivers pass their own
|
|
18
|
+
* `define*` for this (e.g. `defineEntity: defineTable`); the suite stays shape-agnostic.
|
|
19
|
+
*/
|
|
20
|
+
defineEntity: (name: string, shape: Record<string, any>) => any;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Assert a `@schemic/<driver>` conforms to the Schemic driver contract: the Driver is registered with
|
|
24
|
+
* the IR pipeline + execution ops, and its `s` is a Zod-drop-in SUPERSET (the canonical drop-in set is
|
|
25
|
+
* present, carries the right schemas, composes through wrappers, and lowers to the portable IR).
|
|
26
|
+
*/
|
|
27
|
+
declare function describeDriverConformance(opts: DriverConformanceOptions): void;
|
|
28
|
+
|
|
29
|
+
export { type DriverConformanceOptions, describeDriverConformance };
|
package/lib/testing.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import {
|
|
2
|
+
driverNames,
|
|
3
|
+
emitKinds,
|
|
4
|
+
getDriver,
|
|
5
|
+
lowerSchema
|
|
6
|
+
} from "./chunk-T23RNU7G.js";
|
|
7
|
+
|
|
8
|
+
// src/testing.ts
|
|
9
|
+
import { describe, expect, test } from "bun:test";
|
|
10
|
+
var DROP_INS = [
|
|
11
|
+
{ key: "string", build: (s) => s.string() },
|
|
12
|
+
{ key: "number", build: (s) => s.number() },
|
|
13
|
+
{ key: "boolean", build: (s) => s.boolean() },
|
|
14
|
+
{ key: "date", build: (s) => s.date() },
|
|
15
|
+
{ key: "literal", build: (s) => s.literal("a") },
|
|
16
|
+
{ key: "enum", build: (s) => s.enum(["a", "b"]) },
|
|
17
|
+
{ key: "object", build: (s) => s.object({ inner: s.literal("a") }) },
|
|
18
|
+
{ key: "array", build: (s) => s.array(s.literal("a")) }
|
|
19
|
+
];
|
|
20
|
+
var SCALAR_CHECKS = [
|
|
21
|
+
{ key: "string", valid: "hello", invalid: 123 },
|
|
22
|
+
{ key: "number", valid: 123, invalid: "hello" },
|
|
23
|
+
{ key: "boolean", valid: true, invalid: "hello" }
|
|
24
|
+
];
|
|
25
|
+
function toSchema(v) {
|
|
26
|
+
const field = v;
|
|
27
|
+
if (field && isZod(field.schema)) return field.schema;
|
|
28
|
+
if (isZod(v)) return v;
|
|
29
|
+
throw new Error("expected a field (with a `.schema` Zod type) or a Zod type");
|
|
30
|
+
}
|
|
31
|
+
function isZod(v) {
|
|
32
|
+
return !!v && typeof v.safeParse === "function";
|
|
33
|
+
}
|
|
34
|
+
function isField(v) {
|
|
35
|
+
return isZod(v?.schema);
|
|
36
|
+
}
|
|
37
|
+
function describeDriverConformance(opts) {
|
|
38
|
+
const { name, s, driver, defineEntity } = opts;
|
|
39
|
+
describe(`driver conformance: ${name}`, () => {
|
|
40
|
+
describe("Driver contract", () => {
|
|
41
|
+
test("is registered under its name", () => {
|
|
42
|
+
expect(driverNames()).toContain(name);
|
|
43
|
+
expect(getDriver(name)).toBe(driver);
|
|
44
|
+
expect(driver.name).toBe(name);
|
|
45
|
+
});
|
|
46
|
+
test("exposes a kind registry + the schema/execution ops", () => {
|
|
47
|
+
expect(driver.registry).toBeDefined();
|
|
48
|
+
expect(typeof driver.registry.entries).toBe("function");
|
|
49
|
+
expect(driver.registry.names().length).toBeGreaterThan(0);
|
|
50
|
+
for (const op of [
|
|
51
|
+
"explode",
|
|
52
|
+
"introspectAll",
|
|
53
|
+
"connect",
|
|
54
|
+
"apply",
|
|
55
|
+
"close"
|
|
56
|
+
]) {
|
|
57
|
+
expect(typeof driver[op]).toBe("function");
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
describe("zod drop-in surface (s.* is a Zod superset)", () => {
|
|
62
|
+
for (const { key, build } of DROP_INS) {
|
|
63
|
+
test(`s.${key}() exists and returns a field`, () => {
|
|
64
|
+
expect(typeof s[key]).toBe("function");
|
|
65
|
+
const field = build(s);
|
|
66
|
+
expect(isField(field)).toBe(true);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
for (const { key, valid, invalid } of SCALAR_CHECKS) {
|
|
70
|
+
test(`s.${key}() carries a "${key}" Zod schema`, () => {
|
|
71
|
+
const schema = toSchema(s[key]());
|
|
72
|
+
expect(schema.safeParse(valid).success).toBe(true);
|
|
73
|
+
expect(schema.safeParse(invalid).success).toBe(false);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
describe("Zod-clean codecs + wrappers", () => {
|
|
78
|
+
test("decode/encode delegate to the inner Zod schema", () => {
|
|
79
|
+
const field = s.string();
|
|
80
|
+
expect(field.decode("hi")).toBe("hi");
|
|
81
|
+
expect(field.encode("hi")).toBe("hi");
|
|
82
|
+
});
|
|
83
|
+
test("wrappers preserve field-ness (optional/array compose)", () => {
|
|
84
|
+
const field = s.string();
|
|
85
|
+
expect(isField(field.optional())).toBe(true);
|
|
86
|
+
expect(isField(field.array())).toBe(true);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
describe("lowering (drop-in fields \u2192 kind registry)", () => {
|
|
90
|
+
test("an entity of drop-in fields explodes + lowers + emits, carrying every field", () => {
|
|
91
|
+
const shape = {};
|
|
92
|
+
for (const { key, build } of DROP_INS) shape[`f_${key}`] = build(s);
|
|
93
|
+
const entity = defineEntity("schemic_conformance_probe", shape);
|
|
94
|
+
const portable = lowerSchema(
|
|
95
|
+
driver.registry,
|
|
96
|
+
driver.explode([entity], [])
|
|
97
|
+
);
|
|
98
|
+
expect(portable.length).toBeGreaterThan(0);
|
|
99
|
+
const ddl = emitKinds(driver.registry, portable).join("\n");
|
|
100
|
+
expect(ddl.length).toBeGreaterThan(0);
|
|
101
|
+
for (const { key } of DROP_INS) {
|
|
102
|
+
expect(ddl).toContain(`f_${key}`);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
export {
|
|
109
|
+
describeDriverConformance
|
|
110
|
+
};
|
|
111
|
+
//# sourceMappingURL=testing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/testing.ts"],"sourcesContent":["// A shared DRIVER CONFORMANCE suite — the runtime contract a `@schemic/<driver>` must satisfy, asserted\n// with `bun:test`. Each driver runs it against its own authoring surface:\n//\n// import { describeDriverConformance } from \"@schemic/core/testing\";\n// import { defineTable, s, surrealDriver } from \"@schemic/surrealdb\";\n// describeDriverConformance({ name: \"surrealdb\", s, driver: surrealDriver, defineEntity: defineTable });\n//\n// WHY a test, not a type: the zod drop-in builders (`s.string()` = `new <D>Field(z.string())`) are\n// mechanically identical across drivers, but TypeScript has NO higher-kinded types, so a generic core\n// factory can't preserve each driver's field type (it collapses to the base, dropping `$`-methods).\n// Each driver therefore hand-authors its drop-ins, and \"`s` is a Zod SUPERSET\" is enforceable only at\n// runtime. This suite is that enforcement.\n//\n// It DUCK-TYPES fields (a field is \"something with a `.schema` that is a Zod type\") rather than using\n// `instanceof SFieldBase` — a driver may extend its own copy of the base, so identity checks are unsafe.\n\nimport { describe, expect, test } from \"bun:test\";\nimport type * as z from \"zod\";\nimport { type Driver, driverNames, getDriver } from \"./driver/driver\";\nimport { emitKinds, lowerSchema } from \"./kind\";\n\n/** The driver's authoring namespace (`s`) — a bag of field builders. Loosely typed (cross-driver). */\n// biome-ignore lint/suspicious/noExplicitAny: a driver's `s` is dialect-specific; the suite is generic.\ntype Authoring = Record<string, (...args: any[]) => unknown>;\n\nexport interface DriverConformanceOptions {\n /** The driver's registry name (e.g. `\"surrealdb\"`, `\"postgres\"`). */\n name: string;\n /** The driver's authoring namespace — the `s` each package exports. */\n s: Authoring;\n /** The driver under test (already registered by importing its package). */\n driver: Driver<unknown>;\n /**\n * Authors the driver's primary fielded definable — a table, collection, node-type, … — from a name\n * and a field shape. Used to lower a probe object through the pipeline. Drivers pass their own\n * `define*` for this (e.g. `defineEntity: defineTable`); the suite stays shape-agnostic.\n */\n // biome-ignore lint/suspicious/noExplicitAny: dialect-specific definable/shape types.\n defineEntity: (name: string, shape: Record<string, any>) => any;\n}\n\n/**\n * The canonical zod DROP-IN set every driver's `s` MUST expose — the structural Zod builders that make\n * a `@schemic/<driver>` a drop-in for `z`. Each maps to the DB's natural representation (a driver may\n * also offer richer native aliases, e.g. `text`/`varchar` alongside `string`). `object`/`array` nest a\n * `literal` (present everywhere) so a missing `string` doesn't cascade into their tests.\n */\nconst DROP_INS: { key: string; build: (s: Authoring) => unknown }[] = [\n { key: \"string\", build: (s) => s.string() },\n { key: \"number\", build: (s) => s.number() },\n { key: \"boolean\", build: (s) => s.boolean() },\n { key: \"date\", build: (s) => s.date() },\n { key: \"literal\", build: (s) => s.literal(\"a\") },\n { key: \"enum\", build: (s) => s.enum([\"a\", \"b\"]) },\n { key: \"object\", build: (s) => s.object({ inner: s.literal(\"a\") }) },\n { key: \"array\", build: (s) => s.array(s.literal(\"a\")) },\n];\n\n/** Value pairs that prove a scalar drop-in really carries the right Zod schema (unambiguous scalars only). */\nconst SCALAR_CHECKS: { key: string; valid: unknown; invalid: unknown }[] = [\n { key: \"string\", valid: \"hello\", invalid: 123 },\n { key: \"number\", valid: 123, invalid: \"hello\" },\n { key: \"boolean\", valid: true, invalid: \"hello\" },\n];\n\n/** Duck-typed: a field exposes a Zod `.schema`; a raw Zod type IS the schema. Throws if neither. */\nfunction toSchema(v: unknown): z.ZodType {\n const field = v as { schema?: unknown } | null;\n if (field && isZod(field.schema)) return field.schema as z.ZodType;\n if (isZod(v)) return v as z.ZodType;\n throw new Error(\"expected a field (with a `.schema` Zod type) or a Zod type\");\n}\n\nfunction isZod(v: unknown): boolean {\n return !!v && typeof (v as { safeParse?: unknown }).safeParse === \"function\";\n}\n\n/** Is `v` a driver field (has a `.schema` that is a Zod type)? */\nfunction isField(v: unknown): boolean {\n return isZod((v as { schema?: unknown } | null)?.schema);\n}\n\n/**\n * Assert a `@schemic/<driver>` conforms to the Schemic driver contract: the Driver is registered with\n * the IR pipeline + execution ops, and its `s` is a Zod-drop-in SUPERSET (the canonical drop-in set is\n * present, carries the right schemas, composes through wrappers, and lowers to the portable IR).\n */\nexport function describeDriverConformance(\n opts: DriverConformanceOptions,\n): void {\n const { name, s, driver, defineEntity } = opts;\n\n describe(`driver conformance: ${name}`, () => {\n describe(\"Driver contract\", () => {\n test(\"is registered under its name\", () => {\n expect(driverNames()).toContain(name);\n expect(getDriver(name)).toBe(driver);\n expect(driver.name).toBe(name);\n });\n\n test(\"exposes a kind registry + the schema/execution ops\", () => {\n // Schema ops are generic over `registry`; the driver provides the fan-out + execution.\n expect(driver.registry).toBeDefined();\n expect(typeof driver.registry.entries).toBe(\"function\");\n expect(driver.registry.names().length).toBeGreaterThan(0);\n for (const op of [\n \"explode\",\n \"introspectAll\",\n \"connect\",\n \"apply\",\n \"close\",\n ] as const) {\n expect(typeof driver[op]).toBe(\"function\");\n }\n });\n });\n\n describe(\"zod drop-in surface (s.* is a Zod superset)\", () => {\n for (const { key, build } of DROP_INS) {\n test(`s.${key}() exists and returns a field`, () => {\n expect(typeof s[key]).toBe(\"function\");\n const field = build(s);\n expect(isField(field)).toBe(true);\n });\n }\n\n for (const { key, valid, invalid } of SCALAR_CHECKS) {\n test(`s.${key}() carries a \"${key}\" Zod schema`, () => {\n const schema = toSchema(s[key]());\n expect(schema.safeParse(valid).success).toBe(true);\n expect(schema.safeParse(invalid).success).toBe(false);\n });\n }\n });\n\n describe(\"Zod-clean codecs + wrappers\", () => {\n test(\"decode/encode delegate to the inner Zod schema\", () => {\n const field = s.string() as {\n decode: (v: unknown) => unknown;\n encode: (v: unknown) => unknown;\n };\n expect(field.decode(\"hi\")).toBe(\"hi\");\n expect(field.encode(\"hi\")).toBe(\"hi\");\n });\n\n test(\"wrappers preserve field-ness (optional/array compose)\", () => {\n const field = s.string() as {\n optional: () => unknown;\n array: () => unknown;\n };\n expect(isField(field.optional())).toBe(true);\n expect(isField(field.array())).toBe(true);\n });\n });\n\n describe(\"lowering (drop-in fields → kind registry)\", () => {\n test(\"an entity of drop-in fields explodes + lowers + emits, carrying every field\", () => {\n const shape: Record<string, unknown> = {};\n for (const { key, build } of DROP_INS) shape[`f_${key}`] = build(s);\n const entity = defineEntity(\"schemic_conformance_probe\", shape);\n\n // explode (authoring -> kinded definables) -> lowerSchema -> portable objects.\n const portable = lowerSchema(\n driver.registry,\n driver.explode([entity], []),\n );\n // Kind-agnostic: the probe lowers to at least one object (its kind is the driver's own —\n // `table`, `collection`, …); the per-field check below is what proves lowering is faithful.\n expect(portable.length).toBeGreaterThan(0);\n\n // The portable shape is the driver's own, but the emitted DDL is generic: every drop-in\n // field name must appear in it (lowering + emit carried it through).\n const ddl = emitKinds(driver.registry, portable).join(\"\\n\");\n expect(ddl.length).toBeGreaterThan(0);\n for (const { key } of DROP_INS) {\n expect(ddl).toContain(`f_${key}`);\n }\n });\n });\n });\n}\n"],"mappings":";;;;;;;;AAgBA,SAAS,UAAU,QAAQ,YAAY;AA+BvC,IAAM,WAAgE;AAAA,EACpE,EAAE,KAAK,UAAU,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE;AAAA,EAC1C,EAAE,KAAK,UAAU,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE;AAAA,EAC1C,EAAE,KAAK,WAAW,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE;AAAA,EAC5C,EAAE,KAAK,QAAQ,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE;AAAA,EACtC,EAAE,KAAK,WAAW,OAAO,CAAC,MAAM,EAAE,QAAQ,GAAG,EAAE;AAAA,EAC/C,EAAE,KAAK,QAAQ,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,GAAG,CAAC,EAAE;AAAA,EAChD,EAAE,KAAK,UAAU,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,GAAG,EAAE,CAAC,EAAE;AAAA,EACnE,EAAE,KAAK,SAAS,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAG,CAAC,EAAE;AACxD;AAGA,IAAM,gBAAqE;AAAA,EACzE,EAAE,KAAK,UAAU,OAAO,SAAS,SAAS,IAAI;AAAA,EAC9C,EAAE,KAAK,UAAU,OAAO,KAAK,SAAS,QAAQ;AAAA,EAC9C,EAAE,KAAK,WAAW,OAAO,MAAM,SAAS,QAAQ;AAClD;AAGA,SAAS,SAAS,GAAuB;AACvC,QAAM,QAAQ;AACd,MAAI,SAAS,MAAM,MAAM,MAAM,EAAG,QAAO,MAAM;AAC/C,MAAI,MAAM,CAAC,EAAG,QAAO;AACrB,QAAM,IAAI,MAAM,4DAA4D;AAC9E;AAEA,SAAS,MAAM,GAAqB;AAClC,SAAO,CAAC,CAAC,KAAK,OAAQ,EAA8B,cAAc;AACpE;AAGA,SAAS,QAAQ,GAAqB;AACpC,SAAO,MAAO,GAAmC,MAAM;AACzD;AAOO,SAAS,0BACd,MACM;AACN,QAAM,EAAE,MAAM,GAAG,QAAQ,aAAa,IAAI;AAE1C,WAAS,uBAAuB,IAAI,IAAI,MAAM;AAC5C,aAAS,mBAAmB,MAAM;AAChC,WAAK,gCAAgC,MAAM;AACzC,eAAO,YAAY,CAAC,EAAE,UAAU,IAAI;AACpC,eAAO,UAAU,IAAI,CAAC,EAAE,KAAK,MAAM;AACnC,eAAO,OAAO,IAAI,EAAE,KAAK,IAAI;AAAA,MAC/B,CAAC;AAED,WAAK,sDAAsD,MAAM;AAE/D,eAAO,OAAO,QAAQ,EAAE,YAAY;AACpC,eAAO,OAAO,OAAO,SAAS,OAAO,EAAE,KAAK,UAAU;AACtD,eAAO,OAAO,SAAS,MAAM,EAAE,MAAM,EAAE,gBAAgB,CAAC;AACxD,mBAAW,MAAM;AAAA,UACf;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,GAAY;AACV,iBAAO,OAAO,OAAO,EAAE,CAAC,EAAE,KAAK,UAAU;AAAA,QAC3C;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAED,aAAS,+CAA+C,MAAM;AAC5D,iBAAW,EAAE,KAAK,MAAM,KAAK,UAAU;AACrC,aAAK,KAAK,GAAG,iCAAiC,MAAM;AAClD,iBAAO,OAAO,EAAE,GAAG,CAAC,EAAE,KAAK,UAAU;AACrC,gBAAM,QAAQ,MAAM,CAAC;AACrB,iBAAO,QAAQ,KAAK,CAAC,EAAE,KAAK,IAAI;AAAA,QAClC,CAAC;AAAA,MACH;AAEA,iBAAW,EAAE,KAAK,OAAO,QAAQ,KAAK,eAAe;AACnD,aAAK,KAAK,GAAG,iBAAiB,GAAG,gBAAgB,MAAM;AACrD,gBAAM,SAAS,SAAS,EAAE,GAAG,EAAE,CAAC;AAChC,iBAAO,OAAO,UAAU,KAAK,EAAE,OAAO,EAAE,KAAK,IAAI;AACjD,iBAAO,OAAO,UAAU,OAAO,EAAE,OAAO,EAAE,KAAK,KAAK;AAAA,QACtD,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAED,aAAS,+BAA+B,MAAM;AAC5C,WAAK,kDAAkD,MAAM;AAC3D,cAAM,QAAQ,EAAE,OAAO;AAIvB,eAAO,MAAM,OAAO,IAAI,CAAC,EAAE,KAAK,IAAI;AACpC,eAAO,MAAM,OAAO,IAAI,CAAC,EAAE,KAAK,IAAI;AAAA,MACtC,CAAC;AAED,WAAK,yDAAyD,MAAM;AAClE,cAAM,QAAQ,EAAE,OAAO;AAIvB,eAAO,QAAQ,MAAM,SAAS,CAAC,CAAC,EAAE,KAAK,IAAI;AAC3C,eAAO,QAAQ,MAAM,MAAM,CAAC,CAAC,EAAE,KAAK,IAAI;AAAA,MAC1C,CAAC;AAAA,IACH,CAAC;AAED,aAAS,kDAA6C,MAAM;AAC1D,WAAK,+EAA+E,MAAM;AACxF,cAAM,QAAiC,CAAC;AACxC,mBAAW,EAAE,KAAK,MAAM,KAAK,SAAU,OAAM,KAAK,GAAG,EAAE,IAAI,MAAM,CAAC;AAClE,cAAM,SAAS,aAAa,6BAA6B,KAAK;AAG9D,cAAM,WAAW;AAAA,UACf,OAAO;AAAA,UACP,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;AAAA,QAC7B;AAGA,eAAO,SAAS,MAAM,EAAE,gBAAgB,CAAC;AAIzC,cAAM,MAAM,UAAU,OAAO,UAAU,QAAQ,EAAE,KAAK,IAAI;AAC1D,eAAO,IAAI,MAAM,EAAE,gBAAgB,CAAC;AACpC,mBAAW,EAAE,IAAI,KAAK,UAAU;AAC9B,iBAAO,GAAG,EAAE,UAAU,KAAK,GAAG,EAAE;AAAA,QAClC;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH,CAAC;AACH;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@schemic/core",
|
|
3
|
+
"version": "0.1.0-alpha.0",
|
|
4
|
+
"description": "The dialect-neutral engine for Schemic — Driver contract, portable schema IR, and the migration/diff/snapshot engine.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Vertio Solutions",
|
|
7
|
+
"homepage": "https://schemic.dev",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/schemichq/schemic.git",
|
|
11
|
+
"directory": "packages/core"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"sideEffects": false,
|
|
15
|
+
"module": "lib/index.js",
|
|
16
|
+
"types": "lib/index.d.ts",
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"lib",
|
|
22
|
+
"src",
|
|
23
|
+
"LICENSE"
|
|
24
|
+
],
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"bun": "./src/index.ts",
|
|
28
|
+
"import": {
|
|
29
|
+
"types": "./lib/index.d.ts",
|
|
30
|
+
"default": "./lib/index.js"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"./config": {
|
|
34
|
+
"bun": "./src/config.ts",
|
|
35
|
+
"import": {
|
|
36
|
+
"types": "./lib/config.d.ts",
|
|
37
|
+
"default": "./lib/config.js"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"./driver": {
|
|
41
|
+
"bun": "./src/driver/sdk.ts",
|
|
42
|
+
"import": {
|
|
43
|
+
"types": "./lib/driver.d.ts",
|
|
44
|
+
"default": "./lib/driver.js"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"./authoring": {
|
|
48
|
+
"bun": "./src/authoring.ts",
|
|
49
|
+
"import": {
|
|
50
|
+
"types": "./lib/authoring.d.ts",
|
|
51
|
+
"default": "./lib/authoring.js"
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"./testing": {
|
|
55
|
+
"bun": "./src/testing.ts",
|
|
56
|
+
"import": {
|
|
57
|
+
"types": "./lib/testing.d.ts",
|
|
58
|
+
"default": "./lib/testing.js"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"./package.json": "./package.json"
|
|
62
|
+
},
|
|
63
|
+
"scripts": {
|
|
64
|
+
"build": "tsup",
|
|
65
|
+
"prepack": "bun run build",
|
|
66
|
+
"test": "bun test",
|
|
67
|
+
"test:unit": "bun test test/unit",
|
|
68
|
+
"test:live": "bun test test/live",
|
|
69
|
+
"test:e2e": "bun test test/e2e",
|
|
70
|
+
"typecheck": "tsc --noEmit",
|
|
71
|
+
"lint": "biome check .",
|
|
72
|
+
"lint:fix": "biome check --write .",
|
|
73
|
+
"format": "biome format --write ."
|
|
74
|
+
},
|
|
75
|
+
"dependencies": {
|
|
76
|
+
"commander": "^14.0.2",
|
|
77
|
+
"jiti": "^2.4.2",
|
|
78
|
+
"magicast": "^0.5.3"
|
|
79
|
+
},
|
|
80
|
+
"peerDependencies": {
|
|
81
|
+
"surrealdb": "^2.0.3",
|
|
82
|
+
"zod": "^4.3.5"
|
|
83
|
+
},
|
|
84
|
+
"devDependencies": {
|
|
85
|
+
"@biomejs/biome": "^2.3.11",
|
|
86
|
+
"@electric-sql/pglite": "^0.5.2",
|
|
87
|
+
"@types/bun": "latest",
|
|
88
|
+
"surrealdb": "^2.0.3",
|
|
89
|
+
"tsup": "^8",
|
|
90
|
+
"typescript": "^5",
|
|
91
|
+
"zod": "^4.3.5"
|
|
92
|
+
}
|
|
93
|
+
}
|