eslint-plugin-prettier 3.3.1 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +3 -15
- package/eslint-plugin-prettier.js +69 -90
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v3.4.0 (2021-04-15)
|
|
4
|
+
|
|
5
|
+
* feat: support processor virtual filename ([#401](git@github.com:prettier/eslint-plugin-prettier/issues/401)) ([ee0ccc6](git@github.com:prettier/eslint-plugin-prettier/commit/ee0ccc6ac06d13cd546e78b444e53164f59eb27f))
|
|
6
|
+
* Simplify report logic ([#380](git@github.com:prettier/eslint-plugin-prettier/issues/380)) ([d993f24](git@github.com:prettier/eslint-plugin-prettier/commit/d993f247b5661683af031ab3b93955a0dfe448fa))
|
|
7
|
+
* Update: README.md ([#375](git@github.com:prettier/eslint-plugin-prettier/issues/375)) ([3ea4242](git@github.com:prettier/eslint-plugin-prettier/commit/3ea4242a8d4acdb76eb7e7dca9e44d3e87db70e3))
|
|
8
|
+
|
|
3
9
|
## v3.3.1 (2021-01-04)
|
|
4
10
|
|
|
5
11
|
* fix: add eslint-config-prettier as an optional peer dependency ([#374](git@github.com:prettier/eslint-plugin-prettier/issues/374)) ([d59df27](git@github.com:prettier/eslint-plugin-prettier/commit/d59df27890aaffec9e528ceb3155831a0261848d))
|
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@ Runs [Prettier](https://github.com/prettier/prettier) as an [ESLint](http://esli
|
|
|
4
4
|
|
|
5
5
|
If your desired formatting does not match Prettier’s output, you should use a different tool such as [prettier-eslint](https://github.com/prettier/prettier-eslint) instead.
|
|
6
6
|
|
|
7
|
+
Please read [Integrating with linters](https://prettier.io/docs/en/integrating-with-linters.html) before installing.
|
|
8
|
+
|
|
7
9
|
## Sample
|
|
8
10
|
|
|
9
11
|
```js
|
|
@@ -74,20 +76,6 @@ This plugin ships with a `plugin:prettier/recommended` config that sets up both
|
|
|
74
76
|
|
|
75
77
|
You can then set Prettier's own options inside a `.prettierrc` file.
|
|
76
78
|
|
|
77
|
-
3. Some ESLint plugins (such as [eslint-plugin-react](https://github.com/yannickcr/eslint-plugin-react)) also contain rules that conflict with Prettier. Add extra exclusions for the plugins you use like so:
|
|
78
|
-
|
|
79
|
-
```json
|
|
80
|
-
{
|
|
81
|
-
"extends": [
|
|
82
|
-
"plugin:prettier/recommended",
|
|
83
|
-
"prettier/flowtype",
|
|
84
|
-
"prettier/react"
|
|
85
|
-
]
|
|
86
|
-
}
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
For the list of every available exclusion rule set, please see the [readme of eslint-config-prettier](https://github.com/prettier/eslint-config-prettier/blob/master/README.md).
|
|
90
|
-
|
|
91
79
|
Exactly what does `plugin:prettier/recommended` do? Well, this is what it expands to:
|
|
92
80
|
|
|
93
81
|
```json
|
|
@@ -102,7 +90,7 @@ Exactly what does `plugin:prettier/recommended` do? Well, this is what it expand
|
|
|
102
90
|
}
|
|
103
91
|
```
|
|
104
92
|
|
|
105
|
-
- `"extends": ["prettier"]` enables the
|
|
93
|
+
- `"extends": ["prettier"]` enables the config from `eslint-config-prettier`, which turns off some ESLint rules that conflict with Prettier.
|
|
106
94
|
- `"plugins": ["prettier"]` registers this plugin.
|
|
107
95
|
- `"prettier/prettier": "error"` turns on the rule provided by this plugin, which runs Prettier from within ESLint.
|
|
108
96
|
- `"arrow-body-style": "off"` and `"prefer-arrow-callback": "off"` turns off two ESLint core rules that unfortunately are problematic with this plugin – see the next section.
|
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
// Requirements
|
|
10
10
|
// ------------------------------------------------------------------------------
|
|
11
11
|
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
|
|
12
15
|
const {
|
|
13
16
|
showInvisibles,
|
|
14
17
|
generateDifferences
|
|
@@ -25,6 +28,9 @@ const { INSERT, DELETE, REPLACE } = generateDifferences;
|
|
|
25
28
|
// ------------------------------------------------------------------------------
|
|
26
29
|
|
|
27
30
|
// Lazily-loaded Prettier.
|
|
31
|
+
/**
|
|
32
|
+
* @type {import('prettier')}
|
|
33
|
+
*/
|
|
28
34
|
let prettier;
|
|
29
35
|
|
|
30
36
|
// ------------------------------------------------------------------------------
|
|
@@ -32,72 +38,49 @@ let prettier;
|
|
|
32
38
|
// ------------------------------------------------------------------------------
|
|
33
39
|
|
|
34
40
|
/**
|
|
35
|
-
* Reports
|
|
36
|
-
* @param {RuleContext} context - The ESLint rule context.
|
|
37
|
-
* @param {
|
|
38
|
-
* @param {string} text - The text to be inserted.
|
|
41
|
+
* Reports a difference.
|
|
42
|
+
* @param {import('eslint').Rule.RuleContext} context - The ESLint rule context.
|
|
43
|
+
* @param {import('prettier-linter-helpers').Difference} difference - The difference object.
|
|
39
44
|
* @returns {void}
|
|
40
45
|
*/
|
|
41
|
-
function
|
|
42
|
-
const
|
|
43
|
-
const range = [offset, offset];
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
loc: { start: pos, end: pos },
|
|
48
|
-
fix(fixer) {
|
|
49
|
-
return fixer.insertTextAfterRange(range, text);
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
}
|
|
46
|
+
function reportDifference(context, difference) {
|
|
47
|
+
const { operation, offset, deleteText = '', insertText = '' } = difference;
|
|
48
|
+
const range = [offset, offset + deleteText.length];
|
|
49
|
+
const [start, end] = range.map(index =>
|
|
50
|
+
context.getSourceCode().getLocFromIndex(index)
|
|
51
|
+
);
|
|
53
52
|
|
|
54
|
-
/**
|
|
55
|
-
* Reports a "Delete ..." issue where text must be deleted.
|
|
56
|
-
* @param {RuleContext} context - The ESLint rule context.
|
|
57
|
-
* @param {number} offset - The source offset where to delete text.
|
|
58
|
-
* @param {string} text - The text to be deleted.
|
|
59
|
-
* @returns {void}
|
|
60
|
-
*/
|
|
61
|
-
function reportDelete(context, offset, text) {
|
|
62
|
-
const start = context.getSourceCode().getLocFromIndex(offset);
|
|
63
|
-
const end = context.getSourceCode().getLocFromIndex(offset + text.length);
|
|
64
|
-
const range = [offset, offset + text.length];
|
|
65
53
|
context.report({
|
|
66
|
-
|
|
67
|
-
data: {
|
|
54
|
+
messageId: operation,
|
|
55
|
+
data: {
|
|
56
|
+
deleteText: showInvisibles(deleteText),
|
|
57
|
+
insertText: showInvisibles(insertText)
|
|
58
|
+
},
|
|
68
59
|
loc: { start, end },
|
|
69
|
-
fix(
|
|
70
|
-
return fixer.removeRange(range);
|
|
71
|
-
}
|
|
60
|
+
fix: fixer => fixer.replaceTextRange(range, insertText)
|
|
72
61
|
});
|
|
73
62
|
}
|
|
74
63
|
|
|
75
64
|
/**
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
|
|
80
|
-
* @
|
|
81
|
-
* @param {string} insertText - The text to be inserted.
|
|
82
|
-
* @returns {void}
|
|
65
|
+
* Given a filepath, get the nearest path that is a regular file.
|
|
66
|
+
* The filepath provided by eslint may be a virtual filepath rather than a file
|
|
67
|
+
* on disk. This attempts to transform a virtual path into an on-disk path
|
|
68
|
+
* @param {string} filepath
|
|
69
|
+
* @returns {string}
|
|
83
70
|
*/
|
|
84
|
-
function
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
.getLocFromIndex(offset + deleteText.length);
|
|
89
|
-
const range = [offset, offset + deleteText.length];
|
|
90
|
-
context.report({
|
|
91
|
-
message: 'Replace `{{ deleteCode }}` with `{{ insertCode }}`',
|
|
92
|
-
data: {
|
|
93
|
-
deleteCode: showInvisibles(deleteText),
|
|
94
|
-
insertCode: showInvisibles(insertText)
|
|
95
|
-
},
|
|
96
|
-
loc: { start, end },
|
|
97
|
-
fix(fixer) {
|
|
98
|
-
return fixer.replaceTextRange(range, insertText);
|
|
71
|
+
function getOnDiskFilepath(filepath) {
|
|
72
|
+
try {
|
|
73
|
+
if (fs.statSync(filepath).isFile()) {
|
|
74
|
+
return filepath;
|
|
99
75
|
}
|
|
100
|
-
})
|
|
76
|
+
} catch (err) {
|
|
77
|
+
// https://github.com/eslint/eslint/issues/11989
|
|
78
|
+
if (err.code === 'ENOTDIR') {
|
|
79
|
+
return getOnDiskFilepath(path.dirname(filepath));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return filepath;
|
|
101
84
|
}
|
|
102
85
|
|
|
103
86
|
// ------------------------------------------------------------------------------
|
|
@@ -143,7 +126,12 @@ module.exports = {
|
|
|
143
126
|
},
|
|
144
127
|
additionalProperties: true
|
|
145
128
|
}
|
|
146
|
-
]
|
|
129
|
+
],
|
|
130
|
+
messages: {
|
|
131
|
+
[INSERT]: 'Insert `{{ insertText }}`',
|
|
132
|
+
[DELETE]: 'Delete `{{ deleteText }}`',
|
|
133
|
+
[REPLACE]: 'Replace `{{ deleteText }}` with `{{ insertText }}`'
|
|
134
|
+
}
|
|
147
135
|
},
|
|
148
136
|
create(context) {
|
|
149
137
|
const usePrettierrc =
|
|
@@ -152,6 +140,14 @@ module.exports = {
|
|
|
152
140
|
(context.options[1] && context.options[1].fileInfoOptions) || {};
|
|
153
141
|
const sourceCode = context.getSourceCode();
|
|
154
142
|
const filepath = context.getFilename();
|
|
143
|
+
// Processors that extract content from a file, such as the markdown
|
|
144
|
+
// plugin extracting fenced code blocks may choose to specify virtual
|
|
145
|
+
// file paths. If this is the case then we need to resolve prettier
|
|
146
|
+
// config and file info using the on-disk path instead of the virtual
|
|
147
|
+
// path.
|
|
148
|
+
// See https://github.com/eslint/eslint/issues/11989 for ideas around
|
|
149
|
+
// being able to get this value directly from eslint in the future.
|
|
150
|
+
const onDiskFilepath = getOnDiskFilepath(filepath);
|
|
155
151
|
const source = sourceCode.text;
|
|
156
152
|
|
|
157
153
|
return {
|
|
@@ -164,13 +160,13 @@ module.exports = {
|
|
|
164
160
|
const eslintPrettierOptions = context.options[0] || {};
|
|
165
161
|
|
|
166
162
|
const prettierRcOptions = usePrettierrc
|
|
167
|
-
? prettier.resolveConfig.sync(
|
|
163
|
+
? prettier.resolveConfig.sync(onDiskFilepath, {
|
|
168
164
|
editorconfig: true
|
|
169
165
|
})
|
|
170
166
|
: null;
|
|
171
167
|
|
|
172
168
|
const prettierFileInfo = prettier.getFileInfo.sync(
|
|
173
|
-
|
|
169
|
+
onDiskFilepath,
|
|
174
170
|
Object.assign(
|
|
175
171
|
{},
|
|
176
172
|
{ resolveConfig: true, ignorePath: '.prettierignore' },
|
|
@@ -185,7 +181,7 @@ module.exports = {
|
|
|
185
181
|
|
|
186
182
|
const initialOptions = {};
|
|
187
183
|
|
|
188
|
-
// ESLint
|
|
184
|
+
// ESLint supports processors that let you extract and lint JS
|
|
189
185
|
// fragments within a non-JS language. In the cases where prettier
|
|
190
186
|
// supports the same language as a processor, we want to process
|
|
191
187
|
// the provided source code as javascript (as ESLint provides the
|
|
@@ -193,9 +189,14 @@ module.exports = {
|
|
|
193
189
|
// based off the filename. Otherwise, for instance, on a .md file we
|
|
194
190
|
// end up trying to run prettier over a fragment of JS using the
|
|
195
191
|
// markdown parser, which throws an error.
|
|
196
|
-
//
|
|
197
|
-
//
|
|
198
|
-
//
|
|
192
|
+
// Processors may set virtual filenames for these extracted blocks.
|
|
193
|
+
// If they do so then we want to trust the file extension they
|
|
194
|
+
// provide, and no override is needed.
|
|
195
|
+
// If the processor does not set any virtual filename (signified by
|
|
196
|
+
// `filepath` and `onDiskFilepath` being equal) AND we can't
|
|
197
|
+
// infer the parser from the filename, either because no filename
|
|
198
|
+
// was provided or because there is no parser found for the
|
|
199
|
+
// filename, use javascript.
|
|
199
200
|
// This is added to the options first, so that
|
|
200
201
|
// prettierRcOptions and eslintPrettierOptions can still override
|
|
201
202
|
// the parser.
|
|
@@ -207,6 +208,7 @@ module.exports = {
|
|
|
207
208
|
// from the file type.
|
|
208
209
|
const parserBlocklist = [null, 'graphql', 'markdown', 'html'];
|
|
209
210
|
if (
|
|
211
|
+
filepath === onDiskFilepath &&
|
|
210
212
|
parserBlocklist.indexOf(prettierFileInfo.inferredParser) !== -1
|
|
211
213
|
) {
|
|
212
214
|
// Prettier v1.16.0 renamed the `babylon` parser to `babel`
|
|
@@ -227,7 +229,7 @@ module.exports = {
|
|
|
227
229
|
);
|
|
228
230
|
|
|
229
231
|
// prettier.format() may throw a SyntaxError if it cannot parse the
|
|
230
|
-
// source code it is given.
|
|
232
|
+
// source code it is given. Usually for JS files this isn't a
|
|
231
233
|
// problem as ESLint will report invalid syntax before trying to
|
|
232
234
|
// pass it to the prettier plugin. However this might be a problem
|
|
233
235
|
// for non-JS languages that are handled by a plugin. Notably Vue
|
|
@@ -245,7 +247,7 @@ module.exports = {
|
|
|
245
247
|
let message = 'Parsing error: ' + err.message;
|
|
246
248
|
|
|
247
249
|
// Prettier's message contains a codeframe style preview of the
|
|
248
|
-
// invalid code and the line/column at which the error
|
|
250
|
+
// invalid code and the line/column at which the error occurred.
|
|
249
251
|
// ESLint shows those pieces of information elsewhere already so
|
|
250
252
|
// remove them from the message
|
|
251
253
|
if (err.codeFrame) {
|
|
@@ -263,32 +265,9 @@ module.exports = {
|
|
|
263
265
|
if (source !== prettierSource) {
|
|
264
266
|
const differences = generateDifferences(source, prettierSource);
|
|
265
267
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
reportInsert(
|
|
270
|
-
context,
|
|
271
|
-
difference.offset,
|
|
272
|
-
difference.insertText
|
|
273
|
-
);
|
|
274
|
-
break;
|
|
275
|
-
case DELETE:
|
|
276
|
-
reportDelete(
|
|
277
|
-
context,
|
|
278
|
-
difference.offset,
|
|
279
|
-
difference.deleteText
|
|
280
|
-
);
|
|
281
|
-
break;
|
|
282
|
-
case REPLACE:
|
|
283
|
-
reportReplace(
|
|
284
|
-
context,
|
|
285
|
-
difference.offset,
|
|
286
|
-
difference.deleteText,
|
|
287
|
-
difference.insertText
|
|
288
|
-
);
|
|
289
|
-
break;
|
|
290
|
-
}
|
|
291
|
-
});
|
|
268
|
+
for (const difference of differences) {
|
|
269
|
+
reportDifference(context, difference);
|
|
270
|
+
}
|
|
292
271
|
}
|
|
293
272
|
}
|
|
294
273
|
};
|