Skip to content

Commit

Permalink
feat(pkg-manifest): preserve comments in YAML manifests
Browse files Browse the repository at this point in the history
Following on from pnpm#2008 (comment)Closes pnpm#2008.
  • Loading branch information
danielbayley committed Mar 23, 2023
1 parent 2a20328 commit de1b781
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 12 deletions.
@@ -0,0 +1,9 @@
# This is an example of a package.yaml file with comments.

# pnpm should keep comments at the same indentation level
name: 'foo'
version: '1.0.0' # it should keep in-line comments on the same line
# It should allow in-line comments with no other content
type: 'commonjs'

# And it should preserve comments at the end of the file. Note no newline.
@@ -0,0 +1,9 @@
# This is an example of a package.yaml file with comments.

# pnpm should keep comments at the same indentation level
name: 'foo'
version: '1.0.0' # it should keep in-line comments on the same line
# It should allow in-line comments with no other content
type: 'module'

# And it should preserve comments at the end of the file. Note no newline.
22 changes: 15 additions & 7 deletions pkg-manifest/read-project-manifest/src/index.ts
Expand Up @@ -4,12 +4,12 @@ import { PnpmError } from '@pnpm/error'
import { type ProjectManifest } from '@pnpm/types'
import { extractComments, type CommentSpecifier } from '@pnpm/text.comments-parser'
import { writeProjectManifest } from '@pnpm/write-project-manifest'
import readYamlFile from 'read-yaml-file'
import detectIndent from '@gwhitney/detect-indent'
import equal from 'fast-deep-equal'
import isWindows from 'is-windows'
import sortKeys from 'sort-keys'
import {
readYamlFile,
readJson5File,
readJsonFile,
} from './readFile'
Expand Down Expand Up @@ -86,11 +86,15 @@ export async function tryReadProjectManifest (projectDir: string): Promise<{
}
try {
const manifestPath = path.join(projectDir, 'package.yaml')
const manifest = await readPackageYaml(manifestPath)
const { data, text } = await readPackageYaml(manifestPath)
return {
fileName: 'package.yaml',
manifest,
writeProjectManifest: createManifestWriter({ initialManifest: manifest, manifestPath }),
manifest: data,
writeProjectManifest: createManifestWriter({ //initialManifest: data, manifestPath }),
...detectFileFormatting(text), //AndComments(text),
initialManifest: data,
manifestPath,
})
}
} catch (err: any) { // eslint-disable-line
if (err.code !== 'ENOENT') throw err
Expand Down Expand Up @@ -160,10 +164,14 @@ export async function readExactProjectManifest (manifestPath: string) {
}
}
case 'package.yaml': {
const manifest = await readPackageYaml(manifestPath)
const { data, text } = await readPackageYaml(manifestPath)
return {
manifest,
writeProjectManifest: createManifestWriter({ initialManifest: manifest, manifestPath }),
manifest: data,
writeProjectManifest: createManifestWriter({ //initialManifest: manifest, manifestPath }),
...detectFileFormatting(text), //AndComments(text),
initialManifest: data,
manifestPath,
}),
}
}
}
Expand Down
15 changes: 15 additions & 0 deletions pkg-manifest/read-project-manifest/src/readFile.ts
@@ -1,9 +1,24 @@
import gfs from '@pnpm/graceful-fs'
import { type ProjectManifest } from '@pnpm/types'
import YAML from 'yaml'
import JSON5 from 'json5'
import parseJson from 'parse-json'
import stripBom from 'strip-bom'

export async function readYamlFile (filePath: string) {
const text = await readFileWithoutBom(filePath)
try {
return {
data: YAML.parseDocument(text),
text,
}
} catch (err: any) { // eslint-disable-line
err.message = `${err.message as string} in ${filePath}`
err['code'] = 'ERR_PNPM_YAML_PARSE'
throw err
}
}

export async function readJson5File (filePath: string) {
const text = await readFileWithoutBom(filePath)
try {
Expand Down
20 changes: 20 additions & 0 deletions pkg-manifest/read-project-manifest/test/index.ts
Expand Up @@ -101,6 +101,26 @@ test('preserve comments in json5 file', async () => {
const resultingManifest = await fs.readFile('package.json5', 'utf8')
expect(resultingManifest).toBe(modifiedManifest)
})
/* FIXME
test('preserve comments in YAML file', async () => {
const originalManifest = await fs.readFile(
path.join(fixtures, 'commented-package-yaml/package.yaml'), 'utf8')
const modifiedManifest = await fs.readFile(
path.join(fixtures, 'commented-package-yaml/modified.yaml'), 'utf8')
process.chdir(tempy.directory())
await fs.writeFile('package.yaml', originalManifest, 'utf8')
const { manifest, writeProjectManifest } = await readProjectManifest(process.cwd())
// Have to make a change to get it to write anything:
const newManifest = Object.assign({}, manifest, { type: 'commonjs' })
await writeProjectManifest(newManifest)
const resultingManifest = await fs.readFile('package.yaml', 'utf8')
expect(resultingManifest).toBe(modifiedManifest)
})*/

test('do not save manifest if it had no changes', async () => {
process.chdir(tempy.directory())
Expand Down
14 changes: 9 additions & 5 deletions pkg-manifest/write-project-manifest/src/index.ts
Expand Up @@ -2,13 +2,16 @@ import { promises as fs } from 'fs'
import path from 'path'
import { insertComments, type CommentSpecifier } from '@pnpm/text.comments-parser'
import { type ProjectManifest } from '@pnpm/types'
import YAML from 'yaml'
import JSON5 from 'json5'
import writeFileAtomic from 'write-file-atomic'
import writeYamlFile from 'write-yaml-file'

const YAML_FORMAT = {
noCompatMode: true,
noRefs: true,
//noCompatMode: true, // TODO don't try to be compatible with older yaml versions
//noRefs: true, // TODO don't convert duplicate objects into references
//indent: 2,
//indentSeq: false,
//singleQuote: false,
}

export async function writeProjectManifest (
Expand All @@ -20,12 +23,13 @@ export async function writeProjectManifest (
insertFinalNewline?: boolean
}
): Promise<void> {
await fs.mkdir(path.dirname(filePath), { recursive: true })
const fileType = filePath.slice(filePath.lastIndexOf('.') + 1).toLowerCase()
if (fileType === 'yaml') {
return writeYamlFile(filePath, manifest, YAML_FORMAT)
const yaml = YAML.stringify(manifest, YAML_FORMAT)
return writeFileAtomic(filePath, yaml)
}

await fs.mkdir(path.dirname(filePath), { recursive: true })
const trailingNewline = opts?.insertFinalNewline === false ? '' : '\n'
const indent = opts?.indent ?? '\t'

Expand Down

0 comments on commit de1b781

Please sign in to comment.