Skip to content

Commit

Permalink
refactor(compiler-cli): use mkdirSync recursive option instead of cus…
Browse files Browse the repository at this point in the history
…tom implementation (#47678)

The supported Node.js versions for the `@angular/compiler-cli` package (^14.15.0 || >=16.10.0)
allow for the use of the `recursive` option of `mkdirSync`.  Using the `recursive` option
removes the need to manually create each subdirectory in a given path.

PR Close #47678
  • Loading branch information
clydin authored and thePunderWoman committed Oct 13, 2022
1 parent 59f3324 commit d684148
Show file tree
Hide file tree
Showing 2 changed files with 3 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -123,30 +123,11 @@ export class NodeJSFileSystem extends NodeJSReadonlyFileSystem implements FileSy
fs.renameSync(from, to);
}
ensureDir(path: AbsoluteFsPath): void {
const parents: AbsoluteFsPath[] = [];
while (!this.isRoot(path) && !this.exists(path)) {
parents.push(path);
path = this.dirname(path);
}
while (parents.length) {
this.safeMkdir(parents.pop()!);
}
fs.mkdirSync(path, {recursive: true});
}
removeDeep(path: AbsoluteFsPath): void {
fs.rmdirSync(path, {recursive: true});
}

private safeMkdir(path: AbsoluteFsPath): void {
try {
fs.mkdirSync(path);
} catch (err) {
// Ignore the error, if the path already exists and points to a directory.
// Re-throw otherwise.
if (!this.exists(path) || !this.stat(path).isDirectory()) {
throw err;
}
}
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,102 +172,12 @@ describe('NodeJSFileSystem', () => {
});

describe('ensureDir()', () => {
it('should call exists() and fs.mkdir()', () => {
const aPath = fs.resolve('/a');
const abPath = fs.resolve('/a/b');
const xPath = fs.resolve('/x');
const xyPath = fs.resolve('/x/y');
it('should delegate to fs.mkdirSync()', () => {
const mkdirCalls: string[] = [];
const existsCalls: string[] = [];
spyOn(realFs, 'mkdirSync').and.callFake(((path: string) => mkdirCalls.push(path)) as any);
spyOn(fs, 'exists').and.callFake((path: AbsoluteFsPath) => {
existsCalls.push(path);
switch (path) {
case aPath:
return true;
case abPath:
return true;
default:
return false;
}
});

fs.ensureDir(abcPath);
expect(existsCalls).toEqual([abcPath, abPath]);
expect(mkdirCalls).toEqual([abcPath]);

mkdirCalls.length = 0;
existsCalls.length = 0;

fs.ensureDir(xyzPath);
expect(existsCalls).toEqual([xyzPath, xyPath, xPath]);
expect(mkdirCalls).toEqual([xPath, xyPath, xyzPath]);
});

it('should not fail if a directory (that did not exist before) does exist when trying to create it',
() => {
let abcPathExists = false;

spyOn(fs, 'exists').and.callFake((path: AbsoluteFsPath) => {
if (path === abcPath) {
// Pretend `abcPath` is created (e.g. by another process) right after we check if it
// exists for the first time.
const exists = abcPathExists;
abcPathExists = true;
return exists;
}
return false;
});
spyOn(fs, 'stat').and.returnValue({isDirectory: () => true} as any);
const mkdirSyncSpy =
spyOn(realFs, 'mkdirSync').and.callFake(((path: string) => {
if (path === abcPath) {
throw new Error(
'It exists already. Supposedly.');
}
}) as any);

fs.ensureDir(abcPath);
expect(mkdirSyncSpy).toHaveBeenCalledTimes(3);
expect(mkdirSyncSpy).toHaveBeenCalledWith(abcPath);
expect(mkdirSyncSpy).toHaveBeenCalledWith(fs.dirname(abcPath));
});

it('should fail if creating the directory throws and the directory does not exist', () => {
spyOn(fs, 'exists').and.returnValue(false);
spyOn(realFs, 'mkdirSync')
.and.callFake(((path: string) => {
if (path === abcPath) {
throw new Error('Unable to create directory (for whatever reason).');
}
}) as any);

expect(() => fs.ensureDir(abcPath))
.toThrowError('Unable to create directory (for whatever reason).');
});

it('should fail if creating the directory throws and the path points to a file', () => {
const isDirectorySpy = jasmine.createSpy('isDirectory').and.returnValue(false);
let abcPathExists = false;

spyOn(fs, 'exists').and.callFake((path: AbsoluteFsPath) => {
if (path === abcPath) {
// Pretend `abcPath` is created (e.g. by another process) right after we check if it
// exists for the first time.
const exists = abcPathExists;
abcPathExists = true;
return exists;
}
return false;
});
spyOn(fs, 'stat').and.returnValue({isDirectory: isDirectorySpy} as any);
spyOn(realFs, 'mkdirSync').and.callFake(((path: string) => {
if (path === abcPath) {
throw new Error('It exists already. Supposedly.');
}
}) as any);

expect(() => fs.ensureDir(abcPath)).toThrowError('It exists already. Supposedly.');
expect(isDirectorySpy).toHaveBeenCalledTimes(1);
});
});

Expand Down

0 comments on commit d684148

Please sign in to comment.