angular / angular-cli

CLI tool for Angular
https://cli.angular.dev
MIT License
26.78k stars 11.98k forks source link

Schematic with multi select x-promt errors when using command line parameter: 'path ".foo" should be array' #16320

Open d-koppenhagen opened 4 years ago

d-koppenhagen commented 4 years ago

🐞 Bug report

Command (mark with an x)

Is this a regression?

No, it's not. Multi select prompt is just supported within angular cli > 9.0.0-rc.3.

Description

Creating an angular schematic that prompts the user for multiple options is possible since https://github.com/angular/angular-cli/issues/16104. The prompt works quite good now but using the command line for multi selections will cause an error:

Error: Schematic input does not validate against the Schema: {"name":"paul"}
Errors:

  Data path ".name" should be array.
...

At first I opened an issue for the docs because I thought it's just not documented: https://github.com/angular/angular/issues/33851 But after checking the implementation of the angular guard schematic which has --implements parameter (which works) and creating the minimal reproduction repo (see underneath), I think it's a bug somewhere in @angular-devkit/schematics-cli.

πŸ”¬ Minimal Reproduction

I created a very minimal repo for reproduction: https://github.com/d-koppenhagen/ngx-multi-select-schematic

npm i -g @angular-devkit/schematics-cli@next
git clone git@github.com:d-koppenhagen/ngx-multi-select-schematic.git
cd ngx-multi-select-schematic
npm i

βœ… Using prompt works good:

schematics .:hello --debug=false
? Which interfaces would you like to implement? (Press <space> to select, <a> to toggle all, <
i> to invert selection)
❯◉ hans
 β—‰ peter
 β—‰ paul
schematics .:hello --debug=false --name="paul, peter"

❌Using command line parameter fails (event not with just a single name handed over:

schematics .:hello --debug=false --name="paul"
Error: Schematic input does not validate against the Schema: {"name":"paul"}
Errors:

  Data path ".name" should be array.
    at MapSubscriber.registry.compile.pipe.operators_1.map.result [as project] (/usr/local/lib/node_modules/@angular-devkit/schematics-cli/node_modules/@angular-devkit/schematics/tools/schema-option-transform.js:31:27)
    at MapSubscriber._next (/usr/local/lib/node_modules/@angular-devkit/schematics-cli/node_modules/rxjs/internal/operators/map.js:49:35)
    at MapSubscriber.Subscriber.next (/usr/local/lib/node_modules/@angular-devkit/schematics-cli/node_modules/rxjs/internal/Subscriber.js:66:18)
    at ThrowIfEmptySubscriber._next (/usr/local/lib/node_modules/@angular-devkit/schematics-cli/node_modules/rxjs/internal/operators/throwIfEmpty.js:44:26)
    at ThrowIfEmptySubscriber.Subscriber.next (/usr/local/lib/node_modules/@angular-devkit/schematics-cli/node_modules/rxjs/internal/Subscriber.js:66:18)
    at TakeSubscriber._next (/usr/local/lib/node_modules/@angular-devkit/schematics-cli/node_modules/rxjs/internal/operators/take.js:54:30)
    at TakeSubscriber.Subscriber.next (/usr/local/lib/node_modules/@angular-devkit/schematics-cli/node_modules/rxjs/internal/Subscriber.js:66:18)
    at MergeMapSubscriber.notifyNext (/usr/local/lib/node_modules/@angular-devkit/schematics-cli/node_modules/rxjs/internal/operators/mergeMap.js:92:26)
    at InnerSubscriber._next (/usr/local/lib/node_modules/@angular-devkit/schematics-cli/node_modules/rxjs/internal/InnerSubscriber.js:28:21)
    at InnerSubscriber.Subscriber.next (/usr/local/lib/node_modules/@angular-devkit/schematics-cli/node_modules/rxjs/internal/Subscriber.js:66:18)

πŸ”₯ Exception or Error

Error: Schematic input does not validate against the Schema: {"name":"paul"}
Errors:

  Data path ".name" should be array.
    at MapSubscriber.registry.compile.pipe.operators_1.map.result [as project] (/usr/local/lib/node_modules/@angular-devkit/schematics-cli/node_modules/@angular-devkit/schematics/tools/schema-option-transform.js:31:27)
    at MapSubscriber._next (/usr/local/lib/node_modules/@angular-devkit/schematics-cli/node_modules/rxjs/internal/operators/map.js:49:35)
    at MapSubscriber.Subscriber.next (/usr/local/lib/node_modules/@angular-devkit/schematics-cli/node_modules/rxjs/internal/Subscriber.js:66:18)
    at ThrowIfEmptySubscriber._next (/usr/local/lib/node_modules/@angular-devkit/schematics-cli/node_modules/rxjs/internal/operators/throwIfEmpty.js:44:26)
    at ThrowIfEmptySubscriber.Subscriber.next (/usr/local/lib/node_modules/@angular-devkit/schematics-cli/node_modules/rxjs/internal/Subscriber.js:66:18)
    at TakeSubscriber._next (/usr/local/lib/node_modules/@angular-devkit/schematics-cli/node_modules/rxjs/internal/operators/take.js:54:30)
    at TakeSubscriber.Subscriber.next (/usr/local/lib/node_modules/@angular-devkit/schematics-cli/node_modules/rxjs/internal/Subscriber.js:66:18)
    at MergeMapSubscriber.notifyNext (/usr/local/lib/node_modules/@angular-devkit/schematics-cli/node_modules/rxjs/internal/operators/mergeMap.js:92:26)
    at InnerSubscriber._next (/usr/local/lib/node_modules/@angular-devkit/schematics-cli/node_modules/rxjs/internal/InnerSubscriber.js:28:21)
    at InnerSubscriber.Subscriber.next (/usr/local/lib/node_modules/@angular-devkit/schematics-cli/node_modules/rxjs/internal/Subscriber.js:66:18)

🌍 Your Environment


ng version
     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / β–³ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/

Angular CLI: 9.0.0-rc.4
Node: 10.14.0
OS: darwin x64

Angular: undefined
... 
Ivy Workspace: Yes

Package                      Version
------------------------------------------------------
@angular-devkit/architect    0.900.0-rc.4 (cli-only)
@angular-devkit/core         9.0.0-rc.4
@angular-devkit/schematics   9.0.0-rc.4
@schematics/angular          9.0.0-rc.4 (cli-only)
@schematics/update           0.900.0-rc.4 (cli-only)
rxjs                         6.5.3
typescript                   3.6.4
alan-agius4 commented 4 years ago

This is somewhat related to https://github.com/angular/angular-cli/issues/12150 but in this case it's for Array's

d-koppenhagen commented 4 years ago

It seems that the cause of this error is somewhere in validateOptionsWithSchema: https://github.com/angular/angular-cli/blob/fd6bba38a008c6ff89584c3edf8ff5ab326f51d1/packages/angular_devkit/schematics/tools/schema-option-transform.ts#L43 InvalidInputOptions seems to be called with an object of {"name":"paul"} instead of: {"name":["paul"]}

d-koppenhagen commented 4 years ago

hey @alan-agius4 do you think this issue will be faced before releasing Angular 10? I tried to understand the implementation and would like to contribute but I didn't find out how to debug it until now ^^

d-koppenhagen commented 4 years ago

@alan-agius4 sorry, I meant Angular 9 in the above comment.

alan-agius4 commented 4 years ago

@d-koppenhagen, currently this is not a top priority for the team.

d-koppenhagen commented 4 years ago

@alan-agius4 I see. Meanwhile I dounf out how to debug and install the CLI locally. I found the place where the error occurs. I provided a PR (https://github.com/angular/angular-cli/pull/16985) to fix it.

alan-agius4 commented 4 years ago

I don’t think that PR addresses the above issue. In the above issue you are using schematics CLI, however the fix is for Angular CLI.

d-koppenhagen commented 4 years ago

Yes that’s true. But with the fix and building the CLI locally, the described issue doesn’t appear. So I think it will fix it indeed.

d-koppenhagen commented 4 years ago

In the issue I just use the schematics CLI during the schematics development. But in the end I will run the schematic with the Angular CLI using ng add.

Badisi commented 3 years ago

For anyone interested, the current workaround works for me:

schematics .:hello --debug=false --name=paul --name=peter

(tested with Angular CLI: 11.2.12)

Platonn commented 5 months ago

Same problem

(We're using Angular CLI v17.3.8)

We're having the same problem in our open source library Spartacus, when our users run our installation schematics (ng add) with a command line option --features that has a type: array. See the following screenshot:

image

Workaround: first npm-install; then ng-add

Interestingly, the error doesn't happen at all, if I first manually npm-install the pacakge and only then run the same ng add command (with array) option.

Why the problem seems to happen

The problem of mis-interpreting the command-line option as a string instead of array seems to occur, because the anticipated schema.json of our package (which informs that a flag --features is type: array) is not known at the time of parsing the command-line arguments.

As far as I could NodeJS-debug the whole process, AngularCLI command ng add seems to work in the following way:

  1. first it parses the command-line arguments early, without knowing the schema.json of the package that we're going to add
  2. then it npm-installs the package (which means also downloading its schema.json)
  3. then it validates lately if the parsed command-line arguments match the expected type defined in the downloaded schema.json

Above workaround doesn't work when passing the exact version ⚠️

The above mentioned workaround (i.e. first npm-installing the package before running ng add) doesn't work, when I pass the exact version of my package in the ng add command. See the following screenshot:

image

Our plan to resign from type: array

We plan to resign from using type: array (as it seems to be a bug in Angular that we cannot fix ourselves) and use type: string with comma-separated values by convention, e.g. --features="Cart, Order, Checkout". Then in the logic of our installation schematics, we plan to split the strings by comas and therefore have an array effectively.

Idea for a fix in Angular?

@alan-agius4 Do you think AngularCLI could re-parse the command line arguments lately, i.e. after the added package is already npm-installed, so the schema.json of the added package (informing which params are type:array) is really taken into account?

Platonn commented 5 months ago

Hi @alan-agius4 If possible, I'd happy to provide a PR with a fix. My proposed approach is to re-parse the CLI arguments after the package is npm-installed so to we could use the package's precise schema.json for determining properly the types of arguments (e.g. array instead of string).

TBH I'd need a bit of an advice, how we could possibly workaround the limitations of the current architecture. Let me share my understanding of the current architecture:

Do you have any idea of a workaround how we could re-parse the raw CLI arguments (i.e. invoke this.addSchemaOptionsToCommand() in the run() function, after npm-installing a package but before executing the schematics? Thanks to this, we could pass properly interpreted options object to the executed schematics (e.g. --features=foo --features=bar parsed to an array features: ['foo', 'bar'], instead of a string features: 'bar').