Skip to content
This repository was archived by the owner on Aug 7, 2021. It is now read-only.

Commit 0aec512

Browse files
fix: project's package.json indentation is not persisted
In case project's package.json uses tabs or multiple spaces for indentation, the postinstall script of nativescript-dev-webpack overwrites it with two spaces whenever it is executed. The problem is that the plugin tries to modify the package.json and persists it on every operation. Fix the behavior by checking the indentation character and use it when stringifying the content. Also compare the current content of the file with the one we will write and skip the write operation in case they match. Add unit tests for the new methods.
1 parent 2470d3b commit 0aec512

File tree

4 files changed

+127
-5
lines changed

4 files changed

+127
-5
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,5 @@ jasmine-config/reporter.js.map
3232

3333
hooks
3434
.DS_Store
35+
36+
!projectHelpers.spec.js

jasmine-config/jasmine.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
{
22
"spec_dir": ".",
33
"spec_files": [
4-
"./!(node_modules)/**/*.spec.js"
4+
"./!(node_modules)/**/*.spec.js",
5+
"./*.spec.js"
56
],
67
"helpers": [
78
"jasmine-config/**/*.js"

projectHelpers.js

+18-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const { resolve } = require("path");
2-
const { readFileSync, writeFileSync } = require("fs");
2+
const fs = require("fs");
33

44
const hook = require("nativescript-hook")(__dirname);
55

@@ -38,13 +38,26 @@ const isVue = ({ projectDir, packageJson } = {}) => {
3838

3939
const getPackageJson = projectDir => {
4040
const packageJsonPath = getPackageJsonPath(projectDir);
41-
return JSON.parse(readFileSync(packageJsonPath, "utf8"));
41+
return JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
4242
};
4343

4444
const writePackageJson = (content, projectDir) => {
4545
const packageJsonPath = getPackageJsonPath(projectDir);
46-
writeFileSync(packageJsonPath, JSON.stringify(content, null, 2))
46+
const currentJsonContent = fs.readFileSync(packageJsonPath);
47+
const indentation = getIndentationCharacter(currentJsonContent);
48+
const stringifiedContent = JSON.stringify(content, null, indentation);
49+
const currentPackageJsonContent = JSON.parse(currentJsonContent);
50+
51+
if (JSON.stringify(currentPackageJsonContent, null, indentation) !== stringifiedContent) {
52+
fs.writeFileSync(packageJsonPath, stringifiedContent)
53+
}
4754
}
55+
56+
const getIndentationCharacter = (jsonContent) => {
57+
const matches = jsonContent.match(/{\r*\n*(\W*)"/m);
58+
return matches && matches[1];
59+
}
60+
4861
const getProjectDir = hook.findProjectDir;
4962

5063
const getPackageJsonPath = projectDir => resolve(projectDir, "package.json");
@@ -96,5 +109,6 @@ module.exports = {
96109
isVue,
97110
isTypeScript,
98111
writePackageJson,
99-
convertSlashesInPath
112+
convertSlashesInPath,
113+
getIndentationCharacter
100114
};

projectHelpers.spec.js

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
const { getIndentationCharacter, writePackageJson } = require("./projectHelpers");
2+
const fs = require("fs");
3+
4+
describe('projectHelpers', () => {
5+
const originalReadFileSync = fs.readFileSync;
6+
const originalWriteFileSync = fs.writeFileSync;
7+
const tab = "\t";
8+
const multipleSpaces = " ";
9+
const twoSpaces = " ";
10+
11+
afterEach(() => {
12+
fs.readFileSync = originalReadFileSync;
13+
fs.writeFileSync = originalWriteFileSync;
14+
});
15+
16+
describe('getIndentationCharacter', () => {
17+
[
18+
{
19+
testName: 'returns two spaces when file starts with two spaces',
20+
input: `{${twoSpaces}"abc": "1"${twoSpaces}}`,
21+
expectedResult: twoSpaces
22+
},
23+
{
24+
testName: 'returns empty string when file starts without any indentation',
25+
input: `{"abc": "1"}`,
26+
expectedResult: ''
27+
},
28+
{
29+
testName: 'returns tab when file starts with tab',
30+
input: `{${tab}"abc": "1"${tab}}`,
31+
expectedResult: tab
32+
},
33+
{
34+
testName: 'returns two spaces when file starts with two spaces and new line before them',
35+
input: `{\n${twoSpaces}"abc": "1"\n}`,
36+
expectedResult: twoSpaces
37+
},
38+
{
39+
testName: 'returns tab when file starts with tab and new line before them',
40+
input: `{\n${tab}"abc": "1"\n}`,
41+
expectedResult: tab
42+
},
43+
{
44+
testName: 'returns multiple spaces when file starts with multiple spaces and new line before them',
45+
input: `{\n${multipleSpaces}"abc": "1"\n}`,
46+
expectedResult: multipleSpaces
47+
}
48+
].forEach(({ testName, input, expectedResult }) => {
49+
it(testName, () => {
50+
expect(getIndentationCharacter(input)).toEqual(expectedResult);
51+
});
52+
});
53+
});
54+
55+
describe('writePackageJson', () => {
56+
const mockFileSystemApi = () => {
57+
const data = {
58+
isWriteFileSyncCalled: false
59+
};
60+
61+
fs.readFileSync = (p) => {
62+
return JSON.stringify({ a: 1 });
63+
};
64+
65+
fs.writeFileSync = (p, c) => {
66+
data.isWriteFileSyncCalled = true;
67+
};
68+
69+
return data;
70+
};
71+
72+
it('does not write package.json when content has not changed', () => {
73+
const data = mockFileSystemApi();
74+
writePackageJson({ a: 1 }, "projDir");
75+
expect(data.isWriteFileSyncCalled).toBe(false);
76+
});
77+
78+
it('writes content, when the new one is different from the current one', () => {
79+
const data = mockFileSystemApi();
80+
writePackageJson({ b: 2 }, "projDir");
81+
expect(data.isWriteFileSyncCalled).toBe(true);
82+
});
83+
84+
it('keeps indentation of the package.json when rewriting it', () => {
85+
let currentIndentSymbol = tab;
86+
fs.readFileSync = (p) => {
87+
return JSON.stringify({ a: 1 }, null, currentIndentSymbol);
88+
};
89+
90+
let writtenContent = null;
91+
fs.writeFileSync = (p, c) => {
92+
writtenContent = c;
93+
};
94+
95+
// Ensure tab indentation is persisted
96+
writePackageJson({ b: 2 }, "projDir");
97+
expect(writtenContent).toBe(`{\n${tab}"b": 2\n}`);
98+
99+
// Ensure spaces indentation is persisted
100+
currentIndentSymbol = multipleSpaces;
101+
writePackageJson({ b: 2 }, "projDir");
102+
expect(writtenContent).toBe(`{\n${multipleSpaces}"b": 2\n}`);
103+
});
104+
});
105+
});

0 commit comments

Comments
 (0)