104 lines
2.9 KiB
TypeScript
104 lines
2.9 KiB
TypeScript
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<GenerateDtsOptions>
|
|
): 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}<IN, OUT> extends ICstVisitor<IN, OUT> {
|
|
${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"
|
|
}
|