@webpieces/nx-webpieces-rules 0.4.844 → 0.4.846

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 (62) hide show
  1. package/package.json +8 -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.js +27 -22
  59. package/src/rule-pack.js.map +1 -1
  60. package/src/rule-settings.d.ts +5 -0
  61. package/src/rule-settings.js +210 -0
  62. package/src/rule-settings.js.map +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/nx-webpieces-rules",
3
- "version": "0.4.844",
3
+ "version": "0.4.846",
4
4
  "description": "Nx-specific webpieces validation rules, graph tooling, executors, and inference plugin.",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -19,13 +19,13 @@
19
19
  "README.md"
20
20
  ],
21
21
  "dependencies": {
22
- "@webpieces/api-doc-model": "0.4.844",
23
- "@webpieces/code-rules": "0.4.844",
24
- "@webpieces/core-util": "0.4.844",
25
- "@webpieces/eslint-rules": "0.4.844",
26
- "@webpieces/rules-config": "0.4.844",
22
+ "@webpieces/api-doc-model": "0.4.846",
23
+ "@webpieces/code-rules": "0.4.846",
24
+ "@webpieces/core-util": "0.4.846",
25
+ "@webpieces/eslint-rules": "0.4.846",
26
+ "@webpieces/rules-config": "0.4.846",
27
27
  "madge": "8.0.0",
28
- "@webpieces/rules-sdk": "0.4.844"
28
+ "@webpieces/rules-sdk": "0.4.846"
29
29
  },
30
30
  "peerDependencies": {
31
31
  "@nx/devkit": ">=18.0.0"
@@ -41,7 +41,7 @@
41
41
  "access": "public"
42
42
  },
43
43
  "devDependencies": {
44
- "@webpieces/tooling-testkit": "0.4.844"
44
+ "@webpieces/tooling-testkit": "0.4.846"
45
45
  },
46
46
  "types": "./src/index.d.ts",
47
47
  "bin": {
@@ -0,0 +1,59 @@
1
+ import { SchemaShape, BaseRuleConfig } from "@webpieces/rules-sdk";
2
+ /**
3
+ * The modes the two CONTRACT rules accept (#1017).
4
+ *
5
+ * `AFFECTED_PROJECT` is the one a consumer normally picks, and it is the granularity nx already
6
+ * gives: scan the `@ApiPath` contracts of the projects the diff actually touches, instead of every
7
+ * contract in the workspace every time any project is affected. A contract in a project no changed
8
+ * file belongs to cannot have changed, so scanning it is work with no verdict in it — and on a repo
9
+ * measured at 98 endpoints that is the difference between a rule somebody leaves on and one they
10
+ * turn off.
11
+ *
12
+ * `RUN_EVERY_TIME` stays, for the full-repo migration sweep: when a team decides to publish an API
13
+ * they want the whole list at once, not the part of it they happened to edit this week.
14
+ *
15
+ * This is deliberately NOT diff-HUNK scoping. #1016 established that a contract's publishability is
16
+ * not a property of the lines you touched — adding one field to a DTO can break a document through a
17
+ * type three files away — so the unit stays the PROJECT, which is the unit nx itself works in.
18
+ */
19
+ export declare const API_DOC_MODES: readonly ["OFF", "AFFECTED_PROJECT", "RUN_EVERY_TIME"];
20
+ export type ApiDocMode = typeof API_DOC_MODES[number];
21
+ /**
22
+ * `api-rules-for-openapi` — everything that must hold for an `@ApiPath` contract to PRODUCE an
23
+ * OpenAPI document, checked on every contract in the workspace whether or not it declares `@ApiType`.
24
+ *
25
+ * The rule does not restate "what is expressible". It DRIVES `@webpieces/api-doc-model`'s own
26
+ * extractor, so there is exactly one definition of it and the acceptance contract holds by
27
+ * construction: a contract that passes is one where adding `@ApiType(...)` then generates. A second
28
+ * implementation would drift from the generator's on the first release that improved either.
29
+ *
30
+ * `allowedPaths` exempts whole project trees, with the same glob semantics every other rule's
31
+ * `allowedPaths` uses. The per-site escape hatch is
32
+ * `// webpieces-disable api-rules-for-openapi -- <reason>`, and the REASON is mandatory.
33
+ *
34
+ * An EXISTING `no-any-unknown` disable deliberately does not silence this rule. That rule asks
35
+ * "is this type-safe?"; this one asks "is this field PUBLISHED to a partner with no shape?" — a
36
+ * different question with different right answers, so it wants its own, separately argued line.
37
+ */
38
+ export declare class ApiRulesForOpenApiConfig extends BaseRuleConfig {
39
+ mode?: ApiDocMode;
40
+ allowedPaths?: string[];
41
+ static readonly SCHEMA: SchemaShape<ApiRulesForOpenApiConfig>;
42
+ }
43
+ /**
44
+ * `api-rules-for-mcp` — everything `api-rules-for-openapi` checks, PLUS what `McpToolRegistry`
45
+ * enforces at boot, moved to CI.
46
+ *
47
+ * Two rules and not one because the blast radii differ. An OpenAPI defect is DOCUMENT-WIDE: one
48
+ * unshaped field blocks client generation for every operation of that API. An MCP defect blocks one
49
+ * tool. A team publishing a partner API and no tools must be able to run the first without the
50
+ * second, and a config key per rule is the only way to say that.
51
+ *
52
+ * The MCP half drives `McpSchemaRenderer` itself, tool by tool, so "this passes" and "this renders"
53
+ * are the same statement rather than two that can disagree.
54
+ */
55
+ export declare class ApiRulesForMcpConfig extends BaseRuleConfig {
56
+ mode?: ApiDocMode;
57
+ allowedPaths?: string[];
58
+ static readonly SCHEMA: SchemaShape<ApiRulesForMcpConfig>;
59
+ }
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ApiRulesForMcpConfig = exports.ApiRulesForOpenApiConfig = exports.API_DOC_MODES = void 0;
4
+ const rules_sdk_1 = require("@webpieces/rules-sdk");
5
+ /**
6
+ * The modes the two CONTRACT rules accept (#1017).
7
+ *
8
+ * `AFFECTED_PROJECT` is the one a consumer normally picks, and it is the granularity nx already
9
+ * gives: scan the `@ApiPath` contracts of the projects the diff actually touches, instead of every
10
+ * contract in the workspace every time any project is affected. A contract in a project no changed
11
+ * file belongs to cannot have changed, so scanning it is work with no verdict in it — and on a repo
12
+ * measured at 98 endpoints that is the difference between a rule somebody leaves on and one they
13
+ * turn off.
14
+ *
15
+ * `RUN_EVERY_TIME` stays, for the full-repo migration sweep: when a team decides to publish an API
16
+ * they want the whole list at once, not the part of it they happened to edit this week.
17
+ *
18
+ * This is deliberately NOT diff-HUNK scoping. #1016 established that a contract's publishability is
19
+ * not a property of the lines you touched — adding one field to a DTO can break a document through a
20
+ * type three files away — so the unit stays the PROJECT, which is the unit nx itself works in.
21
+ */
22
+ exports.API_DOC_MODES = ['OFF', 'AFFECTED_PROJECT', 'RUN_EVERY_TIME'];
23
+ /**
24
+ * `api-rules-for-openapi` — everything that must hold for an `@ApiPath` contract to PRODUCE an
25
+ * OpenAPI document, checked on every contract in the workspace whether or not it declares `@ApiType`.
26
+ *
27
+ * The rule does not restate "what is expressible". It DRIVES `@webpieces/api-doc-model`'s own
28
+ * extractor, so there is exactly one definition of it and the acceptance contract holds by
29
+ * construction: a contract that passes is one where adding `@ApiType(...)` then generates. A second
30
+ * implementation would drift from the generator's on the first release that improved either.
31
+ *
32
+ * `allowedPaths` exempts whole project trees, with the same glob semantics every other rule's
33
+ * `allowedPaths` uses. The per-site escape hatch is
34
+ * `// webpieces-disable api-rules-for-openapi -- <reason>`, and the REASON is mandatory.
35
+ *
36
+ * An EXISTING `no-any-unknown` disable deliberately does not silence this rule. That rule asks
37
+ * "is this type-safe?"; this one asks "is this field PUBLISHED to a partner with no shape?" — a
38
+ * different question with different right answers, so it wants its own, separately argued line.
39
+ */
40
+ class ApiRulesForOpenApiConfig extends rules_sdk_1.BaseRuleConfig {
41
+ allowedPaths;
42
+ static SCHEMA = {
43
+ mode: new rules_sdk_1.FieldDef('string', exports.API_DOC_MODES),
44
+ allowedPaths: rules_sdk_1.FieldDef.optional('string[]'),
45
+ ...rules_sdk_1.BASE_RULE_SCHEMA,
46
+ };
47
+ }
48
+ exports.ApiRulesForOpenApiConfig = ApiRulesForOpenApiConfig;
49
+ /**
50
+ * `api-rules-for-mcp` — everything `api-rules-for-openapi` checks, PLUS what `McpToolRegistry`
51
+ * enforces at boot, moved to CI.
52
+ *
53
+ * Two rules and not one because the blast radii differ. An OpenAPI defect is DOCUMENT-WIDE: one
54
+ * unshaped field blocks client generation for every operation of that API. An MCP defect blocks one
55
+ * tool. A team publishing a partner API and no tools must be able to run the first without the
56
+ * second, and a config key per rule is the only way to say that.
57
+ *
58
+ * The MCP half drives `McpSchemaRenderer` itself, tool by tool, so "this passes" and "this renders"
59
+ * are the same statement rather than two that can disagree.
60
+ */
61
+ class ApiRulesForMcpConfig extends rules_sdk_1.BaseRuleConfig {
62
+ allowedPaths;
63
+ static SCHEMA = {
64
+ mode: new rules_sdk_1.FieldDef('string', exports.API_DOC_MODES),
65
+ allowedPaths: rules_sdk_1.FieldDef.optional('string[]'),
66
+ ...rules_sdk_1.BASE_RULE_SCHEMA,
67
+ };
68
+ }
69
+ exports.ApiRulesForMcpConfig = ApiRulesForMcpConfig;
70
+ //# sourceMappingURL=api-doc-rules-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-doc-rules-config.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/configs/api-doc-rules-config.ts"],"names":[],"mappings":";;;AAAA,oDAA+F;AAC/F;;;;;;;;;;;;;;;;GAgBG;AACU,QAAA,aAAa,GAAG,CAAC,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,CAAU,CAAC;AAIpF;;;;;;;;;;;;;;;;GAgBG;AACH,MAAa,wBAAyB,SAAQ,0BAAc;IAExD,YAAY,CAAY;IAExB,MAAM,CAAU,MAAM,GAA0C;QAC5D,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,qBAAa,CAAC;QAC3C,YAAY,EAAE,oBAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC3C,GAAG,4BAAgB;KACtB,CAAC;;AARN,4DASC;AAED;;;;;;;;;;;GAWG;AACH,MAAa,oBAAqB,SAAQ,0BAAc;IAEpD,YAAY,CAAY;IAExB,MAAM,CAAU,MAAM,GAAsC;QACxD,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,qBAAa,CAAC;QAC3C,YAAY,EAAE,oBAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC3C,GAAG,4BAAgB;KACtB,CAAC;;AARN,oDASC","sourcesContent":["import { FieldDef, SchemaShape, BaseRuleConfig, BASE_RULE_SCHEMA } from \"@webpieces/rules-sdk\";\n/**\n * The modes the two CONTRACT rules accept (#1017).\n *\n * `AFFECTED_PROJECT` is the one a consumer normally picks, and it is the granularity nx already\n * gives: scan the `@ApiPath` contracts of the projects the diff actually touches, instead of every\n * contract in the workspace every time any project is affected. A contract in a project no changed\n * file belongs to cannot have changed, so scanning it is work with no verdict in it — and on a repo\n * measured at 98 endpoints that is the difference between a rule somebody leaves on and one they\n * turn off.\n *\n * `RUN_EVERY_TIME` stays, for the full-repo migration sweep: when a team decides to publish an API\n * they want the whole list at once, not the part of it they happened to edit this week.\n *\n * This is deliberately NOT diff-HUNK scoping. #1016 established that a contract's publishability is\n * not a property of the lines you touched — adding one field to a DTO can break a document through a\n * type three files away — so the unit stays the PROJECT, which is the unit nx itself works in.\n */\nexport const API_DOC_MODES = ['OFF', 'AFFECTED_PROJECT', 'RUN_EVERY_TIME'] as const;\n\nexport type ApiDocMode = typeof API_DOC_MODES[number];\n\n/**\n * `api-rules-for-openapi` — everything that must hold for an `@ApiPath` contract to PRODUCE an\n * OpenAPI document, checked on every contract in the workspace whether or not it declares `@ApiType`.\n *\n * The rule does not restate \"what is expressible\". It DRIVES `@webpieces/api-doc-model`'s own\n * extractor, so there is exactly one definition of it and the acceptance contract holds by\n * construction: a contract that passes is one where adding `@ApiType(...)` then generates. A second\n * implementation would drift from the generator's on the first release that improved either.\n *\n * `allowedPaths` exempts whole project trees, with the same glob semantics every other rule's\n * `allowedPaths` uses. The per-site escape hatch is\n * `// webpieces-disable api-rules-for-openapi -- <reason>`, and the REASON is mandatory.\n *\n * An EXISTING `no-any-unknown` disable deliberately does not silence this rule. That rule asks\n * \"is this type-safe?\"; this one asks \"is this field PUBLISHED to a partner with no shape?\" — a\n * different question with different right answers, so it wants its own, separately argued line.\n */\nexport class ApiRulesForOpenApiConfig extends BaseRuleConfig {\n declare mode?: ApiDocMode;\n allowedPaths?: string[];\n\n static readonly SCHEMA: SchemaShape<ApiRulesForOpenApiConfig> = {\n mode: new FieldDef('string', API_DOC_MODES),\n allowedPaths: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\n/**\n * `api-rules-for-mcp` — everything `api-rules-for-openapi` checks, PLUS what `McpToolRegistry`\n * enforces at boot, moved to CI.\n *\n * Two rules and not one because the blast radii differ. An OpenAPI defect is DOCUMENT-WIDE: one\n * unshaped field blocks client generation for every operation of that API. An MCP defect blocks one\n * tool. A team publishing a partner API and no tools must be able to run the first without the\n * second, and a config key per rule is the only way to say that.\n *\n * The MCP half drives `McpSchemaRenderer` itself, tool by tool, so \"this passes\" and \"this renders\"\n * are the same statement rather than two that can disagree.\n */\nexport class ApiRulesForMcpConfig extends BaseRuleConfig {\n declare mode?: ApiDocMode;\n allowedPaths?: string[];\n\n static readonly SCHEMA: SchemaShape<ApiRulesForMcpConfig> = {\n mode: new FieldDef('string', API_DOC_MODES),\n allowedPaths: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n"]}
@@ -0,0 +1,25 @@
1
+ import { SchemaShape, BaseRuleConfig } from "@webpieces/rules-sdk";
2
+ import { StructuralMode } from "./rule-configs";
3
+ /**
4
+ * `no-root-union-api-type` — a request or response type that IS a union, on any `@ApiPath` contract.
5
+ *
6
+ * Both the OpenAI and the Anthropic function-calling APIs forbid `oneOf`/`anyOf`/`allOf` at the TOP
7
+ * level of a tool's parameter schema, and a server sends its WHOLE tool list on every request — so
8
+ * ONE offending tool makes every request 400 and the entire client session is unusable, not just
9
+ * that tool. Nested composition, inside a property, is fine; only the root is the problem.
10
+ *
11
+ * It is checked on EVERY `@ApiPath` contract, whether or not it declares `@ApiType`. `@ApiType` is a
12
+ * PUBLISHING decision added later, on purpose, so a shape rule that only ran on contracts which had
13
+ * already opted in would let a team discover six months afterwards that the type was never
14
+ * expressible — by which time it is in partners' generated clients and cannot be changed.
15
+ *
16
+ * `allowedPaths` exempts whole trees, with the same glob semantics every other rule's `allowedPaths`
17
+ * uses. The per-site escape hatch is `// webpieces-disable no-root-union-api-type -- <reason>`, and
18
+ * the REASON is mandatory: this defect's blast radius is every tool in a session, so a suppression
19
+ * has to carry an argument somebody wrote down.
20
+ */
21
+ export declare class NoRootUnionApiTypeConfig extends BaseRuleConfig {
22
+ mode?: StructuralMode;
23
+ allowedPaths?: string[];
24
+ static readonly SCHEMA: SchemaShape<NoRootUnionApiTypeConfig>;
25
+ }
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NoRootUnionApiTypeConfig = void 0;
4
+ const rules_sdk_1 = require("@webpieces/rules-sdk");
5
+ const rule_configs_1 = require("./rule-configs");
6
+ /**
7
+ * `no-root-union-api-type` — a request or response type that IS a union, on any `@ApiPath` contract.
8
+ *
9
+ * Both the OpenAI and the Anthropic function-calling APIs forbid `oneOf`/`anyOf`/`allOf` at the TOP
10
+ * level of a tool's parameter schema, and a server sends its WHOLE tool list on every request — so
11
+ * ONE offending tool makes every request 400 and the entire client session is unusable, not just
12
+ * that tool. Nested composition, inside a property, is fine; only the root is the problem.
13
+ *
14
+ * It is checked on EVERY `@ApiPath` contract, whether or not it declares `@ApiType`. `@ApiType` is a
15
+ * PUBLISHING decision added later, on purpose, so a shape rule that only ran on contracts which had
16
+ * already opted in would let a team discover six months afterwards that the type was never
17
+ * expressible — by which time it is in partners' generated clients and cannot be changed.
18
+ *
19
+ * `allowedPaths` exempts whole trees, with the same glob semantics every other rule's `allowedPaths`
20
+ * uses. The per-site escape hatch is `// webpieces-disable no-root-union-api-type -- <reason>`, and
21
+ * the REASON is mandatory: this defect's blast radius is every tool in a session, so a suppression
22
+ * has to carry an argument somebody wrote down.
23
+ */
24
+ class NoRootUnionApiTypeConfig extends rules_sdk_1.BaseRuleConfig {
25
+ allowedPaths;
26
+ static SCHEMA = {
27
+ mode: new rules_sdk_1.FieldDef('string', rule_configs_1.STRUCTURAL_MODES),
28
+ allowedPaths: rules_sdk_1.FieldDef.optional('string[]'),
29
+ ...rules_sdk_1.BASE_RULE_SCHEMA,
30
+ };
31
+ }
32
+ exports.NoRootUnionApiTypeConfig = NoRootUnionApiTypeConfig;
33
+ //# sourceMappingURL=no-root-union-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-root-union-config.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/configs/no-root-union-config.ts"],"names":[],"mappings":";;;AAAA,oDAA+F;AAC/F,iDAAkE;AAClE;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAa,wBAAyB,SAAQ,0BAAc;IAExD,YAAY,CAAY;IAExB,MAAM,CAAU,MAAM,GAA0C;QAC5D,IAAI,EAAE,IAAI,oBAAQ,CAAC,QAAQ,EAAE,+BAAgB,CAAC;QAC9C,YAAY,EAAE,oBAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC3C,GAAG,4BAAgB;KACtB,CAAC;;AARN,4DASC","sourcesContent":["import { FieldDef, SchemaShape, BaseRuleConfig, BASE_RULE_SCHEMA } from \"@webpieces/rules-sdk\";\nimport { StructuralMode, STRUCTURAL_MODES } from \"./rule-configs\";\n/**\n * `no-root-union-api-type` — a request or response type that IS a union, on any `@ApiPath` contract.\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, and a server sends its WHOLE tool list on every request — so\n * ONE offending tool makes every request 400 and the entire client session is unusable, not just\n * that tool. Nested composition, inside a property, is fine; only the root is the problem.\n *\n * It is checked on EVERY `@ApiPath` contract, whether or not it declares `@ApiType`. `@ApiType` is a\n * PUBLISHING decision added later, on purpose, so a shape rule that only ran on contracts which had\n * already opted in would let a team discover six months afterwards that the type was never\n * expressible — by which time it is in partners' generated clients and cannot be changed.\n *\n * `allowedPaths` exempts whole trees, with the same glob semantics every other rule's `allowedPaths`\n * uses. The per-site escape hatch is `// webpieces-disable no-root-union-api-type -- <reason>`, and\n * the REASON is mandatory: this defect's blast radius is every tool in a session, so a suppression\n * has to carry an argument somebody wrote down.\n */\nexport class NoRootUnionApiTypeConfig extends BaseRuleConfig {\n declare mode?: StructuralMode;\n allowedPaths?: string[];\n\n static readonly SCHEMA: SchemaShape<NoRootUnionApiTypeConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n allowedPaths: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n"]}
@@ -0,0 +1,67 @@
1
+ import { BaseRuleConfig } from "@webpieces/rules-sdk";
2
+ import { SchemaShape } from "@webpieces/rules-sdk";
3
+ export declare const STRUCTURAL_MODES: readonly ["OFF", "RUN_EVERY_TIME"];
4
+ export type StructuralMode = typeof STRUCTURAL_MODES[number];
5
+ export declare class NoFileImportCyclesConfig extends BaseRuleConfig {
6
+ mode?: StructuralMode;
7
+ ignoreTypeOnly?: boolean;
8
+ excludePackages?: string[];
9
+ excludeRegExp?: string[];
10
+ static readonly SCHEMA: SchemaShape<NoFileImportCyclesConfig>;
11
+ }
12
+ export declare class RuntimeArchitectureConfig extends BaseRuleConfig {
13
+ mode?: StructuralMode;
14
+ /**
15
+ * Draw a dashed terminal node for every contract a service calls that NOTHING in-repo
16
+ * implements (firestore, gmail, ...) — the vendor systems the runtime graph otherwise stops one
17
+ * hop short of. Defaults to true; set false in a repo whose external surface is noisy. Purely a
18
+ * RENDER switch: levels, cycle detection and runtime-dependencies.json are identical either way.
19
+ */
20
+ showExternalNodes?: boolean;
21
+ /**
22
+ * Project roots whose exported `*Api` types are contracts for systems OUTSIDE this repo
23
+ * (firestore, gmail, gcp-storage, ...), e.g. `["libraries/apis/external/**"]`. Globs, matched
24
+ * against the nx project root.
25
+ *
26
+ * Needed because an external contract does NOT look like an in-repo one: it is a plain
27
+ * `interface` bound to a Symbol token and injected, never an `abstract class` carrying @ApiPath
28
+ * reached through `createRpcClient`. Without this list the scanner has no way to tell a vendor
29
+ * seam from any other library, so every call leaving the repo is invisible to the runtime graph.
30
+ *
31
+ * Defaults to none, which is correct for a repo with no vendor wrapper libraries.
32
+ */
33
+ externalApiPaths?: string[];
34
+ static readonly SCHEMA: SchemaShape<RuntimeArchitectureConfig>;
35
+ }
36
+ export declare class NxWiringConfig extends BaseRuleConfig {
37
+ mode?: StructuralMode;
38
+ static readonly SCHEMA: SchemaShape<NxWiringConfig>;
39
+ }
40
+ export declare class DiGraphConfig extends BaseRuleConfig {
41
+ mode?: StructuralMode;
42
+ static readonly SCHEMA: SchemaShape<DiGraphConfig>;
43
+ }
44
+ export declare class MissingDesignAnnotationConfig extends BaseRuleConfig {
45
+ mode?: StructuralMode;
46
+ static readonly SCHEMA: SchemaShape<MissingDesignAnnotationConfig>;
47
+ }
48
+ export declare class ValidateArchitectureUnchangedConfig extends BaseRuleConfig {
49
+ mode?: StructuralMode;
50
+ static readonly SCHEMA: SchemaShape<ValidateArchitectureUnchangedConfig>;
51
+ }
52
+ export declare class ValidateNoArchitectureCyclesConfig extends BaseRuleConfig {
53
+ mode?: StructuralMode;
54
+ static readonly SCHEMA: SchemaShape<ValidateNoArchitectureCyclesConfig>;
55
+ }
56
+ export declare class ValidatePackageJsonConfig extends BaseRuleConfig {
57
+ mode?: StructuralMode;
58
+ static readonly SCHEMA: SchemaShape<ValidatePackageJsonConfig>;
59
+ }
60
+ export declare class ValidateVersionsLockedConfig extends BaseRuleConfig {
61
+ mode?: StructuralMode;
62
+ static readonly SCHEMA: SchemaShape<ValidateVersionsLockedConfig>;
63
+ }
64
+ export declare class ValidateEslintSyncConfig extends BaseRuleConfig {
65
+ mode?: StructuralMode;
66
+ static readonly SCHEMA: SchemaShape<ValidateEslintSyncConfig>;
67
+ }
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ValidateEslintSyncConfig = exports.ValidateVersionsLockedConfig = exports.ValidatePackageJsonConfig = exports.ValidateNoArchitectureCyclesConfig = exports.ValidateArchitectureUnchangedConfig = exports.MissingDesignAnnotationConfig = exports.DiGraphConfig = exports.NxWiringConfig = exports.RuntimeArchitectureConfig = exports.NoFileImportCyclesConfig = exports.STRUCTURAL_MODES = void 0;
4
+ const rules_sdk_1 = require("@webpieces/rules-sdk");
5
+ const rules_sdk_2 = require("@webpieces/rules-sdk");
6
+ // Structural / whole-graph rules (import-cycle, runtime-architecture, nx-wiring). They can't be
7
+ // scoped to changed lines/files — a cycle or wiring break can route through a project that wasn't
8
+ // itself edited — so when active they run the FULL check every time (nx-affected already limits
9
+ // them to affected projects externally). RUN_EVERY_TIME replaces the old, vaguer "ON".
10
+ exports.STRUCTURAL_MODES = ['OFF', 'RUN_EVERY_TIME'];
11
+ // NOTE: there is deliberately no `WholeRepoBuildGuardConfig`. That guard has NO webpieces.config.json
12
+ // entry — it is EXPERIMENTAL and OFF by default, and its only switch is the OPT-IN
13
+ // `experimental.whole-repo-build-guard: true` in the optional machine-local ~/.webpieces/config.json
14
+ // (see home-config.ts). The build command it prints
15
+ // is handed to it directly from `commands.pr-gate.buildCommand` by ai-hook-rules' runner. Re-adding a
16
+ // config class here puts the guard back in RULE_SCHEMAS and makes it a fault-Y rule again.
17
+ class NoFileImportCyclesConfig extends rules_sdk_1.BaseRuleConfig {
18
+ ignoreTypeOnly;
19
+ excludePackages;
20
+ // Raw regex escape hatch for a cycle inside the project being checked — generated code, a
21
+ // vendored tree, or a deliberate bidirectional domain model — that `excludePackages` cannot reach
22
+ // (it resolves npm package NAMES, so it only excludes a *sibling* package, never a directory
23
+ // inside this one). Patterns are handed to madge verbatim and matched against ids RELATIVE TO THE
24
+ // PROJECT (e.g. "^src/generated/", "^src/modules/(item|category)/") — NOT workspace-rooted or
25
+ // absolute, which silently match nothing. The executor warns when a pattern matches zero
26
+ // traversed files, so a mis-anchored pattern is visible rather than a silent no-op.
27
+ excludeRegExp;
28
+ static SCHEMA = {
29
+ mode: new rules_sdk_2.FieldDef('string', exports.STRUCTURAL_MODES),
30
+ ignoreTypeOnly: rules_sdk_2.FieldDef.optional('boolean'),
31
+ excludePackages: rules_sdk_2.FieldDef.optional('string[]'),
32
+ excludeRegExp: rules_sdk_2.FieldDef.optional('string[]'),
33
+ ...rules_sdk_1.BASE_RULE_SCHEMA,
34
+ };
35
+ }
36
+ exports.NoFileImportCyclesConfig = NoFileImportCyclesConfig;
37
+ class RuntimeArchitectureConfig extends rules_sdk_1.BaseRuleConfig {
38
+ // NOTE: `servicePaths` / `apiProjectPaths` were removed — they were never read. The runtime graph
39
+ // is derived SOLELY from architecture/dependencies.json apiRelations + project roles (see
40
+ // nx-webpieces-rules/src/lib/runtime-graph.ts), so any config still listing them (a hand-maintained
41
+ // enumeration of api libs) now fails the unknown-field check in validateWebpiecesConfig. There is
42
+ // nothing to enumerate — delete the keys.
43
+ // NOTE: `allowedCycles` was removed — a runtime cycle is no longer allowable at all. CD deploys
44
+ // services in dependency order and a cyclic architecture has no such order, so the runtime graph
45
+ // now THROWS while it is being levelled rather than emitting a flat, unlevellable diagram (see
46
+ // nx-webpieces-rules/src/lib/runtime-graph-levels.ts). A repo that genuinely cannot break a cycle
47
+ // yet declares it PER EDGE with a `cutLegacyCycle:<targetService>` nx tag on the CALLING project,
48
+ // which admits the debt in a place `grep -rn cutLegacyCycle` can enumerate. Delete the key.
49
+ /**
50
+ * Draw a dashed terminal node for every contract a service calls that NOTHING in-repo
51
+ * implements (firestore, gmail, ...) — the vendor systems the runtime graph otherwise stops one
52
+ * hop short of. Defaults to true; set false in a repo whose external surface is noisy. Purely a
53
+ * RENDER switch: levels, cycle detection and runtime-dependencies.json are identical either way.
54
+ */
55
+ showExternalNodes;
56
+ /**
57
+ * Project roots whose exported `*Api` types are contracts for systems OUTSIDE this repo
58
+ * (firestore, gmail, gcp-storage, ...), e.g. `["libraries/apis/external/**"]`. Globs, matched
59
+ * against the nx project root.
60
+ *
61
+ * Needed because an external contract does NOT look like an in-repo one: it is a plain
62
+ * `interface` bound to a Symbol token and injected, never an `abstract class` carrying @ApiPath
63
+ * reached through `createRpcClient`. Without this list the scanner has no way to tell a vendor
64
+ * seam from any other library, so every call leaving the repo is invisible to the runtime graph.
65
+ *
66
+ * Defaults to none, which is correct for a repo with no vendor wrapper libraries.
67
+ */
68
+ externalApiPaths;
69
+ static SCHEMA = {
70
+ mode: new rules_sdk_2.FieldDef('string', exports.STRUCTURAL_MODES),
71
+ showExternalNodes: rules_sdk_2.FieldDef.optional('boolean'),
72
+ externalApiPaths: rules_sdk_2.FieldDef.optional('string[]'),
73
+ ...rules_sdk_1.BASE_RULE_SCHEMA,
74
+ };
75
+ }
76
+ exports.RuntimeArchitectureConfig = RuntimeArchitectureConfig;
77
+ class NxWiringConfig extends rules_sdk_1.BaseRuleConfig {
78
+ static SCHEMA = {
79
+ mode: new rules_sdk_2.FieldDef('string', exports.STRUCTURAL_MODES),
80
+ ...rules_sdk_1.BASE_RULE_SCHEMA,
81
+ };
82
+ }
83
+ exports.NxWiringConfig = NxWiringConfig;
84
+ class DiGraphConfig extends rules_sdk_1.BaseRuleConfig {
85
+ static SCHEMA = {
86
+ mode: new rules_sdk_2.FieldDef('string', exports.STRUCTURAL_MODES),
87
+ ...rules_sdk_1.BASE_RULE_SCHEMA,
88
+ };
89
+ }
90
+ exports.DiGraphConfig = DiGraphConfig;
91
+ class MissingDesignAnnotationConfig extends rules_sdk_1.BaseRuleConfig {
92
+ static SCHEMA = {
93
+ mode: new rules_sdk_2.FieldDef('string', exports.STRUCTURAL_MODES),
94
+ ...rules_sdk_1.BASE_RULE_SCHEMA,
95
+ };
96
+ }
97
+ exports.MissingDesignAnnotationConfig = MissingDesignAnnotationConfig;
98
+ // ---------------------------------------------------------------------------
99
+ // The five Nx infrastructure validators (architecture-unchanged, no-architecture-cycles,
100
+ // packagejson, versions-locked, eslint-sync). Each is whole-graph / whole-repo by nature (a cycle, a
101
+ // drifted dependencies.json, an unlocked version can be introduced by a file nobody in this diff
102
+ // touched), so the only honest mode set is STRUCTURAL_MODES: RUN_EVERY_TIME (the default) or OFF.
103
+ //
104
+ // All five now honor the universal escape hatches (turnOffRuleUntilEpoch / turnOffRuleWhileOnBranch)
105
+ // via shouldSkipRule — the RuleGate is called with honorEpoch:true from
106
+ // every executor. This lets a repo time-box or branch-scope a failing infrastructure check (e.g. hold
107
+ // validate-packagejson off until an upgrade PR lands) with a one-value edit, instead of only the
108
+ // blunt "mode": "OFF". Originally packagejson/versions-locked/eslint-sync were all-or-nothing on the
109
+ // theory that "no blessed baseline" made grandfathering meaningless, but a time-box is a schedule, not
110
+ // a baseline: "do not enforce this until <epoch>/off <branch>" is coherent for any rule.
111
+ // ---------------------------------------------------------------------------
112
+ class ValidateArchitectureUnchangedConfig extends rules_sdk_1.BaseRuleConfig {
113
+ static SCHEMA = {
114
+ mode: new rules_sdk_2.FieldDef('string', exports.STRUCTURAL_MODES),
115
+ ...rules_sdk_1.BASE_RULE_SCHEMA,
116
+ };
117
+ }
118
+ exports.ValidateArchitectureUnchangedConfig = ValidateArchitectureUnchangedConfig;
119
+ class ValidateNoArchitectureCyclesConfig extends rules_sdk_1.BaseRuleConfig {
120
+ static SCHEMA = {
121
+ mode: new rules_sdk_2.FieldDef('string', exports.STRUCTURAL_MODES),
122
+ ...rules_sdk_1.BASE_RULE_SCHEMA,
123
+ };
124
+ }
125
+ exports.ValidateNoArchitectureCyclesConfig = ValidateNoArchitectureCyclesConfig;
126
+ class ValidatePackageJsonConfig extends rules_sdk_1.BaseRuleConfig {
127
+ static SCHEMA = {
128
+ mode: new rules_sdk_2.FieldDef('string', exports.STRUCTURAL_MODES),
129
+ ...rules_sdk_1.BASE_RULE_SCHEMA,
130
+ };
131
+ }
132
+ exports.ValidatePackageJsonConfig = ValidatePackageJsonConfig;
133
+ class ValidateVersionsLockedConfig extends rules_sdk_1.BaseRuleConfig {
134
+ static SCHEMA = {
135
+ mode: new rules_sdk_2.FieldDef('string', exports.STRUCTURAL_MODES),
136
+ ...rules_sdk_1.BASE_RULE_SCHEMA,
137
+ };
138
+ }
139
+ exports.ValidateVersionsLockedConfig = ValidateVersionsLockedConfig;
140
+ class ValidateEslintSyncConfig extends rules_sdk_1.BaseRuleConfig {
141
+ static SCHEMA = {
142
+ mode: new rules_sdk_2.FieldDef('string', exports.STRUCTURAL_MODES),
143
+ ...rules_sdk_1.BASE_RULE_SCHEMA,
144
+ };
145
+ }
146
+ exports.ValidateEslintSyncConfig = ValidateEslintSyncConfig;
147
+ //# sourceMappingURL=rule-configs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule-configs.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/configs/rule-configs.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseRuleConfig, BASE_RULE_SCHEMA } from \"@webpieces/rules-sdk\";\nimport { FieldDef, SchemaShape } from \"@webpieces/rules-sdk\";\n// Structural / whole-graph rules (import-cycle, runtime-architecture, nx-wiring). They can't be\n// scoped to changed lines/files — a cycle or wiring break can route through a project that wasn't\n// itself edited — so when active they run the FULL check every time (nx-affected already limits\n// them to affected projects externally). RUN_EVERY_TIME replaces the old, vaguer \"ON\".\nexport const STRUCTURAL_MODES = ['OFF', 'RUN_EVERY_TIME'] as const;\n\nexport type StructuralMode = typeof STRUCTURAL_MODES[number];\n\n// NOTE: there is deliberately no `WholeRepoBuildGuardConfig`. That guard has NO webpieces.config.json\n// entry — it is EXPERIMENTAL and OFF by default, and its only switch is the OPT-IN\n// `experimental.whole-repo-build-guard: true` in the optional machine-local ~/.webpieces/config.json\n// (see home-config.ts). The build command it prints\n// is handed to it directly from `commands.pr-gate.buildCommand` by ai-hook-rules' runner. Re-adding a\n// config class here puts the guard back in RULE_SCHEMAS and makes it a fault-Y rule again.\n\nexport class NoFileImportCyclesConfig extends BaseRuleConfig {\n declare mode?: StructuralMode;\n ignoreTypeOnly?: boolean;\n excludePackages?: string[];\n // Raw regex escape hatch for a cycle inside the project being checked — generated code, a\n // vendored tree, or a deliberate bidirectional domain model — that `excludePackages` cannot reach\n // (it resolves npm package NAMES, so it only excludes a *sibling* package, never a directory\n // inside this one). Patterns are handed to madge verbatim and matched against ids RELATIVE TO THE\n // PROJECT (e.g. \"^src/generated/\", \"^src/modules/(item|category)/\") — NOT workspace-rooted or\n // absolute, which silently match nothing. The executor warns when a pattern matches zero\n // traversed files, so a mis-anchored pattern is visible rather than a silent no-op.\n excludeRegExp?: string[];\n\n static readonly SCHEMA: SchemaShape<NoFileImportCyclesConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ignoreTypeOnly: FieldDef.optional('boolean'),\n excludePackages: FieldDef.optional('string[]'),\n excludeRegExp: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class RuntimeArchitectureConfig extends BaseRuleConfig {\n declare mode?: StructuralMode;\n // NOTE: `servicePaths` / `apiProjectPaths` were removed — they were never read. The runtime graph\n // is derived SOLELY from architecture/dependencies.json apiRelations + project roles (see\n // nx-webpieces-rules/src/lib/runtime-graph.ts), so any config still listing them (a hand-maintained\n // enumeration of api libs) now fails the unknown-field check in validateWebpiecesConfig. There is\n // nothing to enumerate — delete the keys.\n // NOTE: `allowedCycles` was removed — a runtime cycle is no longer allowable at all. CD deploys\n // services in dependency order and a cyclic architecture has no such order, so the runtime graph\n // now THROWS while it is being levelled rather than emitting a flat, unlevellable diagram (see\n // nx-webpieces-rules/src/lib/runtime-graph-levels.ts). A repo that genuinely cannot break a cycle\n // yet declares it PER EDGE with a `cutLegacyCycle:<targetService>` nx tag on the CALLING project,\n // which admits the debt in a place `grep -rn cutLegacyCycle` can enumerate. Delete the key.\n /**\n * Draw a dashed terminal node for every contract a service calls that NOTHING in-repo\n * implements (firestore, gmail, ...) — the vendor systems the runtime graph otherwise stops one\n * hop short of. Defaults to true; set false in a repo whose external surface is noisy. Purely a\n * RENDER switch: levels, cycle detection and runtime-dependencies.json are identical either way.\n */\n showExternalNodes?: boolean;\n /**\n * Project roots whose exported `*Api` types are contracts for systems OUTSIDE this repo\n * (firestore, gmail, gcp-storage, ...), e.g. `[\"libraries/apis/external/**\"]`. Globs, matched\n * against the nx project root.\n *\n * Needed because an external contract does NOT look like an in-repo one: it is a plain\n * `interface` bound to a Symbol token and injected, never an `abstract class` carrying @ApiPath\n * reached through `createRpcClient`. Without this list the scanner has no way to tell a vendor\n * seam from any other library, so every call leaving the repo is invisible to the runtime graph.\n *\n * Defaults to none, which is correct for a repo with no vendor wrapper libraries.\n */\n externalApiPaths?: string[];\n\n static readonly SCHEMA: SchemaShape<RuntimeArchitectureConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n showExternalNodes: FieldDef.optional('boolean'),\n externalApiPaths: FieldDef.optional('string[]'),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class NxWiringConfig extends BaseRuleConfig {\n declare mode?: StructuralMode;\n\n static readonly SCHEMA: SchemaShape<NxWiringConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class DiGraphConfig extends BaseRuleConfig {\n // Structural: the DI graph is regenerated whole-project on every build (generate +\n // unchanged gate), so it cannot be scoped to changed lines.\n declare mode?: StructuralMode;\n\n static readonly SCHEMA: SchemaShape<DiGraphConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class MissingDesignAnnotationConfig extends BaseRuleConfig {\n // Structural: enforced per-project by the di-graph-generate executor, which\n // roots the whole DI design on @DocumentDesign classes — cannot be line-scoped.\n declare mode?: StructuralMode;\n\n static readonly SCHEMA: SchemaShape<MissingDesignAnnotationConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n\n// ---------------------------------------------------------------------------\n// The five Nx infrastructure validators (architecture-unchanged, no-architecture-cycles,\n// packagejson, versions-locked, eslint-sync). Each is whole-graph / whole-repo by nature (a cycle, a\n// drifted dependencies.json, an unlocked version can be introduced by a file nobody in this diff\n// touched), so the only honest mode set is STRUCTURAL_MODES: RUN_EVERY_TIME (the default) or OFF.\n//\n// All five now honor the universal escape hatches (turnOffRuleUntilEpoch / turnOffRuleWhileOnBranch)\n// via shouldSkipRule — the RuleGate is called with honorEpoch:true from\n// every executor. This lets a repo time-box or branch-scope a failing infrastructure check (e.g. hold\n// validate-packagejson off until an upgrade PR lands) with a one-value edit, instead of only the\n// blunt \"mode\": \"OFF\". Originally packagejson/versions-locked/eslint-sync were all-or-nothing on the\n// theory that \"no blessed baseline\" made grandfathering meaningless, but a time-box is a schedule, not\n// a baseline: \"do not enforce this until <epoch>/off <branch>\" is coherent for any rule.\n// ---------------------------------------------------------------------------\n\nexport class ValidateArchitectureUnchangedConfig extends BaseRuleConfig {\n declare mode?: StructuralMode;\n\n static readonly SCHEMA: SchemaShape<ValidateArchitectureUnchangedConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class ValidateNoArchitectureCyclesConfig extends BaseRuleConfig {\n declare mode?: StructuralMode;\n\n static readonly SCHEMA: SchemaShape<ValidateNoArchitectureCyclesConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class ValidatePackageJsonConfig extends BaseRuleConfig {\n declare mode?: StructuralMode;\n\n static readonly SCHEMA: SchemaShape<ValidatePackageJsonConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class ValidateVersionsLockedConfig extends BaseRuleConfig {\n declare mode?: StructuralMode;\n\n static readonly SCHEMA: SchemaShape<ValidateVersionsLockedConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n\nexport class ValidateEslintSyncConfig extends BaseRuleConfig {\n declare mode?: StructuralMode;\n\n static readonly SCHEMA: SchemaShape<ValidateEslintSyncConfig> = {\n mode: new FieldDef('string', STRUCTURAL_MODES),\n ...BASE_RULE_SCHEMA,\n };\n}\n"]}
@@ -0,0 +1,72 @@
1
+ import { SchemaShape, BaseRuleConfig } from "@webpieces/rules-sdk";
2
+ import { StructuralMode } from "./rule-configs";
3
+ /** One `role:api-client` project and the outside packages it may import (its SDK, inversify, …). Data-only. */
4
+ export declare class ApiClientPackagesEntry {
5
+ /** The nx project name of the `role:api-client` library, e.g. `gmail-client`. */
6
+ project: string;
7
+ /** Package names (globs allowed, e.g. `@google-cloud/*`) it may import beyond `apiLibPackages`. */
8
+ packages: string[];
9
+ static readonly SCHEMA: SchemaShape<ApiClientPackagesEntry>;
10
+ }
11
+ /**
12
+ * `api-lib-dependencies` (D2) — a `role:api-lib` may depend only on other `role:api-lib` projects plus
13
+ * the outside packages in `apiLibPackages`; a `role:api-client` may ALSO import the packages its own
14
+ * `apiClients` entry names (its SDK, `inversify`, `@webpieces/core-context`, …).
15
+ *
16
+ * - `mode` — OFF | RUN_EVERY_TIME (a graph rule: it reads every project, every run).
17
+ * - `apiLibPackages` — required; may be empty (an api library then imports nothing from outside), e.g.
18
+ * `["@webpieces/core-util", "tslib"]`. A workspace project whose name or package name is listed here
19
+ * is allowed too, so a repo whose `core-util` is a workspace project states it the same way.
20
+ * - `apiClients` — required; one entry per `role:api-client` project. A `role:api-client` with no
21
+ * entry is itself a violation: what it may talk to is stated, never inferred.
22
+ */
23
+ export declare class ApiLibDependenciesConfig extends BaseRuleConfig {
24
+ mode?: StructuralMode;
25
+ apiLibPackages: string[];
26
+ apiClients: ApiClientPackagesEntry[];
27
+ static readonly SCHEMA: SchemaShape<ApiLibDependenciesConfig>;
28
+ }
29
+ /**
30
+ * `api-lib-path` (D10) — both directions: every `role:api-lib` / `role:api-client` project lives under
31
+ * one of `paths`, and every project under `paths` carries one of those two roles.
32
+ *
33
+ * - `mode` — OFF | RUN_EVERY_TIME.
34
+ * - `paths` — required, non-empty globs over project ROOTS, e.g. `["libraries/apis/**"]`.
35
+ */
36
+ export declare class ApiLibPathConfig extends BaseRuleConfig {
37
+ mode?: StructuralMode;
38
+ paths: string[];
39
+ static readonly SCHEMA: SchemaShape<ApiLibPathConfig>;
40
+ }
41
+ /**
42
+ * One folder of the runtime layout: the project roots it covers, the framework SETS a project there may
43
+ * carry, and the roles it may have. Data-only.
44
+ *
45
+ * A framework set is written as its tags joined by `+`, in any order: `"browser+node+react-native"`.
46
+ * Listing two sets means EITHER — `["node", "express"]` is a node library or an express one.
47
+ */
48
+ export declare class FrameworkFolderEntry {
49
+ /** Globs over project ROOTS, e.g. `["libraries/universal/**"]`. Non-empty. */
50
+ paths: string[];
51
+ /** The accepted framework sets, each `+`-joined, e.g. `["browser+node+react-native"]`. Non-empty. */
52
+ frameworkSets: string[];
53
+ /** The accepted roles, e.g. `["lib", "designed-lib"]`. Non-empty. */
54
+ roles: string[];
55
+ static readonly SCHEMA: SchemaShape<FrameworkFolderEntry>;
56
+ }
57
+ /**
58
+ * `framework-folder` (D9) — the folder a library lives in and the tags it carries say the same thing,
59
+ * both directions:
60
+ * - a project under an entry's `paths` (the FIRST entry whose glob matches, in `entries` order) must
61
+ * carry one of that entry's `frameworkSets`, exactly, and one of its `roles`;
62
+ * - a LIBRARY (any role but server/app/client/bundle) carrying a framework set and role that some entry
63
+ * lists must live under one of the entries that list them.
64
+ *
65
+ * - `mode` — OFF | RUN_EVERY_TIME.
66
+ * - `entries` — required, non-empty. The recommended layout is in `.claude/rules/framework-tags.md`.
67
+ */
68
+ export declare class FrameworkFolderConfig extends BaseRuleConfig {
69
+ mode?: StructuralMode;
70
+ entries: FrameworkFolderEntry[];
71
+ static readonly SCHEMA: SchemaShape<FrameworkFolderConfig>;
72
+ }