jsdoc-type-pratt-parser
Version:
[](https://www.npmjs.com/package/jsdoc-type-pratt-parser) []
93 lines (80 loc) • 3.19 kB
text/typescript
import { composeParslet, type ParsletFunction } from './Parslet.js'
import { Precedence } from '../Precedence.js'
import type { FunctionResult, RootResult } from '../result/RootResult.js'
import type { IntermediateResult } from '../result/IntermediateResult.js'
import type { KeyValueResult, NonRootResult } from '../result/NonRootResult.js'
import { UnexpectedTypeError } from '../errors.js'
import { assertPlainKeyValueOrRootResult } from '../assertTypes.js'
export function getParameters (value: IntermediateResult): Array<RootResult | KeyValueResult> {
let parameters: NonRootResult[] = []
if (value.type === 'JsdocTypeParameterList') {
parameters = value.elements
} else if (value.type === 'JsdocTypeParenthesis') {
parameters = [value.element]
} else {
throw new UnexpectedTypeError(value)
}
return parameters.map(p => assertPlainKeyValueOrRootResult(p))
}
export function getUnnamedParameters (value: IntermediateResult): RootResult[] {
const parameters = getParameters(value)
if (parameters.some(p => p.type === 'JsdocTypeKeyValue')) {
throw new Error('No parameter should be named')
}
return parameters as RootResult[]
}
export function createFunctionParslet ({ allowNamedParameters, allowNoReturnType, allowWithoutParenthesis, allowNewAsFunctionKeyword }: {
allowNamedParameters?: string[]
allowWithoutParenthesis: boolean
allowNoReturnType: boolean
allowNewAsFunctionKeyword: boolean
}): ParsletFunction {
return composeParslet({
name: 'functionParslet',
accept: (type, next) => type === 'function' || (allowNewAsFunctionKeyword && type === 'new' && next === '('),
parsePrefix: parser => {
const newKeyword = parser.consume('new')
parser.consume('function')
const hasParenthesis = parser.lexer.current.type === '('
if (!hasParenthesis) {
if (!allowWithoutParenthesis) {
throw new Error('function is missing parameter list')
}
return {
type: 'JsdocTypeName',
value: 'function'
}
}
let result: FunctionResult = {
type: 'JsdocTypeFunction',
parameters: [],
arrow: false,
constructor: newKeyword,
parenthesis: hasParenthesis
}
const value = parser.parseIntermediateType(Precedence.FUNCTION)
if (allowNamedParameters === undefined) {
result.parameters = getUnnamedParameters(value)
} else if (newKeyword && value.type === 'JsdocTypeFunction' && value.arrow) {
result = value
result.constructor = true
return result
} else {
result.parameters = getParameters(value)
for (const p of result.parameters) {
if (p.type === 'JsdocTypeKeyValue' && (!allowNamedParameters.includes(p.key))) {
throw new Error(`only allowed named parameters are ${allowNamedParameters.join(', ')} but got ${p.type}`)
}
}
}
if (parser.consume(':')) {
result.returnType = parser.parseType(Precedence.PREFIX)
} else {
if (!allowNoReturnType) {
throw new Error('function is missing return type')
}
}
return result
}
})
}