-
-
Notifications
You must be signed in to change notification settings - Fork 104
/
parser.ts
121 lines (111 loc) · 3.73 KB
/
parser.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import debugFactory from 'debug';
import { buildSchema, GraphQLError } from 'graphql';
import { GraphQLProjectConfig, IGraphQLProject } from 'graphql-config';
import { parseGraphQLSDL, Source } from '@graphql-tools/utils';
import { getDocuments } from './documents.js';
import { convertToESTree, extractComments, extractTokens } from './estree-converter/index.js';
import { loadGraphQLConfig } from './graphql-config.js';
import { version } from './meta.js';
import { getSchema } from './schema.js';
import { getSiblings } from './siblings.js';
import { GraphQLESLintParseResult, ParserOptions, Schema } from './types.js';
import { CWD, VIRTUAL_DOCUMENT_REGEX } from './utils.js';
const debug = debugFactory('graphql-eslint:parser');
debug('cwd %o', CWD);
const LEGACY_PARSER_OPTIONS_KEYS = [
'schema',
'documents',
'extensions',
'include',
'exclude',
'projects',
'schemaOptions',
'graphQLParserOptions',
'skipGraphQLConfig',
'operations',
] as const;
export function parseForESLint(code: string, options: ParserOptions): GraphQLESLintParseResult {
for (const key of LEGACY_PARSER_OPTIONS_KEYS) {
if (key in options) {
throw new Error(
`\`parserOptions.${key}\` was removed in graphql-eslint@4. Use physical graphql-config for setting schema and documents or \`parserOptions.graphQLConfig\` for programmatic usage.`,
);
}
}
try {
const { filePath } = options;
// First parse code from file, in case of syntax error do not try load schema,
// documents or even graphql-config instance
const { document } = parseGraphQLSDL(filePath, code, { noLocation: false });
let project: GraphQLProjectConfig;
let schema: Schema, documents: Source[];
if (typeof window === 'undefined') {
const gqlConfig = loadGraphQLConfig(options);
const realFilepath = filePath.replace(VIRTUAL_DOCUMENT_REGEX, '');
project = gqlConfig.getProjectForFile(realFilepath);
documents = getDocuments(project);
} else {
documents = [
parseGraphQLSDL(
'operation.graphql',
(options.graphQLConfig as IGraphQLProject).documents as string,
{ noLocation: true },
),
];
}
try {
if (typeof window === 'undefined') {
schema = getSchema(project!);
} else {
schema = buildSchema((options.graphQLConfig as IGraphQLProject).schema as string);
}
} catch (error) {
if (error instanceof Error) {
error.message = `Error while loading schema: ${error.message}`;
}
throw error;
}
const rootTree = convertToESTree(document, schema);
return {
services: {
schema,
siblingOperations: getSiblings(documents),
},
ast: {
comments: extractComments(document.loc),
tokens: extractTokens(filePath, code),
loc: rootTree.loc,
range: rootTree.range as [number, number],
type: 'Program',
sourceType: 'script',
body: [rootTree as any],
},
};
} catch (error) {
if (error instanceof Error) {
error.message = `[graphql-eslint] ${error.message}`;
}
// In case of GraphQL parser error, we report it to ESLint as a parser error that matches the requirements
// of ESLint. This will make sure to display it correctly in IDEs and lint results.
if (error instanceof GraphQLError) {
const location = error.locations?.[0];
const eslintError = {
index: error.positions?.[0],
...(location && {
lineNumber: location.line,
column: location.column - 1,
}),
message: error.message,
};
throw eslintError;
}
throw error;
}
}
export const parser = {
parseForESLint,
meta: {
name: '@graphql-eslint/parser',
version,
},
};