in projenrc/jsii.ts [141:370]
constructor(project: yarn.TypeScriptWorkspace, options: JsiiBuildOptions) {
super(project);
this.monoProject = project;
if (!(project instanceof pj.typescript.TypeScriptProject)) {
throw new Error('JsiiBuild() must be passed a TypeScript project');
}
if (!project.parent || !yarn.Monorepo.isMonorepo(project.parent)) {
throw new Error('Project root must be Monorepo component');
}
if (!project.parent.monorepoRelease) {
throw new Error('Monorepo does not have a release component');
}
this.monorepoRelease = project.parent.monorepoRelease;
const tsProject = project;
this.tsProject = tsProject;
if (tsProject.tsconfig) {
throw new Error('The TypeScript project for JsiiBuild() must be configured with { disableTsconfig: true }');
}
if ((tsProject.release?.publisher as any)?.publishJobs?.npm) {
throw new Error('The TypeScript project for JsiiBuild() must be configured without an NPM publishing job');
}
const srcdir = tsProject.srcdir;
const libdir = tsProject.libdir;
tsProject.addFields({ types: `${libdir}/index.d.ts` });
const compressAssembly = options.compressAssembly ?? false;
// this is an unhelpful warning
const jsiiFlags = ['--silence-warnings=reserved-word'];
if (compressAssembly) {
jsiiFlags.push('--compress-assembly');
}
const compatIgnore = options.compatIgnore ?? '.compatignore';
tsProject.addFields({ stability: options.stability ?? Stability.STABLE });
if (options.stability === Stability.DEPRECATED) {
tsProject.addFields({ deprecated: true });
}
const compatTask = tsProject.addTask('compat', {
description: 'Perform API compatibility check against latest version',
exec: `jsii-diff npm:$(node -p "require(\'./package.json\').name") -k --ignore-file ${compatIgnore} || (echo "\nUNEXPECTED BREAKING CHANGES: add keys such as \'removed:constructs.Node.of\' to ${compatIgnore} to skip.\n" && exit 1)`,
});
const compat = options.compat ?? false;
if (compat) {
tsProject.compileTask.spawn(compatTask);
}
tsProject.compileTask.reset(['jsii', ...jsiiFlags].join(' '));
tsProject.watchTask.reset(['jsii', '-w', ...jsiiFlags].join(' '));
// Create a new package:all task, it will be filled with language targets later
this.packageAllTask = tsProject.addTask('package-all', {
description: 'Packages artifacts for all target languages',
});
// in jsii we consider the entire repo (post build) as the build artifact
// which is then used to create the language bindings in separate jobs.
// we achieve this by doing a checkout and overwrite with the files from the js package.
this.packageJsTask = this.addPackagingTask('js');
// When running inside CI we initially only package js. Other targets are packaged in separate jobs.
// Outside of CI (i.e locally) we simply package all targets.
tsProject.packageTask.reset();
tsProject.packageTask.spawn(this.packageJsTask, {
// Only run in CI
condition: 'node -e "if (!process.env.CI) process.exit(1)"',
});
// Do not spawn 'package-all' automatically as part of 'package', the jsii packaging will
// be done as part of the release task.
/*
tsProject.packageTask.spawn(this.packageAllTask, {
// Don't run in CI
condition: 'node -e "if (process.env.CI) process.exit(1)"',
});
*/
const targets: Record<string, any> = {};
const jsii: any = {
outdir: tsProject.artifactsDirectory,
targets,
tsc: {
outDir: libdir,
rootDir: srcdir,
},
};
if (options.excludeTypescript) {
jsii.excludeTypescript = options.excludeTypescript;
}
if (options.composite) {
jsii.projectReferences = true;
}
tsProject.addFields({ jsii });
// FIXME: Not support "runsOn" and the workflow container image for now
const extraJobOptions: Partial<Job> = {
/*
...this.getJobRunsOnConfig(options),
...(options.workflowContainerImage
? { container: { image: options.workflowContainerImage } }
: {}),
*/
};
const npmjs: NpmPublishOptions = {
registry: tsProject.package.npmRegistry,
npmTokenSecret: tsProject.package.npmTokenSecret,
npmProvenance: tsProject.package.npmProvenance,
// No support for CodeArtifact here
// codeArtifactOptions: tsProject.codeArtifactOptions,
};
this.addTargetToBuild('js', this.packageJsTask, extraJobOptions);
this.addTargetToRelease('js', this.packageJsTask, npmjs);
const maven = options.publishToMaven;
if (maven) {
targets.java = {
package: maven.javaPackage,
maven: {
groupId: maven.mavenGroupId,
artifactId: maven.mavenArtifactId,
},
};
const task = this.addPackagingTask('java');
this.addTargetToBuild('java', task, extraJobOptions);
this.addTargetToRelease('java', task, maven);
}
const pypi = options.publishToPypi;
if (pypi) {
targets.python = {
distName: pypi.distName,
module: pypi.module,
};
const task = this.addPackagingTask('python');
this.addTargetToBuild('python', task, extraJobOptions);
this.addTargetToRelease('python', task, pypi);
}
const nuget = options.publishToNuget;
if (nuget) {
targets.dotnet = {
namespace: nuget.dotNetNamespace,
packageId: nuget.packageId,
iconUrl: nuget.iconUrl,
};
const task = this.addPackagingTask('dotnet');
this.addTargetToBuild('dotnet', task, extraJobOptions);
this.addTargetToRelease('dotnet', task, nuget);
}
const golang = options.publishToGo;
if (golang) {
targets.go = {
moduleName: golang.moduleName,
packageName: golang.packageName,
versionSuffix: golang.versionSuffix,
};
const task = this.addPackagingTask('go');
this.addTargetToBuild('go', task, extraJobOptions);
this.addTargetToRelease('go', task, golang);
}
const jsiiSuffix =
options.jsiiVersion === '*'
? // If jsiiVersion is "*", don't specify anything so the user can manage.
''
: // Otherwise, use `jsiiVersion` or fall back to `5.7`
`@${options.jsiiVersion ?? '5.7'}`;
tsProject.addDevDeps(
`jsii${jsiiSuffix}`,
`jsii-rosetta${jsiiSuffix}`,
'jsii-diff',
'jsii-pacmak',
);
tsProject.gitignore.exclude('.jsii', 'tsconfig.json');
tsProject.npmignore?.include('.jsii');
if (options.docgen ?? true) {
// If jsiiVersion is "*", don't specify anything so the user can manage.
// Otherwise use a version that is compatible with all supported jsii releases.
const docgenVersion = options.jsiiVersion === '*' ? '*' : '^10.5.0';
new pj.cdk.JsiiDocgen(tsProject, {
version: docgenVersion,
filePath: options.docgenFilePath,
});
}
// jsii updates .npmignore, so we make it writable
if (tsProject.npmignore) {
tsProject.npmignore.readonly = false;
}
const packageJson = tsProject.package.file;
if ((options.pypiClassifiers ?? []).length > 0) {
packageJson.patch(
pj.JsonPatch.add('/jsii/targets/python/classifiers', options.pypiClassifiers),
);
}
if (options.rosettaStrict) {
packageJson.patch(
pj.JsonPatch.add('/jsii/metadata', {}),
pj.JsonPatch.add('/jsii/metadata/jsii', {}),
pj.JsonPatch.add('/jsii/metadata/jsii/rosetta', {}),
pj.JsonPatch.add('/jsii/metadata/jsii/rosetta/strict', true),
);
}
}