@syncbridge/common 0.5.12 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/classes/base-element.js +4 -2
- package/classes/sb-error.d.ts +9 -4
- package/classes/sb-error.js +6 -10
- package/classes/stack-executor.js +8 -11
- package/constants.js +1 -1
- package/index.d.ts +2 -2
- package/index.js +2 -2
- package/models-document.js +4 -1
- package/package.json +3 -2
- package/processor-factory.js +32 -26
- package/registry/extension-package.js +10 -9
- package/registry/extension-registry.js +5 -4
- package/utils/{profile-utils.js → decode-profile.js} +3 -7
- package/utils/{metadata-utils.js → materialize-metadata.js} +6 -6
- /package/utils/{profile-utils.d.ts → decode-profile.d.ts} +0 -0
- /package/utils/{metadata-utils.d.ts → materialize-metadata.d.ts} +0 -0
package/classes/base-element.js
CHANGED
|
@@ -12,8 +12,10 @@ export class BaseElement extends Runnable {
|
|
|
12
12
|
this.logger = init.logger;
|
|
13
13
|
this.name = init.name;
|
|
14
14
|
this.values = init.values;
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
this.on('error', err => this.logger?.error(err));
|
|
16
|
+
this.on('values-updated', (properties) => {
|
|
17
|
+
this.logger?.info(`Configuration changed. Updated properties: ${properties.join(',')}`);
|
|
18
|
+
});
|
|
17
19
|
}
|
|
18
20
|
get status() {
|
|
19
21
|
return this._context.calculatedStatus || this._context.status;
|
package/classes/sb-error.d.ts
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
import { ErrorIssue } from '@opra/common';
|
|
2
|
+
export declare class SbError extends Error implements ErrorIssue {
|
|
2
3
|
readonly cause?: Error;
|
|
4
|
+
severity: ErrorIssue['severity'];
|
|
3
5
|
code?: string;
|
|
4
6
|
[index: string]: any;
|
|
5
7
|
constructor(message?: string | Error, options?: SbErrorOptions);
|
|
6
|
-
toJSON(): any;
|
|
7
8
|
}
|
|
8
|
-
export interface SbErrorOptions {
|
|
9
|
+
export interface SbErrorOptions extends Partial<ErrorIssue> {
|
|
9
10
|
cause?: Error;
|
|
10
|
-
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
*/
|
|
15
|
+
export declare class SbValidationError extends SbError {
|
|
11
16
|
}
|
package/classes/sb-error.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isPlainObject } from '@jsopen/objects';
|
|
2
2
|
export class SbError extends Error {
|
|
3
|
+
severity = 'error';
|
|
3
4
|
code;
|
|
4
5
|
constructor(message, options) {
|
|
5
6
|
super(typeof message === 'object' ? message.message || '' : message);
|
|
@@ -41,14 +42,9 @@ export class SbError extends Error {
|
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if (k !== 'stack')
|
|
50
|
-
out[k] = this[k];
|
|
51
|
-
}
|
|
52
|
-
return out;
|
|
53
|
-
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
*
|
|
48
|
+
*/
|
|
49
|
+
export class SbValidationError extends SbError {
|
|
54
50
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ValidationError } from 'valgen';
|
|
2
|
+
import { SbValidationError } from './sb-error.js';
|
|
2
3
|
export class StackExecutor {
|
|
3
4
|
stack = [];
|
|
4
5
|
issues = [];
|
|
@@ -30,20 +31,16 @@ export class StackExecutor {
|
|
|
30
31
|
const location = this.stack.join('/');
|
|
31
32
|
if (e instanceof ValidationError) {
|
|
32
33
|
e.issues.forEach(x => {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
});
|
|
34
|
+
const issue = new SbValidationError(x.message, x);
|
|
35
|
+
x.severity = x.severity ?? 'error';
|
|
36
|
+
x.location = location + (x.location ? '/' + x.location : '');
|
|
37
|
+
this.issues.push(issue);
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
40
|
else {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
severity: 'error',
|
|
45
|
-
location,
|
|
46
|
-
});
|
|
41
|
+
e.severity = e.severity ?? 'error';
|
|
42
|
+
e.location = location;
|
|
43
|
+
this.issues.push(e);
|
|
47
44
|
}
|
|
48
45
|
}
|
|
49
46
|
}
|
package/constants.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const version = '0.
|
|
1
|
+
export const version = '0.6.1';
|
|
2
2
|
export const OWN_ELEMENT_METADATA = Symbol.for('OWN_ELEMENT_METADATA');
|
|
3
3
|
export const COMPONENT_OPTIONS = Symbol.for('COMPONENT_OPTIONS');
|
|
4
4
|
export const PROCESSOR_OPTIONS = Symbol.for('PROCESSOR_OPTIONS');
|
package/index.d.ts
CHANGED
|
@@ -16,5 +16,5 @@ export * from './models-document.js';
|
|
|
16
16
|
export * from './processor-factory.js';
|
|
17
17
|
export * from './registry/extension-package.js';
|
|
18
18
|
export * from './registry/extension-registry.js';
|
|
19
|
-
export * from './utils/
|
|
20
|
-
export * from './utils/
|
|
19
|
+
export * from './utils/decode-profile.js';
|
|
20
|
+
export * from './utils/materialize-metadata.js';
|
package/index.js
CHANGED
|
@@ -16,5 +16,5 @@ export * from './models-document.js';
|
|
|
16
16
|
export * from './processor-factory.js';
|
|
17
17
|
export * from './registry/extension-package.js';
|
|
18
18
|
export * from './registry/extension-registry.js';
|
|
19
|
-
export * from './utils/
|
|
20
|
-
export * from './utils/
|
|
19
|
+
export * from './utils/decode-profile.js';
|
|
20
|
+
export * from './utils/materialize-metadata.js';
|
package/models-document.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ApiDocumentFactory } from '@opra/common';
|
|
2
|
+
import { SbError } from './classes/sb-error.js';
|
|
2
3
|
import * as models from './models/index.js';
|
|
3
4
|
let doc;
|
|
4
5
|
export async function initializeModelsDocument() {
|
|
@@ -11,6 +12,8 @@ export async function initializeModelsDocument() {
|
|
|
11
12
|
}
|
|
12
13
|
export function getModelsDocument() {
|
|
13
14
|
if (!doc)
|
|
14
|
-
throw new
|
|
15
|
+
throw new SbError('You must call initializeModelsDocument() first', {
|
|
16
|
+
severity: 'fatal',
|
|
17
|
+
});
|
|
15
18
|
return doc;
|
|
16
19
|
}
|
package/package.json
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syncbridge/common",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "SyncBridge Common utilities",
|
|
5
5
|
"author": "Panates Inc",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"@jsopen/objects": "^2.1.1",
|
|
9
|
+
"fast-deep-equal": "^3.1.3",
|
|
9
10
|
"node-events-async": "^1.5.0",
|
|
10
11
|
"reflect-metadata": "^0.2.2",
|
|
11
12
|
"semver": "^7.7.4",
|
|
12
13
|
"ts-gems": "^3.11.3",
|
|
13
|
-
"valgen": "^5.19.
|
|
14
|
+
"valgen": "^5.19.5"
|
|
14
15
|
},
|
|
15
16
|
"peerDependencies": {
|
|
16
17
|
"@opra/common": ">=1.17.1 <2"
|
package/processor-factory.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import equal from 'fast-deep-equal';
|
|
2
|
+
import { SbError } from './classes/sb-error.js';
|
|
1
3
|
import { StackExecutor } from './classes/stack-executor.js';
|
|
2
4
|
import { initializeModelsDocument } from './models-document.js';
|
|
3
5
|
import { ExtensionRegistry } from './registry/extension-registry.js';
|
|
4
|
-
import { materializeMetadata } from './utils/metadata
|
|
6
|
+
import { materializeMetadata } from './utils/materialize-metadata.js';
|
|
5
7
|
export var ProcessorFactory;
|
|
6
8
|
(function (ProcessorFactory) {
|
|
7
9
|
ProcessorFactory.METADATA_KEY = Symbol('METADATA');
|
|
@@ -49,11 +51,12 @@ export var ProcessorFactory;
|
|
|
49
51
|
await signalUpdates(component);
|
|
50
52
|
}
|
|
51
53
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
const properties = ctx.valueUpdates.get(obj);
|
|
55
|
+
if (properties?.length) {
|
|
56
|
+
await obj.emitAsyncSafe('values-updated', properties);
|
|
54
57
|
}
|
|
55
58
|
};
|
|
56
|
-
signalUpdates(processor);
|
|
59
|
+
await signalUpdates(processor);
|
|
57
60
|
return {
|
|
58
61
|
issues: ctx.stackExecutor.issues,
|
|
59
62
|
};
|
|
@@ -92,8 +95,7 @@ export var ProcessorFactory;
|
|
|
92
95
|
if (processor.stopped &&
|
|
93
96
|
oldMetadata?.className &&
|
|
94
97
|
oldMetadata?.className !== newMetadata.className)
|
|
95
|
-
throw new
|
|
96
|
-
ExtensionRegistry.getComponent(childMetadata.className);
|
|
98
|
+
throw new SbError('Cannot change component class while processor running. You should stop it first.');
|
|
97
99
|
/** Validate sub components */
|
|
98
100
|
if (childMetadata.components) {
|
|
99
101
|
_validateComponents({
|
|
@@ -125,14 +127,14 @@ export var ProcessorFactory;
|
|
|
125
127
|
});
|
|
126
128
|
}
|
|
127
129
|
async function _configureComponent(ctx, key, childMetadata) {
|
|
128
|
-
const {
|
|
130
|
+
const { newProfile, oldMetadata, oldProfile, curPath, owner, processor } = ctx;
|
|
129
131
|
const oldChildMetadata = oldMetadata?.components?.[key];
|
|
130
132
|
const oldChildProfile = oldProfile?.components?.[key];
|
|
131
133
|
const childProfile = newProfile.components[key];
|
|
132
134
|
const componentPath = curPath ? curPath + '/' + key : key;
|
|
133
135
|
let componentInstance = owner.components?.[key];
|
|
134
|
-
/** Create the component only if the
|
|
135
|
-
if (
|
|
136
|
+
/** Create the component only if the owner stopped */ // todo implement hotplug components
|
|
137
|
+
if (owner.stopped) {
|
|
136
138
|
const compReg = ExtensionRegistry.getComponent(childMetadata.className);
|
|
137
139
|
/** Create the component instance */
|
|
138
140
|
const compClass = await compReg.getClass();
|
|
@@ -150,26 +152,30 @@ export var ProcessorFactory;
|
|
|
150
152
|
}
|
|
151
153
|
else {
|
|
152
154
|
componentInstance.values = {};
|
|
153
|
-
const patchValues = (target, valPath, newValues, newVariables,
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
155
|
+
const patchValues = (target, valPath, newValues, newVariables, oldValues, oldVariables) => {
|
|
156
|
+
if (oldValues)
|
|
157
|
+
Object.assign(target, oldValues);
|
|
158
|
+
const updatedValues = ctx.valueUpdates.get(componentInstance) || [];
|
|
159
|
+
ctx.valueUpdates.set(componentInstance, updatedValues);
|
|
160
|
+
if (newVariables) {
|
|
161
|
+
for (const [varKey, varMeta] of Object.entries(newVariables)) {
|
|
162
|
+
const keyPath = valPath ? valPath + '.' + varKey : varKey;
|
|
163
|
+
/** Update only hotplug variables */
|
|
164
|
+
if (varMeta?.hotPlug !== true)
|
|
165
|
+
continue;
|
|
166
|
+
if (varMeta.type === 'nested') {
|
|
167
|
+
target[varKey] = {};
|
|
168
|
+
patchValues(target[varKey], keyPath, newValues[varKey], newVariables[varKey]?.variables || {}, oldValues?.[varKey], oldVariables?.[varKey]?.variables);
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
if (!equal(target[varKey], newValues[varKey])) {
|
|
172
|
+
updatedValues.push(keyPath);
|
|
173
|
+
target[varKey] = newValues[varKey];
|
|
174
|
+
}
|
|
165
175
|
}
|
|
166
|
-
updatedValues.push(keyPath);
|
|
167
|
-
target[varKey] = newValues[varKey];
|
|
168
176
|
}
|
|
169
|
-
if (updatedValues.length)
|
|
170
|
-
ctx.valueUpdates.set(componentInstance, updatedValues);
|
|
171
177
|
};
|
|
172
|
-
patchValues(componentInstance.values, '', childProfile.values || {}, childMetadata.variables || {},
|
|
178
|
+
patchValues(componentInstance.values, '', childProfile.values || {}, childMetadata.variables || {}, oldChildProfile?.values, oldChildMetadata?.variables);
|
|
173
179
|
}
|
|
174
180
|
/** Create the child logger */
|
|
175
181
|
componentInstance.logger = owner.logger?.child({
|
|
@@ -4,6 +4,7 @@ import path from 'node:path';
|
|
|
4
4
|
import process from 'node:process';
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
6
6
|
import { updateErrorMessage } from '@jsopen/objects';
|
|
7
|
+
import { SbError } from '../classes/sb-error.js';
|
|
7
8
|
import { COMPONENT_OPTIONS, PROCESSOR_OPTIONS } from '../constants.js';
|
|
8
9
|
import { isComponentBase, isProcessorBase } from '../utils/type-guartds.js';
|
|
9
10
|
import { normalizeComponentMetadata, normalizeProcessorMetadata, } from './helpers.js';
|
|
@@ -26,10 +27,10 @@ export class ExtensionPackage {
|
|
|
26
27
|
static async fromDirectory(directory) {
|
|
27
28
|
let filename = path.join(directory, 'package.json');
|
|
28
29
|
if (!fs.existsSync(filename))
|
|
29
|
-
throw new
|
|
30
|
+
throw new SbError(`Directory "${directory}" does not contain package.json`);
|
|
30
31
|
const pkgJson = JSON.parse(fs.readFileSync(filename, 'utf8'));
|
|
31
32
|
if (!pkgJson.syncbridge)
|
|
32
|
-
throw new
|
|
33
|
+
throw new SbError(`"${pkgJson.name}" is not a SyncBridge extension package`);
|
|
33
34
|
const out = new ExtensionPackage();
|
|
34
35
|
out.name = pkgJson.name;
|
|
35
36
|
out.version = pkgJson.version;
|
|
@@ -100,7 +101,7 @@ export class ExtensionPackage {
|
|
|
100
101
|
let entryPoint = (resolver || import.meta.resolve)(specifier);
|
|
101
102
|
const pkgJson = locatePkgJson(path.dirname(entryPoint));
|
|
102
103
|
if (!pkgJson) {
|
|
103
|
-
throw new
|
|
104
|
+
throw new SbError(`Can't locate package.json file for "${specifier}"`);
|
|
104
105
|
}
|
|
105
106
|
if (path.isAbsolute(entryPoint) && process.platform === 'win32') {
|
|
106
107
|
entryPoint = pathToFileURL(entryPoint).href;
|
|
@@ -178,11 +179,11 @@ export class ComponentExtension {
|
|
|
178
179
|
const module = await import(this.pkg.entryPoint);
|
|
179
180
|
const ctor = module[this.exportName];
|
|
180
181
|
if (!ctor)
|
|
181
|
-
throw new
|
|
182
|
+
throw new SbError(`Exported component "${this.exportName}" not found in package "${this.pkg.name}"`);
|
|
182
183
|
if (typeof ctor !== 'function')
|
|
183
|
-
throw new
|
|
184
|
+
throw new SbError(`Exported component "${this.exportName}" is not a class`);
|
|
184
185
|
if (!isComponentBase(ctor.prototype))
|
|
185
|
-
throw new
|
|
186
|
+
throw new SbError(`Exported component "${this.exportName}" does not extends ComponentBase`);
|
|
186
187
|
this._ctor = ctor;
|
|
187
188
|
return this._ctor;
|
|
188
189
|
}
|
|
@@ -216,11 +217,11 @@ export class ProcessorExtension {
|
|
|
216
217
|
const module = await import(this.pkg.entryPoint);
|
|
217
218
|
const ctor = module[this.exportName];
|
|
218
219
|
if (!ctor)
|
|
219
|
-
throw new
|
|
220
|
+
throw new SbError(`Exported processor "${this.exportName}" not found in package "${this.pkg.name}"`);
|
|
220
221
|
if (typeof ctor !== 'function')
|
|
221
|
-
throw new
|
|
222
|
+
throw new SbError(`Exported processor "${this.exportName}" is not a class`);
|
|
222
223
|
if (!isProcessorBase(ctor.prototype))
|
|
223
|
-
throw new
|
|
224
|
+
throw new SbError(`Exported processor "${this.exportName}" does not extends ProcessorBase`);
|
|
224
225
|
this._ctor = ctor;
|
|
225
226
|
return this._ctor;
|
|
226
227
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import semver from 'semver';
|
|
2
|
+
import { SbError } from '../classes/sb-error.js';
|
|
2
3
|
import { COMPONENT_OPTIONS, PROCESSOR_OPTIONS } from '../constants.js';
|
|
3
4
|
import { ComponentExtension, ExtensionPackage, ProcessorExtension, } from './extension-package.js';
|
|
4
5
|
import { normalizeComponentMetadata, normalizeProcessorMetadata, } from './helpers.js';
|
|
@@ -24,7 +25,7 @@ export var ExtensionRegistry;
|
|
|
24
25
|
const cmp = findComponent(className, version);
|
|
25
26
|
if (cmp)
|
|
26
27
|
return cmp;
|
|
27
|
-
throw new
|
|
28
|
+
throw new SbError(`Component "${className}" version "${version}" not found in registry`);
|
|
28
29
|
}
|
|
29
30
|
ExtensionRegistry.getComponent = getComponent;
|
|
30
31
|
/**
|
|
@@ -42,7 +43,7 @@ export var ExtensionRegistry;
|
|
|
42
43
|
function getProcessor(className, version = '*') {
|
|
43
44
|
const cmp = findProcessor(className, version);
|
|
44
45
|
if (!cmp) {
|
|
45
|
-
throw new
|
|
46
|
+
throw new SbError(`Processor "${className}" version "${version}" not found in registry`);
|
|
46
47
|
}
|
|
47
48
|
return cmp;
|
|
48
49
|
}
|
|
@@ -75,7 +76,7 @@ export var ExtensionRegistry;
|
|
|
75
76
|
async function registerComponent(ctor) {
|
|
76
77
|
const _metadata = Reflect.getMetadata(COMPONENT_OPTIONS, ctor);
|
|
77
78
|
if (!_metadata)
|
|
78
|
-
throw new
|
|
79
|
+
throw new SbError(`Class "${ctor.name}" has no component metadata.`);
|
|
79
80
|
if (_metadata.abstract)
|
|
80
81
|
return;
|
|
81
82
|
const metadata = await normalizeComponentMetadata(_metadata);
|
|
@@ -100,7 +101,7 @@ export var ExtensionRegistry;
|
|
|
100
101
|
async function registerProcessor(ctor) {
|
|
101
102
|
const _metadata = Reflect.getMetadata(PROCESSOR_OPTIONS, ctor);
|
|
102
103
|
if (!_metadata)
|
|
103
|
-
throw new
|
|
104
|
+
throw new SbError(`Class "${ctor.name}" has no processor metadata.`);
|
|
104
105
|
if (_metadata.abstract)
|
|
105
106
|
return;
|
|
106
107
|
const metadata = await normalizeProcessorMetadata(_metadata);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isAny, isBase64, isBoolean, isDateString, isEmail, isHex, isNumber, isString, isTime, isURL, validator, vg, } from 'valgen';
|
|
2
|
-
import {
|
|
2
|
+
import { SbValidationError } from '../classes/sb-error.js';
|
|
3
3
|
import { StackExecutor } from '../classes/stack-executor.js';
|
|
4
4
|
import { Profile, VariableType, } from '../models/index.js';
|
|
5
5
|
import { getModelsDocument } from '../models-document.js';
|
|
@@ -14,7 +14,7 @@ export function decodeProfile(materializedMetadata, rawProfile, options) {
|
|
|
14
14
|
issues
|
|
15
15
|
.map(issue => `- ${issue.message}. Location: /${issue.location}`)
|
|
16
16
|
.join('\n ');
|
|
17
|
-
throw new
|
|
17
|
+
throw new SbValidationError(msg, {
|
|
18
18
|
workerId: rawProfile.id,
|
|
19
19
|
issues,
|
|
20
20
|
});
|
|
@@ -75,11 +75,7 @@ function _codecProcessElement(stackExecutor, codec, metadata, profile, options)
|
|
|
75
75
|
for (const [k, defComponent] of Object.entries(metadata.components)) {
|
|
76
76
|
if (!profile.components[k]) {
|
|
77
77
|
if (defComponent.required) {
|
|
78
|
-
stackExecutor.issues.push({
|
|
79
|
-
message: `Component "${k}" is required`,
|
|
80
|
-
severity: 'error',
|
|
81
|
-
location: `/components/${k}`,
|
|
82
|
-
});
|
|
78
|
+
stackExecutor.issues.push(new SbValidationError(`Component "${k}" is required`));
|
|
83
79
|
}
|
|
84
80
|
continue;
|
|
85
81
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { clone, merge, omitUndefined } from '@jsopen/objects';
|
|
2
|
-
import {
|
|
2
|
+
import { SbValidationError } from '../classes/sb-error.js';
|
|
3
3
|
import { StackExecutor } from '../classes/stack-executor.js';
|
|
4
4
|
import { VariableType, } from '../models/index.js';
|
|
5
5
|
import { ExtensionRegistry } from '../registry/extension-registry.js';
|
|
@@ -13,7 +13,7 @@ export function materializeMetadata(profile) {
|
|
|
13
13
|
issues
|
|
14
14
|
.map(issue => `- ${issue.message}. Location: /${issue.location}`)
|
|
15
15
|
.join('\n ');
|
|
16
|
-
throw new
|
|
16
|
+
throw new SbValidationError(msg, {
|
|
17
17
|
workerId: profile.id,
|
|
18
18
|
issues,
|
|
19
19
|
});
|
|
@@ -67,12 +67,12 @@ function _materializeComponents(stackExecutor, metadata, profile) {
|
|
|
67
67
|
const profileComponent = profile?.components?.[componentName];
|
|
68
68
|
if (!profileComponent) {
|
|
69
69
|
if (metadataComponent.required)
|
|
70
|
-
throw new
|
|
70
|
+
throw new SbValidationError(`Component "${componentName}" should be configured`);
|
|
71
71
|
return;
|
|
72
72
|
}
|
|
73
73
|
/** istanbul ignore next */
|
|
74
74
|
if (!profileComponent.className)
|
|
75
|
-
throw new
|
|
75
|
+
throw new SbValidationError(`"className" property required`);
|
|
76
76
|
const reg = ExtensionRegistry.getComponent(profileComponent.className);
|
|
77
77
|
materializedComponent.className = profileComponent.className;
|
|
78
78
|
materializedComponent.variables = merge({}, [reg.metadata.variables || {}, metadataComponent.variables || {}], { deep: 'full' });
|
|
@@ -80,14 +80,14 @@ function _materializeComponents(stackExecutor, metadata, profile) {
|
|
|
80
80
|
if (metadataComponent.className) {
|
|
81
81
|
if (materializedComponent.className &&
|
|
82
82
|
materializedComponent.className !== metadataComponent.className)
|
|
83
|
-
throw new
|
|
83
|
+
throw new SbValidationError(`Selected component class "${profileComponent.className}" do not match with definition component class (${metadataComponent.className}).`);
|
|
84
84
|
}
|
|
85
85
|
else {
|
|
86
86
|
const requiredInterfaces = metadataComponent.interfaces || [];
|
|
87
87
|
const implementations = reg.metadata.interfaces || [];
|
|
88
88
|
const filtered = requiredInterfaces.filter(x => !implementations.includes(x));
|
|
89
89
|
if (filtered.length) {
|
|
90
|
-
throw new
|
|
90
|
+
throw new SbValidationError(`Selected component "${profileComponent.className}" do not implements some of required interfaces (${filtered.join(',')}).`);
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
93
|
if (materializedComponent.variables) {
|
|
File without changes
|
|
File without changes
|