graphql-language-service-server
Version:
Server process backing the GraphQL Language Service
72 lines (64 loc) • 1.9 kB
text/typescript
import { Position, Range } from 'graphql-language-service';
import { RangeMapper, SourceParser } from './types';
import { babelParser } from './babel';
import { parse } from '@astrojs/compiler';
type ParseAstroResult =
| { type: 'error'; errors: string[] }
| {
type: 'ok';
scriptOffset: number;
scriptAst: any[];
};
async function parseAstro(source: string): Promise<ParseAstroResult> {
const { ast, diagnostics } = await parse(source, {
position: false, // defaults to `true`
});
if (diagnostics.some(d => d.severity === /* Error */ 1)) {
return {
type: 'error',
errors: diagnostics.map(d => JSON.stringify(d)),
};
}
for (const node of ast.children) {
if (node.type === 'frontmatter') {
try {
return {
type: 'ok',
scriptOffset: (node.position?.start.line ?? 1) - 1,
scriptAst: [babelParser(node.value, ['typescript'])],
};
} catch (error) {
return {
type: 'error',
errors: [String(error)],
};
}
}
}
return { type: 'error', errors: ['Could not find frontmatter block'] };
}
export const astroParser: SourceParser = async (text, uri, logger) => {
const parseAstroResult = await parseAstro(text);
if (parseAstroResult.type === 'error') {
logger.info(
`Could not parse the astro file at ${uri} to extract the graphql tags:`,
);
for (const error of parseAstroResult.errors) {
logger.info(error);
}
return null;
}
const rangeMapper: RangeMapper = range => {
return new Range(
new Position(
range.start.line + parseAstroResult.scriptOffset,
range.start.character,
),
new Position(
range.end.line + parseAstroResult.scriptOffset,
range.end.character,
),
);
};
return { asts: parseAstroResult.scriptAst, rangeMapper };
};