{ "type": "object", "additionalProperties": false, "properties": { "files": { "$ref": "#/$defs/FilesTable", "description": "Which files to scan for imports, whatever their language." }, "languages": { "$ref": "#/$defs/LanguagesTable", "description": "The languages to scan, each in a table of its own. A language is\nenabled when its table is written, even if empty. Without a\n`[languages]` table, the default languages are enabled with their\ndefaults; an empty one enables nothing, which is an error." }, "analysis": { "$ref": "#/$defs/AnalysisTable", "description": "Defaults that apply to every contract." }, "baseline": { "$ref": "#/$defs/BaselineTable", "description": "The baseline of known violations, which `zenith check` ignores so that\nonly new violations fail it." }, "cache": { "$ref": "#/$defs/CacheTable", "description": "The cache of what zenith found in each file on earlier runs, which\nlets it skip reading and parsing the files that haven't changed since." }, "contracts": { "type": "object", "additionalProperties": { "$ref": "#/$defs/ContractTable" }, "description": "The architecture contracts, keyed by id. Ids may contain ASCII\nletters, digits, `-` and `_`, and are what `--contract`, the baseline\nand `zenith-ignore` comments refer to." } }, "title": "zenith.toml", "description": "The configuration of a zenith project. It lives at the project root, which\nall of its paths are relative to.", "$schema": "https://json-schema.org/draft/2020-12/schema", "$defs": { "JsTable": { "type": "object", "additionalProperties": false, "properties": { "include": { "type": "array", "items": { "type": "string" }, "description": "Globs of the files to scan. Defaults to every JavaScript and\nTypeScript file, `**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}`." }, "tsconfig": { "type": "string", "description": "Which `tsconfig.json` files to use: `\"auto\"` (the default) uses the\nnearest one of each file, `\"off\"` uses none, and any other value is\nthe path of the one to use for every file." }, "conditions": { "type": "array", "items": { "type": "string" }, "description": "The condition names to match in `exports` maps, replacing the\ndefaults: `types`, `source`, `import`, `module`, `require`, `node`\nand `default`. Conditions are matched in the order that each package\nlists them." }, "main_fields": { "type": "array", "items": { "type": "string" }, "description": "The `package.json` fields that point at a package's entry point,\nreplacing the defaults: `module`, then `main`." }, "extensions": { "type": "array", "items": { "type": "string" }, "description": "The extensions to try, in order, when a specifier has none, replacing\nthe defaults: `.ts`, `.tsx`, `.d.ts`, `.mts`, `.cts`, `.js`, `.jsx`,\n`.mjs`, `.cjs` and `.json`." }, "alias": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Bundler-only aliases: a specifier prefix, and the path that it maps\nto.", "default": {} }, "ignore_unresolved": { "type": "array", "items": { "type": "string" }, "description": "Name patterns of specifiers that are expected not to resolve, so are\nnot reported as unresolved, e.g. `\"/*\"` for files served from a public\ndirectory, or `\"virtual:*\"`.", "default": [] } }, "description": "JavaScript and TypeScript." }, "GoTable": { "type": "object", "additionalProperties": false, "properties": { "include": { "type": "array", "items": { "type": "string" }, "description": "Globs of the files to scan. Defaults to every Go file, `**/*.go`." }, "ignore_unresolved": { "type": "array", "items": { "type": "string" }, "description": "Name patterns of import paths that are expected not to resolve, so\nare not reported as unresolved.", "default": [] } }, "description": "Go." }, "PythonTable": { "type": "object", "additionalProperties": false, "properties": { "include": { "type": "array", "items": { "type": "string" }, "description": "Globs of the files to scan. Defaults to every Python file and stub,\n`**/*.py` and `**/*.pyi`." }, "roots": { "type": "array", "items": { "type": "string" }, "description": "The directories that absolute imports start from, relative to the\nproject root, as on `sys.path`. Defaults to the `src` directory of each\npackage with a `pyproject.toml`, or the package's own directory when it\nhas none, and the project root." }, "ignore_unresolved": { "type": "array", "items": { "type": "string" }, "description": "Name patterns of module paths that are expected not to resolve, so\nare not reported as unresolved.", "default": [] } }, "description": "Python." }, "RustTable": { "type": "object", "additionalProperties": false, "properties": { "include": { "type": "array", "items": { "type": "string" }, "description": "Globs of the files to scan. Defaults to every Rust file, `**/*.rs`." }, "ignore_unresolved": { "type": "array", "items": { "type": "string" }, "description": "Name patterns of paths that are expected not to resolve, so are not\nreported as unresolved, e.g. `\"generated::*\"` for a module that a\nmacro declares.", "default": [] } }, "description": "Rust." }, "TerraformTable": { "type": "object", "additionalProperties": false, "properties": { "include": { "type": "array", "items": { "type": "string" }, "description": "Globs of the files to scan. Defaults to every Terraform, OpenTofu and\nTerragrunt file: `**/*.tf`, `**/*.tofu` and `**/terragrunt.hcl`." }, "ignore_unresolved": { "type": "array", "items": { "type": "string" }, "description": "Name patterns of module sources and dependency paths that are expected\nnot to resolve, so are not reported as unresolved.", "default": [] }, "registries": { "type": "array", "items": { "type": "string" }, "description": "Name patterns of hosts that serve the public registry's modules, such\nas a mirror, whose modules are named as the public registry's are,\nbesides the public registries themselves.", "default": [] }, "repository_hosts": { "type": "array", "items": { "type": "string" }, "description": "Name patterns of hosts of repositories that module sources may name\nwithout a scheme, as they name GitHub's, such as a GitHub Enterprise\nserver, besides `github.com` and `bitbucket.org`.", "default": [] }, "bucket_hosts": { "type": "array", "items": { "type": "string" }, "description": "Name patterns of hosts of buckets that module sources may name without\na scheme, as they name S3's, besides `*.amazonaws.com` and\n`www.googleapis.com`.", "default": [] } }, "description": "Terraform, OpenTofu and Terragrunt." }, "FilesTable": { "type": "object", "additionalProperties": false, "properties": { "exclude": { "type": "array", "items": { "type": "string" }, "description": "Globs of files and directories to skip, on top of the default\nexcludes, such as `node_modules` and `.next`.", "default": [] }, "respect_gitignore": { "type": "boolean", "description": "Whether to skip the files that `.gitignore`, `.ignore` and the global\ngit excludes ignore.", "default": true } }, "description": "Which files to scan for imports, whatever their language." }, "LanguagesTable": { "type": "object", "additionalProperties": false, "description": "The languages to scan, each in a table of its own.", "properties": { "js": { "$ref": "#/$defs/JsTable", "description": "JavaScript and TypeScript: how their files are found and their imports resolved." }, "typescript": { "$ref": "#/$defs/JsTable", "description": "Another name for `js`. Giving both is an error." }, "go": { "$ref": "#/$defs/GoTable", "description": "Go: how its files are found and their imports resolved." }, "python": { "$ref": "#/$defs/PythonTable", "description": "Python: how its files are found and the imports between its modules resolved." }, "rust": { "$ref": "#/$defs/RustTable", "description": "Rust: how its files are found and the imports between its crates and modules resolved." }, "terraform": { "$ref": "#/$defs/TerraformTable", "description": "Terraform, OpenTofu and Terragrunt: how their files are found and their module sources resolved." } } }, "AnalysisTable": { "type": "object", "additionalProperties": false, "properties": { "exclude_kinds": { "type": "array", "items": { "$ref": "#/$defs/ImportKind" }, "description": "The import kinds that contracts ignore unless they set their own\n`exclude_kinds`, e.g. `[\"type\"]` to exempt type-only imports.", "default": [] }, "reexports": { "$ref": "#/$defs/Reexports", "description": "How contracts see the imports of pass-through modules, the files that\nonly re-export other modules, unless they set their own `reexports`.", "default": "opaque" } }, "description": "Defaults that apply to every contract." }, "ImportKind": { "oneOf": [ { "type": "string", "const": "value", "description": "A static value import or re-export: `import x from \"s\"`, `import \"s\"`,\n`export * from \"s\"`." }, { "type": "string", "const": "type", "description": "A type-only import that is erased at runtime: `import type`, an\nimport whose specifiers are all `type`, or `typeof import(\"s\")`." }, { "type": "string", "const": "dynamic", "description": "A dynamic `import(\"s\")` with a literal specifier." }, { "type": "string", "const": "require", "description": "A CommonJS `require(\"s\")` or TypeScript `import x = require(\"s\")`." } ], "description": "How an import is made. Contracts can exclude imports of given kinds, e.g.\nto exempt type-only imports." }, "Reexports": { "oneOf": [ { "type": "string", "const": "opaque", "description": "An import of a pass-through module imports it, and so every module\nit re-exports." }, { "type": "string", "const": "transparent", "description": "An import of names from a pass-through module imports the modules that\ndefine them, as a bundler that leaves out unused modules loads them." } ], "description": "How a contract sees the imports of pass-through modules, the files that only\nre-export other modules." }, "BaselineTable": { "type": "object", "additionalProperties": false, "properties": { "path": { "type": "string", "description": "The path of the baseline file.", "default": "zenith.baseline.toml" }, "stale": { "$ref": "#/$defs/StaleLevel", "description": "How to report baseline entries whose import no longer exists:\n`\"error\"` fails the check, so that the baseline can only shrink, and\n`\"warn\"` reports a warning.", "default": "error" } }, "description": "The baseline of known violations." }, "StaleLevel": { "oneOf": [ { "type": "string", "const": "error", "description": "Stale entries fail the check, so the baseline can only shrink." }, { "type": "string", "const": "warn", "description": "Stale entries are reported as warnings." } ], "description": "How to report baseline entries whose import no longer exists." }, "CacheTable": { "type": "object", "additionalProperties": false, "properties": { "enabled": { "type": "boolean", "description": "Whether to use the cache. `--no-cache` turns it off for one run.", "default": true }, "dir": { "type": "string", "description": "The directory to keep the cache in. Zenith creates it, with a\n`.gitignore` that ignores everything in it.", "default": ".zenith_cache" } }, "description": "The cache of what zenith found in each file on earlier runs." }, "ContractTable": { "oneOf": [ { "type": "object", "additionalProperties": false, "properties": { "from": { "type": "array", "items": { "$ref": "#/$defs/SelectorValue" }, "description": "The modules that must not import the `to` modules." }, "to": { "type": "array", "items": { "$ref": "#/$defs/SelectorValue" }, "description": "The modules that must not be imported. External packages (`npm:`)\nand builtins (`node:`, `bun:`) are allowed, with `js` enabled." }, "allow_indirect_imports": { "type": "boolean", "description": "If `true`, only direct imports count, rather than chains of\nimports too.", "default": false }, "boundaries": { "type": "array", "items": { "$ref": "#/$defs/SelectorValue" }, "description": "Modules that chains of imports may start or end at, but not pass\nthrough, e.g. `{ path = \"web/**\", directive = \"use server\" }`:\nclient code that imports a server function gets a reference to\nit, not the code that it imports. Has no effect on direct imports,\nso it can't be set with `allow_indirect_imports`." }, "name": { "type": "string", "description": "The title shown in output. Defaults to the contract id." }, "severity": { "$ref": "#/$defs/Severity", "description": "`\"warn\"` reports the contract without failing the check when it\nis broken, for gradual rollout.", "default": "error" }, "exclude_kinds": { "type": "array", "items": { "$ref": "#/$defs/ImportKind" }, "description": "Import kinds to ignore, e.g. `[\"type\"]` to exempt type-only\nimports. Defaults to `[analysis] exclude_kinds`." }, "reexports": { "$ref": "#/$defs/Reexports", "description": "How to see the imports of pass-through modules, the files that only\nre-export other modules: `\"opaque\"`, an import of a pass-through module\nimports every module it re-exports, or `\"transparent\"`, an\nimport of names from it imports the modules that define them.\nDefaults to `[analysis] reexports`." }, "ignore_imports": { "type": "array", "items": { "type": "string" }, "description": "Imports to ignore, as `\" -> \"`: the direct\nimports from the first selector's modules to the second's are\nremoved before checking.", "default": [] }, "unmatched_ignore_imports": { "$ref": "#/$defs/AlertLevel", "description": "How to report an `ignore_imports` entry that matches no import:\n`\"error\"` breaks the contract, `\"warn\"` reports a warning, and\n`\"none\"` says nothing.", "default": "error" }, "guidance": { "type": "string", "description": "Text shown under the violations, e.g. how to fix them." }, "type": { "type": "string", "const": "forbidden" } }, "required": [ "type", "from", "to" ], "description": "The `from` modules must not import the `to` modules, directly or\nthrough other modules." }, { "type": "object", "additionalProperties": false, "properties": { "modules": { "type": "array", "items": { "$ref": "#/$defs/SelectorValue" }, "description": "The modules that must not depend on one another." }, "allow_indirect_imports": { "type": "boolean", "description": "If `true`, only direct imports count, rather than chains of\nimports too.", "default": false }, "boundaries": { "type": "array", "items": { "$ref": "#/$defs/SelectorValue" }, "description": "Modules that chains of imports may start or end at, but not pass\nthrough, e.g. `{ path = \"web/**\", directive = \"use server\" }`:\nclient code that imports a server function gets a reference to\nit, not the code that it imports. Has no effect on direct imports,\nso it can't be set with `allow_indirect_imports`." }, "name": { "type": "string", "description": "The title shown in output. Defaults to the contract id." }, "severity": { "$ref": "#/$defs/Severity", "description": "`\"warn\"` reports the contract without failing the check when it\nis broken, for gradual rollout.", "default": "error" }, "exclude_kinds": { "type": "array", "items": { "$ref": "#/$defs/ImportKind" }, "description": "Import kinds to ignore, e.g. `[\"type\"]` to exempt type-only\nimports. Defaults to `[analysis] exclude_kinds`." }, "reexports": { "$ref": "#/$defs/Reexports", "description": "How to see the imports of pass-through modules, the files that only\nre-export other modules: `\"opaque\"`, an import of a pass-through module\nimports every module it re-exports, or `\"transparent\"`, an\nimport of names from it imports the modules that define them.\nDefaults to `[analysis] reexports`." }, "ignore_imports": { "type": "array", "items": { "type": "string" }, "description": "Imports to ignore, as `\" -> \"`: the direct\nimports from the first selector's modules to the second's are\nremoved before checking.", "default": [] }, "unmatched_ignore_imports": { "$ref": "#/$defs/AlertLevel", "description": "How to report an `ignore_imports` entry that matches no import:\n`\"error\"` breaks the contract, `\"warn\"` reports a warning, and\n`\"none\"` says nothing.", "default": "error" }, "guidance": { "type": "string", "description": "Text shown under the violations, e.g. how to fix them." }, "type": { "type": "string", "const": "independence" } }, "required": [ "type", "modules" ], "description": "The modules must not depend on one another, directly or through other\nmodules." }, { "type": "object", "additionalProperties": false, "properties": { "layers": { "type": "array", "items": { "$ref": "#/$defs/LayerValue" }, "description": "The layers, from highest to lowest. Higher layers may import lower\nlayers, never the reverse." }, "containers": { "type": "array", "items": { "$ref": "#/$defs/SelectorValue" }, "description": "If set, the layers are paths relative to each container, and each\ncontainer is checked on its own." }, "exhaustive": { "type": "boolean", "description": "Whether every child of every container must be declared as a\nlayer. Requires `containers`.", "default": false }, "exhaustive_ignores": { "type": "array", "items": { "type": "string" }, "description": "Children exempt from `exhaustive`: name patterns matched against\nthe base name with or without its JS/TS extension, so `index`\nmatches `index.ts`.", "default": [] }, "allow_indirect_imports": { "type": "boolean", "description": "If `true`, only direct imports count, rather than chains of\nimports too.", "default": false }, "boundaries": { "type": "array", "items": { "$ref": "#/$defs/SelectorValue" }, "description": "Modules that chains of imports may start or end at, but not pass\nthrough, e.g. `{ path = \"web/**\", directive = \"use server\" }`:\nclient code that imports a server function gets a reference to\nit, not the code that it imports. Has no effect on direct imports,\nso it can't be set with `allow_indirect_imports`." }, "name": { "type": "string", "description": "The title shown in output. Defaults to the contract id." }, "severity": { "$ref": "#/$defs/Severity", "description": "`\"warn\"` reports the contract without failing the check when it\nis broken, for gradual rollout.", "default": "error" }, "exclude_kinds": { "type": "array", "items": { "$ref": "#/$defs/ImportKind" }, "description": "Import kinds to ignore, e.g. `[\"type\"]` to exempt type-only\nimports. Defaults to `[analysis] exclude_kinds`." }, "reexports": { "$ref": "#/$defs/Reexports", "description": "How to see the imports of pass-through modules, the files that only\nre-export other modules: `\"opaque\"`, an import of a pass-through module\nimports every module it re-exports, or `\"transparent\"`, an\nimport of names from it imports the modules that define them.\nDefaults to `[analysis] reexports`." }, "ignore_imports": { "type": "array", "items": { "type": "string" }, "description": "Imports to ignore, as `\" -> \"`: the direct\nimports from the first selector's modules to the second's are\nremoved before checking.", "default": [] }, "unmatched_ignore_imports": { "$ref": "#/$defs/AlertLevel", "description": "How to report an `ignore_imports` entry that matches no import:\n`\"error\"` breaks the contract, `\"warn\"` reports a warning, and\n`\"none\"` says nothing.", "default": "error" }, "guidance": { "type": "string", "description": "Text shown under the violations, e.g. how to fix them." }, "type": { "type": "string", "const": "layers" } }, "required": [ "type", "layers" ], "description": "Higher layers may import lower layers, never the reverse." }, { "type": "object", "additionalProperties": false, "properties": { "modules": { "type": "array", "items": { "$ref": "#/$defs/SelectorValue" }, "description": "The protected modules." }, "allowed_importers": { "type": "array", "items": { "$ref": "#/$defs/SelectorValue" }, "description": "The only modules that may directly import the protected modules,\nbesides the protected modules themselves." }, "name": { "type": "string", "description": "The title shown in output. Defaults to the contract id." }, "severity": { "$ref": "#/$defs/Severity", "description": "`\"warn\"` reports the contract without failing the check when it\nis broken, for gradual rollout.", "default": "error" }, "exclude_kinds": { "type": "array", "items": { "$ref": "#/$defs/ImportKind" }, "description": "Import kinds to ignore, e.g. `[\"type\"]` to exempt type-only\nimports. Defaults to `[analysis] exclude_kinds`." }, "reexports": { "$ref": "#/$defs/Reexports", "description": "How to see the imports of pass-through modules, the files that only\nre-export other modules: `\"opaque\"`, an import of a pass-through module\nimports every module it re-exports, or `\"transparent\"`, an\nimport of names from it imports the modules that define them.\nDefaults to `[analysis] reexports`." }, "ignore_imports": { "type": "array", "items": { "type": "string" }, "description": "Imports to ignore, as `\" -> \"`: the direct\nimports from the first selector's modules to the second's are\nremoved before checking.", "default": [] }, "unmatched_ignore_imports": { "$ref": "#/$defs/AlertLevel", "description": "How to report an `ignore_imports` entry that matches no import:\n`\"error\"` breaks the contract, `\"warn\"` reports a warning, and\n`\"none\"` says nothing.", "default": "error" }, "guidance": { "type": "string", "description": "Text shown under the violations, e.g. how to fix them." }, "type": { "type": "string", "const": "protected" } }, "required": [ "type", "modules", "allowed_importers" ], "description": "Only the allowed importers, and the modules themselves, may directly\nimport the modules." }, { "type": "object", "additionalProperties": false, "properties": { "modules": { "type": "array", "items": { "$ref": "#/$defs/SelectorValue" }, "description": "The modules that must not form dependency cycles, e.g. `[\"pkg:*\"]`." }, "depth": { "type": "integer", "format": "uint32", "minimum": 0, "description": "How many further generations of children to check: with `1`, the\nchildren of each directory module must not form cycles either.", "default": 0 }, "skip": { "type": "array", "items": { "$ref": "#/$defs/SelectorValue" }, "description": "Modules whose children are not checked." }, "name": { "type": "string", "description": "The title shown in output. Defaults to the contract id." }, "severity": { "$ref": "#/$defs/Severity", "description": "`\"warn\"` reports the contract without failing the check when it\nis broken, for gradual rollout.", "default": "error" }, "exclude_kinds": { "type": "array", "items": { "$ref": "#/$defs/ImportKind" }, "description": "Import kinds to ignore, e.g. `[\"type\"]` to exempt type-only\nimports. Defaults to `[analysis] exclude_kinds`." }, "reexports": { "$ref": "#/$defs/Reexports", "description": "How to see the imports of pass-through modules, the files that only\nre-export other modules: `\"opaque\"`, an import of a pass-through module\nimports every module it re-exports, or `\"transparent\"`, an\nimport of names from it imports the modules that define them.\nDefaults to `[analysis] reexports`." }, "ignore_imports": { "type": "array", "items": { "type": "string" }, "description": "Imports to ignore, as `\" -> \"`: the direct\nimports from the first selector's modules to the second's are\nremoved before checking.", "default": [] }, "unmatched_ignore_imports": { "$ref": "#/$defs/AlertLevel", "description": "How to report an `ignore_imports` entry that matches no import:\n`\"error\"` breaks the contract, `\"warn\"` reports a warning, and\n`\"none\"` says nothing.", "default": "error" }, "guidance": { "type": "string", "description": "Text shown under the violations, e.g. how to fix them." }, "type": { "type": "string", "const": "acyclic" } }, "required": [ "type", "modules" ], "description": "The modules must not form dependency cycles." }, { "type": "object", "additionalProperties": false, "properties": { "modules": { "type": "array", "items": { "$ref": "#/$defs/SelectorValue" }, "description": "The encapsulated modules, which must be directories." }, "entrypoints": { "type": "array", "items": { "type": "string" }, "description": "Globs, relative to each module, of the files that code outside it\nmay import. They ignore JS/TS extensions, so `index` matches\n`index.ts`, and match files only: `public/**` exposes a directory.", "default": [ "index" ] }, "allowed_importers": { "type": "array", "items": { "$ref": "#/$defs/SelectorValue" }, "description": "Modules that may import any file of the encapsulated modules, e.g.\ntests." }, "name": { "type": "string", "description": "The title shown in output. Defaults to the contract id." }, "severity": { "$ref": "#/$defs/Severity", "description": "`\"warn\"` reports the contract without failing the check when it\nis broken, for gradual rollout.", "default": "error" }, "exclude_kinds": { "type": "array", "items": { "$ref": "#/$defs/ImportKind" }, "description": "Import kinds to ignore, e.g. `[\"type\"]` to exempt type-only\nimports. Defaults to `[analysis] exclude_kinds`." }, "reexports": { "$ref": "#/$defs/Reexports", "description": "How to see the imports of pass-through modules, the files that only\nre-export other modules: `\"opaque\"`, an import of a pass-through module\nimports every module it re-exports, or `\"transparent\"`, an\nimport of names from it imports the modules that define them.\nDefaults to `[analysis] reexports`." }, "ignore_imports": { "type": "array", "items": { "type": "string" }, "description": "Imports to ignore, as `\" -> \"`: the direct\nimports from the first selector's modules to the second's are\nremoved before checking.", "default": [] }, "unmatched_ignore_imports": { "$ref": "#/$defs/AlertLevel", "description": "How to report an `ignore_imports` entry that matches no import:\n`\"error\"` breaks the contract, `\"warn\"` reports a warning, and\n`\"none\"` says nothing.", "default": "error" }, "guidance": { "type": "string", "description": "Text shown under the violations, e.g. how to fix them." }, "type": { "type": "string", "const": "encapsulation" } }, "required": [ "type", "modules" ], "description": "Code outside each module may only import it through its entry points." }, { "type": "object", "additionalProperties": false, "properties": { "modules": { "type": "array", "items": { "$ref": "#/$defs/SelectorValue" }, "description": "The modules whose imports are counted, each on its own." }, "max_fan_in": { "type": "integer", "format": "uint", "minimum": 0, "description": "The most files outside each module that may import it. A file\ncounts once, however many of the module's files it imports." }, "max_fan_out": { "type": "integer", "format": "uint", "minimum": 0, "description": "The most files and packages of the project outside each module\nthat it may import. External packages and builtins don't count. A\nfile or package counts once, however many of the module's files\nimport it." }, "name": { "type": "string", "description": "The title shown in output. Defaults to the contract id." }, "severity": { "$ref": "#/$defs/Severity", "description": "`\"warn\"` reports the contract without failing the check when it\nis broken, for gradual rollout.", "default": "error" }, "exclude_kinds": { "type": "array", "items": { "$ref": "#/$defs/ImportKind" }, "description": "Import kinds to ignore, e.g. `[\"type\"]` to exempt type-only\nimports. Defaults to `[analysis] exclude_kinds`." }, "reexports": { "$ref": "#/$defs/Reexports", "description": "How to see the imports of pass-through modules, the files that only\nre-export other modules: `\"opaque\"`, an import of a pass-through module\nimports every module it re-exports, or `\"transparent\"`, an\nimport of names from it imports the modules that define them.\nDefaults to `[analysis] reexports`." }, "ignore_imports": { "type": "array", "items": { "type": "string" }, "description": "Imports to ignore, as `\" -> \"`: the direct\nimports from the first selector's modules to the second's are\nremoved before checking.", "default": [] }, "unmatched_ignore_imports": { "$ref": "#/$defs/AlertLevel", "description": "How to report an `ignore_imports` entry that matches no import:\n`\"error\"` breaks the contract, `\"warn\"` reports a warning, and\n`\"none\"` says nothing.", "default": "error" }, "guidance": { "type": "string", "description": "Text shown under the violations, e.g. how to fix them." }, "type": { "type": "string", "const": "limits" } }, "required": [ "type", "modules" ], "description": "Each module may only be imported by so many other modules, and import\nso many.", "anyOf": [ { "required": [ "max_fan_in" ] }, { "required": [ "max_fan_out" ] } ] } ], "description": "An architecture contract. Its `type` says what it checks." }, "SelectorValue": { "anyOf": [ { "type": "string", "description": "A selector." }, { "$ref": "#/$defs/SelectorTable", "description": "A selector with filters." } ], "description": "A selector of modules: a path glob such as `web/src/domains/*`, a\nworkspace package (`pkg:@acme/*`), an external package (`npm:react`), a\nbuiltin (`node:*` or `bun:*`), or a table that filters one. External\npackages and builtins belong to the `js` language, which must be enabled." }, "SelectorTable": { "type": "object", "additionalProperties": false, "properties": { "path": { "type": "string", "description": "The selector, in any of its string forms." }, "except": { "type": "array", "items": { "type": "string" }, "description": "Selectors of modules to remove from each matched module.", "default": [] }, "directive": { "type": "string", "description": "Keep only the files that start with this directive, such as\n`\"use client\"`, each as a module of its own." } }, "required": [ "path" ], "description": "A selector with filters." }, "Severity": { "oneOf": [ { "type": "string", "const": "error", "description": "A broken contract fails the check." }, { "type": "string", "const": "warn", "description": "A broken contract is reported without failing the check." } ], "description": "How severe a broken contract is." }, "AlertLevel": { "oneOf": [ { "type": "string", "const": "error", "description": "The contract is broken." }, { "type": "string", "const": "warn", "description": "A warning is reported." }, { "type": "string", "const": "none", "description": "Nothing is reported." } ], "description": "How to report an `ignore_imports` entry that matches no import." }, "LayerValue": { "anyOf": [ { "type": "string", "description": "A layer." }, { "$ref": "#/$defs/LayerTable", "description": "A layer with options." } ], "description": "A layer of a `layers` contract: `\"a\"`, `\"a | b\"` for independent siblings\nthat may not import each other, `\"a : b\"` for siblings that may, and\n`\"(a)\"` for a member that may be missing. Members are selectors." }, "LayerTable": { "type": "object", "additionalProperties": false, "properties": { "layer": { "type": "string", "description": "The layer, in its string form." }, "closed": { "type": "boolean", "description": "Whether the layer is closed: the layers above it may not import the\nlayers below it.", "default": false } }, "required": [ "layer" ], "description": "A layer with options." } } }