UNPKG

@lerna/publish

Version:

Publish packages in the current project

427 lines (407 loc) 15.4 kB
var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var import_core = require("@lerna/core"); var import_dedent = __toESM(require("dedent")); var import_fs_extra = __toESM(require("fs-extra")); var import_npm_package_arg = __toESM(require("npm-package-arg")); var import_os = __toESM(require("os")); var import_p_reduce = __toESM(require("p-reduce")); var import_pacote = __toESM(require("pacote")); var import_path = __toESM(require("path")); var import_slash = __toESM(require("slash")); var import_url = require("url"); var import_yargs_parser = require("yargs-parser"); const childProcess = require("@lerna/child-process"); const initPackageJson = require("pify")(require("init-package-json")); const { builtinNpmrc } = require("./lib/builtin-npmrc"); const { catFile } = require("./lib/cat-file"); const LERNA_MODULE_DATA = require.resolve(import_path.default.join(__dirname, "./lib/lerna-module-data.js")); const DEFAULT_DESCRIPTION = [ "Now I\u2019m the model of a modern major general", "The venerated Virginian veteran whose men are all", "Lining up, to put me up on a pedestal", "Writin\u2019 letters to relatives", "Embellishin\u2019 my elegance and eloquence", "But the elephant is in the room", "The truth is in ya face when ya hear the British cannons go", "BOOM" ].join(" / "); module.exports = function factory(argv) { return new CreateCommand(argv); }; class CreateCommand extends import_core.Command { initialize() { const { bin, description = DEFAULT_DESCRIPTION, esModule, keywords, license, loc: pkgLocation, name: pkgName, yes } = this.options; const { name, scope } = (0, import_npm_package_arg.default)(pkgName); if (!name && pkgName.includes("/")) { throw new import_core.ValidationError( "ENOPKGNAME", "Invalid package name. Use the <loc> positional to specify package directory.\nSee https://github.com/lerna/lerna/tree/main/libs/commands/create#usage for details." ); } this.dirName = scope ? name.split("/").pop() : name; this.pkgName = name; this.pkgsDir = this._getPackagesDir(pkgLocation); this.camelName = (0, import_yargs_parser.camelCase)(this.dirName); this.outDir = esModule ? "dist" : "lib"; this.targetDir = import_path.default.resolve(this.pkgsDir, this.dirName); this.binDir = import_path.default.join(this.targetDir, "bin"); this.binFileName = bin === true ? this.dirName : bin; this.libDir = import_path.default.join(this.targetDir, esModule ? "src" : "lib"); this.libFileName = `${this.dirName}.js`; this.testDir = import_path.default.join(this.targetDir, "__tests__"); this.testFileName = `${this.dirName}.test.js`; this.conf = (0, import_core.npmConf)({ description, esModule, keywords, scope, yes }); this.conf.addFile(builtinNpmrc(), "builtin"); this.conf.set("init-main", `${this.outDir}/${this.libFileName}`); if (esModule) { this.conf.set("init-es-module", `${this.outDir}/${this.dirName}.module.js`); } if (!this.project.isIndependent()) { this.conf.set("init-version", this.project.version); } if (this.conf.get("init-author-name") === "") { this.conf.set("init-author-name", this.gitConfig("user.name")); } if (this.conf.get("init-author-email") === "") { this.conf.set("init-author-email", this.gitConfig("user.email")); } if (license) { this.conf.set("init-license", license); } if (this.options.private) { this.conf.set("private", true); } if (this.options.loglevel === "silent") { this.conf.set("silent", true); } if (this.binFileName) { this.conf.set("bin", { [this.binFileName]: `bin/${this.binFileName}` }); } this.conf.set("directories", { lib: this.outDir, test: "__tests__" }); this.setFiles(); this.setHomepage(); this.setPublishConfig(); this.setRepository(); return Promise.resolve(this.setDependencies()); } _getPackagesDir(pkgLocation) { const packageParentDirs = this.project.packageParentDirs; if (!pkgLocation) { return packageParentDirs[0]; } const normalizedPkgLocation = import_path.default.resolve(this.project.rootPath, import_path.default.normalize(pkgLocation)).toLowerCase(); const packageParentDirsLower = packageParentDirs.map((p) => p.toLowerCase()); const matchingPathIndex = packageParentDirsLower.findIndex((p) => p.indexOf(normalizedPkgLocation) > -1); if (matchingPathIndex > -1) { return packageParentDirs[matchingPathIndex]; } throw new import_core.ValidationError( "ENOPKGDIR", `Location "${pkgLocation}" is not configured as a workspace directory.` ); } execute() { let chain = Promise.resolve(); chain = chain.then(() => import_fs_extra.default.mkdirp(this.libDir)); chain = chain.then(() => import_fs_extra.default.mkdirp(this.testDir)); chain = chain.then(() => Promise.all([this.writeReadme(), this.writeLibFile(), this.writeTestFile()])); if (this.binFileName) { chain = chain.then(() => import_fs_extra.default.mkdirp(this.binDir)); chain = chain.then(() => Promise.all([this.writeBinFile(), this.writeCliFile(), this.writeCliTest()])); } chain = chain.then(() => initPackageJson(this.targetDir, LERNA_MODULE_DATA, this.conf)); return chain.then((data) => { if (this.options.esModule) { this.logger.notice( "\u2714", import_dedent.default` Ensure '${import_path.default.relative(".", this.pkgsDir)}/*/${this.outDir}' has been added to ./.gitignore Ensure rollup or babel build scripts are in the root ` ); } this.logger.success( "create", `New package ${data.name} created at ./${import_path.default.relative(".", this.targetDir)}` ); }); } gitConfig(prop) { return childProcess.execSync("git", ["config", "--get", prop], this.execOpts); } collectExternalVersions() { const extVersions = /* @__PURE__ */ new Map(); for (const { externalDependencies } of this.packageGraph.values()) { for (const [name, resolved] of externalDependencies) { extVersions.set(name, resolved.fetchSpec); } } return extVersions; } hasLocalRelativeFileSpec() { for (const { localDependencies } of this.packageGraph.values()) { for (const spec of localDependencies.values()) { if (spec.type === "directory") { return true; } } } } resolveRelative(depNode) { const relPath = import_path.default.relative(this.targetDir, depNode.location); const spec = import_npm_package_arg.default.resolve(depNode.name, relPath, this.targetDir); return (0, import_slash.default)(spec.saveSpec); } setDependencies() { const inputs = new Set((this.options.dependencies || []).sort()); if (this.options.bin) { inputs.add("yargs"); } if (!inputs.size) { return; } const exts = this.collectExternalVersions(); const localRelative = this.hasLocalRelativeFileSpec(); const savePrefix = this.conf.get("save-exact") ? "" : this.conf.get("save-prefix"); const pacoteOpts = this.conf.snapshot; const decideVersion = (spec) => { if (this.packageGraph.has(spec.name)) { const depNode = this.packageGraph.get(spec.name); if (localRelative) { return this.resolveRelative(depNode); } return `${savePrefix}${depNode.version}`; } if (spec.type === "tag" && spec.fetchSpec === "latest") { if (exts.has(spec.name)) { return exts.get(spec.name); } return import_pacote.default.manifest(spec, pacoteOpts).then((pkg) => `${savePrefix}${pkg.version}`); } if (spec.type === "git") { throw new import_core.ValidationError("EGIT", "Do not use git dependencies"); } return spec.rawSpec; }; let chain = Promise.resolve(); chain = chain.then( () => (0, import_p_reduce.default)( inputs, (obj, input) => { const spec = (0, import_npm_package_arg.default)(input); return Promise.resolve(spec).then(decideVersion).then((version) => { obj[spec.name] = version; return obj; }); }, {} ) ); chain = chain.then((dependencies) => { this.conf.set("dependencies", dependencies); }); return chain; } setFiles() { const files = [this.outDir]; if (this.options.bin) { files.unshift("bin"); } this.conf.set("files", files); } setHomepage() { let { homepage = this.project.manifest.get("homepage") } = this.options; if (!homepage) { return; } if (homepage.indexOf("http") !== 0) { homepage = `http://${homepage}`; } const hurl = new import_url.URL(homepage); const relativeTarget = import_path.default.relative(this.project.rootPath, this.targetDir); if (hurl.hostname.match("github")) { hurl.pathname = import_path.default.posix.join(hurl.pathname, "tree/main", relativeTarget); hurl.hash = "readme"; } else if (!this.options.homepage) { hurl.pathname = import_path.default.posix.join(hurl.pathname, relativeTarget); } this.conf.set("homepage", hurl.href); } setPublishConfig() { const scope = this.conf.get("scope"); const registry = this.options.registry || this.conf.get(`${scope}:registry`) || this.conf.get("registry"); const isPublicRegistry = registry === this.conf.root.registry; const publishConfig = {}; if (scope && isPublicRegistry) { publishConfig.access = this.options.access || "public"; } if (registry && !isPublicRegistry) { publishConfig.registry = registry; } if (this.options.tag) { publishConfig.tag = this.options.tag; } if (Object.keys(publishConfig).length) { this.conf.set("publishConfig", publishConfig); } } setRepository() { try { const url = childProcess.execSync("git", ["remote", "get-url", "origin"], this.execOpts); this.conf.set("repository", url); } catch (err) { this.logger.warn("ENOREMOTE", "No git remote found, skipping repository property"); } } writeReadme() { const readmeContent = import_dedent.default` # \`${this.pkgName}\` > ${this.options.description || "TODO: description"} ## Usage \`\`\` ${// eslint-disable-next-line no-nested-ternary this.options.bin ? import_dedent.default` npm -g i ${this.pkgName} ${this.binFileName} --help ` : this.options.esModule ? `import ${this.camelName} from '${this.pkgName}';` : `const ${this.camelName} = require('${this.pkgName}');`} // TODO: DEMONSTRATE API \`\`\` `; return catFile(this.targetDir, "README.md", readmeContent); } writeLibFile() { const libContent = this.options.esModule ? import_dedent.default` export default function ${this.camelName}() { return 'Hello from ${this.camelName}'; } ` : import_dedent.default` 'use strict'; module.exports = ${this.camelName}; function ${this.camelName}() { return 'Hello from ${this.camelName}'; } `; return catFile(this.libDir, this.libFileName, libContent); } writeTestFile() { const testContent = this.options.esModule ? import_dedent.default` import ${this.camelName} from '../src/${this.dirName}.js'; import { strict as assert } from 'assert'; assert.strictEqual(${this.camelName}(), 'Hello from ${this.camelName}'); console.info('${this.camelName} tests passed'); ` : import_dedent.default` 'use strict'; const ${this.camelName} = require('..'); const assert = require('assert').strict; assert.strictEqual(${this.camelName}(), 'Hello from ${this.camelName}'); console.info('${this.camelName} tests passed'); `; return catFile(this.testDir, this.testFileName, testContent); } writeCliFile() { const cliFileName = "cli.js"; const cliContent = [ this.options.esModule ? import_dedent.default` import factory from 'yargs/yargs'; import ${this.camelName} from './${this.dirName}'; export default cli; ` : import_dedent.default` 'use strict'; const factory = require('yargs/yargs'); const ${this.camelName} = require('./${this.dirName}'); module.exports = cli; `, "", // blank line import_dedent.default` function cli(cwd) { const parser = factory(null, cwd); parser.alias('h', 'help'); parser.alias('v', 'version'); parser.usage( "$0", "TODO: description", yargs => { yargs.options({ // TODO: options }); }, argv => ${this.camelName}(argv) ); return parser; } ` ].join(import_os.default.EOL); return catFile(this.libDir, cliFileName, cliContent); } writeCliTest() { const cliTestFileName = "cli.test.js"; const cliTestContent = [ this.options.esModule ? import_dedent.default` import cli from '../src/cli'; ` : import_dedent.default` 'use strict'; const cli = require('../lib/cli'); `, "", // blank line import_dedent.default` describe('${this.pkgName} cli', () => { // const argv = cli(cwd).parse(['args']); it('needs tests'); }); ` ].join(import_os.default.EOL); return catFile(this.testDir, cliTestFileName, cliTestContent); } writeBinFile() { const binContent = import_dedent.default` #!/usr/bin/env node 'use strict'; // eslint-disable-next-line no-unused-expressions require('../${this.outDir}/cli')${this.options.esModule ? ".default" : ""}().parse(process.argv.slice(2));`; return catFile(this.binDir, this.binFileName, binContent, { mode: 493 }); } } module.exports.CreateCommand = CreateCommand;