Skip to content

Commit 0623f4f

Browse files
Merge pull request #185 from angular/master
Don't skip children with script source attached
2 parents 9998801 + 91cf2d7 commit 0623f4f

File tree

31 files changed

+579
-86
lines changed

31 files changed

+579
-86
lines changed

bin/schematics

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@
1111

1212
require('../lib/bootstrap-local');
1313
const packages = require('../lib/packages').packages;
14-
require(packages['@angular-devkit/schematics-cli'].bin['schematics']);
14+
require(packages['@angular-devkit/schematics-cli'].bin['schematics']).main({ args: process.argv.slice(2) });
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# Schematic Prompts
2+
3+
Schematic prompts provide the ability to introduce user interaction into the schematic execution. The schematic runtime supports the ability to allow schematic options to be configured to display a customizable question to the user and then use the response as the value for the option. These prompts are displayed before the execution of the schematic. This allows users direct the operation of the schematic without requiring indepth knowledge of the full spectrum of options available to the user.
4+
5+
To enable this capability, the JSON Schema used to define the schematic's options supports extensions to allow the declarative definition of the prompts and their respective behavior. No additional logic or changes are required to the JavaScript for a schematic to support the prompts.
6+
7+
## Basic Usage
8+
9+
To illustrate the addition of a prompt to an existing schematic the following example JSON schema for a hypothetical _hello world_ schematic will be used.
10+
11+
```json
12+
{
13+
"properties": {
14+
"name": {
15+
"type": "string",
16+
"minLength": 1,
17+
"default": "world"
18+
},
19+
"useColor": {
20+
"type": "boolean"
21+
}
22+
}
23+
}
24+
```
25+
26+
Suppose it would be preferred if the user was asked for their name. This can be accomplished by augmenting the `name` property definition with an `x-prompt` field.
27+
```json
28+
"x-prompt": "What is your name?"
29+
```
30+
In most cases, only the text of the prompt is required. To minimize the amount of necessary configuration, the above _shorthand_ form is supported and will typically be all that is required. Full details regarding the _longhand_ form can be found in the **Configuration Reference** section.
31+
32+
Adding a prompt to allow the user to decided whether the schematic will use color when executing its hello action is also very similar. The schema with both prompts would be as follows:
33+
```json
34+
{
35+
"properties": {
36+
"name": {
37+
"type": "string",
38+
"minLength": 1,
39+
"default": "world",
40+
"x-prompt": "What is your name?"
41+
},
42+
"useColor": {
43+
"type": "boolean",
44+
"x-prompt": "Would you like the response in color?"
45+
}
46+
}
47+
}
48+
```
49+
50+
Prompts have several different types which provide the ability to display an input method that best represents the schematic option's potential values.
51+
52+
* `confirmation` - A **yes** or **no** question; ideal for boolean options
53+
* `input` - textual input; ideal for string or number options
54+
* `list` - a predefined set of items which may be selected
55+
56+
When using the _shorthand_ form, the most appropriate type will automatically be selected based on the property's schema. In the example, the `name` prompt will use an `input` type because it it is a `string` property. The `useColor` prompt will use a `confirmation` type because it is a boolean property with `yes` corresponding to `true` and `no` corresponding to `false`.
57+
58+
It is also important that the response from the user conforms to the contraints of the property. By specifying constraints using the JSON schema, the prompt runtime will automatically validate the response provided by the user. If the value is not acceptable, the user will be asked to enter a new value. This ensures that any values passed to the schematic will meet the expectations of the schematic's implementation and removes the need to add additional checks within the schematic's code.
59+
60+
## Configuration Reference
61+
62+
The `x-prompt` field supports two alternatives to enable a prompt for a schematic option. A shorthand form when additional customization is not required and a longhand form providing the ability for more control over the prompt. All user responses are validated against the property's schema. For example, string type properties can use a minimum length or regular expression constraint to control the allowed values. In the event the response fails validation, the user will be asked to enter a new value.
63+
64+
### Longhand Form
65+
66+
In the this form, the `x-prompt` field is an object with subfields that can be used to customize the behavior of the prompt. Note that some fields only apply to specific prompt types.
67+
68+
| Field | Data Value | Default |
69+
|-|-|-|
70+
| `type` | `confirmation`, `input`, `list` | see shorthand section for details
71+
| `message` | string | N/A (required)
72+
| `items` | string and/or `label`/`value` object pair | only valid with type `list`
73+
74+
75+
### Shorthand Form
76+
77+
`x-prompt` [type: string] --> Question to display to the user.
78+
79+
For this usage, the type of the prompt is determined by the type of the containing property.
80+
81+
| Property Schema | Prompt Type | Notes |
82+
|-|:-:|:-:|
83+
| `"type": "boolean"` | `confirmation` | |
84+
| `"type": "string"` | `input` | |
85+
| `"type": "number"` | `input` | only valid numbers accepted |
86+
| `"type": "integer"` | `input` | only valid numbers accepted |
87+
| `"enum": [...]` | `list` | enum members become list selections
88+
89+
### `x-prompt` Schema
90+
91+
```json
92+
{
93+
"oneOf": [
94+
{ "type": "string" },
95+
{
96+
"type": "object",
97+
"properties": {
98+
"type": { "type": "string" },
99+
"message": { "type": "string" },
100+
"items": {
101+
"type": "array",
102+
"items": {
103+
"oneOf": [
104+
{ "type": "string" },
105+
{
106+
"type": "object",
107+
"properties": {
108+
"label": { "type": "string" },
109+
"value": { }
110+
},
111+
"required": [ "value" ]
112+
}
113+
]
114+
}
115+
}
116+
},
117+
"required": [ "message" ]
118+
}
119+
]
120+
}
121+
```

packages/angular/cli/commands/config-impl.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
} from '@angular-devkit/core';
1919
import { writeFileSync } from 'fs';
2020
import { Command } from '../models/command';
21-
import { Arguments } from '../models/interface';
21+
import { Arguments, CommandScope } from '../models/interface';
2222
import {
2323
getWorkspace,
2424
getWorkspaceRaw,
@@ -178,6 +178,10 @@ export class ConfigCommand extends Command<ConfigCommandSchema> {
178178
public async run(options: ConfigCommandSchema & Arguments) {
179179
const level = options.global ? 'global' : 'local';
180180

181+
if (!options.global) {
182+
await this.validateScope(CommandScope.InProject);
183+
}
184+
181185
let config =
182186
(getWorkspace(level) as {} as { _workspace: experimental.workspace.WorkspaceSchema });
183187

packages/angular/cli/commands/config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"$longDescription": "",
66

77
"$aliases": [],
8-
"$scope": "in",
8+
"$scope": "all",
99
"$type": "native",
1010
"$impl": "./config-impl#ConfigCommand",
1111

packages/angular/cli/models/command.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,8 @@ export abstract class Command<T extends BaseCommandOptions = BaseCommandOptions>
114114
}
115115
}
116116

117-
async validateScope(): Promise<void> {
118-
switch (this.description.scope) {
117+
async validateScope(scope?: CommandScope): Promise<void> {
118+
switch (scope === undefined ? this.description.scope : scope) {
119119
case CommandScope.OutProject:
120120
if (this.workspace.configFile) {
121121
this.logger.fatal(tags.oneLine`

packages/angular/cli/upgrade/version.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ export class Version {
182182
183183
Please run the following command to install a compatible version of TypeScript.
184184
185-
npm install typescript@'${currentCombo.typescript}'
185+
npm install typescript@"${currentCombo.typescript}"
186186
187187
To disable this warning run "ng config cli.warnings.typescriptMismatch false".
188188
` + '\n')));

packages/angular_devkit/build_angular/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"karma-source-map-support": "1.3.0",
2525
"less": "3.8.1",
2626
"less-loader": "4.1.0",
27-
"license-webpack-plugin": "1.4.0",
27+
"license-webpack-plugin": "2.0.1",
2828
"loader-utils": "1.1.0",
2929
"mini-css-extract-plugin": "0.4.3",
3030
"minimatch": "3.0.4",
Lines changed: 8 additions & 0 deletions
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+
import 'core-js/es7/reflect';

packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/browser.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,10 @@ export function getBrowserConfig(wco: WebpackConfigOptions) {
7979

8080
if (buildOptions.extractLicenses) {
8181
extraPlugins.push(new LicenseWebpackPlugin({
82-
pattern: /.*/,
83-
suppressErrors: true,
82+
stats: {
83+
warnings: false,
84+
errors: false
85+
},
8486
perChunkOutput: false,
8587
outputFilename: `3rdpartylicenses.txt`
8688
}));

packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ export function getCommonConfig(wco: WebpackConfigOptions) {
6262
entryPoints['polyfills'] = [path.resolve(root, buildOptions.polyfills)];
6363
}
6464

65+
if (!buildOptions.aot) {
66+
entryPoints['polyfills'] = [
67+
...(entryPoints['polyfills'] || []),
68+
path.join(__dirname, '..', 'jit-polyfills.js'),
69+
];
70+
}
71+
6572
// determine hashing format
6673
const hashFormat = getOutputHashFormat(buildOptions.outputHashing as any);
6774

packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/typescript.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ export function getAotConfig(
110110
});
111111
}
112112

113-
const test = /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/;
113+
const test = /(?:\.ngfactory\.js|\.ngstyle\.js|\.tsx?)$/;
114114

115115
return {
116116
module: { rules: [{ test, use: loaders }] },

packages/angular_devkit/core/src/virtual-fs/host/memory.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ export class SimpleMemoryHost implements Host<{}> {
180180
path = this._toAbsolute(path);
181181
if (this._isDirectory(path)) {
182182
for (const [cachePath] of this._cache.entries()) {
183-
if (path.startsWith(cachePath + NormalizedSep)) {
183+
if (cachePath.startsWith(path + NormalizedSep) || cachePath === path) {
184184
this._cache.delete(cachePath);
185185
}
186186
}

packages/angular_devkit/core/src/virtual-fs/host/memory_spec.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,22 @@ describe('SimpleMemoryHost', () => {
6565
expect(host.exists(normalize('/sub/file1'))).toBe(false);
6666
});
6767

68+
it('can delete directory', () => {
69+
const host = new SyncDelegateHost(new SimpleMemoryHost());
70+
71+
const buffer = stringToFileBuffer('hello');
72+
73+
expect(host.exists(normalize('/sub/file1'))).toBe(false);
74+
host.write(normalize('/sub/file1'), buffer);
75+
host.write(normalize('/subfile.2'), buffer);
76+
expect(host.exists(normalize('/sub/file1'))).toBe(true);
77+
expect(host.exists(normalize('/subfile.2'))).toBe(true);
78+
host.delete(normalize('/sub'));
79+
expect(host.exists(normalize('/sub/file1'))).toBe(false);
80+
expect(host.exists(normalize('/sub'))).toBe(false);
81+
expect(host.exists(normalize('/subfile.2'))).toBe(true);
82+
});
83+
6884
it('can rename', () => {
6985
const host = new SyncDelegateHost(new SimpleMemoryHost());
7086

0 commit comments

Comments
 (0)