UNPKG

projen

Version:

CDK for software projects

977 lines • 155 kB
"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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