@webpieces/nx-webpieces-rules 0.4.843 → 0.4.845

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 (63) hide show
  1. package/package.json +13 -8
  2. package/src/configs/api-doc-rules-config.d.ts +59 -0
  3. package/src/configs/api-doc-rules-config.js +70 -0
  4. package/src/configs/api-doc-rules-config.js.map +1 -0
  5. package/src/configs/no-root-union-config.d.ts +25 -0
  6. package/src/configs/no-root-union-config.js +33 -0
  7. package/src/configs/no-root-union-config.js.map +1 -0
  8. package/src/configs/rule-configs.d.ts +67 -0
  9. package/src/configs/rule-configs.js +147 -0
  10. package/src/configs/rule-configs.js.map +1 -0
  11. package/src/configs/tag-truth-configs.d.ts +72 -0
  12. package/src/configs/tag-truth-configs.js +98 -0
  13. package/src/configs/tag-truth-configs.js.map +1 -0
  14. package/src/executors/validate-catch-error-pattern/executor.d.ts +1 -1
  15. package/src/executors/validate-catch-error-pattern/executor.js.map +1 -1
  16. package/src/executors/validate-dtos/executor.d.ts +1 -1
  17. package/src/executors/validate-dtos/executor.js.map +1 -1
  18. package/src/executors/validate-modified-files/executor.d.ts +1 -1
  19. package/src/executors/validate-modified-files/executor.js.map +1 -1
  20. package/src/executors/validate-modified-methods/executor.d.ts +1 -1
  21. package/src/executors/validate-modified-methods/executor.js.map +1 -1
  22. package/src/executors/validate-new-methods/executor.d.ts +1 -1
  23. package/src/executors/validate-new-methods/executor.js.map +1 -1
  24. package/src/executors/validate-no-any-unknown/executor.d.ts +1 -1
  25. package/src/executors/validate-no-any-unknown/executor.js.map +1 -1
  26. package/src/executors/validate-no-destructure/executor.d.ts +1 -1
  27. package/src/executors/validate-no-destructure/executor.js.map +1 -1
  28. package/src/executors/validate-no-direct-api-resolver/executor.d.ts +1 -1
  29. package/src/executors/validate-no-direct-api-resolver/executor.js.map +1 -1
  30. package/src/executors/validate-no-implicit-any/executor.d.ts +1 -1
  31. package/src/executors/validate-no-implicit-any/executor.js.map +1 -1
  32. package/src/executors/validate-no-inline-types/executor.d.ts +1 -1
  33. package/src/executors/validate-no-inline-types/executor.js.map +1 -1
  34. package/src/executors/validate-no-unmanaged-exceptions/executor.d.ts +1 -1
  35. package/src/executors/validate-no-unmanaged-exceptions/executor.js.map +1 -1
  36. package/src/executors/validate-prisma-converters/executor.d.ts +1 -1
  37. package/src/executors/validate-prisma-converters/executor.js.map +1 -1
  38. package/src/executors/validate-return-types/executor.d.ts +1 -1
  39. package/src/executors/validate-return-types/executor.js.map +1 -1
  40. package/src/index.d.ts +6 -0
  41. package/src/index.js +25 -1
  42. package/src/index.js.map +1 -1
  43. package/src/lib/api-usage/api-doc-rules.d.ts +2 -2
  44. package/src/lib/api-usage/api-doc-rules.js +2 -2
  45. package/src/lib/api-usage/api-doc-rules.js.map +1 -1
  46. package/src/lib/api-usage/root-union-scan.d.ts +1 -1
  47. package/src/lib/api-usage/root-union-scan.js +1 -1
  48. package/src/lib/api-usage/root-union-scan.js.map +1 -1
  49. package/src/lib/api-usage/wire-closure.d.ts +1 -1
  50. package/src/lib/api-usage/wire-closure.js +2 -2
  51. package/src/lib/api-usage/wire-closure.js.map +1 -1
  52. package/src/lib/tag-truth.d.ts +1 -1
  53. package/src/lib/tag-truth.js +11 -11
  54. package/src/lib/tag-truth.js.map +1 -1
  55. package/src/rule-migrations.d.ts +3 -0
  56. package/src/rule-migrations.js +11 -0
  57. package/src/rule-migrations.js.map +1 -0
  58. package/src/rule-pack.d.ts +2 -0
  59. package/src/rule-pack.js +35 -0
  60. package/src/rule-pack.js.map +1 -0
  61. package/src/rule-settings.d.ts +5 -0
  62. package/src/rule-settings.js +210 -0
  63. package/src/rule-settings.js.map +1 -0
@@ -1 +1 @@
1
- {"version":3,"file":"root-union-scan.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/lib/api-usage/root-union-scan.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `no-root-union-api-type` — REFUSE a request or response type that IS a union.\n *\n * ## Why this breaks the build instead of being a lint warning\n *\n * Both the OpenAI and the Anthropic function-calling APIs forbid `oneOf`/`anyOf`/`allOf` at the TOP\n * LEVEL of a tool's parameter schema. A server sends its WHOLE tool list on every request, so ONE\n * offending tool makes EVERY request return HTTP 400 — the entire client session is bricked, not\n * just that tool, and the symptom a user reports is that every OTHER tool stopped working. It\n * usually arrives by accident: an SDK turns a discriminated union at the root into `{oneOf: [...]}`.\n * Live reports: imagekit-developer/imagekit-nodejs#150, posthog/posthog#61359, vercel/ai#21350,\n * opentokenz/mcpx#28.\n *\n * NESTED composition — a union inside a property — is perfectly fine and is published as `oneOf`\n * with its derived discriminator (#1009). Only the ROOT is the problem.\n *\n * ## Why it lives in the RULES ENGINE and not in the doc parser\n *\n * `@webpieces/api-doc-model` only ever visits contracts that declare `@ApiType`, so a rule\n * implemented there could not — by construction — enforce anything on contracts that have not opted\n * in yet, which is exactly the population this rule exists to protect. `@ApiType` is a PUBLISHING\n * decision added later, on purpose; if the shape rules do not hold from the first line, then adding\n * the annotation becomes a migration nobody expects, on a type already in partners' generated\n * clients. The scan below walks EVERY `@ApiPath` contract in the workspace, `@ApiType` or not.\n *\n * ## Why it is PARSER-ONLY\n *\n * Same reason `ApiSourceIndexBuilder` is: a plain parse cannot be diverted to a decorator-erased\n * `.d.ts` by module resolution, and it is cheap enough to run over every project. The cost is that a\n * union alias declared in a package this workspace does not build is invisible — the same blind spot\n * every other check in this directory has, and the same one `recoverFromDeclaration` documents.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as ts from 'typescript';\nimport {\n loadAndValidate,\n matchesAnyGlob,\n WEBPIECES_DISABLE,\n RULE_NAMES,\n} from '@webpieces/rules-config';\nimport { ProjectInfo } from '../project-info';\nimport { RuleGate } from '../rule-gate';\nimport {\n collectTsFiles,\n hasClassDecorator,\n isAbstractClass,\n isTestFile,\n memberDecorator,\n typeReferenceName,\n} from './api-ast';\n\n/** The rule name, as it is written in a disable comment and as a config key. */\nexport const ROOT_UNION_RULE = RULE_NAMES.NO_ROOT_UNION_API_TYPE;\n\n/**\n * `// webpieces-disable no-root-union-api-type -- <reason>`, with the reason CAPTURED so a\n * reasonless one can be told apart from an absent one. A comma list of rules is the shared spelling\n * (`disable-directives.ts`), so it is accepted here too.\n */\nconst DISABLE_RE = new RegExp(\n `//\\\\s*${WEBPIECES_DISABLE}\\\\s+([\\\\w-]+(?:\\\\s*,\\\\s*[\\\\w-]+)*)(?:\\\\s*--\\\\s*(.*))?$`,\n);\n\n/**\n * The rule's SWITCHES, resolved from webpieces.config.json once per scan.\n *\n * Read here, not inside the scan, so a unit test constructs the scan with explicit values and never\n * touches a config file — and so the config is read exactly once per executor run, beside the\n * `externalApiPaths` read that already happens there.\n */\nexport class RootUnionRule {\n constructor(\n public readonly enabled: boolean,\n /** Project roots this rule does not apply to — `allowedPaths` in the config. */\n public readonly allowedPaths: readonly string[],\n ) {}\n\n /**\n * The DEFAULT: armed, everywhere. A rule entry that is absent means RUN — never invent a default\n * that silently disables a check (the same rule `RuleGate` states for the nx validators).\n */\n // webpieces-disable no-function-outside-class -- static factory of this class\n static enabledEverywhere(): RootUnionRule {\n return new RootUnionRule(true, []);\n }\n\n /** `mode: OFF` and the time-box/branch hatches come from RuleGate, so there is ONE reading of them. */\n // webpieces-disable no-function-outside-class -- static factory of this class\n static fromConfig(workspaceRoot: string): RootUnionRule {\n if (new RuleGate().isDisabled(workspaceRoot, ROOT_UNION_RULE, true)) {\n return new RootUnionRule(false, []);\n }\n const rule = loadAndValidate(workspaceRoot).resolved.rules.get(ROOT_UNION_RULE);\n const allowed = rule?.options['allowedPaths'];\n return new RootUnionRule(true, Array.isArray(allowed) ? (allowed as string[]) : []);\n }\n}\n\n/** ONE contract method whose request or response type is ITSELF a union. */\nexport class RootUnionApiType {\n constructor(\n /** The `@ApiPath` contract class. */\n public readonly api: string,\n /** The `@Endpoint` method on it. */\n public readonly method: string,\n /** `request` or `response` — which side carries the union. */\n public readonly side: string,\n /** The union type's NAME, as written on the method. */\n public readonly typeName: string,\n /** `path/to/File.ts:LINE`, workspace-relative. */\n public readonly at: string,\n /** True when a disable comment names this rule but gives NO reason. */\n public readonly disabledWithoutReason: boolean,\n ) {}\n}\n\n/** What one scan found. Two lists because the two have different cures. */\nexport class RootUnionFindings {\n constructor(\n /** Root-level unions with no disable at all. */\n public readonly violations: readonly RootUnionApiType[],\n /**\n * Sites that DID carry a disable for this rule and gave no reason. A reasonless disable is\n * itself a violation: the blast radius here is every tool in a session, so a suppression has\n * to carry an argument somebody wrote down and the next reader can weigh.\n */\n public readonly reasonlessDisables: readonly RootUnionApiType[],\n ) {}\n\n isEmpty(): boolean {\n return this.violations.length === 0 && this.reasonlessDisables.length === 0;\n }\n}\n\n/** One `type X = A | B` alias found in the workspace, keyed in the index by its NAME. */\nclass UnionAlias {\n constructor(\n public readonly name: string,\n /** The branch type names, in declaration order. */\n public readonly branches: readonly string[],\n ) {}\n}\n\n/** One `@Endpoint` method's declared request/response type names, with where to point an author. */\nclass EndpointTypes {\n constructor(\n public readonly api: string,\n public readonly method: string,\n public readonly requestType: string | null,\n public readonly responseType: string | null,\n public readonly at: string,\n /** The declaration's own lines, decorators included — where a disable comment may sit. */\n public readonly declarationText: string,\n ) {}\n}\n\n/**\n * Walks every project's `src/**` once, indexing union aliases and contract methods, then joins the\n * two. One pass, because the alias and the contract that uses it are routinely in different files\n * and often in different projects.\n */\nexport class RootUnionScan {\n private readonly aliases = new Map<string, UnionAlias>();\n private readonly endpoints: EndpointTypes[] = [];\n /** Alias name -> the disable comment written on its declaration, when it carries one. */\n private readonly aliasDisables = new Map<string, DisableComment>();\n\n constructor(\n private readonly workspaceRoot: string,\n private readonly projectInfos: Map<string, ProjectInfo>,\n /** The rule's switches. ARMED unless a caller read otherwise out of webpieces.config.json. */\n private readonly rule: RootUnionRule = RootUnionRule.enabledEverywhere(),\n ) {}\n\n run(): RootUnionFindings {\n if (!this.rule.enabled) return new RootUnionFindings([], []);\n for (const info of this.projectInfos.values()) {\n if (info.root === '' || info.root === '.') continue;\n if (matchesAnyGlob(info.root, this.rule.allowedPaths)) continue;\n this.indexProject(info);\n }\n const violations: RootUnionApiType[] = [];\n const reasonless: RootUnionApiType[] = [];\n for (const endpoint of this.endpoints) {\n this.judge(endpoint, 'request', endpoint.requestType, violations, reasonless);\n this.judge(endpoint, 'response', endpoint.responseType, violations, reasonless);\n }\n return new RootUnionFindings(violations, reasonless);\n }\n\n /** One side of one method: a union type name is a violation unless a REASONED disable covers it. */\n private judge(\n endpoint: EndpointTypes,\n side: string,\n typeName: string | null,\n violations: RootUnionApiType[],\n reasonless: RootUnionApiType[],\n ): void {\n if (typeName === null || !this.aliases.has(typeName)) return;\n // Either the method or the alias may carry the disable: the method is the site that\n // PUBLISHES the shape, and the alias is the declaration somebody will be looking at when\n // they decide the shape is deliberate. Both are \"the offending declaration\".\n const disable =\n DisableComment.readFrom(endpoint.declarationText) ?? this.aliasDisables.get(typeName);\n const found = new RootUnionApiType(\n endpoint.api,\n endpoint.method,\n side,\n typeName,\n endpoint.at,\n disable !== undefined && !disable.hasReason,\n );\n if (disable === undefined) {\n violations.push(found);\n return;\n }\n if (!disable.hasReason) reasonless.push(found);\n }\n\n private indexProject(info: ProjectInfo): void {\n const srcDir = path.join(path.resolve(this.workspaceRoot, info.root), 'src');\n if (!fs.existsSync(srcDir)) return;\n for (const file of collectTsFiles(srcDir)) {\n if (isTestFile(file)) continue; // a fixture is not a published contract\n const text = fs.readFileSync(file, 'utf8');\n const sourceFile = ts.createSourceFile(file, text, ts.ScriptTarget.Latest, true);\n this.indexNode(sourceFile, sourceFile);\n }\n }\n\n private indexNode(node: ts.Node, sourceFile: ts.SourceFile): void {\n if (ts.isTypeAliasDeclaration(node)) this.indexAlias(node, sourceFile);\n if (ts.isClassDeclaration(node)) this.indexContract(node, sourceFile);\n ts.forEachChild(node, (child: ts.Node) => this.indexNode(child, sourceFile));\n }\n\n /**\n * `type X = A | B` where at least two branches are NAMED types.\n *\n * A union of string literals (`type Phase = 'placed' | 'done'`) is deliberately NOT one: it\n * publishes as `enum`, which is a scalar and carries no `oneOf` at all. `| null` / `| undefined`\n * branches are dropped for the same reason the doc model drops them — they are nullability, not\n * composition.\n */\n private indexAlias(alias: ts.TypeAliasDeclaration, sourceFile: ts.SourceFile): void {\n if (!ts.isUnionTypeNode(alias.type)) return;\n const branches: string[] = [];\n for (const branch of alias.type.types) {\n if (RootUnionScan.isNullish(branch)) continue;\n const named = typeReferenceName(branch);\n if (named === null) return; // not a composition of named object types\n branches.push(named);\n }\n if (branches.length < 2) return;\n const name = alias.name.text;\n this.aliases.set(name, new UnionAlias(name, branches));\n const disable = DisableComment.readFrom(RootUnionScan.textOf(alias, sourceFile));\n if (disable !== undefined) this.aliasDisables.set(name, disable);\n }\n\n // webpieces-disable no-function-outside-class -- private static predicate of this class\n private static isNullish(node: ts.TypeNode): boolean {\n if (\n node.kind === ts.SyntaxKind.UndefinedKeyword ||\n node.kind === ts.SyntaxKind.NullKeyword\n ) {\n return true;\n }\n return ts.isLiteralTypeNode(node) && node.literal.kind === ts.SyntaxKind.NullKeyword;\n }\n\n /** Every `@Endpoint` method of an `abstract class` carrying `@ApiPath` — `@ApiType` or not. */\n private indexContract(cls: ts.ClassDeclaration, sourceFile: ts.SourceFile): void {\n if (!isAbstractClass(cls) || !hasClassDecorator(cls, 'ApiPath') || !cls.name) return;\n const api = cls.name.text;\n for (const member of cls.members) {\n if (!ts.isMethodDeclaration(member) || !ts.isIdentifier(member.name)) continue;\n if (memberDecorator(member, 'Endpoint') === null) continue;\n this.endpoints.push(\n new EndpointTypes(\n api,\n member.name.text,\n typeReferenceName(member.parameters[0]?.type),\n RootUnionScan.awaitedName(member.type),\n this.locate(member, sourceFile),\n RootUnionScan.textOf(member, sourceFile),\n ),\n );\n }\n }\n\n /** `Promise<T>` -> `T`'s name; a bare `T` is read as itself, so both spellings are covered. */\n // webpieces-disable no-function-outside-class -- private static accessor of this class\n private static awaitedName(declared: ts.TypeNode | undefined): string | null {\n if (declared === undefined || !ts.isTypeReferenceNode(declared)) return null;\n const outer = typeReferenceName(declared);\n if (outer !== 'Promise') return outer;\n const args = declared.typeArguments ?? [];\n return args.length === 1 ? typeReferenceName(args[0]) : null;\n }\n\n /**\n * The declaration's own source text INCLUDING its leading trivia, so a disable comment written\n * on the line above the first decorator is part of what is read.\n */\n // webpieces-disable no-function-outside-class -- private static accessor of this class\n private static textOf(node: ts.Node, sourceFile: ts.SourceFile): string {\n return sourceFile.text.slice(node.getFullStart(), node.getEnd());\n }\n\n private locate(node: ts.Node, sourceFile: ts.SourceFile): string {\n const position = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n return `${path.relative(this.workspaceRoot, sourceFile.fileName)}:${position.line + 1}`;\n }\n}\n\n/** ONE `webpieces-disable` naming this rule, and whether it gave a reason. */\nclass DisableComment {\n constructor(public readonly hasReason: boolean) {}\n\n /** The FIRST disable naming this rule in `text`, or undefined when it names none. */\n // webpieces-disable no-function-outside-class -- static factory of this class\n static readFrom(text: string): DisableComment | undefined {\n for (const line of text.split('\\n')) {\n const match = line.match(DISABLE_RE);\n if (match === null) continue;\n const named = match[1].split(',').map((each: string): string => each.trim());\n if (!named.includes(ROOT_UNION_RULE)) continue;\n return new DisableComment((match[2] ?? '').trim() !== '');\n }\n return undefined;\n }\n}\n"]}
1
+ {"version":3,"file":"root-union-scan.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/lib/api-usage/root-union-scan.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `no-root-union-api-type` — REFUSE a request or response type that IS a union.\n *\n * ## Why this breaks the build instead of being a lint warning\n *\n * Both the OpenAI and the Anthropic function-calling APIs forbid `oneOf`/`anyOf`/`allOf` at the TOP\n * LEVEL of a tool's parameter schema. A server sends its WHOLE tool list on every request, so ONE\n * offending tool makes EVERY request return HTTP 400 — the entire client session is bricked, not\n * just that tool, and the symptom a user reports is that every OTHER tool stopped working. It\n * usually arrives by accident: an SDK turns a discriminated union at the root into `{oneOf: [...]}`.\n * Live reports: imagekit-developer/imagekit-nodejs#150, posthog/posthog#61359, vercel/ai#21350,\n * opentokenz/mcpx#28.\n *\n * NESTED composition — a union inside a property — is perfectly fine and is published as `oneOf`\n * with its derived discriminator (#1009). Only the ROOT is the problem.\n *\n * ## Why it lives in the RULES ENGINE and not in the doc parser\n *\n * `@webpieces/api-doc-model` only ever visits contracts that declare `@ApiType`, so a rule\n * implemented there could not — by construction — enforce anything on contracts that have not opted\n * in yet, which is exactly the population this rule exists to protect. `@ApiType` is a PUBLISHING\n * decision added later, on purpose; if the shape rules do not hold from the first line, then adding\n * the annotation becomes a migration nobody expects, on a type already in partners' generated\n * clients. The scan below walks EVERY `@ApiPath` contract in the workspace, `@ApiType` or not.\n *\n * ## Why it is PARSER-ONLY\n *\n * Same reason `ApiSourceIndexBuilder` is: a plain parse cannot be diverted to a decorator-erased\n * `.d.ts` by module resolution, and it is cheap enough to run over every project. The cost is that a\n * union alias declared in a package this workspace does not build is invisible — the same blind spot\n * every other check in this directory has, and the same one `recoverFromDeclaration` documents.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as ts from 'typescript';\nimport { loadAndValidate, matchesAnyGlob, WEBPIECES_DISABLE } from '@webpieces/rules-config';\nimport { ProjectInfo } from '../project-info';\nimport { RuleGate } from '../rule-gate';\nimport {\n collectTsFiles,\n hasClassDecorator,\n isAbstractClass,\n isTestFile,\n memberDecorator,\n typeReferenceName,\n} from './api-ast';\n\n/** The rule name, as it is written in a disable comment and as a config key. */\nexport const ROOT_UNION_RULE = \"no-root-union-api-type\";\n\n/**\n * `// webpieces-disable no-root-union-api-type -- <reason>`, with the reason CAPTURED so a\n * reasonless one can be told apart from an absent one. A comma list of rules is the shared spelling\n * (`disable-directives.ts`), so it is accepted here too.\n */\nconst DISABLE_RE = new RegExp(\n `//\\\\s*${WEBPIECES_DISABLE}\\\\s+([\\\\w-]+(?:\\\\s*,\\\\s*[\\\\w-]+)*)(?:\\\\s*--\\\\s*(.*))?$`,\n);\n\n/**\n * The rule's SWITCHES, resolved from webpieces.config.json once per scan.\n *\n * Read here, not inside the scan, so a unit test constructs the scan with explicit values and never\n * touches a config file — and so the config is read exactly once per executor run, beside the\n * `externalApiPaths` read that already happens there.\n */\nexport class RootUnionRule {\n constructor(\n public readonly enabled: boolean,\n /** Project roots this rule does not apply to — `allowedPaths` in the config. */\n public readonly allowedPaths: readonly string[],\n ) {}\n\n /**\n * The DEFAULT: armed, everywhere. A rule entry that is absent means RUN — never invent a default\n * that silently disables a check (the same rule `RuleGate` states for the nx validators).\n */\n // webpieces-disable no-function-outside-class -- static factory of this class\n static enabledEverywhere(): RootUnionRule {\n return new RootUnionRule(true, []);\n }\n\n /** `mode: OFF` and the time-box/branch hatches come from RuleGate, so there is ONE reading of them. */\n // webpieces-disable no-function-outside-class -- static factory of this class\n static fromConfig(workspaceRoot: string): RootUnionRule {\n if (new RuleGate().isDisabled(workspaceRoot, ROOT_UNION_RULE, true)) {\n return new RootUnionRule(false, []);\n }\n const rule = loadAndValidate(workspaceRoot).resolved.rules.get(ROOT_UNION_RULE);\n const allowed = rule?.options['allowedPaths'];\n return new RootUnionRule(true, Array.isArray(allowed) ? (allowed as string[]) : []);\n }\n}\n\n/** ONE contract method whose request or response type is ITSELF a union. */\nexport class RootUnionApiType {\n constructor(\n /** The `@ApiPath` contract class. */\n public readonly api: string,\n /** The `@Endpoint` method on it. */\n public readonly method: string,\n /** `request` or `response` — which side carries the union. */\n public readonly side: string,\n /** The union type's NAME, as written on the method. */\n public readonly typeName: string,\n /** `path/to/File.ts:LINE`, workspace-relative. */\n public readonly at: string,\n /** True when a disable comment names this rule but gives NO reason. */\n public readonly disabledWithoutReason: boolean,\n ) {}\n}\n\n/** What one scan found. Two lists because the two have different cures. */\nexport class RootUnionFindings {\n constructor(\n /** Root-level unions with no disable at all. */\n public readonly violations: readonly RootUnionApiType[],\n /**\n * Sites that DID carry a disable for this rule and gave no reason. A reasonless disable is\n * itself a violation: the blast radius here is every tool in a session, so a suppression has\n * to carry an argument somebody wrote down and the next reader can weigh.\n */\n public readonly reasonlessDisables: readonly RootUnionApiType[],\n ) {}\n\n isEmpty(): boolean {\n return this.violations.length === 0 && this.reasonlessDisables.length === 0;\n }\n}\n\n/** One `type X = A | B` alias found in the workspace, keyed in the index by its NAME. */\nclass UnionAlias {\n constructor(\n public readonly name: string,\n /** The branch type names, in declaration order. */\n public readonly branches: readonly string[],\n ) {}\n}\n\n/** One `@Endpoint` method's declared request/response type names, with where to point an author. */\nclass EndpointTypes {\n constructor(\n public readonly api: string,\n public readonly method: string,\n public readonly requestType: string | null,\n public readonly responseType: string | null,\n public readonly at: string,\n /** The declaration's own lines, decorators included — where a disable comment may sit. */\n public readonly declarationText: string,\n ) {}\n}\n\n/**\n * Walks every project's `src/**` once, indexing union aliases and contract methods, then joins the\n * two. One pass, because the alias and the contract that uses it are routinely in different files\n * and often in different projects.\n */\nexport class RootUnionScan {\n private readonly aliases = new Map<string, UnionAlias>();\n private readonly endpoints: EndpointTypes[] = [];\n /** Alias name -> the disable comment written on its declaration, when it carries one. */\n private readonly aliasDisables = new Map<string, DisableComment>();\n\n constructor(\n private readonly workspaceRoot: string,\n private readonly projectInfos: Map<string, ProjectInfo>,\n /** The rule's switches. ARMED unless a caller read otherwise out of webpieces.config.json. */\n private readonly rule: RootUnionRule = RootUnionRule.enabledEverywhere(),\n ) {}\n\n run(): RootUnionFindings {\n if (!this.rule.enabled) return new RootUnionFindings([], []);\n for (const info of this.projectInfos.values()) {\n if (info.root === '' || info.root === '.') continue;\n if (matchesAnyGlob(info.root, this.rule.allowedPaths)) continue;\n this.indexProject(info);\n }\n const violations: RootUnionApiType[] = [];\n const reasonless: RootUnionApiType[] = [];\n for (const endpoint of this.endpoints) {\n this.judge(endpoint, 'request', endpoint.requestType, violations, reasonless);\n this.judge(endpoint, 'response', endpoint.responseType, violations, reasonless);\n }\n return new RootUnionFindings(violations, reasonless);\n }\n\n /** One side of one method: a union type name is a violation unless a REASONED disable covers it. */\n private judge(\n endpoint: EndpointTypes,\n side: string,\n typeName: string | null,\n violations: RootUnionApiType[],\n reasonless: RootUnionApiType[],\n ): void {\n if (typeName === null || !this.aliases.has(typeName)) return;\n // Either the method or the alias may carry the disable: the method is the site that\n // PUBLISHES the shape, and the alias is the declaration somebody will be looking at when\n // they decide the shape is deliberate. Both are \"the offending declaration\".\n const disable =\n DisableComment.readFrom(endpoint.declarationText) ?? this.aliasDisables.get(typeName);\n const found = new RootUnionApiType(\n endpoint.api,\n endpoint.method,\n side,\n typeName,\n endpoint.at,\n disable !== undefined && !disable.hasReason,\n );\n if (disable === undefined) {\n violations.push(found);\n return;\n }\n if (!disable.hasReason) reasonless.push(found);\n }\n\n private indexProject(info: ProjectInfo): void {\n const srcDir = path.join(path.resolve(this.workspaceRoot, info.root), 'src');\n if (!fs.existsSync(srcDir)) return;\n for (const file of collectTsFiles(srcDir)) {\n if (isTestFile(file)) continue; // a fixture is not a published contract\n const text = fs.readFileSync(file, 'utf8');\n const sourceFile = ts.createSourceFile(file, text, ts.ScriptTarget.Latest, true);\n this.indexNode(sourceFile, sourceFile);\n }\n }\n\n private indexNode(node: ts.Node, sourceFile: ts.SourceFile): void {\n if (ts.isTypeAliasDeclaration(node)) this.indexAlias(node, sourceFile);\n if (ts.isClassDeclaration(node)) this.indexContract(node, sourceFile);\n ts.forEachChild(node, (child: ts.Node) => this.indexNode(child, sourceFile));\n }\n\n /**\n * `type X = A | B` where at least two branches are NAMED types.\n *\n * A union of string literals (`type Phase = 'placed' | 'done'`) is deliberately NOT one: it\n * publishes as `enum`, which is a scalar and carries no `oneOf` at all. `| null` / `| undefined`\n * branches are dropped for the same reason the doc model drops them — they are nullability, not\n * composition.\n */\n private indexAlias(alias: ts.TypeAliasDeclaration, sourceFile: ts.SourceFile): void {\n if (!ts.isUnionTypeNode(alias.type)) return;\n const branches: string[] = [];\n for (const branch of alias.type.types) {\n if (RootUnionScan.isNullish(branch)) continue;\n const named = typeReferenceName(branch);\n if (named === null) return; // not a composition of named object types\n branches.push(named);\n }\n if (branches.length < 2) return;\n const name = alias.name.text;\n this.aliases.set(name, new UnionAlias(name, branches));\n const disable = DisableComment.readFrom(RootUnionScan.textOf(alias, sourceFile));\n if (disable !== undefined) this.aliasDisables.set(name, disable);\n }\n\n // webpieces-disable no-function-outside-class -- private static predicate of this class\n private static isNullish(node: ts.TypeNode): boolean {\n if (\n node.kind === ts.SyntaxKind.UndefinedKeyword ||\n node.kind === ts.SyntaxKind.NullKeyword\n ) {\n return true;\n }\n return ts.isLiteralTypeNode(node) && node.literal.kind === ts.SyntaxKind.NullKeyword;\n }\n\n /** Every `@Endpoint` method of an `abstract class` carrying `@ApiPath` — `@ApiType` or not. */\n private indexContract(cls: ts.ClassDeclaration, sourceFile: ts.SourceFile): void {\n if (!isAbstractClass(cls) || !hasClassDecorator(cls, 'ApiPath') || !cls.name) return;\n const api = cls.name.text;\n for (const member of cls.members) {\n if (!ts.isMethodDeclaration(member) || !ts.isIdentifier(member.name)) continue;\n if (memberDecorator(member, 'Endpoint') === null) continue;\n this.endpoints.push(\n new EndpointTypes(\n api,\n member.name.text,\n typeReferenceName(member.parameters[0]?.type),\n RootUnionScan.awaitedName(member.type),\n this.locate(member, sourceFile),\n RootUnionScan.textOf(member, sourceFile),\n ),\n );\n }\n }\n\n /** `Promise<T>` -> `T`'s name; a bare `T` is read as itself, so both spellings are covered. */\n // webpieces-disable no-function-outside-class -- private static accessor of this class\n private static awaitedName(declared: ts.TypeNode | undefined): string | null {\n if (declared === undefined || !ts.isTypeReferenceNode(declared)) return null;\n const outer = typeReferenceName(declared);\n if (outer !== 'Promise') return outer;\n const args = declared.typeArguments ?? [];\n return args.length === 1 ? typeReferenceName(args[0]) : null;\n }\n\n /**\n * The declaration's own source text INCLUDING its leading trivia, so a disable comment written\n * on the line above the first decorator is part of what is read.\n */\n // webpieces-disable no-function-outside-class -- private static accessor of this class\n private static textOf(node: ts.Node, sourceFile: ts.SourceFile): string {\n return sourceFile.text.slice(node.getFullStart(), node.getEnd());\n }\n\n private locate(node: ts.Node, sourceFile: ts.SourceFile): string {\n const position = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n return `${path.relative(this.workspaceRoot, sourceFile.fileName)}:${position.line + 1}`;\n }\n}\n\n/** ONE `webpieces-disable` naming this rule, and whether it gave a reason. */\nclass DisableComment {\n constructor(public readonly hasReason: boolean) {}\n\n /** The FIRST disable naming this rule in `text`, or undefined when it names none. */\n // webpieces-disable no-function-outside-class -- static factory of this class\n static readFrom(text: string): DisableComment | undefined {\n for (const line of text.split('\\n')) {\n const match = line.match(DISABLE_RE);\n if (match === null) continue;\n const named = match[1].split(',').map((each: string): string => each.trim());\n if (!named.includes(ROOT_UNION_RULE)) continue;\n return new DisableComment((match[2] ?? '').trim() !== '');\n }\n return undefined;\n }\n}\n"]}
@@ -18,7 +18,7 @@
18
18
  * its own package owns its schema, and the generator's fail-closed components check covers it.
19
19
  */
20
20
  import { DocumentedType } from '@webpieces/api-doc-model';
21
- import { RequiredTypeSuffixEntry } from '@webpieces/rules-config';
21
+ import { RequiredTypeSuffixEntry } from "@webpieces/code-rules";
22
22
  import { ProjectInfo } from '../project-info';
23
23
  /** The `required-type-suffix` entries the wire closure enforces; empty when that rule is OFF. */
24
24
  export declare class WireClosureRule {
@@ -41,10 +41,10 @@ class WireClosureRule {
41
41
  /** `required-type-suffix`'s entries, unless that rule is OFF or time-boxed / branch-scoped off. */
42
42
  // webpieces-disable no-function-outside-class -- static factory of this class
43
43
  static fromConfig(workspaceRoot) {
44
- if (new rule_gate_1.RuleGate().skipReason(workspaceRoot, rules_config_1.RULE_NAMES.REQUIRED_TYPE_SUFFIX, true) !== null) {
44
+ if (new rule_gate_1.RuleGate().skipReason(workspaceRoot, "required-type-suffix", true) !== null) {
45
45
  return WireClosureRule.withoutSuffixes();
46
46
  }
47
- const rule = (0, rules_config_1.loadAndValidate)(workspaceRoot).resolved.rules.get(rules_config_1.RULE_NAMES.REQUIRED_TYPE_SUFFIX);
47
+ const rule = (0, rules_config_1.loadAndValidate)(workspaceRoot).resolved.rules.get("required-type-suffix");
48
48
  const entries = rule?.options['entries'];
49
49
  return new WireClosureRule(Array.isArray(entries) ? entries : []);
50
50
  }
@@ -1 +1 @@
1
- {"version":3,"file":"wire-closure.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/lib/api-usage/wire-closure.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The WIRE CLOSURE of a contract (#1064, D4): every named type an `@ApiPath` contract reaches must be\n * DECLARED in a `role:api-lib` project, and must end in a suffix that project's `required-type-suffix`\n * entry demands.\n *\n * Why it lives here and not in the dependency rule: `api-lib-dependencies` only sees project EDGES. A\n * relative-path import into another library, or a DTO library that itself reaches outside, puts a type\n * on the wire without any edge the graph rule could refuse. The extractor already follows every type a\n * contract reaches through the compiler — the same walk `api-rules-for-openapi` / `api-rules-for-mcp`\n * run, with no generate tag needed — so this is one more question asked of each type that walk found.\n *\n * Every api-lib rule before this one (`required-type-suffix`, `one-enum-spelling-in-api-lib`,\n * `no-utility-types-in-api-lib`, `no-inline-import-in-api-lib`) reads only source files INSIDE the api\n * library. A type declared in another package was, by construction, outside every one of them — which is\n * how `AiProvider` and the `BrowserTelemetry` trio reached the wire from a general library unchecked.\n *\n * A type declared OUTSIDE the workspace (a published package under node_modules) is not judged here:\n * its own package owns its schema, and the generator's fail-closed components check covers it.\n */\n\nimport * as path from 'path';\nimport { DocumentedType } from '@webpieces/api-doc-model';\nimport { SuffixEntryPicker } from '@webpieces/code-rules';\nimport { loadAndValidate, RequiredTypeSuffixEntry, RULE_NAMES } from '@webpieces/rules-config';\nimport { ProjectInfo } from '../project-info';\nimport { resolveRole } from '../role-resolver';\nimport { RuleGate } from '../rule-gate';\n\nconst API_LIB_ROLE = 'api-lib';\n\n/** The `required-type-suffix` entries the wire closure enforces; empty when that rule is OFF. */\nexport class WireClosureRule {\n constructor(public readonly suffixEntries: readonly RequiredTypeSuffixEntry[]) {}\n\n /** Only the role check — what a unit test or a repo with `required-type-suffix` OFF gets. */\n // webpieces-disable no-function-outside-class -- static factory of this class\n static withoutSuffixes(): WireClosureRule {\n return new WireClosureRule([]);\n }\n\n /** `required-type-suffix`'s entries, unless that rule is OFF or time-boxed / branch-scoped off. */\n // webpieces-disable no-function-outside-class -- static factory of this class\n static fromConfig(workspaceRoot: string): WireClosureRule {\n if (new RuleGate().skipReason(workspaceRoot, RULE_NAMES.REQUIRED_TYPE_SUFFIX, true) !== null) {\n return WireClosureRule.withoutSuffixes();\n }\n const rule = loadAndValidate(workspaceRoot).resolved.rules.get(RULE_NAMES.REQUIRED_TYPE_SUFFIX);\n const entries = rule?.options['entries'];\n return new WireClosureRule(Array.isArray(entries) ? (entries as RequiredTypeSuffixEntry[]) : []);\n }\n}\n\n/** ONE wire-closure finding: what is wrong with a reached type, and what to do. */\nexport class WireClosureVerdict {\n constructor(\n public readonly what: string,\n public readonly cure: string,\n ) {}\n}\n\n/** A workspace project root, absolute, for the longest-prefix owner lookup. */\nclass OwnedRoot {\n constructor(\n public readonly info: ProjectInfo,\n public readonly abs: string,\n ) {}\n}\n\n/** Judges every type a contract reaches against the api-lib role and the suffix rule. */\nexport class WireClosure {\n private readonly roots: OwnedRoot[];\n private readonly picker = new SuffixEntryPicker();\n\n constructor(\n private readonly workspaceRoot: string,\n projectInfos: Map<string, ProjectInfo>,\n private readonly rule: WireClosureRule,\n ) {\n this.roots = [...projectInfos.values()]\n .filter((info: ProjectInfo) => info.root !== '' && info.root !== '.')\n .map((info: ProjectInfo) => new OwnedRoot(info, path.resolve(workspaceRoot, info.root)))\n // Longest root first so a nested project wins over its parent.\n .sort((a: OwnedRoot, b: OwnedRoot) => b.abs.length - a.abs.length);\n }\n\n /** Every verdict for ONE reached type, declared in the file `absFile`. */\n judge(type: DocumentedType, absFile: string): WireClosureVerdict[] {\n const abs = path.resolve(this.workspaceRoot, absFile);\n if (abs.split(path.sep).includes('node_modules')) return [];\n const owner = this.ownerOf(abs);\n if (owner === null) return [];\n const relFile = path.relative(this.workspaceRoot, abs).split(path.sep).join('/');\n const role = resolveRole(owner).role ?? 'none';\n const declared = `${type.packageName ?? 'no package'} (project '${owner.name}', role:${role})`;\n const verdicts: WireClosureVerdict[] = [];\n if (role !== API_LIB_ROLE) {\n verdicts.push(new WireClosureVerdict(\n `'${type.name}' goes over the wire but is declared in ${declared}, which is not a role:api-lib ` +\n 'project — every type a contract reaches must be declared in an api library',\n `Move '${type.name}' into a role:api-lib project — as a '…Dto' string enum when it is a ` +\n `string-literal union. Retagging '${owner.name}' is not a way out unless it holds only ` +\n 'contracts and wire types (validate-api-lib-tag refuses a role:api-lib with an implementation).',\n ));\n }\n const governing = this.picker.winner(relFile, this.rule.suffixEntries);\n if (governing !== undefined && !this.endsInSuffix(type.name, governing.entry.suffixes)) {\n verdicts.push(new WireClosureVerdict(\n `'${type.name}' goes over the wire from ${relFile} but does not end in one of ` +\n `[${governing.entry.suffixes.join(', ')}], which the required-type-suffix entry ` +\n `'${governing.glob}' demands of it`,\n `Rename '${type.name}' to end in one of ${governing.entry.suffixes.join(', ')} — the suffix tells a ` +\n 'reader which layer a type belongs to, and a wire type is the layer a partner reads.',\n ));\n }\n return verdicts;\n }\n\n private endsInSuffix(name: string, suffixes: readonly string[]): boolean {\n return suffixes.some((suffix: string) => name.length > suffix.length && name.endsWith(suffix));\n }\n\n private ownerOf(abs: string): ProjectInfo | null {\n for (const root of this.roots) {\n if (abs === root.abs || abs.startsWith(root.abs + path.sep)) return root.info;\n }\n return null;\n }\n}\n"]}
1
+ {"version":3,"file":"wire-closure.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/nx-webpieces-rules/src/lib/api-usage/wire-closure.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The WIRE CLOSURE of a contract (#1064, D4): every named type an `@ApiPath` contract reaches must be\n * DECLARED in a `role:api-lib` project, and must end in a suffix that project's `required-type-suffix`\n * entry demands.\n *\n * Why it lives here and not in the dependency rule: `api-lib-dependencies` only sees project EDGES. A\n * relative-path import into another library, or a DTO library that itself reaches outside, puts a type\n * on the wire without any edge the graph rule could refuse. The extractor already follows every type a\n * contract reaches through the compiler — the same walk `api-rules-for-openapi` / `api-rules-for-mcp`\n * run, with no generate tag needed — so this is one more question asked of each type that walk found.\n *\n * Every api-lib rule before this one (`required-type-suffix`, `one-enum-spelling-in-api-lib`,\n * `no-utility-types-in-api-lib`, `no-inline-import-in-api-lib`) reads only source files INSIDE the api\n * library. A type declared in another package was, by construction, outside every one of them — which is\n * how `AiProvider` and the `BrowserTelemetry` trio reached the wire from a general library unchecked.\n *\n * A type declared OUTSIDE the workspace (a published package under node_modules) is not judged here:\n * its own package owns its schema, and the generator's fail-closed components check covers it.\n */\n\nimport * as path from 'path';\nimport { DocumentedType } from '@webpieces/api-doc-model';\nimport { SuffixEntryPicker } from '@webpieces/code-rules';\nimport { loadAndValidate } from \"@webpieces/rules-config\";\nimport { RequiredTypeSuffixEntry } from \"@webpieces/code-rules\";\nimport { ProjectInfo } from '../project-info';\nimport { resolveRole } from '../role-resolver';\nimport { RuleGate } from '../rule-gate';\n\nconst API_LIB_ROLE = 'api-lib';\n\n/** The `required-type-suffix` entries the wire closure enforces; empty when that rule is OFF. */\nexport class WireClosureRule {\n constructor(public readonly suffixEntries: readonly RequiredTypeSuffixEntry[]) {}\n\n /** Only the role check — what a unit test or a repo with `required-type-suffix` OFF gets. */\n // webpieces-disable no-function-outside-class -- static factory of this class\n static withoutSuffixes(): WireClosureRule {\n return new WireClosureRule([]);\n }\n\n /** `required-type-suffix`'s entries, unless that rule is OFF or time-boxed / branch-scoped off. */\n // webpieces-disable no-function-outside-class -- static factory of this class\n static fromConfig(workspaceRoot: string): WireClosureRule {\n if (new RuleGate().skipReason(workspaceRoot, \"required-type-suffix\", true) !== null) {\n return WireClosureRule.withoutSuffixes();\n }\n const rule = loadAndValidate(workspaceRoot).resolved.rules.get(\"required-type-suffix\");\n const entries = rule?.options['entries'];\n return new WireClosureRule(Array.isArray(entries) ? (entries as RequiredTypeSuffixEntry[]) : []);\n }\n}\n\n/** ONE wire-closure finding: what is wrong with a reached type, and what to do. */\nexport class WireClosureVerdict {\n constructor(\n public readonly what: string,\n public readonly cure: string,\n ) {}\n}\n\n/** A workspace project root, absolute, for the longest-prefix owner lookup. */\nclass OwnedRoot {\n constructor(\n public readonly info: ProjectInfo,\n public readonly abs: string,\n ) {}\n}\n\n/** Judges every type a contract reaches against the api-lib role and the suffix rule. */\nexport class WireClosure {\n private readonly roots: OwnedRoot[];\n private readonly picker = new SuffixEntryPicker();\n\n constructor(\n private readonly workspaceRoot: string,\n projectInfos: Map<string, ProjectInfo>,\n private readonly rule: WireClosureRule,\n ) {\n this.roots = [...projectInfos.values()]\n .filter((info: ProjectInfo) => info.root !== '' && info.root !== '.')\n .map((info: ProjectInfo) => new OwnedRoot(info, path.resolve(workspaceRoot, info.root)))\n // Longest root first so a nested project wins over its parent.\n .sort((a: OwnedRoot, b: OwnedRoot) => b.abs.length - a.abs.length);\n }\n\n /** Every verdict for ONE reached type, declared in the file `absFile`. */\n judge(type: DocumentedType, absFile: string): WireClosureVerdict[] {\n const abs = path.resolve(this.workspaceRoot, absFile);\n if (abs.split(path.sep).includes('node_modules')) return [];\n const owner = this.ownerOf(abs);\n if (owner === null) return [];\n const relFile = path.relative(this.workspaceRoot, abs).split(path.sep).join('/');\n const role = resolveRole(owner).role ?? 'none';\n const declared = `${type.packageName ?? 'no package'} (project '${owner.name}', role:${role})`;\n const verdicts: WireClosureVerdict[] = [];\n if (role !== API_LIB_ROLE) {\n verdicts.push(new WireClosureVerdict(\n `'${type.name}' goes over the wire but is declared in ${declared}, which is not a role:api-lib ` +\n 'project — every type a contract reaches must be declared in an api library',\n `Move '${type.name}' into a role:api-lib project — as a '…Dto' string enum when it is a ` +\n `string-literal union. Retagging '${owner.name}' is not a way out unless it holds only ` +\n 'contracts and wire types (validate-api-lib-tag refuses a role:api-lib with an implementation).',\n ));\n }\n const governing = this.picker.winner(relFile, this.rule.suffixEntries);\n if (governing !== undefined && !this.endsInSuffix(type.name, governing.entry.suffixes)) {\n verdicts.push(new WireClosureVerdict(\n `'${type.name}' goes over the wire from ${relFile} but does not end in one of ` +\n `[${governing.entry.suffixes.join(', ')}], which the required-type-suffix entry ` +\n `'${governing.glob}' demands of it`,\n `Rename '${type.name}' to end in one of ${governing.entry.suffixes.join(', ')} — the suffix tells a ` +\n 'reader which layer a type belongs to, and a wire type is the layer a partner reads.',\n ));\n }\n return verdicts;\n }\n\n private endsInSuffix(name: string, suffixes: readonly string[]): boolean {\n return suffixes.some((suffix: string) => name.length > suffix.length && name.endsWith(suffix));\n }\n\n private ownerOf(abs: string): ProjectInfo | null {\n for (const root of this.roots) {\n if (abs === root.abs || abs.startsWith(root.abs + path.sep)) return root.info;\n }\n return null;\n }\n}\n"]}
@@ -18,7 +18,7 @@
18
18
  * webpieces.config.json, which must state them or fail to load. `TagTruthRules.none()` is what a unit
19
19
  * test or a caller that configured nothing asked for — not a default.
20
20
  */
21
- import { FrameworkFolderEntry } from '@webpieces/rules-config';
21
+ import { FrameworkFolderEntry } from "../configs/tag-truth-configs";
22
22
  import type { EnhancedGraph } from './graph-sorter';
23
23
  import { ProjectInfo } from './project-info';
24
24
  export declare const API_LIB_ROLE = "api-lib";
@@ -113,9 +113,9 @@ class TagTruthRules {
113
113
  const rules = (0, rules_config_1.loadAndValidate)(workspaceRoot).resolved.rules;
114
114
  // webpieces-disable no-any-unknown -- a validated rule entry is still opaque JSON in the option bag
115
115
  const optionsOf = (name) => gate.isDisabled(workspaceRoot, name, true) ? null : (rules.get(name)?.options ?? null);
116
- const deps = optionsOf(rules_config_1.RULE_NAMES.API_LIB_DEPENDENCIES);
117
- const where = optionsOf(rules_config_1.RULE_NAMES.API_LIB_PATH);
118
- const folder = optionsOf(rules_config_1.RULE_NAMES.FRAMEWORK_FOLDER);
116
+ const deps = optionsOf("api-lib-dependencies");
117
+ const where = optionsOf("api-lib-path");
118
+ const folder = optionsOf("framework-folder");
119
119
  return new TagTruthRules(deps === null ? null : TagTruthRules.dependenciesRule(deps), where === null ? null : new ApiLibPathRule(where['paths']), folder === null
120
120
  ? null
121
121
  : new FrameworkFolderRule(folder['entries'].map(FrameworkFolder.fromEntry)));
@@ -174,13 +174,13 @@ class TagTruthValidator {
174
174
  const role = entry.role;
175
175
  if (role === undefined || !API_ROLES.includes(role))
176
176
  return [];
177
- const rulePrefix = `${rules_config_1.RULE_NAMES.API_LIB_DEPENDENCIES}: '${name}' (role:${role})`;
177
+ const rulePrefix = `${"api-lib-dependencies"}: '${name}' (role:${role})`;
178
178
  const clientPackages = rule.apiClientPackages.get(name);
179
179
  if (role === exports.API_CLIENT_ROLE && clientPackages === undefined) {
180
180
  return [
181
181
  `${rulePrefix} has no apiClients entry — what an api-client talks to is stated, never inferred. ` +
182
182
  `Add { "project": "${name}", "packages": [<its SDK, inversify, …>] } to ` +
183
- `${rules_config_1.RULE_NAMES.API_LIB_DEPENDENCIES}.apiClients in webpieces.config.json, or retag it role:api-lib ` +
183
+ `${"api-lib-dependencies"}.apiClients in webpieces.config.json, or retag it role:api-lib ` +
184
184
  'if it bundles no implementation.',
185
185
  ];
186
186
  }
@@ -211,7 +211,7 @@ class TagTruthValidator {
211
211
  continue;
212
212
  problems.push(`${rulePrefix} imports '${pkg}', which ${listName} does not list — an api library's wire contract ` +
213
213
  `must not drag an outside runtime into every consumer. Remove the import, or add '${pkg}' ` +
214
- `to ${rules_config_1.RULE_NAMES.API_LIB_DEPENDENCIES}.${role === exports.API_CLIENT_ROLE ? `apiClients["${name}"].packages` : 'apiLibPackages'}.`);
214
+ `to ${"api-lib-dependencies"}.${role === exports.API_CLIENT_ROLE ? `apiClients["${name}"].packages` : 'apiLibPackages'}.`);
215
215
  }
216
216
  return problems;
217
217
  }
@@ -229,14 +229,14 @@ class TagTruthValidator {
229
229
  const globs = `[${rule.paths.join(', ')}]`;
230
230
  if (isApi && !inPath) {
231
231
  return [
232
- `${rules_config_1.RULE_NAMES.API_LIB_PATH}: '${name}' is role:${entry.role} but lives at '${root}', outside ` +
233
- `${rules_config_1.RULE_NAMES.API_LIB_PATH}.paths ${globs} — move it under one of them ` +
232
+ `${"api-lib-path"}: '${name}' is role:${entry.role} but lives at '${root}', outside ` +
233
+ `${"api-lib-path"}.paths ${globs} — move it under one of them ` +
234
234
  '(nx g @nx/workspace:move), so every contract in the repo is found in one place.',
235
235
  ];
236
236
  }
237
237
  if (inPath && !isApi) {
238
238
  return [
239
- `${rules_config_1.RULE_NAMES.API_LIB_PATH}: '${name}' lives at '${root}', under ${rules_config_1.RULE_NAMES.API_LIB_PATH}.paths ` +
239
+ `${"api-lib-path"}: '${name}' lives at '${root}', under ${"api-lib-path"}.paths ` +
240
240
  `${globs}, but is role:${entry.role ?? 'none'} — everything there is a contract. Retag it ` +
241
241
  'role:api-lib (a contract and/or its DTOs) or role:api-client (a contract plus its SDK ' +
242
242
  'adapter), or move it out of the api tree.',
@@ -251,7 +251,7 @@ class TagTruthValidator {
251
251
  const set = FrameworkFolder.canonical(entry.framework);
252
252
  const role = entry.role;
253
253
  const governing = rule.folders.find((folder) => (0, rules_config_1.matchesAnyGlob)(root, folder.paths));
254
- const prefix = `${rules_config_1.RULE_NAMES.FRAMEWORK_FOLDER}: '${name}' at '${root}'`;
254
+ const prefix = `${"framework-folder"}: '${name}' at '${root}'`;
255
255
  if (governing !== undefined) {
256
256
  const problems = [];
257
257
  const glob = governing.paths.join(', ');
@@ -273,7 +273,7 @@ class TagTruthValidator {
273
273
  return [];
274
274
  const globs = homes.map((folder) => folder.paths.join(', ')).join(' | ');
275
275
  return [
276
- `${prefix} is a role:${role} carrying [${set}], which ${rules_config_1.RULE_NAMES.FRAMEWORK_FOLDER} places under ` +
276
+ `${prefix} is a role:${role} carrying [${set}], which ${"framework-folder"} places under ` +
277
277
  `${globs} — move it there (nx g @nx/workspace:move), so the folder tells a reader what runs where.`,
278
278
  ];
279
279
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tag-truth.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/tag-truth.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Tag truth — the three GRAPH rules that make an nx `role:*` / `framework:*` tag true (#1064):\n *\n * api-lib-dependencies (D2) — a `role:api-lib` depends only on other `role:api-lib` projects plus a\n * stated list of outside packages; a `role:api-client` may also import\n * the packages its own config entry names (its SDK, inversify, …).\n * api-lib-path (D10) — every api-lib / api-client lives under the configured api globs, and\n * everything under them carries one of those two roles.\n * framework-folder (D9) — the folder a library lives in and its framework set + role agree,\n * both directions.\n *\n * They run beside `library-types-match-client` and `role-dependency` (graph-metadata.ts), in\n * `architecture:generate` and `validate-architecture-unchanged`, AFTER enrichGraph has resolved every\n * project's framework set and role — so a tag is read exactly one way. Every problem across every\n * project is collected and thrown as one MetadataValidationError, before anything is written.\n *\n * There is NO default (`.claude/rules/no-rule-defaults.md`): each rule's fields come from\n * webpieces.config.json, which must state them or fail to load. `TagTruthRules.none()` is what a unit\n * test or a caller that configured nothing asked for — not a default.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport {\n ApiClientPackagesEntry,\n FrameworkFolderEntry,\n loadAndValidate,\n matchesAnyGlob,\n RULE_NAMES,\n RuleOptions,\n} from '@webpieces/rules-config';\nimport type { EnhancedGraph, GraphEntry } from './graph-sorter';\nimport { APP_ROLES, MetadataValidationError } from './graph-metadata';\nimport { ProjectInfo } from './project-info';\nimport { RuleGate } from './rule-gate';\nimport { DepUsageScanner } from './dep-usage-scanner';\nimport { toError } from '../toError';\n\n/** The only field of a package.json this check reads. */\ntype RawPackageJson = { name?: string };\n\nexport const API_LIB_ROLE = 'api-lib';\nexport const API_CLIENT_ROLE = 'api-client';\nconst API_ROLES: readonly string[] = [API_LIB_ROLE, API_CLIENT_ROLE];\n\n/** `api-lib-dependencies`, resolved: what an api library may import from outside the api-lib set. */\nexport class ApiLibDependenciesRule {\n constructor(\n /** Package / project names (globs allowed) every api-lib and api-client may depend on. */\n public readonly apiLibPackages: readonly string[],\n /** `role:api-client` project → the extra packages it may depend on. */\n public readonly apiClientPackages: ReadonlyMap<string, readonly string[]>,\n ) {}\n}\n\n/** `api-lib-path`, resolved: the globs every api project — and only api projects — lives under. */\nexport class ApiLibPathRule {\n constructor(public readonly paths: readonly string[]) {}\n}\n\n/** One `framework-folder` entry with its framework sets canonicalised (`a+b`, tokens sorted). */\nexport class FrameworkFolder {\n constructor(\n public readonly paths: readonly string[],\n public readonly frameworkSets: readonly string[],\n public readonly roles: readonly string[],\n ) {}\n\n /** A framework set written in any order, canonicalised: `node+browser` → `browser+node`. */\n // webpieces-disable no-function-outside-class -- static helper of this class\n static canonical(frameworks: readonly string[]): string {\n return [...new Set(frameworks.map((each: string) => each.trim()).filter((each: string) => each !== ''))]\n .sort()\n .join('+');\n }\n\n // webpieces-disable no-function-outside-class -- static factory of this class\n static fromEntry(entry: FrameworkFolderEntry): FrameworkFolder {\n return new FrameworkFolder(\n entry.paths,\n entry.frameworkSets.map((set: string) => FrameworkFolder.canonical(set.split('+'))),\n entry.roles,\n );\n }\n}\n\n/** `framework-folder`, resolved. Entry ORDER matters: the first entry whose glob matches governs. */\nexport class FrameworkFolderRule {\n constructor(public readonly folders: readonly FrameworkFolder[]) {}\n}\n\n/**\n * The three rules' switches, read from webpieces.config.json once. A rule that is OFF (or time-boxed /\n * branch-scoped off) is `null`.\n */\nexport class TagTruthRules {\n constructor(\n public readonly apiLibDependencies: ApiLibDependenciesRule | null,\n public readonly apiLibPath: ApiLibPathRule | null,\n public readonly frameworkFolder: FrameworkFolderRule | null,\n ) {}\n\n /** Every rule off — what a caller that configured nothing asked for. */\n // webpieces-disable no-function-outside-class -- static factory of this class\n static none(): TagTruthRules {\n return new TagTruthRules(null, null, null);\n }\n\n anyEnabled(): boolean {\n return this.apiLibDependencies !== null || this.apiLibPath !== null || this.frameworkFolder !== null;\n }\n\n /** `mode: OFF` and both escape hatches come from RuleGate, so there is ONE reading of them. */\n // webpieces-disable no-function-outside-class -- static factory of this class\n static fromConfig(workspaceRoot: string): TagTruthRules {\n const gate = new RuleGate();\n const rules = loadAndValidate(workspaceRoot).resolved.rules;\n // webpieces-disable no-any-unknown -- a validated rule entry is still opaque JSON in the option bag\n const optionsOf = (name: string): RuleOptions | null =>\n gate.isDisabled(workspaceRoot, name, true) ? null : (rules.get(name)?.options ?? null);\n\n const deps = optionsOf(RULE_NAMES.API_LIB_DEPENDENCIES);\n const where = optionsOf(RULE_NAMES.API_LIB_PATH);\n const folder = optionsOf(RULE_NAMES.FRAMEWORK_FOLDER);\n return new TagTruthRules(\n deps === null ? null : TagTruthRules.dependenciesRule(deps),\n where === null ? null : new ApiLibPathRule(where['paths'] as string[]),\n folder === null\n ? null\n : new FrameworkFolderRule((folder['entries'] as FrameworkFolderEntry[]).map(FrameworkFolder.fromEntry)),\n );\n }\n\n // webpieces-disable no-function-outside-class -- private static reader of this class\n private static dependenciesRule(options: RuleOptions): ApiLibDependenciesRule {\n const clients = new Map<string, readonly string[]>();\n for (const entry of options['apiClients'] as ApiClientPackagesEntry[]) clients.set(entry.project, entry.packages);\n return new ApiLibDependenciesRule(options['apiLibPackages'] as string[], clients);\n }\n}\n\n/** What ONE project imports from production source, and the package name others import it by. */\nexport class ProjectImports {\n constructor(\n /** The project's own `package.json` name, or null when it has none. */\n public readonly packageName: string | null,\n /** Bare package names its production (non-test) source imports. */\n public readonly prodPackages: ReadonlySet<string>,\n ) {}\n}\n\n/** The pure check: every tag-truth problem in a graph whose framework sets and roles are resolved. */\nexport class TagTruthValidator {\n constructor(private readonly rules: TagTruthRules) {}\n\n problems(\n graph: EnhancedGraph,\n infos: Map<string, ProjectInfo>,\n imports: ReadonlyMap<string, ProjectImports>,\n ): string[] {\n const problems: string[] = [];\n for (const name of Object.keys(graph).sort()) {\n const entry = graph[name];\n const info = infos.get(name);\n if (info === undefined || info.root === '' || info.root === '.') continue;\n const root = info.root.replace(/\\\\/g, '/').replace(/\\/+$/, '');\n if (this.rules.apiLibDependencies !== null) {\n problems.push(...this.dependencyProblems(name, entry, graph, imports, this.rules.apiLibDependencies));\n }\n if (this.rules.apiLibPath !== null) {\n problems.push(...this.pathProblems(name, root, entry, this.rules.apiLibPath));\n }\n if (this.rules.frameworkFolder !== null) {\n problems.push(...this.folderProblems(name, root, entry, this.rules.frameworkFolder));\n }\n }\n return problems;\n }\n\n /** D2 — the workspace edges and the outside packages of ONE api-lib / api-client. */\n private dependencyProblems(\n name: string,\n entry: GraphEntry,\n graph: EnhancedGraph,\n imports: ReadonlyMap<string, ProjectImports>,\n rule: ApiLibDependenciesRule,\n ): string[] {\n const role = entry.role;\n if (role === undefined || !API_ROLES.includes(role)) return [];\n const rulePrefix = `${RULE_NAMES.API_LIB_DEPENDENCIES}: '${name}' (role:${role})`;\n const clientPackages = rule.apiClientPackages.get(name);\n if (role === API_CLIENT_ROLE && clientPackages === undefined) {\n return [\n `${rulePrefix} has no apiClients entry — what an api-client talks to is stated, never inferred. ` +\n `Add { \"project\": \"${name}\", \"packages\": [<its SDK, inversify, …>] } to ` +\n `${RULE_NAMES.API_LIB_DEPENDENCIES}.apiClients in webpieces.config.json, or retag it role:api-lib ` +\n 'if it bundles no implementation.',\n ];\n }\n const allowed = [...rule.apiLibPackages, ...(clientPackages ?? [])];\n const listName =\n role === API_CLIENT_ROLE ? `apiLibPackages or its apiClients entry` : 'apiLibPackages';\n const problems: string[] = [];\n const workspaceNames = new Set<string>();\n for (const dep of entry.dependsOn) {\n const depImports = imports.get(dep);\n if (depImports?.packageName) workspaceNames.add(depImports.packageName);\n const depRole = graph[dep]?.role;\n if (depRole === API_LIB_ROLE) continue;\n if (matchesAnyGlob(dep, allowed)) continue;\n if (depImports?.packageName && matchesAnyGlob(depImports.packageName, allowed)) continue;\n problems.push(\n `${rulePrefix} must not depend on '${dep}' (role:${depRole ?? 'none'}) — an api library depends ` +\n `only on role:api-lib projects and the packages ${listName} lists. Move what it needs into a ` +\n `role:api-lib project, or add '${depImports?.packageName ?? dep}' to ${listName}.`,\n );\n }\n const own = imports.get(name);\n for (const pkg of [...(own?.prodPackages ?? [])].sort()) {\n if (pkg === own?.packageName || workspaceNames.has(pkg) || this.isWorkspacePackage(pkg, imports)) continue;\n if (matchesAnyGlob(pkg, allowed)) continue;\n problems.push(\n `${rulePrefix} imports '${pkg}', which ${listName} does not list — an api library's wire contract ` +\n `must not drag an outside runtime into every consumer. Remove the import, or add '${pkg}' ` +\n `to ${RULE_NAMES.API_LIB_DEPENDENCIES}.${role === API_CLIENT_ROLE ? `apiClients[\"${name}\"].packages` : 'apiLibPackages'}.`,\n );\n }\n return problems;\n }\n\n /** A package some workspace project publishes — its edge is judged as a workspace dependency above. */\n private isWorkspacePackage(pkg: string, imports: ReadonlyMap<string, ProjectImports>): boolean {\n for (const each of imports.values()) if (each.packageName === pkg) return true;\n return false;\n }\n\n /** D10 — an api project lives under the api globs, and everything there is an api project. */\n private pathProblems(name: string, root: string, entry: GraphEntry, rule: ApiLibPathRule): string[] {\n const isApi = entry.role !== undefined && API_ROLES.includes(entry.role);\n const inPath = matchesAnyGlob(root, rule.paths);\n const globs = `[${rule.paths.join(', ')}]`;\n if (isApi && !inPath) {\n return [\n `${RULE_NAMES.API_LIB_PATH}: '${name}' is role:${entry.role} but lives at '${root}', outside ` +\n `${RULE_NAMES.API_LIB_PATH}.paths ${globs} — move it under one of them ` +\n '(nx g @nx/workspace:move), so every contract in the repo is found in one place.',\n ];\n }\n if (inPath && !isApi) {\n return [\n `${RULE_NAMES.API_LIB_PATH}: '${name}' lives at '${root}', under ${RULE_NAMES.API_LIB_PATH}.paths ` +\n `${globs}, but is role:${entry.role ?? 'none'} — everything there is a contract. Retag it ` +\n 'role:api-lib (a contract and/or its DTOs) or role:api-client (a contract plus its SDK ' +\n 'adapter), or move it out of the api tree.',\n ];\n }\n return [];\n }\n\n /** D9 — the folder and the tags agree, both directions. */\n private folderProblems(name: string, root: string, entry: GraphEntry, rule: FrameworkFolderRule): string[] {\n if (entry.framework === undefined || entry.role === undefined) return [];\n const set = FrameworkFolder.canonical(entry.framework);\n const role = entry.role;\n const governing = rule.folders.find((folder: FrameworkFolder) => matchesAnyGlob(root, folder.paths));\n const prefix = `${RULE_NAMES.FRAMEWORK_FOLDER}: '${name}' at '${root}'`;\n if (governing !== undefined) {\n const problems: string[] = [];\n const glob = governing.paths.join(', ');\n if (!governing.frameworkSets.includes(set)) {\n problems.push(\n `${prefix} carries framework set [${set}], but the folder ${glob} holds ` +\n `[${governing.frameworkSets.join(' | ')}] — retag it to the folder's set, or move it to ` +\n 'the folder that holds its set.',\n );\n }\n if (!governing.roles.includes(role)) {\n problems.push(\n `${prefix} is role:${role}, but the folder ${glob} holds role ` +\n `${governing.roles.map((each: string) => `role:${each}`).join(' | ')} — retag it, or move it.`,\n );\n }\n return problems;\n }\n if (APP_ROLES.includes(role) || role === 'bundle') return [];\n const homes = rule.folders.filter(\n (folder: FrameworkFolder) => folder.frameworkSets.includes(set) && folder.roles.includes(role),\n );\n if (homes.length === 0) return [];\n const globs = homes.map((folder: FrameworkFolder) => folder.paths.join(', ')).join(' | ');\n return [\n `${prefix} is a role:${role} carrying [${set}], which ${RULE_NAMES.FRAMEWORK_FOLDER} places under ` +\n `${globs} — move it there (nx g @nx/workspace:move), so the folder tells a reader what runs where.`,\n ];\n }\n}\n\n/** The executor-facing entry point: read the config and the imports, check, and throw before any write. */\nexport class TagTruthCheck {\n assertTrue(graph: EnhancedGraph, infos: Map<string, ProjectInfo>, workspaceRoot: string): void {\n const rules = TagTruthRules.fromConfig(workspaceRoot);\n if (!rules.anyEnabled()) return;\n const imports = rules.apiLibDependencies === null ? new Map<string, ProjectImports>() : this.importsOf(infos, workspaceRoot);\n const problems = new TagTruthValidator(rules).problems(graph, infos, imports);\n if (problems.length > 0) throw new MetadataValidationError(problems);\n }\n\n /** Every project's production imports and package name, read from its source and package.json. */\n importsOf(infos: Map<string, ProjectInfo>, workspaceRoot: string): Map<string, ProjectImports> {\n const scanner = new DepUsageScanner();\n const found = new Map<string, ProjectImports>();\n for (const info of infos.values()) {\n if (info.root === '' || info.root === '.') continue;\n const abs = path.resolve(workspaceRoot, info.root);\n found.set(info.name, new ProjectImports(this.packageNameOf(abs), scanner.scan(abs).prodPackages));\n }\n return found;\n }\n\n private packageNameOf(projectDir: string): string | null {\n const file = path.join(projectDir, 'package.json');\n if (!fs.existsSync(file)) return null;\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const parsed = JSON.parse(fs.readFileSync(file, 'utf-8')) as RawPackageJson;\n return typeof parsed.name === 'string' ? parsed.name : null;\n } catch (err: unknown) {\n const error = toError(err);\n throw new Error(`Failed to parse ${file} while reading the package name tag-truth checks against`, {\n cause: error,\n });\n }\n }\n}\n"]}
1
+ {"version":3,"file":"tag-truth.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/tag-truth.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Tag truth — the three GRAPH rules that make an nx `role:*` / `framework:*` tag true (#1064):\n *\n * api-lib-dependencies (D2) — a `role:api-lib` depends only on other `role:api-lib` projects plus a\n * stated list of outside packages; a `role:api-client` may also import\n * the packages its own config entry names (its SDK, inversify, …).\n * api-lib-path (D10) — every api-lib / api-client lives under the configured api globs, and\n * everything under them carries one of those two roles.\n * framework-folder (D9) — the folder a library lives in and its framework set + role agree,\n * both directions.\n *\n * They run beside `library-types-match-client` and `role-dependency` (graph-metadata.ts), in\n * `architecture:generate` and `validate-architecture-unchanged`, AFTER enrichGraph has resolved every\n * project's framework set and role — so a tag is read exactly one way. Every problem across every\n * project is collected and thrown as one MetadataValidationError, before anything is written.\n *\n * There is NO default (`.claude/rules/no-rule-defaults.md`): each rule's fields come from\n * webpieces.config.json, which must state them or fail to load. `TagTruthRules.none()` is what a unit\n * test or a caller that configured nothing asked for — not a default.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { loadAndValidate, matchesAnyGlob, RuleOptions } from \"@webpieces/rules-config\";\nimport { ApiClientPackagesEntry, FrameworkFolderEntry } from \"../configs/tag-truth-configs\";\nimport type { EnhancedGraph, GraphEntry } from './graph-sorter';\nimport { APP_ROLES, MetadataValidationError } from './graph-metadata';\nimport { ProjectInfo } from './project-info';\nimport { RuleGate } from './rule-gate';\nimport { DepUsageScanner } from './dep-usage-scanner';\nimport { toError } from '../toError';\n\n/** The only field of a package.json this check reads. */\ntype RawPackageJson = { name?: string };\n\nexport const API_LIB_ROLE = 'api-lib';\nexport const API_CLIENT_ROLE = 'api-client';\nconst API_ROLES: readonly string[] = [API_LIB_ROLE, API_CLIENT_ROLE];\n\n/** `api-lib-dependencies`, resolved: what an api library may import from outside the api-lib set. */\nexport class ApiLibDependenciesRule {\n constructor(\n /** Package / project names (globs allowed) every api-lib and api-client may depend on. */\n public readonly apiLibPackages: readonly string[],\n /** `role:api-client` project → the extra packages it may depend on. */\n public readonly apiClientPackages: ReadonlyMap<string, readonly string[]>,\n ) {}\n}\n\n/** `api-lib-path`, resolved: the globs every api project — and only api projects — lives under. */\nexport class ApiLibPathRule {\n constructor(public readonly paths: readonly string[]) {}\n}\n\n/** One `framework-folder` entry with its framework sets canonicalised (`a+b`, tokens sorted). */\nexport class FrameworkFolder {\n constructor(\n public readonly paths: readonly string[],\n public readonly frameworkSets: readonly string[],\n public readonly roles: readonly string[],\n ) {}\n\n /** A framework set written in any order, canonicalised: `node+browser` → `browser+node`. */\n // webpieces-disable no-function-outside-class -- static helper of this class\n static canonical(frameworks: readonly string[]): string {\n return [...new Set(frameworks.map((each: string) => each.trim()).filter((each: string) => each !== ''))]\n .sort()\n .join('+');\n }\n\n // webpieces-disable no-function-outside-class -- static factory of this class\n static fromEntry(entry: FrameworkFolderEntry): FrameworkFolder {\n return new FrameworkFolder(\n entry.paths,\n entry.frameworkSets.map((set: string) => FrameworkFolder.canonical(set.split('+'))),\n entry.roles,\n );\n }\n}\n\n/** `framework-folder`, resolved. Entry ORDER matters: the first entry whose glob matches governs. */\nexport class FrameworkFolderRule {\n constructor(public readonly folders: readonly FrameworkFolder[]) {}\n}\n\n/**\n * The three rules' switches, read from webpieces.config.json once. A rule that is OFF (or time-boxed /\n * branch-scoped off) is `null`.\n */\nexport class TagTruthRules {\n constructor(\n public readonly apiLibDependencies: ApiLibDependenciesRule | null,\n public readonly apiLibPath: ApiLibPathRule | null,\n public readonly frameworkFolder: FrameworkFolderRule | null,\n ) {}\n\n /** Every rule off — what a caller that configured nothing asked for. */\n // webpieces-disable no-function-outside-class -- static factory of this class\n static none(): TagTruthRules {\n return new TagTruthRules(null, null, null);\n }\n\n anyEnabled(): boolean {\n return this.apiLibDependencies !== null || this.apiLibPath !== null || this.frameworkFolder !== null;\n }\n\n /** `mode: OFF` and both escape hatches come from RuleGate, so there is ONE reading of them. */\n // webpieces-disable no-function-outside-class -- static factory of this class\n static fromConfig(workspaceRoot: string): TagTruthRules {\n const gate = new RuleGate();\n const rules = loadAndValidate(workspaceRoot).resolved.rules;\n // webpieces-disable no-any-unknown -- a validated rule entry is still opaque JSON in the option bag\n const optionsOf = (name: string): RuleOptions | null =>\n gate.isDisabled(workspaceRoot, name, true) ? null : (rules.get(name)?.options ?? null);\n\n const deps = optionsOf(\"api-lib-dependencies\");\n const where = optionsOf(\"api-lib-path\");\n const folder = optionsOf(\"framework-folder\");\n return new TagTruthRules(\n deps === null ? null : TagTruthRules.dependenciesRule(deps),\n where === null ? null : new ApiLibPathRule(where['paths'] as string[]),\n folder === null\n ? null\n : new FrameworkFolderRule((folder['entries'] as FrameworkFolderEntry[]).map(FrameworkFolder.fromEntry)),\n );\n }\n\n // webpieces-disable no-function-outside-class -- private static reader of this class\n private static dependenciesRule(options: RuleOptions): ApiLibDependenciesRule {\n const clients = new Map<string, readonly string[]>();\n for (const entry of options['apiClients'] as ApiClientPackagesEntry[]) clients.set(entry.project, entry.packages);\n return new ApiLibDependenciesRule(options['apiLibPackages'] as string[], clients);\n }\n}\n\n/** What ONE project imports from production source, and the package name others import it by. */\nexport class ProjectImports {\n constructor(\n /** The project's own `package.json` name, or null when it has none. */\n public readonly packageName: string | null,\n /** Bare package names its production (non-test) source imports. */\n public readonly prodPackages: ReadonlySet<string>,\n ) {}\n}\n\n/** The pure check: every tag-truth problem in a graph whose framework sets and roles are resolved. */\nexport class TagTruthValidator {\n constructor(private readonly rules: TagTruthRules) {}\n\n problems(\n graph: EnhancedGraph,\n infos: Map<string, ProjectInfo>,\n imports: ReadonlyMap<string, ProjectImports>,\n ): string[] {\n const problems: string[] = [];\n for (const name of Object.keys(graph).sort()) {\n const entry = graph[name];\n const info = infos.get(name);\n if (info === undefined || info.root === '' || info.root === '.') continue;\n const root = info.root.replace(/\\\\/g, '/').replace(/\\/+$/, '');\n if (this.rules.apiLibDependencies !== null) {\n problems.push(...this.dependencyProblems(name, entry, graph, imports, this.rules.apiLibDependencies));\n }\n if (this.rules.apiLibPath !== null) {\n problems.push(...this.pathProblems(name, root, entry, this.rules.apiLibPath));\n }\n if (this.rules.frameworkFolder !== null) {\n problems.push(...this.folderProblems(name, root, entry, this.rules.frameworkFolder));\n }\n }\n return problems;\n }\n\n /** D2 — the workspace edges and the outside packages of ONE api-lib / api-client. */\n private dependencyProblems(\n name: string,\n entry: GraphEntry,\n graph: EnhancedGraph,\n imports: ReadonlyMap<string, ProjectImports>,\n rule: ApiLibDependenciesRule,\n ): string[] {\n const role = entry.role;\n if (role === undefined || !API_ROLES.includes(role)) return [];\n const rulePrefix = `${\"api-lib-dependencies\"}: '${name}' (role:${role})`;\n const clientPackages = rule.apiClientPackages.get(name);\n if (role === API_CLIENT_ROLE && clientPackages === undefined) {\n return [\n `${rulePrefix} has no apiClients entry — what an api-client talks to is stated, never inferred. ` +\n `Add { \"project\": \"${name}\", \"packages\": [<its SDK, inversify, …>] } to ` +\n `${\"api-lib-dependencies\"}.apiClients in webpieces.config.json, or retag it role:api-lib ` +\n 'if it bundles no implementation.',\n ];\n }\n const allowed = [...rule.apiLibPackages, ...(clientPackages ?? [])];\n const listName =\n role === API_CLIENT_ROLE ? `apiLibPackages or its apiClients entry` : 'apiLibPackages';\n const problems: string[] = [];\n const workspaceNames = new Set<string>();\n for (const dep of entry.dependsOn) {\n const depImports = imports.get(dep);\n if (depImports?.packageName) workspaceNames.add(depImports.packageName);\n const depRole = graph[dep]?.role;\n if (depRole === API_LIB_ROLE) continue;\n if (matchesAnyGlob(dep, allowed)) continue;\n if (depImports?.packageName && matchesAnyGlob(depImports.packageName, allowed)) continue;\n problems.push(\n `${rulePrefix} must not depend on '${dep}' (role:${depRole ?? 'none'}) — an api library depends ` +\n `only on role:api-lib projects and the packages ${listName} lists. Move what it needs into a ` +\n `role:api-lib project, or add '${depImports?.packageName ?? dep}' to ${listName}.`,\n );\n }\n const own = imports.get(name);\n for (const pkg of [...(own?.prodPackages ?? [])].sort()) {\n if (pkg === own?.packageName || workspaceNames.has(pkg) || this.isWorkspacePackage(pkg, imports)) continue;\n if (matchesAnyGlob(pkg, allowed)) continue;\n problems.push(\n `${rulePrefix} imports '${pkg}', which ${listName} does not list — an api library's wire contract ` +\n `must not drag an outside runtime into every consumer. Remove the import, or add '${pkg}' ` +\n `to ${\"api-lib-dependencies\"}.${role === API_CLIENT_ROLE ? `apiClients[\"${name}\"].packages` : 'apiLibPackages'}.`,\n );\n }\n return problems;\n }\n\n /** A package some workspace project publishes — its edge is judged as a workspace dependency above. */\n private isWorkspacePackage(pkg: string, imports: ReadonlyMap<string, ProjectImports>): boolean {\n for (const each of imports.values()) if (each.packageName === pkg) return true;\n return false;\n }\n\n /** D10 — an api project lives under the api globs, and everything there is an api project. */\n private pathProblems(name: string, root: string, entry: GraphEntry, rule: ApiLibPathRule): string[] {\n const isApi = entry.role !== undefined && API_ROLES.includes(entry.role);\n const inPath = matchesAnyGlob(root, rule.paths);\n const globs = `[${rule.paths.join(', ')}]`;\n if (isApi && !inPath) {\n return [\n `${\"api-lib-path\"}: '${name}' is role:${entry.role} but lives at '${root}', outside ` +\n `${\"api-lib-path\"}.paths ${globs} — move it under one of them ` +\n '(nx g @nx/workspace:move), so every contract in the repo is found in one place.',\n ];\n }\n if (inPath && !isApi) {\n return [\n `${\"api-lib-path\"}: '${name}' lives at '${root}', under ${\"api-lib-path\"}.paths ` +\n `${globs}, but is role:${entry.role ?? 'none'} — everything there is a contract. Retag it ` +\n 'role:api-lib (a contract and/or its DTOs) or role:api-client (a contract plus its SDK ' +\n 'adapter), or move it out of the api tree.',\n ];\n }\n return [];\n }\n\n /** D9 — the folder and the tags agree, both directions. */\n private folderProblems(name: string, root: string, entry: GraphEntry, rule: FrameworkFolderRule): string[] {\n if (entry.framework === undefined || entry.role === undefined) return [];\n const set = FrameworkFolder.canonical(entry.framework);\n const role = entry.role;\n const governing = rule.folders.find((folder: FrameworkFolder) => matchesAnyGlob(root, folder.paths));\n const prefix = `${\"framework-folder\"}: '${name}' at '${root}'`;\n if (governing !== undefined) {\n const problems: string[] = [];\n const glob = governing.paths.join(', ');\n if (!governing.frameworkSets.includes(set)) {\n problems.push(\n `${prefix} carries framework set [${set}], but the folder ${glob} holds ` +\n `[${governing.frameworkSets.join(' | ')}] — retag it to the folder's set, or move it to ` +\n 'the folder that holds its set.',\n );\n }\n if (!governing.roles.includes(role)) {\n problems.push(\n `${prefix} is role:${role}, but the folder ${glob} holds role ` +\n `${governing.roles.map((each: string) => `role:${each}`).join(' | ')} — retag it, or move it.`,\n );\n }\n return problems;\n }\n if (APP_ROLES.includes(role) || role === 'bundle') return [];\n const homes = rule.folders.filter(\n (folder: FrameworkFolder) => folder.frameworkSets.includes(set) && folder.roles.includes(role),\n );\n if (homes.length === 0) return [];\n const globs = homes.map((folder: FrameworkFolder) => folder.paths.join(', ')).join(' | ');\n return [\n `${prefix} is a role:${role} carrying [${set}], which ${\"framework-folder\"} places under ` +\n `${globs} — move it there (nx g @nx/workspace:move), so the folder tells a reader what runs where.`,\n ];\n }\n}\n\n/** The executor-facing entry point: read the config and the imports, check, and throw before any write. */\nexport class TagTruthCheck {\n assertTrue(graph: EnhancedGraph, infos: Map<string, ProjectInfo>, workspaceRoot: string): void {\n const rules = TagTruthRules.fromConfig(workspaceRoot);\n if (!rules.anyEnabled()) return;\n const imports = rules.apiLibDependencies === null ? new Map<string, ProjectImports>() : this.importsOf(infos, workspaceRoot);\n const problems = new TagTruthValidator(rules).problems(graph, infos, imports);\n if (problems.length > 0) throw new MetadataValidationError(problems);\n }\n\n /** Every project's production imports and package name, read from its source and package.json. */\n importsOf(infos: Map<string, ProjectInfo>, workspaceRoot: string): Map<string, ProjectImports> {\n const scanner = new DepUsageScanner();\n const found = new Map<string, ProjectImports>();\n for (const info of infos.values()) {\n if (info.root === '' || info.root === '.') continue;\n const abs = path.resolve(workspaceRoot, info.root);\n found.set(info.name, new ProjectImports(this.packageNameOf(abs), scanner.scan(abs).prodPackages));\n }\n return found;\n }\n\n private packageNameOf(projectDir: string): string | null {\n const file = path.join(projectDir, 'package.json');\n if (!fs.existsSync(file)) return null;\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const parsed = JSON.parse(fs.readFileSync(file, 'utf-8')) as RawPackageJson;\n return typeof parsed.name === 'string' ? parsed.name : null;\n } catch (err: unknown) {\n const error = toError(err);\n throw new Error(`Failed to parse ${file} while reading the package name tag-truth checks against`, {\n cause: error,\n });\n }\n }\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import { RetiredConfigKey } from '@webpieces/rules-sdk';
2
+ /** Removed native fields retain their exact owner-authored repair instructions. */
3
+ export declare const ruleMigrations: readonly RetiredConfigKey[];
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ruleMigrations = void 0;
4
+ const rules_sdk_1 = require("@webpieces/rules-sdk");
5
+ /** Removed native fields retain their exact owner-authored repair instructions. */
6
+ exports.ruleMigrations = [
7
+ new rules_sdk_1.RetiredConfigKey("field", "runtime-architecture.servicePaths", "", "This field was removed — it was never read. The runtime graph is derived automatically from architecture/dependencies.json (apiRelations + project roles). Delete it.", "[runtime-architecture]", false),
8
+ new rules_sdk_1.RetiredConfigKey("field", "runtime-architecture.apiProjectPaths", "", "This field was removed — it was never read. The runtime graph is derived automatically from architecture/dependencies.json, so there is NO list of api libs to maintain. Delete it (do not enumerate api libs and do not replace it with a glob).", "[runtime-architecture]", false),
9
+ new rules_sdk_1.RetiredConfigKey("field", "runtime-architecture.allowedCycles", "", "This field was removed — a runtime cycle is not allowable at all any more. Levelling now FAILS on any cycle, because CD deploys services in dependency order and a cycle has no such order. Delete the key. If a cycle genuinely cannot be broken yet, declare it PER EDGE with a `cutLegacyCycle:<targetService>` nx tag on the CALLING project, which admits the debt where `grep -rn cutLegacyCycle` can enumerate it — there is no config key for it.", "[runtime-architecture]", false),
10
+ ];
11
+ //# sourceMappingURL=rule-migrations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule-migrations.js","sourceRoot":"","sources":["../../../../../packages/tooling/nx-webpieces-rules/src/rule-migrations.ts"],"names":[],"mappings":";;;AAAA,oDAAwD;AAExD,mFAAmF;AACtE,QAAA,cAAc,GAAgC;IACvD,IAAI,4BAAgB,CAAC,OAAO,EAAE,mCAAmC,EAAE,EAAE,EAAE,uKAAuK,EAAE,wBAAwB,EAAE,KAAK,CAAC;IAChR,IAAI,4BAAgB,CAAC,OAAO,EAAE,sCAAsC,EAAE,EAAE,EAAE,mPAAmP,EAAE,wBAAwB,EAAE,KAAK,CAAC;IAC/V,IAAI,4BAAgB,CAAC,OAAO,EAAE,oCAAoC,EAAE,EAAE,EAAE,2bAA2b,EAAE,wBAAwB,EAAE,KAAK,CAAC;CACxiB,CAAC","sourcesContent":["import { RetiredConfigKey } from '@webpieces/rules-sdk';\n\n/** Removed native fields retain their exact owner-authored repair instructions. */\nexport const ruleMigrations: readonly RetiredConfigKey[] = [\n new RetiredConfigKey(\"field\", \"runtime-architecture.servicePaths\", \"\", \"This field was removed — it was never read. The runtime graph is derived automatically from architecture/dependencies.json (apiRelations + project roles). Delete it.\", \"[runtime-architecture]\", false),\n new RetiredConfigKey(\"field\", \"runtime-architecture.apiProjectPaths\", \"\", \"This field was removed — it was never read. The runtime graph is derived automatically from architecture/dependencies.json, so there is NO list of api libs to maintain. Delete it (do not enumerate api libs and do not replace it with a glob).\", \"[runtime-architecture]\", false),\n new RetiredConfigKey(\"field\", \"runtime-architecture.allowedCycles\", \"\", \"This field was removed — a runtime cycle is not allowable at all any more. Levelling now FAILS on any cycle, because CD deploys services in dependency order and a cycle has no such order. Delete the key. If a cycle genuinely cannot be broken yet, declare it PER EDGE with a `cutLegacyCycle:<targetService>` nx tag on the CALLING project, which admits the debt where `grep -rn cutLegacyCycle` can enumerate it — there is no config key for it.\", \"[runtime-architecture]\", false),\n];\n"]}
@@ -0,0 +1,2 @@
1
+ import { RulePackManifest } from '@webpieces/rules-sdk';
2
+ export declare const rulePackManifest: RulePackManifest;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rulePackManifest = void 0;
4
+ const rule_migrations_1 = require("./rule-migrations");
5
+ const rule_settings_1 = require("./rule-settings");
6
+ const rules_sdk_1 = require("@webpieces/rules-sdk");
7
+ const rule_configs_1 = require("./configs/rule-configs");
8
+ const no_root_union_config_1 = require("./configs/no-root-union-config");
9
+ const api_doc_rules_config_1 = require("./configs/api-doc-rules-config");
10
+ const tag_truth_configs_1 = require("./configs/tag-truth-configs");
11
+ const package_json_1 = require("../package.json");
12
+ /** Native Nx policies publish their concrete owner schemas. */
13
+ const ownedRules = [
14
+ new rules_sdk_1.OwnedRuleDefinition('no-file-import-cycles', rule_configs_1.NoFileImportCyclesConfig.SCHEMA, rules_sdk_1.RULE_SCHEMA_API_VERSION, rule_settings_1.optionalTuning['no-file-import-cycles'], rule_settings_1.recommendedSeeds['no-file-import-cycles'], 'rules'),
15
+ new rules_sdk_1.OwnedRuleDefinition('runtime-architecture', rule_configs_1.RuntimeArchitectureConfig.SCHEMA, rules_sdk_1.RULE_SCHEMA_API_VERSION, rule_settings_1.optionalTuning['runtime-architecture'], rule_settings_1.recommendedSeeds['runtime-architecture'], 'rules'),
16
+ new rules_sdk_1.OwnedRuleDefinition('nx-wiring', rule_configs_1.NxWiringConfig.SCHEMA, rules_sdk_1.RULE_SCHEMA_API_VERSION, rule_settings_1.optionalTuning['nx-wiring'], rule_settings_1.recommendedSeeds['nx-wiring'], 'rules'),
17
+ new rules_sdk_1.OwnedRuleDefinition('di-graph', rule_configs_1.DiGraphConfig.SCHEMA, rules_sdk_1.RULE_SCHEMA_API_VERSION, rule_settings_1.optionalTuning['di-graph'], rule_settings_1.recommendedSeeds['di-graph'], 'rules'),
18
+ new rules_sdk_1.OwnedRuleDefinition('missing-design-annotation', rule_configs_1.MissingDesignAnnotationConfig.SCHEMA, rules_sdk_1.RULE_SCHEMA_API_VERSION, rule_settings_1.optionalTuning['missing-design-annotation'], rule_settings_1.recommendedSeeds['missing-design-annotation'], 'rules'),
19
+ new rules_sdk_1.OwnedRuleDefinition('validate-architecture-unchanged', rule_configs_1.ValidateArchitectureUnchangedConfig.SCHEMA, rules_sdk_1.RULE_SCHEMA_API_VERSION, rule_settings_1.optionalTuning['validate-architecture-unchanged'], rule_settings_1.recommendedSeeds['validate-architecture-unchanged'], 'rules'),
20
+ new rules_sdk_1.OwnedRuleDefinition('validate-no-architecture-cycles', rule_configs_1.ValidateNoArchitectureCyclesConfig.SCHEMA, rules_sdk_1.RULE_SCHEMA_API_VERSION, rule_settings_1.optionalTuning['validate-no-architecture-cycles'], rule_settings_1.recommendedSeeds['validate-no-architecture-cycles'], 'rules'),
21
+ new rules_sdk_1.OwnedRuleDefinition('validate-packagejson', rule_configs_1.ValidatePackageJsonConfig.SCHEMA, rules_sdk_1.RULE_SCHEMA_API_VERSION, rule_settings_1.optionalTuning['validate-packagejson'], rule_settings_1.recommendedSeeds['validate-packagejson'], 'rules'),
22
+ new rules_sdk_1.OwnedRuleDefinition('validate-versions-locked', rule_configs_1.ValidateVersionsLockedConfig.SCHEMA, rules_sdk_1.RULE_SCHEMA_API_VERSION, rule_settings_1.optionalTuning['validate-versions-locked'], rule_settings_1.recommendedSeeds['validate-versions-locked'], 'rules'),
23
+ new rules_sdk_1.OwnedRuleDefinition('validate-eslint-sync', rule_configs_1.ValidateEslintSyncConfig.SCHEMA, rules_sdk_1.RULE_SCHEMA_API_VERSION, rule_settings_1.optionalTuning['validate-eslint-sync'], rule_settings_1.recommendedSeeds['validate-eslint-sync'], 'rules'),
24
+ new rules_sdk_1.OwnedRuleDefinition('no-root-union-api-type', no_root_union_config_1.NoRootUnionApiTypeConfig.SCHEMA, rules_sdk_1.RULE_SCHEMA_API_VERSION, rule_settings_1.optionalTuning['no-root-union-api-type'], rule_settings_1.recommendedSeeds['no-root-union-api-type'], 'rules'),
25
+ new rules_sdk_1.OwnedRuleDefinition('api-rules-for-openapi', api_doc_rules_config_1.ApiRulesForOpenApiConfig.SCHEMA, rules_sdk_1.RULE_SCHEMA_API_VERSION, rule_settings_1.optionalTuning['api-rules-for-openapi'], rule_settings_1.recommendedSeeds['api-rules-for-openapi'], 'rules'),
26
+ new rules_sdk_1.OwnedRuleDefinition('api-rules-for-mcp', api_doc_rules_config_1.ApiRulesForMcpConfig.SCHEMA, rules_sdk_1.RULE_SCHEMA_API_VERSION, rule_settings_1.optionalTuning['api-rules-for-mcp'], rule_settings_1.recommendedSeeds['api-rules-for-mcp'], 'rules'),
27
+ new rules_sdk_1.OwnedRuleDefinition('api-lib-dependencies', tag_truth_configs_1.ApiLibDependenciesConfig.SCHEMA, rules_sdk_1.RULE_SCHEMA_API_VERSION, rule_settings_1.optionalTuning['api-lib-dependencies'], rule_settings_1.recommendedSeeds['api-lib-dependencies'], 'rules'),
28
+ new rules_sdk_1.OwnedRuleDefinition('api-lib-path', tag_truth_configs_1.ApiLibPathConfig.SCHEMA, rules_sdk_1.RULE_SCHEMA_API_VERSION, rule_settings_1.optionalTuning['api-lib-path'], rule_settings_1.recommendedSeeds['api-lib-path'], 'rules'),
29
+ new rules_sdk_1.OwnedRuleDefinition('framework-folder', tag_truth_configs_1.FrameworkFolderConfig.SCHEMA, rules_sdk_1.RULE_SCHEMA_API_VERSION, rule_settings_1.optionalTuning['framework-folder'], rule_settings_1.recommendedSeeds['framework-folder'], 'rules'),
30
+ ];
31
+ exports.rulePackManifest = new rules_sdk_1.RulePackManifest('@webpieces/nx-webpieces-rules', package_json_1.version, rules_sdk_1.RULE_PACK_API_VERSION, ownedRules, [
32
+ ...ownedRules.map(rule => new rules_sdk_1.RuleContribution(rule.id, '@webpieces/nx-webpieces-rules', 'build')),
33
+ new rules_sdk_1.RuleContribution('validate-ts-in-src', '@webpieces/ai-hook-rules', 'build'),
34
+ ], rule_migrations_1.ruleMigrations, []);
35
+ //# sourceMappingURL=rule-pack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule-pack.js","sourceRoot":"","sources":["../../../../../packages/tooling/nx-webpieces-rules/src/rule-pack.ts"],"names":[],"mappings":"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","sourcesContent":["import { ruleMigrations } from './rule-migrations';\nimport { optionalTuning, recommendedSeeds } from './rule-settings';\nimport { OwnedRuleDefinition, RuleContribution, RulePackManifest, RULE_PACK_API_VERSION, RULE_SCHEMA_API_VERSION } from '@webpieces/rules-sdk';\nimport { NoFileImportCyclesConfig, RuntimeArchitectureConfig, NxWiringConfig, DiGraphConfig, MissingDesignAnnotationConfig, ValidateArchitectureUnchangedConfig, ValidateNoArchitectureCyclesConfig, ValidatePackageJsonConfig, ValidateVersionsLockedConfig, ValidateEslintSyncConfig } from './configs/rule-configs';\nimport { NoRootUnionApiTypeConfig } from './configs/no-root-union-config';\nimport { ApiRulesForOpenApiConfig, ApiRulesForMcpConfig } from './configs/api-doc-rules-config';\nimport { ApiLibDependenciesConfig, ApiLibPathConfig, FrameworkFolderConfig } from './configs/tag-truth-configs';\nimport { version } from '../package.json';\n\n/** Native Nx policies publish their concrete owner schemas. */\nconst ownedRules = [\n new OwnedRuleDefinition('no-file-import-cycles', NoFileImportCyclesConfig.SCHEMA, RULE_SCHEMA_API_VERSION, optionalTuning['no-file-import-cycles'], recommendedSeeds['no-file-import-cycles'], 'rules'),\n new OwnedRuleDefinition('runtime-architecture', RuntimeArchitectureConfig.SCHEMA, RULE_SCHEMA_API_VERSION, optionalTuning['runtime-architecture'], recommendedSeeds['runtime-architecture'], 'rules'),\n new OwnedRuleDefinition('nx-wiring', NxWiringConfig.SCHEMA, RULE_SCHEMA_API_VERSION, optionalTuning['nx-wiring'], recommendedSeeds['nx-wiring'], 'rules'),\n new OwnedRuleDefinition('di-graph', DiGraphConfig.SCHEMA, RULE_SCHEMA_API_VERSION, optionalTuning['di-graph'], recommendedSeeds['di-graph'], 'rules'),\n new OwnedRuleDefinition('missing-design-annotation', MissingDesignAnnotationConfig.SCHEMA, RULE_SCHEMA_API_VERSION, optionalTuning['missing-design-annotation'], recommendedSeeds['missing-design-annotation'], 'rules'),\n new OwnedRuleDefinition('validate-architecture-unchanged', ValidateArchitectureUnchangedConfig.SCHEMA, RULE_SCHEMA_API_VERSION, optionalTuning['validate-architecture-unchanged'], recommendedSeeds['validate-architecture-unchanged'], 'rules'),\n new OwnedRuleDefinition('validate-no-architecture-cycles', ValidateNoArchitectureCyclesConfig.SCHEMA, RULE_SCHEMA_API_VERSION, optionalTuning['validate-no-architecture-cycles'], recommendedSeeds['validate-no-architecture-cycles'], 'rules'),\n new OwnedRuleDefinition('validate-packagejson', ValidatePackageJsonConfig.SCHEMA, RULE_SCHEMA_API_VERSION, optionalTuning['validate-packagejson'], recommendedSeeds['validate-packagejson'], 'rules'),\n new OwnedRuleDefinition('validate-versions-locked', ValidateVersionsLockedConfig.SCHEMA, RULE_SCHEMA_API_VERSION, optionalTuning['validate-versions-locked'], recommendedSeeds['validate-versions-locked'], 'rules'),\n new OwnedRuleDefinition('validate-eslint-sync', ValidateEslintSyncConfig.SCHEMA, RULE_SCHEMA_API_VERSION, optionalTuning['validate-eslint-sync'], recommendedSeeds['validate-eslint-sync'], 'rules'),\n new OwnedRuleDefinition('no-root-union-api-type', NoRootUnionApiTypeConfig.SCHEMA, RULE_SCHEMA_API_VERSION, optionalTuning['no-root-union-api-type'], recommendedSeeds['no-root-union-api-type'], 'rules'),\n new OwnedRuleDefinition('api-rules-for-openapi', ApiRulesForOpenApiConfig.SCHEMA, RULE_SCHEMA_API_VERSION, optionalTuning['api-rules-for-openapi'], recommendedSeeds['api-rules-for-openapi'], 'rules'),\n new OwnedRuleDefinition('api-rules-for-mcp', ApiRulesForMcpConfig.SCHEMA, RULE_SCHEMA_API_VERSION, optionalTuning['api-rules-for-mcp'], recommendedSeeds['api-rules-for-mcp'], 'rules'),\n new OwnedRuleDefinition('api-lib-dependencies', ApiLibDependenciesConfig.SCHEMA, RULE_SCHEMA_API_VERSION, optionalTuning['api-lib-dependencies'], recommendedSeeds['api-lib-dependencies'], 'rules'),\n new OwnedRuleDefinition('api-lib-path', ApiLibPathConfig.SCHEMA, RULE_SCHEMA_API_VERSION, optionalTuning['api-lib-path'], recommendedSeeds['api-lib-path'], 'rules'),\n new OwnedRuleDefinition('framework-folder', FrameworkFolderConfig.SCHEMA, RULE_SCHEMA_API_VERSION, optionalTuning['framework-folder'], recommendedSeeds['framework-folder'], 'rules'),\n];\n\nexport const rulePackManifest = new RulePackManifest(\n '@webpieces/nx-webpieces-rules',\n version,\n RULE_PACK_API_VERSION,\n ownedRules,\n [\n ...ownedRules.map(rule => new RuleContribution(rule.id, '@webpieces/nx-webpieces-rules', 'build')),\n new RuleContribution('validate-ts-in-src', '@webpieces/ai-hook-rules', 'build'),\n ],\n ruleMigrations,\n [],\n);\n"]}
@@ -0,0 +1,5 @@
1
+ import { ConfigObject } from '@webpieces/rules-sdk';
2
+ /** Optional knobs only. Required behaviour is always supplied by the repository. */
3
+ export declare const optionalTuning: Readonly<Record<string, ConfigObject>>;
4
+ /** Written for review by setup/sync; never used as a loader fallback. */
5
+ export declare const recommendedSeeds: Readonly<Record<string, ConfigObject>>;