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

feat: support local paths #101

Merged
merged 3 commits into from
Jun 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 49 additions & 11 deletions src/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,20 +227,51 @@ export class LicenseChecker extends EventEmitter {
}
}

private async getPackageJson(
packageName: string,
versionSpec: string,
localDirectory: string | null
): Promise<{}> {
// If this has a relative URL, and is a local package, find the package json from the
// indicated directory
if (versionSpec.startsWith('file:') && localDirectory) {
const relativePath = versionSpec.slice('file:'.length);
const packageJsonPath = path.join(
localDirectory,
relativePath,
'package.json'
);
this.emit('package.json', packageJsonPath);
const contents = await fsReadFile(packageJsonPath, 'utf8');
return JSON.parse(contents);
}
return packageJson(packageName, {
version: versionSpec,
fullMetadata: true,
});
}

private async checkLicenses(
packageName: string,
versionSpec: string,
localDirectory: string | null,
...parents: string[]
): Promise<void> {
const spec = `${packageName}@${versionSpec}`;
if (this.failedPackages.has(spec)) return;

try {
const json = await packageJson(packageName, {
version: versionSpec,
fullMetadata: true,
});
await this.checkPackageJson(json, packageName, ...parents);
const json = await this.getPackageJson(
packageName,
versionSpec,
localDirectory
);
await this.checkPackageJson(
json,
packageName,
localDirectory,
...parents
);
} catch (err) {
this.failedPackages.add(spec);
this.emit('error', {
Expand All @@ -254,18 +285,20 @@ export class LicenseChecker extends EventEmitter {

private async checkLicensesForDeps(
deps: Dependencies | undefined,
localDirectory: string | null,
...parents: string[]
): Promise<void> {
if (!deps) return;
for (const pkg of Object.keys(deps)) {
const depVersion = deps[pkg];
await this.checkLicenses(pkg, depVersion, ...parents);
await this.checkLicenses(pkg, depVersion, localDirectory, ...parents);
}
}

private async checkPackageJson(
json: {},
packageName: string | null,
localDirectory: string | null,
...parents: string[]
): Promise<void> {
const pj: PackageJson = ensurePackageJson(json);
Expand Down Expand Up @@ -298,24 +331,29 @@ export class LicenseChecker extends EventEmitter {

await this.checkLicensesForDeps(
pj.dependencies,
localDirectory,
...parents,
packageAndVersion
);
if (this.opts.dev) {
await this.checkLicensesForDeps(
pj.devDependencies,
localDirectory,
...parents,
packageAndVersion
);
}
}

private async checkPackageJsonContent(content: string): Promise<void> {
private async checkPackageJsonContent(
content: string,
localDirectory: string | null
): Promise<void> {
// tslint:disable-next-line:no-any `JSON.parse()` returns any
let json: any = null;
try {
json = JSON.parse(content);
await this.checkPackageJson(json, json.name);
await this.checkPackageJson(json, json.name, localDirectory);
} catch (err) {
const packageName = (json && json.name) || '(unknown package)';
const versionSpec = (json && json.version) || '(unknown version)';
Expand Down Expand Up @@ -369,7 +407,7 @@ export class LicenseChecker extends EventEmitter {
for (const pj of packageJsons) {
this.emit('package.json', pj);
const content = await fsReadFile(pj, 'utf8');
await this.checkPackageJsonContent(content);
await this.checkPackageJsonContent(content, path.dirname(pj));
}
this.emit('end');
}
Expand All @@ -385,7 +423,7 @@ export class LicenseChecker extends EventEmitter {
if (!pkgArgs.name || !pkgArgs.fetchSpec) {
throw new Error(`Invalid package spec: ${pkg}`);
}
await this.checkLicenses(pkgArgs.name, pkgArgs.fetchSpec);
await this.checkLicenses(pkgArgs.name, pkgArgs.fetchSpec, null);
this.emit('end');
}

Expand Down Expand Up @@ -416,7 +454,7 @@ export class LicenseChecker extends EventEmitter {
}
for (const pj of packageJsons) {
this.emit('package.json', pj.filePath);
await this.checkPackageJsonContent(pj.content);
await this.checkPackageJsonContent(pj.content, null);
}
this.emit('end');
}
Expand Down
57 changes: 57 additions & 0 deletions test/checker-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -333,3 +333,60 @@ test.serial('decline private package (local repo)', t => {
}
);
});

test.serial('support local paths', t => {
const primaryPackageJson = JSON.stringify({
name: 'hello',
version: '1.0.0',
license: 'Apache-2.0',
dependencies: {
foo: '^1.2.3',
linked: 'file:../linked',
},
});
const linkedPackageJson = JSON.stringify({
name: 'linked',
version: '1.0.0',
license: 'Apache-2.0',
dependencies: {
baz: '^7.0.0',
},
});
return withFixtures(
{
'path/to/primary': {
'package.json': primaryPackageJson,
'another-file': 'meh, world.',
},
'path/to/linked': {
'package.json': linkedPackageJson,
'another-file': 'i depend on a package with an evil license',
},
},
async () => {
requestedPackages = [];
const nonGreenPackages: string[] = [];
const packageJsonPaths: string[] = [];
const checker = new LicenseChecker();
checker
.on('non-green-license', arg => {
nonGreenPackages.push(`${arg.packageName}@${arg.version}`);
})
.on('package.json', filePath => {
packageJsonPaths.push(filePath);
});
await checker.checkLocalDirectory('path/to/primary');
console.log('requested packages: ', requestedPackages);
t.deepEqual(requestedPackages, [
'foo@^1.2.3',
'bar@^4.5.0',
'baz@^7.0.0',
]);
t.deepEqual(nonGreenPackages, ['bar@4.5.6', 'baz@7.8.9']);
t.deepEqual(packageJsonPaths, [
'path/to/primary/package.json',
'path/to/linked/package.json',
]);
}
);
});