DEV Community

JWP
JWP

Posted on

4 1

Angular Library Folder Structures : Schematics

What if our library were to include a schematic?

Angular CLI: 9.0.7
Node: 12.14.1
OS: win32 x64

Angular: 9.0.7
... animations, cli, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router
Ivy Workspace: Yes

Package                            Version
------------------------------------------------------------
@angular-devkit/architect          0.900.7
@angular-devkit/build-angular      0.900.7
@angular-devkit/build-ng-packagr   0.900.7
@angular-devkit/build-optimizer    0.900.7
@angular-devkit/build-webpack      0.900.7
@angular-devkit/core               9.0.7
@angular-devkit/schematics         9.0.7  <= Must exist
@ngtools/webpack                   9.0.7
@schematics/angular                9.0.7
@schematics/update                 0.900.7
ng-packagr                         9.1.5
rxjs                               6.5.5
typescript                         3.7.5
webpack                            4.41.2
Enter fullscreen mode Exit fullscreen mode

We started...

cd projects
// this requires an environment variable 
// pointing to global node_modules bin folder
schematics blank --schematics --name=schematic

Enter fullscreen mode Exit fullscreen mode

Make sure the outer package.json file and the schematics.json have
same versioning.

Alt Text

Auto-Generated Code

Alt Text

ng build schematics
An unhandled exception occurred: Project 'schematics' does not support the 'build' target.
See "C:\src\AppData\Local\Temp\ng-WJqucJ\angular-errors.log" for further details.
Enter fullscreen mode Exit fullscreen mode

Set up a console.log

Alt Text

ng build schematics
{
  archtectCommand: {
    projectName: 'schematics',
    targetProjectNames: [ 'projecty', 'demo' ]
  }
}
// ok, the target project names does not include our schematics project.
// the angular.json file had no entry for this project!
Enter fullscreen mode Exit fullscreen mode

This doesn't work either

// moved it inside the library
C:\src\projectx\projects\projecty\src\lib> schematics blank --schematics --name=schematics
Enter fullscreen mode Exit fullscreen mode

Back Up

// we tried this command again in different folder.
// the same folder as first try
C:\src\projectx\projects> schematics blank --name=schematics
cd .\schematics
npm install
npm run build

Enter fullscreen mode Exit fullscreen mode

This worked because we were calling the build in the schematics folder, using npm instead of ng. But there was a compiler error.

src/schematics/index_spec.ts:12:25 - error TS2339: Property 'runSchematic' does not exist on type 'SchematicTestRunner'.

12     const tree = runner.runSchematic('schematics', {}, Tree.empty());
Enter fullscreen mode Exit fullscreen mode

Never argue with a compiler...

Alt Text
There it is; the new async version. This means the schematic itself is wrong... The angular/cli doesn't generate schematics correctly. Easy to fix.

Alt Text

This fixes the error:

import { Tree } from '@angular-devkit/schematics';
import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
import * as path from 'path';

const collectionPath = path.join(__dirname, '../collection.json');


describe('schematics', () => {
  it('works', async() => {
    const runner = new SchematicTestRunner('schematics', collectionPath);
    const tree = await runner.runSchematicAsync('schematics', {}, Tree.empty());
    tree.subscribe(tree=>{
      console.log(tree);
      expect(tree.files).toEqual([]);
    });

  });

});

Enter fullscreen mode Exit fullscreen mode

Our first glimpse into a schematic tree!

UnitTestTree {
  _other: HostTree {
    _backend: Empty { capabilities: [Object] },
    _id: -1,
    _ancestry: Set {},
    _dirCache: Map {},
    _record: CordHost {
      _cache: [Map],
      _watchers: Map {},
      _back: [SafeReadonlyHost],
      _filesToCreate: Set {},
      _filesToRename: Map {},
      _filesToRenameRevert: Map {},
      _filesToDelete: Set {},
      _filesToOverwrite: Set {}
    },
    _recordSync: SyncDelegateHost { _delegate: [CordHost] }
  }
Enter fullscreen mode Exit fullscreen mode

Top comments (2)

Collapse
 
xiongemi profile image
Emily Xiong • Edited

I think this code snippet will not render. you need either add toPromise() to the runSchematicAsync:

describe('schematics', () => {
  it('works', async() => {
    const runner = new SchematicTestRunner('schematics', collectionPath);
    const tree = await runner.runSchematicAsync('schematics', {}, Tree.empty()).toPromise();
    expect(tree.files).toEqual([]);
  });
Enter fullscreen mode Exit fullscreen mode

or remove async/await:

it('works', () => {
    const runner = new SchematicTestRunner('schematics', collectionPath);
    const tree = runner.runSchematicAsync('schematics', {}, Tree.empty());
    tree.subscribe(tree=>{
      console.log(tree);
      expect(tree.files).toEqual([]);
    });
  });
Enter fullscreen mode Exit fullscreen mode
Collapse
 
jangelodev profile image
João Angelo

Hi John Peters,
Your tips are very useful
Thanks for sharing

typescript

11 Tips That Make You a Better Typescript Programmer

1 Think in {Set}

Type is an everyday concept to programmers, but it’s surprisingly difficult to define it succinctly. I find it helpful to use Set as a conceptual model instead.

#2 Understand declared type and narrowed type

One extremely powerful typescript feature is automatic type narrowing based on control flow. This means a variable has two types associated with it at any specific point of code location: a declaration type and a narrowed type.

#3 Use discriminated union instead of optional fields

...

Read the whole post now!