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

Commit bd9a4eb

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 b5da72c commit bd9a4eb

File tree

4 files changed

+128
-5
lines changed

4 files changed

+128
-5
lines changed

Diff for: .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

Diff for: 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"

Diff for: projectHelpers.js

+19-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,27 @@ 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 defaultIndentation = " ";
58+
const matches = jsonContent.match(/{\r*\n*(\W*)"/m);
59+
return matches && matches[1];
60+
}
61+
4862
const getProjectDir = hook.findProjectDir;
4963

5064
const getPackageJsonPath = projectDir => resolve(projectDir, "package.json");
@@ -96,5 +110,6 @@ module.exports = {
96110
isVue,
97111
isTypeScript,
98112
writePackageJson,
99-
convertSlashesInPath
113+
convertSlashesInPath,
114+
getIndentationCharacter
100115
};

Diff for: 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)