diff --git a/.yarn/versions/cc34eb37.yml b/.yarn/versions/cc34eb37.yml new file mode 100644 index 000000000000..bf1c10dbe322 --- /dev/null +++ b/.yarn/versions/cc34eb37.yml @@ -0,0 +1,39 @@ +releases: + "@yarnpkg/cli": minor + "@yarnpkg/core": minor + "@yarnpkg/fslib": minor + "@yarnpkg/libzip": minor + "@yarnpkg/plugin-pnpm": minor + "@yarnpkg/pnpify": minor + +declined: + - "@yarnpkg/plugin-compat" + - "@yarnpkg/plugin-constraints" + - "@yarnpkg/plugin-dlx" + - "@yarnpkg/plugin-essentials" + - "@yarnpkg/plugin-exec" + - "@yarnpkg/plugin-file" + - "@yarnpkg/plugin-git" + - "@yarnpkg/plugin-github" + - "@yarnpkg/plugin-http" + - "@yarnpkg/plugin-init" + - "@yarnpkg/plugin-interactive-tools" + - "@yarnpkg/plugin-link" + - "@yarnpkg/plugin-nm" + - "@yarnpkg/plugin-npm" + - "@yarnpkg/plugin-npm-cli" + - "@yarnpkg/plugin-pack" + - "@yarnpkg/plugin-patch" + - "@yarnpkg/plugin-pnp" + - "@yarnpkg/plugin-stage" + - "@yarnpkg/plugin-typescript" + - "@yarnpkg/plugin-version" + - "@yarnpkg/plugin-workspace-tools" + - vscode-zipfs + - "@yarnpkg/builder" + - "@yarnpkg/doctor" + - "@yarnpkg/extensions" + - "@yarnpkg/nm" + - "@yarnpkg/pnp" + - "@yarnpkg/sdks" + - "@yarnpkg/shell" diff --git a/packages/plugin-pnpm/sources/PnpmLinker.ts b/packages/plugin-pnpm/sources/PnpmLinker.ts index a404bb4e85b9..5627b758f5de 100644 --- a/packages/plugin-pnpm/sources/PnpmLinker.ts +++ b/packages/plugin-pnpm/sources/PnpmLinker.ts @@ -1,5 +1,5 @@ import {Descriptor, FetchResult, formatUtils, Installer, InstallPackageExtraApi, Linker, LinkOptions, LinkType, Locator, LocatorHash, Manifest, MessageName, MinimalLinkOptions, Package, Project, miscUtils, structUtils, WindowsLinkType} from '@yarnpkg/core'; -import {Dirent, Filename, PortablePath, setupCopyIndex, ppath, xfs} from '@yarnpkg/fslib'; +import {Filename, PortablePath, setupCopyIndex, ppath, xfs, DirentNoPath} from '@yarnpkg/fslib'; import {jsInstallUtils} from '@yarnpkg/plugin-pnp'; import {UsageError} from 'clipanion'; @@ -339,9 +339,9 @@ function isPnpmVirtualCompatible(locator: Locator, {project}: {project: Project} } async function getNodeModulesListing(nmPath: PortablePath) { - const listing = new Map(); + const listing = new Map(); - let fsListing: Array = []; + let fsListing: Array = []; try { fsListing = await xfs.readdirPromise(nmPath, {withFileTypes: true}); } catch (err) { @@ -377,7 +377,7 @@ async function getNodeModulesListing(nmPath: PortablePath) { return listing; } -async function cleanNodeModules(nmPath: PortablePath, extraneous: Map) { +async function cleanNodeModules(nmPath: PortablePath, extraneous: Map) { const removeNamePromises = []; const scopesToRemove = new Set(); diff --git a/packages/yarnpkg-fslib/sources/FakeFS.ts b/packages/yarnpkg-fslib/sources/FakeFS.ts index 79afaadf38ba..37c67d64b8c4 100644 --- a/packages/yarnpkg-fslib/sources/FakeFS.ts +++ b/packages/yarnpkg-fslib/sources/FakeFS.ts @@ -18,28 +18,39 @@ export type BigIntStats = NodeBigIntStats & { crc?: number; }; -export type Dirent = Exclude & { +export type Dirent = Exclude & { + name: Filename; + path: T; +}; + +export type DirentNoPath = Exclude & { name: Filename; }; export type Dir

= { readonly path: P; - [Symbol.asyncIterator](): AsyncIterableIterator; + [Symbol.asyncIterator](): AsyncIterableIterator; close(): Promise; close(cb: NoParamCallback): void; closeSync(): void; - read(): Promise; - read(cb: (err: NodeJS.ErrnoException | null, dirent: Dirent | null) => void): void; + read(): Promise; + read(cb: (err: NodeJS.ErrnoException | null, dirent: DirentNoPath | null) => void): void; - readSync(): Dirent | null; + readSync(): DirentNoPath | null; }; export type OpendirOptions = Partial<{ bufferSize: number; + recursive: boolean; +}>; + +export type ReaddirOptions = Partial<{ + recursive: boolean; + withFileTypes: boolean; }>; export type CreateReadStreamOptions = Partial<{ @@ -161,15 +172,29 @@ export abstract class FakeFS

{ abstract realpathPromise(p: P): Promise

; abstract realpathSync(p: P): P; - abstract readdirPromise(p: P): Promise>; - abstract readdirPromise(p: P, opts: {withFileTypes: false} | null): Promise>; - abstract readdirPromise(p: P, opts: {withFileTypes: true}): Promise>; - abstract readdirPromise(p: P, opts: {withFileTypes: boolean}): Promise | Array>; - - abstract readdirSync(p: P): Array; - abstract readdirSync(p: P, opts: {withFileTypes: false} | null): Array; - abstract readdirSync(p: P, opts: {withFileTypes: true}): Array; - abstract readdirSync(p: P, opts: {withFileTypes: boolean}): Array | Array; + abstract readdirPromise(p: P, opts?: null): Promise>; + abstract readdirPromise(p: P, opts: {recursive?: false, withFileTypes: true}): Promise>; + abstract readdirPromise(p: P, opts: {recursive?: false, withFileTypes?: false}): Promise>; + abstract readdirPromise(p: P, opts: {recursive?: false, withFileTypes: boolean}): Promise>; + abstract readdirPromise(p: P, opts: {recursive: true, withFileTypes: true}): Promise>>; + abstract readdirPromise(p: P, opts: {recursive: true, withFileTypes?: false}): Promise>; + abstract readdirPromise(p: P, opts: {recursive: true, withFileTypes: boolean}): Promise | P>>; + abstract readdirPromise(p: P, opts: {recursive: boolean, withFileTypes: true}): Promise | DirentNoPath>>; + abstract readdirPromise(p: P, opts: {recursive: boolean, withFileTypes?: false}): Promise>; + abstract readdirPromise(p: P, opts: {recursive: boolean, withFileTypes: boolean}): Promise | DirentNoPath | P>>; + abstract readdirPromise(p: P, opts?: ReaddirOptions | null): Promise | DirentNoPath | P>>; + + abstract readdirSync(p: P, opts?: null): Array; + abstract readdirSync(p: P, opts: {recursive?: false, withFileTypes: true}): Array; + abstract readdirSync(p: P, opts: {recursive?: false, withFileTypes?: false}): Array; + abstract readdirSync(p: P, opts: {recursive?: false, withFileTypes: boolean}): Array; + abstract readdirSync(p: P, opts: {recursive: true, withFileTypes: true}): Array>; + abstract readdirSync(p: P, opts: {recursive: true, withFileTypes?: false}): Array

; + abstract readdirSync(p: P, opts: {recursive: true, withFileTypes: boolean}): Array | P>; + abstract readdirSync(p: P, opts: {recursive: boolean, withFileTypes: true}): Array | DirentNoPath>; + abstract readdirSync(p: P, opts: {recursive: boolean, withFileTypes?: false}): Array

; + abstract readdirSync(p: P, opts: {recursive: boolean, withFileTypes: boolean}): Array | DirentNoPath | P>; + abstract readdirSync(p: P, opts?: ReaddirOptions | null): Array | DirentNoPath | P>; abstract existsPromise(p: P): Promise; abstract existsSync(p: P): boolean; diff --git a/packages/yarnpkg-fslib/sources/MountFS.ts b/packages/yarnpkg-fslib/sources/MountFS.ts index fd0f954d5002..8d1b403c6d21 100644 --- a/packages/yarnpkg-fslib/sources/MountFS.ts +++ b/packages/yarnpkg-fslib/sources/MountFS.ts @@ -1,6 +1,6 @@ import {BigIntStats, constants, Stats} from 'fs'; -import {WatchOptions, WatchCallback, Watcher, StatOptions, StatSyncOptions} from './FakeFS'; +import {WatchOptions, WatchCallback, Watcher, StatOptions, StatSyncOptions, ReaddirOptions, DirentNoPath} from './FakeFS'; import {FakeFS, MkdirOptions, RmdirOptions, WriteFileOptions, OpendirOptions} from './FakeFS'; import {Dirent, SymlinkType} from './FakeFS'; import {CreateReadStreamOptions, CreateWriteStreamOptions, BasePortableFakeFS, ExtractHintOptions, WatchFileOptions, WatchFileCallback, StatWatcher} from './FakeFS'; @@ -806,11 +806,17 @@ export class MountFS extends BasePortableFakeFS { }); } - async readdirPromise(p: PortablePath): Promise>; - async readdirPromise(p: PortablePath, opts: {withFileTypes: false} | null): Promise>; - async readdirPromise(p: PortablePath, opts: {withFileTypes: true}): Promise>; - async readdirPromise(p: PortablePath, opts: {withFileTypes: boolean}): Promise | Array>; - async readdirPromise(p: PortablePath, opts?: {withFileTypes?: boolean} | null): Promise | Array> { + async readdirPromise(p: PortablePath, opts?: null): Promise>; + async readdirPromise(p: PortablePath, opts: {recursive?: false, withFileTypes: true}): Promise>; + async readdirPromise(p: PortablePath, opts: {recursive?: false, withFileTypes?: false}): Promise>; + async readdirPromise(p: PortablePath, opts: {recursive?: false, withFileTypes: boolean}): Promise>; + async readdirPromise(p: PortablePath, opts: {recursive: true, withFileTypes: true}): Promise>>; + async readdirPromise(p: PortablePath, opts: {recursive: true, withFileTypes?: false}): Promise>; + async readdirPromise(p: PortablePath, opts: {recursive: true, withFileTypes: boolean}): Promise | PortablePath>>; + async readdirPromise(p: PortablePath, opts: {recursive: boolean, withFileTypes: true}): Promise | DirentNoPath>>; + async readdirPromise(p: PortablePath, opts: {recursive: boolean, withFileTypes?: false}): Promise>; + async readdirPromise(p: PortablePath, opts: {recursive: boolean, withFileTypes: boolean}): Promise | DirentNoPath | PortablePath>>; + async readdirPromise(p: PortablePath, opts?: ReaddirOptions | null): Promise | DirentNoPath | PortablePath>> { return await this.makeCallPromise(p, async () => { return await this.baseFs.readdirPromise(p, opts as any); }, async (mountFs, {subPath}) => { @@ -820,11 +826,17 @@ export class MountFS extends BasePortableFakeFS { }); } - readdirSync(p: PortablePath): Array; - readdirSync(p: PortablePath, opts: {withFileTypes: false} | null): Array; - readdirSync(p: PortablePath, opts: {withFileTypes: true}): Array; - readdirSync(p: PortablePath, opts: {withFileTypes: boolean}): Array | Array; - readdirSync(p: PortablePath, opts?: {withFileTypes?: boolean} | null): Array | Array { + readdirSync(p: PortablePath, opts?: null): Array; + readdirSync(p: PortablePath, opts: {recursive?: false, withFileTypes: true}): Array; + readdirSync(p: PortablePath, opts: {recursive?: false, withFileTypes?: false}): Array; + readdirSync(p: PortablePath, opts: {recursive?: false, withFileTypes: boolean}): Array; + readdirSync(p: PortablePath, opts: {recursive: true, withFileTypes: true}): Array>; + readdirSync(p: PortablePath, opts: {recursive: true, withFileTypes?: false}): Array; + readdirSync(p: PortablePath, opts: {recursive: true, withFileTypes: boolean}): Array | PortablePath>; + readdirSync(p: PortablePath, opts: {recursive: boolean, withFileTypes: true}): Array | DirentNoPath>; + readdirSync(p: PortablePath, opts: {recursive: boolean, withFileTypes?: false}): Array; + readdirSync(p: PortablePath, opts: {recursive: boolean, withFileTypes: boolean}): Array | DirentNoPath | PortablePath>; + readdirSync(p: PortablePath, opts?: ReaddirOptions | null): Array | DirentNoPath | PortablePath> { return this.makeCallSync(p, () => { return this.baseFs.readdirSync(p, opts as any); }, (mountFs, {subPath}) => { diff --git a/packages/yarnpkg-fslib/sources/NodeFS.ts b/packages/yarnpkg-fslib/sources/NodeFS.ts index 5ce2dca97835..808c85ef8ea8 100644 --- a/packages/yarnpkg-fslib/sources/NodeFS.ts +++ b/packages/yarnpkg-fslib/sources/NodeFS.ts @@ -1,10 +1,10 @@ -import fs, {BigIntStats, Stats} from 'fs'; +import fs, {BigIntStats, Stats} from 'fs'; -import {CreateReadStreamOptions, CreateWriteStreamOptions, Dir, StatWatcher, WatchFileCallback, WatchFileOptions, OpendirOptions} from './FakeFS'; -import {Dirent, SymlinkType, StatSyncOptions, StatOptions} from './FakeFS'; -import {BasePortableFakeFS, WriteFileOptions} from './FakeFS'; -import {MkdirOptions, RmdirOptions, WatchOptions, WatchCallback, Watcher} from './FakeFS'; -import {FSPath, PortablePath, Filename, ppath, npath} from './path'; +import {CreateReadStreamOptions, CreateWriteStreamOptions, Dir, StatWatcher, WatchFileCallback, WatchFileOptions, OpendirOptions, ReaddirOptions, DirentNoPath} from './FakeFS'; +import {Dirent, SymlinkType, StatSyncOptions, StatOptions} from './FakeFS'; +import {BasePortableFakeFS, WriteFileOptions} from './FakeFS'; +import {MkdirOptions, RmdirOptions, WatchOptions, WatchCallback, Watcher} from './FakeFS'; +import {FSPath, PortablePath, Filename, ppath, npath} from './path'; export class NodeFS extends BasePortableFakeFS { private readonly realFs: typeof fs; @@ -422,12 +422,18 @@ export class NodeFS extends BasePortableFakeFS { return this.realFs.readFileSync(fsNativePath, encoding); } - async readdirPromise(p: PortablePath): Promise>; - async readdirPromise(p: PortablePath, opts: {withFileTypes: false} | null): Promise>; - async readdirPromise(p: PortablePath, opts: {withFileTypes: true}): Promise>; - async readdirPromise(p: PortablePath, opts: {withFileTypes: boolean}): Promise | Array>; - async readdirPromise(p: PortablePath, opts?: {withFileTypes?: boolean} | null): Promise | Array> { - return await new Promise | Array>((resolve, reject) => { + async readdirPromise(p: PortablePath, opts?: null): Promise>; + async readdirPromise(p: PortablePath, opts: {recursive?: false, withFileTypes: true}): Promise>; + async readdirPromise(p: PortablePath, opts: {recursive?: false, withFileTypes?: false}): Promise>; + async readdirPromise(p: PortablePath, opts: {recursive?: false, withFileTypes: boolean}): Promise>; + async readdirPromise(p: PortablePath, opts: {recursive: true, withFileTypes: true}): Promise>>; + async readdirPromise(p: PortablePath, opts: {recursive: true, withFileTypes?: false}): Promise>; + async readdirPromise(p: PortablePath, opts: {recursive: true, withFileTypes: boolean}): Promise | PortablePath>>; + async readdirPromise(p: PortablePath, opts: {recursive: boolean, withFileTypes: true}): Promise | DirentNoPath>>; + async readdirPromise(p: PortablePath, opts: {recursive: boolean, withFileTypes?: false}): Promise>; + async readdirPromise(p: PortablePath, opts: {recursive: boolean, withFileTypes: boolean}): Promise | DirentNoPath | PortablePath>>; + async readdirPromise(p: PortablePath, opts?: ReaddirOptions | null): Promise | DirentNoPath | PortablePath>> { + return await new Promise((resolve, reject) => { if (opts?.withFileTypes) { this.realFs.readdir(npath.fromPortablePath(p), {withFileTypes: true}, this.makeCallback(resolve, reject) as any); } else { @@ -436,15 +442,21 @@ export class NodeFS extends BasePortableFakeFS { }); } - readdirSync(p: PortablePath): Array; - readdirSync(p: PortablePath, opts: {withFileTypes: false} | null): Array; - readdirSync(p: PortablePath, opts: {withFileTypes: true}): Array; - readdirSync(p: PortablePath, opts: {withFileTypes: boolean}): Array | Array; - readdirSync(p: PortablePath, opts?: {withFileTypes?: boolean} | null): Array | Array { + readdirSync(p: PortablePath, opts?: null): Array; + readdirSync(p: PortablePath, opts: {recursive?: false, withFileTypes: true}): Array; + readdirSync(p: PortablePath, opts: {recursive?: false, withFileTypes?: false}): Array; + readdirSync(p: PortablePath, opts: {recursive?: false, withFileTypes: boolean}): Array; + readdirSync(p: PortablePath, opts: {recursive: true, withFileTypes: true}): Array>; + readdirSync(p: PortablePath, opts: {recursive: true, withFileTypes?: false}): Array; + readdirSync(p: PortablePath, opts: {recursive: true, withFileTypes: boolean}): Array | PortablePath>; + readdirSync(p: PortablePath, opts: {recursive: boolean, withFileTypes: true}): Array | DirentNoPath>; + readdirSync(p: PortablePath, opts: {recursive: boolean, withFileTypes?: false}): Array; + readdirSync(p: PortablePath, opts: {recursive: boolean, withFileTypes: boolean}): Array | DirentNoPath | PortablePath>; + readdirSync(p: PortablePath, opts?: ReaddirOptions | null): Array | DirentNoPath | PortablePath> { if (opts?.withFileTypes) { - return this.realFs.readdirSync(npath.fromPortablePath(p), {withFileTypes: true} as any); + return this.realFs.readdirSync(npath.fromPortablePath(p), {withFileTypes: true} as any) as Array; } else { - return this.realFs.readdirSync(npath.fromPortablePath(p)) as Array; + return this.realFs.readdirSync(npath.fromPortablePath(p)) as Array; } } diff --git a/packages/yarnpkg-fslib/sources/ProxiedFS.ts b/packages/yarnpkg-fslib/sources/ProxiedFS.ts index 16a99a0f49fb..efa4be569f3e 100644 --- a/packages/yarnpkg-fslib/sources/ProxiedFS.ts +++ b/packages/yarnpkg-fslib/sources/ProxiedFS.ts @@ -1,9 +1,9 @@ -import {Stats, BigIntStats} from 'fs'; +import {Stats, BigIntStats} from 'fs'; -import {CreateReadStreamOptions, CreateWriteStreamOptions, FakeFS, ExtractHintOptions, WatchFileCallback, WatchFileOptions, StatWatcher, Dir, OpendirOptions} from './FakeFS'; -import {Dirent, SymlinkType, StatSyncOptions, StatOptions} from './FakeFS'; -import {MkdirOptions, RmdirOptions, WriteFileOptions, WatchCallback, WatchOptions, Watcher} from './FakeFS'; -import {FSPath, Filename, Path} from './path'; +import {CreateReadStreamOptions, CreateWriteStreamOptions, FakeFS, ExtractHintOptions, WatchFileCallback, WatchFileOptions, StatWatcher, Dir, OpendirOptions, ReaddirOptions, DirentNoPath} from './FakeFS'; +import {Dirent, SymlinkType, StatSyncOptions, StatOptions} from './FakeFS'; +import {MkdirOptions, RmdirOptions, WriteFileOptions, WatchCallback, WatchOptions, Watcher} from './FakeFS'; +import {FSPath, Filename, Path} from './path'; export abstract class ProxiedFS

extends FakeFS

{ protected abstract readonly baseFs: FakeFS; @@ -316,19 +316,31 @@ export abstract class ProxiedFS

extends FakeFS< return this.baseFs.readFileSync(this.fsMapToBase(p), encoding); } - async readdirPromise(p: P): Promise>; - async readdirPromise(p: P, opts: {withFileTypes: false} | null): Promise>; - async readdirPromise(p: P, opts: {withFileTypes: true}): Promise>; - async readdirPromise(p: P, opts: {withFileTypes: boolean}): Promise | Array>; - async readdirPromise(p: P, opts?: {withFileTypes?: boolean} | null): Promise | Array> { + readdirPromise(p: P, opts?: null): Promise>; + readdirPromise(p: P, opts: {recursive?: false, withFileTypes: true}): Promise>; + readdirPromise(p: P, opts: {recursive?: false, withFileTypes?: false}): Promise>; + readdirPromise(p: P, opts: {recursive?: false, withFileTypes: boolean}): Promise>; + readdirPromise(p: P, opts: {recursive: true, withFileTypes: true}): Promise>>; + readdirPromise(p: P, opts: {recursive: true, withFileTypes?: false}): Promise>; + readdirPromise(p: P, opts: {recursive: true, withFileTypes: boolean}): Promise | P>>; + readdirPromise(p: P, opts: {recursive: boolean, withFileTypes: true}): Promise | DirentNoPath>>; + readdirPromise(p: P, opts: {recursive: boolean, withFileTypes?: false}): Promise>; + readdirPromise(p: P, opts: {recursive: boolean, withFileTypes: boolean}): Promise | DirentNoPath | P>>; + readdirPromise(p: P, opts?: ReaddirOptions | null): Promise | DirentNoPath | P | Filename>> { return this.baseFs.readdirPromise(this.mapToBase(p), opts as any); } - readdirSync(p: P): Array; - readdirSync(p: P, opts: {withFileTypes: false} | null): Array; - readdirSync(p: P, opts: {withFileTypes: true}): Array; - readdirSync(p: P, opts: {withFileTypes: boolean}): Array | Array; - readdirSync(p: P, opts?: {withFileTypes?: boolean} | null): Array | Array { + readdirSync(p: P, opts?: null): Array; + readdirSync(p: P, opts: {recursive?: false, withFileTypes: true}): Array; + readdirSync(p: P, opts: {recursive?: false, withFileTypes?: false}): Array; + readdirSync(p: P, opts: {recursive?: false, withFileTypes: boolean}): Array; + readdirSync(p: P, opts: {recursive: true, withFileTypes: true}): Array>; + readdirSync(p: P, opts: {recursive: true, withFileTypes?: false}): Array

; + readdirSync(p: P, opts: {recursive: true, withFileTypes: boolean}): Array | P>; + readdirSync(p: P, opts: {recursive: boolean, withFileTypes: true}): Array | DirentNoPath>; + readdirSync(p: P, opts: {recursive: boolean, withFileTypes?: false}): Array

; + readdirSync(p: P, opts: {recursive: boolean, withFileTypes: boolean}): Array | DirentNoPath | P>; + readdirSync(p: P, opts?: ReaddirOptions | null): Array | DirentNoPath | P | Filename> { return this.baseFs.readdirSync(this.mapToBase(p), opts as any); } diff --git a/packages/yarnpkg-fslib/sources/algorithms/opendir.ts b/packages/yarnpkg-fslib/sources/algorithms/opendir.ts index a55c6770824b..ff1065322b59 100644 --- a/packages/yarnpkg-fslib/sources/algorithms/opendir.ts +++ b/packages/yarnpkg-fslib/sources/algorithms/opendir.ts @@ -1,8 +1,8 @@ -import {NoParamCallback} from 'fs'; +import {NoParamCallback} from 'fs'; -import {Dir, Dirent, FakeFS} from '../FakeFS'; -import * as errors from '../errors'; -import {Filename, Path} from '../path'; +import {Dir, DirentNoPath, FakeFS} from '../FakeFS'; +import * as errors from '../errors'; +import {Filename, Path} from '../path'; export type CustomDirOptions = { onClose?: () => void; @@ -11,7 +11,7 @@ export type CustomDirOptions = { export class CustomDir

implements Dir

{ constructor( public readonly path: P, - private readonly nextDirent: () => Dirent | null, + private readonly nextDirent: () => DirentNoPath | null, private readonly opts: CustomDirOptions = {}, ) {} @@ -25,7 +25,7 @@ export class CustomDir

implements Dir

{ async * [Symbol.asyncIterator]() { try { - let dirent: Dirent | null; + let dirent: DirentNoPath | null; // eslint-disable-next-line no-cond-assign while ((dirent = await this.read()) !== null) { yield dirent; @@ -35,9 +35,9 @@ export class CustomDir

implements Dir

{ } } - read(): Promise; - read(cb: (err: NodeJS.ErrnoException | null, dirent: Dirent | null) => void): void; - read(cb?: (err: NodeJS.ErrnoException | null, dirent: Dirent | null) => void) { + read(): Promise; + read(cb: (err: NodeJS.ErrnoException | null, dirent: DirentNoPath | null) => void): void; + read(cb?: (err: NodeJS.ErrnoException | null, dirent: DirentNoPath | null) => void) { const dirent = this.readSync(); if (typeof cb !== `undefined`) @@ -79,6 +79,7 @@ export function opendir

(fakeFs: FakeFS

, path: P, entries: Arr return Object.assign(fakeFs.statSync(fakeFs.pathUtils.join(path, filename)), { name: filename, + path: undefined, }); }; diff --git a/packages/yarnpkg-fslib/sources/index.ts b/packages/yarnpkg-fslib/sources/index.ts index e85125a0507a..df4843e8490c 100644 --- a/packages/yarnpkg-fslib/sources/index.ts +++ b/packages/yarnpkg-fslib/sources/index.ts @@ -11,24 +11,25 @@ export {setupCopyIndex} from './algorithms/copyPromise' export {opendir, CustomDir} from './algorithms/opendir'; export {watchFile, unwatchFile, unwatchAllFiles} from './algorithms/watchFile'; -export {normalizeLineEndings} from './FakeFS'; -export type {BufferEncodingOrBuffer} from './FakeFS'; -export type {CreateReadStreamOptions} from './FakeFS'; -export type {CreateWriteStreamOptions} from './FakeFS'; -export type {Dirent, Dir, SymlinkType} from './FakeFS'; -export type {MkdirOptions} from './FakeFS'; -export type {RmdirOptions} from './FakeFS'; -export type {WatchOptions} from './FakeFS'; -export type {WatchCallback} from './FakeFS'; -export type {Watcher} from './FakeFS'; -export type {WriteFileOptions} from './FakeFS'; -export type {ExtractHintOptions} from './FakeFS'; -export type {WatchFileOptions} from './FakeFS'; -export type {WatchFileCallback} from './FakeFS'; -export type {StatWatcher} from './FakeFS'; -export type {OpendirOptions} from './FakeFS'; -export type {StatOptions, StatSyncOptions} from './FakeFS'; -export type {Stats, BigIntStats} from './FakeFS'; +export {normalizeLineEndings} from './FakeFS'; +export type {BufferEncodingOrBuffer} from './FakeFS'; +export type {CreateReadStreamOptions} from './FakeFS'; +export type {CreateWriteStreamOptions} from './FakeFS'; +export type {Dirent, DirentNoPath, Dir, SymlinkType} from './FakeFS'; +export type {MkdirOptions} from './FakeFS'; +export type {ReaddirOptions} from './FakeFS'; +export type {RmdirOptions} from './FakeFS'; +export type {WatchOptions} from './FakeFS'; +export type {WatchCallback} from './FakeFS'; +export type {Watcher} from './FakeFS'; +export type {WriteFileOptions} from './FakeFS'; +export type {ExtractHintOptions} from './FakeFS'; +export type {WatchFileOptions} from './FakeFS'; +export type {WatchFileCallback} from './FakeFS'; +export type {StatWatcher} from './FakeFS'; +export type {OpendirOptions} from './FakeFS'; +export type {StatOptions, StatSyncOptions} from './FakeFS'; +export type {Stats, BigIntStats} from './FakeFS'; export {PortablePath, Filename} from './path'; export type {FSPath, Path, NativePath} from './path'; diff --git a/packages/yarnpkg-fslib/sources/statUtils.ts b/packages/yarnpkg-fslib/sources/statUtils.ts index e86644894b07..745eedb52495 100644 --- a/packages/yarnpkg-fslib/sources/statUtils.ts +++ b/packages/yarnpkg-fslib/sources/statUtils.ts @@ -6,8 +6,10 @@ import {Filename} from './path'; export const DEFAULT_MODE = S_IFREG | 0o644; -export class DirEntry { +export class DirEntry { public name: Filename = `` as Filename; + public path: T = `` as T; + public mode: number = 0; isBlockDevice() { diff --git a/packages/yarnpkg-fslib/tests/FakeFS.types.ts b/packages/yarnpkg-fslib/tests/FakeFS.types.ts new file mode 100644 index 000000000000..de8fe7aad397 --- /dev/null +++ b/packages/yarnpkg-fslib/tests/FakeFS.types.ts @@ -0,0 +1,22 @@ +import {Dirent, DirentNoPath, FakeFS, Filename, PortablePath} from '../sources'; + +declare const fakeFs: FakeFS; + +type AssertEqual = [T, Expected] extends [Expected, T] ? true : false; + +function assertEqual() { + return (val: V, expected: AssertEqual) => {}; +} + +Promise.resolve().then(async () => { + assertEqual>()(await fakeFs.readdirPromise(PortablePath.dot), true); + assertEqual>()(await fakeFs.readdirPromise(PortablePath.dot, {}), true); + + assertEqual>()(await fakeFs.readdirPromise(PortablePath.dot, {recursive: Boolean()}), true); + + assertEqual>()(await fakeFs.readdirPromise(PortablePath.dot, {recursive: true}), true); + assertEqual>>()(await fakeFs.readdirPromise(PortablePath.dot, {recursive: true, withFileTypes: true}), true); + + assertEqual>()(await fakeFs.readdirPromise(PortablePath.dot, {recursive: false}), true); + assertEqual>()(await fakeFs.readdirPromise(PortablePath.dot, {recursive: false, withFileTypes: true}), true); +}); diff --git a/packages/yarnpkg-libzip/sources/ZipFS.ts b/packages/yarnpkg-libzip/sources/ZipFS.ts index 458a4e9933c2..67dcf8651093 100644 --- a/packages/yarnpkg-libzip/sources/ZipFS.ts +++ b/packages/yarnpkg-libzip/sources/ZipFS.ts @@ -1,3 +1,4 @@ +import {Dirent, DirentNoPath, ReaddirOptions} from '@yarnpkg/fslib'; import {WatchOptions, WatchCallback, Watcher, Dir, Stats, BigIntStats, StatSyncOptions, StatOptions} from '@yarnpkg/fslib'; import {FakeFS, MkdirOptions, RmdirOptions, WriteFileOptions, OpendirOptions} from '@yarnpkg/fslib'; import {CreateReadStreamOptions, CreateWriteStreamOptions, BasePortableFakeFS, ExtractHintOptions, WatchFileCallback, WatchFileOptions, StatWatcher} from '@yarnpkg/fslib'; @@ -1447,19 +1448,31 @@ export class ZipFS extends BasePortableFakeFS { return this.getFileSource(entry, opts); } - async readdirPromise(p: PortablePath): Promise>; - async readdirPromise(p: PortablePath, opts: {withFileTypes: false} | null): Promise>; - async readdirPromise(p: PortablePath, opts: {withFileTypes: true}): Promise>; - async readdirPromise(p: PortablePath, opts: {withFileTypes: boolean}): Promise | Array>; - async readdirPromise(p: PortablePath, opts?: {withFileTypes?: boolean} | null): Promise | Array> { + async readdirPromise(p: PortablePath, opts?: null): Promise>; + async readdirPromise(p: PortablePath, opts: {recursive?: false, withFileTypes: true}): Promise>; + async readdirPromise(p: PortablePath, opts: {recursive?: false, withFileTypes?: false}): Promise>; + async readdirPromise(p: PortablePath, opts: {recursive?: false, withFileTypes: boolean}): Promise>; + async readdirPromise(p: PortablePath, opts: {recursive: true, withFileTypes: true}): Promise>>; + async readdirPromise(p: PortablePath, opts: {recursive: true, withFileTypes?: false}): Promise>; + async readdirPromise(p: PortablePath, opts: {recursive: true, withFileTypes: boolean}): Promise | PortablePath>>; + async readdirPromise(p: PortablePath, opts: {recursive: boolean, withFileTypes: true}): Promise | DirentNoPath>>; + async readdirPromise(p: PortablePath, opts: {recursive: boolean, withFileTypes?: false}): Promise>; + async readdirPromise(p: PortablePath, opts: {recursive: boolean, withFileTypes: boolean}): Promise | DirentNoPath | PortablePath>>; + async readdirPromise(p: PortablePath, opts?: ReaddirOptions | null): Promise | DirentNoPath | PortablePath>> { return this.readdirSync(p, opts as any); } - readdirSync(p: PortablePath): Array; - readdirSync(p: PortablePath, opts: {withFileTypes: false} | null): Array; - readdirSync(p: PortablePath, opts: {withFileTypes: true}): Array; - readdirSync(p: PortablePath, opts: {withFileTypes: boolean}): Array | Array; - readdirSync(p: PortablePath, opts?: {withFileTypes?: boolean} | null): Array | Array { + readdirSync(p: PortablePath, opts?: null): Array; + readdirSync(p: PortablePath, opts: {recursive?: false, withFileTypes: true}): Array; + readdirSync(p: PortablePath, opts: {recursive?: false, withFileTypes?: false}): Array; + readdirSync(p: PortablePath, opts: {recursive?: false, withFileTypes: boolean}): Array; + readdirSync(p: PortablePath, opts: {recursive: true, withFileTypes: true}): Array>; + readdirSync(p: PortablePath, opts: {recursive: true, withFileTypes?: false}): Array; + readdirSync(p: PortablePath, opts: {recursive: true, withFileTypes: boolean}): Array | PortablePath>; + readdirSync(p: PortablePath, opts: {recursive: boolean, withFileTypes: true}): Array | DirentNoPath>; + readdirSync(p: PortablePath, opts: {recursive: boolean, withFileTypes?: false}): Array; + readdirSync(p: PortablePath, opts: {recursive: boolean, withFileTypes: boolean}): Array | DirentNoPath | PortablePath>; + readdirSync(p: PortablePath, opts?: ReaddirOptions | null): Array | DirentNoPath | PortablePath> { const resolvedP = this.resolveFilename(`scandir '${p}'`, p); if (!this.entries.has(resolvedP) && !this.listings.has(resolvedP)) throw errors.ENOENT(`scandir '${p}'`); @@ -1468,15 +1481,56 @@ export class ZipFS extends BasePortableFakeFS { if (!directoryListing) throw errors.ENOTDIR(`scandir '${p}'`); - const entries = [...directoryListing]; - if (!opts?.withFileTypes) - return entries; + if (opts?.recursive) { + if (opts?.withFileTypes) { + const entries = Array.from(directoryListing, name => { + return Object.assign(this.statImpl(`lstat`, ppath.join(p, name)), { + name, + path: PortablePath.dot, + }); + }); + + for (const entry of entries) { + if (!entry.isDirectory()) + continue; + + const subPath = ppath.join(entry.path, entry.name); + const subListing = this.listings.get(ppath.join(resolvedP, subPath))!; + + for (const child of subListing) { + entries.push(Object.assign(this.statImpl(`lstat`, ppath.join(p, subPath, child)), { + name: child, + path: subPath, + })); + } + } + + return entries; + } else { + const entries: Array = [...directoryListing]; - return entries.map(name => { - return Object.assign(this.statImpl(`lstat`, ppath.join(p, name)), { - name, + for (const subPath of entries) { + const subListing = this.listings.get(ppath.join(resolvedP, subPath)); + if (typeof subListing === `undefined`) + continue; + + for (const child of subListing) { + entries.push(ppath.join(subPath, child)); + } + } + + return entries; + } + } else if (opts?.withFileTypes) { + return Array.from(directoryListing, name => { + return Object.assign(this.statImpl(`lstat`, ppath.join(p, name)), { + name, + path: undefined, + }); }); - }); + } else { + return [...directoryListing]; + } } async readlinkPromise(p: PortablePath) { diff --git a/packages/yarnpkg-libzip/tests/ZipFS.test.ts b/packages/yarnpkg-libzip/tests/ZipFS.test.ts index a177771f31cb..b73276f88184 100644 --- a/packages/yarnpkg-libzip/tests/ZipFS.test.ts +++ b/packages/yarnpkg-libzip/tests/ZipFS.test.ts @@ -911,6 +911,78 @@ describe(`ZipFS`, () => { zipFs.discardAndClose(); }); + it(`should support the recursive flag in readdir`, () => { + const zipFs = new ZipFS(); + + zipFs.mkdirSync(`/foo` as PortablePath); + zipFs.mkdirSync(`/foo/bar` as PortablePath); + zipFs.mkdirSync(`/bar` as PortablePath); + + zipFs.writeFileSync(`/foo/file.txt` as PortablePath, `Test`); + zipFs.writeFileSync(`/foo/bar/file.txt` as PortablePath, `Test`); + zipFs.writeFileSync(`/bar/file.txt` as PortablePath, `Test`); + zipFs.writeFileSync(`/file.txt` as PortablePath, `Test`); + + const zipContent = zipFs.getBufferAndClose(); + + const zipFs2 = new ZipFS(zipContent); + expect(zipFs2.readdirSync(`/` as PortablePath, {recursive: true}).sort()).toEqual([ + `bar`, + `bar/file.txt`, + `file.txt`, + `foo`, + `foo/bar`, + `foo/bar/file.txt`, + `foo/file.txt`, + ]); + + expect(zipFs2.readdirSync(`/foo` as PortablePath, {recursive: true}).sort()).toEqual([ + `bar`, + `bar/file.txt`, + `file.txt`, + ]); + }); + + it(`should support the combination of recursive and withFileTypes in readdir`, () => { + const zipFs = new ZipFS(); + + zipFs.mkdirSync(`/foo` as PortablePath); + zipFs.mkdirSync(`/foo/bar` as PortablePath); + zipFs.mkdirSync(`/bar` as PortablePath); + + zipFs.writeFileSync(`/foo/file.txt` as PortablePath, `Test`); + zipFs.writeFileSync(`/foo/bar/file.txt` as PortablePath, `Test`); + zipFs.writeFileSync(`/bar/file.txt` as PortablePath, `Test`); + zipFs.writeFileSync(`/file.txt` as PortablePath, `Test`); + + const zipContent = zipFs.getBufferAndClose(); + + const readdir = (p: PortablePath) => { + return zipFs2.readdirSync(p, {recursive: true, withFileTypes: true}).sort((a, b) => { + return a.path.localeCompare(b.path) || a.name.localeCompare(b.name); + }).map(({name, path}) => { + return {name, path}; + }); + }; + + const zipFs2 = new ZipFS(zipContent); + expect(readdir(PortablePath.root)).toEqual([ + {name: `bar`, path: `.`}, + {name: `file.txt`, path: `.`}, + {name: `foo`, path: `.`}, + {name: `file.txt`, path: `bar`}, + {name: `bar`, path: `foo`}, + {name: `file.txt`, path: `foo`}, + {name: `file.txt`, path: `foo/bar`}, + ]); + + expect(readdir(ppath.join(PortablePath.root, `foo`))).toEqual([ + {name: `bar`, path: `.`}, + {name: `file.txt`, path: `.`}, + {name: `file.txt`, path: `bar`}, + ]); + }); + it(`should support throwIfNoEntry`, async () => { const zipFs = new ZipFS(); diff --git a/packages/yarnpkg-pnpify/sources/NodeModulesFS.ts b/packages/yarnpkg-pnpify/sources/NodeModulesFS.ts index e2df997a8b53..ad6021ec6678 100644 --- a/packages/yarnpkg-pnpify/sources/NodeModulesFS.ts +++ b/packages/yarnpkg-pnpify/sources/NodeModulesFS.ts @@ -1,3 +1,4 @@ +import {DirentNoPath, ReaddirOptions} from '@yarnpkg/fslib'; import {Dirent, Filename, MkdirOptions, ExtractHintOptions, WatchFileCallback, WatchFileOptions, StatWatcher, OpendirOptions, Dir} from '@yarnpkg/fslib'; import {RmdirOptions} from '@yarnpkg/fslib'; import {FSPath, NativePath, PortablePath, npath, ppath, opendir} from '@yarnpkg/fslib'; @@ -500,19 +501,29 @@ export class PortableNodeModulesFS extends FakeFS { return this.baseFs.readFileSync(this.resolveFilePath(p), encoding); } - async readdirPromise(p: PortablePath): Promise>; - async readdirPromise(p: PortablePath, opts: {withFileTypes: false} | null): Promise>; - async readdirPromise(p: PortablePath, opts: {withFileTypes: true}): Promise>; - async readdirPromise(p: PortablePath, opts: {withFileTypes: boolean}): Promise | Array>; - async readdirPromise(p: PortablePath, opts?: {withFileTypes?: boolean} | null): Promise | Array> { + async readdirPromise(p: PortablePath, opts?: null): Promise>; + async readdirPromise(p: PortablePath, opts: {recursive?: false, withFileTypes: true}): Promise>; + async readdirPromise(p: PortablePath, opts: {recursive?: false, withFileTypes?: false}): Promise>; + async readdirPromise(p: PortablePath, opts: {recursive?: false, withFileTypes: boolean}): Promise>; + async readdirPromise(p: PortablePath, opts: {recursive: true, withFileTypes: true}): Promise>>; + async readdirPromise(p: PortablePath, opts: {recursive: true, withFileTypes?: false}): Promise>; + async readdirPromise(p: PortablePath, opts: {recursive: true, withFileTypes: boolean}): Promise | PortablePath>>; + async readdirPromise(p: PortablePath, opts: {recursive: boolean, withFileTypes: true}): Promise | DirentNoPath>>; + async readdirPromise(p: PortablePath, opts: {recursive: boolean, withFileTypes?: false}): Promise>; + async readdirPromise(p: PortablePath, opts: {recursive: boolean, withFileTypes: boolean}): Promise | DirentNoPath | PortablePath>>; + async readdirPromise(p: PortablePath, opts?: ReaddirOptions | null): Promise | DirentNoPath | PortablePath>> { const pnpPath = this.resolvePath(p); if (pnpPath.dirList || this.resolvePath(ppath.join(p, `node_modules`)).dirList) { + if (opts?.recursive) + throw new Error(`Unsupported option 'recursive' for NodeModulesFS.readdirPromise`); + let fsDirList: Array = []; try { fsDirList = await this.baseFs.readdirPromise(pnpPath.resolvedPath); } catch (e) { // Ignore errors } + const entries = Array.from(pnpPath.dirList || [`node_modules` as Filename]).concat(fsDirList).sort(); if (!opts?.withFileTypes) return entries; @@ -520,26 +531,37 @@ export class PortableNodeModulesFS extends FakeFS { return entries.map(name => { return Object.assign(this.lstatSync(ppath.join(p, name)), { name, + path: undefined, }); - }); + }) ; } else { return await this.baseFs.readdirPromise(pnpPath.resolvedPath, opts as any); } } - readdirSync(p: PortablePath): Array; - readdirSync(p: PortablePath, opts: {withFileTypes: false} | null): Array; - readdirSync(p: PortablePath, opts: {withFileTypes: true}): Array; - readdirSync(p: PortablePath, opts: {withFileTypes: boolean}): Array | Array; - readdirSync(p: PortablePath, opts?: {withFileTypes?: boolean} | null): Array | Array { + readdirSync(p: PortablePath, opts?: null): Array; + readdirSync(p: PortablePath, opts: {recursive?: false, withFileTypes: true}): Array; + readdirSync(p: PortablePath, opts: {recursive?: false, withFileTypes?: false}): Array; + readdirSync(p: PortablePath, opts: {recursive?: false, withFileTypes: boolean}): Array; + readdirSync(p: PortablePath, opts: {recursive: true, withFileTypes: true}): Array>; + readdirSync(p: PortablePath, opts: {recursive: true, withFileTypes?: false}): Array; + readdirSync(p: PortablePath, opts: {recursive: true, withFileTypes: boolean}): Array | PortablePath>; + readdirSync(p: PortablePath, opts: {recursive: boolean, withFileTypes: true}): Array | DirentNoPath>; + readdirSync(p: PortablePath, opts: {recursive: boolean, withFileTypes?: false}): Array; + readdirSync(p: PortablePath, opts: {recursive: boolean, withFileTypes: boolean}): Array | DirentNoPath | PortablePath>; + readdirSync(p: PortablePath, opts?: ReaddirOptions | null): Array | DirentNoPath | PortablePath> { const pnpPath = this.resolvePath(p); if (pnpPath.dirList || this.resolvePath(ppath.join(p, `node_modules`)).dirList) { + if (opts?.recursive) + throw new Error(`Unsupported option 'recursive' for NodeModulesFS.readdirSync`); + let fsDirList: Array = []; try { fsDirList = this.baseFs.readdirSync(pnpPath.resolvedPath); } catch (e) { // Ignore errors } + const entries = Array.from(pnpPath.dirList || [`node_modules` as Filename]).concat(fsDirList).sort(); if (!opts?.withFileTypes) return entries; @@ -547,6 +569,7 @@ export class PortableNodeModulesFS extends FakeFS { return entries.map(name => { return Object.assign(this.lstatSync(ppath.join(p, name)), { name, + path: undefined, }); }); } else {