Load plugins asynchronously (#12790)
This commit is contained in:
1 parent
34fadbe67d
commit
193365eb71
17 files changed
+112
-90
No files matched your search
@@ -1,8 +1,9 @@
|
|||||||
#### [BREAKING] Change public apis to asynchronous (#12574, #12788 by @fisker)
|
#### [BREAKING] Change public apis to asynchronous (#12574, #12788, #12790 by @fisker)
|
||||||
|
|
||||||
- `prettier.format()` returns `Promise<string>`
|
- `prettier.format()` returns `Promise<string>`
|
||||||
- `prettier.formatWithCursor()` returns `Promise<{formatted: string, cursorOffset: number}>`
|
- `prettier.formatWithCursor()` returns `Promise<{formatted: string, cursorOffset: number}>`
|
||||||
- `prettier.check()` returns `Promise<boolean>`
|
- `prettier.check()` returns `Promise<boolean>`
|
||||||
|
- `prettier.getSupportInfo()` returns `Promise`
|
||||||
- `prettier.resolveConfig.sync` is removed
|
- `prettier.resolveConfig.sync` is removed
|
||||||
- `prettier.resolveConfigFile.sync` is removed
|
- `prettier.resolveConfigFile.sync` is removed
|
||||||
- `prettier.getFileInfo.sync` is removed
|
- `prettier.getFileInfo.sync` is removed
|
||||||
+1
-1
@@ -102,7 +102,7 @@ When setting `options.resolveConfig` (`boolean`, default `false`), Prettier will
|
|||||||
|
|
||||||
## `prettier.getSupportInfo()`
|
## `prettier.getSupportInfo()`
|
||||||
|
|
||||||
Returns an object representing the options, parsers, languages and file types Prettier supports.
|
Returns a promise which resolves to an object representing the options, parsers, languages and file types Prettier supports.
|
||||||
|
|
||||||
The support information looks like this:
|
The support information looks like this:
|
||||||
|
|
||||||
|
|||||||
+8
-4
@@ -26,14 +26,18 @@ class Context {
|
|||||||
this.rawArguments = rawArguments;
|
this.rawArguments = rawArguments;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.stack = [];
|
this.stack = [];
|
||||||
|
}
|
||||||
|
|
||||||
const { plugins, pluginSearchDirs } = parseArgvWithoutPlugins(
|
async init() {
|
||||||
|
const { rawArguments, logger } = this;
|
||||||
|
|
||||||
|
const { plugins, pluginSearchDirs } = await parseArgvWithoutPlugins(
|
||||||
rawArguments,
|
rawArguments,
|
||||||
logger,
|
logger,
|
||||||
["plugin", "plugin-search-dir"]
|
["plugin", "plugin-search-dir"]
|
||||||
);
|
);
|
||||||
|
|
||||||
this.pushContextPlugins(plugins, pluginSearchDirs);
|
await this.pushContextPlugins(plugins, pluginSearchDirs);
|
||||||
|
|
||||||
const argv = parseArgv(rawArguments, this.detailedOptions, logger);
|
const argv = parseArgv(rawArguments, this.detailedOptions, logger);
|
||||||
this.argv = argv;
|
this.argv = argv;
|
||||||
@@ -44,8 +48,8 @@ class Context {
|
|||||||
* @param {string[]} plugins
|
* @param {string[]} plugins
|
||||||
* @param {string[]=} pluginSearchDirs
|
* @param {string[]=} pluginSearchDirs
|
||||||
*/
|
*/
|
||||||
pushContextPlugins(plugins, pluginSearchDirs) {
|
async pushContextPlugins(plugins, pluginSearchDirs) {
|
||||||
const options = getContextOptions(plugins, pluginSearchDirs);
|
const options = await getContextOptions(plugins, pluginSearchDirs);
|
||||||
this.stack.push(options);
|
this.stack.push(options);
|
||||||
Object.assign(this, options);
|
Object.assign(this, options);
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -14,15 +14,16 @@ async function run(rawArguments) {
|
|||||||
let logger = createLogger();
|
let logger = createLogger();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const logLevel = parseArgvWithoutPlugins(
|
const { loglevel: logLevel } = await parseArgvWithoutPlugins(
|
||||||
rawArguments,
|
rawArguments,
|
||||||
logger,
|
logger,
|
||||||
"loglevel"
|
"loglevel"
|
||||||
).loglevel;
|
);
|
||||||
if (logLevel !== logger.logLevel) {
|
if (logLevel !== logger.logLevel) {
|
||||||
logger = createLogger(logLevel);
|
logger = createLogger(logLevel);
|
||||||
}
|
}
|
||||||
const context = new Context({ rawArguments, logger });
|
const context = new Context({ rawArguments, logger });
|
||||||
|
await context.init();
|
||||||
if (logger.logLevel !== "debug" && context.performanceTestFlag) {
|
if (logger.logLevel !== "debug" && context.performanceTestFlag) {
|
||||||
context.logger = createLogger("debug");
|
context.logger = createLogger("debug");
|
||||||
}
|
}
|
||||||
@@ -80,10 +81,9 @@ async function main(context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (context.argv.supportInfo) {
|
if (context.argv.supportInfo) {
|
||||||
|
const supportInfo = await prettier.getSupportInfo();
|
||||||
printToScreen(
|
printToScreen(
|
||||||
await prettier.format(stringify(prettier.getSupportInfo()), {
|
await prettier.format(stringify(supportInfo), { parser: "json" })
|
||||||
parser: "json",
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import {
|
|||||||
createDetailedOptionMap,
|
createDetailedOptionMap,
|
||||||
} from "./option-map.js";
|
} from "./option-map.js";
|
||||||
|
|
||||||
function getContextOptions(plugins, pluginSearchDirs) {
|
async function getContextOptions(plugins, pluginSearchDirs) {
|
||||||
const { options: supportOptions, languages } = getSupportInfo({
|
const { options: supportOptions, languages } = await getSupportInfo({
|
||||||
showDeprecated: true,
|
showDeprecated: true,
|
||||||
showUnreleased: true,
|
showUnreleased: true,
|
||||||
showInternal: true,
|
showInternal: true,
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ async function getOptionsForFile(context, filepath) {
|
|||||||
|
|
||||||
const hasPlugins = options && options.plugins;
|
const hasPlugins = options && options.plugins;
|
||||||
if (hasPlugins) {
|
if (hasPlugins) {
|
||||||
context.pushContextPlugins(options.plugins);
|
await context.pushContextPlugins(options.plugins);
|
||||||
}
|
}
|
||||||
|
|
||||||
const appliedOptions = {
|
const appliedOptions = {
|
||||||
|
|||||||
@@ -39,11 +39,13 @@ function parseArgv(rawArguments, detailedOptions, logger, keys) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const detailedOptionsWithoutPlugins = getContextOptions(
|
let detailedOptionsWithoutPlugins;
|
||||||
[],
|
async function parseArgvWithoutPlugins(rawArguments, logger, keys) {
|
||||||
false
|
if (!detailedOptionsWithoutPlugins) {
|
||||||
).detailedOptions;
|
({ detailedOptions: detailedOptionsWithoutPlugins } =
|
||||||
function parseArgvWithoutPlugins(rawArguments, logger, keys) {
|
await getContextOptions([], false));
|
||||||
|
}
|
||||||
|
|
||||||
return parseArgv(
|
return parseArgv(
|
||||||
rawArguments,
|
rawArguments,
|
||||||
detailedOptionsWithoutPlugins,
|
detailedOptionsWithoutPlugins,
|
||||||
|
|||||||
+44
-34
@@ -1,5 +1,5 @@
|
|||||||
import { createRequire } from "node:module";
|
import { createRequire } from "node:module";
|
||||||
import fs from "node:fs";
|
import { promises as fsPromises } from "node:fs";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { fileURLToPath } from "node:url";
|
import { fileURLToPath } from "node:url";
|
||||||
import fastGlob from "fast-glob";
|
import fastGlob from "fast-glob";
|
||||||
@@ -19,7 +19,7 @@ const clearCache = () => {
|
|||||||
memClear(memoizedSearch);
|
memClear(memoizedSearch);
|
||||||
};
|
};
|
||||||
|
|
||||||
function load(plugins, pluginSearchDirs) {
|
async function load(plugins, pluginSearchDirs) {
|
||||||
if (!plugins) {
|
if (!plugins) {
|
||||||
plugins = [];
|
plugins = [];
|
||||||
}
|
}
|
||||||
@@ -61,36 +61,42 @@ function load(plugins, pluginSearchDirs) {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const externalAutoLoadPluginInfos = pluginSearchDirs.flatMap(
|
const externalAutoLoadPluginInfos = (
|
||||||
(pluginSearchDir) => {
|
await Promise.all(
|
||||||
const resolvedPluginSearchDir = path.resolve(
|
pluginSearchDirs.map(async (pluginSearchDir) => {
|
||||||
process.cwd(),
|
const resolvedPluginSearchDir = path.resolve(
|
||||||
pluginSearchDir
|
process.cwd(),
|
||||||
);
|
pluginSearchDir
|
||||||
|
|
||||||
const nodeModulesDir = path.resolve(
|
|
||||||
resolvedPluginSearchDir,
|
|
||||||
"node_modules"
|
|
||||||
);
|
|
||||||
|
|
||||||
// In some fringe cases (ex: files "mounted" as virtual directories), the
|
|
||||||
// isDirectory(resolvedPluginSearchDir) check might be false even though
|
|
||||||
// the node_modules actually exists.
|
|
||||||
if (
|
|
||||||
!isDirectory(nodeModulesDir) &&
|
|
||||||
!isDirectory(resolvedPluginSearchDir)
|
|
||||||
) {
|
|
||||||
throw new Error(
|
|
||||||
`${pluginSearchDir} does not exist or is not a directory`
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
return memoizedSearch(nodeModulesDir).map((pluginName) => ({
|
const nodeModulesDir = path.resolve(
|
||||||
name: pluginName,
|
resolvedPluginSearchDir,
|
||||||
requirePath: resolve(pluginName, { paths: [resolvedPluginSearchDir] }),
|
"node_modules"
|
||||||
}));
|
);
|
||||||
}
|
|
||||||
);
|
// In some fringe cases (ex: files "mounted" as virtual directories), the
|
||||||
|
// isDirectory(resolvedPluginSearchDir) check might be false even though
|
||||||
|
// the node_modules actually exists.
|
||||||
|
if (
|
||||||
|
!(await isDirectory(nodeModulesDir)) &&
|
||||||
|
!(await isDirectory(resolvedPluginSearchDir))
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
`${pluginSearchDir} does not exist or is not a directory`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const pluginNames = await memoizedSearch(nodeModulesDir);
|
||||||
|
|
||||||
|
return pluginNames.map((pluginName) => ({
|
||||||
|
name: pluginName,
|
||||||
|
requirePath: resolve(pluginName, {
|
||||||
|
paths: [resolvedPluginSearchDir],
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
})
|
||||||
|
)
|
||||||
|
).flat();
|
||||||
|
|
||||||
const externalPlugins = [
|
const externalPlugins = [
|
||||||
...uniqByKey(
|
...uniqByKey(
|
||||||
@@ -106,8 +112,8 @@ function load(plugins, pluginSearchDirs) {
|
|||||||
return externalPlugins;
|
return externalPlugins;
|
||||||
}
|
}
|
||||||
|
|
||||||
function findPluginsInNodeModules(nodeModulesDir) {
|
async function findPluginsInNodeModules(nodeModulesDir) {
|
||||||
const pluginPackageJsonPaths = fastGlob.sync(
|
const pluginPackageJsonPaths = await fastGlob(
|
||||||
[
|
[
|
||||||
"prettier-plugin-*/package.json",
|
"prettier-plugin-*/package.json",
|
||||||
"@*/prettier-plugin-*/package.json",
|
"@*/prettier-plugin-*/package.json",
|
||||||
@@ -120,12 +126,16 @@ function findPluginsInNodeModules(nodeModulesDir) {
|
|||||||
return pluginPackageJsonPaths.map(path.dirname);
|
return pluginPackageJsonPaths.map(path.dirname);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isDirectory(dir) {
|
async function isDirectory(dir) {
|
||||||
|
let stat;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return fs.statSync(dir).isDirectory();
|
stat = await fsPromises.stat(dir);
|
||||||
} catch {
|
} catch {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return stat.isDirectory();
|
||||||
}
|
}
|
||||||
|
|
||||||
export { memoizedLoad as loadPlugins, clearCache };
|
export { memoizedLoad as loadPlugins, clearCache };
|
||||||
+3
-2
@@ -39,13 +39,14 @@ function withPlugins(
|
|||||||
fn,
|
fn,
|
||||||
optsArgIdx = 1 // Usually `opts` is the 2nd argument
|
optsArgIdx = 1 // Usually `opts` is the 2nd argument
|
||||||
) {
|
) {
|
||||||
return (...args) => {
|
return async (...args) => {
|
||||||
const opts = args[optsArgIdx] || {};
|
const opts = args[optsArgIdx] || {};
|
||||||
|
|
||||||
args[optsArgIdx] = {
|
args[optsArgIdx] = {
|
||||||
...opts,
|
...opts,
|
||||||
plugins: [
|
plugins: [
|
||||||
...languages,
|
...languages,
|
||||||
...loadPlugins(opts.plugins, opts.pluginSearchDirs),
|
...(await loadPlugins(opts.plugins, opts.pluginSearchDirs)),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
return fn(...args);
|
return fn(...args);
|
||||||
|
|||||||
+3
-1
@@ -10,7 +10,9 @@ function withPlugins(
|
|||||||
fn,
|
fn,
|
||||||
optsArgIdx = 1 // Usually `opts` is the 2nd argument
|
optsArgIdx = 1 // Usually `opts` is the 2nd argument
|
||||||
) {
|
) {
|
||||||
return (...args) => {
|
// Returns Promises to consistent with functions in `index.js`
|
||||||
|
// eslint-disable-next-line require-await
|
||||||
|
return async (...args) => {
|
||||||
const opts = args[optsArgIdx] || {};
|
const opts = args[optsArgIdx] || {};
|
||||||
const plugins = opts.plugins || [];
|
const plugins = opts.plugins || [];
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import * as prettier from "../../../../index.js";
|
import * as prettier from "../../../../index.js";
|
||||||
|
|
||||||
const parsers = prettier
|
const parsers = (await prettier.getSupportInfo()).options
|
||||||
.getSupportInfo()
|
.find((option) => option.name === "parser")
|
||||||
.options.find((option) => option.name === "parser")
|
|
||||||
.choices.filter((choice) => !choice.deprecated)
|
.choices.filter((choice) => !choice.deprecated)
|
||||||
.map((choice) => choice.value);
|
.map((choice) => choice.value);
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ describe("API", () => {
|
|||||||
expect(Array.isArray(ast.program.body)).toBe(true);
|
expect(Array.isArray(ast.program.body)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("prettier.formatAST", () => {
|
test("prettier.formatAST", async () => {
|
||||||
const { formatted: formatResultFromAST } = formatAST(ast, options);
|
const { formatted: formatResultFromAST } = await formatAST(ast, options);
|
||||||
expect(formatResultFromAST).toBe(formatted);
|
expect(formatResultFromAST).toBe(formatted);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -41,8 +41,8 @@ describe("API", () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("prettier.printDocToString", () => {
|
test("prettier.printDocToString", async () => {
|
||||||
const { formatted: stringFromDoc } = printDocToString(doc, options);
|
const { formatted: stringFromDoc } = await printDocToString(doc, options);
|
||||||
expect(stringFromDoc).toBe(formatted);
|
expect(stringFromDoc).toBe(formatted);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ describe("API", () => {
|
|||||||
`return ${formatResultFromDoc}`
|
`return ${formatResultFromDoc}`
|
||||||
)(builders);
|
)(builders);
|
||||||
|
|
||||||
const { formatted: stringFromDoc2 } = printDocToString(doc2, options);
|
const { formatted: stringFromDoc2 } = await printDocToString(doc2, options);
|
||||||
expect(stringFromDoc2).toBe(formatted);
|
expect(stringFromDoc2).toBe(formatted);
|
||||||
|
|
||||||
const formatResultFromDoc2 = await formatDoc(doc2, options);
|
const formatResultFromDoc2 = await formatDoc(doc2, options);
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import prettier from "prettier-local";
|
|||||||
const { formatAST } = prettier.__debug;
|
const { formatAST } = prettier.__debug;
|
||||||
|
|
||||||
describe("formatAST", () => {
|
describe("formatAST", () => {
|
||||||
const formatExportSpecifier = (specifier) => {
|
const formatExportSpecifier = async (specifier) => {
|
||||||
const { formatted } = formatAST(
|
const { formatted } = await formatAST(
|
||||||
{
|
{
|
||||||
type: "Program",
|
type: "Program",
|
||||||
body: [
|
body: [
|
||||||
@@ -19,9 +19,9 @@ describe("formatAST", () => {
|
|||||||
return formatted;
|
return formatted;
|
||||||
};
|
};
|
||||||
|
|
||||||
test("Shorthand specifier", () => {
|
test("Shorthand specifier", async () => {
|
||||||
expect(
|
expect(
|
||||||
formatExportSpecifier({
|
await formatExportSpecifier({
|
||||||
type: "ExportSpecifier",
|
type: "ExportSpecifier",
|
||||||
local: {
|
local: {
|
||||||
type: "Identifier",
|
type: "Identifier",
|
||||||
@@ -35,9 +35,9 @@ describe("formatAST", () => {
|
|||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Shorthand specifier 2", () => {
|
test("Shorthand specifier 2", async () => {
|
||||||
expect(
|
expect(
|
||||||
formatExportSpecifier({
|
await formatExportSpecifier({
|
||||||
type: "ExportSpecifier",
|
type: "ExportSpecifier",
|
||||||
local: {
|
local: {
|
||||||
type: "Identifier",
|
type: "Identifier",
|
||||||
@@ -53,9 +53,9 @@ describe("formatAST", () => {
|
|||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Shorthand specifier 3", () => {
|
test("Shorthand specifier 3", async () => {
|
||||||
expect(
|
expect(
|
||||||
formatExportSpecifier({
|
await formatExportSpecifier({
|
||||||
type: "ExportSpecifier",
|
type: "ExportSpecifier",
|
||||||
local: {
|
local: {
|
||||||
type: "Literal",
|
type: "Literal",
|
||||||
@@ -72,9 +72,9 @@ describe("formatAST", () => {
|
|||||||
).toMatchSnapshot();
|
).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Shorthand specifier 4", () => {
|
test("Shorthand specifier 4", async () => {
|
||||||
expect(
|
expect(
|
||||||
formatExportSpecifier({
|
await formatExportSpecifier({
|
||||||
type: "ExportSpecifier",
|
type: "ExportSpecifier",
|
||||||
local: {
|
local: {
|
||||||
type: "Literal",
|
type: "Literal",
|
||||||
|
|||||||
@@ -7,15 +7,15 @@ import {
|
|||||||
normalizeDetailedOptionMap,
|
normalizeDetailedOptionMap,
|
||||||
} from "../../../src/cli/options/option-map.js";
|
} from "../../../src/cli/options/option-map.js";
|
||||||
|
|
||||||
|
const supportInfo = await prettier.getSupportInfo({
|
||||||
|
showDeprecated: true,
|
||||||
|
showUnreleased: true,
|
||||||
|
showInternal: true,
|
||||||
|
});
|
||||||
|
|
||||||
for (const option of arrayify(
|
for (const option of arrayify(
|
||||||
{
|
{
|
||||||
...createDetailedOptionMap(
|
...createDetailedOptionMap(supportInfo.options),
|
||||||
prettier.getSupportInfo({
|
|
||||||
showDeprecated: true,
|
|
||||||
showUnreleased: true,
|
|
||||||
showInternal: true,
|
|
||||||
}).options
|
|
||||||
),
|
|
||||||
...normalizeDetailedOptionMap(constant.options),
|
...normalizeDetailedOptionMap(constant.options),
|
||||||
},
|
},
|
||||||
"name"
|
"name"
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import prettier from "prettier-local";
|
import prettier from "prettier-local";
|
||||||
import generateSchema from "../../../scripts/utils/generate-schema.mjs";
|
import generateSchema from "../../../scripts/utils/generate-schema.mjs";
|
||||||
|
|
||||||
test("schema", () => {
|
test("schema", async () => {
|
||||||
expect(generateSchema(prettier.getSupportInfo().options)).toMatchSnapshot();
|
const { options } = await prettier.getSupportInfo();
|
||||||
|
const schema = generateSchema(options);
|
||||||
|
|
||||||
|
expect(schema).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
import prettier from "prettier-local";
|
import prettier from "prettier-local";
|
||||||
import runPrettier from "../run-prettier.js";
|
import runPrettier from "../run-prettier.js";
|
||||||
|
|
||||||
test("API getSupportInfo()", () => {
|
test("API getSupportInfo()", async () => {
|
||||||
expect(getCoreInfo()).toMatchSnapshot();
|
expect(await getCoreInfo()).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("CLI --support-info", () => {
|
describe("CLI --support-info", () => {
|
||||||
runPrettier("cli", "--support-info").test({ status: 0 });
|
runPrettier("cli", "--support-info").test({ status: 0 });
|
||||||
});
|
});
|
||||||
|
|
||||||
function getCoreInfo() {
|
async function getCoreInfo() {
|
||||||
const supportInfo = prettier.getSupportInfo();
|
const supportInfo = await prettier.getSupportInfo();
|
||||||
const languages = Object.fromEntries(
|
const languages = Object.fromEntries(
|
||||||
supportInfo.languages.map(({ name, parsers }) => [name, parsers])
|
supportInfo.languages.map(({ name, parsers }) => [name, parsers])
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -59,11 +59,11 @@ async function run(dir, args, options) {
|
|||||||
- Test file `./__tests__/plugin-virtual-directory.js`
|
- Test file `./__tests__/plugin-virtual-directory.js`
|
||||||
- Pull request #5819
|
- Pull request #5819
|
||||||
*/
|
*/
|
||||||
const originalStatSync = fs.statSync;
|
const originalStat = fs.promises.stat;
|
||||||
jest
|
jest
|
||||||
.spyOn(fs, "statSync")
|
.spyOn(fs.promises, "stat")
|
||||||
.mockImplementation((filename) =>
|
.mockImplementation((filename) =>
|
||||||
originalStatSync(
|
originalStat(
|
||||||
path.basename(filename) === "virtualDirectory" ? __filename : filename
|
path.basename(filename) === "virtualDirectory" ? __filename : filename
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in new issue
Block a user