From aa8550104da84ca965af49635a56410120eee553 Mon Sep 17 00:00:00 2001 From: gustaff-weldon Date: Tue, 26 Sep 2017 16:28:36 +0200 Subject: [PATCH] Introduced support for package git dependency urls (coauthored with @synaptiko) --- README.md | 25 +++++- package.json | 1 + src/GitVersionParser.js | 22 +++++ src/Package.js | 18 +++- src/PackageGraph.js | 14 ++- src/PackageUtilities.js | 4 +- src/Repository.js | 20 ++++- src/VersionSerializer.js | 46 ++++++++++ src/commands/PublishCommand.js | 6 ++ test/GitVersionParser.js | 79 +++++++++++++++++ test/Package.js | 116 ++++++++++++++++++++++++- test/PackageGraph.js | 76 +++++++++++++++++ test/Repository.js | 2 +- test/VersionSerializer.js | 151 +++++++++++++++++++++++++++++++++ yarn.lock | 4 + 15 files changed, 569 insertions(+), 15 deletions(-) create mode 100644 src/GitVersionParser.js create mode 100644 src/VersionSerializer.js create mode 100644 test/GitVersionParser.js create mode 100644 test/PackageGraph.js create mode 100644 test/VersionSerializer.js diff --git a/README.md b/README.md index 1f53f34c66f..ac1b844862e 100644 --- a/README.md +++ b/README.md @@ -663,6 +663,8 @@ Running `lerna` without arguments will show all commands/options. } }, "packages": ["packages/*"] + "useGitVersion": true, + "gitVersionPrefix": "v" } ``` @@ -672,6 +674,23 @@ Running `lerna` without arguments will show all commands/options. - `commands.bootstrap.ignore`: an array of globs that won't be bootstrapped when running the `lerna bootstrap` command. - `commands.bootstrap.scope`: an array of globs that restricts which packages will be bootstrapped when running the `lerna bootstrap` command. - `packages`: Array of globs to use as package locations. +- `useGitVersion`: a boolean (defaults to `false`) indicating if [git hosted urls](https://github.com/npm/hosted-git-info) should be allowed instead of plain version number. If enabled, Lerna will attempt to extract and save the interpackage dependency versions using git url-aware parser. + This allows packages to be distributed via git repos if eg. packages are private and [private npm repo is not an option](https://www.dotconferences.com/2016/05/fabien-potencier-monolithic-repositories-vs-many-repositories). + Please note that using `gitVersion` requires `publish` command to be used with `--exact` and is limited to urls with [`committish`](https://docs.npmjs.com/files/package.json#git-urls-as-dependencies) part present. + + Example assuming 2 packages where `my-package-1` depends on `my-package-2`, for which `package.json` of `my-package-1` could be: + ``` + { + name: "my-package-1", + version: "1.0.0", + bin: "bin.js", + dependencies: { "my-package-2": "github:example-user/my-package-2#1.0.0" }, + devDependencies: { "my-dev-dependency": "^1.0.0" }, + peerDependencies: { "my-peer-dependency": "^1.0.0" } + } + ``` +- `gitVersionPrefix`: version prefix string (defaults to 'v') ignored when extracting version number from commitish part of git url. eg. given `github:example-user/my-package-2#v1.0.0` + and `gitVersionPrefix: 'v'` version will be read as `1.0.0`. Ignored if `useGitVersion` is set to `false`. ### Common `devDependencies` @@ -896,9 +915,9 @@ May also be configured in `lerna.json`: #### --use-workspaces -Enables integration with [Yarn Workspaces](https://github.com/yarnpkg/rfcs/blob/master/implemented/0000-workspaces-install-phase-1.md) (available since yarn@0.27+). -The values in the array are the commands in which Lerna will delegate operation to Yarn (currently only bootstrapping). -If `--use-workspaces` is true then `packages` will be overridden by the value from `package.json/workspaces.` +Enables integration with [Yarn Workspaces](https://github.com/yarnpkg/rfcs/blob/master/implemented/0000-workspaces-install-phase-1.md) (available since yarn@0.27+). +The values in the array are the commands in which Lerna will delegate operation to Yarn (currently only bootstrapping). +If `--use-workspaces` is true then `packages` will be overridden by the value from `package.json/workspaces.` May also be configured in `lerna.json`: ```js diff --git a/package.json b/package.json index 32acfb74d41..a6a61618649 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "glob-parent": "^3.1.0", "globby": "^6.1.0", "graceful-fs": "^4.1.11", + "hosted-git-info": "^2.5.0", "inquirer": "^3.2.2", "is-ci": "^1.0.10", "load-json-file": "^3.0.0", diff --git a/src/GitVersionParser.js b/src/GitVersionParser.js new file mode 100644 index 00000000000..8b6fdf49501 --- /dev/null +++ b/src/GitVersionParser.js @@ -0,0 +1,22 @@ +import { escapeRegExp } from "lodash"; +import hostedGitInfo from "hosted-git-info"; + +export default class GitVersionParser { + constructor(versionPrefix = "v") { + this._gitUrlPattern = new RegExp(`(.+?#${escapeRegExp(versionPrefix)})(.+)$`); + } + + parseVersion(version) { + const gitInfo = hostedGitInfo.fromUrl(version); + let targetMatches; + + if (gitInfo && gitInfo.committish) { + targetMatches = this._gitUrlPattern.exec(version); + } + + return { + prefix: targetMatches ? targetMatches[1] : null, + version: targetMatches ? targetMatches[2] : version + }; + } +} diff --git a/src/Package.js b/src/Package.js index 1e061365c42..bd056462a45 100644 --- a/src/Package.js +++ b/src/Package.js @@ -2,6 +2,7 @@ import dedent from "dedent"; import log from "npmlog"; import path from "path"; import semver from "semver"; +import _ from "lodash"; import dependencyIsSatisfied from "./utils/dependencyIsSatisfied"; import NpmUtilities from "./NpmUtilities"; @@ -60,12 +61,27 @@ export default class Package { return this._package.scripts || {}; } + set versionSerializer(versionSerializer) { + const previousSerializer = this._versionSerializer; + + this._versionSerializer = versionSerializer; + + if (previousSerializer) { + this._package = previousSerializer.serialize(this._package); + } + + if (versionSerializer) { + this._package = versionSerializer.deserialize(this._package); + } + } + isPrivate() { return !!this._package.private; } toJSON() { - return this._package; + const pkg = _.cloneDeep(this._package); + return this._versionSerializer ? this._versionSerializer.serialize(pkg) : pkg; } /** diff --git a/src/PackageGraph.js b/src/PackageGraph.js index c595f26a343..2d830df19eb 100644 --- a/src/PackageGraph.js +++ b/src/PackageGraph.js @@ -20,7 +20,7 @@ export class PackageGraphNode { * devDependencies that would normally be included. */ export default class PackageGraph { - constructor(packages, depsOnly = false) { + constructor(packages, depsOnly = false, versionParser) { this.nodes = []; this.nodesByName = {}; @@ -38,11 +38,17 @@ export default class PackageGraph { for (let d = 0; d < depNames.length; d++) { const depName = depNames[d]; - const depVersion = dependencies[depName]; const packageNode = this.nodesByName[depName]; - if (packageNode && semver.satisfies(packageNode.package.version, depVersion)) { - node.dependencies.push(depName); + if (packageNode) { + const depVersion = (versionParser + ? versionParser.parseVersion(dependencies[depName]).version + : dependencies[depName] + ); + + if (semver.satisfies(packageNode.package.version, depVersion)) { + node.dependencies.push(depName); + } } } } diff --git a/src/PackageUtilities.js b/src/PackageUtilities.js index 104dff6efff..741df1f717a 100644 --- a/src/PackageUtilities.js +++ b/src/PackageUtilities.js @@ -87,8 +87,8 @@ export default class PackageUtilities { return packages; } - static getPackageGraph(packages, depsOnly) { - return new PackageGraph(packages, depsOnly); + static getPackageGraph(packages, depsOnly, versionParser) { + return new PackageGraph(packages, depsOnly, versionParser); } /** diff --git a/src/Repository.js b/src/Repository.js index 66903ce4dda..64b56de6ffa 100644 --- a/src/Repository.js +++ b/src/Repository.js @@ -9,6 +9,8 @@ import semver from "semver"; import dependencyIsSatisfied from "./utils/dependencyIsSatisfied"; import Package from "./Package"; import PackageUtilities from "./PackageUtilities"; +import GitVersionParser from "./GitVersionParser"; +import VersionSerializer from "./VersionSerializer"; const DEFAULT_PACKAGE_GLOB = "packages/*"; @@ -118,8 +120,22 @@ export default class Repository { } buildPackageGraph() { - this._packages = PackageUtilities.getPackages(this); - this._packageGraph = PackageUtilities.getPackageGraph(this._packages); + const packages = PackageUtilities.getPackages(this); + const packageGraph = PackageUtilities.getPackageGraph(packages, false, this.lernaJson.useGitVersion + ? new GitVersionParser(this.lernaJson.gitVersionPrefix) + : null); + + if (this.lernaJson.useGitVersion) { + packages.forEach((pkg) => { + pkg.versionSerializer = new VersionSerializer({ + monorepoDependencies: packageGraph.get(pkg.name).dependencies, + versionParser: new GitVersionParser(this.lernaJson.gitVersionPrefix) + }); + }); + } + + this._packages = packages; + this._packageGraph = packageGraph; } hasDependencyInstalled(depName, version) { diff --git a/src/VersionSerializer.js b/src/VersionSerializer.js new file mode 100644 index 00000000000..c99e7c47ef0 --- /dev/null +++ b/src/VersionSerializer.js @@ -0,0 +1,46 @@ +export default class VersionSerializer { + constructor({ monorepoDependencies, versionParser }) { + this._monorepoDependencies = monorepoDependencies; + this._versionParser = versionParser; + this._dependenciesKeys = ["dependencies", "devDependencies", "peerDependencies"]; + this._strippedPrefixes = new Map(); + } + + serialize(pkg) { + this._dependenciesKeys.forEach((key) => { + this._prependPrefix(pkg[key] || {}); + }); + + return pkg; + } + + deserialize(pkg) { + this._dependenciesKeys.forEach((key) => { + this._stripPrefix(pkg[key] || {}); + }); + + return pkg; + } + + _prependPrefix(dependencies) { + this._strippedPrefixes.forEach((prefix, name) => { + const version = dependencies[name]; + if (version) { + dependencies[name] = `${prefix}${version}`; + } + }); + } + + _stripPrefix(dependencies) { + Object.keys(dependencies).forEach((name) => { + if (this._monorepoDependencies.includes(name)) { + const result = this._versionParser.parseVersion(dependencies[name]); + + if (result.prefix) { + dependencies[name] = result.version; + this._strippedPrefixes.set(name, result.prefix); + } + } + }); + } +} diff --git a/src/commands/PublishCommand.js b/src/commands/PublishCommand.js index c905b57d072..3aebb4ce4c6 100644 --- a/src/commands/PublishCommand.js +++ b/src/commands/PublishCommand.js @@ -156,6 +156,11 @@ export default class PublishCommand extends Command { this.gitRemote = this.options.gitRemote || "origin"; this.gitEnabled = !(this.options.canary || this.options.skipGit); + if (this.repository.lernaJson.useGitVersion && !this.options.exact) { + this.logger.error("config", ```Using git version without 'exact' option is not recommended. + Please make sure you publish with --exact.```); + } + if (this.options.canary) { this.logger.info("canary", "enabled"); } @@ -600,6 +605,7 @@ export default class PublishCommand extends Command { }); } + commitAndTagUpdates() { if (this.repository.isIndependent()) { this.tags = this.gitCommitAndTagVersionForUpdates(); diff --git a/test/GitVersionParser.js b/test/GitVersionParser.js new file mode 100644 index 00000000000..0400a09ee80 --- /dev/null +++ b/test/GitVersionParser.js @@ -0,0 +1,79 @@ +import log from "npmlog"; + +// file under test +import GitVersionParser from "../src/GitVersionParser"; + +// silence logs +log.level = "silent"; + +describe("GitVersionParser", () => { + + describe("parseVersion - without prefix", () => { + let parser; + + beforeEach(() => { + parser = new GitVersionParser(""); + }); + + it("should work for semver version", () => { + expect(parser.parseVersion("0.0.2")).toEqual({ + prefix: null, + version: "0.0.2" + }); + + expect(parser.parseVersion("~0.0.2")).toEqual({ + prefix: null, + version: "~0.0.2" + }); + }); + + it("should work for git url", () => { + expect(parser.parseVersion("github:user-foo/project-foo#v0.0.1")).toEqual({ + prefix: "github:user-foo/project-foo#", + version: "v0.0.1" + }); + + expect(parser.parseVersion("git@github.com:user-foo/project-foo#0.0.5")).toEqual({ + prefix: "git@github.com:user-foo/project-foo#", + version: "0.0.5" + }); + }); + }); + + describe("parseVersion - with version prefix", () => { + let parser; + + beforeEach(() => { + parser = new GitVersionParser("v"); + }); + + it("should work for semver version", () => { + expect(parser.parseVersion("0.0.2")).toEqual({ + prefix: null, + version: "0.0.2" + }); + + expect(parser.parseVersion("~0.0.2")).toEqual({ + prefix: null, + version: "~0.0.2" + }); + }); + + it("should work for git url", () => { + expect(parser.parseVersion("github:user-foo/project-foo#v0.0.1")).toEqual({ + prefix: "github:user-foo/project-foo#v", + version: "0.0.1" + }); + + expect(parser.parseVersion("git@github.com:user-foo/project-foo#0.0.5")).toEqual({ + prefix: null, + version: "git@github.com:user-foo/project-foo#0.0.5" + }); + + expect(parser.parseVersion("git@github.com:user-foo/project-foo#v0.0.5")).toEqual({ + prefix: "git@github.com:user-foo/project-foo#v", + version: "0.0.5" + }); + }); + }); +}); diff --git a/test/Package.js b/test/Package.js index 50b13e35ce6..ad7dff61bf2 100644 --- a/test/Package.js +++ b/test/Package.js @@ -105,15 +105,127 @@ describe("Package", () => { }); }); + describe(".set versionSerializer()", () => { + it("should call 'deserialize' method of serializer'", () => { + + const mockSerializer = { + serialize: jest.fn((pkg) => { + return pkg; + }), + deserialize: jest.fn((pkg) => { + return pkg; + }) + }; + + pkg.versionSerializer = mockSerializer; + + expect(mockSerializer.deserialize.mock.calls.length).toBe(1); + expect(mockSerializer.deserialize.mock.calls[0][0]).toBe(pkg._package); + expect(mockSerializer.serialize.mock.calls.length).toBe(0); + }); + + it("should call 'serialize' on old and 'deserialize' on new serializer'", () => { + + const firstMockSerializer = { + serialize: jest.fn((pkg) => { + return pkg; + }), + deserialize: jest.fn((pkg) => { + return pkg; + }) + }; + + const secondMockSerializer = { + serialize: jest.fn((pkg) => { + return pkg; + }), + deserialize: jest.fn((pkg) => { + return pkg; + }) + }; + + pkg.versionSerializer = firstMockSerializer; + + expect(firstMockSerializer.deserialize.mock.calls.length).toBe(1); + expect(firstMockSerializer.deserialize.mock.calls[0][0]).toBe(pkg._package); + expect(firstMockSerializer.serialize.mock.calls.length).toBe(0); + + pkg.versionSerializer = secondMockSerializer; + + expect(firstMockSerializer.deserialize.mock.calls.length).toBe(1); + expect(firstMockSerializer.serialize.mock.calls.length).toBe(1); + expect(firstMockSerializer.serialize.mock.calls[0][0]).toBe(pkg._package); + + expect(secondMockSerializer.deserialize.mock.calls.length).toBe(1); + expect(secondMockSerializer.deserialize.mock.calls[0][0]).toBe(pkg._package); + expect(secondMockSerializer.serialize.mock.calls.length).toBe(0); + }); + }); + + describe(".toJSON()", () => { - it("should return internal package for serialization", () => { - expect(pkg.toJSON()).toBe(pkg._package); + it("should return internal package copy for serialization", () => { + expect(pkg.toJSON()).toEqual(pkg._package); const implicit = JSON.stringify(pkg, null, 2); const explicit = JSON.stringify(pkg._package, null, 2); expect(implicit).toBe(explicit); }); + + it("should not change internal package with versionSerializer", () => { + const mockSerializer = { + serialize: jest.fn((pkg) => { + return Object.assign({}, pkg, { foo: true }); + }), + deserialize: jest.fn((pkg) => { + const newPkg = Object.assign({}, pkg); + delete newPkg.foo; + return newPkg; + }) + }; + + pkg.versionSerializer = mockSerializer; + + let serializedPackage = pkg.toJSON(); + const pkgPackageClone = Object.assign({}, pkg._package, { foo: true }); + + expect(serializedPackage).not.toEqual(pkg._package); + expect(serializedPackage).toEqual(pkgPackageClone); + + expect(mockSerializer.deserialize.mock.calls.length).toBe(1); + expect(mockSerializer.serialize.mock.calls.length).toBe(1); + expect(mockSerializer.serialize.mock.calls[0][0]).toEqual(pkg._package); + + serializedPackage = pkg.toJSON(); + + expect(serializedPackage).not.toEqual(pkg._package); + expect(serializedPackage).toEqual(pkgPackageClone); + + expect(mockSerializer.deserialize.mock.calls.length).toBe(1); + expect(mockSerializer.serialize.mock.calls.length).toBe(2); + expect(mockSerializer.serialize.mock.calls[0][0]).toEqual(pkg._package); + expect(mockSerializer.serialize.mock.calls[1][0]).toEqual(pkg._package); + }); + + it("should use versionSerializer.serialize on internal package before return", () => { + const mockSerializer = { + serialize: jest.fn((pkg) => { + return pkg; + }), + deserialize: jest.fn((pkg) => { + return pkg; + }) + }; + + pkg.versionSerializer = mockSerializer; + + expect(pkg.toJSON()).toEqual(pkg._package); + + expect(mockSerializer.deserialize.mock.calls.length).toBe(1); + expect(mockSerializer.serialize.mock.calls.length).toBe(1); + expect(mockSerializer.serialize.mock.calls[0][0]).toEqual(pkg._package); + }); }); describe(".runScript()", () => { diff --git a/test/PackageGraph.js b/test/PackageGraph.js new file mode 100644 index 00000000000..d1de7ce608f --- /dev/null +++ b/test/PackageGraph.js @@ -0,0 +1,76 @@ +import log from "npmlog"; + +// file under test +import Package from "../src/Package"; +import PackageGraph from "../src/PackageGraph"; + +// silence logs +log.level = "silent"; + +describe("PackageGraph", () => { + + const createPackages = function(version, dependencyVersion) { + dependencyVersion = dependencyVersion || version; + + return [ + new Package( + { + name: "my-package-1", + version: version, + bin: "bin.js", + scripts: { "my-script": "echo 'hello world'" }, + dependencies: { "my-dependency": "^1.0.0" }, + devDependencies: { "my-dev-dependency": "^1.0.0" }, + peerDependencies: { "my-peer-dependency": "^1.0.0" } + }, + "/path/to/package1" + ), + new Package( + { + name: "my-package-2", + version: version, + bin: "bin.js", + scripts: { "my-script": "echo 'hello world'" }, + dependencies: { "my-dependency": "^1.0.0" }, + devDependencies: { "my-package-1": dependencyVersion }, + peerDependencies: { "my-peer-dependency": "^1.0.0" } + }, + "/path/to/package2" + ) + ]; + }; + + describe("constructor", () => { + it(".get should return dependencies", () => { + const [ pkg1, pkg2 ] = createPackages("0.0.1"); + const graph = new PackageGraph([ pkg1, pkg2 ]); + + expect(graph.get(pkg1.name).dependencies).toEqual([]); + expect(graph.get(pkg2.name).dependencies).toEqual([pkg1.name]); + }); + + it(".get should not return the dependencies for unrecognized versions", () => { + const [ pkg1, pkg2 ] = createPackages("0.0.1", "github:user-foo/project-foo#v0.0.1"); + const graph = new PackageGraph([ pkg1, pkg2 ]); + + expect(graph.get(pkg1.name).dependencies).toEqual([]); + expect(graph.get(pkg2.name).dependencies).toEqual([]); + }); + + it(".get should not return the dependencies for unrecognized versions", () => { + const [ pkg1, pkg2 ] = createPackages("0.0.1", "github:user-foo/project-foo#v0.0.1"); + + const mockParser = { + parseVersion: jest.fn().mockReturnValue({ + prefix: "github:user-foo/project-foo#v", + version: "0.0.1" + }) + }; + + const graph = new PackageGraph([pkg1, pkg2], false, mockParser); + + expect(graph.get(pkg1.name).dependencies).toEqual([]); + expect(graph.get(pkg2.name).dependencies).toEqual([ pkg1.name ]); + }); + }); +}); diff --git a/test/Repository.js b/test/Repository.js index 65e7a3ea1be..e8cf07bda0f 100644 --- a/test/Repository.js +++ b/test/Repository.js @@ -138,7 +138,7 @@ describe("Repository", () => { path.join(testDir, "packages"), path.join(testDir, "dir/nested"), path.join(testDir, "globstar"), - ]) + ]); }); }); diff --git a/test/VersionSerializer.js b/test/VersionSerializer.js new file mode 100644 index 00000000000..f5ecc7913eb --- /dev/null +++ b/test/VersionSerializer.js @@ -0,0 +1,151 @@ +import log from "npmlog"; + +// file under test +import VersionSerializer from "../src/VersionSerializer"; + +// silence logs +log.level = "silent"; + +describe("VersionSerializer", () => { + + let serializer; + + beforeEach(() => { + const parser = { + parseVersion(version) { + const chunks = version.split("#"); + return { + prefix: chunks.length > 1 ? chunks[0] + "#" : null, + version: chunks.length > 1 ? chunks[1] : version, + }; + } + }; + serializer = new VersionSerializer({ + monorepoDependencies: [ + "my-package-1", "my-package-2", "my-package-3" + ], + versionParser: parser + }); + }); + + describe("deserialize", () => { + + it("should use version parser for inter-package dependencies only", () => { + const mockParser = { + parseVersion: jest.fn().mockReturnValue({ + prefix: null, + version: "0.0.1" + }) + }; + + serializer = new VersionSerializer({ + monorepoDependencies: [ + "my-package-1", "my-package-2", "my-package-3" + ], + versionParser: mockParser + }); + + const pkg = { + name: "my-package-1", + version: "1.0.0", + bin: "bin.js", + scripts: { "my-script": "echo 'hello world'" }, + dependencies: { "my-dependency": "^1.0.0" }, + devDependencies: { "my-package-2": "^1.0.0" }, + peerDependencies: { "my-package-3": "^1.0.0" } + }; + + serializer.deserialize(pkg); + expect(mockParser.parseVersion.mock.calls.length).toBe(2); + }); + + it("should not touch versions parser does not recognize", () => { + const pkg = { + name: "my-package-1", + version: "1.0.0", + bin: "bin.js", + scripts: { "my-script": "echo 'hello world'" }, + dependencies: { "my-dependency": "^1.0.0" }, + devDependencies: { "my-package-2": "^1.0.0" }, + peerDependencies: { "my-package-3": "^1.0.0" } + }; + + expect(serializer.deserialize(pkg)).toEqual(pkg); + }); + + it("should extract versions recognized by parser", () => { + expect(serializer.deserialize({ + name: "my-package-1", + version: "1.0.0", + bin: "bin.js", + scripts: { "my-script": "echo 'hello world'" }, + dependencies: { "my-dependency": "dont-touch-this#1.0.0" }, + devDependencies: { "my-package-2": "bbb#1.0.0" }, + peerDependencies: { "my-package-3": "ccc#1.0.0" } + })).toEqual({ + name: "my-package-1", + version: "1.0.0", + bin: "bin.js", + scripts: { "my-script": "echo 'hello world'" }, + dependencies: { "my-dependency": "dont-touch-this#1.0.0" }, + devDependencies: { "my-package-2": "1.0.0" }, + peerDependencies: { "my-package-3": "1.0.0" } + }); + }); + }); + + describe("serialize", () => { + + it("should not touch versions parser does not recognize", () => { + const pkg = { + name: "my-package-1", + version: "1.0.0", + bin: "bin.js", + scripts: { "my-script": "echo 'hello world'" }, + dependencies: { "my-dependency": "^1.0.0" }, + devDependencies: { "my-package-2": "^1.0.0" }, + peerDependencies: { "my-package-3": "^1.0.0" } + }; + + expect(serializer.serialize(pkg)).toEqual(pkg); + }); + + it("should write back version strings transformed by deserialize", () => { + expect(serializer.deserialize({ + name: "my-package-1", + version: "1.0.0", + bin: "bin.js", + scripts: { "my-script": "echo 'hello world'" }, + dependencies: { "my-dependency": "dont-touch-this#1.0.0" }, + devDependencies: { "my-package-2": "bbb#1.0.0" }, + peerDependencies: { "my-package-3": "ccc#1.0.0" } + })).toEqual({ + name: "my-package-1", + version: "1.0.0", + bin: "bin.js", + scripts: { "my-script": "echo 'hello world'" }, + dependencies: { "my-dependency": "dont-touch-this#1.0.0" }, + devDependencies: { "my-package-2": "1.0.0" }, + peerDependencies: { "my-package-3": "1.0.0" } + }); + + expect(serializer.serialize({ + name: "my-package-1", + version: "1.0.0", + bin: "bin.js", + scripts: { "my-script": "echo 'hello world'" }, + dependencies: { "my-dependency": "dont-touch-this#1.0.0" }, + devDependencies: { "my-package-2": "1.0.0" }, + peerDependencies: { "my-package-3": "1.0.0" } + })).toEqual({ + name: "my-package-1", + version: "1.0.0", + bin: "bin.js", + scripts: { "my-script": "echo 'hello world'" }, + dependencies: { "my-dependency": "dont-touch-this#1.0.0" }, + devDependencies: { "my-package-2": "bbb#1.0.0" }, + peerDependencies: { "my-package-3": "ccc#1.0.0" } + }); + }); + }); +}); diff --git a/yarn.lock b/yarn.lock index 8b41e83c7c5..255c316bbfb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1926,6 +1926,10 @@ hosted-git-info@^2.1.4: version "2.2.0" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.2.0.tgz#7a0d097863d886c0fabbdcd37bf1758d8becf8a5" +hosted-git-info@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" + html-encoding-sniffer@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz#79bf7a785ea495fe66165e734153f363ff5437da"