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
@@ -0,0 +1,212 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TerraformJsonParser = void 0;
4
+ exports.convertJsonValue = convertJsonValue;
5
+ const blocks_1 = require("../types/blocks");
6
+ const fs_1 = require("../utils/common/fs");
7
+ const valueClassifier_1 = require("../utils/parser/valueClassifier");
8
+ class TerraformJsonParser {
9
+ parseFile(filePath) {
10
+ const json = (0, fs_1.readJsonFile)(filePath);
11
+ return this.parse(json, filePath);
12
+ }
13
+ parse(json, source = 'json-config') {
14
+ const doc = (0, blocks_1.createEmptyDocument)();
15
+ this.parseTerraform(json.terraform, doc, source);
16
+ this.parseProviders(json.provider, doc, source);
17
+ this.parseVariables(json.variable, doc, source);
18
+ this.parseOutputs(json.output, doc, source);
19
+ this.parseLocals(json.locals, doc, source);
20
+ this.parseModules(json.module, doc, source);
21
+ this.parseResources(json.resource, doc, source);
22
+ this.parseData(json.data, doc, source);
23
+ return doc;
24
+ }
25
+ parseTerraform(value, doc, source) {
26
+ if (!Array.isArray(value))
27
+ return;
28
+ for (const item of value) {
29
+ if (item && typeof item === 'object') {
30
+ doc.terraform.push({
31
+ properties: convertAttributes(item),
32
+ raw: JSON.stringify(item),
33
+ source
34
+ });
35
+ }
36
+ }
37
+ }
38
+ parseProviders(value, doc, source) {
39
+ if (!value || typeof value !== 'object')
40
+ return;
41
+ for (const [name, config] of Object.entries(value)) {
42
+ const configs = Array.isArray(config) ? config : [config];
43
+ for (const aliasCfg of configs) {
44
+ if (!isRecord(aliasCfg))
45
+ continue;
46
+ const alias = typeof aliasCfg.alias === 'string' ? aliasCfg.alias : undefined;
47
+ doc.provider.push({
48
+ name,
49
+ alias,
50
+ properties: convertAttributes(aliasCfg),
51
+ raw: JSON.stringify(aliasCfg),
52
+ source
53
+ });
54
+ }
55
+ }
56
+ }
57
+ parseVariables(value, doc, source) {
58
+ if (!value || typeof value !== 'object')
59
+ return;
60
+ for (const [name, config] of Object.entries(value)) {
61
+ const cfg = config || {};
62
+ doc.variable.push({
63
+ name,
64
+ description: typeof cfg.description === 'string' ? cfg.description : undefined,
65
+ type: typeof cfg.type === 'string' ? cfg.type : undefined,
66
+ default: cfg.default !== undefined ? convertJsonValue(cfg.default) : undefined,
67
+ validation: undefined,
68
+ sensitive: typeof cfg.sensitive === 'boolean' ? cfg.sensitive : undefined,
69
+ raw: JSON.stringify(cfg),
70
+ source
71
+ });
72
+ }
73
+ }
74
+ parseOutputs(value, doc, source) {
75
+ if (!value || typeof value !== 'object')
76
+ return;
77
+ for (const [name, config] of Object.entries(value)) {
78
+ const cfg = config || {};
79
+ doc.output.push({
80
+ name,
81
+ description: typeof cfg.description === 'string' ? cfg.description : undefined,
82
+ value: convertJsonValue(cfg.value),
83
+ sensitive: typeof cfg.sensitive === 'boolean' ? cfg.sensitive : undefined,
84
+ raw: JSON.stringify(cfg),
85
+ source
86
+ });
87
+ }
88
+ }
89
+ parseLocals(value, doc, source) {
90
+ if (!value || typeof value !== 'object')
91
+ return;
92
+ for (const [name, val] of Object.entries(value)) {
93
+ const converted = convertJsonValue(val);
94
+ doc.locals.push({
95
+ name,
96
+ type: converted.type,
97
+ value: converted,
98
+ raw: converted.raw,
99
+ source
100
+ });
101
+ }
102
+ }
103
+ parseModules(value, doc, source) {
104
+ if (!value || typeof value !== 'object')
105
+ return;
106
+ for (const [name, config] of Object.entries(value)) {
107
+ const cfg = config || {};
108
+ doc.module.push({
109
+ name,
110
+ properties: convertAttributes(cfg),
111
+ raw: JSON.stringify(cfg),
112
+ source
113
+ });
114
+ }
115
+ }
116
+ parseResources(value, doc, source) {
117
+ if (!value || typeof value !== 'object')
118
+ return;
119
+ for (const [type, resourceByName] of Object.entries(value)) {
120
+ if (!resourceByName || typeof resourceByName !== 'object')
121
+ continue;
122
+ for (const [name, configList] of Object.entries(resourceByName)) {
123
+ const items = Array.isArray(configList) ? configList : [configList];
124
+ for (const cfg of items) {
125
+ if (!cfg || typeof cfg !== 'object')
126
+ continue;
127
+ const parsed = convertAttributes(cfg);
128
+ doc.resource.push({
129
+ type,
130
+ name,
131
+ properties: parsed,
132
+ blocks: [],
133
+ dynamic_blocks: [],
134
+ meta: {},
135
+ raw: JSON.stringify(cfg),
136
+ source
137
+ });
138
+ }
139
+ }
140
+ }
141
+ }
142
+ parseData(value, doc, source) {
143
+ if (!value || typeof value !== 'object')
144
+ return;
145
+ for (const [dataType, dataByName] of Object.entries(value)) {
146
+ if (!dataByName || typeof dataByName !== 'object')
147
+ continue;
148
+ for (const [name, configList] of Object.entries(dataByName)) {
149
+ const items = Array.isArray(configList) ? configList : [configList];
150
+ for (const cfg of items) {
151
+ if (!cfg || typeof cfg !== 'object')
152
+ continue;
153
+ const parsed = convertAttributes(cfg);
154
+ doc.data.push({
155
+ dataType,
156
+ name,
157
+ properties: parsed,
158
+ blocks: [],
159
+ raw: JSON.stringify(cfg),
160
+ source
161
+ });
162
+ }
163
+ }
164
+ }
165
+ }
166
+ }
167
+ exports.TerraformJsonParser = TerraformJsonParser;
168
+ function convertAttributes(obj) {
169
+ const out = {};
170
+ for (const [key, val] of Object.entries(obj)) {
171
+ if (key === 'alias')
172
+ continue;
173
+ out[key] = convertJsonValue(val);
174
+ }
175
+ return out;
176
+ }
177
+ function convertJsonValue(input) {
178
+ if (input === null) {
179
+ return { type: 'literal', value: null, raw: 'null' };
180
+ }
181
+ if (typeof input === 'string') {
182
+ if (looksLikeExpression(input)) {
183
+ return (0, valueClassifier_1.classifyValue)(input);
184
+ }
185
+ return { type: 'literal', value: input, raw: input };
186
+ }
187
+ if (typeof input === 'number' || typeof input === 'boolean') {
188
+ return { type: 'literal', value: input, raw: String(input) };
189
+ }
190
+ if (Array.isArray(input)) {
191
+ return {
192
+ type: 'array',
193
+ value: input.map((item) => convertJsonValue(item)),
194
+ raw: JSON.stringify(input)
195
+ };
196
+ }
197
+ if (typeof input === 'object') {
198
+ const entries = Object.entries(input);
199
+ const value = {};
200
+ for (const [key, val] of entries) {
201
+ value[key] = convertJsonValue(val);
202
+ }
203
+ return { type: 'object', value, raw: JSON.stringify(input) };
204
+ }
205
+ return { type: 'literal', value: String(input), raw: String(input) };
206
+ }
207
+ function looksLikeExpression(value) {
208
+ return value.includes('${') || /^[\w.]+\(/.test(value) || /^[\w.]+$/.test(value);
209
+ }
210
+ function isRecord(value) {
211
+ return Boolean(value && typeof value === 'object' && !Array.isArray(value));
212
+ }
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Main Terraform configuration parser.
3
+ * Parses .tf and .tf.json files into structured TerraformDocument objects.
4
+ */
5
+ import { DirectoryParseOptions, DirectoryParseResult, TerraformDocument } from '../types/blocks';
6
+ /**
7
+ * Main parser for Terraform configuration files.
8
+ * Supports both HCL (.tf) and JSON (.tf.json) formats.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const parser = new TerraformParser();
13
+ *
14
+ * // Parse a single file
15
+ * const doc = parser.parseFile('main.tf');
16
+ * console.log(`Found ${doc.resource.length} resources`);
17
+ *
18
+ * // Parse a directory
19
+ * const result = parser.parseDirectory('./terraform');
20
+ * console.log(`Parsed ${result.files.length} files`);
21
+ *
22
+ * // Access parsed elements
23
+ * for (const resource of doc.resource) {
24
+ * console.log(`${resource.type}.${resource.name}`);
25
+ * }
26
+ * ```
27
+ */
28
+ export declare class TerraformParser {
29
+ private readonly scanner;
30
+ private readonly variableParser;
31
+ private readonly outputParser;
32
+ private readonly localsParser;
33
+ private readonly moduleParser;
34
+ private readonly providerParser;
35
+ private readonly resourceParser;
36
+ private readonly dataParser;
37
+ private readonly terraformSettingsParser;
38
+ private readonly genericBlockParser;
39
+ private readonly jsonParser;
40
+ /**
41
+ * Parses a Terraform configuration file.
42
+ * Automatically detects format (.tf vs .tf.json) and uses appropriate parser.
43
+ *
44
+ * @param filePath - Path to the Terraform file
45
+ * @returns Parsed TerraformDocument containing all blocks
46
+ * @throws {Error} If file cannot be read or parsed
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * const doc = parser.parseFile('main.tf');
51
+ * console.log(doc.variable[0].name);
52
+ * ```
53
+ */
54
+ parseFile(filePath: string): TerraformDocument;
55
+ /**
56
+ * Parses all Terraform files in a directory (recursively).
57
+ *
58
+ * @param dirPath - Path to the directory
59
+ * @param options - Parsing options
60
+ * @returns DirectoryParseResult with combined document and per-file results
61
+ * @throws {Error} If directory does not exist or is not accessible
62
+ *
63
+ * @example
64
+ * ```typescript
65
+ * // Parse with defaults (aggregate + per-file results)
66
+ * const result = parser.parseDirectory('./terraform');
67
+ *
68
+ * // Parse without aggregation
69
+ * const result = parser.parseDirectory('./terraform', { aggregate: false });
70
+ *
71
+ * // Parse without per-file results
72
+ * const result = parser.parseDirectory('./terraform', { includePerFile: false });
73
+ * ```
74
+ */
75
+ parseDirectory(dirPath: string, options?: DirectoryParseOptions): DirectoryParseResult;
76
+ /**
77
+ * Combines multiple TerraformDocuments into a single document.
78
+ * Useful for aggregating configurations from multiple files.
79
+ *
80
+ * @param documents - Array of documents to combine
81
+ * @returns A single TerraformDocument containing all blocks
82
+ *
83
+ * @example
84
+ * ```typescript
85
+ * const doc1 = parser.parseFile('main.tf');
86
+ * const doc2 = parser.parseFile('variables.tf');
87
+ * const combined = parser.combine([doc1, doc2]);
88
+ * ```
89
+ */
90
+ combine(documents: TerraformDocument[]): TerraformDocument;
91
+ }
@@ -0,0 +1,191 @@
1
+ "use strict";
2
+ /**
3
+ * Main Terraform configuration parser.
4
+ * Parses .tf and .tf.json files into structured TerraformDocument objects.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.TerraformParser = void 0;
8
+ const blocks_1 = require("../types/blocks");
9
+ const blockScanner_1 = require("../utils/lexer/blockScanner");
10
+ const fs_1 = require("../utils/common/fs");
11
+ const logger_1 = require("../utils/common/logger");
12
+ const localsParser_1 = require("../parsers/localsParser");
13
+ const genericParser_1 = require("../parsers/genericParser");
14
+ const outputParser_1 = require("../parsers/outputParser");
15
+ const variableParser_1 = require("../parsers/variableParser");
16
+ const terraformJsonParser_1 = require("./terraformJsonParser");
17
+ /**
18
+ * Main parser for Terraform configuration files.
19
+ * Supports both HCL (.tf) and JSON (.tf.json) formats.
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * const parser = new TerraformParser();
24
+ *
25
+ * // Parse a single file
26
+ * const doc = parser.parseFile('main.tf');
27
+ * console.log(`Found ${doc.resource.length} resources`);
28
+ *
29
+ * // Parse a directory
30
+ * const result = parser.parseDirectory('./terraform');
31
+ * console.log(`Parsed ${result.files.length} files`);
32
+ *
33
+ * // Access parsed elements
34
+ * for (const resource of doc.resource) {
35
+ * console.log(`${resource.type}.${resource.name}`);
36
+ * }
37
+ * ```
38
+ */
39
+ class TerraformParser {
40
+ constructor() {
41
+ this.scanner = new blockScanner_1.BlockScanner();
42
+ this.variableParser = new variableParser_1.VariableParser();
43
+ this.outputParser = new outputParser_1.OutputParser();
44
+ this.localsParser = new localsParser_1.LocalsParser();
45
+ this.moduleParser = new genericParser_1.ModuleParser();
46
+ this.providerParser = new genericParser_1.ProviderParser();
47
+ this.resourceParser = new genericParser_1.ResourceParser();
48
+ this.dataParser = new genericParser_1.DataParser();
49
+ this.terraformSettingsParser = new genericParser_1.TerraformSettingsParser();
50
+ this.genericBlockParser = new genericParser_1.GenericBlockParser();
51
+ this.jsonParser = new terraformJsonParser_1.TerraformJsonParser();
52
+ }
53
+ /**
54
+ * Parses a Terraform configuration file.
55
+ * Automatically detects format (.tf vs .tf.json) and uses appropriate parser.
56
+ *
57
+ * @param filePath - Path to the Terraform file
58
+ * @returns Parsed TerraformDocument containing all blocks
59
+ * @throws {Error} If file cannot be read or parsed
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * const doc = parser.parseFile('main.tf');
64
+ * console.log(doc.variable[0].name);
65
+ * ```
66
+ */
67
+ parseFile(filePath) {
68
+ if (filePath.endsWith('.tf.json')) {
69
+ logger_1.logger.info(`Parsing Terraform JSON file: ${filePath}`);
70
+ return this.jsonParser.parseFile(filePath);
71
+ }
72
+ logger_1.logger.info(`Parsing Terraform file: ${filePath}`);
73
+ const content = (0, fs_1.readTextFile)(filePath);
74
+ const blocks = this.scanner.scan(content, filePath);
75
+ const document = (0, blocks_1.createEmptyDocument)();
76
+ for (const block of blocks) {
77
+ switch (block.kind) {
78
+ case 'variable':
79
+ document.variable.push(this.variableParser.parse(block));
80
+ break;
81
+ case 'output':
82
+ document.output.push(this.outputParser.parse(block));
83
+ break;
84
+ case 'locals':
85
+ document.locals.push(...this.localsParser.parse(block));
86
+ break;
87
+ case 'module':
88
+ document.module.push(this.moduleParser.parse(block));
89
+ break;
90
+ case 'provider':
91
+ document.provider.push(this.providerParser.parse(block));
92
+ break;
93
+ case 'resource':
94
+ document.resource.push(this.resourceParser.parse(block));
95
+ break;
96
+ case 'data':
97
+ document.data.push(this.dataParser.parse(block));
98
+ break;
99
+ case 'terraform':
100
+ document.terraform.push(this.terraformSettingsParser.parse(block));
101
+ break;
102
+ case 'moved':
103
+ document.moved.push(this.genericBlockParser.parse(block));
104
+ break;
105
+ case 'import':
106
+ document.import.push(this.genericBlockParser.parse(block));
107
+ break;
108
+ case 'check':
109
+ document.check.push(this.genericBlockParser.parse(block));
110
+ break;
111
+ case 'terraform_data':
112
+ document.terraform_data.push(this.genericBlockParser.parse(block));
113
+ break;
114
+ default:
115
+ document.unknown.push(this.genericBlockParser.parse(block));
116
+ }
117
+ }
118
+ return document;
119
+ }
120
+ /**
121
+ * Parses all Terraform files in a directory (recursively).
122
+ *
123
+ * @param dirPath - Path to the directory
124
+ * @param options - Parsing options
125
+ * @returns DirectoryParseResult with combined document and per-file results
126
+ * @throws {Error} If directory does not exist or is not accessible
127
+ *
128
+ * @example
129
+ * ```typescript
130
+ * // Parse with defaults (aggregate + per-file results)
131
+ * const result = parser.parseDirectory('./terraform');
132
+ *
133
+ * // Parse without aggregation
134
+ * const result = parser.parseDirectory('./terraform', { aggregate: false });
135
+ *
136
+ * // Parse without per-file results
137
+ * const result = parser.parseDirectory('./terraform', { includePerFile: false });
138
+ * ```
139
+ */
140
+ parseDirectory(dirPath, options) {
141
+ if (!(0, fs_1.pathExists)(dirPath) || !(0, fs_1.isDirectory)(dirPath)) {
142
+ throw new Error(`Invalid directory path: ${dirPath}`);
143
+ }
144
+ const aggregate = options?.aggregate !== false;
145
+ const includePerFile = options?.includePerFile !== false;
146
+ const files = (0, fs_1.listTerraformFiles)(dirPath);
147
+ const parsedFiles = files.map((filePath) => ({
148
+ path: filePath,
149
+ document: this.parseFile(filePath)
150
+ }));
151
+ const combined = aggregate ? this.combine(parsedFiles.map((item) => item.document)) : undefined;
152
+ return {
153
+ combined,
154
+ files: includePerFile ? parsedFiles : []
155
+ };
156
+ }
157
+ /**
158
+ * Combines multiple TerraformDocuments into a single document.
159
+ * Useful for aggregating configurations from multiple files.
160
+ *
161
+ * @param documents - Array of documents to combine
162
+ * @returns A single TerraformDocument containing all blocks
163
+ *
164
+ * @example
165
+ * ```typescript
166
+ * const doc1 = parser.parseFile('main.tf');
167
+ * const doc2 = parser.parseFile('variables.tf');
168
+ * const combined = parser.combine([doc1, doc2]);
169
+ * ```
170
+ */
171
+ combine(documents) {
172
+ const combined = (0, blocks_1.createEmptyDocument)();
173
+ for (const doc of documents) {
174
+ combined.terraform.push(...doc.terraform);
175
+ combined.provider.push(...doc.provider);
176
+ combined.variable.push(...doc.variable);
177
+ combined.output.push(...doc.output);
178
+ combined.module.push(...doc.module);
179
+ combined.resource.push(...doc.resource);
180
+ combined.data.push(...doc.data);
181
+ combined.locals.push(...doc.locals);
182
+ combined.moved.push(...doc.moved);
183
+ combined.import.push(...doc.import);
184
+ combined.check.push(...doc.check);
185
+ combined.terraform_data.push(...doc.terraform_data);
186
+ combined.unknown.push(...doc.unknown);
187
+ }
188
+ return combined;
189
+ }
190
+ }
191
+ exports.TerraformParser = TerraformParser;
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Type definitions for Terraform artifacts (state files, plans, tfvars) and dependency graphs.
3
+ */
4
+ import { BlockKind, Reference, TerraformDocument, Value } from './blocks';
5
+ /**
6
+ * Types of nodes in the dependency graph.
7
+ * Extends BlockKind with special node types for references.
8
+ */
9
+ export type GraphNodeKind = BlockKind | 'module_output' | 'path' | 'each' | 'count' | 'self' | 'external';
10
+ /**
11
+ * A node in the dependency graph representing a Terraform element.
12
+ */
13
+ export interface GraphNode {
14
+ /** Unique identifier for the node */
15
+ id: string;
16
+ /** The kind/type of the node */
17
+ kind: GraphNodeKind;
18
+ /** Display name for the node */
19
+ name: string;
20
+ /** Resource/data type (for resource and data nodes) */
21
+ type?: string;
22
+ /** Source file path (if known) */
23
+ source?: string;
24
+ }
25
+ /**
26
+ * An edge in the dependency graph representing a reference.
27
+ */
28
+ export interface GraphEdge {
29
+ /** The source node ID */
30
+ from: string;
31
+ /** The target node ID */
32
+ to: string;
33
+ /** The reference that created this edge */
34
+ reference: Reference;
35
+ /** Source file path where the reference was found */
36
+ source?: string;
37
+ }
38
+ /**
39
+ * Complete dependency graph with nodes, edges, and orphan references.
40
+ */
41
+ export interface DependencyGraph {
42
+ /** All nodes in the graph */
43
+ nodes: GraphNode[];
44
+ /** All edges (dependencies) in the graph */
45
+ edges: GraphEdge[];
46
+ /** References that could not be resolved to nodes */
47
+ orphanReferences: Reference[];
48
+ }
49
+ /**
50
+ * Export format containing document, graph, and metadata.
51
+ */
52
+ export interface TerraformExport {
53
+ /** Export format version */
54
+ version: string;
55
+ /** The parsed document (may be partial for filtered exports) */
56
+ document: Partial<TerraformDocument>;
57
+ /** The dependency graph */
58
+ graph: DependencyGraph;
59
+ }
60
+ /**
61
+ * Parsed tfvars document containing variable assignments.
62
+ */
63
+ export interface TfVarsDocument {
64
+ /** Source file path */
65
+ source: string;
66
+ /** Raw file content */
67
+ raw: string;
68
+ /** Variable assignments (name -> value) */
69
+ assignments: Record<string, Value>;
70
+ }
71
+ /**
72
+ * An output value from Terraform state.
73
+ */
74
+ export interface TerraformStateOutput {
75
+ /** The output value */
76
+ value: unknown;
77
+ /** The output type */
78
+ type?: string | string[];
79
+ /** Whether the output is sensitive */
80
+ sensitive?: boolean;
81
+ }
82
+ /**
83
+ * A resource instance in Terraform state.
84
+ */
85
+ export interface TerraformStateInstance {
86
+ /** Index key (for count/for_each resources) */
87
+ index_key?: string | number;
88
+ /** Resource attributes */
89
+ attributes?: Record<string, unknown>;
90
+ /** Instance status */
91
+ status?: string;
92
+ }
93
+ /**
94
+ * A resource in Terraform state.
95
+ */
96
+ export interface TerraformStateResource {
97
+ /** Module address (for resources in modules) */
98
+ module?: string;
99
+ /** Resource mode (managed or data) */
100
+ mode: 'managed' | 'data';
101
+ /** Resource type */
102
+ type: string;
103
+ /** Resource name */
104
+ name: string;
105
+ /** Provider configuration */
106
+ provider?: string;
107
+ /** Resource instances */
108
+ instances: TerraformStateInstance[];
109
+ }
110
+ /**
111
+ * Parsed Terraform state document.
112
+ */
113
+ export interface TerraformStateDocument {
114
+ /** State format version */
115
+ version: number;
116
+ /** Terraform version that created the state */
117
+ terraform_version?: string;
118
+ /** State serial number */
119
+ serial?: number;
120
+ /** State lineage (unique identifier) */
121
+ lineage?: string;
122
+ /** Output values */
123
+ outputs: Record<string, TerraformStateOutput>;
124
+ /** Resources in state */
125
+ resources: TerraformStateResource[];
126
+ /** Raw state data */
127
+ raw: unknown;
128
+ /** Source file path */
129
+ source: string;
130
+ }
131
+ /**
132
+ * A resource change in a Terraform plan.
133
+ */
134
+ export interface PlanResourceChange {
135
+ /** Resource address */
136
+ address: string;
137
+ /** Module address (if in a module) */
138
+ module_address?: string;
139
+ /** Resource mode */
140
+ mode: 'managed' | 'data';
141
+ /** Resource type */
142
+ type: string;
143
+ /** Resource name */
144
+ name: string;
145
+ /** Provider name */
146
+ provider_name?: string;
147
+ /** Change details */
148
+ change: {
149
+ /** Actions to perform (create, update, delete, etc.) */
150
+ actions: string[];
151
+ /** State before change */
152
+ before?: unknown;
153
+ /** State after change */
154
+ after?: unknown;
155
+ /** Unknown values after change */
156
+ after_unknown?: Record<string, unknown>;
157
+ /** Sensitive values before change */
158
+ before_sensitive?: Record<string, unknown>;
159
+ /** Sensitive values after change */
160
+ after_sensitive?: Record<string, unknown>;
161
+ };
162
+ }
163
+ /**
164
+ * A resource in planned values.
165
+ */
166
+ export interface PlanResource {
167
+ /** Resource address */
168
+ address: string;
169
+ /** Resource mode */
170
+ mode: 'managed' | 'data';
171
+ /** Resource type */
172
+ type: string;
173
+ /** Resource name */
174
+ name: string;
175
+ /** Provider name */
176
+ provider_name?: string;
177
+ /** Resource values */
178
+ values?: Record<string, unknown>;
179
+ }
180
+ /**
181
+ * A module in planned values.
182
+ */
183
+ export interface PlanModule {
184
+ /** Module address */
185
+ address?: string;
186
+ /** Resources in the module */
187
+ resources?: PlanResource[];
188
+ /** Child modules */
189
+ child_modules?: PlanModule[];
190
+ }
191
+ /**
192
+ * Parsed Terraform plan document.
193
+ */
194
+ export interface TerraformPlanDocument {
195
+ /** Plan format version */
196
+ format_version?: string;
197
+ /** Terraform version */
198
+ terraform_version?: string;
199
+ /** Planned values */
200
+ planned_values?: {
201
+ /** Root module */
202
+ root_module?: PlanModule;
203
+ };
204
+ /** Resource changes */
205
+ resource_changes: PlanResourceChange[];
206
+ /** Raw plan data */
207
+ raw: unknown;
208
+ /** Source file path */
209
+ source: string;
210
+ }