cdk-cost-analyzer 0.1.1
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/.cdk-cost-analyzer-cache/metadata.json +12 -0
- package/.gitlab-ci.yml +214 -0
- package/.husky/pre-commit +12 -0
- package/.kiro/hooks/accessibility-audit.kiro.hook +18 -0
- package/.kiro/hooks/api-schema-validation.kiro.hook +21 -0
- package/.kiro/hooks/auto-test-on-save.kiro.hook +19 -0
- package/.kiro/hooks/cdk-synth-on-change.kiro.hook +20 -0
- package/.kiro/hooks/code-coverage-check.kiro.hook +14 -0
- package/.kiro/hooks/commit-message-helper.kiro.hook +14 -0
- package/.kiro/hooks/dependency-update-check.kiro.hook +14 -0
- package/.kiro/hooks/env-file-validation.kiro.hook +18 -0
- package/.kiro/hooks/lint-and-format-on-save.kiro.hook +21 -0
- package/.kiro/hooks/mcp-config-validation.kiro.hook +17 -0
- package/.kiro/hooks/mcp-server-test.kiro.hook +14 -0
- package/.kiro/hooks/performance-analysis.kiro.hook +14 -0
- package/.kiro/hooks/readme-spell-check.kiro.hook +14 -0
- package/.kiro/hooks/security-scan-on-dependency-change.kiro.hook +21 -0
- package/.kiro/hooks/translation-update.kiro.hook +18 -0
- package/.kiro/hooks/update-documentation.kiro.hook +18 -0
- package/.kiro/settings/mcp.json +20 -0
- package/.kiro/specs/cdk-cost-analyzer/design.md +620 -0
- package/.kiro/specs/cdk-cost-analyzer/requirements.md +183 -0
- package/.kiro/specs/cdk-cost-analyzer/tasks.md +357 -0
- package/.kiro/specs/github-actions-ci/design.md +281 -0
- package/.kiro/specs/github-actions-ci/requirements.md +86 -0
- package/.kiro/specs/github-actions-ci/tasks.md +115 -0
- package/.kiro/specs/nlb-calculator-test-coverage/design.md +190 -0
- package/.kiro/specs/nlb-calculator-test-coverage/requirements.md +84 -0
- package/.kiro/specs/nlb-calculator-test-coverage/tasks.md +150 -0
- package/.kiro/specs/production-readiness/design.md +1213 -0
- package/.kiro/specs/production-readiness/requirements.md +312 -0
- package/.kiro/specs/production-readiness/tasks.md +269 -0
- package/.kiro/specs/repository-cleanup/design.md +283 -0
- package/.kiro/specs/repository-cleanup/requirements.md +74 -0
- package/.kiro/specs/repository-cleanup/tasks.md +64 -0
- package/.kiro/steering/aws-cli-best-practices.md +41 -0
- package/.kiro/steering/cdk-best-practices.md +49 -0
- package/.kiro/steering/development-standards.md +54 -0
- package/.kiro/steering/docker-best-practices.md +34 -0
- package/.kiro/steering/documentation-style.md +151 -0
- package/.kiro/steering/git-best-practices.md +37 -0
- package/.kiro/steering/mcp-best-practices.md +95 -0
- package/.kiro/steering/python-best-practices.md +48 -0
- package/.kiro/steering/react-best-practices.md +44 -0
- package/.kiro/steering/security-best-practices.md +41 -0
- package/.kiro/steering/testing-best-practices.md +59 -0
- package/.kiro/steering/typescript-best-practices.md +40 -0
- package/CHANGELOG.md +49 -0
- package/CONTRIBUTING.md +258 -0
- package/LICENSE +19 -0
- package/README.md +480 -0
- package/SECURITY.md +117 -0
- package/dist/api/index.d.ts +11 -0
- package/dist/api/index.js +65 -0
- package/dist/api/types.d.ts +15 -0
- package/dist/api/types.js +3 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +262 -0
- package/dist/config/ConfigManager.d.ts +40 -0
- package/dist/config/ConfigManager.js +238 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.js +19 -0
- package/dist/config/types.d.ts +72 -0
- package/dist/config/types.js +15 -0
- package/dist/diff/DiffEngine.d.ts +7 -0
- package/dist/diff/DiffEngine.js +73 -0
- package/dist/diff/index.d.ts +2 -0
- package/dist/diff/index.js +21 -0
- package/dist/diff/types.d.ts +20 -0
- package/dist/diff/types.js +3 -0
- package/dist/integrations/GitLabIntegration.d.ts +7 -0
- package/dist/integrations/GitLabIntegration.js +45 -0
- package/dist/integrations/index.d.ts +2 -0
- package/dist/integrations/index.js +21 -0
- package/dist/integrations/types.d.ts +11 -0
- package/dist/integrations/types.js +13 -0
- package/dist/parser/TemplateParser.d.ts +8 -0
- package/dist/parser/TemplateParser.js +75 -0
- package/dist/parser/index.d.ts +2 -0
- package/dist/parser/index.js +22 -0
- package/dist/parser/types.d.ts +30 -0
- package/dist/parser/types.js +3 -0
- package/dist/pipeline/PipelineOrchestrator.d.ts +23 -0
- package/dist/pipeline/PipelineOrchestrator.js +191 -0
- package/dist/pipeline/index.d.ts +2 -0
- package/dist/pipeline/index.js +19 -0
- package/dist/pipeline/types.d.ts +41 -0
- package/dist/pipeline/types.js +13 -0
- package/dist/pricing/CacheManager.d.ts +75 -0
- package/dist/pricing/CacheManager.js +195 -0
- package/dist/pricing/PricingClient.d.ts +17 -0
- package/dist/pricing/PricingClient.js +122 -0
- package/dist/pricing/PricingService.d.ts +16 -0
- package/dist/pricing/PricingService.js +149 -0
- package/dist/pricing/calculators/ALBCalculator.d.ts +16 -0
- package/dist/pricing/calculators/ALBCalculator.js +163 -0
- package/dist/pricing/calculators/APIGatewayCalculator.d.ts +10 -0
- package/dist/pricing/calculators/APIGatewayCalculator.js +177 -0
- package/dist/pricing/calculators/CloudFrontCalculator.d.ts +59 -0
- package/dist/pricing/calculators/CloudFrontCalculator.js +151 -0
- package/dist/pricing/calculators/DynamoDBCalculator.d.ts +9 -0
- package/dist/pricing/calculators/DynamoDBCalculator.js +146 -0
- package/dist/pricing/calculators/EC2Calculator.d.ts +7 -0
- package/dist/pricing/calculators/EC2Calculator.js +80 -0
- package/dist/pricing/calculators/ECSCalculator.d.ts +9 -0
- package/dist/pricing/calculators/ECSCalculator.js +116 -0
- package/dist/pricing/calculators/ElastiCacheCalculator.d.ts +8 -0
- package/dist/pricing/calculators/ElastiCacheCalculator.js +106 -0
- package/dist/pricing/calculators/LambdaCalculator.d.ts +13 -0
- package/dist/pricing/calculators/LambdaCalculator.js +111 -0
- package/dist/pricing/calculators/NLBCalculator.d.ts +16 -0
- package/dist/pricing/calculators/NLBCalculator.js +138 -0
- package/dist/pricing/calculators/NatGatewayCalculator.d.ts +12 -0
- package/dist/pricing/calculators/NatGatewayCalculator.js +116 -0
- package/dist/pricing/calculators/RDSCalculator.d.ts +9 -0
- package/dist/pricing/calculators/RDSCalculator.js +103 -0
- package/dist/pricing/calculators/S3Calculator.d.ts +8 -0
- package/dist/pricing/calculators/S3Calculator.js +68 -0
- package/dist/pricing/calculators/VPCEndpointCalculator.d.ts +12 -0
- package/dist/pricing/calculators/VPCEndpointCalculator.js +129 -0
- package/dist/pricing/index.d.ts +10 -0
- package/dist/pricing/index.js +37 -0
- package/dist/pricing/types.d.ts +53 -0
- package/dist/pricing/types.js +22 -0
- package/dist/releasetag.txt +1 -0
- package/dist/reporter/Reporter.d.ts +18 -0
- package/dist/reporter/Reporter.js +412 -0
- package/dist/reporter/index.d.ts +2 -0
- package/dist/reporter/index.js +21 -0
- package/dist/reporter/types.d.ts +72 -0
- package/dist/reporter/types.js +3 -0
- package/dist/synthesis/SynthesisOrchestrator.d.ts +26 -0
- package/dist/synthesis/SynthesisOrchestrator.js +243 -0
- package/dist/synthesis/index.d.ts +2 -0
- package/dist/synthesis/index.js +19 -0
- package/dist/synthesis/types.d.ts +17 -0
- package/dist/synthesis/types.js +13 -0
- package/dist/threshold/ThresholdEnforcer.d.ts +29 -0
- package/dist/threshold/ThresholdEnforcer.js +143 -0
- package/dist/threshold/index.d.ts +2 -0
- package/dist/threshold/index.js +19 -0
- package/dist/threshold/types.d.ts +15 -0
- package/dist/threshold/types.js +17 -0
- package/docs/CALCULATORS.md +820 -0
- package/docs/CI_CD.md +608 -0
- package/docs/CONFIGURATION.md +407 -0
- package/docs/DEVELOPMENT.md +387 -0
- package/docs/RELEASE.md +223 -0
- package/docs/TROUBLESHOOTING.md +847 -0
- package/examples/.cdk-cost-analyzer.yml +85 -0
- package/examples/.gitlab-ci.yml +125 -0
- package/examples/api-usage.js +26 -0
- package/examples/complex/base.json +16 -0
- package/examples/complex/target.json +29 -0
- package/examples/monorepo/.gitlab-ci.yml +251 -0
- package/examples/monorepo/README.md +341 -0
- package/examples/monorepo/package.json +27 -0
- package/examples/monorepo/packages/backend-infra/.cdk-cost-analyzer.yml +34 -0
- package/examples/monorepo/packages/backend-infra/bin/app.ts +16 -0
- package/examples/monorepo/packages/backend-infra/cdk.json +7 -0
- package/examples/monorepo/packages/backend-infra/lib/backend-stack.ts +128 -0
- package/examples/monorepo/packages/backend-infra/package.json +30 -0
- package/examples/monorepo/packages/backend-infra/tsconfig.json +11 -0
- package/examples/monorepo/packages/data-infra/.cdk-cost-analyzer.yml +38 -0
- package/examples/monorepo/packages/data-infra/bin/app.ts +16 -0
- package/examples/monorepo/packages/data-infra/cdk.json +7 -0
- package/examples/monorepo/packages/data-infra/lib/data-stack.ts +121 -0
- package/examples/monorepo/packages/data-infra/package.json +30 -0
- package/examples/monorepo/packages/data-infra/tsconfig.json +11 -0
- package/examples/monorepo/packages/frontend-infra/.cdk-cost-analyzer.yml +31 -0
- package/examples/monorepo/packages/frontend-infra/bin/app.ts +16 -0
- package/examples/monorepo/packages/frontend-infra/cdk.json +7 -0
- package/examples/monorepo/packages/frontend-infra/lib/frontend-stack.ts +60 -0
- package/examples/monorepo/packages/frontend-infra/package.json +30 -0
- package/examples/monorepo/packages/frontend-infra/tsconfig.json +11 -0
- package/examples/monorepo/tsconfig.json +35 -0
- package/examples/multi-stack/.cdk-cost-analyzer.yml +72 -0
- package/examples/multi-stack/.gitlab-ci.yml +184 -0
- package/examples/multi-stack/README.md +279 -0
- package/examples/multi-stack/bin/app.ts +36 -0
- package/examples/multi-stack/cdk.json +72 -0
- package/examples/multi-stack/lib/compute-stack.ts +128 -0
- package/examples/multi-stack/lib/networking-stack.ts +69 -0
- package/examples/multi-stack/lib/storage-stack.ts +141 -0
- package/examples/multi-stack/package-lock.json +4437 -0
- package/examples/multi-stack/package.json +42 -0
- package/examples/multi-stack/tsconfig.json +34 -0
- package/examples/simple/base.json +8 -0
- package/examples/simple/target.json +14 -0
- package/examples/single-stack/.NVP +0 -0
- package/examples/single-stack/.cdk-cost-analyzer.yml +52 -0
- package/examples/single-stack/.gitlab-ci.yml +126 -0
- package/examples/single-stack/README.md +184 -0
- package/examples/single-stack/UeK +0 -0
- package/examples/single-stack/bin/app.ts +16 -0
- package/examples/single-stack/cdk.json +72 -0
- package/examples/single-stack/lib/infrastructure-stack.ts +119 -0
- package/examples/single-stack/package-lock.json +4443 -0
- package/examples/single-stack/package.json +38 -0
- package/examples/single-stack/tsconfig.json +34 -0
- package/package.json +139 -0
- package/test-cdk-project/README-COMPUTE.md +141 -0
- package/test-cdk-project/README.md +95 -0
- package/test-cdk-project/app-with-compute.js +102 -0
- package/test-cdk-project/app.js +81 -0
- package/test-cdk-project/cdk-compute.json +3 -0
- package/test-cdk-project/cdk.context.json +7 -0
- package/test-cdk-project/cdk.json +3 -0
- package/test-cdk-project/cdk.out/TestStack.assets.json +21 -0
- package/test-cdk-project/cdk.out/TestStack.template.json +115 -0
- package/test-cdk-project/cdk.out/cdk.out +1 -0
- package/test-cdk-project/cdk.out/manifest.json +503 -0
- package/test-cdk-project/cdk.out/tree.json +1 -0
- package/test-cdk-project/cdk.out.base/TestStack.assets.json +21 -0
- package/test-cdk-project/cdk.out.base/TestStack.template.json +115 -0
- package/test-cdk-project/cdk.out.base/cdk.out +1 -0
- package/test-cdk-project/cdk.out.base/manifest.json +503 -0
- package/test-cdk-project/cdk.out.base/tree.json +1 -0
- package/test-cdk-project/cdk.out.target/TestStack.assets.json +21 -0
- package/test-cdk-project/cdk.out.target/TestStack.template.json +183 -0
- package/test-cdk-project/cdk.out.target/cdk.out +1 -0
- package/test-cdk-project/cdk.out.target/manifest.json +521 -0
- package/test-cdk-project/cdk.out.target/tree.json +1 -0
- package/test-cdk-project/package-lock.json +422 -0
- package/test-cdk-project/package.json +17 -0
- package/tools/workflows/README.md +102 -0
- package/tools/workflows/validate-workflows.js +109 -0
- package/tools/workflows/workflow-utils.ts +181 -0
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Reporter = void 0;
|
|
4
|
+
class Reporter {
|
|
5
|
+
generateReport(costDelta, format, options) {
|
|
6
|
+
switch (format) {
|
|
7
|
+
case 'text':
|
|
8
|
+
return this.generateTextReport(costDelta, options);
|
|
9
|
+
case 'json':
|
|
10
|
+
return this.generateJsonReport(costDelta, options);
|
|
11
|
+
case 'markdown':
|
|
12
|
+
return this.generateMarkdownReport(costDelta, options);
|
|
13
|
+
default:
|
|
14
|
+
throw new Error(`Unsupported report format: ${format}`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
generateTextReport(costDelta, options) {
|
|
18
|
+
const lines = [];
|
|
19
|
+
lines.push('='.repeat(60));
|
|
20
|
+
lines.push('CDK Cost Analysis Report');
|
|
21
|
+
lines.push('='.repeat(60));
|
|
22
|
+
lines.push('');
|
|
23
|
+
// Add configuration summary if provided
|
|
24
|
+
if (options?.configSummary) {
|
|
25
|
+
lines.push(...this.formatConfigSummaryText(options.configSummary));
|
|
26
|
+
lines.push('');
|
|
27
|
+
}
|
|
28
|
+
// Add threshold status if provided
|
|
29
|
+
if (options?.thresholdStatus) {
|
|
30
|
+
lines.push(...this.formatThresholdStatusText(options.thresholdStatus));
|
|
31
|
+
lines.push('');
|
|
32
|
+
}
|
|
33
|
+
lines.push(`Total Cost Delta: ${this.formatDelta(costDelta.totalDelta, costDelta.currency)}`);
|
|
34
|
+
lines.push('');
|
|
35
|
+
if (costDelta.addedCosts.length > 0) {
|
|
36
|
+
lines.push('ADDED RESOURCES:');
|
|
37
|
+
lines.push('-'.repeat(60));
|
|
38
|
+
const sortedAdded = [...costDelta.addedCosts].sort((a, b) => b.monthlyCost.amount - a.monthlyCost.amount);
|
|
39
|
+
for (const resource of sortedAdded) {
|
|
40
|
+
lines.push(this.formatResourceLine(resource));
|
|
41
|
+
}
|
|
42
|
+
lines.push('');
|
|
43
|
+
}
|
|
44
|
+
if (costDelta.removedCosts.length > 0) {
|
|
45
|
+
lines.push('REMOVED RESOURCES:');
|
|
46
|
+
lines.push('-'.repeat(60));
|
|
47
|
+
const sortedRemoved = [...costDelta.removedCosts].sort((a, b) => b.monthlyCost.amount - a.monthlyCost.amount);
|
|
48
|
+
for (const resource of sortedRemoved) {
|
|
49
|
+
lines.push(this.formatResourceLine(resource));
|
|
50
|
+
}
|
|
51
|
+
lines.push('');
|
|
52
|
+
}
|
|
53
|
+
if (costDelta.modifiedCosts.length > 0) {
|
|
54
|
+
lines.push('MODIFIED RESOURCES:');
|
|
55
|
+
lines.push('-'.repeat(60));
|
|
56
|
+
const sortedModified = [...costDelta.modifiedCosts].sort((a, b) => Math.abs(b.costDelta) - Math.abs(a.costDelta));
|
|
57
|
+
for (const resource of sortedModified) {
|
|
58
|
+
lines.push(this.formatModifiedResourceLine(resource));
|
|
59
|
+
}
|
|
60
|
+
lines.push('');
|
|
61
|
+
}
|
|
62
|
+
if (costDelta.addedCosts.length === 0 &&
|
|
63
|
+
costDelta.removedCosts.length === 0 &&
|
|
64
|
+
costDelta.modifiedCosts.length === 0) {
|
|
65
|
+
lines.push('No resource changes detected.');
|
|
66
|
+
lines.push('');
|
|
67
|
+
}
|
|
68
|
+
lines.push('='.repeat(60));
|
|
69
|
+
return lines.join('\n');
|
|
70
|
+
}
|
|
71
|
+
generateJsonReport(costDelta, options) {
|
|
72
|
+
const report = {
|
|
73
|
+
...costDelta,
|
|
74
|
+
};
|
|
75
|
+
if (options?.configSummary) {
|
|
76
|
+
report.configSummary = options.configSummary;
|
|
77
|
+
}
|
|
78
|
+
if (options?.thresholdStatus) {
|
|
79
|
+
report.thresholdStatus = options.thresholdStatus;
|
|
80
|
+
}
|
|
81
|
+
if (options?.stackName) {
|
|
82
|
+
report.stackName = options.stackName;
|
|
83
|
+
}
|
|
84
|
+
return JSON.stringify(report, null, 2);
|
|
85
|
+
}
|
|
86
|
+
generateMarkdownReport(costDelta, options) {
|
|
87
|
+
const lines = [];
|
|
88
|
+
lines.push('# CDK Cost Analysis Report');
|
|
89
|
+
lines.push('');
|
|
90
|
+
// Add configuration summary if provided
|
|
91
|
+
if (options?.configSummary) {
|
|
92
|
+
lines.push(...this.formatConfigSummaryMarkdown(options.configSummary));
|
|
93
|
+
lines.push('');
|
|
94
|
+
}
|
|
95
|
+
// Add threshold status if provided
|
|
96
|
+
if (options?.thresholdStatus) {
|
|
97
|
+
lines.push(...this.formatThresholdStatusMarkdown(options.thresholdStatus, costDelta));
|
|
98
|
+
lines.push('');
|
|
99
|
+
}
|
|
100
|
+
// Show total cost delta
|
|
101
|
+
lines.push(`**Total Cost Delta:** ${this.formatDelta(costDelta.totalDelta, costDelta.currency)}`);
|
|
102
|
+
lines.push('');
|
|
103
|
+
// If multi-stack, show per-stack breakdowns
|
|
104
|
+
if (options?.multiStack && options?.stacks && options.stacks.length > 1) {
|
|
105
|
+
lines.push('## Per-Stack Cost Breakdown');
|
|
106
|
+
lines.push('');
|
|
107
|
+
lines.push('| Stack | Cost Delta |');
|
|
108
|
+
lines.push('|-------|------------|');
|
|
109
|
+
for (const stack of options.stacks) {
|
|
110
|
+
lines.push(`| ${stack.stackName} | ${this.formatDelta(stack.costDelta.totalDelta, stack.costDelta.currency)} |`);
|
|
111
|
+
}
|
|
112
|
+
lines.push('');
|
|
113
|
+
lines.push('<details>');
|
|
114
|
+
lines.push('<summary><strong>View Detailed Stack Breakdowns</strong></summary>');
|
|
115
|
+
lines.push('');
|
|
116
|
+
for (const stack of options.stacks) {
|
|
117
|
+
lines.push(`### ${stack.stackName}`);
|
|
118
|
+
lines.push('');
|
|
119
|
+
lines.push(...this.formatStackDetailsMarkdown(stack.costDelta));
|
|
120
|
+
lines.push('');
|
|
121
|
+
}
|
|
122
|
+
lines.push('</details>');
|
|
123
|
+
lines.push('');
|
|
124
|
+
}
|
|
125
|
+
if (costDelta.addedCosts.length > 0) {
|
|
126
|
+
lines.push('## Added Resources');
|
|
127
|
+
lines.push('');
|
|
128
|
+
lines.push('| Logical ID | Type | Monthly Cost |');
|
|
129
|
+
lines.push('|------------|------|--------------|');
|
|
130
|
+
const sortedAdded = [...costDelta.addedCosts].sort((a, b) => b.monthlyCost.amount - a.monthlyCost.amount);
|
|
131
|
+
for (const resource of sortedAdded) {
|
|
132
|
+
lines.push(`| ${resource.logicalId} | ${resource.type} | ${this.formatCurrency(resource.monthlyCost.amount, costDelta.currency)} |`);
|
|
133
|
+
}
|
|
134
|
+
lines.push('');
|
|
135
|
+
}
|
|
136
|
+
if (costDelta.removedCosts.length > 0) {
|
|
137
|
+
lines.push('## Removed Resources');
|
|
138
|
+
lines.push('');
|
|
139
|
+
lines.push('| Logical ID | Type | Monthly Cost |');
|
|
140
|
+
lines.push('|------------|------|--------------|');
|
|
141
|
+
const sortedRemoved = [...costDelta.removedCosts].sort((a, b) => b.monthlyCost.amount - a.monthlyCost.amount);
|
|
142
|
+
for (const resource of sortedRemoved) {
|
|
143
|
+
lines.push(`| ${resource.logicalId} | ${resource.type} | ${this.formatCurrency(resource.monthlyCost.amount, costDelta.currency)} |`);
|
|
144
|
+
}
|
|
145
|
+
lines.push('');
|
|
146
|
+
}
|
|
147
|
+
if (costDelta.modifiedCosts.length > 0) {
|
|
148
|
+
lines.push('## Modified Resources');
|
|
149
|
+
lines.push('');
|
|
150
|
+
lines.push('| Logical ID | Type | Old Cost | New Cost | Delta |');
|
|
151
|
+
lines.push('|------------|------|----------|----------|-------|');
|
|
152
|
+
const sortedModified = [...costDelta.modifiedCosts].sort((a, b) => Math.abs(b.costDelta) - Math.abs(a.costDelta));
|
|
153
|
+
for (const resource of sortedModified) {
|
|
154
|
+
lines.push(`| ${resource.logicalId} | ${resource.type} | ` +
|
|
155
|
+
`${this.formatCurrency(resource.oldMonthlyCost.amount, costDelta.currency)} | ` +
|
|
156
|
+
`${this.formatCurrency(resource.newMonthlyCost.amount, costDelta.currency)} | ` +
|
|
157
|
+
`${this.formatDelta(resource.costDelta, costDelta.currency)} |`);
|
|
158
|
+
}
|
|
159
|
+
lines.push('');
|
|
160
|
+
}
|
|
161
|
+
return lines.join('\n');
|
|
162
|
+
}
|
|
163
|
+
formatResourceLine(resource) {
|
|
164
|
+
const cost = this.formatCurrency(resource.monthlyCost.amount, 'USD');
|
|
165
|
+
const confidence = resource.monthlyCost.confidence;
|
|
166
|
+
return ` • ${resource.logicalId} (${resource.type}): ${cost} [${confidence}]`;
|
|
167
|
+
}
|
|
168
|
+
formatModifiedResourceLine(resource) {
|
|
169
|
+
const oldCost = this.formatCurrency(resource.oldMonthlyCost.amount, 'USD');
|
|
170
|
+
const newCost = this.formatCurrency(resource.newMonthlyCost.amount, 'USD');
|
|
171
|
+
const delta = this.formatDelta(resource.costDelta, 'USD');
|
|
172
|
+
return ` • ${resource.logicalId} (${resource.type}): ${oldCost} → ${newCost} (${delta})`;
|
|
173
|
+
}
|
|
174
|
+
formatCurrency(amount, currency) {
|
|
175
|
+
const symbol = currency === 'USD' ? '$' : currency;
|
|
176
|
+
return `${symbol}${amount.toFixed(2)}`;
|
|
177
|
+
}
|
|
178
|
+
formatDelta(amount, currency) {
|
|
179
|
+
const sign = amount > 0 ? '+' : amount < 0 ? '-' : '';
|
|
180
|
+
const absAmount = Math.abs(amount);
|
|
181
|
+
const formatted = this.formatCurrency(absAmount, currency);
|
|
182
|
+
return amount === 0 ? formatted : `${sign}${formatted}`;
|
|
183
|
+
}
|
|
184
|
+
formatConfigSummaryText(config) {
|
|
185
|
+
const lines = [];
|
|
186
|
+
lines.push('CONFIGURATION:');
|
|
187
|
+
lines.push('-'.repeat(60));
|
|
188
|
+
if (config.configPath) {
|
|
189
|
+
lines.push(` Configuration File: ${config.configPath}`);
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
lines.push(' Configuration File: Using defaults');
|
|
193
|
+
}
|
|
194
|
+
if (config.thresholds) {
|
|
195
|
+
if (config.thresholds.environment) {
|
|
196
|
+
lines.push(` Environment: ${config.thresholds.environment}`);
|
|
197
|
+
}
|
|
198
|
+
if (config.thresholds.warning !== undefined) {
|
|
199
|
+
lines.push(` Warning Threshold: $${config.thresholds.warning.toFixed(2)}/month`);
|
|
200
|
+
}
|
|
201
|
+
if (config.thresholds.error !== undefined) {
|
|
202
|
+
lines.push(` Error Threshold: $${config.thresholds.error.toFixed(2)}/month`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (config.excludedResourceTypes &&
|
|
206
|
+
config.excludedResourceTypes.length > 0) {
|
|
207
|
+
lines.push(` Excluded Resource Types: ${config.excludedResourceTypes.join(', ')}`);
|
|
208
|
+
}
|
|
209
|
+
if (config.usageAssumptions &&
|
|
210
|
+
Object.keys(config.usageAssumptions).length > 0) {
|
|
211
|
+
lines.push(' Custom Usage Assumptions:');
|
|
212
|
+
for (const [resourceType, assumptions] of Object.entries(config.usageAssumptions)) {
|
|
213
|
+
lines.push(` - ${resourceType}: ${JSON.stringify(assumptions)}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return lines;
|
|
217
|
+
}
|
|
218
|
+
formatThresholdStatusText(threshold) {
|
|
219
|
+
const lines = [];
|
|
220
|
+
lines.push('THRESHOLD STATUS:');
|
|
221
|
+
lines.push('-'.repeat(60));
|
|
222
|
+
if (threshold.level === 'none') {
|
|
223
|
+
lines.push(' No thresholds configured');
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
const status = threshold.passed ? 'PASSED' : 'EXCEEDED';
|
|
227
|
+
lines.push(` Status: ${status}`);
|
|
228
|
+
if (threshold.threshold !== undefined) {
|
|
229
|
+
lines.push(` Threshold: $${threshold.threshold.toFixed(2)}/month (${threshold.level})`);
|
|
230
|
+
}
|
|
231
|
+
lines.push(` Actual Delta: $${Math.abs(threshold.delta).toFixed(2)}/month`);
|
|
232
|
+
if (!threshold.passed &&
|
|
233
|
+
threshold.recommendations &&
|
|
234
|
+
threshold.recommendations.length > 0) {
|
|
235
|
+
lines.push(' Recommendations:');
|
|
236
|
+
for (const rec of threshold.recommendations) {
|
|
237
|
+
lines.push(` - ${rec}`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return lines;
|
|
242
|
+
}
|
|
243
|
+
formatConfigSummaryMarkdown(config) {
|
|
244
|
+
const lines = [];
|
|
245
|
+
lines.push('<details>');
|
|
246
|
+
lines.push('<summary><strong>Configuration Summary</strong></summary>');
|
|
247
|
+
lines.push('');
|
|
248
|
+
if (config.configPath) {
|
|
249
|
+
lines.push(`**Configuration File:** \`${config.configPath}\``);
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
lines.push('**Configuration File:** Using defaults');
|
|
253
|
+
}
|
|
254
|
+
lines.push('');
|
|
255
|
+
if (config.thresholds) {
|
|
256
|
+
lines.push('**Thresholds:**');
|
|
257
|
+
if (config.thresholds.environment) {
|
|
258
|
+
lines.push(`- Environment: ${config.thresholds.environment}`);
|
|
259
|
+
}
|
|
260
|
+
if (config.thresholds.warning !== undefined) {
|
|
261
|
+
lines.push(`- Warning: $${config.thresholds.warning.toFixed(2)}/month`);
|
|
262
|
+
}
|
|
263
|
+
if (config.thresholds.error !== undefined) {
|
|
264
|
+
lines.push(`- Error: $${config.thresholds.error.toFixed(2)}/month`);
|
|
265
|
+
}
|
|
266
|
+
lines.push('');
|
|
267
|
+
}
|
|
268
|
+
if (config.excludedResourceTypes &&
|
|
269
|
+
config.excludedResourceTypes.length > 0) {
|
|
270
|
+
lines.push('**Excluded Resource Types:**');
|
|
271
|
+
for (const type of config.excludedResourceTypes) {
|
|
272
|
+
lines.push(`- \`${type}\``);
|
|
273
|
+
}
|
|
274
|
+
lines.push('');
|
|
275
|
+
}
|
|
276
|
+
if (config.usageAssumptions &&
|
|
277
|
+
Object.keys(config.usageAssumptions).length > 0) {
|
|
278
|
+
lines.push('**Custom Usage Assumptions:**');
|
|
279
|
+
for (const [resourceType, assumptions] of Object.entries(config.usageAssumptions)) {
|
|
280
|
+
lines.push(`- **${resourceType}:**`);
|
|
281
|
+
const assumptionObj = assumptions;
|
|
282
|
+
for (const [key, value] of Object.entries(assumptionObj)) {
|
|
283
|
+
lines.push(` - ${key}: ${value}`);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
lines.push('');
|
|
287
|
+
}
|
|
288
|
+
lines.push('</details>');
|
|
289
|
+
lines.push('');
|
|
290
|
+
return lines;
|
|
291
|
+
}
|
|
292
|
+
formatThresholdStatusMarkdown(threshold, costDelta) {
|
|
293
|
+
const lines = [];
|
|
294
|
+
if (threshold.level === 'none') {
|
|
295
|
+
return lines;
|
|
296
|
+
}
|
|
297
|
+
const passed = threshold.passed;
|
|
298
|
+
const status = passed ? 'PASSED' : 'EXCEEDED';
|
|
299
|
+
lines.push(`## Threshold Status: ${status}`);
|
|
300
|
+
lines.push('');
|
|
301
|
+
if (threshold.threshold !== undefined) {
|
|
302
|
+
lines.push(`**Threshold:** $${threshold.threshold.toFixed(2)}/month (${threshold.level})`);
|
|
303
|
+
}
|
|
304
|
+
lines.push(`**Actual Delta:** ${this.formatDelta(threshold.delta, costDelta.currency)}/month`);
|
|
305
|
+
lines.push('');
|
|
306
|
+
if (!passed) {
|
|
307
|
+
lines.push('### Action Required');
|
|
308
|
+
lines.push('');
|
|
309
|
+
lines.push(threshold.message);
|
|
310
|
+
lines.push('');
|
|
311
|
+
if (threshold.recommendations && threshold.recommendations.length > 0) {
|
|
312
|
+
lines.push('### Recommendations');
|
|
313
|
+
lines.push('');
|
|
314
|
+
for (const rec of threshold.recommendations) {
|
|
315
|
+
lines.push(`- ${rec}`);
|
|
316
|
+
}
|
|
317
|
+
lines.push('');
|
|
318
|
+
}
|
|
319
|
+
// Show top cost contributors
|
|
320
|
+
const topContributors = this.getTopCostContributors(costDelta, 5);
|
|
321
|
+
if (topContributors.length > 0) {
|
|
322
|
+
lines.push('### Top Cost Contributors');
|
|
323
|
+
lines.push('');
|
|
324
|
+
lines.push('| Resource | Type | Impact |');
|
|
325
|
+
lines.push('|----------|------|--------|');
|
|
326
|
+
for (const contributor of topContributors) {
|
|
327
|
+
lines.push(`| ${contributor.logicalId} | ${contributor.type} | ${this.formatDelta(contributor.impact, costDelta.currency)} |`);
|
|
328
|
+
}
|
|
329
|
+
lines.push('');
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return lines;
|
|
333
|
+
}
|
|
334
|
+
getTopCostContributors(costDelta, limit) {
|
|
335
|
+
const contributors = [];
|
|
336
|
+
// Add added resources
|
|
337
|
+
for (const resource of costDelta.addedCosts) {
|
|
338
|
+
contributors.push({
|
|
339
|
+
logicalId: resource.logicalId,
|
|
340
|
+
type: resource.type,
|
|
341
|
+
impact: resource.monthlyCost.amount,
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
// Add removed resources (negative impact)
|
|
345
|
+
for (const resource of costDelta.removedCosts) {
|
|
346
|
+
contributors.push({
|
|
347
|
+
logicalId: resource.logicalId,
|
|
348
|
+
type: resource.type,
|
|
349
|
+
impact: -resource.monthlyCost.amount,
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
// Add modified resources
|
|
353
|
+
for (const resource of costDelta.modifiedCosts) {
|
|
354
|
+
contributors.push({
|
|
355
|
+
logicalId: resource.logicalId,
|
|
356
|
+
type: resource.type,
|
|
357
|
+
impact: resource.costDelta,
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
// Sort by absolute impact (descending)
|
|
361
|
+
contributors.sort((a, b) => Math.abs(b.impact) - Math.abs(a.impact));
|
|
362
|
+
return contributors.slice(0, limit);
|
|
363
|
+
}
|
|
364
|
+
formatStackDetailsMarkdown(costDelta) {
|
|
365
|
+
const lines = [];
|
|
366
|
+
if (costDelta.addedCosts.length > 0) {
|
|
367
|
+
lines.push('**Added Resources:**');
|
|
368
|
+
lines.push('');
|
|
369
|
+
lines.push('| Logical ID | Type | Monthly Cost |');
|
|
370
|
+
lines.push('|------------|------|--------------|');
|
|
371
|
+
const sortedAdded = [...costDelta.addedCosts].sort((a, b) => b.monthlyCost.amount - a.monthlyCost.amount);
|
|
372
|
+
for (const resource of sortedAdded) {
|
|
373
|
+
lines.push(`| ${resource.logicalId} | ${resource.type} | ${this.formatCurrency(resource.monthlyCost.amount, costDelta.currency)} |`);
|
|
374
|
+
}
|
|
375
|
+
lines.push('');
|
|
376
|
+
}
|
|
377
|
+
if (costDelta.removedCosts.length > 0) {
|
|
378
|
+
lines.push('**Removed Resources:**');
|
|
379
|
+
lines.push('');
|
|
380
|
+
lines.push('| Logical ID | Type | Monthly Cost |');
|
|
381
|
+
lines.push('|------------|------|--------------|');
|
|
382
|
+
const sortedRemoved = [...costDelta.removedCosts].sort((a, b) => b.monthlyCost.amount - a.monthlyCost.amount);
|
|
383
|
+
for (const resource of sortedRemoved) {
|
|
384
|
+
lines.push(`| ${resource.logicalId} | ${resource.type} | ${this.formatCurrency(resource.monthlyCost.amount, costDelta.currency)} |`);
|
|
385
|
+
}
|
|
386
|
+
lines.push('');
|
|
387
|
+
}
|
|
388
|
+
if (costDelta.modifiedCosts.length > 0) {
|
|
389
|
+
lines.push('**Modified Resources:**');
|
|
390
|
+
lines.push('');
|
|
391
|
+
lines.push('| Logical ID | Type | Old Cost | New Cost | Delta |');
|
|
392
|
+
lines.push('|------------|------|----------|----------|-------|');
|
|
393
|
+
const sortedModified = [...costDelta.modifiedCosts].sort((a, b) => Math.abs(b.costDelta) - Math.abs(a.costDelta));
|
|
394
|
+
for (const resource of sortedModified) {
|
|
395
|
+
lines.push(`| ${resource.logicalId} | ${resource.type} | ` +
|
|
396
|
+
`${this.formatCurrency(resource.oldMonthlyCost.amount, costDelta.currency)} | ` +
|
|
397
|
+
`${this.formatCurrency(resource.newMonthlyCost.amount, costDelta.currency)} | ` +
|
|
398
|
+
`${this.formatDelta(resource.costDelta, costDelta.currency)} |`);
|
|
399
|
+
}
|
|
400
|
+
lines.push('');
|
|
401
|
+
}
|
|
402
|
+
if (costDelta.addedCosts.length === 0 &&
|
|
403
|
+
costDelta.removedCosts.length === 0 &&
|
|
404
|
+
costDelta.modifiedCosts.length === 0) {
|
|
405
|
+
lines.push('No resource changes detected.');
|
|
406
|
+
lines.push('');
|
|
407
|
+
}
|
|
408
|
+
return lines;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
exports.Reporter = Reporter;
|
|
412
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUmVwb3J0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcmVwb3J0ZXIvUmVwb3J0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBT0EsTUFBYSxRQUFRO0lBQ25CLGNBQWMsQ0FDWixTQUFvQixFQUNwQixNQUFvQixFQUNwQixPQUF1QjtRQUV2QixRQUFRLE1BQU0sRUFBRSxDQUFDO1lBQ2YsS0FBSyxNQUFNO2dCQUNULE9BQU8sSUFBSSxDQUFDLGtCQUFrQixDQUFDLFNBQVMsRUFBRSxPQUFPLENBQUMsQ0FBQztZQUNyRCxLQUFLLE1BQU07Z0JBQ1QsT0FBTyxJQUFJLENBQUMsa0JBQWtCLENBQUMsU0FBUyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1lBQ3JELEtBQUssVUFBVTtnQkFDYixPQUFPLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxTQUFTLEVBQUUsT0FBTyxDQUFDLENBQUM7WUFDekQ7Z0JBQ0UsTUFBTSxJQUFJLEtBQUssQ0FBQyw4QkFBOEIsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUM1RCxDQUFDO0lBQ0gsQ0FBQztJQUVPLGtCQUFrQixDQUN4QixTQUFvQixFQUNwQixPQUF1QjtRQUV2QixNQUFNLEtBQUssR0FBYSxFQUFFLENBQUM7UUFFM0IsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDM0IsS0FBSyxDQUFDLElBQUksQ0FBQywwQkFBMEIsQ0FBQyxDQUFDO1FBQ3ZDLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQzNCLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7UUFFZix3Q0FBd0M7UUFDeEMsSUFBSSxPQUFPLEVBQUUsYUFBYSxFQUFFLENBQUM7WUFDM0IsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxPQUFPLENB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Q0osQ0FBQztZQUNELEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDakIsQ0FBQztRQUVELElBQ0UsU0FBUyxDQUFDLFVBQVUsQ0FBQyxNQUFNLEtBQUssQ0FBQztZQUNqQyxTQUFTLENBQUMsWUFBWSxDQUFDLE1BQU0sS0FBSyxDQUFDO1lBQ25DLFNBQVMsQ0FBQyxhQUFhLENBQUMsTUFBTSxLQUFLLENBQUMsRUFDcEMsQ0FBQztZQUNELEtBQUssQ0FBQyxJQUFJLENBQUMsK0JBQStCLENBQUMsQ0FBQztZQUM1QyxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ2pCLENBQUM7UUFFRCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7Q0FDRjtBQTlrQkQsNEJBOGtCQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFJlcG9ydGVyIGFzIElSZXBvcnRlciwgUmVwb3J0Rm9ybWF0LCBSZXBvcnRPcHRpb25zIH0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQge1xuICBDb3N0RGVsdGEsXG4gIFJlc291cmNlQ29zdCxcbiAgTW9kaWZpZWRSZXNvdXJjZUNvc3QsXG59IGZyb20gJy4uL3ByaWNpbmcvdHlwZXMnO1xuXG5leHBvcnQgY2xhc3MgUmVwb3J0ZXIgaW1wbGVtZW50cyBJUmVwb3J0ZXIge1xuICBnZW5lcmF0ZVJlcG9ydChcbiAgICBjb3N0RGVsdGE6IENvc3REZWx0YSxcbiAgICBmb3JtYXQ6IFJlcG9ydEZvcm1hdCxcbiAgICBvcHRpb25zPzogUmVwb3J0T3B0aW9ucyxcbiAgKTogc3RyaW5nIHtcbiAgICBzd2l0Y2ggKGZvcm1hdCkge1xuICAgICAgY2FzZSAndGV4dCc6XG4gICAgICAgIHJldHVybiB0aGlzLmdlbmVyYXRlVGV4dFJlcG9ydChjb3N0RGVsdGEsIG9wdGlvbnMpO1xuICAgICAgY2FzZSAnanNvbic6XG4gICAgICAgIHJldHVybiB0aGlzLmdlbmVyYXRlSnNvblJlcG9ydChjb3N0RGVsdGEsIG9wdGlvbnMpO1xuICAgICAgY2FzZSAnbWFya2Rvd24nOlxuICAgICAgICByZXR1cm4gdGhpcy5nZW5lcmF0ZU1hcmtkb3duUmVwb3J0KGNvc3REZWx0YSwgb3B0aW9ucyk7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVuc3VwcG9ydGVkIHJlcG9ydCBmb3JtYXQ6ICR7Zm9ybWF0fWApO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZ2VuZXJhdGVUZXh0UmVwb3J0KFxuICAgIGNvc3REZWx0YTogQ29zdERlbHRhLFxuICAgIG9wdGlvbnM/OiBSZXBvcnRPcHRpb25zLFxuICApOiBzdHJpbmcge1xuICAgIGNvbnN0IGxpbmVzOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgbGluZXMucHVzaCgnPScucmVwZWF0KDYwKSk7XG4gICAgbGluZXMucHVzaCgnQ0RLIENvc3QgQW5hbHlzaXMgUmVwb3J0Jyk7XG4gICAgbGluZXMucHVzaCgnPScucmVwZWF0KDYwKSk7XG4gICAgbGluZXMucHVzaCgnJyk7XG5cbiAgICAvLyBBZGQgY29uZmlndXJhdGlvbiBzdW1tYXJ5IGlmIHByb3ZpZGVkXG4gICAgaWYgKG9wdGlvbnM/LmNvbmZpZ1N1bW1hcnkpIHtcbiAgICAgIGxpbmVzLnB1c2goLi4udGhpcy5mb3JtYXRDb25maWdTdW1tYXJ5VGV4dChvcHRpb25zLmNvbmZpZ1N1bW1hcnkpKTtcbiAgICAgIGxpbmVzLnB1c2goJycpO1xuICAgIH1cblxuICAgIC8vIEFkZCB0aHJlc2hvbGQgc3RhdHVzIGlmIHByb3ZpZGVkXG4gICAgaWYgKG9wdGlvbnM/LnRocmVzaG9sZFN0YXR1cykge1xuICAgICAgbGluZXMucHVzaCguLi50aGlzLmZvcm1hdFRocmVzaG9sZFN0YXR1c1RleHQob3B0aW9ucy50aHJlc2hvbGRTdGF0dXMpKTtcbiAgICAgIGxpbmVzLnB1c2goJycpO1xuICAgIH1cblxuICAgIGxpbmVzLnB1c2goXG4gICAgICBgVG90YWwgQ29zdCBEZWx0YTogJHt0aGlzLmZvcm1hdERlbHRhKGNvc3REZWx0YS50b3RhbERlbHRhLCBjb3N0RGVsdGEuY3VycmVuY3kpfWAsXG4gICAgKTtcbiAgICBsaW5lcy5wdXNoKCcnKTtcblxuICAgIGlmIChjb3N0RGVsdGEuYWRkZWRDb3N0cy5sZW5ndGggPiAwKSB7XG4gICAgICBsaW5lcy5wdXNoKCdBRERFRCBSRVNPVVJDRVM6Jyk7XG4gICAgICBsaW5lcy5wdXNoKCctJy5yZXBlYXQoNjApKTtcblxuICAgICAgY29uc3Qgc29ydGVkQWRkZWQgPSBbLi4uY29zdERlbHRhLmFkZGVkQ29zdHNdLnNvcnQoXG4gICAgICAgIChhLCBiKSA9PiBiLm1vbnRobHlDb3N0LmFtb3VudCAtIGEubW9udGhseUNvc3QuYW1vdW50LFxuICAgICAgKTtcblxuICAgICAgZm9yIChjb25zdCByZXNvdXJjZSBvZiBzb3J0ZWRBZGRlZCkge1xuICAgICAgICBsaW5lcy5wdXNoKHRoaXMuZm9ybWF0UmVzb3VyY2VMaW5lKHJlc291cmNlKSk7XG4gICAgICB9XG4gICAgICBsaW5lcy5wdXNoKCcnKTtcbiAgICB9XG5cbiAgICBpZiAoY29zdERlbHRhLnJlbW92ZWRDb3N0cy5sZW5ndGggPiAwKSB7XG4gICAgICBsaW5lcy5wdXNoKCdSRU1PVkVEIFJFU09VUkNFUzonKTtcbiAgICAgIGxpbmVzLnB1c2goJy0nLnJlcGVhdCg2MCkpO1xuXG4gICAgICBjb25zdCBzb3J0ZWRSZW1vdmVkID0gWy4uLmNvc3REZWx0YS5yZW1vdmVkQ29zdHNdLnNvcnQoXG4gICAgICAgIChhLCBiKSA9PiBiLm1vbnRobHlDb3N0LmFtb3VudCAtIGEubW9udGhseUNvc3QuYW1vdW50LFxuICAgICAgKTtcblxuICAgICAgZm9yIChjb25zdCByZXNvdXJjZSBvZiBzb3J0ZWRSZW1vdmVkKSB7XG4gICAgICAgIGxpbmVzLnB1c2godGhpcy5mb3JtYXRSZXNvdXJjZUxpbmUocmVzb3VyY2UpKTtcbiAgICAgIH1cbiAgICAgIGxpbmVzLnB1c2goJycpO1xuICAgIH1cblxuICAgIGlmIChjb3N0RGVsdGEubW9kaWZpZWRDb3N0cy5sZW5ndGggPiAwKSB7XG4gICAgICBsaW5lcy5wdXNoKCdNT0RJRklFRCBSRVNPVVJDRVM6Jyk7XG4gICAgICBsaW5lcy5wdXNoKCctJy5yZXBlYXQoNjApKTtcblxuICAgICAgY29uc3Qgc29ydGVkTW9kaWZpZWQgPSBbLi4uY29zdERlbHRhLm1vZGlmaWVkQ29zdHNdLnNvcnQoXG4gICAgICAgIChhLCBiKSA9PiBNYXRoLmFicyhiLmNvc3REZWx0YSkgLSBNYXRoLmFicyhhLmNvc3REZWx0YSksXG4gICAgICApO1xuXG4gICAgICBmb3IgKGNvbnN0IHJlc291cmNlIG9mIHNvcnRlZE1vZGlmaWVkKSB7XG4gICAgICAgIGxpbmVzLnB1c2godGhpcy5mb3JtYXRNb2RpZmllZFJlc291cmNlTGluZShyZXNvdXJjZSkpO1xuICAgICAgfVxuICAgICAgbGluZXMucHVzaCgnJyk7XG4gICAgfVxuXG4gICAgaWYgKFxuICAgICAgY29zdERlbHRhLmFkZGVkQ29zdHMubGVuZ3RoID09PSAwICYmXG4gICAgICBjb3N0RGVsdGEucmVtb3ZlZENvc3RzLmxlbmd0aCA9PT0gMCAmJlxuICAgICAgY29zdERlbHRhLm1vZGlmaWVkQ29zdHMubGVuZ3RoID09PSAwXG4gICAgKSB7XG4gICAgICBsaW5lcy5wdXNoKCdObyByZXNvdXJjZSBjaGFuZ2VzIGRldGVjdGVkLicpO1xuICAgICAgbGluZXMucHVzaCgnJyk7XG4gICAgfVxuXG4gICAgbGluZXMucHVzaCgnPScucmVwZWF0KDYwKSk7XG5cbiAgICByZXR1cm4gbGluZXMuam9pbignXFxuJyk7XG4gIH1cblxuICBwcml2YXRlIGdlbmVyYXRlSnNvblJlcG9ydChcbiAgICBjb3N0RGVsdGE6IENvc3REZWx0YSxcbiAgICBvcHRpb25zPzogUmVwb3J0T3B0aW9ucyxcbiAgKTogc3RyaW5nIHtcbiAgICBjb25zdCByZXBvcnQ6IGFueSA9IHtcbiAgICAgIC4uLmNvc3REZWx0YSxcbiAgICB9O1xuXG4gICAgaWYgKG9wdGlvbnM/LmNvbmZpZ1N1bW1hcnkpIHtcbiAgICAgIHJlcG9ydC5jb25maWdTdW1tYXJ5ID0gb3B0aW9ucy5jb25maWdTdW1tYXJ5O1xuICAgIH1cblxuICAgIGlmIChvcHRpb25zPy50aHJlc2hvbGRTdGF0dXMpIHtcbiAgICAgIHJlcG9ydC50aHJlc2hvbGRTdGF0dXMgPSBvcHRpb25zLnRocmVzaG9sZFN0YXR1cztcbiAgICB9XG5cbiAgICBpZiAob3B0aW9ucz8uc3RhY2tOYW1lKSB7XG4gICAgICByZXBvcnQuc3RhY2tOYW1lID0gb3B0aW9ucy5zdGFja05hbWU7XG4gICAgfVxuXG4gICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHJlcG9ydCwgbnVsbCwgMik7XG4gIH1cblxuICBwcml2YXRlIGdlbmVyYXRlTWFya2Rvd25SZXBvcnQoXG4gICAgY29zdERlbHRhOiBDb3N0RGVsdGEsXG4gICAgb3B0aW9ucz86IFJlcG9ydE9wdGlvbnMsXG4gICk6IHN0cmluZyB7XG4gICAgY29uc3QgbGluZXM6IHN0cmluZ1tdID0gW107XG5cbiAgICBsaW5lcy5wdXNoKCcjIENESyBDb3N0IEFuYWx5c2lzIFJlcG9ydCcpO1xuICAgIGxpbmVzLnB1c2goJycpO1xuXG4gICAgLy8gQWRkIGNvbmZpZ3VyYXRpb24gc3VtbWFyeSBpZiBwcm92aWRlZFxuICAgIGlmIChvcHRpb25zPy5jb25maWdTdW1tYXJ5KSB7XG4gICAgICBsaW5lcy5wdXNoKC4uLnRoaXMuZm9ybWF0Q29uZmlnU3VtbWFyeU1hcmtkb3duKG9wdGlvbnMuY29uZmlnU3VtbWFyeSkpO1xuICAgICAgbGluZXMucHVzaCgnJyk7XG4gICAgfVxuXG4gICAgLy8gQWRkIHRocmVzaG9sZCBzdGF0dXMgaWYgcHJvdmlkZWRcbiAgICBpZiAob3B0aW9ucz8udGhyZXNob2xkU3RhdHVzKSB7XG4gICAgICBsaW5lcy5wdXNoKFxuICAgICAgICAuLi50aGlzLmZvcm1hdFRocmVzaG9sZFN0YXR1c01hcmtkb3duKFxuICAgICAgICAgIG9wdGlvbnMudGhyZXNob2xkU3RhdHVzLFxuICAgICAgICAgIGNvc3REZWx0YSxcbiAgICAgICAgKSxcbiAgICAgICk7XG4gICAgICBsaW5lcy5wdXNoKCcnKTtcbiAgICB9XG5cbiAgICAvLyBTaG93IHRvdGFsIGNvc3QgZGVsdGFcbiAgICBsaW5lcy5wdXNoKFxuICAgICAgYCoqVG90YWwgQ29zdCBEZWx0YToqKiAke3RoaXMuZm9ybWF0RGVsdGEoY29zdERlbHRhLnRvdGFsRGVsdGEsIGNvc3REZWx0YS5jdXJyZW5jeSl9YCxcbiAgICApO1xuICAgIGxpbmVzLnB1c2goJycpO1xuXG4gICAgLy8gSWYgbXVsdGktc3RhY2ssIHNob3cgcGVyLXN0YWNrIGJyZWFrZG93bnNcbiAgICBpZiAob3B0aW9ucz8ubXVsdGlTdGFjayAmJiBvcHRpb25zPy5zdGFja3MgJiYgb3B0aW9ucy5zdGFja3MubGVuZ3RoID4gMSkge1xuICAgICAgbGluZXMucHVzaCgnIyMgUGVyLVN0YWNrIENvc3QgQnJlYWtkb3duJyk7XG4gICAgICBsaW5lcy5wdXNoKCcnKTtcbiAgICAgIGxpbmVzLnB1c2goJ3wgU3RhY2sgfCBDb3N0IERlbHRhIHwnKTtcbiAgICAgIGxpbmVzLnB1c2goJ3wtLS0tLS0tfC0tLS0tLS0tLS0tLXwnKTtcbiAgICAgIGZvciAoY29uc3Qgc3RhY2sgb2Ygb3B0aW9ucy5zdGFja3MpIHtcbiAgICAgICAgbGluZXMucHVzaChcbiAgICAgICAgICBgfCAke3N0YWNrLnN0YWNrTmFtZX0gfCAke3RoaXMuZm9ybWF0RGVsdGEoc3RhY2suY29zdERlbHRhLnRvdGFsRGVsdGEsIHN0YWNrLmNvc3REZWx0YS5jdXJyZW5jeSl9IHxgLFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgbGluZXMucHVzaCgnJyk7XG4gICAgICBsaW5lcy5wdXNoKCc8ZGV0YWlscz4nKTtcbiAgICAgIGxpbmVzLnB1c2goXG4gICAgICAgICc8c3VtbWFyeT48c3Ryb25nPlZpZXcgRGV0YWlsZWQgU3RhY2sgQnJlYWtkb3duczwvc3Ryb25nPjwvc3VtbWFyeT4nLFxuICAgICAgKTtcbiAgICAgIGxpbmVzLnB1c2goJycpO1xuICAgICAgZm9yIChjb25zdCBzdGFjayBvZiBvcHRpb25zLnN0YWNrcykge1xuICAgICAgICBsaW5lcy5wdXNoKGAjIyMgJHtzdGFjay5zdGFja05hbWV9YCk7XG4gICAgICAgIGxpbmVzLnB1c2goJycpO1xuICAgICAgICBsaW5lcy5wdXNoKC4uLnRoaXMuZm9ybWF0U3RhY2tEZXRhaWxzTWFya2Rvd24oc3RhY2suY29zdERlbHRhKSk7XG4gICAgICAgIGxpbmVzLnB1c2goJycpO1xuICAgICAgfVxuICAgICAgbGluZXMucHVzaCgnPC9kZXRhaWxzPicpO1xuICAgICAgbGluZXMucHVzaCgnJyk7XG4gICAgfVxuXG4gICAgaWYgKGNvc3REZWx0YS5hZGRlZENvc3RzLmxlbmd0aCA+IDApIHtcbiAgICAgIGxpbmVzLnB1c2goJyMjIEFkZGVkIFJlc291cmNlcycpO1xuICAgICAgbGluZXMucHVzaCgnJyk7XG4gICAgICBsaW5lcy5wdXNoKCd8IExvZ2ljYWwgSUQgfCBUeXBlIHwgTW9udGhseSBDb3N0IHwnKTtcbiAgICAgIGxpbmVzLnB1c2goJ3wtLS0tLS0tLS0tLS18LS0tLS0tfC0tLS0tLS0tLS0tLS0tfCcpO1xuXG4gICAgICBjb25zdCBzb3J0ZWRBZGRlZCA9IFsuLi5jb3N0RGVsdGEuYWRkZWRDb3N0c10uc29ydChcbiAgICAgICAgKGEsIGIpID0+IGIubW9udGhseUNvc3QuYW1vdW50IC0gYS5tb250aGx5Q29zdC5hbW91bnQsXG4gICAgICApO1xuXG4gICAgICBmb3IgKGNvbnN0IHJlc291cmNlIG9mIHNvcnRlZEFkZGVkKSB7XG4gICAgICAgIGxpbmVzLnB1c2goXG4gICAgICAgICAgYHwgJHtyZXNvdXJjZS5sb2dpY2FsSWR9IHwgJHtyZXNvdXJjZS50eXBlfSB8ICR7dGhpcy5mb3JtYXRDdXJyZW5jeShyZXNvdXJjZS5tb250aGx5Q29zdC5hbW91bnQsIGNvc3REZWx0YS5jdXJyZW5jeSl9IHxgLFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgbGluZXMucHVzaCgnJyk7XG4gICAgfVxuXG4gICAgaWYgKGNvc3REZWx0YS5yZW1vdmVkQ29zdHMubGVuZ3RoID4gMCkge1xuICAgICAgbGluZXMucHVzaCgnIyMgUmVtb3ZlZCBSZXNvdXJjZXMnKTtcbiAgICAgIGxpbmVzLnB1c2goJycpO1xuICAgICAgbGluZXMucHVzaCgnfCBMb2dpY2FsIElEIHwgVHlwZSB8IE1vbnRobHkgQ29zdCB8Jyk7XG4gICAgICBsaW5lcy5wdXNoKCd8LS0tLS0tLS0tLS0tfC0tLS0tLXwtLS0tLS0tLS0tLS0tLXwnKTtcblxuICAgICAgY29uc3Qgc29ydGVkUmVtb3ZlZCA9IFsuLi5jb3N0RGVsdGEucmVtb3ZlZENvc3RzXS5zb3J0KFxuICAgICAgICAoYSwgYikgPT4gYi5tb250aGx5Q29zdC5hbW91bnQgLSBhLm1vbnRobHlDb3N0LmFtb3VudCxcbiAgICAgICk7XG5cbiAgICAgIGZvciAoY29uc3QgcmVzb3VyY2Ugb2Ygc29ydGVkUmVtb3ZlZCkge1xuICAgICAgICBsaW5lcy5wdXNoKFxuICAgICAgICAgIGB8ICR7cmVzb3VyY2UubG9naWNhbElkfSB8ICR7cmVzb3VyY2UudHlwZX0gfCAke3RoaXMuZm9ybWF0Q3VycmVuY3kocmVzb3VyY2UubW9udGhseUNvc3QuYW1vdW50LCBjb3N0RGVsdGEuY3VycmVuY3kpfSB8YCxcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIGxpbmVzLnB1c2goJycpO1xuICAgIH1cblxuICAgIGlmIChjb3N0RGVsdGEubW9kaWZpZWRDb3N0cy5sZW5ndGggPiAwKSB7XG4gICAgICBsaW5lcy5wdXNoKCcjIyBNb2RpZmllZCBSZXNvdXJjZXMnKTtcbiAgICAgIGxpbmVzLnB1c2goJycpO1xuICAgICAgbGluZXMucHVzaCgnfCBMb2dpY2FsIElEIHwgVHlwZSB8IE9sZCBDb3N0IHwgTmV3IENvc3QgfCBEZWx0YSB8Jyk7XG4gICAgICBsaW5lcy5wdXNoKCd8LS0tLS0tLS0tLS0tfC0tLS0tLXwtLS0tLS0tLS0tfC0tLS0tLS0tLS18LS0tLS0tLXwnKTtcblxuICAgICAgY29uc3Qgc29ydGVkTW9kaWZpZWQgPSBbLi4uY29zdERlbHRhLm1vZGlmaWVkQ29zdHNdLnNvcnQoXG4gICAgICAgIChhLCBiKSA9PiBNYXRoLmFicyhiLmNvc3REZWx0YSkgLSBNYXRoLmFicyhhLmNvc3REZWx0YSksXG4gICAgICApO1xuXG4gICAgICBmb3IgKGNvbnN0IHJlc291cmNlIG9mIHNvcnRlZE1vZGlmaWVkKSB7XG4gICAgICAgIGxpbmVzLnB1c2goXG4gICAgICAgICAgYHwgJHtyZXNvdXJjZS5sb2dpY2FsSWR9IHwgJHtyZXNvdXJjZS50eXBlfSB8IGAgK1xuICAgICAgICAgICAgYCR7dGhpcy5mb3JtYXRDdXJyZW5jeShyZXNvdXJjZS5vbGRNb250aGx5Q29zdC5hbW91bnQsIGNvc3REZWx0YS5jdXJyZW5jeSl9IHwgYCArXG4gICAgICAgICAgICBgJHt0aGlzLmZvcm1hdEN1cnJlbmN5KHJlc291cmNlLm5ld01vbnRobHlDb3N0LmFtb3VudCwgY29zdERlbHRhLmN1cnJlbmN5KX0gfCBgICtcbiAgICAgICAgICAgIGAke3RoaXMuZm9ybWF0RGVsdGEocmVzb3VyY2UuY29zdERlbHRhLCBjb3N0RGVsdGEuY3VycmVuY3kpfSB8YCxcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIGxpbmVzLnB1c2goJycpO1xuICAgIH1cblxuICAgIHJldHVybiBsaW5lcy5qb2luKCdcXG4nKTtcbiAgfVxuXG4gIHByaXZhdGUgZm9ybWF0UmVzb3VyY2VMaW5lKHJlc291cmNlOiBSZXNvdXJjZUNvc3QpOiBzdHJpbmcge1xuICAgIGNvbnN0IGNvc3QgPSB0aGlzLmZvcm1hdEN1cnJlbmN5KHJlc291cmNlLm1vbnRobHlDb3N0LmFtb3VudCwgJ1VTRCcpO1xuICAgIGNvbnN0IGNvbmZpZGVuY2UgPSByZXNvdXJjZS5tb250aGx5Q29zdC5jb25maWRlbmNlO1xuICAgIHJldHVybiBgICDigKIgJHtyZXNvdXJjZS5sb2dpY2FsSWR9ICgke3Jlc291cmNlLnR5cGV9KTogJHtjb3N0fSBbJHtjb25maWRlbmNlfV1gO1xuICB9XG5cbiAgcHJpdmF0ZSBmb3JtYXRNb2RpZmllZFJlc291cmNlTGluZShyZXNvdXJjZTogTW9kaWZpZWRSZXNvdXJjZUNvc3QpOiBzdHJpbmcge1xuICAgIGNvbnN0IG9sZENvc3QgPSB0aGlzLmZvcm1hdEN1cnJlbmN5KHJlc291cmNlLm9sZE1vbnRobHlDb3N0LmFtb3VudCwgJ1VTRCcpO1xuICAgIGNvbnN0IG5ld0Nvc3QgPSB0aGlzLmZvcm1hdEN1cnJlbmN5KHJlc291cmNlLm5ld01vbnRobHlDb3N0LmFtb3VudCwgJ1VTRCcpO1xuICAgIGNvbnN0IGRlbHRhID0gdGhpcy5mb3JtYXREZWx0YShyZXNvdXJjZS5jb3N0RGVsdGEsICdVU0QnKTtcbiAgICByZXR1cm4gYCAg4oCiICR7cmVzb3VyY2UubG9naWNhbElkfSAoJHtyZXNvdXJjZS50eXBlfSk6ICR7b2xkQ29zdH0g4oaSICR7bmV3Q29zdH0gKCR7ZGVsdGF9KWA7XG4gIH1cblxuICBwcml2YXRlIGZvcm1hdEN1cnJlbmN5KGFtb3VudDogbnVtYmVyLCBjdXJyZW5jeTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBjb25zdCBzeW1ib2wgPSBjdXJyZW5jeSA9PT0gJ1VTRCcgPyAnJCcgOiBjdXJyZW5jeTtcbiAgICByZXR1cm4gYCR7c3ltYm9sfSR7YW1vdW50LnRvRml4ZWQoMil9YDtcbiAgfVxuXG4gIHByaXZhdGUgZm9ybWF0RGVsdGEoYW1vdW50OiBudW1iZXIsIGN1cnJlbmN5OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IHNpZ24gPSBhbW91bnQgPiAwID8gJysnIDogYW1vdW50IDwgMCA/ICctJyA6ICcnO1xuICAgIGNvbnN0IGFic0Ftb3VudCA9IE1hdGguYWJzKGFtb3VudCk7XG4gICAgY29uc3QgZm9ybWF0dGVkID0gdGhpcy5mb3JtYXRDdXJyZW5jeShhYnNBbW91bnQsIGN1cnJlbmN5KTtcbiAgICByZXR1cm4gYW1vdW50ID09PSAwID8gZm9ybWF0dGVkIDogYCR7c2lnbn0ke2Zvcm1hdHRlZH1gO1xuICB9XG5cbiAgcHJpdmF0ZSBmb3JtYXRDb25maWdTdW1tYXJ5VGV4dChjb25maWc6IGFueSk6IHN0cmluZ1tdIHtcbiAgICBjb25zdCBsaW5lczogc3RyaW5nW10gPSBbXTtcbiAgICBsaW5lcy5wdXNoKCdDT05GSUdVUkFUSU9OOicpO1xuICAgIGxpbmVzLnB1c2goJy0nLnJlcGVhdCg2MCkpO1xuXG4gICAgaWYgKGNvbmZpZy5jb25maWdQYXRoKSB7XG4gICAgICBsaW5lcy5wdXNoKGAgIENvbmZpZ3VyYXRpb24gRmlsZTogJHtjb25maWcuY29uZmlnUGF0aH1gKTtcbiAgICB9IGVsc2Uge1xuICAgICAgbGluZXMucHVzaCgnICBDb25maWd1cmF0aW9uIEZpbGU6IFVzaW5nIGRlZmF1bHRzJyk7XG4gICAgfVxuXG4gICAgaWYgKGNvbmZpZy50aHJlc2hvbGRzKSB7XG4gICAgICBpZiAoY29uZmlnLnRocmVzaG9sZHMuZW52aXJvbm1lbnQpIHtcbiAgICAgICAgbGluZXMucHVzaChgICBFbnZpcm9ubWVudDogJHtjb25maWcudGhyZXNob2xkcy5lbnZpcm9ubWVudH1gKTtcbiAgICAgIH1cbiAgICAgIGlmIChjb25maWcudGhyZXNob2xkcy53YXJuaW5nICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgbGluZXMucHVzaChcbiAgICAgICAgICBgICBXYXJuaW5nIFRocmVzaG9sZDogJCR7Y29uZmlnLnRocmVzaG9sZHMud2FybmluZy50b0ZpeGVkKDIpfS9tb250aGAsXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICBpZiAoY29uZmlnLnRocmVzaG9sZHMuZXJyb3IgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBsaW5lcy5wdXNoKFxuICAgICAgICAgIGAgIEVycm9yIFRocmVzaG9sZDogJCR7Y29uZmlnLnRocmVzaG9sZHMuZXJyb3IudG9GaXhlZCgyKX0vbW9udGhgLFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChcbiAgICAgIGNvbmZpZy5leGNsdWRlZFJlc291cmNlVHlwZXMgJiZcbiAgICAgIGNvbmZpZy5leGNsdWRlZFJlc291cmNlVHlwZXMubGVuZ3RoID4gMFxuICAgICkge1xuICAgICAgbGluZXMucHVzaChcbiAgICAgICAgYCAgRXhjbHVkZWQgUmVzb3VyY2UgVHlwZXM6ICR7Y29uZmlnLmV4Y2x1ZGVkUmVzb3VyY2VUeXBlcy5qb2luKCcsICcpfWAsXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmIChcbiAgICAgIGNvbmZpZy51c2FnZUFzc3VtcHRpb25zICYmXG4gICAgICBPYmplY3Qua2V5cyhjb25maWcudXNhZ2VBc3N1bXB0aW9ucykubGVuZ3RoID4gMFxuICAgICkge1xuICAgICAgbGluZXMucHVzaCgnICBDdXN0b20gVXNhZ2UgQXNzdW1wdGlvbnM6Jyk7XG4gICAgICBmb3IgKGNvbnN0IFtyZXNvdXJjZVR5cGUsIGFzc3VtcHRpb25zXSBvZiBPYmplY3QuZW50cmllcyhcbiAgICAgICAgY29uZmlnLnVzYWdlQXNzdW1wdGlvbnMsXG4gICAgICApKSB7XG4gICAgICAgIGxpbmVzLnB1c2goYCAgICAtICR7cmVzb3VyY2VUeXBlfTogJHtKU09OLnN0cmluZ2lmeShhc3N1bXB0aW9ucyl9YCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGxpbmVzO1xuICB9XG5cbiAgcHJpdmF0ZSBmb3JtYXRUaHJlc2hvbGRTdGF0dXNUZXh0KHRocmVzaG9sZDogYW55KTogc3RyaW5nW10ge1xuICAgIGNvbnN0IGxpbmVzOiBzdHJpbmdbXSA9IFtdO1xuICAgIGxpbmVzLnB1c2goJ1RIUkVTSE9MRCBTVEFUVVM6Jyk7XG4gICAgbGluZXMucHVzaCgnLScucmVwZWF0KDYwKSk7XG5cbiAgICBpZiAodGhyZXNob2xkLmxldmVsID09PSAnbm9uZScpIHtcbiAgICAgIGxpbmVzLnB1c2goJyAgTm8gdGhyZXNob2xkcyBjb25maWd1cmVkJyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IHN0YXR1cyA9IHRocmVzaG9sZC5wYXNzZWQgPyAnUEFTU0VEJyA6ICdFWENFRURFRCc7XG4gICAgICBsaW5lcy5wdXNoKGAgIFN0YXR1czogJHtzdGF0dXN9YCk7XG5cbiAgICAgIGlmICh0aHJlc2hvbGQudGhyZXNob2xkICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgbGluZXMucHVzaChcbiAgICAgICAgICBgICBUaHJlc2hvbGQ6ICQke3RocmVzaG9sZC50aHJlc2hvbGQudG9GaXhlZCgyKX0vbW9udGggKCR7dGhyZXNob2xkLmxldmVsfSlgLFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgbGluZXMucHVzaChcbiAgICAgICAgYCAgQWN0dWFsIERlbHRhOiAkJHtNYXRoLmFicyh0aHJlc2hvbGQuZGVsdGEpLnRvRml4ZWQoMil9L21vbnRoYCxcbiAgICAgICk7XG5cbiAgICAgIGlmIChcbiAgICAgICAgIXRocmVzaG9sZC5wYXNzZWQgJiZcbiAgICAgICAgdGhyZXNob2xkLnJlY29tbWVuZGF0aW9ucyAmJlxuICAgICAgICB0aHJlc2hvbGQucmVjb21tZW5kYXRpb25zLmxlbmd0aCA+IDBcbiAgICAgICkge1xuICAgICAgICBsaW5lcy5wdXNoKCcgIFJlY29tbWVuZGF0aW9uczonKTtcbiAgICAgICAgZm9yIChjb25zdCByZWMgb2YgdGhyZXNob2xkLnJlY29tbWVuZGF0aW9ucykge1xuICAgICAgICAgIGxpbmVzLnB1c2goYCAgICAtICR7cmVjfWApO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGxpbmVzO1xuICB9XG5cbiAgcHJpdmF0ZSBmb3JtYXRDb25maWdTdW1tYXJ5TWFya2Rvd24oY29uZmlnOiBhbnkpOiBzdHJpbmdbXSB7XG4gICAgY29uc3QgbGluZXM6IHN0cmluZ1tdID0gW107XG4gICAgbGluZXMucHVzaCgnPGRldGFpbHM+Jyk7XG4gICAgbGluZXMucHVzaCgnPHN1bW1hcnk+PHN0cm9uZz5Db25maWd1cmF0aW9uIFN1bW1hcnk8L3N0cm9uZz48L3N1bW1hcnk+Jyk7XG4gICAgbGluZXMucHVzaCgnJyk7XG5cbiAgICBpZiAoY29uZmlnLmNvbmZpZ1BhdGgpIHtcbiAgICAgIGxpbmVzLnB1c2goYCoqQ29uZmlndXJhdGlvbiBGaWxlOioqIFxcYCR7Y29uZmlnLmNvbmZpZ1BhdGh9XFxgYCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxpbmVzLnB1c2goJyoqQ29uZmlndXJhdGlvbiBGaWxlOioqIFVzaW5nIGRlZmF1bHRzJyk7XG4gICAgfVxuICAgIGxpbmVzLnB1c2goJycpO1xuXG4gICAgaWYgKGNvbmZpZy50aHJlc2hvbGRzKSB7XG4gICAgICBsaW5lcy5wdXNoKCcqKlRocmVzaG9sZHM6KionKTtcbiAgICAgIGlmIChjb25maWcudGhyZXNob2xkcy5lbnZpcm9ubWVudCkge1xuICAgICAgICBsaW5lcy5wdXNoKGAtIEVudmlyb25tZW50OiAke2NvbmZpZy50aHJlc2hvbGRzLmVudmlyb25tZW50fWApO1xuICAgICAgfVxuICAgICAgaWYgKGNvbmZpZy50aHJlc2hvbGRzLndhcm5pbmcgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBsaW5lcy5wdXNoKGAtIFdhcm5pbmc6ICQke2NvbmZpZy50aHJlc2hvbGRzLndhcm5pbmcudG9GaXhlZCgyKX0vbW9udGhgKTtcbiAgICAgIH1cbiAgICAgIGlmIChjb25maWcudGhyZXNob2xkcy5lcnJvciAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGxpbmVzLnB1c2goYC0gRXJyb3I6ICQke2NvbmZpZy50aHJlc2hvbGRzLmVycm9yLnRvRml4ZWQoMil9L21vbnRoYCk7XG4gICAgICB9XG4gICAgICBsaW5lcy5wdXNoKCcnKTtcbiAgICB9XG5cbiAgICBpZiAoXG4gICAgICBjb25maWcuZXhjbHVkZWRSZXNvdXJjZVR5cGVzICYmXG4gICAgICBjb25maWcuZXhjbHVkZWRSZXNvdXJjZVR5cGVzLmxlbmd0aCA+IDBcbiAgICApIHtcbiAgICAgIGxpbmVzLnB1c2goJyoqRXhjbHVkZWQgUmVzb3VyY2UgVHlwZXM6KionKTtcbiAgICAgIGZvciAoY29uc3QgdHlwZSBvZiBjb25maWcuZXhjbHVkZWRSZXNvdXJjZVR5cGVzKSB7XG4gICAgICAgIGxpbmVzLnB1c2goYC0gXFxgJHt0eXBlfVxcYGApO1xuICAgICAgfVxuICAgICAgbGluZXMucHVzaCgnJyk7XG4gICAgfVxuXG4gICAgaWYgKFxuICAgICAgY29uZmlnLnVzYWdlQXNzdW1wdGlvbnMgJiZcbiAgICAgIE9iamVjdC5rZXlzKGNvbmZpZy51c2FnZUFzc3VtcHRpb25zKS5sZW5ndGggPiAwXG4gICAgKSB7XG4gICAgICBsaW5lcy5wdXNoKCcqKkN1c3RvbSBVc2FnZSBBc3N1bXB0aW9uczoqKicpO1xuICAgICAgZm9yIChjb25zdCBbcmVzb3VyY2VUeXBlLCBhc3N1bXB0aW9uc10gb2YgT2JqZWN0LmVudHJpZXMoXG4gICAgICAgIGNvbmZpZy51c2FnZUFzc3VtcHRpb25zLFxuICAgICAgKSkge1xuICAgICAgICBsaW5lcy5wdXNoKGAtICoqJHtyZXNvdXJjZVR5cGV9OioqYCk7XG4gICAgICAgIGNvbnN0IGFzc3VtcHRpb25PYmogPSBhc3N1bXB0aW9ucyBhcyBSZWNvcmQ8c3RyaW5nLCBhbnk+O1xuICAgICAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhhc3N1bXB0aW9uT2JqKSkge1xuICAgICAgICAgIGxpbmVzLnB1c2goYCAgLSAke2tleX06ICR7dmFsdWV9YCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGxpbmVzLnB1c2goJycpO1xuICAgIH1cblxuICAgIGxpbmVzLnB1c2goJzwvZGV0YWlscz4nKTtcbiAgICBsaW5lcy5wdXNoKCcnKTtcblxuICAgIHJldHVybiBsaW5lcztcbiAgfVxuXG4gIHByaXZhdGUgZm9ybWF0VGhyZXNob2xkU3RhdHVzTWFya2Rvd24oXG4gICAgdGhyZXNob2xkOiBhbnksXG4gICAgY29zdERlbHRhOiBDb3N0RGVsdGEsXG4gICk6IHN0cmluZ1tdIHtcbiAgICBjb25zdCBsaW5lczogc3RyaW5nW10gPSBbXTtcblxuICAgIGlmICh0aHJlc2hvbGQubGV2ZWwgPT09ICdub25lJykge1xuICAgICAgcmV0dXJuIGxpbmVzO1xuICAgIH1cblxuICAgIGNvbnN0IHBhc3NlZCA9IHRocmVzaG9sZC5wYXNzZWQ7XG4gICAgY29uc3Qgc3RhdHVzID0gcGFzc2VkID8gJ1BBU1NFRCcgOiAnRVhDRUVERUQnO1xuXG4gICAgbGluZXMucHVzaChgIyMgVGhyZXNob2xkIFN0YXR1czogJHtzdGF0dXN9YCk7XG4gICAgbGluZXMucHVzaCgnJyk7XG5cbiAgICBpZiAodGhyZXNob2xkLnRocmVzaG9sZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBsaW5lcy5wdXNoKFxuICAgICAgICBgKipUaHJlc2hvbGQ6KiogJCR7dGhyZXNob2xkLnRocmVzaG9sZC50b0ZpeGVkKDIpfS9tb250aCAoJHt0aHJlc2hvbGQubGV2ZWx9KWAsXG4gICAgICApO1xuICAgIH1cbiAgICBsaW5lcy5wdXNoKFxuICAgICAgYCoqQWN0dWFsIERlbHRhOioqICR7dGhpcy5mb3JtYXREZWx0YSh0aHJlc2hvbGQuZGVsdGEsIGNvc3REZWx0YS5jdXJyZW5jeSl9L21vbnRoYCxcbiAgICApO1xuICAgIGxpbmVzLnB1c2goJycpO1xuXG4gICAgaWYgKCFwYXNzZWQpIHtcbiAgICAgIGxpbmVzLnB1c2goJyMjIyBBY3Rpb24gUmVxdWlyZWQnKTtcbiAgICAgIGxpbmVzLnB1c2goJycpO1xuICAgICAgbGluZXMucHVzaCh0aHJlc2hvbGQubWVzc2FnZSk7XG4gICAgICBsaW5lcy5wdXNoKCcnKTtcblxuICAgICAgaWYgKHRocmVzaG9sZC5yZWNvbW1lbmRhdGlvbnMgJiYgdGhyZXNob2xkLnJlY29tbWVuZGF0aW9ucy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGxpbmVzLnB1c2goJyMjIyBSZWNvbW1lbmRhdGlvbnMnKTtcbiAgICAgICAgbGluZXMucHVzaCgnJyk7XG4gICAgICAgIGZvciAoY29uc3QgcmVjIG9mIHRocmVzaG9sZC5yZWNvbW1lbmRhdGlvbnMpIHtcbiAgICAgICAgICBsaW5lcy5wdXNoKGAtICR7cmVjfWApO1xuICAgICAgICB9XG4gICAgICAgIGxpbmVzLnB1c2goJycpO1xuICAgICAgfVxuXG4gICAgICAvLyBTaG93IHRvcCBjb3N0IGNvbnRyaWJ1dG9yc1xuICAgICAgY29uc3QgdG9wQ29udHJpYnV0b3JzID0gdGhpcy5nZXRUb3BDb3N0Q29udHJpYnV0b3JzKGNvc3REZWx0YSwgNSk7XG4gICAgICBpZiAodG9wQ29udHJpYnV0b3JzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgbGluZXMucHVzaCgnIyMjIFRvcCBDb3N0IENvbnRyaWJ1dG9ycycpO1xuICAgICAgICBsaW5lcy5wdXNoKCcnKTtcbiAgICAgICAgbGluZXMucHVzaCgnfCBSZXNvdXJjZSB8IFR5cGUgfCBJbXBhY3QgfCcpO1xuICAgICAgICBsaW5lcy5wdXNoKCd8LS0tLS0tLS0tLXwtLS0tLS18LS0tLS0tLS18Jyk7XG4gICAgICAgIGZvciAoY29uc3QgY29udHJpYnV0b3Igb2YgdG9wQ29udHJpYnV0b3JzKSB7XG4gICAgICAgICAgbGluZXMucHVzaChcbiAgICAgICAgICAgIGB8ICR7Y29udHJpYnV0b3IubG9naWNhbElkfSB8ICR7Y29udHJpYnV0b3IudHlwZX0gfCAke3RoaXMuZm9ybWF0RGVsdGEoY29udHJpYnV0b3IuaW1wYWN0LCBjb3N0RGVsdGEuY3VycmVuY3kpfSB8YCxcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIGxpbmVzLnB1c2goJycpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBsaW5lcztcbiAgfVxuXG4gIHByaXZhdGUgZ2V0VG9wQ29zdENvbnRyaWJ1dG9ycyhcbiAgICBjb3N0RGVsdGE6IENvc3REZWx0YSxcbiAgICBsaW1pdDogbnVtYmVyLFxuICApOiBBcnJheTx7IGxvZ2ljYWxJZDogc3RyaW5nOyB0eXBlOiBzdHJpbmc7IGltcGFjdDogbnVtYmVyIH0+IHtcbiAgICBjb25zdCBjb250cmlidXRvcnM6IEFycmF5PHtcbiAgICAgIGxvZ2ljYWxJZDogc3RyaW5nO1xuICAgICAgdHlwZTogc3RyaW5nO1xuICAgICAgaW1wYWN0OiBudW1iZXI7XG4gICAgfT4gPSBbXTtcblxuICAgIC8vIEFkZCBhZGRlZCByZXNvdXJjZXNcbiAgICBmb3IgKGNvbnN0IHJlc291cmNlIG9mIGNvc3REZWx0YS5hZGRlZENvc3RzKSB7XG4gICAgICBjb250cmlidXRvcnMucHVzaCh7XG4gICAgICAgIGxvZ2ljYWxJZDogcmVzb3VyY2UubG9naWNhbElkLFxuICAgICAgICB0eXBlOiByZXNvdXJjZS50eXBlLFxuICAgICAgICBpbXBhY3Q6IHJlc291cmNlLm1vbnRobHlDb3N0LmFtb3VudCxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIC8vIEFkZCByZW1vdmVkIHJlc291cmNlcyAobmVnYXRpdmUgaW1wYWN0KVxuICAgIGZvciAoY29uc3QgcmVzb3VyY2Ugb2YgY29zdERlbHRhLnJlbW92ZWRDb3N0cykge1xuICAgICAgY29udHJpYnV0b3JzLnB1c2goe1xuICAgICAgICBsb2dpY2FsSWQ6IHJlc291cmNlLmxvZ2ljYWxJZCxcbiAgICAgICAgdHlwZTogcmVzb3VyY2UudHlwZSxcbiAgICAgICAgaW1wYWN0OiAtcmVzb3VyY2UubW9udGhseUNvc3QuYW1vdW50LFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gQWRkIG1vZGlmaWVkIHJlc291cmNlc1xuICAgIGZvciAoY29uc3QgcmVzb3VyY2Ugb2YgY29zdERlbHRhLm1vZGlmaWVkQ29zdHMpIHtcbiAgICAgIGNvbnRyaWJ1dG9ycy5wdXNoKHtcbiAgICAgICAgbG9naWNhbElkOiByZXNvdXJjZS5sb2dpY2FsSWQsXG4gICAgICAgIHR5cGU6IHJlc291cmNlLnR5cGUsXG4gICAgICAgIGltcGFjdDogcmVzb3VyY2UuY29zdERlbHRhLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gU29ydCBieSBhYnNvbHV0ZSBpbXBhY3QgKGRlc2NlbmRpbmcpXG4gICAgY29udHJpYnV0b3JzLnNvcnQoKGEsIGIpID0+IE1hdGguYWJzKGIuaW1wYWN0KSAtIE1hdGguYWJzKGEuaW1wYWN0KSk7XG5cbiAgICByZXR1cm4gY29udHJpYnV0b3JzLnNsaWNlKDAsIGxpbWl0KTtcbiAgfVxuXG4gIHByaXZhdGUgZm9ybWF0U3RhY2tEZXRhaWxzTWFya2Rvd24oY29zdERlbHRhOiBDb3N0RGVsdGEpOiBzdHJpbmdbXSB7XG4gICAgY29uc3QgbGluZXM6IHN0cmluZ1tdID0gW107XG5cbiAgICBpZiAoY29zdERlbHRhLmFkZGVkQ29zdHMubGVuZ3RoID4gMCkge1xuICAgICAgbGluZXMucHVzaCgnKipBZGRlZCBSZXNvdXJjZXM6KionKTtcbiAgICAgIGxpbmVzLnB1c2goJycpO1xuICAgICAgbGluZXMucHVzaCgnfCBMb2dpY2FsIElEIHwgVHlwZSB8IE1vbnRobHkgQ29zdCB8Jyk7XG4gICAgICBsaW5lcy5wdXNoKCd8LS0tLS0tLS0tLS0tfC0tLS0tLXwtLS0tLS0tLS0tLS0tLXwnKTtcblxuICAgICAgY29uc3Qgc29ydGVkQWRkZWQgPSBbLi4uY29zdERlbHRhLmFkZGVkQ29zdHNdLnNvcnQoXG4gICAgICAgIChhLCBiKSA9PiBiLm1vbnRobHlDb3N0LmFtb3VudCAtIGEubW9udGhseUNvc3QuYW1vdW50LFxuICAgICAgKTtcblxuICAgICAgZm9yIChjb25zdCByZXNvdXJjZSBvZiBzb3J0ZWRBZGRlZCkge1xuICAgICAgICBsaW5lcy5wdXNoKFxuICAgICAgICAgIGB8ICR7cmVzb3VyY2UubG9naWNhbElkfSB8ICR7cmVzb3VyY2UudHlwZX0gfCAke3RoaXMuZm9ybWF0Q3VycmVuY3kocmVzb3VyY2UubW9udGhseUNvc3QuYW1vdW50LCBjb3N0RGVsdGEuY3VycmVuY3kpfSB8YCxcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIGxpbmVzLnB1c2goJycpO1xuICAgIH1cblxuICAgIGlmIChjb3N0RGVsdGEucmVtb3ZlZENvc3RzLmxlbmd0aCA+IDApIHtcbiAgICAgIGxpbmVzLnB1c2goJyoqUmVtb3ZlZCBSZXNvdXJjZXM6KionKTtcbiAgICAgIGxpbmVzLnB1c2goJycpO1xuICAgICAgbGluZXMucHVzaCgnfCBMb2dpY2FsIElEIHwgVHlwZSB8IE1vbnRobHkgQ29zdCB8Jyk7XG4gICAgICBsaW5lcy5wdXNoKCd8LS0tLS0tLS0tLS0tfC0tLS0tLXwtLS0tLS0tLS0tLS0tLXwnKTtcblxuICAgICAgY29uc3Qgc29ydGVkUmVtb3ZlZCA9IFsuLi5jb3N0RGVsdGEucmVtb3ZlZENvc3RzXS5zb3J0KFxuICAgICAgICAoYSwgYikgPT4gYi5tb250aGx5Q29zdC5hbW91bnQgLSBhLm1vbnRobHlDb3N0LmFtb3VudCxcbiAgICAgICk7XG5cbiAgICAgIGZvciAoY29uc3QgcmVzb3VyY2Ugb2Ygc29ydGVkUmVtb3ZlZCkge1xuICAgICAgICBsaW5lcy5wdXNoKFxuICAgICAgICAgIGB8ICR7cmVzb3VyY2UubG9naWNhbElkfSB8ICR7cmVzb3VyY2UudHlwZX0gfCAke3RoaXMuZm9ybWF0Q3VycmVuY3kocmVzb3VyY2UubW9udGhseUNvc3QuYW1vdW50LCBjb3N0RGVsdGEuY3VycmVuY3kpfSB8YCxcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIGxpbmVzLnB1c2goJycpO1xuICAgIH1cblxuICAgIGlmIChjb3N0RGVsdGEubW9kaWZpZWRDb3N0cy5sZW5ndGggPiAwKSB7XG4gICAgICBsaW5lcy5wdXNoKCcqKk1vZGlmaWVkIFJlc291cmNlczoqKicpO1xuICAgICAgbGluZXMucHVzaCgnJyk7XG4gICAgICBsaW5lcy5wdXNoKCd8IExvZ2ljYWwgSUQgfCBUeXBlIHwgT2xkIENvc3QgfCBOZXcgQ29zdCB8IERlbHRhIHwnKTtcbiAgICAgIGxpbmVzLnB1c2goJ3wtLS0tLS0tLS0tLS18LS0tLS0tfC0tLS0tLS0tLS18LS0tLS0tLS0tLXwtLS0tLS0tfCcpO1xuXG4gICAgICBjb25zdCBzb3J0ZWRNb2RpZmllZCA9IFsuLi5jb3N0RGVsdGEubW9kaWZpZWRDb3N0c10uc29ydChcbiAgICAgICAgKGEsIGIpID0+IE1hdGguYWJzKGIuY29zdERlbHRhKSAtIE1hdGguYWJzKGEuY29zdERlbHRhKSxcbiAgICAgICk7XG5cbiAgICAgIGZvciAoY29uc3QgcmVzb3VyY2Ugb2Ygc29ydGVkTW9kaWZpZWQpIHtcbiAgICAgICAgbGluZXMucHVzaChcbiAgICAgICAgICBgfCAke3Jlc291cmNlLmxvZ2ljYWxJZH0gfCAke3Jlc291cmNlLnR5cGV9IHwgYCArXG4gICAgICAgICAgICBgJHt0aGlzLmZvcm1hdEN1cnJlbmN5KHJlc291cmNlLm9sZE1vbnRobHlDb3N0LmFtb3VudCwgY29zdERlbHRhLmN1cnJlbmN5KX0gfCBgICtcbiAgICAgICAgICAgIGAke3RoaXMuZm9ybWF0Q3VycmVuY3kocmVzb3VyY2UubmV3TW9udGhseUNvc3QuYW1vdW50LCBjb3N0RGVsdGEuY3VycmVuY3kpfSB8IGAgK1xuICAgICAgICAgICAgYCR7dGhpcy5mb3JtYXREZWx0YShyZXNvdXJjZS5jb3N0RGVsdGEsIGNvc3REZWx0YS5jdXJyZW5jeSl9IHxgLFxuICAgICAgICApO1xuICAgICAgfVxuICAgICAgbGluZXMucHVzaCgnJyk7XG4gICAgfVxuXG4gICAgaWYgKFxuICAgICAgY29zdERlbHRhLmFkZGVkQ29zdHMubGVuZ3RoID09PSAwICYmXG4gICAgICBjb3N0RGVsdGEucmVtb3ZlZENvc3RzLmxlbmd0aCA9PT0gMCAmJlxuICAgICAgY29zdERlbHRhLm1vZGlmaWVkQ29zdHMubGVuZ3RoID09PSAwXG4gICAgKSB7XG4gICAgICBsaW5lcy5wdXNoKCdObyByZXNvdXJjZSBjaGFuZ2VzIGRldGVjdGVkLicpO1xuICAgICAgbGluZXMucHVzaCgnJyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGxpbmVzO1xuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.Reporter = void 0;
|
|
18
|
+
var Reporter_1 = require("./Reporter");
|
|
19
|
+
Object.defineProperty(exports, "Reporter", { enumerable: true, get: function () { return Reporter_1.Reporter; } });
|
|
20
|
+
__exportStar(require("./types"), exports);
|
|
21
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcmVwb3J0ZXIvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSx1Q0FBc0M7QUFBN0Isb0dBQUEsUUFBUSxPQUFBO0FBQ2pCLDBDQUF3QiIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCB7IFJlcG9ydGVyIH0gZnJvbSAnLi9SZXBvcnRlcic7XG5leHBvcnQgKiBmcm9tICcuL3R5cGVzJztcbiJdfQ==
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { ConfigSummary } from '../pipeline/types';
|
|
2
|
+
import { CostDelta } from '../pricing/types';
|
|
3
|
+
import { ThresholdEvaluation } from '../threshold/types';
|
|
4
|
+
/**
|
|
5
|
+
* Reporter interface for generating cost analysis reports in various formats.
|
|
6
|
+
*/
|
|
7
|
+
export interface Reporter {
|
|
8
|
+
/**
|
|
9
|
+
* Generate a cost analysis report.
|
|
10
|
+
*
|
|
11
|
+
* @param costDelta - The cost delta containing added, removed, and modified resources
|
|
12
|
+
* @param format - The output format (text, json, or markdown)
|
|
13
|
+
* @param options - Optional reporting options for enhanced reports
|
|
14
|
+
* @returns Formatted report string
|
|
15
|
+
*/
|
|
16
|
+
generateReport(costDelta: CostDelta, format: ReportFormat, options?: ReportOptions): string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Options for customizing report generation.
|
|
20
|
+
*
|
|
21
|
+
* These options enable enhanced reporting features including:
|
|
22
|
+
* - Configuration summaries showing applied settings
|
|
23
|
+
* - Threshold status with actionable guidance
|
|
24
|
+
* - Multi-stack breakdowns for complex applications
|
|
25
|
+
*/
|
|
26
|
+
export interface ReportOptions {
|
|
27
|
+
/**
|
|
28
|
+
* Configuration summary to include in the report.
|
|
29
|
+
* Shows thresholds, usage assumptions, and exclusions applied.
|
|
30
|
+
*/
|
|
31
|
+
configSummary?: ConfigSummary;
|
|
32
|
+
/**
|
|
33
|
+
* Threshold evaluation status to include in the report.
|
|
34
|
+
* Shows whether cost thresholds were exceeded and provides recommendations.
|
|
35
|
+
*/
|
|
36
|
+
thresholdStatus?: ThresholdEvaluation;
|
|
37
|
+
/**
|
|
38
|
+
* Name of the stack being analyzed (for multi-stack reports).
|
|
39
|
+
*/
|
|
40
|
+
stackName?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Whether this is a multi-stack analysis.
|
|
43
|
+
* When true, enables per-stack cost breakdowns in the report.
|
|
44
|
+
*/
|
|
45
|
+
multiStack?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Stack-level cost details for multi-stack reports.
|
|
48
|
+
* Each entry contains the stack name and its cost delta.
|
|
49
|
+
*/
|
|
50
|
+
stacks?: StackCostDelta[];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Stack-level cost delta for multi-stack reporting.
|
|
54
|
+
*/
|
|
55
|
+
export interface StackCostDelta {
|
|
56
|
+
/**
|
|
57
|
+
* Name of the CloudFormation stack.
|
|
58
|
+
*/
|
|
59
|
+
stackName: string;
|
|
60
|
+
/**
|
|
61
|
+
* Cost delta for this specific stack.
|
|
62
|
+
*/
|
|
63
|
+
costDelta: CostDelta;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Supported report output formats.
|
|
67
|
+
*
|
|
68
|
+
* - text: Human-readable console output with ASCII formatting
|
|
69
|
+
* - json: Structured JSON for programmatic processing
|
|
70
|
+
* - markdown: Formatted markdown suitable for GitLab merge request comments
|
|
71
|
+
*/
|
|
72
|
+
export type ReportFormat = 'text' | 'json' | 'markdown';
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcmVwb3J0ZXIvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbmZpZ1N1bW1hcnkgfSBmcm9tICcuLi9waXBlbGluZS90eXBlcyc7XG5pbXBvcnQgeyBDb3N0RGVsdGEgfSBmcm9tICcuLi9wcmljaW5nL3R5cGVzJztcbmltcG9ydCB7IFRocmVzaG9sZEV2YWx1YXRpb24gfSBmcm9tICcuLi90aHJlc2hvbGQvdHlwZXMnO1xuXG4vKipcbiAqIFJlcG9ydGVyIGludGVyZmFjZSBmb3IgZ2VuZXJhdGluZyBjb3N0IGFuYWx5c2lzIHJlcG9ydHMgaW4gdmFyaW91cyBmb3JtYXRzLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFJlcG9ydGVyIHtcbiAgLyoqXG4gICAqIEdlbmVyYXRlIGEgY29zdCBhbmFseXNpcyByZXBvcnQuXG4gICAqXG4gICAqIEBwYXJhbSBjb3N0RGVsdGEgLSBUaGUgY29zdCBkZWx0YSBjb250YWluaW5nIGFkZGVkLCByZW1vdmVkLCBhbmQgbW9kaWZpZWQgcmVzb3VyY2VzXG4gICAqIEBwYXJhbSBmb3JtYXQgLSBUaGUgb3V0cHV0IGZvcm1hdCAodGV4dCwganNvbiwgb3IgbWFya2Rvd24pXG4gICAqIEBwYXJhbSBvcHRpb25zIC0gT3B0aW9uYWwgcmVwb3J0aW5nIG9wdGlvbnMgZm9yIGVuaGFuY2VkIHJlcG9ydHNcbiAgICogQHJldHVybnMgRm9ybWF0dGVkIHJlcG9ydCBzdHJpbmdcbiAgICovXG4gIGdlbmVyYXRlUmVwb3J0KFxuICAgIGNvc3REZWx0YTogQ29zdERlbHRhLFxuICAgIGZvcm1hdDogUmVwb3J0Rm9ybWF0LFxuICAgIG9wdGlvbnM/OiBSZXBvcnRPcHRpb25zLFxuICApOiBzdHJpbmc7XG59XG5cbi8qKlxuICogT3B0aW9ucyBmb3IgY3VzdG9taXppbmcgcmVwb3J0IGdlbmVyYXRpb24uXG4gKlxuICogVGhlc2Ugb3B0aW9ucyBlbmFibGUgZW5oYW5jZWQgcmVwb3J0aW5nIGZlYXR1cmVzIGluY2x1ZGluZzpcbiAqIC0gQ29uZmlndXJhdGlvbiBzdW1tYXJpZXMgc2hvd2luZyBhcHBsaWVkIHNldHRpbmdzXG4gKiAtIFRocmVzaG9sZCBzdGF0dXMgd2l0aCBhY3Rpb25hYmxlIGd1aWRhbmNlXG4gKiAtIE11bHRpLXN0YWNrIGJyZWFrZG93bnMgZm9yIGNvbXBsZXggYXBwbGljYXRpb25zXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVwb3J0T3B0aW9ucyB7XG4gIC8qKlxuICAgKiBDb25maWd1cmF0aW9uIHN1bW1hcnkgdG8gaW5jbHVkZSBpbiB0aGUgcmVwb3J0LlxuICAgKiBTaG93cyB0aHJlc2hvbGRzLCB1c2FnZSBhc3N1bXB0aW9ucywgYW5kIGV4Y2x1c2lvbnMgYXBwbGllZC5cbiAgICovXG4gIGNvbmZpZ1N1bW1hcnk/OiBDb25maWdTdW1tYXJ5O1xuXG4gIC8qKlxuICAgKiBUaHJlc2hvbGQgZXZhbHVhdGlvbiBzdGF0dXMgdG8gaW5jbHVkZSBpbiB0aGUgcmVwb3J0LlxuICAgKiBTaG93cyB3aGV0aGVyIGNvc3QgdGhyZXNob2xkcyB3ZXJlIGV4Y2VlZGVkIGFuZCBwcm92aWRlcyByZWNvbW1lbmRhdGlvbnMuXG4gICAqL1xuICB0aHJlc2hvbGRTdGF0dXM/OiBUaHJlc2hvbGRFdmFsdWF0aW9uO1xuXG4gIC8qKlxuICAgKiBOYW1lIG9mIHRoZSBzdGFjayBiZWluZyBhbmFseXplZCAoZm9yIG11bHRpLXN0YWNrIHJlcG9ydHMpLlxuICAgKi9cbiAgc3RhY2tOYW1lPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoaXMgaXMgYSBtdWx0aS1zdGFjayBhbmFseXNpcy5cbiAgICogV2hlbiB0cnVlLCBlbmFibGVzIHBlci1zdGFjayBjb3N0IGJyZWFrZG93bnMgaW4gdGhlIHJlcG9ydC5cbiAgICovXG4gIG11bHRpU3RhY2s/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBTdGFjay1sZXZlbCBjb3N0IGRldGFpbHMgZm9yIG11bHRpLXN0YWNrIHJlcG9ydHMuXG4gICAqIEVhY2ggZW50cnkgY29udGFpbnMgdGhlIHN0YWNrIG5hbWUgYW5kIGl0cyBjb3N0IGRlbHRhLlxuICAgKi9cbiAgc3RhY2tzPzogU3RhY2tDb3N0RGVsdGFbXTtcbn1cblxuLyoqXG4gKiBTdGFjay1sZXZlbCBjb3N0IGRlbHRhIGZvciBtdWx0aS1zdGFjayByZXBvcnRpbmcuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU3RhY2tDb3N0RGVsdGEge1xuICAvKipcbiAgICogTmFtZSBvZiB0aGUgQ2xvdWRGb3JtYXRpb24gc3RhY2suXG4gICAqL1xuICBzdGFja05hbWU6IHN0cmluZztcblxuICAvKipcbiAgICogQ29zdCBkZWx0YSBmb3IgdGhpcyBzcGVjaWZpYyBzdGFjay5cbiAgICovXG4gIGNvc3REZWx0YTogQ29zdERlbHRhO1xufVxuXG4vKipcbiAqIFN1cHBvcnRlZCByZXBvcnQgb3V0cHV0IGZvcm1hdHMuXG4gKlxuICogLSB0ZXh0OiBIdW1hbi1yZWFkYWJsZSBjb25zb2xlIG91dHB1dCB3aXRoIEFTQ0lJIGZvcm1hdHRpbmdcbiAqIC0ganNvbjogU3RydWN0dXJlZCBKU09OIGZvciBwcm9ncmFtbWF0aWMgcHJvY2Vzc2luZ1xuICogLSBtYXJrZG93bjogRm9ybWF0dGVkIG1hcmtkb3duIHN1aXRhYmxlIGZvciBHaXRMYWIgbWVyZ2UgcmVxdWVzdCBjb21tZW50c1xuICovXG5leHBvcnQgdHlwZSBSZXBvcnRGb3JtYXQgPSAndGV4dCcgfCAnanNvbicgfCAnbWFya2Rvd24nO1xuIl19
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { SynthesisOptions, SynthesisResult } from './types';
|
|
2
|
+
export declare class SynthesisOrchestrator {
|
|
3
|
+
private readonly DEFAULT_OUTPUT_PATH;
|
|
4
|
+
/**
|
|
5
|
+
* Execute CDK synthesis
|
|
6
|
+
*/
|
|
7
|
+
synthesize(options: SynthesisOptions): Promise<SynthesisResult>;
|
|
8
|
+
/**
|
|
9
|
+
* Execute synthesis command
|
|
10
|
+
*
|
|
11
|
+
* Uses shell: false for security to prevent command injection attacks.
|
|
12
|
+
* Arguments are passed as an array to avoid shell interpretation.
|
|
13
|
+
*
|
|
14
|
+
* Implements a 15-second timeout to prevent hanging processes in CI:
|
|
15
|
+
* - Sends SIGTERM for graceful termination
|
|
16
|
+
* - Follows up with SIGKILL after 1 second if process doesn't exit
|
|
17
|
+
* - Prevents duplicate resolution using isResolved flag
|
|
18
|
+
* - Ensures all event listeners are cleaned up
|
|
19
|
+
* - Uses process.kill as fallback for stubborn processes
|
|
20
|
+
*/
|
|
21
|
+
private executeSynthesis;
|
|
22
|
+
/**
|
|
23
|
+
* Find all CloudFormation templates in output directory
|
|
24
|
+
*/
|
|
25
|
+
private findTemplates;
|
|
26
|
+
}
|