diff --git a/.changeset/large-paws-joke.md b/.changeset/large-paws-joke.md new file mode 100644 index 0000000000..dddfb41b09 --- /dev/null +++ b/.changeset/large-paws-joke.md @@ -0,0 +1,5 @@ +--- +"@pnpm/exportable-manifest": major +--- + +Package created. diff --git a/.changeset/large-pugs-retire.md b/.changeset/large-pugs-retire.md new file mode 100644 index 0000000000..9f79654dca --- /dev/null +++ b/.changeset/large-pugs-retire.md @@ -0,0 +1,5 @@ +--- +"@pnpm/make-dedicated-lockfile": minor +--- + +Project created. diff --git a/package.json b/package.json index 901ec0d8e8..52e78913d2 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "test-branch": "pnpm run lint && git remote set-branches --add origin master && git fetch && pnpm run compile && run-p -r verdaccio test-pkgs-branch --workspace-concurrency=2", "test-pkgs-branch": "cross-env PNPM_REGISTRY_MOCK_UPLINK=http://localhost:7348 pnpm run _test --no-sort --filter=...[origin/master]", "verdaccio": "verdaccio --config ./verdaccio.yaml --listen 7348", - "compile": "pnpm run --filter pnpm compile && pnpm run update-manifests", + "compile": "pnpm run --filter pnpm compile --filter @pnpm/make-dedicated-lockfile && pnpm run update-manifests", "watch": "pnpm run --filter @pnpm/fetch compile && pnpm run --filter pnpm compile -- --watch", "coveralls": "lcov-result-merger './packages/*/coverage/lcov.info' | coveralls", "update-manifests": "ts-node utils/updater/src/index.ts" diff --git a/packages/exportable-manifest/README.md b/packages/exportable-manifest/README.md new file mode 100644 index 0000000000..64a7ca6c6c --- /dev/null +++ b/packages/exportable-manifest/README.md @@ -0,0 +1,15 @@ +# @pnpm/exportable-manifest + +> Creates an exportable manifest + +[![npm version](https://img.shields.io/npm/v/@pnpm/exportable-manifest.svg)](https://www.npmjs.com/package/@pnpm/exportable-manifest) + +## Installation + +```sh + add @pnpm/exportable-manifest +``` + +## License + +MIT © [Zoltan Kochan](https://www.kochan.io/) diff --git a/packages/exportable-manifest/package.json b/packages/exportable-manifest/package.json new file mode 100644 index 0000000000..45f837f168 --- /dev/null +++ b/packages/exportable-manifest/package.json @@ -0,0 +1,41 @@ +{ + "name": "@pnpm/exportable-manifest", + "version": "0.0.0", + "description": "Creates an exportable manifest", + "main": "lib/index.js", + "typings": "lib/index.d.ts", + "files": [ + "lib", + "!*.map" + ], + "engines": { + "node": ">=10.13" + }, + "scripts": { + "lint": "tslint -c ../../tslint.json src/**/*.ts test/**/*.ts", + "test": "pnpm run compile", + "prepublishOnly": "pnpm run compile", + "compile": "rimraf lib tsconfig.tsbuildinfo && tsc --build" + }, + "repository": "https://github.com/pnpm/pnpm/blob/master/packages/exportable-manifest", + "keywords": [ + "pnpm" + ], + "author": "Zoltan Kochan (https://www.kochan.io/)", + "license": "MIT", + "bugs": { + "url": "https://github.com/pnpm/pnpm/issues" + }, + "homepage": "https://github.com/pnpm/pnpm/blob/master/packages/exportable-manifest#readme", + "devDependencies": { + "@pnpm/exportable-manifest": "link:", + "@types/ramda": "^0.27.14" + }, + "dependencies": { + "@pnpm/error": "workspace:^1.2.0", + "@pnpm/read-project-manifest": "workspace:^1.0.11", + "@pnpm/types": "workspace:^6.2.0", + "ramda": "^0.27.1" + }, + "funding": "https://opencollective.com/pnpm" +} diff --git a/packages/exportable-manifest/src/index.ts b/packages/exportable-manifest/src/index.ts new file mode 100644 index 0000000000..5f2d32dc7f --- /dev/null +++ b/packages/exportable-manifest/src/index.ts @@ -0,0 +1,77 @@ +import PnpmError from '@pnpm/error' +import { tryReadProjectManifest } from '@pnpm/read-project-manifest' +import { Dependencies, ProjectManifest } from '@pnpm/types' +import path = require('path') +import R = require('ramda') + +// property keys that are copied from publishConfig into the manifest +const PUBLISH_CONFIG_WHITELIST = new Set([ + // manifest fields that may make sense to overwrite + 'bin', + // https://github.com/stereobooster/package.json#package-bundlers + 'main', + 'module', + 'typings', + 'types', + 'exports', + 'browser', + 'esnext', + 'es2015', + 'unpkg', + 'umd:main', +]) + +export default async function makePublishManifest (dir: string, originalManifest: ProjectManifest) { + const publishManifest = { + ...originalManifest, + } + for (const depsField of ['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies']) { + const deps = await makePublishDependencies(dir, originalManifest[depsField]) + if (deps) { + publishManifest[depsField] = deps + } + } + + const { publishConfig } = originalManifest + if (publishConfig) { + Object.keys(publishConfig) + .filter(key => PUBLISH_CONFIG_WHITELIST.has(key)) + .forEach(key => { + publishManifest[key] = publishConfig[key] + }) + } + + return publishManifest +} + +async function makePublishDependencies (dir: string, dependencies: Dependencies | undefined) { + if (!dependencies) return dependencies + const publishDependencies: Dependencies = R.fromPairs( + await Promise.all( + Object.entries(dependencies) + .map(async ([depName, depSpec]) => [ + depName, + await makePublishDependency(depName, depSpec, dir), + ]) + ) as any, // tslint:disable-line + ) + return publishDependencies +} + +async function makePublishDependency (depName: string, depSpec: string, dir: string) { + if (!depSpec.startsWith('workspace:')) { + return depSpec + } + if (depSpec === 'workspace:*') { + const { manifest } = await tryReadProjectManifest(path.join(dir, 'node_modules', depName)) + if (!manifest || !manifest.version) { + throw new PnpmError( + 'CANNOT_RESOLVE_WORKSPACE_PROTOCOL', + `Cannot resolve workspace protocol of dependency "${depName}" ` + + `because this dependency is not installed. Try running "pnpm install".` + ) + } + return manifest.version + } + return depSpec.substr(10) +} diff --git a/packages/exportable-manifest/tsconfig.json b/packages/exportable-manifest/tsconfig.json new file mode 100644 index 0000000000..69f0e26743 --- /dev/null +++ b/packages/exportable-manifest/tsconfig.json @@ -0,0 +1,22 @@ +{ + "extends": "@pnpm/tsconfig", + "compilerOptions": { + "outDir": "lib", + "rootDir": "src" + }, + "include": [ + "src/**/*.ts", + "../../typings/**/*.d.ts" + ], + "references": [ + { + "path": "../error" + }, + { + "path": "../read-project-manifest" + }, + { + "path": "../types" + } + ] +} diff --git a/packages/make-dedicated-lockfile/README.md b/packages/make-dedicated-lockfile/README.md new file mode 100644 index 0000000000..4d62dc3626 --- /dev/null +++ b/packages/make-dedicated-lockfile/README.md @@ -0,0 +1,24 @@ +# @pnpm/make-dedicated-lockfile + +> Creates a dedicated lockfile for a subset of workspace projects + +[![npm version](https://img.shields.io/npm/v/@pnpm/make-dedicated-lockfile.svg)](https://www.npmjs.com/package/@pnpm/make-dedicated-lockfile) + +## Installation + +```sh + add @pnpm/make-dedicated-lockfile +``` + +## Usage + +Open the directory of the workspace project that you want to create a dedicated lockfile for. + +Run `make-dedicated-lockfile` in the terminal. + +A new lockfile will be generated, using dependencies from the shared workspace lockfile but +only those that are related to the project in the current working directory or subdirectories. + +## License + +MIT © [Zoltan Kochan](https://www.kochan.io/) diff --git a/packages/make-dedicated-lockfile/package.json b/packages/make-dedicated-lockfile/package.json new file mode 100644 index 0000000000..08c947cfa3 --- /dev/null +++ b/packages/make-dedicated-lockfile/package.json @@ -0,0 +1,55 @@ +{ + "name": "@pnpm/make-dedicated-lockfile", + "version": "0.0.0", + "description": "Creates a dedicated lockfile for a subset of workspace projects", + "main": "lib/index.js", + "typings": "lib/index.d.ts", + "bin": "./lib/bin.js", + "files": [ + "lib", + "!*.map", + "bin" + ], + "engines": { + "node": ">=10.13" + }, + "scripts": { + "lint": "tslint -c ../../tslint.json src/**/*.ts test/**/*.ts", + "_test": "cd ../.. && c8 --reporter lcov --reports-dir packages/make-dedicated-lockfile/coverage ts-node packages/make-dedicated-lockfile/test --type-check", + "test": "pnpm run compile && pnpm run _test", + "prepublishOnly": "pnpm run compile", + "compile": "rimraf lib tsconfig.tsbuildinfo && tsc --build" + }, + "repository": "https://github.com/pnpm/pnpm/blob/master/packages/make-dedicated-lockfile", + "keywords": [ + "pnpm", + "make-dedicated-lockfile" + ], + "author": "Zoltan Kochan (https://www.kochan.io/)", + "license": "MIT", + "bugs": { + "url": "https://github.com/pnpm/pnpm/issues" + }, + "homepage": "https://github.com/pnpm/pnpm/blob/master/packages/make-dedicated-lockfile#readme", + "dependencies": { + "@pnpm/error": "workspace:^1.2.0", + "@pnpm/exec": "^1.1.5", + "@pnpm/exportable-manifest": "workspace:^0.0.0", + "@pnpm/find-workspace-dir": "workspace:^1.0.0", + "@pnpm/lockfile-file": "workspace:^3.0.11", + "@pnpm/prune-lockfile": "workspace:^2.0.14", + "@pnpm/read-project-manifest": "workspace:^1.0.11", + "@pnpm/types": "workspace:^6.2.0", + "mz": "^2.7.0", + "ramda": "^0.27.1", + "rename-overwrite": "^3.0.0" + }, + "funding": "https://opencollective.com/pnpm", + "devDependencies": { + "@types/mz": "^2.7.1", + "@types/ncp": "^2.0.4", + "@types/ramda": "^0.27.14", + "ncp": "^2.0.0", + "tempy": "^0.6.0" + } +} diff --git a/packages/make-dedicated-lockfile/src/bin.ts b/packages/make-dedicated-lockfile/src/bin.ts new file mode 100644 index 0000000000..8097f61ec7 --- /dev/null +++ b/packages/make-dedicated-lockfile/src/bin.ts @@ -0,0 +1,14 @@ +import PnpmError from '@pnpm/error' +import findWorkspaceDir from '@pnpm/find-workspace-dir' +import makeDedicatedLockfile from '.' + +main() + +async function main () { + const projectDir = process.cwd() + const lockfileDir = await findWorkspaceDir(projectDir) + if (!lockfileDir) { + throw new PnpmError('WORKSPACE_NOT_FOUND', 'Cannot create a dedicated lockfile for a project that is not in a workspace.') + } + await makeDedicatedLockfile(lockfileDir, projectDir) +} diff --git a/packages/make-dedicated-lockfile/src/index.ts b/packages/make-dedicated-lockfile/src/index.ts new file mode 100644 index 0000000000..ab6cac9953 --- /dev/null +++ b/packages/make-dedicated-lockfile/src/index.ts @@ -0,0 +1,86 @@ +import pnpmExec from '@pnpm/exec' +import exportableManifest from '@pnpm/exportable-manifest' +import { + getLockfileImporterId, + ProjectSnapshot, + readWantedLockfile, + writeWantedLockfile, +} from '@pnpm/lockfile-file' +import { pruneSharedLockfile } from '@pnpm/prune-lockfile' +import readProjectManifest from '@pnpm/read-project-manifest' +import { DEPENDENCIES_FIELDS } from '@pnpm/types' +import path = require('path') +import R = require('ramda') +import renameOverwrite = require('rename-overwrite') + +export default async function (lockfileDir: string, projectDir: string) { + const lockfile = await readWantedLockfile(lockfileDir, { ignoreIncompatible: false }) + if (!lockfile) { + throw new Error('no lockfile found') + } + const allImporters = lockfile.importers + lockfile.importers = {} + const baseImporterId = getLockfileImporterId(lockfileDir, projectDir) + for (const [importerId, importer] of Object.entries(allImporters)) { + if (importerId.startsWith(`${baseImporterId}/`)) { + const newImporterId = importerId.substr(baseImporterId.length + 1) + lockfile.importers[newImporterId] = projectSnapshotWithoutLinkedDeps(importer) + continue + } + if (importerId === baseImporterId) { + lockfile.importers['.'] = projectSnapshotWithoutLinkedDeps(importer) + } + } + const dedicatedLockfile = pruneSharedLockfile(lockfile) + + await writeWantedLockfile(projectDir, dedicatedLockfile) + const modulesDir = path.join(projectDir, 'node_modules') + const tmp = path.join(projectDir, 'tmp_node_modules') + const tempModulesDir = path.join(projectDir, 'node_modules/.tmp') + let modulesRenamed = false + try { + await renameOverwrite(modulesDir, tmp) + await renameOverwrite(tmp, tempModulesDir) + modulesRenamed = true + } catch (err) { + if (err['code'] !== 'ENOENT') throw err + } + + const { manifest, writeProjectManifest } = await readProjectManifest(projectDir) + const publishManifest = await exportableManifest(projectDir, manifest) + await writeProjectManifest(publishManifest) + + try { + await pnpmExec([ + 'install', + '--lockfile-dir=.', + '--lockfile-only', + '--filter=.', + '--no-link-workspace-packages', + ], { + cwd: projectDir, + }) + } catch (err) { + throw err + } finally { + if (modulesRenamed) { + await renameOverwrite(tempModulesDir, tmp) + await renameOverwrite(tmp, modulesDir) + } + await writeProjectManifest(manifest) + } +} + +function projectSnapshotWithoutLinkedDeps (projectSnapshot: ProjectSnapshot) { + const newProjectSnapshot: ProjectSnapshot = { + specifiers: projectSnapshot.specifiers, + } + for (const depField of DEPENDENCIES_FIELDS) { + if (!projectSnapshot[depField]) continue + newProjectSnapshot[depField] = R.fromPairs( + Object.entries(projectSnapshot[depField]!) + .filter(([depName, depVersion]) => !depVersion.startsWith('link:')) + ) + } + return newProjectSnapshot +} diff --git a/packages/make-dedicated-lockfile/test/fixture/packages/is-negative/example/package.json b/packages/make-dedicated-lockfile/test/fixture/packages/is-negative/example/package.json new file mode 100644 index 0000000000..76026fb50b --- /dev/null +++ b/packages/make-dedicated-lockfile/test/fixture/packages/is-negative/example/package.json @@ -0,0 +1,7 @@ +{ + "name": "example", + "version": "2.0.0", + "dependencies": { + "lodash": "1.0.0" + } +} diff --git a/packages/make-dedicated-lockfile/test/fixture/packages/is-negative/package.json b/packages/make-dedicated-lockfile/test/fixture/packages/is-negative/package.json new file mode 100644 index 0000000000..89b3637f5f --- /dev/null +++ b/packages/make-dedicated-lockfile/test/fixture/packages/is-negative/package.json @@ -0,0 +1,8 @@ +{ + "name": "is-negative", + "version": "1.0.0", + "dependencies": { + "ramda": "0.26.0", + "is-positive": "workspace:1.0.0" + } +} diff --git a/packages/make-dedicated-lockfile/test/fixture/packages/is-positive/package.json b/packages/make-dedicated-lockfile/test/fixture/packages/is-positive/package.json new file mode 100644 index 0000000000..250c18dfd4 --- /dev/null +++ b/packages/make-dedicated-lockfile/test/fixture/packages/is-positive/package.json @@ -0,0 +1,8 @@ +{ + "name": "is-positive", + "version": "1.0.0", + "dependencies": { + "express": "1.0.0" + } +} + diff --git a/packages/make-dedicated-lockfile/test/fixture/pnpm-lock.yaml b/packages/make-dedicated-lockfile/test/fixture/pnpm-lock.yaml new file mode 100644 index 0000000000..d860aac650 --- /dev/null +++ b/packages/make-dedicated-lockfile/test/fixture/pnpm-lock.yaml @@ -0,0 +1,122 @@ +importers: + packages/is-negative: + dependencies: + is-positive: 'link:../is-positive' + ramda: 0.26.0 + specifiers: + is-positive: 'workspace:1.0.0' + ramda: 0.26.0 + packages/is-negative/example: + dependencies: + lodash: 1.0.0 + specifiers: + lodash: 1.0.0 + packages/is-positive: + dependencies: + express: 1.0.0 + specifiers: + express: 1.0.0 +lockfileVersion: 5.1 +packages: + /connect/3.7.0: + dependencies: + debug: 2.6.9 + finalhandler: 1.1.2 + parseurl: 1.3.3 + utils-merge: 1.0.1 + dev: false + engines: + node: '>= 0.10.0' + resolution: + integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ== + /debug/2.6.9: + dependencies: + ms: 2.0.0 + dev: false + resolution: + integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + /ee-first/1.1.1: + dev: false + resolution: + integrity: sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + /encodeurl/1.0.2: + dev: false + engines: + node: '>= 0.8' + resolution: + integrity: sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + /escape-html/1.0.3: + dev: false + resolution: + integrity: sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + /express/1.0.0: + dependencies: + connect: 3.7.0 + deprecated: express 1.x series is deprecated + dev: false + engines: + node: '>= 0.2.0' + hasBin: true + resolution: + integrity: sha1-SKQ9eKluuSMvYx0jzI3o+FTY4Ok= + /finalhandler/1.1.2: + dependencies: + debug: 2.6.9 + encodeurl: 1.0.2 + escape-html: 1.0.3 + on-finished: 2.3.0 + parseurl: 1.3.3 + statuses: 1.5.0 + unpipe: 1.0.0 + dev: false + engines: + node: '>= 0.8' + resolution: + integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + /lodash/1.0.0: + dev: false + engines: + '0': node + '1': rhino + resolution: + integrity: sha1-JTXC99y2k3zujSZyxfcTju4N9qk= + /ms/2.0.0: + dev: false + resolution: + integrity: sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + /on-finished/2.3.0: + dependencies: + ee-first: 1.1.1 + dev: false + engines: + node: '>= 0.8' + resolution: + integrity: sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + /parseurl/1.3.3: + dev: false + engines: + node: '>= 0.8' + resolution: + integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + /ramda/0.26.0: + dev: false + resolution: + integrity: sha512-maK1XqpgsOo5DwjhROjqDvpm1vkphLQbpleVv+b3t5Y9uOQ0t8hTHT582+mDs7RLrex1kd4lWYizNXWLVjsq9w== + /statuses/1.5.0: + dev: false + engines: + node: '>= 0.6' + resolution: + integrity: sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + /unpipe/1.0.0: + dev: false + engines: + node: '>= 0.8' + resolution: + integrity: sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + /utils-merge/1.0.1: + dev: false + engines: + node: '>= 0.4.0' + resolution: + integrity: sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= diff --git a/packages/make-dedicated-lockfile/test/fixture/pnpm-workspace.yaml b/packages/make-dedicated-lockfile/test/fixture/pnpm-workspace.yaml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/make-dedicated-lockfile/test/index.ts b/packages/make-dedicated-lockfile/test/index.ts new file mode 100644 index 0000000000..9f5c809aae --- /dev/null +++ b/packages/make-dedicated-lockfile/test/index.ts @@ -0,0 +1,27 @@ +import { readWantedLockfile } from '@pnpm/lockfile-file' +import ncpCB = require('ncp') +import path = require('path') +import test = require('tape') +import tempy = require('tempy') +import { promisify } from 'util' +import makeDedicatedLockfile from '../lib' + +const ncp = promisify(ncpCB) + +const fixture = path.join(__dirname, 'fixture') + +test('makeDedicatedLockfile()', async (t) => { + const tmp = tempy.directory() + await ncp(fixture, tmp) + const projectDir = path.join(tmp, 'packages/is-negative') + await makeDedicatedLockfile(tmp, projectDir) + + const lockfile = await readWantedLockfile(projectDir, { ignoreIncompatible: false }) + t.deepEqual(Object.keys(lockfile.importers), ['.', 'example']) + t.deepEqual(Object.keys(lockfile.packages), [ + '/is-positive/1.0.0', + '/lodash/1.0.0', + '/ramda/0.26.0', + ]) + t.end() +}) diff --git a/packages/make-dedicated-lockfile/tsconfig.json b/packages/make-dedicated-lockfile/tsconfig.json new file mode 100644 index 0000000000..6f40b9a56f --- /dev/null +++ b/packages/make-dedicated-lockfile/tsconfig.json @@ -0,0 +1,34 @@ +{ + "extends": "@pnpm/tsconfig", + "compilerOptions": { + "outDir": "lib", + "rootDir": "src" + }, + "include": [ + "src/**/*.ts", + "../../typings/**/*.d.ts" + ], + "references": [ + { + "path": "../error" + }, + { + "path": "../exportable-manifest" + }, + { + "path": "../find-workspace-dir" + }, + { + "path": "../lockfile-file" + }, + { + "path": "../prune-lockfile" + }, + { + "path": "../read-project-manifest" + }, + { + "path": "../types" + } + ] +} diff --git a/packages/plugin-commands-publishing/package.json b/packages/plugin-commands-publishing/package.json index af6f583d74..acf4d9fe3f 100644 --- a/packages/plugin-commands-publishing/package.json +++ b/packages/plugin-commands-publishing/package.json @@ -55,11 +55,11 @@ "@pnpm/cli-utils": "workspace:0.4.19", "@pnpm/config": "workspace:11.2.1", "@pnpm/error": "workspace:1.2.0", + "@pnpm/exportable-manifest": "workspace:^0.0.0", "@pnpm/fetch": "workspace:^2.1.2", "@pnpm/lifecycle": "workspace:9.2.2", "@pnpm/npm-resolver": "workspace:9.0.2", "@pnpm/pick-registry-for-package": "workspace:1.0.3", - "@pnpm/read-project-manifest": "workspace:1.0.11", "@pnpm/resolver-base": "workspace:7.0.3", "@pnpm/run-npm": "workspace:2.0.3", "@pnpm/sort-packages": "workspace:1.0.13", diff --git a/packages/plugin-commands-publishing/src/publish.ts b/packages/plugin-commands-publishing/src/publish.ts index bc9f15ce97..74a8aa19db 100644 --- a/packages/plugin-commands-publishing/src/publish.ts +++ b/packages/plugin-commands-publishing/src/publish.ts @@ -1,10 +1,10 @@ import { docsUrl, readProjectManifest } from '@pnpm/cli-utils' import { Config, types as allTypes } from '@pnpm/config' import PnpmError from '@pnpm/error' +import exportableManifest from '@pnpm/exportable-manifest' import runLifecycleHooks, { RunLifecycleHookOptions } from '@pnpm/lifecycle' -import { tryReadProjectManifest } from '@pnpm/read-project-manifest' import runNpm from '@pnpm/run-npm' -import { Dependencies, ProjectManifest } from '@pnpm/types' +import { ProjectManifest } from '@pnpm/types' import rimraf = require('@zkochan/rimraf') import cpFile = require('cp-file') import { prompt } from 'enquirer' @@ -183,23 +183,6 @@ async function runScriptsIfPresent ( const LICENSE_GLOB = 'LICEN{S,C}E{,.*}' const findLicenses = fg.bind(fg, [LICENSE_GLOB]) as (opts: { cwd: string }) => Promise -// property keys that are copied from publishConfig into the manifest -const PUBLISH_CONFIG_WHITELIST = new Set([ - // manifest fields that may make sense to overwrite - 'bin', - // https://github.com/stereobooster/package.json#package-bundlers - 'main', - 'module', - 'typings', - 'types', - 'exports', - 'browser', - 'esnext', - 'es2015', - 'unpkg', - 'umd:main', -]) - export async function fakeRegularManifest ( opts: { engineStrict?: boolean, @@ -214,7 +197,7 @@ export async function fakeRegularManifest ( ? await copyLicenses(opts.workspaceDir, opts.dir) : [] const { fileName, manifest, writeProjectManifest } = await readProjectManifest(opts.dir, opts) - const publishManifest = await makePublishManifest(opts.dir, manifest) + const publishManifest = await exportableManifest(opts.dir, manifest) const replaceManifest = fileName !== 'package.json' || !R.equals(manifest, publishManifest) if (replaceManifest) { await rimraf(path.join(opts.dir, fileName)) @@ -230,59 +213,6 @@ export async function fakeRegularManifest ( ) } -async function makePublishManifest (dir: string, originalManifest: ProjectManifest) { - const publishManifest = { - ...originalManifest, - dependencies: await makePublishDependencies(dir, originalManifest.dependencies), - devDependencies: await makePublishDependencies(dir, originalManifest.devDependencies), - optionalDependencies: await makePublishDependencies(dir, originalManifest.optionalDependencies), - peerDependencies: await makePublishDependencies(dir, originalManifest.peerDependencies), - } - - const { publishConfig } = originalManifest - if (publishConfig) { - Object.keys(publishConfig) - .filter(key => PUBLISH_CONFIG_WHITELIST.has(key)) - .forEach(key => { - publishManifest[key] = publishConfig[key] - }) - } - - return publishManifest -} - -async function makePublishDependencies (dir: string, dependencies: Dependencies | undefined) { - if (!dependencies) return dependencies - const publishDependencies: Dependencies = R.fromPairs( - await Promise.all( - R.toPairs(dependencies) - .map(async ([depName, depSpec]) => [ - depName, - await makePublishDependency(depName, depSpec, dir), - ]) - ) as any, // tslint:disable-line - ) - return publishDependencies -} - -async function makePublishDependency (depName: string, depSpec: string, dir: string) { - if (!depSpec.startsWith('workspace:')) { - return depSpec - } - if (depSpec === 'workspace:*') { - const { manifest } = await tryReadProjectManifest(path.join(dir, 'node_modules', depName)) - if (!manifest || !manifest.version) { - throw new PnpmError( - 'CANNOT_RESOLVE_WORKSPACE_PROTOCOL', - `Cannot resolve workspace protocol of dependency "${depName}" ` + - `because this dependency is not installed. Try running "pnpm install".` - ) - } - return manifest.version - } - return depSpec.substr(10) -} - async function copyLicenses (sourceDir: string, destDir: string) { const licenses = await findLicenses({ cwd: sourceDir }) if (licenses.length === 0) return [] diff --git a/packages/plugin-commands-publishing/tsconfig.json b/packages/plugin-commands-publishing/tsconfig.json index cdfaa7c3a5..e7ec959598 100644 --- a/packages/plugin-commands-publishing/tsconfig.json +++ b/packages/plugin-commands-publishing/tsconfig.json @@ -18,6 +18,9 @@ { "path": "../error" }, + { + "path": "../exportable-manifest" + }, { "path": "../fetch" }, @@ -30,9 +33,6 @@ { "path": "../pick-registry-for-package" }, - { - "path": "../read-project-manifest" - }, { "path": "../resolver-base" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 36916f267b..fb4b4fae8f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -384,6 +384,22 @@ importers: semver: ^7.3.2 packages/error: specifiers: {} + packages/exportable-manifest: + dependencies: + '@pnpm/error': 'link:../error' + '@pnpm/read-project-manifest': 'link:../read-project-manifest' + '@pnpm/types': 'link:../types' + ramda: 0.27.1 + devDependencies: + '@pnpm/exportable-manifest': 'link:' + '@types/ramda': 0.27.14 + specifiers: + '@pnpm/error': 'workspace:^1.2.0' + '@pnpm/exportable-manifest': 'link:' + '@pnpm/read-project-manifest': 'workspace:^1.0.11' + '@pnpm/types': 'workspace:^6.2.0' + '@types/ramda': ^0.27.14 + ramda: ^0.27.1 packages/fetch: dependencies: '@pnpm/core-loggers': 'link:../core-loggers' @@ -1003,6 +1019,42 @@ importers: dependency-path: 'workspace:5.0.3' ramda: ^0.27.0 tempy: ^0.6.0 + packages/make-dedicated-lockfile: + dependencies: + '@pnpm/error': 'link:../error' + '@pnpm/exec': 1.1.5 + '@pnpm/exportable-manifest': 'link:../exportable-manifest' + '@pnpm/find-workspace-dir': 'link:../find-workspace-dir' + '@pnpm/lockfile-file': 'link:../lockfile-file' + '@pnpm/prune-lockfile': 'link:../prune-lockfile' + '@pnpm/read-project-manifest': 'link:../read-project-manifest' + '@pnpm/types': 'link:../types' + mz: 2.7.0 + ramda: 0.27.1 + rename-overwrite: 3.0.0 + devDependencies: + '@types/mz': 2.7.1 + '@types/ncp': 2.0.4 + '@types/ramda': 0.27.14 + ncp: 2.0.0 + tempy: 0.6.0 + specifiers: + '@pnpm/error': 'workspace:^1.2.0' + '@pnpm/exec': ^1.1.5 + '@pnpm/exportable-manifest': 'workspace:^0.0.0' + '@pnpm/find-workspace-dir': 'workspace:^1.0.0' + '@pnpm/lockfile-file': 'workspace:^3.0.11' + '@pnpm/prune-lockfile': 'workspace:^2.0.14' + '@pnpm/read-project-manifest': 'workspace:^1.0.11' + '@pnpm/types': 'workspace:^6.2.0' + '@types/mz': ^2.7.1 + '@types/ncp': ^2.0.4 + '@types/ramda': ^0.27.14 + mz: ^2.7.0 + ncp: ^2.0.0 + ramda: ^0.27.1 + rename-overwrite: ^3.0.0 + tempy: ^0.6.0 packages/manifest-utils: dependencies: '@pnpm/types': 'link:../types' @@ -1736,11 +1788,11 @@ importers: '@pnpm/cli-utils': 'link:../cli-utils' '@pnpm/config': 'link:../config' '@pnpm/error': 'link:../error' + '@pnpm/exportable-manifest': 'link:../exportable-manifest' '@pnpm/fetch': 'link:../fetch' '@pnpm/lifecycle': 'link:../lifecycle' '@pnpm/npm-resolver': 'link:../npm-resolver' '@pnpm/pick-registry-for-package': 'link:../pick-registry-for-package' - '@pnpm/read-project-manifest': 'link:../read-project-manifest' '@pnpm/resolver-base': 'link:../resolver-base' '@pnpm/run-npm': 'link:../run-npm' '@pnpm/sort-packages': 'link:../sort-packages' @@ -1780,6 +1832,7 @@ importers: '@pnpm/cli-utils': 'workspace:0.4.19' '@pnpm/config': 'workspace:11.2.1' '@pnpm/error': 'workspace:1.2.0' + '@pnpm/exportable-manifest': 'workspace:^0.0.0' '@pnpm/fetch': 'workspace:^2.1.2' '@pnpm/filter-workspace-packages': 'workspace:2.1.12' '@pnpm/lifecycle': 'workspace:9.2.2' @@ -1787,7 +1840,6 @@ importers: '@pnpm/pick-registry-for-package': 'workspace:1.0.3' '@pnpm/plugin-commands-publishing': 'link:' '@pnpm/prepare': 'workspace:0.0.8' - '@pnpm/read-project-manifest': 'workspace:1.0.11' '@pnpm/resolver-base': 'workspace:7.0.3' '@pnpm/run-npm': 'workspace:2.0.3' '@pnpm/sort-packages': 'workspace:1.0.13' @@ -3421,6 +3473,18 @@ packages: node: '>=10' resolution: integrity: sha512-GTsO3rA0vKVx9w3IrB6rrxFfhguAqJxSl0Bg0DG/GxlzKYEe9YlSBImZgR/UxTrSDQICodpCJ/lYC1Vo4+K3eA== + /@pnpm/exec/1.1.5: + dependencies: + '@pnpm/self-installer': 2.1.0 + '@types/got': 8.3.5 + '@types/node': 10.17.28 + command-exists: 1.2.9 + cross-spawn: 6.0.5 + dev: false + engines: + node: '>=4' + resolution: + integrity: sha512-1zLmh6tRftQXfZ1IFHq1IexP0KaJhN6pSCA/IzK+Vixn4hPvxwcIbGjKW0KH9hsHSmrPpmSit2EWj7jGNgfa6Q== /@pnpm/file-reporter/1.0.0: dependencies: graceful-fs: 4.2.4 @@ -3461,6 +3525,13 @@ packages: hasBin: true resolution: integrity: sha512-rHimIrV+aclTGBU0S2OLMytV44boh0RV3G8jRyW3bBQrp5sio2xcXEfYXXh2N4iO5/JbfMMsuFSRIXAWyFv1qw== + /@pnpm/self-installer/2.1.0: + dev: false + engines: + node: '>=4' + hasBin: true + resolution: + integrity: sha512-bfMgLFmg33kY1XBPBgdkbpld6fSeyt6iAlXbIMioArHd1t58EAMFmM2cYZQt4I2MguUpLRDlZwOpYYmirDHhsg== /@pnpm/semver-diff/1.0.2: dev: false engines: @@ -3587,6 +3658,12 @@ packages: '@types/node': 14.0.27 resolution: integrity: sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w== + /@types/got/8.3.5: + dependencies: + '@types/node': 10.17.28 + dev: false + resolution: + integrity: sha512-AaXSrIF99SjjtPVNmCmYb388HML+PKEJb/xmj4SbL2ZO0hHuETZZzyDIKfOqaEoAHZEuX4sC+FRFrHYJoIby6A== /@types/graceful-fs/4.1.3: dependencies: '@types/node': 14.0.23 @@ -3649,7 +3726,7 @@ packages: integrity: sha512-H86h7KmRDVs9UeSiQvtUeVhS+WYpJSYSsZrRvNYpGWGiytEqxwEtvgRnINESQtCgnojIH2wS2WgaMTJP0firBw== /@types/ncp/2.0.4: dependencies: - '@types/node': 14.0.23 + '@types/node': 14.0.27 dev: true resolution: integrity: sha512-erpimpT1pH8QfeNg77ypnjwz6CGMqrnL4DewVbqFzD9FXzSULjmG3KzjZnLNe7bzTSZm2W9DpkHyqop1g1KmgQ== @@ -3659,6 +3736,10 @@ packages: form-data: 3.0.0 resolution: integrity: sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw== + /@types/node/10.17.28: + dev: false + resolution: + integrity: sha512-dzjES1Egb4c1a89C7lKwQh8pwjYmlOAG9dW1pBgxEk57tMrLnssOfEthz8kdkNaBd7lIqQx7APm5+mZ619IiCQ== /@types/node/12.12.50: dev: true resolution: @@ -3706,6 +3787,12 @@ packages: dev: true resolution: integrity: sha512-pojA0+wBhjMWfwZ1tAea/OdUqZxaRQOi/vHldthrOIEPdRQdJb/hvU4yM1uHKGTT89ZZpxe43KM1sq5YGxS5lw== + /@types/ramda/0.27.14: + dependencies: + ts-toolbelt: 6.13.39 + dev: true + resolution: + integrity: sha512-vbw/VAtEJeSJ6Z61QT+epirlnBeJiJIO7ndK1BJ0fKswnfbiTNga/jBG6R3OnBaFYx+UJv6Iv7ZfWDFSsSzNqA== /@types/retry/0.12.0: dev: true resolution: @@ -5208,6 +5295,10 @@ packages: node: '>= 0.8' resolution: integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + /command-exists/1.2.9: + dev: false + resolution: + integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w== /commander/2.1.0: dev: true engines: @@ -5533,7 +5624,6 @@ packages: semver: 5.7.1 shebang-command: 1.2.0 which: 1.3.1 - dev: true engines: node: '>=4.8' resolution: @@ -8779,7 +8869,6 @@ packages: resolution: integrity: sha1-gixFgNer54PfGZZbeJYiyoAWA+Q= /nice-try/1.0.5: - dev: true resolution: integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== /nise/4.0.4: @@ -9461,7 +9550,6 @@ packages: resolution: integrity: sha1-F0uSaHNVNP+8es5r9TpanhtcX18= /path-key/2.0.1: - dev: true engines: node: '>=4' resolution: @@ -9906,6 +9994,10 @@ packages: dev: false resolution: integrity: sha512-pVzZdDpWwWqEVVLshWUHjNwuVP7SfcmPraYuqocJp1yo2U1R7P+5QAfDhdItkuoGqIBnBYrtPp7rEPqDn9HlZA== + /ramda/0.27.1: + dev: false + resolution: + integrity: sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw== /range-parser/1.2.1: dev: true engines: @@ -10666,7 +10758,6 @@ packages: /shebang-command/1.2.0: dependencies: shebang-regex: 1.0.0 - dev: true engines: node: '>=0.10.0' resolution: @@ -10679,7 +10770,6 @@ packages: resolution: integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== /shebang-regex/1.0.0: - dev: true engines: node: '>=0.10.0' resolution: @@ -11557,6 +11647,10 @@ packages: dev: true resolution: integrity: sha512-tVKhhF9X0nMXnpSkXbaOlE1XOzmo4S7mJkoOHVTocFhnBMIzjwU5PwLSusDH+o3KlJbTRJkQ37iu92kX9vjDwA== + /ts-toolbelt/6.13.39: + dev: true + resolution: + integrity: sha512-VD/rJ6+NGFA7AK2KWmGzLifrqA060M9o7+R2BxJtLBlwmfEaGdqGeyUPRDKhMZPMgpT/JMQ6+X+/ppaZNzuhvw== /tslib/1.13.0: dev: true resolution: @@ -12128,7 +12222,6 @@ packages: /which/1.3.1: dependencies: isexe: 2.0.0 - dev: true hasBin: true resolution: integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==