Skip to content

Commit 910aeb6

Browse files
authored
feat!: bump eslint, node and prettier versions, add types support (#508)
1 parent 21d87ab commit 910aeb6

18 files changed

+4559
-3155
lines changed

.changeset/config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"$schema": "https://unpkg.com/@changesets/config@1.6.0/schema.json",
2+
"$schema": "https://unpkg.com/@changesets/config/schema.json",
33
"changelog": [
44
"@changesets/changelog-github",
55
{

.changeset/old-plants-exist.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'eslint-plugin-prettier': major
3+
---
4+
5+
feat!: bump peer eslint to ">=8.0.0" and node to "^14.18.0 || >=16.0.0"

.changeset/orange-eyes-brush.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"eslint-plugin-prettier": major
3+
---
4+
5+
feat!: upgrade to prettier v3

.changeset/pre.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"mode": "pre",
3+
"tag": "alpha",
4+
"initialVersions": {
5+
"eslint-plugin-prettier": "4.2.2"
6+
},
7+
"changesets": []
8+
}

.changeset/quiet-cups-pull.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"eslint-plugin-prettier": minor
3+
---
4+
5+
feat: add typings support

.eslintrc.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
"@1stg",
88
"plugin:eslint-plugin/recommended"
99
],
10+
"parserOptions": {
11+
"project": null
12+
},
1013
"rules": {
1114
"eslint-plugin/report-message-format": [
1215
"error",
@@ -28,7 +31,8 @@
2831
{
2932
"files": "test/*.js",
3033
"rules": {
31-
"no-magic-numbers": "off"
34+
"no-magic-numbers": "off",
35+
"unicorn/prefer-top-level-await": "off"
3236
}
3337
}
3438
]

.github/FUNDING.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
github:
22
- JounQin
33
- 1stG
4-
- rxts
5-
- unts
4+
- rx-ts
5+
- un-ts
66
patreon: 1stG
77
open_collective: prettier
88
custom:

.github/workflows/ci.yml

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,14 @@ on:
88

99
jobs:
1010
ci:
11-
name: 'Test: Node ${{ matrix.node-version }} - ESLint ${{ matrix.eslint-version }}'
11+
name: Lint and Test on Node ${{ matrix.node-version }}
1212
runs-on: ubuntu-latest
1313
strategy:
1414
matrix:
15-
eslint-version:
16-
- 7
17-
- 8
1815
node-version:
19-
- 12
2016
- 14
2117
- 16
18+
- 18
2219

2320
steps:
2421
- uses: actions/checkout@v3
@@ -29,11 +26,8 @@ jobs:
2926
node-version: ${{ matrix.node-version }}
3027
cache: yarn
3128

32-
- name: Use ESLint ${{ matrix.eslint-version }}
33-
run: yarn upgrade eslint@${{ matrix.eslint-version }} --ignore-engines
34-
3529
- name: Install
36-
run: yarn --frozen-lockfile --ignore-engines
30+
run: yarn --frozen-lockfile
3731

3832
- name: Test
3933
run: yarn mocha

.remarkrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"plugins": [
3-
"@1stg/remark-config"
3+
"@1stg/preset"
44
]
55
}

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ If you’re fixing large of amounts of previously unformatted code, consider tem
139139

140140
- An object with the following options
141141

142-
- `usePrettierrc`: Enables loading of the Prettier configuration file, (default: `true`). May be useful if you are using multiple tools that conflict with each other, or do not wish to mix your ESLint settings with your Prettier configuration.
142+
- `usePrettierrc`: Enables loading of the Prettier configuration file, (default: `true`). May be useful if you are using multiple tools that conflict with each other, or do not wish to mix your ESLint settings with your Prettier configuration. And also, it is possible to run prettier without loading the prettierrc config file [via the CLI's --no-config option](https://prettier.io/docs/en/cli.html#--no-config) or through the API by [calling prettier.format() without passing through the options generated by calling resolveConfig](https://prettier.io/docs/en/api.html#prettierresolveconfigfilepath--options).
143143

144144
```json
145145
{

eslint-plugin-prettier.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { ESLint } from 'eslint';
2+
3+
declare const eslintPluginPrettier: ESLint.Plugin;
4+
5+
export = eslintPluginPrettier;

eslint-plugin-prettier.js

Lines changed: 57 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@
33
* @author Andres Suarez
44
*/
55

6+
// @ts-check
7+
8+
/**
9+
* @typedef {import('eslint').AST.Range} Range
10+
* @typedef {import('eslint').AST.SourceLocation} SourceLocation
11+
* @typedef {import('eslint').ESLint.Plugin} Plugin
12+
* @typedef {import('prettier').FileInfoOptions} FileInfoOptions
13+
* @typedef {import('prettier').Options & { onDiskFilepath: string, parserPath: string, usePrettierrc?: boolean }} Options
14+
*/
15+
616
'use strict';
717

818
// ------------------------------------------------------------------------------
@@ -26,9 +36,9 @@ const { INSERT, DELETE, REPLACE } = generateDifferences;
2636

2737
// Lazily-loaded Prettier.
2838
/**
29-
* @type {import('prettier')}
39+
* @type {(source: string, options: Options, fileInfoOptions: FileInfoOptions) => string}
3040
*/
31-
let prettier;
41+
let prettierFormat;
3242

3343
// ------------------------------------------------------------------------------
3444
// Rule Definition
@@ -43,7 +53,7 @@ let prettier;
4353
*/
4454
function reportDifference(context, difference) {
4555
const { operation, offset, deleteText = '', insertText = '' } = difference;
46-
const range = [offset, offset + deleteText.length];
56+
const range = /** @type {Range} */ ([offset, offset + deleteText.length]);
4757
const [start, end] = range.map(index =>
4858
context.getSourceCode().getLocFromIndex(index),
4959
);
@@ -63,7 +73,10 @@ function reportDifference(context, difference) {
6373
// Module Definition
6474
// ------------------------------------------------------------------------------
6575

66-
module.exports = {
76+
/**
77+
* @type {Plugin}
78+
*/
79+
const eslintPluginPrettier = {
6780
configs: {
6881
recommended: {
6982
extends: ['prettier'],
@@ -112,7 +125,10 @@ module.exports = {
112125
create(context) {
113126
const usePrettierrc =
114127
!context.options[1] || context.options[1].usePrettierrc !== false;
115-
const eslintFileInfoOptions =
128+
/**
129+
* @type {FileInfoOptions}
130+
*/
131+
const fileInfoOptions =
116132
(context.options[1] && context.options[1].fileInfoOptions) || {};
117133
const sourceCode = context.getSourceCode();
118134
const filepath = context.getFilename();
@@ -125,134 +141,19 @@ module.exports = {
125141
const source = sourceCode.text;
126142

127143
return {
128-
// eslint-disable-next-line sonarjs/cognitive-complexity
129144
Program() {
130-
if (!prettier) {
145+
if (!prettierFormat) {
131146
// Prettier is expensive to load, so only load it if needed.
132-
prettier = require('prettier');
147+
prettierFormat = require('synckit').createSyncFn(
148+
require.resolve('./worker'),
149+
);
133150
}
134151

152+
/**
153+
* @type {{}}
154+
*/
135155
const eslintPrettierOptions = context.options[0] || {};
136156

137-
const prettierRcOptions = usePrettierrc
138-
? prettier.resolveConfig.sync(onDiskFilepath, {
139-
editorconfig: true,
140-
})
141-
: null;
142-
143-
const { ignored, inferredParser } = prettier.getFileInfo.sync(
144-
onDiskFilepath,
145-
{
146-
resolveConfig: false,
147-
withNodeModules: false,
148-
ignorePath: '.prettierignore',
149-
plugins: prettierRcOptions ? prettierRcOptions.plugins : null,
150-
...eslintFileInfoOptions,
151-
},
152-
);
153-
154-
// Skip if file is ignored using a .prettierignore file
155-
if (ignored) {
156-
return;
157-
}
158-
159-
const initialOptions = {};
160-
161-
// ESLint supports processors that let you extract and lint JS
162-
// fragments within a non-JS language. In the cases where prettier
163-
// supports the same language as a processor, we want to process
164-
// the provided source code as javascript (as ESLint provides the
165-
// rules with fragments of JS) instead of guessing the parser
166-
// based off the filename. Otherwise, for instance, on a .md file we
167-
// end up trying to run prettier over a fragment of JS using the
168-
// markdown parser, which throws an error.
169-
// Processors may set virtual filenames for these extracted blocks.
170-
// If they do so then we want to trust the file extension they
171-
// provide, and no override is needed.
172-
// If the processor does not set any virtual filename (signified by
173-
// `filepath` and `onDiskFilepath` being equal) AND we can't
174-
// infer the parser from the filename, either because no filename
175-
// was provided or because there is no parser found for the
176-
// filename, use javascript.
177-
// This is added to the options first, so that
178-
// prettierRcOptions and eslintPrettierOptions can still override
179-
// the parser.
180-
//
181-
// `parserBlocklist` should contain the list of prettier parser
182-
// names for file types where:
183-
// * Prettier supports parsing the file type
184-
// * There is an ESLint processor that extracts JavaScript snippets
185-
// from the file type.
186-
if (filepath === onDiskFilepath) {
187-
// The following list means the plugin process source into js content
188-
// but with same filename, so we need to change the parser to `babel`
189-
// by default.
190-
// Related ESLint plugins are:
191-
// 1. `eslint-plugin-graphql` (replacement: `@graphql-eslint/eslint-plugin`)
192-
// 2. `eslint-plugin-html`
193-
// 3. `eslint-plugin-markdown@1` (replacement: `eslint-plugin-markdown@2+`)
194-
// 4. `eslint-plugin-svelte3` (replacement: `eslint-plugin-svelte@2+`)
195-
const parserBlocklist = [null, 'markdown', 'html'];
196-
197-
let inferParserToBabel = parserBlocklist.includes(inferredParser);
198-
199-
switch (inferredParser) {
200-
// it could be processed by `@graphql-eslint/eslint-plugin` or `eslint-plugin-graphql`
201-
case 'graphql': {
202-
if (
203-
// for `eslint-plugin-graphql`, see https://github.com/apollographql/eslint-plugin-graphql/blob/master/src/index.js#L416
204-
source.startsWith('ESLintPluginGraphQLFile`')
205-
) {
206-
inferParserToBabel = true;
207-
}
208-
break;
209-
}
210-
// it could be processed by `@ota-meshi/eslint-plugin-svelte`, `eslint-plugin-svelte` or `eslint-plugin-svelte3`
211-
case 'svelte': {
212-
// The `source` would be modified by `eslint-plugin-svelte3`
213-
if (!context.parserPath.includes('svelte-eslint-parser')) {
214-
// We do not support `eslint-plugin-svelte3`,
215-
// the users should run `prettier` on `.svelte` files manually
216-
return;
217-
}
218-
}
219-
}
220-
221-
if (inferParserToBabel) {
222-
initialOptions.parser = 'babel';
223-
}
224-
} else {
225-
// Similar to https://github.com/prettier/stylelint-prettier/pull/22
226-
// In all of the following cases ESLint extracts a part of a file to
227-
// be formatted and there exists a prettier parser for the whole file.
228-
// If you're interested in prettier you'll want a fully formatted file so
229-
// you're about to run prettier over the whole file anyway.
230-
// Therefore running prettier over just the style section is wasteful, so
231-
// skip it.
232-
const parserBlocklist = [
233-
'babel',
234-
'babylon',
235-
'flow',
236-
'typescript',
237-
'vue',
238-
'markdown',
239-
'html',
240-
'mdx',
241-
'angular',
242-
'svelte',
243-
];
244-
if (parserBlocklist.includes(inferredParser)) {
245-
return;
246-
}
247-
}
248-
249-
const prettierOptions = {
250-
...initialOptions,
251-
...prettierRcOptions,
252-
...eslintPrettierOptions,
253-
filepath,
254-
};
255-
256157
// prettier.format() may throw a SyntaxError if it cannot parse the
257158
// source code it is given. Usually for JS files this isn't a
258159
// problem as ESLint will report invalid syntax before trying to
@@ -261,29 +162,51 @@ module.exports = {
261162
// files throw an error if they contain unclosed elements, such as
262163
// `<template><div></template>. In this case report an error at the
263164
// point at which parsing failed.
165+
/**
166+
* @type {string}
167+
*/
264168
let prettierSource;
265169
try {
266-
prettierSource = prettier.format(source, prettierOptions);
170+
prettierSource = prettierFormat(
171+
source,
172+
{
173+
...eslintPrettierOptions,
174+
filepath,
175+
onDiskFilepath,
176+
parserPath: context.parserPath,
177+
usePrettierrc,
178+
},
179+
fileInfoOptions,
180+
);
267181
} catch (err) {
268182
if (!(err instanceof SyntaxError)) {
269183
throw err;
270184
}
271185

272186
let message = 'Parsing error: ' + err.message;
273187

188+
const error =
189+
/** @type {SyntaxError & {codeFrame: string; loc: SourceLocation}} */ (
190+
err
191+
);
192+
274193
// Prettier's message contains a codeframe style preview of the
275194
// invalid code and the line/column at which the error occurred.
276195
// ESLint shows those pieces of information elsewhere already so
277196
// remove them from the message
278-
if (err.codeFrame) {
279-
message = message.replace(`\n${err.codeFrame}`, '');
197+
if (error.codeFrame) {
198+
message = message.replace(`\n${error.codeFrame}`, '');
280199
}
281-
if (err.loc) {
200+
if (error.loc) {
282201
message = message.replace(/ \(\d+:\d+\)$/, '');
283202
}
284203

285-
context.report({ message, loc: err.loc });
204+
context.report({ message, loc: error.loc });
205+
206+
return;
207+
}
286208

209+
if (prettierSource == null) {
287210
return;
288211
}
289212

@@ -300,3 +223,5 @@ module.exports = {
300223
},
301224
},
302225
};
226+
227+
module.exports = eslintPluginPrettier;

0 commit comments

Comments
 (0)