import { Parser } from './Parser.js' import { jsdocGrammar, jsdocNamePathGrammar, jsdocNamePathSpecialGrammar, jsdocNameGrammar } from './grammars/jsdocGrammar.js' import { closureGrammar, closureNamePathGrammar, closureNamePathSpecialGrammar, closureNameGrammar } from './grammars/closureGrammar.js' import { typescriptGrammar, typescriptNamePathGrammar, typescriptNamePathSpecialGrammar, typescriptNameGrammar } from './grammars/typescriptGrammar.js' import { assertResultIsNotReservedWord } from './assertTypes.js' import type { RootResult } from './result/RootResult.js' import { Lexer } from './lexer/Lexer.js' import { rules, looseRules } from './lexer/LexerRules.js' export type ParseMode = 'closure' | 'jsdoc' | 'typescript' /** * This function parses the given expression in the given mode and produces a {@link RootResult}. * @param expression * @param mode */ export function parse ( expression: string, mode: ParseMode, { range = false, rangeStart, loc = false, locStart = { column: 0, line: 1, }, module = true, strictMode = true, asyncFunctionBody = true, classContext = false, computedPropertyParser }: { range?: boolean, rangeStart?: number, loc?: boolean, locStart?: { column: number, line: number, }, module?: boolean, strictMode?: boolean, asyncFunctionBody?: boolean, classContext?: boolean, computedPropertyParser?: ( // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Actual API text: string, options?: any ) => unknown } = {} ): RootResult { let parser: Parser switch (mode) { case 'closure': parser = new Parser(closureGrammar, Lexer.create(looseRules, expression), undefined, { module, strictMode, asyncFunctionBody, classContext, range, rangeStart, loc, locStart }) break case 'jsdoc': parser = new Parser(jsdocGrammar, Lexer.create(looseRules, expression), undefined, { module, strictMode, asyncFunctionBody, classContext, range, rangeStart, loc, locStart }) break case 'typescript': parser = new Parser( typescriptGrammar, Lexer.create(rules, expression), undefined, { module, strictMode, asyncFunctionBody, classContext, range, rangeStart, loc, locStart, externalParsers: { computedPropertyParser } } ) break } const result = parser.parse() return assertResultIsNotReservedWord(parser, result) } /** * This function tries to parse the given expression in multiple modes and returns the first successful * {@link RootResult}. By default it tries `'typescript'`, `'closure'` and `'jsdoc'` in this order. If * no mode was successful it throws the error that was produced by the last parsing attempt. * @param expression * @param modes */ export function tryParse ( expression: string, modes: ParseMode[] = ['typescript', 'closure', 'jsdoc'], { module = true, strictMode = true, asyncFunctionBody = true, classContext = false, range, rangeStart, loc = false, locStart = { column: 0, line: 1, } }: { module?: boolean, strictMode?: boolean, asyncFunctionBody?: boolean, classContext?: boolean, range?: boolean, rangeStart?: number, loc?: boolean, locStart?: { column: number, line: number } } = {} ): RootResult { let error for (const mode of modes) { try { return parse(expression, mode, { module, strictMode, asyncFunctionBody, classContext, range, rangeStart, loc, locStart }) } catch (e) { error = e } } // eslint-disable-next-line @typescript-eslint/only-throw-error -- Ok throw error } /** * This function parses the given expression in the given mode and produces a name path. * @param expression * @param mode */ export function parseNamePath ( expression: string, mode: ParseMode, { includeSpecial = false }: { includeSpecial?: boolean } = {} ): RootResult { switch (mode) { case 'closure': return (new Parser( includeSpecial ? closureNamePathSpecialGrammar : closureNamePathGrammar, Lexer.create(looseRules, expression) )).parse() case 'jsdoc': return (new Parser( includeSpecial ? jsdocNamePathSpecialGrammar : jsdocNamePathGrammar, Lexer.create(looseRules, expression) )).parse() case 'typescript': { return (new Parser( includeSpecial ? typescriptNamePathSpecialGrammar : typescriptNamePathGrammar, Lexer.create(rules, expression) )).parse() } } } /** * This function parses the given expression in the given mode and produces a name. * @param expression * @param mode */ export function parseName ( expression: string, mode: ParseMode ): RootResult { switch (mode) { case 'closure': return (new Parser(closureNameGrammar, Lexer.create(looseRules, expression))).parse() case 'jsdoc': return (new Parser(jsdocNameGrammar, Lexer.create(looseRules, expression))).parse() case 'typescript': return (new Parser( typescriptNameGrammar, Lexer.create(rules, expression) )).parse() } }