import flatten from "lodash/flatten" import isArray from "lodash/isArray" import map from "lodash/map" import reduce from "lodash/reduce" import uniq from "lodash/uniq" import upperFirst from "lodash/upperFirst" import { GenerateDtsOptions } from "@chevrotain/types" import { CstNodeTypeDefinition, PropertyTypeDefinition, PropertyArrayType, TokenArrayType, RuleArrayType } from "./model" export function genDts( model: CstNodeTypeDefinition[], options: Required ): string { let contentParts: string[] = [] contentParts = contentParts.concat( `import type { CstNode, ICstVisitor, IToken } from "chevrotain";` ) contentParts = contentParts.concat( flatten(map(model, (node) => genCstNodeTypes(node))) ) if (options.includeVisitorInterface) { contentParts = contentParts.concat( genVisitor(options.visitorInterfaceName, model) ) } return contentParts.join("\n\n") + "\n" } function genCstNodeTypes(node: CstNodeTypeDefinition) { const nodeCstInterface = genNodeInterface(node) const nodeChildrenInterface = genNodeChildrenType(node) return [nodeCstInterface, nodeChildrenInterface] } function genNodeInterface(node: CstNodeTypeDefinition) { const nodeInterfaceName = getNodeInterfaceName(node.name) const childrenTypeName = getNodeChildrenTypeName(node.name) return `export interface ${nodeInterfaceName} extends CstNode { name: "${node.name}"; children: ${childrenTypeName}; }` } function genNodeChildrenType(node: CstNodeTypeDefinition) { const typeName = getNodeChildrenTypeName(node.name) return `export type ${typeName} = { ${map(node.properties, (property) => genChildProperty(property)).join("\n ")} };` } function genChildProperty(prop: PropertyTypeDefinition) { const typeName = buildTypeString(prop.type) return `${prop.name}${prop.optional ? "?" : ""}: ${typeName}[];` } function genVisitor(name: string, nodes: CstNodeTypeDefinition[]) { return `export interface ${name} extends ICstVisitor { ${map(nodes, (node) => genVisitorFunction(node)).join("\n ")} }` } function genVisitorFunction(node: CstNodeTypeDefinition) { const childrenTypeName = getNodeChildrenTypeName(node.name) return `${node.name}(children: ${childrenTypeName}, param?: IN): OUT;` } function buildTypeString(type: PropertyArrayType) { if (isArray(type)) { const typeNames = uniq(map(type, (t) => getTypeString(t))) const typeString = reduce(typeNames, (sum, t) => sum + " | " + t) return "(" + typeString + ")" } else { return getTypeString(type) } } function getTypeString(type: TokenArrayType | RuleArrayType) { if (type.kind === "token") { return "IToken" } return getNodeInterfaceName(type.name) } function getNodeInterfaceName(ruleName: string) { return upperFirst(ruleName) + "CstNode" } function getNodeChildrenTypeName(ruleName: string) { return upperFirst(ruleName) + "CstChildren" }