@loradb/lora-graphql 0.21.0 → 0.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sources":["../src/migrate.ts","../src/cli.ts"],"sourcesContent":["// `lora-graphql migrate neo4j`: rewrite an @neo4j/graphql SDL into this\n// package's vocabulary. What maps is rewritten; what does not is removed\n// and listed as a TODO. With the client's operations, the opt-in surface\n// (@mutation, @filterable, @sortable) follows observed usage; without\n// them, mutations stay on for every type (as in @neo4j/graphql).\n\nimport {\n Kind,\n parse,\n print,\n visit,\n type ArgumentNode,\n type ConstArgumentNode,\n type ConstDirectiveNode,\n type ConstValueNode,\n type DocumentNode,\n type FieldDefinitionNode,\n type ObjectTypeDefinitionNode,\n type SelectionSetNode,\n type ValueNode,\n} from \"graphql\";\nimport { defaultPlural } from \"./model/build.js\";\n\nexport interface MigrationResult {\n /** The rewritten SDL. */\n typeDefs: string;\n /** What has no equivalent or needs a decision, by type and field. */\n todos: string[];\n}\n\nconst ROOT = new Set([\"Query\", \"Mutation\", \"Subscription\"]);\n\n/** Removed with a TODO: no equivalent here. */\nconst UNSUPPORTED: Record<string, string> = {\n coalesce:\n \"@coalesce is not supported: it hides predicates from indexes; store a value instead\",\n subscriptionsAuthorization:\n \"@subscriptionsAuthorization is not supported: SUBSCRIBE rules go in @authorization\",\n shareable: \"federation (@shareable) is not supported\",\n external: \"federation (@external) is not supported\",\n requires: \"federation (@requires) is not supported\",\n provides: \"federation (@provides) is not supported\",\n exclude: \"@exclude: use @query / @mutation to choose operations\",\n vector:\n \"@vector on types (with a provider) is not supported: put @vector(dimensions:, similarity:) on a [Float!] field\",\n};\n\n/** neo4j 5 filter suffixes → @filterable operators. */\nconst SUFFIX_OPS: Array<[string, string]> = [\n [\"_NOT_IN\", \"IN\"],\n [\"_STARTS_WITH\", \"STARTS_WITH\"],\n [\"_ENDS_WITH\", \"ENDS_WITH\"],\n [\"_CONTAINS\", \"CONTAINS\"],\n [\"_INCLUDES\", \"INCLUDES\"],\n [\"_GTE\", \"GTE\"],\n [\"_LTE\", \"LTE\"],\n [\"_GT\", \"GT\"],\n [\"_LT\", \"LT\"],\n [\"_IN\", \"IN\"],\n [\"_EQ\", \"EQ\"],\n];\n\n/** neo4j 6 nested filter operators → @filterable operators. */\nconst NESTED_OPS: Record<string, string> = {\n eq: \"EQ\",\n in: \"IN\",\n lt: \"LT\",\n lte: \"LTE\",\n gt: \"GT\",\n gte: \"GTE\",\n contains: \"CONTAINS\",\n startsWith: \"STARTS_WITH\",\n endsWith: \"ENDS_WITH\",\n includes: \"INCLUDES\",\n caseInsensitive: \"CASE_INSENSITIVE\",\n};\n\ninterface Usage {\n filters: Map<string, Map<string, Set<string>>>;\n sorts: Map<string, Set<string>>;\n mutations: Map<string, Set<string>>;\n}\n\nexport function migrateNeo4j(\n sdl: string,\n operations: DocumentNode[] = [],\n): MigrationResult {\n const doc = parse(sdl, { noLocation: true });\n const todos: string[] = [];\n const nodeTypes = doc.definitions.filter(\n (d): d is ObjectTypeDefinitionNode =>\n d.kind === Kind.OBJECT_TYPE_DEFINITION &&\n !ROOT.has(d.name.value) &&\n !has(d.directives, \"relationshipProperties\") &&\n !has(d.directives, \"jwt\"),\n );\n const nodeNames = new Set(nodeTypes.map((t) => t.name.value));\n const usage =\n operations.length > 0 ? observe(operations, nodeTypes) : undefined;\n\n const out = visit(doc, {\n ObjectTypeDefinition(t) {\n if (!nodeNames.has(t.name.value)) return undefined;\n const type = t.name.value;\n let directives = migrateDirectives(\n t.directives ?? [],\n type,\n undefined,\n todos,\n );\n if (!has(directives, \"node\"))\n directives = [...directives, directive(\"node\")];\n const ops = usage?.mutations.get(type);\n if (!has(directives, \"mutation\")) {\n if (!usage) {\n directives = [...directives, directive(\"mutation\")];\n todos.push(\n `${type}: @mutation added (@neo4j/graphql generates mutations for every type); remove it or narrow its operations`,\n );\n } else if (ops && ops.size > 0) {\n directives = [\n ...directives,\n directive(\"mutation\", {\n operations: enumList([...ops].sort()),\n }),\n ];\n }\n }\n const idFields = (t.fields ?? []).filter((f) => has(f.directives, \"id\"));\n if (idFields.length === 0) {\n todos.push(\n `${type}: no @id field; add a required @key field (the sort tie-breaker and mutation address)`,\n );\n } else if (idFields.length > 1) {\n todos.push(`${type}: several @id fields; keep one as the @key`);\n }\n const fields = (t.fields ?? []).map((f) =>\n migrateField(f, type, usage, todos),\n );\n return { ...t, directives, fields };\n },\n });\n return { typeDefs: print(out), todos };\n}\n\nfunction migrateField(\n f: FieldDefinitionNode,\n type: string,\n usage: Usage | undefined,\n todos: string[],\n): FieldDefinitionNode {\n let directives = migrateDirectives(\n f.directives ?? [],\n type,\n f.name.value,\n todos,\n );\n const id = directives.find((d) => d.name.value === \"id\");\n if (id) {\n directives = directives.filter(\n (d) => d.name.value !== \"id\" && d.name.value !== \"unique\",\n );\n directives.push(directive(\"key\", { generate: bool(true) }));\n }\n const used = usage?.filters.get(type)?.get(f.name.value);\n if (used && used.size > 0 && !has(directives, \"filterable\")) {\n directives.push(\n has(directives, \"relationship\")\n ? directive(\"filterable\")\n : directive(\"filterable\", { byValue: enumList([...used].sort()) }),\n );\n }\n if (\n usage?.sorts.get(type)?.has(f.name.value) &&\n !has(directives, \"sortable\")\n ) {\n directives.push(directive(\"sortable\"));\n }\n return { ...f, directives };\n}\n\nfunction migrateDirectives(\n directives: readonly ConstDirectiveNode[],\n type: string,\n field: string | undefined,\n todos: string[],\n): ConstDirectiveNode[] {\n const at = field ? `${type}.${field}` : type;\n const out: ConstDirectiveNode[] = [];\n for (const d of directives) {\n const name = d.name.value;\n if (name in UNSUPPORTED) {\n todos.push(`${at}: ${UNSUPPORTED[name]}`);\n continue;\n }\n if (name === \"key\" && !field) {\n todos.push(`${at}: federation @key(fields:) is not supported`);\n continue;\n }\n if (name === \"unique\") {\n out.push(directive(\"unique\"));\n continue;\n }\n if (name === \"relationship\") {\n out.push(migrateRelationship(d, at, todos));\n continue;\n }\n if (name === \"fulltext\") {\n out.push(renameInList(d, \"indexes\", \"indexName\", \"name\"));\n continue;\n }\n if (name === \"subscription\") {\n out.push(migrateSubscription(d, at, todos));\n continue;\n }\n if (name === \"authorization\" || name === \"authentication\") {\n todos.push(\n `${at}: check the @${name} rule's filters: operators are written { field: { eq: ... } } here`,\n );\n }\n out.push(d);\n }\n return out;\n}\n\nfunction migrateRelationship(\n d: ConstDirectiveNode,\n at: string,\n todos: string[],\n): ConstDirectiveNode {\n const args: ConstArgumentNode[] = [];\n for (const a of d.arguments ?? []) {\n const name = a.name.value;\n if (name === \"queryDirection\" && a.value.kind === Kind.ENUM) {\n if (a.value.value.includes(\"UNDIRECTED\")) {\n args.push(arg(\"queryDirection\", enumValue(\"UNDIRECTED\")));\n }\n continue;\n }\n if (name === \"nestedOperations\" && a.value.kind === Kind.LIST) {\n const kept = a.value.values.filter(\n (v) => v.kind === Kind.ENUM && v.value !== \"CONNECT_OR_CREATE\",\n );\n if (kept.length < a.value.values.length) {\n todos.push(`${at}: connectOrCreate is not supported; use upsert`);\n }\n args.push(arg(\"nestedOperations\", { kind: Kind.LIST, values: kept }));\n continue;\n }\n args.push(a);\n }\n return { ...d, arguments: args };\n}\n\nfunction migrateSubscription(\n d: ConstDirectiveNode,\n at: string,\n todos: string[],\n): ConstDirectiveNode {\n const events = d.arguments?.find((a) => a.name.value === \"events\")?.value;\n if (!events || events.kind !== Kind.LIST) return d;\n const ops = new Set<string>();\n let relationships = false;\n for (const e of events.values) {\n if (e.kind !== Kind.ENUM) continue;\n if (e.value.startsWith(\"CREATED\") && !e.value.includes(\"RELATIONSHIP\"))\n ops.add(\"CREATE\");\n else if (e.value.startsWith(\"UPDATED\")) ops.add(\"UPDATE\");\n else if (e.value.startsWith(\"DELETED\") && !e.value.includes(\"RELATIONSHIP\"))\n ops.add(\"DELETE\");\n else if (e.value.includes(\"RELATIONSHIP\")) relationships = true;\n }\n todos.push(\n `${at}: subscriptions see writes made through this library (or the engine change feed), not CDC`,\n );\n return directive(\"subscription\", {\n operations: enumList([...ops].sort()),\n ...(relationships ? { relationships: bool(true) } : {}),\n });\n}\n\n/** What the client's operations use: filters, sorts and mutations per type. */\nfunction observe(\n operations: DocumentNode[],\n types: ObjectTypeDefinitionNode[],\n): Usage {\n const usage: Usage = {\n filters: new Map(),\n sorts: new Map(),\n mutations: new Map(),\n };\n // Root fields as either naming would call them: this package's plural\n // and @neo4j/graphql's (which knows irregular plurals, e.g. people).\n const byPlural = new Map<string, ObjectTypeDefinitionNode>();\n for (const t of types) {\n byPlural.set(defaultPlural(t.name.value), t);\n byPlural.set(neo4jPlural(t.name.value), t);\n }\n const byName = new Map(types.map((t) => [t.name.value, t]));\n const note = (type: string, field: string, op: string) => {\n const fields = usage.filters.get(type) ?? new Map<string, Set<string>>();\n const ops = fields.get(field) ?? new Set<string>();\n ops.add(op);\n fields.set(field, ops);\n usage.filters.set(type, fields);\n };\n const where = (type: ObjectTypeDefinitionNode, value: ValueNode) => {\n if (value.kind !== Kind.OBJECT) return;\n for (const f of value.fields) {\n const key = f.name.value;\n if (key === \"AND\" || key === \"OR\") {\n if (f.value.kind === Kind.LIST)\n for (const v of f.value.values) where(type, v);\n continue;\n }\n if (key === \"NOT\") {\n where(type, f.value);\n continue;\n }\n // neo4j 5 relationship quantifiers: `actors_SOME: { name_EQ: ... }`.\n const quantifier = /^(.+)_(SOME|ALL|NONE|SINGLE)$/.exec(key);\n if (quantifier) {\n const rel = type.fields?.find((x) => x.name.value === quantifier[1]);\n const target = rel && byName.get(namedTypeOf(rel));\n if (rel && target) {\n note(type.name.value, quantifier[1]!, \"EQ\");\n where(target, f.value);\n }\n continue;\n }\n const suffix = SUFFIX_OPS.find(([s]) => key.endsWith(s));\n const fieldName = suffix ? key.slice(0, -suffix[0].length) : key;\n const def = type.fields?.find((x) => x.name.value === fieldName);\n if (!def) continue;\n const target = byName.get(namedTypeOf(def));\n if (target) {\n note(type.name.value, fieldName, \"EQ\");\n // `some` / `all` / `none` / `single`, or a nested where.\n if (f.value.kind === Kind.OBJECT) {\n for (const inner of f.value.fields) where(target, inner.value);\n where(target, f.value);\n }\n continue;\n }\n if (suffix) note(type.name.value, fieldName, suffix[1]);\n else if (f.value.kind === Kind.OBJECT) {\n for (const op of f.value.fields) {\n const mapped = NESTED_OPS[op.name.value];\n if (mapped) note(type.name.value, fieldName, mapped);\n }\n } else note(type.name.value, fieldName, \"EQ\");\n }\n };\n const walk = (set: SelectionSetNode | undefined, root: boolean) => {\n for (const sel of set?.selections ?? []) {\n if (sel.kind !== Kind.FIELD) continue;\n const name = sel.name.value;\n if (root) {\n const mutation = /^(create|update|delete|upsert)(.+)$/.exec(name);\n const plural = name.replace(/(Connection|Aggregate)$/, \"\");\n const type =\n byPlural.get(plural) ??\n (mutation ? byPlural.get(lowerFirst(mutation[2]!)) : undefined);\n if (type && mutation) {\n const ops = usage.mutations.get(type.name.value) ?? new Set<string>();\n const op = mutation[1]!.toUpperCase();\n if (op === \"UPSERT\") {\n ops.add(\"CREATE\");\n ops.add(\"UPDATE\");\n } else ops.add(op);\n usage.mutations.set(type.name.value, ops);\n }\n if (type) {\n for (const a of sel.arguments ?? []) argumentUse(type, a);\n }\n }\n walk(sel.selectionSet, false);\n }\n };\n const argumentUse = (type: ObjectTypeDefinitionNode, a: ArgumentNode) => {\n if (a.name.value === \"where\") where(type, a.value);\n if (a.name.value === \"sort\" || a.name.value === \"options\") {\n const sorts = usage.sorts.get(type.name.value) ?? new Set<string>();\n const collect = (v: ValueNode) => {\n if (v.kind === Kind.LIST) v.values.forEach(collect);\n else if (v.kind === Kind.OBJECT) {\n for (const f of v.fields) {\n if (f.name.value === \"sort\") collect(f.value);\n else if (f.value.kind === Kind.ENUM) sorts.add(f.name.value);\n }\n }\n };\n collect(a.value);\n usage.sorts.set(type.name.value, sorts);\n }\n };\n for (const doc of operations) {\n for (const def of doc.definitions) {\n if (def.kind === Kind.OPERATION_DEFINITION) walk(def.selectionSet, true);\n }\n }\n return usage;\n}\n\nfunction namedTypeOf(f: FieldDefinitionNode): string {\n let t = f.type;\n while (t.kind !== Kind.NAMED_TYPE) t = t.type;\n return t.name.value;\n}\n\nfunction has(\n directives: readonly ConstDirectiveNode[] | undefined,\n name: string,\n): boolean {\n return (directives ?? []).some((d) => d.name.value === name);\n}\n\nfunction directive(\n name: string,\n args: Record<string, ConstValueNode> = {},\n): ConstDirectiveNode {\n return {\n kind: Kind.DIRECTIVE,\n name: { kind: Kind.NAME, value: name },\n arguments: Object.entries(args).map(([k, v]) => arg(k, v)),\n };\n}\n\nfunction arg(name: string, value: ConstValueNode): ConstArgumentNode {\n return { kind: Kind.ARGUMENT, name: { kind: Kind.NAME, value: name }, value };\n}\n\nconst enumValue = (value: string): ConstValueNode => ({\n kind: Kind.ENUM,\n value,\n});\nconst bool = (value: boolean): ConstValueNode => ({\n kind: Kind.BOOLEAN,\n value,\n});\nconst enumList = (values: string[]): ConstValueNode => ({\n kind: Kind.LIST,\n values: values.map(enumValue),\n});\n\n/** Rename a key inside each object of a list argument. */\nfunction renameInList(\n d: ConstDirectiveNode,\n argName: string,\n from: string,\n to: string,\n): ConstDirectiveNode {\n return {\n ...d,\n arguments: (d.arguments ?? []).map((a) =>\n a.name.value === argName && a.value.kind === Kind.LIST\n ? arg(argName, {\n kind: Kind.LIST,\n values: a.value.values.map((v) =>\n v.kind === Kind.OBJECT\n ? {\n ...v,\n fields: v.fields.map((f) =>\n f.name.value === from\n ? { ...f, name: { kind: Kind.NAME, value: to } }\n : f,\n ),\n }\n : v,\n ),\n })\n : a,\n ),\n };\n}\n\nconst IRREGULAR: Record<string, string> = {\n person: \"people\",\n man: \"men\",\n woman: \"women\",\n child: \"children\",\n mouse: \"mice\",\n goose: \"geese\",\n foot: \"feet\",\n tooth: \"teeth\",\n};\n\nfunction neo4jPlural(typeName: string): string {\n const base = lowerFirst(typeName);\n const lower = base.toLowerCase();\n for (const [one, many] of Object.entries(IRREGULAR)) {\n if (lower.endsWith(one))\n return base.slice(0, base.length - one.length) + many;\n }\n return defaultPlural(typeName);\n}\n\nfunction lowerFirst(s: string): string {\n return s.charAt(0).toLowerCase() + s.slice(1);\n}\n","// lora-graphql: the build-time half of the library.\n//\n// lora-graphql print <schema.graphql>\n// lora-graphql directives\n// lora-graphql requirements <schema.graphql> [--ddl]\n// lora-graphql check <schema.graphql> [--operations <file|dir>]... [--variables <file>] [--context <file>]\n// [--baseline <file> [--update-baseline]] [--row-budget <n>]\n// [--database <dir> [--name <db>]] [--json]\n// lora-graphql compile <schema.graphql> --operations <file|dir>... [--out <dir>]\n// lora-graphql analyze <schema.graphql> --database <dir> [--name <db>] [--sample <n>]\n// lora-graphql migrate neo4j <schema.graphql> [--operations <file|dir>]...\n// lora-graphql diff <old.graphql> <new.graphql> [--allow-breaking] [--json]\n\nimport { mkdir, readdir, readFile, stat, writeFile } from \"node:fs/promises\";\nimport { join, relative } from \"node:path\";\nimport {\n getNamedType,\n isEnumType,\n isInputObjectType,\n isListType,\n isNonNullType,\n Kind,\n parse,\n print as printAst,\n typeFromAST,\n visit,\n type DefinitionNode,\n type FragmentDefinitionNode,\n type GraphQLInputType,\n type GraphQLSchema,\n type OperationDefinitionNode,\n} from \"graphql\";\nimport { diffSchemas } from \"./analyze/diff.js\";\nimport { formatProblem, ModelError } from \"./errors.js\";\nimport { buildModel } from \"./model/build.js\";\nimport { directiveTypeDefs } from \"./model/directives.js\";\nimport {\n describeRequirement,\n inferRequirements,\n requirementDdl,\n} from \"./analyze/indexes.js\";\nimport { LoraGraphQL, type CheckOptions } from \"./lora-graphql.js\";\nimport { loraDriver, type LoraDriver } from \"./driver.js\";\nimport { usedFragments } from \"./codegen.js\";\nimport { migrateNeo4j } from \"./migrate.js\";\n\nconst USAGE = `lora-graphql <command>\n\n print <schema.graphql> the public SDL clients see\n directives the directive definitions, for editors\n access <schema.graphql> [--json] who may do what: each type and guarded field,\n operation and kind of caller\n requirements <schema.graphql> [--ddl] constraints and indexes the API needs\n check <schema.graphql> [--operations <file|dir>]... [--json]\n [--variables <file>] [--context <file>]\n [--baseline <file> [--update-baseline]]\n [--row-budget <n>] [--database <dir> [--name <db>]]\n CI gate: model, lint, @cypher statements and\n the plans of your operations, on an in-memory\n LoraDB (or an existing one with --database)\n compile <schema.graphql> --operations <file|dir>... [--out <dir>]\n persisted-operation manifest.json and\n operations.d.ts types\n analyze <schema.graphql> --database <dir> [--name <db>] [--sample <n>]\n statistics JSON for useStatistics()\n migrate neo4j <schema.graphql> [--operations <file|dir>]...\n rewrite an @neo4j/graphql SDL; TODOs for\n what has no equivalent\n diff <old.graphql> <new.graphql> [--allow-breaking] [--json]\n database statements and API changes`;\n\ninterface Io {\n out: (line: string) => void;\n err: (line: string) => void;\n}\n\nexport async function main(\n argv: string[],\n io: Io = defaultIo,\n): Promise<number> {\n const [command, ...rest] = argv;\n const flags = new Set<string>();\n const values = new Map<string, string>();\n const positional: string[] = [];\n const operations: string[] = [];\n for (let i = 0; i < rest.length; i++) {\n const a = rest[i]!;\n if (a === \"--operations\") operations.push(rest[++i] ?? \"\");\n else if (VALUE_FLAGS.has(a)) values.set(a, rest[++i] ?? \"\");\n else if (a.startsWith(\"--\")) flags.add(a);\n else positional.push(a);\n }\n try {\n switch (command) {\n case \"print\":\n return await print(need(positional, 1), io);\n case \"directives\":\n io.out(directiveTypeDefs.trim());\n return 0;\n case \"access\":\n return await access(need(positional, 1), flags.has(\"--json\"), io);\n case \"requirements\":\n return await requirements(need(positional, 1), flags.has(\"--ddl\"), io);\n case \"check\":\n return await check(need(positional, 1), operations, flags, values, io);\n case \"compile\":\n return await compile(need(positional, 1), operations, values, io);\n case \"analyze\":\n return await analyzeCommand(need(positional, 1), values, io);\n case \"migrate\": {\n const [from, file] = need(positional, 2);\n if (from !== \"neo4j\") throw new UsageError(\"migrate supports neo4j\");\n const docs = [];\n for (const path of operations) {\n for (const f of await graphqlFiles(path)) docs.push(parse(f.source));\n }\n const result = migrateNeo4j(await read(file!), docs);\n for (const t of result.todos) io.out(`# TODO(migrate): ${t}`);\n if (result.todos.length > 0) io.out(\"\");\n io.out(result.typeDefs);\n return 0;\n }\n case \"diff\": {\n const [before, after] = need(positional, 2);\n return await diff(before!, after!, flags, io);\n }\n default:\n io.err(USAGE);\n return 2;\n }\n } catch (err) {\n if (err instanceof UsageError) {\n io.err(`${err.message}\\n\\n${USAGE}`);\n return 2;\n }\n if (err instanceof ModelError) {\n io.err(err.message);\n return 1;\n }\n io.err(err instanceof Error ? err.message : String(err));\n return 1;\n }\n}\n\nclass UsageError extends Error {}\n\nconst VALUE_FLAGS = new Set([\n \"--out\",\n \"--variables\",\n \"--context\",\n \"--baseline\",\n \"--row-budget\",\n \"--database\",\n \"--name\",\n \"--sample\",\n]);\n\nfunction need(positional: string[], n: number): string[] {\n if (positional.length < n)\n throw new UsageError(`expected ${n} file argument(s)`);\n return positional;\n}\n\nconst read = (path: string) => readFile(path, \"utf8\");\n\n/** A LoraGraphQL over a driver that refuses to run anything. */\nfunction offline(typeDefs: string): LoraGraphQL {\n const driver: LoraDriver = {\n run: () => Promise.reject(new Error(\"no database\")),\n };\n return new LoraGraphQL({ typeDefs, driver });\n}\n\nasync function access(\n [file]: string[],\n json: boolean,\n io: Io,\n): Promise<number> {\n const matrix = offline(await read(file!)).accessMatrix();\n if (json) {\n io.out(JSON.stringify(matrix, null, 2));\n return 0;\n }\n const rows = matrix.map((e) => [\n e.field ? `${e.type}.${e.field}` : e.type,\n e.operation,\n e.principal,\n e.verdict,\n e.by.join(\", \"),\n ]);\n const widths = [0, 1, 2, 3].map((i) =>\n Math.max(...rows.map((r) => r[i]!.length), 0),\n );\n for (const r of rows) {\n io.out(\n r\n .map((cell, i) => (i < 4 ? cell.padEnd(widths[i]!) : cell))\n .join(\" \")\n .trimEnd(),\n );\n }\n return 0;\n}\n\nasync function print([file]: string[], io: Io): Promise<number> {\n io.out(offline(await read(file!)).printPublicSchema());\n return 0;\n}\n\nasync function requirements(\n [file]: string[],\n ddl: boolean,\n io: Io,\n): Promise<number> {\n const model = buildModel(await read(file!));\n for (const r of inferRequirements(model)) {\n io.out(\n ddl\n ? `${requirementDdl(r)};`\n : `${describeRequirement(r)}, because ${r.reason}`,\n );\n }\n return 0;\n}\n\n/** The node binding's createDatabase, or a message saying how to get it. */\nasync function nodeBinding(\n io: Io,\n command: string,\n): Promise<\n | ((name?: string, options?: { databaseDir?: string }) => Promise<unknown>)\n | undefined\n> {\n try {\n const { createDatabase } =\n (await import(\"@loradb/lora-node\")) as unknown as {\n createDatabase: (\n name?: string,\n options?: { databaseDir?: string },\n ) => Promise<unknown>;\n };\n return createDatabase;\n } catch {\n io.err(\n `${command} needs @loradb/lora-node: npm install --save-dev @loradb/lora-node`,\n );\n return undefined;\n }\n}\n\nasync function check(\n [file]: string[],\n operationPaths: string[],\n flags: Set<string>,\n values: Map<string, string>,\n io: Io,\n): Promise<number> {\n const json = flags.has(\"--json\");\n const typeDefs = await read(file!);\n const createDatabase = await nodeBinding(io, \"check\");\n if (!createDatabase) return 1;\n // An existing database is checked as it is; an in-memory one gets what\n // the API needs, so only the plans are under test.\n const databaseDir = values.get(\"--database\");\n const db = await createDatabase(\n databaseDir ? (values.get(\"--name\") ?? \"app\") : undefined,\n databaseDir ? { databaseDir } : {},\n );\n const lora = new LoraGraphQL({\n typeDefs,\n driver: loraDriver(db as Parameters<typeof loraDriver>[0]),\n });\n if (!databaseDir) await lora.assertSchema({ create: true });\n const schema = lora.getSchema();\n const fixtures = values.has(\"--variables\")\n ? (JSON.parse(await read(values.get(\"--variables\")!)) as Record<\n string,\n Record<string, unknown>\n >)\n : {};\n // GraphQL contexts per operation name, `*` for every other operation.\n const contexts = values.has(\"--context\")\n ? (JSON.parse(await read(values.get(\"--context\")!)) as Record<\n string,\n unknown\n >)\n : {};\n const operations: NonNullable<CheckOptions[\"operations\"]> = [];\n for (const path of operationPaths) {\n for (const f of await graphqlFiles(path)) {\n for (const op of operationsIn(schema, f.path, f.source)) {\n const short = op.name!.split(\"#\")[1] ?? \"\";\n const given = fixtures[op.name!] ?? fixtures[short];\n const context = contexts[op.name!] ?? contexts[short] ?? contexts[\"*\"];\n operations.push({\n ...op,\n ...(given ? { variables: given } : {}),\n ...(context !== undefined ? { context } : {}),\n });\n }\n }\n }\n const rowBudget = values.has(\"--row-budget\")\n ? Number(values.get(\"--row-budget\"))\n : undefined;\n const report = await lora.check({\n operations,\n ...(rowBudget !== undefined ? { rowBudget } : {}),\n });\n\n // Plan baseline: the operators of every statement, so a plan change\n // shows up in review.\n const baselinePath = values.get(\"--baseline\");\n const current: Record<string, string[][]> = {};\n for (const p of report.plans) {\n current[`${p.operation} › ${p.field}`] = p.reports.map((r) => r.operators);\n }\n const changed: string[] = [];\n if (baselinePath) {\n let before: Record<string, string[][]> | undefined;\n try {\n before = JSON.parse(await read(baselinePath)) as Record<\n string,\n string[][]\n >;\n } catch {\n before = undefined;\n }\n if (flags.has(\"--update-baseline\") || !before) {\n await writeFile(baselinePath, JSON.stringify(current, null, 2) + \"\\n\");\n } else {\n for (const key of new Set([\n ...Object.keys(before),\n ...Object.keys(current),\n ])) {\n if (JSON.stringify(before[key]) !== JSON.stringify(current[key])) {\n changed.push(key);\n }\n }\n }\n }\n const ok = report.ok && changed.length === 0;\n\n if (json) {\n io.out(JSON.stringify({ ...report, ok, planChanges: changed }, null, 2));\n return ok ? 0 : 1;\n }\n for (const w of report.warnings) io.out(`warning ${formatProblem(w)}`);\n for (const w of report.lint) io.out(`lint ${formatProblem(w)}`);\n for (const u of report.unused) {\n io.out(\n `unused ${u.type} index ${u.name} on :${u.labels.join(\":\")}(${u.properties.join(\", \")})`,\n );\n }\n for (const s of report.security) io.out(`error ${formatProblem(s)}`);\n for (const m of report.missing)\n io.out(`error missing ${describeRequirement(m)}`);\n for (const c of report.cypher)\n io.out(`error ${c.type}.${c.field}: ${c.message}`);\n for (const e of report.errors)\n io.out(`error ${e.operation}: ${e.message}`);\n for (const p of report.plans) {\n for (const r of p.reports) {\n for (const f of r.findings) {\n io.out(`error ${p.operation} › ${p.field}: ${f.message}`);\n }\n for (const n of r.notes) {\n io.out(`lint ${p.operation} › ${p.field}: ${n.message}`);\n }\n }\n }\n for (const key of changed) {\n io.out(\n `error ${key}: the plan differs from the baseline (--update-baseline to accept)`,\n );\n }\n const checked = report.plans.length;\n io.out(\n ok\n ? `ok ${checked} root field(s) in ${operations.length} operation(s) seek as expected`\n : \"failed\",\n );\n return ok ? 0 : 1;\n}\n\n/** Persisted operations from .graphql files (one per operation) or JSON (id → source). */\nasync function persistedOperations(\n paths: string[],\n): Promise<Record<string, string>> {\n const out: Record<string, string> = {};\n for (const path of paths) {\n const info = await stat(path);\n if (info.isFile() && path.endsWith(\".json\")) {\n Object.assign(\n out,\n JSON.parse(await read(path)) as Record<string, string>,\n );\n continue;\n }\n for (const f of await graphqlFiles(path)) {\n const doc = parse(f.source);\n const fragments = new Map(\n doc.definitions\n .filter(\n (d): d is FragmentDefinitionNode =>\n d.kind === Kind.FRAGMENT_DEFINITION,\n )\n .map((d) => [d.name.value, d]),\n );\n const rel = relative(process.cwd(), f.path);\n doc.definitions\n .filter(\n (d): d is OperationDefinitionNode =>\n d.kind === Kind.OPERATION_DEFINITION,\n )\n .forEach((op, i) => {\n const id = `${rel}#${op.name?.value ?? i + 1}`;\n out[id] = printAst({\n kind: Kind.DOCUMENT,\n definitions: [op, ...usedFragments(op, fragments)],\n });\n });\n }\n }\n return out;\n}\n\nasync function compile(\n [file]: string[],\n operationPaths: string[],\n values: Map<string, string>,\n io: Io,\n): Promise<number> {\n if (operationPaths.length === 0) {\n throw new UsageError(\"compile needs --operations <file|dir>\");\n }\n const lora = offline(await read(file!));\n const manifest = lora.buildManifest(\n await persistedOperations(operationPaths),\n );\n const outDir = values.get(\"--out\") ?? \"lora-graphql\";\n await mkdir(outDir, { recursive: true });\n await writeFile(\n join(outDir, \"manifest.json\"),\n JSON.stringify(manifest) + \"\\n\",\n );\n await writeFile(\n join(outDir, \"operations.d.ts\"),\n lora.generateTypes(manifest),\n );\n io.out(\n `wrote ${Object.keys(manifest.operations).length} operation(s) to ${join(outDir, \"manifest.json\")} and ${join(outDir, \"operations.d.ts\")}`,\n );\n return 0;\n}\n\nasync function analyzeCommand(\n [file]: string[],\n values: Map<string, string>,\n io: Io,\n): Promise<number> {\n const databaseDir = values.get(\"--database\");\n if (!databaseDir) throw new UsageError(\"analyze needs --database <dir>\");\n const createDatabase = await nodeBinding(io, \"analyze\");\n if (!createDatabase) return 1;\n const db = await createDatabase(values.get(\"--name\") ?? \"app\", {\n databaseDir,\n });\n const lora = new LoraGraphQL({\n typeDefs: await read(file!),\n driver: loraDriver(db as Parameters<typeof loraDriver>[0]),\n });\n const sample = values.has(\"--sample\")\n ? Number(values.get(\"--sample\"))\n : undefined;\n const stats = await lora.analyze(sample !== undefined ? { sample } : {});\n io.out(JSON.stringify(stats, null, 2));\n (db as { dispose?: () => void }).dispose?.();\n return 0;\n}\n\nasync function graphqlFiles(\n path: string,\n): Promise<Array<{ path: string; source: string }>> {\n const info = await stat(path);\n if (info.isFile()) return [{ path, source: await read(path) }];\n const out: Array<{ path: string; source: string }> = [];\n for (const entry of await readdir(path, { withFileTypes: true })) {\n const full = join(path, entry.name);\n if (entry.isDirectory()) out.push(...(await graphqlFiles(full)));\n else if (/\\.(graphql|gql)$/.test(entry.name)) {\n out.push({ path: full, source: await read(full) });\n }\n }\n return out;\n}\n\n/** Each query in a file, with example values for its required variables. */\nfunction operationsIn(\n schema: GraphQLSchema,\n path: string,\n source: string,\n): NonNullable<CheckOptions[\"operations\"]> {\n const doc = parse(source);\n const fragments = new Map(\n doc.definitions\n .filter(\n (d): d is FragmentDefinitionNode => d.kind === Kind.FRAGMENT_DEFINITION,\n )\n .map((f) => [f.name.value, f]),\n );\n // The fragments an operation spreads, transitively.\n const used = (root: DefinitionNode): FragmentDefinitionNode[] => {\n const seen = new Map<string, FragmentDefinitionNode>();\n const walk = (node: DefinitionNode) =>\n visit(node, {\n FragmentSpread(spread) {\n const f = fragments.get(spread.name.value);\n if (f && !seen.has(f.name.value)) {\n seen.set(f.name.value, f);\n walk(f);\n }\n },\n });\n walk(root);\n return [...seen.values()];\n };\n return doc.definitions\n .filter(\n (d): d is OperationDefinitionNode =>\n d.kind === Kind.OPERATION_DEFINITION && d.operation === \"query\",\n )\n .map((op, i) => {\n const variables: Record<string, unknown> = {};\n for (const v of op.variableDefinitions ?? []) {\n if (v.defaultValue || v.type.kind !== Kind.NON_NULL_TYPE) continue;\n const type = typeFromAST(schema, v.type) as\n | GraphQLInputType\n | undefined;\n if (type) variables[v.variable.name.value] = sample(type);\n }\n return {\n name: `${path}${op.name ? `#${op.name.value}` : `#${i + 1}`}`,\n document: { kind: Kind.DOCUMENT, definitions: [op, ...used(op)] },\n variables,\n };\n });\n}\n\nconst SAMPLES: Record<string, unknown> = {\n String: \"x\",\n ID: \"x\",\n Int: 1,\n Float: 1,\n Boolean: true,\n BigInt: \"1\",\n Date: \"2026-01-01\",\n Time: \"12:00:00Z\",\n LocalTime: \"12:00:00\",\n DateTime: \"2026-01-01T12:00:00Z\",\n LocalDateTime: \"2026-01-01T12:00:00\",\n Duration: \"P1D\",\n};\n\nfunction sample(type: GraphQLInputType): unknown {\n const inner = isNonNullType(type) ? type.ofType : type;\n if (isListType(inner)) return [sample(inner.ofType)];\n const named = getNamedType(inner);\n if (isEnumType(named)) return named.getValues()[0]?.value;\n if (isInputObjectType(named)) {\n const out: Record<string, unknown> = {};\n for (const f of Object.values(named.getFields())) {\n if (isNonNullType(f.type) && f.defaultValue === undefined) {\n out[f.name] = sample(f.type);\n }\n }\n return out;\n }\n return SAMPLES[named.name] ?? \"x\";\n}\n\nasync function diff(\n before: string,\n after: string,\n flags: Set<string>,\n io: Io,\n): Promise<number> {\n const result = diffSchemas(await read(before), await read(after));\n const breaking = result.api.breaking.length > 0;\n const code = breaking && !flags.has(\"--allow-breaking\") ? 1 : 0;\n if (flags.has(\"--json\")) {\n io.out(JSON.stringify(result, null, 2));\n return code;\n }\n io.out(\"# Database\");\n if (result.database.statements.length === 0) io.out(\"no changes\");\n for (const s of result.database.statements) {\n io.out(`${s.destructive ? \"// destructive: \" : \"// \"}${s.reason}`);\n io.out(`${s.text};`);\n }\n io.out(\"\\n# API\");\n if (!breaking && result.api.dangerous.length === 0) io.out(\"no changes\");\n for (const c of result.api.breaking) io.out(`breaking ${c.description}`);\n for (const c of result.api.dangerous) io.out(`dangerous ${c.description}`);\n for (const n of result.notes) io.out(`note ${n}`);\n return code;\n}\n\nconst defaultIo: Io = {\n out: (line) => process.stdout.write(line + \"\\n\"),\n err: (line) => process.stderr.write(line + \"\\n\"),\n};\n\nconst invokedDirectly =\n typeof process !== \"undefined\" &&\n process.argv[1] !== undefined &&\n /lora-graphql(\\.js)?$|cli\\.js$/.test(process.argv[1]);\nif (invokedDirectly) {\n main(process.argv.slice(2)).then((code) => process.exit(code));\n}\n"],"names":["ROOT","UNSUPPORTED","SUFFIX_OPS","NESTED_OPS","migrateNeo4j","sdl","operations","doc","parse","todos","nodeTypes","d","Kind","has","nodeNames","t","usage","observe","out","visit","type","directives","migrateDirectives","directive","ops","enumList","idFields","f","fields","migrateField","print","bool","used","field","at","name","migrateRelationship","renameInList","migrateSubscription","args","a","arg","enumValue","kept","v","events","relationships","e","types","byPlural","defaultPlural","neo4jPlural","byName","note","op","where","value","key","quantifier","rel","x","target","namedTypeOf","suffix","s","fieldName","def","inner","mapped","walk","set","root","sel","mutation","plural","lowerFirst","argumentUse","sorts","collect","k","values","argName","from","to","IRREGULAR","typeName","base","lower","one","many","USAGE","main","argv","io","defaultIo","command","rest","flags","positional","VALUE_FLAGS","need","directiveTypeDefs","access","requirements","check","compile","analyzeCommand","file","UsageError","docs","path","graphqlFiles","result","read","before","after","diff","err","ModelError","n","readFile","offline","typeDefs","driver","LoraGraphQL","json","matrix","rows","widths","i","r","cell","ddl","model","buildModel","inferRequirements","requirementDdl","describeRequirement","nodeBinding","createDatabase","operationPaths","databaseDir","db","lora","loraDriver","schema","fixtures","contexts","operationsIn","short","given","context","rowBudget","report","baselinePath","current","p","changed","writeFile","ok","w","formatProblem","u","m","c","checked","persistedOperations","paths","stat","fragments","relative","id","printAst","usedFragments","manifest","outDir","mkdir","join","sample","stats","entry","readdir","full","source","seen","node","spread","variables","typeFromAST","SAMPLES","isNonNullType","isListType","named","getNamedType","isEnumType","isInputObjectType","diffSchemas","breaking","code","line","invokedDirectly"],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sources":["../src/migrate.ts","../src/cli.ts"],"sourcesContent":["// `lora-graphql migrate neo4j`: rewrite an @neo4j/graphql SDL into this\n// package's vocabulary. What maps is rewritten; what does not is removed\n// and listed as a TODO. With the client's operations, the opt-in surface\n// (@mutation, @filterable, @sortable) follows observed usage; without\n// them, mutations stay on for every type (as in @neo4j/graphql).\n\nimport {\n Kind,\n parse,\n print,\n visit,\n type ArgumentNode,\n type ConstArgumentNode,\n type ConstDirectiveNode,\n type ConstValueNode,\n type DocumentNode,\n type FieldDefinitionNode,\n type ObjectTypeDefinitionNode,\n type SelectionSetNode,\n type ValueNode,\n} from \"graphql\";\nimport { defaultPlural } from \"./model/build.js\";\n\nexport interface MigrationResult {\n /** The rewritten SDL. */\n typeDefs: string;\n /** What has no equivalent or needs a decision, by type and field. */\n todos: string[];\n}\n\nconst ROOT = new Set([\"Query\", \"Mutation\", \"Subscription\"]);\n\n/** Removed with a TODO: no equivalent here. */\nconst UNSUPPORTED: Record<string, string> = {\n coalesce:\n \"@coalesce is not supported: it hides predicates from indexes; store a value instead\",\n subscriptionsAuthorization:\n \"@subscriptionsAuthorization is not supported: SUBSCRIBE rules go in @authorization\",\n shareable: \"federation (@shareable) is not supported\",\n external: \"federation (@external) is not supported\",\n requires: \"federation (@requires) is not supported\",\n provides: \"federation (@provides) is not supported\",\n exclude: \"@exclude: use @query / @mutation to choose operations\",\n vector:\n \"@vector on types (with a provider) is not supported: put @vector(dimensions:, similarity:) on a [Float!] field\",\n};\n\n/** neo4j 5 filter suffixes → @filterable operators. */\nconst SUFFIX_OPS: Array<[string, string]> = [\n [\"_NOT_IN\", \"IN\"],\n [\"_STARTS_WITH\", \"STARTS_WITH\"],\n [\"_ENDS_WITH\", \"ENDS_WITH\"],\n [\"_CONTAINS\", \"CONTAINS\"],\n [\"_INCLUDES\", \"INCLUDES\"],\n [\"_GTE\", \"GTE\"],\n [\"_LTE\", \"LTE\"],\n [\"_GT\", \"GT\"],\n [\"_LT\", \"LT\"],\n [\"_IN\", \"IN\"],\n [\"_EQ\", \"EQ\"],\n];\n\n/** neo4j 6 nested filter operators → @filterable operators. */\nconst NESTED_OPS: Record<string, string> = {\n eq: \"EQ\",\n in: \"IN\",\n lt: \"LT\",\n lte: \"LTE\",\n gt: \"GT\",\n gte: \"GTE\",\n contains: \"CONTAINS\",\n startsWith: \"STARTS_WITH\",\n endsWith: \"ENDS_WITH\",\n includes: \"INCLUDES\",\n caseInsensitive: \"CASE_INSENSITIVE\",\n};\n\ninterface Usage {\n filters: Map<string, Map<string, Set<string>>>;\n sorts: Map<string, Set<string>>;\n mutations: Map<string, Set<string>>;\n}\n\nexport function migrateNeo4j(\n sdl: string,\n operations: DocumentNode[] = [],\n): MigrationResult {\n const doc = parse(sdl, { noLocation: true });\n const todos: string[] = [];\n const nodeTypes = doc.definitions.filter(\n (d): d is ObjectTypeDefinitionNode =>\n d.kind === Kind.OBJECT_TYPE_DEFINITION &&\n !ROOT.has(d.name.value) &&\n !has(d.directives, \"relationshipProperties\") &&\n !has(d.directives, \"jwt\"),\n );\n const nodeNames = new Set(nodeTypes.map((t) => t.name.value));\n const usage =\n operations.length > 0 ? observe(operations, nodeTypes) : undefined;\n\n const out = visit(doc, {\n ObjectTypeDefinition(t) {\n if (!nodeNames.has(t.name.value)) return undefined;\n const type = t.name.value;\n let directives = migrateDirectives(\n t.directives ?? [],\n type,\n undefined,\n todos,\n );\n if (!has(directives, \"node\"))\n directives = [...directives, directive(\"node\")];\n const ops = usage?.mutations.get(type);\n if (!has(directives, \"mutation\")) {\n if (!usage) {\n directives = [...directives, directive(\"mutation\")];\n todos.push(\n `${type}: @mutation added (@neo4j/graphql generates mutations for every type); remove it or narrow its operations`,\n );\n } else if (ops && ops.size > 0) {\n directives = [\n ...directives,\n directive(\"mutation\", {\n operations: enumList([...ops].sort()),\n }),\n ];\n }\n }\n const idFields = (t.fields ?? []).filter((f) => has(f.directives, \"id\"));\n if (idFields.length === 0) {\n todos.push(\n `${type}: no @id field; add a required @key field (the sort tie-breaker and mutation address)`,\n );\n } else if (idFields.length > 1) {\n todos.push(`${type}: several @id fields; keep one as the @key`);\n }\n const fields = (t.fields ?? []).map((f) =>\n migrateField(f, type, usage, todos),\n );\n return { ...t, directives, fields };\n },\n });\n return { typeDefs: print(out), todos };\n}\n\nfunction migrateField(\n f: FieldDefinitionNode,\n type: string,\n usage: Usage | undefined,\n todos: string[],\n): FieldDefinitionNode {\n let directives = migrateDirectives(\n f.directives ?? [],\n type,\n f.name.value,\n todos,\n );\n const id = directives.find((d) => d.name.value === \"id\");\n if (id) {\n directives = directives.filter(\n (d) => d.name.value !== \"id\" && d.name.value !== \"unique\",\n );\n directives.push(directive(\"key\", { generate: bool(true) }));\n }\n const used = usage?.filters.get(type)?.get(f.name.value);\n if (used && used.size > 0 && !has(directives, \"filterable\")) {\n directives.push(\n has(directives, \"relationship\")\n ? directive(\"filterable\")\n : directive(\"filterable\", { byValue: enumList([...used].sort()) }),\n );\n }\n if (\n usage?.sorts.get(type)?.has(f.name.value) &&\n !has(directives, \"sortable\")\n ) {\n directives.push(directive(\"sortable\"));\n }\n return { ...f, directives };\n}\n\nfunction migrateDirectives(\n directives: readonly ConstDirectiveNode[],\n type: string,\n field: string | undefined,\n todos: string[],\n): ConstDirectiveNode[] {\n const at = field ? `${type}.${field}` : type;\n const out: ConstDirectiveNode[] = [];\n for (const d of directives) {\n const name = d.name.value;\n if (name in UNSUPPORTED) {\n todos.push(`${at}: ${UNSUPPORTED[name]}`);\n continue;\n }\n if (name === \"key\" && !field) {\n todos.push(`${at}: federation @key(fields:) is not supported`);\n continue;\n }\n if (name === \"unique\") {\n out.push(directive(\"unique\"));\n continue;\n }\n if (name === \"relationship\") {\n out.push(migrateRelationship(d, at, todos));\n continue;\n }\n if (name === \"fulltext\") {\n out.push(renameInList(d, \"indexes\", \"indexName\", \"name\"));\n continue;\n }\n if (name === \"subscription\") {\n out.push(migrateSubscription(d, at, todos));\n continue;\n }\n if (name === \"authorization\" || name === \"authentication\") {\n todos.push(\n `${at}: check the @${name} rule's filters: operators are written { field: { eq: ... } } here`,\n );\n }\n out.push(d);\n }\n return out;\n}\n\nfunction migrateRelationship(\n d: ConstDirectiveNode,\n at: string,\n todos: string[],\n): ConstDirectiveNode {\n const args: ConstArgumentNode[] = [];\n for (const a of d.arguments ?? []) {\n const name = a.name.value;\n if (name === \"queryDirection\" && a.value.kind === Kind.ENUM) {\n if (a.value.value.includes(\"UNDIRECTED\")) {\n args.push(arg(\"queryDirection\", enumValue(\"UNDIRECTED\")));\n }\n continue;\n }\n if (name === \"nestedOperations\" && a.value.kind === Kind.LIST) {\n const kept = a.value.values.filter(\n (v) => v.kind === Kind.ENUM && v.value !== \"CONNECT_OR_CREATE\",\n );\n if (kept.length < a.value.values.length) {\n todos.push(`${at}: connectOrCreate is not supported; use upsert`);\n }\n args.push(arg(\"nestedOperations\", { kind: Kind.LIST, values: kept }));\n continue;\n }\n args.push(a);\n }\n return { ...d, arguments: args };\n}\n\nfunction migrateSubscription(\n d: ConstDirectiveNode,\n at: string,\n todos: string[],\n): ConstDirectiveNode {\n const events = d.arguments?.find((a) => a.name.value === \"events\")?.value;\n if (!events || events.kind !== Kind.LIST) return d;\n const ops = new Set<string>();\n let relationships = false;\n for (const e of events.values) {\n if (e.kind !== Kind.ENUM) continue;\n if (e.value.startsWith(\"CREATED\") && !e.value.includes(\"RELATIONSHIP\"))\n ops.add(\"CREATE\");\n else if (e.value.startsWith(\"UPDATED\")) ops.add(\"UPDATE\");\n else if (e.value.startsWith(\"DELETED\") && !e.value.includes(\"RELATIONSHIP\"))\n ops.add(\"DELETE\");\n else if (e.value.includes(\"RELATIONSHIP\")) relationships = true;\n }\n todos.push(\n `${at}: subscriptions see writes made through this library (or the engine change feed), not CDC`,\n );\n return directive(\"subscription\", {\n operations: enumList([...ops].sort()),\n ...(relationships ? { relationships: bool(true) } : {}),\n });\n}\n\n/** What the client's operations use: filters, sorts and mutations per type. */\nfunction observe(\n operations: DocumentNode[],\n types: ObjectTypeDefinitionNode[],\n): Usage {\n const usage: Usage = {\n filters: new Map(),\n sorts: new Map(),\n mutations: new Map(),\n };\n // Root fields as either naming would call them: this package's plural\n // and @neo4j/graphql's (which knows irregular plurals, e.g. people).\n const byPlural = new Map<string, ObjectTypeDefinitionNode>();\n for (const t of types) {\n byPlural.set(defaultPlural(t.name.value), t);\n byPlural.set(neo4jPlural(t.name.value), t);\n }\n const byName = new Map(types.map((t) => [t.name.value, t]));\n const note = (type: string, field: string, op: string) => {\n const fields = usage.filters.get(type) ?? new Map<string, Set<string>>();\n const ops = fields.get(field) ?? new Set<string>();\n ops.add(op);\n fields.set(field, ops);\n usage.filters.set(type, fields);\n };\n const where = (type: ObjectTypeDefinitionNode, value: ValueNode) => {\n if (value.kind !== Kind.OBJECT) return;\n for (const f of value.fields) {\n const key = f.name.value;\n if (key === \"AND\" || key === \"OR\") {\n if (f.value.kind === Kind.LIST)\n for (const v of f.value.values) where(type, v);\n continue;\n }\n if (key === \"NOT\") {\n where(type, f.value);\n continue;\n }\n // neo4j 5 relationship quantifiers: `actors_SOME: { name_EQ: ... }`.\n const quantifier = /^(.+)_(SOME|ALL|NONE|SINGLE)$/.exec(key);\n if (quantifier) {\n const rel = type.fields?.find((x) => x.name.value === quantifier[1]);\n const target = rel && byName.get(namedTypeOf(rel));\n if (rel && target) {\n note(type.name.value, quantifier[1]!, \"EQ\");\n where(target, f.value);\n }\n continue;\n }\n const suffix = SUFFIX_OPS.find(([s]) => key.endsWith(s));\n const fieldName = suffix ? key.slice(0, -suffix[0].length) : key;\n const def = type.fields?.find((x) => x.name.value === fieldName);\n if (!def) continue;\n const target = byName.get(namedTypeOf(def));\n if (target) {\n note(type.name.value, fieldName, \"EQ\");\n // `some` / `all` / `none` / `single`, or a nested where.\n if (f.value.kind === Kind.OBJECT) {\n for (const inner of f.value.fields) where(target, inner.value);\n where(target, f.value);\n }\n continue;\n }\n if (suffix) note(type.name.value, fieldName, suffix[1]);\n else if (f.value.kind === Kind.OBJECT) {\n for (const op of f.value.fields) {\n const mapped = NESTED_OPS[op.name.value];\n if (mapped) note(type.name.value, fieldName, mapped);\n }\n } else note(type.name.value, fieldName, \"EQ\");\n }\n };\n const walk = (set: SelectionSetNode | undefined, root: boolean) => {\n for (const sel of set?.selections ?? []) {\n if (sel.kind !== Kind.FIELD) continue;\n const name = sel.name.value;\n if (root) {\n const mutation = /^(create|update|delete|upsert)(.+)$/.exec(name);\n const plural = name.replace(/(Connection|Aggregate)$/, \"\");\n const type =\n byPlural.get(plural) ??\n (mutation ? byPlural.get(lowerFirst(mutation[2]!)) : undefined);\n if (type && mutation) {\n const ops = usage.mutations.get(type.name.value) ?? new Set<string>();\n const op = mutation[1]!.toUpperCase();\n if (op === \"UPSERT\") {\n ops.add(\"CREATE\");\n ops.add(\"UPDATE\");\n } else ops.add(op);\n usage.mutations.set(type.name.value, ops);\n }\n if (type) {\n for (const a of sel.arguments ?? []) argumentUse(type, a);\n }\n }\n walk(sel.selectionSet, false);\n }\n };\n const argumentUse = (type: ObjectTypeDefinitionNode, a: ArgumentNode) => {\n if (a.name.value === \"where\") where(type, a.value);\n if (a.name.value === \"sort\" || a.name.value === \"options\") {\n const sorts = usage.sorts.get(type.name.value) ?? new Set<string>();\n const collect = (v: ValueNode) => {\n if (v.kind === Kind.LIST) v.values.forEach(collect);\n else if (v.kind === Kind.OBJECT) {\n for (const f of v.fields) {\n if (f.name.value === \"sort\") collect(f.value);\n else if (f.value.kind === Kind.ENUM) sorts.add(f.name.value);\n }\n }\n };\n collect(a.value);\n usage.sorts.set(type.name.value, sorts);\n }\n };\n for (const doc of operations) {\n for (const def of doc.definitions) {\n if (def.kind === Kind.OPERATION_DEFINITION) walk(def.selectionSet, true);\n }\n }\n return usage;\n}\n\nfunction namedTypeOf(f: FieldDefinitionNode): string {\n let t = f.type;\n while (t.kind !== Kind.NAMED_TYPE) t = t.type;\n return t.name.value;\n}\n\nfunction has(\n directives: readonly ConstDirectiveNode[] | undefined,\n name: string,\n): boolean {\n return (directives ?? []).some((d) => d.name.value === name);\n}\n\nfunction directive(\n name: string,\n args: Record<string, ConstValueNode> = {},\n): ConstDirectiveNode {\n return {\n kind: Kind.DIRECTIVE,\n name: { kind: Kind.NAME, value: name },\n arguments: Object.entries(args).map(([k, v]) => arg(k, v)),\n };\n}\n\nfunction arg(name: string, value: ConstValueNode): ConstArgumentNode {\n return { kind: Kind.ARGUMENT, name: { kind: Kind.NAME, value: name }, value };\n}\n\nconst enumValue = (value: string): ConstValueNode => ({\n kind: Kind.ENUM,\n value,\n});\nconst bool = (value: boolean): ConstValueNode => ({\n kind: Kind.BOOLEAN,\n value,\n});\nconst enumList = (values: string[]): ConstValueNode => ({\n kind: Kind.LIST,\n values: values.map(enumValue),\n});\n\n/** Rename a key inside each object of a list argument. */\nfunction renameInList(\n d: ConstDirectiveNode,\n argName: string,\n from: string,\n to: string,\n): ConstDirectiveNode {\n return {\n ...d,\n arguments: (d.arguments ?? []).map((a) =>\n a.name.value === argName && a.value.kind === Kind.LIST\n ? arg(argName, {\n kind: Kind.LIST,\n values: a.value.values.map((v) =>\n v.kind === Kind.OBJECT\n ? {\n ...v,\n fields: v.fields.map((f) =>\n f.name.value === from\n ? { ...f, name: { kind: Kind.NAME, value: to } }\n : f,\n ),\n }\n : v,\n ),\n })\n : a,\n ),\n };\n}\n\nconst IRREGULAR: Record<string, string> = {\n person: \"people\",\n man: \"men\",\n woman: \"women\",\n child: \"children\",\n mouse: \"mice\",\n goose: \"geese\",\n foot: \"feet\",\n tooth: \"teeth\",\n};\n\nfunction neo4jPlural(typeName: string): string {\n const base = lowerFirst(typeName);\n const lower = base.toLowerCase();\n for (const [one, many] of Object.entries(IRREGULAR)) {\n if (lower.endsWith(one))\n return base.slice(0, base.length - one.length) + many;\n }\n return defaultPlural(typeName);\n}\n\nfunction lowerFirst(s: string): string {\n return s.charAt(0).toLowerCase() + s.slice(1);\n}\n","// lora-graphql: the build-time half of the library.\n//\n// lora-graphql print <schema.graphql>\n// lora-graphql directives\n// lora-graphql requirements <schema.graphql> [--ddl]\n// lora-graphql check <schema.graphql> [--operations <file|dir>]... [--variables <file>] [--context <file>]\n// [--baseline <file> [--update-baseline]] [--row-budget <n>]\n// [--database <dir> [--name <db>]] [--json]\n// lora-graphql compile <schema.graphql> --operations <file|dir>... [--out <dir>]\n// lora-graphql analyze <schema.graphql> --database <dir> [--name <db>] [--sample <n>]\n// lora-graphql migrate neo4j <schema.graphql> [--operations <file|dir>]...\n// lora-graphql diff <old.graphql> <new.graphql> [--allow-breaking] [--json]\n// lora-graphql diff --base <git-ref> <file|dir>... [--allow-breaking] [--json]\n\nimport { execFileSync } from \"node:child_process\";\nimport { mkdir, readdir, readFile, stat, writeFile } from \"node:fs/promises\";\nimport { basename, dirname, join, relative } from \"node:path\";\nimport {\n getNamedType,\n isEnumType,\n isInputObjectType,\n isListType,\n isNonNullType,\n Kind,\n parse,\n print as printAst,\n typeFromAST,\n visit,\n type DefinitionNode,\n type FragmentDefinitionNode,\n type GraphQLInputType,\n type GraphQLSchema,\n type OperationDefinitionNode,\n} from \"graphql\";\nimport { diffSchemas } from \"./analyze/diff.js\";\nimport { formatProblem, ModelError } from \"./errors.js\";\nimport { buildModel } from \"./model/build.js\";\nimport { directiveTypeDefs } from \"./model/directives.js\";\nimport {\n describeRequirement,\n inferRequirements,\n requirementDdl,\n} from \"./analyze/indexes.js\";\nimport { LoraGraphQL, type CheckOptions } from \"./lora-graphql.js\";\nimport { loraDriver, type LoraDriver } from \"./driver.js\";\nimport { usedFragments } from \"./codegen.js\";\nimport { migrateNeo4j } from \"./migrate.js\";\n\nconst USAGE = `lora-graphql <command>\n\n print <schema.graphql> the public SDL clients see\n directives the directive definitions, for editors\n access <schema.graphql> [--json] who may do what: each type and guarded field,\n operation and kind of caller\n requirements <schema.graphql> [--ddl] constraints and indexes the API needs\n check <schema.graphql> [--operations <file|dir>]... [--json]\n [--variables <file>] [--context <file>]\n [--baseline <file> [--update-baseline]]\n [--row-budget <n>] [--database <dir> [--name <db>]]\n CI gate: model, lint, @cypher statements and\n the plans of your operations, on an in-memory\n LoraDB (or an existing one with --database)\n compile <schema.graphql> --operations <file|dir>... [--out <dir>]\n persisted-operation manifest.json and\n operations.d.ts types\n analyze <schema.graphql> --database <dir> [--name <db>] [--sample <n>]\n statistics JSON for useStatistics()\n migrate neo4j <schema.graphql> [--operations <file|dir>]...\n rewrite an @neo4j/graphql SDL; TODOs for\n what has no equivalent\n diff <old.graphql> <new.graphql> [--allow-breaking] [--json]\n diff --base <git-ref> <file|dir>... [--allow-breaking] [--json]\n database statements and API changes; exit 1\n on a breaking change or a destructive statement\n (--base: the SDL files at a git ref against the\n working tree, each side concatenated)`;\n\ninterface Io {\n out: (line: string) => void;\n err: (line: string) => void;\n}\n\nexport async function main(\n argv: string[],\n io: Io = defaultIo,\n): Promise<number> {\n const [command, ...rest] = argv;\n const flags = new Set<string>();\n const values = new Map<string, string>();\n const positional: string[] = [];\n const operations: string[] = [];\n for (let i = 0; i < rest.length; i++) {\n const a = rest[i]!;\n if (a === \"--operations\") operations.push(rest[++i] ?? \"\");\n else if (VALUE_FLAGS.has(a)) values.set(a, rest[++i] ?? \"\");\n else if (a.startsWith(\"--\")) flags.add(a);\n else positional.push(a);\n }\n try {\n switch (command) {\n case \"print\":\n return await print(need(positional, 1), io);\n case \"directives\":\n io.out(directiveTypeDefs.trim());\n return 0;\n case \"access\":\n return await access(need(positional, 1), flags.has(\"--json\"), io);\n case \"requirements\":\n return await requirements(need(positional, 1), flags.has(\"--ddl\"), io);\n case \"check\":\n return await check(need(positional, 1), operations, flags, values, io);\n case \"compile\":\n return await compile(need(positional, 1), operations, values, io);\n case \"analyze\":\n return await analyzeCommand(need(positional, 1), values, io);\n case \"migrate\": {\n const [from, file] = need(positional, 2);\n if (from !== \"neo4j\") throw new UsageError(\"migrate supports neo4j\");\n const docs = [];\n for (const path of operations) {\n for (const f of await graphqlFiles(path)) docs.push(parse(f.source));\n }\n const result = migrateNeo4j(await read(file!), docs);\n for (const t of result.todos) io.out(`# TODO(migrate): ${t}`);\n if (result.todos.length > 0) io.out(\"\");\n io.out(result.typeDefs);\n return 0;\n }\n case \"diff\": {\n const base = values.get(\"--base\");\n if (base !== undefined) {\n if (!base) throw new UsageError(\"--base takes a git ref\");\n const paths = need(positional, 1);\n const before = await atGitRef(base, paths);\n if (before === undefined) {\n io.out(\n `${base} has none of ${paths.join(\", \")}; nothing to compare`,\n );\n return 0;\n }\n return diff(before, await sdlFiles(paths), flags, io);\n }\n const [before, after] = need(positional, 2);\n return diff(await read(before!), await read(after!), flags, io);\n }\n default:\n io.err(USAGE);\n return 2;\n }\n } catch (err) {\n if (err instanceof UsageError) {\n io.err(`${err.message}\\n\\n${USAGE}`);\n return 2;\n }\n if (err instanceof ModelError) {\n io.err(err.message);\n return 1;\n }\n io.err(err instanceof Error ? err.message : String(err));\n return 1;\n }\n}\n\nclass UsageError extends Error {}\n\nconst VALUE_FLAGS = new Set([\n \"--base\",\n \"--out\",\n \"--variables\",\n \"--context\",\n \"--baseline\",\n \"--row-budget\",\n \"--database\",\n \"--name\",\n \"--sample\",\n]);\n\nfunction need(positional: string[], n: number): string[] {\n if (positional.length < n)\n throw new UsageError(`expected ${n} file argument(s)`);\n return positional;\n}\n\nconst read = (path: string) => readFile(path, \"utf8\");\n\n/** A LoraGraphQL over a driver that refuses to run anything. */\nfunction offline(typeDefs: string): LoraGraphQL {\n const driver: LoraDriver = {\n run: () => Promise.reject(new Error(\"no database\")),\n };\n return new LoraGraphQL({ typeDefs, driver });\n}\n\nasync function access(\n [file]: string[],\n json: boolean,\n io: Io,\n): Promise<number> {\n const matrix = offline(await read(file!)).accessMatrix();\n if (json) {\n io.out(JSON.stringify(matrix, null, 2));\n return 0;\n }\n const rows = matrix.map((e) => [\n e.field ? `${e.type}.${e.field}` : e.type,\n e.operation,\n e.principal,\n e.verdict,\n e.by.join(\", \"),\n ]);\n const widths = [0, 1, 2, 3].map((i) =>\n Math.max(...rows.map((r) => r[i]!.length), 0),\n );\n for (const r of rows) {\n io.out(\n r\n .map((cell, i) => (i < 4 ? cell.padEnd(widths[i]!) : cell))\n .join(\" \")\n .trimEnd(),\n );\n }\n return 0;\n}\n\nasync function print([file]: string[], io: Io): Promise<number> {\n io.out(offline(await read(file!)).printPublicSchema());\n return 0;\n}\n\nasync function requirements(\n [file]: string[],\n ddl: boolean,\n io: Io,\n): Promise<number> {\n const model = buildModel(await read(file!));\n for (const r of inferRequirements(model)) {\n io.out(\n ddl\n ? `${requirementDdl(r)};`\n : `${describeRequirement(r)}, because ${r.reason}`,\n );\n }\n return 0;\n}\n\n/** The node binding's createDatabase, or a message saying how to get it. */\nasync function nodeBinding(\n io: Io,\n command: string,\n): Promise<\n | ((name?: string, options?: { databaseDir?: string }) => Promise<unknown>)\n | undefined\n> {\n try {\n const { createDatabase } =\n (await import(\"@loradb/lora-node\")) as unknown as {\n createDatabase: (\n name?: string,\n options?: { databaseDir?: string },\n ) => Promise<unknown>;\n };\n return createDatabase;\n } catch {\n io.err(\n `${command} needs @loradb/lora-node: npm install --save-dev @loradb/lora-node`,\n );\n return undefined;\n }\n}\n\nasync function check(\n [file]: string[],\n operationPaths: string[],\n flags: Set<string>,\n values: Map<string, string>,\n io: Io,\n): Promise<number> {\n const json = flags.has(\"--json\");\n const typeDefs = await read(file!);\n const createDatabase = await nodeBinding(io, \"check\");\n if (!createDatabase) return 1;\n // An existing database is checked as it is; an in-memory one gets what\n // the API needs, so only the plans are under test.\n const databaseDir = values.get(\"--database\");\n const db = await createDatabase(\n databaseDir ? (values.get(\"--name\") ?? \"app\") : undefined,\n databaseDir ? { databaseDir } : {},\n );\n const lora = new LoraGraphQL({\n typeDefs,\n driver: loraDriver(db as Parameters<typeof loraDriver>[0]),\n });\n if (!databaseDir) await lora.assertSchema({ create: true });\n const schema = lora.getSchema();\n const fixtures = values.has(\"--variables\")\n ? (JSON.parse(await read(values.get(\"--variables\")!)) as Record<\n string,\n Record<string, unknown>\n >)\n : {};\n // GraphQL contexts per operation name, `*` for every other operation.\n const contexts = values.has(\"--context\")\n ? (JSON.parse(await read(values.get(\"--context\")!)) as Record<\n string,\n unknown\n >)\n : {};\n const operations: NonNullable<CheckOptions[\"operations\"]> = [];\n for (const path of operationPaths) {\n for (const f of await graphqlFiles(path)) {\n for (const op of operationsIn(schema, f.path, f.source)) {\n const short = op.name!.split(\"#\")[1] ?? \"\";\n const given = fixtures[op.name!] ?? fixtures[short];\n const context = contexts[op.name!] ?? contexts[short] ?? contexts[\"*\"];\n operations.push({\n ...op,\n ...(given ? { variables: given } : {}),\n ...(context !== undefined ? { context } : {}),\n });\n }\n }\n }\n const rowBudget = values.has(\"--row-budget\")\n ? Number(values.get(\"--row-budget\"))\n : undefined;\n const report = await lora.check({\n operations,\n ...(rowBudget !== undefined ? { rowBudget } : {}),\n });\n\n // Plan baseline: the operators of every statement, so a plan change\n // shows up in review.\n const baselinePath = values.get(\"--baseline\");\n const current: Record<string, string[][]> = {};\n for (const p of report.plans) {\n current[`${p.operation} › ${p.field}`] = p.reports.map((r) => r.operators);\n }\n const changed: string[] = [];\n if (baselinePath) {\n let before: Record<string, string[][]> | undefined;\n try {\n before = JSON.parse(await read(baselinePath)) as Record<\n string,\n string[][]\n >;\n } catch {\n before = undefined;\n }\n if (flags.has(\"--update-baseline\") || !before) {\n await writeFile(baselinePath, JSON.stringify(current, null, 2) + \"\\n\");\n } else {\n for (const key of new Set([\n ...Object.keys(before),\n ...Object.keys(current),\n ])) {\n if (JSON.stringify(before[key]) !== JSON.stringify(current[key])) {\n changed.push(key);\n }\n }\n }\n }\n const ok = report.ok && changed.length === 0;\n\n if (json) {\n io.out(JSON.stringify({ ...report, ok, planChanges: changed }, null, 2));\n return ok ? 0 : 1;\n }\n for (const w of report.warnings) io.out(`warning ${formatProblem(w)}`);\n for (const w of report.lint) io.out(`lint ${formatProblem(w)}`);\n for (const u of report.unused) {\n io.out(\n `unused ${u.type} index ${u.name} on :${u.labels.join(\":\")}(${u.properties.join(\", \")})`,\n );\n }\n for (const s of report.security) io.out(`error ${formatProblem(s)}`);\n for (const m of report.missing)\n io.out(`error missing ${describeRequirement(m)}`);\n for (const c of report.cypher)\n io.out(`error ${c.type}.${c.field}: ${c.message}`);\n for (const e of report.errors)\n io.out(`error ${e.operation}: ${e.message}`);\n for (const p of report.plans) {\n for (const r of p.reports) {\n for (const f of r.findings) {\n io.out(`error ${p.operation} › ${p.field}: ${f.message}`);\n }\n for (const n of r.notes) {\n io.out(`lint ${p.operation} › ${p.field}: ${n.message}`);\n }\n }\n }\n for (const key of changed) {\n io.out(\n `error ${key}: the plan differs from the baseline (--update-baseline to accept)`,\n );\n }\n const checked = report.plans.length;\n io.out(\n ok\n ? `ok ${checked} root field(s) in ${operations.length} operation(s) seek as expected`\n : \"failed\",\n );\n return ok ? 0 : 1;\n}\n\n/** Persisted operations from .graphql files (one per operation) or JSON (id → source). */\nasync function persistedOperations(\n paths: string[],\n): Promise<Record<string, string>> {\n const out: Record<string, string> = {};\n for (const path of paths) {\n const info = await stat(path);\n if (info.isFile() && path.endsWith(\".json\")) {\n Object.assign(\n out,\n JSON.parse(await read(path)) as Record<string, string>,\n );\n continue;\n }\n for (const f of await graphqlFiles(path)) {\n const doc = parse(f.source);\n const fragments = new Map(\n doc.definitions\n .filter(\n (d): d is FragmentDefinitionNode =>\n d.kind === Kind.FRAGMENT_DEFINITION,\n )\n .map((d) => [d.name.value, d]),\n );\n const rel = relative(process.cwd(), f.path);\n doc.definitions\n .filter(\n (d): d is OperationDefinitionNode =>\n d.kind === Kind.OPERATION_DEFINITION,\n )\n .forEach((op, i) => {\n const id = `${rel}#${op.name?.value ?? i + 1}`;\n out[id] = printAst({\n kind: Kind.DOCUMENT,\n definitions: [op, ...usedFragments(op, fragments)],\n });\n });\n }\n }\n return out;\n}\n\nasync function compile(\n [file]: string[],\n operationPaths: string[],\n values: Map<string, string>,\n io: Io,\n): Promise<number> {\n if (operationPaths.length === 0) {\n throw new UsageError(\"compile needs --operations <file|dir>\");\n }\n const lora = offline(await read(file!));\n const manifest = lora.buildManifest(\n await persistedOperations(operationPaths),\n );\n const outDir = values.get(\"--out\") ?? \"lora-graphql\";\n await mkdir(outDir, { recursive: true });\n await writeFile(\n join(outDir, \"manifest.json\"),\n JSON.stringify(manifest) + \"\\n\",\n );\n await writeFile(\n join(outDir, \"operations.d.ts\"),\n lora.generateTypes(manifest),\n );\n io.out(\n `wrote ${Object.keys(manifest.operations).length} operation(s) to ${join(outDir, \"manifest.json\")} and ${join(outDir, \"operations.d.ts\")}`,\n );\n return 0;\n}\n\nasync function analyzeCommand(\n [file]: string[],\n values: Map<string, string>,\n io: Io,\n): Promise<number> {\n const databaseDir = values.get(\"--database\");\n if (!databaseDir) throw new UsageError(\"analyze needs --database <dir>\");\n const createDatabase = await nodeBinding(io, \"analyze\");\n if (!createDatabase) return 1;\n const db = await createDatabase(values.get(\"--name\") ?? \"app\", {\n databaseDir,\n });\n const lora = new LoraGraphQL({\n typeDefs: await read(file!),\n driver: loraDriver(db as Parameters<typeof loraDriver>[0]),\n });\n const sample = values.has(\"--sample\")\n ? Number(values.get(\"--sample\"))\n : undefined;\n const stats = await lora.analyze(sample !== undefined ? { sample } : {});\n io.out(JSON.stringify(stats, null, 2));\n (db as { dispose?: () => void }).dispose?.();\n return 0;\n}\n\nasync function graphqlFiles(\n path: string,\n): Promise<Array<{ path: string; source: string }>> {\n const info = await stat(path);\n if (info.isFile()) return [{ path, source: await read(path) }];\n const out: Array<{ path: string; source: string }> = [];\n for (const entry of await readdir(path, { withFileTypes: true })) {\n const full = join(path, entry.name);\n if (entry.isDirectory()) out.push(...(await graphqlFiles(full)));\n else if (/\\.(graphql|gql)$/.test(entry.name)) {\n out.push({ path: full, source: await read(full) });\n }\n }\n return out;\n}\n\n/** Each query in a file, with example values for its required variables. */\nfunction operationsIn(\n schema: GraphQLSchema,\n path: string,\n source: string,\n): NonNullable<CheckOptions[\"operations\"]> {\n const doc = parse(source);\n const fragments = new Map(\n doc.definitions\n .filter(\n (d): d is FragmentDefinitionNode => d.kind === Kind.FRAGMENT_DEFINITION,\n )\n .map((f) => [f.name.value, f]),\n );\n // The fragments an operation spreads, transitively.\n const used = (root: DefinitionNode): FragmentDefinitionNode[] => {\n const seen = new Map<string, FragmentDefinitionNode>();\n const walk = (node: DefinitionNode) =>\n visit(node, {\n FragmentSpread(spread) {\n const f = fragments.get(spread.name.value);\n if (f && !seen.has(f.name.value)) {\n seen.set(f.name.value, f);\n walk(f);\n }\n },\n });\n walk(root);\n return [...seen.values()];\n };\n return doc.definitions\n .filter(\n (d): d is OperationDefinitionNode =>\n d.kind === Kind.OPERATION_DEFINITION && d.operation === \"query\",\n )\n .map((op, i) => {\n const variables: Record<string, unknown> = {};\n for (const v of op.variableDefinitions ?? []) {\n if (v.defaultValue || v.type.kind !== Kind.NON_NULL_TYPE) continue;\n const type = typeFromAST(schema, v.type) as\n | GraphQLInputType\n | undefined;\n if (type) variables[v.variable.name.value] = sample(type);\n }\n return {\n name: `${path}${op.name ? `#${op.name.value}` : `#${i + 1}`}`,\n document: { kind: Kind.DOCUMENT, definitions: [op, ...used(op)] },\n variables,\n };\n });\n}\n\nconst SAMPLES: Record<string, unknown> = {\n String: \"x\",\n ID: \"x\",\n Int: 1,\n Float: 1,\n Boolean: true,\n BigInt: \"1\",\n Date: \"2026-01-01\",\n Time: \"12:00:00Z\",\n LocalTime: \"12:00:00\",\n DateTime: \"2026-01-01T12:00:00Z\",\n LocalDateTime: \"2026-01-01T12:00:00\",\n Duration: \"P1D\",\n};\n\nfunction sample(type: GraphQLInputType): unknown {\n const inner = isNonNullType(type) ? type.ofType : type;\n if (isListType(inner)) return [sample(inner.ofType)];\n const named = getNamedType(inner);\n if (isEnumType(named)) return named.getValues()[0]?.value;\n if (isInputObjectType(named)) {\n const out: Record<string, unknown> = {};\n for (const f of Object.values(named.getFields())) {\n if (isNonNullType(f.type) && f.defaultValue === undefined) {\n out[f.name] = sample(f.type);\n }\n }\n return out;\n }\n return SAMPLES[named.name] ?? \"x\";\n}\n\nconst SDL_FILE = /\\.(graphql|gql)$/;\n\n/** The SDL in `paths` (files, or directories searched recursively), joined. */\nasync function sdlFiles(paths: string[]): Promise<string> {\n const parts: string[] = [];\n for (const path of paths) {\n const files = await graphqlFiles(path);\n files.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));\n parts.push(...files.map((f) => f.source));\n }\n return parts.join(\"\\n\");\n}\n\n/**\n * The SDL in `paths` as of git `ref`, joined in the same order as\n * `sdlFiles`, or undefined when the ref has none of them (a base from\n * before the schema existed). A ref that is not a commit is an error: a\n * gate that silently compared nothing would pass without looking.\n */\nasync function atGitRef(\n ref: string,\n paths: string[],\n): Promise<string | undefined> {\n const git = (cwd: string, ...args: string[]) =>\n execFileSync(\"git\", args, {\n cwd,\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n maxBuffer: 64 * 1024 * 1024,\n });\n const parts: string[] = [];\n let found = false;\n for (const path of paths) {\n // Run git next to the path and name it `./…`, so relative and\n // absolute paths both resolve, from any directory of the repository.\n const isDir = await stat(path).then(\n (s) => s.isDirectory(),\n () => !SDL_FILE.test(path),\n );\n const cwd = isDir ? path : dirname(path);\n try {\n git(cwd, \"rev-parse\", \"--verify\", \"--quiet\", `${ref}^{commit}`);\n } catch {\n throw new Error(\n `diff: ${ref} is not a commit (fetch it, or pass another ref)`,\n );\n }\n if (!isDir) {\n try {\n parts.push(git(cwd, \"show\", `${ref}:./${basename(path)}`));\n found = true;\n } catch {\n // Not in the base: a new file.\n }\n continue;\n }\n // Paths come back relative to `cwd`; none when the directory is not\n // in the base.\n const files = git(cwd, \"ls-tree\", \"-r\", \"--name-only\", ref, \"--\", \".\")\n .split(\"\\n\")\n .filter((f) => SDL_FILE.test(f));\n // Same order as sdlFiles: by path.\n files.sort((a, b) => {\n const pa = join(path, a);\n const pb = join(path, b);\n return pa < pb ? -1 : pa > pb ? 1 : 0;\n });\n for (const f of files) {\n parts.push(git(cwd, \"show\", `${ref}:./${f}`));\n found = true;\n }\n }\n return found ? parts.join(\"\\n\") : undefined;\n}\n\nfunction diff(\n before: string,\n after: string,\n flags: Set<string>,\n io: Io,\n): number {\n const result = diffSchemas(before, after);\n const breaking = result.api.breaking.length > 0;\n const destructive = result.database.statements.some((s) => s.destructive);\n const code =\n (breaking || destructive) && !flags.has(\"--allow-breaking\") ? 1 : 0;\n if (flags.has(\"--json\")) {\n io.out(JSON.stringify(result, null, 2));\n return code;\n }\n io.out(\"# Database\");\n if (result.database.statements.length === 0) io.out(\"no changes\");\n for (const s of result.database.statements) {\n io.out(`${s.destructive ? \"// destructive: \" : \"// \"}${s.reason}`);\n io.out(`${s.text};`);\n }\n io.out(\"\\n# API\");\n if (!breaking && result.api.dangerous.length === 0) io.out(\"no changes\");\n for (const c of result.api.breaking) io.out(`breaking ${c.description}`);\n for (const c of result.api.dangerous) io.out(`dangerous ${c.description}`);\n for (const n of result.notes) io.out(`note ${n}`);\n return code;\n}\n\nconst defaultIo: Io = {\n out: (line) => process.stdout.write(line + \"\\n\"),\n err: (line) => process.stderr.write(line + \"\\n\"),\n};\n\nconst invokedDirectly =\n typeof process !== \"undefined\" &&\n process.argv[1] !== undefined &&\n /lora-graphql(\\.js)?$|cli\\.js$/.test(process.argv[1]);\nif (invokedDirectly) {\n main(process.argv.slice(2)).then((code) => process.exit(code));\n}\n"],"names":["ROOT","UNSUPPORTED","SUFFIX_OPS","NESTED_OPS","migrateNeo4j","sdl","operations","doc","parse","todos","nodeTypes","d","Kind","has","nodeNames","t","usage","observe","out","visit","type","directives","migrateDirectives","directive","ops","enumList","idFields","f","fields","migrateField","print","bool","used","field","at","name","migrateRelationship","renameInList","migrateSubscription","args","a","arg","enumValue","kept","v","events","relationships","e","types","byPlural","defaultPlural","neo4jPlural","byName","note","op","where","value","key","quantifier","rel","x","target","namedTypeOf","suffix","s","fieldName","def","inner","mapped","walk","set","root","sel","mutation","plural","lowerFirst","argumentUse","sorts","collect","k","values","argName","from","to","IRREGULAR","typeName","base","lower","one","many","USAGE","main","argv","io","defaultIo","command","rest","flags","positional","i","VALUE_FLAGS","need","directiveTypeDefs","access","requirements","check","compile","analyzeCommand","file","UsageError","docs","path","graphqlFiles","result","read","paths","before","atGitRef","diff","sdlFiles","after","err","ModelError","n","readFile","offline","typeDefs","driver","LoraGraphQL","json","matrix","rows","widths","r","cell","ddl","model","buildModel","inferRequirements","requirementDdl","describeRequirement","nodeBinding","createDatabase","operationPaths","databaseDir","db","lora","loraDriver","schema","fixtures","contexts","operationsIn","short","given","context","rowBudget","report","baselinePath","current","p","changed","writeFile","ok","w","formatProblem","u","m","c","checked","persistedOperations","stat","fragments","relative","id","printAst","usedFragments","manifest","outDir","mkdir","join","sample","stats","entry","readdir","full","source","seen","node","spread","variables","typeFromAST","SAMPLES","isNonNullType","isListType","named","getNamedType","isEnumType","isInputObjectType","SDL_FILE","parts","files","b","ref","git","cwd","execFileSync","found","isDir","dirname","basename","pa","pb","diffSchemas","breaking","destructive","code","line","invokedDirectly"],"mappings":"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"}
@@ -56,6 +56,24 @@ export declare function propertyAccess(ctx: CompileContext, field: {
56
56
  authenticationJwt?: AuthorizationWhere | undefined;
57
57
  authorization?: Authorization | undefined;
58
58
  }, op: AuthOperation): "allowed" | "forbidden" | "unauthenticated";
59
+ /**
60
+ * Reading a relationship property: as `propertyAccess`, and `"row"` when
61
+ * the claims do not grant it but a rule over the relationship's ends (or
62
+ * the caller's node) may, per relationship: see `propertyReadGuard`.
63
+ */
64
+ export declare function propertyReadAccess(ctx: CompileContext, field: Parameters<typeof propertyAccess>[1]): ReturnType<typeof propertyAccess> | "row";
65
+ /**
66
+ * The per-relationship condition for reading a relationship property
67
+ * whose READ rules test `source`, `target`, `edge` or `viewer`, with the
68
+ * statement's owner-side, target-side and relationship variables of
69
+ * `rel`. Any rule grants. Undefined when the claims alone grant; false
70
+ * when nothing can.
71
+ */
72
+ export declare function propertyReadGuard(ctx: CompileContext, rel: RelationshipField, field: Parameters<typeof propertyAccess>[1], vars: {
73
+ owner: string;
74
+ target: string;
75
+ rel: string;
76
+ }): Expr | false | undefined;
59
77
  /** Throws unless `op` may write (or filter by) the relationship property. */
60
78
  export declare function checkPropertyAccess(ctx: CompileContext, type: string, field: Parameters<typeof propertyAccess>[1] & {
61
79
  name: string;
@@ -85,6 +103,16 @@ export declare function maskedValue(ctx: CompileContext, node: NodeType, field:
85
103
  export declare function maskSettled(ctx: CompileContext, node: NodeType, field: {
86
104
  authorization?: Authorization | undefined;
87
105
  }): boolean;
106
+ /**
107
+ * A masked field's stored `raw` value as the reader may see it, decided by
108
+ * the claims alone (for values no statement can test, such as a node's
109
+ * values before a write): the first mask whose `unless` the claims do not
110
+ * settle true substitutes its value, so a mask that depends on the node
111
+ * reads as masked.
112
+ */
113
+ export declare function claimsMaskedValue(ctx: CompileContext, node: NodeType, field: {
114
+ authorization?: Authorization | undefined;
115
+ }, raw: unknown): unknown;
88
116
  /**
89
117
  * `@key(scope: VIEWER)`: a created key must start with the caller's
90
118
  * `@viewer` claim and the separator. Checked in JavaScript before any
@@ -98,6 +126,27 @@ export declare function checkKeyScope(ctx: CompileContext, node: NodeType, key:
98
126
  * to another field (an opaque subject); null when there is no such node.
99
127
  */
100
128
  viewerKey?: unknown): void;
129
+ /**
130
+ * `$viewer` in a @cypher statement: the caller's node's `@key`. The claim
131
+ * itself when `@viewer` maps to the key; otherwise read in the statement
132
+ * with one seek by the claim, so a statement matching `{key: $viewer}`
133
+ * keeps working when `@viewer` moves to an opaque subject. Null signed
134
+ * out, for a claim that is not a string or number, and for a token
135
+ * naming no node.
136
+ */
137
+ export declare function viewerKey(ctx: CompileContext): Expr;
138
+ /**
139
+ * `@authorization` on a Query or Mutation @cypher field: its validate
140
+ * rules, over claims and the caller's node. Throws UNAUTHENTICATED or
141
+ * FORBIDDEN when the claims alone decide against the request; otherwise
142
+ * the condition left for the database (a `viewer` test), or undefined
143
+ * when the call is allowed.
144
+ */
145
+ export declare function rootFieldGuard(ctx: CompileContext, field: {
146
+ name: string;
147
+ owner: string;
148
+ authorization?: Authorization | undefined;
149
+ }): Expr | undefined;
101
150
  /**
102
151
  * Rules on relationship fields for `op` on relationships of `rel`, with
103
152
  * the statement's owner-side, target-side and relationship variables. The
@@ -5,6 +5,14 @@ import { CompileContext } from './context.js';
5
5
  export declare const COMPILED_PER_FIELD = 16;
6
6
  /** Compiled root fields kept in total, across field nodes. */
7
7
  export declare const COMPILED_TOTAL = 4096;
8
+ /** Default `compileCacheBytes`: the approximate size the cache may reach. */
9
+ export declare const COMPILE_CACHE_BYTES: number;
10
+ /**
11
+ * Requests whose variables key is longer than this are compiled but not
12
+ * cached: a 10 000-item `in:` list or an embedding vector rarely repeats,
13
+ * and would hold its statement's parameters for nothing.
14
+ */
15
+ export declare const MAX_CACHED_VARIABLES: number;
8
16
  type Compile = (jwt: Record<string, unknown> | undefined) => {
9
17
  ctx: CompileContext;
10
18
  compiled: CompiledRead;
@@ -20,8 +28,10 @@ export interface CacheRequest {
20
28
  }
21
29
  export declare class CompileCache {
22
30
  #private;
23
- constructor(total?: number);
31
+ constructor(total?: number, maxBytes?: number);
24
32
  get size(): number;
33
+ /** Approximate bytes the cached entries hold. */
34
+ get bytes(): number;
25
35
  /**
26
36
  * The cached compile for this request, or a fresh one from `compile`
27
37
  * (given a context with `jwt` as the claims), stored for later ones.
@@ -1,3 +1,4 @@
1
+ import { Statistics } from '../analyze/statistics.js';
1
2
  import { GraphModel } from '../model/types.js';
2
3
  import { Expr } from './cypher.js';
3
4
  import { SelectionContext } from './selection.js';
@@ -10,6 +11,8 @@ export interface CompileContext extends SelectionContext {
10
11
  reads: {
11
12
  labels: Set<string>;
12
13
  relationships: Set<string>;
14
+ /** A `@cypher` statement ran: what it reads is unknown. */
15
+ opaque?: boolean;
13
16
  };
14
17
  /** The request's claims, or undefined when unauthenticated. */
15
18
  jwt: Record<string, unknown> | undefined;
@@ -19,6 +22,16 @@ export interface CompileContext extends SelectionContext {
19
22
  cost: number;
20
23
  /** Degree statistics from `analyze()`, by `Owner.field`. */
21
24
  degrees: ReadonlyMap<string, number>;
25
+ /** Node counts and degrees from `analyze()`, for filter costs. */
26
+ statistics?: Statistics | undefined;
27
+ /** Relationship levels one `where` may nest (`maxFilterDepth`). */
28
+ maxFilterDepth?: number | undefined;
29
+ /** Items an `in` filter operand may hold (`maxListFilter`). */
30
+ maxListFilter?: number | undefined;
31
+ /** Characters a string filter operand may hold (`maxStringFilter`). */
32
+ maxStringFilter?: number | undefined;
33
+ /** Relationship levels of the `where` being compiled, so far. */
34
+ filterDepth?: number | undefined;
22
35
  /** The GraphQL context, for `"$context.path"` values in rules. */
23
36
  requestContext: unknown;
24
37
  /**
@@ -41,11 +54,18 @@ export interface CompileContext extends SelectionContext {
41
54
  value: unknown;
42
55
  bound: boolean;
43
56
  }>;
57
+ /** The most items a @cypher list argument takes without `@size(max:)`. */
58
+ maxListArgument?: number | undefined;
44
59
  }
45
60
  export declare function newContext(base: SelectionContext, model: GraphModel, options?: {
46
61
  jwt?: Record<string, unknown> | undefined;
47
62
  degrees?: ReadonlyMap<string, number>;
63
+ statistics?: Statistics | undefined;
48
64
  requestContext?: unknown;
65
+ maxListArgument?: number | undefined;
66
+ maxFilterDepth?: number | undefined;
67
+ maxListFilter?: number | undefined;
68
+ maxStringFilter?: number | undefined;
49
69
  }): CompileContext;
50
70
  /** Record that the compile read the claim at `path` (see `claimReads`). */
51
71
  export declare function noteClaim(ctx: CompileContext, path: string, value: unknown, bound: boolean): void;
@@ -0,0 +1,36 @@
1
+ import { AbstractType, NodeType, RelationshipField } from '../model/types.js';
2
+ import { CompileContext } from './context.js';
3
+ type Where = Record<string, unknown>;
4
+ /** Default `maxFilterDepth`: relationship levels one `where` may nest. */
5
+ export declare const MAX_FILTER_DEPTH = 2;
6
+ /** Default `maxListFilter`: items an `in` filter operand may hold. */
7
+ export declare const MAX_LIST_FILTER = 1000;
8
+ /** Default `maxStringFilter`: characters a string filter operand may hold. */
9
+ export declare const MAX_STRING_FILTER = 10000;
10
+ /** Nodes of the type, from statistics; `fallback` without them. */
11
+ export declare function labelRows(ctx: CompileContext, node: NodeType, fallback: number): number;
12
+ /**
13
+ * Related nodes a filter visits per parent through `rel`: the maximum
14
+ * degree when the caller chose the parents, the mean when they are every
15
+ * node of the label, the declared `@cardinality` or the page size without
16
+ * statistics. A single relationship visits one.
17
+ */
18
+ export declare function filterDegree(ctx: CompileContext, rel: RelationshipField, chosen: boolean): number;
19
+ /**
20
+ * Related nodes the filter visits per candidate row, over every
21
+ * relationship it follows, nested levels multiplied. Scalar predicates
22
+ * add nothing (the row is examined anyway); a computed field adds its
23
+ * statement, once per row.
24
+ */
25
+ export declare function perRowCost(ctx: CompileContext, node: NodeType, where: Where | null | undefined, chosen?: boolean): number;
26
+ /** The part of an interface's or union's `where` one member sees. */
27
+ export declare function memberWhere(abstract: AbstractType, member: string, where: Where | null | undefined): Where | undefined;
28
+ /**
29
+ * The extra cost of a root `where` on `node`: the label scan when no
30
+ * index answers it, plus the related nodes it visits from each candidate.
31
+ * `fallback` stands in for the label's size without statistics.
32
+ */
33
+ export declare function rootFilterCost(ctx: CompileContext, node: NodeType, where: Where | null | undefined, fallback: number,
34
+ /** Every match is read (a count or aggregate), not just a page. */
35
+ all?: boolean): number;
36
+ export {};
@@ -14,6 +14,11 @@ export interface SeekExpectation {
14
14
  export interface ReadSet {
15
15
  labels: string[];
16
16
  relationships: string[];
17
+ /**
18
+ * A `@cypher` statement (or a mutation) is part of the read: it may
19
+ * read anything, so every change affects it.
20
+ */
21
+ opaque?: boolean;
17
22
  }
18
23
  export interface CompiledRead {
19
24
  statements: Statement[];
@@ -81,6 +86,8 @@ export declare function compileByKeys(ctx: CompileContext, node: NodeType, keys:
81
86
  export declare function keyOf(value: unknown): string;
82
87
  /** The statement text with its parameters renamed to bound `$pN`s. */
83
88
  export declare function bindStatement(ctx: CompileContext, field: CypherField, args: Args): string;
89
+ /** Default `maxListArgument`: the most items a @cypher list argument takes. */
90
+ export declare const MAX_LIST_ARGUMENT = 1000;
84
91
  export declare function resolveLimit(value: unknown, limit: PageLimit, argument: string): number;
85
92
  export interface Projection {
86
93
  /** Subqueries that must run before the projection is evaluated. */
@@ -1,9 +1,9 @@
1
1
  import * as w from "graphql";
2
- import { b as $, i as b, r as E, j as N, n as i, k as S } from "./driver-DAtBEMWj.js";
2
+ import { c as $, i as v, r as E, m as N, n as i, o as S } from "./driver-C5dSoSD8.js";
3
3
  function k(t, n, o = {}) {
4
- const s = $(t, o), r = $(n, o), l = N, u = new Map(b(s).map((e) => [l(e), e])), c = new Map(b(r).map((e) => [l(e), e])), p = [...c].filter(([e]) => !u.has(e)).map(([, e]) => e), h = [...u].filter(([e]) => !c.has(e)).map(([, e]) => e), d = [], f = [];
4
+ const s = $(t, o), r = $(n, o), l = N, u = new Map(v(s).map((e) => [l(e), e])), c = new Map(v(r).map((e) => [l(e), e])), p = [...c].filter(([e]) => !u.has(e)).map(([, e]) => e), m = [...u].filter(([e]) => !c.has(e)).map(([, e]) => e), d = [], f = [];
5
5
  C(s, r, d, f);
6
- for (const e of h)
6
+ for (const e of m)
7
7
  d.push({
8
8
  text: `DROP ${e.kind === "constraint" ? "CONSTRAINT" : "INDEX"} \`${e.name.replace(/`/g, "``")}\` IF EXISTS`,
9
9
  destructive: !0,
@@ -16,7 +16,7 @@ function k(t, n, o = {}) {
16
16
  reason: e.reason
17
17
  });
18
18
  const a = M(y(s), y(r));
19
- return { database: { create: p, drop: h, statements: d }, api: a, notes: f };
19
+ return { database: { create: p, drop: m, statements: d }, api: a, notes: f };
20
20
  }
21
21
  function C(t, n, o, s) {
22
22
  for (const [r, l] of t.nodes) {
@@ -33,25 +33,25 @@ function C(t, n, o, s) {
33
33
  destructive: !0,
34
34
  reason: `${r}'s label changed from ${c} to ${p}`
35
35
  });
36
- const h = v(l.fields), d = v(u.fields);
37
- for (const [f, a] of h) {
36
+ const m = b(l.fields), d = b(u.fields);
37
+ for (const [f, a] of m) {
38
38
  const e = d.get(f);
39
39
  if (e && e.property !== a.property && o.push({
40
40
  text: `MATCH (n:${i(p)}) WHERE n.${i(a.property)} IS NOT NULL SET n.${i(e.property)} = n.${i(a.property)} REMOVE n.${i(a.property)}`,
41
41
  destructive: !0,
42
42
  reason: `${r}.${f} now stores \`${e.property}\` instead of \`${a.property}\``
43
43
  }), !e) {
44
- const m = [...d.values()].find(
45
- (g) => g.property === a.property && !h.has(g.name)
44
+ const h = [...d.values()].find(
45
+ (g) => g.property === a.property && !m.has(g.name)
46
46
  );
47
- m && s.push(
48
- `${r}.${f} is now ${r}.${m.name} over the same property \`${a.property}\`: an API break with no data migration`
47
+ h && s.push(
48
+ `${r}.${f} is now ${r}.${h.name} over the same property \`${a.property}\`: an API break with no data migration`
49
49
  );
50
50
  }
51
51
  }
52
52
  }
53
53
  }
54
- function v(t) {
54
+ function b(t) {
55
55
  const n = /* @__PURE__ */ new Map();
56
56
  for (const o of t.values()) o.kind === "scalar" && n.set(o.name, o);
57
57
  return n;
@@ -66,6 +66,7 @@ function y(t) {
66
66
  throw new Error("not connected");
67
67
  },
68
68
  resolveChangedNode: n,
69
+ previousValue: () => null,
69
70
  resolveRoot: n,
70
71
  resolveNode: n,
71
72
  resolveCypher: n,
@@ -96,4 +97,4 @@ function M(t, n) {
96
97
  export {
97
98
  k as d
98
99
  };
99
- //# sourceMappingURL=diff-CcRU-3_p.js.map
100
+ //# sourceMappingURL=diff-B9iDdELF.js.map