@quadnix/octo 0.0.2 → 0.0.4

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 (86) hide show
  1. package/package.json +6 -1
  2. package/.eslintrc.cjs +0 -26
  3. package/dist/tsconfig.build.tsbuildinfo +0 -1
  4. package/src/app.type.ts +0 -56
  5. package/src/decorators/action.decorator.spec.ts +0 -43
  6. package/src/decorators/action.decorator.ts +0 -24
  7. package/src/decorators/anchor.decorator.ts +0 -10
  8. package/src/decorators/container.spec.ts +0 -104
  9. package/src/decorators/container.ts +0 -133
  10. package/src/decorators/factory.decorator.ts +0 -13
  11. package/src/decorators/model.decorator.ts +0 -10
  12. package/src/decorators/module.decorator.ts +0 -13
  13. package/src/decorators/overlay.decorator.ts +0 -10
  14. package/src/decorators/resource.decorator.ts +0 -10
  15. package/src/decorators/test-container.spec.ts +0 -50
  16. package/src/decorators/test-container.ts +0 -56
  17. package/src/functions/dependency/dependency.model.spec.ts +0 -43
  18. package/src/functions/dependency/dependency.model.ts +0 -178
  19. package/src/functions/diff/diff-metadata.model.ts +0 -51
  20. package/src/functions/diff/diff.model.ts +0 -33
  21. package/src/functions/diff/diff.utility.ts +0 -163
  22. package/src/functions/module/module.abstract.ts +0 -59
  23. package/src/functions/module/module.interface.ts +0 -5
  24. package/src/index.ts +0 -62
  25. package/src/models/action.interface.ts +0 -35
  26. package/src/models/app/app.interface.ts +0 -5
  27. package/src/models/app/app.model.ts +0 -111
  28. package/src/models/deployment/deployment.interface.ts +0 -5
  29. package/src/models/deployment/deployment.model.ts +0 -35
  30. package/src/models/environment/environment.interface.ts +0 -6
  31. package/src/models/environment/environment.model.spec.ts +0 -125
  32. package/src/models/environment/environment.model.ts +0 -55
  33. package/src/models/execution/execution.interface.ts +0 -8
  34. package/src/models/execution/execution.model.spec.ts +0 -62
  35. package/src/models/execution/execution.model.ts +0 -89
  36. package/src/models/image/image.interface.ts +0 -8
  37. package/src/models/image/image.model.ts +0 -62
  38. package/src/models/model.abstract.ts +0 -324
  39. package/src/models/model.interface.ts +0 -42
  40. package/src/models/pipeline/pipeline.interface.ts +0 -6
  41. package/src/models/pipeline/pipeline.model.ts +0 -47
  42. package/src/models/region/region.interface.ts +0 -5
  43. package/src/models/region/region.model.spec.ts +0 -162
  44. package/src/models/region/region.model.ts +0 -48
  45. package/src/models/server/server.interface.ts +0 -7
  46. package/src/models/server/server.model.ts +0 -56
  47. package/src/models/service/service.interface.ts +0 -5
  48. package/src/models/service/service.model.ts +0 -25
  49. package/src/models/support/support.interface.ts +0 -6
  50. package/src/models/support/support.model.spec.ts +0 -78
  51. package/src/models/support/support.model.ts +0 -52
  52. package/src/overlays/anchor.abstract.ts +0 -41
  53. package/src/overlays/anchor.interface.ts +0 -7
  54. package/src/overlays/anchor.spec.ts +0 -41
  55. package/src/overlays/overlay-data.repository.ts +0 -76
  56. package/src/overlays/overlay.abstract.ts +0 -64
  57. package/src/overlays/overlay.interface.ts +0 -9
  58. package/src/overlays/overlay.service.ts +0 -38
  59. package/src/overlays/overlay.spec.ts +0 -86
  60. package/src/resources/resource-action.interface.ts +0 -9
  61. package/src/resources/resource-data.repository.spec.ts +0 -133
  62. package/src/resources/resource-data.repository.ts +0 -92
  63. package/src/resources/resource.abstract.ts +0 -108
  64. package/src/resources/resource.interface.ts +0 -7
  65. package/src/resources/resource.spec.ts +0 -60
  66. package/src/resources/shared-resource.abstract.ts +0 -53
  67. package/src/resources/shared-resource.spec.ts +0 -133
  68. package/src/services/serialization/model/__snapshots__/model-serialization.service.spec.ts.snap +0 -656
  69. package/src/services/serialization/model/model-serialization.service.spec.ts +0 -195
  70. package/src/services/serialization/model/model-serialization.service.ts +0 -172
  71. package/src/services/serialization/resource/__snapshots__/resource-serialization.service.spec.ts.snap +0 -284
  72. package/src/services/serialization/resource/resource-serialization.service.spec.ts +0 -311
  73. package/src/services/serialization/resource/resource-serialization.service.ts +0 -166
  74. package/src/services/state-management/local.state-provider.spec.ts +0 -42
  75. package/src/services/state-management/local.state-provider.ts +0 -23
  76. package/src/services/state-management/state-management.service.ts +0 -43
  77. package/src/services/state-management/state-provider.interface.ts +0 -5
  78. package/src/services/transaction/__snapshots__/transaction.service.spec.ts.snap +0 -284
  79. package/src/services/transaction/transaction.service.spec.ts +0 -823
  80. package/src/services/transaction/transaction.service.ts +0 -386
  81. package/test/app.e2e-spec.ts +0 -104
  82. package/test/helpers/test-classes.ts +0 -31
  83. package/test/models/__snapshots__/model.e2e-spec.ts.snap +0 -451
  84. package/test/models/model.e2e-spec.ts +0 -366
  85. package/tsconfig.build.json +0 -4
  86. package/tsconfig.json +0 -9
@@ -1,386 +0,0 @@
1
- import {
2
- ActionInputs,
3
- ActionOutputs,
4
- ModelType,
5
- TransactionOptions,
6
- UnknownResource,
7
- UnknownSharedResource,
8
- } from '../../app.type.js';
9
- import { Container } from '../../decorators/container.js';
10
- import { Factory } from '../../decorators/factory.decorator.js';
11
- import { DiffMetadata } from '../../functions/diff/diff-metadata.model.js';
12
- import { Diff, DiffAction } from '../../functions/diff/diff.model.js';
13
- import { IAction } from '../../models/action.interface.js';
14
- import { OverlayDataRepository } from '../../overlays/overlay-data.repository.js';
15
- import { IResourceAction } from '../../resources/resource-action.interface.js';
16
- import { ResourceDataRepository } from '../../resources/resource-data.repository.js';
17
-
18
- export class TransactionService {
19
- private readonly inputs: ActionInputs = {};
20
- private readonly modelActions: IAction<ActionInputs, ActionOutputs>[] = [];
21
- private readonly overlayActions: IAction<ActionInputs, ActionOutputs>[] = [];
22
- private readonly resourceActions: IResourceAction[] = [];
23
-
24
- private async applyModels(
25
- diffs: DiffMetadata[],
26
- resourceDataRepository: ResourceDataRepository,
27
- ): Promise<DiffMetadata[][]> {
28
- const transaction: DiffMetadata[][] = [];
29
-
30
- let currentApplyOrder = 0;
31
- let processed = 0;
32
-
33
- while (processed < diffs.length) {
34
- const diffsInSameLevel = diffs.filter((d) => d.applyOrder === currentApplyOrder);
35
- const diffsProcessedInSameLevel: DiffMetadata[] = [];
36
- const promiseToApplyActions: Promise<ActionOutputs>[] = [];
37
-
38
- for (const diff of diffsInSameLevel) {
39
- if (diff.applied) {
40
- continue;
41
- }
42
-
43
- // Check for duplicate diffs on the same model and same field.
44
- const duplicateDiffs = this.getDuplicateDiffs(diff, diffsInSameLevel);
45
-
46
- // Only process the first diff, given all duplicate diffs are the same.
47
- const diffToProcess = duplicateDiffs[0].diff;
48
-
49
- for (const a of diff.actions as IAction<ActionInputs, ActionOutputs>[]) {
50
- // Resolve input requests.
51
- const inputs: ActionInputs = {};
52
- const inputKeys = a.collectInput(diffToProcess);
53
- inputKeys.map((k) => {
54
- if ((k as string).startsWith('resource')) {
55
- const resourceId = (k as string).substring('resource.'.length);
56
- inputs[k] = resourceDataRepository.getById(resourceId)!;
57
- } else {
58
- inputs[k] = this.inputs[k];
59
- }
60
-
61
- if (!inputs[k]) {
62
- throw new Error('No matching input found to process action!');
63
- }
64
- });
65
-
66
- // Apply all actions on the diff, then update diff metadata with inputs and outputs.
67
- const promiseToApplyAction = a.handle(diffToProcess, inputs).then((outputs) => {
68
- duplicateDiffs.forEach((d) => {
69
- d.updateInputs(inputs);
70
- d.updateOutputs(outputs);
71
- });
72
-
73
- return outputs;
74
- });
75
- promiseToApplyActions.push(promiseToApplyAction);
76
- }
77
-
78
- // Include the diff to process in the list of diffs processed in the same level.
79
- diffsProcessedInSameLevel.push(duplicateDiffs[0]);
80
-
81
- // Mark metadata of each duplicate diffs as applied.
82
- duplicateDiffs.forEach((d) => (d.applied = true));
83
- }
84
-
85
- // Apply all actions of same level, since they can be applied in parallel.
86
- const actionsOutputs = await Promise.all(promiseToApplyActions);
87
-
88
- // Overwrite previous resources with new resources, except for shared resources,
89
- // which can be merged if it exists.
90
- for (const outputs of actionsOutputs) {
91
- for (const [resourceId, resource] of Object.entries(outputs)) {
92
- const previousResource = resourceDataRepository.getById(resourceId);
93
- if (resource.MODEL_TYPE === 'shared-resource' && previousResource) {
94
- resourceDataRepository.add(
95
- (resource as UnknownSharedResource).merge(previousResource as UnknownSharedResource),
96
- );
97
- } else {
98
- resourceDataRepository.add(resource);
99
- }
100
- }
101
- }
102
-
103
- // Add all diff in same level to transaction.
104
- transaction.push(diffsProcessedInSameLevel);
105
-
106
- processed += diffsInSameLevel.length;
107
- currentApplyOrder += 1;
108
- }
109
-
110
- return transaction;
111
- }
112
-
113
- private async applyResources(diffs: DiffMetadata[]): Promise<DiffMetadata[][]> {
114
- const transaction: DiffMetadata[][] = [];
115
-
116
- let currentApplyOrder = 0;
117
- let processed = 0;
118
-
119
- while (processed < diffs.length) {
120
- const diffsInSameLevel = diffs.filter((d) => d.applyOrder === currentApplyOrder);
121
- const diffsProcessedInSameLevel: DiffMetadata[] = [];
122
- const promiseToApplyActions: Promise<void>[] = [];
123
-
124
- for (const diff of diffsInSameLevel) {
125
- if (diff.applied) {
126
- continue;
127
- }
128
-
129
- // Check for duplicate diffs on the same model and same field.
130
- const duplicateDiffs = this.getDuplicateDiffs(diff, diffsInSameLevel);
131
-
132
- // Only process the first diff, given all duplicate diffs are the same.
133
- const diffToProcess = duplicateDiffs[0].diff;
134
-
135
- for (const a of diff.actions as IResourceAction[]) {
136
- promiseToApplyActions.push(a.handle(diffToProcess));
137
- }
138
-
139
- // Include the diff to process in the list of diffs processed in the same level.
140
- diffsProcessedInSameLevel.push(duplicateDiffs[0]);
141
-
142
- // Mark metadata of each duplicate diffs as applied.
143
- duplicateDiffs.forEach((d) => (d.applied = true));
144
- }
145
-
146
- // Apply all actions of same level, since they can be applied in parallel.
147
- await Promise.all(promiseToApplyActions);
148
-
149
- // Add all diff in same level to transaction.
150
- transaction.push(diffsProcessedInSameLevel);
151
-
152
- processed += diffsInSameLevel.length;
153
- currentApplyOrder += 1;
154
- }
155
-
156
- return transaction;
157
- }
158
-
159
- private getDuplicateDiffs(diff: DiffMetadata, diffs: DiffMetadata[]): DiffMetadata[] {
160
- return diffs.filter(
161
- (d) =>
162
- d.model.getContext() === diff.model.getContext() &&
163
- d.field === diff.field &&
164
- d.action === diff.action &&
165
- d.value === diff.value,
166
- );
167
- }
168
-
169
- private getMatchingDiffs(diff: DiffMetadata, diffs: DiffMetadata[]): DiffMetadata[] {
170
- return diffs.filter((d) => d.model.getContext() === diff.model.getContext());
171
- }
172
-
173
- /**
174
- * Before assigning order to a diff, all its model's parent diffs must be processed.
175
- * E.g. diff to add environment, depends on region to exist, thus add region diff gets processed first.
176
- */
177
- private setApplyOrder(diff: DiffMetadata, diffs: DiffMetadata[], seen: DiffMetadata[] = []): void {
178
- // Detect circular dependencies.
179
- if (this.getDuplicateDiffs(diff, seen).length > 0) {
180
- throw new Error('Found circular dependencies!');
181
- }
182
-
183
- // Detect conflicting actions in transaction.
184
- const matchingDiffs = this.getMatchingDiffs(diff, diffs);
185
- const diffActions = matchingDiffs.reduce((accumulator, currentValue) => {
186
- accumulator[currentValue.action] = true;
187
- return accumulator;
188
- }, {});
189
- if (
190
- (diffActions[DiffAction.ADD] && diffActions[DiffAction.UPDATE]) ||
191
- (diffActions[DiffAction.ADD] && diffActions[DiffAction.DELETE]) ||
192
- (diffActions[DiffAction.DELETE] && diffActions[DiffAction.UPDATE])
193
- ) {
194
- throw new Error('Found conflicting actions in same transaction!');
195
- }
196
-
197
- // Skip processing diff that already has the applyOrder set.
198
- if (diff.applyOrder >= 0) {
199
- return;
200
- }
201
-
202
- // Get all dependencies of subject model.
203
- const dependencies = diff.model['dependencies'];
204
- const dependencyApplyOrders: number[] = [-1];
205
-
206
- for (const dependency of dependencies) {
207
- // Iterate diffs looking to match dependency on same field and action.
208
- const matchingParentDiffs = diffs.filter(
209
- (d) =>
210
- d.model.getContext() === dependency.to.getContext() &&
211
- dependency.hasMatchingBehavior(diff.field, diff.action, d.field, d.action),
212
- );
213
-
214
- // On each diff that should be processed first, apply order on it before than self.
215
- for (const matchingParentDiff of matchingParentDiffs) {
216
- this.setApplyOrder(matchingParentDiff, diffs, [...seen, diff]);
217
- dependencyApplyOrders.push(matchingParentDiff.applyOrder);
218
- }
219
- }
220
-
221
- diff.applyOrder = Math.max(...dependencyApplyOrders) + 1;
222
- }
223
-
224
- async *beginTransaction(
225
- diffs: Diff[],
226
- options: TransactionOptions = {
227
- yieldModelTransaction: false,
228
- yieldNewResources: false,
229
- yieldResourceDiffs: false,
230
- yieldResourceTransaction: false,
231
- },
232
- ): AsyncGenerator<DiffMetadata[][] | UnknownResource[], DiffMetadata[][]> {
233
- const overlayDataRepository = await Container.get(OverlayDataRepository);
234
- const resourceDataRepository = await Container.get(ResourceDataRepository);
235
-
236
- // Diff overlays and add to existing diffs.
237
- diffs.push(...overlayDataRepository.diff());
238
-
239
- // Set apply order on model diffs.
240
- const modelDiffs = diffs.map((d) => {
241
- if (d.model.MODEL_TYPE === ModelType.OVERLAY) {
242
- return new DiffMetadata(
243
- d,
244
- this.overlayActions.filter((a) => a.filter(d)),
245
- );
246
- } else {
247
- return new DiffMetadata(
248
- d,
249
- this.modelActions.filter((a) => a.filter(d)),
250
- );
251
- }
252
- });
253
- for (const diff of modelDiffs) {
254
- this.setApplyOrder(diff, modelDiffs);
255
- }
256
-
257
- // Apply model diffs.
258
- const modelTransaction = await this.applyModels(modelDiffs, resourceDataRepository);
259
- if (options.yieldModelTransaction) {
260
- yield modelTransaction;
261
- }
262
-
263
- // Yield new resources.
264
- if (options.yieldNewResources) {
265
- yield resourceDataRepository.getByProperties();
266
- }
267
-
268
- // Generate diff on resources.
269
- diffs = await resourceDataRepository.diff();
270
- const resourceDiffs = diffs.map(
271
- (d) =>
272
- new DiffMetadata(
273
- d,
274
- this.resourceActions.filter((a) => a.filter(d)),
275
- ),
276
- );
277
- // Set apply order on resource diffs.
278
- for (const diff of resourceDiffs) {
279
- this.setApplyOrder(diff, resourceDiffs);
280
- }
281
-
282
- if (options.yieldResourceDiffs) {
283
- yield [resourceDiffs];
284
- }
285
-
286
- // Apply resource diffs.
287
- const resourceTransaction = await this.applyResources(resourceDiffs);
288
- if (options.yieldResourceTransaction) {
289
- yield resourceTransaction;
290
- }
291
-
292
- return modelTransaction;
293
- }
294
-
295
- registerModelActions(actions: IAction<ActionInputs, ActionOutputs>[]): void {
296
- for (const action of actions) {
297
- if (!this.modelActions.find((a) => a.ACTION_NAME === action.ACTION_NAME)) {
298
- this.modelActions.push(action);
299
- }
300
- }
301
- }
302
-
303
- registerOverlayActions(actions: IAction<ActionInputs, ActionOutputs>[]): void {
304
- for (const action of actions) {
305
- if (!this.overlayActions.find((a) => a.ACTION_NAME === action.ACTION_NAME)) {
306
- this.overlayActions.push(action);
307
- }
308
- }
309
- }
310
-
311
- registerResourceActions(actions: IResourceAction[]): void {
312
- for (const action of actions) {
313
- if (!this.resourceActions.find((a) => a.ACTION_NAME === action.ACTION_NAME)) {
314
- this.resourceActions.push(action);
315
- }
316
- }
317
- }
318
-
319
- registerInputs(inputs: ActionInputs): void {
320
- for (const key in inputs) {
321
- this.inputs[key] = inputs[key];
322
- }
323
- }
324
-
325
- async *rollbackTransaction(
326
- modelTransaction: DiffMetadata[][],
327
- options: TransactionOptions = {
328
- yieldResourceDiffs: false,
329
- yieldResourceTransaction: false,
330
- },
331
- ): AsyncGenerator<DiffMetadata[][], DiffMetadata[][]> {
332
- const resourceDataRepository = await Container.get(ResourceDataRepository);
333
-
334
- // Set revert on model diffs.
335
- for (let i = modelTransaction.length - 1; i >= 0; i--) {
336
- const diffsProcessedInSameLevel = modelTransaction[i];
337
-
338
- for (const diff of diffsProcessedInSameLevel) {
339
- for (const a of diff.actions as IAction<ActionInputs, ActionOutputs>[]) {
340
- const outputs = a.revert(diff.diff, diff.inputs, diff.outputs);
341
- for (const outputKey in outputs) {
342
- resourceDataRepository.add(outputs[outputKey]);
343
- }
344
- }
345
- }
346
- }
347
-
348
- // Generate diff on resources.
349
- const diffs = await resourceDataRepository.diff();
350
- const resourceDiffs = diffs.map(
351
- (d) =>
352
- new DiffMetadata(
353
- d,
354
- this.resourceActions.filter((a) => a.filter(d)),
355
- ),
356
- );
357
- // Set apply order on resource diffs.
358
- for (const diff of resourceDiffs) {
359
- this.setApplyOrder(diff, resourceDiffs);
360
- }
361
-
362
- if (options.yieldResourceDiffs) {
363
- yield [resourceDiffs];
364
- }
365
-
366
- // Apply resource diffs.
367
- const resourceTransaction = await this.applyResources(resourceDiffs);
368
- if (options.yieldResourceTransaction) {
369
- yield resourceTransaction;
370
- }
371
-
372
- return resourceTransaction;
373
- }
374
- }
375
-
376
- @Factory<TransactionService>(TransactionService)
377
- export class TransactionServiceFactory {
378
- private static instance: TransactionService;
379
-
380
- static async create(): Promise<TransactionService> {
381
- if (!this.instance) {
382
- this.instance = new TransactionService();
383
- }
384
- return this.instance;
385
- }
386
- }
@@ -1,104 +0,0 @@
1
- import {
2
- App,
3
- Container,
4
- Deployment,
5
- Environment,
6
- Image,
7
- ModelSerializationService,
8
- Region,
9
- Server,
10
- Support,
11
- } from '../src/index.js';
12
-
13
- describe('App E2E Test', () => {
14
- let modelSerializationService: ModelSerializationService;
15
-
16
- beforeAll(async () => {
17
- modelSerializationService = await Container.get(ModelSerializationService);
18
- });
19
-
20
- it('should generate app diff', async () => {
21
- const app0 = new App('test-app');
22
- const image0 = new Image('image', 'tag', { dockerfilePath: '.' });
23
- app0.addImage(image0);
24
- const region0 = new Region('region-1');
25
- app0.addRegion(region0);
26
- const qaEnvironment0 = new Environment('qa');
27
- qaEnvironment0.environmentVariables.set('env', 'QA');
28
- region0.addEnvironment(qaEnvironment0);
29
- app0.addServer(new Server('backend', image0));
30
-
31
- const app1 = (await modelSerializationService.deserialize(await modelSerializationService.serialize(app0))) as App;
32
- const region1 = app1.getChild('region', [{ key: 'regionId', value: 'region-1' }]) as Region;
33
- const backendServer1 = app1.getChild('server', [{ key: 'serverKey', value: 'backend' }]) as Server;
34
- const qaEnvironment1 = region1.getChild('environment', [{ key: 'environmentName', value: 'qa' }]) as Environment;
35
- // Add a deployment to backend server.
36
- backendServer1.addDeployment(new Deployment('backend@v0.0.1'));
37
- // Add a new staging environment.
38
- const stagingEnvironment1 = new Environment('staging');
39
- stagingEnvironment1.environmentVariables.set('env', 'staging');
40
- region1.addEnvironment(stagingEnvironment1);
41
- // Update the qa environment.
42
- qaEnvironment1.environmentVariables.set('env', 'qa');
43
- // Add new server.
44
- const databaseServer1 = new Server('database', image0);
45
- databaseServer1.addDeployment(new Deployment('database@v0.0.1'));
46
- app1.addServer(databaseServer1);
47
- // Add new support.
48
- const nginxSupport1 = new Support('nginx', 'nginx');
49
- nginxSupport1.addDeployment(new Deployment('nginx@v1'));
50
- app1.addSupport(nginxSupport1);
51
-
52
- const diffs = await app1.diff(app0);
53
- expect(diffs).toMatchInlineSnapshot(`
54
- [
55
- {
56
- "action": "update",
57
- "field": "environmentVariables",
58
- "value": {
59
- "key": "env",
60
- "value": "qa",
61
- },
62
- },
63
- {
64
- "action": "add",
65
- "field": "environmentName",
66
- "value": "staging",
67
- },
68
- {
69
- "action": "add",
70
- "field": "environmentVariables",
71
- "value": {
72
- "key": "env",
73
- "value": "staging",
74
- },
75
- },
76
- {
77
- "action": "add",
78
- "field": "deploymentTag",
79
- "value": "backend@v0.0.1",
80
- },
81
- {
82
- "action": "add",
83
- "field": "serverKey",
84
- "value": "database",
85
- },
86
- {
87
- "action": "add",
88
- "field": "deploymentTag",
89
- "value": "database@v0.0.1",
90
- },
91
- {
92
- "action": "add",
93
- "field": "serverKey",
94
- "value": "nginx",
95
- },
96
- {
97
- "action": "add",
98
- "field": "deploymentTag",
99
- "value": "nginx@v1",
100
- },
101
- ]
102
- `);
103
- });
104
- });
@@ -1,31 +0,0 @@
1
- import { AAnchor, AOverlay, AResource, ASharedResource, IOverlay, UnknownModel } from '../../src/index.js';
2
-
3
- export class SharedTestResource extends ASharedResource<TestResource> {
4
- readonly MODEL_NAME: string = 'test-resource';
5
-
6
- constructor(resourceId: string, properties: { [key: string]: unknown }, parents: [TestResource?]) {
7
- super(resourceId, properties, parents as AResource<TestResource>[]);
8
- }
9
- }
10
-
11
- export class TestAnchor extends AAnchor {
12
- constructor(anchorId: string, parent: UnknownModel) {
13
- super(anchorId, parent);
14
- }
15
- }
16
-
17
- export class TestOverlay extends AOverlay<TestOverlay> {
18
- readonly MODEL_NAME: string = 'test-overlay';
19
-
20
- constructor(overlayId: IOverlay['overlayId'], properties: IOverlay['properties'], anchors: AAnchor[]) {
21
- super(overlayId, properties, anchors);
22
- }
23
- }
24
-
25
- export class TestResource extends AResource<TestResource> {
26
- readonly MODEL_NAME: string = 'test-resource';
27
-
28
- constructor(resourceId: string) {
29
- super(resourceId, {}, []);
30
- }
31
- }