{"version":3,"sources":["converters/to-graphql.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAMlD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAOhD,wBAAgB,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,EAAE,UAAU,CAAC,OAAO,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,eAAe,GAAG,SAAS,GAAG,YAAY,CAmqC7O","file":"to-graphql.d.ts","sourcesContent":["import { format } from '@src/parser/format';\nimport ts from 'typescript';\nimport { ToDataReturn } from './to-data-model';\nimport { FormattedOutputNode, FormattedInputNode, formattedInputField, formattedOutputField, FormattedBasicScalar, FormattedEnumMember, FormattedNode, FormattedUnion, FormattedInputObject, FormattedOutputObject, FormattedEnum, FormattedScalar } from '@src/parser/formatted-model';\nimport { FieldType, Kind, MethodDescriptor, List, Param, MethodDescM, Reference } from '../parser/model';\nimport { relative, dirname } from 'path';\nimport { GraphQLArgumentConfig, GraphQLEnumTypeConfig, GraphQLEnumValueConfig, GraphQLFieldConfig, GraphQLInputFieldConfig, GraphQLInputObjectTypeConfig, GraphQLObjectTypeConfig, GraphQLScalarTypeConfig, GraphQLSchemaConfig, GraphQLUnionTypeConfig } from 'graphql';\nimport { seek } from './seek';\nimport { TargetExtension } from '@src/compile';\nimport { InputField, InputList, InputObject, Kind as ModelKind } from 'tt-model';\nimport { compileAsserts } from '@src/validator/compile-asserts';\nimport Chalk from 'chalk';\n\n/**\n * Generate Graphql schema from data\n */\nexport function toGraphQL(\n\tf: ts.NodeFactory,\n\tsrcFile: ts.SourceFile,\n\t{\n\t\tinput: rootInput,\n\t\toutput: rootOutput,\n\t\trootConfig: rootConfig\n\t}: ReturnType<typeof format>,\n\tpretty: boolean,\n\ttargetExtension: TargetExtension | undefined\n): ToDataReturn {\n\ttype SeekNode = FormattedOutputNode | FormattedInputNode | FieldType | FormattedEnumMember | formattedOutputField | formattedInputField | Param;\n\t/** Enable to Rename entities due to duplication */\n\tlet entityNames = new Set<string>();\n\tfunction uniqueEntityName(entity: FormattedInputObject | FormattedOutputObject | FormattedUnion | FormattedEnum | FormattedScalar) {\n\t\tif (\n\t\t\t(entity.kind === Kind.FORMATTED_INPUT_OBJECT || entity.kind === Kind.FORMATTED_OUTPUT_OBJECT)\n\t\t\t&& entity.fields.length === 0\n\t\t)\n\t\t\tthrow `Missing fields on entity \"${entity.name}\"`;\n\t\tlet escName = entity.escapedName;\n\t\tif (entityNames.has(escName)) {\n\t\t\tconst isInput = entity.kind === Kind.FORMATTED_INPUT_OBJECT;\n\t\t\tif (isInput) escName += 'Input';\n\t\t\tlet i = 0, escName2 = escName;\n\t\t\twhile (entityNames.has(escName)) {\n\t\t\t\tescName = `${escName2}_${++i}`;\n\t\t\t}\n\t\t\tconsole.warn(Chalk.yellow(`>> Renamed ${isInput ? 'Input' : 'Output'} Entity \"${entity.escapedName}\" to \"${escName}\" due to duplication`));\n\t\t\tentity.escapedName = escName;\n\t\t}\n\t\tentityNames.add(escName);\n\t}\n\t/** srcFile path */\n\tconst srcFilePath = srcFile.fileName;\n\t/** Create root wrappers */\n\tconst RootWrappersIdentifier = rootConfig.wrappers.length === 0 ? undefined : f.createUniqueName('wrap');\n\t/** Validation schema declarations by the API */\n\tconst inputDeclarations: ts.VariableDeclaration[] = [];\n\t/** Graphql types declaration */\n\tconst graphqlDeclarations: ts.VariableDeclaration[] = [];\n\t/** Graphql imports */\n\tconst gqlImports: Map<string, ts.Identifier> = new Map();\n\tconst GraphQLSchema = _gqlImport('GraphQLSchema');\n\tconst GraphQLNonNull = _gqlImport('GraphQLNonNull');\n\tconst GraphQLList = _gqlImport('GraphQLList');\n\tconst GraphQLObjectType = _gqlImport('GraphQLObjectType');\n\tconst GraphQLInputObjectType = _gqlImport('GraphQLInputObjectType');\n\tconst GraphQLUnionType = _gqlImport('GraphQLUnionType');\n\t/** Import from tt-model */\n\tconst ttModelImports: Map<string, ts.Identifier> = new Map();\n\t// Validation function\n\tconst inputValidationWrapperId = _ttModelImport('pipeInputGQL');\n\tconst ttModelError = _ttModelImport('ModelError');\n\tconst ttModelErrorCode = _ttModelImport('ErrorCodes');\n\t//* Other imports\n\ttype srcImportEntry = Map<string, { varName: ts.Identifier; isClass: boolean }>;\n\tconst srcImports: Map<string, srcImportEntry> = new Map();\n\t/** Create class objects */\n\tconst importCreateObjects: ts.VariableDeclaration[] = [];\n\t/** Reduce identifiers (example: non null strings) */\n\tconst reduceRequiredIds = new Map<ts.Expression, ts.Expression>();\n\t//* Go through Model\n\tconst queue: SeekNode[] = [];\n\t/** Is node visited for first time (as 0) or second time (as 1) */\n\tlet node: FormattedOutputNode | undefined;\n\tif (node = rootOutput.get('Subscription')) { queue.push(node); }\n\tif (node = rootOutput.get('Mutation')) { queue.push(node); }\n\tif (node = rootOutput.get('Query')) { queue.push(node); }\n\t//* Create schema\n\t/** Map entities to their vars */\n\tconst mapEntityVar: Map<SeekNode, ts.Identifier> = new Map();\n\t/** Circles queue */\n\tconst circlesQueue: CircleQueueItem[] = [];\n\t/** Seek validation */\n\tconst seekVldCircle: Set<FormattedInputNode> = new Set();\n\tconst mapVldEntityVar: Map<string, ts.Identifier | false> = new Map();\n\tconst circlesVldQueue: CircleQueueItem[] = [];\n\t/** Go through nodes */\n\tconst seekCircle: Set<FormattedOutputNode | FormattedInputNode> = new Set();\n\tseek<SeekNode, SeekOutputData>(queue, _seekOutputDown, _seekOutputUp);\n\t//* Add circle fields\n\tconst circleStatementsBlock: ts.Statement[] = [];\n\tfor (let i = 0, len = circlesQueue.length; i < len; ++i) {\n\t\tlet item = circlesQueue[i];\n\t\tswitch (item.type) {\n\t\t\tcase Kind.OUTPUT_FIELD: {\n\t\t\t\tlet { field } = item;\n\t\t\t\t// Type\n\t\t\t\tlet fieldConf: { [k in keyof GraphQLFieldConfig<any, any, any>]: any } = {\n\t\t\t\t\ttype: ResolveCircleFieldType(field)\n\t\t\t\t};\n\t\t\t\t// Other info\n\t\t\t\tif (field.deprecated) fieldConf.deprecationReason = field.deprecated;\n\t\t\t\tif (field.jsDoc) fieldConf.description = field.jsDoc;\n\t\t\t\tif (field.method) {\n\t\t\t\t\tfieldConf.resolve = _wrapResolver(field.method, field.param);\n\t\t\t\t\tif (field.param != null && field.param.type != null) {\n\t\t\t\t\t\tfieldConf.args = _fieldArg(field.param);\n\t\t\t\t\t}\n\t\t\t\t} else if (field.alias) {\n\t\t\t\t\tfieldConf.resolve = _resolveOutputAlias(field.name);\n\t\t\t\t}\n\t\t\t\tcircleStatementsBlock.push(_affect(\n\t\t\t\t\tf.createPropertyAccessExpression(item.varId, field.alias ?? field.name),\n\t\t\t\t\t_serializeObject(fieldConf)\n\t\t\t\t));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Kind.INPUT_FIELD: {\n\t\t\t\tlet { field } = item;\n\t\t\t\t// Type\n\t\t\t\tlet fieldConf: { [k in keyof GraphQLInputFieldConfig]: any } = {\n\t\t\t\t\ttype: ResolveCircleFieldType(field)\n\t\t\t\t};\n\t\t\t\t// Other info\n\t\t\t\tif (field.deprecated) fieldConf.deprecationReason = field.deprecated;\n\t\t\t\tif (field.jsDoc) fieldConf.description = field.jsDoc;\n\t\t\t\tcircleStatementsBlock.push(_affect(\n\t\t\t\t\tf.createPropertyAccessExpression(item.varId, field.alias ?? field.name),\n\t\t\t\t\t_serializeObject(fieldConf)\n\t\t\t\t));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Kind.UNION: {\n\t\t\t\tlet { varId, union, isInput } = item;\n\t\t\t\t// Check for circles\n\t\t\t\tconst types: ts.Expression[] = [];\n\t\t\t\tfor (let i = 0, refs = union.types, len = refs.length; i < len; ++i) {\n\t\t\t\t\tlet ref = refs[i];\n\t\t\t\t\tlet refEntity = isInput ? rootOutput.get(ref.name) : rootOutput.get(ref.name);\n\t\t\t\t\tif (refEntity == null) throw `Missing ${isInput ? 'input' : 'output'} entity \"${ref.name}\" using union reference at ${ref.fileName}`;\n\t\t\t\t\ttypes.push(mapEntityVar.get(refEntity)!);\n\t\t\t\t}\n\t\t\t\tcircleStatementsBlock.push(\n\t\t\t\t\tf.createExpressionStatement(f.createCallExpression(\n\t\t\t\t\t\tf.createPropertyAccessExpression(varId, \"push\"), undefined, types\n\t\t\t\t\t))\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tlet c: never = item;\n\t\t\t}\n\t\t}\n\t}\n\t//* Add Input validation circle fields\n\tif (circlesVldQueue.length > 0) {\n\t\tlet values: Map<ts.Identifier, ts.Expression[]> = new Map();\n\t\tfor (let i = 0, len = circlesVldQueue.length; i < len; ++i) {\n\t\t\tlet item = circlesVldQueue[i];\n\t\t\tif (item.type != Kind.INPUT_FIELD) throw new Error(`Unexpected input validation kind \"${Kind[item.type]}\"`);\n\t\t\tlet confExpr = seek<SeekVldNode, SeekOutputData>([item.field], _seekValidationDown, _seekValidationUp)[0] as ts.Expression;\n\t\t\t// Group\n\t\t\tlet grp = values.get(item.varId);\n\t\t\tif (grp == null) values.set(item.varId, [confExpr]);\n\t\t\telse grp.push(confExpr);\n\t\t}\n\t\tvalues.forEach((arr, varId) => {\n\t\t\tcircleStatementsBlock.push(\n\t\t\t\tf.createExpressionStatement(f.createCallExpression(\n\t\t\t\t\tf.createPropertyAccessExpression(varId, 'push'), undefined, arr\n\t\t\t\t))\n\t\t\t);\n\t\t});\n\t}\n\t//* Imports\n\tconst imports = _genImports(); // Generate imports from src\n\timports.push(\n\t\t_genImportDeclaration('graphql', gqlImports), // Graphql imports\n\t\t_genImportDeclaration('tt-model', ttModelImports) // tt-model imports\n\t);\n\n\t//* Create block statement\n\tconst statementsBlock: ts.Statement[] = [];\n\tif (importCreateObjects.length > 0)\n\t\tstatementsBlock.push(f.createVariableStatement(\n\t\t\tundefined, f.createVariableDeclarationList(importCreateObjects)\n\t\t));\n\tif (inputDeclarations.length > 0)\n\t\tstatementsBlock.push(f.createVariableStatement(\n\t\t\tundefined, f.createVariableDeclarationList(inputDeclarations)\n\t\t));\n\tif (graphqlDeclarations.length > 0)\n\t\tstatementsBlock.push(f.createVariableStatement(\n\t\t\tundefined, f.createVariableDeclarationList(graphqlDeclarations)\n\t\t));\n\tif (circleStatementsBlock.length) statementsBlock.push(...circleStatementsBlock);\n\n\t//* Add return statement\n\tconst gqlSchema: { [k in keyof GraphQLSchemaConfig]: ts.Identifier } = {};\n\t// Query\n\tlet q: ts.Identifier | undefined;\n\tlet rEnt: SeekNode | undefined;\n\tif ((rEnt = rootOutput.get('Query')) && (q = mapEntityVar.get(rEnt))) gqlSchema.query = q;\n\tif ((rEnt = rootOutput.get('Mutation')) && (q = mapEntityVar.get(rEnt))) gqlSchema.mutation = q;\n\tif ((rEnt = rootOutput.get('Subscription')) && (q = mapEntityVar.get(rEnt))) gqlSchema.subscription = q;\n\tstatementsBlock.push(f.createReturnStatement(\n\t\tf.createNewExpression(GraphQLSchema, undefined, [\n\t\t\t_serializeObject(gqlSchema)\n\t\t])\n\t));\n\t//* Add root wrappers\n\tif (RootWrappersIdentifier != null) {\n\t\tstatementsBlock.push(_genWrappers(rootConfig.wrappers, RootWrappersIdentifier));\n\t}\n\t//* Return\n\treturn {\n\t\timports,\n\t\tnode: f.createCallExpression(\n\t\t\tf.createParenthesizedExpression(f.createFunctionExpression(\n\t\t\t\tundefined, undefined, undefined, undefined, [], undefined,\n\t\t\t\tf.createBlock(statementsBlock, pretty)\n\t\t\t)), undefined, []\n\t\t)\n\t};\n\t/** Generate GraphQL import */\n\tfunction _gqlImport(name: string) {\n\t\tlet id = gqlImports.get(name);\n\t\tif (id == null) {\n\t\t\tid = f.createUniqueName(name);\n\t\t\tgqlImports.set(name, id);\n\t\t}\n\t\treturn id;\n\t}\n\t/** Generate tt-model import */\n\tfunction _ttModelImport(name: string) {\n\t\tlet id = ttModelImports.get(name);\n\t\tif (id == null) {\n\t\t\tid = f.createUniqueName(name);\n\t\t\tttModelImports.set(name, id);\n\t\t}\n\t\treturn id;\n\t}\n\t/** Generate import declaration for graphQl & tt-model */\n\tfunction _genImportDeclaration(packageName: string, map: Map<string, ts.Identifier>) {\n\t\tconst specifiers: ts.ImportSpecifier[] = [];\n\t\tmap.forEach((id, name) => {\n\t\t\tspecifiers.push(\n\t\t\t\tf.createImportSpecifier(false, f.createIdentifier(name), id)\n\t\t\t);\n\t\t});\n\t\treturn f.createImportDeclaration(\n\t\t\tundefined, undefined,\n\t\t\tf.createImportClause(\n\t\t\t\tfalse, undefined,\n\t\t\t\tf.createNamedImports(specifiers)\n\t\t\t), f.createStringLiteral(packageName)\n\t\t)\n\t}\n\t/** Local import */\n\tfunction _import(method: MethodDescM) {\n\t\tvar fl = srcImports.get(method.fileName);\n\t\tif (fl == null) {\n\t\t\tfl = new Map();\n\t\t\tsrcImports.set(method.fileName, fl);\n\t\t}\n\t\tvar vr = fl.get(method.className);\n\t\tif (vr == null) {\n\t\t\tvr = {\n\t\t\t\tvarName: f.createUniqueName(method.className),\n\t\t\t\tisClass: (method as MethodDescriptor).isClass\n\t\t\t};\n\t\t\tfl.set(method.className, vr);\n\t\t}\n\t\treturn vr.varName;\n\t}\n\t/** Generate Local imports */\n\tfunction _genImports() {\n\t\tconst imports: ts.ImportDeclaration[] = [];\n\t\tconst srcFileDir = dirname(srcFilePath);\n\t\tconst ext = targetExtension ?? '';\n\t\tsrcImports.forEach((entry, filename) => {\n\t\t\tconst specifiers: ts.ImportSpecifier[] = [];\n\t\t\tentry.forEach(({ isClass, varName }, className) => {\n\t\t\t\tif (isClass) {\n\t\t\t\t\tlet isp = f.createUniqueName(className);\n\t\t\t\t\tspecifiers.push(\n\t\t\t\t\t\tf.createImportSpecifier(false, f.createIdentifier(className), isp)\n\t\t\t\t\t);\n\t\t\t\t\t// Create var\n\t\t\t\t\timportCreateObjects.push(\n\t\t\t\t\t\tf.createVariableDeclaration(\n\t\t\t\t\t\t\tvarName, undefined, undefined,\n\t\t\t\t\t\t\tf.createNewExpression(isp, undefined, [])\n\t\t\t\t\t\t)\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tspecifiers.push(\n\t\t\t\t\t\tf.createImportSpecifier(false, f.createIdentifier(className), varName)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t});\n\t\t\t// imports\n\t\t\timports.push(\n\t\t\t\tf.createImportDeclaration(\n\t\t\t\t\tundefined, undefined,\n\t\t\t\t\tf.createImportClause(\n\t\t\t\t\t\tfalse, undefined,\n\t\t\t\t\t\tf.createNamedImports(specifiers)\n\t\t\t\t\t),\n\t\t\t\t\tf.createStringLiteral(\n\t\t\t\t\t\t_relative(srcFileDir, filename.replace(/\\.tsx?$/, ext))\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t);\n\t\t});\n\t\treturn imports;\n\t}\n\t/** serialize object */\n\tfunction _serializeObject(\n\t\tobj: Record<string, ts.Expression | string | number | boolean | undefined>\n\t) {\n\t\tvar fieldArr: ts.ObjectLiteralElementLike[] = [];\n\t\tfor (let k in obj) {\n\t\t\tlet v = obj[k];\n\t\t\tif ((v as ts.Expression)?.kind === ts.SyntaxKind.MethodDeclaration) {\n\t\t\t\tfieldArr.push(v as any as ts.MethodDeclaration);\n\t\t\t} else {\n\t\t\t\tif (v == null) v = f.createIdentifier('undefined');\n\t\t\t\telse if (typeof v === 'string') v = f.createStringLiteral(v);\n\t\t\t\telse if (typeof v === 'number') v = f.createNumericLiteral(v);\n\t\t\t\telse if (typeof v === 'boolean')\n\t\t\t\t\tv = v === true ? f.createTrue() : f.createFalse();\n\t\t\t\tfieldArr.push(f.createPropertyAssignment(f.createIdentifier(k), v));\n\t\t\t}\n\t\t}\n\t\treturn f.createObjectLiteralExpression(fieldArr, pretty);\n\t}\n\n\t/** Seek down */\n\tfunction _seekOutputDown(node: SeekNode, isInput: boolean, parentNode: SeekNode | undefined): SeekNode[] | { nodes: SeekNode[], isInput: boolean } | undefined {\n\t\tswitch (node.kind) {\n\t\t\tcase Kind.FORMATTED_OUTPUT_OBJECT: {\n\t\t\t\t// Add entity to circle check\n\t\t\t\tseekCircle.add(node);\n\t\t\t\treturn node.fields;\n\t\t\t}\n\t\t\tcase Kind.FORMATTED_INPUT_OBJECT: {\n\t\t\t\t// Add entity to circle check\n\t\t\t\tseekCircle.add(node);\n\t\t\t\treturn node.fields;\n\t\t\t}\n\t\t\tcase Kind.OUTPUT_FIELD: {\n\t\t\t\treturn node.param == null ? [node.type] : [node.type, node.param];\n\t\t\t}\n\t\t\tcase Kind.INPUT_FIELD: {\n\t\t\t\treturn node.type == null ? undefined : [node.type];\n\t\t\t}\n\t\t\tcase Kind.PARAM: {\n\t\t\t\t// return node.type == null ? undefined : { isInput: true, nodes: [node.type] };\n\t\t\t\t// return undefined;\n\t\t\t\tlet ref = node.type;\n\t\t\t\tif (ref != null) {\n\t\t\t\t\tlet entity = rootInput.get(ref.name);\n\t\t\t\t\tlet returnValue: FieldType[] = [];\n\t\t\t\t\tif (entity == null) throw `Missing input entity ${ref.name}`;\n\t\t\t\t\tif (entity.kind !== Kind.FORMATTED_INPUT_OBJECT)\n\t\t\t\t\t\tthrow `Entity param \"${ref.name}\" expected input object. Got ${Kind[entity.kind]} at ${ref.fileName}`;\n\t\t\t\t\tfor (let i = 0, fields = entity.fields, len = fields.length; i < len; ++i) {\n\t\t\t\t\t\treturnValue.push(fields[i].type);\n\t\t\t\t\t}\n\t\t\t\t\treturn { isInput: true, nodes: returnValue };\n\t\t\t\t}\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tcase Kind.UNION: {\n\t\t\t\t// Add entity to circle check\n\t\t\t\tseekCircle.add(node);\n\t\t\t\treturn node.types;\n\t\t\t}\n\t\t\tcase Kind.ENUM: return node.members;\n\t\t\tcase Kind.LIST: return [node.type];\n\t\t\tcase Kind.REF: {\n\t\t\t\tlet entity = _getEntity(node, isInput);\n\t\t\t\tif (mapEntityVar.has(entity)) return undefined;\n\t\t\t\tif (seekCircle.has(entity)) return undefined; // Circular\n\t\t\t\treturn [entity];\n\t\t\t}\n\t\t\tcase Kind.SCALAR:\n\t\t\tcase Kind.BASIC_SCALAR:\n\t\t\tcase Kind.ENUM_MEMBER:\n\t\t\t\treturn undefined;\n\t\t\tdefault: {\n\t\t\t\tlet _never: never = node;\n\t\t\t\tthrow _never;\n\t\t\t}\n\t\t}\n\t}\n\t/**\n\t * Seek up\n\t * Returns each time the identifier to the var of this node and if has circle from reference\n\t * @return {node: ts.Node, hasCircle:boolean}\n\t */\n\tfunction _seekOutputUp(entity: SeekNode, isInput: boolean, parentNode: SeekNode | undefined, childrenData: SeekOutputData[]): SeekOutputData {\n\t\tvar varId: SeekOutputData;\n\t\tswitch (entity.kind) {\n\t\t\tcase Kind.FORMATTED_OUTPUT_OBJECT: {\n\t\t\t\t// Remove entity from circle check\n\t\t\t\tseekCircle.delete(entity);\n\t\t\t\t// Deduplicate Entity Name\n\t\t\t\tuniqueEntityName(entity);\n\t\t\t\t// Check for circles\n\t\t\t\tconst fields: ts.PropertyAssignment[] = [];\n\t\t\t\tconst circleFields: formattedOutputField[] = []\n\t\t\t\tfor (let i = 0, arr = entity.fields, len = arr.length; i < len; ++i) {\n\t\t\t\t\tlet field = childrenData[i] as ts.PropertyAssignment;\n\t\t\t\t\tif (field == null) circleFields.push(arr[i]);\n\t\t\t\t\telse fields.push(field);\n\t\t\t\t}\n\t\t\t\t// Create fields\n\t\t\t\tlet objFields: ts.Expression = f.createObjectLiteralExpression(fields, pretty);\n\t\t\t\tif (circleFields.length) {\n\t\t\t\t\tlet fieldsVar = f.createUniqueName(`${entity.escapedName}_fields`);\n\t\t\t\t\tgraphqlDeclarations.push(\n\t\t\t\t\t\tf.createVariableDeclaration(\n\t\t\t\t\t\t\tfieldsVar, undefined, undefined, objFields\n\t\t\t\t\t\t)\n\t\t\t\t\t);\n\t\t\t\t\tobjFields = fieldsVar;\n\t\t\t\t\t// Add to circle queue\n\t\t\t\t\tfor (let i = 0, len = circleFields.length; i < len; ++i) {\n\t\t\t\t\t\tcirclesQueue.push({\n\t\t\t\t\t\t\ttype: Kind.OUTPUT_FIELD, node: entity, field: circleFields[i], varId: fieldsVar\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Create object\n\t\t\t\tlet entityConf: { [k in keyof GraphQLObjectTypeConfig<any, any>]: any } = {\n\t\t\t\t\tname: entity.escapedName,\n\t\t\t\t\tfields: objFields\n\t\t\t\t};\n\t\t\t\tif (entity.jsDoc) entityConf.description = entity.jsDoc;\n\t\t\t\tlet vName = varId = f.createUniqueName(entity.escapedName);\n\t\t\t\tgraphqlDeclarations.push(\n\t\t\t\t\tf.createVariableDeclaration(\n\t\t\t\t\t\tvName, undefined, undefined,\n\t\t\t\t\t\tf.createNewExpression(GraphQLObjectType, undefined, [\n\t\t\t\t\t\t\t_serializeObject(entityConf)\n\t\t\t\t\t\t])\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t\t// Add var\n\t\t\t\tmapEntityVar.set(entity, vName);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Kind.OUTPUT_FIELD: {\n\t\t\t\t//* Type\n\t\t\t\tvarId = childrenData[0] as ts.Expression | undefined; // \"undefined\" means has circular to parents\n\t\t\t\tif (varId != null) {\n\t\t\t\t\t// Type\n\t\t\t\t\tif (entity.required) varId = genRequiredExpr(varId, 'required' + entity.name);\n\t\t\t\t\tlet fieldConf: { [k in keyof GraphQLFieldConfig<any, any, any>]: any } = {\n\t\t\t\t\t\ttype: varId\n\t\t\t\t\t};\n\t\t\t\t\t// Other info\n\t\t\t\t\tif (entity.deprecated) fieldConf.deprecationReason = entity.deprecated;\n\t\t\t\t\tif (entity.jsDoc) fieldConf.description = entity.jsDoc;\n\t\t\t\t\tif (entity.method) {\n\t\t\t\t\t\tfieldConf.resolve = _wrapResolver(entity.method, entity.param);\n\t\t\t\t\t\tlet paramId = childrenData[1] as ts.Expression | undefined; // \"undefined\" means has no param\n\t\t\t\t\t\tif (paramId != null) fieldConf.args = paramId;\n\t\t\t\t\t} else if (entity.alias) {\n\t\t\t\t\t\tfieldConf.resolve = _resolveOutputAlias(entity.name);\n\t\t\t\t\t}\n\t\t\t\t\tvarId = f.createPropertyAssignment(entity.alias ?? entity.name, _serializeObject(fieldConf));\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Kind.FORMATTED_INPUT_OBJECT: {\n\t\t\t\t// Remove entity from circle check\n\t\t\t\tseekCircle.delete(entity);\n\t\t\t\t// Deduplicate Entity Name\n\t\t\t\tuniqueEntityName(entity);\n\t\t\t\t// Check for circles\n\t\t\t\tconst fields: ts.PropertyAssignment[] = [];\n\t\t\t\tconst circleFields: formattedInputField[] = []\n\t\t\t\tfor (let i = 0, arr = entity.fields, len = arr.length; i < len; ++i) {\n\t\t\t\t\tlet field = childrenData[i] as ts.PropertyAssignment;\n\t\t\t\t\tif (field == null) circleFields.push(arr[i]);\n\t\t\t\t\telse fields.push(field);\n\t\t\t\t}\n\t\t\t\t// Create fields\n\t\t\t\tlet objFields: ts.Expression = f.createObjectLiteralExpression(fields, pretty);\n\t\t\t\tif (circleFields.length) {\n\t\t\t\t\tlet fieldsVar = f.createUniqueName(`${entity.escapedName}_fields`);\n\t\t\t\t\tgraphqlDeclarations.push(\n\t\t\t\t\t\tf.createVariableDeclaration(\n\t\t\t\t\t\t\tfieldsVar, undefined, undefined, objFields\n\t\t\t\t\t\t)\n\t\t\t\t\t);\n\t\t\t\t\tobjFields = fieldsVar;\n\t\t\t\t\t// Add to circle queue\n\t\t\t\t\tfor (let i = 0, len = circleFields.length; i < len; ++i) {\n\t\t\t\t\t\tcirclesQueue.push({\n\t\t\t\t\t\t\ttype: Kind.INPUT_FIELD, node: entity, field: circleFields[i], varId: fieldsVar\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Create object\n\t\t\t\tlet entityConf: { [k in keyof GraphQLInputObjectTypeConfig]: any } = {\n\t\t\t\t\tname: entity.escapedName,\n\t\t\t\t\tfields: objFields\n\t\t\t\t};\n\t\t\t\tif (entity.jsDoc) entityConf.description = entity.jsDoc;\n\t\t\t\tlet vName = varId = f.createUniqueName(entity.escapedName);\n\t\t\t\tgraphqlDeclarations.push(\n\t\t\t\t\tf.createVariableDeclaration(\n\t\t\t\t\t\tvName, undefined, undefined,\n\t\t\t\t\t\tf.createNewExpression(GraphQLInputObjectType, undefined, [\n\t\t\t\t\t\t\t_serializeObject(entityConf)\n\t\t\t\t\t\t])\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t\t// Add var\n\t\t\t\tmapEntityVar.set(entity, vName);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Kind.PARAM: {\n\t\t\t\tif (childrenData.length > 0) {\n\t\t\t\t\tvarId = _fieldArg(entity);\n\t\t\t\t} else varId = undefined;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Kind.INPUT_FIELD: {\n\t\t\t\t//* Type\n\t\t\t\tvarId = childrenData[0] as ts.Expression | undefined; // \"undefined\" means has circular to parents\n\t\t\t\tif (varId != null) {\n\t\t\t\t\t// Type\n\t\t\t\t\tif (entity.required) varId = genRequiredExpr(varId, 'required' + entity.name);\n\t\t\t\t\tlet fieldConf: { [k in keyof GraphQLInputFieldConfig]: any } = {\n\t\t\t\t\t\ttype: varId\n\t\t\t\t\t};\n\t\t\t\t\t// Other info\n\t\t\t\t\tif (entity.defaultValue) fieldConf.defaultValue = f.createIdentifier(entity.defaultValue);\n\t\t\t\t\tif (entity.deprecated) fieldConf.deprecationReason = entity.deprecated;\n\t\t\t\t\tif (entity.jsDoc) fieldConf.description = entity.jsDoc;\n\t\t\t\t\tvarId = f.createPropertyAssignment(entity.alias ?? entity.name, _serializeObject(fieldConf));\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Kind.UNION: {\n\t\t\t\t// Remove entity from circle check\n\t\t\t\tseekCircle.delete(entity);\n\t\t\t\t// Deduplicate Entity Name\n\t\t\t\tuniqueEntityName(entity);\n\t\t\t\tlet typesArr: ts.Identifier = f.createUniqueName(`${entity.escapedName}_types`);\n\t\t\t\tlet types: ts.Expression[];\n\t\t\t\t// Check if has circles\n\t\t\t\tif (childrenData.some(e => e == null)) {\n\t\t\t\t\t//* Has circles\n\t\t\t\t\tcirclesQueue.push({ type: Kind.UNION, union: entity, varId: typesArr, isInput });\n\t\t\t\t\ttypes = [];\n\t\t\t\t} else {\n\t\t\t\t\t//* Has no circle\n\t\t\t\t\ttypes = childrenData as ts.Expression[];\n\t\t\t\t}\n\t\t\t\t// Create types list\n\t\t\t\tgraphqlDeclarations.push(\n\t\t\t\t\tf.createVariableDeclaration(\n\t\t\t\t\t\ttypesArr, undefined, undefined,\n\t\t\t\t\t\tf.createArrayLiteralExpression(types, pretty)\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t\t// create union\n\t\t\t\tif (entity.parser == null) throw `Missing resolver for UNION \"${entity.name}\"`;\n\t\t\t\tlet entityConf: { [k in keyof GraphQLUnionTypeConfig<any, any>]: any } = {\n\t\t\t\t\tname: entity.escapedName,\n\t\t\t\t\ttypes: typesArr,\n\t\t\t\t\tresolveType: _createMethod('resolveType', ['value', 'ctx', 'info'], [\n\t\t\t\t\t\tf.createReturnStatement(f.createElementAccessExpression(\n\t\t\t\t\t\t\ttypesArr,\n\t\t\t\t\t\t\t_callExpression(\n\t\t\t\t\t\t\t\tf.createPropertyAccessExpression(\n\t\t\t\t\t\t\t\t\t_import(entity.parser),\n\t\t\t\t\t\t\t\t\tf.createIdentifier('resolveType')\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t, ['value', 'ctx', 'info'])\n\t\t\t\t\t\t))\n\t\t\t\t\t])\n\t\t\t\t};\n\t\t\t\tif (entity.jsDoc) entityConf.description = entity.jsDoc;\n\t\t\t\tlet vName = varId = f.createUniqueName(entity.escapedName);\n\t\t\t\tgraphqlDeclarations.push(\n\t\t\t\t\tf.createVariableDeclaration(\n\t\t\t\t\t\tvName, undefined, undefined,\n\t\t\t\t\t\tf.createNewExpression(GraphQLUnionType, undefined, [\n\t\t\t\t\t\t\t_serializeObject(entityConf)\n\t\t\t\t\t\t])\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t\t// Add var\n\t\t\t\tmapEntityVar.set(entity, vName);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Kind.LIST: {\n\t\t\t\tvarId = childrenData[0] as ts.Expression | undefined; // \"undefined\" means has circular to parents\n\t\t\t\tif (varId != null) {\n\t\t\t\t\tif (entity.required) varId = genRequiredExpr(varId, 'requiredList');\n\t\t\t\t\tvarId = f.createNewExpression(GraphQLList, undefined, [varId]);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Kind.REF: {\n\t\t\t\tvarId = childrenData[0]; // \"undefined\" means has circular to parents\n\t\t\t\tif (varId == null) {\n\t\t\t\t\tlet refEntity = _getEntity(entity, isInput);\n\t\t\t\t\tvarId = mapEntityVar.get(refEntity);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Kind.ENUM_MEMBER: {\n\t\t\t\tlet memberConf: { [k in keyof GraphQLEnumValueConfig]: any } = {\n\t\t\t\t\tvalue: entity.value\n\t\t\t\t};\n\t\t\t\tif (entity.jsDoc) memberConf.description = entity.jsDoc;\n\t\t\t\tif (entity.deprecated) memberConf.deprecationReason = entity.deprecated;\n\t\t\t\tvarId = f.createPropertyAssignment(\n\t\t\t\t\tentity.name,\n\t\t\t\t\t_serializeObject(memberConf)\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Kind.ENUM: {\n\t\t\t\t// Deduplicate Entity Name\n\t\t\t\tuniqueEntityName(entity);\n\t\t\t\tlet varName = f.createUniqueName(entity.escapedName);\n\t\t\t\tvarId = varName;\n\t\t\t\tlet entityConf: { [k in keyof GraphQLEnumTypeConfig]: any; } = {\n\t\t\t\t\tname: entity.escapedName,\n\t\t\t\t\tvalues: f.createObjectLiteralExpression(\n\t\t\t\t\t\tchildrenData as ts.PropertyAssignment[],\n\t\t\t\t\t\tpretty\n\t\t\t\t\t)\n\t\t\t\t};\n\t\t\t\tif (entity.jsDoc) entityConf.description = entity.jsDoc;\n\t\t\t\tgraphqlDeclarations.push(\n\t\t\t\t\tf.createVariableDeclaration(\n\t\t\t\t\t\tvarName, undefined, undefined,\n\t\t\t\t\t\tf.createNewExpression(_gqlImport('GraphQLEnumType'), undefined, [\n\t\t\t\t\t\t\t_serializeObject(entityConf)\n\t\t\t\t\t\t])\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t\t// Add var\n\t\t\t\tmapEntityVar.set(entity, varName);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Kind.SCALAR: {\n\t\t\t\t// Deduplicate Entity Name\n\t\t\t\tuniqueEntityName(entity);\n\t\t\t\tlet varName = f.createUniqueName(entity.escapedName);\n\t\t\t\tvarId = varName;\n\t\t\t\tlet parserVar = _import(entity.parser);\n\t\t\t\tlet scalarConf: { [k in keyof GraphQLScalarTypeConfig<any, any>]: any; } = {\n\t\t\t\t\tname: entity.escapedName,\n\t\t\t\t\tparseValue: _getMethodCall(parserVar, entity.parser, 'parse'),\n\t\t\t\t\tserialize: _getMethodCall(parserVar, entity.parser, 'serialize')\n\t\t\t\t};\n\t\t\t\tif (entity.jsDoc) scalarConf.description = entity.jsDoc;\n\t\t\t\tgraphqlDeclarations.push(\n\t\t\t\t\tf.createVariableDeclaration(\n\t\t\t\t\t\tvarName, undefined, undefined,\n\t\t\t\t\t\tf.createNewExpression(\n\t\t\t\t\t\t\t_gqlImport('GraphQLScalarType'),\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\t[_serializeObject(scalarConf)]\n\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t\t// Add var\n\t\t\t\tmapEntityVar.set(entity, varName);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Kind.BASIC_SCALAR: {\n\t\t\t\tswitch (entity.name) {\n\t\t\t\t\t//* Graph QL basic scalars\n\t\t\t\t\tcase 'boolean': varId = _gqlImport('GraphQLBoolean'); break;\n\t\t\t\t\tcase 'number': varId = _gqlImport('GraphQLFloat'); break;\n\t\t\t\t\tcase 'string': varId = _gqlImport('GraphQLString'); break;\n\t\t\t\t\tcase 'Int': varId = _gqlImport('GraphQLInt'); break;\n\t\t\t\t\t//* Other scalars\n\t\t\t\t\tcase 'uFloat': varId = _createBasicScalar('uFloatScalar', entity); break;\n\t\t\t\t\tcase 'uInt': varId = _createBasicScalar('uIntScalar', entity); break;\n\t\t\t\t\tcase 'Buffer': varId = _createBasicScalar('bufferScalar', entity); break;\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\tlet _never: never = entity;\n\t\t\t\t\t\tthrow _never;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Add entity var\n\t\t\t\tmapEntityVar.set(entity, varId as ts.Identifier);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tlet _never: never = entity;\n\t\t\t\tthrow _never;\n\t\t\t}\n\t\t}\n\t\treturn varId;\n\t}\n\t/** Generate Object field args */\n\tfunction _fieldArg(param: Param) {\n\t\tlet ref = param.type!;\n\t\tlet refEntity = rootInput.get(ref.name)!;\n\t\tif (refEntity.kind !== Kind.FORMATTED_INPUT_OBJECT)\n\t\t\tthrow `Entity arg \"${refEntity.name}\" expected input object. Got ${Kind[refEntity.kind]} at ${refEntity.fileNames}`;\n\t\tlet properties: ts.PropertyAssignment[] = [];\n\t\tfor (let i = 0, fields = refEntity.fields, len = fields.length; i < len; ++i) {\n\t\t\tlet field = fields[i];\n\t\t\tlet paramVar = ResolveCircleFieldType(field);\n\t\t\tlet fieldConf: { [k in keyof GraphQLArgumentConfig]: any } = { type: paramVar };\n\t\t\tif (field.defaultValue) fieldConf.defaultValue = f.createIdentifier(field.defaultValue);\n\t\t\tif (field.jsDoc) fieldConf.description = field.jsDoc;\n\t\t\tif (field.deprecated) fieldConf.deprecationReason = field.deprecated;\n\t\t\tproperties.push(f.createPropertyAssignment(field.alias ?? field.name, _serializeObject(fieldConf)));\n\t\t}\n\t\treturn f.createObjectLiteralExpression(properties, pretty);\n\t}\n\t/** Create basic scalar */\n\tfunction _createBasicScalar(parserName: string, entity: FormattedBasicScalar): ts.Identifier {\n\t\tvar scalarVar = f.createUniqueName(entity.escapedName);\n\t\tvar scalarParser = _ttModelImport(parserName);\n\t\tvar uIntConf: { [k in keyof GraphQLScalarTypeConfig<any, any>]: any } =\n\t\t{\n\t\t\tname: entity.escapedName,\n\t\t\tparseValue: f.createPropertyAccessExpression(scalarParser, 'parse'),\n\t\t\tserialize: f.createPropertyAccessExpression(scalarParser, 'serialize'),\n\t\t\tdescription: f.createPropertyAccessExpression(scalarParser, 'description'),\n\t\t};\n\t\t// if(comment!=null) uIntConf.description= comment;\n\t\tgraphqlDeclarations.push(\n\t\t\tf.createVariableDeclaration(\n\t\t\t\tscalarVar,\n\t\t\t\tundefined,\n\t\t\t\tundefined,\n\t\t\t\tf.createNewExpression(_gqlImport('GraphQLScalarType'), undefined, [\n\t\t\t\t\t_serializeObject(uIntConf)\n\t\t\t\t])\n\t\t\t)\n\t\t);\n\t\treturn scalarVar;\n\t}\n\t/** Generate method call */\n\tfunction _getMethodCall(varId: ts.Identifier, method: MethodDescM, methodName?: string) {\n\t\tmethodName ??= method.name!;\n\t\tif (methodName == null) {\n\t\t\t// function\n\t\t\treturn varId;\n\t\t} else {\n\t\t\t// Method from class\n\t\t\treturn f.createPropertyAccessExpression(\n\t\t\t\tvarId,\n\t\t\t\t(method as MethodDescriptor).isClass\n\t\t\t\t\t? f.createIdentifier(methodName)\n\t\t\t\t\t: f.createIdentifier(\n\t\t\t\t\t\t(method as MethodDescriptor).isStatic === false\n\t\t\t\t\t\t\t? `prototype.${methodName}`\n\t\t\t\t\t\t\t: methodName\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\t}\n\t/** Resolve output alias */\n\tfunction _resolveOutputAlias(name: string) {\n\t\treturn f.createFunctionExpression(\n\t\t\tundefined, undefined, undefined, undefined, _getResolverArgs(['parent']), undefined, f.createBlock([\n\t\t\t\tf.createReturnStatement(\n\t\t\t\t\tf.createPropertyAccessExpression(\n\t\t\t\t\t\tf.createIdentifier('parent'), name\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t], pretty)\n\t\t);\n\t}\n\t/** Generate method */\n\tfunction _createMethod(name: string, args: string[], body: ts.Statement[]) {\n\t\tvar params = [];\n\t\tfor (let i = 0, len = args.length; i < len; ++i) {\n\t\t\tparams.push(\n\t\t\t\tf.createParameterDeclaration(\n\t\t\t\t\tundefined, undefined, undefined,\n\t\t\t\t\tf.createIdentifier(args[i]), undefined,\n\t\t\t\t\tf.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), undefined\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\t\treturn f.createMethodDeclaration(\n\t\t\tundefined, undefined, undefined,\n\t\t\tf.createIdentifier(name),\n\t\t\tundefined, undefined, params,\n\t\t\tundefined, f.createBlock(body, pretty)\n\t\t);\n\t}\n\t/** Resolve field type */\n\tfunction ResolveCircleFieldType(field: formattedInputField | formattedOutputField): ts.Expression {\n\t\tlet tp = field.type;\n\t\tif (tp == null) throw new Error(`Missing type at ${field.className}.${field.name}`);\n\t\tlet q: List[] = [];\n\t\tlet isInput = field.kind === Kind.INPUT_FIELD;\n\t\twhile (tp.kind != Kind.REF) {\n\t\t\tq.push(tp);\n\t\t\ttp = tp.type;\n\t\t}\n\t\tlet entity = _getEntity(tp, isInput);\n\t\tlet varId: ts.Expression | undefined = mapEntityVar.get(entity);\n\t\tif (varId == null) throw `Missing definition for entity \"${entity.name}\"`;\n\t\t// wrap with list and requires\n\t\tfor (let i = 0, len = q.length; i < len; ++i) {\n\t\t\tlet l = q[i];\n\t\t\tif (l.required) varId = genRequiredExpr(varId, 'requiredExpr');\n\t\t\tvarId = f.createNewExpression(GraphQLList, undefined, [varId]);\n\t\t}\n\t\t// If field required\n\t\tif (field.required) varId = genRequiredExpr(varId, 'requiredExpr');\n\t\treturn varId;\n\t}\n\t/** Get required expression */\n\tfunction genRequiredExpr(varId: ts.Expression, exprName: string) {\n\t\tlet id = reduceRequiredIds.get(varId);\n\t\tif (id == null) {\n\t\t\tlet varName = f.createUniqueName(exprName);\n\t\t\tgraphqlDeclarations.push(\n\t\t\t\tf.createVariableDeclaration(\n\t\t\t\t\tvarName, undefined, undefined,\n\t\t\t\t\tf.createNewExpression(GraphQLNonNull, undefined, [varId])\n\t\t\t\t)\n\t\t\t);\n\t\t\treduceRequiredIds.set(varId, varName);\n\t\t\tvarId = varName;\n\t\t} else {\n\t\t\tvarId = id;\n\t\t}\n\t\treturn varId;\n\t}\n\t//* Validate input data\n\t/** Add resolver */\n\ttype SeekVldNode = FormattedInputNode | FieldType | FormattedEnumMember | formattedInputField;\n\tfunction _wrapResolver(method: MethodDescM, param: Param | undefined): ts.Expression {\n\t\tlet resolveCb = _getMethodCall(_import(method), method);\n\t\tlet useAsync = false;\n\t\tseekVldCircle.clear();\n\t\t// mapVldEntityVar.clear();\n\t\t// circlesVldQueue.length = 0;\n\t\tlet result: ts.Expression | false | undefined;\n\t\tlet inputType = param?.type;\n\t\tif (inputType != null) {\n\t\t\tlet inputEntity = rootInput.get(inputType.name);\n\t\t\tif (inputEntity == null) throw `Unexpected missing input entity \"${inputType.name}\" referenced at: ${inputType.fileName}`;\n\t\t\tresult = mapVldEntityVar.get(inputEntity.escapedName);\n\t\t\tif (result == null) result = seek<SeekVldNode, SeekOutputData>([inputEntity], _seekValidationDown, _seekValidationUp)[0] as ts.Expression | false | undefined;\n\t\t}\n\t\t// Create wrapper\n\t\tlet body: ts.Statement[] = [];\n\t\t//* Add before\n\t\tif (rootConfig.before.length > 0) {\n\t\t\tfor (let i = 0, arr = rootConfig.before, len = arr.length; i < len; ++i) {\n\t\t\t\tlet method = arr[i];\n\t\t\t\tbody.push(_affect('args', _callMethod(method)));\n\t\t\t\tif (method.isAsync) useAsync = true;\n\t\t\t}\n\t\t}\n\t\t//* Validate input data\n\t\tif (result != null && result !== false) {\n\t\t\tbody.push(\n\t\t\t\t// Validation\n\t\t\t\tf.createVariableStatement(undefined, f.createVariableDeclarationList([\n\t\t\t\t\tf.createVariableDeclaration(\n\t\t\t\t\t\tf.createIdentifier(\"resp\"),\n\t\t\t\t\t\tundefined, undefined,\n\t\t\t\t\t\tf.createAwaitExpression(\n\t\t\t\t\t\t\t_callExpression(inputValidationWrapperId, [result, 'parent', 'args', 'ctx', 'info'])\n\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t], ts.NodeFlags.Let)),\n\t\t\t\t// Check for errors\n\t\t\t\tf.createIfStatement(\n\t\t\t\t\tf.createBinaryExpression(_propertyAccess('resp', 'errors', 'length'),\n\t\t\t\t\t\tf.createToken(ts.SyntaxKind.GreaterThanToken),\n\t\t\t\t\t\tf.createNumericLiteral(\"0\")\n\t\t\t\t\t),\n\t\t\t\t\tf.createThrowStatement(\n\t\t\t\t\t\tf.createNewExpression(ttModelError, undefined, [\n\t\t\t\t\t\t\tf.createPropertyAccessExpression(ttModelErrorCode, \"VALIDATION_ERRORS\"),\n\t\t\t\t\t\t\tf.createIdentifier('`Model Errors:\\\\n\\\\t‣ ${ resp.errors.join(\"\\\\n\\\\t‣ \")}`')\n\t\t\t\t\t\t])\n\t\t\t\t\t),\n\t\t\t\t\tundefined\n\t\t\t\t),\n\t\t\t\t// Affect value\n\t\t\t\t_affect('args', f.createPropertyAccessExpression(f.createIdentifier(\"resp\"), 'value'))\n\t\t\t);\n\t\t\tuseAsync = true; // Validation is an async operation\n\t\t}\n\t\t//* Return resolver value\n\t\tif (rootConfig.after.length === 0) {\n\t\t\tbody.push(\n\t\t\t\tf.createExpressionStatement(f.createIdentifier('//@ts-ignore')),\n\t\t\t\tf.createReturnStatement(_callExpression(resolveCb, ['parent', 'args', 'ctx', 'info']))\n\t\t\t);\n\t\t} else {\n\t\t\tlet expr: ts.CallExpression | ts.AwaitExpression = _callExpression(resolveCb, ['parent', 'args', 'ctx', 'info']);\n\t\t\tif (method.isAsync) {\n\t\t\t\tuseAsync = true;\n\t\t\t\texpr = f.createAwaitExpression(expr);\n\t\t\t}\n\t\t\tbody.push(\n\t\t\t\tf.createExpressionStatement(f.createIdentifier('//@ts-ignore')),\n\t\t\t\t_affect('args', expr));\n\t\t\t//* Add \"rootConfig.after\"\n\t\t\tfor (let i = 0, arr = rootConfig.after, len = arr.length; i < len; ++i) {\n\t\t\t\tlet method = arr[i];\n\t\t\t\tbody.push(_affect('args', _callMethod(method)));\n\t\t\t\tif (method.isAsync) useAsync = true;\n\t\t\t}\n\t\t\tbody.push(f.createReturnStatement(f.createIdentifier('args')));\n\t\t}\n\n\t\tvar fx = f.createFunctionExpression(\n\t\t\tuseAsync ? [f.createModifier(ts.SyntaxKind.AsyncKeyword)] : undefined\n\t\t\t, undefined, undefined, undefined, _getResolverArgs(['parent', 'args', 'ctx', 'info']), undefined, f.createBlock(body, pretty));\n\t\t//* Add wrappers\n\t\tif (RootWrappersIdentifier != null) {\n\t\t\tfx = f.createFunctionExpression(undefined, undefined, undefined, undefined, _getResolverArgs(['parent', 'args', 'ctx', 'info']), undefined, f.createBlock([\n\t\t\t\tf.createReturnStatement(\n\t\t\t\t\t_callExpression(RootWrappersIdentifier, ['parent', 'args', 'ctx', 'info', fx])\n\t\t\t\t)\n\t\t\t], pretty))\n\t\t}\n\t\t//* Return\n\t\treturn fx;\n\t}\n\t/** Seek validation down */\n\tfunction _seekValidationDown(node: SeekVldNode, isInput: boolean, parentNode: SeekVldNode | undefined): SeekVldNode[] | { nodes: SeekVldNode[], isInput: boolean } | undefined | false {\n\t\tswitch (node.kind) {\n\t\t\tcase Kind.FORMATTED_INPUT_OBJECT: {\n\t\t\t\t// Add entity to circle check\n\t\t\t\tseekVldCircle.add(node);\n\t\t\t\treturn node.fields;\n\t\t\t}\n\t\t\tcase Kind.INPUT_FIELD: return node.type == null ? undefined : [node.type];\n\t\t\tcase Kind.ENUM: return node.members\n\t\t\tcase Kind.LIST: return [node.type];\n\t\t\tcase Kind.REF: {\n\t\t\t\tlet entity = _getEntity(node, true) as FormattedInputNode;\n\t\t\t\tlet entityEscapedName = entity.escapedName;\n\t\t\t\tif (mapVldEntityVar.has(entityEscapedName)) return undefined;\n\t\t\t\tif (seekVldCircle.has(entity)) return undefined; // Circular\n\t\t\t\treturn [entity];\n\t\t\t}\n\t\t\tcase Kind.UNION: // No union in graphQL\n\t\t\tcase Kind.SCALAR:\n\t\t\tcase Kind.BASIC_SCALAR:\n\t\t\tcase Kind.ENUM_MEMBER:\n\t\t\t\treturn false;\n\t\t\tdefault: {\n\t\t\t\tlet n: never = node;\n\t\t\t}\n\t\t}\n\t}\n\t/** Seek validation up */\n\tfunction _seekValidationUp(node: SeekVldNode, isInput: boolean, parentNode: SeekVldNode | undefined, childrenData: SeekOutputData[]): SeekOutputData {\n\t\tvar varId: SeekOutputData;\n\t\tswitch (node.kind) {\n\t\t\tcase Kind.FORMATTED_INPUT_OBJECT: {\n\t\t\t\t// Remove entity from circle check\n\t\t\t\tseekVldCircle.delete(node);\n\t\t\t\t// Check for circles\n\t\t\t\tconst fields: ts.ObjectLiteralExpression[] = [];\n\t\t\t\tconst circleFields: formattedInputField[] = [];\n\t\t\t\tlet activeFieldsCount = 0;\n\t\t\t\tfor (let i = 0, arr = node.fields, len = arr.length; i < len; ++i) {\n\t\t\t\t\tlet field = childrenData[i] as ts.ObjectLiteralExpression | undefined | false;\n\t\t\t\t\tlet fieldData = arr[i];\n\t\t\t\t\tif (field == null) circleFields.push(fieldData);\n\t\t\t\t\telse if (field != false) {\n\t\t\t\t\t\tfields.push(field);\n\t\t\t\t\t\t++activeFieldsCount;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlet conf: { [k in keyof InputField]: any } = {\n\t\t\t\t\t\t\tname: fieldData.name,\n\t\t\t\t\t\t\talias: fieldData.alias ?? fieldData.name,\n\t\t\t\t\t\t\trequired: fieldData.required,\n\t\t\t\t\t\t\ttype: undefined,\n\t\t\t\t\t\t\tassert: undefined,\n\t\t\t\t\t\t\tpipe: undefined,\n\t\t\t\t\t\t\tpipeAsync: false\n\t\t\t\t\t\t};\n\t\t\t\t\t\tfields.push(_serializeObject(conf));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Ignore if has no child to valid and has no validation\n\t\t\t\tif (\n\t\t\t\t\tactiveFieldsCount === 0 &&\n\t\t\t\t\tcircleFields.length === 0 &&\n\t\t\t\t\tnode.before == null &&\n\t\t\t\t\tnode.after == null &&\n\t\t\t\t\t(node.wrappers == null || node.wrappers.length === 0)\n\t\t\t\t) {\n\t\t\t\t\tvarId = false;\n\t\t\t\t\tmapVldEntityVar.set(node.escapedName, false);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t// Create properties list\n\t\t\t\tlet fieldsArrExpression: ts.Expression = f.createArrayLiteralExpression(fields, pretty);\n\t\t\t\tif (circleFields.length) {\n\t\t\t\t\tlet fieldsVar = f.createUniqueName(`${node.escapedName}_fields`);\n\t\t\t\t\tinputDeclarations.push(\n\t\t\t\t\t\tf.createVariableDeclaration(\n\t\t\t\t\t\t\tfieldsVar, undefined, undefined, fieldsArrExpression\n\t\t\t\t\t\t)\n\t\t\t\t\t);\n\t\t\t\t\tfieldsArrExpression = fieldsVar;\n\t\t\t\t\t// Add to circle queue\n\t\t\t\t\tfor (let i = 0, len = circleFields.length; i < len; ++i) {\n\t\t\t\t\t\tcirclesVldQueue.push({\n\t\t\t\t\t\t\ttype: Kind.INPUT_FIELD, node, field: circleFields[i], varId: fieldsVar\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Create object\n\t\t\t\tlet beforeConf = _concatBeforeAfter(node.before);\n\t\t\t\tlet afterConf = _concatBeforeAfter(node.after);\n\t\t\t\tlet entityConf: { [k in keyof InputObject]: any } = {\n\t\t\t\t\tkind: ModelKind.INPUT_OBJECT,\n\t\t\t\t\tname: node.name,\n\t\t\t\t\tfields: fieldsArrExpression,\n\t\t\t\t\tbefore: beforeConf.expr,\n\t\t\t\t\tbeforeAsync: beforeConf.isAsync,\n\t\t\t\t\tafter: afterConf.expr,\n\t\t\t\t\tafterAsync: afterConf.isAsync,\n\t\t\t\t\twrap: node.wrappers == null ? undefined : _genWrappers(node.wrappers)\n\t\t\t\t};\n\t\t\t\tlet vName = varId = f.createUniqueName(node.escapedName);\n\t\t\t\tinputDeclarations.push(\n\t\t\t\t\tf.createVariableDeclaration(\n\t\t\t\t\t\tvName, undefined, undefined, _serializeObject(entityConf)\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t\t// Add var\n\t\t\t\tmapVldEntityVar.set(node.escapedName, vName);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Kind.INPUT_FIELD: {\n\t\t\t\t//* Type\n\t\t\t\tvarId = childrenData[0] as ts.Expression | undefined | false; // \"undefined\" means has circular to parents\n\t\t\t\tif (varId == null) { } // circular field\n\t\t\t\telse if ( // Ignore if own children ignored and has no validation rule\n\t\t\t\t\tvarId === false &&\n\t\t\t\t\tnode.alias == null &&\n\t\t\t\t\tnode.asserts == null &&\n\t\t\t\t\tnode.convert == null &&\n\t\t\t\t\tnode.pipe.length === 0\n\t\t\t\t) { }\n\t\t\t\telse {\n\t\t\t\t\t// Conf\n\t\t\t\t\tlet pipeM = _generatePipe(node);\n\t\t\t\t\tlet conf: { [k in keyof InputField]: any } = {\n\t\t\t\t\t\tname: node.name,\n\t\t\t\t\t\talias: node.alias ?? node.name,\n\t\t\t\t\t\trequired: node.required,\n\t\t\t\t\t\ttype: varId === false ? undefined : varId,\n\t\t\t\t\t\tassert: node.asserts == null ? undefined : compileAsserts(node.name, node.asserts, node.type, f, pretty),\n\t\t\t\t\t\tpipe: pipeM.fx,\n\t\t\t\t\t\tpipeAsync: pipeM.useAsync\n\t\t\t\t\t};\n\t\t\t\t\tvarId = _serializeObject(conf);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Kind.LIST: {\n\t\t\t\tvarId = childrenData[0] as ts.Expression | undefined | false; // \"undefined\" means has circular to parents\n\t\t\t\tif (varId != null && varId != false) {\n\t\t\t\t\tlet conf: { [k in keyof InputList]: any } = {\n\t\t\t\t\t\tkind: ModelKind.INPUT_LIST,\n\t\t\t\t\t\trequired: node.required, // Graphql will take care of this\n\t\t\t\t\t\ttype: varId\n\t\t\t\t\t};\n\t\t\t\t\tvarId = _serializeObject(conf);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Kind.REF: {\n\t\t\t\tvarId = childrenData[0]; // \"undefined\" means has circular to parents\n\t\t\t\tif (varId == null) {\n\t\t\t\t\tlet refEntity = _getEntity(node, true);\n\t\t\t\t\tif (refEntity == null) throw `Missing entity: ${node.name}`;\n\t\t\t\t\tvarId = mapVldEntityVar.get(refEntity.escapedName);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Kind.UNION: // No union in graphQL\n\t\t\tcase Kind.ENUM:\n\t\t\tcase Kind.SCALAR:\n\t\t\tcase Kind.BASIC_SCALAR:\n\t\t\tcase Kind.ENUM_MEMBER:\n\t\t\t\tvarId = false;\n\t\t\t\tbreak; // Those are already checked by graphQL\n\t\t\tdefault: {\n\t\t\t\tlet n: never = node;\n\t\t\t}\n\t\t}\n\t\treturn varId;\n\t}\n\n\t/** Resolver args */\n\tfunction _getResolverArgs(args: string[]) {\n\t\tvar result: ts.ParameterDeclaration[] = [];\n\t\tfor (let i = 0, len = args.length; i < len; i++) {\n\t\t\tresult.push(\n\t\t\t\tf.createParameterDeclaration(undefined, undefined, undefined,\n\t\t\t\t\tf.createIdentifier(args[i]), undefined,\n\t\t\t\t\tf.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), undefined)\n\t\t\t);\n\t\t}\n\t\treturn result;\n\t}\n\t/** Concat before and after */\n\tfunction _concatBeforeAfter(arr: MethodDescM[] | undefined): { expr: ts.Expression | undefined, isAsync: boolean } {\n\t\tif (arr == null) return { expr: undefined, isAsync: false };\n\t\tlet body: ts.Statement[] = [];\n\t\t// Add first methods\n\t\tlet len = arr.length - 1;\n\t\tlet useAsync = false;\n\t\tfor (let i = 0; i < len; ++i) {\n\t\t\tlet method = arr[i];\n\t\t\tlet expr: ts.Expression = _createMethodCallExp(method);\n\t\t\tif (method.isAsync) {\n\t\t\t\texpr = f.createAwaitExpression(expr);\n\t\t\t\tuseAsync = true;\n\t\t\t}\n\t\t\tbody.push(_affect('args', expr));\n\t\t}\n\t\t// Add Last method\n\t\tlet method = arr[len];\n\t\tbody.push(f.createReturnStatement(_createMethodCallExp(method)));\n\t\t// create method\n\t\treturn {\n\t\t\texpr: f.createFunctionExpression(\n\t\t\t\tuseAsync ? [f.createModifier(ts.SyntaxKind.AsyncKeyword)] : undefined,\n\t\t\t\tundefined, undefined, undefined, _getResolverArgs(['parent', 'args', 'ctx', 'info']), undefined, f.createBlock(body)),\n\t\t\tisAsync: useAsync || method.isAsync\n\t\t};\n\t}\n\t/** Create resolver call expression */\n\tfunction _createMethodCallExp(method: MethodDescM) {\n\t\tlet vldId = _import(method);\n\t\treturn _callExpression(_getMethodCall(vldId, method), ['parent', 'args', 'ctx', 'info']);\n\t}\n\t/** Generate wrappers */\n\tfunction _genWrappers(wrappers: MethodDescM[]): ts.FunctionExpression;\n\tfunction _genWrappers(wrappers: MethodDescM[], name: ts.Identifier | string): ts.FunctionDeclaration;\n\tfunction _genWrappers(wrappers: MethodDescM[], name?: ts.Identifier | string | undefined) {\n\t\tlet body: ts.Statement[] = [];\n\t\tlet wLen = wrappers.length - 1;\n\t\t// Add others if len > 2\n\t\tlet nextId = f.createIdentifier('next');\n\t\tfor (let i = wLen - 1; i >= 0; --i) {\n\t\t\tlet method = wrappers[i];\n\t\t\tlet methodId = f.createUniqueName('next');\n\t\t\tbody.push(\n\t\t\t\tf.createFunctionDeclaration(\n\t\t\t\t\tundefined, undefined, undefined, methodId, undefined, [], undefined,\n\t\t\t\t\tf.createBlock([\n\t\t\t\t\t\tf.createExpressionStatement(\n\t\t\t\t\t\t\tf.createCallExpression(\n\t\t\t\t\t\t\t\t_getMethodCall(_import(method), method), undefined,\n\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\tf.createIdentifier('parent'),\n\t\t\t\t\t\t\t\t\tf.createIdentifier('args'),\n\t\t\t\t\t\t\t\t\tf.createIdentifier('ctx'),\n\t\t\t\t\t\t\t\t\tf.createIdentifier('info'),\n\t\t\t\t\t\t\t\t\tnextId\n\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t)\n\t\t\t\t\t]))\n\t\t\t);\n\t\t\tnextId = methodId;\n\t\t}\n\t\t// Add last one\n\t\tlet method = wrappers[wLen];\n\t\tbody.push(\n\t\t\tf.createExpressionStatement(\n\t\t\t\tf.createCallExpression(\n\t\t\t\t\t_getMethodCall(_import(method), method), undefined,\n\t\t\t\t\t[\n\t\t\t\t\t\tf.createIdentifier('parent'),\n\t\t\t\t\t\tf.createIdentifier('args'),\n\t\t\t\t\t\tf.createIdentifier('ctx'),\n\t\t\t\t\t\tf.createIdentifier('info'),\n\t\t\t\t\t\tnextId\n\t\t\t\t\t]\n\t\t\t\t)\n\t\t\t)\n\t\t)\n\t\t// create method\n\t\tlet params = _getResolverArgs(['parent', 'args', 'ctx', 'info', 'next']);\n\t\tif (name == null)\n\t\t\treturn f.createFunctionExpression(\n\t\t\t\tundefined, undefined, undefined, undefined, params, undefined, f.createBlock(body));\n\t\telse return f.createFunctionDeclaration(undefined, undefined, undefined, name, undefined, params, undefined, f.createBlock(body));\n\t}\n\t/** Create call expression */\n\tfunction _callExpression(expr: ts.Expression, params: (string | ts.Expression)[]) {\n\t\tlet args = [];\n\t\tfor (let i = 0, len = params.length; i < len; i++) {\n\t\t\tlet param = params[i];\n\t\t\tif (typeof param === 'string')\n\t\t\t\targs.push(f.createIdentifier(param));\n\t\t\telse\n\t\t\t\targs.push(param);\n\t\t}\n\t\t//return\n\t\treturn f.createCallExpression(expr, undefined, args);\n\t}\n\t/** Affect expression */\n\tfunction _affect(varname: string | ts.Expression, value: ts.Expression) {\n\t\tif (typeof varname === 'string') varname = f.createIdentifier(varname);\n\t\treturn f.createExpressionStatement(\n\t\t\tf.createBinaryExpression(\n\t\t\t\tvarname,\n\t\t\t\tf.createToken(ts.SyntaxKind.EqualsToken),\n\t\t\t\tvalue\n\t\t\t)\n\t\t)\n\t}\n\t/** Add method expression expression */\n\tfunction _callMethod(method: MethodDescM, args = ['parent', 'args', 'ctx', 'info']) {\n\t\tlet expr: ts.CallExpression | ts.AwaitExpression = _callExpression(_getMethodCall(_import(method), method), args);\n\t\tif (method.isAsync) expr = f.createAwaitExpression(expr);\n\t\treturn expr;\n\t}\n\t/** Get entity or it's converted by name */\n\tfunction _getEntity(ref: Reference, isInput: boolean) {\n\t\tlet rootEntityMap = isInput === true ? rootInput : rootOutput;\n\t\tlet entity = rootEntityMap.get(ref.name);\n\t\tif (entity == null)\n\t\t\tthrow `Missing ${isInput ? 'input' : 'output'} entity \"${ref.name}\" referenced at ${ref.fileName}`;\n\t\t// Check if has converter\n\t\tlet cnv = (entity as FormattedInputObject).convert;\n\t\tif (cnv != null && cnv.type != null) {\n\t\t\tlet ent = rootEntityMap.get(cnv.type.name);\n\t\t\tif (ent == null)\n\t\t\t\tthrow `Missing ${isInput ? 'input' : 'output'} entity \"${cnv.type.name}\" converted from \"${entity.name}\" defined at \"${cnv.className}.${cnv.name}\" at ${cnv.fileName}`;\n\t\t\tentity = ent;\n\t\t}\n\t\treturn entity;\n\t}\n\t/** Generate pipe */\n\tfunction _generatePipe(node: formattedInputField) {\n\t\tvar pipe = node.convert == null ? node.pipe : [...node.pipe, node.convert];\n\t\tvar result: ts.FunctionExpression | undefined;\n\t\tvar useAsync = false;\n\t\tif (pipe.length > 0) {\n\t\t\t// Add first functions\n\t\t\tlet body: ts.Statement[] = [];\n\t\t\tlet lastIndex = pipe.length - 1;\n\t\t\tfor (let i = 0; i < lastIndex; ++i) {\n\t\t\t\tlet method = pipe[i];\n\t\t\t\tlet expr: ts.Expression = _createMethodCallExp(method);\n\t\t\t\tif (method.isAsync) {\n\t\t\t\t\texpr = f.createAwaitExpression(expr);\n\t\t\t\t\tuseAsync = true;\n\t\t\t\t}\n\t\t\t\tbody.push(_affect('args', expr));\n\t\t\t}\n\t\t\t// Add last line with return statement\n\t\t\tbody.push(\n\t\t\t\tf.createReturnStatement(_createMethodCallExp(pipe[lastIndex]))\n\t\t\t);\n\t\t\tif (pipe[lastIndex].isAsync) useAsync = true; // Even pipeline is sync, it still return's promise\n\n\t\t\tresult = f.createFunctionExpression(\n\t\t\t\tuseAsync ? [f.createModifier(ts.SyntaxKind.AsyncKeyword)] : undefined,\n\t\t\t\tundefined, undefined, undefined, _getResolverArgs(['parent', 'args', 'ctx', 'info']),\n\t\t\t\tundefined, f.createBlock(body, pretty)\n\t\t\t);\n\t\t}\n\t\treturn { fx: result, useAsync };\n\t}\n\t/** Property access */\n\tfunction _propertyAccess(...props: string[]) {\n\t\tvar result: ts.PropertyAccessExpression =\n\t\t\tf.createPropertyAccessExpression(f.createIdentifier(props[0]), f.createIdentifier(props[1]));\n\t\tfor (let i = 2, len = props.length; i < len; ++i)\n\t\t\tresult = f.createPropertyAccessExpression(result, f.createIdentifier(props[i]));\n\t\treturn result;\n\t}\n}\n\n/** Seek data */\ntype SeekOutputData = ts.Expression | ts.PropertyAssignment | undefined | false;\n\n\n/** Relative path */\nfunction _relative(from: string, to: string) {\n\tvar p = relative(from, to);\n\tp = p.replace(/\\\\/g, '/');\n\tvar c = p.charAt(0);\n\tif (c !== '.' && c !== '/') p = './' + p;\n\treturn p;\n}\n\n/** Circle queue item */\ntype CircleQueueItem = CircleQueueInputField | CircleQueueOutputField | CircleQueueUnion;\ninterface CircleQueueInputField {\n\ttype: Kind.INPUT_FIELD\n\t/** Node containing circle */\n\tnode: FormattedInputNode,\n\t/** Field of circle */\n\tfield: formattedInputField,\n\t/** Fields var */\n\tvarId: ts.Identifier\n}\ninterface CircleQueueOutputField {\n\ttype: Kind.OUTPUT_FIELD\n\t/** Node containing circle */\n\tnode: FormattedOutputNode,\n\t/** Field of circle */\n\tfield: formattedOutputField,\n\t/** Fields var */\n\tvarId: ts.Identifier\n}\n\ninterface CircleQueueUnion {\n\ttype: Kind.UNION,\n\t/** Union entity */\n\tunion: FormattedUnion,\n\t/** types array var */\n\tvarId: ts.Identifier\n\tisInput: boolean\n}\n\n\n"]}