diff --git a/.gitignore b/.gitignore index 2f9c7302..4ab4a5ea 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,5 @@ jasmine-config/reporter.js.map hooks .DS_Store + +!projectHelpers.spec.js diff --git a/jasmine-config/jasmine.json b/jasmine-config/jasmine.json index 31a4a781..84db3eb2 100644 --- a/jasmine-config/jasmine.json +++ b/jasmine-config/jasmine.json @@ -1,7 +1,8 @@ { "spec_dir": ".", "spec_files": [ - "./!(node_modules)/**/*.spec.js" + "./!(node_modules)/**/*.spec.js", + "./*.spec.js" ], "helpers": [ "jasmine-config/**/*.js" diff --git a/package.json b/package.json index b7366a86..f16c5033 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "scripts": { "postinstall": "node postinstall.js", "postpack": "rm -rf node_modules", - "prepare": "tsc", + "prepare": "tsc && npm run jasmine", "test": "npm run prepare && npm run jasmine", "jasmine": "jasmine --config=jasmine-config/jasmine.json", "version": "rm package-lock.json && conventional-changelog -p angular -i CHANGELOG.md -s && git add CHANGELOG.md" diff --git a/projectHelpers.js b/projectHelpers.js index 50413157..0f61b76c 100644 --- a/projectHelpers.js +++ b/projectHelpers.js @@ -1,5 +1,5 @@ const { resolve } = require("path"); -const { readFileSync, writeFileSync } = require("fs"); +const fs = require("fs"); const hook = require("nativescript-hook")(__dirname); @@ -38,13 +38,26 @@ const isVue = ({ projectDir, packageJson } = {}) => { const getPackageJson = projectDir => { const packageJsonPath = getPackageJsonPath(projectDir); - return JSON.parse(readFileSync(packageJsonPath, "utf8")); + return JSON.parse(fs.readFileSync(packageJsonPath, "utf8")); }; const writePackageJson = (content, projectDir) => { const packageJsonPath = getPackageJsonPath(projectDir); - writeFileSync(packageJsonPath, JSON.stringify(content, null, 2)) + const currentJsonContent = fs.readFileSync(packageJsonPath); + const indentation = getIndentationCharacter(currentJsonContent); + const stringifiedContent = JSON.stringify(content, null, indentation); + const currentPackageJsonContent = JSON.parse(currentJsonContent); + + if (JSON.stringify(currentPackageJsonContent, null, indentation) !== stringifiedContent) { + fs.writeFileSync(packageJsonPath, stringifiedContent) + } } + +const getIndentationCharacter = (jsonContent) => { + const matches = jsonContent && jsonContent.toString().match(/{\r*\n*(\W*)"/m); + return matches && matches[1]; +} + const getProjectDir = hook.findProjectDir; const getPackageJsonPath = projectDir => resolve(projectDir, "package.json"); @@ -96,5 +109,6 @@ module.exports = { isVue, isTypeScript, writePackageJson, - convertSlashesInPath + convertSlashesInPath, + getIndentationCharacter }; \ No newline at end of file diff --git a/projectHelpers.spec.js b/projectHelpers.spec.js new file mode 100644 index 00000000..c8a83b88 --- /dev/null +++ b/projectHelpers.spec.js @@ -0,0 +1,110 @@ +const { getIndentationCharacter, writePackageJson } = require("./projectHelpers"); +const fs = require("fs"); + +describe('projectHelpers', () => { + const originalReadFileSync = fs.readFileSync; + const originalWriteFileSync = fs.writeFileSync; + const tab = "\t"; + const multipleSpaces = " "; + const twoSpaces = " "; + + afterEach(() => { + fs.readFileSync = originalReadFileSync; + fs.writeFileSync = originalWriteFileSync; + }); + + describe('getIndentationCharacter', () => { + [ + { + testName: 'returns two spaces when file starts with two spaces', + input: `{${twoSpaces}"abc": "1"${twoSpaces}}`, + expectedResult: twoSpaces + }, + { + testName: 'returns two spaces when file starts with two spaces and binary content is passed', + input: Buffer.from(`{${twoSpaces}"abc": "1"${twoSpaces}}`), + expectedResult: twoSpaces + }, + { + testName: 'returns empty string when file starts without any indentation', + input: `{"abc": "1"}`, + expectedResult: '' + }, + { + testName: 'returns tab when file starts with tab', + input: `{${tab}"abc": "1"${tab}}`, + expectedResult: tab + }, + { + testName: 'returns two spaces when file starts with two spaces and new line before them', + input: `{\n${twoSpaces}"abc": "1"\n}`, + expectedResult: twoSpaces + }, + { + testName: 'returns tab when file starts with tab and new line before them', + input: `{\n${tab}"abc": "1"\n}`, + expectedResult: tab + }, + { + testName: 'returns multiple spaces when file starts with multiple spaces and new line before them', + input: `{\n${multipleSpaces}"abc": "1"\n}`, + expectedResult: multipleSpaces + } + ].forEach(({ testName, input, expectedResult }) => { + it(testName, () => { + expect(getIndentationCharacter(input)).toEqual(expectedResult); + }); + }); + }); + + describe('writePackageJson', () => { + const mockFileSystemApi = () => { + const data = { + isWriteFileSyncCalled: false + }; + + fs.readFileSync = (p) => { + return JSON.stringify({ a: 1 }); + }; + + fs.writeFileSync = (p, c) => { + data.isWriteFileSyncCalled = true; + }; + + return data; + }; + + it('does not write package.json when content has not changed', () => { + const data = mockFileSystemApi(); + writePackageJson({ a: 1 }, "projDir"); + expect(data.isWriteFileSyncCalled).toBe(false); + }); + + it('writes content, when the new one is different from the current one', () => { + const data = mockFileSystemApi(); + writePackageJson({ b: 2 }, "projDir"); + expect(data.isWriteFileSyncCalled).toBe(true); + }); + + it('keeps indentation of the package.json when rewriting it', () => { + let currentIndentSymbol = tab; + fs.readFileSync = (p) => { + return JSON.stringify({ a: 1 }, null, currentIndentSymbol); + }; + + let writtenContent = null; + fs.writeFileSync = (p, c) => { + writtenContent = c; + }; + + // Ensure tab indentation is persisted + writePackageJson({ b: 2 }, "projDir"); + expect(writtenContent).toBe(`{\n${tab}"b": 2\n}`); + + // Ensure spaces indentation is persisted + currentIndentSymbol = multipleSpaces; + writePackageJson({ b: 2 }, "projDir"); + expect(writtenContent).toBe(`{\n${multipleSpaces}"b": 2\n}`); + }); + }); +});