diff --git a/pkg-manifest/read-project-manifest/fixtures/commented-package-yaml/modified.yaml b/pkg-manifest/read-project-manifest/fixtures/commented-package-yaml/modified.yaml new file mode 100644 index 00000000000..27918e1dfea --- /dev/null +++ b/pkg-manifest/read-project-manifest/fixtures/commented-package-yaml/modified.yaml @@ -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. diff --git a/pkg-manifest/read-project-manifest/fixtures/commented-package-yaml/package.yaml b/pkg-manifest/read-project-manifest/fixtures/commented-package-yaml/package.yaml new file mode 100644 index 00000000000..f608f225c84 --- /dev/null +++ b/pkg-manifest/read-project-manifest/fixtures/commented-package-yaml/package.yaml @@ -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. diff --git a/pkg-manifest/read-project-manifest/src/index.ts b/pkg-manifest/read-project-manifest/src/index.ts index 9c4f924c032..bd7e293430b 100644 --- a/pkg-manifest/read-project-manifest/src/index.ts +++ b/pkg-manifest/read-project-manifest/src/index.ts @@ -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' @@ -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 @@ -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, + }), } } } diff --git a/pkg-manifest/read-project-manifest/src/readFile.ts b/pkg-manifest/read-project-manifest/src/readFile.ts index 6a92cd5ddd9..e7bb692f4a7 100644 --- a/pkg-manifest/read-project-manifest/src/readFile.ts +++ b/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 { diff --git a/pkg-manifest/read-project-manifest/test/index.ts b/pkg-manifest/read-project-manifest/test/index.ts index 1f4959d29c9..76b54f58234 100644 --- a/pkg-manifest/read-project-manifest/test/index.ts +++ b/pkg-manifest/read-project-manifest/test/index.ts @@ -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()) diff --git a/pkg-manifest/write-project-manifest/src/index.ts b/pkg-manifest/write-project-manifest/src/index.ts index ffedeca4434..3d1a59c9a86 100644 --- a/pkg-manifest/write-project-manifest/src/index.ts +++ b/pkg-manifest/write-project-manifest/src/index.ts @@ -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 ( @@ -20,12 +23,13 @@ export async function writeProjectManifest ( insertFinalNewline?: boolean } ): Promise { + 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'