Skip to content

Commit 7db8ba4

Browse files
so1veJounQin
andauthored
feat!: add toml plugin, use taplo inside instead (#314)
Co-authored-by: JounQin <[email protected]>
1 parent ac2b2fb commit 7db8ba4

19 files changed

+431
-12
lines changed

.changeset/honest-pigs-type.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"prettier-plugin-toml": patch
3+
---
4+
5+
fix: do not remove blank lines after comments - close https://github.com/un-ts/toml-tools/issues/74

.changeset/purple-years-divide.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"prettier-plugin-toml": major
3+
---
4+
5+
feat!: add `toml` plugin, use `taplo` inside instead

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ This repository is a monorepo managed by [changesets][] what means we actually p
2323
| [`prettier-plugin-pkg`](/packages/pkg) | An opinionated package.json formatter plugin for Prettier | [![npm](https://img.shields.io/npm/v/prettier-plugin-pkg.svg)](https://www.npmjs.com/package/prettier-plugin-pkg) |
2424
| [`prettier-plugin-sh`](/packages/sh) | An opinionated `shellscript` formatter plugin for Prettier, also support simple format of `Dockerfile`, `properties`, `gitignore`, `dotenv`, `hosts`, `jvmoptions`... | [![npm](https://img.shields.io/npm/v/prettier-plugin-sh.svg)](https://www.npmjs.com/package/prettier-plugin-sh) |
2525
| [`prettier-plugin-sql`](/packages/sql) | An opinionated sql formatter plugin for Prettier | [![npm](https://img.shields.io/npm/v/prettier-plugin-sql.svg)](https://www.npmjs.com/package/prettier-plugin-sql) |
26+
| [`prettier-plugin-toml`](/packages/toml) | An opinionated `toml` formatter plugin for Prettier | [![npm](https://img.shields.io/npm/v/prettier-plugin-toml.svg)](https://www.npmjs.com/package/prettier-plugin-toml) |
2627

2728
## Sponsors
2829

package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
"prettier-plugin-pkg": "workspace:*",
5555
"prettier-plugin-sh": "workspace:*",
5656
"prettier-plugin-sql": "workspace:*",
57+
"prettier-plugin-toml": "workspace:*",
5758
"react": "^18.2.0",
5859
"react-dom": "^18.2.0",
5960
"react-router-dom": "^6.18.0",
@@ -75,7 +76,8 @@
7576
"prettier-plugin-autocorrect": "workspace:*",
7677
"prettier-plugin-pkg": "workspace:*",
7778
"prettier-plugin-sh": "workspace:*",
78-
"prettier-plugin-sql": "workspace:*"
79+
"prettier-plugin-sql": "workspace:*",
80+
"prettier-plugin-toml": "workspace:*"
7981
},
8082
"browserslist": [
8183
"extends @1stg/browserslist-config/modern"

packages/toml/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Change Log

packages/toml/LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2019 UnTS
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

packages/toml/README.md

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# prettier-plugin-toml ![npm bundle size](https://img.shields.io/bundlephobia/min/prettier-plugin-toml) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/prettier-plugin-toml)
2+
3+
> An opinionated `toml` formatter plugin for [Prettier][]
4+
5+
Prettier is an opinionated code formatter. It enforces a consistent style by parsing your code and re-printing, taking various rules into account.
6+
7+
This plugin adds support for `toml` through [taplo][].
8+
9+
## Notice
10+
11+
This plugin is still under development, its printer just wraps [taplo][]'s default printer.
12+
Of course it should just work, but may not match [prettier][]'s format sometimes.
13+
14+
## Requirements
15+
16+
`prettier-plugin-toml` is an evergreen module. 🌲 This module requires an [LTS](https://github.com/nodejs/Release) Node version (v16.0.0+).
17+
18+
## Install
19+
20+
Using npm:
21+
22+
```sh
23+
# npm
24+
npm i -D prettier prettier-plugin-toml
25+
26+
# yarn
27+
yarn add -D prettier prettier-plugin-toml
28+
```
29+
30+
## Usage
31+
32+
Once installed, [Prettier plugins](https://prettier.io/docs/en/plugins.html) must be added to `.prettierrc`:
33+
34+
```json
35+
{
36+
"plugins": ["prettier-plugin-toml"]
37+
}
38+
```
39+
40+
Then:
41+
42+
```sh
43+
# npx
44+
npx prettier --write foo.toml
45+
46+
# yarn
47+
yarn prettier --write foo.toml
48+
```
49+
50+
## Sponsors
51+
52+
| 1stG | RxTS | UnTS |
53+
| ---------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
54+
| [![1stG Open Collective backers and sponsors](https://opencollective.com/1stG/organizations.svg)](https://opencollective.com/1stG) | [![RxTS Open Collective backers and sponsors](https://opencollective.com/rxts/organizations.svg)](https://opencollective.com/rxts) | [![UnTS Open Collective backers and sponsors](https://opencollective.com/unts/organizations.svg)](https://opencollective.com/unts) |
55+
56+
## Backers
57+
58+
[![Backers](https://raw.githubusercontent.com/1stG/static/master/sponsors.svg)](https://github.com/sponsors/JounQin)
59+
60+
| 1stG | RxTS | UnTS |
61+
| -------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
62+
| [![1stG Open Collective backers and sponsors](https://opencollective.com/1stG/individuals.svg)](https://opencollective.com/1stG) | [![RxTS Open Collective backers and sponsors](https://opencollective.com/rxts/individuals.svg)](https://opencollective.com/rxts) | [![UnTS Open Collective backers and sponsors](https://opencollective.com/unts/individuals.svg)](https://opencollective.com/unts) |
63+
64+
## Changelog
65+
66+
Detailed changes for each release are documented in [CHANGELOG.md](./CHANGELOG.md).
67+
68+
## License
69+
70+
[MIT][] © [Ray][]@[mk1.io][]
71+
72+
[mk1.io]: https://mk1.io
73+
[mit]: http://opensource.org/licenses/MIT
74+
[prettier]: https://prettier.io
75+
[ray]: https://GitHub.com/so1ve
76+
[taplo]: https://github.com/tamasfe/taplo

packages/toml/package.json

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
"name": "prettier-plugin-toml",
3+
"version": "1.0.0",
4+
"type": "module",
5+
"description": "An opinionated `toml` formatter plugin for Prettier",
6+
"repository": "[email protected]/un-ts/prettier.git",
7+
"homepage": "https://github.com/un-ts/prettier/tree/master/packages/prettier",
8+
"author": "Ray (https://mk1.io) <[email protected]>",
9+
"contributors": [
10+
"JounQin (https://www.1stG.me) <[email protected]>"
11+
],
12+
"funding": "https://opencollective.com/unts",
13+
"license": "MIT",
14+
"engines": {
15+
"node": ">=16.0.0"
16+
},
17+
"main": "./lib/index.cjs",
18+
"module": "./lib/index.js",
19+
"exports": {
20+
"types": "./lib/index.d.ts",
21+
"import": "./lib/index.js",
22+
"require": "./lib/index.cjs"
23+
},
24+
"types": "./lib/index.d.ts",
25+
"files": [
26+
"lib"
27+
],
28+
"keywords": [
29+
"toml",
30+
"plugin",
31+
"prettier",
32+
"prettier-plugin"
33+
],
34+
"peerDependencies": {
35+
"prettier": "^3.0.3"
36+
},
37+
"dependencies": {
38+
"@taplo/lib": "^0.4.0-alpha.2"
39+
}
40+
}

packages/toml/src/index.ts

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { Taplo } from '@taplo/lib'
2+
import type { Plugin } from 'prettier'
3+
4+
import { languages } from './languages.js'
5+
import { prettierOptionsDefinitions } from './options.js'
6+
import type { PrettierOptions, TaploOptions } from './types.js'
7+
8+
const PLUGIN_NAME = 'toml'
9+
10+
let taplo: Taplo | undefined
11+
12+
async function format(code: string, options: TaploOptions) {
13+
if (!taplo) {
14+
taplo = await Taplo.initialize()
15+
}
16+
17+
return taplo.format(code, { options })
18+
}
19+
20+
const TomlPlugin: Plugin<string> = {
21+
languages,
22+
parsers: {
23+
[PLUGIN_NAME]: {
24+
async parse(code: string, options: PrettierOptions) {
25+
const indentString = options.useTabs
26+
? '\t'
27+
: ' '.repeat(options.tabWidth)
28+
29+
return await format(code.trim(), {
30+
...options,
31+
columnWidth: options.printWidth,
32+
indentString,
33+
trailingNewline: true,
34+
arrayTrailingComma: options.trailingComma !== 'none',
35+
crlf: options.endOfLine === 'crlf',
36+
})
37+
},
38+
astFormat: PLUGIN_NAME,
39+
locStart: () => -1,
40+
locEnd: () => -1,
41+
},
42+
},
43+
printers: {
44+
[PLUGIN_NAME]: {
45+
print: ({ node }) => node,
46+
},
47+
},
48+
options: prettierOptionsDefinitions,
49+
}
50+
51+
export default TomlPlugin

packages/toml/src/options.ts

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import type { SupportOption } from 'prettier'
2+
3+
import type { PrettierTaploOptions } from './types'
4+
5+
/**
6+
* @see https://github.com/tamasfe/taplo/blob/848722f2c604de68535e5a3e0bb2a2c1d3c7dc74/crates/taplo/src/formatter/mod.rs#L150-L168
7+
*/
8+
export const prettierOptionsDefinitions = {
9+
alignEntries: {
10+
name: 'alignEntries',
11+
type: 'boolean',
12+
category: 'taplo',
13+
default: false,
14+
description: 'Align consecutive entries vertically.',
15+
},
16+
alignComments: {
17+
name: 'alignComments',
18+
type: 'boolean',
19+
category: 'taplo',
20+
default: true,
21+
description:
22+
'Align consecutive comments after entries and items vertically. This applies to comments that are after entries or array items.',
23+
},
24+
arrayAutoExpand: {
25+
name: 'arrayAutoExpand',
26+
type: 'boolean',
27+
category: 'taplo',
28+
default: true,
29+
description:
30+
'Expand arrays to multiple lines that exceed the maximum column width.',
31+
},
32+
arrayAutoCollapse: {
33+
name: 'arrayAutoCollapse',
34+
type: 'boolean',
35+
category: 'taplo',
36+
default: true,
37+
description:
38+
"Collapse arrays that don't exceed the maximum column width and don't contain comments.",
39+
},
40+
compactArrays: {
41+
name: 'compactArrays',
42+
type: 'boolean',
43+
category: 'taplo',
44+
default: true,
45+
description: 'Omit white space padding from single-line arrays.',
46+
},
47+
compactInlineTables: {
48+
name: 'compactInlineTables',
49+
type: 'boolean',
50+
category: 'taplo',
51+
default: false,
52+
description:
53+
'Omit white space padding from the start and end of inline tables.',
54+
},
55+
compactEntries: {
56+
name: 'compactEntries',
57+
type: 'boolean',
58+
category: 'taplo',
59+
default: false,
60+
description: 'Omit white space around `=`.',
61+
},
62+
indentTables: {
63+
name: 'indentTables',
64+
type: 'boolean',
65+
category: 'taplo',
66+
default: false,
67+
description:
68+
'Indent based on tables and arrays of tables and their subtables, subtables out of order are not indented.',
69+
},
70+
indentEntries: {
71+
name: 'indentEntries',
72+
type: 'boolean',
73+
category: 'taplo',
74+
default: false,
75+
description: 'Indent entries under tables.',
76+
},
77+
reorderKeys: {
78+
name: 'reorderKeys',
79+
type: 'boolean',
80+
category: 'taplo',
81+
default: false,
82+
description:
83+
'Alphabetically reorder keys that are not separated by empty lines.',
84+
},
85+
allowedBlankLines: {
86+
name: 'allowedBlankLines',
87+
type: 'int',
88+
category: 'taplo',
89+
default: 1,
90+
description:
91+
'The maximum number of allowed blank lines between entries and tables.',
92+
},
93+
} satisfies Record<keyof PrettierTaploOptions, SupportOption>

packages/toml/src/types.ts

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import type { FormatOptions } from '@taplo/lib'
2+
import type { ParserOptions } from 'prettier'
3+
4+
export type TaploOptions = NonNullable<FormatOptions['options']>
5+
export type PrettierTaploOptions = Omit<
6+
TaploOptions,
7+
| 'arrayTrailingComma'
8+
| 'columnWidth'
9+
| 'crlf'
10+
| 'indentString'
11+
| 'trailingNewline'
12+
>
13+
export type PrettierOptions = ParserOptions & PrettierTaploOptions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2+
3+
exports[`parser and printer > should format all fixtures > comments.toml 1`] = `
4+
"# This is a TOML comment
5+
6+
# This is a multiline
7+
# TOML comment
8+
9+
str1 = \\"I'm a string.\\"
10+
"
11+
`;
12+
13+
exports[`parser and printer > should format all fixtures > fixture1.toml 1`] = `
14+
"[foo]
15+
asfd = 1
16+
bar = [
17+
'averyloooooooooooooooooooooooooooooooooooooooooooooooooooong',
18+
\\"arrrrrrrrrrrrrrrrrrrrrrrray\\",
19+
'thatexceedsthemaximumcolumnwidth',
20+
]
21+
"
22+
`;

packages/toml/test/fixtures.spec.ts

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import fs from 'node:fs'
2+
import path from 'node:path'
3+
import { fileURLToPath } from 'node:url'
4+
5+
import { format } from 'prettier'
6+
7+
import TomlPlugin from 'prettier-plugin-toml'
8+
9+
const _dirname =
10+
typeof __dirname === 'undefined'
11+
? path.dirname(fileURLToPath(import.meta.url))
12+
: __dirname
13+
14+
describe('parser and printer', () => {
15+
it('should format all fixtures', async () => {
16+
const fixtures = path.resolve(_dirname, 'fixtures')
17+
for (const relativeFilepath of fs.readdirSync(fixtures)) {
18+
const filepath = path.resolve(fixtures, relativeFilepath)
19+
const input = fs.readFileSync(filepath, 'utf8')
20+
21+
try {
22+
const output = await format(input, {
23+
filepath,
24+
parser: 'toml',
25+
plugins: [TomlPlugin],
26+
})
27+
28+
expect(output).toMatchSnapshot(relativeFilepath)
29+
} catch (err: unknown) {
30+
expect((err as Error).message).toMatchSnapshot(relativeFilepath)
31+
}
32+
}
33+
})
34+
})

0 commit comments

Comments
 (0)