@aws-mdaa/dataops-job-l3-construct 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/.jsii +38 -28
  2. package/README.md +5 -0
  3. package/lib/dataops-job-l3-construct.d.ts +8 -1
  4. package/lib/dataops-job-l3-construct.js +40 -13
  5. package/node_modules/@aws-mdaa/config/README.md +3 -0
  6. package/node_modules/@aws-mdaa/config/lib/blueprint-value-transformer.d.ts +20 -0
  7. package/node_modules/@aws-mdaa/config/lib/blueprint-value-transformer.js +70 -0
  8. package/node_modules/@aws-mdaa/config/lib/blueprint-value-transformer.ts +88 -0
  9. package/node_modules/@aws-mdaa/config/lib/config.d.ts +87 -0
  10. package/node_modules/@aws-mdaa/config/lib/config.js +7 -0
  11. package/node_modules/@aws-mdaa/config/lib/config.ts +92 -0
  12. package/node_modules/@aws-mdaa/config/lib/index.d.ts +11 -0
  13. package/node_modules/@aws-mdaa/config/lib/index.js +28 -0
  14. package/node_modules/@aws-mdaa/config/lib/index.ts +12 -0
  15. package/node_modules/@aws-mdaa/config/lib/param-transformer.d.ts +49 -0
  16. package/node_modules/@aws-mdaa/config/lib/param-transformer.js +160 -0
  17. package/node_modules/@aws-mdaa/config/lib/param-transformer.ts +159 -0
  18. package/node_modules/@aws-mdaa/config/lib/path-value-transformer.d.ts +10 -0
  19. package/node_modules/@aws-mdaa/config/lib/path-value-transformer.js +30 -0
  20. package/node_modules/@aws-mdaa/config/lib/path-value-transformer.ts +27 -0
  21. package/node_modules/@aws-mdaa/config/lib/ref-value-transformer.d.ts +44 -0
  22. package/node_modules/@aws-mdaa/config/lib/ref-value-transformer.js +243 -0
  23. package/node_modules/@aws-mdaa/config/lib/ref-value-transformer.ts +302 -0
  24. package/node_modules/@aws-mdaa/config/lib/ssm-ref-transformer.d.ts +8 -0
  25. package/node_modules/@aws-mdaa/config/lib/ssm-ref-transformer.js +22 -0
  26. package/node_modules/@aws-mdaa/config/lib/ssm-ref-transformer.ts +21 -0
  27. package/node_modules/@aws-mdaa/config/lib/transformer.d.ts +35 -0
  28. package/node_modules/@aws-mdaa/config/lib/transformer.js +66 -0
  29. package/node_modules/@aws-mdaa/config/lib/transformer.ts +74 -0
  30. package/node_modules/@aws-mdaa/config/package.json +42 -0
  31. package/node_modules/@aws-mdaa/config/test/blueprint-value-transformer.test.js +224 -0
  32. package/node_modules/@aws-mdaa/config/test/blueprint-value-transformer.test.ts +259 -0
  33. package/node_modules/@aws-mdaa/config/test/config-nt.test.d.ts +5 -0
  34. package/node_modules/@aws-mdaa/config/test/config-nt.test.js +129 -0
  35. package/node_modules/@aws-mdaa/config/test/config-nt.test.ts +163 -0
  36. package/node_modules/@aws-mdaa/config/test/config.test.d.ts +5 -0
  37. package/node_modules/@aws-mdaa/config/test/config.test.js +409 -0
  38. package/node_modules/@aws-mdaa/config/test/config.test.ts +517 -0
  39. package/node_modules/@aws-mdaa/config/test/param-transformer.test.d.ts +5 -0
  40. package/node_modules/@aws-mdaa/config/test/param-transformer.test.js +216 -0
  41. package/node_modules/@aws-mdaa/config/test/param-transformer.test.ts +234 -0
  42. package/node_modules/@aws-mdaa/config/test/path-value-transformer.test.d.ts +5 -0
  43. package/node_modules/@aws-mdaa/config/test/path-value-transformer.test.js +59 -0
  44. package/node_modules/@aws-mdaa/config/test/path-value-transformer.test.ts +68 -0
  45. package/node_modules/@aws-mdaa/config/test/ref-value-transformer.test.d.ts +5 -0
  46. package/node_modules/@aws-mdaa/config/test/ref-value-transformer.test.js +254 -0
  47. package/node_modules/@aws-mdaa/config/test/ref-value-transformer.test.ts +304 -0
  48. package/node_modules/@aws-mdaa/config/test/ssm-ref-transformer.test.d.ts +5 -0
  49. package/node_modules/@aws-mdaa/config/test/ssm-ref-transformer.test.js +66 -0
  50. package/node_modules/@aws-mdaa/config/test/ssm-ref-transformer.test.ts +79 -0
  51. package/node_modules/@aws-mdaa/config/tsconfig.tsbuildinfo +1 -0
  52. package/node_modules/lodash/README.md +2 -2
  53. package/node_modules/lodash/_baseOrderBy.js +1 -1
  54. package/node_modules/lodash/_baseUnset.js +7 -20
  55. package/node_modules/lodash/_setCacheHas.js +1 -1
  56. package/node_modules/lodash/compact.js +1 -1
  57. package/node_modules/lodash/core.js +3 -3
  58. package/node_modules/lodash/core.min.js +26 -25
  59. package/node_modules/lodash/fromPairs.js +3 -1
  60. package/node_modules/lodash/lodash.js +38 -27
  61. package/node_modules/lodash/lodash.min.js +125 -129
  62. package/node_modules/lodash/package.json +4 -2
  63. package/node_modules/lodash/random.js +9 -0
  64. package/node_modules/lodash/template.js +16 -4
  65. package/node_modules/lodash/templateSettings.js +4 -0
  66. package/package.json +27 -32
  67. package/node_modules/@aws-mdaa/s3-bucketpolicy-helper/README.md +0 -185
  68. package/node_modules/@aws-mdaa/s3-bucketpolicy-helper/lib/index.d.ts +0 -57
  69. package/node_modules/@aws-mdaa/s3-bucketpolicy-helper/lib/index.js +0 -198
  70. package/node_modules/@aws-mdaa/s3-bucketpolicy-helper/lib/index.ts +0 -241
  71. package/node_modules/@aws-mdaa/s3-bucketpolicy-helper/package.json +0 -44
  72. package/node_modules/@aws-mdaa/s3-bucketpolicy-helper/test/bucketpolicy-helper.test.js +0 -200
  73. package/node_modules/@aws-mdaa/s3-bucketpolicy-helper/test/bucketpolicy-helper.test.ts +0 -215
  74. package/node_modules/@aws-mdaa/s3-bucketpolicy-helper/tsconfig.tsbuildinfo +0 -1
  75. package/node_modules/@aws-mdaa/s3-inventory-helper/.npmignore +0 -34
  76. package/node_modules/@aws-mdaa/s3-inventory-helper/README.md +0 -3
  77. package/node_modules/@aws-mdaa/s3-inventory-helper/jest.config.js +0 -5
  78. package/node_modules/@aws-mdaa/s3-inventory-helper/lib/index.d.ts +0 -48
  79. package/node_modules/@aws-mdaa/s3-inventory-helper/lib/index.js +0 -213
  80. package/node_modules/@aws-mdaa/s3-inventory-helper/lib/index.ts +0 -241
  81. package/node_modules/@aws-mdaa/s3-inventory-helper/package.json +0 -44
  82. package/node_modules/@aws-mdaa/s3-inventory-helper/test/TODO +0 -0
  83. package/node_modules/@aws-mdaa/s3-inventory-helper/tsconfig.json +0 -40
  84. package/node_modules/@aws-mdaa/s3-inventory-helper/tsconfig.tsbuildinfo +0 -1
  85. package/node_modules/@aws-mdaa/s3-inventory-helper/typedoc.json +0 -7
  86. /package/node_modules/@aws-mdaa/{s3-bucketpolicy-helper → config}/.npmignore +0 -0
  87. /package/node_modules/@aws-mdaa/{s3-bucketpolicy-helper → config}/jest.config.js +0 -0
  88. /package/node_modules/@aws-mdaa/{s3-bucketpolicy-helper/test/bucketpolicy-helper.test.d.ts → config/test/blueprint-value-transformer.test.d.ts} +0 -0
  89. /package/node_modules/@aws-mdaa/{s3-bucketpolicy-helper → config}/tsconfig.json +0 -0
  90. /package/node_modules/@aws-mdaa/{s3-bucketpolicy-helper → config}/typedoc.json +0 -0
@@ -0,0 +1,224 @@
1
+ "use strict";
2
+ /*!
3
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const aws_cdk_lib_1 = require("aws-cdk-lib");
8
+ const lib_1 = require("../lib");
9
+ describe('MdaaConfigBlueprintRefValueTransformer', () => {
10
+ let mockNaming;
11
+ let stack;
12
+ beforeEach(() => {
13
+ stack = new aws_cdk_lib_1.Stack();
14
+ mockNaming = {
15
+ props: {
16
+ org: 'test-org',
17
+ env: 'test-env',
18
+ domain: 'test-domain',
19
+ moduleName: 'test-module',
20
+ },
21
+ withModuleName: jest.fn().mockReturnThis(),
22
+ withDomain: jest.fn().mockReturnThis(),
23
+ withOrg: jest.fn().mockReturnThis(),
24
+ withEnv: jest.fn().mockReturnThis(),
25
+ withSuffix: jest.fn().mockReturnThis(),
26
+ ssmDomainPath: jest.fn().mockReturnValue('/test/domain/path'),
27
+ ssmEnvPath: jest.fn().mockReturnValue('/test/env/path'),
28
+ ssmOrgPath: jest.fn().mockReturnValue('/test-org/'),
29
+ resourceName: jest
30
+ .fn()
31
+ .mockImplementation((suffix) => (suffix ? `test-resource-${suffix}` : 'test-resource')),
32
+ ssmPath: jest.fn().mockImplementation((path) => `/test/${path}`),
33
+ stackName: jest.fn().mockImplementation((name) => (name ? `test-stack-${name}` : 'test-stack')),
34
+ exportName: jest.fn().mockImplementation((path) => `test-export-${path}`),
35
+ };
36
+ });
37
+ test('returns unchanged value without refs', () => {
38
+ const transformer = new lib_1.MdaaConfigBlueprintRefValueTransformer({
39
+ naming: mockNaming,
40
+ scope: stack,
41
+ });
42
+ expect(transformer.transformValue('plain-value')).toBe('plain-value');
43
+ });
44
+ test('returns unchanged value with empty string', () => {
45
+ const transformer = new lib_1.MdaaConfigBlueprintRefValueTransformer({
46
+ naming: mockNaming,
47
+ scope: stack,
48
+ });
49
+ expect(transformer.transformValue('')).toBe('');
50
+ });
51
+ test('transforms blueprint ref', () => {
52
+ const transformer = new lib_1.MdaaConfigBlueprintRefValueTransformer({
53
+ naming: mockNaming,
54
+ scope: stack,
55
+ });
56
+ const result = transformer.transformValue('{{blueprint:/some/path}}');
57
+ expect(result).toContain('{{resolve:ssm:/test-org/');
58
+ expect(result).toContain('/some/path}}');
59
+ expect(mockNaming.ssmOrgPath).toHaveBeenCalledWith('', false);
60
+ });
61
+ test('transforms blueprint ref with prefix and suffix', () => {
62
+ const transformer = new lib_1.MdaaConfigBlueprintRefValueTransformer({
63
+ naming: mockNaming,
64
+ scope: stack,
65
+ });
66
+ const result = transformer.transformValue('prefix-{{blueprint:/path}}-suffix');
67
+ expect(result).toContain('prefix-');
68
+ expect(result).toContain('-suffix');
69
+ expect(result).toContain('{{resolve:ssm:');
70
+ });
71
+ test('handles multiple blueprint refs', () => {
72
+ const transformer = new lib_1.MdaaConfigBlueprintRefValueTransformer({
73
+ naming: mockNaming,
74
+ scope: stack,
75
+ });
76
+ const result = transformer.transformValue('{{blueprint:/path1}}-{{blueprint:/path2}}');
77
+ expect(result).toContain('/path1}}');
78
+ expect(result).toContain('/path2}}');
79
+ });
80
+ test('reuses existing CfnParameter for datazoneEnvironmentProjectId', () => {
81
+ const transformer = new lib_1.MdaaConfigBlueprintRefValueTransformer({
82
+ naming: mockNaming,
83
+ scope: stack,
84
+ });
85
+ // First call creates the parameter
86
+ transformer.transformValue('{{blueprint:/path1}}');
87
+ // Second call should reuse the same parameter
88
+ transformer.transformValue('{{blueprint:/path2}}');
89
+ // Should only have one datazoneEnvironmentProjectId parameter
90
+ const params = stack.node.children.filter(child => child.node.id === 'datazoneEnvironmentProjectId');
91
+ expect(params.length).toBe(1);
92
+ });
93
+ test('ignores non-blueprint refs', () => {
94
+ const transformer = new lib_1.MdaaConfigBlueprintRefValueTransformer({
95
+ naming: mockNaming,
96
+ scope: stack,
97
+ });
98
+ const result = transformer.transformValue('{{other:value}}');
99
+ // Non-blueprint refs should remain unchanged
100
+ expect(result).toBe('{{other:value}}');
101
+ });
102
+ test('handles nested refs in blueprint path', () => {
103
+ const transformer = new lib_1.MdaaConfigBlueprintRefValueTransformer({
104
+ naming: mockNaming,
105
+ scope: stack,
106
+ });
107
+ // Nested refs should be processed recursively
108
+ const result = transformer.transformValue('{{blueprint:/{{other}}/path}}');
109
+ // The inner ref is not a blueprint ref, so it stays as-is in the path
110
+ expect(result).toContain('{{resolve:ssm:');
111
+ });
112
+ test('handles unbalanced braces gracefully', () => {
113
+ const transformer = new lib_1.MdaaConfigBlueprintRefValueTransformer({
114
+ naming: mockNaming,
115
+ scope: stack,
116
+ });
117
+ // Unbalanced braces should be skipped
118
+ expect(transformer.transformValue('{{blueprint:/path')).toBe('{{blueprint:/path');
119
+ expect(transformer.transformValue('blueprint:/path}}')).toBe('blueprint:/path}}');
120
+ });
121
+ test('logs resolved blueprint path', () => {
122
+ const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
123
+ const transformer = new lib_1.MdaaConfigBlueprintRefValueTransformer({
124
+ naming: mockNaming,
125
+ scope: stack,
126
+ });
127
+ transformer.transformValue('{{blueprint:/test/path}}');
128
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Resolving blueprint path:'));
129
+ consoleSpy.mockRestore();
130
+ });
131
+ test('handles blueprint ref with special characters in path', () => {
132
+ const transformer = new lib_1.MdaaConfigBlueprintRefValueTransformer({
133
+ naming: mockNaming,
134
+ scope: stack,
135
+ });
136
+ const result = transformer.transformValue('{{blueprint:/path/with-dashes_and_underscores/123}}');
137
+ expect(result).toContain('{{resolve:ssm:');
138
+ expect(result).toContain('/path/with-dashes_and_underscores/123}}');
139
+ });
140
+ test('handles blueprint ref at start of string', () => {
141
+ const transformer = new lib_1.MdaaConfigBlueprintRefValueTransformer({
142
+ naming: mockNaming,
143
+ scope: stack,
144
+ });
145
+ const result = transformer.transformValue('{{blueprint:/path}}-suffix');
146
+ expect(result).toMatch(/^\{\{resolve:ssm:/);
147
+ expect(result).toContain('-suffix');
148
+ });
149
+ test('handles blueprint ref at end of string', () => {
150
+ const transformer = new lib_1.MdaaConfigBlueprintRefValueTransformer({
151
+ naming: mockNaming,
152
+ scope: stack,
153
+ });
154
+ const result = transformer.transformValue('prefix-{{blueprint:/path}}');
155
+ expect(result).toContain('prefix-');
156
+ expect(result).toMatch(/\}\}$/);
157
+ });
158
+ test('handles multiple different ref types mixed', () => {
159
+ const transformer = new lib_1.MdaaConfigBlueprintRefValueTransformer({
160
+ naming: mockNaming,
161
+ scope: stack,
162
+ });
163
+ const result = transformer.transformValue('{{blueprint:/path1}}-{{other:ref}}-{{blueprint:/path2}}');
164
+ expect(result).toContain('/path1}}');
165
+ expect(result).toContain('{{other:ref}}');
166
+ expect(result).toContain('/path2}}');
167
+ });
168
+ test('handles empty blueprint path', () => {
169
+ const transformer = new lib_1.MdaaConfigBlueprintRefValueTransformer({
170
+ naming: mockNaming,
171
+ scope: stack,
172
+ });
173
+ const result = transformer.transformValue('{{blueprint:}}');
174
+ expect(result).toContain('{{resolve:ssm:');
175
+ });
176
+ test('handles blueprint ref with only slashes', () => {
177
+ const transformer = new lib_1.MdaaConfigBlueprintRefValueTransformer({
178
+ naming: mockNaming,
179
+ scope: stack,
180
+ });
181
+ const result = transformer.transformValue('{{blueprint:/}}');
182
+ expect(result).toContain('{{resolve:ssm:');
183
+ expect(result).toContain('/}}');
184
+ });
185
+ test('creates parameter on first blueprint ref', () => {
186
+ const transformer = new lib_1.MdaaConfigBlueprintRefValueTransformer({
187
+ naming: mockNaming,
188
+ scope: stack,
189
+ });
190
+ const childrenBefore = stack.node.children.length;
191
+ transformer.transformValue('{{blueprint:/first}}');
192
+ const childrenAfter = stack.node.children.length;
193
+ expect(childrenAfter).toBeGreaterThan(childrenBefore);
194
+ });
195
+ test('does not create duplicate parameters', () => {
196
+ const transformer = new lib_1.MdaaConfigBlueprintRefValueTransformer({
197
+ naming: mockNaming,
198
+ scope: stack,
199
+ });
200
+ transformer.transformValue('{{blueprint:/first}}');
201
+ const childrenAfterFirst = stack.node.children.length;
202
+ transformer.transformValue('{{blueprint:/second}}');
203
+ const childrenAfterSecond = stack.node.children.length;
204
+ // Should not create additional parameters
205
+ expect(childrenAfterSecond).toBe(childrenAfterFirst);
206
+ });
207
+ test('throws when blueprint ref without scope', () => {
208
+ const transformer = new lib_1.MdaaConfigBlueprintRefValueTransformer({
209
+ naming: mockNaming,
210
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
211
+ scope: undefined,
212
+ });
213
+ expect(() => transformer.transformValue('{{blueprint:/path}}')).toThrow('Unable to resolve blueprint params outside of a Construct');
214
+ });
215
+ test('throws when blueprint ref without naming', () => {
216
+ const transformer = new lib_1.MdaaConfigBlueprintRefValueTransformer({
217
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
218
+ naming: undefined,
219
+ scope: stack,
220
+ });
221
+ expect(() => transformer.transformValue('{{blueprint:/path}}')).toThrow('Unable to resolve blueprint params without a naming implementation');
222
+ });
223
+ });
224
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmx1ZXByaW50LXZhbHVlLXRyYW5zZm9ybWVyLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJibHVlcHJpbnQtdmFsdWUtdHJhbnNmb3JtZXIudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7OztHQUdHOztBQUVILDZDQUFvQztBQUNwQyxnQ0FBZ0U7QUFHaEUsUUFBUSxDQUFDLHdDQUF3QyxFQUFFLEdBQUcsRUFBRTtJQUN0RCxJQUFJLFVBQStCLENBQUM7SUFDcEMsSUFBSSxLQUFZLENBQUM7SUFFakIsVUFBVSxDQUFDLEdBQUcsRUFBRTtRQUNkLEtBQUssR0FBRyxJQUFJLG1CQUFLLEVBQUUsQ0FBQztRQUNwQixVQUFVLEdBQUc7WUFDWCxLQUFLLEVBQUU7Z0JBQ0wsR0FBRyxFQUFFLFVBQVU7Z0JBQ2YsR0FBRyxFQUFFLFVBQVU7Z0JBQ2YsTUFBTSxFQUFFLGFBQWE7Z0JBQ3JCLFVBQVUsRUFBRSxhQUFhO2FBQzFCO1lBQ0QsY0FBYyxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxjQUFjLEVBQUU7WUFDMUMsVUFBVSxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxjQUFjLEVBQUU7WUFDdEMsT0FBTyxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxjQUFjLEVBQUU7WUFDbkMsT0FBTyxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxjQUFjLEVBQUU7WUFDbkMsVUFBVSxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxjQUFjLEVBQUU7WUFDdEMsYUFBYSxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxlQUFlLENBQUMsbUJBQW1CLENBQUM7WUFDN0QsVUFBVSxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxlQUFlLENBQUMsZ0JBQWdCLENBQUM7WUFDdkQsVUFBVSxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxlQUFlLENBQUMsWUFBWSxDQUFDO1lBQ25ELFlB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KiBDb3B5cmlnaHQgQW1hem9uLmNvbSwgSW5jLiBvciBpdHMgYWZmaWxpYXRlcy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG4gKi9cblxuaW1wb3J0IHsgU3RhY2sgfSBmcm9tICdhd3MtY2RrLWxpYic7XG5pbXBvcnQgeyBNZGFhQ29uZmlnQmx1ZXByaW50UmVmVmFsdWVUcmFuc2Zvcm1lciB9IGZyb20gJy4uL2xpYic7XG5pbXBvcnQgeyBJTWRhYVJlc291cmNlTmFtaW5nIH0gZnJvbSAnQGF3cy1tZGFhL25hbWluZyc7XG5cbmRlc2NyaWJlKCdNZGFhQ29uZmlnQmx1ZXByaW50UmVmVmFsdWVUcmFuc2Zvcm1lcicsICgpID0+IHtcbiAgbGV0IG1vY2tOYW1pbmc6IElNZGFhUmVzb3VyY2VOYW1pbmc7XG4gIGxldCBzdGFjazogU3RhY2s7XG5cbiAgYmVmb3JlRWFjaCgoKSA9PiB7XG4gICAgc3RhY2sgPSBuZXcgU3RhY2soKTtcbiAgICBtb2NrTmFtaW5nID0ge1xuICAgICAgcHJvcHM6IHtcbiAgICAgICAgb3JnOiAndGVzdC1vcmcnLFxuICAgICAgICBlbnY6ICd0ZXN0LWVudicsXG4gICAgICAgIGRvbWFpbjogJ3Rlc3QtZG9tYWluJyxcbiAgICAgICAgbW9kdWxlTmFtZTogJ3Rlc3QtbW9kdWxlJyxcbiAgICAgIH0sXG4gICAgICB3aXRoTW9kdWxlTmFtZTogamVzdC5mbigpLm1vY2tSZXR1cm5UaGlzKCksXG4gICAgICB3aXRoRG9tYWluOiBqZXN0LmZuKCkubW9ja1JldHVyblRoaXMoKSxcbiAgICAgIHdpdGhPcmc6IGplc3QuZm4oKS5tb2NrUmV0dXJuVGhpcygpLFxuICAgICAgd2l0aEVudjogamVzdC5mbigpLm1vY2tSZXR1cm5UaGlzKCksXG4gICAgICB3aXRoU3VmZml4OiBqZXN0LmZuKCkubW9ja1JldHVyblRoaXMoKSxcbiAgICAgIHNzbURvbWFpblBhdGg6IGplc3QuZm4oKS5tb2NrUmV0dXJuVmFsdWUoJy90ZXN0L2RvbWFpbi9wYXRoJyksXG4gICAgICBzc21FbnZQYXRoOiBqZXN0LmZuKCkubW9ja1JldHVyblZhbHVlKCcvdGVzdC9lbnYvcGF0aCcpLFxuICAgICAgc3NtT3JnUGF0aDogamVzdC5mbigpLm1vY2tSZXR1cm5WYWx1ZSgnL3Rlc3Qtb3JnLycpLFxuICAgICAgcmVzb3VyY2VOYW1lOiBqZXN0XG4gICAgICAgIC5mbigpXG4gICAgICAgIC5tb2NrSW1wbGVtZW50YXRpb24oKHN1ZmZpeD86IHN0cmluZykgPT4gKHN1ZmZpeCA/IGB0ZXN0LXJlc291cmNlLSR7c3VmZml4fWAgOiAndGVzdC1yZXNvdXJjZScpKSxcbiAgICAgIHNzbVBhdGg6IGplc3QuZm4oKS5tb2NrSW1wbGVtZW50YXRpb24oKHBhdGg6IHN0cmluZykgPT4gYC90ZXN0LyR7cGF0aH1gKSxcbiAgICAgIHN0YWNrTmFtZTogamVzdC5mbigpLm1vY2tJbXBsZW1lbnRhdGlvbigobmFtZT86IHN0cmluZykgPT4gKG5hbWUgPyBgdGVzdC1zdGFjay0ke25hbWV9YCA6ICd0ZXN0LXN0YWNrJykpLFxuICAgICAgZXhwb3J0TmFtZTogamVzdC5mbigpLm1vY2tJbXBsZW1lbnRhdGlvbigocGF0aDogc3RyaW5nKSA9PiBgdGVzdC1leHBvcnQtJHtwYXRofWApLFxuICAgIH0gYXMgdW5rbm93biBhcyBJTWRhYVJlc291cmNlTmFtaW5nO1xuICB9KTtcblxuICB0ZXN0KCdyZXR1cm5zIHVuY2hhbmdlZCB2YWx1ZSB3aXRob3V0IHJlZnMnLCAoKSA9PiB7XG4gICAgY29uc3QgdHJhbnNmb3JtZXIgPSBuZXcgTWRhYUNvbmZpZ0JsdWVwcmludFJlZlZhbHVlVHJhbnNmb3JtZXIoe1xuICAgICAgbmFtaW5nOiBtb2NrTmFtaW5nLFxuICAgICAgc2NvcGU6IHN0YWNrLFxuICAgIH0pO1xuICAgIGV4cGVjdCh0cmFuc2Zvcm1lci50cmFuc2Zvcm1WYWx1ZSgncGxhaW4tdmFsdWUnKSkudG9CZSgncGxhaW4tdmFsdWUnKTtcbiAgfSk7XG5cbiAgdGVzdCgncmV0dXJucyB1bmNoYW5nZWQgdmFsdWUgd2l0aCBlbXB0eSBzdHJpbmcnLCAoKSA9PiB7XG4gICAgY29uc3QgdHJhbnNmb3JtZXIgPSBuZXcgTWRhYUNvbmZpZ0JsdWVwcmludFJlZlZhbHVlVHJhbnNmb3JtZXIoe1xuICAgICAgbmFtaW5nOiBtb2NrTmFtaW5nLFxuICAgICAgc2NvcGU6IHN0YWNrLFxuICAgIH0pO1xuICAgIGV4cGVjdCh0cmFuc2Zvcm1lci50cmFuc2Zvcm1WYWx1ZSgnJykpLnRvQmUoJycpO1xuICB9KTtcblxuICB0ZXN0KCd0cmFuc2Zvcm1zIGJsdWVwcmludCByZWYnLCAoKSA9PiB7XG4gICAgY29uc3QgdHJhbnNmb3JtZXIgPSBuZXcgTWRhYUNvbmZpZ0JsdWVwcmludFJlZlZhbHVlVHJhbnNmb3JtZXIoe1xuICAgICAgbmFtaW5nOiBtb2NrTmFtaW5nLFxuICAgICAgc2NvcGU6IHN0YWNrLFxuICAgIH0pO1xuICAgIGNvbnN0IHJlc3VsdCA9IHRyYW5zZm9ybWVyLnRyYW5zZm9ybVZhbHVlKCd7e2JsdWVwcmludDovc29tZS9wYXRofX0nKTtcbiAgICBleHBlY3QocmVzdWx0KS50b0NvbnRhaW4oJ3t7cmVzb2x2ZTpzc206L3Rlc3Qtb3JnLycpO1xuICAgIGV4cGVjdChyZXN1bHQpLnRvQ29udGFpbignL3NvbWUvcGF0aH19Jyk7XG4gICAgZXhwZWN0KG1vY2tOYW1pbmcuc3NtT3JnUGF0aCkudG9IYXZlQmVlbkNhbGxlZFdpdGgoJycsIGZhbHNlKTtcbiAgfSk7XG5cbiAgdGVzdCgndHJhbnNmb3JtcyBibHVlcHJpbnQgcmVmIHdpdGggcHJlZml4IGFuZCBzdWZmaXgnLCAoKSA9PiB7XG4gICAgY29uc3QgdHJhbnNmb3JtZXIgPSBuZXcgTWRhYUNvbmZpZ0JsdWVwcmludFJlZlZhbHVlVHJhbnNmb3JtZXIoe1xuICAgICAgbmFtaW5nOiBtb2NrTmFtaW5nLFxuICAgICAgc2NvcGU6IHN0YWNrLFxuICAgIH0pO1xuICAgIGNvbnN0IHJlc3VsdCA9IHRyYW5zZm9ybWVyLnRyYW5zZm9ybVZhbHVlKCdwcmVmaXgte3tibHVlcHJpbnQ6L3BhdGh9fS1zdWZmaXgnKTtcbiAgICBleHBlY3QocmVzdWx0KS50b0NvbnRhaW4oJ3ByZWZpeC0nKTtcbiAgICBleHBlY3QocmVzdWx0KS50b0NvbnRhaW4oJy1zdWZmaXgnKTtcbiAgICBleHBlY3QocmVzdWx0KS50b0NvbnRhaW4oJ3t7cmVzb2x2ZTpzc206Jyk7XG4gIH0pO1xuXG4gIHRlc3QoJ2hhbmRsZXMgbXVsdGlwbGUgYmx1ZXByaW50IHJlZnMnLCAoKSA9PiB7XG4gICAgY29uc3QgdHJhbnNmb3JtZXIgPSBuZXcgTWRhYUNvbmZpZ0JsdWVwcmludFJlZlZhbHVlVHJhbnNmb3JtZXIoe1xuICAgICAgbmFtaW5nOiBtb2NrTmFtaW5nLFxuICAgICAgc2NvcGU6IHN0YWNrLFxuICAgIH0pO1xuICAgIGNvbnN0IHJlc3VsdCA9IHRyYW5zZm9ybWVyLnRyYW5zZm9ybVZhbHVlKCd7e2JsdWVwcmludDovcGF0aDF9fS17e2JsdWVwcmludDovcGF0aDJ9fScpO1xuICAgIGV4cGVjdChyZXN1bHQpLnRvQ29udGFpbignL3BhdGgxfX0nKTtcbiAgICBleHBlY3QocmVzdWx0KS50b0NvbnRhaW4oJy9wYXRoMn19Jyk7XG4gIH0pO1xuXG4gIHRlc3QoJ3JldXNlcyBleGlzdGluZyBDZm5QYXJhbWV0ZXIgZm9yIGRhdGF6b25lRW52aXJvbm1lbnRQcm9qZWN0SWQnLCAoKSA9PiB7XG4gICAgY29uc3QgdHJhbnNmb3JtZXIgPSBuZXcgTWRhYUNvbmZpZ0JsdWVwcmludFJlZlZhbHVlVHJhbnNmb3JtZXIoe1xuICAgICAgbmFtaW5nOiBtb2NrTmFtaW5nLFxuICAgICAgc2NvcGU6IHN0YWNrLFxuICAgIH0pO1xuXG4gICAgLy8gRmlyc3QgY2FsbCBjcmVhdGVzIHRoZSBwYXJhbWV0ZXJcbiAgICB0cmFuc2Zvcm1lci50cmFuc2Zvcm1WYWx1ZSgne3tibHVlcHJpbnQ6L3BhdGgxfX0nKTtcblxuICAgIC8vIFNlY29uZCBjYWxsIHNob3VsZCByZXVzZSB0aGUgc2FtZSBwYXJhbWV0ZXJcbiAgICB0cmFuc2Zvcm1lci50cmFuc2Zvcm1WYWx1ZSgne3tibHVlcHJpbnQ6L3BhdGgyfX0nKTtcblxuICAgIC8vIFNob3VsZCBvbmx5IGhhdmUgb25lIGRhdGF6b25lRW52aXJvbm1lbnRQcm9qZWN0SWQgcGFyYW1ldGVyXG4gICAgY29uc3QgcGFyYW1zID0gc3RhY2subm9kZS5jaGlsZHJlbi5maWx0ZXIoY2hpbGQgPT4gY2hpbGQubm9kZS5pZCA9PT0gJ2RhdGF6b25lRW52aXJvbm1lbnRQcm9qZWN0SWQnKTtcbiAgICBleHBlY3QocGFyYW1zLmxlbmd0aCkudG9CZSgxKTtcbiAgfSk7XG5cbiAgdGVzdCgnaWdub3JlcyBub24tYmx1ZXByaW50IHJlZnMnLCAoKSA9PiB7XG4gICAgY29uc3QgdHJhbnNmb3JtZXIgPSBuZXcgTWRhYUNvbmZpZ0JsdWVwcmludFJlZlZhbHVlVHJhbnNmb3JtZXIoe1xuICAgICAgbmFtaW5nOiBtb2NrTmFtaW5nLFxuICAgICAgc2NvcGU6IHN0YWNrLFxuICAgIH0pO1xuICAgIGNvbnN0IHJlc3VsdCA9IHRyYW5zZm9ybWVyLnRyYW5zZm9ybVZhbHVlKCd7e290aGVyOnZhbHVlfX0nKTtcbiAgICAvLyBOb24tYmx1ZXByaW50IHJlZnMgc2hvdWxkIHJlbWFpbiB1bmNoYW5nZWRcbiAgICBleHBlY3QocmVzdWx0KS50b0JlKCd7e290aGVyOnZhbHVlfX0nKTtcbiAgfSk7XG5cbiAgdGVzdCgnaGFuZGxlcyBuZXN0ZWQgcmVmcyBpbiBibHVlcHJpbnQgcGF0aCcsICgpID0+IHtcbiAgICBjb25zdCB0cmFuc2Zvcm1lciA9IG5ldyBNZGFhQ29uZmlnQmx1ZXByaW50UmVmVmFsdWVUcmFuc2Zvcm1lcih7XG4gICAgICBuYW1pbmc6IG1vY2tOYW1pbmcsXG4gICAgICBzY29wZTogc3RhY2ssXG4gICAgfSk7XG4gICAgLy8gTmVzdGVkIHJlZnMgc2hvdWxkIGJlIHByb2Nlc3NlZCByZWN1cnNpdmVseVxuICAgIGNvbnN0IHJlc3VsdCA9IHRyYW5zZm9ybWVyLnRyYW5zZm9ybVZhbHVlKCd7e2JsdWVwcmludDove3tvdGhlcn19L3BhdGh9fScpO1xuICAgIC8vIFRoZSBpbm5lciByZWYgaXMgbm90IGEgYmx1ZXByaW50IHJlZiwgc28gaXQgc3RheXMgYXMtaXMgaW4gdGhlIHBhdGhcbiAgICBleHBlY3QocmVzdWx0KS50b0NvbnRhaW4oJ3t7cmVzb2x2ZTpzc206Jyk7XG4gIH0pO1xuXG4gIHRlc3QoJ2hhbmRsZXMgdW5iYWxhbmNlZCBicmFjZXMgZ3JhY2VmdWxseScsICgpID0+IHtcbiAgICBjb25zdCB0cmFuc2Zvcm1lciA9IG5ldyBNZGFhQ29uZmlnQmx1ZXByaW50UmVmVmFsdWVUcmFuc2Zvcm1lcih7XG4gICAgICBuYW1pbmc6IG1vY2tOYW1pbmcsXG4gICAgICBzY29wZTogc3RhY2ssXG4gICAgfSk7XG4gICAgLy8gVW5iYWxhbmNlZCBicmFjZXMgc2hvdWxkIGJlIHNraXBwZWRcbiAgICBleHBlY3QodHJhbnNmb3JtZXIudHJhbnNmb3JtVmFsdWUoJ3t7Ymx1ZXByaW50Oi9wYXRoJykpLnRvQmUoJ3t7Ymx1ZXByaW50Oi9wYXRoJyk7XG4gICAgZXhwZWN0KHRyYW5zZm9ybWVyLnRyYW5zZm9ybVZhbHVlKCdibHVlcHJpbnQ6L3BhdGh9fScpKS50b0JlKCdibHVlcHJpbnQ6L3BhdGh9fScpO1xuICB9KTtcblxuICB0ZXN0KCdsb2dzIHJlc29sdmVkIGJsdWVwcmludCBwYXRoJywgKCkgPT4ge1xuICAgIGNvbnN0IGNvbnNvbGVTcHkgPSBqZXN0LnNweU9uKGNvbnNvbGUsICdsb2cnKS5tb2NrSW1wbGVtZW50YXRpb24oKTtcbiAgICBjb25zdCB0cmFuc2Zvcm1lciA9IG5ldyBNZGFhQ29uZmlnQmx1ZXByaW50UmVmVmFsdWVUcmFuc2Zvcm1lcih7XG4gICAgICBuYW1pbmc6IG1vY2tOYW1pbmcsXG4gICAgICBzY29wZTogc3RhY2ssXG4gICAgfSk7XG5cbiAgICB0cmFuc2Zvcm1lci50cmFuc2Zvcm1WYWx1ZSgne3tibHVlcHJpbnQ6L3Rlc3QvcGF0aH19Jyk7XG5cbiAgICBleHBlY3QoY29uc29sZVNweSkudG9IYXZlQmVlbkNhbGxlZFdpdGgoZXhwZWN0LnN0cmluZ0NvbnRhaW5pbmcoJ1Jlc29sdmluZyBibHVlcHJpbnQgcGF0aDonKSk7XG4gICAgY29uc29sZVNweS5tb2NrUmVzdG9yZSgpO1xuICB9KTtcblxuICB0ZXN0KCdoYW5kbGVzIGJsdWVwcmludCByZWYgd2l0aCBzcGVjaWFsIGNoYXJhY3RlcnMgaW4gcGF0aCcsICgpID0+IHtcbiAgICBjb25zdCB0cmFuc2Zvcm1lciA9IG5ldyBNZGFhQ29uZmlnQmx1ZXByaW50UmVmVmFsdWVUcmFuc2Zvcm1lcih7XG4gICAgICBuYW1pbmc6IG1vY2tOYW1pbmcsXG4gICAgICBzY29wZTogc3RhY2ssXG4gICAgfSk7XG4gICAgY29uc3QgcmVzdWx0ID0gdHJhbnNmb3JtZXIudHJhbnNmb3JtVmFsdWUoJ3t7Ymx1ZXByaW50Oi9wYXRoL3dpdGgtZGFzaGVzX2FuZF91bmRlcnNjb3Jlcy8xMjN9fScpO1xuICAgIGV4cGVjdChyZXN1bHQpLnRvQ29udGFpbigne3tyZXNvbHZlOnNzbTonKTtcbiAgICBleHBlY3QocmVzdWx0KS50b0NvbnRhaW4oJy9wYXRoL3dpdGgtZGFzaGVzX2FuZF91bmRlcnNjb3Jlcy8xMjN9fScpO1xuICB9KTtcblxuICB0ZXN0KCdoYW5kbGVzIGJsdWVwcmludCByZWYgYXQgc3RhcnQgb2Ygc3RyaW5nJywgKCkgPT4ge1xuICAgIGNvbnN0IHRyYW5zZm9ybWVyID0gbmV3IE1kYWFDb25maWdCbHVlcHJpbnRSZWZWYWx1ZVRyYW5zZm9ybWVyKHtcbiAgICAgIG5hbWluZzogbW9ja05hbWluZyxcbiAgICAgIHNjb3BlOiBzdGFjayxcbiAgICB9KTtcbiAgICBjb25zdCByZXN1bHQgPSB0cmFuc2Zvcm1lci50cmFuc2Zvcm1WYWx1ZSgne3tibHVlcHJpbnQ6L3BhdGh9fS1zdWZmaXgnKTtcbiAgICBleHBlY3QocmVzdWx0KS50b01hdGNoKC9eXFx7XFx7cmVzb2x2ZTpzc206Lyk7XG4gICAgZXhwZWN0KHJlc3VsdCkudG9Db250YWluKCctc3VmZml4Jyk7XG4gIH0pO1xuXG4gIHRlc3QoJ2hhbmRsZXMgYmx1ZXByaW50IHJlZiBhdCBlbmQgb2Ygc3RyaW5nJywgKCkgPT4ge1xuICAgIGNvbnN0IHRyYW5zZm9ybWVyID0gbmV3IE1kYWFDb25maWdCbHVlcHJpbnRSZWZWYWx1ZVRyYW5zZm9ybWVyKHtcbiAgICAgIG5hbWluZzogbW9ja05hbWluZyxcbiAgICAgIHNjb3BlOiBzdGFjayxcbiAgICB9KTtcbiAgICBjb25zdCByZXN1bHQgPSB0cmFuc2Zvcm1lci50cmFuc2Zvcm1WYWx1ZSgncHJlZml4LXt7Ymx1ZXByaW50Oi9wYXRofX0nKTtcbiAgICBleHBlY3QocmVzdWx0KS50b0NvbnRhaW4oJ3ByZWZpeC0nKTtcbiAgICBleHBlY3QocmVzdWx0KS50b01hdGNoKC9cXH1cXH0kLyk7XG4gIH0pO1xuXG4gIHRlc3QoJ2hhbmRsZXMgbXVsdGlwbGUgZGlmZmVyZW50IHJlZiB0eXBlcyBtaXhlZCcsICgpID0+IHtcbiAgICBjb25zdCB0cmFuc2Zvcm1lciA9IG5ldyBNZGFhQ29uZmlnQmx1ZXByaW50UmVmVmFsdWVUcmFuc2Zvcm1lcih7XG4gICAgICBuYW1pbmc6IG1vY2tOYW1pbmcsXG4gICAgICBzY29wZTogc3RhY2ssXG4gICAgfSk7XG4gICAgY29uc3QgcmVzdWx0ID0gdHJhbnNmb3JtZXIudHJhbnNmb3JtVmFsdWUoJ3t7Ymx1ZXByaW50Oi9wYXRoMX19LXt7b3RoZXI6cmVmfX0te3tibHVlcHJpbnQ6L3BhdGgyfX0nKTtcbiAgICBleHBlY3QocmVzdWx0KS50b0NvbnRhaW4oJy9wYXRoMX19Jyk7XG4gICAgZXhwZWN0KHJlc3VsdCkudG9Db250YWluKCd7e290aGVyOnJlZn19Jyk7XG4gICAgZXhwZWN0KHJlc3VsdCkudG9Db250YWluKCcvcGF0aDJ9fScpO1xuICB9KTtcblxuICB0ZXN0KCdoYW5kbGVzIGVtcHR5IGJsdWVwcmludCBwYXRoJywgKCkgPT4ge1xuICAgIGNvbnN0IHRyYW5zZm9ybWVyID0gbmV3IE1kYWFDb25maWdCbHVlcHJpbnRSZWZWYWx1ZVRyYW5zZm9ybWVyKHtcbiAgICAgIG5hbWluZzogbW9ja05hbWluZyxcbiAgICAgIHNjb3BlOiBzdGFjayxcbiAgICB9KTtcbiAgICBjb25zdCByZXN1bHQgPSB0cmFuc2Zvcm1lci50cmFuc2Zvcm1WYWx1ZSgne3tibHVlcHJpbnQ6fX0nKTtcbiAgICBleHBlY3QocmVzdWx0KS50b0NvbnRhaW4oJ3t7cmVzb2x2ZTpzc206Jyk7XG4gIH0pO1xuXG4gIHRlc3QoJ2hhbmRsZXMgYmx1ZXByaW50IHJlZiB3aXRoIG9ubHkgc2xhc2hlcycsICgpID0+IHtcbiAgICBjb25zdCB0cmFuc2Zvcm1lciA9IG5ldyBNZGFhQ29uZmlnQmx1ZXByaW50UmVmVmFsdWVUcmFuc2Zvcm1lcih7XG4gICAgICBuYW1pbmc6IG1vY2tOYW1pbmcsXG4gICAgICBzY29wZTogc3RhY2ssXG4gICAgfSk7XG4gICAgY29uc3QgcmVzdWx0ID0gdHJhbnNmb3JtZXIudHJhbnNmb3JtVmFsdWUoJ3t7Ymx1ZXByaW50Oi99fScpO1xuICAgIGV4cGVjdChyZXN1bHQpLnRvQ29udGFpbigne3tyZXNvbHZlOnNzbTonKTtcbiAgICBleHBlY3QocmVzdWx0KS50b0NvbnRhaW4oJy99fScpO1xuICB9KTtcblxuICB0ZXN0KCdjcmVhdGVzIHBhcmFtZXRlciBvbiBmaXJzdCBibHVlcHJpbnQgcmVmJywgKCkgPT4ge1xuICAgIGNvbnN0IHRyYW5zZm9ybWVyID0gbmV3IE1kYWFDb25maWdCbHVlcHJpbnRSZWZWYWx1ZVRyYW5zZm9ybWVyKHtcbiAgICAgIG5hbWluZzogbW9ja05hbWluZyxcbiAgICAgIHNjb3BlOiBzdGFjayxcbiAgICB9KTtcblxuICAgIGNvbnN0IGNoaWxkcmVuQmVmb3JlID0gc3RhY2subm9kZS5jaGlsZHJlbi5sZW5ndGg7XG4gICAgdHJhbnNmb3JtZXIudHJhbnNmb3JtVmFsdWUoJ3t7Ymx1ZXByaW50Oi9maXJzdH19Jyk7XG4gICAgY29uc3QgY2hpbGRyZW5BZnRlciA9IHN0YWNrLm5vZGUuY2hpbGRyZW4ubGVuZ3RoO1xuXG4gICAgZXhwZWN0KGNoaWxkcmVuQWZ0ZXIpLnRvQmVHcmVhdGVyVGhhbihjaGlsZHJlbkJlZm9yZSk7XG4gIH0pO1xuXG4gIHRlc3QoJ2RvZXMgbm90IGNyZWF0ZSBkdXBsaWNhdGUgcGFyYW1ldGVycycsICgpID0+IHtcbiAgICBjb25zdCB0cmFuc2Zvcm1lciA9IG5ldyBNZGFhQ29uZmlnQmx1ZXByaW50UmVmVmFsdWVUcmFuc2Zvcm1lcih7XG4gICAgICBuYW1pbmc6IG1vY2tOYW1pbmcsXG4gICAgICBzY29wZTogc3RhY2ssXG4gICAgfSk7XG5cbiAgICB0cmFuc2Zvcm1lci50cmFuc2Zvcm1WYWx1ZSgne3tibHVlcHJpbnQ6L2ZpcnN0fX0nKTtcbiAgICBjb25zdCBjaGlsZHJlbkFmdGVyRmlyc3QgPSBzdGFjay5ub2RlLmNoaWxkcmVuLmxlbmd0aDtcblxuICAgIHRyYW5zZm9ybWVyLnRyYW5zZm9ybVZhbHVlKCd7e2JsdWVwcmludDovc2Vjb25kfX0nKTtcbiAgICBjb25zdCBjaGlsZHJlbkFmdGVyU2Vjb25kID0gc3RhY2subm9kZS5jaGlsZHJlbi5sZW5ndGg7XG5cbiAgICAvLyBTaG91bGQgbm90IGNyZWF0ZSBhZGRpdGlvbmFsIHBhcmFtZXRlcnNcbiAgICBleHBlY3QoY2hpbGRyZW5BZnRlclNlY29uZCkudG9CZShjaGlsZHJlbkFmdGVyRmlyc3QpO1xuICB9KTtcblxuICB0ZXN0KCd0aHJvd3Mgd2hlbiBibHVlcHJpbnQgcmVmIHdpdGhvdXQgc2NvcGUnLCAoKSA9PiB7XG4gICAgY29uc3QgdHJhbnNmb3JtZXIgPSBuZXcgTWRhYUNvbmZpZ0JsdWVwcmludFJlZlZhbHVlVHJhbnNmb3JtZXIoe1xuICAgICAgbmFtaW5nOiBtb2NrTmFtaW5nLFxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1leHBsaWNpdC1hbnlcbiAgICAgIHNjb3BlOiB1bmRlZmluZWQgYXMgYW55LFxuICAgIH0pO1xuICAgIGV4cGVjdCgoKSA9PiB0cmFuc2Zvcm1lci50cmFuc2Zvcm1WYWx1ZSgne3tibHVlcHJpbnQ6L3BhdGh9fScpKS50b1Rocm93KFxuICAgICAgJ1VuYWJsZSB0byByZXNvbHZlIGJsdWVwcmludCBwYXJhbXMgb3V0c2lkZSBvZiBhIENvbnN0cnVjdCcsXG4gICAgKTtcbiAgfSk7XG5cbiAgdGVzdCgndGhyb3dzIHdoZW4gYmx1ZXByaW50IHJlZiB3aXRob3V0IG5hbWluZycsICgpID0+IHtcbiAgICBjb25zdCB0cmFuc2Zvcm1lciA9IG5ldyBNZGFhQ29uZmlnQmx1ZXByaW50UmVmVmFsdWVUcmFuc2Zvcm1lcih7XG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueVxuICAgICAgbmFtaW5nOiB1bmRlZmluZWQgYXMgYW55LFxuICAgICAgc2NvcGU6IHN0YWNrLFxuICAgIH0pO1xuICAgIGV4cGVjdCgoKSA9PiB0cmFuc2Zvcm1lci50cmFuc2Zvcm1WYWx1ZSgne3tibHVlcHJpbnQ6L3BhdGh9fScpKS50b1Rocm93KFxuICAgICAgJ1VuYWJsZSB0byByZXNvbHZlIGJsdWVwcmludCBwYXJhbXMgd2l0aG91dCBhIG5hbWluZyBpbXBsZW1lbnRhdGlvbicsXG4gICAgKTtcbiAgfSk7XG59KTtcbiJdfQ==
@@ -0,0 +1,259 @@
1
+ /*!
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ import { Stack } from 'aws-cdk-lib';
7
+ import { MdaaConfigBlueprintRefValueTransformer } from '../lib';
8
+ import { IMdaaResourceNaming } from '@aws-mdaa/naming';
9
+
10
+ describe('MdaaConfigBlueprintRefValueTransformer', () => {
11
+ let mockNaming: IMdaaResourceNaming;
12
+ let stack: Stack;
13
+
14
+ beforeEach(() => {
15
+ stack = new Stack();
16
+ mockNaming = {
17
+ props: {
18
+ org: 'test-org',
19
+ env: 'test-env',
20
+ domain: 'test-domain',
21
+ moduleName: 'test-module',
22
+ },
23
+ withModuleName: jest.fn().mockReturnThis(),
24
+ withDomain: jest.fn().mockReturnThis(),
25
+ withOrg: jest.fn().mockReturnThis(),
26
+ withEnv: jest.fn().mockReturnThis(),
27
+ withSuffix: jest.fn().mockReturnThis(),
28
+ ssmDomainPath: jest.fn().mockReturnValue('/test/domain/path'),
29
+ ssmEnvPath: jest.fn().mockReturnValue('/test/env/path'),
30
+ ssmOrgPath: jest.fn().mockReturnValue('/test-org/'),
31
+ resourceName: jest
32
+ .fn()
33
+ .mockImplementation((suffix?: string) => (suffix ? `test-resource-${suffix}` : 'test-resource')),
34
+ ssmPath: jest.fn().mockImplementation((path: string) => `/test/${path}`),
35
+ stackName: jest.fn().mockImplementation((name?: string) => (name ? `test-stack-${name}` : 'test-stack')),
36
+ exportName: jest.fn().mockImplementation((path: string) => `test-export-${path}`),
37
+ } as unknown as IMdaaResourceNaming;
38
+ });
39
+
40
+ test('returns unchanged value without refs', () => {
41
+ const transformer = new MdaaConfigBlueprintRefValueTransformer({
42
+ naming: mockNaming,
43
+ scope: stack,
44
+ });
45
+ expect(transformer.transformValue('plain-value')).toBe('plain-value');
46
+ });
47
+
48
+ test('returns unchanged value with empty string', () => {
49
+ const transformer = new MdaaConfigBlueprintRefValueTransformer({
50
+ naming: mockNaming,
51
+ scope: stack,
52
+ });
53
+ expect(transformer.transformValue('')).toBe('');
54
+ });
55
+
56
+ test('transforms blueprint ref', () => {
57
+ const transformer = new MdaaConfigBlueprintRefValueTransformer({
58
+ naming: mockNaming,
59
+ scope: stack,
60
+ });
61
+ const result = transformer.transformValue('{{blueprint:/some/path}}');
62
+ expect(result).toContain('{{resolve:ssm:/test-org/');
63
+ expect(result).toContain('/some/path}}');
64
+ expect(mockNaming.ssmOrgPath).toHaveBeenCalledWith('', false);
65
+ });
66
+
67
+ test('transforms blueprint ref with prefix and suffix', () => {
68
+ const transformer = new MdaaConfigBlueprintRefValueTransformer({
69
+ naming: mockNaming,
70
+ scope: stack,
71
+ });
72
+ const result = transformer.transformValue('prefix-{{blueprint:/path}}-suffix');
73
+ expect(result).toContain('prefix-');
74
+ expect(result).toContain('-suffix');
75
+ expect(result).toContain('{{resolve:ssm:');
76
+ });
77
+
78
+ test('handles multiple blueprint refs', () => {
79
+ const transformer = new MdaaConfigBlueprintRefValueTransformer({
80
+ naming: mockNaming,
81
+ scope: stack,
82
+ });
83
+ const result = transformer.transformValue('{{blueprint:/path1}}-{{blueprint:/path2}}');
84
+ expect(result).toContain('/path1}}');
85
+ expect(result).toContain('/path2}}');
86
+ });
87
+
88
+ test('reuses existing CfnParameter for datazoneEnvironmentProjectId', () => {
89
+ const transformer = new MdaaConfigBlueprintRefValueTransformer({
90
+ naming: mockNaming,
91
+ scope: stack,
92
+ });
93
+
94
+ // First call creates the parameter
95
+ transformer.transformValue('{{blueprint:/path1}}');
96
+
97
+ // Second call should reuse the same parameter
98
+ transformer.transformValue('{{blueprint:/path2}}');
99
+
100
+ // Should only have one datazoneEnvironmentProjectId parameter
101
+ const params = stack.node.children.filter(child => child.node.id === 'datazoneEnvironmentProjectId');
102
+ expect(params.length).toBe(1);
103
+ });
104
+
105
+ test('ignores non-blueprint refs', () => {
106
+ const transformer = new MdaaConfigBlueprintRefValueTransformer({
107
+ naming: mockNaming,
108
+ scope: stack,
109
+ });
110
+ const result = transformer.transformValue('{{other:value}}');
111
+ // Non-blueprint refs should remain unchanged
112
+ expect(result).toBe('{{other:value}}');
113
+ });
114
+
115
+ test('handles nested refs in blueprint path', () => {
116
+ const transformer = new MdaaConfigBlueprintRefValueTransformer({
117
+ naming: mockNaming,
118
+ scope: stack,
119
+ });
120
+ // Nested refs should be processed recursively
121
+ const result = transformer.transformValue('{{blueprint:/{{other}}/path}}');
122
+ // The inner ref is not a blueprint ref, so it stays as-is in the path
123
+ expect(result).toContain('{{resolve:ssm:');
124
+ });
125
+
126
+ test('handles unbalanced braces gracefully', () => {
127
+ const transformer = new MdaaConfigBlueprintRefValueTransformer({
128
+ naming: mockNaming,
129
+ scope: stack,
130
+ });
131
+ // Unbalanced braces should be skipped
132
+ expect(transformer.transformValue('{{blueprint:/path')).toBe('{{blueprint:/path');
133
+ expect(transformer.transformValue('blueprint:/path}}')).toBe('blueprint:/path}}');
134
+ });
135
+
136
+ test('logs resolved blueprint path', () => {
137
+ const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
138
+ const transformer = new MdaaConfigBlueprintRefValueTransformer({
139
+ naming: mockNaming,
140
+ scope: stack,
141
+ });
142
+
143
+ transformer.transformValue('{{blueprint:/test/path}}');
144
+
145
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Resolving blueprint path:'));
146
+ consoleSpy.mockRestore();
147
+ });
148
+
149
+ test('handles blueprint ref with special characters in path', () => {
150
+ const transformer = new MdaaConfigBlueprintRefValueTransformer({
151
+ naming: mockNaming,
152
+ scope: stack,
153
+ });
154
+ const result = transformer.transformValue('{{blueprint:/path/with-dashes_and_underscores/123}}');
155
+ expect(result).toContain('{{resolve:ssm:');
156
+ expect(result).toContain('/path/with-dashes_and_underscores/123}}');
157
+ });
158
+
159
+ test('handles blueprint ref at start of string', () => {
160
+ const transformer = new MdaaConfigBlueprintRefValueTransformer({
161
+ naming: mockNaming,
162
+ scope: stack,
163
+ });
164
+ const result = transformer.transformValue('{{blueprint:/path}}-suffix');
165
+ expect(result).toMatch(/^\{\{resolve:ssm:/);
166
+ expect(result).toContain('-suffix');
167
+ });
168
+
169
+ test('handles blueprint ref at end of string', () => {
170
+ const transformer = new MdaaConfigBlueprintRefValueTransformer({
171
+ naming: mockNaming,
172
+ scope: stack,
173
+ });
174
+ const result = transformer.transformValue('prefix-{{blueprint:/path}}');
175
+ expect(result).toContain('prefix-');
176
+ expect(result).toMatch(/\}\}$/);
177
+ });
178
+
179
+ test('handles multiple different ref types mixed', () => {
180
+ const transformer = new MdaaConfigBlueprintRefValueTransformer({
181
+ naming: mockNaming,
182
+ scope: stack,
183
+ });
184
+ const result = transformer.transformValue('{{blueprint:/path1}}-{{other:ref}}-{{blueprint:/path2}}');
185
+ expect(result).toContain('/path1}}');
186
+ expect(result).toContain('{{other:ref}}');
187
+ expect(result).toContain('/path2}}');
188
+ });
189
+
190
+ test('handles empty blueprint path', () => {
191
+ const transformer = new MdaaConfigBlueprintRefValueTransformer({
192
+ naming: mockNaming,
193
+ scope: stack,
194
+ });
195
+ const result = transformer.transformValue('{{blueprint:}}');
196
+ expect(result).toContain('{{resolve:ssm:');
197
+ });
198
+
199
+ test('handles blueprint ref with only slashes', () => {
200
+ const transformer = new MdaaConfigBlueprintRefValueTransformer({
201
+ naming: mockNaming,
202
+ scope: stack,
203
+ });
204
+ const result = transformer.transformValue('{{blueprint:/}}');
205
+ expect(result).toContain('{{resolve:ssm:');
206
+ expect(result).toContain('/}}');
207
+ });
208
+
209
+ test('creates parameter on first blueprint ref', () => {
210
+ const transformer = new MdaaConfigBlueprintRefValueTransformer({
211
+ naming: mockNaming,
212
+ scope: stack,
213
+ });
214
+
215
+ const childrenBefore = stack.node.children.length;
216
+ transformer.transformValue('{{blueprint:/first}}');
217
+ const childrenAfter = stack.node.children.length;
218
+
219
+ expect(childrenAfter).toBeGreaterThan(childrenBefore);
220
+ });
221
+
222
+ test('does not create duplicate parameters', () => {
223
+ const transformer = new MdaaConfigBlueprintRefValueTransformer({
224
+ naming: mockNaming,
225
+ scope: stack,
226
+ });
227
+
228
+ transformer.transformValue('{{blueprint:/first}}');
229
+ const childrenAfterFirst = stack.node.children.length;
230
+
231
+ transformer.transformValue('{{blueprint:/second}}');
232
+ const childrenAfterSecond = stack.node.children.length;
233
+
234
+ // Should not create additional parameters
235
+ expect(childrenAfterSecond).toBe(childrenAfterFirst);
236
+ });
237
+
238
+ test('throws when blueprint ref without scope', () => {
239
+ const transformer = new MdaaConfigBlueprintRefValueTransformer({
240
+ naming: mockNaming,
241
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
242
+ scope: undefined as any,
243
+ });
244
+ expect(() => transformer.transformValue('{{blueprint:/path}}')).toThrow(
245
+ 'Unable to resolve blueprint params outside of a Construct',
246
+ );
247
+ });
248
+
249
+ test('throws when blueprint ref without naming', () => {
250
+ const transformer = new MdaaConfigBlueprintRefValueTransformer({
251
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
252
+ naming: undefined as any,
253
+ scope: stack,
254
+ });
255
+ expect(() => transformer.transformValue('{{blueprint:/path}}')).toThrow(
256
+ 'Unable to resolve blueprint params without a naming implementation',
257
+ );
258
+ });
259
+ });
@@ -0,0 +1,5 @@
1
+ /*!
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ export {};