angular-cli icon indicating copy to clipboard operation
angular-cli copied to clipboard

`Rule` from `@angular-devkit/schematics` should accept return type `Promise<Tree>`

Open Platonn opened this issue 2 years ago • 4 comments

🚀 Feature request

Rule from @angular-devkit/schematics should accept return type Promise<Tree>

Command (mark with an x)

  • [ ] new
  • [ ] build
  • [ ] serve
  • [ ] test
  • [ ] e2e
  • [ ] generate
  • [ ] add
  • [ ] update
  • [ ] lint
  • [ ] extract-i18n
  • [ ] run
  • [ ] config
  • [ ] help
  • [ ] version
  • [ ] doc
  • [x] other: compiling custom schematics that depend on @angular-devkit/schematics

Description

The interface Rule from @angular-devkit/schematics should accept the return type Promise<Tree> for asynchronous schematics. Now it only accepts Observable<Tree>: https://github.com/angular/angular-cli/blob/37a06a7c37f5b4286d58b475e6e12c86f00fac5b/packages/angular_devkit/schematics/src/engine/interface.ts#L234-L237

The current problem with Rule accepting only Observable<Tree> it that it accepts only the Observable from rxjs of a fixed version 6.6.7 (at the moment of writing) which is hardcoded in dependencies in package.json of @angular-devkit/schematics: https://github.com/angular/angular-cli/blob/c2737dd51ab68a538a317fc0d7a377032d346b53/packages/angular_devkit/schematics/package.json#L20

Therefore, if I'm writing custom schematics in my repo, while having any slightly different version of rxjs installed, e.g. 6.6.3, then I get an error about incompatible variants of the interface Subscriber - between my installed version in node_modules and the fixed version from node_modules/@angular-devkit/core/node_modules/rxjs (which is derived from the interface Rule)

Example of custom schematics for minimal reproduction:

import { Rule, Tree } from '@angular-devkit/schematics';
import { of } from 'rxjs';

export function migrate(): Rule {
  return (tree: Tree) => {
    return of(tree);
  };
}

The error message in detail:

(parameter) _context: SchematicContext
Type '(tree: Tree, _context: SchematicContext) => Observable<Tree>' is not assignable to type 'Rule'.
  Type 'Observable<Tree>' is not assignable to type 'void | Rule | Tree | Observable<Tree> | Promise<void | Rule>'.
    Type 'import("/Users/krzysztof/code/develop-ng13/node_modules/rxjs/internal/Observable").Observable<import("/Users/krzysztof/code/develop-ng13/node_modules/@angular-devkit/schematics/src/tree/interface").Tree>' is not assignable to type 'import("/Users/krzysztof/code/develop-ng13/node_modules/@angular-devkit/core/node_modules/rxjs/internal/Observable").Observable<import("/Users/krzysztof/code/develop-ng13/node_modules/@angular-devkit/schematics/src/tree/interface").Tree>'.
      The types of 'source.operator.call' are incompatible between these types.
        Type '(subscriber: import("/Users/krzysztof/code/develop-ng13/node_modules/rxjs/internal/Subscriber").Subscriber<any>, source: any) => import("/Users/krzysztof/code/develop-ng13/node_modules/rxjs/internal/types").TeardownLogic' is not assignable to type '(subscriber: import("/Users/krzysztof/code/develop-ng13/node_modules/@angular-devkit/core/node_modules/rxjs/internal/Subscriber").Subscriber<any>, source: any) => import("/Users/krzysztof/code/develop-ng13/node_modules/@angular-devkit/core/node_modules/rxjs/internal/types").TeardownLogic'.
          Types of parameters 'subscriber' and 'subscriber' are incompatible.
            Type 'import("/Users/krzysztof/code/develop-ng13/node_modules/@angular-devkit/core/node_modules/rxjs/internal/Subscriber").Subscriber<any>' is not assignable to type 'import("/Users/krzysztof/code/develop-ng13/node_modules/rxjs/internal/Subscriber").Subscriber<any>'.
              Property 'isStopped' is protected but type 'Subscriber<T>' is not a class derived from 'Subscriber<T>'.

Describe the solution you'd like

  • expose Promise<Tree> as a return type of Rule

Describe alternatives you've considered

  • workaround on my side: return Promise<Rule | void> instead of Promise<Tree>
  • workaround on Angular's side: move rxjs from dependencies to peerDependencies in package.json of @angular-devkit/schematics and relax the version to ^6.6.0 (but still.. what if somebody is using rxjs7 in their repo?)
  • I'm opened to your other suggested ideas or workarounds

Platonn avatar Mar 01 '22 15:03 Platonn

This feature request is now candidate for our backlog! In the next phase, the community has 60 days to upvote. If the request receives more than 20 upvotes, we'll move it to our consideration list.

You can find more details about the feature request process in our documentation.

angular-robot[bot] avatar Mar 02 '22 13:03 angular-robot[bot]

I'm currently working rxjs 7.5+ and my schematics build broke because of this dependency. It should have the rxjs peerDependency which supports both v6 and v7:

  "peerDependencies": {
    "rxjs": "^6.5.3 || ^7.4.0",
    "zone.js": "~0.11.4"
  },

Taken from @angular/[email protected] package.json

shaharkazaz avatar Mar 19 '22 11:03 shaharkazaz

Just a heads up that we kicked off a community voting process for your feature request. There are 20 days until the voting process ends.

Find more details about Angular's feature request process in our documentation.

angular-robot[bot] avatar Apr 10 '22 13:04 angular-robot[bot]

Taking a quick look at this, it seems that the problem is more with mismatch between the schematics' Observable type and the @angular-devkit/schematics Observable return type. Proper solution is probably to convert the return type to use Subscribable<T>, and separately we should maybe look into finding ways to dedupe RxJS dependencies in the project.

dgp1130 avatar Aug 11 '22 17:08 dgp1130