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(jsii-diff): make assembly validation optional #926

Merged
merged 3 commits into from
Nov 5, 2019
Merged
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
29 changes: 18 additions & 11 deletions packages/jsii-diff/bin/jsii-diff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ async function main(): Promise<number> {
.option('experimental-errors', { alias: 'e', type: 'boolean', default: false, desc: 'Error on experimental API changes' })
.option('ignore-file', { alias: 'i', type: 'string', desc: 'Ignore API changes with keys from file (file may be missing)' })
.option('keys', { alias: 'k', type: 'boolean', default: false, desc: 'Show diagnostic suppression keys' })
.option('validate', { alias: 'd', type: 'boolean', default: false, desc: 'Validate the assemblies that are being loaded' })
.usage('$0 <original> [updated]', 'Compare two JSII assemblies.', args => args
.positional('original', {
description: 'Original assembly (file, package or "npm:package@version")',
Expand All @@ -36,14 +37,14 @@ async function main(): Promise<number> {
configureLog4js(argv.verbose);

LOG.debug(`Loading original assembly from ${(argv as any).original}`);
const loadOriginal = await loadAssembly((argv as any).original);
const loadOriginal = await loadAssembly((argv as any).original, argv);
if (!loadOriginal.success) {
process.stderr.write(`Could not load '${loadOriginal.resolved}': ${showDownloadFailure(loadOriginal.reason)}. Skipping analysis\n`);
return 0;
}

LOG.debug(`Loading updated assembly from ${(argv as any).updated}`);
const loadUpdated = await loadAssembly((argv as any).updated);
const loadUpdated = await loadAssembly((argv as any).updated, argv);
if (!loadUpdated.success) {
process.stderr.write(`Could not load '${loadUpdated.resolved}': ${showDownloadFailure(loadUpdated.reason)}. Skipping analysis\n`);
return 0;
Expand Down Expand Up @@ -82,29 +83,34 @@ async function main(): Promise<number> {
// Allow both npm:<package> (legacy) and npm://<package> (looks better)
const NPM_REGEX = /^npm:(\/\/)?/;


interface LoadOptions {
validate: boolean;
}

/**
* Load the indicated assembly from the given name
*
* Supports downloading from NPM as well as from file or directory.
*/
async function loadAssembly(requested: string): Promise<LoadAssemblyResult> {
async function loadAssembly(requested: string, options: LoadOptions): Promise<LoadAssemblyResult> {
let resolved = requested;
try {
if (NPM_REGEX.exec(requested)) {
let pkg = requested.replace(NPM_REGEX, '');
if (!pkg) { pkg = await loadPackageNameFromAssembly(); }
if (!pkg) { pkg = await loadPackageNameFromAssembly(options); }

resolved = `npm://${pkg}`;
if (!pkg.includes('@', 1)) { resolved += '@latest'; }

const download = await downloadNpmPackage(pkg, loadFromFilesystem);
const download = await downloadNpmPackage(pkg, f => loadFromFilesystem(f, options));
if (download.success) {
return { requested, resolved, success: true, assembly: download.result };
}
return { requested, resolved, success: false, reason: download.reason };
}
// We don't accept failure loading from the filesystem
return { requested, resolved, success: true, assembly: await loadFromFilesystem(requested) };
return { requested, resolved, success: true, assembly: await loadFromFilesystem(requested, options) };

} catch (e) {
// Prepend information about which assembly we've failed to load
Expand All @@ -125,25 +131,26 @@ async function loadAssembly(requested: string): Promise<LoadAssemblyResult> {
type LoadAssemblyResult = { requested: string, resolved: string }
& ({ success: true, assembly: reflect.Assembly } | { success: false, reason: DownloadFailure });

async function loadPackageNameFromAssembly(): Promise<string> {
async function loadPackageNameFromAssembly(options: LoadOptions): Promise<string> {
const JSII_ASSEMBLY_FILE = '.jsii';
if (!await fs.pathExists(JSII_ASSEMBLY_FILE)) {
throw new Error(`No NPM package name given and no ${JSII_ASSEMBLY_FILE} file in the current directory. Please specify a package name.`);
}
const module = spec.validateAssembly(await fs.readJSON(JSII_ASSEMBLY_FILE, { encoding: 'utf-8' }));
const contents = await fs.readJSON(JSII_ASSEMBLY_FILE, { encoding: 'utf-8' });
const module = options.validate ? spec.validateAssembly(contents) : contents as spec.Assembly;
if (!module.name) { throw new Error(`Could not find package in ${JSII_ASSEMBLY_FILE}`); }

return module.name;
}

async function loadFromFilesystem(name: string) {
async function loadFromFilesystem(name: string, options: LoadOptions) {
const stat = await fs.stat(name);

const ts = new reflect.TypeSystem();
if (stat.isDirectory()) {
return ts.loadModule(name);
return ts.loadModule(name, options);
}
return ts.loadFile(name);
return ts.loadFile(name, options);

}

Expand Down