projen
Version:
CDK for software projects
977 lines • 155 kB
JavaScript
"use strict";
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.NpmAccess = exports.NodePackageManager = exports.NodePackage = exports.CodeArtifactAuthProvider = void 0;
exports.defaultNpmToken = defaultNpmToken;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const fs_1 = require("fs");
const path_1 = require("path");
const semver = require("semver");
const util_1 = require("./util");
const yarnrc_1 = require("./yarnrc");
const _resolve_1 = require("../_resolve");
const component_1 = require("../component");
const dependencies_1 = require("../dependencies");
const json_1 = require("../json");
const release_1 = require("../release");
const task_runtime_1 = require("../task-runtime");
const util_2 = require("../util");
const UNLICENSED = "UNLICENSED";
const DEFAULT_NPM_REGISTRY_URL = "https://registry.npmjs.org/";
const GITHUB_PACKAGES_REGISTRY = "npm.pkg.github.com";
const DEFAULT_NPM_TOKEN_SECRET = "NPM_TOKEN";
const DEFAULT_GITHUB_TOKEN_SECRET = "GITHUB_TOKEN";
/**
* Options for authorizing requests to a AWS CodeArtifact npm repository.
*/
var CodeArtifactAuthProvider;
(function (CodeArtifactAuthProvider) {
/**
* Fixed credentials provided via Github secrets.
*/
CodeArtifactAuthProvider["ACCESS_AND_SECRET_KEY_PAIR"] = "ACCESS_AND_SECRET_KEY_PAIR";
/**
* Ephemeral credentials provided via Github's OIDC integration with an IAM role.
* See:
* https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc.html
* https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services
*/
CodeArtifactAuthProvider["GITHUB_OIDC"] = "GITHUB_OIDC";
})(CodeArtifactAuthProvider || (exports.CodeArtifactAuthProvider = CodeArtifactAuthProvider = {}));
/**
* Represents the npm `package.json` file.
*/
class NodePackage extends component_1.Component {
/**
* Returns the `NodePackage` instance associated with a project or `undefined` if
* there is no NodePackage.
* @param project The project
* @returns A NodePackage, or undefined
*/
static of(project) {
const isIt = (o) => o instanceof NodePackage;
return project.components.find(isIt);
}
constructor(project, options = {}) {
super(project);
this.scripts = {};
this.scriptsToBeRemoved = new Set();
this.keywords = new Set();
this.bin = {};
this.engines = {};
this.packageName = options.packageName ?? project.name;
this.peerDependencyOptions = {
pinnedDevDependency: true,
...options.peerDependencyOptions,
};
this.allowLibraryDependencies = options.allowLibraryDependencies ?? true;
this.packageManager =
options.packageManager ?? NodePackageManager.YARN_CLASSIC;
this.entrypoint = options.entrypoint ?? "lib/index.js";
this.lockFile = determineLockfile(this.packageManager);
this.project.annotateGenerated(`/${this.lockFile}`);
const { npmAccess, npmRegistry, npmRegistryUrl, npmTokenSecret, codeArtifactOptions, scopedPackagesOptions, npmProvenance, } = this.parseNpmOptions(options);
this.npmAccess = npmAccess;
this.npmRegistry = npmRegistry;
this.npmRegistryUrl = npmRegistryUrl;
this.npmTokenSecret = npmTokenSecret;
this.codeArtifactOptions = codeArtifactOptions;
this.scopedPackagesOptions = scopedPackagesOptions;
this.npmProvenance = npmProvenance;
this.processDeps(options);
this._prev = this.readPackageJson();
// empty objects are here to preserve order for backwards compatibility
this.manifest = {
name: this.packageName,
description: options.description,
repository: !options.repository
? undefined
: {
type: "git",
url: options.repository,
directory: options.repositoryDirectory,
},
bin: () => this.renderBin(),
scripts: () => this.renderScripts(),
author: this.renderAuthor(options),
devDependencies: {},
peerDependencies: {},
dependencies: {},
bundledDependencies: [],
...this.renderPackageResolutions(),
keywords: () => this.renderKeywords(),
engines: () => this.renderEngines(),
main: this.entrypoint !== "" ? this.entrypoint : undefined,
license: () => this.license ?? UNLICENSED,
homepage: options.homepage,
publishConfig: () => this.renderPublishConfig(),
typesVersions: this._prev?.typesVersions,
// in release CI builds we bump the version before we run "build" so we want
// to preserve the version number. otherwise, we always set it to 0.0.0
version: this.determineVersion(this._prev?.version),
bugs: options.bugsEmail || options.bugsUrl
? {
email: options.bugsEmail,
url: options.bugsUrl,
}
: undefined,
};
// Configure Yarn Berry if using
if (this.packageManager === NodePackageManager.YARN_BERRY ||
this.packageManager === NodePackageManager.YARN2) {
this.configureYarnBerry(project, options);
}
// add tasks for scripts from options (if specified)
// @deprecated
for (const [cmdname, shell] of Object.entries(options.scripts ?? {})) {
project.addTask(cmdname, { exec: shell });
}
this.file = new json_1.JsonFile(this, "package.json", {
obj: this.manifest,
readonly: false, // we want "yarn add" to work and we have anti-tamper
newline: true, // all package managers prefer a newline, see https://github.com/projen/projen/issues/2076
committed: true, // needs to be committed so users can install the dependencies
});
this.addKeywords(...(options.keywords ?? []));
this.addBin(options.bin ?? {});
// automatically add all executable files under "bin"
if (options.autoDetectBin ?? true) {
this.autoDiscoverBinaries();
}
// node version
this.minNodeVersion = options.minNodeVersion;
this.maxNodeVersion = options.maxNodeVersion;
this.pnpmVersion = options.pnpmVersion ?? "10";
this.bunVersion = options.bunVersion ?? "latest";
this.addNodeEngine();
this.addCodeArtifactLoginScript();
// license
if (options.licensed ?? true) {
this.license = options.license ?? "Apache-2.0";
}
this.installTask = project.addTask("install", {
description: "Install project dependencies and update lockfile (non-frozen)",
exec: this.installAndUpdateLockfileCommand,
});
this.installCiTask = project.addTask("install:ci", {
description: "Install project dependencies using frozen lockfile",
exec: this.installCommand,
});
}
/**
* 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) {
for (const dep of deps) {
this.project.deps.addDependency(dep, dependencies_1.DependencyType.RUNTIME);
}
}
/**
* 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) {
for (const dep of deps) {
this.project.deps.addDependency(dep, dependencies_1.DependencyType.BUILD);
}
}
/**
* 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) {
if (Object.keys(deps).length && !this.allowLibraryDependencies) {
throw new Error(`cannot add peer dependencies to an APP project: ${Object.keys(deps).join(",")}`);
}
for (const dep of deps) {
this.project.deps.addDependency(dep, dependencies_1.DependencyType.PEER);
}
}
/**
* 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) {
if (deps.length && !this.allowLibraryDependencies) {
throw new Error(`cannot add bundled dependencies to an APP project: ${deps.join(",")}`);
}
for (const dep of deps) {
this.project.deps.addDependency(dep, dependencies_1.DependencyType.BUNDLED);
}
}
/**
* Adds an `engines` requirement to your package.
* @param engine The engine (e.g. `node`)
* @param version The semantic version requirement (e.g. `^10`)
*/
addEngine(engine, version) {
this.engines[engine] = version;
}
/**
* Adds keywords to package.json (deduplicated)
* @param keywords The keywords to add
*/
addKeywords(...keywords) {
for (const k of keywords) {
this.keywords.add(k);
}
}
addBin(bins) {
for (const [k, v] of Object.entries(bins)) {
this.bin[k] = v;
}
}
/**
* Add a npm package.json script.
*
* @param name The script name
* @param command The command to execute
*/
setScript(name, command) {
this.scripts[name] = command;
}
/**
* Removes an npm script (always successful).
*
* @param name The name of the script.
*/
removeScript(name) {
// need to keep track in case there's a task of the same name
this.scriptsToBeRemoved.add(name);
delete this.scripts[name];
}
/**
* Indicates if a script by the given name is defined.
* @param name The name of the script
* @deprecated Use `project.tasks.tryFind(name)`
*/
hasScript(name) {
return this.project.tasks.tryFind(name) !== undefined;
}
/**
* Directly set fields in `package.json`.
* @escape
* @param name field name
* @param value field value
*/
addField(name, value) {
this.manifest[name] = value;
}
/**
* Sets the package version.
* @param version Package version.
*/
addVersion(version) {
this.manifest.version = version;
}
/**
* Defines resolutions for dependencies to change the normally resolved
* version of a dependency to something else.
*
* @param resolutions Names resolutions to be added. Specify a version or
* range with this syntax:
* `module@^7`
*/
addPackageResolutions(...resolutions) {
for (const resolution of resolutions) {
this.project.deps.addDependency(resolution, dependencies_1.DependencyType.OVERRIDE);
}
}
/**
* Returns the command to execute in order to install all dependencies (always frozen).
*/
get installCommand() {
return this.renderInstallCommand(true);
}
/**
* Renders `yarn install` or `npm install` with lockfile update (not frozen)
*/
get installAndUpdateLockfileCommand() {
return this.renderInstallCommand(false);
}
/**
* Attempt to resolve the currently installed version for a given dependency.
*
* @remarks
* This method will first look through the current project's dependencies.
* If found and semantically valid (not '*'), that will be used.
* Otherwise, it will fall back to locating a `package.json` manifest for the dependency
* through node's internal resolution reading the version from there.
*
* @param dependencyName Dependency to resolve for.
*/
tryResolveDependencyVersion(dependencyName) {
try {
const fromDeps = this.project.deps.tryGetDependency(dependencyName);
const version = semver.coerce(fromDeps?.version, { loose: true });
if (version) {
return version.format();
}
}
catch { }
return (0, util_1.tryResolveDependencyVersion)(dependencyName, {
paths: [this.project.outdir],
});
}
// ---------------------------------------------------------------------------------------
synthesize() {
this._renderedDeps = this.renderDependencies();
super.synthesize();
}
postSynthesize() {
super.postSynthesize();
// only run "install" if package.json has changed or if we don't have a
// `node_modules` directory.
if (this.file.changed ||
!(0, fs_1.existsSync)((0, path_1.join)(this.project.outdir, "node_modules"))) {
this.installDependencies();
}
// resolve "*" deps in package.json and update it. if it was changed,
// install deps again so that lockfile is updated.
if (this.resolveDepsAndWritePackageJson()) {
this.installDependencies();
}
}
/**
* The command which executes "projen".
* @deprecated use `project.projenCommand` instead.
*/
get projenCommand() {
return this.project.projenCommand;
}
/**
* Returns `true` if we are running within a CI build.
*/
get isAutomatedBuild() {
return (0, util_2.isTruthy)(process.env.CI);
}
determineVersion(currVersion) {
if (!this.isReleaseBuild) {
return "0.0.0";
}
return currVersion ?? "0.0.0";
}
/**
* Returns `true` if this is a CI release build.
*/
get isReleaseBuild() {
return (0, util_2.isTruthy)(process.env.RELEASE);
}
// -------------------------------------------------------------------------------------------
parseNpmOptions(options) {
let npmRegistryUrl = options.npmRegistryUrl;
if (options.npmRegistry) {
if (npmRegistryUrl) {
throw new Error('cannot use the deprecated "npmRegistry" together with "npmRegistryUrl". please use "npmRegistryUrl" instead.');
}
npmRegistryUrl = `https://${options.npmRegistry}`;
}
const npmr = new URL(npmRegistryUrl ?? DEFAULT_NPM_REGISTRY_URL);
if (!npmr || !npmr.hostname || !npmr.href) {
throw new Error(`unable to determine npm registry host from url ${npmRegistryUrl}. Is this really a URL?`);
}
const npmAccess = options.npmAccess ?? defaultNpmAccess(this.packageName);
if (!isScoped(this.packageName) && npmAccess === NpmAccess.RESTRICTED) {
throw new Error(`"npmAccess" cannot be RESTRICTED for non-scoped npm package "${this.packageName}"`);
}
const npmProvenance = options.npmProvenance ?? npmAccess === NpmAccess.PUBLIC;
if (npmProvenance && npmAccess !== NpmAccess.PUBLIC) {
throw new Error(`"npmProvenance" can only be enabled for public packages`);
}
const isAwsCodeArtifact = (0, release_1.isAwsCodeArtifactRegistry)(npmRegistryUrl);
const hasScopedPackage = options.scopedPackagesOptions &&
options.scopedPackagesOptions.length !== 0;
if (isAwsCodeArtifact) {
if (options.npmTokenSecret) {
throw new Error('"npmTokenSecret" must not be specified when publishing AWS CodeArtifact.');
}
else if (options.codeArtifactOptions?.authProvider ===
CodeArtifactAuthProvider.GITHUB_OIDC) {
if (options.codeArtifactOptions.accessKeyIdSecret ||
options.codeArtifactOptions.secretAccessKeySecret) {
throw new Error("access and secret key pair should not be provided when using GITHUB_OIDC auth provider for AWS CodeArtifact");
}
else if (!options.codeArtifactOptions.roleToAssume) {
throw new Error('"roleToAssume" property is required when using GITHUB_OIDC for AWS CodeArtifact options');
}
}
}
else {
if ((options.codeArtifactOptions?.accessKeyIdSecret ||
options.codeArtifactOptions?.secretAccessKeySecret ||
options.codeArtifactOptions?.roleToAssume) &&
!hasScopedPackage) {
throw new Error("codeArtifactOptions must only be specified when publishing AWS CodeArtifact or used in scoped packages.");
}
}
// apply defaults for AWS CodeArtifact
let codeArtifactOptions;
if (isAwsCodeArtifact || hasScopedPackage) {
const authProvider = options.codeArtifactOptions?.authProvider ??
CodeArtifactAuthProvider.ACCESS_AND_SECRET_KEY_PAIR;
const isAccessSecretKeyPairAuth = authProvider === CodeArtifactAuthProvider.ACCESS_AND_SECRET_KEY_PAIR;
codeArtifactOptions = {
authProvider,
accessKeyIdSecret: options.codeArtifactOptions?.accessKeyIdSecret ??
(isAccessSecretKeyPairAuth ? "AWS_ACCESS_KEY_ID" : undefined),
secretAccessKeySecret: options.codeArtifactOptions?.secretAccessKeySecret ??
(isAccessSecretKeyPairAuth ? "AWS_SECRET_ACCESS_KEY" : undefined),
roleToAssume: options.codeArtifactOptions?.roleToAssume,
};
}
return {
npmAccess,
npmRegistry: npmr.hostname + this.renderNpmRegistryPath(npmr.pathname),
npmRegistryUrl: npmr.href,
npmTokenSecret: defaultNpmToken(options.npmTokenSecret, npmr.hostname),
codeArtifactOptions,
scopedPackagesOptions: this.parseScopedPackagesOptions(options.scopedPackagesOptions),
npmProvenance,
};
}
parseScopedPackagesOptions(scopedPackagesOptions) {
if (!scopedPackagesOptions) {
return undefined;
}
return scopedPackagesOptions.map((option) => {
if (!isScoped(option.scope)) {
throw new Error(`Scope must start with "@" in options, found ${option.scope}`);
}
if (!(0, release_1.isAwsCodeArtifactRegistry)(option.registryUrl)) {
throw new Error(`Only AWS Code artifact scoped registry is supported for now, found ${option.registryUrl}`);
}
const result = {
registryUrl: option.registryUrl,
scope: option.scope,
};
return result;
});
}
addCodeArtifactLoginScript() {
if (!this.scopedPackagesOptions ||
this.scopedPackagesOptions.length === 0) {
return;
}
this.project.addTask("ca:login", {
steps: [
{ exec: "which aws" }, // check that AWS CLI is installed
...this.scopedPackagesOptions.map((scopedPackagesOption) => {
const { registryUrl, scope } = scopedPackagesOption;
const { domain, region, accountId, registry } = (0, util_1.extractCodeArtifactDetails)(registryUrl);
// reference: https://docs.aws.amazon.com/codeartifact/latest/ug/npm-auth.html
const commands = [
`npm config set ${scope}:registry ${registryUrl}`,
`CODEARTIFACT_AUTH_TOKEN=$(aws codeartifact get-authorization-token --domain ${domain} --region ${region} --domain-owner ${accountId} --query authorizationToken --output text)`,
`npm config set //${registry}:_authToken=$CODEARTIFACT_AUTH_TOKEN`,
];
if (!this.minNodeVersion || semver.major(this.minNodeVersion) <= 16) {
commands.push(`npm config set //${registry}:always-auth=true`);
}
return {
exec: commands.join("; "),
};
}),
],
});
}
addNodeEngine() {
if (!this.minNodeVersion && !this.maxNodeVersion) {
return;
}
let nodeVersion = "";
if (this.minNodeVersion) {
nodeVersion += `>= ${this.minNodeVersion}`;
}
if (this.maxNodeVersion) {
nodeVersion += ` <= ${this.maxNodeVersion}`;
}
this.addEngine("node", nodeVersion);
}
renderNpmRegistryPath(path) {
if (!path || path == "/") {
return "";
}
else {
return path;
}
}
renderInstallCommand(frozen) {
switch (this.packageManager) {
case NodePackageManager.YARN:
case NodePackageManager.YARN_CLASSIC:
return [
"yarn install",
"--check-files", // ensure all modules exist (especially projen which was just removed).
...(frozen ? ["--frozen-lockfile"] : []),
].join(" ");
case NodePackageManager.YARN2:
case NodePackageManager.YARN_BERRY:
return ["yarn install", ...(frozen ? ["--immutable"] : [])].join(" ");
case NodePackageManager.NPM:
return frozen ? "npm ci" : "npm install";
case NodePackageManager.PNPM:
return frozen
? "pnpm i --frozen-lockfile"
: "pnpm i --no-frozen-lockfile";
case NodePackageManager.BUN:
return ["bun install", ...(frozen ? ["--frozen-lockfile"] : [])].join(" ");
default:
throw new Error(`unexpected package manager ${this.packageManager}`);
}
}
processDeps(options) {
this.addDeps(...(options.deps ?? []));
this.addDevDeps(...(options.devDeps ?? []));
this.addPeerDeps(...(options.peerDeps ?? []));
this.addBundledDeps(...(options.bundledDeps ?? []));
}
renderDependencies() {
const devDependencies = {};
const peerDependencies = {};
const dependencies = {};
const bundledDependencies = new Array();
// synthetic dependencies: add a pinned build dependency to ensure we are
// testing against the minimum requirement of the peer.
if (this.peerDependencyOptions.pinnedDevDependency) {
for (const dep of this.project.deps.all.filter((d) => d.type === dependencies_1.DependencyType.PEER)) {
let req = dep.name;
// Skip if we already have a runtime dependency on this peer and no build dependency yet.
// If there is a build dep already, we need to override its version.
if (this.project.deps.tryGetDependency(dep.name, dependencies_1.DependencyType.RUNTIME) &&
!this.project.deps.tryGetDependency(dep.name, dependencies_1.DependencyType.BUILD)) {
continue;
}
if (dep.version) {
const ver = (0, util_1.minVersion)(dep.version);
if (!ver) {
throw new Error(`unable to determine minimum semver for peer dependency ${dep.name}@${dep.version}`);
}
req += "@" + ver;
}
this.addDevDeps(req);
}
}
for (const dep of this.project.deps.all) {
let version = dep.version ?? "*";
let name = dep.name;
if (name.startsWith("file:")) {
const localDependencyPath = name.substring(5);
const depPackageJson = (0, path_1.resolve)(this.project.outdir, localDependencyPath, "package.json");
const pkgFile = (0, fs_1.readFileSync)(depPackageJson, "utf8");
const pkg = JSON.parse(pkgFile);
version = localDependencyPath;
name = pkg.name;
}
switch (dep.type) {
case dependencies_1.DependencyType.BUNDLED:
bundledDependencies.push(name);
const depDecls = this.project.deps.all.filter((d) => d.name === name);
if (depDecls.some((d) => d.type === dependencies_1.DependencyType.PEER)) {
throw new Error(`unable to bundle "${name}": it cannot appear as a peer dependency (bundled would always take precedence over peer)`);
}
// I've observed that at least npm 10.8.2 will silently fail to bundle
// a dependency if it is [also] part of `devDependencies`. It must exist in
// `dependencies` and `dependencies` only.
if (depDecls.some((d) => d.type === dependencies_1.DependencyType.BUILD)) {
throw new Error(`unable to bundle "${name}": it cannot appear as a devDependency (only prod dependencies are bundled, and any dependency appearing as a devDependency is considered to be not a prod dependency)`);
}
// also add as a runtime dependency
dependencies[name] = version;
break;
case dependencies_1.DependencyType.PEER:
peerDependencies[name] = version;
break;
case dependencies_1.DependencyType.RUNTIME:
dependencies[name] = version;
break;
case dependencies_1.DependencyType.TEST:
case dependencies_1.DependencyType.DEVENV:
case dependencies_1.DependencyType.BUILD:
devDependencies[name] = version;
break;
}
}
// returns a lazy value to normalize during synthesis
const normalize = (obj) => () => (0, util_2.sorted)(obj);
// update the manifest we are about to save into `package.json`
this.manifest.devDependencies = normalize(devDependencies);
this.manifest.peerDependencies = normalize(peerDependencies);
this.manifest.dependencies = normalize(dependencies);
this.manifest.bundledDependencies = (0, util_2.sorted)(bundledDependencies);
// nothing further to do if package.json file does not exist
if (!this._prev) {
return { devDependencies, peerDependencies, dependencies };
}
const readDeps = (user, current = {}) => {
for (const [name, userVersion] of Object.entries(user)) {
const currentVersion = current[name];
// respect user version if it's not '*' or if current version is undefined
if (userVersion !== "*" || !currentVersion || currentVersion === "*") {
continue;
}
// memoize current version in memory so it is preserved when saving
user[name] = currentVersion;
}
// report removals
for (const name of Object.keys(current ?? {})) {
if (!user[name]) {
this.project.logger.verbose(`${name}: removed`);
}
}
};
readDeps(devDependencies, this._prev.devDependencies);
readDeps(dependencies, this._prev.dependencies);
readDeps(peerDependencies, this._prev.peerDependencies);
return { devDependencies, dependencies, peerDependencies };
}
/**
* Resolves any deps that do not have a specified version (e.g. `*`) and
* update `package.json` if needed.
*
* @returns `true` if package.json was updated or `false` if not.
*/
resolveDepsAndWritePackageJson() {
const outdir = this.project.outdir;
const rootPackageJson = (0, path_1.join)(outdir, "package.json");
const original = (0, fs_1.readFileSync)(rootPackageJson, "utf8");
const pkg = JSON.parse(original);
const resolveDeps = (current, user) => {
const result = {};
current = current ?? {};
user = user ?? {};
for (const [name, currentDefinition] of Object.entries(user)) {
// find actual version from node_modules
let desiredVersion = currentDefinition;
if (currentDefinition === "*") {
// we already know we don't have the version in project `deps`,
// so skip straight to checking manifest.
const resolvedVersion = (0, util_1.tryResolveDependencyVersion)(name, {
paths: [this.project.outdir],
});
if (!resolvedVersion) {
this.project.logger.warn(`unable to resolve version for ${name} from installed modules`);
continue;
}
desiredVersion = `^${resolvedVersion}`;
}
if (currentDefinition !== desiredVersion) {
this.project.logger.verbose(`${name}: ${currentDefinition} => ${desiredVersion}`);
}
result[name] = desiredVersion;
}
// print removed packages
for (const name of Object.keys(current)) {
if (!result[name]) {
this.project.logger.verbose(`${name} removed`);
}
}
return result;
};
const rendered = this._renderedDeps;
if (!rendered) {
throw new Error("assertion failed");
}
const deps = resolveDeps(pkg.dependencies, rendered.dependencies);
const devDeps = resolveDeps(pkg.devDependencies, rendered.devDependencies);
const peerDeps = resolveDeps(pkg.peerDependencies, rendered.peerDependencies);
if (this.peerDependencyOptions.pinnedDevDependency) {
for (const [name, version] of Object.entries(peerDeps)) {
// Skip if we already have a runtime dependency on this peer
// or if devDependency version is already set.
// Relies on the "*" devDependency added in the presynth step
if (deps[name] || rendered.devDependencies[name] !== "*") {
continue;
}
// Take version and pin as dev dependency
const ver = (0, util_1.minVersion)(version);
if (!ver) {
throw new Error(`unable to determine minimum semver for peer dependency ${name}@${version}`);
}
devDeps[name] = ver;
}
}
pkg.dependencies = (0, util_2.sorted)(deps);
pkg.devDependencies = (0, util_2.sorted)(devDeps);
pkg.peerDependencies = (0, util_2.sorted)(peerDeps);
const updated = JSON.stringify(pkg, undefined, 2) + "\n";
if (original === updated) {
return false;
}
(0, util_2.writeFile)(rootPackageJson, updated);
return true;
}
renderPackageResolutions() {
const render = () => {
const overridingDependencies = this.project.deps.all.filter((dep) => dep.type === dependencies_1.DependencyType.OVERRIDE);
if (!overridingDependencies.length) {
return undefined;
}
return Object.fromEntries(overridingDependencies.map(({ name, version = "*" }) => [name, version]));
};
switch (this.packageManager) {
case NodePackageManager.NPM:
return { overrides: render };
case NodePackageManager.PNPM:
return this.project.parent
? undefined
: { pnpm: { overrides: render } };
case NodePackageManager.YARN:
case NodePackageManager.YARN2:
case NodePackageManager.YARN_CLASSIC:
case NodePackageManager.YARN_BERRY:
case NodePackageManager.BUN:
default:
return { resolutions: render };
}
}
renderPublishConfig() {
// When npm provenance is enabled, we need to always render the public access
// But when npmAccess is the set to the default, we prefer to omit it
const shouldOmitAccess = !this.npmProvenance &&
this.npmAccess === defaultNpmAccess(this.packageName);
// omit values if they are the same as the npm defaults
return (0, _resolve_1.resolve)({
registry: this.npmRegistryUrl !== DEFAULT_NPM_REGISTRY_URL
? this.npmRegistryUrl
: undefined,
access: shouldOmitAccess ? undefined : this.npmAccess,
}, { omitEmpty: true });
}
renderKeywords() {
const kwds = Array.from(this.keywords);
return (0, util_2.sorted)(kwds.sort());
}
renderEngines() {
return (0, util_2.sorted)(this.engines);
}
autoDiscoverBinaries() {
const binrel = "bin";
const bindir = (0, path_1.join)(this.project.outdir, binrel);
if ((0, fs_1.existsSync)(bindir)) {
for (const file of (0, fs_1.readdirSync)(bindir)) {
try {
(0, fs_1.accessSync)((0, path_1.join)(bindir, file), fs_1.constants.X_OK);
const binPath = (0, path_1.join)(binrel, file);
const normalizedPath = (0, util_2.normalizePersistedPath)(binPath);
this.bin[file] = normalizedPath;
}
catch (e) {
// not executable, skip
}
}
}
}
renderAuthor(options) {
let author;
if (options.authorName) {
author = {
name: options.authorName,
email: options.authorEmail,
url: options.authorUrl,
organization: options.authorOrganization ?? false,
};
}
else {
if (options.authorEmail ||
options.authorUrl ||
options.authorOrganization !== undefined) {
throw new Error('"authorName" is required if specifying "authorEmail" or "authorUrl"');
}
}
return author;
}
renderBin() {
return (0, util_2.sorted)(this.bin);
}
renderScripts() {
const result = {};
const tasks = this.project.tasks.all
.filter((t) =>
// Must remove to prevent overriding built-in npm command (which would loop)
t.name !== this.installTask.name && t.name !== this.installCiTask.name)
.sort((x, y) => x.name.localeCompare(y.name));
for (const task of tasks) {
if (this.scriptsToBeRemoved.has(task.name)) {
continue;
}
result[task.name] = this.npmScriptForTask(task);
}
return {
...result,
...this.scripts,
};
}
npmScriptForTask(task) {
return `${this.projenCommand} ${task.name}`;
}
readPackageJson() {
const file = (0, path_1.join)(this.project.outdir, "package.json");
if (!(0, fs_1.existsSync)(file)) {
return undefined;
}
return JSON.parse((0, fs_1.readFileSync)(file, "utf-8"));
}
installDependencies() {
this.project.logger.info("Installing dependencies...");
const runtime = new task_runtime_1.TaskRuntime(this.project.outdir);
const taskToRun = this.isAutomatedBuild
? this.installCiTask
: this.installTask;
runtime.runTask(taskToRun.name);
}
configureYarnBerry(project, options) {
const { version = "4.0.1", yarnRcOptions = {}, zeroInstalls = false, } = options.yarnBerryOptions || {};
this.checkForConflictingYarnOptions(yarnRcOptions);
// Set the `packageManager` field in `package.json` to the version specified. This tells `corepack` which version
// of `yarn` to use.
this.addField("packageManager", `yarn@${version}`);
this.configureYarnBerryGitignore(zeroInstalls);
new yarnrc_1.Yarnrc(project, version, yarnRcOptions);
}
checkForConflictingYarnOptions(yarnRcOptions) {
if (this.npmAccess &&
yarnRcOptions.npmPublishAccess &&
this.npmAccess.toString() !== yarnRcOptions.npmPublishAccess.toString()) {
throw new Error(`Cannot set npmAccess (${this.npmAccess}) and yarnRcOptions.npmPublishAccess (${yarnRcOptions.npmPublishAccess}) to different values.`);
}
if (this.npmRegistryUrl &&
yarnRcOptions.npmRegistryServer &&
this.npmRegistryUrl !== yarnRcOptions.npmRegistryServer) {
throw new Error(`Cannot set npmRegistryUrl (${this.npmRegistryUrl}) and yarnRcOptions.npmRegistryServer (${yarnRcOptions.npmRegistryServer}) to different values.`);
}
}
/** See https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored */
configureYarnBerryGitignore(zeroInstalls) {
const { gitignore } = this.project;
// These patterns are the same whether or not you're using zero-installs
gitignore.exclude(".yarn/*");
gitignore.include(".yarn/patches", ".yarn/plugins", ".yarn/releases", ".yarn/sdks", ".yarn/versions");
if (zeroInstalls) {
gitignore.include("!.yarn/cache");
}
else {
gitignore.exclude(".pnp.*");
}
}
}
exports.NodePackage = NodePackage;
_a = JSII_RTTI_SYMBOL_1;
NodePackage[_a] = { fqn: "projen.javascript.NodePackage", version: "0.95.2" };
/**
* The node package manager to use.
*/
var NodePackageManager;
(function (NodePackageManager) {
/**
* Use `yarn` as the package manager.
*
* @deprecated For `yarn` 1.x use `YARN_CLASSIC` for `yarn` >= 2 use `YARN_BERRY`. Currently, `NodePackageManager.YARN` means `YARN_CLASSIC`. In the future, we might repurpose it to mean `YARN_BERRY`.
*/
NodePackageManager["YARN"] = "yarn";
/**
* Use `yarn` versions >= 2 as the package manager.
*
* @deprecated use YARN_BERRY instead
*/
NodePackageManager["YARN2"] = "yarn2";
/**
* Use `yarn` 1.x as the package manager.
*/
NodePackageManager["YARN_CLASSIC"] = "yarn_classic";
/**
* Use `yarn` versions >= 2 as the package manager.
*/
NodePackageManager["YARN_BERRY"] = "yarn_berry";
/**
* Use `npm` as the package manager.
*/
NodePackageManager["NPM"] = "npm";
/**
* Use `pnpm` as the package manager.
*/
NodePackageManager["PNPM"] = "pnpm";
/**
* Use `bun` as the package manager
*/
NodePackageManager["BUN"] = "bun";
})(NodePackageManager || (exports.NodePackageManager = NodePackageManager = {}));
/**
* Npm package access level
*/
var NpmAccess;
(function (NpmAccess) {
/**
* Package is public.
*/
NpmAccess["PUBLIC"] = "public";
/**
* Package can only be accessed with credentials.
*/
NpmAccess["RESTRICTED"] = "restricted";
})(NpmAccess || (exports.NpmAccess = NpmAccess = {}));
/**
* Determines if an npm package is "scoped" (i.e. it starts with "xxx@").
*/
function isScoped(packageName) {
return packageName.includes("@");
}
function defaultNpmAccess(packageName) {
return isScoped(packageName) ? NpmAccess.RESTRICTED : NpmAccess.PUBLIC;
}
function defaultNpmToken(npmToken, registry) {
// if we are publishing to AWS CdodeArtifact, no NPM_TOKEN used (will be requested using AWS CLI later).
if ((0, release_1.isAwsCodeArtifactRegistry)(registry)) {
return undefined;
}
// if we are publishing to GitHub Packages, default to GITHUB_TOKEN.
const isGitHubPackages = registry === GITHUB_PACKAGES_REGISTRY;
return (npmToken ??
(isGitHubPackages ? DEFAULT_GITHUB_TOKEN_SECRET : DEFAULT_NPM_TOKEN_SECRET));
}
function determineLockfile(packageManager) {
if (packageManager === NodePackageManager.YARN ||
packageManager === NodePackageManager.YARN2 ||
packageManager === NodePackageManager.YARN_CLASSIC ||
packageManager === NodePackageManager.YARN_BERRY) {
return "yarn.lock";
}
else if (packageManager === NodePackageManager.NPM) {
return "package-lock.json";
}
else if (packageManager === NodePackageManager.PNPM) {
return "pnpm-lock.yaml";
}
else if (packageManager === NodePackageManager.BUN) {
return "bun.lockb";
}
throw new Error(`unsupported package manager ${packageManager}`);
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZS1wYWNrYWdlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2phdmFzY3JpcHQvbm9kZS1wYWNrYWdlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7QUF1dURBLDBDQWVDOztBQXR2REQsMkJBTVk7QUFDWiwrQkFBcUM7QUFDckMsaUNBQWlDO0FBQ2pDLGlDQUlnQjtBQUNoQixxQ0FBaUQ7QUFDakQsMENBQXFEO0FBQ3JELDRDQUF5QztBQUN6QyxrREFBaUQ7QUFDakQsa0NBQW1DO0FBRW5DLHdDQUF1RDtBQUV2RCxrREFBOEM7QUFDOUMsa0NBQThFO0FBRTlFLE1BQU0sVUFBVSxHQUFHLFlBQVksQ0FBQztBQUNoQyxNQUFNLHdCQUF3QixHQUFHLDZCQUE2QixDQUFDO0FBQy9ELE1BQU0sd0JBQXdCLEdBQUcsb0JBQW9CLENBQUM7QUFDdEQsTUFBTSx3QkFBd0IsR0FBRyxXQUFXLENBQUM7QUFDN0MsTUFBTSwyQkFBMkIsR0FBRyxjQUFjLENBQUM7QUEwVW5EOztHQUVHO0FBQ0gsSUFBWSx3QkFhWDtBQWJELFdBQVksd0JBQXdCO0lBQ2xDOztPQUVHO0lBQ0gscUZBQXlELENBQUE7SUFFekQ7Ozs7O09BS0c7SUFDSCx1REFBMkIsQ0FBQTtBQUM3QixDQUFDLEVBYlcsd0JBQXdCLHdDQUF4Qix3QkFBd0IsUUFhbkM7QUE4REQ7O0dBRUc7QUFDSCxNQUFhLFdBQVksU0FBUSxxQkFBUztJQUN4Qzs7Ozs7T0FLRztJQUNJLE1BQU0sQ0FBQyxFQUFFLENBQUMsT0FBZ0I7UUFDL0IsTUFBTSxJQUFJLEdBQUcsQ0FBQyxDQUFZLEVBQW9CLEVBQUUsQ0FBQyxDQUFDLFlBQVksV0FBVyxDQUFDO1FBQzFFLE9BQU8sT0FBTyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDdkMsQ0FBQztJQTZIRCxZQUFZLE9BQWdCLEVBQUUsVUFBOEIsRUFBRTtRQUM1RCxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7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