Skip to content

Commit 134eaa6

Browse files
committed
fix unused-files-patterns check and add tests
1 parent 0ec0e7f commit 134eaa6

File tree

5 files changed

+98
-6
lines changed

5 files changed

+98
-6
lines changed

src/package.ts

+19-4
Original file line numberDiff line numberDiff line change
@@ -1955,7 +1955,7 @@ export async function ls(options: ILSOptions = {}): Promise<void> {
19551955
if (options.tree) {
19561956
const printableFileStructure = await util.generateFileStructureTree(
19571957
getDefaultPackageName(manifest, options),
1958-
files.map(f => ({ origin: f, tree: f }))
1958+
files.map(f => ({ origin: path.join(cwd, f), tree: f }))
19591959
);
19601960
console.log(printableFileStructure.join('\n'));
19611961
} else {
@@ -1998,8 +1998,23 @@ export async function printAndValidatePackagedFiles(files: IFile[], cwd: string,
19981998
// Throw an error if the extension uses the files property in package.json and
19991999
// the package does not include at least one file for each include pattern
20002000
else if (manifest.files !== undefined && manifest.files.length > 0 && !options.allowUnusedFilesPattern) {
2001-
const originalFilePaths = files.map(f => util.vsixPathToFilePath(f.path));
2002-
const unusedIncludePatterns = manifest.files.filter(includePattern => !originalFilePaths.some(filePath => minimatch(filePath, includePattern, MinimatchOptions)));
2001+
const localPaths = (files.filter(f => !isInMemoryFile(f)) as ILocalFile[]).map(f => util.normalize(f.localPath));
2002+
const filesIncludePatterns = manifest.files.map(includePattern => util.normalize(path.join(cwd, includePattern)));
2003+
2004+
const unusedIncludePatterns = filesIncludePatterns.filter(includePattern => {
2005+
// Check if the pattern provided by the user matches any file in the package
2006+
if (localPaths.some(localFilePath => minimatch(localFilePath, includePattern, MinimatchOptions))) {
2007+
return false;
2008+
}
2009+
// Check if the pattern provided by the user matches any folder in the package
2010+
if (!/(^|\/)[^/]*\*[^/]*$/.test(includePattern)) {
2011+
includePattern = (/\/$/.test(includePattern) ? `${includePattern}**` : `${includePattern}/**`);
2012+
return !localPaths.some(localFilePath => minimatch(localFilePath, includePattern, MinimatchOptions));
2013+
}
2014+
// Pattern does not match any file or folder
2015+
return true;
2016+
});
2017+
20032018
if (unusedIncludePatterns.length > 0) {
20042019
let message = '';
20052020
message += `The following include patterns in the ${chalk.bold('"files"')} property in package.json do not match any files packaged in the extension:\n`;
@@ -2017,7 +2032,7 @@ export async function printAndValidatePackagedFiles(files: IFile[], cwd: string,
20172032
getDefaultPackageName(manifest, options),
20182033
files.map(f => ({
20192034
// File path relative to the extension root
2020-
origin: util.vsixPathToFilePath(f.path),
2035+
origin: !isInMemoryFile(f) ? f.localPath : path.join(cwd, util.vsixPathToFilePath(f.path)),
20212036
// File path in the VSIX
20222037
tree: f.path
20232038
})),
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
LICENSE...
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Some text in here!
2+
Some text in here!
3+
Some text in here!
4+
Some text in here!
5+
Some text in here!
6+
Some text in here!
7+
Some text in here!
8+
Some text in here!
9+
Some text in here!
10+
Some text in here!
11+
Some text in here!
12+
Some text in here!

src/test/fixtures/manifestFiles/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
"publisher": "joaomoreno",
44
"version": "1.0.0",
55
"engines": { "vscode": "*" },
6-
"files": ["foo", "foo2/bar2/include.me", "*/bar3/**", "package.json"]
6+
"files": ["foo", "foo2/bar2/include.me", "*/bar3/**", "package.json", "LICENSE"]
77
}

src/test/package.test.ts

+65-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
versionBump,
1515
VSIX,
1616
LicenseProcessor,
17+
printAndValidatePackagedFiles,
1718
} from '../package';
1819
import { ManifestPackage } from '../manifest';
1920
import * as path from 'path';
@@ -88,6 +89,36 @@ function createManifest(extra: Partial<ManifestPackage> = {}): ManifestPackage {
8889
};
8990
}
9091

92+
async function testPrintAndValidatePackagedFiles(files: IFile[], cwd: string, manifest: ManifestPackage, options: IPackageOptions, errorExpected: boolean, warningExpected: boolean): Promise<void> {
93+
const originalLogError = log.error;
94+
const originalLogWarn = log.warn;
95+
const originalProcessExit = process.exit;
96+
const warns: string[] = [];
97+
const errors: string[] = [];
98+
log.error = (message: string) => errors.push(message);
99+
log.warn = (message: string) => warns.push(message);
100+
process.exit = (() => { throw Error('Error'); }) as () => never;
101+
102+
let exitedOrErrorThrown = false;
103+
try {
104+
await printAndValidatePackagedFiles(files, cwd, manifest, options);
105+
} catch (e) {
106+
exitedOrErrorThrown = true;
107+
} finally {
108+
process.exit = originalProcessExit;
109+
log.error = originalLogError;
110+
log.warn = originalLogWarn;
111+
}
112+
113+
if (errorExpected !== !!errors.length || exitedOrErrorThrown !== errorExpected) {
114+
throw new Error(errors.length ? errors.join('\n') : 'Expected error');
115+
}
116+
117+
if (warningExpected !== !!warns.length) {
118+
throw new Error(warns.length ? warns.join('\n') : 'Expected warning');
119+
}
120+
}
121+
91122
describe('collect', function () {
92123
this.timeout(60000);
93124

@@ -133,22 +164,55 @@ describe('collect', function () {
133164
]);
134165
});
135166

136-
it('should include content of manifest.files', async () => {
167+
it('manifest.files', async () => {
137168
const cwd = fixture('manifestFiles');
138169
const manifest = await readManifest(cwd);
139170
const files = await collect(manifest, { cwd });
140171
const names = files.map(f => f.path).sort();
141172

173+
await testPrintAndValidatePackagedFiles(files, cwd, manifest, {}, false, false);
174+
142175
assert.deepStrictEqual(names, [
143176
'[Content_Types].xml',
144177
'extension.vsixmanifest',
178+
'extension/LICENSE.txt',
145179
'extension/foo/bar/hello.txt',
146180
'extension/foo2/bar2/include.me',
147181
'extension/foo3/bar3/hello.txt',
148182
'extension/package.json',
149183
]);
150184
});
151185

186+
it('manifest.files unused-files-patterns check 1', async () => {
187+
const cwd = fixture('manifestFiles');
188+
const manifest = await readManifest(cwd);
189+
190+
const manifestCopy = { ...manifest, files: [...manifest.files ?? [], 'extension/foo/bar/bye.txt'] };
191+
const files = await collect(manifestCopy, { cwd });
192+
193+
await testPrintAndValidatePackagedFiles(files, cwd, manifestCopy, {}, true, false);
194+
});
195+
196+
it('manifest.files unused-files-patterns check 2', async () => {
197+
const cwd = fixture('manifestFiles');
198+
const manifest = await readManifest(cwd);
199+
200+
const manifestCopy = { ...manifest, files: [...manifest.files ?? [], 'extension/fo'] };
201+
const files = await collect(manifestCopy, { cwd });
202+
203+
await testPrintAndValidatePackagedFiles(files, cwd, manifestCopy, {}, true, false);
204+
});
205+
206+
it('manifest.files unused-files-patterns check 3', async () => {
207+
const cwd = fixture('manifestFiles');
208+
const manifest = await readManifest(cwd);
209+
210+
const manifestCopy = { ...manifest, files: ['**'] };
211+
const files = await collect(manifestCopy, { cwd });
212+
213+
await testPrintAndValidatePackagedFiles(files, cwd, manifestCopy, {}, false, false);
214+
});
215+
152216
it('should ignore devDependencies', () => {
153217
const cwd = fixture('devDependencies');
154218
return readManifest(cwd)

0 commit comments

Comments
 (0)