UNPKG

5.25 kBJavaScriptView Raw
1/**
2 * The handler, an instance of which is created for every instance of GQLBase.
3 * The handler manages the fetching and decoding of files bearing the IDL
4 * schema associated with the class represented by this instance of GQLBase.
5 *
6 * @class IDLFileHandler
7 */
8export class IDLFileHandler {
9 path: ?string;
10
11 extension: ?string;
12
13 /**
14 * The IDLFileHandler checks the SCHEMA value returned by the class type
15 * of the supplied instance. If the resulting value is a Symbol, then the
16 * handler's responsibility is to find the file, load it from disk and
17 * provide various means of using its contents; i.e. as a Buffer, a String
18 * or wrapped in a SyntaxTree instance.
19 *
20 * @memberof IDLFileHandler
21 * @method ⎆⠀constructor
22 * @constructor
23 *
24 * @param {Function} Class a function or class definition that presumably
25 * extends from GQLBase were it an instance.
26 */
27 constructor(Class: Function) {
28 // $FlowFixMe
29 const symbol = typeof Class.SCHEMA === 'symbol' && Class.SCHEMA || null;
30 const pattern = /Symbol\(Path (.*?) Extension (.*?)\)/;
31
32 if (symbol) {
33 let symbolString = symbol.toString();
34
35 if (symbol === Class.ADJACENT_FILE) {
36 if (Class.module === module) {
37 throw new Error(`
38 The a static getter for 'module' on ${Class.name} must be present
39 that returns the module object where the Class is defined. Try the
40 following:
41
42 // your ${Class.name}.js file
43 import { GQLBase } from 'graphql-lattice'
44
45 const ${Class.name}Module = module;
46
47 class ${Class.name} extends GQLBase {
48 ...
49
50 static get module() {
51 return ${Class.name}Module;
52 }
53 }
54
55 `);
56 }
57
58 const filename = Class.module.filename;
59 const extension = Path.extname(filename)
60 const dir = Path.dirname(filename)
61 const filefixed = Path.basename(filename, extension)
62 const build = Path.resolve(Path.join(dir, `${filefixed}.graphql`))
63
64 this.path = build;
65 this.extension = '.graphql';
66 }
67 else if (pattern.test(symbolString)) {
68 const parsed = pattern.exec(symbolString);
69 const extension = parsed[2] || '.graphql'
70 const dir = Path.dirname(parsed[1])
71 const file = Path.basename(parsed[1], extension)
72 const build = Path.resolve(Path.join(dir, `${file}${extension}`))
73
74 this.path = build;
75 this.extension = extension;
76 }
77 }
78 else {
79 this.path = this.extension = null;
80 }
81 }
82
83 /**
84 * Loads the calculated file determined by the decoding of the meaning of
85 * the Symbol returned by the SCHEMA property of the instance supplied to
86 * the IDLFileHandler upon creation.
87 *
88 * @instance
89 * @memberof IDLFileHandler
90 * @method ⌾⠀getFile
91 *
92 * @return {Buffer|null} returns the Buffer containing the file base IDL
93 * schema or null if none was found or a direct string schema is returned
94 * by the SCHEMA property
95 */
96 getFile(): Buffer {
97 return fs.readFileSync(String(this.path));
98 }
99
100 /**
101 * If getFile() returns a Buffer, this is the string representation of the
102 * underlying file contents. As a means of validating the contents of the
103 * file, the string contents are parsed into an AST and back to a string.
104 *
105 * @instance
106 * @memberof IDLFileHandler
107 * @method ⌾⠀getSchema
108 *
109 * @return {string|null} the string contents of the Buffer containing the
110 * file based IDL schema.
111 */
112 getSchema(): ?string {
113 if (!this.path) { return null; }
114
115 const tree = this.getSyntaxTree();
116
117 return tree.toString();
118 }
119
120 /**
121 * If getFile() returns a Buffer, the string contents are passed to a new
122 * instance of SyntaxTree which parses this into an AST for manipulation.
123 *
124 * @instance
125 * @memberof IDLFileHandler
126 * @method ⌾⠀getSyntaxTree
127 *
128 * @return {SyntaxTree|null} a SyntaxTree instance constructed from the IDL
129 * schema contents loaded from disk. Null is returned if a calculated path
130 * cannot be found; always occurs when SCHEMA returns a string.
131 */
132 getSyntaxTree(): SyntaxTree {
133 const buffer = this.getFile();
134 const tree = new SyntaxTree(buffer.toString());
135
136 return tree;
137 }
138
139 /**
140 * Returns the `constructor` name. If invoked as the context, or `this`,
141 * object of the `toString` method of `Object`'s `prototype`, the resulting
142 * value will be `[object MyClass]`, given an instance of `MyClass`
143 *
144 * @method ⌾⠀[Symbol.toStringTag]
145 * @memberof IDLFileHandler
146 *
147 * @return {string} the name of the class this is an instance of
148 * @ComputedType
149 */
150 get [Symbol.toStringTag]() { return this.constructor.name }
151
152 /**
153 * Applies the same logic as {@link #[Symbol.toStringTag]} but on a static
154 * scale. So, if you perform `Object.prototype.toString.call(MyClass)`
155 * the result would be `[object MyClass]`.
156 *
157 * @method ⌾⠀[Symbol.toStringTag]
158 * @memberof IDLFileHandler
159 * @static
160 *
161 * @return {string} the name of this class
162 * @ComputedType
163 */
164 static get [Symbol.toStringTag]() { return this.name }
165}
166
167export default IDLFileHandler
\No newline at end of file