UNPKG

jsdoc-type-pratt-parser

Version:

[![Npm Package](https://badgen.net/npm/v/jsdoc-type-pratt-parser)](https://www.npmjs.com/package/jsdoc-type-pratt-parser) [![Test Status](https://github.com/jsdoc-type-pratt-parser/jsdoc-type-pratt-parser/actions/workflows/test.yml/badge.svg?branch=main)]

339 lines (285 loc) 8.68 kB
import { extractSpecialParams, notAvailableTransform, transform, type TransformRules } from './transform.js' import { assertRootResult } from '../assertTypes.js' import type { RootResult } from '../result/RootResult.js' import { quote } from './stringify.js' export const reservedWords = [ 'null', 'true', 'false', 'break', 'case', 'catch', 'class', 'const', 'continue', 'debugger', 'default', 'delete', 'do', 'else', 'export', 'extends', 'finally', 'for', 'function', 'if', 'import', 'in', 'instanceof', 'new', 'return', 'super', 'switch', 'this', 'throw', 'try', 'typeof', 'var', 'void', 'while', 'with', 'yield' ] interface ModifiableResult { optional?: boolean nullable?: boolean repeatable?: boolean } export type CatharsisParseResult = CatharsisNameResult | CatharsisUnionResult | CatharsisGenericResult | CatharsisNullResult | CatharsisUndefinedResult | CatharsisAllResult | CatharsisUnknownResult | CatharsisFunctionResult | CatharsisRecordResult | CatharsisFieldResult export type CatharsisNameResult = ModifiableResult & { type: 'NameExpression' name: string reservedWord?: boolean } export type CatharsisUnionResult = ModifiableResult & { type: 'TypeUnion' elements: CatharsisParseResult[] } export type CatharsisGenericResult = ModifiableResult & { type: 'TypeApplication' expression: CatharsisParseResult applications: CatharsisParseResult[] } export type CatharsisNullResult = ModifiableResult & { type: 'NullLiteral' } export type CatharsisUndefinedResult = ModifiableResult & { type: 'UndefinedLiteral' } export type CatharsisAllResult = ModifiableResult & { type: 'AllLiteral' } export type CatharsisUnknownResult = ModifiableResult & { type: 'UnknownLiteral' } export type CatharsisFunctionResult = ModifiableResult & { type: 'FunctionType' params: CatharsisParseResult[] result?: CatharsisParseResult this?: CatharsisParseResult new?: CatharsisParseResult } export type CatharsisFieldResult = ModifiableResult & { type: 'FieldType' key: CatharsisParseResult value: CatharsisParseResult | undefined } export type CatharsisRecordResult = ModifiableResult & { type: 'RecordType' fields: CatharsisFieldResult[] } function makeName (value: string): CatharsisNameResult { const result: CatharsisNameResult = { type: 'NameExpression', name: value } if (reservedWords.includes(value)) { result.reservedWord = true } return result } const catharsisTransformRules: TransformRules<CatharsisParseResult> = { JsdocTypeOptional: (result, transform) => { const transformed = transform(result.element) transformed.optional = true return transformed }, JsdocTypeNullable: (result, transform) => { const transformed = transform(result.element) transformed.nullable = true return transformed }, JsdocTypeNotNullable: (result, transform) => { const transformed = transform(result.element) transformed.nullable = false return transformed }, JsdocTypeVariadic: (result, transform) => { if (result.element === undefined) { throw new Error('dots without value are not allowed in catharsis mode') } const transformed = transform(result.element) transformed.repeatable = true return transformed }, JsdocTypeAny: () => ({ type: 'AllLiteral' }), JsdocTypeNull: () => ({ type: 'NullLiteral' }), JsdocTypeStringValue: result => makeName(quote(result.value, result.meta.quote)), JsdocTypeUndefined: () => ({ type: 'UndefinedLiteral' }), JsdocTypeUnknown: () => ({ type: 'UnknownLiteral' }), JsdocTypeFunction: (result, transform) => { const params = extractSpecialParams(result) const transformed: CatharsisFunctionResult = { type: 'FunctionType', params: params.params.map(transform) } if (params.this !== undefined) { transformed.this = transform(params.this) } if (params.new !== undefined) { transformed.new = transform(params.new) } if (result.returnType !== undefined) { transformed.result = transform(result.returnType) } return transformed }, JsdocTypeGeneric: (result, transform) => ({ type: 'TypeApplication', applications: result.elements.map(o => transform(o)), expression: transform(result.left) }), JsdocTypeSpecialNamePath: result => makeName(result.specialType + ':' + quote(result.value, result.meta.quote)), JsdocTypeName: result => { if (result.value !== 'function') { return makeName(result.value) } else { return { type: 'FunctionType', params: [] } } }, JsdocTypeNumber: result => makeName(result.value.toString()), JsdocTypeObject: (result, transform) => { const transformed: CatharsisRecordResult = { type: 'RecordType', fields: [] } for (const field of result.elements) { if (field.type !== 'JsdocTypeObjectField' && field.type !== 'JsdocTypeJsdocObjectField') { transformed.fields.push({ type: 'FieldType', key: transform(field), value: undefined }) } else { transformed.fields.push(transform(field) as unknown as CatharsisFieldResult) } } return transformed }, JsdocTypeObjectField: (result, transform) => { if (typeof result.key !== 'string') { throw new Error('Index signatures and mapped types are not supported') } return { type: 'FieldType', key: makeName(quote(result.key, result.meta.quote)), value: result.right === undefined ? undefined : transform(result.right) } }, JsdocTypeJsdocObjectField: (result, transform) => ({ type: 'FieldType', key: transform(result.left), value: transform(result.right) }), JsdocTypeUnion: (result, transform) => ({ type: 'TypeUnion', elements: result.elements.map(e => transform(e)) }), JsdocTypeKeyValue: (result, transform) => ({ type: 'FieldType', key: makeName(result.key), value: result.right === undefined ? undefined : transform(result.right) }), JsdocTypeNamePath: (result, transform) => { const leftResult = transform(result.left) as CatharsisNameResult let rightValue if (result.right.type === 'JsdocTypeIndexedAccessIndex') { throw new TypeError('JsdocTypeIndexedAccessIndex is not supported in catharsis') } if (result.right.type === 'JsdocTypeSpecialNamePath') { rightValue = (transform(result.right) as CatharsisNameResult).name } else { rightValue = quote(result.right.value, result.right.meta.quote) } const joiner = result.pathType === 'inner' ? '~' : result.pathType === 'instance' ? '#' : '.' return makeName(`${leftResult.name}${joiner}${rightValue}`) }, JsdocTypeSymbol: result => { let value = '' let element = result.element let trailingDots = false if (element?.type === 'JsdocTypeVariadic') { if (element.meta.position === 'prefix') { value = '...' } else { trailingDots = true } element = element.element } if (element?.type === 'JsdocTypeName') { value += element.value } else if (element?.type === 'JsdocTypeNumber') { value += element.value.toString() } if (trailingDots) { value += '...' } return makeName(`${result.value}(${value})`) }, JsdocTypeParenthesis: (result, transform) => transform(assertRootResult(result.element)), JsdocTypeMappedType: notAvailableTransform, JsdocTypeIndexSignature: notAvailableTransform, JsdocTypeImport: notAvailableTransform, JsdocTypeKeyof: notAvailableTransform, JsdocTypeTuple: notAvailableTransform, JsdocTypeTypeof: notAvailableTransform, JsdocTypeIntersection: notAvailableTransform, JsdocTypeProperty: notAvailableTransform, JsdocTypePredicate: notAvailableTransform, JsdocTypeAsserts: notAvailableTransform, JsdocTypeReadonlyArray: notAvailableTransform, JsdocTypeAssertsPlain: notAvailableTransform, JsdocTypeConditional: notAvailableTransform, JsdocTypeTypeParameter: notAvailableTransform, JsdocTypeCallSignature: notAvailableTransform, JsdocTypeConstructorSignature: notAvailableTransform, JsdocTypeMethodSignature: notAvailableTransform, JsdocTypeIndexedAccessIndex: notAvailableTransform, JsdocTypeTemplateLiteral: notAvailableTransform, JsdocTypeComputedProperty: notAvailableTransform, JsdocTypeComputedMethod: notAvailableTransform } export function catharsisTransform (result: RootResult): CatharsisParseResult { return transform(catharsisTransformRules, result) }