Skip to content

Commit

Permalink
Re-add EditorConfig support (undo #3213) (#3255)
Browse files Browse the repository at this point in the history
* Revert "Revert "Respect EditorConfig settings" (#3213)"

This reverts commit d2241fc.

* Comment out EditorConfig docs

See #3213 (comment)

* editorconfig: Support `indent_size = 0`

See #2760 (comment)
and josephfrazier/editorconfig-to-prettier@c38b84c

* Revert "Comment out EditorConfig docs"

This reverts commit ddfa529.

* Mark EditorConfig functionality as v1.9.0+

See #3255 (comment)

* editorconfig: Upgrade editorconfig-to-prettier to 0.0.4

* editorconfig: Only enable for CLI, by default

#3255 (comment)

* editorconfig: Add tests confirming that editorconfig is ignored by default in the API

#3255 (comment)

* editorconfig: Add/fix CLI option parsing

* editorconfig: Move docs from configuration.md to options.md

* editorconfig: Add `oppositeDescription` to show docs for `--no-editorconfig`

Addresses #3255 (comment)

* editorconfig: Update test snapshots

* editorconfig: Remove unnecessary options parsing code

Addresses #3255 (comment)

* editorconfig: Move docs from options.md to api.md and cli.md

Addresses #3255 (comment)

* resolveConfig: return null if both .prettierrc and .editorconfig are missing

Addresses #3255 (comment)

* Don't add now-failing tests

The way these tests work, both `tests_integration/cli/config/.prettierrc`
and `.prettierrc` apply to `tests_integration/cli/config/editorconfig/file.shouldnotexist`,
so the test wouldn't work even on master. Here's a way to confirm that:

```js
const path = require('path')
const assert = require('assert')
const prettier = require('./')

const file = './tests_integration/cli/config/editorconfig/file.shouldnotexist'
console.log(prettier.resolveConfig.sync(file))
assert(prettier.resolveConfig.sync(file) === null)
```
  • Loading branch information
josephfrazier authored and azz committed Dec 4, 2017
1 parent 1122701 commit cecf065
Show file tree
Hide file tree
Showing 19 changed files with 365 additions and 19 deletions.
6 changes: 6 additions & 0 deletions docs/api.md
Expand Up @@ -49,6 +49,12 @@ prettier.resolveConfig(filePath).then(options => {
});
```

If `options.editorconfig` is `true` and an [`.editorconfig` file](http://editorconfig.org/) is in your project, Prettier will parse it and convert its properties to the corresponding prettier configuration. This configuration will be overridden by `.prettierrc`, etc. Currently, the following EditorConfig properties are supported:

* `indent_style`
* `indent_size`/`tab_width`
* `max_line_length`

Use `prettier.resolveConfig.sync(filePath [, options])` if you'd like to use sync version.

## `prettier.clearConfigCache()`
Expand Down
4 changes: 4 additions & 0 deletions docs/cli.md
Expand Up @@ -94,6 +94,10 @@ If a config file is found will evaluate it and ignore other CLI options. If no c

This option adds support to editor integrations where users define their default configuration but want to respect project specific configuration.

## `--no-editorconfig`

Don't take .editorconfig into account when parsing configuration. See the [`prettier.resolveConfig` docs](./api.md) for details.

## `--with-node-modules`

Prettier CLI will ignore files located in `node_modules` directory. To opt-out from this behavior use `--with-node-modules` flag.
Expand Down
3 changes: 3 additions & 0 deletions package.json
Expand Up @@ -22,6 +22,8 @@
"cosmiconfig": "3.1.0",
"dashify": "0.2.2",
"diff": "3.2.0",
"editorconfig": "0.14.2",
"editorconfig-to-prettier": "0.0.4",
"emoji-regex": "6.5.1",
"escape-string-regexp": "1.0.5",
"esutils": "2.0.2",
Expand All @@ -37,6 +39,7 @@
"minimatch": "3.0.4",
"minimist": "1.2.0",
"parse5": "3.0.3",
"path-root": "0.1.1",
"postcss-less": "1.1.3",
"postcss-media-query-parser": "0.2.3",
"postcss-scss": "1.0.2",
Expand Down
8 changes: 8 additions & 0 deletions src/cli-constant.js
Expand Up @@ -158,6 +158,14 @@ const detailedOptions = normalizeDetailedOptions({
"debug-print-doc": {
type: "boolean"
},
editorconfig: {
type: "boolean",
category: CATEGORY_CONFIG,
description: "Take .editorconfig into account when parsing configuration.",
oppositeDescription:
"Don't take .editorconfig into account when parsing configuration.",
default: true
},
"find-config-path": {
type: "path",
category: CATEGORY_CONFIG,
Expand Down
1 change: 1 addition & 0 deletions src/cli-util.js
Expand Up @@ -159,6 +159,7 @@ function getOptionsOrDie(argv, filePath) {
: `resolve config from '${filePath}'`
);
const options = resolver.resolveConfig.sync(filePath, {
editorconfig: argv.editorconfig,
config: argv["config"]
});

Expand Down
47 changes: 47 additions & 0 deletions src/resolve-config-editorconfig.js
@@ -0,0 +1,47 @@
"use strict";

const editorconfig = require("editorconfig");
const mem = require("mem");
const pathRoot = require("path-root");
const editorConfigToPrettier = require("editorconfig-to-prettier");

const maybeParse = (filePath, config, parse) => {
const root = filePath && pathRoot(filePath);
return filePath && !config && parse(filePath, { root });
};

const editorconfigAsyncNoCache = (filePath, config) => {
return Promise.resolve(maybeParse(filePath, config, editorconfig.parse)).then(
editorConfigToPrettier
);
};
const editorconfigAsyncWithCache = mem(editorconfigAsyncNoCache);

const editorconfigSyncNoCache = (filePath, config) => {
return editorConfigToPrettier(
maybeParse(filePath, config, editorconfig.parseSync)
);
};
const editorconfigSyncWithCache = mem(editorconfigSyncNoCache);

function getLoadFunction(opts) {
if (!opts.editorconfig) {
return () => null;
}

if (opts.sync) {
return opts.cache ? editorconfigSyncWithCache : editorconfigSyncNoCache;
}

return opts.cache ? editorconfigAsyncWithCache : editorconfigAsyncNoCache;
}

function clearCache() {
mem.clear(editorconfigSyncWithCache);
mem.clear(editorconfigAsyncWithCache);
}

module.exports = {
getLoadFunction,
clearCache
};
48 changes: 37 additions & 11 deletions src/resolve-config.js
Expand Up @@ -5,6 +5,8 @@ const minimatch = require("minimatch");
const path = require("path");
const mem = require("mem");

const resolveEditorConfig = require("./resolve-config-editorconfig");

const getExplorerMemoized = mem(opts =>
thirdParty.cosmiconfig("prettier", {
sync: opts.sync,
Expand All @@ -26,23 +28,47 @@ function getLoadFunction(opts) {
return getExplorerMemoized(opts).load;
}

function resolveConfig(filePath, opts) {
function _resolveConfig(filePath, opts, sync) {
opts = Object.assign({ useCache: true }, opts);
const load = getLoadFunction({ cache: !!opts.useCache, sync: false });
return load(filePath, opts.config).then(result => {
return !result ? null : mergeOverrides(result, filePath);
});
const loadOpts = {
cache: !!opts.useCache,
sync: !!sync,
editorconfig: !!opts.editorconfig
};
const load = getLoadFunction(loadOpts);
const loadEditorConfig = resolveEditorConfig.getLoadFunction(loadOpts);
const arr = [load, loadEditorConfig].map(l => l(filePath, opts.config));

const unwrapAndMerge = arr => {
const result = arr[0];
const editorConfigured = arr[1];
const merged = Object.assign(
{},
editorConfigured,
mergeOverrides(Object.assign({}, result), filePath)
);

if (!result && !editorConfigured) {
return null;
}

return merged;
};

if (loadOpts.sync) {
return unwrapAndMerge(arr);
}

return Promise.all(arr).then(unwrapAndMerge);
}

resolveConfig.sync = (filePath, opts) => {
opts = Object.assign({ useCache: true }, opts);
const load = getLoadFunction({ cache: !!opts.useCache, sync: true });
const result = load(filePath, opts.config);
return !result ? null : mergeOverrides(result, filePath);
};
const resolveConfig = (filePath, opts) => _resolveConfig(filePath, opts, false);

resolveConfig.sync = (filePath, opts) => _resolveConfig(filePath, opts, true);

function clearCache() {
mem.clear(getExplorerMemoized);
resolveEditorConfig.clearCache();
}

function resolveConfigFile(filePath) {
Expand Down
Expand Up @@ -3,7 +3,22 @@
exports[`CLI overrides take precedence (stderr) 1`] = `""`;

exports[`CLI overrides take precedence (stdout) 1`] = `
"console.log(
"function f() {
console.log(
\\"should have tab width 8\\"
)
}
function f() {
console.log(
\\"should have space width 2\\"
)
}
function f() {
console.log(
\\"should have space width 8\\"
)
}
console.log(
\\"jest/__best-tests__/file.js should have semi\\"
);
console.log(
Expand Down Expand Up @@ -84,7 +99,16 @@ exports[`resolves configuration file with --find-config-path file (write) 1`] =
exports[`resolves configuration from external files (stderr) 1`] = `""`;

exports[`resolves configuration from external files (stdout) 1`] = `
"console.log(\\"jest/__best-tests__/file.js should have semi\\");
"function f() {
console.log(\\"should have tab width 8\\")
}
function f() {
console.log(\\"should have space width 2\\")
}
function f() {
console.log(\\"should have space width 8\\")
}
console.log(\\"jest/__best-tests__/file.js should have semi\\");
console.log(\\"jest/Component.js should not have semi\\")
console.log(\\"jest/Component.test.js should have semi\\");
function js() {
Expand Down
26 changes: 26 additions & 0 deletions tests_integration/__tests__/__snapshots__/early-exit.js.snap
Expand Up @@ -89,6 +89,19 @@ Default: -1
exports[`show detailed usage with --help cursor-offset (write) 1`] = `Array []`;
exports[`show detailed usage with --help editorconfig (stderr) 1`] = `""`;
exports[`show detailed usage with --help editorconfig (stdout) 1`] = `
"--editorconfig
Take .editorconfig into account when parsing configuration.
Default: true
"
`;
exports[`show detailed usage with --help editorconfig (write) 1`] = `Array []`;
exports[`show detailed usage with --help find-config-path (stderr) 1`] = `""`;
exports[`show detailed usage with --help find-config-path (stdout) 1`] = `
Expand Down Expand Up @@ -226,6 +239,17 @@ exports[`show detailed usage with --help no-config (stdout) 1`] = `
exports[`show detailed usage with --help no-config (write) 1`] = `Array []`;
exports[`show detailed usage with --help no-editorconfig (stderr) 1`] = `""`;
exports[`show detailed usage with --help no-editorconfig (stdout) 1`] = `
"--no-editorconfig
Don't take .editorconfig into account when parsing configuration.
"
`;
exports[`show detailed usage with --help no-editorconfig (write) 1`] = `Array []`;
exports[`show detailed usage with --help no-semi (stderr) 1`] = `""`;
exports[`show detailed usage with --help no-semi (stdout) 1`] = `
Expand Down Expand Up @@ -522,6 +546,7 @@ Config options:
--config-precedence <cli-override|file-override|prefer-file>
Define in which order config files and CLI options should be evaluated.
Defaults to cli-override.
--no-editorconfig Don't take .editorconfig into account when parsing configuration.
--find-config-path <path>
Find and print the path to a configuration file for the given input file.
--ignore-path <path> Path to a file with patterns describing files to ignore.
Expand Down Expand Up @@ -660,6 +685,7 @@ Config options:
--config-precedence <cli-override|file-override|prefer-file>
Define in which order config files and CLI options should be evaluated.
Defaults to cli-override.
--no-editorconfig Don't take .editorconfig into account when parsing configuration.
--find-config-path <path>
Find and print the path to a configuration file for the given input file.
--ignore-path <path> Path to a file with patterns describing files to ignore.
Expand Down
Expand Up @@ -80,7 +80,22 @@ exports[`CLI overrides take lower precedence with --config-precedence file-overr
exports[`CLI overrides take precedence with --config-precedence cli-override (stderr) 1`] = `""`;
exports[`CLI overrides take precedence with --config-precedence cli-override (stdout) 1`] = `
"console.log(
"function f() {
console.log(
\\"should have tab width 8\\"
)
}
function f() {
console.log(
\\"should have space width 2\\"
)
}
function f() {
console.log(
\\"should have space width 8\\"
)
}
console.log(
\\"jest/__best-tests__/file.js should have semi\\"
);
console.log(
Expand Down Expand Up @@ -137,7 +152,22 @@ exports[`CLI overrides take precedence with --config-precedence cli-override (wr
exports[`CLI overrides take precedence without --config-precedence (stderr) 1`] = `""`;
exports[`CLI overrides take precedence without --config-precedence (stdout) 1`] = `
"console.log(
"function f() {
console.log(
\\"should have tab width 8\\"
)
}
function f() {
console.log(
\\"should have space width 2\\"
)
}
function f() {
console.log(
\\"should have space width 8\\"
)
}
console.log(
\\"jest/__best-tests__/file.js should have semi\\"
);
console.log(
Expand Down

0 comments on commit cecf065

Please sign in to comment.