Skip to content

Commit 06426ec

Browse files
committed
fix: preserve trailing whitespace in manifest
1 parent 8ac9f2e commit 06426ec

6 files changed

+60
-23
lines changed

lib/createInlinePluginCreator.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
const { writeFileSync } = require("fs");
22
const debug = require("debug")("msr:inlinePlugin");
33
const getCommitsFiltered = require("./getCommitsFiltered");
4-
const { getManifest, getIndent } = require("./getManifest");
4+
const getManifest = require("./getManifest");
55
const hasChangedDeep = require("./hasChangedDeep");
6+
const recognizeFormat = require("./recognizeFormat");
67
const { get } = require("lodash");
78

89
/**
@@ -32,7 +33,7 @@ function createInlinePluginCreator(packages, multiContext, synchronizer, flags)
3233
const updateManifestDeps = (pkg, path) => {
3334
// Get and parse manifest file contents.
3435
const manifest = getManifest(path);
35-
const indent = getIndent(path);
36+
const { indent, trailingWhitespace } = recognizeFormat(manifest.__contents__);
3637
const updateDependency = (scope, name, version) => {
3738
if (get(manifest, `${scope}.${name}`)) {
3839
manifest[scope][name] = version;
@@ -56,7 +57,7 @@ function createInlinePluginCreator(packages, multiContext, synchronizer, flags)
5657
});
5758

5859
// Write package.json back out.
59-
writeFileSync(path, JSON.stringify(manifest, null, indent));
60+
writeFileSync(path, JSON.stringify(manifest, null, indent) + trailingWhitespace);
6061
};
6162

6263
/**

lib/getManifest.js

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ function readManifest(path) {
1717
try {
1818
stat = lstatSync(path);
1919
} catch (_) {
20-
// istanbul ignore next (hard to test — happens if no read acccess etc).
20+
// istanbul ignore next (hard to test — happens if no read access etc).
2121
throw new ReferenceError(`package.json cannot be read: "${path}"`);
2222
}
2323

@@ -33,22 +33,6 @@ function readManifest(path) {
3333
}
3434
}
3535

36-
/**
37-
* Extract the current indent sequence from file.
38-
*
39-
* @param {string} path The path to the package.json manifest file.
40-
* @returns {string} indent symbols
41-
*
42-
* @internal
43-
*/
44-
function getIndent(path) {
45-
// Read the file.
46-
const contents = readManifest(path);
47-
const match = /\n([^"]+)/.exec(contents);
48-
49-
return match ? match[1] : 2;
50-
}
51-
5236
/**
5337
* Get the parsed contents of a package.json manifest file.
5438
*
@@ -87,9 +71,12 @@ function getManifest(path) {
8771
checkDeps("peerDependencies");
8872
checkDeps("optionalDependencies");
8973

74+
// NOTE non-enumerable prop is skipped by JSON.stringify
75+
Object.defineProperty(manifest, "__contents__", { enumerable: false, value: contents });
76+
9077
// Return contents.
9178
return manifest;
9279
}
9380

9481
// Exports.
95-
module.exports = { getManifest, getIndent };
82+
module.exports = getManifest;

lib/getWorkspacesYarn.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const glob = require("bash-glob");
2-
const { getManifest } = require("./getManifest");
2+
const getManifest = require("./getManifest");
33
const { checker } = require("./blork");
44

55
/**

lib/multiSemanticRelease.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const getLogger = require("./getLogger");
66
const getSynchronizer = require("./getSynchronizer");
77
const getConfig = require("./getConfig");
88
const getConfigSemantic = require("./getConfigSemantic");
9-
const { getManifest } = require("./getManifest");
9+
const getManifest = require("./getManifest");
1010
const cleanPath = require("./cleanPath");
1111
const RescopedStream = require("./RescopedStream");
1212
const createInlinePluginCreator = require("./createInlinePluginCreator");

lib/recognizeFormat.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* Information about the format of a file.
3+
* @typedef FileFormat
4+
* @property {string|number} indent Indentation characters
5+
* @property {string} trailingWhitespace Trailing whitespace at the end of the file
6+
*/
7+
8+
/**
9+
* Detects the indentation and trailing whitespace of a file.
10+
*
11+
* @param {string} contents contents of the file
12+
* @returns {FileFormat} Formatting of the file
13+
*/
14+
function recognizeFormat(contents) {
15+
const indentMatch = /\n([^"]+)/.exec(contents);
16+
const trailingWhitespaceMatch = /}(\s*)$/.exec(contents);
17+
18+
return {
19+
indent: indentMatch ? indentMatch[1] : 2,
20+
trailingWhitespace: trailingWhitespaceMatch ? trailingWhitespaceMatch[1] : "",
21+
};
22+
}
23+
24+
// Exports.
25+
module.exports = recognizeFormat;

test/lib/recognizeFormat.test.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/** @typedef {import('@types/jest')} */
2+
const recognizeFormat = require("../../lib/recognizeFormat");
3+
4+
// Tests.
5+
describe("recognizeFormat()", () => {
6+
describe("Indentation", () => {
7+
test("Normal indentation", () =>
8+
expect(
9+
recognizeFormat(`{
10+
"a": "b",
11+
"c": {
12+
"d": "e"
13+
}
14+
}`).indent
15+
).toBe("\t"));
16+
test("No indentation", () => expect(recognizeFormat('{"a": "b"}').indent).toBe(2));
17+
});
18+
19+
describe("Trailing whitespace", () => {
20+
test("No trailing whitespace", () => expect(recognizeFormat('{"a": "b"}').trailingWhitespace).toBe(""));
21+
test("Newline", () => expect(recognizeFormat('{"a": "b"}\n').trailingWhitespace).toBe("\n"));
22+
test("Multiple newlines", () => expect(recognizeFormat('{"a": "b"}\n\n').trailingWhitespace).toBe("\n\n"));
23+
});
24+
});

0 commit comments

Comments
 (0)