xy-sql-formatter
Version:
Format whitespace in a SQL query to make it more readable
47 lines (39 loc) • 1.59 kB
text/typescript
import nearley from 'nearley';
import Tokenizer from '../lexer/Tokenizer.js';
import { disambiguateTokens } from '../lexer/disambiguateTokens.js';
import { ParamTypes } from '../lexer/TokenizerOptions.js';
import { StatementNode } from './ast.js';
import grammar from './grammar.js';
import LexerAdapter from './LexerAdapter.js';
import { createEofToken } from '../lexer/token.js';
const { Parser: NearleyParser, Grammar } = nearley;
export interface Parser {
parse(sql: string, paramTypesOverrides: ParamTypes): StatementNode[];
}
/**
* Creates a parser object which wraps the setup of Nearley parser
*/
export function createParser(tokenizer: Tokenizer): Parser {
let paramTypesOverrides: ParamTypes = {};
const lexer = new LexerAdapter(chunk => [
...disambiguateTokens(tokenizer.tokenize(chunk, paramTypesOverrides)),
createEofToken(chunk.length),
]);
const parser = new NearleyParser(Grammar.fromCompiled(grammar), { lexer });
return {
parse: (sql: string, paramTypes: ParamTypes) => {
// share paramTypesOverrides with Tokenizer
paramTypesOverrides = paramTypes;
const { results } = parser.feed(sql);
if (results.length === 1) {
return results[0];
} else if (results.length === 0) {
// Ideally we would report a line number where the parser failed,
// but I haven't found a way to get this info from Nearley :(
throw new Error('Parse error: Invalid SQL');
} else {
throw new Error(`Parse error: Ambiguous grammar\n${JSON.stringify(results, undefined, 2)}`);
}
},
};
}