graphql-language-service-server
Version:
Server process backing the GraphQL Language Service
179 lines • 6.61 kB
JavaScript
import { Position, Range } from 'graphql-language-service-utils';
import { parse } from '@babel/parser';
const PARSER_OPTIONS = {
allowImportExportEverywhere: true,
allowReturnOutsideFunction: true,
allowSuperOutsideMethod: true,
sourceType: 'module',
strictMode: false,
};
const CREATE_CONTAINER_FUNCTIONS = {
createFragmentContainer: true,
createPaginationContainer: true,
createRefetchContainer: true,
};
const DEFAULT_STABLE_TAGS = ['graphql', 'graphqls', 'gql'];
export const DEFAULT_TAGS = [...DEFAULT_STABLE_TAGS, 'graphql.experimental'];
const BABEL_PLUGINS = [
'jsx',
'doExpressions',
'objectRestSpread',
['decorators', { decoratorsBeforeExport: false }],
'classProperties',
'classPrivateProperties',
'classPrivateMethods',
'exportDefaultFrom',
'exportNamespaceFrom',
'asyncGenerators',
'functionBind',
'functionSent',
'dynamicImport',
'numericSeparator',
'optionalChaining',
'importMeta',
'bigInt',
'optionalCatchBinding',
'throwExpressions',
['pipelineOperator', { proposal: 'minimal' }],
'nullishCoalescingOperator',
'topLevelAwait',
'logicalAssignment',
];
export function findGraphQLTags(text, ext) {
const result = [];
const plugins = BABEL_PLUGINS.slice(0, BABEL_PLUGINS.length);
if (ext === '.ts' || ext === '.tsx') {
plugins === null || plugins === void 0 ? void 0 : plugins.push('typescript');
}
else {
plugins === null || plugins === void 0 ? void 0 : plugins.push('flow', 'flowComments');
}
PARSER_OPTIONS.plugins = plugins;
const ast = parse(text, PARSER_OPTIONS);
const visitors = {
CallExpression: (node) => {
if ('callee' in node) {
const callee = node.callee;
if (!((callee.type === 'Identifier' &&
CREATE_CONTAINER_FUNCTIONS[callee.name]) ||
(callee.kind === 'MemberExpression' &&
callee.object.type === 'Identifier' &&
callee.object.value === 'Relay' &&
callee.property.type === 'Identifier' &&
CREATE_CONTAINER_FUNCTIONS[callee.property.name]))) {
traverse(node, visitors);
return;
}
if ('arguments' in node) {
const fragments = node.arguments[1];
if (fragments.type === 'ObjectExpression') {
fragments.properties.forEach((property) => {
if ('value' in property &&
'loc' in property.value &&
'tag' in property.value) {
const tagName = getGraphQLTagName(property.value.tag);
const template = getGraphQLText(property.value.quasi);
if (tagName && property.value.loc) {
const loc = property.value.loc;
const range = new Range(new Position(loc.start.line - 1, loc.start.column), new Position(loc.end.line - 1, loc.end.column));
result.push({
tag: tagName,
template,
range,
});
}
}
});
}
else if ('tag' in fragments) {
const tagName = getGraphQLTagName(fragments.tag);
const template = getGraphQLText(fragments.quasi);
if (tagName && fragments.loc) {
const loc = fragments.loc;
const range = new Range(new Position(loc.start.line - 1, loc.start.column), new Position(loc.end.line - 1, loc.end.column));
result.push({
tag: tagName,
template,
range,
});
}
}
for (let ii = 2; ii < node.arguments.length; ii++) {
visit(node.arguments[ii], visitors);
}
}
}
},
TaggedTemplateExpression: (node) => {
const tagName = getGraphQLTagName(node.tag);
if (tagName) {
const loc = node.quasi.quasis[0].loc;
if (loc) {
const range = new Range(new Position(loc.start.line - 1, loc.start.column), new Position(loc.end.line - 1, loc.end.column));
result.push({
tag: tagName,
template: node.quasi.quasis[0].value.raw,
range,
});
}
}
},
};
visit(ast, visitors);
return result;
}
const IGNORED_KEYS = {
comments: true,
end: true,
leadingComments: true,
loc: true,
name: true,
start: true,
trailingComments: true,
type: true,
};
function getGraphQLTagName(tag) {
if (tag.type === 'Identifier' &&
DEFAULT_STABLE_TAGS.some(t => t === tag.name)) {
return tag.name;
}
else if (tag.type === 'MemberExpression' &&
tag.object.type === 'Identifier' &&
tag.object.name === 'graphql' &&
tag.property.type === 'Identifier' &&
tag.property.name === 'experimental') {
return 'graphql.experimental';
}
return null;
}
function getGraphQLText(quasi) {
const quasis = quasi.quasis;
return quasis[0].value.raw;
}
function visit(node, visitors) {
const fn = visitors[node.type];
if (fn && fn != null) {
fn(node);
return;
}
traverse(node, visitors);
}
function traverse(node, visitors) {
for (const key in node) {
if (IGNORED_KEYS[key]) {
continue;
}
const prop = node[key];
if (prop && typeof prop === 'object' && typeof prop.type === 'string') {
visit(prop, visitors);
}
else if (Array.isArray(prop)) {
prop.forEach(item => {
if (item && typeof item === 'object' && typeof item.type === 'string') {
visit(item, visitors);
}
});
}
}
}
//# sourceMappingURL=findGraphQLTags.js.map