@build-astron-co/nimbus 0.2.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 +21 -0
- package/README.md +628 -0
- package/bin/nimbus +38 -0
- package/package.json +80 -0
- package/src/__tests__/app.test.ts +76 -0
- package/src/__tests__/audit.test.ts +877 -0
- package/src/__tests__/circuit-breaker.test.ts +116 -0
- package/src/__tests__/cli-run.test.ts +115 -0
- package/src/__tests__/context-manager.test.ts +502 -0
- package/src/__tests__/context.test.ts +242 -0
- package/src/__tests__/enterprise.test.ts +401 -0
- package/src/__tests__/generator.test.ts +433 -0
- package/src/__tests__/hooks.test.ts +582 -0
- package/src/__tests__/init.test.ts +436 -0
- package/src/__tests__/intent-parser.test.ts +229 -0
- package/src/__tests__/llm-router.test.ts +209 -0
- package/src/__tests__/lsp.test.ts +293 -0
- package/src/__tests__/modes.test.ts +336 -0
- package/src/__tests__/permissions.test.ts +338 -0
- package/src/__tests__/serve.test.ts +275 -0
- package/src/__tests__/sessions.test.ts +227 -0
- package/src/__tests__/sharing.test.ts +288 -0
- package/src/__tests__/snapshots.test.ts +581 -0
- package/src/__tests__/state-db.test.ts +334 -0
- package/src/__tests__/stream-with-tools.test.ts +732 -0
- package/src/__tests__/subagents.test.ts +176 -0
- package/src/__tests__/system-prompt.test.ts +169 -0
- package/src/__tests__/tool-converter.test.ts +256 -0
- package/src/__tests__/tool-schemas.test.ts +397 -0
- package/src/__tests__/tools.test.ts +143 -0
- package/src/__tests__/version.test.ts +49 -0
- package/src/agent/compaction-agent.ts +227 -0
- package/src/agent/context-manager.ts +435 -0
- package/src/agent/context.ts +427 -0
- package/src/agent/deploy-preview.ts +426 -0
- package/src/agent/index.ts +68 -0
- package/src/agent/loop.ts +717 -0
- package/src/agent/modes.ts +429 -0
- package/src/agent/permissions.ts +466 -0
- package/src/agent/subagents/base.ts +116 -0
- package/src/agent/subagents/cost.ts +51 -0
- package/src/agent/subagents/explore.ts +42 -0
- package/src/agent/subagents/general.ts +54 -0
- package/src/agent/subagents/index.ts +102 -0
- package/src/agent/subagents/infra.ts +59 -0
- package/src/agent/subagents/security.ts +69 -0
- package/src/agent/system-prompt.ts +436 -0
- package/src/app.ts +122 -0
- package/src/audit/activity-log.ts +290 -0
- package/src/audit/compliance-checker.ts +540 -0
- package/src/audit/cost-tracker.ts +318 -0
- package/src/audit/index.ts +23 -0
- package/src/audit/security-scanner.ts +596 -0
- package/src/auth/guard.ts +75 -0
- package/src/auth/index.ts +56 -0
- package/src/auth/oauth.ts +455 -0
- package/src/auth/providers.ts +470 -0
- package/src/auth/sso.ts +113 -0
- package/src/auth/store.ts +505 -0
- package/src/auth/types.ts +187 -0
- package/src/build.ts +141 -0
- package/src/cli/index.ts +16 -0
- package/src/cli/init.ts +854 -0
- package/src/cli/openapi-spec.ts +356 -0
- package/src/cli/run.ts +237 -0
- package/src/cli/serve-auth.ts +80 -0
- package/src/cli/serve.ts +462 -0
- package/src/cli/web.ts +67 -0
- package/src/cli.ts +1417 -0
- package/src/clients/core-engine-client.ts +227 -0
- package/src/clients/enterprise-client.ts +334 -0
- package/src/clients/generator-client.ts +351 -0
- package/src/clients/git-client.ts +627 -0
- package/src/clients/github-client.ts +410 -0
- package/src/clients/helm-client.ts +504 -0
- package/src/clients/index.ts +80 -0
- package/src/clients/k8s-client.ts +497 -0
- package/src/clients/llm-client.ts +161 -0
- package/src/clients/rest-client.ts +130 -0
- package/src/clients/service-discovery.ts +33 -0
- package/src/clients/terraform-client.ts +482 -0
- package/src/clients/tools-client.ts +1843 -0
- package/src/clients/ws-client.ts +115 -0
- package/src/commands/analyze/index.ts +352 -0
- package/src/commands/apply/helm.ts +473 -0
- package/src/commands/apply/index.ts +213 -0
- package/src/commands/apply/k8s.ts +454 -0
- package/src/commands/apply/terraform.ts +582 -0
- package/src/commands/ask.ts +167 -0
- package/src/commands/audit/index.ts +238 -0
- package/src/commands/auth-cloud.ts +294 -0
- package/src/commands/auth-list.ts +134 -0
- package/src/commands/auth-profile.ts +121 -0
- package/src/commands/auth-status.ts +141 -0
- package/src/commands/aws/ec2.ts +501 -0
- package/src/commands/aws/iam.ts +397 -0
- package/src/commands/aws/index.ts +133 -0
- package/src/commands/aws/lambda.ts +396 -0
- package/src/commands/aws/rds.ts +439 -0
- package/src/commands/aws/s3.ts +439 -0
- package/src/commands/aws/vpc.ts +393 -0
- package/src/commands/aws-discover.ts +649 -0
- package/src/commands/aws-terraform.ts +805 -0
- package/src/commands/azure/aks.ts +376 -0
- package/src/commands/azure/functions.ts +253 -0
- package/src/commands/azure/index.ts +116 -0
- package/src/commands/azure/storage.ts +478 -0
- package/src/commands/azure/vm.ts +355 -0
- package/src/commands/billing/index.ts +256 -0
- package/src/commands/chat.ts +314 -0
- package/src/commands/config.ts +346 -0
- package/src/commands/cost/cloud-cost-estimator.ts +266 -0
- package/src/commands/cost/estimator.ts +79 -0
- package/src/commands/cost/index.ts +594 -0
- package/src/commands/cost/parsers/terraform.ts +273 -0
- package/src/commands/cost/parsers/types.ts +25 -0
- package/src/commands/cost/pricing/aws.ts +544 -0
- package/src/commands/cost/pricing/azure.ts +499 -0
- package/src/commands/cost/pricing/gcp.ts +396 -0
- package/src/commands/cost/pricing/index.ts +40 -0
- package/src/commands/demo.ts +250 -0
- package/src/commands/doctor.ts +794 -0
- package/src/commands/drift/index.ts +439 -0
- package/src/commands/explain.ts +277 -0
- package/src/commands/feedback.ts +389 -0
- package/src/commands/fix.ts +324 -0
- package/src/commands/fs/index.ts +402 -0
- package/src/commands/gcp/compute.ts +325 -0
- package/src/commands/gcp/functions.ts +271 -0
- package/src/commands/gcp/gke.ts +438 -0
- package/src/commands/gcp/iam.ts +344 -0
- package/src/commands/gcp/index.ts +129 -0
- package/src/commands/gcp/storage.ts +284 -0
- package/src/commands/generate-helm.ts +1249 -0
- package/src/commands/generate-k8s.ts +1560 -0
- package/src/commands/generate-terraform.ts +1460 -0
- package/src/commands/gh/index.ts +863 -0
- package/src/commands/git/index.ts +1343 -0
- package/src/commands/helm/index.ts +1126 -0
- package/src/commands/help.ts +539 -0
- package/src/commands/history.ts +142 -0
- package/src/commands/import.ts +868 -0
- package/src/commands/index.ts +367 -0
- package/src/commands/init.ts +1046 -0
- package/src/commands/k8s/index.ts +1137 -0
- package/src/commands/login.ts +631 -0
- package/src/commands/logout.ts +83 -0
- package/src/commands/onboarding.ts +228 -0
- package/src/commands/plan/display.ts +279 -0
- package/src/commands/plan/index.ts +599 -0
- package/src/commands/preview.ts +452 -0
- package/src/commands/questionnaire.ts +1270 -0
- package/src/commands/resume.ts +55 -0
- package/src/commands/team/index.ts +346 -0
- package/src/commands/template.ts +232 -0
- package/src/commands/tf/index.ts +1034 -0
- package/src/commands/upgrade.ts +550 -0
- package/src/commands/usage/index.ts +134 -0
- package/src/commands/version.ts +170 -0
- package/src/compat/index.ts +2 -0
- package/src/compat/runtime.ts +12 -0
- package/src/compat/sqlite.ts +107 -0
- package/src/config/index.ts +17 -0
- package/src/config/manager.ts +530 -0
- package/src/config/safety-policy.ts +358 -0
- package/src/config/schema.ts +125 -0
- package/src/config/types.ts +527 -0
- package/src/context/context-db.ts +199 -0
- package/src/demo/index.ts +349 -0
- package/src/demo/scenarios/full-journey.ts +229 -0
- package/src/demo/scenarios/getting-started.ts +127 -0
- package/src/demo/scenarios/helm-release.ts +341 -0
- package/src/demo/scenarios/k8s-deployment.ts +194 -0
- package/src/demo/scenarios/terraform-vpc.ts +170 -0
- package/src/demo/types.ts +92 -0
- package/src/engine/cost-estimator.ts +438 -0
- package/src/engine/diagram-generator.ts +256 -0
- package/src/engine/drift-detector.ts +902 -0
- package/src/engine/executor.ts +1035 -0
- package/src/engine/index.ts +76 -0
- package/src/engine/orchestrator.ts +636 -0
- package/src/engine/planner.ts +720 -0
- package/src/engine/safety.ts +743 -0
- package/src/engine/verifier.ts +770 -0
- package/src/enterprise/audit.ts +348 -0
- package/src/enterprise/auth.ts +270 -0
- package/src/enterprise/billing.ts +822 -0
- package/src/enterprise/index.ts +17 -0
- package/src/enterprise/teams.ts +443 -0
- package/src/generator/best-practices.ts +1608 -0
- package/src/generator/helm.ts +630 -0
- package/src/generator/index.ts +37 -0
- package/src/generator/intent-parser.ts +514 -0
- package/src/generator/kubernetes.ts +976 -0
- package/src/generator/terraform.ts +1867 -0
- package/src/history/index.ts +8 -0
- package/src/history/manager.ts +322 -0
- package/src/history/types.ts +34 -0
- package/src/hooks/config.ts +432 -0
- package/src/hooks/engine.ts +391 -0
- package/src/hooks/index.ts +4 -0
- package/src/llm/auth-bridge.ts +198 -0
- package/src/llm/circuit-breaker.ts +140 -0
- package/src/llm/config-loader.ts +201 -0
- package/src/llm/cost-calculator.ts +171 -0
- package/src/llm/index.ts +8 -0
- package/src/llm/model-aliases.ts +115 -0
- package/src/llm/provider-registry.ts +63 -0
- package/src/llm/providers/anthropic.ts +433 -0
- package/src/llm/providers/bedrock.ts +477 -0
- package/src/llm/providers/google.ts +405 -0
- package/src/llm/providers/ollama.ts +767 -0
- package/src/llm/providers/openai-compatible.ts +340 -0
- package/src/llm/providers/openai.ts +328 -0
- package/src/llm/providers/openrouter.ts +338 -0
- package/src/llm/router.ts +1035 -0
- package/src/llm/types.ts +232 -0
- package/src/lsp/client.ts +298 -0
- package/src/lsp/languages.ts +116 -0
- package/src/lsp/manager.ts +278 -0
- package/src/mcp/client.ts +402 -0
- package/src/mcp/index.ts +5 -0
- package/src/mcp/manager.ts +133 -0
- package/src/nimbus.ts +214 -0
- package/src/plugins/index.ts +27 -0
- package/src/plugins/loader.ts +334 -0
- package/src/plugins/manager.ts +376 -0
- package/src/plugins/types.ts +284 -0
- package/src/scanners/cicd-scanner.ts +258 -0
- package/src/scanners/cloud-scanner.ts +466 -0
- package/src/scanners/framework-scanner.ts +469 -0
- package/src/scanners/iac-scanner.ts +388 -0
- package/src/scanners/index.ts +539 -0
- package/src/scanners/language-scanner.ts +276 -0
- package/src/scanners/package-manager-scanner.ts +277 -0
- package/src/scanners/types.ts +172 -0
- package/src/sessions/manager.ts +365 -0
- package/src/sessions/types.ts +44 -0
- package/src/sharing/sync.ts +296 -0
- package/src/sharing/viewer.ts +97 -0
- package/src/snapshots/index.ts +2 -0
- package/src/snapshots/manager.ts +530 -0
- package/src/state/artifacts.ts +147 -0
- package/src/state/audit.ts +137 -0
- package/src/state/billing.ts +240 -0
- package/src/state/checkpoints.ts +117 -0
- package/src/state/config.ts +67 -0
- package/src/state/conversations.ts +14 -0
- package/src/state/credentials.ts +154 -0
- package/src/state/db.ts +58 -0
- package/src/state/index.ts +26 -0
- package/src/state/messages.ts +115 -0
- package/src/state/projects.ts +123 -0
- package/src/state/schema.ts +236 -0
- package/src/state/sessions.ts +147 -0
- package/src/state/teams.ts +200 -0
- package/src/telemetry.ts +108 -0
- package/src/tools/aws-ops.ts +952 -0
- package/src/tools/azure-ops.ts +579 -0
- package/src/tools/file-ops.ts +593 -0
- package/src/tools/gcp-ops.ts +625 -0
- package/src/tools/git-ops.ts +773 -0
- package/src/tools/github-ops.ts +799 -0
- package/src/tools/helm-ops.ts +943 -0
- package/src/tools/index.ts +17 -0
- package/src/tools/k8s-ops.ts +819 -0
- package/src/tools/schemas/converter.ts +184 -0
- package/src/tools/schemas/devops.ts +612 -0
- package/src/tools/schemas/index.ts +73 -0
- package/src/tools/schemas/standard.ts +1144 -0
- package/src/tools/schemas/types.ts +705 -0
- package/src/tools/terraform-ops.ts +862 -0
- package/src/types/ambient.d.ts +193 -0
- package/src/types/config.ts +83 -0
- package/src/types/drift.ts +116 -0
- package/src/types/enterprise.ts +335 -0
- package/src/types/index.ts +20 -0
- package/src/types/plan.ts +44 -0
- package/src/types/request.ts +65 -0
- package/src/types/response.ts +54 -0
- package/src/types/service.ts +51 -0
- package/src/ui/App.tsx +997 -0
- package/src/ui/DeployPreview.tsx +169 -0
- package/src/ui/Header.tsx +68 -0
- package/src/ui/InputBox.tsx +350 -0
- package/src/ui/MessageList.tsx +585 -0
- package/src/ui/PermissionPrompt.tsx +151 -0
- package/src/ui/StatusBar.tsx +158 -0
- package/src/ui/ToolCallDisplay.tsx +409 -0
- package/src/ui/chat-ui.ts +853 -0
- package/src/ui/index.ts +33 -0
- package/src/ui/ink/index.ts +711 -0
- package/src/ui/streaming.ts +176 -0
- package/src/ui/types.ts +57 -0
- package/src/utils/analytics.ts +72 -0
- package/src/utils/cost-warning.ts +27 -0
- package/src/utils/env.ts +46 -0
- package/src/utils/errors.ts +69 -0
- package/src/utils/event-bus.ts +38 -0
- package/src/utils/index.ts +24 -0
- package/src/utils/logger.ts +171 -0
- package/src/utils/rate-limiter.ts +121 -0
- package/src/utils/service-auth.ts +49 -0
- package/src/utils/validation.ts +53 -0
- package/src/version.ts +4 -0
- package/src/watcher/index.ts +163 -0
- package/src/wizard/approval.ts +383 -0
- package/src/wizard/index.ts +25 -0
- package/src/wizard/prompts.ts +338 -0
- package/src/wizard/types.ts +171 -0
- package/src/wizard/ui.ts +556 -0
- package/src/wizard/wizard.ts +304 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terraform HCL Parser
|
|
3
|
+
*
|
|
4
|
+
* A simplified HCL parser that extracts resource blocks and their attributes
|
|
5
|
+
* from .tf files. Handles the most common HCL patterns including nested blocks,
|
|
6
|
+
* string/number/boolean attributes, and single-line comments.
|
|
7
|
+
*
|
|
8
|
+
* This is intentionally not a full HCL grammar parser -- it covers the patterns
|
|
9
|
+
* found in the vast majority of real-world Terraform configurations.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import * as fs from 'node:fs';
|
|
13
|
+
import * as path from 'node:path';
|
|
14
|
+
import type { TerraformResource } from './types';
|
|
15
|
+
|
|
16
|
+
export { TerraformResource };
|
|
17
|
+
|
|
18
|
+
export class TerraformParser {
|
|
19
|
+
/**
|
|
20
|
+
* Parse all .tf files in a directory (non-recursive for safety).
|
|
21
|
+
* Skips files that cannot be read and continues with the rest.
|
|
22
|
+
*/
|
|
23
|
+
async parseDirectory(directory: string): Promise<TerraformResource[]> {
|
|
24
|
+
const entries = fs.readdirSync(directory);
|
|
25
|
+
const tfFiles = entries.filter(f => f.endsWith('.tf'));
|
|
26
|
+
const resources: TerraformResource[] = [];
|
|
27
|
+
|
|
28
|
+
for (const file of tfFiles) {
|
|
29
|
+
try {
|
|
30
|
+
const content = fs.readFileSync(path.join(directory, file), 'utf-8');
|
|
31
|
+
resources.push(...this.parseHCL(content));
|
|
32
|
+
} catch {
|
|
33
|
+
// Skip files that cannot be read (permissions, encoding, etc.)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return resources;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Parse HCL content and extract all resource blocks.
|
|
42
|
+
*
|
|
43
|
+
* Strategy:
|
|
44
|
+
* 1. Strip comments (# and //)
|
|
45
|
+
* 2. Find top-level `resource "type" "name"` declarations
|
|
46
|
+
* 3. Extract the balanced brace block body
|
|
47
|
+
* 4. Parse attributes (including nested blocks) from the body
|
|
48
|
+
*/
|
|
49
|
+
parseHCL(content: string): TerraformResource[] {
|
|
50
|
+
const resources: TerraformResource[] = [];
|
|
51
|
+
|
|
52
|
+
// Strip single-line comments but preserve newlines for line-based matching
|
|
53
|
+
const stripped = this.stripComments(content);
|
|
54
|
+
|
|
55
|
+
// We use a manual scan to find resource blocks because regex alone
|
|
56
|
+
// cannot reliably match balanced braces with arbitrary nesting depth.
|
|
57
|
+
const resourceKeyword = 'resource';
|
|
58
|
+
let pos = 0;
|
|
59
|
+
|
|
60
|
+
while (pos < stripped.length) {
|
|
61
|
+
// Find next occurrence of the word "resource" at a word boundary
|
|
62
|
+
const idx = stripped.indexOf(resourceKeyword, pos);
|
|
63
|
+
if (idx === -1) {
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Make sure it is a standalone keyword (not part of another word)
|
|
68
|
+
const before = idx > 0 ? stripped[idx - 1] : '\n';
|
|
69
|
+
const after = stripped[idx + resourceKeyword.length];
|
|
70
|
+
if (/\w/.test(before) || (after !== undefined && /[^\s"]/.test(after))) {
|
|
71
|
+
pos = idx + resourceKeyword.length;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Parse: resource "type" "name" {
|
|
76
|
+
const afterKeyword = stripped.substring(idx + resourceKeyword.length);
|
|
77
|
+
const headerMatch = afterKeyword.match(/^\s+"([^"]+)"\s+"([^"]+)"\s*\{/);
|
|
78
|
+
if (!headerMatch) {
|
|
79
|
+
pos = idx + resourceKeyword.length;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const type = headerMatch[1];
|
|
84
|
+
const name = headerMatch[2];
|
|
85
|
+
|
|
86
|
+
// Find the balanced closing brace
|
|
87
|
+
const braceStart = idx + resourceKeyword.length + headerMatch[0].indexOf('{');
|
|
88
|
+
const body = this.extractBlock(stripped, braceStart);
|
|
89
|
+
if (body === null) {
|
|
90
|
+
pos = idx + resourceKeyword.length;
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const attributes = this.parseAttributes(body);
|
|
95
|
+
const provider = this.detectProvider(type);
|
|
96
|
+
|
|
97
|
+
resources.push({ type, name, provider, attributes });
|
|
98
|
+
|
|
99
|
+
// Advance past the block we just parsed
|
|
100
|
+
pos = braceStart + body.length + 2; // +2 for the opening and closing braces
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return resources;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ------------------------------------------------------------------
|
|
107
|
+
// Private helpers
|
|
108
|
+
// ------------------------------------------------------------------
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Strip single-line comments (# and //) and multi-line comments.
|
|
112
|
+
* Preserves newlines so that line-based attribute parsing still works.
|
|
113
|
+
*/
|
|
114
|
+
private stripComments(content: string): string {
|
|
115
|
+
let result = '';
|
|
116
|
+
let i = 0;
|
|
117
|
+
let inString = false;
|
|
118
|
+
|
|
119
|
+
while (i < content.length) {
|
|
120
|
+
// Handle string literals -- don't strip inside them
|
|
121
|
+
if (content[i] === '"' && (i === 0 || content[i - 1] !== '\\')) {
|
|
122
|
+
inString = !inString;
|
|
123
|
+
result += content[i];
|
|
124
|
+
i++;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (inString) {
|
|
129
|
+
result += content[i];
|
|
130
|
+
i++;
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Multi-line comment /* ... */
|
|
135
|
+
if (content[i] === '/' && content[i + 1] === '*') {
|
|
136
|
+
const end = content.indexOf('*/', i + 2);
|
|
137
|
+
if (end === -1) {
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
// Preserve newlines
|
|
141
|
+
const chunk = content.substring(i, end + 2);
|
|
142
|
+
result += chunk.replace(/[^\n]/g, ' ');
|
|
143
|
+
i = end + 2;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Single-line comments: # or //
|
|
148
|
+
if (content[i] === '#' || (content[i] === '/' && content[i + 1] === '/')) {
|
|
149
|
+
const nl = content.indexOf('\n', i);
|
|
150
|
+
if (nl === -1) {
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
result += `${' '.repeat(nl - i)}\n`;
|
|
154
|
+
i = nl + 1;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
result += content[i];
|
|
159
|
+
i++;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Extract the content between balanced braces starting at `start`.
|
|
167
|
+
* `start` must point to the opening '{'.
|
|
168
|
+
* Returns the inner content (without the outer braces), or null on failure.
|
|
169
|
+
*/
|
|
170
|
+
private extractBlock(content: string, start: number): string | null {
|
|
171
|
+
if (content[start] !== '{') {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
let depth = 0;
|
|
175
|
+
let inString = false;
|
|
176
|
+
|
|
177
|
+
for (let i = start; i < content.length; i++) {
|
|
178
|
+
const ch = content[i];
|
|
179
|
+
if (ch === '"' && (i === 0 || content[i - 1] !== '\\')) {
|
|
180
|
+
inString = !inString;
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
if (inString) {
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
if (ch === '{') {
|
|
187
|
+
depth++;
|
|
188
|
+
}
|
|
189
|
+
if (ch === '}') {
|
|
190
|
+
depth--;
|
|
191
|
+
if (depth === 0) {
|
|
192
|
+
return content.substring(start + 1, i);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Parse attributes from an HCL block body.
|
|
202
|
+
* Handles:
|
|
203
|
+
* - string: key = "value"
|
|
204
|
+
* - number: key = 123 or key = 1.5
|
|
205
|
+
* - boolean: key = true / false
|
|
206
|
+
* - nested blocks: block_label { ... } -- flattened with prefix
|
|
207
|
+
*/
|
|
208
|
+
parseAttributes(body: string): Record<string, any> {
|
|
209
|
+
const attrs: Record<string, any> = {};
|
|
210
|
+
|
|
211
|
+
// Match simple key = "value" patterns
|
|
212
|
+
const stringAttrRegex = /^\s*(\w[\w.-]*)\s*=\s*"([^"]*)"$/gm;
|
|
213
|
+
let match: RegExpExecArray | null;
|
|
214
|
+
while ((match = stringAttrRegex.exec(body)) !== null) {
|
|
215
|
+
attrs[match[1]] = match[2];
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Match numeric assignments: key = 123 (or 1.5)
|
|
219
|
+
const numAttrRegex = /^\s*(\w[\w.-]*)\s*=\s*(\d+(?:\.\d+)?)\s*$/gm;
|
|
220
|
+
while ((match = numAttrRegex.exec(body)) !== null) {
|
|
221
|
+
attrs[match[1]] = parseFloat(match[2]);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Match boolean assignments: key = true / false
|
|
225
|
+
const boolAttrRegex = /^\s*(\w[\w.-]*)\s*=\s*(true|false)\s*$/gm;
|
|
226
|
+
while ((match = boolAttrRegex.exec(body)) !== null) {
|
|
227
|
+
attrs[match[1]] = match[2] === 'true';
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Parse nested blocks and flatten with prefix
|
|
231
|
+
// e.g. root_block_device { volume_size = 50 } => root_block_device.volume_size = 50
|
|
232
|
+
const nestedBlockRegex = /(\w[\w.-]*)\s*\{/g;
|
|
233
|
+
let nestedMatch: RegExpExecArray | null;
|
|
234
|
+
while ((nestedMatch = nestedBlockRegex.exec(body)) !== null) {
|
|
235
|
+
const blockName = nestedMatch[1];
|
|
236
|
+
// Skip if this looks like an assignment (key = {) -- that is a map literal
|
|
237
|
+
const beforeBrace = body.substring(0, nestedMatch.index + blockName.length);
|
|
238
|
+
if (/=\s*$/.test(beforeBrace.substring(Math.max(0, beforeBrace.length - 10)))) {
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
const innerBody = this.extractBlock(
|
|
242
|
+
body,
|
|
243
|
+
nestedMatch.index +
|
|
244
|
+
blockName.length +
|
|
245
|
+
body.substring(nestedMatch.index + blockName.length).indexOf('{')
|
|
246
|
+
);
|
|
247
|
+
if (innerBody) {
|
|
248
|
+
const innerAttrs = this.parseAttributes(innerBody);
|
|
249
|
+
for (const [k, v] of Object.entries(innerAttrs)) {
|
|
250
|
+
attrs[`${blockName}.${k}`] = v;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return attrs;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Detect the cloud provider from the Terraform resource type prefix.
|
|
260
|
+
*/
|
|
261
|
+
private detectProvider(type: string): 'aws' | 'gcp' | 'azure' | 'unknown' {
|
|
262
|
+
if (type.startsWith('aws_')) {
|
|
263
|
+
return 'aws';
|
|
264
|
+
}
|
|
265
|
+
if (type.startsWith('google_')) {
|
|
266
|
+
return 'gcp';
|
|
267
|
+
}
|
|
268
|
+
if (type.startsWith('azurerm_')) {
|
|
269
|
+
return 'azure';
|
|
270
|
+
}
|
|
271
|
+
return 'unknown';
|
|
272
|
+
}
|
|
273
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for Terraform resource parsing
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface TerraformResource {
|
|
6
|
+
/** Resource type, e.g. "aws_instance", "google_compute_instance", "azurerm_virtual_machine" */
|
|
7
|
+
type: string;
|
|
8
|
+
/** Resource name as declared in HCL */
|
|
9
|
+
name: string;
|
|
10
|
+
/** Detected cloud provider */
|
|
11
|
+
provider: 'aws' | 'gcp' | 'azure' | 'unknown';
|
|
12
|
+
/** Parsed attributes from the resource block */
|
|
13
|
+
attributes: Record<string, any>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface TerraformBlock {
|
|
17
|
+
/** Block type: "resource", "data", "module", "variable", etc. */
|
|
18
|
+
blockType: string;
|
|
19
|
+
/** Block labels, e.g. ["aws_instance", "web"] */
|
|
20
|
+
labels: string[];
|
|
21
|
+
/** Flat key-value attributes parsed from the block */
|
|
22
|
+
attributes: Record<string, any>;
|
|
23
|
+
/** Nested sub-blocks */
|
|
24
|
+
blocks: TerraformBlock[];
|
|
25
|
+
}
|