@webpieces/nx-webpieces-rules 0.4.899 → 0.4.900

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/nx-webpieces-rules",
3
- "version": "0.4.899",
3
+ "version": "0.4.900",
4
4
  "description": "Nx-specific webpieces validation rules, graph tooling, executors, and inference plugin.",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -20,12 +20,12 @@
20
20
  "README.md"
21
21
  ],
22
22
  "dependencies": {
23
- "@webpieces/api-doc-model": "0.4.899",
24
- "@webpieces/core-util": "0.4.899",
25
- "@webpieces/eslint-rules": "0.4.899",
26
- "@webpieces/rules-config": "0.4.899",
23
+ "@webpieces/api-doc-model": "0.4.900",
24
+ "@webpieces/core-util": "0.4.900",
25
+ "@webpieces/eslint-rules": "0.4.900",
26
+ "@webpieces/rules-config": "0.4.900",
27
27
  "madge": "8.0.0",
28
- "@webpieces/rules-sdk": "0.4.899"
28
+ "@webpieces/rules-sdk": "0.4.900"
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.899"
44
+ "@webpieces/tooling-testkit": "0.4.900"
45
45
  },
46
46
  "types": "./src/index.d.ts",
47
47
  "bin": {
@@ -10,7 +10,9 @@
10
10
  * This is what build order follows via `^build`.
11
11
  * - generateReducedGraph() → transitive reduction of the full graph: the minimal
12
12
  * edge set with identical reachability, used as the
13
- * architecture VIEW written to dependencies.json.
13
+ * architecture VIEW written to dependencies.json. A path
14
+ * through a `drawOnGraph:false` project never removes a
15
+ * visible edge (see visible-transitive-reduction.ts).
14
16
  */
15
17
  /**
16
18
  * Build the full dependency graph from nx's project graph.
@@ -11,14 +11,18 @@
11
11
  * This is what build order follows via `^build`.
12
12
  * - generateReducedGraph() → transitive reduction of the full graph: the minimal
13
13
  * edge set with identical reachability, used as the
14
- * architecture VIEW written to dependencies.json.
14
+ * architecture VIEW written to dependencies.json. A path
15
+ * through a `drawOnGraph:false` project never removes a
16
+ * visible edge (see visible-transitive-reduction.ts).
15
17
  */
16
18
  Object.defineProperty(exports, "__esModule", { value: true });
17
19
  exports.generateRawGraph = generateRawGraph;
18
20
  exports.generateGraph = generateGraph;
19
21
  exports.generateReducedGraph = generateReducedGraph;
20
22
  const devkit_1 = require("@nx/devkit");
21
- const transitive_reduction_1 = require("./transitive-reduction");
23
+ const graph_metadata_1 = require("./graph-metadata");
24
+ const draw_on_graph_resolver_1 = require("./draw-on-graph-resolver");
25
+ const visible_transitive_reduction_1 = require("./visible-transitive-reduction");
22
26
  /**
23
27
  * Projects to exclude from graph validation (tools, configs, etc.)
24
28
  */
@@ -74,6 +78,21 @@ async function generateGraph() {
74
78
  */
75
79
  async function generateReducedGraph() {
76
80
  const full = await generateGraph();
77
- return (0, transitive_reduction_1.transitiveReduction)(full);
81
+ const hidden = await new HiddenProjectFinder().find();
82
+ return new visible_transitive_reduction_1.VisibleTransitiveReduction().reduce(full, hidden);
83
+ }
84
+ /**
85
+ * The projects tagged `drawOnGraph:false`. A malformed tag is NOT reported here: enrichGraph
86
+ * reports it with every other metadata problem, and such a project is treated as drawn.
87
+ */
88
+ class HiddenProjectFinder {
89
+ async find() {
90
+ const hidden = new Set();
91
+ for (const info of (await (0, graph_metadata_1.collectProjectInfo)()).values()) {
92
+ if ((0, draw_on_graph_resolver_1.resolveDrawOnGraph)(info).drawOnGraph === false)
93
+ hidden.add(info.name);
94
+ }
95
+ return hidden;
96
+ }
78
97
  }
79
98
  //# sourceMappingURL=graph-generator.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"graph-generator.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/graph-generator.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;AAoBH,4CA0BC;AAKD,sCAEC;AAUD,oDAGC;AAhED,uCAAqD;AACrD,iEAA6D;AAE7D;;GAEG;AACH,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAS,CAAC,cAAc,CAAC,CAAC,CAAC;AAE5D;;;;;;;;;GASG;AACI,KAAK,UAAU,gBAAgB;IAClC,MAAM,YAAY,GAAG,MAAM,IAAA,gCAAuB,GAAE,CAAC;IACrD,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IAEnE,MAAM,OAAO,GAA6B,EAAE,CAAC;IAE7C,KAAK,MAAM,WAAW,IAAI,iBAAiB,EAAE,CAAC;QAC1C,IAAI,iBAAiB,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;YACrC,SAAS;QACb,CAAC;QAED,MAAM,KAAK,GAAG,YAAY,CAAC,YAAY,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;QAC3D,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACvB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;YAC3B,wEAAwE;YACxE,IAAI,MAAM,KAAK,WAAW;gBAAE,SAAS;YACrC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC;gBAAE,SAAS,CAAC,uBAAuB;YACrE,IAAI,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC;gBAAE,SAAS;YAC5C,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACrB,CAAC;QAED,OAAO,CAAC,WAAW,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;IACnD,CAAC;IAED,OAAO,OAAO,CAAC;AACnB,CAAC;AAED;;GAEG;AACI,KAAK,UAAU,aAAa;IAC/B,OAAO,gBAAgB,EAAE,CAAC;AAC9B,CAAC;AAED;;;;;;;GAOG;AACI,KAAK,UAAU,oBAAoB;IACtC,MAAM,IAAI,GAAG,MAAM,aAAa,EAAE,CAAC;IACnC,OAAO,IAAA,0CAAmB,EAAC,IAAI,CAAC,CAAC;AACrC,CAAC","sourcesContent":["/**\n * Graph Generator\n *\n * Builds the workspace dependency graph from nx's OWN project graph\n * (createProjectGraphAsync). nx already derives those edges from BOTH source\n * imports AND package.json workspace deps, so there is no hand-maintained edge\n * list and no separate import scan — we consume what nx already computed.\n *\n * - generateGraph() → the FULL graph (every workspace edge nx knows).\n * This is what build order follows via `^build`.\n * - generateReducedGraph() → transitive reduction of the full graph: the minimal\n * edge set with identical reachability, used as the\n * architecture VIEW written to dependencies.json.\n */\n\nimport { createProjectGraphAsync } from '@nx/devkit';\nimport { transitiveReduction } from './transitive-reduction';\n\n/**\n * Projects to exclude from graph validation (tools, configs, etc.)\n */\nconst EXCLUDED_PROJECTS = new Set<string>(['architecture']);\n\n/**\n * Build the full dependency graph from nx's project graph.\n *\n * nx's `projectGraph.nodes` are the workspace projects; `projectGraph.dependencies`\n * holds every edge nx inferred (imports + package.json). We keep only edges whose\n * target is another workspace project (dropping `npm:` externals) and drop excluded\n * projects.\n *\n * Returns: { projectName: [workspaceDependencyNames] } (deps sorted, deduped)\n */\nexport async function generateRawGraph(): Promise<Record<string, string[]>> {\n const projectGraph = await createProjectGraphAsync();\n const workspaceProjects = new Set(Object.keys(projectGraph.nodes));\n\n const rawDeps: Record<string, string[]> = {};\n\n for (const projectName of workspaceProjects) {\n if (EXCLUDED_PROJECTS.has(projectName)) {\n continue;\n }\n\n const edges = projectGraph.dependencies[projectName] ?? [];\n const deps = new Set<string>();\n for (const edge of edges) {\n const target = edge.target;\n // Keep only workspace→workspace edges; skip self and excluded projects.\n if (target === projectName) continue;\n if (!workspaceProjects.has(target)) continue; // drops npm: externals\n if (EXCLUDED_PROJECTS.has(target)) continue;\n deps.add(target);\n }\n\n rawDeps[projectName] = Array.from(deps).sort();\n }\n\n return rawDeps;\n}\n\n/**\n * The full workspace dependency graph (every edge nx knows).\n */\nexport async function generateGraph(): Promise<Record<string, string[]>> {\n return generateRawGraph();\n}\n\n/**\n * The transitively-reduced view of the full graph. This is the canonical\n * \"architecture graph\" written to and validated against dependencies.json.\n *\n * Reduction is undefined on cycles; callers that care about cycles\n * (validate-no-architecture-cycles) run on the FULL graph and throw first. For the\n * view executors, the downstream topological sort also throws on any cycle.\n */\nexport async function generateReducedGraph(): Promise<Record<string, string[]>> {\n const full = await generateGraph();\n return transitiveReduction(full);\n}\n"]}
1
+ {"version":3,"file":"graph-generator.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/graph-generator.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;AAsBH,4CA0BC;AAKD,sCAEC;AAUD,oDAIC;AAnED,uCAAqD;AACrD,qDAAsD;AACtD,qEAA8D;AAC9D,iFAA4E;AAE5E;;GAEG;AACH,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAS,CAAC,cAAc,CAAC,CAAC,CAAC;AAE5D;;;;;;;;;GASG;AACI,KAAK,UAAU,gBAAgB;IAClC,MAAM,YAAY,GAAG,MAAM,IAAA,gCAAuB,GAAE,CAAC;IACrD,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IAEnE,MAAM,OAAO,GAA6B,EAAE,CAAC;IAE7C,KAAK,MAAM,WAAW,IAAI,iBAAiB,EAAE,CAAC;QAC1C,IAAI,iBAAiB,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;YACrC,SAAS;QACb,CAAC;QAED,MAAM,KAAK,GAAG,YAAY,CAAC,YAAY,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;QAC3D,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACvB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;YAC3B,wEAAwE;YACxE,IAAI,MAAM,KAAK,WAAW;gBAAE,SAAS;YACrC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC;gBAAE,SAAS,CAAC,uBAAuB;YACrE,IAAI,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC;gBAAE,SAAS;YAC5C,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACrB,CAAC;QAED,OAAO,CAAC,WAAW,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;IACnD,CAAC;IAED,OAAO,OAAO,CAAC;AACnB,CAAC;AAED;;GAEG;AACI,KAAK,UAAU,aAAa;IAC/B,OAAO,gBAAgB,EAAE,CAAC;AAC9B,CAAC;AAED;;;;;;;GAOG;AACI,KAAK,UAAU,oBAAoB;IACtC,MAAM,IAAI,GAAG,MAAM,aAAa,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,MAAM,IAAI,mBAAmB,EAAE,CAAC,IAAI,EAAE,CAAC;IACtD,OAAO,IAAI,yDAA0B,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACjE,CAAC;AAED;;;GAGG;AACH,MAAM,mBAAmB;IACrB,KAAK,CAAC,IAAI;QACN,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;QACjC,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,IAAA,mCAAkB,GAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;YACvD,IAAI,IAAA,2CAAkB,EAAC,IAAI,CAAC,CAAC,WAAW,KAAK,KAAK;gBAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9E,CAAC;QACD,OAAO,MAAM,CAAC;IAClB,CAAC;CACJ","sourcesContent":["/**\n * Graph Generator\n *\n * Builds the workspace dependency graph from nx's OWN project graph\n * (createProjectGraphAsync). nx already derives those edges from BOTH source\n * imports AND package.json workspace deps, so there is no hand-maintained edge\n * list and no separate import scan — we consume what nx already computed.\n *\n * - generateGraph() → the FULL graph (every workspace edge nx knows).\n * This is what build order follows via `^build`.\n * - generateReducedGraph() → transitive reduction of the full graph: the minimal\n * edge set with identical reachability, used as the\n * architecture VIEW written to dependencies.json. A path\n * through a `drawOnGraph:false` project never removes a\n * visible edge (see visible-transitive-reduction.ts).\n */\n\nimport { createProjectGraphAsync } from '@nx/devkit';\nimport { collectProjectInfo } from './graph-metadata';\nimport { resolveDrawOnGraph } from './draw-on-graph-resolver';\nimport { VisibleTransitiveReduction } from './visible-transitive-reduction';\n\n/**\n * Projects to exclude from graph validation (tools, configs, etc.)\n */\nconst EXCLUDED_PROJECTS = new Set<string>(['architecture']);\n\n/**\n * Build the full dependency graph from nx's project graph.\n *\n * nx's `projectGraph.nodes` are the workspace projects; `projectGraph.dependencies`\n * holds every edge nx inferred (imports + package.json). We keep only edges whose\n * target is another workspace project (dropping `npm:` externals) and drop excluded\n * projects.\n *\n * Returns: { projectName: [workspaceDependencyNames] } (deps sorted, deduped)\n */\nexport async function generateRawGraph(): Promise<Record<string, string[]>> {\n const projectGraph = await createProjectGraphAsync();\n const workspaceProjects = new Set(Object.keys(projectGraph.nodes));\n\n const rawDeps: Record<string, string[]> = {};\n\n for (const projectName of workspaceProjects) {\n if (EXCLUDED_PROJECTS.has(projectName)) {\n continue;\n }\n\n const edges = projectGraph.dependencies[projectName] ?? [];\n const deps = new Set<string>();\n for (const edge of edges) {\n const target = edge.target;\n // Keep only workspace→workspace edges; skip self and excluded projects.\n if (target === projectName) continue;\n if (!workspaceProjects.has(target)) continue; // drops npm: externals\n if (EXCLUDED_PROJECTS.has(target)) continue;\n deps.add(target);\n }\n\n rawDeps[projectName] = Array.from(deps).sort();\n }\n\n return rawDeps;\n}\n\n/**\n * The full workspace dependency graph (every edge nx knows).\n */\nexport async function generateGraph(): Promise<Record<string, string[]>> {\n return generateRawGraph();\n}\n\n/**\n * The transitively-reduced view of the full graph. This is the canonical\n * \"architecture graph\" written to and validated against dependencies.json.\n *\n * Reduction is undefined on cycles; callers that care about cycles\n * (validate-no-architecture-cycles) run on the FULL graph and throw first. For the\n * view executors, the downstream topological sort also throws on any cycle.\n */\nexport async function generateReducedGraph(): Promise<Record<string, string[]>> {\n const full = await generateGraph();\n const hidden = await new HiddenProjectFinder().find();\n return new VisibleTransitiveReduction().reduce(full, hidden);\n}\n\n/**\n * The projects tagged `drawOnGraph:false`. A malformed tag is NOT reported here: enrichGraph\n * reports it with every other metadata problem, and such a project is treated as drawn.\n */\nclass HiddenProjectFinder {\n async find(): Promise<Set<string>> {\n const hidden = new Set<string>();\n for (const info of (await collectProjectInfo()).values()) {\n if (resolveDrawOnGraph(info).drawOnGraph === false) hidden.add(info.name);\n }\n return hidden;\n }\n}\n"]}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Visible Transitive Reduction (#1215)
3
+ *
4
+ * The plain transitive reduction drops a direct edge A → C whenever a longer path A → B → C exists.
5
+ * That is correct on the FULL graph, but the rendered graphs then omit every project tagged
6
+ * `drawOnGraph:false`. When B is such a hidden project, hiding it removes the only path the
7
+ * reduction kept, and A → C vanishes from the picture although A really depends on C directly.
8
+ * That is exactly how `rules-sdk` rendered as an orphan: every rules package reaches it through the
9
+ * hidden, test-only `tooling-testkit`, so every direct edge into it was reduced away.
10
+ *
11
+ * So the reduction is computed TWICE and unioned:
12
+ * - over the full graph, which keeps every edge that touches a hidden project (the JSON stays a
13
+ * complete data view, hidden projects included);
14
+ * - over the VISIBLE graph only (hidden projects and their edges removed first), which decides
15
+ * which visible → visible edges are drawn. A path through a hidden project never makes a visible
16
+ * edge redundant.
17
+ *
18
+ * Every visible → visible edge the full reduction keeps is also kept by the visible reduction (no
19
+ * sibling reaches its target in the full graph, so none does in a subgraph), so the union only ADDS
20
+ * the edges that were wrongly removed through a hidden project. Both halves are subsets of the full
21
+ * graph and the full reduction alone already preserves reachability, so the union does too — and
22
+ * every added edge is implied by a longer existing path, so no dependency level changes.
23
+ */
24
+ export declare class VisibleTransitiveReduction {
25
+ /**
26
+ * @param full - Full DAG as { project: [directChildren] }
27
+ * @param hidden - Projects tagged `drawOnGraph:false`
28
+ * @returns Reduced graph { project: [children] } (children sorted)
29
+ */
30
+ reduce(full: Record<string, string[]>, hidden: ReadonlySet<string>): Record<string, string[]>;
31
+ /** The full graph with every hidden project, and every edge touching one, removed. */
32
+ private visibleSubgraph;
33
+ }
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ /**
3
+ * Visible Transitive Reduction (#1215)
4
+ *
5
+ * The plain transitive reduction drops a direct edge A → C whenever a longer path A → B → C exists.
6
+ * That is correct on the FULL graph, but the rendered graphs then omit every project tagged
7
+ * `drawOnGraph:false`. When B is such a hidden project, hiding it removes the only path the
8
+ * reduction kept, and A → C vanishes from the picture although A really depends on C directly.
9
+ * That is exactly how `rules-sdk` rendered as an orphan: every rules package reaches it through the
10
+ * hidden, test-only `tooling-testkit`, so every direct edge into it was reduced away.
11
+ *
12
+ * So the reduction is computed TWICE and unioned:
13
+ * - over the full graph, which keeps every edge that touches a hidden project (the JSON stays a
14
+ * complete data view, hidden projects included);
15
+ * - over the VISIBLE graph only (hidden projects and their edges removed first), which decides
16
+ * which visible → visible edges are drawn. A path through a hidden project never makes a visible
17
+ * edge redundant.
18
+ *
19
+ * Every visible → visible edge the full reduction keeps is also kept by the visible reduction (no
20
+ * sibling reaches its target in the full graph, so none does in a subgraph), so the union only ADDS
21
+ * the edges that were wrongly removed through a hidden project. Both halves are subsets of the full
22
+ * graph and the full reduction alone already preserves reachability, so the union does too — and
23
+ * every added edge is implied by a longer existing path, so no dependency level changes.
24
+ */
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.VisibleTransitiveReduction = void 0;
27
+ const transitive_reduction_1 = require("./transitive-reduction");
28
+ class VisibleTransitiveReduction {
29
+ /**
30
+ * @param full - Full DAG as { project: [directChildren] }
31
+ * @param hidden - Projects tagged `drawOnGraph:false`
32
+ * @returns Reduced graph { project: [children] } (children sorted)
33
+ */
34
+ reduce(full, hidden) {
35
+ const reduced = (0, transitive_reduction_1.transitiveReduction)(full);
36
+ if (hidden.size === 0)
37
+ return reduced;
38
+ const visibleReduced = (0, transitive_reduction_1.transitiveReduction)(this.visibleSubgraph(full, hidden));
39
+ const result = {};
40
+ for (const project of Object.keys(reduced)) {
41
+ const children = new Set(reduced[project]);
42
+ for (const child of visibleReduced[project] ?? [])
43
+ children.add(child);
44
+ result[project] = Array.from(children).sort();
45
+ }
46
+ return result;
47
+ }
48
+ /** The full graph with every hidden project, and every edge touching one, removed. */
49
+ visibleSubgraph(full, hidden) {
50
+ const visible = {};
51
+ for (const project of Object.keys(full)) {
52
+ if (hidden.has(project))
53
+ continue;
54
+ visible[project] = (full[project] ?? []).filter((dep) => !hidden.has(dep));
55
+ }
56
+ return visible;
57
+ }
58
+ }
59
+ exports.VisibleTransitiveReduction = VisibleTransitiveReduction;
60
+ //# sourceMappingURL=visible-transitive-reduction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visible-transitive-reduction.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/visible-transitive-reduction.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;;;AAEH,iEAA6D;AAE7D,MAAa,0BAA0B;IACnC;;;;OAIG;IACH,MAAM,CAAC,IAA8B,EAAE,MAA2B;QAC9D,MAAM,OAAO,GAAG,IAAA,0CAAmB,EAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO,OAAO,CAAC;QAEtC,MAAM,cAAc,GAAG,IAAA,0CAAmB,EAAC,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;QAC/E,MAAM,MAAM,GAA6B,EAAE,CAAC;QAC5C,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACzC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAS,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;YACnD,KAAK,MAAM,KAAK,IAAI,cAAc,CAAC,OAAO,CAAC,IAAI,EAAE;gBAAE,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACvE,MAAM,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QAClD,CAAC;QACD,OAAO,MAAM,CAAC;IAClB,CAAC;IAED,sFAAsF;IAC9E,eAAe,CACnB,IAA8B,EAC9B,MAA2B;QAE3B,MAAM,OAAO,GAA6B,EAAE,CAAC;QAC7C,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACtC,IAAI,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC;gBAAE,SAAS;YAClC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAW,EAAW,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QAChG,CAAC;QACD,OAAO,OAAO,CAAC;IACnB,CAAC;CACJ;AAhCD,gEAgCC","sourcesContent":["/**\n * Visible Transitive Reduction (#1215)\n *\n * The plain transitive reduction drops a direct edge A → C whenever a longer path A → B → C exists.\n * That is correct on the FULL graph, but the rendered graphs then omit every project tagged\n * `drawOnGraph:false`. When B is such a hidden project, hiding it removes the only path the\n * reduction kept, and A → C vanishes from the picture although A really depends on C directly.\n * That is exactly how `rules-sdk` rendered as an orphan: every rules package reaches it through the\n * hidden, test-only `tooling-testkit`, so every direct edge into it was reduced away.\n *\n * So the reduction is computed TWICE and unioned:\n * - over the full graph, which keeps every edge that touches a hidden project (the JSON stays a\n * complete data view, hidden projects included);\n * - over the VISIBLE graph only (hidden projects and their edges removed first), which decides\n * which visible → visible edges are drawn. A path through a hidden project never makes a visible\n * edge redundant.\n *\n * Every visible → visible edge the full reduction keeps is also kept by the visible reduction (no\n * sibling reaches its target in the full graph, so none does in a subgraph), so the union only ADDS\n * the edges that were wrongly removed through a hidden project. Both halves are subsets of the full\n * graph and the full reduction alone already preserves reachability, so the union does too — and\n * every added edge is implied by a longer existing path, so no dependency level changes.\n */\n\nimport { transitiveReduction } from './transitive-reduction';\n\nexport class VisibleTransitiveReduction {\n /**\n * @param full - Full DAG as { project: [directChildren] }\n * @param hidden - Projects tagged `drawOnGraph:false`\n * @returns Reduced graph { project: [children] } (children sorted)\n */\n reduce(full: Record<string, string[]>, hidden: ReadonlySet<string>): Record<string, string[]> {\n const reduced = transitiveReduction(full);\n if (hidden.size === 0) return reduced;\n\n const visibleReduced = transitiveReduction(this.visibleSubgraph(full, hidden));\n const result: Record<string, string[]> = {};\n for (const project of Object.keys(reduced)) {\n const children = new Set<string>(reduced[project]);\n for (const child of visibleReduced[project] ?? []) children.add(child);\n result[project] = Array.from(children).sort();\n }\n return result;\n }\n\n /** The full graph with every hidden project, and every edge touching one, removed. */\n private visibleSubgraph(\n full: Record<string, string[]>,\n hidden: ReadonlySet<string>,\n ): Record<string, string[]> {\n const visible: Record<string, string[]> = {};\n for (const project of Object.keys(full)) {\n if (hidden.has(project)) continue;\n visible[project] = (full[project] ?? []).filter((dep: string): boolean => !hidden.has(dep));\n }\n return visible;\n }\n}\n"]}