parse-hcl 0.1.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/LICENSE +201 -0
- package/README.md +749 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +91 -0
- package/dist/index.d.ts +51 -0
- package/dist/index.js +74 -0
- package/dist/parsers/genericParser.d.ts +167 -0
- package/dist/parsers/genericParser.js +268 -0
- package/dist/parsers/localsParser.d.ts +30 -0
- package/dist/parsers/localsParser.js +43 -0
- package/dist/parsers/outputParser.d.ts +25 -0
- package/dist/parsers/outputParser.js +44 -0
- package/dist/parsers/variableParser.d.ts +62 -0
- package/dist/parsers/variableParser.js +249 -0
- package/dist/services/artifactParsers.d.ts +12 -0
- package/dist/services/artifactParsers.js +157 -0
- package/dist/services/terraformJsonParser.d.ts +16 -0
- package/dist/services/terraformJsonParser.js +212 -0
- package/dist/services/terraformParser.d.ts +91 -0
- package/dist/services/terraformParser.js +191 -0
- package/dist/types/artifacts.d.ts +210 -0
- package/dist/types/artifacts.js +5 -0
- package/dist/types/blocks.d.ts +419 -0
- package/dist/types/blocks.js +28 -0
- package/dist/utils/common/errors.d.ts +46 -0
- package/dist/utils/common/errors.js +54 -0
- package/dist/utils/common/fs.d.ts +5 -0
- package/dist/utils/common/fs.js +48 -0
- package/dist/utils/common/logger.d.ts +5 -0
- package/dist/utils/common/logger.js +17 -0
- package/dist/utils/common/valueHelpers.d.ts +4 -0
- package/dist/utils/common/valueHelpers.js +23 -0
- package/dist/utils/graph/graphBuilder.d.ts +33 -0
- package/dist/utils/graph/graphBuilder.js +373 -0
- package/dist/utils/lexer/blockScanner.d.ts +36 -0
- package/dist/utils/lexer/blockScanner.js +143 -0
- package/dist/utils/lexer/hclLexer.d.ts +119 -0
- package/dist/utils/lexer/hclLexer.js +525 -0
- package/dist/utils/parser/bodyParser.d.ts +26 -0
- package/dist/utils/parser/bodyParser.js +81 -0
- package/dist/utils/parser/valueClassifier.d.ts +21 -0
- package/dist/utils/parser/valueClassifier.js +434 -0
- package/dist/utils/serialization/serializer.d.ts +9 -0
- package/dist/utils/serialization/serializer.js +63 -0
- package/dist/utils/serialization/yaml.d.ts +1 -0
- package/dist/utils/serialization/yaml.js +81 -0
- package/package.json +66 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Parser for Terraform locals blocks.
|
|
4
|
+
* Extracts local value definitions from locals blocks.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.LocalsParser = void 0;
|
|
8
|
+
const bodyParser_1 = require("../utils/parser/bodyParser");
|
|
9
|
+
/**
|
|
10
|
+
* Parser for Terraform locals definition blocks.
|
|
11
|
+
* Converts a single locals block into multiple LocalValue entries.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```hcl
|
|
15
|
+
* locals {
|
|
16
|
+
* environment = "production"
|
|
17
|
+
* tags = {
|
|
18
|
+
* Name = "example"
|
|
19
|
+
* Env = local.environment
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
class LocalsParser {
|
|
25
|
+
/**
|
|
26
|
+
* Parses a locals block into an array of LocalValue objects.
|
|
27
|
+
* Each attribute in the locals block becomes a separate LocalValue.
|
|
28
|
+
*
|
|
29
|
+
* @param block - The raw HCL block to parse
|
|
30
|
+
* @returns Array of LocalValue objects, one per local definition
|
|
31
|
+
*/
|
|
32
|
+
parse(block) {
|
|
33
|
+
const parsed = (0, bodyParser_1.parseBlockBody)(block.body);
|
|
34
|
+
return Object.entries(parsed.attributes).map(([name, value]) => ({
|
|
35
|
+
name,
|
|
36
|
+
type: value.type,
|
|
37
|
+
value,
|
|
38
|
+
raw: value.raw,
|
|
39
|
+
source: block.source
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.LocalsParser = LocalsParser;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parser for Terraform output blocks.
|
|
3
|
+
* Extracts output value declarations with their expressions and metadata.
|
|
4
|
+
*/
|
|
5
|
+
import { HclBlock, OutputBlock } from '../types/blocks';
|
|
6
|
+
/**
|
|
7
|
+
* Parser for Terraform output definition blocks.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```hcl
|
|
11
|
+
* output "instance_ip" {
|
|
12
|
+
* description = "The public IP of the instance"
|
|
13
|
+
* value = aws_instance.web.public_ip
|
|
14
|
+
* sensitive = false
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare class OutputParser {
|
|
19
|
+
/**
|
|
20
|
+
* Parses an output block into a structured OutputBlock.
|
|
21
|
+
* @param block - The raw HCL block to parse
|
|
22
|
+
* @returns Parsed OutputBlock with all extracted fields
|
|
23
|
+
*/
|
|
24
|
+
parse(block: HclBlock): OutputBlock;
|
|
25
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Parser for Terraform output blocks.
|
|
4
|
+
* Extracts output value declarations with their expressions and metadata.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.OutputParser = void 0;
|
|
8
|
+
const bodyParser_1 = require("../utils/parser/bodyParser");
|
|
9
|
+
const valueHelpers_1 = require("../utils/common/valueHelpers");
|
|
10
|
+
/**
|
|
11
|
+
* Parser for Terraform output definition blocks.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```hcl
|
|
15
|
+
* output "instance_ip" {
|
|
16
|
+
* description = "The public IP of the instance"
|
|
17
|
+
* value = aws_instance.web.public_ip
|
|
18
|
+
* sensitive = false
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
class OutputParser {
|
|
23
|
+
/**
|
|
24
|
+
* Parses an output block into a structured OutputBlock.
|
|
25
|
+
* @param block - The raw HCL block to parse
|
|
26
|
+
* @returns Parsed OutputBlock with all extracted fields
|
|
27
|
+
*/
|
|
28
|
+
parse(block) {
|
|
29
|
+
const name = block.labels[0] || 'unknown';
|
|
30
|
+
const parsed = (0, bodyParser_1.parseBlockBody)(block.body);
|
|
31
|
+
const description = (0, valueHelpers_1.literalString)(parsed.attributes.description) ?? parsed.attributes.description?.raw;
|
|
32
|
+
const value = parsed.attributes.value;
|
|
33
|
+
const sensitive = (0, valueHelpers_1.literalBoolean)(parsed.attributes.sensitive);
|
|
34
|
+
return {
|
|
35
|
+
name,
|
|
36
|
+
description,
|
|
37
|
+
value,
|
|
38
|
+
sensitive,
|
|
39
|
+
raw: block.raw,
|
|
40
|
+
source: block.source
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.OutputParser = OutputParser;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parser for Terraform variable blocks.
|
|
3
|
+
* Extracts variable declarations with type constraints, defaults, and validations.
|
|
4
|
+
*/
|
|
5
|
+
import { HclBlock, TypeConstraint, VariableBlock } from '../types/blocks';
|
|
6
|
+
/**
|
|
7
|
+
* Parser for Terraform variable definition blocks.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```hcl
|
|
11
|
+
* variable "instance_type" {
|
|
12
|
+
* type = string
|
|
13
|
+
* default = "t2.micro"
|
|
14
|
+
* description = "EC2 instance type"
|
|
15
|
+
* sensitive = false
|
|
16
|
+
*
|
|
17
|
+
* validation {
|
|
18
|
+
* condition = can(regex("^t[23]\\.", var.instance_type))
|
|
19
|
+
* error_message = "Must be a t2 or t3 instance type."
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare class VariableParser {
|
|
25
|
+
/**
|
|
26
|
+
* Parses a variable block into a structured VariableBlock.
|
|
27
|
+
* @param block - The raw HCL block to parse
|
|
28
|
+
* @returns Parsed VariableBlock with all extracted fields
|
|
29
|
+
*/
|
|
30
|
+
parse(block: HclBlock): VariableBlock;
|
|
31
|
+
/**
|
|
32
|
+
* Extracts validation rules from nested validation blocks.
|
|
33
|
+
* @param blocks - Nested blocks from the variable body
|
|
34
|
+
* @returns VariableValidation if a validation block exists
|
|
35
|
+
*/
|
|
36
|
+
private extractValidation;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Parses a Terraform type constraint expression into a structured TypeConstraint.
|
|
40
|
+
*
|
|
41
|
+
* Supports:
|
|
42
|
+
* - Primitive types: string, number, bool, any
|
|
43
|
+
* - Collection types: list(T), set(T), map(T)
|
|
44
|
+
* - Structural types: object({ attr = type, ... }), tuple([type, ...])
|
|
45
|
+
* - Optional attributes: optional(type)
|
|
46
|
+
*
|
|
47
|
+
* @param raw - The raw type expression string
|
|
48
|
+
* @returns Parsed TypeConstraint
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* parseTypeConstraint('string')
|
|
53
|
+
* // { base: 'string', raw: 'string' }
|
|
54
|
+
*
|
|
55
|
+
* parseTypeConstraint('list(string)')
|
|
56
|
+
* // { base: 'list', element: { base: 'string', raw: 'string' }, raw: 'list(string)' }
|
|
57
|
+
*
|
|
58
|
+
* parseTypeConstraint('object({ name = string, age = optional(number) })')
|
|
59
|
+
* // { base: 'object', attributes: { name: {...}, age: {...} }, raw: '...' }
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare function parseTypeConstraint(raw: string): TypeConstraint;
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Parser for Terraform variable blocks.
|
|
4
|
+
* Extracts variable declarations with type constraints, defaults, and validations.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.VariableParser = void 0;
|
|
8
|
+
exports.parseTypeConstraint = parseTypeConstraint;
|
|
9
|
+
const bodyParser_1 = require("../utils/parser/bodyParser");
|
|
10
|
+
const valueHelpers_1 = require("../utils/common/valueHelpers");
|
|
11
|
+
/**
|
|
12
|
+
* Parser for Terraform variable definition blocks.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```hcl
|
|
16
|
+
* variable "instance_type" {
|
|
17
|
+
* type = string
|
|
18
|
+
* default = "t2.micro"
|
|
19
|
+
* description = "EC2 instance type"
|
|
20
|
+
* sensitive = false
|
|
21
|
+
*
|
|
22
|
+
* validation {
|
|
23
|
+
* condition = can(regex("^t[23]\\.", var.instance_type))
|
|
24
|
+
* error_message = "Must be a t2 or t3 instance type."
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
class VariableParser {
|
|
30
|
+
/**
|
|
31
|
+
* Parses a variable block into a structured VariableBlock.
|
|
32
|
+
* @param block - The raw HCL block to parse
|
|
33
|
+
* @returns Parsed VariableBlock with all extracted fields
|
|
34
|
+
*/
|
|
35
|
+
parse(block) {
|
|
36
|
+
const name = block.labels[0] || 'unknown';
|
|
37
|
+
const parsed = (0, bodyParser_1.parseBlockBody)(block.body);
|
|
38
|
+
const description = (0, valueHelpers_1.literalString)(parsed.attributes.description) ?? parsed.attributes.description?.raw;
|
|
39
|
+
const typeRaw = (0, valueHelpers_1.literalString)(parsed.attributes.type) ?? parsed.attributes.type?.raw;
|
|
40
|
+
const sensitive = (0, valueHelpers_1.literalBoolean)(parsed.attributes.sensitive);
|
|
41
|
+
const nullable = (0, valueHelpers_1.literalBoolean)(parsed.attributes.nullable);
|
|
42
|
+
const validation = this.extractValidation(parsed.blocks);
|
|
43
|
+
// Parse type constraint if present
|
|
44
|
+
const typeConstraint = typeRaw ? parseTypeConstraint(typeRaw) : undefined;
|
|
45
|
+
return {
|
|
46
|
+
name,
|
|
47
|
+
description,
|
|
48
|
+
type: typeRaw,
|
|
49
|
+
typeConstraint,
|
|
50
|
+
default: parsed.attributes.default,
|
|
51
|
+
validation,
|
|
52
|
+
sensitive,
|
|
53
|
+
nullable,
|
|
54
|
+
raw: block.raw,
|
|
55
|
+
source: block.source
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Extracts validation rules from nested validation blocks.
|
|
60
|
+
* @param blocks - Nested blocks from the variable body
|
|
61
|
+
* @returns VariableValidation if a validation block exists
|
|
62
|
+
*/
|
|
63
|
+
extractValidation(blocks) {
|
|
64
|
+
const validationBlock = blocks.find((child) => child.type === 'validation');
|
|
65
|
+
if (!validationBlock) {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
const condition = validationBlock.attributes.condition;
|
|
69
|
+
const errorMessage = validationBlock.attributes.error_message;
|
|
70
|
+
if (!condition && !errorMessage) {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
condition,
|
|
75
|
+
error_message: errorMessage
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
exports.VariableParser = VariableParser;
|
|
80
|
+
/**
|
|
81
|
+
* Parses a Terraform type constraint expression into a structured TypeConstraint.
|
|
82
|
+
*
|
|
83
|
+
* Supports:
|
|
84
|
+
* - Primitive types: string, number, bool, any
|
|
85
|
+
* - Collection types: list(T), set(T), map(T)
|
|
86
|
+
* - Structural types: object({ attr = type, ... }), tuple([type, ...])
|
|
87
|
+
* - Optional attributes: optional(type)
|
|
88
|
+
*
|
|
89
|
+
* @param raw - The raw type expression string
|
|
90
|
+
* @returns Parsed TypeConstraint
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```typescript
|
|
94
|
+
* parseTypeConstraint('string')
|
|
95
|
+
* // { base: 'string', raw: 'string' }
|
|
96
|
+
*
|
|
97
|
+
* parseTypeConstraint('list(string)')
|
|
98
|
+
* // { base: 'list', element: { base: 'string', raw: 'string' }, raw: 'list(string)' }
|
|
99
|
+
*
|
|
100
|
+
* parseTypeConstraint('object({ name = string, age = optional(number) })')
|
|
101
|
+
* // { base: 'object', attributes: { name: {...}, age: {...} }, raw: '...' }
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
function parseTypeConstraint(raw) {
|
|
105
|
+
const trimmed = raw.trim();
|
|
106
|
+
// Primitive types
|
|
107
|
+
const primitives = ['string', 'number', 'bool', 'any'];
|
|
108
|
+
if (primitives.includes(trimmed)) {
|
|
109
|
+
return { base: trimmed, raw: trimmed };
|
|
110
|
+
}
|
|
111
|
+
// Check for collection types: list(T), set(T), map(T)
|
|
112
|
+
const collectionMatch = trimmed.match(/^(list|set|map)\s*\(\s*([\s\S]*)\s*\)$/);
|
|
113
|
+
if (collectionMatch) {
|
|
114
|
+
const [, base, inner] = collectionMatch;
|
|
115
|
+
return {
|
|
116
|
+
base,
|
|
117
|
+
element: parseTypeConstraint(inner),
|
|
118
|
+
raw: trimmed
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
// Check for optional(T)
|
|
122
|
+
const optionalMatch = trimmed.match(/^optional\s*\(\s*([\s\S]*)\s*\)$/);
|
|
123
|
+
if (optionalMatch) {
|
|
124
|
+
const inner = parseTypeConstraint(optionalMatch[1]);
|
|
125
|
+
return {
|
|
126
|
+
...inner,
|
|
127
|
+
optional: true,
|
|
128
|
+
raw: trimmed
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
// Check for tuple([T1, T2, ...])
|
|
132
|
+
const tupleMatch = trimmed.match(/^tuple\s*\(\s*\[([\s\S]*)\]\s*\)$/);
|
|
133
|
+
if (tupleMatch) {
|
|
134
|
+
const elements = parseTupleElements(tupleMatch[1]);
|
|
135
|
+
const result = {
|
|
136
|
+
base: 'tuple',
|
|
137
|
+
raw: trimmed
|
|
138
|
+
};
|
|
139
|
+
if (elements.length > 0) {
|
|
140
|
+
result.elements = elements;
|
|
141
|
+
}
|
|
142
|
+
return result;
|
|
143
|
+
}
|
|
144
|
+
// Check for object({ attr = type, ... })
|
|
145
|
+
const objectMatch = trimmed.match(/^object\s*\(\s*\{([\s\S]*)\}\s*\)$/);
|
|
146
|
+
if (objectMatch) {
|
|
147
|
+
const attributes = parseObjectTypeAttributes(objectMatch[1]);
|
|
148
|
+
return {
|
|
149
|
+
base: 'object',
|
|
150
|
+
attributes,
|
|
151
|
+
raw: trimmed
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
// Default: treat as unknown/complex type expression
|
|
155
|
+
return { base: trimmed, raw: trimmed };
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Parses tuple element types from the inner content of a tuple type.
|
|
159
|
+
* @param inner - The content inside tuple([ ... ])
|
|
160
|
+
* @returns Array of TypeConstraints for each element
|
|
161
|
+
*/
|
|
162
|
+
function parseTupleElements(inner) {
|
|
163
|
+
const elements = [];
|
|
164
|
+
const trimmed = inner.trim();
|
|
165
|
+
if (!trimmed) {
|
|
166
|
+
return elements;
|
|
167
|
+
}
|
|
168
|
+
// Split by commas, respecting nested structures
|
|
169
|
+
let depth = 0;
|
|
170
|
+
let current = '';
|
|
171
|
+
const entries = [];
|
|
172
|
+
for (let i = 0; i < trimmed.length; i++) {
|
|
173
|
+
const char = trimmed[i];
|
|
174
|
+
if (char === '(' || char === '{' || char === '[') {
|
|
175
|
+
depth++;
|
|
176
|
+
current += char;
|
|
177
|
+
}
|
|
178
|
+
else if (char === ')' || char === '}' || char === ']') {
|
|
179
|
+
depth--;
|
|
180
|
+
current += char;
|
|
181
|
+
}
|
|
182
|
+
else if (char === ',' && depth === 0) {
|
|
183
|
+
const entry = current.trim();
|
|
184
|
+
if (entry) {
|
|
185
|
+
entries.push(entry);
|
|
186
|
+
}
|
|
187
|
+
current = '';
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
current += char;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// Don't forget the last entry
|
|
194
|
+
const final = current.trim();
|
|
195
|
+
if (final) {
|
|
196
|
+
entries.push(final);
|
|
197
|
+
}
|
|
198
|
+
// Parse each element type
|
|
199
|
+
for (const entry of entries) {
|
|
200
|
+
elements.push(parseTypeConstraint(entry));
|
|
201
|
+
}
|
|
202
|
+
return elements;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Parses object type attributes from the inner content of an object type.
|
|
206
|
+
* @param inner - The content inside object({ ... })
|
|
207
|
+
* @returns Record of attribute names to their TypeConstraints
|
|
208
|
+
*/
|
|
209
|
+
function parseObjectTypeAttributes(inner) {
|
|
210
|
+
const attributes = {};
|
|
211
|
+
const trimmed = inner.trim();
|
|
212
|
+
if (!trimmed) {
|
|
213
|
+
return attributes;
|
|
214
|
+
}
|
|
215
|
+
// Simple parsing: split by commas (handling nested parentheses)
|
|
216
|
+
let depth = 0;
|
|
217
|
+
let current = '';
|
|
218
|
+
const entries = [];
|
|
219
|
+
for (let i = 0; i < trimmed.length; i++) {
|
|
220
|
+
const char = trimmed[i];
|
|
221
|
+
if (char === '(' || char === '{' || char === '[') {
|
|
222
|
+
depth++;
|
|
223
|
+
current += char;
|
|
224
|
+
}
|
|
225
|
+
else if (char === ')' || char === '}' || char === ']') {
|
|
226
|
+
depth--;
|
|
227
|
+
current += char;
|
|
228
|
+
}
|
|
229
|
+
else if (char === ',' && depth === 0) {
|
|
230
|
+
entries.push(current.trim());
|
|
231
|
+
current = '';
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
current += char;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
if (current.trim()) {
|
|
238
|
+
entries.push(current.trim());
|
|
239
|
+
}
|
|
240
|
+
// Parse each entry (format: "name = type" or "name = optional(type)")
|
|
241
|
+
for (const entry of entries) {
|
|
242
|
+
const match = entry.match(/^(\w+)\s*=\s*([\s\S]+)$/);
|
|
243
|
+
if (match) {
|
|
244
|
+
const [, attrName, attrType] = match;
|
|
245
|
+
attributes[attrName] = parseTypeConstraint(attrType);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return attributes;
|
|
249
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { TerraformPlanDocument, TerraformStateDocument, TfVarsDocument } from '../types/artifacts';
|
|
2
|
+
export declare class TfVarsParser {
|
|
3
|
+
parseFile(filePath: string): TfVarsDocument;
|
|
4
|
+
}
|
|
5
|
+
export declare class TfStateParser {
|
|
6
|
+
parseFile(filePath: string): TerraformStateDocument;
|
|
7
|
+
parse(raw: unknown, source?: string): TerraformStateDocument;
|
|
8
|
+
}
|
|
9
|
+
export declare class TfPlanParser {
|
|
10
|
+
parseFile(filePath: string): TerraformPlanDocument;
|
|
11
|
+
parse(raw: unknown, source?: string): TerraformPlanDocument;
|
|
12
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TfPlanParser = exports.TfStateParser = exports.TfVarsParser = void 0;
|
|
4
|
+
const bodyParser_1 = require("../utils/parser/bodyParser");
|
|
5
|
+
const fs_1 = require("../utils/common/fs");
|
|
6
|
+
const terraformJsonParser_1 = require("./terraformJsonParser");
|
|
7
|
+
class TfVarsParser {
|
|
8
|
+
parseFile(filePath) {
|
|
9
|
+
if (filePath.endsWith('.json')) {
|
|
10
|
+
const json = (0, fs_1.readJsonFile)(filePath);
|
|
11
|
+
const assignments = {};
|
|
12
|
+
for (const [key, val] of Object.entries(json)) {
|
|
13
|
+
assignments[key] = (0, terraformJsonParser_1.convertJsonValue)(val);
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
source: filePath,
|
|
17
|
+
raw: JSON.stringify(json),
|
|
18
|
+
assignments
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const raw = (0, fs_1.readTextFile)(filePath);
|
|
22
|
+
const parsed = (0, bodyParser_1.parseBlockBody)(raw);
|
|
23
|
+
return {
|
|
24
|
+
source: filePath,
|
|
25
|
+
raw,
|
|
26
|
+
assignments: parsed.attributes
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.TfVarsParser = TfVarsParser;
|
|
31
|
+
class TfStateParser {
|
|
32
|
+
parseFile(filePath) {
|
|
33
|
+
const raw = (0, fs_1.readJsonFile)(filePath);
|
|
34
|
+
return this.parse(raw, filePath);
|
|
35
|
+
}
|
|
36
|
+
parse(raw, source = '') {
|
|
37
|
+
const data = raw || {};
|
|
38
|
+
const resources = Array.isArray(data.resources) ? data.resources.map(normalizeStateResource) : [];
|
|
39
|
+
const outputs = normalizeStateOutputs(data.outputs || {});
|
|
40
|
+
return {
|
|
41
|
+
version: typeof data.version === 'number' ? data.version : Number(data.version) || 0,
|
|
42
|
+
terraform_version: typeof data.terraform_version === 'string' ? data.terraform_version : undefined,
|
|
43
|
+
serial: typeof data.serial === 'number' ? data.serial : undefined,
|
|
44
|
+
lineage: typeof data.lineage === 'string' ? data.lineage : undefined,
|
|
45
|
+
outputs,
|
|
46
|
+
resources,
|
|
47
|
+
raw,
|
|
48
|
+
source
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.TfStateParser = TfStateParser;
|
|
53
|
+
class TfPlanParser {
|
|
54
|
+
parseFile(filePath) {
|
|
55
|
+
const raw = (0, fs_1.readJsonFile)(filePath);
|
|
56
|
+
return this.parse(raw, filePath);
|
|
57
|
+
}
|
|
58
|
+
parse(raw, source = '') {
|
|
59
|
+
const data = raw || {};
|
|
60
|
+
const plannedValues = data.planned_values;
|
|
61
|
+
const resourceChanges = Array.isArray(data.resource_changes) ? data.resource_changes : [];
|
|
62
|
+
return {
|
|
63
|
+
format_version: typeof data.format_version === 'string' ? data.format_version : undefined,
|
|
64
|
+
terraform_version: typeof data.terraform_version === 'string' ? data.terraform_version : undefined,
|
|
65
|
+
planned_values: plannedValues
|
|
66
|
+
? { root_module: normalizePlanModule(plannedValues.root_module || {}) }
|
|
67
|
+
: undefined,
|
|
68
|
+
resource_changes: resourceChanges.map(normalizePlanResourceChange),
|
|
69
|
+
raw,
|
|
70
|
+
source
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
exports.TfPlanParser = TfPlanParser;
|
|
75
|
+
function normalizeStateOutputs(outputs) {
|
|
76
|
+
const result = {};
|
|
77
|
+
for (const [name, value] of Object.entries(outputs)) {
|
|
78
|
+
const output = value;
|
|
79
|
+
result[name] = {
|
|
80
|
+
value: output.value ?? value,
|
|
81
|
+
type: output.type,
|
|
82
|
+
sensitive: Boolean(output.sensitive)
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
function normalizeStateResource(resource) {
|
|
88
|
+
const data = resource || {};
|
|
89
|
+
const instancesRaw = Array.isArray(data.instances) ? data.instances : [];
|
|
90
|
+
return {
|
|
91
|
+
module: typeof data.module === 'string' ? data.module : undefined,
|
|
92
|
+
mode: data.mode === 'data' ? 'data' : 'managed',
|
|
93
|
+
type: typeof data.type === 'string' ? data.type : 'unknown',
|
|
94
|
+
name: typeof data.name === 'string' ? data.name : 'unknown',
|
|
95
|
+
provider: typeof data.provider === 'string' ? data.provider : undefined,
|
|
96
|
+
instances: instancesRaw.map(normalizeStateInstance)
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function normalizeStateInstance(instance) {
|
|
100
|
+
const data = instance || {};
|
|
101
|
+
return {
|
|
102
|
+
index_key: typeof data.index_key === 'string' || typeof data.index_key === 'number'
|
|
103
|
+
? data.index_key
|
|
104
|
+
: typeof data.index === 'string' || typeof data.index === 'number'
|
|
105
|
+
? data.index
|
|
106
|
+
: undefined,
|
|
107
|
+
attributes: data.attributes || data.attributes_flat,
|
|
108
|
+
status: typeof data.status === 'string' ? data.status : undefined
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function normalizePlanModule(module) {
|
|
112
|
+
const resourcesRaw = Array.isArray(module.resources) ? module.resources : [];
|
|
113
|
+
const childrenRaw = Array.isArray(module.child_modules) ? module.child_modules : [];
|
|
114
|
+
return {
|
|
115
|
+
address: typeof module.address === 'string' ? module.address : undefined,
|
|
116
|
+
resources: resourcesRaw.map(normalizePlanResource),
|
|
117
|
+
child_modules: childrenRaw.map((child) => normalizePlanModule(child || {}))
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function normalizePlanResource(resource) {
|
|
121
|
+
const data = resource || {};
|
|
122
|
+
const address = typeof data.address === 'string' ? data.address : undefined;
|
|
123
|
+
return {
|
|
124
|
+
address: address ?? buildAddress(data),
|
|
125
|
+
mode: data.mode === 'data' ? 'data' : 'managed',
|
|
126
|
+
type: typeof data.type === 'string' ? data.type : 'unknown',
|
|
127
|
+
name: typeof data.name === 'string' ? data.name : 'unknown',
|
|
128
|
+
provider_name: typeof data.provider_name === 'string' ? data.provider_name : undefined,
|
|
129
|
+
values: data.values || undefined
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function normalizePlanResourceChange(change) {
|
|
133
|
+
const data = change || {};
|
|
134
|
+
const changeData = data.change || {};
|
|
135
|
+
return {
|
|
136
|
+
address: typeof data.address === 'string' ? data.address : buildAddress(data),
|
|
137
|
+
module_address: typeof data.module_address === 'string' ? data.module_address : undefined,
|
|
138
|
+
mode: data.mode === 'data' ? 'data' : 'managed',
|
|
139
|
+
type: typeof data.type === 'string' ? data.type : 'unknown',
|
|
140
|
+
name: typeof data.name === 'string' ? data.name : 'unknown',
|
|
141
|
+
provider_name: typeof data.provider_name === 'string' ? data.provider_name : undefined,
|
|
142
|
+
change: {
|
|
143
|
+
actions: Array.isArray(changeData.actions) ? changeData.actions : [],
|
|
144
|
+
before: changeData.before,
|
|
145
|
+
after: changeData.after,
|
|
146
|
+
after_unknown: changeData.after_unknown || undefined,
|
|
147
|
+
before_sensitive: changeData.before_sensitive || undefined,
|
|
148
|
+
after_sensitive: changeData.after_sensitive || undefined
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function buildAddress(data) {
|
|
153
|
+
const mode = data.mode === 'data' ? 'data' : 'resource';
|
|
154
|
+
const type = typeof data.type === 'string' ? data.type : 'unknown';
|
|
155
|
+
const name = typeof data.name === 'string' ? data.name : 'unknown';
|
|
156
|
+
return `${mode}.${type}.${name}`;
|
|
157
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { TerraformDocument, Value } from '../types/blocks';
|
|
2
|
+
type JsonConfig = Record<string, unknown>;
|
|
3
|
+
export declare class TerraformJsonParser {
|
|
4
|
+
parseFile(filePath: string): TerraformDocument;
|
|
5
|
+
parse(json: JsonConfig, source?: string): TerraformDocument;
|
|
6
|
+
private parseTerraform;
|
|
7
|
+
private parseProviders;
|
|
8
|
+
private parseVariables;
|
|
9
|
+
private parseOutputs;
|
|
10
|
+
private parseLocals;
|
|
11
|
+
private parseModules;
|
|
12
|
+
private parseResources;
|
|
13
|
+
private parseData;
|
|
14
|
+
}
|
|
15
|
+
export declare function convertJsonValue(input: unknown): Value;
|
|
16
|
+
export {};
|