Skip to content

Commit ccd9303

Browse files
Fix report lint issues not on first char of file for .vue and support ESLint fixes and suggestions (#2735)
* move * rename * more * more * more * more * more * more * more * moree * moree * moree * moree * more * more * more * [skip ci] * more * fix icons * update docs to use Nextra 4 * [skip ci] * fix lint [skip ci] * more [skip ci] * more * upd * pnpm dedupe * yoyo * aa * aa * build pass * more * aa * aa * [skip ci] * Update examples/vue-code-file/test.vue [skip ci] Co-authored-by: Brendan Mulholland <[email protected]> * polish * add changeset --------- Co-authored-by: Brendan Mulholland <[email protected]>
1 parent 007f3f2 commit ccd9303

File tree

10 files changed

+195
-27
lines changed

10 files changed

+195
-27
lines changed

.changeset/fast-fishes-shake.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@graphql-eslint/eslint-plugin': patch
3+
---
4+
5+
fix reporting lint issues not on first char of file for `.vue` and support ESLint fixes and suggestions for them. Use [new official example](https://github.com/dimaMachina/graphql-eslint/blob/master/examples/vue-code-file/eslint.config.js)

examples/vue-code-file/eslint.config.js

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,30 @@
1-
import vueParser from 'vue-eslint-parser';
1+
import { mergeProcessors } from 'eslint-merge-processors';
2+
import pluginVue from 'eslint-plugin-vue';
3+
import processorVueBlocks from 'eslint-processor-vue-blocks';
24
import js from '@eslint/js';
35
import graphqlPlugin from '@graphql-eslint/eslint-plugin';
46

57
export default [
68
{
7-
files: ['**/*.js', '**/*.vue'],
9+
files: ['**/*.js'],
810
processor: graphqlPlugin.processor,
911
rules: js.configs.recommended.rules,
1012
},
13+
...pluginVue.configs['flat/recommended'],
1114
{
1215
files: ['**/*.vue'],
13-
languageOptions: {
14-
parser: vueParser,
15-
},
16+
// `eslint-plugin-vue` will set a default processor for `.vue` files
17+
// we use `eslint-merge-processors` to extend it
18+
processor: mergeProcessors([
19+
pluginVue.processors.vue,
20+
processorVueBlocks({
21+
blocks: {
22+
script: true,
23+
scriptSetup: true,
24+
customBlocks: true,
25+
},
26+
}),
27+
]),
1628
},
1729
{
1830
files: ['**/*.graphql'],

examples/vue-code-file/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
},
1313
"devDependencies": {
1414
"@graphql-eslint/eslint-plugin": "workspace:*",
15-
"@vue/compiler-sfc": "3.5.13",
1615
"eslint": "9.14.0",
17-
"vue-eslint-parser": "9.4.3"
16+
"eslint-merge-processors": "^0.1.0",
17+
"eslint-plugin-vue": "^9.31.0",
18+
"eslint-processor-vue-blocks": "^0.1.2"
1819
}
1920
}

examples/vue-code-file/test.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<template>
2-
<span>test</span>
2+
<!-- use the variables to satisfy the no-unused-vars lint -->
3+
<span>{{ GET_USER }}</span>
4+
<span>{{ GET_ANOTHER_USER }}</span>
35
</template>
46
<script>
5-
/* eslint-disable no-unused-vars */
6-
77
const GET_USER = /* GraphQL */ `
88
query {
99
user {

packages/plugin/__tests__/__snapshots__/examples.spec.md

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -626,21 +626,71 @@ exports[`Examples > should work in vue 1`] = `
626626
filePath: examples/vue-code-file/test.vue,
627627
messages: [
628628
{
629-
column: 0,
630-
line: 1,
629+
column: 8,
630+
endColumn: 16,
631+
endLine: 7,
632+
line: 7,
633+
message: 'GET_USER' is assigned a value but never used.,
634+
messageId: unusedVar,
635+
nodeType: Identifier,
636+
ruleId: no-unused-vars,
637+
severity: 2,
638+
},
639+
{
640+
column: 4,
641+
endColumn: 9,
642+
endLine: 8,
643+
line: 8,
631644
message: Anonymous GraphQL operations are forbidden. Make sure to name your query!,
632645
messageId: no-anonymous-operations,
633646
nodeType: null,
634647
ruleId: @graphql-eslint/no-anonymous-operations,
635648
severity: 2,
649+
suggestions: [
650+
{
651+
desc: Rename to \`user\`,
652+
fix: {
653+
range: [
654+
40,
655+
40,
656+
],
657+
text: user,
658+
},
659+
},
660+
],
636661
},
637662
{
638-
column: 0,
639-
line: 1,
663+
column: 8,
664+
endColumn: 24,
665+
endLine: 15,
666+
line: 15,
667+
message: 'GET_ANOTHER_USER' is assigned a value but never used.,
668+
messageId: unusedVar,
669+
nodeType: Identifier,
670+
ruleId: no-unused-vars,
671+
severity: 2,
672+
},
673+
{
674+
column: 10,
675+
endColumn: 19,
676+
endLine: 16,
677+
line: 16,
640678
message: Operation "UserQuery" should not have "Query" suffix,
641679
nodeType: Name,
642680
ruleId: @graphql-eslint/naming-convention,
643681
severity: 2,
682+
suggestions: [
683+
{
684+
desc: Rename to \`User\`,
685+
fix: {
686+
range: [
687+
128,
688+
137,
689+
],
690+
text: User,
691+
},
692+
},
693+
],
644694
},
645695
],
646696
},
@@ -669,6 +719,28 @@ exports[`Examples > should work in vue 2`] = `
669719
ruleId: @graphql-eslint/naming-convention,
670720
severity: 2,
671721
},
722+
{
723+
column: 7,
724+
endColumn: 15,
725+
endLine: 7,
726+
line: 7,
727+
message: 'GET_USER' is assigned a value but never used.,
728+
messageId: unusedVar,
729+
nodeType: Identifier,
730+
ruleId: no-unused-vars,
731+
severity: 2,
732+
},
733+
{
734+
column: 7,
735+
endColumn: 23,
736+
endLine: 15,
737+
line: 15,
738+
message: 'GET_ANOTHER_USER' is assigned a value but never used.,
739+
messageId: unusedVar,
740+
nodeType: Identifier,
741+
ruleId: no-unused-vars,
742+
severity: 2,
743+
},
672744
],
673745
},
674746
]

packages/plugin/__tests__/examples.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ describe('Examples', () => {
114114

115115
it('should work in vue', () => {
116116
const cwd = path.join(CWD, 'examples', 'vue-code-file');
117-
testESLintOutput(cwd, 2);
117+
testESLintOutput(cwd, 4);
118118
});
119119

120120
it('should work in multiple projects', () => {

packages/plugin/src/graphql-config.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import fs from 'node:fs';
12
import path from 'node:path';
23
import debugFactory from 'debug';
34
import { GraphQLConfig, GraphQLExtensionDeclaration, loadConfigSync } from 'graphql-config';
@@ -7,10 +8,21 @@ import { ParserOptions } from './types.js';
78
const debug = debugFactory('graphql-eslint:graphql-config');
89
let graphQLConfig: GraphQLConfig;
910

11+
/**
12+
* Filepath can be a virtual file, so we need to find the first existing path
13+
*
14+
*/
15+
export function getFirstExistingPath(filePath: string): string {
16+
while (!fs.existsSync(filePath)) {
17+
filePath = path.dirname(filePath);
18+
}
19+
return filePath;
20+
}
21+
1022
export function loadOnDiskGraphQLConfig(filePath: string): GraphQLConfig {
1123
return loadConfigSync({
1224
// load config relative to the file being linted
13-
rootDir: path.dirname(filePath),
25+
rootDir: getFirstExistingPath(path.dirname(filePath)),
1426
throwOnMissing: false,
1527
extensions: [codeFileLoaderExtension],
1628
});

packages/plugin/src/parser.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ import { GraphQLProjectConfig, IGraphQLProject } from 'graphql-config';
44
import { parseGraphQLSDL, Source } from '@graphql-tools/utils';
55
import { getDocuments } from './documents.js';
66
import { convertToESTree, extractComments, extractTokens } from './estree-converter/index.js';
7-
import { loadGraphQLConfig } from './graphql-config.js';
7+
import { getFirstExistingPath, loadGraphQLConfig } from './graphql-config.js';
88
import { version } from './meta.js';
99
import { getSchema } from './schema.js';
1010
import { getSiblings } from './siblings.js';
1111
import { GraphQLESLintParseResult, ParserOptions, Schema } from './types.js';
12-
import { CWD, VIRTUAL_DOCUMENT_REGEX } from './utils.js';
12+
import { CWD } from './utils.js';
1313

1414
const debug = debugFactory('graphql-eslint:parser');
1515

@@ -44,11 +44,9 @@ export function parseForESLint(code: string, options: ParserOptions): GraphQLESL
4444
const { document } = parseGraphQLSDL(filePath, code, { noLocation: false });
4545
let project: GraphQLProjectConfig;
4646
let schema: Schema, documents: Source[];
47-
4847
if (typeof window === 'undefined') {
4948
const gqlConfig = loadGraphQLConfig(options);
50-
const realFilepath = filePath.replace(VIRTUAL_DOCUMENT_REGEX, '');
51-
project = gqlConfig.getProjectForFile(realFilepath);
49+
project = gqlConfig.getProjectForFile(getFirstExistingPath(filePath));
5250
documents = getDocuments(project);
5351
} else {
5452
documents = [

packages/plugin/src/processor.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ export const processor = {
2929
},
3030
supportsAutofix: true,
3131
preprocess(code, filePath) {
32+
if (process.env.ESLINT_USE_FLAT_CONFIG !== 'false' && filePath.endsWith('.vue')) {
33+
throw new Error(
34+
"Processing of `.vue` files is no longer supported, follow the new official vue example for ESLint's flat config https://github.com/dimaMachina/graphql-eslint/tree/master/examples/vue-code-file",
35+
);
36+
}
3237
if (!onDiskConfigLoaded) {
3338
onDiskConfig = loadOnDiskGraphQLConfig(filePath);
3439
onDiskConfigLoaded = true;

0 commit comments

Comments
 (0)