Angular Library Folder Structures : Schematics
Tags: angular, typescript
Published: 2020-06-28 16:42:26

What if our library were to include a [schematic](https://angular.io/?search=schematics)?

```
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
```
 
We started...

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

```

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

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/csaf65ds17fpljdauydu.png)

**Auto-Generated Code**

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/abpnfkivdisxdxz0we9v.png)

```
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.
```

**Set up a console.log**

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/y1k4b9h86tbuq989cqh4.png)

```
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!
```

This doesn't work either

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

**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

```
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());
```

Never argue with a compiler...

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/gsg3vkydkug47yllzdze.png)
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](https://dev-to-uploads.s3.amazonaws.com/i/k1cei307rmulhseys79o.png)

This fixes the error:

```typescript
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([]);
    });
      
  });

});

```
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] }
  }
```