diff --git a/src/main.ts b/src/main.ts index a08c467d..4c35dcec 100644 --- a/src/main.ts +++ b/src/main.ts @@ -75,8 +75,9 @@ module.exports = function (argv: string[]): void { .option('--dependencies', 'Enable dependency detection via npm or yarn', undefined) .option('--no-dependencies', 'Disable dependency detection via npm or yarn', undefined) .option('--readme-path ', 'Path to README file (defaults to README.md)') - .action(({ tree, yarn, packagedDependencies, ignoreFile, dependencies, readmePath }) => - main(ls({ tree, useYarn: yarn, packagedDependencies, ignoreFile, dependencies, readmePath })) + .option('--follow-symlinks', 'Recurse into symlinked directories instead of treating them as files') + .action(({ tree, yarn, packagedDependencies, ignoreFile, dependencies, readmePath, followSymlinks }) => + main(ls({ tree, useYarn: yarn, packagedDependencies, ignoreFile, dependencies, readmePath, followSymlinks })) ); program @@ -119,6 +120,7 @@ module.exports = function (argv: string[]): void { .option('--allow-unused-files-pattern', 'Allow include patterns for the files field in package.json that does not match any file') .option('--skip-license', 'Allow packaging without license file') .option('--sign-tool ', 'Path to the VSIX signing tool. Will be invoked with two arguments: `SIGNTOOL `.') + .option('--follow-symlinks', 'Recurse into symlinked directories instead of treating them as files') .action( ( version, @@ -147,6 +149,7 @@ module.exports = function (argv: string[]): void { allowUnusedFilesPattern, skipLicense, signTool, + followSymlinks, } ) => main( @@ -176,6 +179,7 @@ module.exports = function (argv: string[]): void { allowUnusedFilesPattern, skipLicense, signTool, + followSymlinks, }) ) ); @@ -229,6 +233,7 @@ module.exports = function (argv: string[]): void { .option('--allow-unused-files-pattern', 'Allow include patterns for the files field in package.json that does not match any file') .option('--skip-duplicate', 'Fail silently if version already exists on the marketplace') .option('--skip-license', 'Allow publishing without license file') + .option('--follow-symlinks', 'Recurse into symlinked directories instead of treating them as files') .action( ( version, @@ -263,6 +268,7 @@ module.exports = function (argv: string[]): void { skipDuplicate, skipLicense, signTool, + followSymlinks, } ) => main( @@ -297,7 +303,8 @@ module.exports = function (argv: string[]): void { allowUnusedFilesPattern, skipDuplicate, skipLicense, - signTool + signTool, + followSymlinks }) ) ); diff --git a/src/package.ts b/src/package.ts index f31e9689..b0b95ea3 100644 --- a/src/package.ts +++ b/src/package.ts @@ -95,11 +95,16 @@ export interface IPackageOptions { * `target` is set. For example, if `target` is `linux-x64` and there are * folders named `win32-x64`, `darwin-arm64` or `web`, the files inside * those folders will be ignored. - * + * * @default false */ readonly ignoreOtherTargetFolders?: boolean; + /** + * Recurse into symlinked directories instead of treating them as files. + */ + readonly followSymlinks?: boolean; + readonly commitMessage?: string; readonly gitTagVersion?: boolean; readonly updatePackageJson?: boolean; @@ -1630,11 +1635,12 @@ const defaultIgnore = [ async function collectAllFiles( cwd: string, dependencies: 'npm' | 'yarn' | 'none' | undefined, - dependencyEntryPoints?: string[] + dependencyEntryPoints?: string[], + followSymlinks:boolean = true ): Promise { const deps = await getDependencies(cwd, dependencies, dependencyEntryPoints); const promises = deps.map(dep => - glob('**', { cwd: dep, nodir: true, dot: true, ignore: 'node_modules/**' }).then(files => + glob('**', { cwd: dep, nodir: true, follow: followSymlinks, dot: true, ignore: 'node_modules/**' }).then(files => files.map(f => path.relative(cwd, path.join(dep, f))).map(f => f.replace(/\\/g, '/')) ) ); @@ -1664,11 +1670,12 @@ function collectFiles( ignoreFile?: string, manifestFileIncludes?: string[], readmePath?: string, + followSymlinks:boolean = false ): Promise { readmePath = readmePath ?? 'README.md'; const notIgnored = ['!package.json', `!${readmePath}`]; - return collectAllFiles(cwd, dependencies, dependencyEntryPoints).then(files => { + return collectAllFiles(cwd, dependencies, dependencyEntryPoints, followSymlinks).then(files => { files = files.filter(f => !/\r$/m.test(f)); return ( @@ -1683,7 +1690,7 @@ function collectFiles( manifestFileIncludes ? // include all files in manifestFileIncludes and ignore the rest Promise.resolve(manifestFileIncludes.map(file => `!${file}`).concat(['**']).join('\n\r')) : - // "files" property not used in package.json + // "files" property not used in package.json Promise.resolve('') ) @@ -1775,7 +1782,7 @@ export function collect(manifest: ManifestPackage, options: IPackageOptions = {} const ignoreFile = options.ignoreFile || undefined; const processors = createDefaultProcessors(manifest, options); - return collectFiles(cwd, getDependenciesOption(options), packagedDependencies, ignoreFile, manifest.files, options.readmePath).then(fileNames => { + return collectFiles(cwd, getDependenciesOption(options), packagedDependencies, ignoreFile, manifest.files, options.readmePath, options.followSymlinks).then(fileNames => { const files = fileNames.map(f => ({ path: util.filePathToVsixPath(f), localPath: path.join(cwd, f) })); return processFiles(processors, files); @@ -1948,6 +1955,7 @@ export interface IListFilesOptions { readonly dependencies?: boolean; readonly prepublish?: boolean; readonly readmePath?: string; + readonly followSymlinks?: boolean; } /** @@ -1961,7 +1969,7 @@ export async function listFiles(options: IListFilesOptions = {}): Promise 0 && !options.allowUnusedFilesPattern) { const localPaths = (files.filter(f => !isInMemoryFile(f)) as ILocalFile[]).map(f => util.normalize(f.localPath)); diff --git a/src/publish.ts b/src/publish.ts index 318eb7d3..0810112e 100644 --- a/src/publish.ts +++ b/src/publish.ts @@ -58,6 +58,11 @@ export interface IPublishOptions { readonly dependencyEntryPoints?: string[]; readonly ignoreFile?: string; + /** + * Recurse into symlinked directories instead of treating them as files + */ + readonly followSymlinks?: boolean; + /** * The Personal Access Token to use. * @@ -352,4 +357,4 @@ export async function getPAT(publisher: string, options: IPublishOptions | IUnpu } return (await getPublisher(publisher)).pat; -} \ No newline at end of file +}