fix: don't alway add a trailing new line to package.json

ref #2716
PR #2744
This commit is contained in:
Zoltan Kochan
2020-08-01 23:31:01 +03:00
committed by GitHub
parent 0a8ff3ad3e
commit 3bd3253e37
7 changed files with 95 additions and 30 deletions

View File

@@ -0,0 +1,5 @@
---
"@pnpm/read-project-manifest": patch
---
Trailing new lines are preserved, when updating the read manifests.

View File

@@ -0,0 +1,5 @@
---
"@pnpm/write-project-manifest": minor
---
New option added: insertFinalNewline. By default, a new line is added to the end of the file. When `options.insertFinalNewline` is false, no trailing new line is added.

View File

@@ -49,12 +49,11 @@ export async function tryReadProjectManifest (projectDir: string): Promise<{
try {
const manifestPath = path.join(projectDir, 'package.json')
const { data, text } = await readJsonFile(manifestPath)
const { indent } = detectIndent(text)
return {
fileName: 'package.json',
manifest: data,
writeProjectManifest: createManifestWriter({
indent,
...detectFileFormatting(text),
initialManifest: data,
manifestPath,
}),
@@ -65,12 +64,11 @@ export async function tryReadProjectManifest (projectDir: string): Promise<{
try {
const manifestPath = path.join(projectDir, 'package.json5')
const { data, text } = await readJson5File(manifestPath)
const { indent } = detectIndent(text)
return {
fileName: 'package.json5',
manifest: data,
writeProjectManifest: createManifestWriter({
indent,
...detectFileFormatting(text),
initialManifest: data,
manifestPath,
}),
@@ -111,16 +109,22 @@ export async function tryReadProjectManifest (projectDir: string): Promise<{
}
}
function detectFileFormatting (text: string) {
return {
indent: detectIndent(text).indent,
insertFinalNewline: text.endsWith('\n'),
}
}
export async function readExactProjectManifest (manifestPath: string) {
const base = path.basename(manifestPath).toLowerCase()
switch (base) {
case 'package.json': {
const { data, text } = await readJsonFile(manifestPath)
const { indent } = detectIndent(text)
return {
manifest: data,
writeProjectManifest: createManifestWriter({
indent,
...detectFileFormatting(text),
initialManifest: data,
manifestPath,
}),
@@ -128,11 +132,10 @@ export async function readExactProjectManifest (manifestPath: string) {
}
case 'package.json5': {
const { data, text } = await readJson5File(manifestPath)
const { indent } = detectIndent(text)
return {
manifest: data,
writeProjectManifest: createManifestWriter({
indent,
...detectFileFormatting(text),
initialManifest: data,
manifestPath,
}),
@@ -164,6 +167,7 @@ function createManifestWriter (
opts: {
initialManifest: ProjectManifest,
indent?: string | number | undefined,
insertFinalNewline?: boolean,
manifestPath: string,
}
): (WriteProjectManifest) {
@@ -171,7 +175,10 @@ function createManifestWriter (
return async (updatedManifest: ProjectManifest, force?: boolean) => {
updatedManifest = normalize(updatedManifest)
if (force === true || !equal(initialManifest, updatedManifest)) {
return writeProjectManifest(opts.manifestPath, updatedManifest, { indent: opts.indent })
return writeProjectManifest(opts.manifestPath, updatedManifest, {
indent: opts.indent,
insertFinalNewline: opts.insertFinalNewline,
})
}
}
}

View File

@@ -164,3 +164,31 @@ test('fail on invalid YAML', async (t) => {
t.end()
})
test('preserve trailing new line at the end of package.json', async (t) => {
process.chdir(tempy.directory())
await writeFile('package.json', '{}', 'utf8')
const { manifest, writeProjectManifest } = await readProjectManifest(process.cwd())
await writeProjectManifest({ ...manifest, dependencies: { bar: '1.0.0' } })
const rawManifest = await readFile('package.json', 'utf8')
t.equal(rawManifest, '{"dependencies":{"bar":"1.0.0"}}')
t.end()
})
test('preserve trailing new line at the end of package.json5', async (t) => {
process.chdir(tempy.directory())
await writeFile('package.json5', '{}', 'utf8')
const { manifest, writeProjectManifest } = await readProjectManifest(process.cwd())
await writeProjectManifest({ ...manifest, dependencies: { bar: '1.0.0' } })
const rawManifest = await readFile('package.json5', 'utf8')
t.equal(rawManifest, "{dependencies:{bar:'1.0.0'}}")
t.end()
})

View File

@@ -30,12 +30,16 @@
"homepage": "https://github.com/pnpm/pnpm/blob/master/packages/write-project-manifest#readme",
"dependencies": {
"@pnpm/types": "workspace:^6.2.0",
"write-json-file": "4.0.0",
"write-json5-file": "^3.0.0",
"json5": "^2.1.3",
"mz": "^2.7.0",
"write-file-atomic": "^3.0.3",
"write-yaml-file": "^4.1.0"
},
"devDependencies": {
"@pnpm/write-project-manifest": "link:",
"@types/json5": "^0.0.30",
"@types/mz": "^2.7.1",
"@types/write-file-atomic": "^3.0.1",
"tempy": "^0.6.0"
},
"funding": "https://opencollective.com/pnpm"

View File

@@ -1,6 +1,8 @@
import { ProjectManifest } from '@pnpm/types'
import writeJsonFile = require('write-json-file')
import writeJson5File = require('write-json5-file')
import JSON5 = require('json5')
import fs = require('mz/fs')
import path = require('path')
import writeFileAtomic = require('write-file-atomic')
import writeYamlFile = require('write-yaml-file')
const YAML_FORMAT = {
@@ -8,18 +10,24 @@ const YAML_FORMAT = {
noRefs: true,
}
export default function writeProjectManifest (
export default async function writeProjectManifest (
filePath: string,
manifest: ProjectManifest,
opts?: { indent?: string | number | undefined }
): Promise<void> {
switch (filePath.substr(filePath.lastIndexOf('.') + 1).toLowerCase()) {
case 'json5':
return writeJson5File(filePath, manifest, opts)
case 'yaml':
return writeYamlFile(filePath, manifest, YAML_FORMAT)
case 'json':
default:
return writeJsonFile(filePath, manifest, opts)
opts?: {
indent?: string | number | undefined,
insertFinalNewline?: boolean,
}
): Promise<void> {
const fileType = filePath.substr(filePath.lastIndexOf('.') + 1).toLowerCase()
if (fileType === 'yaml') {
return writeYamlFile(filePath, manifest, YAML_FORMAT)
}
await fs.mkdir(path.dirname(filePath), { recursive: true })
const trailingNewline = opts?.insertFinalNewline === false ? '' : '\n'
const json = (fileType === 'json5' ? JSON5 : JSON)
.stringify(manifest, null, opts?.indent ?? '\t')
return writeFileAtomic(filePath, `${json}${trailingNewline}`)
}

20
pnpm-lock.yaml generated
View File

@@ -2832,18 +2832,26 @@ importers:
packages/write-project-manifest:
dependencies:
'@pnpm/types': 'link:../types'
write-json-file: 4.0.0
write-json5-file: 3.0.0
json5: 2.1.3
mz: 2.7.0
write-file-atomic: 3.0.3
write-yaml-file: 4.1.0
devDependencies:
'@pnpm/write-project-manifest': 'link:'
'@types/json5': 0.0.30
'@types/mz': 2.7.1
'@types/write-file-atomic': 3.0.1
tempy: 0.6.0
specifiers:
'@pnpm/types': 'workspace:^6.2.0'
'@pnpm/write-project-manifest': 'link:'
'@types/json5': ^0.0.30
'@types/mz': ^2.7.1
'@types/write-file-atomic': ^3.0.1
json5: ^2.1.3
mz: ^2.7.0
tempy: ^0.6.0
write-json-file: 4.0.0
write-json5-file: ^3.0.0
write-file-atomic: ^3.0.3
write-yaml-file: ^4.1.0
privatePackages/assert-project:
dependencies:
@@ -3636,7 +3644,7 @@ packages:
integrity: sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=
/@types/mz/2.7.1:
dependencies:
'@types/node': 14.0.23
'@types/node': 14.0.27
resolution:
integrity: sha512-H86h7KmRDVs9UeSiQvtUeVhS+WYpJSYSsZrRvNYpGWGiytEqxwEtvgRnINESQtCgnojIH2wS2WgaMTJP0firBw==
/@types/ncp/2.0.4:
@@ -3790,7 +3798,7 @@ packages:
integrity: sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==
/@types/write-file-atomic/3.0.1:
dependencies:
'@types/node': 14.0.23
'@types/node': 14.0.27
dev: true
resolution:
integrity: sha512-o5Pl/qux8JEuFpof5fUg/Fl6R3N26ExJlsmWpB67ayrEJDMIxWdM9NDJacisXeNB7YW+vij8onctH8Pr1Zhi5g==