graphql-modules 3.1.2-alpha-20260121024117-e03d9c26de1cfd3971986f82b995963e1cc77056 → 3.1.2-alpha-20260121025807-95ab4fb1994c3cf68c88a7cf234efd8f99f92ed1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/application/apollo.js +81 -0
- package/cjs/application/application.js +149 -0
- package/cjs/application/context.js +144 -0
- package/cjs/application/di.js +48 -0
- package/cjs/application/execution.js +42 -0
- package/cjs/application/operation-controller.js +16 -0
- package/cjs/application/subscription.js +54 -0
- package/cjs/application/tokens.js +20 -0
- package/cjs/application/types.js +0 -0
- package/cjs/async-context.browser.mjs +7 -0
- package/cjs/async-context.node.cjs +14 -0
- package/cjs/di/decorators.js +78 -0
- package/cjs/di/errors.js +87 -0
- package/cjs/di/forward-ref.js +26 -0
- package/cjs/di/index.js +19 -0
- package/cjs/di/injector.js +173 -0
- package/cjs/di/metadata.js +22 -0
- package/cjs/di/providers.js +60 -0
- package/cjs/di/registry.js +44 -0
- package/cjs/di/resolution.js +166 -0
- package/cjs/di/utils.js +44 -0
- package/cjs/index.js +31 -0
- package/cjs/module/factory.js +71 -0
- package/cjs/module/metadata.js +110 -0
- package/cjs/module/module.js +27 -0
- package/cjs/module/resolvers.js +341 -0
- package/cjs/module/tokens.js +21 -0
- package/cjs/module/type-defs.js +24 -0
- package/cjs/module/types.js +0 -0
- package/cjs/package.json +9 -0
- package/cjs/shared/di.js +0 -0
- package/cjs/shared/errors.js +82 -0
- package/cjs/shared/gql.js +12 -0
- package/cjs/shared/middleware.js +109 -0
- package/cjs/shared/types.js +0 -0
- package/cjs/shared/utils.js +115 -0
- package/cjs/testing/di.js +9 -0
- package/cjs/testing/graphql.js +10 -0
- package/cjs/testing/index.js +17 -0
- package/cjs/testing/test-application.js +65 -0
- package/cjs/testing/test-injector.js +22 -0
- package/cjs/testing/test-module.js +270 -0
- package/esm/application/apollo.js +77 -0
- package/esm/application/application.js +146 -0
- package/esm/application/context.js +140 -0
- package/esm/application/di.js +42 -0
- package/esm/application/execution.js +39 -0
- package/esm/application/operation-controller.js +13 -0
- package/esm/application/subscription.js +51 -0
- package/esm/application/tokens.js +17 -0
- package/esm/application/types.js +0 -0
- package/esm/async-context.browser.mjs +7 -0
- package/esm/async-context.node.cjs +14 -0
- package/esm/di/decorators.js +72 -0
- package/esm/di/errors.js +79 -0
- package/esm/di/forward-ref.js +22 -0
- package/esm/di/index.js +4 -0
- package/esm/di/injector.js +168 -0
- package/esm/di/metadata.js +17 -0
- package/esm/di/providers.js +50 -0
- package/esm/di/registry.js +40 -0
- package/esm/di/resolution.js +159 -0
- package/esm/di/utils.js +36 -0
- package/esm/index.js +16 -0
- package/esm/module/factory.js +68 -0
- package/esm/module/metadata.js +107 -0
- package/esm/module/module.js +24 -0
- package/esm/module/resolvers.js +337 -0
- package/esm/module/tokens.js +18 -0
- package/esm/module/type-defs.js +21 -0
- package/esm/module/types.js +0 -0
- package/esm/shared/di.js +0 -0
- package/esm/shared/errors.js +69 -0
- package/esm/shared/gql.js +9 -0
- package/esm/shared/middleware.js +103 -0
- package/esm/shared/types.js +0 -0
- package/esm/shared/utils.js +101 -0
- package/esm/testing/di.js +6 -0
- package/esm/testing/graphql.js +7 -0
- package/esm/testing/index.js +14 -0
- package/esm/testing/test-application.js +62 -0
- package/esm/testing/test-injector.js +18 -0
- package/esm/testing/test-module.js +266 -0
- package/package.json +29 -9
- package/typings/application/apollo.d.ts +22 -0
- package/typings/application/application.d.ts +32 -0
- package/typings/application/context.d.ts +24 -0
- package/typings/application/di.d.ts +22 -0
- package/typings/application/execution.d.ts +8 -0
- package/typings/application/operation-controller.d.ts +5 -0
- package/typings/application/subscription.d.ts +8 -0
- package/typings/application/tokens.d.ts +17 -0
- package/typings/application/types.d.ts +130 -0
- package/typings/di/decorators.d.ts +11 -0
- package/typings/di/errors.d.ts +16 -0
- package/typings/di/forward-ref.d.ts +7 -0
- package/typings/di/index.d.ts +5 -0
- package/typings/di/injector.d.ts +50 -0
- package/typings/di/metadata.d.ts +12 -0
- package/typings/di/providers.d.ts +44 -0
- package/typings/di/registry.d.ts +11 -0
- package/typings/di/resolution.d.ts +63 -0
- package/typings/di/utils.d.ts +8 -0
- package/typings/index.d.ts +13 -0
- package/typings/module/factory.d.ts +16 -0
- package/typings/module/metadata.d.ts +12 -0
- package/typings/module/module.d.ts +22 -0
- package/typings/module/resolvers.d.ts +13 -0
- package/typings/module/tokens.d.ts +18 -0
- package/typings/module/type-defs.d.ts +7 -0
- package/typings/module/types.d.ts +51 -0
- package/typings/shared/di.d.ts +3 -0
- package/typings/shared/errors.d.ts +36 -0
- package/typings/shared/gql.d.ts +2 -0
- package/typings/shared/middleware.d.ts +21 -0
- package/typings/shared/types.d.ts +22 -0
- package/typings/shared/utils.d.ts +12 -0
- package/typings/testing/di.d.ts +2 -0
- package/typings/testing/graphql.d.ts +14 -0
- package/typings/testing/index.d.ts +14 -0
- package/typings/testing/test-application.d.ts +2 -0
- package/typings/testing/test-injector.d.ts +4 -0
- package/typings/testing/test-module.d.ts +10 -0
- package/LICENSE.md +0 -21
- package/index.js +0 -2359
- package/index.mjs +0 -2344
- /package/{application/apollo.d.ts → typings/application/apollo.d.cts} +0 -0
- /package/{application/application.d.ts → typings/application/application.d.cts} +0 -0
- /package/{application/context.d.ts → typings/application/context.d.cts} +0 -0
- /package/{application/di.d.ts → typings/application/di.d.cts} +0 -0
- /package/{application/execution.d.ts → typings/application/execution.d.cts} +0 -0
- /package/{application/operation-controller.d.ts → typings/application/operation-controller.d.cts} +0 -0
- /package/{application/subscription.d.ts → typings/application/subscription.d.cts} +0 -0
- /package/{application/tokens.d.ts → typings/application/tokens.d.cts} +0 -0
- /package/{application/types.d.ts → typings/application/types.d.cts} +0 -0
- /package/{di/decorators.d.ts → typings/di/decorators.d.cts} +0 -0
- /package/{di/errors.d.ts → typings/di/errors.d.cts} +0 -0
- /package/{di/forward-ref.d.ts → typings/di/forward-ref.d.cts} +0 -0
- /package/{di/index.d.ts → typings/di/index.d.cts} +0 -0
- /package/{di/injector.d.ts → typings/di/injector.d.cts} +0 -0
- /package/{di/metadata.d.ts → typings/di/metadata.d.cts} +0 -0
- /package/{di/providers.d.ts → typings/di/providers.d.cts} +0 -0
- /package/{di/registry.d.ts → typings/di/registry.d.cts} +0 -0
- /package/{di/resolution.d.ts → typings/di/resolution.d.cts} +0 -0
- /package/{di/utils.d.ts → typings/di/utils.d.cts} +0 -0
- /package/{index.d.ts → typings/index.d.cts} +0 -0
- /package/{module/factory.d.ts → typings/module/factory.d.cts} +0 -0
- /package/{module/metadata.d.ts → typings/module/metadata.d.cts} +0 -0
- /package/{module/module.d.ts → typings/module/module.d.cts} +0 -0
- /package/{module/resolvers.d.ts → typings/module/resolvers.d.cts} +0 -0
- /package/{module/tokens.d.ts → typings/module/tokens.d.cts} +0 -0
- /package/{module/type-defs.d.ts → typings/module/type-defs.d.cts} +0 -0
- /package/{module/types.d.ts → typings/module/types.d.cts} +0 -0
- /package/{shared/di.d.ts → typings/shared/di.d.cts} +0 -0
- /package/{shared/errors.d.ts → typings/shared/errors.d.cts} +0 -0
- /package/{shared/gql.d.ts → typings/shared/gql.d.cts} +0 -0
- /package/{shared/middleware.d.ts → typings/shared/middleware.d.cts} +0 -0
- /package/{shared/types.d.ts → typings/shared/types.d.cts} +0 -0
- /package/{shared/utils.d.ts → typings/shared/utils.d.cts} +0 -0
- /package/{testing/di.d.ts → typings/testing/di.d.cts} +0 -0
- /package/{testing/graphql.d.ts → typings/testing/graphql.d.cts} +0 -0
- /package/{testing/index.d.ts → typings/testing/index.d.cts} +0 -0
- /package/{testing/test-application.d.ts → typings/testing/test-application.d.cts} +0 -0
- /package/{testing/test-injector.d.ts → typings/testing/test-injector.d.cts} +0 -0
- /package/{testing/test-module.d.ts → typings/testing/test-module.d.cts} +0 -0
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import { GraphQLScalarType, concatAST, Kind, defaultFieldResolver, } from 'graphql';
|
|
2
|
+
import { useLocation, ExtraResolverError, ResolverDuplicatedError, ResolverInvalidError, } from './../shared/errors';
|
|
3
|
+
import { isNil, isDefined, isPrimitive } from '../shared/utils';
|
|
4
|
+
import { createMiddleware, mergeMiddlewareMaps, validateMiddlewareMap, } from '../shared/middleware';
|
|
5
|
+
const resolverMetadataProp = Symbol('metadata');
|
|
6
|
+
export function createResolvers(config, metadata, app) {
|
|
7
|
+
const ensure = ensureImplements(metadata);
|
|
8
|
+
const normalizedModuleMiddlewareMap = config.middlewares || {};
|
|
9
|
+
const middlewareMap = mergeMiddlewareMaps(app.middlewareMap, normalizedModuleMiddlewareMap);
|
|
10
|
+
validateMiddlewareMap(normalizedModuleMiddlewareMap, metadata);
|
|
11
|
+
const resolvers = addDefaultResolvers(mergeResolvers(config), middlewareMap, config);
|
|
12
|
+
// Wrap resolvers
|
|
13
|
+
for (const typeName in resolvers) {
|
|
14
|
+
if (resolvers.hasOwnProperty(typeName)) {
|
|
15
|
+
const obj = resolvers[typeName];
|
|
16
|
+
if (isScalarResolver(obj)) {
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
else if (isEnumResolver(obj)) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
else if (obj && typeof obj === 'object') {
|
|
23
|
+
for (const fieldName in obj) {
|
|
24
|
+
if (obj.hasOwnProperty(fieldName)) {
|
|
25
|
+
ensure.type(typeName, fieldName);
|
|
26
|
+
const path = [typeName, fieldName];
|
|
27
|
+
// function
|
|
28
|
+
if (isResolveFn(obj[fieldName])) {
|
|
29
|
+
const resolver = wrapResolver({
|
|
30
|
+
config,
|
|
31
|
+
resolver: obj[fieldName],
|
|
32
|
+
middlewareMap,
|
|
33
|
+
path,
|
|
34
|
+
isTypeResolver: fieldName === '__isTypeOf' || fieldName === '__resolveType',
|
|
35
|
+
isReferenceResolver: fieldName === '__resolveReference',
|
|
36
|
+
isObjectResolver: fieldName === '__resolveObject',
|
|
37
|
+
});
|
|
38
|
+
resolvers[typeName][fieldName] = resolver;
|
|
39
|
+
}
|
|
40
|
+
else if (isResolveOptions(obj[fieldName])) {
|
|
41
|
+
// { resolve }
|
|
42
|
+
if (isDefined(obj[fieldName].resolve)) {
|
|
43
|
+
const resolver = wrapResolver({
|
|
44
|
+
config,
|
|
45
|
+
resolver: obj[fieldName].resolve,
|
|
46
|
+
middlewareMap,
|
|
47
|
+
path,
|
|
48
|
+
});
|
|
49
|
+
resolvers[typeName][fieldName].resolve = resolver;
|
|
50
|
+
}
|
|
51
|
+
// { subscribe }
|
|
52
|
+
if (isDefined(obj[fieldName].subscribe)) {
|
|
53
|
+
const resolver = wrapResolver({
|
|
54
|
+
config,
|
|
55
|
+
resolver: obj[fieldName].subscribe,
|
|
56
|
+
middlewareMap,
|
|
57
|
+
path,
|
|
58
|
+
});
|
|
59
|
+
resolvers[typeName][fieldName].subscribe = resolver;
|
|
60
|
+
}
|
|
61
|
+
if (isDefined(obj[fieldName].extensions)) {
|
|
62
|
+
// Do NOT add a resolve if one is not specified, it will cause
|
|
63
|
+
// change in behavior in systems like `grafast`
|
|
64
|
+
resolvers[typeName][fieldName].extensions =
|
|
65
|
+
obj[fieldName].extensions;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return resolvers;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Wrap a resolver so we use module's context instead of app context.
|
|
77
|
+
* Use a middleware if available.
|
|
78
|
+
* Attach metadata to a resolver (we will see if it's helpful, probably in error handling)
|
|
79
|
+
*/
|
|
80
|
+
function wrapResolver({ resolver, config, path, middlewareMap, isTypeResolver, isReferenceResolver, isObjectResolver, }) {
|
|
81
|
+
if (isTypeResolver || isReferenceResolver) {
|
|
82
|
+
const wrappedResolver = (root, context, info) => {
|
|
83
|
+
const ctx = {
|
|
84
|
+
root,
|
|
85
|
+
context: isReferenceResolver
|
|
86
|
+
? context.ɵgetModuleContext(config.id, context)
|
|
87
|
+
: // We mark the context object as possibly undefined,
|
|
88
|
+
// because graphql-jit for some reason doesn't pass it for isTypeOf or resolveType methods
|
|
89
|
+
context === null || context === void 0 ? void 0 : context.ɵgetModuleContext(config.id, context),
|
|
90
|
+
info,
|
|
91
|
+
};
|
|
92
|
+
return resolver(ctx.root, ctx.context, ctx.info);
|
|
93
|
+
};
|
|
94
|
+
writeResolverMetadata(wrappedResolver, config);
|
|
95
|
+
return wrappedResolver;
|
|
96
|
+
}
|
|
97
|
+
if (isObjectResolver) {
|
|
98
|
+
const wrappedResolver = (root, fields, context, info) => {
|
|
99
|
+
const moduleContext = context.ɵgetModuleContext(config.id, context);
|
|
100
|
+
return resolver(root, fields, moduleContext, info);
|
|
101
|
+
};
|
|
102
|
+
writeResolverMetadata(wrappedResolver, config);
|
|
103
|
+
return wrappedResolver;
|
|
104
|
+
}
|
|
105
|
+
const middleware = createMiddleware(path, middlewareMap);
|
|
106
|
+
const wrappedResolver = (root, args, context, info) => {
|
|
107
|
+
const ctx = {
|
|
108
|
+
root,
|
|
109
|
+
args,
|
|
110
|
+
context: context.ɵgetModuleContext(config.id, context),
|
|
111
|
+
info,
|
|
112
|
+
};
|
|
113
|
+
return middleware(ctx, () => resolver(ctx.root, ctx.args, ctx.context, ctx.info));
|
|
114
|
+
};
|
|
115
|
+
writeResolverMetadata(wrappedResolver, config);
|
|
116
|
+
return wrappedResolver;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* We iterate over every defined resolver and check if it's valid and not duplicated
|
|
120
|
+
*/
|
|
121
|
+
function mergeResolvers(config) {
|
|
122
|
+
if (!config.resolvers) {
|
|
123
|
+
return {};
|
|
124
|
+
}
|
|
125
|
+
const resolvers = Array.isArray(config.resolvers)
|
|
126
|
+
? config.resolvers
|
|
127
|
+
: [config.resolvers];
|
|
128
|
+
const container = {};
|
|
129
|
+
for (const currentResolvers of resolvers) {
|
|
130
|
+
for (const typeName in currentResolvers) {
|
|
131
|
+
if (currentResolvers.hasOwnProperty(typeName)) {
|
|
132
|
+
const value = currentResolvers[typeName];
|
|
133
|
+
if (isNil(value)) {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
else if (isScalarResolver(value)) {
|
|
137
|
+
addScalar({ typeName, resolver: value, container, config });
|
|
138
|
+
}
|
|
139
|
+
else if (isEnumResolver(value)) {
|
|
140
|
+
addEnum({ typeName, resolver: value, container, config });
|
|
141
|
+
}
|
|
142
|
+
else if (value && typeof value === 'object') {
|
|
143
|
+
addObject({ typeName, fields: value, container, config });
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
throw new ResolverInvalidError(`Resolver of "${typeName}" is invalid`, useLocation({ dirname: config.dirname, id: config.id }));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return container;
|
|
152
|
+
}
|
|
153
|
+
function addObject({ typeName, fields, container, config, }) {
|
|
154
|
+
if (!container[typeName]) {
|
|
155
|
+
container[typeName] = {};
|
|
156
|
+
}
|
|
157
|
+
for (const fieldName in fields) {
|
|
158
|
+
if (fields.hasOwnProperty(fieldName)) {
|
|
159
|
+
const resolver = fields[fieldName];
|
|
160
|
+
if (isResolveFn(resolver)) {
|
|
161
|
+
if (container[typeName][fieldName]) {
|
|
162
|
+
throw new ResolverDuplicatedError(`Duplicated resolver of "${typeName}.${fieldName}"`, useLocation({ dirname: config.dirname, id: config.id }));
|
|
163
|
+
}
|
|
164
|
+
writeResolverMetadata(resolver, config);
|
|
165
|
+
container[typeName][fieldName] = resolver;
|
|
166
|
+
}
|
|
167
|
+
else if (isResolveOptions(resolver)) {
|
|
168
|
+
if (!container[typeName][fieldName]) {
|
|
169
|
+
container[typeName][fieldName] = {};
|
|
170
|
+
}
|
|
171
|
+
// resolve
|
|
172
|
+
if (isDefined(resolver.resolve)) {
|
|
173
|
+
if (container[typeName][fieldName].resolve) {
|
|
174
|
+
throw new ResolverDuplicatedError(`Duplicated resolver of "${typeName}.${fieldName}" (resolve method)`, useLocation({ dirname: config.dirname, id: config.id }));
|
|
175
|
+
}
|
|
176
|
+
writeResolverMetadata(resolver.resolve, config);
|
|
177
|
+
container[typeName][fieldName].resolve = resolver.resolve;
|
|
178
|
+
}
|
|
179
|
+
// subscribe
|
|
180
|
+
if (isDefined(resolver.subscribe)) {
|
|
181
|
+
if (container[typeName][fieldName].subscribe) {
|
|
182
|
+
throw new ResolverDuplicatedError(`Duplicated resolver of "${typeName}.${fieldName}" (subscribe method)`, useLocation({ dirname: config.dirname, id: config.id }));
|
|
183
|
+
}
|
|
184
|
+
writeResolverMetadata(resolver.subscribe, config);
|
|
185
|
+
container[typeName][fieldName].subscribe = resolver.subscribe;
|
|
186
|
+
}
|
|
187
|
+
// extensions
|
|
188
|
+
if (isDefined(resolver.extensions)) {
|
|
189
|
+
if (container[typeName][fieldName].extensions) {
|
|
190
|
+
throw new ResolverDuplicatedError(`Duplicated resolver of "${typeName}.${fieldName}" (extensions object)`, useLocation({ dirname: config.dirname, id: config.id }));
|
|
191
|
+
}
|
|
192
|
+
writeResolverMetadata(resolver.extensions, config);
|
|
193
|
+
container[typeName][fieldName].extensions = resolver.extensions;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
function addScalar({ typeName, resolver, container, config, }) {
|
|
200
|
+
if (container[typeName]) {
|
|
201
|
+
throw new ResolverDuplicatedError(`Duplicated resolver of scalar "${typeName}"`, useLocation({ dirname: config.dirname, id: config.id }));
|
|
202
|
+
}
|
|
203
|
+
writeResolverMetadata(resolver.parseLiteral, config);
|
|
204
|
+
writeResolverMetadata(resolver.parseValue, config);
|
|
205
|
+
writeResolverMetadata(resolver.serialize, config);
|
|
206
|
+
container[typeName] = resolver;
|
|
207
|
+
}
|
|
208
|
+
function addEnum({ typeName, resolver, container, config, }) {
|
|
209
|
+
if (!container[typeName]) {
|
|
210
|
+
container[typeName] = {};
|
|
211
|
+
}
|
|
212
|
+
for (const key in resolver) {
|
|
213
|
+
if (resolver.hasOwnProperty(key)) {
|
|
214
|
+
const value = resolver[key];
|
|
215
|
+
if (container[typeName][key]) {
|
|
216
|
+
throw new ResolverDuplicatedError(`Duplicated resolver of "${typeName}.${key}" enum value`, useLocation({ dirname: config.dirname, id: config.id }));
|
|
217
|
+
}
|
|
218
|
+
container[typeName][key] = value;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Helps to make sure a resolver has a corresponding type/field definition.
|
|
224
|
+
* We don't want to pass resolve function that are not related to the module.
|
|
225
|
+
*/
|
|
226
|
+
function ensureImplements(metadata) {
|
|
227
|
+
return {
|
|
228
|
+
type(name, field) {
|
|
229
|
+
var _a, _b;
|
|
230
|
+
const type = []
|
|
231
|
+
.concat((_a = metadata.implements) === null || _a === void 0 ? void 0 : _a[name], (_b = metadata.extends) === null || _b === void 0 ? void 0 : _b[name])
|
|
232
|
+
.filter(isDefined);
|
|
233
|
+
if (type === null || type === void 0 ? void 0 : type.includes(field)) {
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
const id = `"${name}.${field}"`;
|
|
237
|
+
throw new ExtraResolverError(`Resolver of "${id}" type cannot be implemented`, `${id} is not defined`, useLocation({ dirname: metadata.dirname, id: metadata.id }));
|
|
238
|
+
},
|
|
239
|
+
scalar(name) {
|
|
240
|
+
var _a;
|
|
241
|
+
if ((((_a = metadata.implements) === null || _a === void 0 ? void 0 : _a.__scalars) || []).includes(name)) {
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
throw new ExtraResolverError(`Resolver of "${name}" scalar cannot be implemented`, `${name} is not defined`, useLocation({ dirname: metadata.dirname, id: metadata.id }));
|
|
245
|
+
},
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
function writeResolverMetadata(resolver, config) {
|
|
249
|
+
if (!resolver) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
resolver[resolverMetadataProp] = {
|
|
253
|
+
moduleId: config.id,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
export function readResolverMetadata(resolver) {
|
|
257
|
+
return resolver[resolverMetadataProp];
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* In order to use middlewares on fields
|
|
261
|
+
* that are defined in SDL but have no implemented resolvers,
|
|
262
|
+
* we would have to recreate GraphQLSchema and wrap resolve functions.
|
|
263
|
+
*
|
|
264
|
+
* Since we can't access GraphQLSchema on a module level
|
|
265
|
+
* and recreating GraphQLSchema seems unreasonable,
|
|
266
|
+
* we can create default resolvers instead.
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
*
|
|
270
|
+
* gql`
|
|
271
|
+
* type Query {
|
|
272
|
+
* me: User!
|
|
273
|
+
* }
|
|
274
|
+
*
|
|
275
|
+
* type User {
|
|
276
|
+
* name: String!
|
|
277
|
+
* }
|
|
278
|
+
* `
|
|
279
|
+
*
|
|
280
|
+
* The resolver of `Query.me` is implemented and resolver of `User.name` is not.
|
|
281
|
+
* In case where a middleware wants to intercept the resolver of `User.name`,
|
|
282
|
+
* we use a default field resolver from `graphql` package
|
|
283
|
+
* and put it next to other defined resolvers.
|
|
284
|
+
*
|
|
285
|
+
* This way our current logic of wrapping resolvers and running
|
|
286
|
+
* middleware functions stays untouched.
|
|
287
|
+
*/
|
|
288
|
+
function addDefaultResolvers(resolvers, middlewareMap, config) {
|
|
289
|
+
const container = resolvers;
|
|
290
|
+
const sdl = Array.isArray(config.typeDefs)
|
|
291
|
+
? concatAST(config.typeDefs)
|
|
292
|
+
: config.typeDefs;
|
|
293
|
+
function hasMiddleware(typeName, fieldName) {
|
|
294
|
+
var _a, _b, _c, _d, _e, _f;
|
|
295
|
+
return ((((_b = (_a = middlewareMap['*']) === null || _a === void 0 ? void 0 : _a['*']) === null || _b === void 0 ? void 0 : _b.length) ||
|
|
296
|
+
((_d = (_c = middlewareMap[typeName]) === null || _c === void 0 ? void 0 : _c['*']) === null || _d === void 0 ? void 0 : _d.length) ||
|
|
297
|
+
((_f = (_e = middlewareMap[typeName]) === null || _e === void 0 ? void 0 : _e[fieldName]) === null || _f === void 0 ? void 0 : _f.length)) > 0);
|
|
298
|
+
}
|
|
299
|
+
sdl.definitions.forEach((definition) => {
|
|
300
|
+
if (definition.kind === Kind.OBJECT_TYPE_DEFINITION ||
|
|
301
|
+
definition.kind === Kind.OBJECT_TYPE_EXTENSION) {
|
|
302
|
+
// Right now we only support Object type
|
|
303
|
+
if (definition.fields) {
|
|
304
|
+
const typeName = definition.name.value;
|
|
305
|
+
definition.fields.forEach((field) => {
|
|
306
|
+
var _a;
|
|
307
|
+
const fieldName = field.name.value;
|
|
308
|
+
if (!((_a = container[typeName]) === null || _a === void 0 ? void 0 : _a[fieldName]) &&
|
|
309
|
+
hasMiddleware(typeName, fieldName)) {
|
|
310
|
+
if (!container[typeName]) {
|
|
311
|
+
container[typeName] = {};
|
|
312
|
+
}
|
|
313
|
+
container[typeName][fieldName] = defaultFieldResolver;
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
return container;
|
|
320
|
+
}
|
|
321
|
+
//
|
|
322
|
+
// Resolver helpers
|
|
323
|
+
//
|
|
324
|
+
function isResolveFn(value) {
|
|
325
|
+
return typeof value === 'function';
|
|
326
|
+
}
|
|
327
|
+
function isResolveOptions(value) {
|
|
328
|
+
return (isDefined(value.resolve) ||
|
|
329
|
+
isDefined(value.subscribe) ||
|
|
330
|
+
isDefined(value.extensions));
|
|
331
|
+
}
|
|
332
|
+
function isScalarResolver(obj) {
|
|
333
|
+
return obj instanceof GraphQLScalarType;
|
|
334
|
+
}
|
|
335
|
+
function isEnumResolver(obj) {
|
|
336
|
+
return Object.values(obj).every(isPrimitive);
|
|
337
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { InjectionToken } from '../di';
|
|
2
|
+
/**
|
|
3
|
+
* @api
|
|
4
|
+
* `MODULE_ID` is an InjectionToken representing module's ID
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { MODULE_ID, Inject, Injectable } from 'graphql-modules';
|
|
9
|
+
*
|
|
10
|
+
* (A)Injectable()
|
|
11
|
+
* export class Data {
|
|
12
|
+
* constructor((A)Inject(MODULE_ID) moduleId: string) {
|
|
13
|
+
* console.log(`Data used in ${moduleId} module`)
|
|
14
|
+
* }
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export const MODULE_ID = new InjectionToken('module-id');
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Kind } from 'graphql';
|
|
2
|
+
import { NonDocumentNodeError, useLocation } from '../shared/errors';
|
|
3
|
+
/**
|
|
4
|
+
* Create a list of DocumentNode objects based on Module's config.
|
|
5
|
+
* Add a location, so we get richer errors.
|
|
6
|
+
*/
|
|
7
|
+
export function createTypeDefs(config) {
|
|
8
|
+
const typeDefs = Array.isArray(config.typeDefs)
|
|
9
|
+
? config.typeDefs
|
|
10
|
+
: [config.typeDefs];
|
|
11
|
+
ensureDocumentNode(config, typeDefs);
|
|
12
|
+
return typeDefs;
|
|
13
|
+
}
|
|
14
|
+
function ensureDocumentNode(config, typeDefs) {
|
|
15
|
+
function ensureEach(doc, i) {
|
|
16
|
+
if ((doc === null || doc === void 0 ? void 0 : doc.kind) !== Kind.DOCUMENT) {
|
|
17
|
+
throw new NonDocumentNodeError(`Expected parsed document but received ${typeof doc} at index ${i} in typeDefs list`, useLocation(config));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
typeDefs.forEach(ensureEach);
|
|
21
|
+
}
|
|
File without changes
|
package/esm/shared/di.js
ADDED
|
File without changes
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export class ModuleNonUniqueIdError extends ExtendableBuiltin(Error) {
|
|
2
|
+
constructor(message, ...rest) {
|
|
3
|
+
super(composeMessage(message, ...rest));
|
|
4
|
+
this.name = this.constructor.name;
|
|
5
|
+
this.message = composeMessage(message, ...rest);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
export class ModuleDuplicatedError extends ExtendableBuiltin(Error) {
|
|
9
|
+
constructor(message, ...rest) {
|
|
10
|
+
super(composeMessage(message, ...rest));
|
|
11
|
+
this.name = this.constructor.name;
|
|
12
|
+
this.message = composeMessage(message, ...rest);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export class ExtraResolverError extends ExtendableBuiltin(Error) {
|
|
16
|
+
constructor(message, ...rest) {
|
|
17
|
+
super(composeMessage(message, ...rest));
|
|
18
|
+
this.name = this.constructor.name;
|
|
19
|
+
this.message = composeMessage(message, ...rest);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export class ExtraMiddlewareError extends ExtendableBuiltin(Error) {
|
|
23
|
+
constructor(message, ...rest) {
|
|
24
|
+
super(composeMessage(message, ...rest));
|
|
25
|
+
this.name = this.constructor.name;
|
|
26
|
+
this.message = composeMessage(message, ...rest);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export class ResolverDuplicatedError extends ExtendableBuiltin(Error) {
|
|
30
|
+
constructor(message, ...rest) {
|
|
31
|
+
super(composeMessage(message, ...rest));
|
|
32
|
+
this.name = this.constructor.name;
|
|
33
|
+
this.message = composeMessage(message, ...rest);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export class ResolverInvalidError extends ExtendableBuiltin(Error) {
|
|
37
|
+
constructor(message, ...rest) {
|
|
38
|
+
super(composeMessage(message, ...rest));
|
|
39
|
+
this.name = this.constructor.name;
|
|
40
|
+
this.message = composeMessage(message, ...rest);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export class NonDocumentNodeError extends ExtendableBuiltin(Error) {
|
|
44
|
+
constructor(message, ...rest) {
|
|
45
|
+
super(composeMessage(message, ...rest));
|
|
46
|
+
this.name = this.constructor.name;
|
|
47
|
+
this.message = composeMessage(message, ...rest);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// helpers
|
|
51
|
+
export function useLocation({ dirname, id }) {
|
|
52
|
+
return dirname
|
|
53
|
+
? `Module "${id}" located at ${dirname}`
|
|
54
|
+
: [
|
|
55
|
+
`Module "${id}"`,
|
|
56
|
+
`Hint: pass __dirname to "dirname" option of your modules to get more insightful errors`,
|
|
57
|
+
].join('\n');
|
|
58
|
+
}
|
|
59
|
+
export function ExtendableBuiltin(cls) {
|
|
60
|
+
function ExtendableBuiltin() {
|
|
61
|
+
cls.apply(this, arguments);
|
|
62
|
+
}
|
|
63
|
+
ExtendableBuiltin.prototype = Object.create(cls.prototype);
|
|
64
|
+
Object.setPrototypeOf(ExtendableBuiltin, cls);
|
|
65
|
+
return ExtendableBuiltin;
|
|
66
|
+
}
|
|
67
|
+
export function composeMessage(...lines) {
|
|
68
|
+
return lines.join('\n');
|
|
69
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { parse, Kind } from 'graphql';
|
|
2
|
+
export function gql(literals) {
|
|
3
|
+
const result = typeof literals === 'string' ? literals : literals[0];
|
|
4
|
+
const parsed = parse(result);
|
|
5
|
+
if (!parsed || parsed.kind !== Kind.DOCUMENT) {
|
|
6
|
+
throw new Error('Not a valid GraphQL document.');
|
|
7
|
+
}
|
|
8
|
+
return parsed;
|
|
9
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { mergeDeepWith } from 'ramda';
|
|
2
|
+
import { isDefined } from './utils';
|
|
3
|
+
import { ExtraMiddlewareError, useLocation } from './errors';
|
|
4
|
+
export function compose(middleware) {
|
|
5
|
+
if (!Array.isArray(middleware)) {
|
|
6
|
+
throw new TypeError('Middleware stack must be an array!');
|
|
7
|
+
}
|
|
8
|
+
for (const fn of middleware) {
|
|
9
|
+
if (typeof fn !== 'function') {
|
|
10
|
+
throw new TypeError('Middleware must be composed of functions!');
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return function composed(context, next) {
|
|
14
|
+
// last called middleware
|
|
15
|
+
let index = -1;
|
|
16
|
+
function dispatch(i) {
|
|
17
|
+
if (i <= index) {
|
|
18
|
+
return Promise.reject(new Error('next() called multiple times'));
|
|
19
|
+
}
|
|
20
|
+
index = i;
|
|
21
|
+
const fn = i === middleware.length ? next : middleware[i];
|
|
22
|
+
if (!fn) {
|
|
23
|
+
return Promise.resolve();
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
return Promise.reject(err);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return dispatch(0);
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export function createMiddleware(path, middlewareMap) {
|
|
36
|
+
const middlewares = middlewareMap ? pickMiddlewares(path, middlewareMap) : [];
|
|
37
|
+
return compose(middlewares);
|
|
38
|
+
}
|
|
39
|
+
export function mergeMiddlewareMaps(app, mod) {
|
|
40
|
+
const merge = (left, right) => {
|
|
41
|
+
return mergeDeepWith((l, r) => {
|
|
42
|
+
if (Array.isArray(l)) {
|
|
43
|
+
return l.concat(r || []);
|
|
44
|
+
}
|
|
45
|
+
return merge(l, r);
|
|
46
|
+
}, left, right);
|
|
47
|
+
};
|
|
48
|
+
return merge(app, mod);
|
|
49
|
+
}
|
|
50
|
+
function pickMiddlewares(path, middlewareMap) {
|
|
51
|
+
var _a;
|
|
52
|
+
const middlewares = [];
|
|
53
|
+
const [type, field] = path;
|
|
54
|
+
if ((_a = middlewareMap['*']) === null || _a === void 0 ? void 0 : _a['*']) {
|
|
55
|
+
middlewares.push(...middlewareMap['*']['*']);
|
|
56
|
+
}
|
|
57
|
+
const typeMap = middlewareMap[type];
|
|
58
|
+
if (typeMap) {
|
|
59
|
+
if (typeMap['*']) {
|
|
60
|
+
middlewares.push(...typeMap['*']);
|
|
61
|
+
}
|
|
62
|
+
if (field && typeMap[field]) {
|
|
63
|
+
middlewares.push(...typeMap[field]);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return middlewares.filter(isDefined);
|
|
67
|
+
}
|
|
68
|
+
export function validateMiddlewareMap(middlewareMap, metadata) {
|
|
69
|
+
const exists = checkExistence(metadata);
|
|
70
|
+
for (const typeName in middlewareMap.types) {
|
|
71
|
+
if (middlewareMap.types.hasOwnProperty(typeName)) {
|
|
72
|
+
const typeMiddlewareMap = middlewareMap[typeName];
|
|
73
|
+
if (!exists.type(typeName)) {
|
|
74
|
+
throw new ExtraMiddlewareError(`Cannot apply a middleware to non existing "${typeName}" type`, useLocation({ dirname: metadata.dirname, id: metadata.id }));
|
|
75
|
+
}
|
|
76
|
+
for (const fieldName in typeMiddlewareMap[typeName]) {
|
|
77
|
+
if (typeMiddlewareMap[typeName].hasOwnProperty(fieldName)) {
|
|
78
|
+
if (!exists.field(typeName, fieldName)) {
|
|
79
|
+
throw new ExtraMiddlewareError(`Cannot apply a middleware to non existing "${typeName}.${fieldName}" type.field`, useLocation({ dirname: metadata.dirname, id: metadata.id }));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Helps to make sure a middleware has a corresponding type/field definition.
|
|
88
|
+
* We don't want to pass a module-level middlewares that are not related to the module.
|
|
89
|
+
* Not because it's dangerous but to prevent unused middlewares.
|
|
90
|
+
*/
|
|
91
|
+
function checkExistence(metadata) {
|
|
92
|
+
return {
|
|
93
|
+
type(name) {
|
|
94
|
+
var _a, _b;
|
|
95
|
+
return isDefined(((_a = metadata.implements) === null || _a === void 0 ? void 0 : _a[name]) || ((_b = metadata.extends) === null || _b === void 0 ? void 0 : _b[name]));
|
|
96
|
+
},
|
|
97
|
+
field(type, name) {
|
|
98
|
+
var _a, _b, _c, _d;
|
|
99
|
+
return isDefined(((_b = (_a = metadata.implements) === null || _a === void 0 ? void 0 : _a[type]) === null || _b === void 0 ? void 0 : _b.includes(name)) ||
|
|
100
|
+
((_d = (_c = metadata.extends) === null || _c === void 0 ? void 0 : _c[type]) === null || _d === void 0 ? void 0 : _d.includes(name)));
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { GraphQLSchema } from 'graphql';
|
|
2
|
+
export function flatten(arr) {
|
|
3
|
+
return Array.prototype.concat(...arr);
|
|
4
|
+
}
|
|
5
|
+
export function isDefined(val) {
|
|
6
|
+
return !isNil(val);
|
|
7
|
+
}
|
|
8
|
+
export function isNil(val) {
|
|
9
|
+
return val === null || typeof val === 'undefined';
|
|
10
|
+
}
|
|
11
|
+
export function isObject(val) {
|
|
12
|
+
return Object.prototype.toString.call(val) === '[object Object]';
|
|
13
|
+
}
|
|
14
|
+
export function isPrimitive(val) {
|
|
15
|
+
return ['number', 'string', 'boolean', 'symbol', 'bigint'].includes(typeof val);
|
|
16
|
+
}
|
|
17
|
+
export function isAsyncIterable(obj) {
|
|
18
|
+
return obj && typeof obj[Symbol.asyncIterator] === 'function';
|
|
19
|
+
}
|
|
20
|
+
export function tapAsyncIterator(iterable, doneCallback) {
|
|
21
|
+
const iteratorMethod = iterable[Symbol.asyncIterator];
|
|
22
|
+
const iterator = iteratorMethod.call(iterable);
|
|
23
|
+
function mapResult(result) {
|
|
24
|
+
if (result.done) {
|
|
25
|
+
doneCallback();
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
async next() {
|
|
31
|
+
try {
|
|
32
|
+
let result = await iterator.next();
|
|
33
|
+
return mapResult(result);
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
doneCallback();
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
async return(value) {
|
|
41
|
+
try {
|
|
42
|
+
const result = await iterator.return(value);
|
|
43
|
+
return mapResult(result);
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
doneCallback();
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
throw(error) {
|
|
51
|
+
doneCallback();
|
|
52
|
+
return iterator.throw(error);
|
|
53
|
+
},
|
|
54
|
+
[Symbol.asyncIterator]() {
|
|
55
|
+
return this;
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export function once(cb) {
|
|
60
|
+
let called = false;
|
|
61
|
+
return () => {
|
|
62
|
+
if (!called) {
|
|
63
|
+
called = true;
|
|
64
|
+
cb();
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
export function share(factory) {
|
|
69
|
+
let cached = null;
|
|
70
|
+
return (arg) => {
|
|
71
|
+
if (!cached) {
|
|
72
|
+
cached = factory(arg);
|
|
73
|
+
}
|
|
74
|
+
return cached;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
export function uniqueId(isNotUsed) {
|
|
78
|
+
let id;
|
|
79
|
+
while (!isNotUsed((id = Math.random().toString(16).substr(2)))) { }
|
|
80
|
+
return id;
|
|
81
|
+
}
|
|
82
|
+
export function isNotSchema(obj) {
|
|
83
|
+
return obj instanceof GraphQLSchema === false;
|
|
84
|
+
}
|
|
85
|
+
export function merge(source, target) {
|
|
86
|
+
const result = {
|
|
87
|
+
...source,
|
|
88
|
+
...target,
|
|
89
|
+
};
|
|
90
|
+
function attachSymbols(obj) {
|
|
91
|
+
const symbols = Object.getOwnPropertySymbols(obj);
|
|
92
|
+
for (const symbol of symbols) {
|
|
93
|
+
result[symbol] = obj[symbol];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (source) {
|
|
97
|
+
attachSymbols(source);
|
|
98
|
+
}
|
|
99
|
+
attachSymbols(target);
|
|
100
|
+
return result;
|
|
101
|
+
}
|