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.
Files changed (47) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +749 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +91 -0
  5. package/dist/index.d.ts +51 -0
  6. package/dist/index.js +74 -0
  7. package/dist/parsers/genericParser.d.ts +167 -0
  8. package/dist/parsers/genericParser.js +268 -0
  9. package/dist/parsers/localsParser.d.ts +30 -0
  10. package/dist/parsers/localsParser.js +43 -0
  11. package/dist/parsers/outputParser.d.ts +25 -0
  12. package/dist/parsers/outputParser.js +44 -0
  13. package/dist/parsers/variableParser.d.ts +62 -0
  14. package/dist/parsers/variableParser.js +249 -0
  15. package/dist/services/artifactParsers.d.ts +12 -0
  16. package/dist/services/artifactParsers.js +157 -0
  17. package/dist/services/terraformJsonParser.d.ts +16 -0
  18. package/dist/services/terraformJsonParser.js +212 -0
  19. package/dist/services/terraformParser.d.ts +91 -0
  20. package/dist/services/terraformParser.js +191 -0
  21. package/dist/types/artifacts.d.ts +210 -0
  22. package/dist/types/artifacts.js +5 -0
  23. package/dist/types/blocks.d.ts +419 -0
  24. package/dist/types/blocks.js +28 -0
  25. package/dist/utils/common/errors.d.ts +46 -0
  26. package/dist/utils/common/errors.js +54 -0
  27. package/dist/utils/common/fs.d.ts +5 -0
  28. package/dist/utils/common/fs.js +48 -0
  29. package/dist/utils/common/logger.d.ts +5 -0
  30. package/dist/utils/common/logger.js +17 -0
  31. package/dist/utils/common/valueHelpers.d.ts +4 -0
  32. package/dist/utils/common/valueHelpers.js +23 -0
  33. package/dist/utils/graph/graphBuilder.d.ts +33 -0
  34. package/dist/utils/graph/graphBuilder.js +373 -0
  35. package/dist/utils/lexer/blockScanner.d.ts +36 -0
  36. package/dist/utils/lexer/blockScanner.js +143 -0
  37. package/dist/utils/lexer/hclLexer.d.ts +119 -0
  38. package/dist/utils/lexer/hclLexer.js +525 -0
  39. package/dist/utils/parser/bodyParser.d.ts +26 -0
  40. package/dist/utils/parser/bodyParser.js +81 -0
  41. package/dist/utils/parser/valueClassifier.d.ts +21 -0
  42. package/dist/utils/parser/valueClassifier.js +434 -0
  43. package/dist/utils/serialization/serializer.d.ts +9 -0
  44. package/dist/utils/serialization/serializer.js +63 -0
  45. package/dist/utils/serialization/yaml.d.ts +1 -0
  46. package/dist/utils/serialization/yaml.js +81 -0
  47. package/package.json +66 -0
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const path_1 = __importDefault(require("path"));
8
+ const terraformParser_1 = require("./services/terraformParser");
9
+ const artifactParsers_1 = require("./services/artifactParsers");
10
+ const serializer_1 = require("./utils/serialization/serializer");
11
+ function parseArgs(argv) {
12
+ const opts = { format: 'json', graph: false, prune: true };
13
+ for (let i = 0; i < argv.length; i += 1) {
14
+ const arg = argv[i];
15
+ if (arg === '--file' && argv[i + 1]) {
16
+ opts.file = argv[++i];
17
+ }
18
+ else if (arg === '--dir' && argv[i + 1]) {
19
+ opts.dir = argv[++i];
20
+ }
21
+ else if (arg === '--format' && argv[i + 1]) {
22
+ const fmt = argv[++i];
23
+ if (fmt === 'json' || fmt === 'yaml') {
24
+ opts.format = fmt;
25
+ }
26
+ }
27
+ else if (arg === '--graph') {
28
+ opts.graph = true;
29
+ }
30
+ else if (arg === '--no-prune') {
31
+ opts.prune = false;
32
+ }
33
+ }
34
+ return opts;
35
+ }
36
+ function main() {
37
+ const opts = parseArgs(process.argv.slice(2));
38
+ const parser = new terraformParser_1.TerraformParser();
39
+ if (!opts.file && !opts.dir) {
40
+ console.error('Usage: parse-hcl --file <path> | --dir <path> [--format json|yaml] [--graph] [--no-prune]');
41
+ process.exit(1);
42
+ }
43
+ if (opts.file) {
44
+ const filePath = path_1.default.resolve(opts.file);
45
+ const ext = path_1.default.extname(filePath);
46
+ if (ext.includes('tfvars')) {
47
+ emit(tfvarsParse(filePath), opts);
48
+ return;
49
+ }
50
+ if (ext === '.tfstate') {
51
+ emit(new artifactParsers_1.TfStateParser().parseFile(filePath), opts);
52
+ return;
53
+ }
54
+ if (ext === '.json' && filePath.endsWith('plan.json')) {
55
+ emit(new artifactParsers_1.TfPlanParser().parseFile(filePath), opts);
56
+ return;
57
+ }
58
+ const doc = parser.parseFile(filePath);
59
+ emit(doc, opts);
60
+ return;
61
+ }
62
+ if (opts.dir) {
63
+ const dirPath = path_1.default.resolve(opts.dir);
64
+ const result = parser.parseDirectory(dirPath);
65
+ const combined = result.combined ?? parser.combine(result.files.map((f) => f.document));
66
+ emit(opts.graph ? (0, serializer_1.toExport)(combined, { pruneEmpty: opts.prune }) : result, opts);
67
+ }
68
+ }
69
+ function tfvarsParse(filePath) {
70
+ return new artifactParsers_1.TfVarsParser().parseFile(filePath);
71
+ }
72
+ function emit(data, opts) {
73
+ if (opts.graph && !isTerraformDoc(data)) {
74
+ console.warn('Graph export requested but input is not a Terraform document; emitting raw output.');
75
+ }
76
+ if (opts.format === 'yaml') {
77
+ console.info((0, serializer_1.toYamlDocument)(data, { pruneEmpty: opts.prune }));
78
+ return;
79
+ }
80
+ if (opts.graph && isTerraformDoc(data)) {
81
+ console.info((0, serializer_1.toJsonExport)(data, { pruneEmpty: opts.prune }));
82
+ return;
83
+ }
84
+ console.info((0, serializer_1.toJson)(data, { pruneEmpty: opts.prune }));
85
+ }
86
+ function isTerraformDoc(data) {
87
+ return Boolean(data && typeof data === 'object' && 'resource' in data);
88
+ }
89
+ if (require.main === module) {
90
+ main();
91
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * parse-hcl - Lightweight Terraform HCL Parser
3
+ *
4
+ * A TypeScript library for parsing Terraform configuration files (.tf, .tf.json)
5
+ * and related artifacts (tfvars, tfstate, plan.json).
6
+ *
7
+ * @packageDocumentation
8
+ *
9
+ * @example Basic Usage
10
+ * ```typescript
11
+ * import { TerraformParser, toJson, buildDependencyGraph } from 'parse-hcl';
12
+ *
13
+ * const parser = new TerraformParser();
14
+ *
15
+ * // Parse a single file
16
+ * const doc = parser.parseFile('main.tf');
17
+ *
18
+ * // Parse a directory
19
+ * const result = parser.parseDirectory('./terraform');
20
+ *
21
+ * // Build dependency graph
22
+ * const graph = buildDependencyGraph(doc);
23
+ *
24
+ * // Serialize to JSON
25
+ * const json = toJson(doc);
26
+ * ```
27
+ *
28
+ * @example Working with Artifacts
29
+ * ```typescript
30
+ * import { TfVarsParser, TfStateParser, TfPlanParser } from 'parse-hcl';
31
+ *
32
+ * // Parse tfvars
33
+ * const tfvars = new TfVarsParser().parseFile('terraform.tfvars');
34
+ *
35
+ * // Parse state
36
+ * const state = new TfStateParser().parseFile('terraform.tfstate');
37
+ *
38
+ * // Parse plan
39
+ * const plan = new TfPlanParser().parseFile('plan.json');
40
+ * ```
41
+ */
42
+ export * from './types/blocks';
43
+ export * from './types/artifacts';
44
+ export * from './services/terraformParser';
45
+ export * from './services/artifactParsers';
46
+ export * from './services/terraformJsonParser';
47
+ export * from './utils/serialization/serializer';
48
+ export * from './utils/graph/graphBuilder';
49
+ export * from './utils/common/errors';
50
+ export { classifyValue } from './utils/parser/valueClassifier';
51
+ export { parseTypeConstraint } from './parsers/variableParser';
package/dist/index.js ADDED
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ /**
3
+ * parse-hcl - Lightweight Terraform HCL Parser
4
+ *
5
+ * A TypeScript library for parsing Terraform configuration files (.tf, .tf.json)
6
+ * and related artifacts (tfvars, tfstate, plan.json).
7
+ *
8
+ * @packageDocumentation
9
+ *
10
+ * @example Basic Usage
11
+ * ```typescript
12
+ * import { TerraformParser, toJson, buildDependencyGraph } from 'parse-hcl';
13
+ *
14
+ * const parser = new TerraformParser();
15
+ *
16
+ * // Parse a single file
17
+ * const doc = parser.parseFile('main.tf');
18
+ *
19
+ * // Parse a directory
20
+ * const result = parser.parseDirectory('./terraform');
21
+ *
22
+ * // Build dependency graph
23
+ * const graph = buildDependencyGraph(doc);
24
+ *
25
+ * // Serialize to JSON
26
+ * const json = toJson(doc);
27
+ * ```
28
+ *
29
+ * @example Working with Artifacts
30
+ * ```typescript
31
+ * import { TfVarsParser, TfStateParser, TfPlanParser } from 'parse-hcl';
32
+ *
33
+ * // Parse tfvars
34
+ * const tfvars = new TfVarsParser().parseFile('terraform.tfvars');
35
+ *
36
+ * // Parse state
37
+ * const state = new TfStateParser().parseFile('terraform.tfstate');
38
+ *
39
+ * // Parse plan
40
+ * const plan = new TfPlanParser().parseFile('plan.json');
41
+ * ```
42
+ */
43
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
44
+ if (k2 === undefined) k2 = k;
45
+ var desc = Object.getOwnPropertyDescriptor(m, k);
46
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
47
+ desc = { enumerable: true, get: function() { return m[k]; } };
48
+ }
49
+ Object.defineProperty(o, k2, desc);
50
+ }) : (function(o, m, k, k2) {
51
+ if (k2 === undefined) k2 = k;
52
+ o[k2] = m[k];
53
+ }));
54
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
55
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
56
+ };
57
+ Object.defineProperty(exports, "__esModule", { value: true });
58
+ exports.parseTypeConstraint = exports.classifyValue = void 0;
59
+ // Type definitions
60
+ __exportStar(require("./types/blocks"), exports);
61
+ __exportStar(require("./types/artifacts"), exports);
62
+ // Main parsers
63
+ __exportStar(require("./services/terraformParser"), exports);
64
+ __exportStar(require("./services/artifactParsers"), exports);
65
+ __exportStar(require("./services/terraformJsonParser"), exports);
66
+ // Utilities
67
+ __exportStar(require("./utils/serialization/serializer"), exports);
68
+ __exportStar(require("./utils/graph/graphBuilder"), exports);
69
+ __exportStar(require("./utils/common/errors"), exports);
70
+ // Re-export commonly used utilities
71
+ var valueClassifier_1 = require("./utils/parser/valueClassifier");
72
+ Object.defineProperty(exports, "classifyValue", { enumerable: true, get: function () { return valueClassifier_1.classifyValue; } });
73
+ var variableParser_1 = require("./parsers/variableParser");
74
+ Object.defineProperty(exports, "parseTypeConstraint", { enumerable: true, get: function () { return variableParser_1.parseTypeConstraint; } });
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Generic parsers for Terraform blocks.
3
+ * Handles resource, data, provider, module, terraform settings, and unknown block types.
4
+ */
5
+ import { DataBlock, GenericBlock, ModuleBlock, ProviderBlock, ResourceBlock, TerraformSettingsBlock } from '../types/blocks';
6
+ import { HclBlock } from '../types/blocks';
7
+ /**
8
+ * Parser for terraform settings blocks.
9
+ *
10
+ * @example
11
+ * ```hcl
12
+ * terraform {
13
+ * required_version = ">= 1.0.0"
14
+ * required_providers {
15
+ * aws = {
16
+ * source = "hashicorp/aws"
17
+ * version = "~> 4.0"
18
+ * }
19
+ * }
20
+ * }
21
+ * ```
22
+ */
23
+ export declare class TerraformSettingsParser {
24
+ /**
25
+ * Parses a terraform settings block.
26
+ * @param block - The raw HCL block to parse
27
+ * @returns Parsed TerraformSettingsBlock
28
+ */
29
+ parse(block: HclBlock): TerraformSettingsBlock;
30
+ }
31
+ /**
32
+ * Parser for provider configuration blocks.
33
+ *
34
+ * @example
35
+ * ```hcl
36
+ * provider "aws" {
37
+ * alias = "west"
38
+ * region = "us-west-2"
39
+ * }
40
+ * ```
41
+ */
42
+ export declare class ProviderParser {
43
+ /**
44
+ * Parses a provider configuration block.
45
+ * @param block - The raw HCL block to parse
46
+ * @returns Parsed ProviderBlock with name, alias, and properties
47
+ */
48
+ parse(block: HclBlock): ProviderBlock;
49
+ }
50
+ /**
51
+ * Parser for module call blocks.
52
+ *
53
+ * @example
54
+ * ```hcl
55
+ * module "vpc" {
56
+ * source = "terraform-aws-modules/vpc/aws"
57
+ * version = "3.0.0"
58
+ *
59
+ * name = "my-vpc"
60
+ * cidr = "10.0.0.0/16"
61
+ * }
62
+ * ```
63
+ */
64
+ export declare class ModuleParser {
65
+ /**
66
+ * Parses a module call block.
67
+ * @param block - The raw HCL block to parse
68
+ * @returns Parsed ModuleBlock with name and all properties
69
+ */
70
+ parse(block: HclBlock): ModuleBlock;
71
+ }
72
+ /**
73
+ * Parser for resource definition blocks.
74
+ * Separates meta-arguments (count, for_each, depends_on, etc.) from resource properties.
75
+ *
76
+ * @example
77
+ * ```hcl
78
+ * resource "aws_instance" "web" {
79
+ * count = 3
80
+ * ami = var.ami_id
81
+ * instance_type = "t2.micro"
82
+ *
83
+ * tags = {
84
+ * Name = "web-${count.index}"
85
+ * }
86
+ *
87
+ * dynamic "ebs_block_device" {
88
+ * for_each = var.ebs_volumes
89
+ * content {
90
+ * device_name = ebs_block_device.value.device_name
91
+ * volume_size = ebs_block_device.value.size
92
+ * }
93
+ * }
94
+ * }
95
+ * ```
96
+ */
97
+ export declare class ResourceParser {
98
+ /**
99
+ * Parses a resource block, separating properties, meta-arguments, and dynamic blocks.
100
+ * @param block - The raw HCL block to parse
101
+ * @returns Parsed ResourceBlock with separated concerns
102
+ */
103
+ parse(block: HclBlock): ResourceBlock;
104
+ /**
105
+ * Extracts dynamic blocks from nested blocks.
106
+ * @param blocks - Nested blocks from the resource body
107
+ * @returns Array of DynamicBlock objects
108
+ */
109
+ private extractDynamicBlocks;
110
+ }
111
+ /**
112
+ * Parser for data source blocks.
113
+ *
114
+ * @example
115
+ * ```hcl
116
+ * data "aws_ami" "ubuntu" {
117
+ * most_recent = true
118
+ *
119
+ * filter {
120
+ * name = "name"
121
+ * values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
122
+ * }
123
+ *
124
+ * owners = ["099720109477"]
125
+ * }
126
+ * ```
127
+ */
128
+ export declare class DataParser {
129
+ /**
130
+ * Parses a data source block.
131
+ * @param block - The raw HCL block to parse
132
+ * @returns Parsed DataBlock with type, name, properties, and nested blocks
133
+ */
134
+ parse(block: HclBlock): DataBlock;
135
+ }
136
+ /**
137
+ * Parser for generic/unknown block types.
138
+ * Used for moved, import, check, terraform_data, and unrecognized blocks.
139
+ *
140
+ * @example
141
+ * ```hcl
142
+ * moved {
143
+ * from = aws_instance.old
144
+ * to = aws_instance.new
145
+ * }
146
+ *
147
+ * import {
148
+ * to = aws_instance.example
149
+ * id = "i-1234567890abcdef0"
150
+ * }
151
+ *
152
+ * check "health" {
153
+ * assert {
154
+ * condition = data.http.health.status_code == 200
155
+ * error_message = "Health check failed"
156
+ * }
157
+ * }
158
+ * ```
159
+ */
160
+ export declare class GenericBlockParser {
161
+ /**
162
+ * Parses a generic block into a GenericBlock structure.
163
+ * @param block - The raw HCL block to parse
164
+ * @returns Parsed GenericBlock with type, labels, properties, and nested blocks
165
+ */
166
+ parse(block: HclBlock): GenericBlock;
167
+ }
@@ -0,0 +1,268 @@
1
+ "use strict";
2
+ /**
3
+ * Generic parsers for Terraform blocks.
4
+ * Handles resource, data, provider, module, terraform settings, and unknown block types.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.GenericBlockParser = exports.DataParser = exports.ResourceParser = exports.ModuleParser = exports.ProviderParser = exports.TerraformSettingsParser = void 0;
8
+ const bodyParser_1 = require("../utils/parser/bodyParser");
9
+ const valueHelpers_1 = require("../utils/common/valueHelpers");
10
+ /** Meta-argument keys that are separated from resource properties */
11
+ const META_KEYS = new Set(['count', 'for_each', 'provider', 'depends_on', 'lifecycle']);
12
+ /**
13
+ * Parser for terraform settings blocks.
14
+ *
15
+ * @example
16
+ * ```hcl
17
+ * terraform {
18
+ * required_version = ">= 1.0.0"
19
+ * required_providers {
20
+ * aws = {
21
+ * source = "hashicorp/aws"
22
+ * version = "~> 4.0"
23
+ * }
24
+ * }
25
+ * }
26
+ * ```
27
+ */
28
+ class TerraformSettingsParser {
29
+ /**
30
+ * Parses a terraform settings block.
31
+ * @param block - The raw HCL block to parse
32
+ * @returns Parsed TerraformSettingsBlock
33
+ */
34
+ parse(block) {
35
+ const parsed = (0, bodyParser_1.parseBlockBody)(block.body);
36
+ return {
37
+ properties: parsed.attributes,
38
+ raw: block.raw,
39
+ source: block.source
40
+ };
41
+ }
42
+ }
43
+ exports.TerraformSettingsParser = TerraformSettingsParser;
44
+ /**
45
+ * Parser for provider configuration blocks.
46
+ *
47
+ * @example
48
+ * ```hcl
49
+ * provider "aws" {
50
+ * alias = "west"
51
+ * region = "us-west-2"
52
+ * }
53
+ * ```
54
+ */
55
+ class ProviderParser {
56
+ /**
57
+ * Parses a provider configuration block.
58
+ * @param block - The raw HCL block to parse
59
+ * @returns Parsed ProviderBlock with name, alias, and properties
60
+ */
61
+ parse(block) {
62
+ const name = block.labels[0] || 'default';
63
+ const parsed = (0, bodyParser_1.parseBlockBody)(block.body);
64
+ return {
65
+ name,
66
+ alias: (0, valueHelpers_1.literalString)(parsed.attributes.alias) ?? parsed.attributes.alias?.raw,
67
+ properties: parsed.attributes,
68
+ raw: block.raw,
69
+ source: block.source
70
+ };
71
+ }
72
+ }
73
+ exports.ProviderParser = ProviderParser;
74
+ /**
75
+ * Parser for module call blocks.
76
+ *
77
+ * @example
78
+ * ```hcl
79
+ * module "vpc" {
80
+ * source = "terraform-aws-modules/vpc/aws"
81
+ * version = "3.0.0"
82
+ *
83
+ * name = "my-vpc"
84
+ * cidr = "10.0.0.0/16"
85
+ * }
86
+ * ```
87
+ */
88
+ class ModuleParser {
89
+ /**
90
+ * Parses a module call block.
91
+ * @param block - The raw HCL block to parse
92
+ * @returns Parsed ModuleBlock with name and all properties
93
+ */
94
+ parse(block) {
95
+ const name = block.labels[0] || 'unnamed';
96
+ const parsed = (0, bodyParser_1.parseBlockBody)(block.body);
97
+ return {
98
+ name,
99
+ properties: parsed.attributes,
100
+ raw: block.raw,
101
+ source: block.source
102
+ };
103
+ }
104
+ }
105
+ exports.ModuleParser = ModuleParser;
106
+ /**
107
+ * Parser for resource definition blocks.
108
+ * Separates meta-arguments (count, for_each, depends_on, etc.) from resource properties.
109
+ *
110
+ * @example
111
+ * ```hcl
112
+ * resource "aws_instance" "web" {
113
+ * count = 3
114
+ * ami = var.ami_id
115
+ * instance_type = "t2.micro"
116
+ *
117
+ * tags = {
118
+ * Name = "web-${count.index}"
119
+ * }
120
+ *
121
+ * dynamic "ebs_block_device" {
122
+ * for_each = var.ebs_volumes
123
+ * content {
124
+ * device_name = ebs_block_device.value.device_name
125
+ * volume_size = ebs_block_device.value.size
126
+ * }
127
+ * }
128
+ * }
129
+ * ```
130
+ */
131
+ class ResourceParser {
132
+ /**
133
+ * Parses a resource block, separating properties, meta-arguments, and dynamic blocks.
134
+ * @param block - The raw HCL block to parse
135
+ * @returns Parsed ResourceBlock with separated concerns
136
+ */
137
+ parse(block) {
138
+ const [type, name] = block.labels;
139
+ const parsed = (0, bodyParser_1.parseBlockBody)(block.body);
140
+ const meta = {};
141
+ const properties = {};
142
+ // Separate meta-arguments from properties
143
+ for (const [key, value] of Object.entries(parsed.attributes)) {
144
+ if (META_KEYS.has(key)) {
145
+ meta[key] = value;
146
+ }
147
+ else {
148
+ properties[key] = value;
149
+ }
150
+ }
151
+ return {
152
+ type: type || 'unknown',
153
+ name: name || 'unnamed',
154
+ properties,
155
+ blocks: parsed.blocks.filter((child) => child.type !== 'dynamic'),
156
+ dynamic_blocks: this.extractDynamicBlocks(parsed.blocks),
157
+ meta,
158
+ raw: block.raw,
159
+ source: block.source
160
+ };
161
+ }
162
+ /**
163
+ * Extracts dynamic blocks from nested blocks.
164
+ * @param blocks - Nested blocks from the resource body
165
+ * @returns Array of DynamicBlock objects
166
+ */
167
+ extractDynamicBlocks(blocks) {
168
+ const dynamicBlocks = [];
169
+ for (const block of blocks) {
170
+ if (block.type !== 'dynamic') {
171
+ continue;
172
+ }
173
+ const label = block.labels[0] || 'dynamic';
174
+ const for_each = block.attributes.for_each;
175
+ const iterator = (0, valueHelpers_1.literalString)(block.attributes.iterator);
176
+ const contentBlock = block.blocks.find((child) => child.type === 'content');
177
+ dynamicBlocks.push({
178
+ label,
179
+ for_each,
180
+ iterator,
181
+ content: contentBlock?.attributes || {},
182
+ raw: block.raw
183
+ });
184
+ }
185
+ return dynamicBlocks;
186
+ }
187
+ }
188
+ exports.ResourceParser = ResourceParser;
189
+ /**
190
+ * Parser for data source blocks.
191
+ *
192
+ * @example
193
+ * ```hcl
194
+ * data "aws_ami" "ubuntu" {
195
+ * most_recent = true
196
+ *
197
+ * filter {
198
+ * name = "name"
199
+ * values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
200
+ * }
201
+ *
202
+ * owners = ["099720109477"]
203
+ * }
204
+ * ```
205
+ */
206
+ class DataParser {
207
+ /**
208
+ * Parses a data source block.
209
+ * @param block - The raw HCL block to parse
210
+ * @returns Parsed DataBlock with type, name, properties, and nested blocks
211
+ */
212
+ parse(block) {
213
+ const [dataType, name] = block.labels;
214
+ const parsed = (0, bodyParser_1.parseBlockBody)(block.body);
215
+ return {
216
+ dataType: dataType || 'unknown',
217
+ name: name || 'unnamed',
218
+ properties: parsed.attributes,
219
+ blocks: parsed.blocks,
220
+ raw: block.raw,
221
+ source: block.source
222
+ };
223
+ }
224
+ }
225
+ exports.DataParser = DataParser;
226
+ /**
227
+ * Parser for generic/unknown block types.
228
+ * Used for moved, import, check, terraform_data, and unrecognized blocks.
229
+ *
230
+ * @example
231
+ * ```hcl
232
+ * moved {
233
+ * from = aws_instance.old
234
+ * to = aws_instance.new
235
+ * }
236
+ *
237
+ * import {
238
+ * to = aws_instance.example
239
+ * id = "i-1234567890abcdef0"
240
+ * }
241
+ *
242
+ * check "health" {
243
+ * assert {
244
+ * condition = data.http.health.status_code == 200
245
+ * error_message = "Health check failed"
246
+ * }
247
+ * }
248
+ * ```
249
+ */
250
+ class GenericBlockParser {
251
+ /**
252
+ * Parses a generic block into a GenericBlock structure.
253
+ * @param block - The raw HCL block to parse
254
+ * @returns Parsed GenericBlock with type, labels, properties, and nested blocks
255
+ */
256
+ parse(block) {
257
+ const parsed = (0, bodyParser_1.parseBlockBody)(block.body);
258
+ return {
259
+ type: block.keyword,
260
+ labels: block.labels,
261
+ properties: parsed.attributes,
262
+ blocks: parsed.blocks,
263
+ raw: block.raw,
264
+ source: block.source
265
+ };
266
+ }
267
+ }
268
+ exports.GenericBlockParser = GenericBlockParser;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Parser for Terraform locals blocks.
3
+ * Extracts local value definitions from locals blocks.
4
+ */
5
+ import { HclBlock, LocalValue } from '../types/blocks';
6
+ /**
7
+ * Parser for Terraform locals definition blocks.
8
+ * Converts a single locals block into multiple LocalValue entries.
9
+ *
10
+ * @example
11
+ * ```hcl
12
+ * locals {
13
+ * environment = "production"
14
+ * tags = {
15
+ * Name = "example"
16
+ * Env = local.environment
17
+ * }
18
+ * }
19
+ * ```
20
+ */
21
+ export declare class LocalsParser {
22
+ /**
23
+ * Parses a locals block into an array of LocalValue objects.
24
+ * Each attribute in the locals block becomes a separate LocalValue.
25
+ *
26
+ * @param block - The raw HCL block to parse
27
+ * @returns Array of LocalValue objects, one per local definition
28
+ */
29
+ parse(block: HclBlock): LocalValue[];
30
+ }