@intentius/chant 0.44.5 → 0.44.7

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 (42) hide show
  1. package/dist/cli/commands/carve-bridge.d.ts.map +1 -1
  2. package/dist/cli/commands/carve-emit.d.ts +3 -1
  3. package/dist/cli/commands/carve-emit.d.ts.map +1 -1
  4. package/dist/cli/commands/carve.d.ts +64 -2
  5. package/dist/cli/commands/carve.d.ts.map +1 -1
  6. package/dist/terraform/adopt-state.d.ts +18 -1
  7. package/dist/terraform/adopt-state.d.ts.map +1 -1
  8. package/dist/terraform/aws-resources.d.ts +29 -0
  9. package/dist/terraform/aws-resources.d.ts.map +1 -1
  10. package/dist/terraform/bridge.d.ts +8 -0
  11. package/dist/terraform/bridge.d.ts.map +1 -1
  12. package/dist/terraform/carve.d.ts +8 -3
  13. package/dist/terraform/carve.d.ts.map +1 -1
  14. package/dist/terraform/graph.d.ts +10 -4
  15. package/dist/terraform/graph.d.ts.map +1 -1
  16. package/dist/terraform/parse.d.ts.map +1 -1
  17. package/dist/terraform/score.d.ts +11 -0
  18. package/dist/terraform/score.d.ts.map +1 -1
  19. package/dist/terraform/types.d.ts +11 -0
  20. package/dist/terraform/types.d.ts.map +1 -1
  21. package/package.json +1 -1
  22. package/src/cli/commands/carve-bridge.test.ts +32 -0
  23. package/src/cli/commands/carve-bridge.ts +3 -0
  24. package/src/cli/commands/carve-emit-state.test.ts +107 -0
  25. package/src/cli/commands/carve-emit.ts +37 -5
  26. package/src/cli/commands/carve.test.ts +82 -3
  27. package/src/cli/commands/carve.ts +81 -6
  28. package/src/terraform/__fixtures__/advise.test.ts +114 -1
  29. package/src/terraform/adopt-state.test.ts +64 -0
  30. package/src/terraform/adopt-state.ts +52 -2
  31. package/src/terraform/aws-resources.test.ts +102 -1
  32. package/src/terraform/aws-resources.ts +144 -2
  33. package/src/terraform/bridge.test.ts +30 -0
  34. package/src/terraform/bridge.ts +19 -1
  35. package/src/terraform/carve.test.ts +34 -0
  36. package/src/terraform/carve.ts +0 -0
  37. package/src/terraform/graph.test.ts +45 -0
  38. package/src/terraform/graph.ts +35 -16
  39. package/src/terraform/parse.ts +4 -1
  40. package/src/terraform/score.test.ts +25 -0
  41. package/src/terraform/score.ts +27 -4
  42. package/src/terraform/types.ts +11 -0
@@ -6,11 +6,18 @@
6
6
  * score = 100
7
7
  * - 12 * inbound # survivors that depend on this → each a TF data-source patch
8
8
  * - 4 * outbound # this depends on survivors → a deferred deploy-time input
9
+ * - 4 * outputs # an output block reads this → a one-line rewrite (#1638)
9
10
  * - 15 * (tier - 1) # native-spec map: tier1=0, tier2=-15, tier3=-30
10
11
  * - 10 * has_dynamic # count / for_each / data present
11
12
  * - 3 * (instances - 1) # state-expanded instance count
12
13
  * clamp 0..100 (unsupported provider/type → 0)
13
14
  *
15
+ * An `output` block referencing the target is a real inbound dependency — the
16
+ * surviving plan errors on the dangling reference — so it cannot score as
17
+ * free. It is not a data-source patch either: bridging it rewrites one
18
+ * expression in a block that manages no infrastructure, the same order of work
19
+ * as recording an outbound deferred input. Hence 4, not 12.
20
+ *
14
21
  * Sub-resources that inline into a parent (see `FOLDS_INTO`) are folded into the
15
22
  * parent's carve set: they are removed from the ranking and their edge to the
16
23
  * parent is not counted as inbound — inlining them is free, not boundary work.
@@ -23,8 +30,11 @@ import type { TfGraph, TfNode } from "./types";
23
30
  export type PeelabilityBand = "clean leaf" | "carvable w/ edits" | "leave in Terraform";
24
31
 
25
32
  export interface PeelabilityBreakdown {
33
+ /** Inbound edges from resource/module blocks — a data-source patch each. */
26
34
  inbound: number;
27
35
  outbound: number;
36
+ /** Inbound edges from `output` blocks — a one-line rewrite each (#1638). */
37
+ outputs: number;
28
38
  tier: 1 | 2 | 3 | null;
29
39
  hasDynamic: boolean;
30
40
  instances: number;
@@ -32,6 +42,7 @@ export interface PeelabilityBreakdown {
32
42
  penalties: {
33
43
  inbound: number;
34
44
  outbound: number;
45
+ outputs: number;
35
46
  tier: number;
36
47
  dynamic: number;
37
48
  instances: number;
@@ -82,8 +93,11 @@ function computeFolds(graph: TfGraph): { folded: Set<string>; childrenOf: Map<st
82
93
  }
83
94
 
84
95
  function scoreNode(node: TfNode, graph: TfGraph, foldedChildren: Set<string>): Peelability {
85
- // Inbound excludes edges from this node's own folded sub-resources.
86
- const inbound = inboundEdges(graph, node.address).filter((e) => !foldedChildren.has(e.from)).length;
96
+ // Inbound excludes edges from this node's own folded sub-resources, and
97
+ // counts output blocks separately they cost less to bridge (#1638).
98
+ const inboundAll = inboundEdges(graph, node.address).filter((e) => !foldedChildren.has(e.from));
99
+ const inbound = inboundAll.filter((e) => e.fromKind !== "output").length;
100
+ const outputs = inboundAll.length - inbound;
87
101
  const outbound = outboundEdges(graph, node.address).length;
88
102
 
89
103
  const tierInfo = node.kind === "module" ? { tier: MODULE_TIER, mapsTo: undefined } : resolveTier(node.type!);
@@ -99,10 +113,11 @@ function scoreNode(node: TfNode, graph: TfGraph, foldedChildren: Set<string>): P
99
113
  breakdown: {
100
114
  inbound,
101
115
  outbound,
116
+ outputs,
102
117
  tier: null,
103
118
  hasDynamic: node.hasDynamic,
104
119
  instances: node.instances,
105
- penalties: { inbound: 0, outbound: 0, tier: 0, dynamic: 0, instances: 0 },
120
+ penalties: { inbound: 0, outbound: 0, outputs: 0, tier: 0, dynamic: 0, instances: 0 },
106
121
  },
107
122
  };
108
123
  }
@@ -110,12 +125,19 @@ function scoreNode(node: TfNode, graph: TfGraph, foldedChildren: Set<string>): P
110
125
  const penalties = {
111
126
  inbound: -12 * inbound,
112
127
  outbound: -4 * outbound,
128
+ outputs: -4 * outputs,
113
129
  tier: -15 * (tier - 1),
114
130
  dynamic: node.hasDynamic ? -10 : 0,
115
131
  instances: -3 * Math.max(0, node.instances - 1),
116
132
  };
117
133
  const score = clamp(
118
- 100 + penalties.inbound + penalties.outbound + penalties.tier + penalties.dynamic + penalties.instances,
134
+ 100 +
135
+ penalties.inbound +
136
+ penalties.outbound +
137
+ penalties.outputs +
138
+ penalties.tier +
139
+ penalties.dynamic +
140
+ penalties.instances,
119
141
  );
120
142
 
121
143
  return {
@@ -127,6 +149,7 @@ function scoreNode(node: TfNode, graph: TfGraph, foldedChildren: Set<string>): P
127
149
  breakdown: {
128
150
  inbound,
129
151
  outbound,
152
+ outputs,
130
153
  tier,
131
154
  hasDynamic: node.hasDynamic,
132
155
  instances: node.instances,
@@ -46,6 +46,15 @@ export interface TfNode {
46
46
  export interface TfEdge {
47
47
  from: string;
48
48
  to: string;
49
+ /**
50
+ * The kind of block the reference came from, when it is not one of the
51
+ * graph's own nodes. `"output"` marks a root-module `output` block (#1638):
52
+ * a real dependency — `terraform plan` errors on the dangling reference the
53
+ * moment the carve lands — but a cheaper one to bridge than a resource's,
54
+ * since the patch is a single expression edit in a block that manages
55
+ * nothing. Absent means the reference came from a resource or module node.
56
+ */
57
+ fromKind?: "output";
49
58
  /** The attribute path(s) referenced, e.g. `["id", "arn"]`. */
50
59
  attrs: string[];
51
60
  /**
@@ -72,5 +81,7 @@ export interface Hcl2JsonTree {
72
81
  resource?: Record<string, Record<string, unknown[]>>;
73
82
  module?: Record<string, unknown[]>;
74
83
  data?: Record<string, Record<string, unknown[]>>;
84
+ /** Root-module `output` blocks. Not nodes — they reference, they are not carvable (#1638). */
85
+ output?: Record<string, unknown[]>;
75
86
  [k: string]: unknown;
76
87
  }