Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: use fs.promises #4314

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 5 additions & 5 deletions cli/run/getConfigPath.ts
@@ -1,13 +1,13 @@
import { readdirSync } from 'fs';
import { promises as fs } from 'fs';
import { resolve } from 'path';
import { cwd } from 'process';
import { handleError } from '../logging';

const DEFAULT_CONFIG_BASE = 'rollup.config';

export function getConfigPath(commandConfig: string | true): string {
export async function getConfigPath(commandConfig: string | true): Promise<string> {
if (commandConfig === true) {
return resolve(findConfigFileNameInCwd());
return resolve(await findConfigFileNameInCwd());
}
if (commandConfig.slice(0, 5) === 'node:') {
const pkgName = commandConfig.slice(5);
Expand All @@ -30,8 +30,8 @@ export function getConfigPath(commandConfig: string | true): string {
return resolve(commandConfig);
}

function findConfigFileNameInCwd(): string {
const filesInWorkingDir = new Set(readdirSync(cwd()));
async function findConfigFileNameInCwd(): Promise<string> {
const filesInWorkingDir = new Set(await fs.readdir(cwd()));
for (const extension of ['mjs', 'cjs', 'ts']) {
const fileName = `${DEFAULT_CONFIG_BASE}.${extension}`;
if (filesInWorkingDir.has(fileName)) return fileName;
Expand Down
2 changes: 1 addition & 1 deletion cli/run/index.ts
Expand Up @@ -89,7 +89,7 @@ async function getConfigs(
command: any
): Promise<{ options: MergedRollupOptions[]; warnings: BatchWarnings }> {
if (command.config) {
const configFile = getConfigPath(command.config);
const configFile = await getConfigPath(command.config);
const { options, warnings } = await loadAndParseConfigFile(configFile, command);
return { options, warnings };
}
Expand Down
6 changes: 3 additions & 3 deletions cli/run/loadConfigFile.ts
@@ -1,4 +1,4 @@
import { realpathSync } from 'fs';
import { promises as fs } from 'fs';
import { extname, isAbsolute } from 'path';
import { pathToFileURL } from 'url';
import * as rollup from '../../src/node-entry';
Expand Down Expand Up @@ -57,7 +57,7 @@ async function loadConfigFile(
return getConfigList(configFileExport, commandOptions);
}

function getDefaultFromCjs(namespace: GenericConfigObject) {
function getDefaultFromCjs(namespace: GenericConfigObject): unknown {
return namespace.__esModule ? namespace.default : namespace;
}

Expand Down Expand Up @@ -103,7 +103,7 @@ async function getDefaultFromTranspiledConfigFile(
}

async function loadConfigFromBundledFile(fileName: string, bundledCode: string): Promise<unknown> {
const resolvedFileName = realpathSync(fileName);
const resolvedFileName = await fs.realpath(fileName);
const extension = extname(resolvedFileName);
const defaultLoader = require.extensions[extension];
require.extensions[extension] = (module: NodeModule, requiredFileName: string) => {
Expand Down
6 changes: 3 additions & 3 deletions cli/run/watch-cli.ts
@@ -1,4 +1,4 @@
import { type FSWatcher, readFileSync } from 'fs';
import { type FSWatcher, promises } from 'fs';
import chokidar from 'chokidar';
import dateTime from 'date-time';
import ms from 'pretty-ms';
Expand All @@ -22,7 +22,7 @@ export async function watch(command: Record<string, any>): Promise<void> {
let watcher: RollupWatcher;
let configWatcher: FSWatcher;
let resetScreen: (heading: string) => void;
const configFile = command.config ? getConfigPath(command.config) : null;
const configFile = command.config ? await getConfigPath(command.config) : null;

onExit(close);
process.on('uncaughtException', close);
Expand All @@ -40,7 +40,7 @@ export async function watch(command: Record<string, any>): Promise<void> {

async function reloadConfigFile() {
try {
const newConfigFileData = readFileSync(configFile, 'utf-8');
const newConfigFileData = await promises.readFile(configFile, 'utf8');
if (newConfigFileData === configFileData) {
return;
}
Expand Down
3 changes: 2 additions & 1 deletion src/ModuleLoader.ts
Expand Up @@ -253,7 +253,8 @@ export class ModuleLoader {
let source: LoadResult;
try {
source = await this.readQueue.run(
async () => (await this.pluginDriver.hookFirst('load', [id])) ?? (await readFile(id))
async () =>
(await this.pluginDriver.hookFirst('load', [id])) ?? (await readFile(id, 'utf8'))
);
} catch (err: any) {
timeEnd('load modules', 3);
Expand Down
30 changes: 6 additions & 24 deletions src/utils/fs.ts
@@ -1,28 +1,10 @@
import fs from 'fs';
import { promises as fs } from 'fs';
import { dirname } from './path';

export * from 'fs';
export const { lstat, readdir, readFile, realpath } = fs;

export const readFile = (file: string): Promise<string> =>
new Promise<string>((fulfil, reject) =>
fs.readFile(file, 'utf-8', (err, contents) => (err ? reject(err) : fulfil(contents)))
);

function mkdirpath(path: string) {
const dir = dirname(path);
fs.mkdirSync(dir, { recursive: true });
}

export function writeFile(dest: string, data: string | Uint8Array): Promise<void> {
return new Promise<void>((fulfil, reject) => {
mkdirpath(dest);

fs.writeFile(dest, data, err => {
if (err) {
reject(err);
} else {
fulfil();
}
});
});
export async function writeFile(dest: string, data: string | Uint8Array): Promise<void> {
const dir = dirname(dest);
await fs.mkdir(dir, { recursive: true });
await fs.writeFile(dest, data);
}
28 changes: 15 additions & 13 deletions src/utils/resolveId.ts
@@ -1,6 +1,6 @@
import { CustomPluginOptions, Plugin, ResolvedId, ResolveIdResult } from '../rollup/types';
import { PluginDriver } from './PluginDriver';
import { lstatSync, readdirSync, realpathSync } from './fs';
import { lstat, readdir, realpath } from './fs';
import { basename, dirname, isAbsolute, resolve } from './path';
import { resolveIdViaPlugins } from './resolveIdViaPlugins';

Expand Down Expand Up @@ -45,26 +45,28 @@ export async function resolveId(
);
}

function addJsExtensionIfNecessary(file: string, preserveSymlinks: boolean) {
let found = findFile(file, preserveSymlinks);
if (found) return found;
found = findFile(file + '.mjs', preserveSymlinks);
if (found) return found;
found = findFile(file + '.js', preserveSymlinks);
return found;
async function addJsExtensionIfNecessary(
file: string,
preserveSymlinks: boolean
): Promise<string | undefined> {
return (
(await findFile(file, preserveSymlinks)) ??
(await findFile(file + '.mjs', preserveSymlinks)) ??
(await findFile(file + '.js', preserveSymlinks))
);
}

function findFile(file: string, preserveSymlinks: boolean): string | undefined {
async function findFile(file: string, preserveSymlinks: boolean): Promise<string | undefined> {
try {
const stats = lstatSync(file);
const stats = await lstat(file);
if (!preserveSymlinks && stats.isSymbolicLink())
return findFile(realpathSync(file), preserveSymlinks);
return await findFile(await realpath(file), preserveSymlinks);
if ((preserveSymlinks && stats.isSymbolicLink()) || stats.isFile()) {
// check case
const name = basename(file);
const files = readdirSync(dirname(file));
const files = await readdir(dirname(file));

if (files.indexOf(name) !== -1) return file;
if (files.includes(name)) return file;
}
} catch {
// suppress
Expand Down
15 changes: 7 additions & 8 deletions test/function/samples/max-parallel-file-reads-default/_config.js
@@ -1,24 +1,23 @@
const assert = require('assert');
const fs = require('fs');
const { promises } = require('fs');

const fsReadFile = fs.readFile;
const fsReadFile = promises.readFile;
let currentReads = 0;
let maxReads = 0;

module.exports = {
description: 'maxParallelFileReads not set',
before() {
fs.readFile = (path, options, callback) => {
promises.readFile = async (path, options) => {
currentReads++;
maxReads = Math.max(maxReads, currentReads);
fsReadFile(path, options, (err, data) => {
currentReads--;
callback(err, data);
});
const content = await fsReadFile(path, options);
currentReads--;
return content;
};
},
after() {
fs.readFile = fsReadFile;
promises.readFile = fsReadFile;
assert.strictEqual(maxReads, 5, 'Wrong number of parallel file reads: ' + maxReads);
}
};
18 changes: 9 additions & 9 deletions test/function/samples/max-parallel-file-reads-error/_config.js
@@ -1,8 +1,8 @@
const fs = require('fs');
const path = require('path');
const { promises } = require('fs');
const { join } = require('path');
const { loader } = require('../../../utils.js');

const fsReadFile = fs.readFile;
const fsReadFile = promises.readFile;

module.exports = {
description: 'maxParallelFileReads: fileRead error is forwarded',
Expand All @@ -13,19 +13,19 @@ module.exports = {
})
},
before() {
fs.readFile = (path, options, callback) => {
promises.readFile = (path, options) => {
if (path.endsWith('dep.js')) {
return callback(new Error('broken'));
throw new Error('broken');
}

fsReadFile(path, options, callback);
fsReadFile(path, options);
};
},
after() {
fs.readFile = fsReadFile;
promises.readFile = fsReadFile;
},
error: {
message: `Could not load ${path.join(__dirname, 'dep.js')} (imported by main): broken`,
watchFiles: ['main', path.join(__dirname, 'dep.js')]
message: `Could not load ${join(__dirname, 'dep.js')} (imported by main): broken`,
watchFiles: ['main', join(__dirname, 'dep.js')]
}
};
@@ -1,7 +1,7 @@
const assert = require('assert');
const fs = require('fs');
const { promises } = require('fs');

const fsReadFile = fs.readFile;
const fsReadFile = promises.readFile;
let currentReads = 0;
let maxReads = 0;

Expand All @@ -11,17 +11,16 @@ module.exports = {
maxParallelFileReads: 0
},
before() {
fs.readFile = (path, options, callback) => {
promises.readFile = async (path, options) => {
currentReads++;
maxReads = Math.max(maxReads, currentReads);
fsReadFile(path, options, (err, data) => {
currentReads--;
callback(err, data);
});
const content = await fsReadFile(path, options);
currentReads--;
return content;
};
},
after() {
fs.readFile = fsReadFile;
promises.readFile = fsReadFile;
assert.strictEqual(maxReads, 5, 'Wrong number of parallel file reads: ' + maxReads);
}
};
15 changes: 7 additions & 8 deletions test/function/samples/max-parallel-file-reads-set/_config.js
@@ -1,7 +1,7 @@
const assert = require('assert');
const fs = require('fs');
const { promises } = require('fs');

const fsReadFile = fs.readFile;
const fsReadFile = promises.readFile;
let currentReads = 0;
let maxReads = 0;

Expand All @@ -11,17 +11,16 @@ module.exports = {
maxParallelFileReads: 3
},
before() {
fs.readFile = (path, options, callback) => {
promises.readFile = async (path, options) => {
currentReads++;
maxReads = Math.max(maxReads, currentReads);
fsReadFile(path, options, (err, data) => {
currentReads--;
callback(err, data);
});
const content = await fsReadFile(path, options);
currentReads--;
return content;
};
},
after() {
fs.readFile = fsReadFile;
promises.readFile = fsReadFile;
assert.strictEqual(maxReads, 3, 'Wrong number of parallel file reads: ' + maxReads);
}
};
@@ -1,7 +1,7 @@
const assert = require('assert');
const fs = require('fs');
const { promises } = require('fs');

const fsReadFile = fs.readFile;
const fsReadFile = promises.readFile;
let currentReads = 0;
let maxReads = 0;

Expand All @@ -11,26 +11,23 @@ module.exports = {
maxParallelFileReads: 3,
plugins: [
{
async load(id) {
return new Promise((fulfil, reject) =>
fs.readFile(id, 'utf-8', (err, contents) => (err ? reject(err) : fulfil(contents)))
);
load(id) {
return promises.readFile(id, 'utf-8');
}
}
]
},
before() {
fs.readFile = (path, options, callback) => {
promises.readFile = async (path, options) => {
currentReads++;
maxReads = Math.max(maxReads, currentReads);
fsReadFile(path, options, (err, data) => {
currentReads--;
callback(err, data);
});
const content = await fsReadFile(path, options);
currentReads--;
return content;
};
},
after() {
fs.readFile = fsReadFile;
promises.readFile = fsReadFile;
assert.strictEqual(maxReads, 3, 'Wrong number of parallel file reads: ' + maxReads);
}
};