Skip to content

Commit 586ecc0

Browse files
authored
Merge pull request #12 from TinkoffCreditSystems/ng-morph-tree
Ng morph tree
2 parents d81d5a4 + 0744ec1 commit 586ecc0

File tree

6 files changed

+83
-19
lines changed

6 files changed

+83
-19
lines changed

libs/ng-morph/project/classes/devkit-file-system.ts

+9-9
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import { DirectoryEntry, FileSystem } from './file-system';
2323
export class DevkitFileSystem extends FileSystem {
2424
private _updateRecorderCache = new Map<string, UpdateRecorder>();
2525

26-
constructor(private _tree: Tree) {
26+
constructor(readonly tree: Tree) {
2727
super();
2828
}
2929

@@ -36,13 +36,13 @@ export class DevkitFileSystem extends FileSystem {
3636
if (this._updateRecorderCache.has(filePath)) {
3737
return this._updateRecorderCache.get(filePath) as UpdateRecorder;
3838
}
39-
const recorder = this._tree.beginUpdate(filePath);
39+
const recorder = this.tree.beginUpdate(filePath);
4040
this._updateRecorderCache.set(filePath, recorder);
4141
return recorder;
4242
}
4343

4444
commitEdits() {
45-
this._updateRecorderCache.forEach((r) => this._tree.commitUpdate(r));
45+
this._updateRecorderCache.forEach((r) => this.tree.commitUpdate(r));
4646
this._updateRecorderCache.clear();
4747
}
4848

@@ -51,7 +51,7 @@ export class DevkitFileSystem extends FileSystem {
5151
// directory exists. It throws a specific error though if a directory
5252
// is being read as a file. We use that to check if a directory exists.
5353
try {
54-
return this._tree.get(fileOrDirPath) !== null;
54+
return this.tree.get(fileOrDirPath) !== null;
5555
} catch (e) {
5656
if (e instanceof PathIsDirectoryException) {
5757
return true;
@@ -61,25 +61,25 @@ export class DevkitFileSystem extends FileSystem {
6161
}
6262

6363
overwrite(filePath: Path, content: string) {
64-
this._tree.overwrite(filePath, content);
64+
this.tree.overwrite(filePath, content);
6565
}
6666

6767
create(filePath: Path, content: string) {
68-
this._tree.create(filePath, content);
68+
this.tree.create(filePath, content);
6969
}
7070

7171
delete(filePath: Path) {
72-
this._tree.delete(filePath);
72+
this.tree.delete(filePath);
7373
}
7474

7575
read(filePath: Path) {
76-
const buffer = this._tree.read(filePath);
76+
const buffer = this.tree.read(filePath);
7777
return buffer !== null ? buffer.toString() : null;
7878
}
7979

8080
readDirectory(dirPath: Path): DirectoryEntry {
8181
try {
82-
const { subdirs: directories, subfiles: files } = this._tree.getDir(
82+
const { subdirs: directories, subfiles: files } = this.tree.getDir(
8383
dirPath
8484
);
8585
return { directories, files };

libs/ng-morph/project/classes/file-system.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { UpdateRecorder } from './update-recorder';
1010
import { FileSystemHost } from 'ts-morph';
1111
import { basename, join } from 'path';
1212
import * as miltimatch from 'multimatch';
13+
import { DevkitFileSystem } from './devkit-file-system';
1314

1415
/**
1516
* A workspace path semantically is equivalent to the `Path` type provided by the
@@ -87,7 +88,7 @@ export abstract class FileSystem {
8788
}
8889

8990
export class NgCliFileSystem implements FileSystemHost {
90-
constructor(public fs: FileSystem) {}
91+
constructor(public fs: DevkitFileSystem) {}
9192

9293
async copy(srcPath: string, destPath: string): Promise<void> {
9394
this.copySync(srcPath, destPath);

libs/ng-morph/project/classes/ng-cli-project.ts

+19
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Project } from 'ts-morph';
22
import { NgCliProjectOptions } from '../types/ng-cli-project-options';
33
import { DevkitFileSystem } from './devkit-file-system';
44
import { NgCliFileSystem } from './file-system';
5+
import { NgMorphTree } from './ng-morph-tree';
56

67
export class NgCliProject extends Project {
78
constructor({ host, ...options }: NgCliProjectOptions) {
@@ -14,4 +15,22 @@ export class NgCliProject extends Project {
1415
getFileSystem(): NgCliFileSystem {
1516
return super.getFileSystem() as NgCliFileSystem;
1617
}
18+
19+
async save(): Promise<void> {
20+
await super.save();
21+
await this.trySaveTree();
22+
}
23+
24+
saveSync() {
25+
super.saveSync();
26+
this.trySaveTree();
27+
}
28+
29+
private async trySaveTree(): Promise<void> {
30+
const tree = this.getFileSystem().fs.tree;
31+
32+
if (tree instanceof NgMorphTree) {
33+
return tree.commitChanges();
34+
}
35+
}
1736
}

libs/ng-morph/project/classes/ng-morph-tree.spec.ts

+39-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
import { Tree } from '@angular-devkit/schematics';
2-
import { NgMorphTree } from 'ng-morph/project/classes/ng-morph-tree';
3-
import { createProject, setActiveProject } from 'ng-morph/project';
4-
import { getSourceFile } from 'ng-morph/source-file';
2+
import { NgMorphTree } from './ng-morph-tree';
3+
import {
4+
createProject,
5+
saveActiveProject,
6+
setActiveProject,
7+
} from 'ng-morph/project';
8+
import { createSourceFile, getSourceFile } from 'ng-morph/source-file';
9+
import * as fs from 'fs';
10+
import { join } from 'path';
511

612
describe('NgMorphTree', () => {
713
let tree: Tree;
@@ -18,16 +24,44 @@ describe('NgMorphTree', () => {
1824

1925
it('should read from fs', () => {
2026
expect(getSourceFile('/ng-morph-tree.ts')?.getFullText())
21-
.toStrictEqual(`import { HostTree } from '@angular-devkit/schematics';
27+
.toStrictEqual(`import { HostSink, HostTree } from '@angular-devkit/schematics';
2228
import { ScopedHost } from '@angular-devkit/core/src/virtual-fs/host';
2329
import { NodeJsSyncHost } from '@angular-devkit/core/node';
2430
import { normalize } from '@angular-devkit/core';
2531
2632
export class NgMorphTree extends HostTree {
33+
private hostSink: HostSink;
34+
2735
constructor(root: string = process.cwd()) {
28-
super(new ScopedHost(new NodeJsSyncHost(), normalize(root)));
36+
const host = new ScopedHost(new NodeJsSyncHost(), normalize(root));
37+
super(host);
38+
39+
this.hostSink = new HostSink(host);
40+
}
41+
42+
commitChanges(): Promise<void> {
43+
return this.hostSink.commit(this).toPromise();
2944
}
3045
}
3146
`);
3247
});
48+
49+
it('should write to fs', () => {
50+
createSourceFile('__file.ts', `content`, { overwrite: true });
51+
52+
const spy = jest.spyOn(fs, 'writeFileSync');
53+
54+
spy.mockImplementationOnce(() => {
55+
// empty
56+
});
57+
58+
saveActiveProject();
59+
60+
expect(spy).toHaveBeenCalledWith(
61+
join(__dirname, '__file.ts'),
62+
Uint8Array.from([99, 111, 110, 116, 101, 110, 116])
63+
);
64+
65+
spy.mockRestore();
66+
});
3367
});
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
1-
import { HostTree } from '@angular-devkit/schematics';
1+
import { HostSink, HostTree } from '@angular-devkit/schematics';
22
import { ScopedHost } from '@angular-devkit/core/src/virtual-fs/host';
33
import { NodeJsSyncHost } from '@angular-devkit/core/node';
44
import { normalize } from '@angular-devkit/core';
55

66
export class NgMorphTree extends HostTree {
7+
private hostSink: HostSink;
8+
79
constructor(root: string = process.cwd()) {
8-
super(new ScopedHost(new NodeJsSyncHost(), normalize(root)));
10+
const host = new ScopedHost(new NodeJsSyncHost(), normalize(root));
11+
super(host);
12+
13+
this.hostSink = new HostSink(host);
14+
}
15+
16+
commitChanges(): Promise<void> {
17+
return this.hostSink.commit(this).toPromise();
918
}
1019
}

libs/ng-morph/source-file/helpers/create-source-file.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import { SourceFile } from 'ts-morph';
33

44
export function createSourceFile(
55
filePath: string,
6-
content?: string
6+
content?: string,
7+
{ overwrite = false }: { overwrite?: boolean } = {}
78
): SourceFile {
8-
return getActiveProject().createSourceFile(filePath, content);
9+
return getActiveProject().createSourceFile(filePath, content, { overwrite });
910
}

0 commit comments

Comments
 (0)