Skip to content

Commit 79a6988

Browse files
hanslKeen Yee Liau
authored and
Keen Yee Liau
committed
feat(@angular-devkit/architect): add node architect host
This host resolves using the package resolution and reading the targets from the workspace API.
1 parent 68220f1 commit 79a6988

File tree

3 files changed

+142
-0
lines changed

3 files changed

+142
-0
lines changed

packages/angular_devkit/architect/BUILD

+25
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,31 @@ ts_json_schema(
2828
src = "src/progress-schema.json",
2929
)
3030

31+
ts_library(
32+
name = "node",
33+
srcs = glob(
34+
include = ["node/**/*.ts"],
35+
exclude = [
36+
"**/*_spec.ts",
37+
"**/*_spec_large.ts",
38+
],
39+
),
40+
module_name = "@angular-devkit/architect/node",
41+
module_root = "node/index.d.ts",
42+
# strict_checks = False,
43+
deps = [
44+
"//packages/angular_devkit/core",
45+
"//packages/angular_devkit/core:node",
46+
"@rxjs",
47+
"@rxjs//operators",
48+
"@npm//@types/node",
49+
":architect",
50+
":builder_builders_schema",
51+
":builder_input_schema",
52+
":builder_output_schema",
53+
],
54+
)
55+
3156
ts_library(
3257
name = "architect",
3358
srcs = glob(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
export * from './node-modules-architect-host';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
import { experimental, json } from '@angular-devkit/core';
9+
import { resolve } from '@angular-devkit/core/node';
10+
import * as path from 'path';
11+
import { Schema as BuilderSchema } from '../src/builders-schema';
12+
import { BuilderInfo } from '../src/index2';
13+
import { Target } from '../src/input-schema';
14+
import { ArchitectHost, Builder, BuilderSymbol } from '../src/internal';
15+
16+
17+
export type NodeModulesBuilderInfo = BuilderInfo & {
18+
import: string;
19+
};
20+
21+
22+
// TODO: create a base class for all workspace related hosts.
23+
export class WorkspaceNodeModulesArchitectHost implements ArchitectHost<NodeModulesBuilderInfo> {
24+
constructor(
25+
protected _workspace: experimental.workspace.Workspace,
26+
protected _root: string,
27+
) {}
28+
29+
async getBuilderNameForTarget(target: Target) {
30+
return this._workspace.getProjectTargets(target.project)[target.target]['builder'];
31+
}
32+
33+
/**
34+
* Resolve a builder. This needs to be a string which will be used in a dynamic `import()`
35+
* clause. This should throw if no builder can be found. The dynamic import will throw if
36+
* it is unsupported.
37+
* @param builderStr The name of the builder to be used.
38+
* @returns All the info needed for the builder itself.
39+
*/
40+
resolveBuilder(builderStr: string): Promise<NodeModulesBuilderInfo> {
41+
const [packageName, builderName] = builderStr.split(':', 2);
42+
if (!builderName) {
43+
throw new Error('No builder name specified.');
44+
}
45+
46+
const packageJsonPath = resolve(packageName, {
47+
basedir: this._root,
48+
checkLocal: true,
49+
checkGlobal: true,
50+
resolvePackageJson: true,
51+
});
52+
53+
const packageJson = require(packageJsonPath);
54+
if (!packageJson['builders']) {
55+
throw new Error(`Package ${JSON.stringify(packageName)} has no builders defined.`);
56+
}
57+
58+
const builderJsonPath = path.resolve(path.dirname(packageJsonPath), packageJson['builders']);
59+
const builderJson = require(builderJsonPath) as BuilderSchema;
60+
61+
const builder = builderJson.builders && builderJson.builders[builderName];
62+
63+
if (!builder) {
64+
throw new Error(`Cannot find builder ${JSON.stringify(builderName)}.`);
65+
}
66+
67+
const importPath = builder.implementation;
68+
if (!importPath) {
69+
throw new Error('Invalid builder JSON');
70+
}
71+
72+
return Promise.resolve({
73+
name: builderStr,
74+
builderName,
75+
description: builder['description'],
76+
optionSchema: require(path.resolve(path.dirname(builderJsonPath), builder.schema)),
77+
import: path.resolve(path.dirname(builderJsonPath), importPath),
78+
});
79+
}
80+
81+
async getCurrentDirectory() {
82+
return process.cwd();
83+
}
84+
85+
async getWorkspaceRoot() {
86+
return this._root;
87+
}
88+
89+
async getOptionsForTarget(target: Target): Promise<json.JsonObject> {
90+
const targetSpec = this._workspace.getProjectTargets(target.project)[target.target];
91+
if (target.configuration && !targetSpec['configurations']) {
92+
throw new Error('Configuration not set in the workspace.');
93+
}
94+
95+
return {
96+
...targetSpec['options'],
97+
...(target.configuration ? targetSpec['configurations'][target.configuration] : 0),
98+
};
99+
}
100+
101+
async loadBuilder(info: NodeModulesBuilderInfo): Promise<Builder> {
102+
const builder = (await import(info.import)).default;
103+
if (builder[BuilderSymbol]) {
104+
return builder;
105+
}
106+
107+
throw new Error('Builder is not a builder');
108+
}
109+
}

0 commit comments

Comments
 (0)