jsii-pacmak
Version:
A code generation framework for jsii backend languages
152 lines • 6.88 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.pacmak = exports.configureLogging = exports.TargetName = void 0;
const jsii_reflect_1 = require("jsii-reflect");
const jsii_rosetta_1 = require("jsii-rosetta");
const path_1 = require("path");
const process_1 = require("process");
const logging = require("./logging");
const npm_modules_1 = require("./npm-modules");
const targets_1 = require("./targets");
Object.defineProperty(exports, "TargetName", { enumerable: true, get: function () { return targets_1.TargetName; } });
const timer_1 = require("./timer");
const util_1 = require("./util");
var logging_1 = require("./logging");
Object.defineProperty(exports, "configureLogging", { enumerable: true, get: function () { return logging_1.configure; } });
/**
* Generates code in the desired targets.
*/
async function pacmak({ argv = {}, clean = true, codeOnly = false, fingerprint = true, force = false, forceSubdirectory = true, forceTarget = false, inputDirectories, outputDirectory, parallel = true, recurse = false, rosettaTablet, rosettaUnknownSnippets = undefined, runtimeTypeChecking = true, targets = Object.values(targets_1.TargetName), timers = new timer_1.Timers(), updateNpmIgnoreFiles = false, validateAssemblies = false, }) {
const rosetta = new jsii_rosetta_1.RosettaTabletReader({
unknownSnippets: rosettaUnknownSnippets,
prefixDisclaimer: true,
});
if (rosettaTablet) {
await rosetta.loadTabletFromFile(rosettaTablet);
}
const modulesToPackageSorted = await (0, npm_modules_1.findJsiiModules)(inputDirectories, recurse);
const modulesToPackageFlat = (0, util_1.flatten)(modulesToPackageSorted);
logging.info(`Found ${modulesToPackageFlat.length} modules to package`);
if (modulesToPackageFlat.length === 0) {
logging.warn('Nothing to do');
return;
}
if (outputDirectory) {
// Ensure this is consistently interpreted as relative to cwd(). This is transparent for absolute
// paths, as those would be returned unmodified.
const absoluteOutputDirectory = (0, path_1.resolve)((0, process_1.cwd)(), outputDirectory);
for (const mod of modulesToPackageFlat) {
mod.outputDirectory = absoluteOutputDirectory;
}
}
else if (updateNpmIgnoreFiles) {
// if outdir is coming from package.json, verify it is excluded by .npmignore. if it is explicitly
// defined via --out, don't perform this verification.
await (0, npm_modules_1.updateAllNpmIgnores)(modulesToPackageFlat);
}
const packCommand = argv['pack-command'];
await timers.recordAsync(packCommand, () => {
logging.info('Packaging NPM bundles');
return Promise.all(modulesToPackageFlat.map((m) => m.npmPack(packCommand)));
});
await timers.recordAsync('load jsii', () => {
logging.info('Loading jsii assemblies and translations');
const system = new jsii_reflect_1.TypeSystem();
return Promise.all(modulesToPackageFlat.map(async (m) => {
await m.load(system, validateAssemblies);
return rosetta.addAssembly(m.assembly.spec, m.moduleDirectory);
}));
});
try {
const targetSets = sliceTargets(modulesToPackageSorted, targets, forceTarget);
if (targetSets.every((s) => s.modulesSorted.length === 0)) {
throw new Error(`None of the requested packages had any targets to build for '${targets.join(', ')}' (use --force-target to force)`);
}
const perLanguageDirectory = targetSets.length > 1 || forceSubdirectory;
// We run all target sets in parallel for minimal wall clock time
await Promise.all(mapParallelOrSerial(targetSets, async (targetSet) => {
logging.info(`Packaging '${targetSet.targetType}' for ${describePackages(targetSet)}`);
return timers
.recordAsync(targetSet.targetType, () => buildTargetsForLanguage(targetSet.targetType, targetSet.modulesSorted, {
argv,
clean,
codeOnly,
fingerprint,
force,
perLanguageDirectory,
rosetta,
runtimeTypeChecking,
}))
.then(() => logging.info(`${targetSet.targetType} finished`), (err) => {
logging.warn(`${targetSet.targetType} failed`);
return Promise.reject(err);
});
}, { parallel }));
}
finally {
if (clean) {
logging.debug('Cleaning up');
await timers.recordAsync('cleanup', () => Promise.all(modulesToPackageFlat.map((m) => m.cleanup())));
}
else {
logging.info('Temporary directories retained (--no-clean)');
}
}
logging.info(`Packaged. ${timers.display()}`);
}
exports.pacmak = pacmak;
//#endregion
//#region Building
async function buildTargetsForLanguage(targetLanguage, modules, { argv, clean, codeOnly, fingerprint, force, perLanguageDirectory, rosetta, runtimeTypeChecking, }) {
// ``argv.target`` is guaranteed valid by ``yargs`` through the ``choices`` directive.
const factory = targets_1.ALL_BUILDERS[targetLanguage];
if (!factory) {
throw new Error(`Unsupported target: '${targetLanguage}'`);
}
return factory(modules, {
arguments: argv,
clean: clean,
codeOnly: codeOnly,
fingerprint: fingerprint,
force: force,
languageSubdirectory: perLanguageDirectory,
rosetta,
runtimeTypeChecking,
}).buildModules();
}
function sliceTargets(modulesSorted, requestedTargets, force) {
const ret = new Array();
for (const target of requestedTargets) {
ret.push({
targetType: target,
modulesSorted: modulesSorted
.map((modules) => modules.filter((m) => force || m.availableTargets.includes(target)))
.filter((ms) => ms.length > 0),
});
}
return ret;
}
//#endregion
//#region Parallelization
function mapParallelOrSerial(collection, mapper, { parallel }) {
const result = new Array();
for (const item of collection) {
result.push(result.length === 0 || parallel
? // Running parallel, or first element
mapper(item)
: // Wait for the previous promise, then make the next one
result[result.length - 1].then(() => mapper(item), (error) => Promise.reject(error)));
}
return result;
}
//#endregion
//#region Misc. Utilities
function describePackages(target) {
const modules = (0, util_1.flatten)(target.modulesSorted);
if (modules.length > 0 && modules.length < 5) {
return modules.map((m) => m.name).join(', ');
}
return `${modules.length} modules`;
}
//#endregion
//# sourceMappingURL=index.js.map
;