Skip to content

Commit

Permalink
feat: cache realpath and realpathSync methods
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-akait authored Mar 6, 2024
2 parents 91bd21f + 379ca70 commit 283136c
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 2 deletions.
14 changes: 14 additions & 0 deletions lib/CachedInputFileSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,19 @@ module.exports = class CachedInputFileSystem {
this.readlinkSync = /** @type {SyncFileSystem["readlinkSync"]} */ (
readlinkSync
);

this._realpathBackend = createBackend(
duration,
this.fileSystem.realpath,
this.fileSystem.realpathSync,
this.fileSystem
);
const realpath = this._realpathBackend.provide;
this.realpath = /** @type {FileSystem["realpath"]} */ (realpath);
const realpathSync = this._realpathBackend.provideSync;
this.realpathSync = /** @type {SyncFileSystem["realpathSync"]} */ (
realpathSync
);
}

/**
Expand All @@ -589,5 +602,6 @@ module.exports = class CachedInputFileSystem {
this._readFileBackend.purge(what);
this._readlinkBackend.purge(what);
this._readJsonBackend.purge(what);
this._realpathBackend.purge(what);
}
};
6 changes: 4 additions & 2 deletions lib/Resolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ const {

/** @typedef {import("./ResolverFactory").ResolveOptions} ResolveOptions */

/** @typedef {Error & {details?: string}} ErrorWithDetail */
/** @typedef {Error & { details?: string }} ErrorWithDetail */

/** @typedef {(err: ErrorWithDetail|null, res?: string|false, req?: ResolveRequest) => void} ResolveCallback */
/** @typedef {(err: ErrorWithDetail | null, res?: string | false, req?: ResolveRequest) => void} ResolveCallback */

/**
* @typedef {Object} FileSystemStats
Expand Down Expand Up @@ -65,6 +65,7 @@ const {
* @property {(function(string, FileSystemCallback<Buffer | string>): void) & function(string, object, FileSystemCallback<Buffer | string>): void} readlink
* @property {(function(string, FileSystemCallback<FileSystemStats>): void) & function(string, object, FileSystemCallback<Buffer | string>): void=} lstat
* @property {(function(string, FileSystemCallback<FileSystemStats>): void) & function(string, object, FileSystemCallback<Buffer | string>): void} stat
* @property {(function(string, FileSystemCallback<Buffer | string>): void) & function(string, object, FileSystemCallback<Buffer | string>): void=} realpath
*/

/**
Expand All @@ -75,6 +76,7 @@ const {
* @property {function(string, object=): Buffer | string} readlinkSync
* @property {function(string, object=): FileSystemStats=} lstatSync
* @property {function(string, object=): FileSystemStats} statSync
* @property {function(string, object=): string | Buffer=} realpathSync
*/

/**
Expand Down
84 changes: 84 additions & 0 deletions test/CachedInputFileSystem.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,90 @@ describe("CachedInputFileSystem OperationMergerBackend ('lstat' and 'lstatSync')
});
});

describe("CachedInputFileSystem OperationMergerBackend ('realpath' and 'realpathSync')", () => {
let fs;

beforeEach(() => {
fs = new CachedInputFileSystem(
{
realpath: function (path, options, callback) {
if (!callback) {
callback = options;
options = undefined;
}
setTimeout(
() =>
callback(null, {
path,
options
}),
100
);
},
realpathSync: function (path, options) {
return {
path,
options
};
}
},
0
);
});
afterEach(() => {
fs.purge();
});

it("should join accesses", function (done) {
fs.realpath("a", function (err, result) {
expect(result).toBeDefined();
result.a = true;
});
fs.realpath("a", function (err, result) {
expect(result).toBeDefined();
expect(result.a).toBeDefined();
done();
});
});

it("should not join accesses with options", function (done) {
fs.realpath("a", function (err, result) {
expect(result).toBeDefined();

result.a = true;

expect(result).toBeDefined();
expect(result.path).toEqual("a");
expect(result.options).toBeUndefined();
});
fs.realpath("a", { options: true }, function (err, result) {
expect(result).toBeDefined();
expect(result.a).toBeUndefined();
expect(result.path).toEqual("a");
expect(result.options).toMatchObject({ options: true });
done();
});
});

it("should not cache accesses", function (done) {
fs.realpath("a", function (err, result) {
result.a = true;
fs.realpath("a", function (err, result) {
expect(result.a).toBeUndefined();
done();
});
});
});

it("should not cache sync accesses", () => {
const result = fs.realpathSync("a");
result.a = true;
const result2 = fs.realpathSync("a");

expect(result2.a).toBeUndefined();
});
});

describe("CachedInputFileSystem CacheBackend", () => {
let fs;

Expand Down
17 changes: 17 additions & 0 deletions types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,15 @@ declare class CachedInputFileSystem {
): void;
};
readlinkSync: (arg0: string, arg1?: object) => string | Buffer;
realpath?: {
(arg0: string, arg1: FileSystemCallback<string | Buffer>): void;
(
arg0: string,
arg1: object,
arg2: FileSystemCallback<string | Buffer>
): void;
};
realpathSync?: (arg0: string, arg1?: object) => string | Buffer;
purge(what?: string | Set<string> | string[]): void;
}
declare class CloneBasenamePlugin {
Expand Down Expand Up @@ -206,6 +215,14 @@ declare interface FileSystem {
arg2: FileSystemCallback<string | Buffer>
): void;
};
realpath?: {
(arg0: string, arg1: FileSystemCallback<string | Buffer>): void;
(
arg0: string,
arg1: object,
arg2: FileSystemCallback<string | Buffer>
): void;
};
}
declare interface FileSystemCallback<T> {
(err?: null | (PossibleFileSystemError & Error), result?: T): any;
Expand Down

0 comments on commit 283136c

Please sign in to comment.