@angular-devkit/core 8.0.0-rc.1 → 8.0.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/README.md +107 -1
- package/node/host.js +1 -1
- package/package.json +1 -1
- package/src/json/schema/interface.d.ts +0 -1
- package/src/json/schema/registry.js +1 -3
- package/src/json/schema/visitor.js +1 -4
- package/src/utils/lang.d.ts +1 -0
- package/src/utils/lang.js +1 -0
- package/src/workspace/core.d.ts +43 -0
- package/src/workspace/core.js +43 -0
- package/src/workspace/host.js +2 -2
- package/src/workspace/json/metadata.js +3 -0
- package/src/workspace/json/writer.js +1 -1
package/README.md
CHANGED
|
@@ -56,4 +56,110 @@ export class CoreSchemaRegistry implements SchemaRegistry {
|
|
|
56
56
|
|
|
57
57
|
# Utils
|
|
58
58
|
|
|
59
|
-
# Virtual FS
|
|
59
|
+
# Virtual FS
|
|
60
|
+
|
|
61
|
+
# Workspaces
|
|
62
|
+
|
|
63
|
+
The `workspaces` namespace provides an API for interacting with the workspace file formats.
|
|
64
|
+
It provides an abstraction of the underlying storage format of the workspace and provides
|
|
65
|
+
support for both reading and writing. Currently, the only supported format is the JSON-based
|
|
66
|
+
format used by the Angular CLI. For this format, the API provides internal change tracking of values which
|
|
67
|
+
enables fine-grained updates to the underlying storage of the workspace. This allows for the
|
|
68
|
+
retention of existing formatting and comments.
|
|
69
|
+
|
|
70
|
+
A workspace is defined via the following object model. Definition collection objects are specialized
|
|
71
|
+
Javascript `Map` objects with an additional `add` method to simplify addition and provide more localized
|
|
72
|
+
error checking of the newly added values.
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
export interface WorkspaceDefinition {
|
|
76
|
+
readonly extensions: Record<string, JsonValue | undefined>;
|
|
77
|
+
readonly projects: ProjectDefinitionCollection;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface ProjectDefinition {
|
|
81
|
+
readonly extensions: Record<string, JsonValue | undefined>;
|
|
82
|
+
readonly targets: TargetDefinitionCollection;
|
|
83
|
+
root: string;
|
|
84
|
+
prefix?: string;
|
|
85
|
+
sourceRoot?: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface TargetDefinition {
|
|
89
|
+
options?: Record<string, JsonValue | undefined>;
|
|
90
|
+
configurations?: Record<string, Record<string, JsonValue | undefined> | undefined>;
|
|
91
|
+
builder: string;
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The API is asynchronous and has two main functions to facilitate reading, creation, and modifying
|
|
96
|
+
a workspace: `readWorkspace` and `writeWorkspace`.
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
export enum WorkspaceFormat {
|
|
100
|
+
JSON,
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
export function readWorkspace(
|
|
106
|
+
path: string,
|
|
107
|
+
host: WorkspaceHost,
|
|
108
|
+
format?: WorkspaceFormat,
|
|
109
|
+
): Promise<{ workspace: WorkspaceDefinition; }>;
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
export function writeWorkspace(
|
|
114
|
+
workspace: WorkspaceDefinition,
|
|
115
|
+
host: WorkspaceHost,
|
|
116
|
+
path?: string,
|
|
117
|
+
format?: WorkspaceFormat,
|
|
118
|
+
): Promise<void>;
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
A `WorkspaceHost` abstracts the underlying data access methods from the functions. It provides
|
|
122
|
+
methods to read, write, and analyze paths. A utility function is provided to create
|
|
123
|
+
an instance of a `WorkspaceHost` from the Angular DevKit's virtual filesystem host abstraction.
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
export interface WorkspaceHost {
|
|
127
|
+
readFile(path: string): Promise<string>;
|
|
128
|
+
writeFile(path: string, data: string): Promise<void>;
|
|
129
|
+
isDirectory(path: string): Promise<boolean>;
|
|
130
|
+
isFile(path: string): Promise<boolean>;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function createWorkspaceHost(host: virtualFs.Host): WorkspaceHost;
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Usage Example
|
|
137
|
+
|
|
138
|
+
To demonstrate the usage of the API, the following code will show how to add a option property
|
|
139
|
+
to a build target for an application.
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
import { NodeJsSyncHost } from '@angular-devkit/core/node';
|
|
143
|
+
import { workspaces } from '@angular-devkit/core';
|
|
144
|
+
|
|
145
|
+
async function demonstrate() {
|
|
146
|
+
const host = workspaces.createWorkspaceHost(new NodeJsSyncHost());
|
|
147
|
+
const workspace = await workspaces.readWorkspace('path/to/workspace/directory/', host);
|
|
148
|
+
|
|
149
|
+
const project = workspace.projects.get('my-app');
|
|
150
|
+
if (!project) {
|
|
151
|
+
throw new Error('my-app does not exist');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const buildTarget = project.targets.get('build');
|
|
155
|
+
if (!buildTarget) {
|
|
156
|
+
throw new Error('build target does not exist');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
buildTarget.options.optimization = true;
|
|
160
|
+
|
|
161
|
+
await workspaces.writeWorkspace(workspace, host);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
demonstrate();
|
|
165
|
+
```
|
package/node/host.js
CHANGED
|
@@ -114,7 +114,7 @@ class NodeJsAsyncHost {
|
|
|
114
114
|
return _callFs(fs.stat, src_1.getSystemPath(path)).pipe(operators_1.map(stat => stat.isDirectory()));
|
|
115
115
|
}
|
|
116
116
|
isFile(path) {
|
|
117
|
-
return _callFs(fs.stat, src_1.getSystemPath(path)).pipe(operators_1.map(stat => stat.
|
|
117
|
+
return _callFs(fs.stat, src_1.getSystemPath(path)).pipe(operators_1.map(stat => stat.isFile()));
|
|
118
118
|
}
|
|
119
119
|
// Some hosts may not support stat.
|
|
120
120
|
stat(path) {
|
package/package.json
CHANGED
|
@@ -79,7 +79,6 @@ export interface PromptDefinition {
|
|
|
79
79
|
type: string;
|
|
80
80
|
message: string;
|
|
81
81
|
default?: string | string[] | number | boolean | null;
|
|
82
|
-
priority: number;
|
|
83
82
|
validator?: (value: string) => boolean | string | Promise<boolean | string>;
|
|
84
83
|
items?: Array<string | {
|
|
85
84
|
value: JsonValue;
|
|
@@ -428,7 +428,6 @@ class CoreSchemaRegistry {
|
|
|
428
428
|
id: path,
|
|
429
429
|
type,
|
|
430
430
|
message,
|
|
431
|
-
priority: 0,
|
|
432
431
|
raw: schema,
|
|
433
432
|
items,
|
|
434
433
|
multiselect: type === 'list' ? schema.multiselect : false,
|
|
@@ -480,7 +479,6 @@ class CoreSchemaRegistry {
|
|
|
480
479
|
if (!provider) {
|
|
481
480
|
return rxjs_1.of(data);
|
|
482
481
|
}
|
|
483
|
-
prompts.sort((a, b) => b.priority - a.priority);
|
|
484
482
|
return rxjs_1.from(provider(prompts)).pipe(operators_1.map(answers => {
|
|
485
483
|
for (const path in answers) {
|
|
486
484
|
const pathFragments = path.split('/').map(pf => {
|
|
@@ -552,7 +550,7 @@ class CoreSchemaRegistry {
|
|
|
552
550
|
const fragments = JSON.parse(pointer);
|
|
553
551
|
const source = this._sourceMap.get(schema.$source);
|
|
554
552
|
let value = source ? source(schema) : rxjs_1.of(undefined);
|
|
555
|
-
if (!
|
|
553
|
+
if (!rxjs_1.isObservable(value)) {
|
|
556
554
|
value = rxjs_1.of(value);
|
|
557
555
|
}
|
|
558
556
|
return value.pipe(
|
|
@@ -9,7 +9,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
9
9
|
*/
|
|
10
10
|
const rxjs_1 = require("rxjs");
|
|
11
11
|
const operators_1 = require("rxjs/operators");
|
|
12
|
-
const utils_1 = require("../../utils");
|
|
13
12
|
const pointer_1 = require("./pointer");
|
|
14
13
|
function _getObjectSubSchema(schema, key) {
|
|
15
14
|
if (typeof schema !== 'object' || schema === null) {
|
|
@@ -46,9 +45,7 @@ root) {
|
|
|
46
45
|
}
|
|
47
46
|
}
|
|
48
47
|
const value = visitor(json, ptr, schema, root);
|
|
49
|
-
return (
|
|
50
|
-
? value
|
|
51
|
-
: rxjs_1.of(value)).pipe(operators_1.concatMap((value) => {
|
|
48
|
+
return (rxjs_1.isObservable(value) ? value : rxjs_1.of(value)).pipe(operators_1.concatMap(value => {
|
|
52
49
|
if (Array.isArray(value)) {
|
|
53
50
|
return rxjs_1.concat(rxjs_1.from(value).pipe(operators_1.mergeMap((item, i) => {
|
|
54
51
|
return _visitJsonRecursive(item, visitor, pointer_1.joinJsonPointer(ptr, '' + i), _getObjectSubSchema(schema, '' + i), refResolver, context, root || value).pipe(operators_1.tap(x => value[i] = x));
|
package/src/utils/lang.d.ts
CHANGED
|
@@ -12,5 +12,6 @@ import { Observable } from 'rxjs';
|
|
|
12
12
|
export declare function isPromise(obj: any): obj is Promise<any>;
|
|
13
13
|
/**
|
|
14
14
|
* Determine if the argument is an Observable
|
|
15
|
+
* @deprecated as of 8.0; use rxjs' built-in version
|
|
15
16
|
*/
|
|
16
17
|
export declare function isObservable(obj: any | Observable<any>): obj is Observable<any>;
|
package/src/utils/lang.js
CHANGED
package/src/workspace/core.d.ts
CHANGED
|
@@ -1,11 +1,54 @@
|
|
|
1
1
|
import { WorkspaceDefinition } from './definitions';
|
|
2
2
|
import { WorkspaceHost } from './host';
|
|
3
|
+
/**
|
|
4
|
+
* Supported workspace formats
|
|
5
|
+
*/
|
|
3
6
|
export declare enum WorkspaceFormat {
|
|
4
7
|
JSON = 0
|
|
5
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* @private
|
|
11
|
+
*/
|
|
6
12
|
export declare function _test_addWorkspaceFile(name: string, format: WorkspaceFormat): void;
|
|
13
|
+
/**
|
|
14
|
+
* @private
|
|
15
|
+
*/
|
|
7
16
|
export declare function _test_removeWorkspaceFile(name: string): void;
|
|
17
|
+
/**
|
|
18
|
+
* Reads and constructs a `WorkspaceDefinition`. If the function is provided with a path to a
|
|
19
|
+
* directory instead of a file, a search of the directory's files will commence to attempt to
|
|
20
|
+
* locate a known workspace file. Currently the following are considered known workspace files:
|
|
21
|
+
* - `angular.json`
|
|
22
|
+
* - `.angular.json`
|
|
23
|
+
*
|
|
24
|
+
* @param path The path to either a workspace file or a directory containing a workspace file.
|
|
25
|
+
* @param host The `WorkspaceHost` to use to access the file and directory data.
|
|
26
|
+
* @param format An optional `WorkspaceFormat` value. Used if the path specifies a non-standard
|
|
27
|
+
* file name that would prevent automatically discovering the format.
|
|
28
|
+
*
|
|
29
|
+
*
|
|
30
|
+
* @return An `Promise` of the read result object with the `WorkspaceDefinition` contained within
|
|
31
|
+
* the `workspace` property.
|
|
32
|
+
*/
|
|
8
33
|
export declare function readWorkspace(path: string, host: WorkspaceHost, format?: WorkspaceFormat): Promise<{
|
|
9
34
|
workspace: WorkspaceDefinition;
|
|
10
35
|
}>;
|
|
36
|
+
/**
|
|
37
|
+
* Writes a `WorkspaceDefinition` to the underlying storage via the provided `WorkspaceHost`.
|
|
38
|
+
* If the `WorkspaceDefinition` was created via the `readWorkspace` function, metadata will be
|
|
39
|
+
* used to determine the path and format of the Workspace. In all other cases, the `path` and
|
|
40
|
+
* `format` options must be specified as they would be otherwise unknown.
|
|
41
|
+
*
|
|
42
|
+
* @param workspace The `WorkspaceDefinition` that will be written.
|
|
43
|
+
* @param host The `WorkspaceHost` to use to access/write the file and directory data.
|
|
44
|
+
* @param path The path to a file location for the output. Required if `readWorkspace` was not
|
|
45
|
+
* used to create the `WorkspaceDefinition`. Optional otherwise; will override the
|
|
46
|
+
* `WorkspaceDefinition` metadata if provided.
|
|
47
|
+
* @param format The `WorkspaceFormat` to use for output. Required if `readWorkspace` was not
|
|
48
|
+
* used to create the `WorkspaceDefinition`. Optional otherwise; will override the
|
|
49
|
+
* `WorkspaceDefinition` metadata if provided.
|
|
50
|
+
*
|
|
51
|
+
*
|
|
52
|
+
* @return An `Promise` of type `void`.
|
|
53
|
+
*/
|
|
11
54
|
export declare function writeWorkspace(workspace: WorkspaceDefinition, host: WorkspaceHost, path?: string, format?: WorkspaceFormat): Promise<void>;
|
package/src/workspace/core.js
CHANGED
|
@@ -11,14 +11,23 @@ const virtual_fs_1 = require("../virtual-fs");
|
|
|
11
11
|
const reader_1 = require("./json/reader");
|
|
12
12
|
const writer_1 = require("./json/writer");
|
|
13
13
|
const formatLookup = new WeakMap();
|
|
14
|
+
/**
|
|
15
|
+
* Supported workspace formats
|
|
16
|
+
*/
|
|
14
17
|
var WorkspaceFormat;
|
|
15
18
|
(function (WorkspaceFormat) {
|
|
16
19
|
WorkspaceFormat[WorkspaceFormat["JSON"] = 0] = "JSON";
|
|
17
20
|
})(WorkspaceFormat = exports.WorkspaceFormat || (exports.WorkspaceFormat = {}));
|
|
21
|
+
/**
|
|
22
|
+
* @private
|
|
23
|
+
*/
|
|
18
24
|
function _test_addWorkspaceFile(name, format) {
|
|
19
25
|
workspaceFiles[name] = format;
|
|
20
26
|
}
|
|
21
27
|
exports._test_addWorkspaceFile = _test_addWorkspaceFile;
|
|
28
|
+
/**
|
|
29
|
+
* @private
|
|
30
|
+
*/
|
|
22
31
|
function _test_removeWorkspaceFile(name) {
|
|
23
32
|
delete workspaceFiles[name];
|
|
24
33
|
}
|
|
@@ -28,6 +37,22 @@ const workspaceFiles = {
|
|
|
28
37
|
'angular.json': WorkspaceFormat.JSON,
|
|
29
38
|
'.angular.json': WorkspaceFormat.JSON,
|
|
30
39
|
};
|
|
40
|
+
/**
|
|
41
|
+
* Reads and constructs a `WorkspaceDefinition`. If the function is provided with a path to a
|
|
42
|
+
* directory instead of a file, a search of the directory's files will commence to attempt to
|
|
43
|
+
* locate a known workspace file. Currently the following are considered known workspace files:
|
|
44
|
+
* - `angular.json`
|
|
45
|
+
* - `.angular.json`
|
|
46
|
+
*
|
|
47
|
+
* @param path The path to either a workspace file or a directory containing a workspace file.
|
|
48
|
+
* @param host The `WorkspaceHost` to use to access the file and directory data.
|
|
49
|
+
* @param format An optional `WorkspaceFormat` value. Used if the path specifies a non-standard
|
|
50
|
+
* file name that would prevent automatically discovering the format.
|
|
51
|
+
*
|
|
52
|
+
*
|
|
53
|
+
* @return An `Promise` of the read result object with the `WorkspaceDefinition` contained within
|
|
54
|
+
* the `workspace` property.
|
|
55
|
+
*/
|
|
31
56
|
async function readWorkspace(path, host, format) {
|
|
32
57
|
if (await host.isDirectory(path)) {
|
|
33
58
|
// TODO: Warn if multiple found (requires diagnostics support)
|
|
@@ -70,6 +95,24 @@ async function readWorkspace(path, host, format) {
|
|
|
70
95
|
return { workspace };
|
|
71
96
|
}
|
|
72
97
|
exports.readWorkspace = readWorkspace;
|
|
98
|
+
/**
|
|
99
|
+
* Writes a `WorkspaceDefinition` to the underlying storage via the provided `WorkspaceHost`.
|
|
100
|
+
* If the `WorkspaceDefinition` was created via the `readWorkspace` function, metadata will be
|
|
101
|
+
* used to determine the path and format of the Workspace. In all other cases, the `path` and
|
|
102
|
+
* `format` options must be specified as they would be otherwise unknown.
|
|
103
|
+
*
|
|
104
|
+
* @param workspace The `WorkspaceDefinition` that will be written.
|
|
105
|
+
* @param host The `WorkspaceHost` to use to access/write the file and directory data.
|
|
106
|
+
* @param path The path to a file location for the output. Required if `readWorkspace` was not
|
|
107
|
+
* used to create the `WorkspaceDefinition`. Optional otherwise; will override the
|
|
108
|
+
* `WorkspaceDefinition` metadata if provided.
|
|
109
|
+
* @param format The `WorkspaceFormat` to use for output. Required if `readWorkspace` was not
|
|
110
|
+
* used to create the `WorkspaceDefinition`. Optional otherwise; will override the
|
|
111
|
+
* `WorkspaceDefinition` metadata if provided.
|
|
112
|
+
*
|
|
113
|
+
*
|
|
114
|
+
* @return An `Promise` of type `void`.
|
|
115
|
+
*/
|
|
73
116
|
async function writeWorkspace(workspace, host, path, format) {
|
|
74
117
|
if (format === undefined) {
|
|
75
118
|
format = formatLookup.get(workspace);
|
package/src/workspace/host.js
CHANGED
|
@@ -19,7 +19,7 @@ function createWorkspaceHost(host) {
|
|
|
19
19
|
},
|
|
20
20
|
async isDirectory(path) {
|
|
21
21
|
try {
|
|
22
|
-
return host.isDirectory(virtual_fs_1.normalize(path)).toPromise();
|
|
22
|
+
return await host.isDirectory(virtual_fs_1.normalize(path)).toPromise();
|
|
23
23
|
}
|
|
24
24
|
catch (_a) {
|
|
25
25
|
// some hosts throw if path does not exist
|
|
@@ -28,7 +28,7 @@ function createWorkspaceHost(host) {
|
|
|
28
28
|
},
|
|
29
29
|
async isFile(path) {
|
|
30
30
|
try {
|
|
31
|
-
return host.isFile(virtual_fs_1.normalize(path)).toPromise();
|
|
31
|
+
return await host.isFile(virtual_fs_1.normalize(path)).toPromise();
|
|
32
32
|
}
|
|
33
33
|
catch (_a) {
|
|
34
34
|
// some hosts throw if path does not exist
|
|
@@ -23,6 +23,9 @@ class JsonWorkspaceMetadata {
|
|
|
23
23
|
for (let i = this.changes.length - 1; i >= 0; --i) {
|
|
24
24
|
const currentPath = this.changes[i].path;
|
|
25
25
|
if (currentPath === path || currentPath.startsWith(path + '/')) {
|
|
26
|
+
if (op === 'replace' && currentPath === path && this.changes[i].op === 'add') {
|
|
27
|
+
op = 'add';
|
|
28
|
+
}
|
|
26
29
|
this.changes.splice(i, 1);
|
|
27
30
|
}
|
|
28
31
|
}
|
|
@@ -37,7 +37,7 @@ function convertJsonWorkspace(workspace, schema) {
|
|
|
37
37
|
$schema: schema || './node_modules/@angular/cli/lib/config/schema.json',
|
|
38
38
|
version: 1,
|
|
39
39
|
...workspace.extensions,
|
|
40
|
-
projects: convertJsonProjectCollection(workspace.projects),
|
|
40
|
+
projects: workspace.projects ? convertJsonProjectCollection(workspace.projects) : {},
|
|
41
41
|
};
|
|
42
42
|
return obj;
|
|
43
43
|
}
|