1 | <!DOCTYPE html>
|
2 | <html lang="en">
|
3 | <head>
|
4 | <meta charset="utf-8">
|
5 | <meta name="viewport" content="width=device-width,initial-scale=1">
|
6 | <title>LatticeFactory.js - Documentation</title>
|
7 |
|
8 | <script src="scripts/prettify/prettify.js"></script>
|
9 | <script src="scripts/prettify/lang-css.js"></script>
|
10 | |
11 |
|
12 |
|
13 | <link type="text/css" rel="stylesheet" href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css">
|
14 | <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
15 | <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
|
16 | </head>
|
17 | <body>
|
18 |
|
19 | <input type="checkbox" id="nav-trigger" class="nav-trigger" />
|
20 | <label for="nav-trigger" class="navicon-button x">
|
21 | <div class="navicon"></div>
|
22 | </label>
|
23 |
|
24 | <label for="nav-trigger" class="overlay"></label>
|
25 |
|
26 | <nav>
|
27 | <li class="nav-link nav-home-link"><a href="index.html">Home</a></li><li class="nav-heading">Classes</li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="AwaitingPromiseError.html">AwaitingPromiseError</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="AwaitingPromiseError.html#%25E2%258C%25BE%25E2%25A0%2580asyncFn">⌾⠀asyncFn</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="AwaitingPromiseError.html#%25E2%258C%25BE%25E2%25A0%2580setPromise">⌾⠀setPromise</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="AwaitingPromiseError_exports.AwaitingPromiseError.html">AwaitingPromiseError</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="AwaitingPromiseError_exports.AwaitingPromiseError.html#setPromise">setPromise</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="Deferred_exports.Deferred.html">Deferred</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="DirectTypeAdd.html">DirectTypeAdd</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="FunctionExecutionError_FunctionExecutionError.html">FunctionExecutionError</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="GQLBase.html">GQLBase</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLBase.html#.apiDocs">apiDocs</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLBase.html#.%25E2%258C%25BE%25E2%25A0%2580getMergedRoot">⌾⠀getMergedRoot</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLBase.html#.%25E2%258C%25BE%25E2%25A0%2580getProp">⌾⠀getProp</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLBase.html#.%25E2%258C%25BE%25E2%25A0%2580getResolver">⌾⠀getResolver</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLBase.html#.%25E2%258C%25BE%25E2%25A0%2580IDLFilePath">⌾⠀IDLFilePath</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLBase.html#.%25E2%258C%25BE%25E2%25A0%2580MUTATORS">⌾⠀MUTATORS</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLBase.html#.%25E2%258C%25BE%25E2%25A0%2580RESOLVERS">⌾⠀RESOLVERS</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLBase.html#.%25E2%258C%25BE%25E2%25A0%2580setupModel">⌾⠀setupModel</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLBase.html#.%25E2%25AC%2587%25EF%25B8%258E%25E2%25A0%2580handler">⬇︎⠀handler</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLBase.html#.%25E2%25AC%2587%25EF%25B8%258E%25E2%25A0%2580SCHEMA">⬇︎⠀SCHEMA</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLBase.html#%25E2%258C%25BE%25E2%25A0%2580applyAutoProps">⌾⠀applyAutoProps</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLBase.html#%25E2%258C%25BE%25E2%25A0%2580callProp">⌾⠀callProp</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLBase.html#%25E2%258C%25BE%25E2%25A0%2580extendModel">⌾⠀extendModel</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLBase.html#%25E2%258C%25BE%25E2%25A0%2580getModel">⌾⠀getModel</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLBase.html#%25E2%258C%25BE%25E2%25A0%2580getProp">⌾⠀getProp</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLBase.html#%25E2%258C%25BE%25E2%25A0%2580getResolver">⌾⠀getResolver</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLBase.html#%25E2%258C%25BE%25E2%25A0%2580setModel">⌾⠀setModel</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLBase.html#%25E2%25AC%2586%25EF%25B8%258E%25E2%25A0%2580requestData">⬆︎⠀requestData</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLBase.html#%25E2%25AC%2587%25EF%25B8%258E%25E2%25A0%2580requestData">⬇︎⠀requestData</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLBase.html#~deleteProperty">deleteProperty</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLBase.html#~set">set</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="GQLBase.%25E2%258E%2586%25E2%25A0%2580constructor.html">⎆⠀constructor</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="GQLEnum.html">GQLEnum</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLEnum.html#..get">.get</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLEnum.html#..set">.set</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLEnum.html#.valueFor">valueFor</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLEnum.html#.%25E2%25AC%2587%25EF%25B8%258E%25E2%25A0%2580enums">⬇︎⠀enums</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLEnum.html#.%25E2%25AC%2587%25EF%25B8%258E%25E2%25A0%2580name">⬇︎⠀name</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLEnum.html#.%25E2%25AC%2587%25EF%25B8%258E%25E2%25A0%2580value">⬇︎⠀value</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLEnum.html#.%25E2%25AC%2587%25EF%25B8%258E%25E2%25A0%2580values">⬇︎⠀values</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLEnum.html#GenerateEnumsProxyHandler">GenerateEnumsProxyHandler</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="GQLExpressMiddleware.html">GQLExpressMiddleware</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLExpressMiddleware.html#.clearCache">clearCache</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLExpressMiddleware.html#.%25E2%258C%25BE%25E2%25A0%2580generateSchemaSDL">⌾⠀generateSchemaSDL</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLExpressMiddleware.html#astMiddleware">astMiddleware</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLExpressMiddleware.html#schemaMiddleware">schemaMiddleware</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLExpressMiddleware.html#%25E2%258C%25BE%25E2%25A0%2580customMiddleware">⌾⠀customMiddleware</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLExpressMiddleware.html#%25E2%25AC%2587%25EF%25B8%258E%25E2%25A0%2580middleware">⬇︎⠀middleware</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLExpressMiddleware.html#%25E2%25AC%2587%25EF%25B8%258E%25E2%25A0%2580middlewareWithoutGraphiQL">⬇︎⠀middlewareWithoutGraphiQL</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLExpressMiddleware.html#%25E2%25AC%2587%25EF%25B8%258E%25E2%25A0%2580schema">⬇︎⠀schema</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="GQLExpressMiddleware.%25E2%258E%2586%25E2%25A0%2580constructor.html">⎆⠀constructor</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="GQLInterface.html">GQLInterface</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLInterface.html#.%25E2%258C%25BE%25E2%25A0%2580resolveType">⌾⠀resolveType</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="GQLScalar.html">GQLScalar</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLScalar.html#.parseLiteral">parseLiteral</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLScalar.html#.parseValue">parseValue</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLScalar.html#.serialize">serialize</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="IDLFileHandler.html">IDLFileHandler</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="IDLFileHandler.html#%25E2%258C%25BE%25E2%25A0%2580getFile">⌾⠀getFile</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="IDLFileHandler.html#%25E2%258C%25BE%25E2%25A0%2580getSchema">⌾⠀getSchema</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="IDLFileHandler.html#%25E2%258C%25BE%25E2%25A0%2580getSyntaxTree">⌾⠀getSyntaxTree</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="IDLFileHandler.%25E2%258E%2586%25E2%25A0%2580constructor.html">⎆⠀constructor</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="ModuleParser.html">ModuleParser</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="ModuleParser.html#.%25E2%258C%25BE%25E2%25A0%2580arrayToPattern">⌾⠀arrayToPattern</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="ModuleParser.html#.%25E2%258C%25BE%25E2%25A0%2580checkForPackageExtensions">⌾⠀checkForPackageExtensions</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="ModuleParser.html#%25E2%258C%25BE%25E2%25A0%2580findGQLBaseClasses">⌾⠀findGQLBaseClasses</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="ModuleParser.html#%25E2%258C%25BE%25E2%25A0%2580importClass">⌾⠀importClass</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="ModuleParser.html#%25E2%258C%25BE%25E2%25A0%2580parse">⌾⠀parse</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="ModuleParser.html#%25E2%258C%25BE%25E2%25A0%2580parseSync">⌾⠀parseSync</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="ModuleParser.html#~%25E2%258C%25BE%25E2%25A0%2580walk">⌾⠀walk</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="ModuleParser.html#~%25E2%258C%25BE%25E2%25A0%2580walkSync">⌾⠀walkSync</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="ModuleParser.html#~%25E2%258E%2586%25E2%25A0%2580constructor">⎆⠀constructor</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="ModuleParser.exports.ModuleParser.html">exports.ModuleParser</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="SchemaUtils.html">SchemaUtils</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="SchemaUtils.html#.%25E2%258C%25BE%25E2%25A0%2580createMergedRoot">⌾⠀createMergedRoot</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="SchemaUtils.html#.%25E2%258C%25BE%25E2%25A0%2580injectComments">⌾⠀injectComments</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="SchemaUtils.html#.%25E2%258C%25BE%25E2%25A0%2580injectEnums">⌾⠀injectEnums</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="SchemaUtils.html#.%25E2%258C%25BE%25E2%25A0%2580injectInterfaceResolvers">⌾⠀injectInterfaceResolvers</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="SchemaUtils.html#.%25E2%258C%25BE%25E2%25A0%2580injectScalars">⌾⠀injectScalars</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="SyntaxTree.html">SyntaxTree</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="SyntaxTree.html#.%25E2%258C%25BE%25E2%25A0%2580EmptyDocument">⌾⠀EmptyDocument</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="SyntaxTree.html#.%25E2%258C%25BE%25E2%25A0%2580EmptyMutation">⌾⠀EmptyMutation</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="SyntaxTree.html#.%25E2%258C%25BE%25E2%25A0%2580EmptyQuery">⌾⠀EmptyQuery</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="SyntaxTree.html#.%25E2%258C%25BE%25E2%25A0%2580findDefinition">⌾⠀findDefinition</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="SyntaxTree.html#.%25E2%258C%25BE%25E2%25A0%2580findField">⌾⠀findField</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="SyntaxTree.html#.%25E2%258C%25BE%25E2%25A0%2580findInASTArrayByNameValue">⌾⠀findInASTArrayByNameValue</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="SyntaxTree.html#.%25E2%258C%25BE%25E2%25A0%2580from">⌾⠀from</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="SyntaxTree.html#.%25E2%258C%25BE%25E2%25A0%2580fromAST">⌾⠀fromAST</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="SyntaxTree.html#.%25E2%258C%25BE%25E2%25A0%2580fromSchema">⌾⠀fromSchema</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="SyntaxTree.html#.%25E2%258E%2586%25E2%25A0%2580constructor">⎆⠀constructor</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="SyntaxTree.html#%25E2%258C%25BE%25E2%25A0%2580appendDefinitions">⌾⠀appendDefinitions</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="SyntaxTree.html#%25E2%258C%25BE%25E2%25A0%2580consumeDefinition">⌾⠀consumeDefinition</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="SyntaxTree.html#%25E2%258C%25BE%25E2%25A0%2580find">⌾⠀find</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="SyntaxTree.html#%25E2%258C%25BE%25E2%25A0%2580findEnumDefinition">⌾⠀findEnumDefinition</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="SyntaxTree.html#%25E2%258C%25BE%25E2%25A0%2580setAST">⌾⠀setAST</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="SyntaxTree.html#%25E2%258C%25BE%25E2%25A0%2580toString">⌾⠀toString</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="SyntaxTree.html#%25E2%258C%25BE%25E2%25A0%2580updateAST">⌾⠀updateAST</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="SyntaxTree.html#%25E2%25AC%2586%25EF%25B8%258E%25E2%25A0%2580ast">⬆︎⠀ast</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="SyntaxTree.html#%25E2%25AC%2587%25EF%25B8%258E%25E2%25A0%2580ast">⬇︎⠀ast</a></span></li><li class="nav-heading"><span class="nav-item-type type-class">C</span><span class="nav-item-name"><a href="utils.Deferred.html">Deferred</a></span></li><li class="nav-heading">Namespaces</li><li class="nav-heading"><span class="nav-item-type type-namespace">N</span><span class="nav-item-name"><a href="decorators.html">decorators</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="decorators.html#.%25E2%258C%25BE%25E2%25A0%2580extractBits">⌾⠀extractBits</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="decorators.html#..%25F0%259F%258F%25B7%25E2%25A0%2580AdjacentSchema">.🏷⠀AdjacentSchema</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="decorators.html#..%25F0%259F%258F%25B7%25E2%25A0%2580FileSchema">.🏷⠀FileSchema</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="decorators.html#..%25F0%259F%258F%25B7%25E2%25A0%2580Getters">.🏷⠀Getters</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="decorators.html#..%25F0%259F%258F%25B7%25E2%25A0%2580Properties">.🏷⠀Properties</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="decorators.html#..%25F0%259F%258F%25B7%25E2%25A0%2580Schema">.🏷⠀Schema</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="decorators.html#..%25F0%259F%258F%25B7%25E2%25A0%2580Setters">.🏷⠀Setters</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="decorators.html#~decorate">decorate</a></span></li><li class="nav-heading"><span class="nav-item-type type-namespace">N</span><span class="nav-item-name"><a href="GQLBaseEnv.html">GQLBaseEnv</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="GQLBaseEnv.html#~notDefined">notDefined</a></span></li><li class="nav-heading"><a href="global.html">Globals</a></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#applyTags">applyTags</a></span></li><li class="nav-item"><span class="nav-item-type type-member">M</span><span class="nav-item-name"><a href="global.html#AsyncFunctionExecutionError">AsyncFunctionExecutionError</a></span></li><li class="nav-item"><span class="nav-item-type type-member">M</span><span class="nav-item-name"><a href="global.html#CHECK_API_DOCS">CHECK_API_DOCS</a></span></li><li class="nav-item"><span class="nav-item-type type-member">M</span><span class="nav-item-name"><a href="global.html#CHECK_RESOLVERS">CHECK_RESOLVERS</a></span></li><li class="nav-item"><span class="nav-item-type type-member">M</span><span class="nav-item-name"><a href="global.html#CHECK_SCHEMA">CHECK_SCHEMA</a></span></li><li class="nav-item"><span class="nav-item-type type-member">M</span><span class="nav-item-name"><a href="global.html#CHECKLIST">CHECKLIST</a></span></li><li class="nav-item"><span class="nav-item-type type-member">M</span><span class="nav-item-name"><a href="global.html#FunctionExecutionError">FunctionExecutionError</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#getChecklist">getChecklist</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#hasChecklist">hasChecklist</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#newChecklist">newChecklist</a></span></li><li class="nav-item"><span class="nav-item-type type-function">F</span><span class="nav-item-name"><a href="global.html#setChecklist">setChecklist</a></span></li><li class="nav-item"><span class="nav-item-type type-member">M</span><span class="nav-item-name"><a href="global.html#types">types</a></span></li>
|
28 | </nav>
|
29 |
|
30 | <div id="main">
|
31 |
|
32 | <h1 class="page-title">LatticeFactory.js</h1>
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 | <section>
|
41 | <article>
|
42 | <pre class="prettyprint source linenums"><code>// @flow
|
43 |
|
44 | import { GQLBase, META_KEY } from './GQLBase'
|
45 | import { GQLEnum } from './GQLEnum'
|
46 | import { GQLInterface } from './GQLInterface'
|
47 | import { GQLScalar } from './GQLScalar'
|
48 | // import { GQLUnion } from './GQLUnion'
|
49 | import { SyntaxTree } from './SyntaxTree'
|
50 | import { customDedent } from 'ne-tag-fns'
|
51 | import { typeOf, extendsFrom } from 'ne-types'
|
52 | import { inspect } from 'util'
|
53 | import { resolver, mutator, subscriptor } from './decorators/Resolvers'
|
54 | import { Properties } from './decorators/ModelProperties'
|
55 | import { LatticeLogs as LL } from './utils'
|
56 |
|
57 | const _i = (...args) => inspect(...args, {colors: true, depth: 3})
|
58 |
|
59 |
|
60 | /**
|
61 | * The CHECKLIST Symbol is used as a storage key in the metadata staging
|
62 | * area for each of the GQLBase extended classes. In the LatticeFactory
|
63 | * it is used to determine where in the flow of construction the class
|
64 | * currently is.
|
65 | *
|
66 | * @type {Symbol}
|
67 | */
|
68 | export const CHECKLIST = Symbol.for('checklist')
|
69 |
|
70 | /**
|
71 | * The CHECK_SCHEMA Symbol is part of the CHECKLIST for a constructed
|
72 | * GQLBase extended class. It denotes that the class has had its SCHEMA
|
73 | * getter defined.
|
74 | *
|
75 | * @type {Symbol}
|
76 | */
|
77 | export const CHECK_SCHEMA = Symbol.for('checklist-schema')
|
78 |
|
79 | /**
|
80 | * The CHECK_RESOLVERS Symbol is part of the CHECKLIST for a constructed
|
81 | * GQLBase extended class. It denotes that the class has had its instance
|
82 | * field resolvers as well as its static Query, Mutation and Subscription
|
83 | * resolvers injected and defined.
|
84 | *
|
85 | * @type {Symbol}
|
86 | */
|
87 | export const CHECK_RESOLVERS = Symbol.for('checklist-resolvers')
|
88 |
|
89 | /**
|
90 | * The CHECK_API_DOCS Symbol is part of the CHECKLIST for a constructed
|
91 | * GQLBase extended class. It denotes that the class has had its api docs
|
92 | * defined, processed and setup on the class in a way that it will be
|
93 | * picked up in the build lifecycle.
|
94 | *
|
95 | * @type {Symbol}
|
96 | */
|
97 | export const CHECK_API_DOCS = Symbol.for('checklist-api-docs')
|
98 |
|
99 | /**
|
100 | * Peeks into the metadata storage area of a given GQLBase extended
|
101 | * class and fetches the factory checklist if one exists.
|
102 | *
|
103 | * @param {Function} Class a reference to the GQLBase class to peek in
|
104 | * @return {Object} an object setup with at least three booleans keyed by
|
105 | * the constants CHECK_SCHEMA, CHECK_RESOLVERS, and CHECK_API_DOCS or null
|
106 | * if none exists
|
107 | */
|
108 | export function getChecklist(Class: Function) {
|
109 | return (Class && Class[META_KEY] && Class[META_KEY][CHECKLIST]) || null
|
110 | }
|
111 |
|
112 | /**
|
113 | * Obtains the checklist from the supplied GQLBase extended class. If the
|
114 | * class has a checklist, its checklist item is set to true or the boolean
|
115 | * value specified.
|
116 | *
|
117 | * @param {Function} Class a reference to the GQLBase class to set
|
118 | * @param {Symbol} item one of CHECK_SCHEMA, CHECK_RESOLVERS, or
|
119 | * CHECK_API_DOCS
|
120 | * @param {Boolean} value the value for the checklist item to set
|
121 | */
|
122 | export function setChecklist(
|
123 | Class: Function,
|
124 | item: Symbol,
|
125 | value: boolean = true
|
126 | ) {
|
127 | let checklist = getChecklist(Class)
|
128 |
|
129 | if (checklist) {
|
130 | // $FlowFixMe
|
131 | checklist[item] = value
|
132 | }
|
133 | }
|
134 |
|
135 | /**
|
136 | * This function, when invoked with only a class will return true if the
|
137 | * Class has a defined checklist. If one ore more CHECKLIST symbols are
|
138 | * passed, the function will only return true if all the supplied symbols
|
139 | * are set to truthy values.
|
140 | *
|
141 | * @param {Function} Class a reference to the GQLBase class to set
|
142 | * @param {Array<Symbol>} items any of CHECK_SCHEMA, CHECK_RESOLVERS, or
|
143 | * CHECK_API_DOCS
|
144 | * @return {Boolean} true if the checklist and/or all items are true and
|
145 | * present.
|
146 | */
|
147 | export function hasChecklist(Class: Function, ...items: Array<Symbol>) {
|
148 | let checklist = getChecklist(Class)
|
149 |
|
150 | if (checklist && items.length) {
|
151 | for (let item of items) {
|
152 | if (!checklist[item]) {
|
153 | return false
|
154 | }
|
155 | }
|
156 |
|
157 | return true
|
158 | }
|
159 |
|
160 | return checklist
|
161 | }
|
162 |
|
163 | /**
|
164 | * Injects and creates a new CHECKLIST object on the supplied GQLBase
|
165 | * extended class. All items are installed and set to false.
|
166 | *
|
167 | * @param {Function} Class a reference to the GQLBase class to set
|
168 | */
|
169 | export function newChecklist(Class: Function) {
|
170 | if (Class) {
|
171 | // $FlowFixMe
|
172 | Class[META_KEY][CHECKLIST] = {
|
173 | [CHECK_SCHEMA]: false,
|
174 | [CHECK_RESOLVERS]: false,
|
175 | [CHECK_API_DOCS]: false,
|
176 |
|
177 | get keys() {
|
178 | return [
|
179 | CHECK_SCHEMA, CHECK_RESOLVERS, CHECK_API_DOCS
|
180 | ]
|
181 | },
|
182 |
|
183 | get complete() {
|
184 | return this.keys.reduce((p,c,i,a) => {
|
185 | if (!p || !this[c]) { return false }
|
186 | }, true)
|
187 | }
|
188 | }
|
189 | }
|
190 | else {
|
191 | throw new Error(customDedent({dropLowest:true})`
|
192 | Cannot create new checklist metadata on a non-existent class
|
193 | `)
|
194 | }
|
195 | }
|
196 |
|
197 | export class ValidationResults {
|
198 | errors: Array<Error>
|
199 |
|
200 | constructor(errors: Array<Error> = []) {
|
201 | this.errors = errors
|
202 | }
|
203 |
|
204 | get valid(): boolean { return this.errors.length === 0 }
|
205 |
|
206 | // $FlowFixMe
|
207 | get [Symbol.toStringTag](): string { return this.constructor.name }
|
208 |
|
209 | // $FlowFixMe
|
210 | static get [Symbol.toStringTag](): string { return this.name }
|
211 | }
|
212 |
|
213 | export class LatticeFactory {
|
214 |
|
215 | /**
|
216 | * Walks through a supplied template object and collects errors with its
|
217 | * format before bubbling up an exception if any part of it fails to
|
218 | * pass muster. The exception can be prevented from throwing if hide is set
|
219 | * to true
|
220 | *
|
221 | * @param {Object} template an object to be parsed for construction via the
|
222 | * Lattice Factory
|
223 | * @param {boolean} hide if true, an invalid template will NOT throw errors
|
224 | * @return {ValidationResults} a `ValidationResults` object containing the
|
225 | * collected errors and a `valid` that is dynamically calculated.
|
226 | */
|
227 | static validateTemplate(
|
228 | template: Object,
|
229 | hide: boolean = false
|
230 | ): ValidationResults {
|
231 | let results = new ValidationResults()
|
232 | let indent = (string: string, count: number = 4, space: string = ' ') => (
|
233 | string
|
234 | .split('\n')
|
235 | .map(s => s.trim().replace(/(^)/gm, `$1${space.repeat(count)}`))
|
236 | .join('\n')
|
237 | )
|
238 |
|
239 | if (typeof template.name === 'undefined') {
|
240 | results.errors.push(new Error(customDedent({dropLowest:true})`
|
241 | The \`template.name\` field must exist or the creation for the Lattice
|
242 | factory class generation to succeed.
|
243 |
|
244 | Please read the documentation for more information on the format of
|
245 | a LatticeFactory template.
|
246 | `))
|
247 | }
|
248 |
|
249 | if (!extendsFrom(template.name, String)) {
|
250 | results.errors.push(new Error(customDedent({dropLowest:true})`
|
251 | The \`template.name\` field must be a string.
|
252 |
|
253 | Please read the documentation for more information on the format of
|
254 | a LatticeFactory template.
|
255 | `))
|
256 | }
|
257 |
|
258 | if (typeof template.schema === 'undefined') {
|
259 | results.errors.push(new Error(customDedent({dropLowest:true})`
|
260 | The \`template.schema\` field must exist or the creation for the
|
261 | Lattice factory class generation to succeed.
|
262 |
|
263 | Please read the documentation for more information on the format of
|
264 | a LatticeFactory template.
|
265 | `))
|
266 | }
|
267 |
|
268 | if (!extendsFrom(template.schema, String)) {
|
269 | results.errors.push(new Error(customDedent({dropLowest:true})`
|
270 | The \`template.schema\` field must be a string of GraphQL SDL/IDL
|
271 |
|
272 | Please read the documentation for more information on the format of
|
273 | a LatticeFactory template.
|
274 | `))
|
275 | }
|
276 |
|
277 | if (
|
278 | !extendsFrom(template.resolvers, Object) // Supports 95% of objects
|
279 | || typeof template.resolvers !== 'object' // Supports Object.create(null)
|
280 | ) {
|
281 | results.errors.push(new Error(customDedent({dropLowest:true})`\x1b[91;1m
|
282 | The \`template.resolvers\` field must be an Object containing the
|
283 | resolver functions. Query, Mutation and Subscription resolvers will
|
284 | take the following signature. Additionally, the keys for these special
|
285 | resolvers must be Query, Mutation or Subscription; respectively
|
286 | \x1b[37;22m
|
287 | Query: { [resolver]: (requestData, resolverParameters) => {} }
|
288 | Mutation: { [resolver]: (requestData, resolverParameters) => {} }
|
289 | Subscription: { [resolver]: (requestData, resolverParameters) => {} }
|
290 |
|
291 | where:
|
292 | \`requestData\` is an object with { req, res, gql|next } depending
|
293 | on the graphql server implementation (FB Reference, Apollo, etc)
|
294 | \`resovlerParameters\` is an object with keys matching those
|
295 | parameters defined in the SCHEMA for the resolver in question.
|
296 | \x1b[91;1m
|
297 | Field resolvers should be found under the key name of the type
|
298 | or interface in question and must correspond to the following signature
|
299 | \x1b[37;22m
|
300 | [Type]: { [resolver]: (resolverParameters) => {} }
|
301 |
|
302 | where:
|
303 | \`Type\` is the name of the GQL type defined in the schema
|
304 | \`resovlerParameters\` is an object with keys matching those
|
305 | parameters defined in the SCHEMA for the resolver in question.
|
306 |
|
307 | * it is worth noting that the field resolvers are not static and
|
308 | can access the \`requestData\` object via \`this.requestData\`
|
309 | \x1b[91;1m
|
310 | Please read the documentation for more information on the format of
|
311 | a LatticeFactory template.\x1b[0m
|
312 | `))
|
313 | }
|
314 |
|
315 | if (typeof template.docs === 'undefined') {
|
316 | results.errors.push(new Error(customDedent({dropLowest:true})`
|
317 | The \`template.docs\` field must exist for the creation of the
|
318 | Lattice factory class generation to succeed.
|
319 |
|
320 | Please read the documentation for more information on the format of
|
321 | a LatticeFactory template.
|
322 | `))
|
323 | }
|
324 |
|
325 | if (
|
326 | !extendsFrom(template.docs, Object) // Supports 95% of objects
|
327 | || typeof template.docs !== 'object' // Supports Object.create(null)
|
328 | ) {
|
329 | let dr = '\x1b[31m', br = '\x1b[91m'
|
330 | let b1 = '\x1b[1m', b0 = '\x1b[22m'
|
331 | let bb = '\x1b[90m'
|
332 | let dg = '\x1b[37m', bg = '\x1b[97m'
|
333 | let a0 = '\x1b[0m'
|
334 | let gr = '\x1b[32m', bgr = '\x1b[92m'
|
335 |
|
336 | results.errors.push(new Error(customDedent({dropLowest:true})`\x1b[1;91m
|
337 | The \`template.docs\` field must be an object containing keys and
|
338 | value pairs matching the types, enums, unions and interfaces defined
|
339 | in your schema.
|
340 |
|
341 | The special Symbol object TYPE can be used to reference the docs for
|
342 | the named or keyed field describing the documentation to be processed
|
343 | Comments for the \`Query\`, \`Mutation\`, and \`Subscription\` [TYPE]
|
344 | entries will replace any previous one that comes before it. Typically
|
345 | this field is best left undescribed since there will ever only be
|
346 | one of each at most.
|
347 |
|
348 | \x1b[22;31mExamples should look something like this:\x1b[22;37m
|
349 | import { TYPE, joinLines } from 'graphql-lattice'
|
350 |
|
351 | export default {
|
352 | ${bb}/* other fields */${dg}
|
353 |
|
354 | ${b1}schema:${b0} joinLines${gr}\`
|
355 | type Person { id: ID name: String }
|
356 | type Query { findPerson(id: ID): Person }
|
357 | type Mutation { setPersonName(id: ID, name: String): Person }
|
358 | \`${dg},
|
359 |
|
360 | ${b1}docs:${b0} {
|
361 | ${b1}Person:${b0} {
|
362 | [TYPE]: ${gr}'A contrived person type'${dg},
|
363 | id: ${gr}'A unique identifier for a person'${dg},
|
364 | name: ${gr}'A string denoting the name of a person'${dg}
|
365 | },
|
366 | ${b1}Query:${b0} {
|
367 | findPerson: ${gr}'A query taking an ID, returns a Person'${dg},
|
368 | },
|
369 | ${b1}Mutation:${b0} {
|
370 | setPersonName: joinLines${gr}\`
|
371 | A mutation that sets the name of the user identified by an
|
372 | ID to the new name value supplied
|
373 | \`${dg}
|
374 | }
|
375 | }
|
376 | }
|
377 | \x1b[22;31m
|
378 | Note the usage of \`Person\`, \`Query\` and \`Mutation\` explicitly
|
379 | as keys to the supplied \`docs\` object.\x1b[0m
|
380 | `))
|
381 | }
|
382 |
|
383 | if (!results.valid) {
|
384 | let errorStrings = []
|
385 |
|
386 | for (let error of results.errors) {
|
387 | let { message, stack } = error
|
388 |
|
389 | stack = stack
|
390 | .trim()
|
391 | .split('\n')
|
392 | .splice(message.split('\n').length)
|
393 | .map(s => s.trim())
|
394 | .join('\n')
|
395 | message = message.replace(/(Error:\s)/, '$1\n').trim()
|
396 |
|
397 | errorStrings.push(
|
398 | `\x1b[31;1m${message}\x1b[0m\n` + indent(stack)
|
399 | )
|
400 | }
|
401 |
|
402 | let error = new Error(customDedent({dropLowest:true})`
|
403 | OOPS!
|
404 |
|
405 | An error occurred validating your factory template. The object
|
406 | in question is as follows:
|
407 |
|
408 | @template
|
409 |
|
410 | The individual errors that occurred are:
|
411 | \n@errors`
|
412 | .replace(/@template/, indent(_i(template)))
|
413 | .replace(/@errors/, errorStrings.join('\n\n'))
|
414 | )
|
415 |
|
416 | error.stack = error.message
|
417 | error.message = ''
|
418 |
|
419 | if (!hide) throw error
|
420 | }
|
421 |
|
422 | return results
|
423 | }
|
424 |
|
425 | /**
|
426 | * The starting point of a LatticeFactory object -> class creation. The name
|
427 | * of the class and baseClass to use are provided and are created from there.
|
428 | * At this point, the generated class is still incomplete. It must complete
|
429 | * the entire checklist before being deemed valid.
|
430 | *
|
431 | * @param {string} name name of the class to create
|
432 | * @param {Function} baseClass the Lattice class your new class should extend;
|
433 | * while this can be anything, it should be GQLBase, GQLInterface, GQLEnum or
|
434 | * GQLUnion. This defaults to GQLBase should nothing be supplied
|
435 | * @return {Function} actually this returns the generated class
|
436 | */
|
437 | static generateClass(name: string, baseClass: Function = GQLBase) {
|
438 | if (!name) {
|
439 | throw new Error('LatticeFactory.generateClass needs a name!!')
|
440 | }
|
441 |
|
442 | // Alright ladies and gentlemen, hold onto your hats; we're entering the
|
443 | // meta zone!!! The way the following works is to make sure that our
|
444 | // passed in base class `baseClass` is actually in scope as the name of
|
445 | // the value it represents. We use the `new Function()` syntax to do that
|
446 | // but we do it via eval since we don't know the name of the function
|
447 | // at the time we write the code
|
448 | //
|
449 | // So given a class name of "Car" and baseName equalling GQLBase, the Class
|
450 | // instance, fn would look something like the results of calling this
|
451 | //
|
452 | // let fn = new Function(
|
453 | // "GQLBase",
|
454 | // "class Car extends GQLBase {}; return Car;"
|
455 | // )
|
456 | //
|
457 | // Which in turn sets fn to something that would be the same as
|
458 | //
|
459 | // function fn(GQLBase) { class Car extends GQLBase {}; return Car }
|
460 | //
|
461 | // Which means that when we invoke fn(baseClass), which is fn(GQLBase),
|
462 | // we get the results we intend; even if GQLBase is not necessarily in
|
463 | // the scope of the function at the time of call. Neat. Scary. OMG Thanks
|
464 | // for code comments. You're welcome future me.
|
465 | let fn = eval(`(new Function(
|
466 | "${baseClass.name}",
|
467 | "class ${name} extends ${baseClass.name} {}; return ${name};"
|
468 | ))`);
|
469 |
|
470 | let Class = fn(baseClass)
|
471 |
|
472 | this.brandClass(Class)
|
473 | newChecklist(Class)
|
474 |
|
475 | return Class;
|
476 | }
|
477 |
|
478 | /**
|
479 | * Injects the SCHEMA property into the newly defined class. The supplied
|
480 | * `schema` string becomes what the new class returns when `.SCHEMA` is
|
481 | * gotten.
|
482 | *
|
483 | * @param {Function} Class this will throw an error if the class is not one
|
484 | * generated by the LatticeFactory or if the class itself is null or undefined
|
485 | * @param {string} schema the string that the new class should return
|
486 | * @return {Function} returns the modified Class with the `CHECK_SCHEMA`
|
487 | * portion ticked off internally.
|
488 | */
|
489 | static injectSchema(Class: Function, schema: string) {
|
490 | if (!Class || !hasChecklist(Class)) {
|
491 | throw new Error(customDedent({dropLowest:true})`
|
492 | Either the supplied schema string is invalid
|
493 | SCHEMA: \`
|
494 | ${schema}
|
495 | \`
|
496 |
|
497 | Or your supplied class ${(Class && Class.name) || 'undefined'} is
|
498 | non-existent. Please check your code and try the LatticeFactory
|
499 | again.
|
500 | `)
|
501 | }
|
502 |
|
503 | // $FlowFixMe
|
504 | Object.defineProperty(Class, 'SCHEMA', {
|
505 | get() { return schema }
|
506 | })
|
507 |
|
508 | setChecklist(Class, CHECK_SCHEMA)
|
509 |
|
510 | return Class
|
511 | }
|
512 |
|
513 | /**
|
514 | * Injects the resolvers into appropriate areas. Resolvers keyed by `Query`,
|
515 | * `Mutation`, or `Subscription` will be placed into the appropriate area
|
516 | * in `Class[META_KEY]` which acts as a staging area originally designed for
|
517 | * use with the @resolver, @mutator and @subscriptor decorators. These will
|
518 | * be bound in a typical fashion as is done with the decorators making the
|
519 | * first parameter becoming the requestData of the object instance and the
|
520 | * second being the object containing the parameters for the resolver as
|
521 | * passed in by GraphQL. Subsequent parameters will be supplied as is the
|
522 | * fashion of the system you're using; Facebook's reference implementation or
|
523 | * Apollo or something else.
|
524 | *
|
525 | * Resolvers keyed by type name are considered to be field resolvers and
|
526 | * have a different signature. They can be properties of the key, in
|
527 | * which case they will simply be installed as getters. Or they can be
|
528 | * functions; synchronous or asynchronous. Function field resolvers are
|
529 | * instance methods and can make use of `this.getModel()` or
|
530 | * `this.requestData` internally.
|
531 | *
|
532 | * @param {Function} Class the class, generated by generateClass() lest an
|
533 | * error be thrown, to which to add the resolvers from a template
|
534 | * @param {Object} resolverObj an object containing the resolvers as dictated
|
535 | * by the new format.
|
536 | * @return {Function} returns the modified Class with the `CHECK_RESOLVERS`
|
537 | * portion ticked off internally.
|
538 | */
|
539 | static injectResolvers(Class: Function, resolvers: Object): Function {
|
540 | if (!hasChecklist(Class, CHECK_SCHEMA)) {
|
541 | throw new Error(customDedent({dropLowest:true})`
|
542 | \`injectResolvers\` cannot be called on a class without a SCHEMA.
|
543 | Please verify your progress in the process and try again.
|
544 | `)
|
545 | }
|
546 |
|
547 | let tree = SyntaxTree.from(Class.SCHEMA)
|
548 | let outline = tree ? tree.outline : {}
|
549 |
|
550 | if (Class.name in outline && Class.name in resolvers) {
|
551 | let fields = Object.keys(outline[Class.name])
|
552 |
|
553 | for (let fieldResolver of fields) {
|
554 | if (!fieldResolver in resolvers[Class.name]) {
|
555 | LL.warn(customDedent({dropLowest: true})`
|
556 | ${fieldResolver} not supplied in resolvers for ${Class.name}
|
557 | `)
|
558 | continue;
|
559 | }
|
560 |
|
561 | let prop = resolvers[Class.name][fieldResolver]
|
562 |
|
563 | if (prop && typeof prop === 'function') {
|
564 | LL.info('Injecting [fn] %s', fieldResolver)
|
565 | Object.defineProperty(Class.prototype, fieldResolver, {
|
566 | value: prop
|
567 | })
|
568 | }
|
569 | else {
|
570 | LL.info('Injecting [prop] %s', fieldResolver)
|
571 | Properties(fieldResolver)(Class, ['factory-props'])
|
572 | }
|
573 | }
|
574 | }
|
575 |
|
576 | for (let [type: string, decorator: Function] of [
|
577 | ['Query', resolver],
|
578 | ['Mutation', mutator],
|
579 | ['Subscription', subscriptor]
|
580 | ]) {
|
581 | let keys = Object.keys(outline[type] || {})
|
582 |
|
583 | // $FlowFixMe
|
584 | if (!type in outline || !keys.length) { continue; }
|
585 |
|
586 | for (let fnName of keys) {
|
587 | let fn = resolvers[fnName]
|
588 | decorator(Class, fnName, {value: fn})
|
589 | LL.info('Adding %s resolver [%s]', type, fnName)
|
590 | }
|
591 | }
|
592 |
|
593 | setChecklist(Class, CHECK_RESOLVERS)
|
594 |
|
595 | return Class
|
596 | }
|
597 |
|
598 | static injectDocs(Class: Function, docs: Object): Function {
|
599 | if (!hasChecklist(Class, CHECK_SCHEMA, CHECK_RESOLVERS)) {
|
600 | throw new Error(customDedent({dropLowest:true})`
|
601 | \`injectDocs\` cannot be called on a class without a SCHEMA or
|
602 | RESOLVERS defined. Please verify your progress in the process and try
|
603 | again.
|
604 | `)
|
605 | }
|
606 |
|
607 | let copyProp = (
|
608 | o: mixed,
|
609 | prop: string | Symbol,
|
610 | to: mixed,
|
611 | as: ?(string | Symbol)
|
612 | ): mixed => {
|
613 | // $FlowFixMe
|
614 | let prototype = o.prototype || Object.getPrototypeOf(o)
|
615 | let descriptor = Object.getOwnPropertyDescriptor(prototype, prop)
|
616 |
|
617 | if (!as) {
|
618 | as = prop
|
619 | }
|
620 |
|
621 | if (descriptor) {
|
622 | Object.defineProperty(to, as, descriptor)
|
623 | }
|
624 | else {
|
625 | // $FlowFixMe
|
626 | to[as] = o[prop]
|
627 | }
|
628 | }
|
629 |
|
630 | // Create an object our future `static apiDocs()` method of our factory
|
631 | // generated class will return
|
632 | let result = {}
|
633 |
|
634 | // Setup the constants we will need in this conversion
|
635 | const { TYPE } = this;
|
636 | const {
|
637 | DOC_CLASS, DOC_FIELDS, DOC_QUERY, DOC_MUTATION, DOC_SUBSCRIPTION,
|
638 | DOC_QUERIES, DOC_MUTATIONS, DOC_SUBSCRIPTIONS
|
639 | } = GQLBase
|
640 |
|
641 | // This part might get a little meta, so I have provided comments. You are
|
642 | // welcome future me. I hope it helps. This gnarly block should cover all
|
643 | // the descriptions for Query, Mutation, Subscription and the Class we
|
644 | // are creating. Other superfluous
|
645 | for (let [Type, TopLevelConstant, FieldConstants] of [
|
646 | ['Query', DOC_QUERY, DOC_QUERIES],
|
647 | ['Mutation', DOC_MUTATION, DOC_MUTATIONS],
|
648 | ['Subscription', DOC_SUBSCRIPTION, DOC_SUBSCRIPTIONS],
|
649 | [Class.name, DOC_CLASS, DOC_FIELDS]
|
650 | ]) {
|
651 | // One of 'Query', 'Mutation', or 'Subscription'
|
652 | if (docs[Type]) {
|
653 | // If a top level description is present (i.e. Query, Mutation or
|
654 | // Subscription description)
|
655 | if (docs[Type][TYPE]) {
|
656 | copyProp(docs[Type], TYPE, result, TopLevelConstant)
|
657 | }
|
658 |
|
659 | // Fetch the properties from the supplied docs object; TYPE Symbols
|
660 | // do not show up in a call to entries which is why it is handled above
|
661 | // $FlowFixMe
|
662 | let entries = Object.entries(docs[Type])
|
663 |
|
664 | // If we have entries to document, create an object to hold those
|
665 | // values; i.e. if we have `{ Query: { getPeople: 'desc' } }`, we need
|
666 | // to make sure we have `{ [DOC_QUERIES]: { getPeople: 'desc' } }` in
|
667 | // our result. The object holding getPeople in the end there is defined
|
668 | // below when we have something to copy.
|
669 | if (entries.length) {
|
670 | result[FieldConstants] = {}
|
671 | }
|
672 |
|
673 | // For each name value pair defined above, copy its descriptor or base
|
674 | // value if a descriptor isn't available
|
675 | for (let [prop, value] of entries) {
|
676 | copyProp(docs[Type], prop, result[FieldConstants])
|
677 | }
|
678 | }
|
679 | }
|
680 |
|
681 | Object.defineProperty(Class, 'apiDocs', {
|
682 | value: function() { return result }
|
683 | })
|
684 |
|
685 | setChecklist(Class, CHECK_API_DOCS)
|
686 |
|
687 | return Class
|
688 | }
|
689 |
|
690 | static build(template: Object): Function {
|
691 | let validationResults = this.validateTemplate(template)
|
692 | let Class = this.generateClass(template.name, template.type || GQLBase)
|
693 |
|
694 | if (!Class) {
|
695 | throw new Error(customDedent({dropLowest: true})`
|
696 | LatticeFactory was unable to build your Class from the name and types
|
697 | supplied in your template. You provided the following template. Please
|
698 | look it over and correct any errors before trying again.
|
699 |
|
700 | \x1b[1mTemplate\x1b[0m
|
701 | ${_i(template)}
|
702 | `)
|
703 | }
|
704 |
|
705 | this.injectSchema(Class, template.schema)
|
706 | this.injectResolvers(Class, template.resolvers || {})
|
707 | this.injectDocs(Class, template.docs || {})
|
708 |
|
709 | // Need to fix how auto-props work; for now create one instance...
|
710 | new Class({})
|
711 |
|
712 | if (!hasChecklist(Class, CHECK_SCHEMA, CHECK_RESOLVERS, CHECK_API_DOCS)) {
|
713 | let _schema = hasChecklist(Class, CHECK_SCHEMA) ? '✅' : '❌'
|
714 | let _resolvers = hasChecklist(Class, CHECK_RESOLVERS) ? '✅' : '❌'
|
715 | let _apiDocs = hasChecklist(Class, CHECK_API_DOCS) ? '✅' : '❌'
|
716 |
|
717 | throw new Error(customDedent({dropLowest: true})`
|
718 | Something went wrong in the process of building the class called
|
719 | ${Class && Class.name || template && template.name || 'Unknown!'},
|
720 | please check the supplied template for errors.
|
721 |
|
722 | [ ${_schema} ] Has a SCHEMA defined
|
723 | [ ${_resolvers} ] Has defined RESOLVERS matching the SCHEMA
|
724 | [ ${_apiDocs} ] Has defined API Docs matching the SCHEMA
|
725 |
|
726 | \x1b[1mTemplate\x1b[0m
|
727 | ${_i(template)}
|
728 |
|
729 | \x1b[1mClass\x1b[0m
|
730 | ${_i(Class)}
|
731 | `)
|
732 | }
|
733 |
|
734 | return Class
|
735 | }
|
736 |
|
737 | /**
|
738 | * A static helper method to consistently tag, or brand, classes with a
|
739 | * symbol that denotes they were created using the LatticeFactory process.
|
740 | * This is done by setting a `Symbol` on the root of the class or in the
|
741 | * `[META_KEY]` object for classes extending `GQLBase`.
|
742 | *
|
743 | * @method ⌾⠀brandClass
|
744 | * @memberof LatticeFactory
|
745 | * @static
|
746 | *
|
747 | * @param {Function} Class the class to brand with the `FACTORY_CLASS` symbol
|
748 | * @return {Function} returns the Class value passed in
|
749 | */
|
750 | static brandClass(Class: ?Function): ?Function {
|
751 | if (Class) {
|
752 | if (extendsFrom(Class, GQLBase)) {
|
753 | Class[META_KEY][this.FACTORY_CLASS] = true
|
754 | }
|
755 | else {
|
756 | Class[this.FACTORY_CLASS] = true
|
757 | }
|
758 | }
|
759 |
|
760 | return Class
|
761 | }
|
762 |
|
763 | /**
|
764 | * A static helper to check and see if the supplied class or function was
|
765 | * branded with the `brandClass()` function. This amounts to storing the
|
766 | * boolean true under the property `Class[LatticeFactory.FACTORY_CLASS]` or
|
767 | * `Class[META_KEY][LatticeFacatory.FACTORY_CLASS]` for `GQLBase` extended
|
768 | * classes.
|
769 | *
|
770 | * @method ⌾⠀isFactoryClass
|
771 | * @memberof LatticeFactory
|
772 | * @static
|
773 | *
|
774 | * @param {Function} Class the class to check for `FACTORY_CLASS` branding
|
775 | * @return {boolean} true if the brand exists, false otherwise
|
776 | */
|
777 | static isFactoryClass(Class: Function): boolean {
|
778 | if (Class) {
|
779 | return (extendsFrom(Class, GQLBase)
|
780 | ? !!Class[META_KEY][this.FACTORY_CLASS]
|
781 | : !!Class[this.FACTORY_CLASS]
|
782 | )
|
783 | }
|
784 |
|
785 | return false
|
786 | }
|
787 |
|
788 | /**
|
789 | * A static helper method to consistently remove any previous tag or brand
|
790 | * applied with `brandClass`, this is done by removing a previously set
|
791 | * `Symbol` on the root of the class or in the `[META_KEY]` object for
|
792 | * classes extending `GQLBase`.
|
793 | *
|
794 | * @method ⌾⠀removeClassBrand
|
795 | * @memberof LatticeFactory
|
796 | * @static
|
797 | *
|
798 | * @param {Function} Class the class to brand with the `FACTORY_CLASS` symbol
|
799 | * @return {Function} returns the Class value passed in
|
800 | */
|
801 | static removeClassBrand(Class: Function): Function {
|
802 | if (Class) {
|
803 | if (extendsFrom(Class, GQLBase)) {
|
804 | delete Class[META_KEY][this.FACTORY_CLASS]
|
805 | }
|
806 | else {
|
807 | delete Class[this.FACTORY_CLASS]
|
808 | }
|
809 | }
|
810 |
|
811 | return Class
|
812 | }
|
813 |
|
814 | /**
|
815 | * A constant that reports that this class is `'[object LatticeFactory]'`
|
816 | * rather than `'[object Object]'` when introspected with tools such as
|
817 | * `Object.prototype.toString.apply(class)`.
|
818 | *
|
819 | * @memberof LatticeFactory
|
820 | * @type {Symbol}
|
821 | * @static
|
822 | */
|
823 | // $FlowFixMe
|
824 | static get [Symbol.toStringTag]() { return this.name }
|
825 |
|
826 | /**
|
827 | * A constant exported as part of LatticeFactory that can be used for
|
828 | * defining documentation for the type itself.
|
829 | *
|
830 | * @memberof LatticeFactory
|
831 | * @type {Symbol}
|
832 | * @static
|
833 | */
|
834 | static get TYPE(): Symbol { return Symbol.for('API Docs Type Constant') }
|
835 |
|
836 | /**
|
837 | * A constant exported as part of LatticeFactory that can be used for
|
838 | * identifying classes that were generated with LatticeFactory.
|
839 | *
|
840 | * @memberof LatticeFactory
|
841 | * @type {Symbol}
|
842 | * @static
|
843 | */
|
844 | static get FACTORY_CLASS(): Symbol { return Symbol.for('Factory Class') }
|
845 | }
|
846 |
|
847 | export const isFactoryClass = LatticeFactory.isFactoryClass
|
848 |
|
849 | // TESTING REPL
|
850 | /**
|
851 | var { LatticeFactory, getChecklist, hasChecklist, CHECKLIST, CHECK_SCHEMA, CHECK_RESOLVERS } = require('./dist/LatticeFactory'); var { GQLBase, META_KEY, joinLines, SyntaxTree, typeOf } = require('./dist/lattice'); var gql = joinLines, LF = LatticeFactory, TYPE = LF.TYPE;
|
852 | var PersonDef = { name: 'Person', schema: gql` enum StatType { PHYSICAL, MENTAL } type Person { name: String stats(type:StatType): Stat } type Query { findPerson(id: ID): Person } `, resolvers: { Query: { findPerson({req, res, next}, {id}) { console.log('find person') } }, Person: { stats({type}) { let { req, res, next} = this.requestData } } }, docs: { StatType: { [TYPE]: `A type of statistic associated with people`, PHYSICAL: `Physical attributes`, MENTAL: `Mental attributes` }, Person: { [TYPE]: `Represents a person`, personId: `Unique id of the person in question`, name: `The name of the person`, stats: `Allows you to query the stats of a person based on type` }, Query: { [TYPE]: 'Top level query desc.', findPerson: `Searches the system for the specified user` } } };
|
853 | var Person = LF.build(PersonDef), p = new Person({name: 'Brielle'})
|
854 | Person.getProp('stats',true,{requestData:{req:1,res:2,next:3}})
|
855 | var Broke = LF.build({name: 'Broke', schema: gql`type Broke {name: String}`, resolvers:{}, docs:{}})
|
856 | var t = LF.validateTemplate({name: '', type: GQLBase, resolvers: {}, docs: {}, schema: ''});
|
857 | */
|
858 | </code></pre>
|
859 | </article>
|
860 | </section>
|
861 |
|
862 |
|
863 |
|
864 |
|
865 | </div>
|
866 |
|
867 | <br class="clear">
|
868 |
|
869 | <footer>
|
870 | Generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Fri Jun 08 2018 19:28:39 GMT-0700 (PDT) using the Minami theme.
|
871 | </footer>
|
872 |
|
873 | <script>prettyPrint();</script>
|
874 | <script src="scripts/linenumber.js"></script>
|
875 | </body>
|
876 | </html>
|