cvx-kit 0.1.11 → 0.1.13

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.
Files changed (46) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +1 -0
  3. package/dist/contracts.d.mts +2 -1
  4. package/dist/contracts.mjs +1 -1
  5. package/dist/index.d.mts +2 -1
  6. package/dist/index.mjs +1 -1
  7. package/dist/modules/contracts/binding.d.mts +26 -0
  8. package/dist/modules/contracts/binding.mjs +2 -0
  9. package/dist/modules/contracts/binding.mjs.map +1 -0
  10. package/dist/modules/contracts/domain.d.mts +59 -0
  11. package/dist/modules/contracts/domain.mjs +2 -0
  12. package/dist/modules/contracts/domain.mjs.map +1 -0
  13. package/dist/modules/effect/command.d.mts +39 -1
  14. package/dist/modules/effect/command.mjs +1 -1
  15. package/dist/modules/effect/command.mjs.map +1 -1
  16. package/dist/modules/effect/crud.d.mts +6 -0
  17. package/dist/modules/effect/domain.d.mts +72 -0
  18. package/dist/modules/effect/domain.mjs +2 -0
  19. package/dist/modules/effect/domain.mjs.map +1 -0
  20. package/dist/modules/effect/operation.d.mts +4 -3
  21. package/dist/modules/effect/operation.mjs.map +1 -1
  22. package/dist/modules/effect/query.d.mts +24 -8
  23. package/dist/modules/effect/query.mjs +1 -1
  24. package/dist/modules/effect/query.mjs.map +1 -1
  25. package/dist/modules/foundation/foundation.d.mts +109 -0
  26. package/dist/modules/foundation/foundation.mjs +2 -0
  27. package/dist/modules/foundation/foundation.mjs.map +1 -0
  28. package/dist/modules/foundation/operation.d.mts +140 -0
  29. package/dist/modules/foundation/operation.mjs +2 -0
  30. package/dist/modules/foundation/operation.mjs.map +1 -0
  31. package/dist/oxlint/ownership.mjs +1 -1
  32. package/dist/oxlint/ownership.mjs.map +1 -1
  33. package/dist/oxlint/reserved-files.d.mts +6 -0
  34. package/dist/oxlint/reserved-files.mjs +2 -0
  35. package/dist/oxlint/reserved-files.mjs.map +1 -0
  36. package/dist/oxlint.d.mts +1 -1
  37. package/dist/oxlint.mjs +1 -1
  38. package/dist/oxlint.mjs.map +1 -1
  39. package/docs/commands-legacy.md +3 -1
  40. package/docs/conventions.md +7 -3
  41. package/docs/domain-contracts.md +148 -0
  42. package/docs/effect.md +2 -0
  43. package/docs/oxlint.md +4 -0
  44. package/package.json +1 -1
  45. package/scripts/test-packed-effect.mjs +14 -0
  46. package/scripts/test-packed-oxlint.mjs +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ownership.mjs","names":["ownershipRules","metadata","settings","consumerOptions","context","root","resolve","existsSync","realpathSync","architectureAnchor","issue","inspectArchitecture","file","appFile","reason","componentFacade","standard","flag","node","statement","imported","containsComponentReference","argument","isDbWrite","isExternalCall","delegatingBody","owners","resolver","createResolver","sources","sourceVisitors","typeOnlySource","target","resolveImport","source","path","match","publicNames","exportedNames","declaration","item","isDbAccess","ref","memberPath","rootMember","componentRoot","isFunctionsImport","assembly","role","basename","pure","read","declarative","actionSide","method","propertyName","constructor","binding"],"sources":["../../src/oxlint/ownership.ts"],"sourcesContent":["import { existsSync, realpathSync } from 'node:fs'\nimport { basename, resolve } from 'node:path'\nimport type { CreateRule, ESTree } from '@oxlint/plugins'\nimport {\n\tarchitectureAnchor,\n\tinspectArchitecture,\n\tcreateResolver,\n\tresolveImport,\n} from './architecture'\nimport {\n\tconsumerOptions,\n\tappFile,\n\timported,\n\tsourceVisitors,\n\tisFunctionsImport,\n\ttypeOnlySource,\n\tisDbAccess,\n\tisExternalCall,\n\tcontainsComponentReference,\n\trootMember,\n\tmemberPath,\n\tisDbWrite,\n\tmetadata,\n\tcomponentRoot,\n\tpropertyName,\n\tbinding,\n\texportedNames,\n\tdelegatingBody,\n} from './ast'\n\nexport const ownershipRules = {\n\t'project-structure': {\n\t\tmeta: metadata('Validate the application tree, colocated tests, and module cycles.', {\n\t\t\tstructure: '{{file}}: {{message}}',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tconst settings = consumerOptions.parse(context.options[0] ?? {})\n\t\t\tconst root = resolve(context.cwd, settings.convexDir)\n\t\t\tif (\n\t\t\t\t(existsSync(context.filename)\n\t\t\t\t\t? realpathSync(context.filename)\n\t\t\t\t\t: resolve(context.filename)) !== architectureAnchor(root)\n\t\t\t)\n\t\t\t\treturn {}\n\t\t\treturn {\n\t\t\t\tProgram(node) {\n\t\t\t\t\tfor (const issue of inspectArchitecture({\n\t\t\t\t\t\tcwd: context.cwd,\n\t\t\t\t\t\tconvexDir: settings.convexDir,\n\t\t\t\t\t}))\n\t\t\t\t\t\tcontext.report({\n\t\t\t\t\t\t\tnode,\n\t\t\t\t\t\t\tmessageId: 'structure',\n\t\t\t\t\t\t\tdata: { file: issue.file, message: issue.message },\n\t\t\t\t\t\t})\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'root-wiring-only': {\n\t\tmeta: metadata('Keep root files limited to configuration, assembly, and component facades.', {\n\t\t\townership:\n\t\t\t\t'Root files only wire configuration and components. Move behavior into domain/<module>/: {{reason}}.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tconst file = appFile(context)\n\t\t\tif (!file || file.includes('/')) return {}\n\t\t\tlet issue: ESTree.Node | null = null\n\t\t\tlet reason = 'business implementation'\n\t\t\tlet componentFacade = false\n\t\t\tconst standard =\n\t\t\t\t/^(?:convex\\.config|auth\\.config|vite\\.config|vitest\\.config|auth|schema|functions|triggers|foundation|http|crons)\\.[cm]?[jt]s$/.test(\n\t\t\t\t\tfile,\n\t\t\t\t)\n\t\t\tfunction flag(node: ESTree.Node) {\n\t\t\t\tissue ??= node\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tProgram(node) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tnode.body.some(\n\t\t\t\t\t\t\t(statement) =>\n\t\t\t\t\t\t\t\tstatement.type === 'FunctionDeclaration' ||\n\t\t\t\t\t\t\t\t(statement.type === 'ExportNamedDeclaration' &&\n\t\t\t\t\t\t\t\t\tstatement.declaration?.type === 'FunctionDeclaration'),\n\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t\t\tflag(node)\n\t\t\t\t},\n\t\t\t\tNewExpression(node) {\n\t\t\t\t\tif (\n\t\t\t\t\t\timported(context, node.callee) &&\n\t\t\t\t\t\tnode.arguments.some((argument) => containsComponentReference(context, argument))\n\t\t\t\t\t)\n\t\t\t\t\t\tcomponentFacade = true\n\t\t\t\t},\n\t\t\t\tCallExpression(node) {\n\t\t\t\t\tif (\n\t\t\t\t\t\timported(context, node.callee) &&\n\t\t\t\t\t\tnode.arguments.some((argument) => containsComponentReference(context, argument))\n\t\t\t\t\t)\n\t\t\t\t\t\tcomponentFacade = true\n\t\t\t\t\tif (\n\t\t\t\t\t\tisDbWrite(node) ||\n\t\t\t\t\t\tisExternalCall(context, node) ||\n\t\t\t\t\t\t(file === 'schema.ts' && !(imported(context, node.callee)?.name === 'defineSchema'))\n\t\t\t\t\t)\n\t\t\t\t\t\tflag(node)\n\t\t\t\t},\n\t\t\t\tArrowFunctionExpression(node) {\n\t\t\t\t\tif (!node.body || !delegatingBody(node.body)) flag(node)\n\t\t\t\t},\n\t\t\t\tFunctionExpression(node) {\n\t\t\t\t\tif (!node.body || !delegatingBody(node.body)) flag(node)\n\t\t\t\t},\n\t\t\t\tIfStatement: flag,\n\t\t\t\tSwitchStatement: flag,\n\t\t\t\tConditionalExpression: flag,\n\t\t\t\tForStatement: flag,\n\t\t\t\tForOfStatement: flag,\n\t\t\t\tWhileStatement: flag,\n\t\t\t\t'Program:exit'(node) {\n\t\t\t\t\tif (!standard && !componentFacade) {\n\t\t\t\t\t\tissue = node\n\t\t\t\t\t\treason = 'unknown root file; only declared component facades may add root source files'\n\t\t\t\t\t}\n\t\t\t\t\tif (issue) context.report({ node: issue, messageId: 'ownership', data: { reason } })\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'application-orchestration': {\n\t\tmeta: metadata('Reserve application/ for thin cross-domain coordination.', {\n\t\t\townership:\n\t\t\t\t'application/ only coordinates two or more domains. Move schemas, providers, storage access, helpers, and business decisions into their owning domain.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tif (!appFile(context)?.startsWith('application/')) return {}\n\t\t\tconst owners = new Set<string>()\n\t\t\tconst resolver = createResolver()\n\t\t\tlet issue: ESTree.Node | null = null\n\t\t\tfunction flag(node: ESTree.Node) {\n\t\t\t\tissue ??= node\n\t\t\t}\n\t\t\tconst sources = sourceVisitors(context, (node, source) => {\n\t\t\t\tif (typeOnlySource(node)) return\n\t\t\t\tconst target = resolveImport(resolver, context.filename, source)\n\t\t\t\tconst path = target && appFile(context, target)\n\t\t\t\tconst match = path?.match(/^domain\\/([^/]+)\\/(?:commands|queries|rules)(?:\\.[cm]?[jt]s)?$/)\n\t\t\t\tif (match && match[1] !== 'shared') owners.add(match[1])\n\t\t\t\tif (path?.startsWith('domain/') && !match && !path.startsWith('domain/shared/')) flag(node)\n\t\t\t\tif (\n\t\t\t\t\t!path &&\n\t\t\t\t\t![\n\t\t\t\t\t\t'cvx-kit',\n\t\t\t\t\t\t'cvx-kit/components/foundation',\n\t\t\t\t\t\t'@convex-dev/workflow',\n\t\t\t\t\t\t'convex/values',\n\t\t\t\t\t].includes(source)\n\t\t\t\t)\n\t\t\t\t\tflag(node)\n\t\t\t})\n\t\t\treturn {\n\t\t\t\t...sources,\n\t\t\t\tProgram(node) {\n\t\t\t\t\tconst publicNames = exportedNames(node)\n\t\t\t\t\tfor (const statement of node.body) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tstatement.type === 'FunctionDeclaration' &&\n\t\t\t\t\t\t\tstatement.id &&\n\t\t\t\t\t\t\t!publicNames.has(statement.id.name)\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\tflag(statement)\n\t\t\t\t\t\tconst declaration =\n\t\t\t\t\t\t\tstatement.type === 'ExportNamedDeclaration' ? statement.declaration : statement\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tdeclaration?.type === 'TSTypeAliasDeclaration' ||\n\t\t\t\t\t\t\tdeclaration?.type === 'TSInterfaceDeclaration'\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\tflag(statement)\n\t\t\t\t\t\tif (declaration?.type === 'VariableDeclaration')\n\t\t\t\t\t\t\tfor (const item of declaration.declarations) {\n\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\titem.init &&\n\t\t\t\t\t\t\t\t\t['ObjectExpression', 'ArrayExpression', 'Literal'].includes(item.init.type)\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\tflag(item)\n\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\tstatement.type === 'VariableDeclaration' &&\n\t\t\t\t\t\t\t\t\titem.id.type === 'Identifier' &&\n\t\t\t\t\t\t\t\t\t!publicNames.has(item.id.name) &&\n\t\t\t\t\t\t\t\t\t['ArrowFunctionExpression', 'FunctionExpression'].includes(item.init?.type ?? '')\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\tflag(item)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tCallExpression(node) {\n\t\t\t\t\tsources.CallExpression?.(node)\n\t\t\t\t\tif (isDbAccess(node) || isExternalCall(context, node)) flag(node)\n\t\t\t\t\tconst ref = imported(context, node.callee)\n\t\t\t\t\tif (ref && ['zod', 'zod/v4'].includes(ref.source)) flag(node)\n\t\t\t\t},\n\t\t\t\tMemberExpression(node) {\n\t\t\t\t\tconst path = memberPath(node)\n\t\t\t\t\tif (path.length >= 4 && path[1] === 'domain') {\n\t\t\t\t\t\tconst ref = imported(context, rootMember(node))\n\t\t\t\t\t\tif (ref?.name === 'internal' && /_generated\\/api/.test(ref.source)) owners.add(path[2])\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tNewExpression: flag,\n\t\t\t\tIfStatement: flag,\n\t\t\t\tSwitchStatement: flag,\n\t\t\t\tConditionalExpression: flag,\n\t\t\t\t'Program:exit'(node) {\n\t\t\t\t\tif (owners.size < 2 || issue)\n\t\t\t\t\t\tcontext.report({ node: issue ?? node, messageId: 'ownership' })\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'internal-function-ownership': {\n\t\tmeta: metadata('Place internal handlers with their owner, never in root, api/, or shared/.', {\n\t\t\townership:\n\t\t\t\t'Declare system/internal handlers in domain/<module>/, cross-domain application/, migrations/, or an isolated component.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tconst file = appFile(context) ?? ''\n\t\t\tif (\n\t\t\t\tcomponentRoot(context, context.filename) ||\n\t\t\t\t/^(?:domain\\/(?!shared\\/)[^/]+\\/|application\\/|migrations\\/)/.test(file)\n\t\t\t)\n\t\t\t\treturn {}\n\t\t\treturn {\n\t\t\t\tCallExpression(node) {\n\t\t\t\t\tif (node.callee.type === 'CallExpression') return\n\t\t\t\t\tconst ref = imported(context, node.callee)\n\t\t\t\t\tif (\n\t\t\t\t\t\tref &&\n\t\t\t\t\t\t((isFunctionsImport(context, ref.source) &&\n\t\t\t\t\t\t\t/^system(Query|Mutation|Action)$/.test(ref.name)) ||\n\t\t\t\t\t\t\t(/(?:_generated\\/server|convex\\/server)/.test(ref.source) &&\n\t\t\t\t\t\t\t\t/^internal(Query|Mutation|Action)(Generic)?$/.test(ref.name)))\n\t\t\t\t\t)\n\t\t\t\t\t\tcontext.report({ node, messageId: 'ownership' })\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'domain-file-responsibilities': {\n\t\tmeta: metadata(\n\t\t\t'Keep invariants pure, reads read-only, shapes declarative, and I/O action-side.',\n\t\t\t{\n\t\t\t\townership:\n\t\t\t\t\t'Respect this domain file responsibility: pure rules, read-only queries, declarative schemas/tables/constants, and external I/O only in actions or integrations.',\n\t\t\t},\n\t\t),\n\t\tcreate(context) {\n\t\t\tconst file = appFile(context) ?? ''\n\t\t\tconst assembly = file === 'domain/table.ts'\n\t\t\tif (!assembly && !/^domain\\/[^/]+\\//.test(file)) return {}\n\t\t\tconst role = basename(file).replace(/\\.[cm]?[jt]s$/, '')\n\t\t\tconst pure = role === 'rules'\n\t\t\tconst read = role === 'queries'\n\t\t\tconst declarative = ['schema', 'table', 'constants'].includes(role)\n\t\t\tconst actionSide =\n\t\t\t\t/(?:^|\\/)(?:actions|integrations|providers)(?:\\/|\\.)/.test(file) ||\n\t\t\t\t/(?:^|_)actions\\./.test(file)\n\t\t\tconst resolver = createResolver()\n\t\t\tlet issue: ESTree.Node | null = null\n\t\t\tfunction flag(node: ESTree.Node) {\n\t\t\t\tissue ??= node\n\t\t\t}\n\t\t\tconst sources = sourceVisitors(context, (node, source) => {\n\t\t\t\tif (typeOnlySource(node)) return\n\t\t\t\tconst target = resolveImport(resolver, context.filename, source)\n\t\t\t\tconst path = target && appFile(context, target)\n\t\t\t\tif (\n\t\t\t\t\tassembly &&\n\t\t\t\t\tsource !== 'cvx-kit/zod-table' &&\n\t\t\t\t\t!/^domain\\/[^/]+\\/table(?:\\.[cm]?[jt]s)?$/.test(path ?? '')\n\t\t\t\t)\n\t\t\t\t\tflag(node)\n\t\t\t\tif (pure && path && !/(?:^|\\/)(?:rules|constants)(?:\\.[cm]?[jt]s)?$/.test(path)) flag(node)\n\t\t\t\tif (\n\t\t\t\t\t(pure || read || declarative) &&\n\t\t\t\t\t!path &&\n\t\t\t\t\t![\n\t\t\t\t\t\t'zod',\n\t\t\t\t\t\t'zod/v4',\n\t\t\t\t\t\t'convex/values',\n\t\t\t\t\t\t'cvx-kit',\n\t\t\t\t\t\t'cvx-kit/zod-table',\n\t\t\t\t\t\t'cvx-kit/errors',\n\t\t\t\t\t].includes(source)\n\t\t\t\t)\n\t\t\t\t\tflag(node)\n\t\t\t\tif (\n\t\t\t\t\tread &&\n\t\t\t\t\tpath &&\n\t\t\t\t\t/(?:^|\\/)(?:commands|actions|integrations|providers)(?:[./]|$)/.test(path)\n\t\t\t\t)\n\t\t\t\t\tflag(node)\n\t\t\t})\n\t\t\treturn {\n\t\t\t\t...sources,\n\t\t\t\tProgram(node) {\n\t\t\t\t\tif (!assembly) return\n\t\t\t\t\tfor (const statement of node.body) {\n\t\t\t\t\t\tif (statement.type === 'ImportDeclaration' || statement.type === 'EmptyStatement')\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\tconst declaration =\n\t\t\t\t\t\t\tstatement.type === 'ExportNamedDeclaration' ? statement.declaration : statement\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tdeclaration?.type !== 'VariableDeclaration' ||\n\t\t\t\t\t\t\tdeclaration.declarations.some((item) => item.init?.type !== 'CallExpression')\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\tflag(statement)\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tCallExpression(node) {\n\t\t\t\t\tsources.CallExpression?.(node)\n\t\t\t\t\tif (assembly) {\n\t\t\t\t\t\tconst ref = imported(context, node.callee)\n\t\t\t\t\t\tif (ref?.source !== 'cvx-kit/zod-table' || ref.name !== 'createModule') flag(node)\n\t\t\t\t\t}\n\t\t\t\t\tconst method = node.callee.type === 'MemberExpression' ? propertyName(node.callee) : null\n\t\t\t\t\tif (\n\t\t\t\t\t\t(pure || declarative) &&\n\t\t\t\t\t\t(isDbAccess(node) ||\n\t\t\t\t\t\t\t['runQuery', 'runMutation', 'runAction', 'runAfter', 'runAt'].includes(method ?? ''))\n\t\t\t\t\t)\n\t\t\t\t\t\tflag(node)\n\t\t\t\t\tif (\n\t\t\t\t\t\tread &&\n\t\t\t\t\t\t(isDbWrite(node) ||\n\t\t\t\t\t\t\t['runMutation', 'runAction', 'runAfter', 'runAt'].includes(method ?? ''))\n\t\t\t\t\t)\n\t\t\t\t\t\tflag(node)\n\t\t\t\t\tconst constructor = imported(context, node.callee)\n\t\t\t\t\tif (\n\t\t\t\t\t\tconstructor &&\n\t\t\t\t\t\tisFunctionsImport(context, constructor.source) &&\n\t\t\t\t\t\t(pure || declarative || (read && /(?:Mutation|Action)$/.test(constructor.name)))\n\t\t\t\t\t)\n\t\t\t\t\t\tflag(node)\n\t\t\t\t\tif (\n\t\t\t\t\t\tread &&\n\t\t\t\t\t\tnode.callee.type === 'MemberExpression' &&\n\t\t\t\t\t\tpropertyName(node.callee.object) === 'storage' &&\n\t\t\t\t\t\t['store', 'delete', 'generateUploadUrl'].includes(method ?? '')\n\t\t\t\t\t)\n\t\t\t\t\t\tflag(node)\n\t\t\t\t\tif (!actionSide && isExternalCall(context, node)) flag(node)\n\t\t\t\t\tif (\n\t\t\t\t\t\tpure &&\n\t\t\t\t\t\tnode.callee.type === 'MemberExpression' &&\n\t\t\t\t\t\tnode.callee.object.type === 'Identifier' &&\n\t\t\t\t\t\t!binding(context, node.callee.object)?.defs.length &&\n\t\t\t\t\t\t((node.callee.object.name === 'Date' && method === 'now') ||\n\t\t\t\t\t\t\t(node.callee.object.name === 'Math' && method === 'random'))\n\t\t\t\t\t)\n\t\t\t\t\t\tflag(node)\n\t\t\t\t},\n\t\t\t\tMemberExpression(node) {\n\t\t\t\t\tif (pure && ['db', 'storage', 'scheduler', 'env'].includes(propertyName(node) ?? ''))\n\t\t\t\t\t\tflag(node)\n\t\t\t\t},\n\t\t\t\tNewExpression(node) {\n\t\t\t\t\tif (!(pure || read || declarative)) return\n\t\t\t\t\tif (\n\t\t\t\t\t\tnode.callee.type === 'Identifier' &&\n\t\t\t\t\t\t!binding(context, node.callee)?.defs.length &&\n\t\t\t\t\t\t['Error', 'TypeError', 'RangeError', 'Set', 'Map', 'RegExp'].includes(node.callee.name)\n\t\t\t\t\t)\n\t\t\t\t\t\treturn\n\t\t\t\t\tflag(node)\n\t\t\t\t},\n\t\t\t\t'Program:exit'() {\n\t\t\t\t\tif (issue) context.report({ node: issue, messageId: 'ownership' })\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n} satisfies Record<string, CreateRule>\n\nexport type OwnershipRuleName = keyof typeof ownershipRules\n"],"mappings":"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"}
1
+ {"version":3,"file":"ownership.mjs","names":["ownershipRules","metadata","settings","consumerOptions","context","root","resolve","existsSync","realpathSync","architectureAnchor","issue","inspectArchitecture","file","appFile","reason","componentFacade","standard","flag","node","statement","imported","containsComponentReference","argument","isDbWrite","isExternalCall","delegatingBody","owners","resolver","createResolver","sources","sourceVisitors","typeOnlySource","target","resolveImport","source","path","match","publicNames","exportedNames","declaration","item","isDbAccess","ref","memberPath","rootMember","componentRoot","isFunctionsImport","assembly","role","basename","pure","read","declarative","actionSide","method","propertyName","constructor","binding"],"sources":["../../src/oxlint/ownership.ts"],"sourcesContent":["import { existsSync, realpathSync } from 'node:fs'\nimport { basename, resolve } from 'node:path'\nimport type { CreateRule, ESTree } from '@oxlint/plugins'\nimport {\n\tarchitectureAnchor,\n\tinspectArchitecture,\n\tcreateResolver,\n\tresolveImport,\n} from './architecture'\nimport {\n\tconsumerOptions,\n\tappFile,\n\timported,\n\tsourceVisitors,\n\tisFunctionsImport,\n\ttypeOnlySource,\n\tisDbAccess,\n\tisExternalCall,\n\tcontainsComponentReference,\n\trootMember,\n\tmemberPath,\n\tisDbWrite,\n\tmetadata,\n\tcomponentRoot,\n\tpropertyName,\n\tbinding,\n\texportedNames,\n\tdelegatingBody,\n} from './ast'\n\nexport const ownershipRules = {\n\t'project-structure': {\n\t\tmeta: metadata('Validate the application tree, colocated tests, and module cycles.', {\n\t\t\tstructure: '{{file}}: {{message}}',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tconst settings = consumerOptions.parse(context.options[0] ?? {})\n\t\t\tconst root = resolve(context.cwd, settings.convexDir)\n\t\t\tif (\n\t\t\t\t(existsSync(context.filename)\n\t\t\t\t\t? realpathSync(context.filename)\n\t\t\t\t\t: resolve(context.filename)) !== architectureAnchor(root)\n\t\t\t)\n\t\t\t\treturn {}\n\t\t\treturn {\n\t\t\t\tProgram(node) {\n\t\t\t\t\tfor (const issue of inspectArchitecture({\n\t\t\t\t\t\tcwd: context.cwd,\n\t\t\t\t\t\tconvexDir: settings.convexDir,\n\t\t\t\t\t}))\n\t\t\t\t\t\tcontext.report({\n\t\t\t\t\t\t\tnode,\n\t\t\t\t\t\t\tmessageId: 'structure',\n\t\t\t\t\t\t\tdata: { file: issue.file, message: issue.message },\n\t\t\t\t\t\t})\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'root-wiring-only': {\n\t\tmeta: metadata('Keep root files limited to configuration, assembly, and component facades.', {\n\t\t\townership:\n\t\t\t\t'Root files only wire configuration and components. Move behavior into domain/<module>/: {{reason}}.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tconst file = appFile(context)\n\t\t\tif (!file || file.includes('/')) return {}\n\t\t\tlet issue: ESTree.Node | null = null\n\t\t\tlet reason = 'business implementation'\n\t\t\tlet componentFacade = false\n\t\t\tconst standard =\n\t\t\t\t/^(?:convex\\.config|auth\\.config|vite\\.config|vitest\\.config|auth|schema|functions|triggers|foundation|http|crons)\\.[cm]?[jt]s$/.test(\n\t\t\t\t\tfile,\n\t\t\t\t)\n\t\t\tfunction flag(node: ESTree.Node) {\n\t\t\t\tissue ??= node\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tProgram(node) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tnode.body.some(\n\t\t\t\t\t\t\t(statement) =>\n\t\t\t\t\t\t\t\tstatement.type === 'FunctionDeclaration' ||\n\t\t\t\t\t\t\t\t(statement.type === 'ExportNamedDeclaration' &&\n\t\t\t\t\t\t\t\t\tstatement.declaration?.type === 'FunctionDeclaration'),\n\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t\t\tflag(node)\n\t\t\t\t},\n\t\t\t\tNewExpression(node) {\n\t\t\t\t\tif (\n\t\t\t\t\t\timported(context, node.callee) &&\n\t\t\t\t\t\tnode.arguments.some((argument) => containsComponentReference(context, argument))\n\t\t\t\t\t)\n\t\t\t\t\t\tcomponentFacade = true\n\t\t\t\t},\n\t\t\t\tCallExpression(node) {\n\t\t\t\t\tif (\n\t\t\t\t\t\timported(context, node.callee) &&\n\t\t\t\t\t\tnode.arguments.some((argument) => containsComponentReference(context, argument))\n\t\t\t\t\t)\n\t\t\t\t\t\tcomponentFacade = true\n\t\t\t\t\tif (\n\t\t\t\t\t\tisDbWrite(node) ||\n\t\t\t\t\t\tisExternalCall(context, node) ||\n\t\t\t\t\t\t(file === 'schema.ts' && !(imported(context, node.callee)?.name === 'defineSchema'))\n\t\t\t\t\t)\n\t\t\t\t\t\tflag(node)\n\t\t\t\t},\n\t\t\t\tArrowFunctionExpression(node) {\n\t\t\t\t\tif (!node.body || !delegatingBody(node.body)) flag(node)\n\t\t\t\t},\n\t\t\t\tFunctionExpression(node) {\n\t\t\t\t\tif (!node.body || !delegatingBody(node.body)) flag(node)\n\t\t\t\t},\n\t\t\t\tIfStatement: flag,\n\t\t\t\tSwitchStatement: flag,\n\t\t\t\tConditionalExpression: flag,\n\t\t\t\tForStatement: flag,\n\t\t\t\tForOfStatement: flag,\n\t\t\t\tWhileStatement: flag,\n\t\t\t\t'Program:exit'(node) {\n\t\t\t\t\tif (!standard && !componentFacade) {\n\t\t\t\t\t\tissue = node\n\t\t\t\t\t\treason = 'unknown root file; only declared component facades may add root source files'\n\t\t\t\t\t}\n\t\t\t\t\tif (issue) context.report({ node: issue, messageId: 'ownership', data: { reason } })\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'application-orchestration': {\n\t\tmeta: metadata('Reserve application/ for thin cross-domain coordination.', {\n\t\t\townership:\n\t\t\t\t'application/ only coordinates two or more domains. Move schemas, providers, storage access, helpers, and business decisions into their owning domain.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tif (!appFile(context)?.startsWith('application/')) return {}\n\t\t\tconst owners = new Set<string>()\n\t\t\tconst resolver = createResolver()\n\t\t\tlet issue: ESTree.Node | null = null\n\t\t\tfunction flag(node: ESTree.Node) {\n\t\t\t\tissue ??= node\n\t\t\t}\n\t\t\tconst sources = sourceVisitors(context, (node, source) => {\n\t\t\t\tif (typeOnlySource(node)) return\n\t\t\t\tconst target = resolveImport(resolver, context.filename, source)\n\t\t\t\tconst path = target && appFile(context, target)\n\t\t\t\tconst match = path?.match(/^domain\\/([^/]+)\\/(?:commands|queries|rules)(?:\\.[cm]?[jt]s)?$/)\n\t\t\t\tif (match && match[1] !== 'shared') owners.add(match[1])\n\t\t\t\tif (path?.startsWith('domain/') && !match && !path.startsWith('domain/shared/')) flag(node)\n\t\t\t\tif (\n\t\t\t\t\t!path &&\n\t\t\t\t\t![\n\t\t\t\t\t\t'cvx-kit',\n\t\t\t\t\t\t'cvx-kit/components/foundation',\n\t\t\t\t\t\t'@convex-dev/workflow',\n\t\t\t\t\t\t'convex/values',\n\t\t\t\t\t].includes(source)\n\t\t\t\t)\n\t\t\t\t\tflag(node)\n\t\t\t})\n\t\t\treturn {\n\t\t\t\t...sources,\n\t\t\t\tProgram(node) {\n\t\t\t\t\tconst publicNames = exportedNames(node)\n\t\t\t\t\tfor (const statement of node.body) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tstatement.type === 'FunctionDeclaration' &&\n\t\t\t\t\t\t\tstatement.id &&\n\t\t\t\t\t\t\t!publicNames.has(statement.id.name)\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\tflag(statement)\n\t\t\t\t\t\tconst declaration =\n\t\t\t\t\t\t\tstatement.type === 'ExportNamedDeclaration' ? statement.declaration : statement\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tdeclaration?.type === 'TSTypeAliasDeclaration' ||\n\t\t\t\t\t\t\tdeclaration?.type === 'TSInterfaceDeclaration'\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\tflag(statement)\n\t\t\t\t\t\tif (declaration?.type === 'VariableDeclaration')\n\t\t\t\t\t\t\tfor (const item of declaration.declarations) {\n\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\titem.init &&\n\t\t\t\t\t\t\t\t\t['ObjectExpression', 'ArrayExpression', 'Literal'].includes(item.init.type)\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\tflag(item)\n\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\tstatement.type === 'VariableDeclaration' &&\n\t\t\t\t\t\t\t\t\titem.id.type === 'Identifier' &&\n\t\t\t\t\t\t\t\t\t!publicNames.has(item.id.name) &&\n\t\t\t\t\t\t\t\t\t['ArrowFunctionExpression', 'FunctionExpression'].includes(item.init?.type ?? '')\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\tflag(item)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tCallExpression(node) {\n\t\t\t\t\tsources.CallExpression?.(node)\n\t\t\t\t\tif (isDbAccess(node) || isExternalCall(context, node)) flag(node)\n\t\t\t\t\tconst ref = imported(context, node.callee)\n\t\t\t\t\tif (ref && ['zod', 'zod/v4'].includes(ref.source)) flag(node)\n\t\t\t\t},\n\t\t\t\tMemberExpression(node) {\n\t\t\t\t\tconst path = memberPath(node)\n\t\t\t\t\tif (path.length >= 4 && path[1] === 'domain') {\n\t\t\t\t\t\tconst ref = imported(context, rootMember(node))\n\t\t\t\t\t\tif (ref?.name === 'internal' && /_generated\\/api/.test(ref.source)) owners.add(path[2])\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tNewExpression: flag,\n\t\t\t\tIfStatement: flag,\n\t\t\t\tSwitchStatement: flag,\n\t\t\t\tConditionalExpression: flag,\n\t\t\t\t'Program:exit'(node) {\n\t\t\t\t\tif (owners.size < 2 || issue)\n\t\t\t\t\t\tcontext.report({ node: issue ?? node, messageId: 'ownership' })\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'internal-function-ownership': {\n\t\tmeta: metadata('Place internal handlers with their owner, never in root, api/, or shared/.', {\n\t\t\townership:\n\t\t\t\t'Declare system/internal handlers in domain/<module>/, cross-domain application/, migrations/, or an isolated component.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tconst file = appFile(context) ?? ''\n\t\t\tif (\n\t\t\t\tcomponentRoot(context, context.filename) ||\n\t\t\t\t/^(?:domain\\/(?!shared\\/)[^/]+\\/|application\\/|migrations\\/)/.test(file)\n\t\t\t)\n\t\t\t\treturn {}\n\t\t\treturn {\n\t\t\t\tCallExpression(node) {\n\t\t\t\t\tif (node.callee.type === 'CallExpression') return\n\t\t\t\t\tconst ref = imported(context, node.callee)\n\t\t\t\t\tif (\n\t\t\t\t\t\tref &&\n\t\t\t\t\t\t((isFunctionsImport(context, ref.source) &&\n\t\t\t\t\t\t\t/^system(Query|Mutation|Action)$/.test(ref.name)) ||\n\t\t\t\t\t\t\t(/(?:_generated\\/server|convex\\/server)/.test(ref.source) &&\n\t\t\t\t\t\t\t\t/^internal(Query|Mutation|Action)(Generic)?$/.test(ref.name)))\n\t\t\t\t\t)\n\t\t\t\t\t\tcontext.report({ node, messageId: 'ownership' })\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'domain-file-responsibilities': {\n\t\tmeta: metadata(\n\t\t\t'Keep invariants pure, reads read-only, shapes declarative, and I/O action-side.',\n\t\t\t{\n\t\t\t\townership:\n\t\t\t\t\t'Respect this domain file responsibility: pure rules, read-only queries, declarative schemas/tables/constants, and external I/O only in actions or integrations.',\n\t\t\t},\n\t\t),\n\t\tcreate(context) {\n\t\t\tconst file = appFile(context) ?? ''\n\t\t\tconst assembly = file === 'domain/table.ts'\n\t\t\tif (!assembly && !/^domain\\/[^/]+\\//.test(file)) return {}\n\t\t\tconst role = basename(file).replace(/\\.[cm]?[jt]s$/, '')\n\t\t\tconst pure = role === 'rules'\n\t\t\tconst read = role === 'queries'\n\t\t\tconst declarative = ['schema', 'table', 'contracts', 'constants'].includes(role)\n\t\t\tconst actionSide =\n\t\t\t\t/(?:^|\\/)(?:actions|integrations|providers)(?:\\/|\\.)/.test(file) ||\n\t\t\t\t/(?:^|_)actions\\./.test(file)\n\t\t\tconst resolver = createResolver()\n\t\t\tlet issue: ESTree.Node | null = null\n\t\t\tfunction flag(node: ESTree.Node) {\n\t\t\t\tissue ??= node\n\t\t\t}\n\t\t\tconst sources = sourceVisitors(context, (node, source) => {\n\t\t\t\tif (typeOnlySource(node)) return\n\t\t\t\tconst target = resolveImport(resolver, context.filename, source)\n\t\t\t\tconst path = target && appFile(context, target)\n\t\t\t\tif (\n\t\t\t\t\tassembly &&\n\t\t\t\t\tsource !== 'cvx-kit/zod-table' &&\n\t\t\t\t\t!/^domain\\/[^/]+\\/table(?:\\.[cm]?[jt]s)?$/.test(path ?? '')\n\t\t\t\t)\n\t\t\t\t\tflag(node)\n\t\t\t\tif (pure && path && !/(?:^|\\/)(?:rules|constants)(?:\\.[cm]?[jt]s)?$/.test(path)) flag(node)\n\t\t\t\tif (\n\t\t\t\t\t(pure || read || declarative) &&\n\t\t\t\t\t!path &&\n\t\t\t\t\t![\n\t\t\t\t\t\t'zod',\n\t\t\t\t\t\t'zod/v4',\n\t\t\t\t\t\t'convex/values',\n\t\t\t\t\t\t'cvx-kit',\n\t\t\t\t\t\t'cvx-kit/zod-table',\n\t\t\t\t\t\t'cvx-kit/errors',\n\t\t\t\t\t\t'cvx-kit/contracts',\n\t\t\t\t\t].includes(source)\n\t\t\t\t)\n\t\t\t\t\tflag(node)\n\t\t\t\tif (\n\t\t\t\t\tread &&\n\t\t\t\t\tpath &&\n\t\t\t\t\t/(?:^|\\/)(?:commands|actions|integrations|providers)(?:[./]|$)/.test(path)\n\t\t\t\t)\n\t\t\t\t\tflag(node)\n\t\t\t})\n\t\t\treturn {\n\t\t\t\t...sources,\n\t\t\t\tProgram(node) {\n\t\t\t\t\tif (!assembly) return\n\t\t\t\t\tfor (const statement of node.body) {\n\t\t\t\t\t\tif (statement.type === 'ImportDeclaration' || statement.type === 'EmptyStatement')\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\tconst declaration =\n\t\t\t\t\t\t\tstatement.type === 'ExportNamedDeclaration' ? statement.declaration : statement\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tdeclaration?.type !== 'VariableDeclaration' ||\n\t\t\t\t\t\t\tdeclaration.declarations.some((item) => item.init?.type !== 'CallExpression')\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\tflag(statement)\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tCallExpression(node) {\n\t\t\t\t\tsources.CallExpression?.(node)\n\t\t\t\t\tif (assembly) {\n\t\t\t\t\t\tconst ref = imported(context, node.callee)\n\t\t\t\t\t\tif (ref?.source !== 'cvx-kit/zod-table' || ref.name !== 'createModule') flag(node)\n\t\t\t\t\t}\n\t\t\t\t\tconst method = node.callee.type === 'MemberExpression' ? propertyName(node.callee) : null\n\t\t\t\t\tif (\n\t\t\t\t\t\t(pure || declarative) &&\n\t\t\t\t\t\t(isDbAccess(node) ||\n\t\t\t\t\t\t\t['runQuery', 'runMutation', 'runAction', 'runAfter', 'runAt'].includes(method ?? ''))\n\t\t\t\t\t)\n\t\t\t\t\t\tflag(node)\n\t\t\t\t\tif (\n\t\t\t\t\t\tread &&\n\t\t\t\t\t\t(isDbWrite(node) ||\n\t\t\t\t\t\t\t['runMutation', 'runAction', 'runAfter', 'runAt'].includes(method ?? ''))\n\t\t\t\t\t)\n\t\t\t\t\t\tflag(node)\n\t\t\t\t\tconst constructor = imported(context, node.callee)\n\t\t\t\t\tif (\n\t\t\t\t\t\tconstructor &&\n\t\t\t\t\t\tisFunctionsImport(context, constructor.source) &&\n\t\t\t\t\t\t(pure || declarative || (read && /(?:Mutation|Action)$/.test(constructor.name)))\n\t\t\t\t\t)\n\t\t\t\t\t\tflag(node)\n\t\t\t\t\tif (\n\t\t\t\t\t\tread &&\n\t\t\t\t\t\tnode.callee.type === 'MemberExpression' &&\n\t\t\t\t\t\tpropertyName(node.callee.object) === 'storage' &&\n\t\t\t\t\t\t['store', 'delete', 'generateUploadUrl'].includes(method ?? '')\n\t\t\t\t\t)\n\t\t\t\t\t\tflag(node)\n\t\t\t\t\tif (!actionSide && isExternalCall(context, node)) flag(node)\n\t\t\t\t\tif (\n\t\t\t\t\t\tpure &&\n\t\t\t\t\t\tnode.callee.type === 'MemberExpression' &&\n\t\t\t\t\t\tnode.callee.object.type === 'Identifier' &&\n\t\t\t\t\t\t!binding(context, node.callee.object)?.defs.length &&\n\t\t\t\t\t\t((node.callee.object.name === 'Date' && method === 'now') ||\n\t\t\t\t\t\t\t(node.callee.object.name === 'Math' && method === 'random'))\n\t\t\t\t\t)\n\t\t\t\t\t\tflag(node)\n\t\t\t\t},\n\t\t\t\tProperty(node) {\n\t\t\t\t\tif (\n\t\t\t\t\t\trole === 'contracts' &&\n\t\t\t\t\t\t['handler', 'context', 'audit', 'prepare', 'middleware', 'guard'].includes(\n\t\t\t\t\t\t\tnode.key.type === 'Identifier'\n\t\t\t\t\t\t\t\t? node.key.name\n\t\t\t\t\t\t\t\t: String(node.key.type === 'Literal' ? node.key.value : ''),\n\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t\t\tflag(node)\n\t\t\t\t},\n\t\t\t\tMemberExpression(node) {\n\t\t\t\t\tif (pure && ['db', 'storage', 'scheduler', 'env'].includes(propertyName(node) ?? ''))\n\t\t\t\t\t\tflag(node)\n\t\t\t\t},\n\t\t\t\tNewExpression(node) {\n\t\t\t\t\tif (!(pure || read || declarative)) return\n\t\t\t\t\tif (\n\t\t\t\t\t\tnode.callee.type === 'Identifier' &&\n\t\t\t\t\t\t!binding(context, node.callee)?.defs.length &&\n\t\t\t\t\t\t['Error', 'TypeError', 'RangeError', 'Set', 'Map', 'RegExp'].includes(node.callee.name)\n\t\t\t\t\t)\n\t\t\t\t\t\treturn\n\t\t\t\t\tflag(node)\n\t\t\t\t},\n\t\t\t\t'Program:exit'() {\n\t\t\t\t\tif (issue) context.report({ node: issue, messageId: 'ownership' })\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n} satisfies Record<string, CreateRule>\n\nexport type OwnershipRuleName = keyof typeof ownershipRules\n"],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { CreateRule } from "@oxlint/plugins";
2
+ //#region src/oxlint/reserved-files.d.ts
3
+ /** Reserved files prove their exported declaration's provenance, not an unused import. */
4
+ export declare const reservedDomainFiles: CreateRule;
5
+ //#endregion
6
+ //# sourceMappingURL=reserved-files.d.mts.map
@@ -0,0 +1,2 @@
1
+ import{createResolver as e,resolveImport as t}from"./architecture.mjs";import{appFile as n,exportName as r,metadata as i,propertyName as a}from"./ast.mjs";import{readFileSync as o}from"node:fs";import{parseSync as s}from"oxc-parser";const c={meta:i(`Require kit-backed declarations in reserved domain files.`,{anatomy:`{{file}} must export {{expected}} built with cvx-kit; imports or local lookalikes do not count.`}),create(e){let t=n(e)??``,r=t.match(/^domain\/(?:.+\/)?(commands|queries|contracts|schema|table)\.ts$/);if(!r)return{};let i=r[1];return{Program(n){let r=u(e,n,e.filename),a=l(n).map(e=>r(e)),o=i===`commands`?`one Command registry`:i===`queries`?`one Query registry`:i===`schema`?`zodTable shapes`:i===`contracts`?`declarative contracts`:t===`domain/table.ts`?`createModule assembly`:`a table topology map`,s=i===`commands`?`registry:Command`:i===`queries`?`registry:Query`:i===`schema`?`shape`:i===`contracts`?`contract`:t===`domain/table.ts`?`assembly`:`topology`,c=a.filter(e=>e===s).length;(i===`commands`||i===`queries`?c===1:c>0)||e.report({node:n,messageId:`anatomy`,data:{file:t,expected:o}})}}}};function l(e){let t=[],n=/* @__PURE__ */ new Map;for(let r of e.body){let e=r.type===`ExportNamedDeclaration`?r.declaration:r;if(e?.type===`VariableDeclaration`&&e.kind===`const`)for(let i of e.declarations)i.id.type===`Identifier`&&i.init&&(n.set(i.id.name,i.init),r.type===`ExportNamedDeclaration`&&t.push(i.init))}for(let i of e.body){if(i.type===`ExportNamedDeclaration`&&i.exportKind!==`type`&&!i.source)for(let e of i.specifiers){if(e.exportKind===`type`)continue;let i=n.get(r(e.local)??``);i&&t.push(i)}i.type===`ExportDefaultDeclaration`&&i.declaration.type!==`FunctionDeclaration`&&i.declaration.type!==`ClassDeclaration`&&i.declaration.type!==`TSInterfaceDeclaration`&&t.push(i.declaration)}return t}function u(i,c,l,d=/* @__PURE__ */ new Set){let f=/* @__PURE__ */ new Map,p=/* @__PURE__ */ new Map,m=e();for(let e of c.body){if(e.type===`ImportDeclaration`&&e.importKind!==`type`)for(let t of e.specifiers)(t.type!==`ImportSpecifier`||t.importKind!==`type`)&&f.set(t.local.name,{source:e.source.value,name:t.type===`ImportSpecifier`?r(t.imported)??``:t.type===`ImportNamespaceSpecifier`?`*`:`default`});let t=e.type===`ExportNamedDeclaration`?e.declaration:e;if(t?.type===`VariableDeclaration`&&t.kind===`const`){for(let e of t.declarations)if(e.init&&(e.id.type===`Identifier`&&p.set(e.id.name,{expression:e.init}),e.id.type===`ObjectPattern`))for(let t of e.id.properties)t.type===`Property`&&t.value.type===`Identifier`&&p.set(t.value.name,{expression:e.init,member:r(t.key)??``})}}function h(e,a){if([`cvx-kit`,`cvx-kit/effect`,`cvx-kit/components/foundation`,`cvx-kit/contracts`,`cvx-kit/zod-table`,`cvx-kit/errors`].includes(e))return a===`*`?`namespace:${e}`:e===`cvx-kit/effect`&&a===`createEffectFoundation`||e===`cvx-kit`&&a===`createFoundation`||[`cvx-kit`,`cvx-kit/components/foundation`].includes(e)&&a===`Foundation`?`foundationFactory`:[`cvx-kit`,`cvx-kit/zod-table`].includes(e)&&[`zodTable`,`zodVariantTable`].includes(a)?`shapeFactory`:[`cvx-kit`,`cvx-kit/zod-table`].includes(e)&&a===`createModule`?`assemblyFactory`:e===`cvx-kit/contracts`&&[`defineDomainContract`,`operationContract`].includes(a)||e===`cvx-kit/errors`&&a===`defineErrorContract`?`contractFactory`:null;if([`zod`,`zod/v4`,`convex/values`].includes(e))return`validator`;let c=t(m,l,e),f=c&&n(i,c);if(!c||!f||!/^(?:foundation\.ts|domain\/.+\/(?:schema|contracts)\.ts)$/.test(f)||d.has(c)||d.size>=6)return null;if(a===`*`)return`namespace:${e}`;let p=s(c,o(c,`utf8`));if(p.errors.length)return null;let h=p.program,g=u(i,h,c,new Set(d).add(c));for(let e of h.body)if(e.type===`ExportNamedDeclaration`&&e.exportKind!==`type`){if(e.declaration?.type===`VariableDeclaration`)for(let t of e.declaration.declarations){if(t.id.type===`Identifier`&&t.id.name===a)return g(t.id);if(t.id.type===`ObjectPattern`){for(let e of t.id.properties)if(e.type===`Property`&&e.value.type===`Identifier`&&e.value.name===a)return g(e.value)}}for(let t of e.specifiers)if(t.exportKind!==`type`&&r(t.exported)===a&&!e.source)return g(t.local)}return null}function g(e,t){return e===`foundation`&&[`Command`,`Query`].includes(t)?t:e?.startsWith(`namespace:`)?h(e.slice(10),t):e===`validator`||e===`contract`?`validator`:e===`shape`&&t===`table`?`table`:e===`table`&&[`index`,`searchIndex`,`vectorIndex`].includes(t)?`indexFactory`:null}function _(e,t=/* @__PURE__ */ new Set){if(e.type===`TSAsExpression`||e.type===`TSSatisfiesExpression`||e.type===`TSNonNullExpression`)return _(e.expression,t);if(e.type===`Identifier`){if(t.has(e.name))return null;let n=f.get(e.name);if(n)return h(n.source,n.name);let r=p.get(e.name);if(!r)return null;let i=_(r.expression,new Set(t).add(e.name));return r.member?g(i,r.member):i}if(e.type===`MemberExpression`)return g(_(e.object,t),a(e)??``);if(e.type===`CallExpression`||e.type===`NewExpression`){let n=_(e.callee,t);return n===`foundationFactory`?`foundation`:n===`Command`||n===`Query`?`registry:${n}`:n===`shapeFactory`?`shape`:n===`assemblyFactory`?`assembly`:n===`contractFactory`||n===`validator`?`contract`:n===`indexFactory`?`table`:null}if(e.type===`ObjectExpression`){let n=e.properties.map(e=>e.type===`Property`?_(e.value,t):null);if(n.length&&n.every(e=>e===`table`||e===`topology`))return`topology`;if(n.some(e=>e===`contract`||e===`validator`)&&n.every(e=>e===`contract`||e===`validator`||e===`data`))return`contract`;if(n.every(e=>e===`data`))return`data`}return e.type===`Literal`?`data`:null}return _}export{c as reservedDomainFiles};
2
+ //# sourceMappingURL=reserved-files.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reserved-files.mjs","names":["reservedDomainFiles","metadata","file","appFile","context","match","role","evaluate","provenance","program","values","publicExpressions","expression","expected","wanted","count","value","expressions","declarations","statement","declaration","item","specifier","exportName","imports","variables","resolver","createResolver","property","imported","source","name","target","resolveImport","filename","visited","parsed","parseSync","readFileSync","remote","evaluateRemote","member","owner","node","active","reference","variable","propertyName","callee"],"sources":["../../src/oxlint/reserved-files.ts"],"sourcesContent":["import { readFileSync } from 'node:fs'\nimport type { Context, CreateRule, ESTree } from '@oxlint/plugins'\nimport { parseSync } from 'oxc-parser'\nimport { appFile, metadata, propertyName, exportName } from './ast'\nimport { createResolver, resolveImport } from './architecture'\n\n/** Reserved files prove their exported declaration's provenance, not an unused import. */\nexport const reservedDomainFiles: CreateRule = {\n\tmeta: metadata('Require kit-backed declarations in reserved domain files.', {\n\t\tanatomy:\n\t\t\t'{{file}} must export {{expected}} built with cvx-kit; imports or local lookalikes do not count.',\n\t}),\n\tcreate(context) {\n\t\tconst file = appFile(context) ?? ''\n\t\tconst match = file.match(/^domain\\/(?:.+\\/)?(commands|queries|contracts|schema|table)\\.ts$/)\n\t\tif (!match) return {}\n\t\tconst role = match[1]\n\t\treturn {\n\t\t\tProgram(program) {\n\t\t\t\tconst evaluate = provenance(context, program, context.filename)\n\t\t\t\tconst exports = publicExpressions(program)\n\t\t\t\tconst values = exports.map((expression) => evaluate(expression))\n\t\t\t\tconst expected =\n\t\t\t\t\trole === 'commands'\n\t\t\t\t\t\t? 'one Command registry'\n\t\t\t\t\t\t: role === 'queries'\n\t\t\t\t\t\t\t? 'one Query registry'\n\t\t\t\t\t\t\t: role === 'schema'\n\t\t\t\t\t\t\t\t? 'zodTable shapes'\n\t\t\t\t\t\t\t\t: role === 'contracts'\n\t\t\t\t\t\t\t\t\t? 'declarative contracts'\n\t\t\t\t\t\t\t\t\t: file === 'domain/table.ts'\n\t\t\t\t\t\t\t\t\t\t? 'createModule assembly'\n\t\t\t\t\t\t\t\t\t\t: 'a table topology map'\n\t\t\t\tconst wanted =\n\t\t\t\t\trole === 'commands'\n\t\t\t\t\t\t? 'registry:Command'\n\t\t\t\t\t\t: role === 'queries'\n\t\t\t\t\t\t\t? 'registry:Query'\n\t\t\t\t\t\t\t: role === 'schema'\n\t\t\t\t\t\t\t\t? 'shape'\n\t\t\t\t\t\t\t\t: role === 'contracts'\n\t\t\t\t\t\t\t\t\t? 'contract'\n\t\t\t\t\t\t\t\t\t: file === 'domain/table.ts'\n\t\t\t\t\t\t\t\t\t\t? 'assembly'\n\t\t\t\t\t\t\t\t\t\t: 'topology'\n\t\t\t\tconst count = values.filter((value) => value === wanted).length\n\t\t\t\tconst valid = role === 'commands' || role === 'queries' ? count === 1 : count > 0\n\t\t\t\tif (!valid)\n\t\t\t\t\tcontext.report({ node: program, messageId: 'anatomy', data: { file, expected } })\n\t\t\t},\n\t\t}\n\t},\n}\n\nfunction publicExpressions(program: ESTree.Program): ESTree.Expression[] {\n\tconst expressions: ESTree.Expression[] = []\n\tconst declarations = new Map<string, ESTree.Expression>()\n\tfor (const statement of program.body) {\n\t\tconst declaration =\n\t\t\tstatement.type === 'ExportNamedDeclaration' ? statement.declaration : statement\n\t\tif (declaration?.type === 'VariableDeclaration' && declaration.kind === 'const')\n\t\t\tfor (const item of declaration.declarations) {\n\t\t\t\tif (item.id.type === 'Identifier' && item.init) {\n\t\t\t\t\tdeclarations.set(item.id.name, item.init)\n\t\t\t\t\tif (statement.type === 'ExportNamedDeclaration') expressions.push(item.init)\n\t\t\t\t}\n\t\t\t}\n\t}\n\tfor (const statement of program.body) {\n\t\tif (\n\t\t\tstatement.type === 'ExportNamedDeclaration' &&\n\t\t\tstatement.exportKind !== 'type' &&\n\t\t\t!statement.source\n\t\t)\n\t\t\tfor (const specifier of statement.specifiers) {\n\t\t\t\tif (specifier.exportKind === 'type') continue\n\t\t\t\tconst expression = declarations.get(exportName(specifier.local) ?? '')\n\t\t\t\tif (expression) expressions.push(expression)\n\t\t\t}\n\t\tif (\n\t\t\tstatement.type === 'ExportDefaultDeclaration' &&\n\t\t\tstatement.declaration.type !== 'FunctionDeclaration' &&\n\t\t\tstatement.declaration.type !== 'ClassDeclaration' &&\n\t\t\tstatement.declaration.type !== 'TSInterfaceDeclaration'\n\t\t) {\n\t\t\texpressions.push(statement.declaration)\n\t\t}\n\t}\n\treturn expressions\n}\n\nfunction provenance(\n\tcontext: Context,\n\tprogram: ESTree.Program,\n\tfilename: string,\n\tvisited = new Set<string>(),\n) {\n\tconst imports = new Map<string, { source: string; name: string }>()\n\tconst variables = new Map<string, { expression: ESTree.Expression; member?: string }>()\n\tconst resolver = createResolver()\n\tfor (const statement of program.body) {\n\t\tif (statement.type === 'ImportDeclaration' && statement.importKind !== 'type')\n\t\t\tfor (const specifier of statement.specifiers) {\n\t\t\t\tif (specifier.type === 'ImportSpecifier' && specifier.importKind === 'type') continue\n\t\t\t\timports.set(specifier.local.name, {\n\t\t\t\t\tsource: statement.source.value,\n\t\t\t\t\tname:\n\t\t\t\t\t\tspecifier.type === 'ImportSpecifier'\n\t\t\t\t\t\t\t? (exportName(specifier.imported) ?? '')\n\t\t\t\t\t\t\t: specifier.type === 'ImportNamespaceSpecifier'\n\t\t\t\t\t\t\t\t? '*'\n\t\t\t\t\t\t\t\t: 'default',\n\t\t\t\t})\n\t\t\t}\n\t\tconst declaration =\n\t\t\tstatement.type === 'ExportNamedDeclaration' ? statement.declaration : statement\n\t\tif (declaration?.type === 'VariableDeclaration' && declaration.kind === 'const')\n\t\t\tfor (const item of declaration.declarations) {\n\t\t\t\tif (!item.init) continue\n\t\t\t\tif (item.id.type === 'Identifier') variables.set(item.id.name, { expression: item.init })\n\t\t\t\tif (item.id.type === 'ObjectPattern')\n\t\t\t\t\tfor (const property of item.id.properties) {\n\t\t\t\t\t\tif (property.type === 'Property' && property.value.type === 'Identifier')\n\t\t\t\t\t\t\tvariables.set(property.value.name, {\n\t\t\t\t\t\t\t\texpression: item.init,\n\t\t\t\t\t\t\t\tmember: exportName(property.key) ?? '',\n\t\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t}\n\t}\n\tfunction imported(source: string, name: string): string | null {\n\t\tif (\n\t\t\t[\n\t\t\t\t'cvx-kit',\n\t\t\t\t'cvx-kit/effect',\n\t\t\t\t'cvx-kit/components/foundation',\n\t\t\t\t'cvx-kit/contracts',\n\t\t\t\t'cvx-kit/zod-table',\n\t\t\t\t'cvx-kit/errors',\n\t\t\t].includes(source)\n\t\t) {\n\t\t\tif (name === '*') return `namespace:${source}`\n\t\t\tif (\n\t\t\t\t(source === 'cvx-kit/effect' && name === 'createEffectFoundation') ||\n\t\t\t\t(source === 'cvx-kit' && name === 'createFoundation') ||\n\t\t\t\t(['cvx-kit', 'cvx-kit/components/foundation'].includes(source) && name === 'Foundation')\n\t\t\t)\n\t\t\t\treturn 'foundationFactory'\n\t\t\tif (\n\t\t\t\t['cvx-kit', 'cvx-kit/zod-table'].includes(source) &&\n\t\t\t\t['zodTable', 'zodVariantTable'].includes(name)\n\t\t\t)\n\t\t\t\treturn 'shapeFactory'\n\t\t\tif (['cvx-kit', 'cvx-kit/zod-table'].includes(source) && name === 'createModule')\n\t\t\t\treturn 'assemblyFactory'\n\t\t\tif (\n\t\t\t\tsource === 'cvx-kit/contracts' &&\n\t\t\t\t['defineDomainContract', 'operationContract'].includes(name)\n\t\t\t)\n\t\t\t\treturn 'contractFactory'\n\t\t\tif (source === 'cvx-kit/errors' && name === 'defineErrorContract') return 'contractFactory'\n\t\t\treturn null\n\t\t}\n\t\tif (['zod', 'zod/v4', 'convex/values'].includes(source)) return 'validator'\n\t\tconst target = resolveImport(resolver, filename, source)\n\t\tconst file = target && appFile(context, target)\n\t\tif (\n\t\t\t!target ||\n\t\t\t!file ||\n\t\t\t!/^(?:foundation\\.ts|domain\\/.+\\/(?:schema|contracts)\\.ts)$/.test(file) ||\n\t\t\tvisited.has(target) ||\n\t\t\tvisited.size >= 6\n\t\t)\n\t\t\treturn null\n\t\tif (name === '*') return `namespace:${source}`\n\t\tconst parsed = parseSync(target, readFileSync(target, 'utf8'))\n\t\tif (parsed.errors.length) return null\n\t\t// SAFETY: oxc-parser and the rule API share these declaration fields; provenance never reads rule-API loc/tokens.\n\t\t// oxlint-disable-next-line anti-slop/no-chained-type-assertions\n\t\tconst remote = parsed.program as unknown as ESTree.Program\n\t\tconst nextVisited = new Set(visited).add(target)\n\t\tconst evaluateRemote = provenance(context, remote, target, nextVisited)\n\t\tfor (const statement of remote.body) {\n\t\t\tif (statement.type !== 'ExportNamedDeclaration' || statement.exportKind === 'type') continue\n\t\t\tif (statement.declaration?.type === 'VariableDeclaration')\n\t\t\t\tfor (const item of statement.declaration.declarations) {\n\t\t\t\t\tif (item.id.type === 'Identifier' && item.id.name === name) return evaluateRemote(item.id)\n\t\t\t\t\tif (item.id.type === 'ObjectPattern')\n\t\t\t\t\t\tfor (const property of item.id.properties)\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tproperty.type === 'Property' &&\n\t\t\t\t\t\t\t\tproperty.value.type === 'Identifier' &&\n\t\t\t\t\t\t\t\tproperty.value.name === name\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\treturn evaluateRemote(property.value)\n\t\t\t\t}\n\t\t\tfor (const specifier of statement.specifiers)\n\t\t\t\tif (\n\t\t\t\t\tspecifier.exportKind !== 'type' &&\n\t\t\t\t\texportName(specifier.exported) === name &&\n\t\t\t\t\t!statement.source\n\t\t\t\t)\n\t\t\t\t\treturn evaluateRemote(specifier.local)\n\t\t}\n\t\treturn null\n\t}\n\tfunction member(owner: string | null, name: string): string | null {\n\t\tif (owner === 'foundation' && ['Command', 'Query'].includes(name)) return name\n\t\tif (owner?.startsWith('namespace:')) return imported(owner.slice(10), name)\n\t\tif (owner === 'validator' || owner === 'contract') return 'validator'\n\t\tif (owner === 'shape' && name === 'table') return 'table'\n\t\tif (owner === 'table' && ['index', 'searchIndex', 'vectorIndex'].includes(name))\n\t\t\treturn 'indexFactory'\n\t\treturn null\n\t}\n\tfunction evaluate(node: ESTree.Node, active = new Set<string>()): string | null {\n\t\tif (\n\t\t\tnode.type === 'TSAsExpression' ||\n\t\t\tnode.type === 'TSSatisfiesExpression' ||\n\t\t\tnode.type === 'TSNonNullExpression'\n\t\t)\n\t\t\treturn evaluate(node.expression, active)\n\t\tif (node.type === 'Identifier') {\n\t\t\tif (active.has(node.name)) return null\n\t\t\tconst reference = imports.get(node.name)\n\t\t\tif (reference) return imported(reference.source, reference.name)\n\t\t\tconst variable = variables.get(node.name)\n\t\t\tif (!variable) return null\n\t\t\tconst value = evaluate(variable.expression, new Set(active).add(node.name))\n\t\t\treturn variable.member ? member(value, variable.member) : value\n\t\t}\n\t\tif (node.type === 'MemberExpression')\n\t\t\treturn member(evaluate(node.object, active), propertyName(node) ?? '')\n\t\tif (node.type === 'CallExpression' || node.type === 'NewExpression') {\n\t\t\tconst callee = evaluate(node.callee, active)\n\t\t\tif (callee === 'foundationFactory') return 'foundation'\n\t\t\tif (callee === 'Command' || callee === 'Query') return `registry:${callee}`\n\t\t\tif (callee === 'shapeFactory') return 'shape'\n\t\t\tif (callee === 'assemblyFactory') return 'assembly'\n\t\t\tif (callee === 'contractFactory' || callee === 'validator') return 'contract'\n\t\t\tif (callee === 'indexFactory') return 'table'\n\t\t\treturn null\n\t\t}\n\t\tif (node.type === 'ObjectExpression') {\n\t\t\tconst values = node.properties.map((property) =>\n\t\t\t\tproperty.type === 'Property' ? evaluate(property.value, active) : null,\n\t\t\t)\n\t\t\tif (values.length && values.every((value) => value === 'table' || value === 'topology'))\n\t\t\t\treturn 'topology'\n\t\t\tif (\n\t\t\t\tvalues.some((value) => value === 'contract' || value === 'validator') &&\n\t\t\t\tvalues.every((value) => value === 'contract' || value === 'validator' || value === 'data')\n\t\t\t)\n\t\t\t\treturn 'contract'\n\t\t\tif (values.every((value) => value === 'data')) return 'data'\n\t\t}\n\t\tif (node.type === 'Literal') return 'data'\n\t\treturn null\n\t}\n\treturn evaluate\n}\n"],"mappings":"yOAOA,MAAaA,EAAkC,CAC9C,KAAMC,EAAS,4DAA6D,CAC3E,QACC,iGACF,CAAC,EACD,OAAO,EAAS,CACf,IAAMC,EAAOC,EAAQC,CAAO,GAAK,GAC3BC,EAAQH,EAAK,MAAM,kEAAkE,EAC3F,GAAI,CAACG,EAAO,MAAO,CAAC,EACpB,IAAMC,EAAOD,EAAM,GACnB,MAAO,CACN,QAAQ,EAAS,CAChB,IAAME,EAAWC,EAAWJ,EAASK,EAASL,EAAQ,QAAQ,EAExDM,EADUC,EAAkBF,CACb,CAAC,CAAC,IAAK,GAAeF,EAASK,CAAU,CAAC,EACzDC,EACLP,IAAS,WACN,uBACAA,IAAS,UACR,qBACAA,IAAS,SACR,kBACAA,IAAS,YACR,wBACAJ,IAAS,kBACR,wBACA,uBACFY,EACLR,IAAS,WACN,mBACAA,IAAS,UACR,iBACAA,IAAS,SACR,QACAA,IAAS,YACR,WACAJ,IAAS,kBACR,WACA,WACFa,EAAQL,EAAO,OAAQ,GAAUM,IAAUF,CAAM,CAAC,CAAC,QAC3CR,IAAS,YAAcA,IAAS,UAAYS,IAAU,EAAIA,EAAQ,IAE/EX,EAAQ,OAAO,CAAE,KAAMK,EAAS,UAAW,UAAW,KAAM,CAAE,OAAM,UAAS,CAAE,CAAC,CAClF,CACD,CACD,CACD,EAEA,SAASE,EAAkB,EAA8C,CACxE,IAAMM,EAAmC,CAAC,EACpCC,kBAAe,IAAI,IACzB,IAAK,IAAMC,KAAaV,EAAQ,KAAM,CACrC,IAAMW,EACLD,EAAU,OAAS,yBAA2BA,EAAU,YAAcA,EACvE,GAAIC,GAAa,OAAS,uBAAyBA,EAAY,OAAS,QAClE,IAAA,IAAMC,KAAQD,EAAY,aAC1BC,EAAK,GAAG,OAAS,cAAgBA,EAAK,OACzCH,EAAa,IAAIG,EAAK,GAAG,KAAMA,EAAK,IAAI,EACpCF,EAAU,OAAS,0BAA0BF,EAAY,KAAKI,EAAK,IAAI,EAG/E,CACA,IAAK,IAAMF,KAAaV,EAAQ,KAAM,CACrC,GACCU,EAAU,OAAS,0BACnBA,EAAU,aAAe,QACzB,CAACA,EAAU,OAEX,IAAK,IAAMG,KAAaH,EAAU,WAAY,CAC7C,GAAIG,EAAU,aAAe,OAAQ,SACrC,IAAMV,EAAaM,EAAa,IAAIK,EAAWD,EAAU,KAAK,GAAK,EAAE,EACjEV,GAAYK,EAAY,KAAKL,CAAU,CAC5C,CAEAO,EAAU,OAAS,4BACnBA,EAAU,YAAY,OAAS,uBAC/BA,EAAU,YAAY,OAAS,oBAC/BA,EAAU,YAAY,OAAS,0BAE/BF,EAAY,KAAKE,EAAU,WAAW,CAExC,CACA,OAAOF,CACR,CAEA,SAAST,EACR,EACA,EACA,EACA,kBAAU,IAAI,IACb,CACD,IAAMgB,kBAAU,IAAI,IACdC,kBAAY,IAAI,IAChBC,EAAWC,EAAe,EAChC,IAAK,IAAMR,KAAaV,EAAQ,KAAM,CACrC,GAAIU,EAAU,OAAS,qBAAuBA,EAAU,aAAe,OACtE,IAAK,IAAMG,KAAaH,EAAU,YAC7BG,EAAU,OAAS,mBAAqBA,EAAU,aAAe,SACrEE,EAAQ,IAAIF,EAAU,MAAM,KAAM,CACjC,OAAQH,EAAU,OAAO,MACzB,KACCG,EAAU,OAAS,kBACfC,EAAWD,EAAU,QAAQ,GAAK,GACnCA,EAAU,OAAS,2BAClB,IACA,SACN,CAAC,EAEH,IAAMF,EACLD,EAAU,OAAS,yBAA2BA,EAAU,YAAcA,EACvE,GAAIC,GAAa,OAAS,uBAAyBA,EAAY,OAAS,QACvE,KAAK,IAAMC,KAAQD,EAAY,aAC9B,GAAKC,EAAK,OACNA,EAAK,GAAG,OAAS,cAAcI,EAAU,IAAIJ,EAAK,GAAG,KAAM,CAAE,WAAYA,EAAK,IAAK,CAAC,EACpFA,EAAK,GAAG,OAAS,iBACf,IAAA,IAAMO,KAAYP,EAAK,GAAG,WAC1BO,EAAS,OAAS,YAAcA,EAAS,MAAM,OAAS,cAC3DH,EAAU,IAAIG,EAAS,MAAM,KAAM,CAClC,WAAYP,EAAK,KACjB,OAAQE,EAAWK,EAAS,GAAG,GAAK,EACrC,CAAC,CAEL,CACF,CACA,SAASC,EAAS,EAAgB,EAA6B,CAC9D,GACC,CACC,UACA,iBACA,gCACA,oBACA,oBACA,gBACD,CAAC,CAAC,SAASC,CAAM,EAsBjB,OApBIC,IAAS,IAAY,aAAaD,IAEpCA,IAAW,kBAAoBC,IAAS,0BACxCD,IAAW,WAAaC,IAAS,oBACjC,CAAC,UAAW,+BAA+B,CAAC,CAAC,SAASD,CAAM,GAAKC,IAAS,aAEpE,oBAEP,CAAC,UAAW,mBAAmB,CAAC,CAAC,SAASD,CAAM,GAChD,CAAC,WAAY,iBAAiB,CAAC,CAAC,SAASC,CAAI,EAEtC,eACJ,CAAC,UAAW,mBAAmB,CAAC,CAAC,SAASD,CAAM,GAAKC,IAAS,eAC1D,kBAEPD,IAAW,qBACX,CAAC,uBAAwB,mBAAmB,CAAC,CAAC,SAASC,CAAI,GAGxDD,IAAW,kBAAoBC,IAAS,sBAA8B,kBACnE,KAER,GAAI,CAAC,MAAO,SAAU,eAAe,CAAC,CAAC,SAASD,CAAM,EAAG,MAAO,YAChE,IAAME,EAASC,EAAcP,EAAUQ,EAAUJ,CAAM,EACjD5B,EAAO8B,GAAU7B,EAAQC,EAAS4B,CAAM,EAC9C,GACC,CAACA,GACD,CAAC9B,GACD,CAAC,4DAA4D,KAAKA,CAAI,GACtEiC,EAAQ,IAAIH,CAAM,GAClBG,EAAQ,MAAQ,EAEhB,OAAO,KACR,GAAIJ,IAAS,IAAK,MAAO,aAAaD,IACtC,IAAMM,EAASC,EAAUL,EAAQM,EAAaN,EAAQ,MAAM,CAAC,EAC7D,GAAII,EAAO,OAAO,OAAQ,OAAO,KAGjC,IAAMG,EAASH,EAAO,QAEhBI,EAAiBhC,EAAWJ,EAASmC,EAAQP,EAD/B,IAAI,IAAIG,CAAO,CAAC,CAAC,IAAIH,CAC4B,CAAC,EACtE,IAAK,IAAMb,KAAaoB,EAAO,KAC9B,GAAIpB,EAAU,OAAS,0BAA4BA,EAAU,aAAe,OAC5E,IAAIA,EAAU,aAAa,OAAS,sBACnC,IAAK,IAAME,KAAQF,EAAU,YAAY,aAAc,CACtD,GAAIE,EAAK,GAAG,OAAS,cAAgBA,EAAK,GAAG,OAASU,EAAM,OAAOS,EAAenB,EAAK,EAAE,EACzF,GAAIA,EAAK,GAAG,OAAS,gBACf,KAAA,IAAMO,KAAYP,EAAK,GAAG,WAC9B,GACCO,EAAS,OAAS,YAClBA,EAAS,MAAM,OAAS,cACxBA,EAAS,MAAM,OAASG,EAExB,OAAOS,EAAeZ,EAAS,KAAK,CAAA,CACxC,CACD,IAAK,IAAMN,KAAaH,EAAU,WACjC,GACCG,EAAU,aAAe,QACzBC,EAAWD,EAAU,QAAQ,IAAMS,GACnC,CAACZ,EAAU,OAEX,OAAOqB,EAAelB,EAAU,KAAK,CAPtC,CASF,OAAO,IACR,CACA,SAASmB,EAAO,EAAsB,EAA6B,CAOlE,OANIC,IAAU,cAAgB,CAAC,UAAW,OAAO,CAAC,CAAC,SAASX,CAAI,EAAUA,EACtEW,GAAO,WAAW,YAAY,EAAUb,EAASa,EAAM,MAAM,EAAE,EAAGX,CAAI,EACtEW,IAAU,aAAeA,IAAU,WAAmB,YACtDA,IAAU,SAAWX,IAAS,QAAgB,QAC9CW,IAAU,SAAW,CAAC,QAAS,cAAe,aAAa,CAAC,CAAC,SAASX,CAAI,EACtE,eACD,IACR,CACA,SAASxB,EAAS,EAAmB,kBAAS,IAAI,IAA8B,CAC/E,GACCoC,EAAK,OAAS,kBACdA,EAAK,OAAS,yBACdA,EAAK,OAAS,sBAEd,OAAOpC,EAASoC,EAAK,WAAYC,CAAM,EACxC,GAAID,EAAK,OAAS,aAAc,CAC/B,GAAIC,EAAO,IAAID,EAAK,IAAI,EAAG,OAAO,KAClC,IAAME,EAAYrB,EAAQ,IAAImB,EAAK,IAAI,EACvC,GAAIE,EAAW,OAAOhB,EAASgB,EAAU,OAAQA,EAAU,IAAI,EAC/D,IAAMC,EAAWrB,EAAU,IAAIkB,EAAK,IAAI,EACxC,GAAI,CAACG,EAAU,OAAO,KACtB,IAAM9B,EAAQT,EAASuC,EAAS,WAAY,IAAI,IAAIF,CAAM,CAAC,CAAC,IAAID,EAAK,IAAI,CAAC,EAC1E,OAAOG,EAAS,OAASL,EAAOzB,EAAO8B,EAAS,MAAM,EAAI9B,CAC3D,CACA,GAAI2B,EAAK,OAAS,mBACjB,OAAOF,EAAOlC,EAASoC,EAAK,OAAQC,CAAM,EAAGG,EAAaJ,CAAI,GAAK,EAAE,EACtE,GAAIA,EAAK,OAAS,kBAAoBA,EAAK,OAAS,gBAAiB,CACpE,IAAMK,EAASzC,EAASoC,EAAK,OAAQC,CAAM,EAO3C,OANII,IAAW,oBAA4B,aACvCA,IAAW,WAAaA,IAAW,QAAgB,YAAYA,IAC/DA,IAAW,eAAuB,QAClCA,IAAW,kBAA0B,WACrCA,IAAW,mBAAqBA,IAAW,YAAoB,WAC/DA,IAAW,eAAuB,QAC/B,IACR,CACA,GAAIL,EAAK,OAAS,mBAAoB,CACrC,IAAMjC,EAASiC,EAAK,WAAW,IAAK,GACnCf,EAAS,OAAS,WAAarB,EAASqB,EAAS,MAAOgB,CAAM,EAAI,IACnE,EACA,GAAIlC,EAAO,QAAUA,EAAO,MAAO,GAAUM,IAAU,SAAWA,IAAU,UAAU,EACrF,MAAO,WACR,GACCN,EAAO,KAAM,GAAUM,IAAU,YAAcA,IAAU,WAAW,GACpEN,EAAO,MAAO,GAAUM,IAAU,YAAcA,IAAU,aAAeA,IAAU,MAAM,EAEzF,MAAO,WACR,GAAIN,EAAO,MAAO,GAAUM,IAAU,MAAM,EAAG,MAAO,MACvD,CAEA,OADI2B,EAAK,OAAS,UAAkB,OAC7B,IACR,CACA,OAAOpC,CACR"}
package/dist/oxlint.d.mts CHANGED
@@ -3,7 +3,7 @@ import { OwnershipRuleName } from "./oxlint/ownership.mjs";
3
3
  import { Plugin, Rule } from "@oxlint/plugins";
4
4
  //#region src/oxlint.d.ts
5
5
  export declare function checkArchitecture(options?: ArchitectureOptions): ArchitectureDiagnostic[];
6
- export type RuleName = OwnershipRuleName | 'component-boundaries' | 'no-component-env' | 'schema-file-boundaries' | 'no-internal-reexports' | 'public-api-first' | 'named-private-helpers' | 'no-raw-builders' | 'no-handwritten-references' | 'domain-import-boundaries' | 'public-functions-in-api' | 'thin-api-adapters' | 'no-inline-enums' | 'no-unbounded-reads' | 'no-manual-timestamps' | 'root-facade-ownership';
6
+ export type RuleName = OwnershipRuleName | 'component-boundaries' | 'no-component-env' | 'schema-file-boundaries' | 'no-internal-reexports' | 'public-api-first' | 'named-private-helpers' | 'no-raw-builders' | 'no-handwritten-references' | 'domain-import-boundaries' | 'public-functions-in-api' | 'thin-api-adapters' | 'no-inline-enums' | 'no-unbounded-reads' | 'no-manual-timestamps' | 'reserved-domain-file-anatomy' | 'root-facade-ownership';
7
7
  export declare const rules: Record<RuleName, Rule>;
8
8
  declare const plugin: Plugin;
9
9
  //#endregion
package/dist/oxlint.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import{createResolver as e,inspectArchitecture as t,resolveImport as n}from"./oxlint/architecture.mjs";import{appFile as r,binding as i,componentRoot as a,exportName as o,exportedNames as s,hasCall as c,imported as l,isDbWrite as u,isFunctionsImport as d,isTableChain as f,metadata as p,propertyName as m,sourceVisitors as h,staticString as g}from"./oxlint/ast.mjs";import{ownershipRules as _}from"./oxlint/ownership.mjs";import{basename as v,dirname as y,relative as b,sep as x}from"node:path";function S(e={}){return t(e)}const C=T({..._,"root-facade-ownership":{meta:p(`Configure shared kit infrastructure once in its root facade.`,{facade:`Configure {{name}} once in convex/{{file}}; import that facade elsewhere.`}),create(e){if(a(e,e.filename))return{};let t=/* @__PURE__ */ new Set;function n(n){let i=l(e,n.callee);if(!i)return;let a=null;[`cvx-kit`,`cvx-kit/auth`].includes(i.source)&&i.name===`createAuthFunctions`&&(a=`functions.ts`),[`cvx-kit`,`cvx-kit/triggers`].includes(i.source)&&i.name===`createTriggers`&&(a=`triggers.ts`),[`cvx-kit`,`cvx-kit/components/foundation`].includes(i.source)&&i.name===`Foundation`&&(a=`foundation.ts`),a&&((r(e)!==a||t.has(i.name))&&e.report({node:n,messageId:`facade`,data:{name:i.name,file:a}}),t.add(i.name))}return{CallExpression:n,NewExpression:n}}},"no-raw-builders":{meta:p(`Build host functions through the auth-aware root constructors.`,{builder:`Import raw builders only in convex/functions.ts; use auth*/role*/admin* or system* elsewhere.`}),create(t){if(r(t)===`functions.ts`||a(t,t.filename))return{};let i=e();return{ImportDeclaration(e){if(e.importKind===`type`)return;let a=e.source.value,s=n(i,t.filename,a),c=s&&r(t,s)?.startsWith(`_generated/`)?r(t,s):a;if(/(?:^|\/)_generated\/server(?:\.[cm]?[jt]s)?$/.test(c)||c===`convex/server`)for(let n of e.specifiers){if(n.type===`ImportSpecifier`&&n.importKind===`type`)continue;let e=n.type===`ImportSpecifier`?o(n.imported):null;(e===null&&c!==`convex/server`||e&&/^(?:internal)?(?:Query|Mutation|Action)(?:Generic)?$|^(?:query|mutation|action)(?:Generic)?$/.test(e))&&t.report({node:n,messageId:`builder`})}},CallExpression(e){let n=l(t,e.callee);n?.source===`convex/server`&&/^(?:internal)?(?:Query|Mutation|Action)Generic$|^(?:query|mutation|action)Generic$/.test(n.name)&&e.callee.type===`MemberExpression`&&t.report({node:e,messageId:`builder`})}}}},"no-handwritten-references":{meta:p(`Use generated api/internal references.`,{reference:`Use generated api/internal references instead of makeFunctionReference.`}),create(e){return{CallExpression(t){let n=l(e,t.callee);n?.source===`convex/server`&&n.name===`makeFunctionReference`&&e.report({node:t,messageId:`reference`})}}}},"domain-import-boundaries":{meta:p(`Keep api, application, domain, and shared dependencies directed.`,{boundary:`Follow api → application/domain → shared; sibling modules expose only rules.ts and queries.ts.`}),create(t){let i=r(t),a=e();return h(t,(e,o)=>{if(!i)return;let s=n(a,t.filename,o);if(!s)return;let c=r(t,s)?.replace(/\.[cm]?[jt]s$/,``);if(!c){s.split(x).includes(`node_modules`)||t.report({node:e,messageId:`boundary`});return}let l=i.split(`/`),u=c.split(`/`),d=!1;l[0]===`domain`?(d=[`api`,`application`,`migrations`].includes(u[0]),u[0]===`domain`&&l[1]!==u[1]&&u[1]!==`shared`&&l[1]!==`table.ts`&&(d=l[1]===`shared`||![`rules`,`queries`].includes(u.slice(2).join(`/`)))):l[0]===`api`?d=[`api`,`migrations`].includes(u[0])||u[0]===`domain`&&u[1]!==`shared`&&u[1]!==(l.length>2?l[1]:v(i).replace(/\.[cm]?[jt]s$/,``)):l[0]===`application`&&(d=[`api`,`migrations`].includes(u[0])),u[0]===`migrations`&&l[0]!==`migrations`&&(d=!0),[`api`,`domain`,`application`].includes(l[0])&&u.length>1&&![`api`,`domain`,`application`,`_generated`,`components`,`migrations`].includes(u[0])&&(d=!0),d&&t.report({node:e,messageId:`boundary`})})}},"public-functions-in-api":{meta:p(`Expose authenticated public functions only through api/.`,{public:`Declare public auth*/role*/admin* functions in convex/api/<module>.ts.`}),create(e){return r(e)?.startsWith(`api/`)?{}:{CallExpression(t){let n=l(e,t.callee);t.callee.type!==`CallExpression`&&n&&d(e,n.source)&&/^(auth|role|admin)(Query|Mutation|Action)$/.test(n.name)&&e.report({node:t,messageId:`public`})}}}},"thin-api-adapters":{meta:p(`Keep business decisions and writes in domain executors.`,{adapter:`Move business branches, private helpers, and database writes into the owning domain executor.`}),create(e){return r(e)?.startsWith(`api/`)?{IfStatement(t){e.report({node:t,messageId:`adapter`})},SwitchStatement(t){e.report({node:t,messageId:`adapter`})},ConditionalExpression(t){e.report({node:t,messageId:`adapter`})},Program(t){let n=s(t);for(let r of t.body)if(r.type===`FunctionDeclaration`&&r.id&&!n.has(r.id.name)&&e.report({node:r,messageId:`adapter`}),r.type===`VariableDeclaration`)for(let t of r.declarations)t.id.type===`Identifier`&&!n.has(t.id.name)&&[`ArrowFunctionExpression`,`FunctionExpression`].includes(t.init?.type??``)&&e.report({node:t,messageId:`adapter`})},CallExpression(t){u(t)&&e.report({node:t,messageId:`adapter`})}}:{}}},"no-inline-enums":{meta:p(`Keep vocabularies in named constants.ts tuples.`,{vocabulary:`Define a named readonly tuple in constants.ts and pass it to z.enum().`}),create(e){return{CallExpression(t){let n=l(e,t.callee),r=t.arguments[0];for(;r?.type===`TSAsExpression`||r?.type===`TSSatisfiesExpression`;)r=r.expression;n&&/^zod(?:\/v4)?$/.test(n.source)&&n.name===`enum`&&r?.type===`ArrayExpression`&&e.report({node:t,messageId:`vocabulary`})}}}},"no-unbounded-reads":{meta:p(`Bound collection reads through include or pagination.`,{bounded:`Use include(...).execute(limit) or bounded pagination; do not collect() or resolve() an unbounded query.`}),create(e){return a(e,e.filename)?{}:{CallExpression(t){if(t.callee.type!==`MemberExpression`)return;let n=m(t.callee);(n===`collect`&&c(t.callee.object,`query`)||n===`resolve`&&c(t.callee.object,`include`))&&e.report({node:t,messageId:`bounded`})}}}},"no-manual-timestamps":{meta:p(`Let timestamps triggers own createdAt and updatedAt.`,{timestamp:`Remove {{field}} from this write; register the timestamps trigger instead.`}),create(e){return a(e,e.filename)?{}:{CallExpression(t){if(!u(t))return;let n=t.arguments.at(-1);if(n?.type===`ObjectExpression`)for(let t of n.properties){if(t.type!==`Property`)continue;let n=t.computed?g(t.key):o(t.key);(n===`createdAt`||n===`updatedAt`)&&e.report({node:t,messageId:`timestamp`,data:{field:n}})}}}}},"component-boundaries":{meta:p(`Keep portable components isolated and consume their client facades.`,{boundary:`Components may import only their own files and npm dependencies; inject host policy through the client API.`,facade:`Import a component through its client.ts facade, not its private implementation.`}),create(t){let i=a(t,t.filename),o=e();return h(t,(e,s)=>{s.startsWith(`.`)||/^cvx-kit\/components\/[^/]+\//.test(s)&&!/^cvx-kit\/components\/[^/]+\/convex\.config(?:\.js)?$/.test(s)&&t.report({node:e,messageId:`facade`});let c=n(o,t.filename,s);c&&!c.split(x).includes(`node_modules`)&&(i&&(b(i,c).startsWith(`..${x}`)||c===y(i))?t.report({node:e,messageId:`boundary`}):!i&&a(t,c)&&!/^client(?:\.[cm]?[jt]s)?$/.test(v(c))&&!(r(t)===`convex.config.ts`&&/^convex\.config(?:\.[cm]?[jt]s)?$/.test(v(c)))&&t.report({node:e,messageId:`facade`}))})}},"no-component-env":{meta:p(`Pass environment configuration into portable components.`,{env:`Portable components must receive configuration through arguments; do not read process.env.`}),create(e){if(!a(e,e.filename))return{};function t(t){if(t.type!==`Identifier`)return!1;let n=i(e,t);return t.name===`process`&&!n?.defs.length||n?.defs.some(e=>e.type===`ImportBinding`&&e.parent?.type===`ImportDeclaration`&&[`node:process`,`process`].includes(e.parent.source.value)&&[`ImportDefaultSpecifier`,`ImportNamespaceSpecifier`].includes(e.node.type))}return{ImportDeclaration(t){if([`node:process`,`process`].includes(t.source.value))for(let n of t.specifiers)n.type===`ImportSpecifier`&&o(n.imported)===`env`&&e.report({node:n,messageId:`env`})},MemberExpression(n){if(m(n)!==`env`)return;let r=n.object,a=r.type===`MemberExpression`&&m(r)===`process`&&r.object.type===`Identifier`&&r.object.name===`globalThis`&&!i(e,r.object)?.defs.length;(t(r)||a)&&e.report({node:n,messageId:`env`})},VariableDeclarator(n){if(n.init&&t(n.init)&&n.id.type===`ObjectPattern`)for(let t of n.id.properties)t.type===`Property`&&(t.computed?g(t.key):o(t.key))===`env`&&e.report({node:t,messageId:`env`})}}}},"schema-file-boundaries":{meta:p(`Keep storage shapes and indexes in their documented owners.`,{schema:`{{builder}} belongs in {{file}}.`}),create(e){return{CallExpression(t){let n=l(e,t.callee),i=r(e);if(!i)return;let o=null;n?.source===`convex/server`&&(n.name===`defineSchema`&&i!==`schema.ts`&&!(a(e,e.filename)&&v(i)===`schema.ts`)&&(o=`the root schema.ts (or a component schema.ts)`),n.name===`defineTable`&&!(a(e,e.filename)&&[`schema.ts`,`table.ts`].includes(v(i)))&&(o=`a component schema.ts/table.ts; host tables use zodTable in domain/<module>/schema.ts`)),n&&[`cvx-kit`,`cvx-kit/zod-table`].includes(n.source)&&[`zodTable`,`tenantTable`,`zodVariantTable`].includes(n.name)&&!/^domain\/[^/]+\/schema\.ts$/.test(i)&&(o=`domain/<module>/schema.ts`),o&&e.report({node:t,messageId:`schema`,data:{builder:n?.name??`table`,file:o}}),t.callee.type===`MemberExpression`&&[`index`,`searchIndex`,`vectorIndex`].includes(m(t.callee)??``)&&f(t.callee.object)&&!a(e,e.filename)&&!/^domain\/[^/]+\/table\.ts$/.test(i)&&e.report({node:t,messageId:`schema`,data:{builder:`Table indexes`,file:`domain/<module>/table.ts`}})}}}},"no-internal-reexports":{meta:p(`Import from owning modules directly; consumer apps have no barrels.`,{reexport:`Import from the owning file directly; do not re-export imports inside convex/.`}),create(e){function t(t){if(t.source){e.report({node:t,messageId:`reexport`});return}for(let n of t.type===`ExportNamedDeclaration`?t.specifiers:[])i(e,n.local)?.defs.some(e=>e.type===`ImportBinding`)&&e.report({node:n,messageId:`reexport`})}return{ExportNamedDeclaration:t,ExportAllDeclaration:t,ExportDefaultDeclaration(t){t.declaration.type===`Identifier`&&i(e,t.declaration)?.defs.some(e=>e.type===`ImportBinding`)&&e.report({node:t,messageId:`reexport`})}}}},"public-api-first":{meta:p(`Place private helper implementations after the exported API.`,{order:`Move this private helper below the exported API so the file reads from public purpose to implementation.`}),create(e){return{Program(t){let n=s(t),r=t.body.findLastIndex(e=>e.type.startsWith(`Export`));for(let i of t.body.slice(0,r<0?0:r))i.type===`FunctionDeclaration`&&i.id&&!n.has(i.id.name)&&e.report({node:i,messageId:`order`})}}}},"named-private-helpers":{meta:p(`Use named declarations for top-level private helper functions.`,{helper:`Declare this private helper with function name(...) at the bottom of the file.`}),create(e){return{Program(t){let n=s(t);for(let r of t.body)if(r.type===`VariableDeclaration`)for(let t of r.declarations)t.id.type===`Identifier`&&!n.has(t.id.name)&&(t.init?.type===`ArrowFunctionExpression`||t.init?.type===`FunctionExpression`)&&e.report({node:t,messageId:`helper`})}}}}}),w={meta:{name:`cvx`},rules:C};function T(e){let t={...e},n=Object.keys(e);for(let i of n){let n=e[i];t[i]={meta:{...n.meta,schema:[{type:`object`,properties:{convexDir:{type:`string`,minLength:1}},additionalProperties:!1}]},create(e){let t=r(e);return!t||/(?:^|\/)(?:_generated|__tests__)(?:\/|$)/.test(t)||/\.(?:test|spec)\.[cm]?[jt]s$/.test(t)?{}:n.create(e)}}}return t}export{S as checkArchitecture,w as default,C as rules};
1
+ import{createResolver as e,inspectArchitecture as t,resolveImport as n}from"./oxlint/architecture.mjs";import{appFile as r,binding as i,componentRoot as a,exportName as o,exportedNames as s,hasCall as c,imported as l,isDbWrite as u,isFunctionsImport as d,isTableChain as f,metadata as p,propertyName as m,sourceVisitors as h,staticString as g}from"./oxlint/ast.mjs";import{reservedDomainFiles as _}from"./oxlint/reserved-files.mjs";import{ownershipRules as v}from"./oxlint/ownership.mjs";import{basename as y,dirname as b,relative as x,sep as S}from"node:path";function C(e={}){return t(e)}const w=E({...v,"reserved-domain-file-anatomy":_,"root-facade-ownership":{meta:p(`Configure shared kit infrastructure once in its root facade.`,{facade:`Configure {{name}} once in convex/{{file}}; import that facade elsewhere.`}),create(e){if(a(e,e.filename))return{};let t=/* @__PURE__ */ new Set;function n(n){let i=l(e,n.callee);if(!i)return;let a=null;[`cvx-kit`,`cvx-kit/auth`].includes(i.source)&&i.name===`createAuthFunctions`&&(a=`functions.ts`),[`cvx-kit`,`cvx-kit/triggers`].includes(i.source)&&i.name===`createTriggers`&&(a=`triggers.ts`),[`cvx-kit`,`cvx-kit/components/foundation`].includes(i.source)&&i.name===`Foundation`&&(a=`foundation.ts`),(i.source===`cvx-kit/effect`&&i.name===`createEffectFoundation`||i.source===`cvx-kit`&&i.name===`createFoundation`)&&(a=`foundation.ts`),a&&((r(e)!==a||t.has(i.name))&&e.report({node:n,messageId:`facade`,data:{name:i.name,file:a}}),t.add(i.name))}return{CallExpression:n,NewExpression:n}}},"no-raw-builders":{meta:p(`Build host functions through the auth-aware root constructors.`,{builder:`Import raw builders only in convex/functions.ts; use auth*/role*/admin* or system* elsewhere.`}),create(t){if(r(t)===`functions.ts`||a(t,t.filename))return{};let i=e();return{ImportDeclaration(e){if(e.importKind===`type`)return;let a=e.source.value,s=n(i,t.filename,a),c=s&&r(t,s)?.startsWith(`_generated/`)?r(t,s):a;if(/(?:^|\/)_generated\/server(?:\.[cm]?[jt]s)?$/.test(c)||c===`convex/server`)for(let n of e.specifiers){if(n.type===`ImportSpecifier`&&n.importKind===`type`)continue;let e=n.type===`ImportSpecifier`?o(n.imported):null;(e===null&&c!==`convex/server`||e&&/^(?:internal)?(?:Query|Mutation|Action)(?:Generic)?$|^(?:query|mutation|action)(?:Generic)?$/.test(e))&&t.report({node:n,messageId:`builder`})}},CallExpression(e){let n=l(t,e.callee);n?.source===`convex/server`&&/^(?:internal)?(?:Query|Mutation|Action)Generic$|^(?:query|mutation|action)Generic$/.test(n.name)&&e.callee.type===`MemberExpression`&&t.report({node:e,messageId:`builder`})}}}},"no-handwritten-references":{meta:p(`Use generated api/internal references.`,{reference:`Use generated api/internal references instead of makeFunctionReference.`}),create(e){return{CallExpression(t){let n=l(e,t.callee);n?.source===`convex/server`&&n.name===`makeFunctionReference`&&e.report({node:t,messageId:`reference`})}}}},"domain-import-boundaries":{meta:p(`Keep api, application, domain, and shared dependencies directed.`,{boundary:`Follow api → application/domain → shared; sibling modules expose only rules.ts and queries.ts.`}),create(t){let i=r(t),a=e();return h(t,(e,o)=>{if(!i)return;let s=n(a,t.filename,o);if(!s)return;let c=r(t,s)?.replace(/\.[cm]?[jt]s$/,``);if(!c){s.split(S).includes(`node_modules`)||t.report({node:e,messageId:`boundary`});return}let l=i.split(`/`),u=c.split(`/`),d=!1;l[0]===`domain`?(d=[`api`,`application`,`migrations`].includes(u[0]),u[0]===`domain`&&l[1]!==u[1]&&u[1]!==`shared`&&l[1]!==`table.ts`&&(d=l[1]===`shared`||![`rules`,`queries`].includes(u.slice(2).join(`/`)))):l[0]===`api`?d=[`api`,`migrations`].includes(u[0])||u[0]===`domain`&&u[1]!==`shared`&&u[1]!==(l.length>2?l[1]:y(i).replace(/\.[cm]?[jt]s$/,``)):l[0]===`application`&&(d=[`api`,`migrations`].includes(u[0])),u[0]===`migrations`&&l[0]!==`migrations`&&(d=!0),[`api`,`domain`,`application`].includes(l[0])&&u.length>1&&![`api`,`domain`,`application`,`_generated`,`components`,`migrations`].includes(u[0])&&(d=!0),d&&t.report({node:e,messageId:`boundary`})})}},"public-functions-in-api":{meta:p(`Expose authenticated public functions only through api/.`,{public:`Declare public auth*/role*/admin* functions in convex/api/<module>.ts.`}),create(e){return r(e)?.startsWith(`api/`)?{}:{CallExpression(t){let n=l(e,t.callee);t.callee.type!==`CallExpression`&&n&&d(e,n.source)&&/^(auth|role|admin)(Query|Mutation|Action)$/.test(n.name)&&e.report({node:t,messageId:`public`})}}}},"thin-api-adapters":{meta:p(`Keep business decisions and writes in domain executors.`,{adapter:`Move business branches, private helpers, and database writes into the owning domain executor.`}),create(e){return r(e)?.startsWith(`api/`)?{IfStatement(t){e.report({node:t,messageId:`adapter`})},SwitchStatement(t){e.report({node:t,messageId:`adapter`})},ConditionalExpression(t){e.report({node:t,messageId:`adapter`})},Program(t){let n=s(t);for(let r of t.body)if(r.type===`FunctionDeclaration`&&r.id&&!n.has(r.id.name)&&e.report({node:r,messageId:`adapter`}),r.type===`VariableDeclaration`)for(let t of r.declarations)t.id.type===`Identifier`&&!n.has(t.id.name)&&[`ArrowFunctionExpression`,`FunctionExpression`].includes(t.init?.type??``)&&e.report({node:t,messageId:`adapter`})},CallExpression(t){u(t)&&e.report({node:t,messageId:`adapter`})}}:{}}},"no-inline-enums":{meta:p(`Keep vocabularies in named constants.ts tuples.`,{vocabulary:`Define a named readonly tuple in constants.ts and pass it to z.enum().`}),create(e){return{CallExpression(t){let n=l(e,t.callee),r=t.arguments[0];for(;r?.type===`TSAsExpression`||r?.type===`TSSatisfiesExpression`;)r=r.expression;n&&/^zod(?:\/v4)?$/.test(n.source)&&n.name===`enum`&&r?.type===`ArrayExpression`&&e.report({node:t,messageId:`vocabulary`})}}}},"no-unbounded-reads":{meta:p(`Bound collection reads through include or pagination.`,{bounded:`Use include(...).execute(limit) or bounded pagination; do not collect() or resolve() an unbounded query.`}),create(e){return a(e,e.filename)?{}:{CallExpression(t){if(t.callee.type!==`MemberExpression`)return;let n=m(t.callee);(n===`collect`&&c(t.callee.object,`query`)||n===`resolve`&&c(t.callee.object,`include`))&&e.report({node:t,messageId:`bounded`})}}}},"no-manual-timestamps":{meta:p(`Let timestamps triggers own createdAt and updatedAt.`,{timestamp:`Remove {{field}} from this write; register the timestamps trigger instead.`}),create(e){return a(e,e.filename)?{}:{CallExpression(t){if(!u(t))return;let n=t.arguments.at(-1);if(n?.type===`ObjectExpression`)for(let t of n.properties){if(t.type!==`Property`)continue;let n=t.computed?g(t.key):o(t.key);(n===`createdAt`||n===`updatedAt`)&&e.report({node:t,messageId:`timestamp`,data:{field:n}})}}}}},"component-boundaries":{meta:p(`Keep portable components isolated and consume their client facades.`,{boundary:`Components may import only their own files and npm dependencies; inject host policy through the client API.`,facade:`Import a component through its client.ts facade, not its private implementation.`}),create(t){let i=a(t,t.filename),o=e();return h(t,(e,s)=>{s.startsWith(`.`)||/^cvx-kit\/components\/[^/]+\//.test(s)&&!/^cvx-kit\/components\/[^/]+\/convex\.config(?:\.js)?$/.test(s)&&t.report({node:e,messageId:`facade`});let c=n(o,t.filename,s);c&&!c.split(S).includes(`node_modules`)&&(i&&(x(i,c).startsWith(`..${S}`)||c===b(i))?t.report({node:e,messageId:`boundary`}):!i&&a(t,c)&&!/^client(?:\.[cm]?[jt]s)?$/.test(y(c))&&!(r(t)===`convex.config.ts`&&/^convex\.config(?:\.[cm]?[jt]s)?$/.test(y(c)))&&t.report({node:e,messageId:`facade`}))})}},"no-component-env":{meta:p(`Pass environment configuration into portable components.`,{env:`Portable components must receive configuration through arguments; do not read process.env.`}),create(e){if(!a(e,e.filename))return{};function t(t){if(t.type!==`Identifier`)return!1;let n=i(e,t);return t.name===`process`&&!n?.defs.length||n?.defs.some(e=>e.type===`ImportBinding`&&e.parent?.type===`ImportDeclaration`&&[`node:process`,`process`].includes(e.parent.source.value)&&[`ImportDefaultSpecifier`,`ImportNamespaceSpecifier`].includes(e.node.type))}return{ImportDeclaration(t){if([`node:process`,`process`].includes(t.source.value))for(let n of t.specifiers)n.type===`ImportSpecifier`&&o(n.imported)===`env`&&e.report({node:n,messageId:`env`})},MemberExpression(n){if(m(n)!==`env`)return;let r=n.object,a=r.type===`MemberExpression`&&m(r)===`process`&&r.object.type===`Identifier`&&r.object.name===`globalThis`&&!i(e,r.object)?.defs.length;(t(r)||a)&&e.report({node:n,messageId:`env`})},VariableDeclarator(n){if(n.init&&t(n.init)&&n.id.type===`ObjectPattern`)for(let t of n.id.properties)t.type===`Property`&&(t.computed?g(t.key):o(t.key))===`env`&&e.report({node:t,messageId:`env`})}}}},"schema-file-boundaries":{meta:p(`Keep storage shapes and indexes in their documented owners.`,{schema:`{{builder}} belongs in {{file}}.`}),create(e){return{CallExpression(t){let n=l(e,t.callee),i=r(e);if(!i)return;let o=null;n?.source===`convex/server`&&(n.name===`defineSchema`&&i!==`schema.ts`&&!(a(e,e.filename)&&y(i)===`schema.ts`)&&(o=`the root schema.ts (or a component schema.ts)`),n.name===`defineTable`&&!(a(e,e.filename)&&[`schema.ts`,`table.ts`].includes(y(i)))&&(o=`a component schema.ts/table.ts; host tables use zodTable in domain/<module>/schema.ts`)),n&&[`cvx-kit`,`cvx-kit/zod-table`].includes(n.source)&&[`zodTable`,`tenantTable`,`zodVariantTable`].includes(n.name)&&!/^domain\/[^/]+\/schema\.ts$/.test(i)&&(o=`domain/<module>/schema.ts`),o&&e.report({node:t,messageId:`schema`,data:{builder:n?.name??`table`,file:o}}),t.callee.type===`MemberExpression`&&[`index`,`searchIndex`,`vectorIndex`].includes(m(t.callee)??``)&&f(t.callee.object)&&!a(e,e.filename)&&!/^domain\/[^/]+\/table\.ts$/.test(i)&&e.report({node:t,messageId:`schema`,data:{builder:`Table indexes`,file:`domain/<module>/table.ts`}})}}}},"no-internal-reexports":{meta:p(`Import from owning modules directly; consumer apps have no barrels.`,{reexport:`Import from the owning file directly; do not re-export imports inside convex/.`}),create(e){function t(t){if(t.source){e.report({node:t,messageId:`reexport`});return}for(let n of t.type===`ExportNamedDeclaration`?t.specifiers:[])i(e,n.local)?.defs.some(e=>e.type===`ImportBinding`)&&e.report({node:n,messageId:`reexport`})}return{ExportNamedDeclaration:t,ExportAllDeclaration:t,ExportDefaultDeclaration(t){t.declaration.type===`Identifier`&&i(e,t.declaration)?.defs.some(e=>e.type===`ImportBinding`)&&e.report({node:t,messageId:`reexport`})}}}},"public-api-first":{meta:p(`Place private helper implementations after the exported API.`,{order:`Move this private helper below the exported API so the file reads from public purpose to implementation.`}),create(e){return{Program(t){let n=s(t),r=t.body.findLastIndex(e=>e.type.startsWith(`Export`));for(let i of t.body.slice(0,r<0?0:r))i.type===`FunctionDeclaration`&&i.id&&!n.has(i.id.name)&&e.report({node:i,messageId:`order`})}}}},"named-private-helpers":{meta:p(`Use named declarations for top-level private helper functions.`,{helper:`Declare this private helper with function name(...) at the bottom of the file.`}),create(e){return{Program(t){let n=s(t);for(let r of t.body)if(r.type===`VariableDeclaration`)for(let t of r.declarations)t.id.type===`Identifier`&&!n.has(t.id.name)&&(t.init?.type===`ArrowFunctionExpression`||t.init?.type===`FunctionExpression`)&&e.report({node:t,messageId:`helper`})}}}}}),T={meta:{name:`cvx`},rules:w};function E(e){let t={...e},n=Object.keys(e);for(let i of n){let n=e[i];t[i]={meta:{...n.meta,schema:[{type:`object`,properties:{convexDir:{type:`string`,minLength:1}},additionalProperties:!1}]},create(e){let t=r(e);return!t||/(?:^|\/)(?:_generated|__tests__)(?:\/|$)/.test(t)||/\.(?:test|spec)\.[cm]?[jt]s$/.test(t)?{}:n.create(e)}}}return t}export{C as checkArchitecture,T as default,w as rules};
2
2
  //# sourceMappingURL=oxlint.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"oxlint.mjs","names":["checkArchitecture","inspectArchitecture","options","rules","scopeRules","ownershipRules","metadata","componentRoot","context","seen","check","ref","imported","node","file","appFile","resolver","createResolver","importedSource","target","resolveImport","source","specifier","name","exportName","sourceVisitors","resolved","sep","from","to","forbidden","basename","isFunctionsImport","exported","exportedNames","statement","declaration","isDbWrite","values","propertyName","hasCall","data","property","field","staticString","owner","relative","dirname","isProcess","variable","binding","def","object","globalProcess","expected","isTableChain","exports","lastExport","plugin","scoped","names","rule"],"sources":["../src/oxlint.ts"],"sourcesContent":["import { basename, dirname, relative, sep } from 'node:path'\nimport type { CreateRule, ESTree, Plugin, Rule } from '@oxlint/plugins'\nimport {\n\tinspectArchitecture,\n\tcreateResolver,\n\tresolveImport,\n\ttype ArchitectureOptions,\n\ttype ArchitectureDiagnostic,\n} from './oxlint/architecture'\nimport { ownershipRules, type OwnershipRuleName } from './oxlint/ownership'\nimport {\n\tappFile,\n\timported,\n\tsourceVisitors,\n\tisFunctionsImport,\n\tisTableChain,\n\tisDbWrite,\n\thasCall,\n\tmetadata,\n\tcomponentRoot,\n\tstaticString,\n\tpropertyName,\n\tbinding,\n\texportedNames,\n\texportName,\n} from './oxlint/ast'\n\nexport type { ArchitectureOptions, ArchitectureDiagnostic } from './oxlint/architecture'\n\nexport function checkArchitecture(options: ArchitectureOptions = {}): ArchitectureDiagnostic[] {\n\treturn inspectArchitecture(options)\n}\n\nexport type RuleName =\n\t| OwnershipRuleName\n\t| 'component-boundaries'\n\t| 'no-component-env'\n\t| 'schema-file-boundaries'\n\t| 'no-internal-reexports'\n\t| 'public-api-first'\n\t| 'named-private-helpers'\n\t| 'no-raw-builders'\n\t| 'no-handwritten-references'\n\t| 'domain-import-boundaries'\n\t| 'public-functions-in-api'\n\t| 'thin-api-adapters'\n\t| 'no-inline-enums'\n\t| 'no-unbounded-reads'\n\t| 'no-manual-timestamps'\n\t| 'root-facade-ownership'\n\n/** Consumer application rules derived from docs/conventions.md. */\nconst applicationRules: Record<RuleName, CreateRule> = {\n\t...ownershipRules,\n\t'root-facade-ownership': {\n\t\tmeta: metadata('Configure shared kit infrastructure once in its root facade.', {\n\t\t\tfacade: 'Configure {{name}} once in convex/{{file}}; import that facade elsewhere.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tif (componentRoot(context, context.filename)) return {}\n\t\t\tconst seen = new Set<string>()\n\t\t\tfunction check(node: ESTree.CallExpression | ESTree.NewExpression) {\n\t\t\t\tconst ref = imported(context, node.callee)\n\t\t\t\tif (!ref) return\n\t\t\t\tlet file: string | null = null\n\t\t\t\tif (['cvx-kit', 'cvx-kit/auth'].includes(ref.source) && ref.name === 'createAuthFunctions')\n\t\t\t\t\tfile = 'functions.ts'\n\t\t\t\tif (['cvx-kit', 'cvx-kit/triggers'].includes(ref.source) && ref.name === 'createTriggers')\n\t\t\t\t\tfile = 'triggers.ts'\n\t\t\t\tif (\n\t\t\t\t\t['cvx-kit', 'cvx-kit/components/foundation'].includes(ref.source) &&\n\t\t\t\t\tref.name === 'Foundation'\n\t\t\t\t)\n\t\t\t\t\tfile = 'foundation.ts'\n\t\t\t\tif (!file) return\n\t\t\t\tif (appFile(context) !== file || seen.has(ref.name))\n\t\t\t\t\tcontext.report({ node, messageId: 'facade', data: { name: ref.name, file } })\n\t\t\t\tseen.add(ref.name)\n\t\t\t}\n\t\t\treturn { CallExpression: check, NewExpression: check }\n\t\t},\n\t},\n\t'no-raw-builders': {\n\t\tmeta: metadata('Build host functions through the auth-aware root constructors.', {\n\t\t\tbuilder:\n\t\t\t\t'Import raw builders only in convex/functions.ts; use auth*/role*/admin* or system* elsewhere.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tif (appFile(context) === 'functions.ts' || componentRoot(context, context.filename)) return {}\n\t\t\tconst resolver = createResolver()\n\t\t\treturn {\n\t\t\t\tImportDeclaration(node) {\n\t\t\t\t\tif (node.importKind === 'type') return\n\t\t\t\t\tconst importedSource = node.source.value\n\t\t\t\t\tconst target = resolveImport(resolver, context.filename, importedSource)\n\t\t\t\t\tconst source =\n\t\t\t\t\t\ttarget && appFile(context, target)?.startsWith('_generated/')\n\t\t\t\t\t\t\t? appFile(context, target)!\n\t\t\t\t\t\t\t: importedSource\n\t\t\t\t\tif (\n\t\t\t\t\t\t!/(?:^|\\/)_generated\\/server(?:\\.[cm]?[jt]s)?$/.test(source) &&\n\t\t\t\t\t\tsource !== 'convex/server'\n\t\t\t\t\t)\n\t\t\t\t\t\treturn\n\t\t\t\t\tfor (const specifier of node.specifiers) {\n\t\t\t\t\t\tif (specifier.type === 'ImportSpecifier' && specifier.importKind === 'type') continue\n\t\t\t\t\t\tconst name =\n\t\t\t\t\t\t\tspecifier.type === 'ImportSpecifier' ? exportName(specifier.imported) : null\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t(name === null && source !== 'convex/server') ||\n\t\t\t\t\t\t\t(name &&\n\t\t\t\t\t\t\t\t/^(?:internal)?(?:Query|Mutation|Action)(?:Generic)?$|^(?:query|mutation|action)(?:Generic)?$/.test(\n\t\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\t))\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tcontext.report({ node: specifier, messageId: 'builder' })\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tCallExpression(node) {\n\t\t\t\t\tconst ref = imported(context, node.callee)\n\t\t\t\t\tif (\n\t\t\t\t\t\tref?.source === 'convex/server' &&\n\t\t\t\t\t\t/^(?:internal)?(?:Query|Mutation|Action)Generic$|^(?:query|mutation|action)Generic$/.test(\n\t\t\t\t\t\t\tref.name,\n\t\t\t\t\t\t) &&\n\t\t\t\t\t\tnode.callee.type === 'MemberExpression'\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontext.report({ node, messageId: 'builder' })\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'no-handwritten-references': {\n\t\tmeta: metadata('Use generated api/internal references.', {\n\t\t\treference: 'Use generated api/internal references instead of makeFunctionReference.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\treturn {\n\t\t\t\tCallExpression(node) {\n\t\t\t\t\tconst ref = imported(context, node.callee)\n\t\t\t\t\tif (ref?.source === 'convex/server' && ref.name === 'makeFunctionReference')\n\t\t\t\t\t\tcontext.report({ node, messageId: 'reference' })\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'domain-import-boundaries': {\n\t\tmeta: metadata('Keep api, application, domain, and shared dependencies directed.', {\n\t\t\tboundary:\n\t\t\t\t'Follow api → application/domain → shared; sibling modules expose only rules.ts and queries.ts.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tconst file = appFile(context)\n\t\t\tconst resolver = createResolver()\n\t\t\treturn sourceVisitors(context, (node, source) => {\n\t\t\t\tif (!file) return\n\t\t\t\tconst resolved = resolveImport(resolver, context.filename, source)\n\t\t\t\tif (!resolved) return\n\t\t\t\tconst target = appFile(context, resolved)?.replace(/\\.[cm]?[jt]s$/, '')\n\t\t\t\tif (!target) {\n\t\t\t\t\tif (!resolved.split(sep).includes('node_modules'))\n\t\t\t\t\t\tcontext.report({ node, messageId: 'boundary' })\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst from = file.split('/')\n\t\t\t\tconst to = target.split('/')\n\t\t\t\tlet forbidden = false\n\t\t\t\tif (from[0] === 'domain') {\n\t\t\t\t\tforbidden = ['api', 'application', 'migrations'].includes(to[0])\n\t\t\t\t\tif (\n\t\t\t\t\t\tto[0] === 'domain' &&\n\t\t\t\t\t\tfrom[1] !== to[1] &&\n\t\t\t\t\t\tto[1] !== 'shared' &&\n\t\t\t\t\t\tfrom[1] !== 'table.ts'\n\t\t\t\t\t) {\n\t\t\t\t\t\tforbidden =\n\t\t\t\t\t\t\tfrom[1] === 'shared' || !['rules', 'queries'].includes(to.slice(2).join('/'))\n\t\t\t\t\t}\n\t\t\t\t} else if (from[0] === 'api') {\n\t\t\t\t\tforbidden =\n\t\t\t\t\t\t['api', 'migrations'].includes(to[0]) ||\n\t\t\t\t\t\t(to[0] === 'domain' &&\n\t\t\t\t\t\t\tto[1] !== 'shared' &&\n\t\t\t\t\t\t\tto[1] !== (from.length > 2 ? from[1] : basename(file).replace(/\\.[cm]?[jt]s$/, '')))\n\t\t\t\t} else if (from[0] === 'application') forbidden = ['api', 'migrations'].includes(to[0])\n\t\t\t\tif (to[0] === 'migrations' && from[0] !== 'migrations') forbidden = true\n\t\t\t\tif (\n\t\t\t\t\t['api', 'domain', 'application'].includes(from[0]) &&\n\t\t\t\t\tto.length > 1 &&\n\t\t\t\t\t!['api', 'domain', 'application', '_generated', 'components', 'migrations'].includes(\n\t\t\t\t\t\tto[0],\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t\t\tforbidden = true\n\t\t\t\tif (forbidden) context.report({ node, messageId: 'boundary' })\n\t\t\t})\n\t\t},\n\t},\n\t'public-functions-in-api': {\n\t\tmeta: metadata('Expose authenticated public functions only through api/.', {\n\t\t\tpublic: 'Declare public auth*/role*/admin* functions in convex/api/<module>.ts.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tif (appFile(context)?.startsWith('api/')) return {}\n\t\t\treturn {\n\t\t\t\tCallExpression(node) {\n\t\t\t\t\tconst ref = imported(context, node.callee)\n\t\t\t\t\tif (\n\t\t\t\t\t\tnode.callee.type !== 'CallExpression' &&\n\t\t\t\t\t\tref &&\n\t\t\t\t\t\tisFunctionsImport(context, ref.source) &&\n\t\t\t\t\t\t/^(auth|role|admin)(Query|Mutation|Action)$/.test(ref.name)\n\t\t\t\t\t)\n\t\t\t\t\t\tcontext.report({ node, messageId: 'public' })\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'thin-api-adapters': {\n\t\tmeta: metadata('Keep business decisions and writes in domain executors.', {\n\t\t\tadapter:\n\t\t\t\t'Move business branches, private helpers, and database writes into the owning domain executor.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tif (!appFile(context)?.startsWith('api/')) return {}\n\t\t\treturn {\n\t\t\t\tIfStatement(node) {\n\t\t\t\t\tcontext.report({ node, messageId: 'adapter' })\n\t\t\t\t},\n\t\t\t\tSwitchStatement(node) {\n\t\t\t\t\tcontext.report({ node, messageId: 'adapter' })\n\t\t\t\t},\n\t\t\t\tConditionalExpression(node) {\n\t\t\t\t\tcontext.report({ node, messageId: 'adapter' })\n\t\t\t\t},\n\t\t\t\tProgram(node) {\n\t\t\t\t\tconst exported = exportedNames(node)\n\t\t\t\t\tfor (const statement of node.body) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tstatement.type === 'FunctionDeclaration' &&\n\t\t\t\t\t\t\tstatement.id &&\n\t\t\t\t\t\t\t!exported.has(statement.id.name)\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\tcontext.report({ node: statement, messageId: 'adapter' })\n\t\t\t\t\t\tif (statement.type === 'VariableDeclaration')\n\t\t\t\t\t\t\tfor (const declaration of statement.declarations) {\n\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\tdeclaration.id.type === 'Identifier' &&\n\t\t\t\t\t\t\t\t\t!exported.has(declaration.id.name) &&\n\t\t\t\t\t\t\t\t\t['ArrowFunctionExpression', 'FunctionExpression'].includes(\n\t\t\t\t\t\t\t\t\t\tdeclaration.init?.type ?? '',\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\tcontext.report({ node: declaration, messageId: 'adapter' })\n\t\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tCallExpression(node) {\n\t\t\t\t\tif (isDbWrite(node)) context.report({ node, messageId: 'adapter' })\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'no-inline-enums': {\n\t\tmeta: metadata('Keep vocabularies in named constants.ts tuples.', {\n\t\t\tvocabulary: 'Define a named readonly tuple in constants.ts and pass it to z.enum().',\n\t\t}),\n\t\tcreate(context) {\n\t\t\treturn {\n\t\t\t\tCallExpression(node) {\n\t\t\t\t\tconst ref = imported(context, node.callee)\n\t\t\t\t\tlet values = node.arguments[0]\n\t\t\t\t\twhile (values?.type === 'TSAsExpression' || values?.type === 'TSSatisfiesExpression')\n\t\t\t\t\t\tvalues = values.expression\n\t\t\t\t\tif (\n\t\t\t\t\t\tref &&\n\t\t\t\t\t\t/^zod(?:\\/v4)?$/.test(ref.source) &&\n\t\t\t\t\t\tref.name === 'enum' &&\n\t\t\t\t\t\tvalues?.type === 'ArrayExpression'\n\t\t\t\t\t)\n\t\t\t\t\t\tcontext.report({ node, messageId: 'vocabulary' })\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'no-unbounded-reads': {\n\t\tmeta: metadata('Bound collection reads through include or pagination.', {\n\t\t\tbounded:\n\t\t\t\t'Use include(...).execute(limit) or bounded pagination; do not collect() or resolve() an unbounded query.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tif (componentRoot(context, context.filename)) return {}\n\t\t\treturn {\n\t\t\t\tCallExpression(node) {\n\t\t\t\t\tif (node.callee.type !== 'MemberExpression') return\n\t\t\t\t\tconst name = propertyName(node.callee)\n\t\t\t\t\tif (\n\t\t\t\t\t\t(name === 'collect' && hasCall(node.callee.object, 'query')) ||\n\t\t\t\t\t\t(name === 'resolve' && hasCall(node.callee.object, 'include'))\n\t\t\t\t\t)\n\t\t\t\t\t\tcontext.report({ node, messageId: 'bounded' })\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'no-manual-timestamps': {\n\t\tmeta: metadata('Let timestamps triggers own createdAt and updatedAt.', {\n\t\t\ttimestamp: 'Remove {{field}} from this write; register the timestamps trigger instead.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tif (componentRoot(context, context.filename)) return {}\n\t\t\treturn {\n\t\t\t\tCallExpression(node) {\n\t\t\t\t\tif (!isDbWrite(node)) return\n\t\t\t\t\tconst data = node.arguments.at(-1)\n\t\t\t\t\tif (data?.type !== 'ObjectExpression') return\n\t\t\t\t\tfor (const property of data.properties) {\n\t\t\t\t\t\tif (property.type !== 'Property') continue\n\t\t\t\t\t\tconst field = property.computed ? staticString(property.key) : exportName(property.key)\n\t\t\t\t\t\tif (field === 'createdAt' || field === 'updatedAt')\n\t\t\t\t\t\t\tcontext.report({ node: property, messageId: 'timestamp', data: { field } })\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'component-boundaries': {\n\t\tmeta: metadata('Keep portable components isolated and consume their client facades.', {\n\t\t\tboundary:\n\t\t\t\t'Components may import only their own files and npm dependencies; inject host policy through the client API.',\n\t\t\tfacade: 'Import a component through its client.ts facade, not its private implementation.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tconst owner = componentRoot(context, context.filename)\n\t\t\tconst resolver = createResolver()\n\n\t\t\treturn sourceVisitors(context, (node, specifier) => {\n\t\t\t\tif (!specifier.startsWith('.')) {\n\t\t\t\t\tif (\n\t\t\t\t\t\t/^cvx-kit\\/components\\/[^/]+\\//.test(specifier) &&\n\t\t\t\t\t\t!/^cvx-kit\\/components\\/[^/]+\\/convex\\.config(?:\\.js)?$/.test(specifier)\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontext.report({ node, messageId: 'facade' })\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst target = resolveImport(resolver, context.filename, specifier)\n\t\t\t\tif (!target || target.split(sep).includes('node_modules')) return\n\t\t\t\tif (\n\t\t\t\t\towner &&\n\t\t\t\t\t(relative(owner, target).startsWith(`..${sep}`) || target === dirname(owner))\n\t\t\t\t) {\n\t\t\t\t\tcontext.report({ node, messageId: 'boundary' })\n\t\t\t\t} else if (\n\t\t\t\t\t!owner &&\n\t\t\t\t\tcomponentRoot(context, target) &&\n\t\t\t\t\t!/^client(?:\\.[cm]?[jt]s)?$/.test(basename(target)) &&\n\t\t\t\t\t!(\n\t\t\t\t\t\tappFile(context) === 'convex.config.ts' &&\n\t\t\t\t\t\t/^convex\\.config(?:\\.[cm]?[jt]s)?$/.test(basename(target))\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tcontext.report({ node, messageId: 'facade' })\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\t},\n\t'no-component-env': {\n\t\tmeta: metadata('Pass environment configuration into portable components.', {\n\t\t\tenv: 'Portable components must receive configuration through arguments; do not read process.env.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tif (!componentRoot(context, context.filename)) return {}\n\t\t\tfunction isProcess(node: ESTree.Node) {\n\t\t\t\tif (node.type !== 'Identifier') return false\n\t\t\t\tconst variable = binding(context, node)\n\t\t\t\tif (node.name === 'process' && !variable?.defs.length) return true\n\t\t\t\treturn variable?.defs.some(\n\t\t\t\t\t(def) =>\n\t\t\t\t\t\tdef.type === 'ImportBinding' &&\n\t\t\t\t\t\tdef.parent?.type === 'ImportDeclaration' &&\n\t\t\t\t\t\t['node:process', 'process'].includes(def.parent.source.value) &&\n\t\t\t\t\t\t['ImportDefaultSpecifier', 'ImportNamespaceSpecifier'].includes(def.node.type),\n\t\t\t\t)\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tImportDeclaration(node) {\n\t\t\t\t\tif (['node:process', 'process'].includes(node.source.value)) {\n\t\t\t\t\t\tfor (const specifier of node.specifiers) {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tspecifier.type === 'ImportSpecifier' &&\n\t\t\t\t\t\t\t\texportName(specifier.imported) === 'env'\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tcontext.report({ node: specifier, messageId: 'env' })\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tMemberExpression(node) {\n\t\t\t\t\tif (propertyName(node) !== 'env') return\n\t\t\t\t\tconst object = node.object\n\t\t\t\t\tconst globalProcess =\n\t\t\t\t\t\tobject.type === 'MemberExpression' &&\n\t\t\t\t\t\tpropertyName(object) === 'process' &&\n\t\t\t\t\t\tobject.object.type === 'Identifier' &&\n\t\t\t\t\t\tobject.object.name === 'globalThis' &&\n\t\t\t\t\t\t!binding(context, object.object)?.defs.length\n\t\t\t\t\tif (isProcess(object) || globalProcess) context.report({ node, messageId: 'env' })\n\t\t\t\t},\n\t\t\t\tVariableDeclarator(node) {\n\t\t\t\t\tif (node.init && isProcess(node.init) && node.id.type === 'ObjectPattern') {\n\t\t\t\t\t\tfor (const property of node.id.properties) {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tproperty.type === 'Property' &&\n\t\t\t\t\t\t\t\t(property.computed ? staticString(property.key) : exportName(property.key)) ===\n\t\t\t\t\t\t\t\t\t'env'\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tcontext.report({ node: property, messageId: 'env' })\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'schema-file-boundaries': {\n\t\tmeta: metadata('Keep storage shapes and indexes in their documented owners.', {\n\t\t\tschema: '{{builder}} belongs in {{file}}.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\treturn {\n\t\t\t\tCallExpression(node) {\n\t\t\t\t\tconst ref = imported(context, node.callee)\n\t\t\t\t\tconst file = appFile(context)\n\t\t\t\t\tif (!file) return\n\t\t\t\t\tlet expected: string | null = null\n\t\t\t\t\tif (ref?.source === 'convex/server') {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tref.name === 'defineSchema' &&\n\t\t\t\t\t\t\tfile !== 'schema.ts' &&\n\t\t\t\t\t\t\t!(componentRoot(context, context.filename) && basename(file) === 'schema.ts')\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\texpected = 'the root schema.ts (or a component schema.ts)'\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tref.name === 'defineTable' &&\n\t\t\t\t\t\t\t!(\n\t\t\t\t\t\t\t\tcomponentRoot(context, context.filename) &&\n\t\t\t\t\t\t\t\t['schema.ts', 'table.ts'].includes(basename(file))\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\texpected =\n\t\t\t\t\t\t\t\t'a component schema.ts/table.ts; host tables use zodTable in domain/<module>/schema.ts'\n\t\t\t\t\t}\n\t\t\t\t\tif (\n\t\t\t\t\t\tref &&\n\t\t\t\t\t\t['cvx-kit', 'cvx-kit/zod-table'].includes(ref.source) &&\n\t\t\t\t\t\t['zodTable', 'tenantTable', 'zodVariantTable'].includes(ref.name) &&\n\t\t\t\t\t\t!/^domain\\/[^/]+\\/schema\\.ts$/.test(file)\n\t\t\t\t\t)\n\t\t\t\t\t\texpected = 'domain/<module>/schema.ts'\n\t\t\t\t\tif (expected)\n\t\t\t\t\t\tcontext.report({\n\t\t\t\t\t\t\tnode,\n\t\t\t\t\t\t\tmessageId: 'schema',\n\t\t\t\t\t\t\tdata: { builder: ref?.name ?? 'table', file: expected },\n\t\t\t\t\t\t})\n\t\t\t\t\tif (\n\t\t\t\t\t\tnode.callee.type === 'MemberExpression' &&\n\t\t\t\t\t\t['index', 'searchIndex', 'vectorIndex'].includes(propertyName(node.callee) ?? '') &&\n\t\t\t\t\t\tisTableChain(node.callee.object) &&\n\t\t\t\t\t\t!componentRoot(context, context.filename) &&\n\t\t\t\t\t\t!/^domain\\/[^/]+\\/table\\.ts$/.test(file)\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontext.report({\n\t\t\t\t\t\t\tnode,\n\t\t\t\t\t\t\tmessageId: 'schema',\n\t\t\t\t\t\t\tdata: { builder: 'Table indexes', file: 'domain/<module>/table.ts' },\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'no-internal-reexports': {\n\t\tmeta: metadata('Import from owning modules directly; consumer apps have no barrels.', {\n\t\t\treexport: 'Import from the owning file directly; do not re-export imports inside convex/.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tfunction check(node: ESTree.ExportNamedDeclaration | ESTree.ExportAllDeclaration) {\n\t\t\t\tif (node.source) {\n\t\t\t\t\tcontext.report({ node, messageId: 'reexport' })\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tfor (const specifier of node.type === 'ExportNamedDeclaration' ? node.specifiers : []) {\n\t\t\t\t\tif (binding(context, specifier.local)?.defs.some((def) => def.type === 'ImportBinding')) {\n\t\t\t\t\t\tcontext.report({ node: specifier, messageId: 'reexport' })\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tExportNamedDeclaration: check,\n\t\t\t\tExportAllDeclaration: check,\n\t\t\t\tExportDefaultDeclaration(node) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tnode.declaration.type === 'Identifier' &&\n\t\t\t\t\t\tbinding(context, node.declaration)?.defs.some((def) => def.type === 'ImportBinding')\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontext.report({ node, messageId: 'reexport' })\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'public-api-first': {\n\t\tmeta: metadata('Place private helper implementations after the exported API.', {\n\t\t\torder:\n\t\t\t\t'Move this private helper below the exported API so the file reads from public purpose to implementation.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\treturn {\n\t\t\t\tProgram(node) {\n\t\t\t\t\tconst exports = exportedNames(node)\n\t\t\t\t\tconst lastExport = node.body.findLastIndex((statement) =>\n\t\t\t\t\t\tstatement.type.startsWith('Export'),\n\t\t\t\t\t)\n\t\t\t\t\tfor (const statement of node.body.slice(0, lastExport < 0 ? 0 : lastExport)) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tstatement.type === 'FunctionDeclaration' &&\n\t\t\t\t\t\t\tstatement.id &&\n\t\t\t\t\t\t\t!exports.has(statement.id.name)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tcontext.report({ node: statement, messageId: 'order' })\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'named-private-helpers': {\n\t\tmeta: metadata('Use named declarations for top-level private helper functions.', {\n\t\t\thelper: 'Declare this private helper with function name(...) at the bottom of the file.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\treturn {\n\t\t\t\tProgram(node) {\n\t\t\t\t\tconst exports = exportedNames(node)\n\t\t\t\t\tfor (const statement of node.body) {\n\t\t\t\t\t\tif (statement.type !== 'VariableDeclaration') continue\n\t\t\t\t\t\tfor (const declaration of statement.declarations) {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tdeclaration.id.type === 'Identifier' &&\n\t\t\t\t\t\t\t\t!exports.has(declaration.id.name) &&\n\t\t\t\t\t\t\t\t(declaration.init?.type === 'ArrowFunctionExpression' ||\n\t\t\t\t\t\t\t\t\tdeclaration.init?.type === 'FunctionExpression')\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tcontext.report({ node: declaration, messageId: 'helper' })\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n}\n\nexport const rules: Record<RuleName, Rule> = scopeRules(applicationRules)\nconst plugin: Plugin = { meta: { name: 'cvx' }, rules }\nexport default plugin\n\nfunction scopeRules(source: Record<RuleName, CreateRule>): Record<RuleName, Rule> {\n\tconst scoped = { ...source }\n\t// SAFETY: source is the closed applicationRules record; its own keys are exactly RuleName.\n\tconst names = Object.keys(source) as RuleName[]\n\tfor (const name of names) {\n\t\tconst rule = source[name]\n\t\tscoped[name] = {\n\t\t\tmeta: {\n\t\t\t\t...rule.meta,\n\t\t\t\tschema: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'object',\n\t\t\t\t\t\tproperties: { convexDir: { type: 'string', minLength: 1 } },\n\t\t\t\t\t\tadditionalProperties: false,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t\tcreate(context) {\n\t\t\t\tconst file = appFile(context)\n\t\t\t\tif (\n\t\t\t\t\t!file ||\n\t\t\t\t\t/(?:^|\\/)(?:_generated|__tests__)(?:\\/|$)/.test(file) ||\n\t\t\t\t\t/\\.(?:test|spec)\\.[cm]?[jt]s$/.test(file)\n\t\t\t\t)\n\t\t\t\t\treturn {}\n\t\t\t\treturn rule.create(context)\n\t\t\t},\n\t\t}\n\t}\n\treturn scoped\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"oxlint.mjs","names":["checkArchitecture","inspectArchitecture","options","rules","scopeRules","ownershipRules","reservedDomainFiles","metadata","componentRoot","context","seen","check","ref","imported","node","file","appFile","resolver","createResolver","importedSource","target","resolveImport","source","specifier","name","exportName","sourceVisitors","resolved","sep","from","to","forbidden","basename","isFunctionsImport","exported","exportedNames","statement","declaration","isDbWrite","values","propertyName","hasCall","data","property","field","staticString","owner","relative","dirname","isProcess","variable","binding","def","object","globalProcess","expected","isTableChain","exports","lastExport","plugin","scoped","names","rule"],"sources":["../src/oxlint.ts"],"sourcesContent":["import { basename, dirname, relative, sep } from 'node:path'\nimport type { CreateRule, ESTree, Plugin, Rule } from '@oxlint/plugins'\nimport {\n\tinspectArchitecture,\n\tcreateResolver,\n\tresolveImport,\n\ttype ArchitectureOptions,\n\ttype ArchitectureDiagnostic,\n} from './oxlint/architecture'\nimport { reservedDomainFiles } from './oxlint/reserved-files'\nimport { ownershipRules, type OwnershipRuleName } from './oxlint/ownership'\nimport {\n\tappFile,\n\timported,\n\tsourceVisitors,\n\tisFunctionsImport,\n\tisTableChain,\n\tisDbWrite,\n\thasCall,\n\tmetadata,\n\tcomponentRoot,\n\tstaticString,\n\tpropertyName,\n\tbinding,\n\texportedNames,\n\texportName,\n} from './oxlint/ast'\n\nexport type { ArchitectureOptions, ArchitectureDiagnostic } from './oxlint/architecture'\n\nexport function checkArchitecture(options: ArchitectureOptions = {}): ArchitectureDiagnostic[] {\n\treturn inspectArchitecture(options)\n}\n\nexport type RuleName =\n\t| OwnershipRuleName\n\t| 'component-boundaries'\n\t| 'no-component-env'\n\t| 'schema-file-boundaries'\n\t| 'no-internal-reexports'\n\t| 'public-api-first'\n\t| 'named-private-helpers'\n\t| 'no-raw-builders'\n\t| 'no-handwritten-references'\n\t| 'domain-import-boundaries'\n\t| 'public-functions-in-api'\n\t| 'thin-api-adapters'\n\t| 'no-inline-enums'\n\t| 'no-unbounded-reads'\n\t| 'no-manual-timestamps'\n\t| 'reserved-domain-file-anatomy'\n\t| 'root-facade-ownership'\n\n/** Consumer application rules derived from docs/conventions.md. */\nconst applicationRules: Record<RuleName, CreateRule> = {\n\t...ownershipRules,\n\t'reserved-domain-file-anatomy': reservedDomainFiles,\n\t'root-facade-ownership': {\n\t\tmeta: metadata('Configure shared kit infrastructure once in its root facade.', {\n\t\t\tfacade: 'Configure {{name}} once in convex/{{file}}; import that facade elsewhere.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tif (componentRoot(context, context.filename)) return {}\n\t\t\tconst seen = new Set<string>()\n\t\t\tfunction check(node: ESTree.CallExpression | ESTree.NewExpression) {\n\t\t\t\tconst ref = imported(context, node.callee)\n\t\t\t\tif (!ref) return\n\t\t\t\tlet file: string | null = null\n\t\t\t\tif (['cvx-kit', 'cvx-kit/auth'].includes(ref.source) && ref.name === 'createAuthFunctions')\n\t\t\t\t\tfile = 'functions.ts'\n\t\t\t\tif (['cvx-kit', 'cvx-kit/triggers'].includes(ref.source) && ref.name === 'createTriggers')\n\t\t\t\t\tfile = 'triggers.ts'\n\t\t\t\tif (\n\t\t\t\t\t['cvx-kit', 'cvx-kit/components/foundation'].includes(ref.source) &&\n\t\t\t\t\tref.name === 'Foundation'\n\t\t\t\t)\n\t\t\t\t\tfile = 'foundation.ts'\n\t\t\t\tif (\n\t\t\t\t\t(ref.source === 'cvx-kit/effect' && ref.name === 'createEffectFoundation') ||\n\t\t\t\t\t(ref.source === 'cvx-kit' && ref.name === 'createFoundation')\n\t\t\t\t)\n\t\t\t\t\tfile = 'foundation.ts'\n\t\t\t\tif (!file) return\n\t\t\t\tif (appFile(context) !== file || seen.has(ref.name))\n\t\t\t\t\tcontext.report({ node, messageId: 'facade', data: { name: ref.name, file } })\n\t\t\t\tseen.add(ref.name)\n\t\t\t}\n\t\t\treturn { CallExpression: check, NewExpression: check }\n\t\t},\n\t},\n\t'no-raw-builders': {\n\t\tmeta: metadata('Build host functions through the auth-aware root constructors.', {\n\t\t\tbuilder:\n\t\t\t\t'Import raw builders only in convex/functions.ts; use auth*/role*/admin* or system* elsewhere.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tif (appFile(context) === 'functions.ts' || componentRoot(context, context.filename)) return {}\n\t\t\tconst resolver = createResolver()\n\t\t\treturn {\n\t\t\t\tImportDeclaration(node) {\n\t\t\t\t\tif (node.importKind === 'type') return\n\t\t\t\t\tconst importedSource = node.source.value\n\t\t\t\t\tconst target = resolveImport(resolver, context.filename, importedSource)\n\t\t\t\t\tconst source =\n\t\t\t\t\t\ttarget && appFile(context, target)?.startsWith('_generated/')\n\t\t\t\t\t\t\t? appFile(context, target)!\n\t\t\t\t\t\t\t: importedSource\n\t\t\t\t\tif (\n\t\t\t\t\t\t!/(?:^|\\/)_generated\\/server(?:\\.[cm]?[jt]s)?$/.test(source) &&\n\t\t\t\t\t\tsource !== 'convex/server'\n\t\t\t\t\t)\n\t\t\t\t\t\treturn\n\t\t\t\t\tfor (const specifier of node.specifiers) {\n\t\t\t\t\t\tif (specifier.type === 'ImportSpecifier' && specifier.importKind === 'type') continue\n\t\t\t\t\t\tconst name =\n\t\t\t\t\t\t\tspecifier.type === 'ImportSpecifier' ? exportName(specifier.imported) : null\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t(name === null && source !== 'convex/server') ||\n\t\t\t\t\t\t\t(name &&\n\t\t\t\t\t\t\t\t/^(?:internal)?(?:Query|Mutation|Action)(?:Generic)?$|^(?:query|mutation|action)(?:Generic)?$/.test(\n\t\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\t))\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tcontext.report({ node: specifier, messageId: 'builder' })\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tCallExpression(node) {\n\t\t\t\t\tconst ref = imported(context, node.callee)\n\t\t\t\t\tif (\n\t\t\t\t\t\tref?.source === 'convex/server' &&\n\t\t\t\t\t\t/^(?:internal)?(?:Query|Mutation|Action)Generic$|^(?:query|mutation|action)Generic$/.test(\n\t\t\t\t\t\t\tref.name,\n\t\t\t\t\t\t) &&\n\t\t\t\t\t\tnode.callee.type === 'MemberExpression'\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontext.report({ node, messageId: 'builder' })\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'no-handwritten-references': {\n\t\tmeta: metadata('Use generated api/internal references.', {\n\t\t\treference: 'Use generated api/internal references instead of makeFunctionReference.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\treturn {\n\t\t\t\tCallExpression(node) {\n\t\t\t\t\tconst ref = imported(context, node.callee)\n\t\t\t\t\tif (ref?.source === 'convex/server' && ref.name === 'makeFunctionReference')\n\t\t\t\t\t\tcontext.report({ node, messageId: 'reference' })\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'domain-import-boundaries': {\n\t\tmeta: metadata('Keep api, application, domain, and shared dependencies directed.', {\n\t\t\tboundary:\n\t\t\t\t'Follow api → application/domain → shared; sibling modules expose only rules.ts and queries.ts.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tconst file = appFile(context)\n\t\t\tconst resolver = createResolver()\n\t\t\treturn sourceVisitors(context, (node, source) => {\n\t\t\t\tif (!file) return\n\t\t\t\tconst resolved = resolveImport(resolver, context.filename, source)\n\t\t\t\tif (!resolved) return\n\t\t\t\tconst target = appFile(context, resolved)?.replace(/\\.[cm]?[jt]s$/, '')\n\t\t\t\tif (!target) {\n\t\t\t\t\tif (!resolved.split(sep).includes('node_modules'))\n\t\t\t\t\t\tcontext.report({ node, messageId: 'boundary' })\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tconst from = file.split('/')\n\t\t\t\tconst to = target.split('/')\n\t\t\t\tlet forbidden = false\n\t\t\t\tif (from[0] === 'domain') {\n\t\t\t\t\tforbidden = ['api', 'application', 'migrations'].includes(to[0])\n\t\t\t\t\tif (\n\t\t\t\t\t\tto[0] === 'domain' &&\n\t\t\t\t\t\tfrom[1] !== to[1] &&\n\t\t\t\t\t\tto[1] !== 'shared' &&\n\t\t\t\t\t\tfrom[1] !== 'table.ts'\n\t\t\t\t\t) {\n\t\t\t\t\t\tforbidden =\n\t\t\t\t\t\t\tfrom[1] === 'shared' || !['rules', 'queries'].includes(to.slice(2).join('/'))\n\t\t\t\t\t}\n\t\t\t\t} else if (from[0] === 'api') {\n\t\t\t\t\tforbidden =\n\t\t\t\t\t\t['api', 'migrations'].includes(to[0]) ||\n\t\t\t\t\t\t(to[0] === 'domain' &&\n\t\t\t\t\t\t\tto[1] !== 'shared' &&\n\t\t\t\t\t\t\tto[1] !== (from.length > 2 ? from[1] : basename(file).replace(/\\.[cm]?[jt]s$/, '')))\n\t\t\t\t} else if (from[0] === 'application') forbidden = ['api', 'migrations'].includes(to[0])\n\t\t\t\tif (to[0] === 'migrations' && from[0] !== 'migrations') forbidden = true\n\t\t\t\tif (\n\t\t\t\t\t['api', 'domain', 'application'].includes(from[0]) &&\n\t\t\t\t\tto.length > 1 &&\n\t\t\t\t\t!['api', 'domain', 'application', '_generated', 'components', 'migrations'].includes(\n\t\t\t\t\t\tto[0],\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t\t\tforbidden = true\n\t\t\t\tif (forbidden) context.report({ node, messageId: 'boundary' })\n\t\t\t})\n\t\t},\n\t},\n\t'public-functions-in-api': {\n\t\tmeta: metadata('Expose authenticated public functions only through api/.', {\n\t\t\tpublic: 'Declare public auth*/role*/admin* functions in convex/api/<module>.ts.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tif (appFile(context)?.startsWith('api/')) return {}\n\t\t\treturn {\n\t\t\t\tCallExpression(node) {\n\t\t\t\t\tconst ref = imported(context, node.callee)\n\t\t\t\t\tif (\n\t\t\t\t\t\tnode.callee.type !== 'CallExpression' &&\n\t\t\t\t\t\tref &&\n\t\t\t\t\t\tisFunctionsImport(context, ref.source) &&\n\t\t\t\t\t\t/^(auth|role|admin)(Query|Mutation|Action)$/.test(ref.name)\n\t\t\t\t\t)\n\t\t\t\t\t\tcontext.report({ node, messageId: 'public' })\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'thin-api-adapters': {\n\t\tmeta: metadata('Keep business decisions and writes in domain executors.', {\n\t\t\tadapter:\n\t\t\t\t'Move business branches, private helpers, and database writes into the owning domain executor.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tif (!appFile(context)?.startsWith('api/')) return {}\n\t\t\treturn {\n\t\t\t\tIfStatement(node) {\n\t\t\t\t\tcontext.report({ node, messageId: 'adapter' })\n\t\t\t\t},\n\t\t\t\tSwitchStatement(node) {\n\t\t\t\t\tcontext.report({ node, messageId: 'adapter' })\n\t\t\t\t},\n\t\t\t\tConditionalExpression(node) {\n\t\t\t\t\tcontext.report({ node, messageId: 'adapter' })\n\t\t\t\t},\n\t\t\t\tProgram(node) {\n\t\t\t\t\tconst exported = exportedNames(node)\n\t\t\t\t\tfor (const statement of node.body) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tstatement.type === 'FunctionDeclaration' &&\n\t\t\t\t\t\t\tstatement.id &&\n\t\t\t\t\t\t\t!exported.has(statement.id.name)\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\tcontext.report({ node: statement, messageId: 'adapter' })\n\t\t\t\t\t\tif (statement.type === 'VariableDeclaration')\n\t\t\t\t\t\t\tfor (const declaration of statement.declarations) {\n\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\tdeclaration.id.type === 'Identifier' &&\n\t\t\t\t\t\t\t\t\t!exported.has(declaration.id.name) &&\n\t\t\t\t\t\t\t\t\t['ArrowFunctionExpression', 'FunctionExpression'].includes(\n\t\t\t\t\t\t\t\t\t\tdeclaration.init?.type ?? '',\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\tcontext.report({ node: declaration, messageId: 'adapter' })\n\t\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tCallExpression(node) {\n\t\t\t\t\tif (isDbWrite(node)) context.report({ node, messageId: 'adapter' })\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'no-inline-enums': {\n\t\tmeta: metadata('Keep vocabularies in named constants.ts tuples.', {\n\t\t\tvocabulary: 'Define a named readonly tuple in constants.ts and pass it to z.enum().',\n\t\t}),\n\t\tcreate(context) {\n\t\t\treturn {\n\t\t\t\tCallExpression(node) {\n\t\t\t\t\tconst ref = imported(context, node.callee)\n\t\t\t\t\tlet values = node.arguments[0]\n\t\t\t\t\twhile (values?.type === 'TSAsExpression' || values?.type === 'TSSatisfiesExpression')\n\t\t\t\t\t\tvalues = values.expression\n\t\t\t\t\tif (\n\t\t\t\t\t\tref &&\n\t\t\t\t\t\t/^zod(?:\\/v4)?$/.test(ref.source) &&\n\t\t\t\t\t\tref.name === 'enum' &&\n\t\t\t\t\t\tvalues?.type === 'ArrayExpression'\n\t\t\t\t\t)\n\t\t\t\t\t\tcontext.report({ node, messageId: 'vocabulary' })\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'no-unbounded-reads': {\n\t\tmeta: metadata('Bound collection reads through include or pagination.', {\n\t\t\tbounded:\n\t\t\t\t'Use include(...).execute(limit) or bounded pagination; do not collect() or resolve() an unbounded query.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tif (componentRoot(context, context.filename)) return {}\n\t\t\treturn {\n\t\t\t\tCallExpression(node) {\n\t\t\t\t\tif (node.callee.type !== 'MemberExpression') return\n\t\t\t\t\tconst name = propertyName(node.callee)\n\t\t\t\t\tif (\n\t\t\t\t\t\t(name === 'collect' && hasCall(node.callee.object, 'query')) ||\n\t\t\t\t\t\t(name === 'resolve' && hasCall(node.callee.object, 'include'))\n\t\t\t\t\t)\n\t\t\t\t\t\tcontext.report({ node, messageId: 'bounded' })\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'no-manual-timestamps': {\n\t\tmeta: metadata('Let timestamps triggers own createdAt and updatedAt.', {\n\t\t\ttimestamp: 'Remove {{field}} from this write; register the timestamps trigger instead.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tif (componentRoot(context, context.filename)) return {}\n\t\t\treturn {\n\t\t\t\tCallExpression(node) {\n\t\t\t\t\tif (!isDbWrite(node)) return\n\t\t\t\t\tconst data = node.arguments.at(-1)\n\t\t\t\t\tif (data?.type !== 'ObjectExpression') return\n\t\t\t\t\tfor (const property of data.properties) {\n\t\t\t\t\t\tif (property.type !== 'Property') continue\n\t\t\t\t\t\tconst field = property.computed ? staticString(property.key) : exportName(property.key)\n\t\t\t\t\t\tif (field === 'createdAt' || field === 'updatedAt')\n\t\t\t\t\t\t\tcontext.report({ node: property, messageId: 'timestamp', data: { field } })\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'component-boundaries': {\n\t\tmeta: metadata('Keep portable components isolated and consume their client facades.', {\n\t\t\tboundary:\n\t\t\t\t'Components may import only their own files and npm dependencies; inject host policy through the client API.',\n\t\t\tfacade: 'Import a component through its client.ts facade, not its private implementation.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tconst owner = componentRoot(context, context.filename)\n\t\t\tconst resolver = createResolver()\n\n\t\t\treturn sourceVisitors(context, (node, specifier) => {\n\t\t\t\tif (!specifier.startsWith('.')) {\n\t\t\t\t\tif (\n\t\t\t\t\t\t/^cvx-kit\\/components\\/[^/]+\\//.test(specifier) &&\n\t\t\t\t\t\t!/^cvx-kit\\/components\\/[^/]+\\/convex\\.config(?:\\.js)?$/.test(specifier)\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontext.report({ node, messageId: 'facade' })\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst target = resolveImport(resolver, context.filename, specifier)\n\t\t\t\tif (!target || target.split(sep).includes('node_modules')) return\n\t\t\t\tif (\n\t\t\t\t\towner &&\n\t\t\t\t\t(relative(owner, target).startsWith(`..${sep}`) || target === dirname(owner))\n\t\t\t\t) {\n\t\t\t\t\tcontext.report({ node, messageId: 'boundary' })\n\t\t\t\t} else if (\n\t\t\t\t\t!owner &&\n\t\t\t\t\tcomponentRoot(context, target) &&\n\t\t\t\t\t!/^client(?:\\.[cm]?[jt]s)?$/.test(basename(target)) &&\n\t\t\t\t\t!(\n\t\t\t\t\t\tappFile(context) === 'convex.config.ts' &&\n\t\t\t\t\t\t/^convex\\.config(?:\\.[cm]?[jt]s)?$/.test(basename(target))\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tcontext.report({ node, messageId: 'facade' })\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\t},\n\t'no-component-env': {\n\t\tmeta: metadata('Pass environment configuration into portable components.', {\n\t\t\tenv: 'Portable components must receive configuration through arguments; do not read process.env.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tif (!componentRoot(context, context.filename)) return {}\n\t\t\tfunction isProcess(node: ESTree.Node) {\n\t\t\t\tif (node.type !== 'Identifier') return false\n\t\t\t\tconst variable = binding(context, node)\n\t\t\t\tif (node.name === 'process' && !variable?.defs.length) return true\n\t\t\t\treturn variable?.defs.some(\n\t\t\t\t\t(def) =>\n\t\t\t\t\t\tdef.type === 'ImportBinding' &&\n\t\t\t\t\t\tdef.parent?.type === 'ImportDeclaration' &&\n\t\t\t\t\t\t['node:process', 'process'].includes(def.parent.source.value) &&\n\t\t\t\t\t\t['ImportDefaultSpecifier', 'ImportNamespaceSpecifier'].includes(def.node.type),\n\t\t\t\t)\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tImportDeclaration(node) {\n\t\t\t\t\tif (['node:process', 'process'].includes(node.source.value)) {\n\t\t\t\t\t\tfor (const specifier of node.specifiers) {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tspecifier.type === 'ImportSpecifier' &&\n\t\t\t\t\t\t\t\texportName(specifier.imported) === 'env'\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tcontext.report({ node: specifier, messageId: 'env' })\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tMemberExpression(node) {\n\t\t\t\t\tif (propertyName(node) !== 'env') return\n\t\t\t\t\tconst object = node.object\n\t\t\t\t\tconst globalProcess =\n\t\t\t\t\t\tobject.type === 'MemberExpression' &&\n\t\t\t\t\t\tpropertyName(object) === 'process' &&\n\t\t\t\t\t\tobject.object.type === 'Identifier' &&\n\t\t\t\t\t\tobject.object.name === 'globalThis' &&\n\t\t\t\t\t\t!binding(context, object.object)?.defs.length\n\t\t\t\t\tif (isProcess(object) || globalProcess) context.report({ node, messageId: 'env' })\n\t\t\t\t},\n\t\t\t\tVariableDeclarator(node) {\n\t\t\t\t\tif (node.init && isProcess(node.init) && node.id.type === 'ObjectPattern') {\n\t\t\t\t\t\tfor (const property of node.id.properties) {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tproperty.type === 'Property' &&\n\t\t\t\t\t\t\t\t(property.computed ? staticString(property.key) : exportName(property.key)) ===\n\t\t\t\t\t\t\t\t\t'env'\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tcontext.report({ node: property, messageId: 'env' })\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'schema-file-boundaries': {\n\t\tmeta: metadata('Keep storage shapes and indexes in their documented owners.', {\n\t\t\tschema: '{{builder}} belongs in {{file}}.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\treturn {\n\t\t\t\tCallExpression(node) {\n\t\t\t\t\tconst ref = imported(context, node.callee)\n\t\t\t\t\tconst file = appFile(context)\n\t\t\t\t\tif (!file) return\n\t\t\t\t\tlet expected: string | null = null\n\t\t\t\t\tif (ref?.source === 'convex/server') {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tref.name === 'defineSchema' &&\n\t\t\t\t\t\t\tfile !== 'schema.ts' &&\n\t\t\t\t\t\t\t!(componentRoot(context, context.filename) && basename(file) === 'schema.ts')\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\texpected = 'the root schema.ts (or a component schema.ts)'\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tref.name === 'defineTable' &&\n\t\t\t\t\t\t\t!(\n\t\t\t\t\t\t\t\tcomponentRoot(context, context.filename) &&\n\t\t\t\t\t\t\t\t['schema.ts', 'table.ts'].includes(basename(file))\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\texpected =\n\t\t\t\t\t\t\t\t'a component schema.ts/table.ts; host tables use zodTable in domain/<module>/schema.ts'\n\t\t\t\t\t}\n\t\t\t\t\tif (\n\t\t\t\t\t\tref &&\n\t\t\t\t\t\t['cvx-kit', 'cvx-kit/zod-table'].includes(ref.source) &&\n\t\t\t\t\t\t['zodTable', 'tenantTable', 'zodVariantTable'].includes(ref.name) &&\n\t\t\t\t\t\t!/^domain\\/[^/]+\\/schema\\.ts$/.test(file)\n\t\t\t\t\t)\n\t\t\t\t\t\texpected = 'domain/<module>/schema.ts'\n\t\t\t\t\tif (expected)\n\t\t\t\t\t\tcontext.report({\n\t\t\t\t\t\t\tnode,\n\t\t\t\t\t\t\tmessageId: 'schema',\n\t\t\t\t\t\t\tdata: { builder: ref?.name ?? 'table', file: expected },\n\t\t\t\t\t\t})\n\t\t\t\t\tif (\n\t\t\t\t\t\tnode.callee.type === 'MemberExpression' &&\n\t\t\t\t\t\t['index', 'searchIndex', 'vectorIndex'].includes(propertyName(node.callee) ?? '') &&\n\t\t\t\t\t\tisTableChain(node.callee.object) &&\n\t\t\t\t\t\t!componentRoot(context, context.filename) &&\n\t\t\t\t\t\t!/^domain\\/[^/]+\\/table\\.ts$/.test(file)\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontext.report({\n\t\t\t\t\t\t\tnode,\n\t\t\t\t\t\t\tmessageId: 'schema',\n\t\t\t\t\t\t\tdata: { builder: 'Table indexes', file: 'domain/<module>/table.ts' },\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'no-internal-reexports': {\n\t\tmeta: metadata('Import from owning modules directly; consumer apps have no barrels.', {\n\t\t\treexport: 'Import from the owning file directly; do not re-export imports inside convex/.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\tfunction check(node: ESTree.ExportNamedDeclaration | ESTree.ExportAllDeclaration) {\n\t\t\t\tif (node.source) {\n\t\t\t\t\tcontext.report({ node, messageId: 'reexport' })\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\tfor (const specifier of node.type === 'ExportNamedDeclaration' ? node.specifiers : []) {\n\t\t\t\t\tif (binding(context, specifier.local)?.defs.some((def) => def.type === 'ImportBinding')) {\n\t\t\t\t\t\tcontext.report({ node: specifier, messageId: 'reexport' })\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tExportNamedDeclaration: check,\n\t\t\t\tExportAllDeclaration: check,\n\t\t\t\tExportDefaultDeclaration(node) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tnode.declaration.type === 'Identifier' &&\n\t\t\t\t\t\tbinding(context, node.declaration)?.defs.some((def) => def.type === 'ImportBinding')\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontext.report({ node, messageId: 'reexport' })\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'public-api-first': {\n\t\tmeta: metadata('Place private helper implementations after the exported API.', {\n\t\t\torder:\n\t\t\t\t'Move this private helper below the exported API so the file reads from public purpose to implementation.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\treturn {\n\t\t\t\tProgram(node) {\n\t\t\t\t\tconst exports = exportedNames(node)\n\t\t\t\t\tconst lastExport = node.body.findLastIndex((statement) =>\n\t\t\t\t\t\tstatement.type.startsWith('Export'),\n\t\t\t\t\t)\n\t\t\t\t\tfor (const statement of node.body.slice(0, lastExport < 0 ? 0 : lastExport)) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tstatement.type === 'FunctionDeclaration' &&\n\t\t\t\t\t\t\tstatement.id &&\n\t\t\t\t\t\t\t!exports.has(statement.id.name)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tcontext.report({ node: statement, messageId: 'order' })\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n\t'named-private-helpers': {\n\t\tmeta: metadata('Use named declarations for top-level private helper functions.', {\n\t\t\thelper: 'Declare this private helper with function name(...) at the bottom of the file.',\n\t\t}),\n\t\tcreate(context) {\n\t\t\treturn {\n\t\t\t\tProgram(node) {\n\t\t\t\t\tconst exports = exportedNames(node)\n\t\t\t\t\tfor (const statement of node.body) {\n\t\t\t\t\t\tif (statement.type !== 'VariableDeclaration') continue\n\t\t\t\t\t\tfor (const declaration of statement.declarations) {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tdeclaration.id.type === 'Identifier' &&\n\t\t\t\t\t\t\t\t!exports.has(declaration.id.name) &&\n\t\t\t\t\t\t\t\t(declaration.init?.type === 'ArrowFunctionExpression' ||\n\t\t\t\t\t\t\t\t\tdeclaration.init?.type === 'FunctionExpression')\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tcontext.report({ node: declaration, messageId: 'helper' })\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t}\n\t\t},\n\t},\n}\n\nexport const rules: Record<RuleName, Rule> = scopeRules(applicationRules)\nconst plugin: Plugin = { meta: { name: 'cvx' }, rules }\nexport default plugin\n\nfunction scopeRules(source: Record<RuleName, CreateRule>): Record<RuleName, Rule> {\n\tconst scoped = { ...source }\n\t// SAFETY: source is the closed applicationRules record; its own keys are exactly RuleName.\n\tconst names = Object.keys(source) as RuleName[]\n\tfor (const name of names) {\n\t\tconst rule = source[name]\n\t\tscoped[name] = {\n\t\t\tmeta: {\n\t\t\t\t...rule.meta,\n\t\t\t\tschema: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'object',\n\t\t\t\t\t\tproperties: { convexDir: { type: 'string', minLength: 1 } },\n\t\t\t\t\t\tadditionalProperties: false,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t},\n\t\t\tcreate(context) {\n\t\t\t\tconst file = appFile(context)\n\t\t\t\tif (\n\t\t\t\t\t!file ||\n\t\t\t\t\t/(?:^|\\/)(?:_generated|__tests__)(?:\\/|$)/.test(file) ||\n\t\t\t\t\t/\\.(?:test|spec)\\.[cm]?[jt]s$/.test(file)\n\t\t\t\t)\n\t\t\t\t\treturn {}\n\t\t\t\treturn rule.create(context)\n\t\t\t},\n\t\t}\n\t}\n\treturn scoped\n}\n"],"mappings":"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"}
@@ -241,7 +241,7 @@ The public API layer then wraps the executor in an `authMutation` and passes
241
241
  8. **Complete**: await the closure returned by `prepare`, including when audit
242
242
  returns null. A failure propagates inside the observation boundary.
243
243
  9. **Emit the observation**: `{ operation, classification, outcome,
244
- errorCode?, durationMs }` — completed, denied, or failed per
244
+ errorCode?, durationMs }` — completed, denied, or failed per
245
245
  `classifyError`.
246
246
 
247
247
  ### Guards and permissions
@@ -509,3 +509,5 @@ knowing. Metadata defaults are set at construction and merged per-executor.
509
509
  telemetry silently disappears (see regexes above).
510
510
  5. Keep operation registries frozen (`as const`) in the domain's
511
511
  `commands.ts`; vocabulary tuples live in `constants.ts`.
512
+
513
+ See [Optional domain contracts](./domain-contracts.md) for shared declarations, named implementations, and registry audit defaults in both Effect and Promise registries.
@@ -121,7 +121,7 @@ another file's function to shorten an import.
121
121
  | `schema.ts` | `defineSchema(domainTables)` | table definitions, validators |
122
122
  | `functions.ts` | the single `createAuthFunctions<DataModel>()` call and its exported constructors | handlers, business policy beyond the injected config |
123
123
  | `triggers.ts` | `createTriggers()`, `timestamps`/`appendOnly`/`noDelete` registrations, calls to per-entity `register<Entity>Triggers` | trigger _logic_ for a specific entity (that lives in the entity) |
124
- | `foundation.ts` | the single `createEffectFoundation(...)`, bound command/query exports | command definitions |
124
+ | `foundation.ts` | one `createEffectFoundation(...)` or `createFoundation(...)`, bound command/query exports | command definitions |
125
125
  | `<component>.ts` | `new <Client>(components.<name>)` + minimal admin plumbing | workflow/business definitions |
126
126
  | `http.ts` | route registration delegating request handling to the owning domain | webhook business logic |
127
127
  | `crons.ts` | `cronJobs()` declarations targeting `internal.domain.<entity>...` | handler logic |
@@ -155,7 +155,7 @@ moves to the domain.
155
155
 
156
156
  ### `domain/<entity>/schema.ts` — shapes only
157
157
 
158
- - The entity's single `zodTable(...)` call, with `serverFields`,
158
+ - The module's `zodTable(...)` declarations (one per owned table), with `serverFields`,
159
159
  `commandFields`, `publicFields` decided deliberately.
160
160
  - DTO compositions derived from the table's boundaries
161
161
  (`z.object({ ...<entity>.publicDto.shape, ... }).strict()`).
@@ -318,7 +318,7 @@ component internals (anything below a component's client facade),
318
318
  - Zod objects that cross a boundary are `.strict()` — always.
319
319
  - `Object.freeze` for registries and long-lived configuration objects.
320
320
  - Comments state constraints the code can't (`// Optional only for rows
321
- created before <epoch>.`) — never narration of the next line.
321
+ created before <epoch>.`) — never narration of the next line.
322
322
  - One entity concept per file; when a file serves two purposes, split it
323
323
  along the anatomy in §2.
324
324
 
@@ -327,3 +327,7 @@ Optional request context can be added through the existing Effect API adapter's
327
327
  and consume `ctx.commands.exec(name, input)` through the application's existing
328
328
  function helper names. Keep dependencies local to each feature; explicit execution
329
329
  and input-only command handlers remain supported. See [optional context injection](./command-context.md).
330
+
331
+ ### Reserved domain declarations
332
+
333
+ Existing commands.ts and queries.ts each export one kit-backed Command or Query registry. Contracts.ts contains schemas, an optional defineDomainContract declaration, and an optional root error contract; handlers stay in their registries. See [Optional domain contracts](./domain-contracts.md).