From f6e4c30a99a87778cdf2989814e06e3ea21c57ce Mon Sep 17 00:00:00 2001 From: David Thompson Date: Mon, 5 May 2025 12:41:30 -0400 Subject: [PATCH] Add option to remove trailing comma This option is available in prettier so implementing it is trivial. Needs the 'estree' prettier plugin, which is responsible for formatting JSON. As a result, this might increase the size of the language server. eg. in the following, when 'yaml.format.trailingComma` is set to `false`, the last comma should be removed: ```yaml { key: 'value', food: 'raisins', airport: 'YYZ', lightened_bulb: 'illuminating', } ``` See redhat-developer/vscode-yaml#1112 Signed-off-by: David Thompson --- package.json | 2 +- .../handlers/settingsHandlers.ts | 4 ++ src/languageservice/services/yamlFormatter.ts | 6 ++- src/languageservice/yamlLanguageService.ts | 1 + src/yamlSettings.ts | 1 + test/formatter.test.ts | 42 +++++++++++++++++-- yarn.lock | 8 ++-- 7 files changed, 54 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 28d4cd26a..676cb3440 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "dependencies": { "ajv": "^8.11.0", "lodash": "4.17.21", - "prettier": "^3.0.0", + "prettier": "^3.5.0", "request-light": "^0.5.7", "vscode-json-languageservice": "4.1.8", "vscode-languageserver": "^9.0.0", diff --git a/src/languageserver/handlers/settingsHandlers.ts b/src/languageserver/handlers/settingsHandlers.ts index fff3e1b4a..6306983bb 100644 --- a/src/languageserver/handlers/settingsHandlers.ts +++ b/src/languageserver/handlers/settingsHandlers.ts @@ -107,6 +107,10 @@ export class SettingsHandler { this.yamlSettings.yamlFormatterSettings.bracketSpacing = settings.yaml.format.bracketSpacing; } + if (settings.yaml.format.trailingComma !== undefined) { + this.yamlSettings.yamlFormatterSettings.trailingComma = settings.yaml.format.trailingComma; + } + if (settings.yaml.format.enable !== undefined) { this.yamlSettings.yamlFormatterSettings.enable = settings.yaml.format.enable; } diff --git a/src/languageservice/services/yamlFormatter.ts b/src/languageservice/services/yamlFormatter.ts index a3cb6ea67..d2eb57537 100644 --- a/src/languageservice/services/yamlFormatter.ts +++ b/src/languageservice/services/yamlFormatter.ts @@ -7,7 +7,8 @@ import { Range, Position, TextEdit, FormattingOptions } from 'vscode-languageserver-types'; import { CustomFormatterOptions, LanguageSettings } from '../yamlLanguageService'; import { Options } from 'prettier'; -import * as parser from 'prettier/plugins/yaml'; +import * as yamlPlugin from 'prettier/plugins/yaml'; +import * as estreePlugin from 'prettier/plugins/estree'; import { format } from 'prettier/standalone'; import { TextDocument } from 'vscode-languageserver-textdocument'; @@ -33,7 +34,7 @@ export class YAMLFormatter { const prettierOptions: Options = { parser: 'yaml', - plugins: [parser], + plugins: [yamlPlugin, estreePlugin], // --- FormattingOptions --- tabWidth: (options.tabWidth as number) || options.tabSize, @@ -44,6 +45,7 @@ export class YAMLFormatter { // 'preserve' is the default for Options.proseWrap. See also server.ts proseWrap: 'always' === options.proseWrap ? 'always' : 'never' === options.proseWrap ? 'never' : 'preserve', printWidth: options.printWidth, + trailingComma: options.trailingComma === false ? 'none' : 'all', }; const formatted = await format(text, prettierOptions); diff --git a/src/languageservice/yamlLanguageService.ts b/src/languageservice/yamlLanguageService.ts index b76688db1..fd414a319 100644 --- a/src/languageservice/yamlLanguageService.ts +++ b/src/languageservice/yamlLanguageService.ts @@ -151,6 +151,7 @@ export interface SchemaConfiguration { export interface CustomFormatterOptions { singleQuote?: boolean; bracketSpacing?: boolean; + trailingComma?: boolean; proseWrap?: string; printWidth?: number; enable?: boolean; diff --git a/src/yamlSettings.ts b/src/yamlSettings.ts index fc0260342..575e3bb10 100644 --- a/src/yamlSettings.ts +++ b/src/yamlSettings.ts @@ -69,6 +69,7 @@ export class SettingsState { bracketSpacing: true, proseWrap: 'preserve', printWidth: 80, + trailingComma: true, enable: true, } as CustomFormatterOptions; yamlShouldHover = true; diff --git a/test/formatter.test.ts b/test/formatter.test.ts index 5ab02ae44..256938e69 100644 --- a/test/formatter.test.ts +++ b/test/formatter.test.ts @@ -2,12 +2,12 @@ * Copyright (c) Red Hat. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { setupLanguageService, setupTextDocument } from './utils/testHelper'; -import { ServiceSetup } from './utils/serviceSetup'; import * as assert from 'assert'; import { TextEdit } from 'vscode-languageserver-types'; -import { SettingsState, TextDocumentTestManager } from '../src/yamlSettings'; import { LanguageHandlers } from '../src/languageserver/handlers/languageHandlers'; +import { SettingsState, TextDocumentTestManager } from '../src/yamlSettings'; +import { ServiceSetup } from './utils/serviceSetup'; +import { setupLanguageService, setupTextDocument } from './utils/testHelper'; describe('Formatter Tests', () => { let languageHandler: LanguageHandlers; @@ -60,6 +60,42 @@ describe('Formatter Tests', () => { assert.equal(edits[0].newText, 'comments: >\n test test test\n test test test\n test test test\n test test test\n'); }); + it('Formatting handles trailing commas (enabled)', async () => { + const content = `{ + key: 'value', + food: 'raisins', + airport: 'YYZ', + lightened_bulb: 'illuminating', +} +`; + const edits = await parseSetup(content, { singleQuote: true }); + assert.equal(edits[0].newText, content); + }); + + it('Formatting handles trailing commas (disabled)', async () => { + const content = `{ + key: 'value', + food: 'raisins', + airport: 'YYZ', + lightened_bulb: 'illuminating', +} +`; + const edits = await parseSetup(content, { + singleQuote: true, + trailingComma: false, + }); + assert.equal( + edits[0].newText, + `{ + key: 'value', + food: 'raisins', + airport: 'YYZ', + lightened_bulb: 'illuminating' +} +` + ); + }); + it('Formatting uses tabSize', async () => { const content = `map: k1: v1 diff --git a/yarn.lock b/yarn.lock index 3d0b4412b..7ad1c14e1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2675,10 +2675,10 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@^3.0.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.1.tgz#e68935518dd90bb7ec4821ba970e68f8de16e1ac" - integrity sha512-7CAwy5dRsxs8PHXT3twixW9/OEll8MLE0VRPCJyl7CkS6VHGPSlsVaWTiASPTyGyYRyApxlaWTzwUxVNrhcwDg== +prettier@^3.5.0: + version "3.5.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.5.3.tgz#4fc2ce0d657e7a02e602549f053b239cb7dfe1b5" + integrity sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw== process-on-spawn@^1.0.0: version "1.0.0"