@syncbridge/common 0.4.6 → 0.5.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/LICENSE +17 -11
- package/classes/stack-executor.d.ts +1 -0
- package/classes/stack-executor.js +12 -0
- package/constants.d.ts +1 -0
- package/constants.js +1 -0
- package/index.d.ts +2 -2
- package/index.js +2 -2
- package/interfaces/index.d.ts +0 -1
- package/interfaces/index.js +0 -1
- package/models/profile/profile.d.ts +1 -0
- package/models/profile/profile.js +7 -0
- package/models-document.d.ts +1 -1
- package/models-document.js +1 -0
- package/package.json +3 -2
- package/processor-factory.js +9 -23
- package/registry/extension-package.d.ts +53 -0
- package/registry/extension-package.js +267 -0
- package/registry/extension-registry.d.ts +43 -0
- package/registry/extension-registry.js +234 -0
- package/registry/registry.d.ts +0 -0
- package/registry/registry.js +273 -0
- package/utils/metadata-utils.js +1 -1
- package/utils/resolve-promises.d.ts +1 -0
- package/utils/resolve-promises.js +10 -0
- package/interfaces/extension-package.interface.d.ts +0 -6
- package/interfaces/extension-package.interface.js +0 -1
- package/registry.d.ts +0 -32
- package/registry.js +0 -205
- package/utils/make-extension-package.d.ts +0 -3
- package/utils/make-extension-package.js +0 -13
package/LICENSE
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
MIT License
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
the proprietary property of Panates and are protected by copyright laws
|
|
5
|
-
and international copyright treaties.
|
|
3
|
+
Copyright (c) 2022 Panates
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
civil and/or criminal penalties.
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -2,6 +2,7 @@ import { ErrorIssue } from '@opra/common';
|
|
|
2
2
|
export declare class StackExecutor {
|
|
3
3
|
stack: string[];
|
|
4
4
|
issues: StackExecutor.Issue[];
|
|
5
|
+
executeAsync(stack: string, fn: () => Promise<any>): Promise<void>;
|
|
5
6
|
execute(stack: string, fn: () => any): void;
|
|
6
7
|
handleError(e: any): void;
|
|
7
8
|
}
|
|
@@ -2,6 +2,18 @@ import { ValidationError } from 'valgen';
|
|
|
2
2
|
export class StackExecutor {
|
|
3
3
|
stack = [];
|
|
4
4
|
issues = [];
|
|
5
|
+
async executeAsync(stack, fn) {
|
|
6
|
+
this.stack.push(stack);
|
|
7
|
+
try {
|
|
8
|
+
await fn();
|
|
9
|
+
}
|
|
10
|
+
catch (e) {
|
|
11
|
+
this.handleError(e);
|
|
12
|
+
}
|
|
13
|
+
finally {
|
|
14
|
+
this.stack.pop();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
5
17
|
execute(stack, fn) {
|
|
6
18
|
this.stack.push(stack);
|
|
7
19
|
try {
|
package/constants.d.ts
CHANGED
package/constants.js
CHANGED
package/index.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export * from './models/index.js';
|
|
|
14
14
|
export * as models from './models/index.js';
|
|
15
15
|
export * from './models-document.js';
|
|
16
16
|
export * from './processor-factory.js';
|
|
17
|
-
export * from './registry.js';
|
|
18
|
-
export * from './
|
|
17
|
+
export * from './registry/extension-package.js';
|
|
18
|
+
export * from './registry/extension-registry.js';
|
|
19
19
|
export * from './utils/metadata-utils.js';
|
|
20
20
|
export * from './utils/profile-utils.js';
|
package/index.js
CHANGED
|
@@ -14,7 +14,7 @@ export * from './models/index.js';
|
|
|
14
14
|
export * as models from './models/index.js';
|
|
15
15
|
export * from './models-document.js';
|
|
16
16
|
export * from './processor-factory.js';
|
|
17
|
-
export * from './registry.js';
|
|
18
|
-
export * from './
|
|
17
|
+
export * from './registry/extension-package.js';
|
|
18
|
+
export * from './registry/extension-registry.js';
|
|
19
19
|
export * from './utils/metadata-utils.js';
|
|
20
20
|
export * from './utils/profile-utils.js';
|
package/interfaces/index.d.ts
CHANGED
package/interfaces/index.js
CHANGED
|
@@ -65,6 +65,13 @@ __decorate([
|
|
|
65
65
|
}),
|
|
66
66
|
__metadata("design:type", String)
|
|
67
67
|
], Profile.prototype, "processorClass", void 0);
|
|
68
|
+
__decorate([
|
|
69
|
+
ApiField({
|
|
70
|
+
label: 'Processor Version',
|
|
71
|
+
description: 'Determines which installed version will be used. This value accepts semver format. https://semver.npmjs.com/',
|
|
72
|
+
}),
|
|
73
|
+
__metadata("design:type", String)
|
|
74
|
+
], Profile.prototype, "processorVersion", void 0);
|
|
68
75
|
__decorate([
|
|
69
76
|
ApiField({
|
|
70
77
|
label: 'Group',
|
package/models-document.d.ts
CHANGED
package/models-document.js
CHANGED
package/package.json
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syncbridge/common",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "SyncBridge Common utilities",
|
|
5
5
|
"author": "Panates Inc",
|
|
6
|
-
"license": "
|
|
6
|
+
"license": "MIT",
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"@jsopen/objects": "^2.0.2",
|
|
9
9
|
"node-events-async": "^1.5.0",
|
|
10
10
|
"reflect-metadata": "^0.2.2",
|
|
11
|
+
"semver": "^7.7.3",
|
|
11
12
|
"ts-gems": "^3.11.3",
|
|
12
13
|
"valgen": "^5.19.4"
|
|
13
14
|
},
|
package/processor-factory.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { StackExecutor } from './classes/stack-executor.js';
|
|
2
2
|
import { initializeModelsDocument } from './models-document.js';
|
|
3
|
-
import { ExtensionRegistry } from './registry.js';
|
|
3
|
+
import { ExtensionRegistry } from './registry/extension-registry.js';
|
|
4
4
|
import { materializeMetadata } from './utils/metadata-utils.js';
|
|
5
5
|
export var ProcessorFactory;
|
|
6
6
|
(function (ProcessorFactory) {
|
|
@@ -8,8 +8,9 @@ export var ProcessorFactory;
|
|
|
8
8
|
ProcessorFactory.PROFILE_KEY = Symbol('PROFILE');
|
|
9
9
|
async function createProcessor(profile, options) {
|
|
10
10
|
await initializeModelsDocument();
|
|
11
|
-
const reg = ExtensionRegistry.getProcessor(profile.processorClass);
|
|
12
|
-
const
|
|
11
|
+
const reg = ExtensionRegistry.getProcessor(profile.processorClass, profile.processorVersion);
|
|
12
|
+
const processorClass = await reg.getClass();
|
|
13
|
+
const processor = new processorClass({
|
|
13
14
|
name: profile.displayName,
|
|
14
15
|
logger: options?.logger,
|
|
15
16
|
values: profile.values || {},
|
|
@@ -30,14 +31,14 @@ export var ProcessorFactory;
|
|
|
30
31
|
async function _configureProcessor(processor, profile) {
|
|
31
32
|
const processorMetadata = materializeMetadata(profile);
|
|
32
33
|
const stackExecutor = new StackExecutor();
|
|
33
|
-
function configureComponents(owner, curPath, newMetadata, newProfile, oldMetadata, oldProfile) {
|
|
34
|
+
async function configureComponents(owner, curPath, newMetadata, newProfile, oldMetadata, oldProfile) {
|
|
34
35
|
if (!newMetadata.components)
|
|
35
36
|
return;
|
|
36
37
|
// Stack: components
|
|
37
|
-
stackExecutor.
|
|
38
|
+
await stackExecutor.executeAsync('components', async () => {
|
|
38
39
|
for (const [key, childMetadata] of Object.entries(newMetadata.components)) {
|
|
39
40
|
// Stack: components/componentName
|
|
40
|
-
stackExecutor.
|
|
41
|
+
await stackExecutor.executeAsync(key, async () => {
|
|
41
42
|
const oldChildMetadata = oldMetadata?.components?.[key];
|
|
42
43
|
const oldChildProfile = oldProfile?.components?.[key];
|
|
43
44
|
const childProfile = newProfile.components[key];
|
|
@@ -47,7 +48,7 @@ export var ProcessorFactory;
|
|
|
47
48
|
if (processor.stopped) {
|
|
48
49
|
const compReg = ExtensionRegistry.getComponent(childMetadata.className);
|
|
49
50
|
/** Create the component instance */
|
|
50
|
-
const compClass = compReg.
|
|
51
|
+
const compClass = await compReg.getClass();
|
|
51
52
|
componentInstance = new compClass({
|
|
52
53
|
processor: processor,
|
|
53
54
|
parent: owner,
|
|
@@ -84,23 +85,8 @@ export var ProcessorFactory;
|
|
|
84
85
|
}
|
|
85
86
|
});
|
|
86
87
|
}
|
|
87
|
-
configureComponents(processor, '', processorMetadata, profile, processor[ProcessorFactory.METADATA_KEY], processor[ProcessorFactory.PROFILE_KEY]);
|
|
88
|
+
await configureComponents(processor, '', processorMetadata, profile, processor[ProcessorFactory.METADATA_KEY], processor[ProcessorFactory.PROFILE_KEY]);
|
|
88
89
|
processor[ProcessorFactory.METADATA_KEY] = processorMetadata;
|
|
89
90
|
processor[ProcessorFactory.PROFILE_KEY] = profile;
|
|
90
|
-
// processor.on('error', err => this.logger.error(err));
|
|
91
|
-
// processor.on('status-change', args => {
|
|
92
|
-
// this.messageHandler.emit('status-change', args);
|
|
93
|
-
// });
|
|
94
|
-
// processor.on(
|
|
95
|
-
// 'component-status-change',
|
|
96
|
-
// (component, status, statusMessage) => {
|
|
97
|
-
// this.messageHandler.emit('component-status-change', {
|
|
98
|
-
// componentName: component.name,
|
|
99
|
-
// path: component.path,
|
|
100
|
-
// status,
|
|
101
|
-
// statusMessage,
|
|
102
|
-
// });
|
|
103
|
-
// },
|
|
104
|
-
// );
|
|
105
91
|
}
|
|
106
92
|
})(ProcessorFactory || (ProcessorFactory = {}));
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { Type } from 'ts-gems';
|
|
3
|
+
import { ComponentBase } from '../classes/component-base.js';
|
|
4
|
+
import { ProcessorBase } from '../classes/processor-base.js';
|
|
5
|
+
import { ComponentMetadata, ProcessorMetadata } from '../models/index.js';
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
9
|
+
export declare class ExtensionPackage {
|
|
10
|
+
name: string;
|
|
11
|
+
version: string;
|
|
12
|
+
description: string;
|
|
13
|
+
entryPoint: string;
|
|
14
|
+
components: ExtensionPackageComponent[];
|
|
15
|
+
processors: ExtensionPackageProcessor[];
|
|
16
|
+
errors: Error[];
|
|
17
|
+
sortVersions(): void;
|
|
18
|
+
/**
|
|
19
|
+
*
|
|
20
|
+
* @param directory
|
|
21
|
+
* @static
|
|
22
|
+
*/
|
|
23
|
+
static fromDirectory(directory: string): Promise<ExtensionPackage>;
|
|
24
|
+
static fromNodePackage(specifier: string, resolver?: (name: string) => string): Promise<ExtensionPackage>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
*
|
|
28
|
+
*/
|
|
29
|
+
export declare class ExtensionPackageComponent {
|
|
30
|
+
readonly pkg: ExtensionPackage;
|
|
31
|
+
readonly exportName: string;
|
|
32
|
+
readonly metadata: ComponentMetadata;
|
|
33
|
+
protected _ctor?: Type<ComponentBase>;
|
|
34
|
+
constructor(pkg: ExtensionPackage, exportName: string, metadata: ComponentMetadata, ctor?: Type<ComponentBase>);
|
|
35
|
+
get className(): string;
|
|
36
|
+
get displayName(): string;
|
|
37
|
+
get version(): string;
|
|
38
|
+
getClass(): Promise<Type<ComponentBase>>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
*
|
|
42
|
+
*/
|
|
43
|
+
export declare class ExtensionPackageProcessor {
|
|
44
|
+
readonly pkg: ExtensionPackage;
|
|
45
|
+
readonly exportName: string;
|
|
46
|
+
readonly metadata: ProcessorMetadata;
|
|
47
|
+
protected _ctor?: Type<ProcessorBase>;
|
|
48
|
+
constructor(pkg: ExtensionPackage, exportName: string, metadata: ProcessorMetadata, ctor?: Type<ProcessorBase>);
|
|
49
|
+
get className(): string;
|
|
50
|
+
get displayName(): string;
|
|
51
|
+
get version(): string;
|
|
52
|
+
getClass(): Promise<Type<ProcessorBase>>;
|
|
53
|
+
}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import process from 'node:process';
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
6
|
+
import { ComponentBase } from '../classes/component-base.js';
|
|
7
|
+
import { ProcessorBase } from '../classes/processor-base.js';
|
|
8
|
+
import { COMPONENT_OPTIONS, PROCESSOR_OPTIONS } from '../constants.js';
|
|
9
|
+
import { ComponentMetadata, ProcessorMetadata } from '../models/index.js';
|
|
10
|
+
import { initializeModelsDocument } from '../models-document.js';
|
|
11
|
+
import { resolvePromisesDeep } from '../utils/resolve-promises.js';
|
|
12
|
+
let _compMetadataTypeDecoder;
|
|
13
|
+
let _procMetadataTypeDecoder;
|
|
14
|
+
async function getCompMetadataTypeDecoder() {
|
|
15
|
+
if (!_compMetadataTypeDecoder) {
|
|
16
|
+
const apiDoc = await initializeModelsDocument();
|
|
17
|
+
const compMetadataType = apiDoc.node.getComplexType(ComponentMetadata);
|
|
18
|
+
_compMetadataTypeDecoder = compMetadataType.generateCodec('decode', {
|
|
19
|
+
coerce: true,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return _compMetadataTypeDecoder;
|
|
23
|
+
}
|
|
24
|
+
async function getProcMetadataTypeDecoder() {
|
|
25
|
+
if (!_procMetadataTypeDecoder) {
|
|
26
|
+
const apiDoc = await initializeModelsDocument();
|
|
27
|
+
const procMetadataType = apiDoc.node.getComplexType(ProcessorMetadata);
|
|
28
|
+
_procMetadataTypeDecoder = procMetadataType.generateCodec('decode', {
|
|
29
|
+
coerce: true,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return _procMetadataTypeDecoder;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
*
|
|
36
|
+
*/
|
|
37
|
+
export class ExtensionPackage {
|
|
38
|
+
components = [];
|
|
39
|
+
processors = [];
|
|
40
|
+
errors = [];
|
|
41
|
+
sortVersions() {
|
|
42
|
+
this.components.sort((a, b) => a.version.localeCompare(b.version));
|
|
43
|
+
this.processors.sort((a, b) => a.version.localeCompare(b.version));
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
*
|
|
47
|
+
* @param directory
|
|
48
|
+
* @static
|
|
49
|
+
*/
|
|
50
|
+
static async fromDirectory(directory) {
|
|
51
|
+
const compMetadataTypeDecoder = await getCompMetadataTypeDecoder();
|
|
52
|
+
let filename = path.join(directory, 'package.json');
|
|
53
|
+
if (!fs.existsSync(filename))
|
|
54
|
+
throw new TypeError(`Directory "${directory}" does not contain package.json`);
|
|
55
|
+
const pkgJson = JSON.parse(fs.readFileSync(filename, 'utf8'));
|
|
56
|
+
if (!pkgJson.syncbridge)
|
|
57
|
+
throw new TypeError(`"${pkgJson.name}" is not a SyncBridge extension package`);
|
|
58
|
+
const out = new ExtensionPackage();
|
|
59
|
+
out.name = pkgJson.name;
|
|
60
|
+
out.version = pkgJson.version;
|
|
61
|
+
out.description = pkgJson.description;
|
|
62
|
+
out.entryPoint = path.join(directory, pkgJson.module || pkgJson.main);
|
|
63
|
+
let metadata;
|
|
64
|
+
if (pkgJson.syncbridge.components) {
|
|
65
|
+
for (const ctorName of pkgJson.syncbridge.components) {
|
|
66
|
+
filename = path.join(directory, 'metadata', ctorName + '.json');
|
|
67
|
+
if (!fs.existsSync(filename)) {
|
|
68
|
+
out.errors.push(new Error(`Component (${ctorName}) metadata file not found`));
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
metadata = JSON.parse(fs.readFileSync(filename, 'utf8'));
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
out.errors.push(new Error(`Component (${ctorName}) metadata file read error`));
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
metadata = compMetadataTypeDecoder(metadata);
|
|
80
|
+
}
|
|
81
|
+
catch (e) {
|
|
82
|
+
out.errors.push(new Error(`Component (${ctorName}) metadata validation error. ` + e.message));
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (metadata.abstract)
|
|
86
|
+
continue;
|
|
87
|
+
out.components = out.components || [];
|
|
88
|
+
out.components.push(new ExtensionPackageComponent(out, ctorName, metadata));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (pkgJson.syncbridge.processors) {
|
|
92
|
+
for (const ctorName of pkgJson.syncbridge.processors) {
|
|
93
|
+
filename = path.join(directory, 'metadata', ctorName + '.json');
|
|
94
|
+
if (!fs.existsSync(filename)) {
|
|
95
|
+
out.errors.push(new Error(`Processors (${ctorName}) metadata file not found`));
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
metadata = JSON.parse(fs.readFileSync(filename, 'utf8'));
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
out.errors.push(new Error(`Processors (${ctorName}) metadata file read error`));
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
metadata = compMetadataTypeDecoder(metadata);
|
|
107
|
+
}
|
|
108
|
+
catch (e) {
|
|
109
|
+
out.errors.push(new Error(`Processor (${ctorName}) metadata validation error. ` + e.message));
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if (metadata.abstract)
|
|
113
|
+
continue;
|
|
114
|
+
out.processors = out.processors || [];
|
|
115
|
+
out.processors.push(new ExtensionPackageProcessor(out, ctorName, metadata));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
out.sortVersions();
|
|
119
|
+
return out;
|
|
120
|
+
}
|
|
121
|
+
static async fromNodePackage(specifier, resolver = import.meta.resolve) {
|
|
122
|
+
const compMetadataTypeDecoder = await getCompMetadataTypeDecoder();
|
|
123
|
+
const procMetadataTypeDecoder = await getProcMetadataTypeDecoder();
|
|
124
|
+
let entryPoint = fileURLToPath(resolver(specifier));
|
|
125
|
+
const pkgJson = locatePkgJson(path.dirname(entryPoint));
|
|
126
|
+
if (!pkgJson) {
|
|
127
|
+
throw new TypeError(`Can't locate package.json file for "${specifier}"`);
|
|
128
|
+
}
|
|
129
|
+
if (path.isAbsolute(entryPoint) && process.platform === 'win32') {
|
|
130
|
+
entryPoint = pathToFileURL(entryPoint).href;
|
|
131
|
+
}
|
|
132
|
+
const out = new ExtensionPackage();
|
|
133
|
+
out.name = pkgJson.name;
|
|
134
|
+
out.version = pkgJson.version;
|
|
135
|
+
out.description = pkgJson.description;
|
|
136
|
+
out.entryPoint = entryPoint;
|
|
137
|
+
const module = await import(entryPoint);
|
|
138
|
+
for (const [ctorName, v] of Object.entries(module)) {
|
|
139
|
+
if (typeof v !== 'function')
|
|
140
|
+
continue;
|
|
141
|
+
let metadata = Reflect.getMetadata(COMPONENT_OPTIONS, v);
|
|
142
|
+
if (metadata) {
|
|
143
|
+
metadata = await resolvePromisesDeep(metadata);
|
|
144
|
+
try {
|
|
145
|
+
metadata = compMetadataTypeDecoder(metadata);
|
|
146
|
+
}
|
|
147
|
+
catch (e) {
|
|
148
|
+
out.errors.push(new Error(`Component (${ctorName}) metadata validation error. ` + e.message));
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (metadata.abstract)
|
|
152
|
+
continue;
|
|
153
|
+
out.components = out.components || [];
|
|
154
|
+
out.components.push(new ExtensionPackageComponent(out, ctorName, metadata));
|
|
155
|
+
}
|
|
156
|
+
metadata = Reflect.getMetadata(PROCESSOR_OPTIONS, v);
|
|
157
|
+
if (metadata) {
|
|
158
|
+
metadata = await resolvePromisesDeep(metadata);
|
|
159
|
+
try {
|
|
160
|
+
metadata = procMetadataTypeDecoder(metadata);
|
|
161
|
+
}
|
|
162
|
+
catch (e) {
|
|
163
|
+
out.errors.push(new Error(`Processor (${ctorName}) metadata validation error. ` + e.message));
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
if (metadata.abstract)
|
|
167
|
+
continue;
|
|
168
|
+
out.processors = out.processors || [];
|
|
169
|
+
out.processors.push(new ExtensionPackageProcessor(out, ctorName, metadata));
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
out.sortVersions();
|
|
173
|
+
return out;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
*
|
|
178
|
+
*/
|
|
179
|
+
export class ExtensionPackageComponent {
|
|
180
|
+
pkg;
|
|
181
|
+
exportName;
|
|
182
|
+
metadata;
|
|
183
|
+
_ctor;
|
|
184
|
+
constructor(pkg, exportName, metadata, ctor) {
|
|
185
|
+
this.pkg = pkg;
|
|
186
|
+
this.exportName = exportName;
|
|
187
|
+
this.metadata = metadata;
|
|
188
|
+
this._ctor = ctor;
|
|
189
|
+
}
|
|
190
|
+
get className() {
|
|
191
|
+
return this.metadata.className;
|
|
192
|
+
}
|
|
193
|
+
get displayName() {
|
|
194
|
+
return this.metadata.displayName;
|
|
195
|
+
}
|
|
196
|
+
get version() {
|
|
197
|
+
return this.pkg.version;
|
|
198
|
+
}
|
|
199
|
+
async getClass() {
|
|
200
|
+
if (this._ctor)
|
|
201
|
+
return this._ctor;
|
|
202
|
+
const module = await import(this.pkg.entryPoint);
|
|
203
|
+
const ctor = module[this.exportName];
|
|
204
|
+
if (!ctor)
|
|
205
|
+
throw new TypeError(`Exported component "${this.exportName}" not found in package "${this.pkg.name}"`);
|
|
206
|
+
if (typeof ctor !== 'function')
|
|
207
|
+
throw new TypeError(`Exported component "${this.exportName}" is not a class`);
|
|
208
|
+
if (!(ctor.prototype instanceof ComponentBase))
|
|
209
|
+
throw new TypeError(`Exported component "${this.exportName}" does not extends ComponentBase`);
|
|
210
|
+
this._ctor = ctor;
|
|
211
|
+
return this._ctor;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
*
|
|
216
|
+
*/
|
|
217
|
+
export class ExtensionPackageProcessor {
|
|
218
|
+
pkg;
|
|
219
|
+
exportName;
|
|
220
|
+
metadata;
|
|
221
|
+
_ctor;
|
|
222
|
+
constructor(pkg, exportName, metadata, ctor) {
|
|
223
|
+
this.pkg = pkg;
|
|
224
|
+
this.exportName = exportName;
|
|
225
|
+
this.metadata = metadata;
|
|
226
|
+
this._ctor = ctor;
|
|
227
|
+
}
|
|
228
|
+
get className() {
|
|
229
|
+
return this.metadata.className;
|
|
230
|
+
}
|
|
231
|
+
get displayName() {
|
|
232
|
+
return this.metadata.displayName;
|
|
233
|
+
}
|
|
234
|
+
get version() {
|
|
235
|
+
return this.pkg.version;
|
|
236
|
+
}
|
|
237
|
+
async getClass() {
|
|
238
|
+
if (this._ctor)
|
|
239
|
+
return this._ctor;
|
|
240
|
+
const module = await import(this.pkg.entryPoint);
|
|
241
|
+
const ctor = module[this.exportName];
|
|
242
|
+
if (!ctor)
|
|
243
|
+
throw new TypeError(`Exported processor "${this.exportName}" not found in package "${this.pkg.name}"`);
|
|
244
|
+
if (typeof ctor !== 'function')
|
|
245
|
+
throw new TypeError(`Exported processor "${this.exportName}" is not a class`);
|
|
246
|
+
if (!(ctor.prototype instanceof ProcessorBase))
|
|
247
|
+
throw new TypeError(`Exported processor "${this.exportName}" does not extends ProcessorBase`);
|
|
248
|
+
this._ctor = ctor;
|
|
249
|
+
return this._ctor;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
*
|
|
254
|
+
*/
|
|
255
|
+
function locatePkgJson(directory) {
|
|
256
|
+
if (directory.startsWith('file:'))
|
|
257
|
+
directory = fileURLToPath(directory);
|
|
258
|
+
for (let i = 0; i < 3; i++) {
|
|
259
|
+
const f = path.resolve(directory, 'package.json');
|
|
260
|
+
if (fs.existsSync(f)) {
|
|
261
|
+
const json = JSON.parse(fs.readFileSync(f, 'utf8'));
|
|
262
|
+
if (json.name && json.version)
|
|
263
|
+
return json;
|
|
264
|
+
}
|
|
265
|
+
directory = path.dirname(directory);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Type } from 'ts-gems';
|
|
2
|
+
import { ExtensionPackage, ExtensionPackageComponent, ExtensionPackageProcessor } from './extension-package.js';
|
|
3
|
+
export declare namespace ExtensionRegistry {
|
|
4
|
+
let _resolver: {
|
|
5
|
+
(specifier: string): string;
|
|
6
|
+
(specifier: string, parent?: string | import("node:url").URL): string;
|
|
7
|
+
};
|
|
8
|
+
export const packages: Map<string, ExtensionPackage[]>;
|
|
9
|
+
export const components: Map<string, ExtensionPackageComponent[]>;
|
|
10
|
+
export const processors: Map<string, ExtensionPackageProcessor[]>;
|
|
11
|
+
/**
|
|
12
|
+
*
|
|
13
|
+
*/
|
|
14
|
+
export function findComponent(className: string, version?: string): ExtensionPackageComponent | undefined;
|
|
15
|
+
/**
|
|
16
|
+
*
|
|
17
|
+
*/
|
|
18
|
+
export function getComponent(className: string, version?: string): ExtensionPackageComponent;
|
|
19
|
+
/**
|
|
20
|
+
*
|
|
21
|
+
*/
|
|
22
|
+
export function findProcessor(className: string, version?: string): ExtensionPackageProcessor | undefined;
|
|
23
|
+
/**
|
|
24
|
+
*
|
|
25
|
+
*/
|
|
26
|
+
export function getProcessor(className: string, version?: string): ExtensionPackageProcessor;
|
|
27
|
+
/**
|
|
28
|
+
*
|
|
29
|
+
* @param resolver
|
|
30
|
+
*/
|
|
31
|
+
export function setResolver(resolver: typeof _resolver): void;
|
|
32
|
+
/**
|
|
33
|
+
*
|
|
34
|
+
*/
|
|
35
|
+
export function registerExtensionPackage(directory: string): Promise<ExtensionPackage>;
|
|
36
|
+
/**
|
|
37
|
+
*
|
|
38
|
+
*/
|
|
39
|
+
export function registerNodePackage(specifier: string): Promise<ExtensionPackage>;
|
|
40
|
+
export function registerComponent(ctor: Type): Promise<ExtensionPackageComponent | undefined>;
|
|
41
|
+
export function registerProcessor(ctor: Type): Promise<ExtensionPackageProcessor | undefined>;
|
|
42
|
+
export {};
|
|
43
|
+
}
|