UNPKG

3.69 kBJavaScriptView Raw
1const debug = require('debug')('upward-js:ResolverVisitor');
2const { inspect } = require('util');
3const { ResolverList, ResolversByType } = require('./resolvers');
4const { zipObject } = require('lodash');
5const isPrimitive = require('./isPrimitive');
6
7class ResolverVisitor {
8 constructor(io, rootDefinition, context, upwardPath) {
9 this.io = io;
10 this.rootDefinition = rootDefinition;
11 this.context = context;
12 this.upwardPath = upwardPath;
13 this.context.setVisitor(this);
14 }
15 async downward(contextNames) {
16 debug('resolving downward: %o', contextNames);
17 let passedMiddleware = false;
18 const valuePromises = contextNames.map(async name => {
19 const value = await this.upward(this.rootDefinition, name);
20 if (typeof value === 'function') {
21 debug(
22 '%s request returned a function, we are assuming it is a middleware'
23 );
24 passedMiddleware = value;
25 throw new Error('PASSED_MIDDLEWARE');
26 }
27 return value;
28 });
29 try {
30 const values = await Promise.all(valuePromises);
31 return zipObject(contextNames, values);
32 } catch (e) {
33 if (e.message === 'PASSED_MIDDLEWARE') {
34 debug(
35 `returning middleware from visitor.downward() instead of object`
36 );
37 return passedMiddleware;
38 } else {
39 throw e;
40 }
41 }
42 }
43 async upward(definition, propertyName) {
44 debug('resolving upward: %s from %o', propertyName, definition);
45 if (!definition.hasOwnProperty(propertyName)) {
46 throw new Error(
47 `Context value '${propertyName}' not defined in ${inspect(
48 definition
49 )}.`
50 );
51 }
52 const defined = definition[propertyName];
53
54 const resolver = this.getResolverFor(defined, propertyName);
55
56 if (resolver) {
57 return resolver.resolve(defined);
58 }
59
60 if (isPrimitive(defined)) {
61 debug(
62 'defined: %s is primitive, yielding to context.get("%s")',
63 defined,
64 defined
65 );
66 return this.context.get(defined);
67 }
68
69 if (typeof defined !== 'object' || !this.getResolverFailure) {
70 throw new Error(`Unexpected value in config: ${defined}`);
71 } else {
72 throw new Error(this.getResolverFailure);
73 }
74 }
75 getResolverFor(defined, propertyName) {
76 let Resolver;
77 for (Resolver of ResolverList) {
78 const recognized =
79 Resolver.recognize && Resolver.recognize(defined);
80 if (recognized) {
81 return {
82 resolve: () => new Resolver(this).resolve(recognized)
83 };
84 }
85 }
86 if (defined.resolver) {
87 Resolver = ResolversByType[defined.resolver];
88 if (!Resolver) {
89 this.getResolverFailure = `Unrecognized resolver type: ${
90 defined.resolver
91 }`;
92 }
93 } else {
94 Resolver = ResolverList.find(({ telltale }) =>
95 defined.hasOwnProperty(telltale)
96 );
97 if (!Resolver) {
98 this.getResolverFailure = `Unrecognized configuration. Could not match a resolver to ${propertyName}: ${inspect(
99 defined
100 )}`;
101 }
102 }
103 if (Resolver) return new Resolver(this);
104 }
105}
106
107module.exports = ResolverVisitor;