@friggframework/devtools 2.0.0-next.45 → 2.0.0-next.47
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/infrastructure/ARCHITECTURE.md +487 -0
- package/infrastructure/HEALTH.md +468 -0
- package/infrastructure/README.md +51 -0
- package/infrastructure/__tests__/postgres-config.test.js +914 -0
- package/infrastructure/__tests__/template-generation.test.js +687 -0
- package/infrastructure/create-frigg-infrastructure.js +1 -1
- package/infrastructure/docs/POSTGRES-CONFIGURATION.md +630 -0
- package/infrastructure/{DEPLOYMENT-INSTRUCTIONS.md → docs/deployment-instructions.md} +3 -3
- package/infrastructure/{IAM-POLICY-TEMPLATES.md → docs/iam-policy-templates.md} +9 -10
- package/infrastructure/domains/database/aurora-builder.js +809 -0
- package/infrastructure/domains/database/aurora-builder.test.js +950 -0
- package/infrastructure/domains/database/aurora-discovery.js +87 -0
- package/infrastructure/domains/database/aurora-discovery.test.js +188 -0
- package/infrastructure/domains/database/aurora-resolver.js +210 -0
- package/infrastructure/domains/database/aurora-resolver.test.js +347 -0
- package/infrastructure/domains/database/migration-builder.js +695 -0
- package/infrastructure/domains/database/migration-builder.test.js +294 -0
- package/infrastructure/domains/database/migration-resolver.js +163 -0
- package/infrastructure/domains/database/migration-resolver.test.js +337 -0
- package/infrastructure/domains/health/application/ports/IPropertyReconciler.js +164 -0
- package/infrastructure/domains/health/application/ports/IResourceDetector.js +129 -0
- package/infrastructure/domains/health/application/ports/IResourceImporter.js +142 -0
- package/infrastructure/domains/health/application/ports/IStackRepository.js +131 -0
- package/infrastructure/domains/health/application/ports/index.js +26 -0
- package/infrastructure/domains/health/application/use-cases/__tests__/execute-resource-import-use-case.test.js +679 -0
- package/infrastructure/domains/health/application/use-cases/__tests__/mismatch-analyzer-method-name.test.js +167 -0
- package/infrastructure/domains/health/application/use-cases/__tests__/repair-via-import-use-case.test.js +1130 -0
- package/infrastructure/domains/health/application/use-cases/execute-resource-import-use-case.js +221 -0
- package/infrastructure/domains/health/application/use-cases/reconcile-properties-use-case.js +152 -0
- package/infrastructure/domains/health/application/use-cases/reconcile-properties-use-case.test.js +343 -0
- package/infrastructure/domains/health/application/use-cases/repair-via-import-use-case.js +535 -0
- package/infrastructure/domains/health/application/use-cases/repair-via-import-use-case.test.js +376 -0
- package/infrastructure/domains/health/application/use-cases/run-health-check-use-case.js +213 -0
- package/infrastructure/domains/health/application/use-cases/run-health-check-use-case.test.js +441 -0
- package/infrastructure/domains/health/docs/ACME-DEV-DRIFT-ANALYSIS.md +267 -0
- package/infrastructure/domains/health/docs/BUILD-VS-DEPLOYED-TEMPLATE-ANALYSIS.md +324 -0
- package/infrastructure/domains/health/docs/ORPHAN-DETECTION-ANALYSIS.md +386 -0
- package/infrastructure/domains/health/docs/SPEC-CLEANUP-COMMAND.md +1419 -0
- package/infrastructure/domains/health/docs/TDD-IMPLEMENTATION-SUMMARY.md +391 -0
- package/infrastructure/domains/health/docs/TEMPLATE-COMPARISON-IMPLEMENTATION.md +551 -0
- package/infrastructure/domains/health/domain/entities/issue.js +299 -0
- package/infrastructure/domains/health/domain/entities/issue.test.js +528 -0
- package/infrastructure/domains/health/domain/entities/property-mismatch.js +108 -0
- package/infrastructure/domains/health/domain/entities/property-mismatch.test.js +275 -0
- package/infrastructure/domains/health/domain/entities/resource.js +159 -0
- package/infrastructure/domains/health/domain/entities/resource.test.js +432 -0
- package/infrastructure/domains/health/domain/entities/stack-health-report.js +306 -0
- package/infrastructure/domains/health/domain/entities/stack-health-report.test.js +601 -0
- package/infrastructure/domains/health/domain/services/__tests__/health-score-percentage-based.test.js +380 -0
- package/infrastructure/domains/health/domain/services/__tests__/import-progress-monitor.test.js +971 -0
- package/infrastructure/domains/health/domain/services/__tests__/import-template-generator.test.js +1150 -0
- package/infrastructure/domains/health/domain/services/__tests__/logical-id-mapper.test.js +672 -0
- package/infrastructure/domains/health/domain/services/__tests__/template-parser.test.js +496 -0
- package/infrastructure/domains/health/domain/services/__tests__/update-progress-monitor.test.js +419 -0
- package/infrastructure/domains/health/domain/services/health-score-calculator.js +248 -0
- package/infrastructure/domains/health/domain/services/health-score-calculator.test.js +504 -0
- package/infrastructure/domains/health/domain/services/import-progress-monitor.js +195 -0
- package/infrastructure/domains/health/domain/services/import-template-generator.js +435 -0
- package/infrastructure/domains/health/domain/services/logical-id-mapper.js +345 -0
- package/infrastructure/domains/health/domain/services/mismatch-analyzer.js +234 -0
- package/infrastructure/domains/health/domain/services/mismatch-analyzer.test.js +431 -0
- package/infrastructure/domains/health/domain/services/property-mutability-config.js +382 -0
- package/infrastructure/domains/health/domain/services/template-parser.js +245 -0
- package/infrastructure/domains/health/domain/services/update-progress-monitor.js +192 -0
- package/infrastructure/domains/health/domain/value-objects/health-score.js +138 -0
- package/infrastructure/domains/health/domain/value-objects/health-score.test.js +267 -0
- package/infrastructure/domains/health/domain/value-objects/property-mutability.js +161 -0
- package/infrastructure/domains/health/domain/value-objects/property-mutability.test.js +198 -0
- package/infrastructure/domains/health/domain/value-objects/resource-state.js +167 -0
- package/infrastructure/domains/health/domain/value-objects/resource-state.test.js +196 -0
- package/infrastructure/domains/health/domain/value-objects/stack-identifier.js +192 -0
- package/infrastructure/domains/health/domain/value-objects/stack-identifier.test.js +262 -0
- package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-cfn-tagged.test.js +312 -0
- package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-multi-stack.test.js +367 -0
- package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-relationship-analysis.test.js +432 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-property-reconciler.js +784 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-property-reconciler.test.js +1133 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-resource-detector.js +565 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-resource-detector.test.js +554 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-resource-importer.js +318 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-resource-importer.test.js +398 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-stack-repository.js +777 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-stack-repository.test.js +580 -0
- package/infrastructure/domains/integration/integration-builder.js +397 -0
- package/infrastructure/domains/integration/integration-builder.test.js +593 -0
- package/infrastructure/domains/integration/integration-resolver.js +170 -0
- package/infrastructure/domains/integration/integration-resolver.test.js +369 -0
- package/infrastructure/domains/integration/websocket-builder.js +69 -0
- package/infrastructure/domains/integration/websocket-builder.test.js +195 -0
- package/infrastructure/domains/networking/vpc-builder.js +1829 -0
- package/infrastructure/domains/networking/vpc-builder.test.js +1262 -0
- package/infrastructure/domains/networking/vpc-discovery.js +177 -0
- package/infrastructure/domains/networking/vpc-discovery.test.js +350 -0
- package/infrastructure/domains/networking/vpc-resolver.js +324 -0
- package/infrastructure/domains/networking/vpc-resolver.test.js +501 -0
- package/infrastructure/domains/parameters/ssm-builder.js +79 -0
- package/infrastructure/domains/parameters/ssm-builder.test.js +189 -0
- package/infrastructure/domains/parameters/ssm-discovery.js +84 -0
- package/infrastructure/domains/parameters/ssm-discovery.test.js +210 -0
- package/infrastructure/{iam-generator.js → domains/security/iam-generator.js} +2 -2
- package/infrastructure/domains/security/kms-builder.js +366 -0
- package/infrastructure/domains/security/kms-builder.test.js +374 -0
- package/infrastructure/domains/security/kms-discovery.js +80 -0
- package/infrastructure/domains/security/kms-discovery.test.js +177 -0
- package/infrastructure/domains/security/kms-resolver.js +96 -0
- package/infrastructure/domains/security/kms-resolver.test.js +216 -0
- package/infrastructure/domains/shared/base-builder.js +112 -0
- package/infrastructure/domains/shared/base-resolver.js +186 -0
- package/infrastructure/domains/shared/base-resolver.test.js +305 -0
- package/infrastructure/domains/shared/builder-orchestrator.js +212 -0
- package/infrastructure/domains/shared/builder-orchestrator.test.js +213 -0
- package/infrastructure/domains/shared/cloudformation-discovery-v2.js +334 -0
- package/infrastructure/domains/shared/cloudformation-discovery.js +375 -0
- package/infrastructure/domains/shared/cloudformation-discovery.test.js +590 -0
- package/infrastructure/domains/shared/environment-builder.js +119 -0
- package/infrastructure/domains/shared/environment-builder.test.js +247 -0
- package/infrastructure/domains/shared/providers/aws-provider-adapter.js +544 -0
- package/infrastructure/domains/shared/providers/aws-provider-adapter.test.js +377 -0
- package/infrastructure/domains/shared/providers/azure-provider-adapter.stub.js +93 -0
- package/infrastructure/domains/shared/providers/cloud-provider-adapter.js +136 -0
- package/infrastructure/domains/shared/providers/gcp-provider-adapter.stub.js +82 -0
- package/infrastructure/domains/shared/providers/provider-factory.js +108 -0
- package/infrastructure/domains/shared/providers/provider-factory.test.js +170 -0
- package/infrastructure/domains/shared/resource-discovery.js +192 -0
- package/infrastructure/domains/shared/resource-discovery.test.js +552 -0
- package/infrastructure/domains/shared/types/app-definition.js +205 -0
- package/infrastructure/domains/shared/types/discovery-result.js +106 -0
- package/infrastructure/domains/shared/types/discovery-result.test.js +258 -0
- package/infrastructure/domains/shared/types/index.js +46 -0
- package/infrastructure/domains/shared/types/resource-ownership.js +108 -0
- package/infrastructure/domains/shared/types/resource-ownership.test.js +101 -0
- package/infrastructure/domains/shared/utilities/base-definition-factory.js +380 -0
- package/infrastructure/domains/shared/utilities/base-definition-factory.js.bak +338 -0
- package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +248 -0
- package/infrastructure/domains/shared/utilities/handler-path-resolver.js +134 -0
- package/infrastructure/domains/shared/utilities/handler-path-resolver.test.js +268 -0
- package/infrastructure/domains/shared/utilities/prisma-layer-manager.js +55 -0
- package/infrastructure/domains/shared/utilities/prisma-layer-manager.test.js +138 -0
- package/infrastructure/{env-validator.js → domains/shared/validation/env-validator.js} +2 -1
- package/infrastructure/domains/shared/validation/env-validator.test.js +173 -0
- package/infrastructure/esbuild.config.js +53 -0
- package/infrastructure/infrastructure-composer.js +87 -0
- package/infrastructure/{serverless-template.test.js → infrastructure-composer.test.js} +115 -24
- package/infrastructure/scripts/build-prisma-layer.js +553 -0
- package/infrastructure/scripts/build-prisma-layer.test.js +102 -0
- package/infrastructure/{build-time-discovery.js → scripts/build-time-discovery.js} +80 -48
- package/infrastructure/{build-time-discovery.test.js → scripts/build-time-discovery.test.js} +5 -4
- package/layers/prisma/nodejs/package.json +8 -0
- package/management-ui/server/utils/cliIntegration.js +1 -1
- package/management-ui/server/utils/environment/awsParameterStore.js +29 -18
- package/package.json +11 -11
- package/frigg-cli/.eslintrc.js +0 -141
- package/frigg-cli/__tests__/unit/commands/build.test.js +0 -251
- package/frigg-cli/__tests__/unit/commands/db-setup.test.js +0 -548
- package/frigg-cli/__tests__/unit/commands/install.test.js +0 -400
- package/frigg-cli/__tests__/unit/commands/ui.test.js +0 -346
- package/frigg-cli/__tests__/unit/utils/database-validator.test.js +0 -366
- package/frigg-cli/__tests__/unit/utils/error-messages.test.js +0 -304
- package/frigg-cli/__tests__/unit/utils/prisma-runner.test.js +0 -486
- package/frigg-cli/__tests__/utils/mock-factory.js +0 -270
- package/frigg-cli/__tests__/utils/prisma-mock.js +0 -194
- package/frigg-cli/__tests__/utils/test-fixtures.js +0 -463
- package/frigg-cli/__tests__/utils/test-setup.js +0 -287
- package/frigg-cli/build-command/index.js +0 -65
- package/frigg-cli/db-setup-command/index.js +0 -193
- package/frigg-cli/deploy-command/index.js +0 -175
- package/frigg-cli/generate-command/__tests__/generate-command.test.js +0 -301
- package/frigg-cli/generate-command/azure-generator.js +0 -43
- package/frigg-cli/generate-command/gcp-generator.js +0 -47
- package/frigg-cli/generate-command/index.js +0 -332
- package/frigg-cli/generate-command/terraform-generator.js +0 -555
- package/frigg-cli/generate-iam-command.js +0 -118
- package/frigg-cli/index.js +0 -75
- package/frigg-cli/index.test.js +0 -158
- package/frigg-cli/init-command/backend-first-handler.js +0 -756
- package/frigg-cli/init-command/index.js +0 -93
- package/frigg-cli/init-command/template-handler.js +0 -143
- package/frigg-cli/install-command/backend-js.js +0 -33
- package/frigg-cli/install-command/commit-changes.js +0 -16
- package/frigg-cli/install-command/environment-variables.js +0 -127
- package/frigg-cli/install-command/environment-variables.test.js +0 -136
- package/frigg-cli/install-command/index.js +0 -54
- package/frigg-cli/install-command/install-package.js +0 -13
- package/frigg-cli/install-command/integration-file.js +0 -30
- package/frigg-cli/install-command/logger.js +0 -12
- package/frigg-cli/install-command/template.js +0 -90
- package/frigg-cli/install-command/validate-package.js +0 -75
- package/frigg-cli/jest.config.js +0 -124
- package/frigg-cli/package.json +0 -54
- package/frigg-cli/start-command/index.js +0 -149
- package/frigg-cli/start-command/start-command.test.js +0 -297
- package/frigg-cli/test/init-command.test.js +0 -180
- package/frigg-cli/test/npm-registry.test.js +0 -319
- package/frigg-cli/ui-command/index.js +0 -154
- package/frigg-cli/utils/app-resolver.js +0 -319
- package/frigg-cli/utils/backend-path.js +0 -25
- package/frigg-cli/utils/database-validator.js +0 -161
- package/frigg-cli/utils/error-messages.js +0 -257
- package/frigg-cli/utils/npm-registry.js +0 -167
- package/frigg-cli/utils/prisma-runner.js +0 -280
- package/frigg-cli/utils/process-manager.js +0 -199
- package/frigg-cli/utils/repo-detection.js +0 -405
- package/infrastructure/aws-discovery.js +0 -1176
- package/infrastructure/aws-discovery.test.js +0 -1220
- package/infrastructure/serverless-template.js +0 -2094
- /package/infrastructure/{WEBSOCKET-CONFIGURATION.md → docs/WEBSOCKET-CONFIGURATION.md} +0 -0
- /package/infrastructure/{GENERATE-IAM-DOCS.md → docs/generate-iam-command.md} +0 -0
- /package/infrastructure/{iam-generator.test.js → domains/security/iam-generator.test.js} +0 -0
- /package/infrastructure/{frigg-deployment-iam-stack.yaml → domains/security/templates/frigg-deployment-iam-stack.yaml} +0 -0
- /package/infrastructure/{iam-policy-basic.json → domains/security/templates/iam-policy-basic.json} +0 -0
- /package/infrastructure/{iam-policy-full.json → domains/security/templates/iam-policy-full.json} +0 -0
- /package/infrastructure/{run-discovery.js → scripts/run-discovery.js} +0 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PropertyMutability Value Object
|
|
3
|
+
*
|
|
4
|
+
* Enum-like immutable mutability classification for CloudFormation resource properties
|
|
5
|
+
*
|
|
6
|
+
* Types:
|
|
7
|
+
* - MUTABLE: Property can be changed without replacing the resource (Update requires: No interruption)
|
|
8
|
+
* - IMMUTABLE: Property cannot be changed - requires resource replacement (Update requires: Replacement)
|
|
9
|
+
* - CONDITIONAL: Property mutability depends on other properties or conditions (Update requires: Some interruptions)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
class PropertyMutability {
|
|
13
|
+
/**
|
|
14
|
+
* Valid mutability types
|
|
15
|
+
* @type {string[]}
|
|
16
|
+
*/
|
|
17
|
+
static VALID_TYPES = [
|
|
18
|
+
'MUTABLE',
|
|
19
|
+
'IMMUTABLE',
|
|
20
|
+
'CONDITIONAL',
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Create a new PropertyMutability
|
|
25
|
+
*
|
|
26
|
+
* @param {string} value - Mutability type
|
|
27
|
+
*/
|
|
28
|
+
constructor(value) {
|
|
29
|
+
if (value === undefined || value === null) {
|
|
30
|
+
throw new Error('Property mutability is required');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!PropertyMutability.VALID_TYPES.includes(value)) {
|
|
34
|
+
throw new Error(`Invalid property mutability: ${value}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
this._value = value;
|
|
38
|
+
|
|
39
|
+
// Make immutable
|
|
40
|
+
Object.freeze(this);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Get mutability value
|
|
45
|
+
* @returns {string}
|
|
46
|
+
*/
|
|
47
|
+
get value() {
|
|
48
|
+
return this._value;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Prevent modification of value
|
|
53
|
+
* @throws {TypeError}
|
|
54
|
+
*/
|
|
55
|
+
set value(newValue) {
|
|
56
|
+
throw new TypeError('Cannot modify immutable property value');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Check if property is mutable
|
|
61
|
+
* @returns {boolean}
|
|
62
|
+
*/
|
|
63
|
+
isMutable() {
|
|
64
|
+
return this._value === 'MUTABLE';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Check if property is immutable
|
|
69
|
+
* @returns {boolean}
|
|
70
|
+
*/
|
|
71
|
+
isImmutable() {
|
|
72
|
+
return this._value === 'IMMUTABLE';
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Check if property mutability is conditional
|
|
77
|
+
* @returns {boolean}
|
|
78
|
+
*/
|
|
79
|
+
isConditional() {
|
|
80
|
+
return this._value === 'CONDITIONAL';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Check if property can be changed
|
|
85
|
+
* @returns {boolean}
|
|
86
|
+
*/
|
|
87
|
+
canChange() {
|
|
88
|
+
return this._value === 'MUTABLE';
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Check if changing property requires resource replacement
|
|
93
|
+
* @returns {boolean}
|
|
94
|
+
*/
|
|
95
|
+
requiresReplacement() {
|
|
96
|
+
return this._value === 'IMMUTABLE';
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Get description of mutability type
|
|
101
|
+
* @returns {string}
|
|
102
|
+
*/
|
|
103
|
+
getDescription() {
|
|
104
|
+
const descriptions = {
|
|
105
|
+
MUTABLE: 'Property can be changed without replacing the resource',
|
|
106
|
+
IMMUTABLE: 'Property cannot be changed - requires resource replacement',
|
|
107
|
+
CONDITIONAL: 'Property mutability depends on other property values or conditions',
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
return descriptions[this._value];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Check equality with another PropertyMutability
|
|
115
|
+
*
|
|
116
|
+
* @param {PropertyMutability} other
|
|
117
|
+
* @returns {boolean}
|
|
118
|
+
*/
|
|
119
|
+
equals(other) {
|
|
120
|
+
if (!(other instanceof PropertyMutability)) {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return this._value === other._value;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Get string representation
|
|
129
|
+
*
|
|
130
|
+
* @returns {string}
|
|
131
|
+
*/
|
|
132
|
+
toString() {
|
|
133
|
+
return this._value;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Predefined mutability: MUTABLE
|
|
138
|
+
* @type {PropertyMutability}
|
|
139
|
+
*/
|
|
140
|
+
static get MUTABLE() {
|
|
141
|
+
return new PropertyMutability('MUTABLE');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Predefined mutability: IMMUTABLE
|
|
146
|
+
* @type {PropertyMutability}
|
|
147
|
+
*/
|
|
148
|
+
static get IMMUTABLE() {
|
|
149
|
+
return new PropertyMutability('IMMUTABLE');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Predefined mutability: CONDITIONAL
|
|
154
|
+
* @type {PropertyMutability}
|
|
155
|
+
*/
|
|
156
|
+
static get CONDITIONAL() {
|
|
157
|
+
return new PropertyMutability('CONDITIONAL');
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
module.exports = PropertyMutability;
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for PropertyMutability Value Object
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const PropertyMutability = require('./property-mutability');
|
|
6
|
+
|
|
7
|
+
describe('PropertyMutability', () => {
|
|
8
|
+
describe('valid mutability types', () => {
|
|
9
|
+
it('should accept MUTABLE', () => {
|
|
10
|
+
const mutability = new PropertyMutability('MUTABLE');
|
|
11
|
+
|
|
12
|
+
expect(mutability.value).toBe('MUTABLE');
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('should accept IMMUTABLE', () => {
|
|
16
|
+
const mutability = new PropertyMutability('IMMUTABLE');
|
|
17
|
+
|
|
18
|
+
expect(mutability.value).toBe('IMMUTABLE');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should accept CONDITIONAL', () => {
|
|
22
|
+
const mutability = new PropertyMutability('CONDITIONAL');
|
|
23
|
+
|
|
24
|
+
expect(mutability.value).toBe('CONDITIONAL');
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe('invalid mutability types', () => {
|
|
29
|
+
it('should reject invalid mutability', () => {
|
|
30
|
+
expect(() => {
|
|
31
|
+
new PropertyMutability('INVALID');
|
|
32
|
+
}).toThrow('Invalid property mutability: INVALID');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should reject lowercase mutability', () => {
|
|
36
|
+
expect(() => {
|
|
37
|
+
new PropertyMutability('mutable');
|
|
38
|
+
}).toThrow('Invalid property mutability: mutable');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should reject null', () => {
|
|
42
|
+
expect(() => {
|
|
43
|
+
new PropertyMutability(null);
|
|
44
|
+
}).toThrow('Property mutability is required');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should reject undefined', () => {
|
|
48
|
+
expect(() => {
|
|
49
|
+
new PropertyMutability(undefined);
|
|
50
|
+
}).toThrow('Property mutability is required');
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe('mutability checks', () => {
|
|
55
|
+
it('should check if property is mutable', () => {
|
|
56
|
+
const mutability = new PropertyMutability('MUTABLE');
|
|
57
|
+
|
|
58
|
+
expect(mutability.isMutable()).toBe(true);
|
|
59
|
+
expect(mutability.isImmutable()).toBe(false);
|
|
60
|
+
expect(mutability.isConditional()).toBe(false);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should check if property is immutable', () => {
|
|
64
|
+
const mutability = new PropertyMutability('IMMUTABLE');
|
|
65
|
+
|
|
66
|
+
expect(mutability.isMutable()).toBe(false);
|
|
67
|
+
expect(mutability.isImmutable()).toBe(true);
|
|
68
|
+
expect(mutability.isConditional()).toBe(false);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should check if property is conditionally mutable', () => {
|
|
72
|
+
const mutability = new PropertyMutability('CONDITIONAL');
|
|
73
|
+
|
|
74
|
+
expect(mutability.isMutable()).toBe(false);
|
|
75
|
+
expect(mutability.isImmutable()).toBe(false);
|
|
76
|
+
expect(mutability.isConditional()).toBe(true);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe('changeability checks', () => {
|
|
81
|
+
it('should allow changes for mutable properties', () => {
|
|
82
|
+
const mutability = new PropertyMutability('MUTABLE');
|
|
83
|
+
|
|
84
|
+
expect(mutability.canChange()).toBe(true);
|
|
85
|
+
expect(mutability.requiresReplacement()).toBe(false);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should not allow changes for immutable properties', () => {
|
|
89
|
+
const mutability = new PropertyMutability('IMMUTABLE');
|
|
90
|
+
|
|
91
|
+
expect(mutability.canChange()).toBe(false);
|
|
92
|
+
expect(mutability.requiresReplacement()).toBe(true);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('should conditionally allow changes', () => {
|
|
96
|
+
const mutability = new PropertyMutability('CONDITIONAL');
|
|
97
|
+
|
|
98
|
+
// Conditional means it depends on other factors
|
|
99
|
+
expect(mutability.canChange()).toBe(false); // Can't change without conditions met
|
|
100
|
+
expect(mutability.requiresReplacement()).toBe(false); // Doesn't always require replacement
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
describe('equality', () => {
|
|
105
|
+
it('should be equal to same mutability', () => {
|
|
106
|
+
const m1 = new PropertyMutability('MUTABLE');
|
|
107
|
+
const m2 = new PropertyMutability('MUTABLE');
|
|
108
|
+
|
|
109
|
+
expect(m1.equals(m2)).toBe(true);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should not be equal to different mutability', () => {
|
|
113
|
+
const m1 = new PropertyMutability('MUTABLE');
|
|
114
|
+
const m2 = new PropertyMutability('IMMUTABLE');
|
|
115
|
+
|
|
116
|
+
expect(m1.equals(m2)).toBe(false);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('should not be equal to non-PropertyMutability', () => {
|
|
120
|
+
const mutability = new PropertyMutability('MUTABLE');
|
|
121
|
+
|
|
122
|
+
expect(mutability.equals('MUTABLE')).toBe(false);
|
|
123
|
+
expect(mutability.equals(null)).toBe(false);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
describe('toString', () => {
|
|
128
|
+
it('should return string representation', () => {
|
|
129
|
+
const mutability = new PropertyMutability('MUTABLE');
|
|
130
|
+
|
|
131
|
+
expect(mutability.toString()).toBe('MUTABLE');
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
describe('static constants', () => {
|
|
136
|
+
it('should provide MUTABLE constant', () => {
|
|
137
|
+
expect(PropertyMutability.MUTABLE.value).toBe('MUTABLE');
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should provide IMMUTABLE constant', () => {
|
|
141
|
+
expect(PropertyMutability.IMMUTABLE.value).toBe('IMMUTABLE');
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('should provide CONDITIONAL constant', () => {
|
|
145
|
+
expect(PropertyMutability.CONDITIONAL.value).toBe('CONDITIONAL');
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('should provide VALID_TYPES array', () => {
|
|
149
|
+
expect(PropertyMutability.VALID_TYPES).toEqual([
|
|
150
|
+
'MUTABLE',
|
|
151
|
+
'IMMUTABLE',
|
|
152
|
+
'CONDITIONAL',
|
|
153
|
+
]);
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe('immutability', () => {
|
|
158
|
+
it('should not allow modification of value', () => {
|
|
159
|
+
const mutability = new PropertyMutability('MUTABLE');
|
|
160
|
+
|
|
161
|
+
expect(() => {
|
|
162
|
+
mutability.value = 'IMMUTABLE';
|
|
163
|
+
}).toThrow();
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('should be frozen', () => {
|
|
167
|
+
const mutability = new PropertyMutability('MUTABLE');
|
|
168
|
+
|
|
169
|
+
expect(Object.isFrozen(mutability)).toBe(true);
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
describe('description', () => {
|
|
174
|
+
it('should provide description for MUTABLE', () => {
|
|
175
|
+
const mutability = new PropertyMutability('MUTABLE');
|
|
176
|
+
|
|
177
|
+
expect(mutability.getDescription()).toBe(
|
|
178
|
+
'Property can be changed without replacing the resource'
|
|
179
|
+
);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it('should provide description for IMMUTABLE', () => {
|
|
183
|
+
const mutability = new PropertyMutability('IMMUTABLE');
|
|
184
|
+
|
|
185
|
+
expect(mutability.getDescription()).toBe(
|
|
186
|
+
'Property cannot be changed - requires resource replacement'
|
|
187
|
+
);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('should provide description for CONDITIONAL', () => {
|
|
191
|
+
const mutability = new PropertyMutability('CONDITIONAL');
|
|
192
|
+
|
|
193
|
+
expect(mutability.getDescription()).toBe(
|
|
194
|
+
'Property mutability depends on other property values or conditions'
|
|
195
|
+
);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
});
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ResourceState Value Object
|
|
3
|
+
*
|
|
4
|
+
* Enum-like immutable state for CloudFormation resources
|
|
5
|
+
*
|
|
6
|
+
* States:
|
|
7
|
+
* - IN_STACK: Resource exists in CloudFormation stack and matches expected definition
|
|
8
|
+
* - ORPHANED: Resource exists in AWS but not in CloudFormation stack
|
|
9
|
+
* - MISSING: Resource is in CloudFormation stack but not in AWS
|
|
10
|
+
* - DRIFTED: Resource exists in both but properties differ
|
|
11
|
+
* - EXTERNAL: Resource is intentionally external to stack
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
class ResourceState {
|
|
15
|
+
/**
|
|
16
|
+
* Valid resource states
|
|
17
|
+
* @type {string[]}
|
|
18
|
+
*/
|
|
19
|
+
static VALID_STATES = [
|
|
20
|
+
'IN_STACK',
|
|
21
|
+
'ORPHANED',
|
|
22
|
+
'MISSING',
|
|
23
|
+
'DRIFTED',
|
|
24
|
+
'EXTERNAL',
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Create a new ResourceState
|
|
29
|
+
*
|
|
30
|
+
* @param {string} value - State value
|
|
31
|
+
*/
|
|
32
|
+
constructor(value) {
|
|
33
|
+
if (value === undefined || value === null) {
|
|
34
|
+
throw new Error('Resource state is required');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (!ResourceState.VALID_STATES.includes(value)) {
|
|
38
|
+
throw new Error(`Invalid resource state: ${value}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
this._value = value;
|
|
42
|
+
|
|
43
|
+
// Make immutable
|
|
44
|
+
Object.freeze(this);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Get state value
|
|
49
|
+
* @returns {string}
|
|
50
|
+
*/
|
|
51
|
+
get value() {
|
|
52
|
+
return this._value;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Prevent modification of value
|
|
57
|
+
* @throws {TypeError}
|
|
58
|
+
*/
|
|
59
|
+
set value(newValue) {
|
|
60
|
+
throw new TypeError('Cannot modify immutable property value');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Check if resource is in stack
|
|
65
|
+
* @returns {boolean}
|
|
66
|
+
*/
|
|
67
|
+
isInStack() {
|
|
68
|
+
return this._value === 'IN_STACK';
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Check if resource is orphaned
|
|
73
|
+
* @returns {boolean}
|
|
74
|
+
*/
|
|
75
|
+
isOrphaned() {
|
|
76
|
+
return this._value === 'ORPHANED';
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Check if resource is missing
|
|
81
|
+
* @returns {boolean}
|
|
82
|
+
*/
|
|
83
|
+
isMissing() {
|
|
84
|
+
return this._value === 'MISSING';
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Check if resource has drifted
|
|
89
|
+
* @returns {boolean}
|
|
90
|
+
*/
|
|
91
|
+
isDrifted() {
|
|
92
|
+
return this._value === 'DRIFTED';
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Check if resource is external
|
|
97
|
+
* @returns {boolean}
|
|
98
|
+
*/
|
|
99
|
+
isExternal() {
|
|
100
|
+
return this._value === 'EXTERNAL';
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Check equality with another ResourceState
|
|
105
|
+
*
|
|
106
|
+
* @param {ResourceState} other
|
|
107
|
+
* @returns {boolean}
|
|
108
|
+
*/
|
|
109
|
+
equals(other) {
|
|
110
|
+
if (!(other instanceof ResourceState)) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return this._value === other._value;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Get string representation
|
|
119
|
+
*
|
|
120
|
+
* @returns {string}
|
|
121
|
+
*/
|
|
122
|
+
toString() {
|
|
123
|
+
return this._value;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Predefined state: IN_STACK
|
|
128
|
+
* @type {ResourceState}
|
|
129
|
+
*/
|
|
130
|
+
static get IN_STACK() {
|
|
131
|
+
return new ResourceState('IN_STACK');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Predefined state: ORPHANED
|
|
136
|
+
* @type {ResourceState}
|
|
137
|
+
*/
|
|
138
|
+
static get ORPHANED() {
|
|
139
|
+
return new ResourceState('ORPHANED');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Predefined state: MISSING
|
|
144
|
+
* @type {ResourceState}
|
|
145
|
+
*/
|
|
146
|
+
static get MISSING() {
|
|
147
|
+
return new ResourceState('MISSING');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Predefined state: DRIFTED
|
|
152
|
+
* @type {ResourceState}
|
|
153
|
+
*/
|
|
154
|
+
static get DRIFTED() {
|
|
155
|
+
return new ResourceState('DRIFTED');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Predefined state: EXTERNAL
|
|
160
|
+
* @type {ResourceState}
|
|
161
|
+
*/
|
|
162
|
+
static get EXTERNAL() {
|
|
163
|
+
return new ResourceState('EXTERNAL');
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
module.exports = ResourceState;
|