From b2a77d3cb13b7dac419f7a124568973c4ed3019d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Fri, 20 Nov 2020 10:09:05 +0100 Subject: [PATCH] build: add a script to fix order of deps keys in package.json files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new step to `bin/fix-monorepo.js` to ensure that all public packages list deps in the following order, starting after `publishConfig` or `license` field: 1. `peerDependencies` 2. `dependencies 3. `devDependencies` Signed-off-by: Miroslav Bajtoš --- bin/fix-monorepo.js | 56 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/bin/fix-monorepo.js b/bin/fix-monorepo.js index d19ba81941ea..da4e27187671 100644 --- a/bin/fix-monorepo.js +++ b/bin/fix-monorepo.js @@ -10,14 +10,19 @@ */ 'use strict'; +const path = require('path'); + const syncDevDeps = require('./sync-dev-deps'); const updateMonorepo = require('./update-monorepo-file'); const { + isJsonEqual, + loadLernaRepo, runMain, updatePackageDeps, updatePackageJson, updateTsProjectRefs, + writeJsonSync, } = require('../packages/monorepo'); async function fixMonorepo() { @@ -31,6 +36,57 @@ async function fixMonorepo() { await updateMonorepo(); // Ensure TypeScript project references are up to date await updateTsProjectRefs(); + // Ensure consistent order of keys in package.json + await updateOrderOfPackageJsonFields(); } runMain(module, fixMonorepo); + +async function updateOrderOfPackageJsonFields() { + const {packages} = await loadLernaRepo(); + for (const pkg of packages.filter(p => !p.private)) { + const manifest = pkg.toJSON(); + + // Keys to update in the desired order, + // filtered to those present in `package.json` only. + const depKeys = [ + 'peerDependencies', + 'dependencies', + 'devDependencies', + ].filter(k => k in manifest); + + // Get all top-level keys like "name", "version", "dependencies" + let keys = Object.keys(manifest); + // Remove "*dependencies" + keys = keys.filter(k => !depKeys.includes(k)); + + // Find the position of "publishConfig" (if present) or "license" + let ix = keys.indexOf('publishConfig'); + if (ix === -1) { + ix = keys.indexOf('license'); + if (ix === -1) { + const relPath = path.relative(pkg.rootPath, pkg.manifestLocation); + throw new Error( + `Fatal error: ${relPath} is missing required "license" field.`, + ); + } + } + + // Insert back "*dependencies" after "publishConfig" or "license" + keys.splice( + ix + 1, // index at which to start changing the array. + 0, // number of elements to remove + ...depKeys, // elements to insert + ); + + // Build a new manifest with the keys in the correct order + const updated = {}; + for (const k of keys) { + updated[k] = manifest[k]; + } + + if (!isJsonEqual(updated, manifest)) { + writeJsonSync(pkg.manifestLocation, updated); + } + } +}