@intentius/chant-lexicon-terraform 0.66.1 → 0.67.0
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/dist/behaviour/kinds.d.ts +36 -0
- package/dist/behaviour/kinds.d.ts.map +1 -0
- package/dist/behaviour/predict.d.ts +1 -1
- package/dist/integrity.json +2 -2
- package/dist/manifest.json +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/behaviour/kinds.ts +200 -0
- package/src/behaviour/predict.test.ts +1 -1
- package/src/behaviour/predict.ts +1 -1
- package/src/behaviour/request.ts +2 -2
- package/src/plugin.ts +2 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a terraform root's blocks are worth to a behaviour engine (#2382).
|
|
3
|
+
*
|
|
4
|
+
* Contributed as rows through the plugin's `behaviourKinds` field; the
|
|
5
|
+
* vocabulary and the resolution are `packages/core/src/behaviour-kinds.ts`.
|
|
6
|
+
*
|
|
7
|
+
* These rows lived in one cross-lexicon table until #2382, which is why the
|
|
8
|
+
* version before this one described terraform's block shape in prose: it could
|
|
9
|
+
* not import it. This file can. Every `resource` block parses to one entity with
|
|
10
|
+
* the same `entityType`, `Terraform::Resource` (`../hcl/parse.ts`), so the
|
|
11
|
+
* type an engine would price is the segment before the first dot of
|
|
12
|
+
* `props.address`, and the arguments a size is read from are under
|
|
13
|
+
* `props.body` in terraform's own vocabulary — `instance_type`, not
|
|
14
|
+
* `InstanceType`.
|
|
15
|
+
*
|
|
16
|
+
* ## One lexicon, every provider there is
|
|
17
|
+
*
|
|
18
|
+
* A terraform root can declare anything any provider offers, so unlike the aws
|
|
19
|
+
* or k8s lexicons this one models part of what it declares and says so. An
|
|
20
|
+
* `aws_` type reaches the tables below; every other prefix is a substrate
|
|
21
|
+
* nothing here models, named by its provider, through `notModelledWhen`. An
|
|
22
|
+
* `aws_` type with no row stays `unknown-type` — the one verdict that is a
|
|
23
|
+
* defect rather than a decision, and the reason the two are separate hooks.
|
|
24
|
+
*
|
|
25
|
+
* The rows are the CloudFormation rows of the aws lexicon's table, spelled the
|
|
26
|
+
* way the aws provider spells them. They exist because a choudoufu root is a
|
|
27
|
+
* terraform root and the live path (#2360) predicts the account it holds;
|
|
28
|
+
* without them every resource in such an estate was `provider-not-modelled`
|
|
29
|
+
* and the declared-versus-live delta was a difference between two zeroes.
|
|
30
|
+
*/
|
|
31
|
+
import type { BehaviourKinds } from "@intentius/chant/behaviour-kinds";
|
|
32
|
+
/** The entity type every `resource` block arrives as. */
|
|
33
|
+
export declare const TERRAFORM_RESOURCE_TYPE = "Terraform::Resource";
|
|
34
|
+
/** This lexicon's answer for its own blocks. */
|
|
35
|
+
export declare const terraformBehaviourKinds: BehaviourKinds;
|
|
36
|
+
//# sourceMappingURL=kinds.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kinds.d.ts","sourceRoot":"","sources":["../../src/behaviour/kinds.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAEvE,yDAAyD;AACzD,eAAO,MAAM,uBAAuB,wBAAwB,CAAC;AAmJ7D,gDAAgD;AAChD,eAAO,MAAM,uBAAuB,EAAE,cAiBrC,CAAC"}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* declaration — through the same injected activities, builds the engine's
|
|
10
10
|
* request from them (`./request.ts`), and hands it to whichever lexicon fronts
|
|
11
11
|
* the engine. The terraform lexicon has no engine of its own and dials none:
|
|
12
|
-
* `deps.predict` is
|
|
12
|
+
* `deps.predict` is core's `predictBehaviour` in production, and a fixture
|
|
13
13
|
* in a test.
|
|
14
14
|
*
|
|
15
15
|
* ## Four moves, in this order
|
package/dist/integrity.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"algorithm": "sha256",
|
|
3
3
|
"artifacts": {
|
|
4
|
-
"manifest.json": "
|
|
4
|
+
"manifest.json": "cae82ee1bedff7d2e9723c4a3aec058f4bfc66f1d2c9b0e837e6d8677e58c7e9",
|
|
5
5
|
"meta.json": "ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356",
|
|
6
6
|
"types/index.d.ts": "022927e6a7b351cc4cf52d5f973f60ccd140e5810e17b32fb8868965aa1db161",
|
|
7
7
|
"rules/plan-before-apply.ts": "31b1b3176799fd365b2583fe3947edd187c2a863e3dc0094ed9e91ece2464c99",
|
|
@@ -37,5 +37,5 @@
|
|
|
37
37
|
"rules/tf028.ts": "81ef95659c40ad1774c83e663473ed769143d894a4ba0517c3defa31f00ba723",
|
|
38
38
|
"skills/chant-terraform.md": "d9ca7b7c28aed0038ce775a3491150298492eed2858fd3651ed9bfca0e577ae8"
|
|
39
39
|
},
|
|
40
|
-
"composite": "
|
|
40
|
+
"composite": "4226871167d3deee8b1523868b782fd34226013fda3f42e4e3dc7aaf33bec4e4"
|
|
41
41
|
}
|
package/dist/manifest.json
CHANGED
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsB,aAAa,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsB,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAgElF;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,EAAE,aAmP7B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentius/chant-lexicon-terraform",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.67.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"src/",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
58
|
"zod": "^4.3.6",
|
|
59
|
-
"@intentius/chant": "^0.
|
|
59
|
+
"@intentius/chant": "^0.67.0",
|
|
60
60
|
"typescript": "^5.9.3"
|
|
61
61
|
},
|
|
62
62
|
"description": "terraform lexicon for chant, existing Terraform root modules as declarable entities",
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a terraform root's blocks are worth to a behaviour engine (#2382).
|
|
3
|
+
*
|
|
4
|
+
* Contributed as rows through the plugin's `behaviourKinds` field; the
|
|
5
|
+
* vocabulary and the resolution are `packages/core/src/behaviour-kinds.ts`.
|
|
6
|
+
*
|
|
7
|
+
* These rows lived in one cross-lexicon table until #2382, which is why the
|
|
8
|
+
* version before this one described terraform's block shape in prose: it could
|
|
9
|
+
* not import it. This file can. Every `resource` block parses to one entity with
|
|
10
|
+
* the same `entityType`, `Terraform::Resource` (`../hcl/parse.ts`), so the
|
|
11
|
+
* type an engine would price is the segment before the first dot of
|
|
12
|
+
* `props.address`, and the arguments a size is read from are under
|
|
13
|
+
* `props.body` in terraform's own vocabulary — `instance_type`, not
|
|
14
|
+
* `InstanceType`.
|
|
15
|
+
*
|
|
16
|
+
* ## One lexicon, every provider there is
|
|
17
|
+
*
|
|
18
|
+
* A terraform root can declare anything any provider offers, so unlike the aws
|
|
19
|
+
* or k8s lexicons this one models part of what it declares and says so. An
|
|
20
|
+
* `aws_` type reaches the tables below; every other prefix is a substrate
|
|
21
|
+
* nothing here models, named by its provider, through `notModelledWhen`. An
|
|
22
|
+
* `aws_` type with no row stays `unknown-type` — the one verdict that is a
|
|
23
|
+
* defect rather than a decision, and the reason the two are separate hooks.
|
|
24
|
+
*
|
|
25
|
+
* The rows are the CloudFormation rows of the aws lexicon's table, spelled the
|
|
26
|
+
* way the aws provider spells them. They exist because a choudoufu root is a
|
|
27
|
+
* terraform root and the live path (#2360) predicts the account it holds;
|
|
28
|
+
* without them every resource in such an estate was `provider-not-modelled`
|
|
29
|
+
* and the declared-versus-live delta was a difference between two zeroes.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import type { BehaviourKinds } from "@intentius/chant/behaviour-kinds";
|
|
33
|
+
|
|
34
|
+
/** The entity type every `resource` block arrives as. */
|
|
35
|
+
export const TERRAFORM_RESOURCE_TYPE = "Terraform::Resource";
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* A terraform resource type: the provider's name, an underscore, and the rest.
|
|
39
|
+
* Terraform's own naming rule, and the whole of what tells a type apart from
|
|
40
|
+
* the identity a live row can carry in an address's place.
|
|
41
|
+
*/
|
|
42
|
+
const TERRAFORM_TYPE = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*_[a-z0-9_]+$/;
|
|
43
|
+
|
|
44
|
+
/** Provider types an engine prices, with the argument its size is read from. */
|
|
45
|
+
const MAPPED: BehaviourKinds["mapped"] = {
|
|
46
|
+
aws_instance: { kind: "compute", sizeProp: "body.instance_type", sizeType: "string" },
|
|
47
|
+
aws_ebs_volume: { kind: "block-store", sizeProp: "body.size", sizeType: "number", regionProp: "body.availability_zone" },
|
|
48
|
+
aws_lambda_function: { kind: "serverless", sizeProp: "body.memory_size", sizeType: "number" },
|
|
49
|
+
aws_db_instance: { kind: "database", sizeProp: "body.instance_class", sizeType: "string" },
|
|
50
|
+
/** The cluster carries the rate an engine prices; its instances (`aws_rds_cluster_instance`) carry the class. */
|
|
51
|
+
aws_rds_cluster: { kind: "database" },
|
|
52
|
+
aws_rds_cluster_instance: { kind: "database", sizeProp: "body.instance_class", sizeType: "string" },
|
|
53
|
+
aws_dynamodb_table: { kind: "database", sizeProp: "body.billing_mode", sizeType: "string" },
|
|
54
|
+
aws_elasticache_cluster: { kind: "cache", sizeProp: "body.node_type", sizeType: "string" },
|
|
55
|
+
aws_sqs_queue: { kind: "queue" },
|
|
56
|
+
aws_sns_topic: { kind: "queue" },
|
|
57
|
+
aws_s3_bucket: { kind: "object-store" },
|
|
58
|
+
aws_lb: { kind: "load-balancer", sizeProp: "body.load_balancer_type", sizeType: "string" },
|
|
59
|
+
/** The provider's older name for `aws_lb`; the same resource. */
|
|
60
|
+
aws_alb: { kind: "load-balancer", sizeProp: "body.load_balancer_type", sizeType: "string" },
|
|
61
|
+
aws_cloudfront_distribution: { kind: "cdn" },
|
|
62
|
+
aws_eks_cluster: { kind: "control-plane" },
|
|
63
|
+
/** No size: `instance_types` is a list, and this contract's `size` is one string. */
|
|
64
|
+
aws_eks_node_group: { kind: "compute" },
|
|
65
|
+
aws_ecs_service: { kind: "compute" },
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/** Provider types that are real and carry no rate, with the reason for each. */
|
|
69
|
+
const UNMAPPED: BehaviourKinds["unmapped"] = {
|
|
70
|
+
// ── Grants ───────────────────────────────────────────────────────
|
|
71
|
+
aws_iam_role: "a role is a grant, not a resource traffic flows through: no rate, no capacity, no verdict under a lost zone",
|
|
72
|
+
aws_iam_policy: "a policy document is a statement about permission; nothing about it saturates or accrues",
|
|
73
|
+
aws_iam_role_policy: "a policy document attached inline to a role; a statement about permission",
|
|
74
|
+
aws_iam_role_policy_attachment: "the attachment of a grant to a role; neither end is priced by it",
|
|
75
|
+
aws_iam_instance_profile: "a wrapper that hands a role to an instance; the instance carries the figures",
|
|
76
|
+
aws_s3_bucket_policy: "a bucket policy is a grant on the bucket beside it, and the bucket carries the figures",
|
|
77
|
+
aws_sqs_queue_policy: "a queue policy is a grant on the queue beside it, and the queue carries the figures",
|
|
78
|
+
aws_lambda_permission: "a grant letting one service invoke a function; the function carries the figures",
|
|
79
|
+
|
|
80
|
+
// ── Boundaries, and the wiring that puts things inside them ──────
|
|
81
|
+
aws_vpc: "a network boundary rather than a node: its contribution to a prediction is the zone membership that reaches the engine as containment coverage",
|
|
82
|
+
aws_subnet: "a network boundary rather than a node: its contribution to a prediction is the zone membership that reaches the engine as containment coverage",
|
|
83
|
+
aws_security_group: "a filter on edges that already exist, not a thing at either end of one",
|
|
84
|
+
aws_security_group_rule: "one rule of a filter on edges that already exist; the rule is not a thing at either end of one",
|
|
85
|
+
aws_vpc_security_group_ingress_rule: "one rule of a filter on edges that already exist; the rule is not a thing at either end of one",
|
|
86
|
+
aws_vpc_security_group_egress_rule: "one rule of a filter on edges that already exist; the rule is not a thing at either end of one",
|
|
87
|
+
aws_route_table: "routing, which decides where an edge goes and is not itself at either end of one",
|
|
88
|
+
aws_route: "routing, which decides where an edge goes and is not itself at either end of one",
|
|
89
|
+
aws_route_table_association: "an association between two boundaries; nothing flows through it that does not already flow through them",
|
|
90
|
+
aws_internet_gateway: "a boundary crossing rather than a resource: no rate of its own and no capacity to saturate",
|
|
91
|
+
aws_db_subnet_group: "the set of subnets a database may sit in; the database carries the figures",
|
|
92
|
+
aws_elasticache_subnet_group: "the set of subnets a cache may sit in; the cache carries the figures",
|
|
93
|
+
aws_ecs_cluster: "a namespace for services rather than capacity of its own; the services and their nodes carry the figures",
|
|
94
|
+
aws_network_interface: "where an instance's networking lives; the instance carries the figures",
|
|
95
|
+
|
|
96
|
+
// ── Meters chant cannot read ─────────────────────────────────────
|
|
97
|
+
aws_cloudwatch_log_group: "priced by the volume ingested into it, which the declaration does not state and no engine can infer from a graph",
|
|
98
|
+
aws_wafv2_web_acl: "priced by the requests inspected through it, which the declaration does not state",
|
|
99
|
+
aws_nat_gateway: "priced as an hourly rate plus a per-gigabyte meter on everything that crosses it. The declaration states the first and nothing at all about the second, and no engine kind here models a half-known price",
|
|
100
|
+
aws_eip: "priced only while it is attached to nothing, which is a fact about the running account rather than about the declaration",
|
|
101
|
+
aws_ecr_repository: "priced by the gigabytes stored in it, which the declaration does not state",
|
|
102
|
+
aws_kms_key: "priced per key per month plus a per-request meter the declaration does not state, and neither half is an hourly rate",
|
|
103
|
+
aws_route53_zone: "priced per zone per month plus a per-query meter the declaration does not state",
|
|
104
|
+
aws_route53_record: "a record in a zone priced per query; the zone is where the meter is, and the declaration does not state it",
|
|
105
|
+
aws_sns_topic_subscription: "priced by the notifications delivered through it; the topic is what the graph has an edge to",
|
|
106
|
+
aws_cloudwatch_event_rule: "priced by the events matched, which is a fact about traffic the declaration does not state",
|
|
107
|
+
|
|
108
|
+
// ── Templates, not instances ─────────────────────────────────────
|
|
109
|
+
aws_ecs_task_definition: "a template a service runs copies of; the service carries the figures, and pricing both would count the estate twice",
|
|
110
|
+
aws_lambda_event_source_mapping: "the wiring between a queue and a function, both of which are priced where they are declared",
|
|
111
|
+
aws_lb_target_group: "a set of targets behind a load balancer; the load balancer carries the rate",
|
|
112
|
+
aws_lb_target_group_attachment: "one target's membership of a target group; the target and the load balancer carry the figures",
|
|
113
|
+
aws_lb_listener: "a port on a load balancer; the load balancer carries the rate",
|
|
114
|
+
aws_lb_listener_rule: "a routing rule on a listener, and a rule is not a thing at either end of an edge",
|
|
115
|
+
aws_launch_template: "a template instances are launched from; the instances carry the figures",
|
|
116
|
+
|
|
117
|
+
// ── Settings on the resource beside them ─────────────────────────
|
|
118
|
+
aws_s3_bucket_versioning: "a setting on the bucket beside it; the bucket carries the figures",
|
|
119
|
+
aws_s3_bucket_public_access_block: "a setting on the bucket beside it; the bucket carries the figures",
|
|
120
|
+
aws_s3_bucket_server_side_encryption_configuration: "a setting on the bucket beside it; the bucket carries the figures",
|
|
121
|
+
aws_s3_bucket_lifecycle_configuration: "a setting on the bucket beside it; the bucket carries the figures",
|
|
122
|
+
aws_s3_bucket_ownership_controls: "a setting on the bucket beside it; the bucket carries the figures",
|
|
123
|
+
aws_s3_bucket_acl: "a grant on the bucket beside it; the bucket carries the figures",
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
/** The root's own blocks, which are not resources in any account. */
|
|
127
|
+
const BLOCKS: Readonly<Record<string, string>> = {
|
|
128
|
+
// ── Terraform blocks that are not resources ──────────────────────
|
|
129
|
+
// A `resource` block is not here: it is `Terraform::Resource` whatever its
|
|
130
|
+
// provider type, and `coverageFor` dispatches it on the provider type in
|
|
131
|
+
// its address to the
|
|
132
|
+
// terraform half of the table (`./mapping-terraform.ts`, #2360).
|
|
133
|
+
"Terraform::Terraform": "the root's settings block, which names providers and a backend and holds nothing in any account",
|
|
134
|
+
"Terraform::Provider": "a provider configuration: how terraform reaches an account, not a thing the account holds",
|
|
135
|
+
"Terraform::Variable": "a root module input; it shapes what is created and is never created itself",
|
|
136
|
+
"Terraform::Output": "a value the root publishes after an apply, not a thing the account holds",
|
|
137
|
+
"Terraform::Locals": "named expressions a root reuses; they exist only in the evaluation",
|
|
138
|
+
"Terraform::Module": "a call to a child module; the blocks the call expands to are entities of their own and carry the figures",
|
|
139
|
+
"Terraform::Data": "a read of something that exists outside this root; whatever it reads is priced where it is declared",
|
|
140
|
+
"Terraform::Live": "choudoufu's estate declaration, which names the ownership marker every resource of the root carries and holds nothing itself",
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const UNMODELLED_TERRAFORM_PROVIDERS: ReadonlyArray<{ prefix: string; substrate: string }> = [
|
|
144
|
+
{ prefix: "google_", substrate: "Google Cloud (the google terraform provider)" },
|
|
145
|
+
{ prefix: "google-beta_", substrate: "Google Cloud (the google-beta terraform provider)" },
|
|
146
|
+
{ prefix: "azurerm_", substrate: "Azure (the azurerm terraform provider)" },
|
|
147
|
+
{ prefix: "azuread_", substrate: "Azure (the azuread terraform provider)" },
|
|
148
|
+
{
|
|
149
|
+
prefix: "kubernetes_",
|
|
150
|
+
substrate:
|
|
151
|
+
"the kubernetes terraform provider. The Kubernetes rows are the k8s lexicon's own types, and a manifest applied through terraform is a different entity with a different shape",
|
|
152
|
+
},
|
|
153
|
+
{ prefix: "helm_", substrate: "Helm through terraform (a chart is a package, and what it installs is Kubernetes)" },
|
|
154
|
+
{ prefix: "null_", substrate: "the null provider, a utility with nothing in any account" },
|
|
155
|
+
{ prefix: "random_", substrate: "the random provider, a utility with nothing in any account" },
|
|
156
|
+
{ prefix: "local_", substrate: "the local provider, which writes files on the machine running terraform" },
|
|
157
|
+
{ prefix: "tls_", substrate: "the tls provider, a utility with nothing in any account" },
|
|
158
|
+
{ prefix: "time_", substrate: "the time provider, a utility with nothing in any account" },
|
|
159
|
+
{ prefix: "archive_", substrate: "the archive provider, a utility with nothing in any account" },
|
|
160
|
+
{ prefix: "external_", substrate: "the external provider, a program run on the machine running terraform" },
|
|
161
|
+
{ prefix: "terraform_", substrate: "terraform's own built-in provider, which holds nothing in any account" },
|
|
162
|
+
];
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* The provider type an engine would price, off the block's address — or the
|
|
166
|
+
* `resourceType` a live row states, which `observeAmbient` already uses.
|
|
167
|
+
* `undefined` is "nothing to look up", the same no-opinion an unseen type
|
|
168
|
+
* gets, which is why a live row whose ARN stands in for an address is not
|
|
169
|
+
* sliced at a dot and read as a type.
|
|
170
|
+
*/
|
|
171
|
+
function resolveType(props: Record<string, unknown> | undefined): string | undefined {
|
|
172
|
+
const stated = props?.resourceType;
|
|
173
|
+
if (typeof stated === "string" && stated.length > 0) return stated;
|
|
174
|
+
const address = props?.address;
|
|
175
|
+
if (typeof address !== "string") return undefined;
|
|
176
|
+
const dot = address.indexOf(".");
|
|
177
|
+
if (dot <= 0) return undefined;
|
|
178
|
+
const type = address.slice(0, dot);
|
|
179
|
+
return TERRAFORM_TYPE.test(type) ? type : undefined;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** This lexicon's answer for its own blocks. */
|
|
183
|
+
export const terraformBehaviourKinds: BehaviourKinds = {
|
|
184
|
+
provider: "aws",
|
|
185
|
+
prefixes: ["Terraform::"],
|
|
186
|
+
resolveType: (entityType, props) =>
|
|
187
|
+
entityType === TERRAFORM_RESOURCE_TYPE ? resolveType(props) : entityType,
|
|
188
|
+
mapped: MAPPED,
|
|
189
|
+
unmapped: { ...UNMAPPED, ...BLOCKS },
|
|
190
|
+
notModelledWhen: (type) => {
|
|
191
|
+
// A root block keyed by its own entity type is this lexicon's, not
|
|
192
|
+
// another provider's, and an `aws_` type with no row is a missing row.
|
|
193
|
+
if (type.startsWith("aws_") || type.startsWith("Terraform::")) return undefined;
|
|
194
|
+
for (const { prefix, substrate } of UNMODELLED_TERRAFORM_PROVIDERS) {
|
|
195
|
+
if (type.startsWith(prefix)) return substrate;
|
|
196
|
+
}
|
|
197
|
+
const provider = type.includes("_") ? type.slice(0, type.indexOf("_")) : type;
|
|
198
|
+
return `the ${provider} terraform provider, which nothing here models`;
|
|
199
|
+
},
|
|
200
|
+
};
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*
|
|
11
11
|
* ## The engine
|
|
12
12
|
*
|
|
13
|
-
* `deps.predict` is
|
|
13
|
+
* `deps.predict` is core's `predictBehaviour` in production. Here it is
|
|
14
14
|
* {@link tariff}, which prices a node per hour by its provider type and
|
|
15
15
|
* nothing else. That is a poor cost model and a good instrument: it makes an
|
|
16
16
|
* estate's total a plain sum over the entities that side of the path sent, so
|
package/src/behaviour/predict.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* declaration — through the same injected activities, builds the engine's
|
|
10
10
|
* request from them (`./request.ts`), and hands it to whichever lexicon fronts
|
|
11
11
|
* the engine. The terraform lexicon has no engine of its own and dials none:
|
|
12
|
-
* `deps.predict` is
|
|
12
|
+
* `deps.predict` is core's `predictBehaviour` in production, and a fixture
|
|
13
13
|
* in a test.
|
|
14
14
|
*
|
|
15
15
|
* ## Four moves, in this order
|
package/src/behaviour/request.ts
CHANGED
|
@@ -276,7 +276,7 @@ export function substituteReferences(
|
|
|
276
276
|
* for an address it had none of, and is not a type.
|
|
277
277
|
*
|
|
278
278
|
* This is the kind a node is given for `reconstructEdges`, and it is the same
|
|
279
|
-
* derivation
|
|
279
|
+
* derivation `./kinds.ts`'s `resolveType` runs to look a coverage row up,
|
|
280
280
|
* so the graph and the coverage table agree on what a block is. A live row
|
|
281
281
|
* states its own type instead, on `props.resourceType`, the name
|
|
282
282
|
* `observeAmbient` already uses for it.
|
|
@@ -401,7 +401,7 @@ function liveRootPart(
|
|
|
401
401
|
if (entity.entityType !== RESOURCE_TYPE) {
|
|
402
402
|
// A variable, an output, a data block: not a thing the account holds,
|
|
403
403
|
// so the account has nothing to say about it. It rides through as
|
|
404
|
-
// declared, and
|
|
404
|
+
// declared, and the coverage rows decline it by name on both sides alike.
|
|
405
405
|
part.sources[d.name] = "live";
|
|
406
406
|
part.entities.set(d.name, entity);
|
|
407
407
|
continue;
|
package/src/plugin.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AuditEntitiesInput, LexiconPlugin } from "@intentius/chant/lexicon";
|
|
2
|
+
import { terraformBehaviourKinds } from "./behaviour/kinds";
|
|
2
3
|
import type { CompletionContext, HoverContext } from "@intentius/chant/lsp/types";
|
|
3
4
|
import type { Declarable } from "@intentius/chant/declarable";
|
|
4
5
|
import { createSkillsLoader } from "@intentius/chant/lexicon-plugin-helpers";
|
|
@@ -70,6 +71,7 @@ function looksLikeHcl(text: string): boolean {
|
|
|
70
71
|
* and `codegen/` stay near-empty and there is no `upstreamPin`.
|
|
71
72
|
*/
|
|
72
73
|
export const terraformPlugin: LexiconPlugin = {
|
|
74
|
+
behaviourKinds: terraformBehaviourKinds,
|
|
73
75
|
name: "terraform",
|
|
74
76
|
serializer: terraformSerializer,
|
|
75
77
|
configSchema: terraformConfigSchema,
|