diff --git a/packages/lerna/migrations.json b/packages/lerna/migrations.json index 623d056898..44ffaffbb8 100644 --- a/packages/lerna/migrations.json +++ b/packages/lerna/migrations.json @@ -1,5 +1,11 @@ { "generators": { + "add-schema-config": { + "cli": "nx", + "version": "7.0.0-alpha.5", + "description": "Add `$schema` config to lerna.json if not already present to allow for IDE validation of lerna.json", + "implementation": "./dist/migrations/add-schema-config/add-schema-config" + }, "remove-invalid-init-config": { "cli": "nx", "version": "7.0.0-alpha.2", diff --git a/packages/lerna/project.json b/packages/lerna/project.json index 76f2609b9c..349c90803b 100644 --- a/packages/lerna/project.json +++ b/packages/lerna/project.json @@ -79,6 +79,7 @@ "packages/lerna/src/commands/version/lib/prompt-version.ts", "packages/lerna/src/commands/version/lib/remote-branch-exists.ts", "packages/lerna/src/commands/version/lib/update-lockfile-version.ts", + "packages/lerna/src/migrations/add-schema-config/add-schema-config.ts", "packages/lerna/src/migrations/remove-invalid-init-config/remove-invalid-init-config.ts", "packages/lerna/src/migrations/remove-invalid-use-workspaces/remove-invalid-use-workspaces.ts", "packages/lerna/src/migrations/remove-unnecessary-use-nx/remove-unnecessary-use-nx.ts", diff --git a/packages/lerna/schemas/lerna-schema.json b/packages/lerna/schemas/lerna-schema.json index 5508fe71d2..a681bc87e1 100644 --- a/packages/lerna/schemas/lerna-schema.json +++ b/packages/lerna/schemas/lerna-schema.json @@ -3,7 +3,12 @@ "$id": "https://lerna.js.org/docs/getting-started#adding-lerna", "title": "JSON schema for Lerna configuration", "type": "object", + "additionalProperties": false, "properties": { + "$schema": { + "type": "string", + "description": "The JSON schema version used to validate this configuration file" + }, "version": { "type": "string", "description": "The version of the repository, or \"independent\" for a repository with independently versioned packages.", @@ -25,6 +30,7 @@ }, "command": { "type": "object", + "additionalProperties": false, "description": "Options for individual Lerna commands.", "properties": { "add": { diff --git a/packages/lerna/src/migrations/add-schema-config/add-schema-config.test.ts b/packages/lerna/src/migrations/add-schema-config/add-schema-config.test.ts new file mode 100644 index 0000000000..a6a2736404 --- /dev/null +++ b/packages/lerna/src/migrations/add-schema-config/add-schema-config.test.ts @@ -0,0 +1,33 @@ +import { readJson, Tree, writeJson } from "@nx/devkit"; +import { createTreeWithEmptyWorkspace } from "@nx/devkit/testing"; +import addSchemaConfigMigration from "./add-schema-config"; + +describe("add-schema-config", () => { + let tree: Tree; + + beforeEach(() => { + tree = createTreeWithEmptyWorkspace(); + }); + + it(`should add "$schema" config if not already present`, async () => { + writeJson(tree, "lerna.json", {}); + await addSchemaConfigMigration(tree); + expect(readJson(tree, "lerna.json")).toMatchInlineSnapshot(` + Object { + "$schema": "node_modules/lerna/schemas/lerna-schema.json", + } + `); + }); + + it(`should not not modify the "$schema" config if it is already present`, async () => { + writeJson(tree, "lerna.json", { + $schema: "./some/path/to/schema.json", + }); + await addSchemaConfigMigration(tree); + expect(readJson(tree, "lerna.json")).toMatchInlineSnapshot(` + Object { + "$schema": "./some/path/to/schema.json", + } + `); + }); +}); diff --git a/packages/lerna/src/migrations/add-schema-config/add-schema-config.ts b/packages/lerna/src/migrations/add-schema-config/add-schema-config.ts new file mode 100644 index 0000000000..2b68fb66ea --- /dev/null +++ b/packages/lerna/src/migrations/add-schema-config/add-schema-config.ts @@ -0,0 +1,12 @@ +import { formatFiles, readJson, Tree, writeJson } from "@nx/devkit"; + +export default async function generator(tree: Tree) { + const lernaJson = readJson(tree, "lerna.json"); + + if (!lernaJson.$schema) { + lernaJson.$schema = "node_modules/lerna/schemas/lerna-schema.json"; + writeJson(tree, "lerna.json", lernaJson); + } + + await formatFiles(tree); +}