Skip to content

Commit

Permalink
feat: support local paths (#101)
Browse files Browse the repository at this point in the history
For local packages, follow local package references.

Fixes: #96
  • Loading branch information
ofrobots authored Jun 5, 2019
1 parent 6844ce0 commit 6d08407
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 11 deletions.
60 changes: 49 additions & 11 deletions src/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,34 @@ 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}`;
Expand All @@ -243,11 +268,17 @@ export class LicenseChecker extends EventEmitter {
if (this.localPackages.has(`${packageName}@${version}`)) 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 @@ -261,18 +292,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 @@ -305,24 +338,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 @@ -383,7 +421,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 @@ -399,7 +437,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 @@ -430,7 +468,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 @@ -386,3 +386,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',
]);
}
);
});

0 comments on commit 6d08407

Please sign in to comment.