@teambit/harmony 0.2.11 → 0.3.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.
- package/aspect.ts +49 -0
- package/config/config.ts +36 -0
- package/config/index.ts +1 -0
- package/container.ts +22 -0
- package/dist/aspect.js +1 -0
- package/dist/aspect.js.map +1 -0
- package/dist/config/config.d.ts +1 -1
- package/dist/config/config.js +1 -0
- package/dist/config/config.js.map +1 -0
- package/dist/config/index.js +2 -0
- package/dist/config/index.js.map +1 -0
- package/dist/container.js +1 -0
- package/dist/container.js.map +1 -0
- package/dist/exceptions/extension-init-error.js +1 -0
- package/dist/exceptions/extension-init-error.js.map +1 -0
- package/dist/exceptions/extension-load-error.d.ts +1 -1
- package/dist/exceptions/extension-load-error.js +1 -0
- package/dist/exceptions/extension-load-error.js.map +1 -0
- package/dist/exceptions/extension-potential-circular.js +1 -0
- package/dist/exceptions/extension-potential-circular.js.map +1 -0
- package/dist/exceptions/harmony-already-running.js +1 -0
- package/dist/exceptions/harmony-already-running.js.map +1 -0
- package/dist/exceptions/harmony-error.js +1 -0
- package/dist/exceptions/harmony-error.js.map +1 -0
- package/dist/exceptions/hook-not-found.js +1 -0
- package/dist/exceptions/hook-not-found.js.map +1 -0
- package/dist/exceptions/index.js +7 -2
- package/dist/exceptions/index.js.map +1 -0
- package/dist/exceptions/runtime-not-defined.js +1 -1
- package/dist/exceptions/runtime-not-defined.js.map +1 -0
- package/dist/extension/any-extension.js +1 -0
- package/dist/extension/any-extension.js.map +1 -0
- package/dist/extension/decorator.d.ts +2 -2
- package/dist/extension/decorator.js +1 -0
- package/dist/extension/decorator.js.map +1 -0
- package/dist/extension/extension-manifest.js +1 -0
- package/dist/extension/extension-manifest.js.map +1 -0
- package/dist/extension/extension.d.ts +2 -2
- package/dist/extension/extension.js +1 -0
- package/dist/extension/extension.js.map +1 -0
- package/dist/extension/index.js +2 -0
- package/dist/extension/index.js.map +1 -0
- package/dist/extension-graph/extension-graph.d.ts +2 -2
- package/dist/extension-graph/extension-graph.js +5 -4
- package/dist/extension-graph/extension-graph.js.map +1 -0
- package/dist/extension-graph/from-extension.js +3 -2
- package/dist/extension-graph/from-extension.js.map +1 -0
- package/dist/extension-graph/index.js +6 -1
- package/dist/extension-graph/index.js.map +1 -0
- package/dist/factory/extension-factory.js +1 -0
- package/dist/factory/extension-factory.js.map +1 -0
- package/dist/factory/index.js +2 -0
- package/dist/factory/index.js.map +1 -0
- package/dist/fixtures/aspects/babel/babel.aspect.js +1 -0
- package/dist/fixtures/aspects/babel/babel.aspect.js.map +1 -0
- package/dist/fixtures/aspects/babel/babel.cli.js +1 -0
- package/dist/fixtures/aspects/babel/babel.cli.js.map +1 -0
- package/dist/fixtures/aspects/react/react.aspect.js +1 -0
- package/dist/fixtures/aspects/react/react.aspect.js.map +1 -0
- package/dist/fixtures/aspects/react/react.cli.js +2 -1
- package/dist/fixtures/aspects/react/react.cli.js.map +1 -0
- package/dist/fixtures/aspects/react/react.ui.js +1 -0
- package/dist/fixtures/aspects/react/react.ui.js.map +1 -0
- package/dist/fixtures/aspects/ui/ui.aspect.js +1 -0
- package/dist/fixtures/aspects/ui/ui.aspect.js.map +1 -0
- package/dist/fixtures/aspects/ui/ui.ui.js +1 -0
- package/dist/fixtures/aspects/ui/ui.ui.js.map +1 -0
- package/dist/fixtures/babel/babel.extension.d.ts +1 -1
- package/dist/fixtures/babel/babel.extension.js +8 -26
- package/dist/fixtures/babel/babel.extension.js.map +1 -0
- package/dist/fixtures/babel/index.js +1 -1
- package/dist/fixtures/babel/index.js.map +1 -0
- package/dist/fixtures/base-compiler/base-compiler.extension.js +5 -23
- package/dist/fixtures/base-compiler/base-compiler.extension.js.map +1 -0
- package/dist/fixtures/base-compiler/index.js +2 -0
- package/dist/fixtures/base-compiler/index.js.map +1 -0
- package/dist/fixtures/cli/cli.extension.js +5 -12
- package/dist/fixtures/cli/cli.extension.js.map +1 -0
- package/dist/fixtures/cli/command.js +1 -1
- package/dist/fixtures/cli/command.js.map +1 -0
- package/dist/fixtures/cli/index.js +2 -1
- package/dist/fixtures/cli/index.js.map +1 -0
- package/dist/fixtures/typescript/index.js +1 -1
- package/dist/fixtures/typescript/index.js.map +1 -0
- package/dist/fixtures/typescript/typescript.js +8 -22
- package/dist/fixtures/typescript/typescript.js.map +1 -0
- package/dist/harmony-config/config-reader.js +3 -2
- package/dist/harmony-config/config-reader.js.map +1 -0
- package/dist/harmony-config/exceptions/index.js +2 -0
- package/dist/harmony-config/exceptions/index.js.map +1 -0
- package/dist/harmony-config/exceptions/read-config-error.d.ts +1 -1
- package/dist/harmony-config/exceptions/read-config-error.js +1 -0
- package/dist/harmony-config/exceptions/read-config-error.js.map +1 -0
- package/dist/harmony-config/harmony-config.js +5 -4
- package/dist/harmony-config/harmony-config.js.map +1 -0
- package/dist/harmony-config/index.js +2 -0
- package/dist/harmony-config/index.js.map +1 -0
- package/dist/harmony-config/locator.js +1 -1
- package/dist/harmony-config/locator.js.map +1 -0
- package/dist/harmony.docs.mdx +249 -0
- package/dist/harmony.js +3 -2
- package/dist/harmony.js.map +1 -0
- package/dist/{factory/extension-factory.spec.d.ts → harmony.spec.old.d.ts} +0 -0
- package/dist/{harmony.spec.js → harmony.spec.old.js} +12 -23
- package/dist/harmony.spec.old.js.map +1 -0
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -0
- package/dist/readme.md +80 -0
- package/dist/runtimes/exceptions/index.js +2 -0
- package/dist/runtimes/exceptions/index.js.map +1 -0
- package/dist/runtimes/exceptions/runtime-module-error.d.ts +1 -1
- package/dist/runtimes/exceptions/runtime-module-error.js +1 -0
- package/dist/runtimes/exceptions/runtime-module-error.js.map +1 -0
- package/dist/runtimes/exceptions/runtime-not-defined.js +1 -0
- package/dist/runtimes/exceptions/runtime-not-defined.js.map +1 -0
- package/dist/runtimes/index.js +2 -0
- package/dist/runtimes/index.js.map +1 -0
- package/dist/runtimes/runtime-definition.js +1 -0
- package/dist/runtimes/runtime-definition.js.map +1 -0
- package/dist/runtimes/runtime-manifest.js +1 -0
- package/dist/runtimes/runtime-manifest.js.map +1 -0
- package/dist/runtimes/runtimes.js +1 -0
- package/dist/runtimes/runtimes.js.map +1 -0
- package/dist/slots/index.js +2 -0
- package/dist/slots/index.js.map +1 -0
- package/dist/slots/registry.js +1 -0
- package/dist/slots/registry.js.map +1 -0
- package/dist/slots/slot.js +1 -0
- package/dist/slots/slot.js.map +1 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/async-for-each.js +1 -0
- package/dist/utils/async-for-each.js.map +1 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +1 -0
- package/exceptions/extension-init-error.ts +1 -0
- package/exceptions/extension-load-error.ts +28 -0
- package/exceptions/extension-potential-circular.ts +24 -0
- package/exceptions/harmony-already-running.ts +1 -0
- package/exceptions/harmony-error.ts +1 -0
- package/exceptions/hook-not-found.ts +1 -0
- package/exceptions/index.ts +5 -0
- package/{dist/extension-graph/extension-graph.spec.d.ts → exceptions/runtime-not-defined.ts} +0 -0
- package/extension/any-extension.ts +8 -0
- package/extension/decorator.ts +126 -0
- package/extension/extension-manifest.ts +51 -0
- package/extension/extension.ts +138 -0
- package/extension/index.ts +3 -0
- package/extension-graph/extension-graph.ts +151 -0
- package/extension-graph/from-extension.ts +72 -0
- package/extension-graph/index.ts +1 -0
- package/factory/extension-factory.ts +8 -0
- package/factory/index.ts +1 -0
- package/fixtures/aspects/babel/babel.aspect.ts +14 -0
- package/fixtures/aspects/babel/babel.cli.ts +16 -0
- package/fixtures/aspects/react/react.aspect.ts +22 -0
- package/fixtures/aspects/react/react.cli.ts +26 -0
- package/fixtures/aspects/react/react.ui.ts +16 -0
- package/fixtures/aspects/ui/ui.aspect.ts +13 -0
- package/fixtures/aspects/ui/ui.ui.ts +11 -0
- package/fixtures/babel/babel.extension.ts +20 -0
- package/{dist/extension/extension.spec.d.ts → fixtures/babel/index.ts} +0 -0
- package/fixtures/base-compiler/base-compiler.extension.ts +31 -0
- package/fixtures/base-compiler/index.ts +1 -0
- package/fixtures/cli/cli.extension.ts +25 -0
- package/fixtures/cli/command.ts +6 -0
- package/fixtures/cli/index.ts +1 -0
- package/fixtures/typescript/index.ts +0 -0
- package/fixtures/typescript/typescript.ts +20 -0
- package/harmony-config/config-reader.ts +17 -0
- package/harmony-config/exceptions/index.ts +1 -0
- package/harmony-config/exceptions/read-config-error.ts +9 -0
- package/harmony-config/harmony-config.ts +49 -0
- package/harmony-config/index.ts +1 -0
- package/harmony-config/locator.ts +0 -0
- package/harmony.docs.mdx +249 -0
- package/harmony.spec.old.ts +177 -0
- package/harmony.ts +146 -0
- package/index.ts +10 -0
- package/package-tar/teambit-harmony-0.3.0.tgz +0 -0
- package/package.json +41 -28
- package/preview-1649080456374.js +1 -0
- package/readme.md +58 -137
- package/runtimes/exceptions/index.ts +2 -0
- package/runtimes/exceptions/runtime-module-error.ts +9 -0
- package/runtimes/exceptions/runtime-not-defined.ts +5 -0
- package/runtimes/index.ts +3 -0
- package/runtimes/runtime-definition.ts +32 -0
- package/runtimes/runtime-manifest.ts +12 -0
- package/runtimes/runtimes.ts +34 -0
- package/slots/index.ts +2 -0
- package/slots/registry.ts +36 -0
- package/slots/slot.ts +11 -0
- package/tsconfig.json +26 -0
- package/types/asset.d.ts +29 -0
- package/types/style.d.ts +42 -0
- package/types.ts +7 -0
- package/utils/async-for-each.ts +10 -0
- package/utils/index.ts +1 -0
- package/dist/extension/extension.spec.js +0 -1
- package/dist/extension-graph/extension-graph.spec.js +0 -1
- package/dist/factory/extension-factory.spec.js +0 -6
- package/dist/harmony-config/harmony-config.spec.d.ts +0 -1
- package/dist/harmony-config/harmony-config.spec.js +0 -8
- package/dist/harmony.spec.d.ts +0 -1
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { ProviderFn } from '../types';
|
|
2
|
+
import { Harmony } from '../harmony';
|
|
3
|
+
import { ExtensionManifest } from './extension-manifest';
|
|
4
|
+
import { ExtensionInstantiationException } from '../exceptions/extension-init-error';
|
|
5
|
+
import { RuntimeDefinition } from '../runtimes';
|
|
6
|
+
|
|
7
|
+
export type ExtensionProps = {
|
|
8
|
+
name: string;
|
|
9
|
+
// TODO: changes from any to something meaningful
|
|
10
|
+
dependencies: any[];
|
|
11
|
+
provider: ProviderFn;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* harmony's extension definition. this can be used to define and extend `Harmony` applications.
|
|
16
|
+
*/
|
|
17
|
+
export class Extension {
|
|
18
|
+
constructor(
|
|
19
|
+
/**
|
|
20
|
+
* manifest of the extension.
|
|
21
|
+
*/
|
|
22
|
+
readonly manifest: ExtensionManifest
|
|
23
|
+
) {}
|
|
24
|
+
|
|
25
|
+
private _instance = null;
|
|
26
|
+
|
|
27
|
+
private _loaded = false;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* returns the instance of the extension
|
|
31
|
+
*/
|
|
32
|
+
get instance() {
|
|
33
|
+
return this._instance;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
get name() {
|
|
37
|
+
const metadata = Reflect.getMetadata('harmony:name', this.manifest);
|
|
38
|
+
return metadata || this.manifest.id || this.manifest.name;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get id() {
|
|
42
|
+
return this.name;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get dependencies(): Extension[] {
|
|
46
|
+
const metadata = Reflect.getMetadata('harmony:dependencies', this.manifest);
|
|
47
|
+
return metadata || this.manifest.dependencies || [];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
get provider() {
|
|
51
|
+
const metadata = Reflect.getMetadata('harmony:provider', this.manifest);
|
|
52
|
+
return metadata || this.manifest.provider;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
get files() {
|
|
56
|
+
return this.manifest.files;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* returns an indication of the extension already loaded (the provider run)
|
|
61
|
+
* We don't rely on the instance since an extension provider might return null
|
|
62
|
+
*/
|
|
63
|
+
get loaded() {
|
|
64
|
+
return this._loaded;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
toString(): string {
|
|
68
|
+
return JSON.stringify(this.name);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private buildSlotRegistries(slots: ((registerFn: () => void) => any)[], context: Harmony) {
|
|
72
|
+
return slots.map((slot) => {
|
|
73
|
+
return slot(() => {
|
|
74
|
+
return context.current;
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
get declareRuntime() {
|
|
80
|
+
return this.manifest.declareRuntime;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
getRuntime(runtime: RuntimeDefinition) {
|
|
84
|
+
return this.manifest.getRuntime(runtime);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
getSlots(extensionRuntime: any) {
|
|
88
|
+
if (extensionRuntime.slots && extensionRuntime.slots.length) {
|
|
89
|
+
return extensionRuntime.slots;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return this.manifest.slots || [];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
getConfig(context: Harmony, extensionRuntime: any) {
|
|
96
|
+
const defaultConfig = extensionRuntime.defaultConfig || this.manifest.defaultConfig || {};
|
|
97
|
+
const config = context.config.get(this.name) || {};
|
|
98
|
+
return Object.assign({}, defaultConfig, config);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* initiate Harmony in run-time.
|
|
103
|
+
*/
|
|
104
|
+
async __run(dependencies: any[], context: Harmony, runtime: RuntimeDefinition) {
|
|
105
|
+
const name = this.name;
|
|
106
|
+
context.initExtension(name);
|
|
107
|
+
const extensionRuntime = this.getRuntime(runtime);
|
|
108
|
+
|
|
109
|
+
if (!extensionRuntime) {
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// @ts-ignore
|
|
114
|
+
const registries = this.buildSlotRegistries(this.getSlots(extensionRuntime), context);
|
|
115
|
+
const config = this.getConfig(context, extensionRuntime);
|
|
116
|
+
|
|
117
|
+
if (!this.loaded) {
|
|
118
|
+
if (extensionRuntime.provider) this._instance = await extensionRuntime.provider(dependencies, config, registries, context);
|
|
119
|
+
else {
|
|
120
|
+
try {
|
|
121
|
+
// @ts-ignore
|
|
122
|
+
this._instance = new extensionRuntime.manifest(...dependencies);
|
|
123
|
+
} catch(err) {
|
|
124
|
+
throw new ExtensionInstantiationException(err.toString());
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
// @ts-ignore adding the extension ID to the instance.
|
|
128
|
+
// this._instance.id = this.manifest.name;
|
|
129
|
+
// @ts-ignore adding the extension ID to the instance.
|
|
130
|
+
// this._instance.config = config;
|
|
131
|
+
this._loaded = true;
|
|
132
|
+
return this._instance;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
context.endExtension();
|
|
136
|
+
return Promise.resolve(this.instance);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { Graph } from 'cleargraph';
|
|
2
|
+
import { fromExtension, fromExtensions } from './from-extension';
|
|
3
|
+
import { ExtensionManifest } from '../extension';
|
|
4
|
+
import { Extension } from '../extension';
|
|
5
|
+
import { RuntimeDefinition, Runtimes } from '../runtimes';
|
|
6
|
+
import { RequireFn } from '../harmony';
|
|
7
|
+
|
|
8
|
+
function getName(manifest: any) {
|
|
9
|
+
return Reflect.getMetadata('harmony:name', manifest) || manifest.id || manifest.name;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type Edge = {
|
|
13
|
+
type: string,
|
|
14
|
+
runtime?: string
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default class DependencyGraph extends Graph<Extension, Edge> {
|
|
18
|
+
private cache = new Map<string, Extension>();
|
|
19
|
+
|
|
20
|
+
getRuntimeDependencies(aspect: Extension, runtime: RuntimeDefinition): Extension[] {
|
|
21
|
+
const dependencies = this.successors(aspect.name);
|
|
22
|
+
const runtimeDeps = this.successors(aspect.name, (edge) => {
|
|
23
|
+
if (!edge.runtime) return false;
|
|
24
|
+
return edge.runtime === runtime.name;
|
|
25
|
+
});
|
|
26
|
+
const runtimeManifest = aspect.getRuntime(runtime);
|
|
27
|
+
if (!runtimeManifest) return Array.from(dependencies.values());
|
|
28
|
+
|
|
29
|
+
if (runtimeDeps && runtimeDeps.size) return this.sortDeps(runtimeManifest.dependencies, Array.from(runtimeDeps.values()));
|
|
30
|
+
return this.sortDeps(runtimeManifest.dependencies, Array.from(dependencies.values()));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
private sortDeps(originalDependencies: any[], targetDependencies: any[]) {
|
|
34
|
+
return targetDependencies.sort((a, b) => {
|
|
35
|
+
return originalDependencies.findIndex(item => item.id === a.id) - originalDependencies.findIndex(item => item.id === b.id);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
byExecutionOrder() {
|
|
40
|
+
return this.toposort(true);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private async enrichRuntimeExtension(id: string, aspect: Extension, runtime: RuntimeDefinition, runtimes: Runtimes, requireFn: RequireFn) {
|
|
44
|
+
await requireFn(aspect, runtime);
|
|
45
|
+
const runtimeManifest = aspect.getRuntime(runtime)
|
|
46
|
+
if (!runtimeManifest) return;
|
|
47
|
+
const deps = runtimeManifest.dependencies;
|
|
48
|
+
if (!deps) return;
|
|
49
|
+
const promises = deps.map(async (dep: any) => {
|
|
50
|
+
if (!this.hasNode(dep.id)) {
|
|
51
|
+
this.add(dep);
|
|
52
|
+
if (dep.declareRuntime) {
|
|
53
|
+
runtimes.add(dep.declareRuntime);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
await requireFn(this.get(dep.id), runtime);
|
|
57
|
+
await this.enrichRuntimeExtension(dep.id, this.get(dep.id), runtime, runtimes, requireFn);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
this.setEdge(id, dep.id, {
|
|
61
|
+
runtime: runtime.name,
|
|
62
|
+
type: 'runtime-dependency'
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
return Promise.all(promises);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async enrichRuntime(runtime: RuntimeDefinition, runtimes: Runtimes, requireFn: RequireFn) {
|
|
70
|
+
const promises = Array.from(this.nodes.entries()).map(async ([id, aspect]) => {
|
|
71
|
+
return this.enrichRuntimeExtension(id, aspect, runtime, runtimes, requireFn);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
return Promise.all(promises);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
add(manifest: ExtensionManifest) {
|
|
78
|
+
const { vertices, edges } = fromExtension(manifest);
|
|
79
|
+
this.setNodes(vertices);
|
|
80
|
+
this.setEdges(edges);
|
|
81
|
+
|
|
82
|
+
return this;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
load(extensions: ExtensionManifest[]) {
|
|
86
|
+
const newExtensions = extensions.filter((extension) => {
|
|
87
|
+
if (!extension.id) return false;
|
|
88
|
+
return !this.get(extension.id);
|
|
89
|
+
});
|
|
90
|
+
const { vertices, edges } = fromExtensions(newExtensions);
|
|
91
|
+
// Only set new vertices
|
|
92
|
+
this.setNodes(vertices, false); // false because we don't want to override already-loaded extensions
|
|
93
|
+
this.setEdges(edges);
|
|
94
|
+
|
|
95
|
+
return this;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// :TODO refactor this asap
|
|
99
|
+
getExtension(manifest: ExtensionManifest) {
|
|
100
|
+
const id = getName(manifest);
|
|
101
|
+
const cachedVertex = this.cache.get(id);
|
|
102
|
+
if (cachedVertex) return cachedVertex;
|
|
103
|
+
|
|
104
|
+
const res = this.node(id);
|
|
105
|
+
if (res) {
|
|
106
|
+
this.cache.set(res.name, res);
|
|
107
|
+
return res;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
get extensions(): ExtensionManifest[] {
|
|
114
|
+
return Array.from(this.nodes.values());
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
get aspects() {
|
|
118
|
+
return this.extensions;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
get(id: string): any {
|
|
122
|
+
const cachedVertex = this.cache.get(id);
|
|
123
|
+
if (cachedVertex) return cachedVertex;
|
|
124
|
+
|
|
125
|
+
const res = this.node(id);
|
|
126
|
+
if (res) {
|
|
127
|
+
this.cache.set(res.name, res);
|
|
128
|
+
return res;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* build Harmony from a single extension.
|
|
136
|
+
*/
|
|
137
|
+
static fromRoot(extension: ExtensionManifest) {
|
|
138
|
+
const { vertices, edges } = fromExtension(extension);
|
|
139
|
+
|
|
140
|
+
return new DependencyGraph(vertices, edges);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* build Harmony from set of extensions
|
|
145
|
+
*/
|
|
146
|
+
static from(extensions: ExtensionManifest[]) {
|
|
147
|
+
const { vertices, edges } = fromExtensions(extensions);
|
|
148
|
+
|
|
149
|
+
return new DependencyGraph(vertices, edges);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { ExtensionManifest } from '../extension';
|
|
2
|
+
import { extensionFactory } from '../factory';
|
|
3
|
+
import ExtensionPotentialCircular from '../exceptions/extension-potential-circular';
|
|
4
|
+
import { Extension } from '../extension';
|
|
5
|
+
import { Edge } from './extension-graph';
|
|
6
|
+
|
|
7
|
+
function getName(manifest: any) {
|
|
8
|
+
return Reflect.getMetadata('harmony:name', manifest) || manifest.id || manifest.name;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* build vertices and edges from the given extension
|
|
13
|
+
*/
|
|
14
|
+
export function fromExtension(extension: ExtensionManifest) {
|
|
15
|
+
const vertices: { [id: string]: Extension } = {};
|
|
16
|
+
let edges: { sourceId: string; targetId: string; edge: Edge }[] = [];
|
|
17
|
+
|
|
18
|
+
function iterate(root: ExtensionManifest) {
|
|
19
|
+
const id = getName(root);
|
|
20
|
+
if (vertices[id]) return;
|
|
21
|
+
|
|
22
|
+
const instance = extensionFactory(root);
|
|
23
|
+
const validDeps = instance.dependencies.filter(dep => dep).map(dep => extensionFactory(dep));
|
|
24
|
+
if (instance.dependencies.length > validDeps.length) {
|
|
25
|
+
throw new ExtensionPotentialCircular(instance, validDeps);
|
|
26
|
+
}
|
|
27
|
+
vertices[id] = instance;
|
|
28
|
+
const newEdges = validDeps.map(dep => {
|
|
29
|
+
return {
|
|
30
|
+
sourceId: id,
|
|
31
|
+
targetId: dep.name,
|
|
32
|
+
edge: {
|
|
33
|
+
type: 'dependency'
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
edges = edges.concat(newEdges);
|
|
39
|
+
|
|
40
|
+
// @ts-ignore
|
|
41
|
+
instance.dependencies.forEach(dep => iterate(dep));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
iterate(extension);
|
|
45
|
+
|
|
46
|
+
let vertexArray: { id: string; node: Extension }[] = [];
|
|
47
|
+
for (let [key, value] of Object.entries(vertices)) {
|
|
48
|
+
vertexArray.push({ id: key, node: value });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
vertices: vertexArray,
|
|
53
|
+
edges
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* build vertices and edges from the given list of extensions
|
|
59
|
+
*/
|
|
60
|
+
export function fromExtensions(extensions: ExtensionManifest[]) {
|
|
61
|
+
const perExtension = extensions.map(ext => fromExtension(ext));
|
|
62
|
+
|
|
63
|
+
return perExtension.reduce(
|
|
64
|
+
(acc, subgraph) => {
|
|
65
|
+
acc.edges = acc.edges.concat(subgraph.edges);
|
|
66
|
+
acc.vertices = acc.vertices.concat(subgraph.vertices);
|
|
67
|
+
|
|
68
|
+
return acc;
|
|
69
|
+
},
|
|
70
|
+
{ vertices: [], edges: [] }
|
|
71
|
+
);
|
|
72
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as DependencyGraph } from './extension-graph';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ExtensionManifest } from '../extension/extension-manifest';
|
|
2
|
+
import { Extension } from '../extension/extension';
|
|
3
|
+
|
|
4
|
+
export function extensionFactory(manifest: ExtensionManifest) {
|
|
5
|
+
// to allow the use of `provide` as an alias to `provider` in ExtensionManifest
|
|
6
|
+
if (manifest.provide) manifest.provider = manifest.provide;
|
|
7
|
+
return new Extension(manifest);
|
|
8
|
+
}
|
package/factory/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { extensionFactory } from './extension-factory';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { BabelCLI } from './babel.cli';
|
|
2
|
+
import { Aspect } from '../../../aspect';
|
|
3
|
+
|
|
4
|
+
export type { BabelCLI };
|
|
5
|
+
|
|
6
|
+
export const BabelAspect = Aspect.create({
|
|
7
|
+
id: '@teambit/babel',
|
|
8
|
+
dependencies: [],
|
|
9
|
+
files: [
|
|
10
|
+
require.resolve('./babel.cli')
|
|
11
|
+
]
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export default BabelAspect;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { BabelAspect } from './babel.aspect';
|
|
2
|
+
import { CLIRuntime } from '../react/react.aspect';
|
|
3
|
+
|
|
4
|
+
export class BabelCLI {
|
|
5
|
+
compile() {
|
|
6
|
+
console.log('compiled!');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
static runtime = CLIRuntime;
|
|
10
|
+
|
|
11
|
+
static async provider() {
|
|
12
|
+
return new BabelCLI();
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
BabelAspect.addRuntime(BabelCLI);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { BabelAspect } from '../babel/babel.aspect';
|
|
2
|
+
import { Aspect } from '../../../aspect';
|
|
3
|
+
import { Slot } from '../../../slots';
|
|
4
|
+
import { RuntimeDefinition } from '../../../runtimes';
|
|
5
|
+
import { UIAspect } from '../ui/ui.aspect';
|
|
6
|
+
|
|
7
|
+
export type Config = {};
|
|
8
|
+
|
|
9
|
+
export const CLIRuntime = RuntimeDefinition.create({ name: 'cli' })
|
|
10
|
+
|
|
11
|
+
export const ReactAspect = Aspect.create({
|
|
12
|
+
id: '@teambit/react',
|
|
13
|
+
dependencies: [UIAspect],
|
|
14
|
+
defaultConfig: {},
|
|
15
|
+
declareRuntime: CLIRuntime,
|
|
16
|
+
files: [
|
|
17
|
+
require.resolve('./react.cli'),
|
|
18
|
+
require.resolve('./react.ui')
|
|
19
|
+
]
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export default ReactAspect;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import ReactAspect, { CLIRuntime } from './react.aspect';
|
|
2
|
+
import BabelAspect, { BabelCLI } from '../babel/babel.aspect';
|
|
3
|
+
import { Slot, SlotRegistry } from '../../../slots';
|
|
4
|
+
|
|
5
|
+
export class ReactCLI {
|
|
6
|
+
constructor(
|
|
7
|
+
private babel: BabelCLI
|
|
8
|
+
) {}
|
|
9
|
+
|
|
10
|
+
static runtime = CLIRuntime;
|
|
11
|
+
|
|
12
|
+
hello() {
|
|
13
|
+
return this.babel.compile();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static dependencies = [BabelAspect];
|
|
17
|
+
|
|
18
|
+
static slots = [Slot.withType<string>()];
|
|
19
|
+
|
|
20
|
+
static async provider([babelCli]: [BabelCLI], config: {}, [stringSlot]: [SlotRegistry<string>]) {
|
|
21
|
+
stringSlot.register('hi there');
|
|
22
|
+
return new ReactCLI(babelCli);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
ReactAspect.addRuntime(ReactCLI);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import ReactAspect from './react.aspect';
|
|
2
|
+
import { UIRuntime } from '../ui/ui.aspect';
|
|
3
|
+
|
|
4
|
+
export class ReactUI {
|
|
5
|
+
static runtime = UIRuntime;
|
|
6
|
+
|
|
7
|
+
render() {
|
|
8
|
+
return 'rendering something!';
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
static async provider() {
|
|
12
|
+
return new ReactUI();
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
ReactAspect.addRuntime(ReactUI);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Aspect } from '../../../aspect';
|
|
2
|
+
import { RuntimeDefinition } from '../../../runtimes';
|
|
3
|
+
|
|
4
|
+
export const UIRuntime = RuntimeDefinition.create({ name: 'ui' });
|
|
5
|
+
|
|
6
|
+
export const UIAspect = Aspect.create({
|
|
7
|
+
id: '@teambit/ui',
|
|
8
|
+
dependencies: [],
|
|
9
|
+
declareRuntime: UIRuntime,
|
|
10
|
+
files: [
|
|
11
|
+
require.resolve('./ui.ui')
|
|
12
|
+
]
|
|
13
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Extension, provider } from '../..';
|
|
2
|
+
import { BaseCompiler } from '../base-compiler';
|
|
3
|
+
|
|
4
|
+
class Mock {
|
|
5
|
+
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// @Extension({
|
|
9
|
+
// dependencies: [BaseCompiler]
|
|
10
|
+
// })
|
|
11
|
+
export class Babel {
|
|
12
|
+
constructor(
|
|
13
|
+
private mock?: Mock
|
|
14
|
+
) {}
|
|
15
|
+
|
|
16
|
+
// @provider()
|
|
17
|
+
async provide([baseCompiler]: [BaseCompiler]) {
|
|
18
|
+
return new Babel();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Extension } from "../..";
|
|
2
|
+
import { CLI, Command } from '../cli';
|
|
3
|
+
|
|
4
|
+
// @Extension()
|
|
5
|
+
export class BaseCompiler {
|
|
6
|
+
constructor(
|
|
7
|
+
private cli: CLI
|
|
8
|
+
) {}
|
|
9
|
+
|
|
10
|
+
// @Config()
|
|
11
|
+
config() {
|
|
12
|
+
return {
|
|
13
|
+
cjs: 'blue/green'
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// @Command
|
|
18
|
+
main() {
|
|
19
|
+
return {
|
|
20
|
+
synopsis: 'compile <id>',
|
|
21
|
+
report: () => {
|
|
22
|
+
return 'compiled in 0.1 secs';
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
compile() {
|
|
28
|
+
this.cli.run();
|
|
29
|
+
return 'hello world';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { BaseCompiler } from './base-compiler.extension';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Extension, createHook } from '../..';
|
|
2
|
+
import { HookRegistry, hook } from '../..';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* hook for registering new CLI commands.
|
|
6
|
+
*/
|
|
7
|
+
export const Command = createHook();
|
|
8
|
+
|
|
9
|
+
export type CommandDefinition = {
|
|
10
|
+
synopsis: string,
|
|
11
|
+
report: string
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// @Extension()
|
|
15
|
+
export class CLI {
|
|
16
|
+
/**
|
|
17
|
+
* registry for the commands hook
|
|
18
|
+
*/
|
|
19
|
+
private commands = HookRegistry.of<CommandDefinition>(Command);
|
|
20
|
+
|
|
21
|
+
run() {
|
|
22
|
+
const commands = this.commands.list();
|
|
23
|
+
return commands;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './cli.extension';
|
|
File without changes
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Extension } from '../..';
|
|
2
|
+
import { BaseCompiler } from '../base-compiler';
|
|
3
|
+
|
|
4
|
+
// @Extension({
|
|
5
|
+
// name: 'typescript',
|
|
6
|
+
// dependencies: [BaseCompiler]
|
|
7
|
+
// })
|
|
8
|
+
export class TypeScript {
|
|
9
|
+
constructor(
|
|
10
|
+
private compiler: string
|
|
11
|
+
) {}
|
|
12
|
+
|
|
13
|
+
compile() {
|
|
14
|
+
return this.compiler;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static async provider([baseCompiler]: [BaseCompiler]) {
|
|
18
|
+
return new TypeScript(baseCompiler.compile());
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { parse } from 'comment-json';
|
|
2
|
+
import { readFileSync, existsSync } from 'fs-extra';
|
|
3
|
+
import { ReadConfigError } from './exceptions/read-config-error';
|
|
4
|
+
|
|
5
|
+
export function readConfigFile(path: string, mustExist = true) {
|
|
6
|
+
if (!mustExist && !existsSync(path)) {
|
|
7
|
+
return {};
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
const json = parse(readFileSync(path, 'utf8'));
|
|
12
|
+
delete json.$schema;
|
|
13
|
+
return json;
|
|
14
|
+
} catch (err) {
|
|
15
|
+
throw new ReadConfigError(path, err);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ReadConfigError } from './read-config-error';
|