cdk-cost-analyzer 0.1.10 → 0.1.11

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 (46) hide show
  1. package/.cdk-cost-analyzer-cache/metadata.json +26 -2
  2. package/.kiro/specs/single-template-analysis/tasks.md +67 -54
  3. package/README.md +31 -1
  4. package/dist/analysis/SingleTemplateAnalyzer.d.ts +23 -0
  5. package/dist/analysis/SingleTemplateAnalyzer.js +168 -0
  6. package/dist/analysis/index.d.ts +1 -0
  7. package/dist/analysis/index.js +6 -0
  8. package/dist/api/index.d.ts +24 -0
  9. package/dist/api/index.js +56 -1
  10. package/dist/api/single-template-types.d.ts +83 -0
  11. package/dist/api/single-template-types.js +3 -0
  12. package/dist/cli/index.js +43 -54
  13. package/dist/pricing/calculators/LambdaCalculator.d.ts +2 -0
  14. package/dist/pricing/calculators/LambdaCalculator.js +48 -1
  15. package/dist/releasetag.txt +1 -1
  16. package/dist/reporter/SingleTemplateReporter.d.ts +31 -0
  17. package/dist/reporter/SingleTemplateReporter.js +186 -0
  18. package/dist/reporter/index.d.ts +1 -0
  19. package/dist/reporter/index.js +4 -2
  20. package/docs/SINGLE-TEMPLATE-ANALYSIS.md +372 -0
  21. package/examples/single-template-usage.js +208 -0
  22. package/package.json +1 -1
  23. package/test-cdk-project/README-COMPUTE.md +0 -141
  24. package/test-cdk-project/README.md +0 -95
  25. package/test-cdk-project/app-with-compute.js +0 -102
  26. package/test-cdk-project/app.js +0 -81
  27. package/test-cdk-project/cdk-compute.json +0 -3
  28. package/test-cdk-project/cdk.context.json +0 -7
  29. package/test-cdk-project/cdk.json +0 -3
  30. package/test-cdk-project/cdk.out/TestStack.assets.json +0 -21
  31. package/test-cdk-project/cdk.out/TestStack.template.json +0 -115
  32. package/test-cdk-project/cdk.out/cdk.out +0 -1
  33. package/test-cdk-project/cdk.out/manifest.json +0 -503
  34. package/test-cdk-project/cdk.out/tree.json +0 -1
  35. package/test-cdk-project/cdk.out.base/TestStack.assets.json +0 -21
  36. package/test-cdk-project/cdk.out.base/TestStack.template.json +0 -115
  37. package/test-cdk-project/cdk.out.base/cdk.out +0 -1
  38. package/test-cdk-project/cdk.out.base/manifest.json +0 -503
  39. package/test-cdk-project/cdk.out.base/tree.json +0 -1
  40. package/test-cdk-project/cdk.out.target/TestStack.assets.json +0 -21
  41. package/test-cdk-project/cdk.out.target/TestStack.template.json +0 -183
  42. package/test-cdk-project/cdk.out.target/cdk.out +0 -1
  43. package/test-cdk-project/cdk.out.target/manifest.json +0 -521
  44. package/test-cdk-project/cdk.out.target/tree.json +0 -1
  45. package/test-cdk-project/package-lock.json +0 -422
  46. package/test-cdk-project/package.json +0 -17
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SingleTemplateReporter = void 0;
4
+ /**
5
+ * Reporter for generating formatted output for single template cost analysis
6
+ */
7
+ class SingleTemplateReporter {
8
+ /**
9
+ * Generate a formatted report from single template analysis result
10
+ *
11
+ * @param result - The analysis result
12
+ * @param format - Output format (text, json, or markdown)
13
+ * @param options - Optional formatting preferences
14
+ * @returns Formatted report string
15
+ */
16
+ generateReport(result, format, options) {
17
+ const opts = {
18
+ showBreakdown: true,
19
+ showAssumptions: true,
20
+ groupByType: true,
21
+ sortBy: 'cost',
22
+ ...options,
23
+ };
24
+ switch (format) {
25
+ case 'json':
26
+ return this.generateJsonReport(result);
27
+ case 'markdown':
28
+ return this.generateMarkdownReport(result, opts);
29
+ case 'text':
30
+ default:
31
+ return this.generateTextReport(result, opts);
32
+ }
33
+ }
34
+ /**
35
+ * Generate JSON format report
36
+ */
37
+ generateJsonReport(result) {
38
+ return JSON.stringify(result, null, 2);
39
+ }
40
+ /**
41
+ * Generate text format report
42
+ */
43
+ generateTextReport(result, options) {
44
+ let report = '';
45
+ // Header
46
+ report += '='.repeat(80) + '\n';
47
+ report += 'Single Template Cost Analysis\n';
48
+ report += '='.repeat(80) + '\n\n';
49
+ // Summary
50
+ report += `Total Monthly Cost: $${result.totalMonthlyCost.toFixed(2)} ${result.currency}\n`;
51
+ report += `Analysis Date: ${result.metadata.analyzedAt.toISOString()}\n`;
52
+ report += `Region: ${result.metadata.region}\n`;
53
+ report += `Template Hash: ${result.metadata.templateHash}\n\n`;
54
+ // Resource counts
55
+ report += `Total Resources: ${result.metadata.resourceCount}\n`;
56
+ report += `Supported Resources: ${result.metadata.supportedResourceCount}\n`;
57
+ report += `Unsupported Resources: ${result.metadata.unsupportedResourceCount}\n\n`;
58
+ // Cost breakdown by confidence
59
+ if (result.costBreakdown.byConfidenceLevel.length > 0) {
60
+ report += '-'.repeat(80) + '\n';
61
+ report += 'Cost Confidence Breakdown\n';
62
+ report += '-'.repeat(80) + '\n\n';
63
+ for (const conf of result.costBreakdown.byConfidenceLevel) {
64
+ const percentage = ((conf.totalCost / result.totalMonthlyCost) * 100).toFixed(1);
65
+ report += `${conf.confidence.toUpperCase().padEnd(10)} ${conf.count} resources $${conf.totalCost.toFixed(2)} (${percentage}%)\n`;
66
+ }
67
+ report += '\n';
68
+ }
69
+ // Resource breakdown
70
+ if (options.showBreakdown && options.groupByType) {
71
+ report += '-'.repeat(80) + '\n';
72
+ report += 'Cost Breakdown by Resource Type\n';
73
+ report += '-'.repeat(80) + '\n\n';
74
+ for (const typeGroup of result.costBreakdown.byResourceType) {
75
+ const percentage = ((typeGroup.totalCost / result.totalMonthlyCost) * 100).toFixed(1);
76
+ report += `${typeGroup.resourceType}\n`;
77
+ report += ` Count: ${typeGroup.count}\n`;
78
+ report += ` Total Cost: $${typeGroup.totalCost.toFixed(2)} (${percentage}%)\n`;
79
+ // Show individual resources
80
+ const sortedResources = this.sortResources(typeGroup.resources, options.sortBy);
81
+ for (const resource of sortedResources) {
82
+ const conf = resource.monthlyCost.confidence;
83
+ const confIndicator = conf === 'high' ? '✓' : conf === 'medium' ? '~' : conf === 'low' ? '?' : '✗';
84
+ report += ` ${confIndicator} ${resource.logicalId.padEnd(40)} $${resource.monthlyCost.amount.toFixed(2)}\n`;
85
+ }
86
+ report += '\n';
87
+ }
88
+ }
89
+ // Assumptions
90
+ if (options.showAssumptions && result.costBreakdown.assumptions.length > 0) {
91
+ report += '-'.repeat(80) + '\n';
92
+ report += 'Cost Calculation Assumptions\n';
93
+ report += '-'.repeat(80) + '\n\n';
94
+ for (const assumption of result.costBreakdown.assumptions) {
95
+ report += ` • ${assumption}\n`;
96
+ }
97
+ report += '\n';
98
+ }
99
+ // Legend
100
+ report += '-'.repeat(80) + '\n';
101
+ report += 'Legend: ✓ High confidence ~ Medium confidence ? Low confidence ✗ Unknown/Unsupported\n';
102
+ report += '='.repeat(80) + '\n';
103
+ return report;
104
+ }
105
+ /**
106
+ * Generate markdown format report
107
+ */
108
+ generateMarkdownReport(result, options) {
109
+ let report = '';
110
+ // Header
111
+ report += '# Single Template Cost Analysis\n\n';
112
+ // Summary
113
+ report += '## Summary\n\n';
114
+ report += `**Total Monthly Cost:** $${result.totalMonthlyCost.toFixed(2)} ${result.currency}\n\n`;
115
+ report += `- **Analysis Date:** ${result.metadata.analyzedAt.toISOString()}\n`;
116
+ report += `- **Region:** ${result.metadata.region}\n`;
117
+ report += `- **Template Hash:** ${result.metadata.templateHash}\n\n`;
118
+ // Resource counts
119
+ report += '## Resource Overview\n\n';
120
+ report += `- **Total Resources:** ${result.metadata.resourceCount}\n`;
121
+ report += `- **Supported Resources:** ${result.metadata.supportedResourceCount}\n`;
122
+ report += `- **Unsupported Resources:** ${result.metadata.unsupportedResourceCount}\n\n`;
123
+ // Cost breakdown by confidence
124
+ if (result.costBreakdown.byConfidenceLevel.length > 0) {
125
+ report += '## Cost Confidence Breakdown\n\n';
126
+ report += '| Confidence | Resources | Cost | Percentage |\n';
127
+ report += '|------------|-----------|------|------------|\n';
128
+ for (const conf of result.costBreakdown.byConfidenceLevel) {
129
+ const percentage = ((conf.totalCost / result.totalMonthlyCost) * 100).toFixed(1);
130
+ report += `| ${conf.confidence} | ${conf.count} | $${conf.totalCost.toFixed(2)} | ${percentage}% |\n`;
131
+ }
132
+ report += '\n';
133
+ }
134
+ // Resource breakdown by type
135
+ if (options.showBreakdown && options.groupByType) {
136
+ report += '## Cost Breakdown by Resource Type\n\n';
137
+ for (const typeGroup of result.costBreakdown.byResourceType) {
138
+ const percentage = ((typeGroup.totalCost / result.totalMonthlyCost) * 100).toFixed(1);
139
+ report += `### ${typeGroup.resourceType}\n\n`;
140
+ report += `- **Count:** ${typeGroup.count}\n`;
141
+ report += `- **Total Cost:** $${typeGroup.totalCost.toFixed(2)} (${percentage}%)\n\n`;
142
+ // Show individual resources in table
143
+ report += '| Resource | Cost | Confidence |\n';
144
+ report += '|----------|------|------------|\n';
145
+ const sortedResources = this.sortResources(typeGroup.resources, options.sortBy);
146
+ for (const resource of sortedResources) {
147
+ const conf = resource.monthlyCost.confidence;
148
+ report += `| ${resource.logicalId} | $${resource.monthlyCost.amount.toFixed(2)} | ${conf} |\n`;
149
+ }
150
+ report += '\n';
151
+ }
152
+ }
153
+ // Assumptions
154
+ if (options.showAssumptions && result.costBreakdown.assumptions.length > 0) {
155
+ report += '## Cost Calculation Assumptions\n\n';
156
+ for (const assumption of result.costBreakdown.assumptions) {
157
+ report += `- ${assumption}\n`;
158
+ }
159
+ report += '\n';
160
+ }
161
+ // Legend
162
+ report += '---\n\n';
163
+ report += '*Confidence levels: high (✓), medium (~), low (?), unknown/unsupported (✗)*\n';
164
+ return report;
165
+ }
166
+ /**
167
+ * Sort resources based on specified criteria
168
+ */
169
+ sortResources(resources, sortBy) {
170
+ const sorted = [...resources];
171
+ switch (sortBy) {
172
+ case 'cost':
173
+ sorted.sort((a, b) => b.monthlyCost.amount - a.monthlyCost.amount);
174
+ break;
175
+ case 'name':
176
+ sorted.sort((a, b) => a.logicalId.localeCompare(b.logicalId));
177
+ break;
178
+ case 'type':
179
+ sorted.sort((a, b) => a.type.localeCompare(b.type));
180
+ break;
181
+ }
182
+ return sorted;
183
+ }
184
+ }
185
+ exports.SingleTemplateReporter = SingleTemplateReporter;
186
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2luZ2xlVGVtcGxhdGVSZXBvcnRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9yZXBvcnRlci9TaW5nbGVUZW1wbGF0ZVJlcG9ydGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUtBOztHQUVHO0FBQ0gsTUFBYSxzQkFBc0I7SUFDakM7Ozs7Ozs7T0FPRztJQUNILGNBQWMsQ0FDWixNQUFnQyxFQUNoQyxNQUFvQyxFQUNwQyxPQUFxQztRQUVyQyxNQUFNLElBQUksR0FBRztZQUNYLGFBQWEsRUFBRSxJQUFJO1lBQ25CLGVBQWUsRUFBRSxJQUFJO1lBQ3JCLFdBQVcsRUFBRSxJQUFJO1lBQ2pCLE1BQU0sRUFBRSxNQUFrQztZQUMxQyxHQUFHLE9BQU87U0FDWCxDQUFDO1FBRUYsUUFBUSxNQUFNLEVBQUUsQ0FBQztZQUNmLEtBQUssTUFBTTtnQkFDVCxPQUFPLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUN6QyxLQUFLLFVBQVU7Z0JBQ2IsT0FBTyxJQUFJLENBQUMsc0JBQXNCLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxDQUFDO1lBQ25ELEtBQUssTUFBTSxDQUFDO1lBQ1o7Z0JBQ0UsT0FBTyxJQUFJLENBQUMsa0JBQWtCLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQ2pELENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxrQkFBa0IsQ0FBQyxNQUFnQztRQUN6RCxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQztJQUN6QyxDQUFDO0lBRUQ7O09BRUc7SUFDSyxrQkFBa0IsQ0FDeEIsTUFBZ0MsRUFDaEMsT0FBOEM7UUFFOUMsSUFBSSxNQUFNLEdBQUcsRUFBRSxDQUFDO1FBRWhCLFNBQVM7UUFDVCxNQUFNLElBQUksR0FBRyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUM7UUFD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R0FBRyxDQUFDLEdBQUcsU0FBUyxDQUFDLENBQUM7UUFFOUIsUUFBUSxNQUFNLEVBQUUsQ0FBQztZQUNmLEtBQUssTUFBTTtnQkFDVCxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsQ0FBQztnQkFDbkUsTUFBTTtZQUNSLEtBQUssTUFBTTtnQkFDVCxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7Z0JBQzlELE1BQU07WUFDUixLQUFLLE1BQU07Z0JBQ1QsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO2dCQUNwRCxNQUFNO1FBQ1YsQ0FBQztRQUVELE9BQU8sTUFBTSxDQUFDO0lBQ2hCLENBQUM7Q0FDRjtBQTdORCx3REE2TkMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBTaW5nbGVUZW1wbGF0ZUNvc3RSZXN1bHQsXG4gIFNpbmdsZVRlbXBsYXRlUmVwb3J0T3B0aW9ucyxcbn0gZnJvbSAnLi4vYXBpL3NpbmdsZS10ZW1wbGF0ZS10eXBlcyc7XG5cbi8qKlxuICogUmVwb3J0ZXIgZm9yIGdlbmVyYXRpbmcgZm9ybWF0dGVkIG91dHB1dCBmb3Igc2luZ2xlIHRlbXBsYXRlIGNvc3QgYW5hbHlzaXNcbiAqL1xuZXhwb3J0IGNsYXNzIFNpbmdsZVRlbXBsYXRlUmVwb3J0ZXIge1xuICAvKipcbiAgICogR2VuZXJhdGUgYSBmb3JtYXR0ZWQgcmVwb3J0IGZyb20gc2luZ2xlIHRlbXBsYXRlIGFuYWx5c2lzIHJlc3VsdFxuICAgKiBcbiAgICogQHBhcmFtIHJlc3VsdCAtIFRoZSBhbmFseXNpcyByZXN1bHRcbiAgICogQHBhcmFtIGZvcm1hdCAtIE91dHB1dCBmb3JtYXQgKHRleHQsIGpzb24sIG9yIG1hcmtkb3duKVxuICAgKiBAcGFyYW0gb3B0aW9ucyAtIE9wdGlvbmFsIGZvcm1hdHRpbmcgcHJlZmVyZW5jZXNcbiAgICogQHJldHVybnMgRm9ybWF0dGVkIHJlcG9ydCBzdHJpbmdcbiAgICovXG4gIGdlbmVyYXRlUmVwb3J0KFxuICAgIHJlc3VsdDogU2luZ2xlVGVtcGxhdGVDb3N0UmVzdWx0LFxuICAgIGZvcm1hdDogJ3RleHQnIHwgJ2pzb24nIHwgJ21hcmtkb3duJyxcbiAgICBvcHRpb25zPzogU2luZ2xlVGVtcGxhdGVSZXBvcnRPcHRpb25zLFxuICApOiBzdHJpbmcge1xuICAgIGNvbnN0IG9wdHMgPSB7XG4gICAgICBzaG93QnJlYWtkb3duOiB0cnVlLFxuICAgICAgc2hvd0Fzc3VtcHRpb25zOiB0cnVlLFxuICAgICAgZ3JvdXBCeVR5cGU6IHRydWUsXG4gICAgICBzb3J0Qnk6ICdjb3N0JyBhcyAnY29zdCcgfCAnbmFtZScgfCAndHlwZScsXG4gICAgICAuLi5vcHRpb25zLFxuICAgIH07XG5cbiAgICBzd2l0Y2ggKGZvcm1hdCkge1xuICAgICAgY2FzZSAnanNvbic6XG4gICAgICAgIHJldHVybiB0aGlzLmdlbmVyYXRlSnNvblJlcG9ydChyZXN1bHQpO1xuICAgICAgY2FzZSAnbWFya2Rvd24nOlxuICAgICAgICByZXR1cm4gdGhpcy5nZW5lcmF0ZU1hcmtkb3duUmVwb3J0KHJlc3VsdCwgb3B0cyk7XG4gICAgICBjYXNlICd0ZXh0JzpcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiB0aGlzLmdlbmVyYXRlVGV4dFJlcG9ydChyZXN1bHQsIG9wdHMpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSBKU09OIGZvcm1hdCByZXBvcnRcbiAgICovXG4gIHByaXZhdGUgZ2VuZXJhdGVKc29uUmVwb3J0KHJlc3VsdDogU2luZ2xlVGVtcGxhdGVDb3N0UmVzdWx0KTogc3RyaW5nIHtcbiAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkocmVzdWx0LCBudWxsLCAyKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSB0ZXh0IGZvcm1hdCByZXBvcnRcbiAgICovXG4gIHByaXZhdGUgZ2VuZXJhdGVUZXh0UmVwb3J0KFxuICAgIHJlc3VsdDogU2luZ2xlVGVtcGxhdGVDb3N0UmVzdWx0LFxuICAgIG9wdGlvbnM6IFJlcXVpcmVkPFNpbmdsZVRlbXBsYXRlUmVwb3J0T3B0aW9ucz4sXG4gICk6IHN0cmluZyB7XG4gICAgbGV0IHJlcG9ydCA9ICcnO1xuXG4gICAgLy8gSGVhZGVyXG4gICAgcmVwb3J0ICs9ICc9Jy5yZXBlYXQoODApICsgJ1xcbic7XG4gICAgcmVwb3J0ICs9ICdTaW5nbGUgVGVtcGxhdGUgQ29zdCBBbmFseXNpc1xcbic7XG4gICAgcmVwb3J0ICs9ICc9Jy5yZXBlYXQoODApICsgJ1xcblxcbic7XG5cbiAgICAvLyBTdW1tYXJ5XG4gICAgcmVwb3J0ICs9IGBUb3RhbCBNb250aGx5IENvc3Q6ICQke3Jlc3VsdC50b3RhbE1vbnRobHlDb3N0LnRvRml4ZWQoMil9ICR7cmVzdWx0LmN1cnJlbmN5fVxcbmA7XG4gICAgcmVwb3J0ICs9IGBBbmFseXNpcyBEYXRlOiAke3Jlc3VsdC5tZXRhZGF0YS5hbmFseXplZEF0LnRvSVNPU3RyaW5nKCl9XFxuYDtcbiAgICByZXBvcnQgKz0gYFJlZ2lvbjogJHtyZXN1bHQubWV0YWRhdGEucmVnaW9ufVxcbmA7XG4gICAgcmVwb3J0ICs9IGBUZW1wbGF0ZSBIYXNoOiAke3Jlc3VsdC5tZXRhZGF0YS50ZW1wbGF0ZUhhc2h9XFxuXFxuYDtcblxuICAgIC8vIFJlc291cmNlIGNvdW50c1xuICAgIHJlcG9ydCArPSBgVG90YWwgUmVzb3VyY2VzOiAke3Jlc3VsdC5tZXRhZGF0YS5yZXNvdXJjZUNvdW50fVxcbmA7XG4gICAgcmVwb3J0ICs9IGBTdXBwb3J0ZWQgUmVzb3VyY2VzOiAke3Jlc3VsdC5tZXRhZGF0YS5zdXBwb3J0ZWRSZXNvdXJjZUNvdW50fVxcbmA7XG4gICAgcmVwb3J0ICs9IGBVbnN1cHBvcnRlZCBSZXNvdXJjZXM6ICR7cmVzdWx0Lm1ldGFkYXRhLnVuc3VwcG9ydGVkUmVzb3VyY2VDb3VudH1cXG5cXG5gO1xuXG4gICAgLy8gQ29zdCBicmVha2Rvd24gYnkgY29uZmlkZW5jZVxuICAgIGlmIChyZXN1bHQuY29zdEJyZWFrZG93bi5ieUNvbmZpZGVuY2VMZXZlbC5sZW5ndGggPiAwKSB7XG4gICAgICByZXBvcnQgKz0gJy0nLnJlcGVhdCg4MCkgKyAnXFxuJztcbiAgICAgIHJlcG9ydCArPSAnQ29zdCBDb25maWRlbmNlIEJyZWFrZG93blxcbic7XG4gICAgICByZXBvcnQgKz0gJy0nLnJlcGVhdCg4MCkgKyAnXFxuXFxuJztcblxuICAgICAgZm9yIChjb25zdCBjb25mIG9mIHJlc3VsdC5jb3N0QnJlYWtkb3duLmJ5Q29uZmlkZW5jZUxldmVsKSB7XG4gICAgICAgIGNvbnN0IHBlcmNlbnRhZ2UgPSAoKGNvbmYudG90YWxDb3N0IC8gcmVzdWx0LnRvdGFsTW9udGhseUNvc3QpICogMTAwKS50b0ZpeGVkKDEpO1xuICAgICAgICByZXBvcnQgKz0gYCR7Y29uZi5jb25maWRlbmNlLnRvVXBwZXJDYXNlKCkucGFkRW5kKDEwKX0gJHtjb25mLmNvdW50fSByZXNvdXJjZXMgICQke2NvbmYudG90YWxDb3N0LnRvRml4ZWQoMil9ICgke3BlcmNlbnRhZ2V9JSlcXG5gO1xuICAgICAgfVxuICAgICAgcmVwb3J0ICs9ICdcXG4nO1xuICAgIH1cblxuICAgIC8vIFJlc291cmNlIGJyZWFrZG93blxuICAgIGlmIChvcHRpb25zLnNob3dCcmVha2Rvd24gJiYgb3B0aW9ucy5ncm91cEJ5VHlwZSkge1xuICAgICAgcmVwb3J0ICs9ICctJy5yZXBlYXQoODApICsgJ1xcbic7XG4gICAgICByZXBvcnQgKz0gJ0Nvc3QgQnJlYWtkb3duIGJ5IFJlc291cmNlIFR5cGVcXG4nO1xuICAgICAgcmVwb3J0ICs9ICctJy5yZXBlYXQoODApICsgJ1xcblxcbic7XG5cbiAgICAgIGZvciAoY29uc3QgdHlwZUdyb3VwIG9mIHJlc3VsdC5jb3N0QnJlYWtkb3duLmJ5UmVzb3VyY2VUeXBlKSB7XG4gICAgICAgIGNvbnN0IHBlcmNlbnRhZ2UgPSAoKHR5cGVHcm91cC50b3RhbENvc3QgLyByZXN1bHQudG90YWxNb250aGx5Q29zdCkgKiAxMDApLnRvRml4ZWQoMSk7XG4gICAgICAgIHJlcG9ydCArPSBgJHt0eXBlR3JvdXAucmVzb3VyY2VUeXBlfVxcbmA7XG4gICAgICAgIHJlcG9ydCArPSBgICBDb3VudDogJHt0eXBlR3JvdXAuY291bnR9XFxuYDtcbiAgICAgICAgcmVwb3J0ICs9IGAgIFRvdGFsIENvc3Q6ICQke3R5cGVHcm91cC50b3RhbENvc3QudG9GaXhlZCgyKX0gKCR7cGVyY2VudGFnZX0lKVxcbmA7XG5cbiAgICAgICAgLy8gU2hvdyBpbmRpdmlkdWFsIHJlc291cmNlc1xuICAgICAgICBjb25zdCBzb3J0ZWRSZXNvdXJjZXMgPSB0aGlzLnNvcnRSZXNvdXJjZXModHlwZUdyb3VwLnJlc291cmNlcywgb3B0aW9ucy5zb3J0QnkpO1xuICAgICAgICBmb3IgKGNvbnN0IHJlc291cmNlIG9mIHNvcnRlZFJlc291cmNlcykge1xuICAgICAgICAgIGNvbnN0IGNvbmYgPSByZXNvdXJjZS5tb250aGx5Q29zdC5jb25maWRlbmNlO1xuICAgICAgICAgIGNvbnN0IGNvbmZJbmRpY2F0b3IgPSBjb25mID09PSAnaGlnaCcgPyAn4pyTJyA6IGNvbmYgPT09ICdtZWRpdW0nID8gJ34nIDogY29uZiA9PT0gJ2xvdycgPyAnPycgOiAn4pyXJztcbiAgICAgICAgICByZXBvcnQgKz0gYCAgICAke2NvbmZJbmRpY2F0b3J9ICR7cmVzb3VyY2UubG9naWNhbElkLnBhZEVuZCg0MCl9ICQke3Jlc291cmNlLm1vbnRobHlDb3N0LmFtb3VudC50b0ZpeGVkKDIpfVxcbmA7XG4gICAgICAgIH1cbiAgICAgICAgcmVwb3J0ICs9ICdcXG4nO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEFzc3VtcHRpb25zXG4gICAgaWYgKG9wdGlvbnMuc2hvd0Fzc3VtcHRpb25zICYmIHJlc3VsdC5jb3N0QnJlYWtkb3duLmFzc3VtcHRpb25zLmxlbmd0aCA+IDApIHtcbiAgICAgIHJlcG9ydCArPSAnLScucmVwZWF0KDgwKSArICdcXG4nO1xuICAgICAgcmVwb3J0ICs9ICdDb3N0IENhbGN1bGF0aW9uIEFzc3VtcHRpb25zXFxuJztcbiAgICAgIHJlcG9ydCArPSAnLScucmVwZWF0KDgwKSArICdcXG5cXG4nO1xuXG4gICAgICBmb3IgKGNvbnN0IGFzc3VtcHRpb24gb2YgcmVzdWx0LmNvc3RCcmVha2Rvd24uYXNzdW1wdGlvbnMpIHtcbiAgICAgICAgcmVwb3J0ICs9IGAgIOKAoiAke2Fzc3VtcHRpb259XFxuYDtcbiAgICAgIH1cbiAgICAgIHJlcG9ydCArPSAnXFxuJztcbiAgICB9XG5cbiAgICAvLyBMZWdlbmRcbiAgICByZXBvcnQgKz0gJy0nLnJlcGVhdCg4MCkgKyAnXFxuJztcbiAgICByZXBvcnQgKz0gJ0xlZ2VuZDog4pyTIEhpZ2ggY29uZmlkZW5jZSAgfiBNZWRpdW0gY29uZmlkZW5jZSAgPyBMb3cgY29uZmlkZW5jZSAg4pyXIFVua25vd24vVW5zdXBwb3J0ZWRcXG4nO1xuICAgIHJlcG9ydCArPSAnPScucmVwZWF0KDgwKSArICdcXG4nO1xuXG4gICAgcmV0dXJuIHJlcG9ydDtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSBtYXJrZG93biBmb3JtYXQgcmVwb3J0XG4gICAqL1xuICBwcml2YXRlIGdlbmVyYXRlTWFya2Rvd25SZXBvcnQoXG4gICAgcmVzdWx0OiBTaW5nbGVUZW1wbGF0ZUNvc3RSZXN1bHQsXG4gICAgb3B0aW9uczogUmVxdWlyZWQ8U2luZ2xlVGVtcGxhdGVSZXBvcnRPcHRpb25zPixcbiAgKTogc3RyaW5nIHtcbiAgICBsZXQgcmVwb3J0ID0gJyc7XG5cbiAgICAvLyBIZWFkZXJcbiAgICByZXBvcnQgKz0gJyMgU2luZ2xlIFRlbXBsYXRlIENvc3QgQW5hbHlzaXNcXG5cXG4nO1xuXG4gICAgLy8gU3VtbWFyeVxuICAgIHJlcG9ydCArPSAnIyMgU3VtbWFyeVxcblxcbic7XG4gICAgcmVwb3J0ICs9IGAqKlRvdGFsIE1vbnRobHkgQ29zdDoqKiAkJHtyZXN1bHQudG90YWxNb250aGx5Q29zdC50b0ZpeGVkKDIpfSAke3Jlc3VsdC5jdXJyZW5jeX1cXG5cXG5gO1xuICAgIHJlcG9ydCArPSBgLSAqKkFuYWx5c2lzIERhdGU6KiogJHtyZXN1bHQubWV0YWRhdGEuYW5hbHl6ZWRBdC50b0lTT1N0cmluZygpfVxcbmA7XG4gICAgcmVwb3J0ICs9IGAtICoqUmVnaW9uOioqICR7cmVzdWx0Lm1ldGFkYXRhLnJlZ2lvbn1cXG5gO1xuICAgIHJlcG9ydCArPSBgLSAqKlRlbXBsYXRlIEhhc2g6KiogJHtyZXN1bHQubWV0YWRhdGEudGVtcGxhdGVIYXNofVxcblxcbmA7XG5cbiAgICAvLyBSZXNvdXJjZSBjb3VudHNcbiAgICByZXBvcnQgKz0gJyMjIFJlc291cmNlIE92ZXJ2aWV3XFxuXFxuJztcbiAgICByZXBvcnQgKz0gYC0gKipUb3RhbCBSZXNvdXJjZXM6KiogJHtyZXN1bHQubWV0YWRhdGEucmVzb3VyY2VDb3VudH1cXG5gO1xuICAgIHJlcG9ydCArPSBgLSAqKlN1cHBvcnRlZCBSZXNvdXJjZXM6KiogJHtyZXN1bHQubWV0YWRhdGEuc3VwcG9ydGVkUmVzb3VyY2VDb3VudH1cXG5gO1xuICAgIHJlcG9ydCArPSBgLSAqKlVuc3VwcG9ydGVkIFJlc291cmNlczoqKiAke3Jlc3VsdC5tZXRhZGF0YS51bnN1cHBvcnRlZFJlc291cmNlQ291bnR9XFxuXFxuYDtcblxuICAgIC8vIENvc3QgYnJlYWtkb3duIGJ5IGNvbmZpZGVuY2VcbiAgICBpZiAocmVzdWx0LmNvc3RCcmVha2Rvd24uYnlDb25maWRlbmNlTGV2ZWwubGVuZ3RoID4gMCkge1xuICAgICAgcmVwb3J0ICs9ICcjIyBDb3N0IENvbmZpZGVuY2UgQnJlYWtkb3duXFxuXFxuJztcbiAgICAgIHJlcG9ydCArPSAnfCBDb25maWRlbmNlIHwgUmVzb3VyY2VzIHwgQ29zdCB8IFBlcmNlbnRhZ2UgfFxcbic7XG4gICAgICByZXBvcnQgKz0gJ3wtLS0tLS0tLS0tLS18LS0tLS0tLS0tLS18LS0tLS0tfC0tLS0tLS0tLS0tLXxcXG4nO1xuXG4gICAgICBmb3IgKGNvbnN0IGNvbmYgb2YgcmVzdWx0LmNvc3RCcmVha2Rvd24uYnlDb25maWRlbmNlTGV2ZWwpIHtcbiAgICAgICAgY29uc3QgcGVyY2VudGFnZSA9ICgoY29uZi50b3RhbENvc3QgLyByZXN1bHQudG90YWxNb250aGx5Q29zdCkgKiAxMDApLnRvRml4ZWQoMSk7XG4gICAgICAgIHJlcG9ydCArPSBgfCAke2NvbmYuY29uZmlkZW5jZX0gfCAke2NvbmYuY291bnR9IHwgJCR7Y29uZi50b3RhbENvc3QudG9GaXhlZCgyKX0gfCAke3BlcmNlbnRhZ2V9JSB8XFxuYDtcbiAgICAgIH1cbiAgICAgIHJlcG9ydCArPSAnXFxuJztcbiAgICB9XG5cbiAgICAvLyBSZXNvdXJjZSBicmVha2Rvd24gYnkgdHlwZVxuICAgIGlmIChvcHRpb25zLnNob3dCcmVha2Rvd24gJiYgb3B0aW9ucy5ncm91cEJ5VHlwZSkge1xuICAgICAgcmVwb3J0ICs9ICcjIyBDb3N0IEJyZWFrZG93biBieSBSZXNvdXJjZSBUeXBlXFxuXFxuJztcblxuICAgICAgZm9yIChjb25zdCB0eXBlR3JvdXAgb2YgcmVzdWx0LmNvc3RCcmVha2Rvd24uYnlSZXNvdXJjZVR5cGUpIHtcbiAgICAgICAgY29uc3QgcGVyY2VudGFnZSA9ICgodHlwZUdyb3VwLnRvdGFsQ29zdCAvIHJlc3VsdC50b3RhbE1vbnRobHlDb3N0KSAqIDEwMCkudG9GaXhlZCgxKTtcbiAgICAgICAgcmVwb3J0ICs9IGAjIyMgJHt0eXBlR3JvdXAucmVzb3VyY2VUeXBlfVxcblxcbmA7XG4gICAgICAgIHJlcG9ydCArPSBgLSAqKkNvdW50OioqICR7dHlwZUdyb3VwLmNvdW50fVxcbmA7XG4gICAgICAgIHJlcG9ydCArPSBgLSAqKlRvdGFsIENvc3Q6KiogJCR7dHlwZUdyb3VwLnRvdGFsQ29zdC50b0ZpeGVkKDIpfSAoJHtwZXJjZW50YWdlfSUpXFxuXFxuYDtcblxuICAgICAgICAvLyBTaG93IGluZGl2aWR1YWwgcmVzb3VyY2VzIGluIHRhYmxlXG4gICAgICAgIHJlcG9ydCArPSAnfCBSZXNvdXJjZSB8IENvc3QgfCBDb25maWRlbmNlIHxcXG4nO1xuICAgICAgICByZXBvcnQgKz0gJ3wtLS0tLS0tLS0tfC0tLS0tLXwtLS0tLS0tLS0tLS18XFxuJztcblxuICAgICAgICBjb25zdCBzb3J0ZWRSZXNvdXJjZXMgPSB0aGlzLnNvcnRSZXNvdXJjZXModHlwZUdyb3VwLnJlc291cmNlcywgb3B0aW9ucy5zb3J0QnkpO1xuICAgICAgICBmb3IgKGNvbnN0IHJlc291cmNlIG9mIHNvcnRlZFJlc291cmNlcykge1xuICAgICAgICAgIGNvbnN0IGNvbmYgPSByZXNvdXJjZS5tb250aGx5Q29zdC5jb25maWRlbmNlO1xuICAgICAgICAgIHJlcG9ydCArPSBgfCAke3Jlc291cmNlLmxvZ2ljYWxJZH0gfCAkJHtyZXNvdXJjZS5tb250aGx5Q29zdC5hbW91bnQudG9GaXhlZCgyKX0gfCAke2NvbmZ9IHxcXG5gO1xuICAgICAgICB9XG4gICAgICAgIHJlcG9ydCArPSAnXFxuJztcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBBc3N1bXB0aW9uc1xuICAgIGlmIChvcHRpb25zLnNob3dBc3N1bXB0aW9ucyAmJiByZXN1bHQuY29zdEJyZWFrZG93bi5hc3N1bXB0aW9ucy5sZW5ndGggPiAwKSB7XG4gICAgICByZXBvcnQgKz0gJyMjIENvc3QgQ2FsY3VsYXRpb24gQXNzdW1wdGlvbnNcXG5cXG4nO1xuICAgICAgZm9yIChjb25zdCBhc3N1bXB0aW9uIG9mIHJlc3VsdC5jb3N0QnJlYWtkb3duLmFzc3VtcHRpb25zKSB7XG4gICAgICAgIHJlcG9ydCArPSBgLSAke2Fzc3VtcHRpb259XFxuYDtcbiAgICAgIH1cbiAgICAgIHJlcG9ydCArPSAnXFxuJztcbiAgICB9XG5cbiAgICAvLyBMZWdlbmRcbiAgICByZXBvcnQgKz0gJy0tLVxcblxcbic7XG4gICAgcmVwb3J0ICs9ICcqQ29uZmlkZW5jZSBsZXZlbHM6IGhpZ2ggKOKckyksIG1lZGl1bSAofiksIGxvdyAoPyksIHVua25vd24vdW5zdXBwb3J0ZWQgKOKclykqXFxuJztcblxuICAgIHJldHVybiByZXBvcnQ7XG4gIH1cblxuICAvKipcbiAgICogU29ydCByZXNvdXJjZXMgYmFzZWQgb24gc3BlY2lmaWVkIGNyaXRlcmlhXG4gICAqL1xuICBwcml2YXRlIHNvcnRSZXNvdXJjZXMoXG4gICAgcmVzb3VyY2VzOiBBcnJheTx7IGxvZ2ljYWxJZDogc3RyaW5nOyB0eXBlOiBzdHJpbmc7IG1vbnRobHlDb3N0OiBhbnkgfT4sXG4gICAgc29ydEJ5OiAnY29zdCcgfCAnbmFtZScgfCAndHlwZScsXG4gICk6IEFycmF5PHsgbG9naWNhbElkOiBzdHJpbmc7IHR5cGU6IHN0cmluZzsgbW9udGhseUNvc3Q6IGFueSB9PiB7XG4gICAgY29uc3Qgc29ydGVkID0gWy4uLnJlc291cmNlc107XG5cbiAgICBzd2l0Y2ggKHNvcnRCeSkge1xuICAgICAgY2FzZSAnY29zdCc6XG4gICAgICAgIHNvcnRlZC5zb3J0KChhLCBiKSA9PiBiLm1vbnRobHlDb3N0LmFtb3VudCAtIGEubW9udGhseUNvc3QuYW1vdW50KTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICduYW1lJzpcbiAgICAgICAgc29ydGVkLnNvcnQoKGEsIGIpID0+IGEubG9naWNhbElkLmxvY2FsZUNvbXBhcmUoYi5sb2dpY2FsSWQpKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICd0eXBlJzpcbiAgICAgICAgc29ydGVkLnNvcnQoKGEsIGIpID0+IGEudHlwZS5sb2NhbGVDb21wYXJlKGIudHlwZSkpO1xuICAgICAgICBicmVhaztcbiAgICB9XG5cbiAgICByZXR1cm4gc29ydGVkO1xuICB9XG59XG4iXX0=
@@ -1,2 +1,3 @@
1
1
  export { Reporter } from './Reporter';
2
+ export { SingleTemplateReporter } from './SingleTemplateReporter';
2
3
  export * from './types';
@@ -14,8 +14,10 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.Reporter = void 0;
17
+ exports.SingleTemplateReporter = exports.Reporter = void 0;
18
18
  var Reporter_1 = require("./Reporter");
19
19
  Object.defineProperty(exports, "Reporter", { enumerable: true, get: function () { return Reporter_1.Reporter; } });
20
+ var SingleTemplateReporter_1 = require("./SingleTemplateReporter");
21
+ Object.defineProperty(exports, "SingleTemplateReporter", { enumerable: true, get: function () { return SingleTemplateReporter_1.SingleTemplateReporter; } });
20
22
  __exportStar(require("./types"), exports);
21
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcmVwb3J0ZXIvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSx1Q0FBc0M7QUFBN0Isb0dBQUEsUUFBUSxPQUFBO0FBQ2pCLDBDQUF3QiIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCB7IFJlcG9ydGVyIH0gZnJvbSAnLi9SZXBvcnRlcic7XG5leHBvcnQgKiBmcm9tICcuL3R5cGVzJztcbiJdfQ==
23
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcmVwb3J0ZXIvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSx1Q0FBc0M7QUFBN0Isb0dBQUEsUUFBUSxPQUFBO0FBQ2pCLG1FQUFrRTtBQUF6RCxnSUFBQSxzQkFBc0IsT0FBQTtBQUMvQiwwQ0FBd0IiLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgeyBSZXBvcnRlciB9IGZyb20gJy4vUmVwb3J0ZXInO1xuZXhwb3J0IHsgU2luZ2xlVGVtcGxhdGVSZXBvcnRlciB9IGZyb20gJy4vU2luZ2xlVGVtcGxhdGVSZXBvcnRlcic7XG5leHBvcnQgKiBmcm9tICcuL3R5cGVzJztcbiJdfQ==
@@ -0,0 +1,372 @@
1
+ # Single Template Cost Analysis - Quick Reference
2
+
3
+ ## Overview
4
+
5
+ The single template cost analysis feature allows you to estimate the monthly costs of AWS resources defined in a CloudFormation template without requiring a comparison baseline.
6
+
7
+ ## CLI Usage
8
+
9
+ ### Basic Analysis
10
+
11
+ ```bash
12
+ # Analyze a template with default settings (eu-central-1)
13
+ cdk-cost-analyzer analyze template.json
14
+
15
+ # Specify a region
16
+ cdk-cost-analyzer analyze template.yaml --region us-east-1
17
+
18
+ # Different output formats
19
+ cdk-cost-analyzer analyze template.json --format text # Default, human-readable
20
+ cdk-cost-analyzer analyze template.json --format json # Machine-readable
21
+ cdk-cost-analyzer analyze template.json --format markdown # Documentation-friendly
22
+
23
+ # Enable debug logging
24
+ cdk-cost-analyzer analyze template.json --debug
25
+ ```
26
+
27
+ ### With Configuration
28
+
29
+ ```bash
30
+ # Use a configuration file for usage assumptions and exclusions
31
+ cdk-cost-analyzer analyze template.json --config .cdk-cost-analyzer.yml --region us-east-1
32
+ ```
33
+
34
+ Example configuration file (`.cdk-cost-analyzer.yml`):
35
+
36
+ ```yaml
37
+ usageAssumptions:
38
+ lambda:
39
+ invocationsPerMonth: 10000000
40
+ averageDurationMs: 500
41
+ s3:
42
+ storageGB: 1000
43
+ requestsPerMonth: 1000000
44
+ natGateway:
45
+ dataProcessedGB: 500
46
+
47
+ exclusions:
48
+ resourceTypes:
49
+ - AWS::IAM::Role
50
+ - AWS::Logs::LogGroup
51
+ ```
52
+
53
+ ## API Usage
54
+
55
+ ### TypeScript/JavaScript
56
+
57
+ ```typescript
58
+ import { analyzeSingleTemplate } from 'cdk-cost-analyzer';
59
+
60
+ // Basic analysis
61
+ const result = await analyzeSingleTemplate({
62
+ template: templateContent, // JSON or YAML string
63
+ region: 'us-east-1',
64
+ format: 'text'
65
+ });
66
+
67
+ console.log(result.summary);
68
+ console.log(`Total cost: $${result.totalMonthlyCost.toFixed(2)}`);
69
+ ```
70
+
71
+ ### With Configuration
72
+
73
+ ```typescript
74
+ const result = await analyzeSingleTemplate({
75
+ template: templateContent,
76
+ region: 'us-east-1',
77
+ config: {
78
+ usageAssumptions: {
79
+ lambda: {
80
+ invocationsPerMonth: 10000000,
81
+ averageDurationMs: 500
82
+ }
83
+ },
84
+ excludedResourceTypes: ['AWS::IAM::Role']
85
+ }
86
+ });
87
+ ```
88
+
89
+ ### Accessing Detailed Results
90
+
91
+ ```typescript
92
+ const result = await analyzeSingleTemplate({
93
+ template: templateContent,
94
+ region: 'us-east-1'
95
+ });
96
+
97
+ // Total cost
98
+ console.log(`Total: $${result.totalMonthlyCost} ${result.currency}`);
99
+
100
+ // Metadata
101
+ console.log(`Total resources: ${result.metadata.resourceCount}`);
102
+ console.log(`Supported: ${result.metadata.supportedResourceCount}`);
103
+ console.log(`Unsupported: ${result.metadata.unsupportedResourceCount}`);
104
+
105
+ // Resource costs
106
+ result.resourceCosts.forEach(rc => {
107
+ console.log(`${rc.logicalId} (${rc.type}): $${rc.monthlyCost.amount}`);
108
+ console.log(` Confidence: ${rc.monthlyCost.confidence}`);
109
+ console.log(` Assumptions: ${rc.monthlyCost.assumptions.join(', ')}`);
110
+ });
111
+
112
+ // Cost breakdown by type
113
+ result.costBreakdown.byResourceType.forEach(group => {
114
+ console.log(`${group.resourceType}: ${group.count} resources, $${group.totalCost}`);
115
+ });
116
+ ```
117
+
118
+ ## Output Formats
119
+
120
+ ### Text Format (Default)
121
+
122
+ Human-readable report with:
123
+ - Total monthly cost
124
+ - Resource counts and support status
125
+ - Cost confidence breakdown
126
+ - Cost breakdown by resource type
127
+ - Individual resource costs with visual indicators
128
+ - Assumptions list
129
+ - Legend
130
+
131
+ Example:
132
+ ```
133
+ ================================================================================
134
+ Single Template Cost Analysis
135
+ ================================================================================
136
+
137
+ Total Monthly Cost: $123.45 USD
138
+ Analysis Date: 2024-01-20T10:30:00.000Z
139
+ Region: us-east-1
140
+ Template Hash: abc123def456
141
+
142
+ Total Resources: 5
143
+ Supported: 4
144
+ Unsupported: 1
145
+
146
+ --------------------------------------------------------------------------------
147
+ Cost Confidence Breakdown
148
+ --------------------------------------------------------------------------------
149
+
150
+ HIGH 2 resources $100.00 (81.0%)
151
+ MEDIUM 2 resources $23.45 (19.0%)
152
+
153
+ --------------------------------------------------------------------------------
154
+ Cost Breakdown by Resource Type
155
+ --------------------------------------------------------------------------------
156
+
157
+ AWS::EC2::Instance
158
+ Count: 1
159
+ Total Cost: $100.00 (81.0%)
160
+ ✓ MyInstance $100.00
161
+
162
+ AWS::S3::Bucket
163
+ Count: 1
164
+ Total Cost: $23.45 (19.0%)
165
+ ~ MyBucket $23.45
166
+
167
+ ...
168
+ ```
169
+
170
+ ### JSON Format
171
+
172
+ Machine-readable format for programmatic processing:
173
+
174
+ ```json
175
+ {
176
+ "totalMonthlyCost": 123.45,
177
+ "currency": "USD",
178
+ "resourceCosts": [...],
179
+ "costBreakdown": {
180
+ "byResourceType": [...],
181
+ "byConfidenceLevel": [...],
182
+ "assumptions": [...]
183
+ },
184
+ "metadata": {
185
+ "templateHash": "abc123def456",
186
+ "region": "us-east-1",
187
+ "analyzedAt": "2024-01-20T10:30:00.000Z",
188
+ "resourceCount": 5,
189
+ "supportedResourceCount": 4,
190
+ "unsupportedResourceCount": 1
191
+ }
192
+ }
193
+ ```
194
+
195
+ ### Markdown Format
196
+
197
+ Documentation-friendly format with tables:
198
+
199
+ ```markdown
200
+ # Single Template Cost Analysis
201
+
202
+ ## Summary
203
+
204
+ **Total Monthly Cost:** $123.45 USD
205
+
206
+ - **Analysis Date:** 2024-01-20T10:30:00.000Z
207
+ - **Region:** us-east-1
208
+ - **Template Hash:** abc123def456
209
+
210
+ ## Resource Overview
211
+
212
+ - **Total Resources:** 5
213
+ - **Supported Resources:** 4
214
+ - **Unsupported Resources:** 1
215
+
216
+ ## Cost Confidence Breakdown
217
+
218
+ | Confidence | Resources | Cost | Percentage |
219
+ |------------|-----------|------|------------|
220
+ | high | 2 | $100.00 | 81.0% |
221
+ | medium | 2 | $23.45 | 19.0% |
222
+
223
+ ...
224
+ ```
225
+
226
+ ## Error Handling
227
+
228
+ ### Missing Template File
229
+
230
+ ```bash
231
+ $ cdk-cost-analyzer analyze missing.json
232
+ Error: Template file not found: missing.json
233
+ ```
234
+
235
+ ### Invalid Template
236
+
237
+ ```bash
238
+ $ cdk-cost-analyzer analyze invalid.json
239
+ Error: Failed to parse template: Unexpected token...
240
+ ```
241
+
242
+ ### Missing AWS Credentials
243
+
244
+ ```bash
245
+ $ cdk-cost-analyzer analyze template.json
246
+ Error: AWS credentials not configured. Please set AWS credentials using one of:
247
+ - AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables
248
+ - AWS_PROFILE environment variable
249
+ - AWS credentials file (~/.aws/credentials)
250
+ - For CI/CD, configure AWS credentials in your pipeline
251
+ ```
252
+
253
+ ## Confidence Levels
254
+
255
+ | Level | Symbol | Meaning |
256
+ |-------|--------|---------|
257
+ | high | ✓ | Pricing data available, minimal assumptions |
258
+ | medium | ~ | Some assumptions made about usage patterns |
259
+ | low | ? | Significant assumptions or limited pricing data |
260
+ | unknown | ✗ | Resource type not supported or no pricing data |
261
+
262
+ ## Supported Resource Types
263
+
264
+ The analyzer supports 14+ AWS resource types including:
265
+ - EC2 Instances
266
+ - S3 Buckets
267
+ - Lambda Functions
268
+ - RDS Database Instances
269
+ - DynamoDB Tables
270
+ - ECS Services
271
+ - API Gateway (REST, HTTP, WebSocket)
272
+ - NAT Gateways
273
+ - Application Load Balancers
274
+ - Network Load Balancers
275
+ - VPC Endpoints
276
+ - CloudFront Distributions
277
+ - ElastiCache Clusters
278
+
279
+ See [CALCULATORS.md](../docs/CALCULATORS.md) for complete list and calculation details.
280
+
281
+ ## Usage Assumptions
282
+
283
+ Default assumptions (can be overridden in config):
284
+
285
+ - **S3**: 100GB storage, 10,000 requests/month
286
+ - **Lambda**: 1M invocations/month, 1s average duration
287
+ - **NAT Gateway**: 500GB data processed/month
288
+ - **ALB**: 50 new connections/sec, 5,000 active/min, 1,000GB processed
289
+ - **CloudFront**: 100GB data transfer, 1M requests/month
290
+
291
+ All assumptions are displayed in the output report.
292
+
293
+ ## Common Use Cases
294
+
295
+ ### 1. Pre-Deployment Cost Estimation
296
+
297
+ ```bash
298
+ # Before deploying a new stack
299
+ cdk synth > template.json
300
+ cdk-cost-analyzer analyze template.json --region us-east-1
301
+ ```
302
+
303
+ ### 2. Template Validation
304
+
305
+ ```bash
306
+ # Check if a template can be analyzed for costs
307
+ cdk-cost-analyzer analyze template.yaml --format json | jq '.metadata.supportedResourceCount'
308
+ ```
309
+
310
+ ### 3. Cost Comparison of Template Variations
311
+
312
+ ```bash
313
+ # Analyze different configurations
314
+ cdk-cost-analyzer analyze template-small.json > cost-small.txt
315
+ cdk-cost-analyzer analyze template-large.json > cost-large.txt
316
+ diff cost-small.txt cost-large.txt
317
+ ```
318
+
319
+ ### 4. CI/CD Integration
320
+
321
+ ```yaml
322
+ # .github/workflows/cost-check.yml
323
+ - name: Analyze Costs
324
+ run: |
325
+ cdk synth > template.json
326
+ cdk-cost-analyzer analyze template.json --format markdown >> $GITHUB_STEP_SUMMARY
327
+ ```
328
+
329
+ ### 5. Documentation Generation
330
+
331
+ ```bash
332
+ # Generate cost documentation for a template
333
+ cdk-cost-analyzer analyze infrastructure.json --format markdown > docs/cost-estimate.md
334
+ ```
335
+
336
+ ## Tips
337
+
338
+ 1. **Use Debug Mode**: Add `--debug` flag to see detailed pricing API queries and responses
339
+ 2. **Cache Pricing Data**: The tool automatically caches pricing data for 24 hours
340
+ 3. **Regional Pricing**: Always specify the region where resources will be deployed
341
+ 4. **Custom Assumptions**: Create a config file for your project's specific usage patterns
342
+ 5. **JSON Output**: Use JSON format for integrating with other tools or dashboards
343
+
344
+ ## Troubleshooting
345
+
346
+ ### Zero costs for resources
347
+
348
+ ```bash
349
+ # Use debug mode to see pricing queries
350
+ cdk-cost-analyzer analyze template.json --debug 2>&1 | grep "Pricing API"
351
+ ```
352
+
353
+ ### Slow analysis
354
+
355
+ ```bash
356
+ # Pricing data is cached, first run may be slow
357
+ # Subsequent runs use cache and are faster
358
+ ```
359
+
360
+ ### Inconsistent results
361
+
362
+ ```bash
363
+ # Clear the cache if you get stale pricing data
364
+ rm -rf .cdk-cost-analyzer-cache
365
+ ```
366
+
367
+ ## Further Reading
368
+
369
+ - [Configuration Guide](../docs/CONFIGURATION.md)
370
+ - [Calculator Reference](../docs/CALCULATORS.md)
371
+ - [Troubleshooting Guide](../docs/TROUBLESHOOTING.md)
372
+ - [API Examples](../examples/api-usage.js)