diff --git a/docs/configuration.md b/docs/configuration.md index 38afd0f312a0..1cb62755b1ed 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -6,6 +6,7 @@ title: Configuration File Prettier uses [cosmiconfig](https://github.com/davidtheclark/cosmiconfig) for configuration file support. This means you can configure prettier via: - A `.prettierrc` file, written in YAML or JSON, with optional extensions: `.yaml/.yml/.json/.js`. +- A `.prettierrc.toml` file, written in TOML (the `.toml` extension is _required_). - A `prettier.config.js` file that exports an object. - A `"prettier"` key in your `package.json` file. @@ -42,6 +43,14 @@ printWidth: 100 parser: flow ``` +TOML: + +```toml +# .prettierrc.toml +printWidth = 100 +parser = "flow" +``` + ## Configuration Overrides Prettier borrows eslint's [override format](http://eslint.org/docs/user-guide/configuring#example-configuration). This allows you to apply configuration to specific files. diff --git a/package.json b/package.json index 4d8597e9daca..c64c68f78203 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "@babel/code-frame": "7.0.0-beta.46", "@babel/parser": "7.0.0-beta.49", "@glimmer/syntax": "0.30.3", + "@iarna/toml": "2.0.0", "camelcase": "4.1.0", "chalk": "2.1.0", "cjk-regex": "1.0.2", diff --git a/src/config/resolve-config.js b/src/config/resolve-config.js index b3ae94f1fa80..ef6898dc4d78 100644 --- a/src/config/resolve-config.js +++ b/src/config/resolve-config.js @@ -6,6 +6,7 @@ const path = require("path"); const mem = require("mem"); const resolveEditorConfig = require("./resolve-config-editorconfig"); +const loadToml = require("../utils/load-toml"); const getExplorerMemoized = mem(opts => { const explorer = thirdParty.cosmiconfig("prettier", { @@ -22,6 +23,19 @@ const getExplorerMemoized = mem(opts => { delete result.config.$schema; } return result; + }, + searchPlaces: [ + "package.json", + ".prettierrc", + ".prettierrc.json", + ".prettierrc.yaml", + ".prettierrc.yml", + ".prettierrc.js", + "prettier.config.js", + ".prettierrc.toml" + ], + loaders: { + ".toml": loadToml } }); diff --git a/src/utils/load-toml.js b/src/utils/load-toml.js new file mode 100644 index 000000000000..f8b5c7c7948c --- /dev/null +++ b/src/utils/load-toml.js @@ -0,0 +1,12 @@ +"use strict"; + +const parse = require("@iarna/toml/parse-string"); + +module.exports = function(filePath, content) { + try { + return parse(content); + } catch (error) { + error.message = `TOML Error in ${filePath}:\n${error.message}`; + throw error; + } +}; diff --git a/tests_integration/__tests__/__snapshots__/config-resolution.js.snap b/tests_integration/__tests__/__snapshots__/config-resolution.js.snap index 79857ce207f9..96d3dec43199 100644 --- a/tests_integration/__tests__/__snapshots__/config-resolution.js.snap +++ b/tests_integration/__tests__/__snapshots__/config-resolution.js.snap @@ -62,6 +62,16 @@ function rcJson() { ], ); } +function rcToml() { + console.log.apply( + null, + [ + 'rc-toml/file.js', + 'should have trailing comma', + 'and single quotes', + ], + ); +} function rcYaml() { console.log.apply( null, @@ -142,6 +152,13 @@ function rcJson() { 'and single quotes', ]); } +function rcToml() { + console.log.apply(null, [ + 'rc-toml/file.js', + 'should have trailing comma', + 'and single quotes', + ]); +} function rcYaml() { console.log.apply(null, [ 'rc-yaml/file.js', @@ -181,6 +198,15 @@ exports[`resolves json configuration file with --find-config-path file (stdout) exports[`resolves json configuration file with --find-config-path file (write) 1`] = `Array []`; +exports[`resolves toml configuration file with --find-config-path file (stderr) 1`] = `""`; + +exports[`resolves toml configuration file with --find-config-path file (stdout) 1`] = ` +"rc-toml/.prettierrc.toml +" +`; + +exports[`resolves toml configuration file with --find-config-path file (write) 1`] = `Array []`; + exports[`resolves yaml configuration file with --find-config-path file (stderr) 1`] = `""`; exports[`resolves yaml configuration file with --find-config-path file (stdout) 1`] = ` diff --git a/tests_integration/__tests__/__snapshots__/load-toml.js.snap b/tests_integration/__tests__/__snapshots__/load-toml.js.snap new file mode 100644 index 000000000000..175f48849c8f --- /dev/null +++ b/tests_integration/__tests__/__snapshots__/load-toml.js.snap @@ -0,0 +1,36 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`TOML loads toml successfully 1`] = ` +Object { + "database": Object { + "connection_max": 5000, + "enabled": true, + "ports": Array [ + 8001, + 8001, + 8002, + ], + "server": "192.168.1.1", + Symbol(type): Symbol(table), + Symbol(declared): true, + }, + "owner": Object { + "dob": 1979-05-27T15:32:00.000Z, + "name": "Tom Preston-Werner", + Symbol(type): Symbol(table), + Symbol(declared): true, + }, + "title": "TOML Example", + Symbol(type): Symbol(table), + Symbol(declared): false, +} +`; + +exports[`TOML throws error on incorrect toml 1`] = ` +"TOML Error in example.toml: +Unknown character \\"47\\" at row 1, col 2, pos 1: +1> ///ERROR/// + ^ + +" +`; diff --git a/tests_integration/__tests__/__snapshots__/with-config-precedence.js.snap b/tests_integration/__tests__/__snapshots__/with-config-precedence.js.snap index 5e817c5fac16..ce5002c6b275 100644 --- a/tests_integration/__tests__/__snapshots__/with-config-precedence.js.snap +++ b/tests_integration/__tests__/__snapshots__/with-config-precedence.js.snap @@ -139,6 +139,16 @@ function rcJson() { ], ); } +function rcToml() { + console.log.apply( + null, + [ + 'rc-toml/file.js', + 'should have trailing comma', + 'and single quotes', + ], + ); +} function rcYaml() { console.log.apply( null, @@ -216,6 +226,16 @@ function rcJson() { ], ); } +function rcToml() { + console.log.apply( + null, + [ + 'rc-toml/file.js', + 'should have trailing comma', + 'and single quotes', + ], + ); +} function rcYaml() { console.log.apply( null, diff --git a/tests_integration/__tests__/config-resolution.js b/tests_integration/__tests__/config-resolution.js index d78a55eb84ae..6072fde9796d 100644 --- a/tests_integration/__tests__/config-resolution.js +++ b/tests_integration/__tests__/config-resolution.js @@ -43,6 +43,12 @@ describe("resolves yaml configuration file with --find-config-path file", () => }); }); +describe("resolves toml configuration file with --find-config-path file", () => { + runPrettier("cli/config/", ["--find-config-path", "rc-toml/file.js"]).test({ + status: 0 + }); +}); + describe("prints nothing when no file found with --find-config-path", () => { runPrettier("cli/config/", ["--find-config-path", ".."]).test({ stdout: "", diff --git a/tests_integration/__tests__/load-toml.js b/tests_integration/__tests__/load-toml.js new file mode 100644 index 000000000000..138847a92da3 --- /dev/null +++ b/tests_integration/__tests__/load-toml.js @@ -0,0 +1,37 @@ +"use strict"; + +const loadToml = require("../../src/utils/load-toml"); + +describe("TOML", () => { + const exampleFilePath = "example.toml"; + + const exampleToml = ` +# This is a TOML document. +title = "TOML Example" +[owner] +name = "Tom Preston-Werner" +dob = 1979-05-27T07:32:00-08:00 # First class dates +[database] +server = "192.168.1.1" +ports = [ 8001, 8001, 8002 ] +connection_max = 5000 +enabled = true +`; + + const wrongToml = "///ERROR///"; + + test("loads toml successfully", () => { + const parsedToml = loadToml(exampleFilePath, exampleToml); + expect(parsedToml).toMatchSnapshot(); + }); + + test("throws error on incorrect toml", () => { + expect(() => { + loadToml(exampleFilePath, wrongToml); + }).toThrow(); + + expect(() => { + loadToml(exampleFilePath, wrongToml); + }).toThrowErrorMatchingSnapshot(); + }); +}); diff --git a/tests_integration/cli/config/rc-toml/.prettierrc.toml b/tests_integration/cli/config/rc-toml/.prettierrc.toml new file mode 100644 index 000000000000..971b0d4cff7b --- /dev/null +++ b/tests_integration/cli/config/rc-toml/.prettierrc.toml @@ -0,0 +1,2 @@ +trailingComma = "all" +singleQuote = true diff --git a/tests_integration/cli/config/rc-toml/file.js b/tests_integration/cli/config/rc-toml/file.js new file mode 100644 index 000000000000..75df5b4b52d2 --- /dev/null +++ b/tests_integration/cli/config/rc-toml/file.js @@ -0,0 +1,7 @@ +function rcToml() { + console.log.apply(null, [ + "rc-toml/file.js", + "should have trailing comma", + "and single quotes" + ]); +} diff --git a/yarn.lock b/yarn.lock index 89b47ccfa23c..64843118f27a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -563,6 +563,10 @@ dependencies: "@glimmer/util" "^0.30.3" +"@iarna/toml@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@iarna/toml/-/toml-2.0.0.tgz#7802115684397785b3b6dc8a3ba50e30d7a7422b" + "@types/commander@^2.11.0": version "2.12.2" resolved "https://registry.yarnpkg.com/@types/commander/-/commander-2.12.2.tgz#183041a23842d4281478fa5d23c5ca78e6fd08ae"