jsii-diff
Version:
Assembly comparison for jsii
170 lines • 5.8 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.RecursionBreaker = void 0;
exports.inTempDir = inTempDir;
exports.showDownloadFailure = showDownloadFailure;
exports.downloadNpmPackage = downloadNpmPackage;
exports.flatMap = flatMap;
const childProcess = __importStar(require("child_process"));
const fs = __importStar(require("fs-extra"));
const log4js = __importStar(require("log4js"));
const os = __importStar(require("os"));
const path = __importStar(require("path"));
const util = __importStar(require("util"));
const LOG = log4js.getLogger('jsii-diff');
const exec = util.promisify(childProcess.exec);
async function inTempDir(block) {
const origDir = process.cwd();
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'jsii'));
process.chdir(tmpDir);
try {
return await block();
}
finally {
process.chdir(origDir);
await fs.remove(tmpDir);
}
}
function showDownloadFailure(f) {
switch (f) {
case 'no_such_package':
return 'NPM package does not exist';
default:
return undefined;
}
}
async function downloadNpmPackage(pkg, block) {
validateValidPackageSpecifier(pkg);
return inTempDir(async () => {
LOG.info(`Fetching NPM package ${pkg}`);
try {
// Need to install package and dependencies in order for jsii-reflect
// to not bork when it can find the dependencies.
//
// This executes the shell, which is necessary: on Windows, npm is a .cmd file,
// and only the shell and execute .bat/.cmd files. We have validated the package
// name already to make sure it contains only safe characters.
await exec(`npm install --silent --prefix . ${pkg}`);
}
catch (e) {
// If this fails, might be because the package doesn't exist
if (!isSubprocesFailedError(e)) {
throw e;
}
if (await npmPackageExists(pkg)) {
throw new Error(`NPM fetch failed: ${e}. Please try again.`);
}
LOG.warn(`NPM package ${pkg} does not exist.`);
return {
success: false,
reason: 'no_such_package',
};
}
const pkgDir = trimVersionString(pkg);
return {
success: true,
result: await block(path.join(process.cwd(), 'node_modules', pkgDir)),
};
});
}
function isSubprocesFailedError(e) {
return e.code !== undefined && e.cmd !== undefined;
}
async function npmPackageExists(pkg) {
try {
LOG.info(`Checking existence of ${pkg}`);
// This executes the shell, which is necessary: on Windows, npm is a .cmd file,
// and only the shell and execute .bat/.cmd files. We have validated the package
// name already to make sure it contains only safe characters.
await exec(`npm show --silent ${pkg}`);
return true;
}
catch (e) {
if (!isSubprocesFailedError(e)) {
throw e;
}
return false;
}
}
/**
* Trim an optional version string from an NPM package name
*/
function trimVersionString(pkg) {
// The arbitrary char before the @ prevents matching a @ at the start of the
// string.
return pkg.replace(/(.)@.*$/, '$1');
}
/**
* Validate a package name against a list of allowed characters
*
* If we are too strict here, that's not a biggy: script writers are always
* able to download their exotically-named NPM package themselves before running
* jsii-diff on it.
*/
function validateValidPackageSpecifier(pkg) {
if (pkg.match(/[^a-z0-9@/:._-]/i)) {
throw new Error(`Invalid package name, only 'a-z0-9@/:._-' are allowed: ${JSON.stringify(pkg)}`);
}
}
function flatMap(xs, fn) {
const ret = new Array();
for (const x of xs) {
ret.push(...fn(x));
}
return ret;
}
/**
* Don't recurse infinitely by guarding a block with `do()`.
*/
class RecursionBreaker {
constructor() {
this.elements = new Set();
}
do(key, block) {
if (this.elements.has(key)) {
return;
}
this.elements.add(key);
try {
block();
}
finally {
this.elements.delete(key);
}
}
}
exports.RecursionBreaker = RecursionBreaker;
//# sourceMappingURL=util.js.map