@angular-devkit/build-angular 0.1101.0-next.3 → 0.1101.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/package.json +25 -25
- package/src/babel/babel-loader.d.ts +24 -0
- package/src/babel/presets/application.d.ts +2 -1
- package/src/babel/presets/application.js +30 -0
- package/src/babel/webpack-loader.d.ts +2 -0
- package/src/babel/webpack-loader.js +114 -0
- package/src/browser/index.js +3 -4
- package/src/browser/schema.d.ts +9 -6
- package/src/browser/schema.json +4 -4
- package/src/browser/tests/setup.d.ts +18 -0
- package/src/browser/tests/setup.js +20 -0
- package/src/dev-server/schema.d.ts +9 -8
- package/src/dev-server/schema.json +4 -4
- package/src/extract-i18n/index.js +24 -1
- package/src/extract-i18n/schema.d.ts +2 -0
- package/src/extract-i18n/schema.js +2 -0
- package/src/extract-i18n/schema.json +6 -2
- package/src/karma/schema.d.ts +4 -2
- package/src/karma/schema.json +1 -1
- package/src/server/index.js +1 -1
- package/src/server/schema.d.ts +6 -4
- package/src/server/schema.json +2 -2
- package/src/testing/builder-harness.d.ts +50 -0
- package/src/testing/builder-harness.js +307 -0
- package/src/testing/file-watching.d.ts +19 -0
- package/src/testing/file-watching.js +34 -0
- package/src/testing/index.d.ts +9 -0
- package/src/testing/index.js +5 -0
- package/src/testing/jasmine-helpers.d.ts +26 -0
- package/src/testing/jasmine-helpers.js +86 -0
- package/src/utils/build-options.d.ts +2 -2
- package/src/utils/load-translations.js +3 -0
- package/src/utils/webpack-browser-config.js +12 -2
- package/src/webpack/configs/browser.js +1 -1
- package/src/webpack/configs/common.js +14 -30
- package/src/webpack/configs/styles.js +6 -0
- package/src/webpack/es5-polyfills.js +7 -0
- package/src/webpack/plugins/builder-watch-plugin.d.ts +51 -0
- package/src/webpack/plugins/builder-watch-plugin.js +103 -0
- package/src/webpack/plugins/karma.d.ts +0 -7
- package/src/webpack/plugins/karma.js +14 -23
package/src/karma/schema.d.ts
CHANGED
|
@@ -65,7 +65,8 @@ export interface Schema {
|
|
|
65
65
|
*/
|
|
66
66
|
scripts?: ExtraEntryPoint[];
|
|
67
67
|
/**
|
|
68
|
-
* Output source maps.
|
|
68
|
+
* Output source maps for scripts and styles. For more information, see
|
|
69
|
+
* https://angular.io/guide/workspace-config#source-map-configuration.
|
|
69
70
|
*/
|
|
70
71
|
sourceMap?: SourceMapUnion;
|
|
71
72
|
/**
|
|
@@ -130,7 +131,8 @@ export interface ExtraEntryPointClass {
|
|
|
130
131
|
input: string;
|
|
131
132
|
}
|
|
132
133
|
/**
|
|
133
|
-
* Output source maps.
|
|
134
|
+
* Output source maps for scripts and styles. For more information, see
|
|
135
|
+
* https://angular.io/guide/workspace-config#source-map-configuration.
|
|
134
136
|
*/
|
|
135
137
|
export declare type SourceMapUnion = boolean | SourceMapClass;
|
|
136
138
|
export interface SourceMapClass {
|
package/src/karma/schema.json
CHANGED
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"description": "Globs of files to include, relative to workspace or project root. \nThere are 2 special cases:\n - when a path to directory is provided, all spec files ending \".spec.@(ts|tsx)\" will be included\n - when a path to a file is provided, and a matching spec file exists it will be included instead"
|
|
68
68
|
},
|
|
69
69
|
"sourceMap": {
|
|
70
|
-
"description": "Output source maps.",
|
|
70
|
+
"description": "Output source maps for scripts and styles. For more information, see https://angular.io/guide/workspace-config#source-map-configuration.",
|
|
71
71
|
"default": true,
|
|
72
72
|
"oneOf": [
|
|
73
73
|
{
|
package/src/server/index.js
CHANGED
|
@@ -44,7 +44,7 @@ function execute(options, context, transforms = {}) {
|
|
|
44
44
|
context.logger.warn(core_1.tags.stripIndent `
|
|
45
45
|
Warning: Turning off 'bundleDependencies' with Ivy may result in undefined behaviour
|
|
46
46
|
unless 'node_modules' are transformed using the standalone Angular compatibility compiler (NGCC).
|
|
47
|
-
See:
|
|
47
|
+
See: https://angular.io/guide/ivy#ivy-and-universal-app-shell
|
|
48
48
|
`);
|
|
49
49
|
}
|
|
50
50
|
}
|
package/src/server/schema.d.ts
CHANGED
|
@@ -70,7 +70,7 @@ export interface Schema {
|
|
|
70
70
|
/**
|
|
71
71
|
* Enables optimization of the build output. Including minification of scripts and styles,
|
|
72
72
|
* tree-shaking and dead-code elimination. For more information, see
|
|
73
|
-
* https://angular.io/guide/workspace-config#optimization-
|
|
73
|
+
* https://angular.io/guide/workspace-config#optimization-configuration.
|
|
74
74
|
*/
|
|
75
75
|
optimization?: OptimizationUnion;
|
|
76
76
|
/**
|
|
@@ -103,7 +103,8 @@ export interface Schema {
|
|
|
103
103
|
*/
|
|
104
104
|
showCircularDependencies?: boolean;
|
|
105
105
|
/**
|
|
106
|
-
* Output source maps.
|
|
106
|
+
* Output source maps for scripts and styles. For more information, see
|
|
107
|
+
* https://angular.io/guide/workspace-config#source-map-configuration.
|
|
107
108
|
*/
|
|
108
109
|
sourceMap?: SourceMapUnion;
|
|
109
110
|
/**
|
|
@@ -158,7 +159,7 @@ export declare type Localize = string[] | boolean;
|
|
|
158
159
|
/**
|
|
159
160
|
* Enables optimization of the build output. Including minification of scripts and styles,
|
|
160
161
|
* tree-shaking and dead-code elimination. For more information, see
|
|
161
|
-
* https://angular.io/guide/workspace-config#optimization-
|
|
162
|
+
* https://angular.io/guide/workspace-config#optimization-configuration.
|
|
162
163
|
*/
|
|
163
164
|
export declare type OptimizationUnion = boolean | OptimizationClass;
|
|
164
165
|
export interface OptimizationClass {
|
|
@@ -181,7 +182,8 @@ export declare enum OutputHashing {
|
|
|
181
182
|
None = "none"
|
|
182
183
|
}
|
|
183
184
|
/**
|
|
184
|
-
* Output source maps.
|
|
185
|
+
* Output source maps for scripts and styles. For more information, see
|
|
186
|
+
* https://angular.io/guide/workspace-config#source-map-configuration.
|
|
185
187
|
*/
|
|
186
188
|
export declare type SourceMapUnion = boolean | SourceMapClass;
|
|
187
189
|
export interface SourceMapClass {
|
package/src/server/schema.json
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"additionalProperties": false
|
|
30
30
|
},
|
|
31
31
|
"optimization": {
|
|
32
|
-
"description": "Enables optimization of the build output. Including minification of scripts and styles, tree-shaking and dead-code elimination. For more information, see https://angular.io/guide/workspace-config#optimization-
|
|
32
|
+
"description": "Enables optimization of the build output. Including minification of scripts and styles, tree-shaking and dead-code elimination. For more information, see https://angular.io/guide/workspace-config#optimization-configuration.",
|
|
33
33
|
"x-user-analytics": 16,
|
|
34
34
|
"default": false,
|
|
35
35
|
"oneOf": [
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"default": ""
|
|
73
73
|
},
|
|
74
74
|
"sourceMap": {
|
|
75
|
-
"description": "Output source maps.",
|
|
75
|
+
"description": "Output source maps for scripts and styles. For more information, see https://angular.io/guide/workspace-config#source-map-configuration.",
|
|
76
76
|
"default": true,
|
|
77
77
|
"oneOf": [
|
|
78
78
|
{
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright Google Inc. All Rights Reserved.
|
|
5
|
+
*
|
|
6
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
7
|
+
* found in the LICENSE file at https://angular.io/license
|
|
8
|
+
*/
|
|
9
|
+
import { BuilderHandlerFn, BuilderInfo, BuilderOutput } from '@angular-devkit/architect';
|
|
10
|
+
import { TestProjectHost } from '@angular-devkit/architect/testing';
|
|
11
|
+
import { json, logging } from '@angular-devkit/core';
|
|
12
|
+
import { Observable } from 'rxjs';
|
|
13
|
+
export interface BuilderHarnessExecutionResult<T extends BuilderOutput = BuilderOutput> {
|
|
14
|
+
result?: T;
|
|
15
|
+
error?: Error;
|
|
16
|
+
logs: readonly logging.LogEntry[];
|
|
17
|
+
}
|
|
18
|
+
export interface BuilderHarnessExecutionOptions {
|
|
19
|
+
configuration: string;
|
|
20
|
+
outputLogsOnFailure: boolean;
|
|
21
|
+
outputLogsOnException: boolean;
|
|
22
|
+
useNativeFileWatching: boolean;
|
|
23
|
+
}
|
|
24
|
+
export declare class BuilderHarness<T> {
|
|
25
|
+
private readonly builderHandler;
|
|
26
|
+
private readonly host;
|
|
27
|
+
private readonly builderInfo;
|
|
28
|
+
private schemaRegistry;
|
|
29
|
+
private projectName;
|
|
30
|
+
private projectMetadata;
|
|
31
|
+
private targetName?;
|
|
32
|
+
private options;
|
|
33
|
+
private builderTargets;
|
|
34
|
+
private watcherNotifier?;
|
|
35
|
+
constructor(builderHandler: BuilderHandlerFn<T & json.JsonObject>, host: TestProjectHost, builderInfo?: Partial<BuilderInfo>);
|
|
36
|
+
useProject(name: string, metadata?: Record<string, unknown>): this;
|
|
37
|
+
useTarget(name: string, baseOptions: T): this;
|
|
38
|
+
withConfiguration(configuration: string, options: T): this;
|
|
39
|
+
withBuilderTarget<O>(target: string, handler: BuilderHandlerFn<O & json.JsonObject>, options?: O, info?: Partial<BuilderInfo>): this;
|
|
40
|
+
execute(options?: Partial<BuilderHarnessExecutionOptions>): Observable<BuilderHarnessExecutionResult>;
|
|
41
|
+
executeOnce(options?: Partial<BuilderHarnessExecutionOptions>): Promise<BuilderHarnessExecutionResult>;
|
|
42
|
+
appendToFile(path: string, content: string): Promise<void>;
|
|
43
|
+
writeFile(path: string, content: string | Buffer): Promise<void>;
|
|
44
|
+
writeFiles(files: Record<string, string | Buffer>): Promise<void>;
|
|
45
|
+
removeFile(path: string): Promise<void>;
|
|
46
|
+
modifyFile(path: string, modifier: (content: string) => string | Promise<string>): Promise<void>;
|
|
47
|
+
hasFile(path: string): boolean;
|
|
48
|
+
readFile(path: string): string;
|
|
49
|
+
private validateProjectName;
|
|
50
|
+
}
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BuilderHarness = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* @license
|
|
6
|
+
* Copyright Google Inc. All Rights Reserved.
|
|
7
|
+
*
|
|
8
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
9
|
+
* found in the LICENSE file at https://angular.io/license
|
|
10
|
+
*/
|
|
11
|
+
const architect_1 = require("@angular-devkit/architect");
|
|
12
|
+
const core_1 = require("@angular-devkit/core");
|
|
13
|
+
const rxjs_1 = require("rxjs");
|
|
14
|
+
const operators_1 = require("rxjs/operators");
|
|
15
|
+
const file_watching_1 = require("./file-watching");
|
|
16
|
+
class BuilderHarness {
|
|
17
|
+
constructor(builderHandler, host, builderInfo) {
|
|
18
|
+
this.builderHandler = builderHandler;
|
|
19
|
+
this.host = host;
|
|
20
|
+
this.schemaRegistry = new core_1.json.schema.CoreSchemaRegistry();
|
|
21
|
+
this.projectName = 'test';
|
|
22
|
+
this.projectMetadata = { root: '.', sourceRoot: 'src' };
|
|
23
|
+
this.options = new Map();
|
|
24
|
+
this.builderTargets = new Map();
|
|
25
|
+
// Generate default pseudo builder info for test purposes
|
|
26
|
+
this.builderInfo = {
|
|
27
|
+
builderName: builderHandler.name,
|
|
28
|
+
description: '',
|
|
29
|
+
optionSchema: true,
|
|
30
|
+
...builderInfo,
|
|
31
|
+
};
|
|
32
|
+
this.schemaRegistry.addPostTransform(core_1.json.schema.transforms.addUndefinedDefaults);
|
|
33
|
+
}
|
|
34
|
+
useProject(name, metadata = {}) {
|
|
35
|
+
if (!name) {
|
|
36
|
+
throw new Error('Project name cannot be an empty string.');
|
|
37
|
+
}
|
|
38
|
+
this.projectName = name;
|
|
39
|
+
this.projectMetadata = metadata;
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
useTarget(name, baseOptions) {
|
|
43
|
+
if (!name) {
|
|
44
|
+
throw new Error('Target name cannot be an empty string.');
|
|
45
|
+
}
|
|
46
|
+
this.targetName = name;
|
|
47
|
+
this.options.set(null, baseOptions);
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
withConfiguration(configuration, options) {
|
|
51
|
+
this.options.set(configuration, options);
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
withBuilderTarget(target, handler, options, info) {
|
|
55
|
+
this.builderTargets.set(target, {
|
|
56
|
+
handler,
|
|
57
|
+
options: options || {},
|
|
58
|
+
info: { builderName: handler.name, description: '', optionSchema: true, ...info },
|
|
59
|
+
});
|
|
60
|
+
return this;
|
|
61
|
+
}
|
|
62
|
+
execute(options = {}) {
|
|
63
|
+
var _a;
|
|
64
|
+
const { configuration, outputLogsOnException = true, outputLogsOnFailure = true, useNativeFileWatching = false, } = options;
|
|
65
|
+
const targetOptions = {
|
|
66
|
+
...this.options.get(null),
|
|
67
|
+
...((_a = (configuration && this.options.get(configuration))) !== null && _a !== void 0 ? _a : {}),
|
|
68
|
+
};
|
|
69
|
+
if (!useNativeFileWatching) {
|
|
70
|
+
if (this.watcherNotifier) {
|
|
71
|
+
throw new Error('Only one harness execution at a time is supported.');
|
|
72
|
+
}
|
|
73
|
+
this.watcherNotifier = new file_watching_1.WatcherNotifier();
|
|
74
|
+
}
|
|
75
|
+
const contextHost = {
|
|
76
|
+
findBuilderByTarget: async (project, target) => {
|
|
77
|
+
this.validateProjectName(project);
|
|
78
|
+
if (target === this.targetName) {
|
|
79
|
+
return {
|
|
80
|
+
info: this.builderInfo,
|
|
81
|
+
handler: this.builderHandler,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const builderTarget = this.builderTargets.get(target);
|
|
85
|
+
if (builderTarget) {
|
|
86
|
+
return { info: builderTarget.info, handler: builderTarget.handler };
|
|
87
|
+
}
|
|
88
|
+
throw new Error('Project target does not exist.');
|
|
89
|
+
},
|
|
90
|
+
async getBuilderName(project, target) {
|
|
91
|
+
return (await this.findBuilderByTarget(project, target)).info.builderName;
|
|
92
|
+
},
|
|
93
|
+
getMetadata: async (project) => {
|
|
94
|
+
this.validateProjectName(project);
|
|
95
|
+
return this.projectMetadata;
|
|
96
|
+
},
|
|
97
|
+
getOptions: async (project, target, configuration) => {
|
|
98
|
+
var _a, _b;
|
|
99
|
+
this.validateProjectName(project);
|
|
100
|
+
if (target === this.targetName) {
|
|
101
|
+
return (_a = this.options.get(configuration !== null && configuration !== void 0 ? configuration : null)) !== null && _a !== void 0 ? _a : {};
|
|
102
|
+
}
|
|
103
|
+
else if (configuration !== undefined) {
|
|
104
|
+
// Harness builder targets currently do not support configurations
|
|
105
|
+
return {};
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
return ((_b = this.builderTargets.get(target)) === null || _b === void 0 ? void 0 : _b.options) || {};
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
hasTarget: async (project, target) => {
|
|
112
|
+
this.validateProjectName(project);
|
|
113
|
+
return this.targetName === target || this.builderTargets.has(target);
|
|
114
|
+
},
|
|
115
|
+
validate: async (options, builderName) => {
|
|
116
|
+
let schema;
|
|
117
|
+
if (builderName === this.builderInfo.builderName) {
|
|
118
|
+
schema = this.builderInfo.optionSchema;
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
for (const [, value] of this.builderTargets) {
|
|
122
|
+
if (value.info.builderName === builderName) {
|
|
123
|
+
schema = value.info.optionSchema;
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const validator = await this.schemaRegistry.compile(schema !== null && schema !== void 0 ? schema : true).toPromise();
|
|
129
|
+
const { data } = await validator(options).toPromise();
|
|
130
|
+
return data;
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
const context = new HarnessBuilderContext(this.builderInfo, core_1.getSystemPath(this.host.root()), contextHost, useNativeFileWatching ? undefined : this.watcherNotifier);
|
|
134
|
+
if (this.targetName !== undefined) {
|
|
135
|
+
context.target = {
|
|
136
|
+
project: this.projectName,
|
|
137
|
+
target: this.targetName,
|
|
138
|
+
configuration: configuration,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
const logs = [];
|
|
142
|
+
context.logger.subscribe((e) => logs.push(e));
|
|
143
|
+
return this.schemaRegistry.compile(this.builderInfo.optionSchema).pipe(operators_1.mergeMap((validator) => validator(targetOptions)), operators_1.map((validationResult) => validationResult.data), operators_1.mergeMap((data) => convertBuilderOutputToObservable(this.builderHandler(data, context))), operators_1.map((buildResult) => ({ result: buildResult, error: undefined })), operators_1.catchError((error) => {
|
|
144
|
+
if (outputLogsOnException) {
|
|
145
|
+
// tslint:disable-next-line: no-console
|
|
146
|
+
console.error(logs.map((entry) => entry.message).join('\n'));
|
|
147
|
+
// tslint:disable-next-line: no-console
|
|
148
|
+
console.error(error);
|
|
149
|
+
}
|
|
150
|
+
return rxjs_1.of({ result: undefined, error });
|
|
151
|
+
}), operators_1.map(({ result, error }) => {
|
|
152
|
+
if (outputLogsOnFailure && (result === null || result === void 0 ? void 0 : result.success) === false && logs.length > 0) {
|
|
153
|
+
// tslint:disable-next-line: no-console
|
|
154
|
+
console.error(logs.map((entry) => entry.message).join('\n'));
|
|
155
|
+
}
|
|
156
|
+
// Capture current logs and clear for next
|
|
157
|
+
const currentLogs = logs.slice();
|
|
158
|
+
logs.length = 0;
|
|
159
|
+
return { result, error, logs: currentLogs };
|
|
160
|
+
}), operators_1.finalize(() => {
|
|
161
|
+
this.watcherNotifier = undefined;
|
|
162
|
+
for (const teardown of context.teardowns) {
|
|
163
|
+
teardown();
|
|
164
|
+
}
|
|
165
|
+
}));
|
|
166
|
+
}
|
|
167
|
+
async executeOnce(options) {
|
|
168
|
+
// Return the first result
|
|
169
|
+
return this.execute(options).pipe(operators_1.first()).toPromise();
|
|
170
|
+
}
|
|
171
|
+
async appendToFile(path, content) {
|
|
172
|
+
await this.writeFile(path, this.readFile(path).concat(content));
|
|
173
|
+
}
|
|
174
|
+
async writeFile(path, content) {
|
|
175
|
+
var _a;
|
|
176
|
+
this.host
|
|
177
|
+
.scopedSync()
|
|
178
|
+
.write(core_1.normalize(path), typeof content === 'string' ? Buffer.from(content) : content);
|
|
179
|
+
(_a = this.watcherNotifier) === null || _a === void 0 ? void 0 : _a.notify([
|
|
180
|
+
{ path: core_1.getSystemPath(core_1.join(this.host.root(), path)), type: 'modified' },
|
|
181
|
+
]);
|
|
182
|
+
}
|
|
183
|
+
async writeFiles(files) {
|
|
184
|
+
var _a;
|
|
185
|
+
const watchEvents = this.watcherNotifier
|
|
186
|
+
? []
|
|
187
|
+
: undefined;
|
|
188
|
+
for (const [path, content] of Object.entries(files)) {
|
|
189
|
+
this.host
|
|
190
|
+
.scopedSync()
|
|
191
|
+
.write(core_1.normalize(path), typeof content === 'string' ? Buffer.from(content) : content);
|
|
192
|
+
watchEvents === null || watchEvents === void 0 ? void 0 : watchEvents.push({ path: core_1.getSystemPath(core_1.join(this.host.root(), path)), type: 'modified' });
|
|
193
|
+
}
|
|
194
|
+
if (watchEvents) {
|
|
195
|
+
(_a = this.watcherNotifier) === null || _a === void 0 ? void 0 : _a.notify(watchEvents);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
async removeFile(path) {
|
|
199
|
+
var _a;
|
|
200
|
+
this.host.scopedSync().delete(core_1.normalize(path));
|
|
201
|
+
(_a = this.watcherNotifier) === null || _a === void 0 ? void 0 : _a.notify([
|
|
202
|
+
{ path: core_1.getSystemPath(core_1.join(this.host.root(), path)), type: 'deleted' },
|
|
203
|
+
]);
|
|
204
|
+
}
|
|
205
|
+
async modifyFile(path, modifier) {
|
|
206
|
+
var _a;
|
|
207
|
+
const content = this.readFile(path);
|
|
208
|
+
await this.writeFile(path, await modifier(content));
|
|
209
|
+
(_a = this.watcherNotifier) === null || _a === void 0 ? void 0 : _a.notify([
|
|
210
|
+
{ path: core_1.getSystemPath(core_1.join(this.host.root(), path)), type: 'modified' },
|
|
211
|
+
]);
|
|
212
|
+
}
|
|
213
|
+
hasFile(path) {
|
|
214
|
+
return this.host.scopedSync().exists(core_1.normalize(path));
|
|
215
|
+
}
|
|
216
|
+
readFile(path) {
|
|
217
|
+
const content = this.host.scopedSync().read(core_1.normalize(path));
|
|
218
|
+
return Buffer.from(content).toString('utf8');
|
|
219
|
+
}
|
|
220
|
+
validateProjectName(name) {
|
|
221
|
+
if (name !== this.projectName) {
|
|
222
|
+
throw new Error(`Project "${name}" does not exist.`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
exports.BuilderHarness = BuilderHarness;
|
|
227
|
+
class HarnessBuilderContext {
|
|
228
|
+
constructor(builder, basePath, contextHost, watcherFactory) {
|
|
229
|
+
this.builder = builder;
|
|
230
|
+
this.contextHost = contextHost;
|
|
231
|
+
this.watcherFactory = watcherFactory;
|
|
232
|
+
this.id = Math.trunc(Math.random() * 1000000);
|
|
233
|
+
this.logger = new core_1.logging.Logger(`builder-harness-${this.id}`);
|
|
234
|
+
this.teardowns = [];
|
|
235
|
+
this.workspaceRoot = this.currentDirectory = basePath;
|
|
236
|
+
}
|
|
237
|
+
get analytics() {
|
|
238
|
+
// Can be undefined even though interface does not allow it
|
|
239
|
+
return undefined;
|
|
240
|
+
}
|
|
241
|
+
addTeardown(teardown) {
|
|
242
|
+
this.teardowns.push(teardown);
|
|
243
|
+
}
|
|
244
|
+
async getBuilderNameForTarget(target) {
|
|
245
|
+
return this.contextHost.getBuilderName(target.project, target.target);
|
|
246
|
+
}
|
|
247
|
+
async getProjectMetadata(targetOrName) {
|
|
248
|
+
const project = typeof targetOrName === 'string' ? targetOrName : targetOrName.project;
|
|
249
|
+
return this.contextHost.getMetadata(project);
|
|
250
|
+
}
|
|
251
|
+
async getTargetOptions(target) {
|
|
252
|
+
return this.contextHost.getOptions(target.project, target.target, target.configuration);
|
|
253
|
+
}
|
|
254
|
+
// Unused by builders in this package
|
|
255
|
+
async scheduleBuilder(builderName, options, scheduleOptions) {
|
|
256
|
+
throw new Error('Not Implemented.');
|
|
257
|
+
}
|
|
258
|
+
async scheduleTarget(target, overrides, scheduleOptions) {
|
|
259
|
+
const { info, handler } = await this.contextHost.findBuilderByTarget(target.project, target.target);
|
|
260
|
+
const targetOptions = await this.validateOptions({
|
|
261
|
+
...(await this.getTargetOptions(target)),
|
|
262
|
+
...overrides,
|
|
263
|
+
}, info.builderName);
|
|
264
|
+
const context = new HarnessBuilderContext(info, this.workspaceRoot, this.contextHost, this.watcherFactory);
|
|
265
|
+
context.target = target;
|
|
266
|
+
context.logger = (scheduleOptions === null || scheduleOptions === void 0 ? void 0 : scheduleOptions.logger) || this.logger.createChild('');
|
|
267
|
+
const progressSubject = new rxjs_1.Subject();
|
|
268
|
+
const output = convertBuilderOutputToObservable(handler(targetOptions, context));
|
|
269
|
+
const run = {
|
|
270
|
+
id: context.id,
|
|
271
|
+
info,
|
|
272
|
+
progress: progressSubject.asObservable(),
|
|
273
|
+
async stop() {
|
|
274
|
+
for (const teardown of context.teardowns) {
|
|
275
|
+
await teardown();
|
|
276
|
+
}
|
|
277
|
+
progressSubject.complete();
|
|
278
|
+
},
|
|
279
|
+
output: output.pipe(operators_1.shareReplay()),
|
|
280
|
+
get result() {
|
|
281
|
+
return this.output.pipe(operators_1.first()).toPromise();
|
|
282
|
+
},
|
|
283
|
+
};
|
|
284
|
+
return run;
|
|
285
|
+
}
|
|
286
|
+
async validateOptions(options, builderName) {
|
|
287
|
+
return this.contextHost.validate(options, builderName);
|
|
288
|
+
}
|
|
289
|
+
// Unused report methods
|
|
290
|
+
reportRunning() { }
|
|
291
|
+
reportStatus() { }
|
|
292
|
+
reportProgress() { }
|
|
293
|
+
}
|
|
294
|
+
function isAsyncIterable(obj) {
|
|
295
|
+
return !!obj && typeof obj[Symbol.asyncIterator] === 'function';
|
|
296
|
+
}
|
|
297
|
+
function convertBuilderOutputToObservable(output) {
|
|
298
|
+
if (architect_1.isBuilderOutput(output)) {
|
|
299
|
+
return rxjs_1.of(output);
|
|
300
|
+
}
|
|
301
|
+
else if (isAsyncIterable(output)) {
|
|
302
|
+
return architect_1.fromAsyncIterable(output);
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
return rxjs_1.from(output);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
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 { BuilderWatcherCallback, BuilderWatcherFactory } from '../webpack/plugins/builder-watch-plugin';
|
|
9
|
+
export declare class WatcherNotifier implements BuilderWatcherFactory {
|
|
10
|
+
private readonly descriptors;
|
|
11
|
+
notify(events: Iterable<{
|
|
12
|
+
path: string;
|
|
13
|
+
type: 'modified' | 'deleted';
|
|
14
|
+
}>): void;
|
|
15
|
+
watch(files: Iterable<string>, directories: Iterable<string>, callback: BuilderWatcherCallback): {
|
|
16
|
+
close(): void;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export { BuilderWatcherFactory };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WatcherNotifier = void 0;
|
|
4
|
+
class WatcherDescriptor {
|
|
5
|
+
constructor(files, directories, callback) {
|
|
6
|
+
this.files = files;
|
|
7
|
+
this.directories = directories;
|
|
8
|
+
this.callback = callback;
|
|
9
|
+
}
|
|
10
|
+
shouldNotify(path) {
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
class WatcherNotifier {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.descriptors = new Set();
|
|
17
|
+
}
|
|
18
|
+
notify(events) {
|
|
19
|
+
for (const descriptor of this.descriptors) {
|
|
20
|
+
for (const { path } of events) {
|
|
21
|
+
if (descriptor.shouldNotify(path)) {
|
|
22
|
+
descriptor.callback([...events]);
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
watch(files, directories, callback) {
|
|
29
|
+
const descriptor = new WatcherDescriptor(new Set(files), new Set(directories), callback);
|
|
30
|
+
this.descriptors.add(descriptor);
|
|
31
|
+
return { close: () => this.descriptors.delete(descriptor) };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.WatcherNotifier = WatcherNotifier;
|
|
@@ -0,0 +1,9 @@
|
|
|
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 { BuilderHarnessExecutionOptions, BuilderHarnessExecutionResult } from './builder-harness';
|
|
9
|
+
export { HarnessFileMatchers, describeBuilder } from './jasmine-helpers';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.describeBuilder = void 0;
|
|
4
|
+
var jasmine_helpers_1 = require("./jasmine-helpers");
|
|
5
|
+
Object.defineProperty(exports, "describeBuilder", { enumerable: true, get: function () { return jasmine_helpers_1.describeBuilder; } });
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/// <reference types="jasmine" />
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright Google Inc. All Rights Reserved.
|
|
5
|
+
*
|
|
6
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
7
|
+
* found in the LICENSE file at https://angular.io/license
|
|
8
|
+
*/
|
|
9
|
+
import { BuilderHandlerFn } from '@angular-devkit/architect';
|
|
10
|
+
import { json } from '@angular-devkit/core';
|
|
11
|
+
import { BuilderHarness } from './builder-harness';
|
|
12
|
+
export declare function describeBuilder<T>(builderHandler: BuilderHandlerFn<T & json.JsonObject>, options: {
|
|
13
|
+
name?: string;
|
|
14
|
+
schemaPath: string;
|
|
15
|
+
}, specDefinitions: (harness: JasmineBuilderHarness<T>) => void): void;
|
|
16
|
+
declare class JasmineBuilderHarness<T> extends BuilderHarness<T> {
|
|
17
|
+
expectFile(path: string): HarnessFileMatchers;
|
|
18
|
+
}
|
|
19
|
+
export interface HarnessFileMatchers {
|
|
20
|
+
toExist(): boolean;
|
|
21
|
+
toNotExist(): boolean;
|
|
22
|
+
readonly content: jasmine.ArrayLikeMatchers<string>;
|
|
23
|
+
readonly size: jasmine.Matchers<number>;
|
|
24
|
+
}
|
|
25
|
+
export declare function expectFile<T>(path: string, harness: BuilderHarness<T>): HarnessFileMatchers;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.expectFile = exports.describeBuilder = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const test_utils_1 = require("../test-utils");
|
|
6
|
+
const builder_harness_1 = require("./builder-harness");
|
|
7
|
+
const optionSchemaCache = new Map();
|
|
8
|
+
function describeBuilder(builderHandler, options, specDefinitions) {
|
|
9
|
+
let optionSchema = optionSchemaCache.get(options.schemaPath);
|
|
10
|
+
if (optionSchema === undefined) {
|
|
11
|
+
optionSchema = JSON.parse(fs_1.readFileSync(options.schemaPath, 'utf8'));
|
|
12
|
+
optionSchemaCache.set(options.schemaPath, optionSchema);
|
|
13
|
+
}
|
|
14
|
+
const harness = new JasmineBuilderHarness(builderHandler, test_utils_1.host, {
|
|
15
|
+
builderName: options.name,
|
|
16
|
+
optionSchema,
|
|
17
|
+
});
|
|
18
|
+
describe(options.name || builderHandler.name, () => {
|
|
19
|
+
beforeEach(() => test_utils_1.host.initialize().toPromise());
|
|
20
|
+
afterEach(() => test_utils_1.host.restore().toPromise());
|
|
21
|
+
specDefinitions(harness);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
exports.describeBuilder = describeBuilder;
|
|
25
|
+
class JasmineBuilderHarness extends builder_harness_1.BuilderHarness {
|
|
26
|
+
expectFile(path) {
|
|
27
|
+
return expectFile(path, this);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Add a Jasmine expectation filter to an expectation that always fails with a message.
|
|
32
|
+
* @param base The base expectation (`expect(...)`) to use.
|
|
33
|
+
* @param message The message to provide in the expectation failure.
|
|
34
|
+
*/
|
|
35
|
+
function createFailureExpectation(base, message) {
|
|
36
|
+
// Needed typings are not included in the Jasmine types
|
|
37
|
+
const expectation = base;
|
|
38
|
+
expectation.expector = expectation.expector.addFilter({
|
|
39
|
+
selectComparisonFunc() {
|
|
40
|
+
return () => ({
|
|
41
|
+
pass: false,
|
|
42
|
+
message,
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
return expectation;
|
|
47
|
+
}
|
|
48
|
+
function expectFile(path, harness) {
|
|
49
|
+
return {
|
|
50
|
+
toExist() {
|
|
51
|
+
const exists = harness.hasFile(path);
|
|
52
|
+
expect(exists).toBe(true, 'Expected file to exist: ' + path);
|
|
53
|
+
return exists;
|
|
54
|
+
},
|
|
55
|
+
toNotExist() {
|
|
56
|
+
const exists = harness.hasFile(path);
|
|
57
|
+
expect(exists).toBe(false, 'Expected file to not exist: ' + path);
|
|
58
|
+
return !exists;
|
|
59
|
+
},
|
|
60
|
+
get content() {
|
|
61
|
+
try {
|
|
62
|
+
return expect(harness.readFile(path)).withContext(`With file content for '${path}'`);
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
if (e.code !== 'ENOENT') {
|
|
66
|
+
throw e;
|
|
67
|
+
}
|
|
68
|
+
// File does not exist so always fail the expectation
|
|
69
|
+
return createFailureExpectation(expect(''), `Expected file content but file does not exist: '${path}'`);
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
get size() {
|
|
73
|
+
try {
|
|
74
|
+
return expect(Buffer.byteLength(harness.readFile(path))).withContext(`With file size for '${path}'`);
|
|
75
|
+
}
|
|
76
|
+
catch (e) {
|
|
77
|
+
if (e.code !== 'ENOENT') {
|
|
78
|
+
throw e;
|
|
79
|
+
}
|
|
80
|
+
// File does not exist so always fail the expectation
|
|
81
|
+
return createFailureExpectation(expect(0), `Expected file size but file does not exist: '${path}'`);
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
exports.expectFile = expectFile;
|
|
@@ -68,7 +68,7 @@ export interface BuildOptions {
|
|
|
68
68
|
fileReplacements: NormalizedFileReplacement[];
|
|
69
69
|
experimentalRollupPass?: boolean;
|
|
70
70
|
allowedCommonJsDependencies?: string[];
|
|
71
|
-
|
|
71
|
+
differentialLoadingNeeded?: boolean;
|
|
72
72
|
}
|
|
73
73
|
export interface WebpackTestOptions extends BuildOptions {
|
|
74
74
|
codeCoverage?: boolean;
|
|
@@ -84,5 +84,5 @@ export interface WebpackConfigOptions<T = BuildOptions> {
|
|
|
84
84
|
buildOptions: T;
|
|
85
85
|
tsConfig: ParsedConfiguration;
|
|
86
86
|
tsConfigPath: string;
|
|
87
|
-
|
|
87
|
+
scriptTarget: import('typescript').ScriptTarget;
|
|
88
88
|
}
|
|
@@ -51,6 +51,9 @@ async function importParsers() {
|
|
|
51
51
|
const localizeDiag = await Promise.resolve().then(() => require('@angular/localize/src/tools/src/diagnostics'));
|
|
52
52
|
const diagnostics = new localizeDiag.Diagnostics();
|
|
53
53
|
const parsers = {
|
|
54
|
+
arb: new (await Promise.resolve().then(() => require(
|
|
55
|
+
// tslint:disable-next-line:trailing-comma
|
|
56
|
+
'@angular/localize/src/tools/src/translate/translation_files/translation_parsers/arb_translation_parser'))).ArbTranslationParser(),
|
|
54
57
|
json: new (await Promise.resolve().then(() => require(
|
|
55
58
|
// tslint:disable-next-line:trailing-comma
|
|
56
59
|
'@angular/localize/src/tools/src/translate/translation_files/translation_parsers/simple_json_translation_parser'))).SimpleJsonTranslationParser(),
|