projen
Version:
CDK for software projects
821 lines • 125 kB
JavaScript
"use strict";
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.NodeProject = exports.AutoRelease = void 0;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const path_1 = require("path");
const bundler_1 = require("./bundler");
const jest_1 = require("./jest");
const license_checker_1 = require("./license-checker");
const node_package_1 = require("./node-package");
const projenrc_1 = require("./projenrc");
const build_1 = require("../build");
const consts_1 = require("../build/private/consts");
const common_1 = require("../common");
const dependencies_1 = require("../dependencies");
const github_1 = require("../github");
const biome_1 = require("./biome/biome");
const util_1 = require("./util");
const constants_1 = require("../github/constants");
const util_2 = require("../github/private/util");
const workflows_model_1 = require("../github/workflows-model");
const ignore_file_1 = require("../ignore-file");
const javascript_1 = require("../javascript");
const license_1 = require("../license");
const projenrc_json_1 = require("../projenrc-json");
const release_1 = require("../release");
const runner_options_1 = require("../runner-options");
const util_3 = require("../util");
const path_2 = require("../util/path");
const PROJEN_SCRIPT = "projen";
/**
* Automatic bump modes
*/
var AutoRelease;
(function (AutoRelease) {
/**
* Automatically bump & release a new version for every commit to "main"
*/
AutoRelease[AutoRelease["EVERY_COMMIT"] = 0] = "EVERY_COMMIT";
/**
* Automatically bump & release a new version on a daily basis.
*/
AutoRelease[AutoRelease["DAILY"] = 1] = "DAILY";
})(AutoRelease || (exports.AutoRelease = AutoRelease = {}));
/**
* Node.js project.
*
* @pjid node
*/
class NodeProject extends github_1.GitHubProject {
/**
* The .npmrc file
*/
get npmrc() {
if (!this._npmrc) {
this._npmrc = new javascript_1.NpmConfig(this, { omitEmpty: true });
}
return this._npmrc;
}
/**
* @deprecated use `package.allowLibraryDependencies`
*/
get allowLibraryDependencies() {
return this.package.allowLibraryDependencies;
}
/**
* @deprecated use `package.entrypoint`
*/
get entrypoint() {
return this.package.entrypoint;
}
/**
* The minimum node version required by this package to function.
*
* This value indicates the package is incompatible with older versions.
*/
get minNodeVersion() {
return this.package.minNodeVersion;
}
/**
* Maximum node version supported by this package.
*
* The value indicates the package is incompatible with newer versions.
*/
get maxNodeVersion() {
return this.package.maxNodeVersion;
}
/**
* The package manager to use.
*
* @deprecated use `package.packageManager`
*/
get packageManager() {
return this.package.packageManager;
}
/**
* @deprecated use `package.addField(x, y)`
*/
get manifest() {
return this.package.manifest;
}
constructor(options) {
super({
...options,
// Node projects have the specific projen version locked via lockfile, so we can skip the @<VERSION> part of the top-level project
projenCommand: options.projenCommand ?? "npx projen",
});
this.package = new node_package_1.NodePackage(this, options);
this.workflowBootstrapSteps = options.workflowBootstrapSteps ?? [];
this.workflowGitIdentity =
options.workflowGitIdentity ?? constants_1.DEFAULT_GITHUB_ACTIONS_USER;
this.workflowPackageCache = options.workflowPackageCache ?? false;
this.artifactsDirectory =
options.artifactsDirectory ?? consts_1.DEFAULT_ARTIFACTS_DIRECTORY;
(0, util_2.ensureNotHiddenPath)(this.artifactsDirectory, "artifactsDirectory");
const normalizedArtifactsDirectory = (0, util_3.normalizePersistedPath)(this.artifactsDirectory);
this.artifactsJavascriptDirectory = path_1.posix.join(normalizedArtifactsDirectory, "js");
this.runScriptCommand = (() => {
switch (this.packageManager) {
case node_package_1.NodePackageManager.NPM:
return "npm run";
case node_package_1.NodePackageManager.YARN:
case node_package_1.NodePackageManager.YARN2:
case node_package_1.NodePackageManager.YARN_CLASSIC:
case node_package_1.NodePackageManager.YARN_BERRY:
return "yarn run";
case node_package_1.NodePackageManager.PNPM:
return "pnpm run";
case node_package_1.NodePackageManager.BUN:
return "bun run";
default:
throw new Error(`unexpected package manager ${this.packageManager}`);
}
})();
const envCommand = (() => {
switch (this.packageManager) {
case node_package_1.NodePackageManager.PNPM:
return '$(pnpm -c exec "node --print process.env.PATH")';
case node_package_1.NodePackageManager.BUN:
return '$(bun --eval "console.log(process.env.PATH)")';
default:
return '$(npx -c "node --print process.env.PATH")';
}
})();
this.nodeVersion =
options.workflowNodeVersion ?? this.package.minNodeVersion;
// add PATH for all tasks which includes the project's npm .bin list
this.tasks.addEnvironment("PATH", envCommand);
this.addLicense(options);
if (options.npmignoreEnabled ?? true) {
this.npmignore = new ignore_file_1.IgnoreFile(this, ".npmignore", options.npmIgnoreOptions);
}
this.addDefaultGitIgnore();
if (options.gitignore?.length) {
for (const i of options.gitignore) {
this.gitignore.exclude(i);
}
}
if (options.npmignore?.length) {
if (!this.npmignore) {
throw new Error('.npmignore is not defined for an APP project type. Add "npmIgnore: true" to override this');
}
for (const i of options.npmignore) {
this.npmignore.exclude(i);
}
}
if (!this.ejected) {
this.setScript(PROJEN_SCRIPT, this.package.projenCommand);
}
this.npmignore?.exclude(`/${common_1.PROJEN_DIR}/`);
const projen = options.projenDevDependency ?? (this.parent ? false : true);
if (projen && !this.ejected) {
const postfix = options.projenVersion ? `@${options.projenVersion}` : "";
this.addDevDeps(`projen${postfix}`);
if (!this.deps.isDependencySatisfied("constructs", dependencies_1.DependencyType.BUILD, "^10.0.0")) {
this.addDevDeps(`constructs@^10.0.0`);
}
}
if (!options.defaultReleaseBranch) {
throw new Error('"defaultReleaseBranch" is temporarily a required option while we migrate its default value from "master" to "main"');
}
const buildEnabled = options.buildWorkflow ?? (this.parent ? false : true);
// configure jest if enabled
// must be before the build/release workflows
if (options.jest ?? true) {
this.jest = new jest_1.Jest(this, options.jestOptions);
}
const workflowPermissions = {
idToken: this.determineIdTokenPermissions(options),
};
const buildWorkflowOptions = options.buildWorkflowOptions ?? {};
if (buildEnabled && (this.github || github_1.GitHub.of(this.root))) {
this.buildWorkflow = new build_1.BuildWorkflow(this, {
buildTask: this.buildTask,
artifactsDirectory: this.artifactsDirectory,
containerImage: options.workflowContainerImage,
gitIdentity: this.workflowGitIdentity,
mutableBuild: options.mutableBuild,
workflowTriggers: options.buildWorkflowTriggers,
permissions: workflowPermissions,
...buildWorkflowOptions,
preBuildSteps: this.renderWorkflowSetup({
installStepConfiguration: {
workingDirectory: this.determineInstallWorkingDirectory(),
},
mutable: buildWorkflowOptions.mutableBuild ?? options.mutableBuild ?? true,
}).concat(buildWorkflowOptions.preBuildSteps ?? []),
postBuildSteps: [...(options.postBuildSteps ?? [])],
...(0, runner_options_1.filteredRunsOnOptions)(options.workflowRunsOn, options.workflowRunsOnGroup),
});
this.buildWorkflow.addPostBuildSteps(...this.renderUploadCoverageJobStep(options));
this.maybeAddCodecovIgnores(options);
}
// Build release tasks array
const releaseTasks = [];
// Add security audit before release if enabled
if (options.auditDeps) {
const auditTask = this.addAuditTask(options);
const runOn = options.auditDepsOptions?.runOn ?? "build";
if (runOn === "release") {
releaseTasks.push(auditTask);
}
else if (runOn === "build") {
this.preCompileTask.spawn(auditTask);
}
// "manual" mode doesn't add to any task
}
const release = options.release ??
options.releaseWorkflow ??
(this.parent ? false : true);
if (release) {
// Add build task
releaseTasks.push(this.buildTask);
this.release = new release_1.Release(this, {
versionFile: "package.json", // this is where "version" is set after bump
tasks: releaseTasks,
branch: options.defaultReleaseBranch ?? "main",
...options,
artifactsDirectory: this.artifactsDirectory,
releaseWorkflowSetupSteps: [
...this.renderWorkflowSetup({
installStepConfiguration: {
workingDirectory: this.determineInstallWorkingDirectory(),
},
mutable: false,
}),
...(options.releaseWorkflowSetupSteps ?? []),
],
postBuildSteps: [
...(options.postBuildSteps ?? []),
...this.renderUploadCoverageJobStep(options),
],
workflowNodeVersion: this.nodeVersion,
workflowPermissions,
});
this.maybeAddCodecovIgnores(options);
this.publisher = this.release.publisher;
const nodePackageToReleaseCodeArtifactAuthProviderMapping = {
[node_package_1.CodeArtifactAuthProvider.ACCESS_AND_SECRET_KEY_PAIR]: release_1.CodeArtifactAuthProvider.ACCESS_AND_SECRET_KEY_PAIR,
[node_package_1.CodeArtifactAuthProvider.GITHUB_OIDC]: release_1.CodeArtifactAuthProvider.GITHUB_OIDC,
};
if (options.releaseToNpm ?? false) {
const codeArtifactOptions = (0, release_1.isAwsCodeArtifactRegistry)(this.package.npmRegistry)
? {
accessKeyIdSecret: options.codeArtifactOptions?.accessKeyIdSecret,
secretAccessKeySecret: options.codeArtifactOptions?.secretAccessKeySecret,
roleToAssume: options.codeArtifactOptions?.roleToAssume,
authProvider: options.codeArtifactOptions?.authProvider
? nodePackageToReleaseCodeArtifactAuthProviderMapping[options.codeArtifactOptions.authProvider]
: release_1.CodeArtifactAuthProvider.ACCESS_AND_SECRET_KEY_PAIR,
}
: {};
this.release.publisher.publishToNpm({
registry: this.package.npmRegistry,
npmTokenSecret: this.package.npmTokenSecret,
npmProvenance: this.package.npmProvenance,
trustedPublishing: options.npmTrustedPublishing ?? false,
codeArtifactOptions,
});
}
}
else {
// validate that no release options are selected if the release workflow is disabled.
if (options.releaseToNpm) {
throw new Error('"releaseToNpm" is not supported if "release" is not set');
}
if (options.releaseEveryCommit) {
throw new Error('"releaseEveryCommit" is not supported if "release" is not set');
}
if (options.releaseSchedule) {
throw new Error('"releaseSchedule" is not supported if "release" is not set');
}
}
if ((options.autoMerge ?? true) &&
this.github?.mergify &&
this.buildWorkflow?.buildJobIds) {
this.autoMerge = new github_1.AutoMerge(this.github, options.autoMergeOptions);
this.autoMerge.addConditionsLater({
render: () => this.buildWorkflow?.buildJobIds.map((id) => `status-success=${id}`) ??
[],
});
}
const dependabot = options.dependabot ?? false;
const depsUpgrade = options.depsUpgrade ?? !dependabot;
if (dependabot && depsUpgrade) {
throw new Error("'dependabot' cannot be configured together with 'depsUpgrade'");
}
const depsAutoApprove = options.autoApproveUpgrades ?? false;
if (depsAutoApprove && !this.autoApprove && this.github) {
throw new Error("Automatic approval of dependencies upgrades requires configuring `autoApproveOptions`");
}
const autoApproveLabel = (condition) => condition && this.autoApprove?.label
? [this.autoApprove.label]
: undefined;
if (dependabot) {
const defaultOptions = {
labels: autoApproveLabel(depsAutoApprove),
};
this.github?.addDependabot((0, util_3.deepMerge)([defaultOptions, options.dependabotOptions ?? {}]));
}
if (depsUpgrade) {
const defaultOptions = {
workflowOptions: {
container: options.workflowContainerImage
? {
image: options.workflowContainerImage,
}
: undefined,
labels: autoApproveLabel(depsAutoApprove),
gitIdentity: this.workflowGitIdentity,
permissions: workflowPermissions,
},
};
this.upgradeWorkflow = new javascript_1.UpgradeDependencies(this, (0, util_3.deepMerge)([defaultOptions, options.depsUpgradeOptions ?? {}]));
}
if (options.pullRequestTemplate ?? true) {
this.github?.addPullRequestTemplate(...(options.pullRequestTemplateContents ?? []));
}
const projenrcJs = options.projenrcJs ?? !options.projenrcJson;
if (!this.parent && projenrcJs) {
const projenrcJsFile = new projenrc_1.Projenrc(this, options.projenrcJsOptions);
this.npmignore?.exclude(`/${projenrcJsFile.filePath}`);
}
else if (options.projenrcJson) {
const projenrcJsonFile = projenrc_json_1.ProjenrcJson.of(this);
if (projenrcJsonFile) {
this.npmignore?.exclude(`/${projenrcJsonFile.filePath}`);
}
}
// add a bundler component - this enables things like Lambda bundling and in the future web bundling.
this.bundler = new bundler_1.Bundler(this, options.bundlerOptions);
const shouldPackage = options.package ?? true;
if (release && !shouldPackage) {
this.logger.warn("When `release` is enabled, `package` must also be enabled as it is required by release. Force enabling `package`.");
}
if (release || shouldPackage) {
this.packageTask.exec(`mkdir -p ${this.artifactsJavascriptDirectory}`);
const pkgMgr = this.package.packageManager === node_package_1.NodePackageManager.PNPM
? "pnpm"
: "npm";
this.packageTask.exec(`${pkgMgr} pack --pack-destination ${this.artifactsJavascriptDirectory}`);
}
if ((0, util_3.multipleSelected)([options.biome, options.prettier])) {
throw new Error("Only one of biome and prettier can be enabled.");
}
if (options.biome ?? false) {
this.biome = new biome_1.Biome(this, { ...options.biomeOptions });
}
if (options.prettier ?? false) {
this.prettier = new javascript_1.Prettier(this, { ...options.prettierOptions });
}
// For PNPM, the default resolution mode is "lowest", which leads to any non-versioned (ie '*') dependencies being
// resolved to the lowest available version, which is unlikely to be expected behaviour for users. We set resolution
// mode to "highest" to match the behaviour of yarn and npm.
if (this.package.packageManager === node_package_1.NodePackageManager.PNPM) {
this.npmrc.addConfig("resolution-mode", "highest");
}
if (options.checkLicenses) {
new license_checker_1.LicenseChecker(this, options.checkLicenses);
}
}
determineInstallWorkingDirectory() {
if (this.parent) {
return (0, path_2.ensureRelativePathStartsWithDot)((0, path_1.relative)(".", this.root.outdir));
}
return;
}
determineIdTokenPermissions(options) {
const { codeCovTokenSecret, scopedPackagesOptions, codeArtifactOptions } = options;
const useCodeCoveOidc = this.useCodecov(options) && !codeCovTokenSecret;
const hasScopedPackages = (scopedPackagesOptions ?? []).length > 0;
const useCodeArtifactOidc = codeArtifactOptions?.authProvider ===
release_1.CodeArtifactAuthProvider.GITHUB_OIDC;
if (useCodeCoveOidc || (useCodeArtifactOidc && hasScopedPackages)) {
return workflows_model_1.JobPermission.WRITE;
}
return undefined;
}
useCodecov(options) {
// Use Codecov when it is enabled or if or a secret token name is passed in
// AND jest must be configured
return (options.codeCov || options.codeCovTokenSecret) && this.jest?.config;
}
maybeAddCodecovIgnores(options) {
if (this.useCodecov(options)) {
this.addGitIgnore("codecov");
this.addGitIgnore("codecov.*");
}
}
renderUploadCoverageJobStep(options) {
// run codecov if enabled or a secret token name is passed in
// AND jest must be configured
if (this.useCodecov(options)) {
return [
{
name: "Upload coverage to Codecov",
uses: "codecov/codecov-action@v5",
with: options.codeCovTokenSecret
? {
token: `\${{ secrets.${options.codeCovTokenSecret} }}`,
directory: this.jest?.config.coverageDirectory,
}
: {
directory: this.jest?.config.coverageDirectory,
use_oidc: true,
},
},
];
}
else {
return [];
}
}
addBins(bins) {
this.package.addBin(bins);
}
/**
* Replaces the contents of an npm package.json script.
*
* @param name The script name
* @param command The command to execute
*/
setScript(name, command) {
this.package.setScript(name, command);
}
/**
* Replaces the contents of multiple npm package.json scripts.
* @param scripts The scripts to set
*/
addScripts(scripts) {
for (const [name, command] of Object.entries(scripts)) {
this.package.setScript(name, command);
}
}
/**
* Removes the npm script (always successful).
* @param name The name of the script.
*/
removeScript(name) {
this.package.removeScript(name);
}
/**
* Indicates if a script by the name name is defined.
* @param name The name of the script
* @deprecated Use `project.tasks.tryFind(name)`
*/
hasScript(name) {
return this.package.hasScript(name);
}
/**
* DEPRECATED
* @deprecated use `project.compileTask.exec()`
*/
addCompileCommand(...commands) {
for (const c of commands) {
this.compileTask.exec(c);
}
}
/**
* DEPRECATED
* @deprecated use `project.testTask.exec()`
*/
addTestCommand(...commands) {
for (const c of commands) {
this.testTask.exec(c);
}
}
/**
* Directly set fields in `package.json`.
* @param fields The fields to set
*/
addFields(fields) {
for (const [name, value] of Object.entries(fields)) {
this.package.addField(name, value);
}
}
/**
* Adds keywords to package.json (deduplicated)
* @param keywords The keywords to add
*/
addKeywords(...keywords) {
this.package.addKeywords(...keywords);
}
/**
* Get steps for scoped package access
*
* @param codeArtifactOptions Details of logging in to AWS
* @returns array of job steps required for each private scoped packages
*/
getScopedPackageSteps(codeArtifactOptions) {
const parsedCodeArtifactOptions = {
accessKeyIdSecret: codeArtifactOptions?.accessKeyIdSecret ?? "AWS_ACCESS_KEY_ID",
secretAccessKeySecret: codeArtifactOptions?.secretAccessKeySecret ?? "AWS_SECRET_ACCESS_KEY",
roleToAssume: codeArtifactOptions?.roleToAssume,
authProvider: codeArtifactOptions?.authProvider,
};
if (parsedCodeArtifactOptions.authProvider ===
node_package_1.CodeArtifactAuthProvider.GITHUB_OIDC) {
return [
{
name: "Configure AWS Credentials",
uses: "aws-actions/configure-aws-credentials@v5",
with: {
"aws-region": "us-east-2",
"role-to-assume": parsedCodeArtifactOptions.roleToAssume,
"role-duration-seconds": 900,
},
},
{
name: "AWS CodeArtifact Login",
run: `${this.runScriptCommand} ca:login`,
},
];
}
if (parsedCodeArtifactOptions.roleToAssume) {
return [
{
name: "Configure AWS Credentials",
uses: "aws-actions/configure-aws-credentials@v5",
with: {
"aws-access-key-id": (0, util_2.secretToString)(parsedCodeArtifactOptions.accessKeyIdSecret),
"aws-secret-access-key": (0, util_2.secretToString)(parsedCodeArtifactOptions.secretAccessKeySecret),
"aws-region": "us-east-2",
"role-to-assume": parsedCodeArtifactOptions.roleToAssume,
"role-duration-seconds": 900,
},
},
{
name: "AWS CodeArtifact Login",
run: `${this.runScriptCommand} ca:login`,
},
];
}
return [
{
name: "AWS CodeArtifact Login",
run: `${this.runScriptCommand} ca:login`,
env: {
AWS_ACCESS_KEY_ID: (0, util_2.secretToString)(parsedCodeArtifactOptions.accessKeyIdSecret),
AWS_SECRET_ACCESS_KEY: (0, util_2.secretToString)(parsedCodeArtifactOptions.secretAccessKeySecret),
},
},
];
}
/**
* Returns the set of workflow steps which should be executed to bootstrap a
* workflow.
*
* @param options Options.
* @returns Job steps
*/
renderWorkflowSetup(options = {}) {
const install = new Array();
// first run the workflow bootstrap steps
install.push(...this.workflowBootstrapSteps);
if (this.package.packageManager === node_package_1.NodePackageManager.PNPM) {
install.push({
name: "Setup pnpm",
uses: "pnpm/action-setup@v4",
with: { version: this.package.pnpmVersion },
});
}
else if (this.package.packageManager === node_package_1.NodePackageManager.BUN) {
install.push({
name: "Setup bun",
uses: "oven-sh/setup-bun@v2",
with: { "bun-version": this.package.bunVersion },
});
}
if (this.package.packageManager !== node_package_1.NodePackageManager.BUN) {
if (this.nodeVersion || this.workflowPackageCache) {
const pm = this.package.packageManager;
const cache = (0, util_1.isYarnClassic)(pm) || (0, util_1.isYarnBerry)(pm)
? "yarn"
: pm === node_package_1.NodePackageManager.PNPM
? "pnpm"
: "npm";
install.push({
name: "Setup Node.js",
uses: "actions/setup-node@v5",
with: {
...(this.nodeVersion && {
"node-version": this.nodeVersion,
}),
...(this.workflowPackageCache && {
cache,
}),
},
});
}
}
const mutable = options.mutable ?? false;
if (this.package.scopedPackagesOptions) {
install.push(...this.getScopedPackageSteps(this.package.codeArtifactOptions));
}
install.push({
name: "Install dependencies",
run: mutable
? this.package.installAndUpdateLockfileCommand
: this.package.installCommand,
...(options.installStepConfiguration ?? {}),
});
return install;
}
/**
* Defines normal dependencies.
*
* @param deps Names modules to install. By default, the the dependency will
* be installed in the next `npx projen` run and the version will be recorded
* in your `package.json` file. You can upgrade manually or using `yarn
* add/upgrade`. If you wish to specify a version range use this syntax:
* `module@^7`.
*/
addDeps(...deps) {
return this.package.addDeps(...deps);
}
/**
* Defines development/test dependencies.
*
* @param deps Names modules to install. By default, the the dependency will
* be installed in the next `npx projen` run and the version will be recorded
* in your `package.json` file. You can upgrade manually or using `yarn
* add/upgrade`. If you wish to specify a version range use this syntax:
* `module@^7`.
*/
addDevDeps(...deps) {
return this.package.addDevDeps(...deps);
}
/**
* Defines peer dependencies.
*
* When adding peer dependencies, a devDependency will also be added on the
* pinned version of the declared peer. This will ensure that you are testing
* your code against the minimum version required from your consumers.
*
* @param deps Names modules to install. By default, the the dependency will
* be installed in the next `npx projen` run and the version will be recorded
* in your `package.json` file. You can upgrade manually or using `yarn
* add/upgrade`. If you wish to specify a version range use this syntax:
* `module@^7`.
*/
addPeerDeps(...deps) {
return this.package.addPeerDeps(...deps);
}
/**
* Defines bundled dependencies.
*
* Bundled dependencies will be added as normal dependencies as well as to the
* `bundledDependencies` section of your `package.json`.
*
* @param deps Names modules to install. By default, the the dependency will
* be installed in the next `npx projen` run and the version will be recorded
* in your `package.json` file. You can upgrade manually or using `yarn
* add/upgrade`. If you wish to specify a version range use this syntax:
* `module@^7`.
*/
addBundledDeps(...deps) {
return this.package.addBundledDeps(...deps);
}
/**
* Adds patterns to be ignored by npm.
*
* @param pattern The pattern to ignore.
*
* @remarks
* If you are having trouble getting an ignore to populate, try using your construct or component's preSynthesize method to properly delay calling this method.
*/
addPackageIgnore(pattern) {
this.npmignore?.addPatterns(pattern);
}
addLicense(options) {
if (this.package.license) {
new license_1.License(this, {
spdx: this.package.license,
copyrightOwner: options.copyrightOwner ?? options.authorName,
copyrightPeriod: options.copyrightPeriod,
});
}
}
addDefaultGitIgnore() {
this.gitignore.exclude("# Logs", "logs", "*.log", "npm-debug.log*", "yarn-debug.log*", "yarn-error.log*", "lerna-debug.log*", "# Diagnostic reports (https://nodejs.org/api/report.html)", "report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json", "# Runtime data", "pids", "*.pid", "*.seed", "*.pid.lock", "# Directory for instrumented libs generated by jscoverage/JSCover", "lib-cov", "# Coverage directory used by tools like istanbul", "coverage", "*.lcov", "# nyc test coverage", ".nyc_output", "# Compiled binary addons (https://nodejs.org/api/addons.html)", "build/Release", "# Dependency directories", "node_modules/", "jspm_packages/", "# TypeScript cache", "*.tsbuildinfo", "# Optional eslint cache", ".eslintcache", "# Output of 'npm pack'", "*.tgz", "# Yarn Integrity file", ".yarn-integrity", "# parcel-bundler cache (https://parceljs.org/)", ".cache");
}
/**
* Returns the shell command to execute in order to run a task. This will
* typically be `npx projen TASK`.
*
* @param task The task for which the command is required
*/
runTaskCommand(task) {
return `${this.package.projenCommand} ${task.name}`;
}
/**
* The job ID of the build workflow.
*/
get buildWorkflowJobId() {
return this.buildWorkflow?.buildJobIds[0];
}
/**
* Adds a security audit task.
*/
addAuditTask(options) {
const auditLevel = options.auditDepsOptions?.level ?? "high";
const auditProdOnly = options.auditDepsOptions?.prodOnly ?? false;
// Create audit task
const auditTask = this.tasks.addTask("audit", {
description: "Run security audit",
});
// Add package manager specific audit command
const auditCommand = this.getAuditCommand(auditLevel, auditProdOnly);
auditTask.exec(auditCommand);
return auditTask;
}
/**
* Gets the appropriate audit command for the package manager.
*/
getAuditCommand(level, prodOnly) {
const levelFlag = this.getAuditLevelFlag(level);
const prodFlag = prodOnly ? this.getAuditProdFlag() : "";
switch (this.packageManager) {
case node_package_1.NodePackageManager.NPM:
return `npm audit${levelFlag}${prodFlag}`;
case node_package_1.NodePackageManager.YARN:
case node_package_1.NodePackageManager.YARN_CLASSIC:
// Use Node.js to call yarn and handle exit code cross-platform
const threshold = this.getYarnClassicThreshold(level);
return `node -e "const { execSync } = require('child_process'); try { execSync('yarn audit${levelFlag}${prodFlag}', {stdio: 'inherit'}); } catch(e) { process.exit(e.status < ${threshold} ? 0 : 1); }"`;
case node_package_1.NodePackageManager.YARN2:
case node_package_1.NodePackageManager.YARN_BERRY:
return `yarn npm audit --recursive${levelFlag}${prodFlag}`;
case node_package_1.NodePackageManager.PNPM:
return `pnpm audit${levelFlag}${prodFlag}`;
case node_package_1.NodePackageManager.BUN:
return `bun audit${levelFlag}${prodFlag}`;
default:
throw new Error(`Unsupported package manager: ${this.packageManager}`);
}
}
/**
* Gets the threshold value for yarn classic based on vulnerability level.
*/
getYarnClassicThreshold(level) {
switch (level) {
case "low":
return 2; // Pass for exit code < 2, fail for >= 2 (LOW and above)
case "moderate":
return 4; // Pass for exit code < 4, fail for >= 4 (MODERATE and above)
case "high":
return 8; // Pass for exit code < 8, fail for >= 8 (HIGH and above)
case "critical":
return 16; // Pass for exit code < 16, fail for >= 16 (CRITICAL)
default:
return 2;
}
}
/**
* Gets the audit level flag for the package manager.
*/
getAuditLevelFlag(level) {
switch (this.packageManager) {
case node_package_1.NodePackageManager.NPM:
return ` --audit-level=${level}`;
case node_package_1.NodePackageManager.YARN:
case node_package_1.NodePackageManager.YARN_CLASSIC:
return ` --level ${level}`;
case node_package_1.NodePackageManager.YARN2:
case node_package_1.NodePackageManager.YARN_BERRY:
return ` --severity ${level}`;
case node_package_1.NodePackageManager.PNPM:
return ` --audit-level ${level}`;
case node_package_1.NodePackageManager.BUN:
return ` --audit-level ${level}`;
default:
return "";
}
}
/**
* Gets the production-only flag for the package manager.
*/
getAuditProdFlag() {
switch (this.packageManager) {
case node_package_1.NodePackageManager.NPM:
return " --omit=dev";
case node_package_1.NodePackageManager.YARN:
case node_package_1.NodePackageManager.YARN_CLASSIC:
return " --groups dependencies";
case node_package_1.NodePackageManager.YARN2:
case node_package_1.NodePackageManager.YARN_BERRY:
return " --environment production";
case node_package_1.NodePackageManager.PNPM:
return " --prod";
case node_package_1.NodePackageManager.BUN:
return " --production";
default:
return "";
}
}
}
exports.NodeProject = NodeProject;
_a = JSII_RTTI_SYMBOL_1;
NodeProject[_a] = { fqn: "projen.javascript.NodeProject", version: "0.98.32" };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZS1wcm9qZWN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2phdmFzY3JpcHQvbm9kZS1wcm9qZWN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsK0JBQXVDO0FBQ3ZDLHVDQUFvRDtBQUNwRCxpQ0FBMkM7QUFDM0MsdURBQTBFO0FBQzFFLGlEQU13QjtBQUN4Qix5Q0FBdUQ7QUFDdkQsb0NBQXFFO0FBQ3JFLG9EQUFzRTtBQUN0RSxzQ0FBdUM7QUFDdkMsa0RBQWlEO0FBQ2pELHNDQU9tQjtBQUNuQix5Q0FBb0Q7QUFDcEQsaUNBQW9EO0FBQ3BELG1EQUFrRTtBQUNsRSxpREFBNkU7QUFDN0UsK0RBTW1DO0FBQ25DLGdEQUErRDtBQUMvRCw4Q0FNdUI7QUFDdkIsd0NBQXFDO0FBQ3JDLG9EQUFnRDtBQUNoRCx3Q0FRb0I7QUFDcEIsc0RBQTBEO0FBRTFELGtDQUE4RTtBQUM5RSx1Q0FBK0Q7QUFFL0QsTUFBTSxhQUFhLEdBQUcsUUFBUSxDQUFDO0FBMlcvQjs7R0FFRztBQUNILElBQVksV0FVWDtBQVZELFdBQVksV0FBVztJQUNyQjs7T0FFRztJQUNILDZEQUFZLENBQUE7SUFFWjs7T0FFRztJQUNILCtDQUFLLENBQUE7QUFDUCxDQUFDLEVBVlcsV0FBVywyQkFBWCxXQUFXLFFBVXRCO0FBRUQ7Ozs7R0FJRztBQUNILE1BQWEsV0FBWSxTQUFRLHNCQUFhO0lBVzVDOztPQUVHO0lBQ0gsSUFBVyxLQUFLO1FBQ2QsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNqQixJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksc0JBQVMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUN6RCxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDO0lBQ3JCLENBQUM7SUFHRDs7T0FFRztJQUNILElBQVcsd0JBQXdCO1FBQ2pDLE9BQU8sSUFBSSxD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