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,270 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mockModule = mockModule;
|
|
4
|
+
exports.testModule = testModule;
|
|
5
|
+
const graphql_1 = require("graphql");
|
|
6
|
+
const factory_1 = require("../module/factory");
|
|
7
|
+
const application_1 = require("../application/application");
|
|
8
|
+
const module_1 = require("../module/module");
|
|
9
|
+
function mockModule(testedModule, overrideConfig) {
|
|
10
|
+
const sourceProviders = typeof testedModule.config.providers === 'function'
|
|
11
|
+
? testedModule.config.providers()
|
|
12
|
+
: testedModule.config.providers;
|
|
13
|
+
const overrideProviders = typeof overrideConfig.providers === 'function'
|
|
14
|
+
? overrideConfig.providers()
|
|
15
|
+
: overrideConfig.providers;
|
|
16
|
+
const newModule = (0, module_1.createModule)({
|
|
17
|
+
...testedModule.config,
|
|
18
|
+
providers: [...(sourceProviders || []), ...(overrideProviders || [])],
|
|
19
|
+
});
|
|
20
|
+
newModule['ɵoriginalModule'] = testedModule;
|
|
21
|
+
return newModule;
|
|
22
|
+
}
|
|
23
|
+
function testModule(testedModule, config) {
|
|
24
|
+
var _a;
|
|
25
|
+
const mod = transformModule(testedModule, config);
|
|
26
|
+
const modules = [mod].concat((_a = config === null || config === void 0 ? void 0 : config.modules) !== null && _a !== void 0 ? _a : []);
|
|
27
|
+
return (0, application_1.createApplication)({
|
|
28
|
+
...(config || {}),
|
|
29
|
+
modules,
|
|
30
|
+
providers: config === null || config === void 0 ? void 0 : config.providers,
|
|
31
|
+
middlewares: config === null || config === void 0 ? void 0 : config.middlewares,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function transformModule(mod, config) {
|
|
35
|
+
const transforms = [];
|
|
36
|
+
if (config === null || config === void 0 ? void 0 : config.replaceExtensions) {
|
|
37
|
+
transforms.push((m) => (0, factory_1.moduleFactory)({
|
|
38
|
+
...m.config,
|
|
39
|
+
typeDefs: replaceExtensions(m.typeDefs),
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
if (config === null || config === void 0 ? void 0 : config.typeDefs) {
|
|
43
|
+
transforms.push((m) => (0, factory_1.moduleFactory)({
|
|
44
|
+
...m.config,
|
|
45
|
+
typeDefs: m.typeDefs.concat(config.typeDefs),
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
if (config === null || config === void 0 ? void 0 : config.inheritTypeDefs) {
|
|
49
|
+
transforms.push((m) => (0, factory_1.moduleFactory)({
|
|
50
|
+
...m.config,
|
|
51
|
+
typeDefs: inheritTypeDefs(m.typeDefs, config.inheritTypeDefs),
|
|
52
|
+
}));
|
|
53
|
+
}
|
|
54
|
+
if (config === null || config === void 0 ? void 0 : config.resolvers) {
|
|
55
|
+
transforms.push((m) => {
|
|
56
|
+
const resolvers = m.config.resolvers
|
|
57
|
+
? Array.isArray(m.config.resolvers)
|
|
58
|
+
? m.config.resolvers
|
|
59
|
+
: [m.config.resolvers]
|
|
60
|
+
: [];
|
|
61
|
+
return (0, factory_1.moduleFactory)({
|
|
62
|
+
...m.config,
|
|
63
|
+
resolvers: resolvers.concat(config.resolvers),
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
if (config === null || config === void 0 ? void 0 : config.providers) {
|
|
68
|
+
transforms.push((m) => {
|
|
69
|
+
const sourceProviders = typeof m.config.providers === 'function'
|
|
70
|
+
? m.config.providers()
|
|
71
|
+
: m.config.providers;
|
|
72
|
+
const overrideProviders = typeof config.providers === 'function'
|
|
73
|
+
? config.providers()
|
|
74
|
+
: config.providers;
|
|
75
|
+
return (0, factory_1.moduleFactory)({
|
|
76
|
+
...m.config,
|
|
77
|
+
providers: [...(sourceProviders || []), ...(overrideProviders || [])],
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
if (transforms) {
|
|
82
|
+
return transforms.reduce((m, transform) => transform(m), mod);
|
|
83
|
+
}
|
|
84
|
+
return mod;
|
|
85
|
+
}
|
|
86
|
+
function inheritTypeDefs(originalTypeDefs, modules) {
|
|
87
|
+
const original = (0, graphql_1.concatAST)(originalTypeDefs);
|
|
88
|
+
const typeDefs = treeshakeTypesDefs(original, modules.reduce((typeDefs, externalMod) => typeDefs.concat(externalMod.typeDefs), []));
|
|
89
|
+
return typeDefs;
|
|
90
|
+
}
|
|
91
|
+
function replaceExtensions(typeDefs) {
|
|
92
|
+
const types = [];
|
|
93
|
+
const extensions = [];
|
|
94
|
+
// List all object types
|
|
95
|
+
typeDefs.forEach((doc) => {
|
|
96
|
+
(0, graphql_1.visit)(doc, {
|
|
97
|
+
ObjectTypeDefinition(node) {
|
|
98
|
+
types.push(node.name.value);
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
// turn object type extensions into object types
|
|
103
|
+
return typeDefs.map((doc) => {
|
|
104
|
+
return (0, graphql_1.visit)(doc, {
|
|
105
|
+
ObjectTypeExtension(node) {
|
|
106
|
+
// only if object type doesn't exist
|
|
107
|
+
if (extensions.includes(node.name.value) ||
|
|
108
|
+
types.includes(node.name.value)) {
|
|
109
|
+
return node;
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
...node,
|
|
113
|
+
kind: graphql_1.Kind.OBJECT_TYPE_DEFINITION,
|
|
114
|
+
};
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
function treeshakeTypesDefs(originalSource, sources) {
|
|
120
|
+
const namedTypes = originalSource.definitions.filter(isNamedTypeDefinition);
|
|
121
|
+
const typesToVisit = namedTypes.map((def) => def.name.value);
|
|
122
|
+
const rootFields = namedTypes.reduce((acc, node) => {
|
|
123
|
+
const typeName = node.name.value;
|
|
124
|
+
if (isRootType(typeName) && hasFields(node)) {
|
|
125
|
+
if (!acc[typeName]) {
|
|
126
|
+
acc[typeName] = [];
|
|
127
|
+
}
|
|
128
|
+
node.fields.forEach((field) => {
|
|
129
|
+
acc[typeName].push(field.name.value);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
return acc;
|
|
133
|
+
}, {});
|
|
134
|
+
const schema = (0, graphql_1.concatAST)([originalSource].concat(sources));
|
|
135
|
+
const involvedTypes = new Set(visitTypes(schema, typesToVisit, rootFields));
|
|
136
|
+
return {
|
|
137
|
+
kind: graphql_1.Kind.DOCUMENT,
|
|
138
|
+
definitions: schema.definitions.filter((def) => {
|
|
139
|
+
var _a, _b;
|
|
140
|
+
if (isNamedTypeDefinition(def)) {
|
|
141
|
+
const typeName = def.name.value;
|
|
142
|
+
if (!involvedTypes.has(def.name.value)) {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
if ((_a = rootFields[typeName]) === null || _a === void 0 ? void 0 : _a.length) {
|
|
146
|
+
const rootType = def;
|
|
147
|
+
if ((_b = rootType.fields) === null || _b === void 0 ? void 0 : _b.every((field) => !rootFields[typeName].includes(field.name.value))) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return true;
|
|
153
|
+
}),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function isNamedTypeDefinition(def) {
|
|
157
|
+
return (!!def &&
|
|
158
|
+
def.kind !== graphql_1.Kind.SCHEMA_DEFINITION &&
|
|
159
|
+
def.kind !== graphql_1.Kind.SCHEMA_EXTENSION);
|
|
160
|
+
}
|
|
161
|
+
function visitTypes(schema, types, rootFields) {
|
|
162
|
+
const visitedTypes = [];
|
|
163
|
+
const scalars = schema.definitions
|
|
164
|
+
.filter((def) => def.kind === graphql_1.Kind.SCALAR_TYPE_DEFINITION ||
|
|
165
|
+
def.kind === graphql_1.Kind.SCALAR_TYPE_EXTENSION)
|
|
166
|
+
.map((def) => def.name.value);
|
|
167
|
+
for (const typeName of types) {
|
|
168
|
+
collectType(typeName);
|
|
169
|
+
}
|
|
170
|
+
return visitedTypes;
|
|
171
|
+
function collectField(field, parentTypeName) {
|
|
172
|
+
var _a;
|
|
173
|
+
if (parentTypeName &&
|
|
174
|
+
isRootType(parentTypeName) &&
|
|
175
|
+
((_a = rootFields[parentTypeName]) === null || _a === void 0 ? void 0 : _a.length) &&
|
|
176
|
+
!rootFields[parentTypeName].includes(field.name.value)) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
collectType(resolveType(field.type));
|
|
180
|
+
if (field.arguments) {
|
|
181
|
+
field.arguments.forEach((arg) => {
|
|
182
|
+
collectType(resolveType(arg.type));
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
if (field.directives) {
|
|
186
|
+
field.directives.forEach((directive) => {
|
|
187
|
+
collectType(directive.name.value);
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
function collectType(typeName) {
|
|
192
|
+
if (visitedTypes.includes(typeName)) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (isScalar(typeName)) {
|
|
196
|
+
visitedTypes.push(typeName);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
const types = findTypes(typeName);
|
|
200
|
+
visitedTypes.push(typeName);
|
|
201
|
+
types.forEach((type) => {
|
|
202
|
+
if (hasFields(type)) {
|
|
203
|
+
type.fields.forEach((field) => {
|
|
204
|
+
collectField(field, typeName);
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
if (hasTypes(type)) {
|
|
208
|
+
type.types.forEach((t) => {
|
|
209
|
+
collectType(resolveType(t));
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
if (hasInterfaces(type)) {
|
|
213
|
+
type.interfaces.forEach((i) => {
|
|
214
|
+
collectType(resolveType(i));
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
function resolveType(type) {
|
|
220
|
+
if (type.kind === 'ListType') {
|
|
221
|
+
return resolveType(type.type);
|
|
222
|
+
}
|
|
223
|
+
if (type.kind === 'NonNullType') {
|
|
224
|
+
return resolveType(type.type);
|
|
225
|
+
}
|
|
226
|
+
return type.name.value;
|
|
227
|
+
}
|
|
228
|
+
function isScalar(name) {
|
|
229
|
+
return scalars
|
|
230
|
+
.concat(['String', 'Boolean', 'Int', 'ID', 'Float'])
|
|
231
|
+
.includes(name);
|
|
232
|
+
}
|
|
233
|
+
function findTypes(typeName) {
|
|
234
|
+
const types = schema.definitions.filter((def) => isNamedTypeDefinition(def) && def.name.value === typeName);
|
|
235
|
+
if (!types.length) {
|
|
236
|
+
throw new Error(`Missing type "${typeName}"`);
|
|
237
|
+
}
|
|
238
|
+
return types;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
function hasInterfaces(def) {
|
|
242
|
+
return (hasPropValue(def, 'interfaces') &&
|
|
243
|
+
[
|
|
244
|
+
graphql_1.Kind.OBJECT_TYPE_DEFINITION,
|
|
245
|
+
graphql_1.Kind.OBJECT_TYPE_EXTENSION,
|
|
246
|
+
graphql_1.Kind.INTERFACE_TYPE_DEFINITION,
|
|
247
|
+
graphql_1.Kind.INTERFACE_TYPE_EXTENSION,
|
|
248
|
+
].includes(def.kind));
|
|
249
|
+
}
|
|
250
|
+
function hasTypes(def) {
|
|
251
|
+
return ([graphql_1.Kind.UNION_TYPE_DEFINITION, graphql_1.Kind.UNION_TYPE_EXTENSION].includes(def.kind) && hasPropValue(def, 'types'));
|
|
252
|
+
}
|
|
253
|
+
function hasFields(def) {
|
|
254
|
+
return ([
|
|
255
|
+
graphql_1.Kind.OBJECT_TYPE_DEFINITION,
|
|
256
|
+
graphql_1.Kind.OBJECT_TYPE_EXTENSION,
|
|
257
|
+
graphql_1.Kind.INTERFACE_TYPE_DEFINITION,
|
|
258
|
+
graphql_1.Kind.INTERFACE_TYPE_EXTENSION,
|
|
259
|
+
graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION,
|
|
260
|
+
graphql_1.Kind.INPUT_OBJECT_TYPE_EXTENSION,
|
|
261
|
+
].includes(def.kind) && hasPropValue(def, 'fields'));
|
|
262
|
+
}
|
|
263
|
+
function hasPropValue(obj, prop) {
|
|
264
|
+
return Object.prototype.hasOwnProperty.call(obj, prop) && obj[prop];
|
|
265
|
+
}
|
|
266
|
+
function isRootType(typeName) {
|
|
267
|
+
return (typeName === 'Query' ||
|
|
268
|
+
typeName === 'Mutation' ||
|
|
269
|
+
typeName === 'Subscription');
|
|
270
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { wrapSchema } from '@graphql-tools/wrap';
|
|
2
|
+
import { execute } from 'graphql';
|
|
3
|
+
import { uniqueId } from '../shared/utils';
|
|
4
|
+
const CONTEXT_ID = Symbol.for('context-id');
|
|
5
|
+
export function apolloExecutorCreator({ createExecution, }) {
|
|
6
|
+
return function createApolloExecutor(options) {
|
|
7
|
+
const executor = createExecution(options);
|
|
8
|
+
return async function executorAdapter(requestContext) {
|
|
9
|
+
return executor({
|
|
10
|
+
schema: requestContext.schema,
|
|
11
|
+
document: requestContext.document,
|
|
12
|
+
operationName: requestContext.operationName,
|
|
13
|
+
variableValues: requestContext.request.variables,
|
|
14
|
+
contextValue: requestContext.context,
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export function apolloSchemaCreator({ createSubscription, contextBuilder, schema, }) {
|
|
20
|
+
const createApolloSchema = () => {
|
|
21
|
+
const sessions = {};
|
|
22
|
+
const subscription = createSubscription();
|
|
23
|
+
function getSession(ctx, { context, ɵdestroy: destroy }) {
|
|
24
|
+
if (!ctx[CONTEXT_ID]) {
|
|
25
|
+
ctx[CONTEXT_ID] = uniqueId((id) => !sessions[id]);
|
|
26
|
+
sessions[ctx[CONTEXT_ID]] = {
|
|
27
|
+
count: 0,
|
|
28
|
+
session: {
|
|
29
|
+
context,
|
|
30
|
+
destroy() {
|
|
31
|
+
if (--sessions[ctx[CONTEXT_ID]].count === 0) {
|
|
32
|
+
destroy();
|
|
33
|
+
delete sessions[ctx[CONTEXT_ID]];
|
|
34
|
+
delete ctx[CONTEXT_ID];
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
sessions[ctx[CONTEXT_ID]].count++;
|
|
41
|
+
return sessions[ctx[CONTEXT_ID]].session;
|
|
42
|
+
}
|
|
43
|
+
return wrapSchema({
|
|
44
|
+
schema,
|
|
45
|
+
batch: true,
|
|
46
|
+
executor(input) {
|
|
47
|
+
if (input.operationType === 'subscription') {
|
|
48
|
+
return subscription({
|
|
49
|
+
schema,
|
|
50
|
+
document: input.document,
|
|
51
|
+
variableValues: input.variables,
|
|
52
|
+
contextValue: input.context,
|
|
53
|
+
rootValue: input.rootValue,
|
|
54
|
+
operationName: input.operationName,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
// Create an execution context and run within it
|
|
58
|
+
return contextBuilder(input.context).runWithContext((env) => {
|
|
59
|
+
const { context, destroy } = getSession(input.context, env);
|
|
60
|
+
// It's important to wrap the executeFn within a promise
|
|
61
|
+
// so we can easily control the end of execution (with finally)
|
|
62
|
+
return Promise.resolve()
|
|
63
|
+
.then(() => execute({
|
|
64
|
+
schema,
|
|
65
|
+
document: input.document,
|
|
66
|
+
contextValue: context,
|
|
67
|
+
variableValues: input.variables,
|
|
68
|
+
rootValue: input.rootValue,
|
|
69
|
+
operationName: input.operationName,
|
|
70
|
+
}))
|
|
71
|
+
.finally(destroy);
|
|
72
|
+
});
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
return createApolloSchema;
|
|
77
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { makeExecutableSchema } from '@graphql-tools/schema';
|
|
2
|
+
import { ReflectiveInjector, onlySingletonProviders, onlyOperationProviders, Scope, } from '../di';
|
|
3
|
+
import { ModuleDuplicatedError, ModuleNonUniqueIdError, } from '../shared/errors';
|
|
4
|
+
import { flatten, isDefined } from '../shared/utils';
|
|
5
|
+
import { createGlobalProvidersMap, attachGlobalProvidersMap, instantiateSingletonProviders, } from './di';
|
|
6
|
+
import { createContextBuilder } from './context';
|
|
7
|
+
import { executionCreator } from './execution';
|
|
8
|
+
import { subscriptionCreator } from './subscription';
|
|
9
|
+
import { apolloSchemaCreator, apolloExecutorCreator } from './apollo';
|
|
10
|
+
import { operationControllerCreator } from './operation-controller';
|
|
11
|
+
/**
|
|
12
|
+
* @api
|
|
13
|
+
* Creates Application out of Modules. Accepts `ApplicationConfig`.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
*
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import { createApplication } from 'graphql-modules';
|
|
19
|
+
* import { usersModule } from './users';
|
|
20
|
+
* import { postsModule } from './posts';
|
|
21
|
+
* import { commentsModule } from './comments';
|
|
22
|
+
*
|
|
23
|
+
* const app = createApplication({
|
|
24
|
+
* modules: [
|
|
25
|
+
* usersModule,
|
|
26
|
+
* postsModule,
|
|
27
|
+
* commentsModule
|
|
28
|
+
* ]
|
|
29
|
+
* })
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export function createApplication(applicationConfig) {
|
|
33
|
+
function applicationFactory(cfg) {
|
|
34
|
+
const config = cfg || applicationConfig;
|
|
35
|
+
const providers = config.providers && typeof config.providers === 'function'
|
|
36
|
+
? config.providers()
|
|
37
|
+
: config.providers;
|
|
38
|
+
// Creates an Injector with singleton classes at application level
|
|
39
|
+
const appSingletonProviders = ReflectiveInjector.resolve(onlySingletonProviders(providers));
|
|
40
|
+
const appInjector = ReflectiveInjector.createFromResolved({
|
|
41
|
+
name: 'App (Singleton Scope)',
|
|
42
|
+
providers: appSingletonProviders,
|
|
43
|
+
});
|
|
44
|
+
// Filter Operation-scoped providers, and keep it here
|
|
45
|
+
// so we don't do it over and over again
|
|
46
|
+
const appOperationProviders = ReflectiveInjector.resolve(onlyOperationProviders(providers));
|
|
47
|
+
const middlewareMap = config.middlewares || {};
|
|
48
|
+
// Validations
|
|
49
|
+
ensureModuleUniqueIds(config.modules);
|
|
50
|
+
// Create all modules
|
|
51
|
+
const modules = config.modules.map((mod) => mod.factory({
|
|
52
|
+
injector: appInjector,
|
|
53
|
+
middlewares: middlewareMap,
|
|
54
|
+
}));
|
|
55
|
+
const modulesMap = createModulesMap(modules);
|
|
56
|
+
const singletonGlobalProvidersMap = createGlobalProvidersMap({
|
|
57
|
+
modules,
|
|
58
|
+
scope: Scope.Singleton,
|
|
59
|
+
});
|
|
60
|
+
const operationGlobalProvidersMap = createGlobalProvidersMap({
|
|
61
|
+
modules,
|
|
62
|
+
scope: Scope.Operation,
|
|
63
|
+
});
|
|
64
|
+
attachGlobalProvidersMap({
|
|
65
|
+
injector: appInjector,
|
|
66
|
+
globalProvidersMap: singletonGlobalProvidersMap,
|
|
67
|
+
moduleInjectorGetter(moduleId) {
|
|
68
|
+
return modulesMap.get(moduleId).injector;
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
// Creating a schema, flattening the typedefs and resolvers
|
|
72
|
+
// is not expensive since it happens only once
|
|
73
|
+
const typeDefs = flatten(modules.map((mod) => mod.typeDefs));
|
|
74
|
+
const resolvers = modules.map((mod) => mod.resolvers).filter(isDefined);
|
|
75
|
+
const schema = (applicationConfig.schemaBuilder || makeExecutableSchema)({
|
|
76
|
+
typeDefs,
|
|
77
|
+
resolvers,
|
|
78
|
+
});
|
|
79
|
+
const contextBuilder = createContextBuilder({
|
|
80
|
+
appInjector,
|
|
81
|
+
appLevelOperationProviders: appOperationProviders,
|
|
82
|
+
modulesMap: modulesMap,
|
|
83
|
+
singletonGlobalProvidersMap,
|
|
84
|
+
operationGlobalProvidersMap,
|
|
85
|
+
});
|
|
86
|
+
const createOperationController = operationControllerCreator({
|
|
87
|
+
contextBuilder,
|
|
88
|
+
});
|
|
89
|
+
const createSubscription = subscriptionCreator({ contextBuilder });
|
|
90
|
+
const createExecution = executionCreator({ contextBuilder });
|
|
91
|
+
const createSchemaForApollo = apolloSchemaCreator({
|
|
92
|
+
createSubscription,
|
|
93
|
+
contextBuilder,
|
|
94
|
+
schema,
|
|
95
|
+
});
|
|
96
|
+
const createApolloExecutor = apolloExecutorCreator({
|
|
97
|
+
createExecution,
|
|
98
|
+
});
|
|
99
|
+
instantiateSingletonProviders({
|
|
100
|
+
appInjector,
|
|
101
|
+
modulesMap,
|
|
102
|
+
});
|
|
103
|
+
return {
|
|
104
|
+
typeDefs,
|
|
105
|
+
resolvers,
|
|
106
|
+
schema,
|
|
107
|
+
injector: appInjector,
|
|
108
|
+
createOperationController,
|
|
109
|
+
createSubscription,
|
|
110
|
+
createExecution,
|
|
111
|
+
createSchemaForApollo,
|
|
112
|
+
createApolloExecutor,
|
|
113
|
+
ɵfactory: applicationFactory,
|
|
114
|
+
ɵconfig: config,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
return applicationFactory();
|
|
118
|
+
}
|
|
119
|
+
function createModulesMap(modules) {
|
|
120
|
+
var _a;
|
|
121
|
+
const modulesMap = new Map();
|
|
122
|
+
for (const module of modules) {
|
|
123
|
+
if (modulesMap.has(module.id)) {
|
|
124
|
+
const location = module.metadata.dirname;
|
|
125
|
+
const existingLocation = (_a = modulesMap.get(module.id)) === null || _a === void 0 ? void 0 : _a.metadata.dirname;
|
|
126
|
+
const info = [];
|
|
127
|
+
if (existingLocation) {
|
|
128
|
+
info.push(`Already registered module located at: ${existingLocation}`);
|
|
129
|
+
}
|
|
130
|
+
if (location) {
|
|
131
|
+
info.push(`Duplicated module located at: ${location}`);
|
|
132
|
+
}
|
|
133
|
+
throw new ModuleDuplicatedError(`Module "${module.id}" already exists`, ...info);
|
|
134
|
+
}
|
|
135
|
+
modulesMap.set(module.id, module);
|
|
136
|
+
}
|
|
137
|
+
return modulesMap;
|
|
138
|
+
}
|
|
139
|
+
function ensureModuleUniqueIds(modules) {
|
|
140
|
+
const collisions = modules
|
|
141
|
+
.filter((mod, i, all) => i !== all.findIndex((m) => m.id === mod.id))
|
|
142
|
+
.map((m) => m.id);
|
|
143
|
+
if (collisions.length) {
|
|
144
|
+
throw new ModuleNonUniqueIdError(`Modules with non-unique ids: ${collisions.join(', ')}`, `All modules should have unique ids, please locate and fix them.`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { ReflectiveInjector } from '../di';
|
|
2
|
+
import { once, merge } from '../shared/utils';
|
|
3
|
+
import async_context from '#async-context';
|
|
4
|
+
import { attachGlobalProvidersMap } from './di';
|
|
5
|
+
import { CONTEXT } from './tokens';
|
|
6
|
+
export function createContextBuilder({ appInjector, modulesMap, appLevelOperationProviders, singletonGlobalProvidersMap, operationGlobalProvidersMap, }) {
|
|
7
|
+
// This is very critical. It creates an execution context.
|
|
8
|
+
// It has to run on every operation.
|
|
9
|
+
const contextBuilder = (context) => {
|
|
10
|
+
// Cache for context per module
|
|
11
|
+
let contextCache = {};
|
|
12
|
+
// A list of providers with OnDestroy hooks
|
|
13
|
+
// It's a tuple because we want to know which Injector controls the provider
|
|
14
|
+
// and we want to know if the provider was even instantiated.
|
|
15
|
+
let providersToDestroy = [];
|
|
16
|
+
function registerProvidersToDestroy(injector) {
|
|
17
|
+
injector._providers.forEach((provider) => {
|
|
18
|
+
if (provider.factory.hasOnDestroyHook) {
|
|
19
|
+
// keep provider key's id (it doesn't change over time)
|
|
20
|
+
// and related injector
|
|
21
|
+
providersToDestroy.push([injector, provider.key.id]);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
let appContext;
|
|
26
|
+
attachGlobalProvidersMap({
|
|
27
|
+
injector: appInjector,
|
|
28
|
+
globalProvidersMap: singletonGlobalProvidersMap,
|
|
29
|
+
moduleInjectorGetter(moduleId) {
|
|
30
|
+
return modulesMap.get(moduleId).injector;
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
appInjector.setExecutionContextGetter(function executionContextGetter() {
|
|
34
|
+
var _a;
|
|
35
|
+
return (((_a = async_context.getAsyncContext()) === null || _a === void 0 ? void 0 : _a.getApplicationContext()) || appContext);
|
|
36
|
+
});
|
|
37
|
+
function createModuleExecutionContextGetter(moduleId) {
|
|
38
|
+
return function moduleExecutionContextGetter() {
|
|
39
|
+
var _a;
|
|
40
|
+
return (((_a = async_context.getAsyncContext()) === null || _a === void 0 ? void 0 : _a.getModuleContext(moduleId)) ||
|
|
41
|
+
getModuleContext(moduleId, context));
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
modulesMap.forEach((mod, moduleId) => {
|
|
45
|
+
mod.injector.setExecutionContextGetter(createModuleExecutionContextGetter(moduleId));
|
|
46
|
+
});
|
|
47
|
+
// As the name of the Injector says, it's an Operation scoped Injector
|
|
48
|
+
// Application level
|
|
49
|
+
// Operation scoped - means it's created and destroyed on every GraphQL Operation
|
|
50
|
+
const operationAppInjector = ReflectiveInjector.createFromResolved({
|
|
51
|
+
name: 'App (Operation Scope)',
|
|
52
|
+
providers: appLevelOperationProviders.concat(ReflectiveInjector.resolve([
|
|
53
|
+
{
|
|
54
|
+
provide: CONTEXT,
|
|
55
|
+
useValue: context,
|
|
56
|
+
},
|
|
57
|
+
])),
|
|
58
|
+
parent: appInjector,
|
|
59
|
+
});
|
|
60
|
+
// Create a context for application-level ExecutionContext
|
|
61
|
+
appContext = merge(context, {
|
|
62
|
+
injector: operationAppInjector,
|
|
63
|
+
});
|
|
64
|
+
// Track Providers with OnDestroy hooks
|
|
65
|
+
registerProvidersToDestroy(operationAppInjector);
|
|
66
|
+
function getModuleContext(moduleId, ctx) {
|
|
67
|
+
var _a;
|
|
68
|
+
// Reuse a context or create if not available
|
|
69
|
+
if (!contextCache[moduleId]) {
|
|
70
|
+
// We're interested in operation-scoped providers only
|
|
71
|
+
const providers = (_a = modulesMap.get(moduleId)) === null || _a === void 0 ? void 0 : _a.operationProviders;
|
|
72
|
+
// Create module-level Operation-scoped Injector
|
|
73
|
+
const operationModuleInjector = ReflectiveInjector.createFromResolved({
|
|
74
|
+
name: `Module "${moduleId}" (Operation Scope)`,
|
|
75
|
+
providers: providers.concat(ReflectiveInjector.resolve([
|
|
76
|
+
{
|
|
77
|
+
provide: CONTEXT,
|
|
78
|
+
useFactory() {
|
|
79
|
+
return contextCache[moduleId];
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
])),
|
|
83
|
+
// This injector has a priority
|
|
84
|
+
parent: modulesMap.get(moduleId).injector,
|
|
85
|
+
// over this one
|
|
86
|
+
fallbackParent: operationAppInjector,
|
|
87
|
+
});
|
|
88
|
+
// Same as on application level, we need to collect providers with OnDestroy hooks
|
|
89
|
+
registerProvidersToDestroy(operationModuleInjector);
|
|
90
|
+
contextCache[moduleId] = merge(ctx, {
|
|
91
|
+
injector: operationModuleInjector,
|
|
92
|
+
moduleId,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
return contextCache[moduleId];
|
|
96
|
+
}
|
|
97
|
+
const sharedContext = merge(
|
|
98
|
+
// We want to pass the received context
|
|
99
|
+
context || {}, {
|
|
100
|
+
// Here's something very crutial
|
|
101
|
+
// It's a function that is used in module's context creation
|
|
102
|
+
ɵgetModuleContext: getModuleContext,
|
|
103
|
+
});
|
|
104
|
+
attachGlobalProvidersMap({
|
|
105
|
+
injector: operationAppInjector,
|
|
106
|
+
globalProvidersMap: operationGlobalProvidersMap,
|
|
107
|
+
moduleInjectorGetter(moduleId) {
|
|
108
|
+
return getModuleContext(moduleId, sharedContext).injector;
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
const env = {
|
|
112
|
+
ɵdestroy: once(() => {
|
|
113
|
+
providersToDestroy.forEach(([injector, keyId]) => {
|
|
114
|
+
// If provider was instantiated
|
|
115
|
+
if (injector._isObjectDefinedByKeyId(keyId)) {
|
|
116
|
+
// call its OnDestroy hook
|
|
117
|
+
injector._getObjByKeyId(keyId).onDestroy();
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
contextCache = {};
|
|
121
|
+
}),
|
|
122
|
+
ɵinjector: operationAppInjector,
|
|
123
|
+
context: sharedContext,
|
|
124
|
+
};
|
|
125
|
+
return {
|
|
126
|
+
...env,
|
|
127
|
+
runWithContext(cb) {
|
|
128
|
+
return async_context.runWithAsyncContext({
|
|
129
|
+
getApplicationContext() {
|
|
130
|
+
return appContext;
|
|
131
|
+
},
|
|
132
|
+
getModuleContext(moduleId) {
|
|
133
|
+
return getModuleContext(moduleId, context);
|
|
134
|
+
},
|
|
135
|
+
}, cb, env);
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
return contextBuilder;
|
|
140
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Scope } from '../di';
|
|
2
|
+
export function instantiateSingletonProviders({ appInjector, modulesMap, }) {
|
|
3
|
+
appInjector.instantiateAll();
|
|
4
|
+
modulesMap.forEach((mod) => {
|
|
5
|
+
mod.injector.instantiateAll();
|
|
6
|
+
});
|
|
7
|
+
}
|
|
8
|
+
export function createGlobalProvidersMap({ modules, scope, }) {
|
|
9
|
+
const globalProvidersMap = {};
|
|
10
|
+
const propType = scope === Scope.Singleton ? 'singletonProviders' : 'operationProviders';
|
|
11
|
+
modules.forEach((mod) => {
|
|
12
|
+
mod[propType].forEach((provider) => {
|
|
13
|
+
if (provider.factory.isGlobal) {
|
|
14
|
+
const key = provider.key.id;
|
|
15
|
+
if (globalProvidersMap[key]) {
|
|
16
|
+
throw duplicatedGlobalTokenError(provider, [
|
|
17
|
+
mod.id,
|
|
18
|
+
globalProvidersMap[key],
|
|
19
|
+
]);
|
|
20
|
+
}
|
|
21
|
+
globalProvidersMap[key] = mod.id;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
return globalProvidersMap;
|
|
26
|
+
}
|
|
27
|
+
export function attachGlobalProvidersMap({ injector, globalProvidersMap, moduleInjectorGetter, }) {
|
|
28
|
+
injector._globalProvidersMap = {
|
|
29
|
+
has(key) {
|
|
30
|
+
return typeof globalProvidersMap[key] === 'string';
|
|
31
|
+
},
|
|
32
|
+
get(key) {
|
|
33
|
+
return moduleInjectorGetter(globalProvidersMap[key]);
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export function duplicatedGlobalTokenError(provider, modules) {
|
|
38
|
+
return Error([
|
|
39
|
+
`Failed to define '${provider.key.displayName}' token as global.`,
|
|
40
|
+
`Token provided by two modules: '${modules.join("', '")}'`,
|
|
41
|
+
].join(' '));
|
|
42
|
+
}
|