@effect-gql/federation 0.1.0 → 1.0.0
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/README.md +100 -0
- package/index.cjs +618 -0
- package/index.cjs.map +1 -0
- package/index.d.cts +577 -0
- package/index.d.ts +577 -0
- package/index.js +570 -0
- package/index.js.map +1 -0
- package/package.json +14 -27
- package/dist/directives.d.ts +0 -136
- package/dist/directives.d.ts.map +0 -1
- package/dist/directives.js +0 -171
- package/dist/directives.js.map +0 -1
- package/dist/entities.d.ts +0 -31
- package/dist/entities.d.ts.map +0 -1
- package/dist/entities.js +0 -76
- package/dist/entities.js.map +0 -1
- package/dist/federated-builder.d.ts +0 -182
- package/dist/federated-builder.d.ts.map +0 -1
- package/dist/federated-builder.js +0 -442
- package/dist/federated-builder.js.map +0 -1
- package/dist/index.d.ts +0 -7
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -40
- package/dist/index.js.map +0 -1
- package/dist/pipe-api.d.ts +0 -163
- package/dist/pipe-api.d.ts.map +0 -1
- package/dist/pipe-api.js +0 -127
- package/dist/pipe-api.js.map +0 -1
- package/dist/scalars.d.ts +0 -12
- package/dist/scalars.d.ts.map +0 -1
- package/dist/scalars.js +0 -59
- package/dist/scalars.js.map +0 -1
- package/dist/types.d.ts +0 -89
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -41
- package/dist/types.js.map +0 -1
- package/src/directives.ts +0 -170
- package/src/entities.ts +0 -90
- package/src/federated-builder.ts +0 -593
- package/src/index.ts +0 -47
- package/src/pipe-api.ts +0 -263
- package/src/scalars.ts +0 -59
- package/src/types.ts +0 -114
package/index.js
ADDED
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
import { Pipeable, Effect, Runtime } from 'effect';
|
|
2
|
+
import * as S from 'effect/Schema';
|
|
3
|
+
import { GraphQLScalarType, Kind, GraphQLSchemaBuilder, GraphQLNonNull, GraphQLList, GraphQLObjectType, GraphQLSchema, printSchema, GraphQLUnionType, GraphQLString } from '@effect-gql/core';
|
|
4
|
+
|
|
5
|
+
// src/federated-builder.ts
|
|
6
|
+
function parseLiteralToValue(ast) {
|
|
7
|
+
switch (ast.kind) {
|
|
8
|
+
case Kind.STRING:
|
|
9
|
+
case Kind.BOOLEAN:
|
|
10
|
+
return ast.value;
|
|
11
|
+
case Kind.INT:
|
|
12
|
+
return parseInt(ast.value, 10);
|
|
13
|
+
case Kind.FLOAT:
|
|
14
|
+
return parseFloat(ast.value);
|
|
15
|
+
case Kind.NULL:
|
|
16
|
+
return null;
|
|
17
|
+
case Kind.LIST:
|
|
18
|
+
return ast.values.map(parseLiteralToValue);
|
|
19
|
+
case Kind.OBJECT: {
|
|
20
|
+
const obj = {};
|
|
21
|
+
for (const field2 of ast.fields) {
|
|
22
|
+
obj[field2.name.value] = parseLiteralToValue(field2.value);
|
|
23
|
+
}
|
|
24
|
+
return obj;
|
|
25
|
+
}
|
|
26
|
+
default:
|
|
27
|
+
return void 0;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
var AnyScalar = new GraphQLScalarType({
|
|
31
|
+
name: "_Any",
|
|
32
|
+
description: "The _Any scalar is used to pass representations of entities from external services.",
|
|
33
|
+
serialize: (value) => value,
|
|
34
|
+
parseValue: (value) => value,
|
|
35
|
+
parseLiteral: parseLiteralToValue
|
|
36
|
+
});
|
|
37
|
+
var FieldSetScalar = new GraphQLScalarType({
|
|
38
|
+
name: "_FieldSet",
|
|
39
|
+
description: "A string representing a selection of fields.",
|
|
40
|
+
serialize: (value) => value,
|
|
41
|
+
parseValue: (value) => value,
|
|
42
|
+
parseLiteral: (ast) => {
|
|
43
|
+
if (ast.kind === Kind.STRING) {
|
|
44
|
+
return ast.value;
|
|
45
|
+
}
|
|
46
|
+
return void 0;
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
function createEntityUnion(entities, typeRegistry) {
|
|
50
|
+
const types = Array.from(entities.keys()).map((name) => typeRegistry.get(name)).filter(Boolean);
|
|
51
|
+
if (types.length === 0) {
|
|
52
|
+
throw new Error("At least one entity must be registered to create _Entity union");
|
|
53
|
+
}
|
|
54
|
+
return new GraphQLUnionType({
|
|
55
|
+
name: "_Entity",
|
|
56
|
+
description: "Union of all types that have @key directives",
|
|
57
|
+
types: () => types,
|
|
58
|
+
resolveType: (value) => value.__typename
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function createEntitiesResolver(entities) {
|
|
62
|
+
return async (_parent, args, context) => {
|
|
63
|
+
const effects = args.representations.map((representation) => {
|
|
64
|
+
const entityName = representation.__typename;
|
|
65
|
+
const entity2 = entities.get(entityName);
|
|
66
|
+
if (!entity2) {
|
|
67
|
+
return Effect.fail(new Error(`Unknown entity type: ${entityName}`));
|
|
68
|
+
}
|
|
69
|
+
return entity2.resolveReference(representation).pipe(
|
|
70
|
+
Effect.map((result) => {
|
|
71
|
+
if (result !== null && typeof result === "object") {
|
|
72
|
+
return { ...result, __typename: entityName };
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}),
|
|
76
|
+
// Catch individual entity resolution errors and return null
|
|
77
|
+
Effect.catchAll(
|
|
78
|
+
(error) => Effect.logError(`Failed to resolve entity ${entityName}`, error).pipe(Effect.as(null))
|
|
79
|
+
)
|
|
80
|
+
);
|
|
81
|
+
});
|
|
82
|
+
return Runtime.runPromise(context.runtime)(Effect.all(effects, { concurrency: "unbounded" }));
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function createServiceType() {
|
|
86
|
+
return new GraphQLObjectType({
|
|
87
|
+
name: "_Service",
|
|
88
|
+
description: "Provides SDL for the subgraph schema",
|
|
89
|
+
fields: {
|
|
90
|
+
sdl: {
|
|
91
|
+
type: GraphQLString,
|
|
92
|
+
description: "The SDL representing the subgraph schema"
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
function createServiceResolver(sdl) {
|
|
98
|
+
return () => ({ sdl });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// src/types.ts
|
|
102
|
+
function toDirectiveApplication(directive) {
|
|
103
|
+
switch (directive._tag) {
|
|
104
|
+
case "key":
|
|
105
|
+
return {
|
|
106
|
+
name: "key",
|
|
107
|
+
args: {
|
|
108
|
+
fields: directive.fields,
|
|
109
|
+
...directive.resolvable !== void 0 ? { resolvable: directive.resolvable } : {}
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
case "external":
|
|
113
|
+
return { name: "external" };
|
|
114
|
+
case "requires":
|
|
115
|
+
return { name: "requires", args: { fields: directive.fields } };
|
|
116
|
+
case "provides":
|
|
117
|
+
return { name: "provides", args: { fields: directive.fields } };
|
|
118
|
+
case "shareable":
|
|
119
|
+
return { name: "shareable" };
|
|
120
|
+
case "inaccessible":
|
|
121
|
+
return { name: "inaccessible" };
|
|
122
|
+
case "override":
|
|
123
|
+
return {
|
|
124
|
+
name: "override",
|
|
125
|
+
args: {
|
|
126
|
+
from: directive.from,
|
|
127
|
+
...directive.label !== void 0 ? { label: directive.label } : {}
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
case "interfaceObject":
|
|
131
|
+
return { name: "interfaceObject" };
|
|
132
|
+
case "tag":
|
|
133
|
+
return { name: "tag", args: { name: directive.name } };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// src/federated-builder.ts
|
|
138
|
+
var FederatedSchemaBuilder = class _FederatedSchemaBuilder {
|
|
139
|
+
constructor(state) {
|
|
140
|
+
this.state = state;
|
|
141
|
+
}
|
|
142
|
+
pipe() {
|
|
143
|
+
return Pipeable.pipeArguments(this, arguments);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Create an empty federated schema builder
|
|
147
|
+
*/
|
|
148
|
+
static empty = new _FederatedSchemaBuilder({
|
|
149
|
+
coreBuilder: GraphQLSchemaBuilder.empty,
|
|
150
|
+
entities: /* @__PURE__ */ new Map(),
|
|
151
|
+
version: "2.3"
|
|
152
|
+
});
|
|
153
|
+
/**
|
|
154
|
+
* Create a builder with custom configuration
|
|
155
|
+
*/
|
|
156
|
+
static create(config = {}) {
|
|
157
|
+
return new _FederatedSchemaBuilder({
|
|
158
|
+
coreBuilder: GraphQLSchemaBuilder.empty,
|
|
159
|
+
entities: /* @__PURE__ */ new Map(),
|
|
160
|
+
version: config.version ?? "2.3"
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Create a new builder with updated state
|
|
165
|
+
*/
|
|
166
|
+
with(updates) {
|
|
167
|
+
return new _FederatedSchemaBuilder({
|
|
168
|
+
...this.state,
|
|
169
|
+
...updates
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Get the underlying core builder for advanced usage
|
|
174
|
+
*/
|
|
175
|
+
get coreBuilder() {
|
|
176
|
+
return this.state.coreBuilder;
|
|
177
|
+
}
|
|
178
|
+
// ============================================================================
|
|
179
|
+
// Entity Registration
|
|
180
|
+
// ============================================================================
|
|
181
|
+
/**
|
|
182
|
+
* Register an entity type with @key directive(s) and reference resolver.
|
|
183
|
+
*
|
|
184
|
+
* Entities are the core building block of Apollo Federation. They represent
|
|
185
|
+
* types that can be resolved across subgraph boundaries using their key fields.
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```typescript
|
|
189
|
+
* builder.entity({
|
|
190
|
+
* name: "User",
|
|
191
|
+
* schema: UserSchema,
|
|
192
|
+
* keys: [key({ fields: "id" })],
|
|
193
|
+
* resolveReference: (ref) => UserService.findById(ref.id),
|
|
194
|
+
* })
|
|
195
|
+
* ```
|
|
196
|
+
*/
|
|
197
|
+
entity(config) {
|
|
198
|
+
const { name, schema, keys, directives } = config;
|
|
199
|
+
const typeDirectives = [
|
|
200
|
+
// Add @key directives
|
|
201
|
+
...keys.map(
|
|
202
|
+
(k) => ({
|
|
203
|
+
name: "key",
|
|
204
|
+
args: {
|
|
205
|
+
fields: k.fields,
|
|
206
|
+
...k.resolvable !== void 0 ? { resolvable: k.resolvable } : {}
|
|
207
|
+
}
|
|
208
|
+
})
|
|
209
|
+
),
|
|
210
|
+
// Add additional directives
|
|
211
|
+
...directives?.map(toDirectiveApplication) ?? []
|
|
212
|
+
];
|
|
213
|
+
const newCoreBuilder = this.state.coreBuilder.objectType({
|
|
214
|
+
name,
|
|
215
|
+
schema,
|
|
216
|
+
directives: typeDirectives
|
|
217
|
+
});
|
|
218
|
+
const newEntities = new Map(this.state.entities);
|
|
219
|
+
newEntities.set(name, config);
|
|
220
|
+
return this.with({
|
|
221
|
+
coreBuilder: newCoreBuilder,
|
|
222
|
+
entities: newEntities
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
// ============================================================================
|
|
226
|
+
// Delegate to Core Builder
|
|
227
|
+
// ============================================================================
|
|
228
|
+
/**
|
|
229
|
+
* Add a query field
|
|
230
|
+
*/
|
|
231
|
+
query(name, config) {
|
|
232
|
+
return this.with({
|
|
233
|
+
coreBuilder: this.state.coreBuilder.query(name, config)
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Add a mutation field
|
|
238
|
+
*/
|
|
239
|
+
mutation(name, config) {
|
|
240
|
+
return this.with({
|
|
241
|
+
coreBuilder: this.state.coreBuilder.mutation(name, config)
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Add a subscription field
|
|
246
|
+
*/
|
|
247
|
+
subscription(name, config) {
|
|
248
|
+
return this.with({
|
|
249
|
+
coreBuilder: this.state.coreBuilder.subscription(name, config)
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Register an object type (non-entity)
|
|
254
|
+
*/
|
|
255
|
+
objectType(config) {
|
|
256
|
+
return this.with({
|
|
257
|
+
coreBuilder: this.state.coreBuilder.objectType(config)
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Register an interface type
|
|
262
|
+
*/
|
|
263
|
+
interfaceType(config) {
|
|
264
|
+
return this.with({
|
|
265
|
+
coreBuilder: this.state.coreBuilder.interfaceType(config)
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Register an enum type
|
|
270
|
+
*/
|
|
271
|
+
enumType(config) {
|
|
272
|
+
return this.with({
|
|
273
|
+
coreBuilder: this.state.coreBuilder.enumType(config)
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Register a union type
|
|
278
|
+
*/
|
|
279
|
+
unionType(config) {
|
|
280
|
+
return this.with({
|
|
281
|
+
coreBuilder: this.state.coreBuilder.unionType(config)
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Register an input type
|
|
286
|
+
*/
|
|
287
|
+
inputType(config) {
|
|
288
|
+
return this.with({
|
|
289
|
+
coreBuilder: this.state.coreBuilder.inputType(config)
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Add a computed/relational field to an object type
|
|
294
|
+
*/
|
|
295
|
+
field(typeName, fieldName, config) {
|
|
296
|
+
return this.with({
|
|
297
|
+
coreBuilder: this.state.coreBuilder.field(
|
|
298
|
+
typeName,
|
|
299
|
+
fieldName,
|
|
300
|
+
config
|
|
301
|
+
)
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
// ============================================================================
|
|
305
|
+
// Schema Building
|
|
306
|
+
// ============================================================================
|
|
307
|
+
/**
|
|
308
|
+
* Build the federated GraphQL schema with _entities and _service queries.
|
|
309
|
+
*
|
|
310
|
+
* Returns both the executable schema and the Federation-compliant SDL.
|
|
311
|
+
*/
|
|
312
|
+
buildFederatedSchema() {
|
|
313
|
+
let builderForSchema = this.state.coreBuilder;
|
|
314
|
+
const needsPlaceholder = !this.hasQueryFields();
|
|
315
|
+
if (needsPlaceholder) {
|
|
316
|
+
builderForSchema = builderForSchema.query("_placeholder", {
|
|
317
|
+
type: S.String,
|
|
318
|
+
resolve: () => Effect.succeed("placeholder")
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
const baseSchema = builderForSchema.buildSchema();
|
|
322
|
+
const typeRegistry = /* @__PURE__ */ new Map();
|
|
323
|
+
const typeMap = baseSchema.getTypeMap();
|
|
324
|
+
for (const [name, type] of Object.entries(typeMap)) {
|
|
325
|
+
const isObjectType = type.constructor.name === "GraphQLObjectType";
|
|
326
|
+
if (isObjectType && !name.startsWith("__")) {
|
|
327
|
+
typeRegistry.set(name, type);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
const entityUnion = this.state.entities.size > 0 ? createEntityUnion(this.state.entities, typeRegistry) : null;
|
|
331
|
+
const serviceType = createServiceType();
|
|
332
|
+
const federationQueryFields = {};
|
|
333
|
+
if (entityUnion) {
|
|
334
|
+
federationQueryFields._entities = {
|
|
335
|
+
type: new GraphQLNonNull(new GraphQLList(entityUnion)),
|
|
336
|
+
args: {
|
|
337
|
+
representations: {
|
|
338
|
+
type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(AnyScalar)))
|
|
339
|
+
}
|
|
340
|
+
},
|
|
341
|
+
resolve: createEntitiesResolver(this.state.entities)
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
const sdl = this.generateFederatedSDL(baseSchema, needsPlaceholder);
|
|
345
|
+
federationQueryFields._service = {
|
|
346
|
+
type: new GraphQLNonNull(serviceType),
|
|
347
|
+
resolve: createServiceResolver(sdl)
|
|
348
|
+
};
|
|
349
|
+
const baseQueryType = baseSchema.getQueryType();
|
|
350
|
+
const baseQueryFields = baseQueryType?.getFields() ?? {};
|
|
351
|
+
const queryType = new GraphQLObjectType({
|
|
352
|
+
name: "Query",
|
|
353
|
+
fields: () => {
|
|
354
|
+
const fields = {};
|
|
355
|
+
for (const [name, field2] of Object.entries(baseQueryFields)) {
|
|
356
|
+
if (name === "_placeholder") continue;
|
|
357
|
+
fields[name] = {
|
|
358
|
+
type: field2.type,
|
|
359
|
+
args: field2.args.reduce(
|
|
360
|
+
(acc, arg) => {
|
|
361
|
+
acc[arg.name] = {
|
|
362
|
+
type: arg.type,
|
|
363
|
+
description: arg.description,
|
|
364
|
+
defaultValue: arg.defaultValue
|
|
365
|
+
};
|
|
366
|
+
return acc;
|
|
367
|
+
},
|
|
368
|
+
{}
|
|
369
|
+
),
|
|
370
|
+
description: field2.description,
|
|
371
|
+
resolve: field2.resolve,
|
|
372
|
+
extensions: field2.extensions
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
Object.assign(fields, federationQueryFields);
|
|
376
|
+
return fields;
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
const types = [AnyScalar, FieldSetScalar, serviceType];
|
|
380
|
+
if (entityUnion) {
|
|
381
|
+
types.push(entityUnion);
|
|
382
|
+
}
|
|
383
|
+
for (const [name, type] of Object.entries(typeMap)) {
|
|
384
|
+
if (!name.startsWith("__") && name !== "Query") {
|
|
385
|
+
types.push(type);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
const schema = new GraphQLSchema({
|
|
389
|
+
query: queryType,
|
|
390
|
+
mutation: baseSchema.getMutationType() ?? void 0,
|
|
391
|
+
subscription: baseSchema.getSubscriptionType() ?? void 0,
|
|
392
|
+
types
|
|
393
|
+
});
|
|
394
|
+
return { schema, sdl };
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Check if the core builder has any query fields registered
|
|
398
|
+
*/
|
|
399
|
+
hasQueryFields() {
|
|
400
|
+
try {
|
|
401
|
+
const schema = this.state.coreBuilder.buildSchema();
|
|
402
|
+
const queryType = schema.getQueryType();
|
|
403
|
+
return queryType !== null && queryType !== void 0;
|
|
404
|
+
} catch {
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Build a standard (non-federated) schema.
|
|
410
|
+
* Useful for testing or running without a gateway.
|
|
411
|
+
*/
|
|
412
|
+
buildSchema() {
|
|
413
|
+
return this.state.coreBuilder.buildSchema();
|
|
414
|
+
}
|
|
415
|
+
// ============================================================================
|
|
416
|
+
// SDL Generation
|
|
417
|
+
// ============================================================================
|
|
418
|
+
/**
|
|
419
|
+
* Generate Federation-compliant SDL with directive annotations.
|
|
420
|
+
*/
|
|
421
|
+
generateFederatedSDL(schema, excludePlaceholder = false) {
|
|
422
|
+
const lines = [
|
|
423
|
+
`extend schema @link(url: "https://specs.apollo.dev/federation/v${this.state.version}", import: ["@key", "@shareable", "@external", "@requires", "@provides", "@override", "@inaccessible", "@interfaceObject", "@tag"])`,
|
|
424
|
+
""
|
|
425
|
+
];
|
|
426
|
+
let baseSDL = printSchema(schema);
|
|
427
|
+
if (excludePlaceholder) {
|
|
428
|
+
baseSDL = baseSDL.replace(/\s*_placeholder:\s*String\n?/g, "");
|
|
429
|
+
}
|
|
430
|
+
const annotatedSDL = this.annotateSDLWithDirectives(baseSDL, schema);
|
|
431
|
+
lines.push(annotatedSDL);
|
|
432
|
+
return lines.join("\n");
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Annotate SDL types with their federation directives from extensions.
|
|
436
|
+
*/
|
|
437
|
+
annotateSDLWithDirectives(sdl, schema) {
|
|
438
|
+
const typeMap = schema.getTypeMap();
|
|
439
|
+
let result = sdl;
|
|
440
|
+
for (const [typeName, type] of Object.entries(typeMap)) {
|
|
441
|
+
if (typeName.startsWith("__")) continue;
|
|
442
|
+
const directives = type.extensions?.directives;
|
|
443
|
+
if (!directives || directives.length === 0) continue;
|
|
444
|
+
const directiveStr = directives.map(formatDirective).join(" ");
|
|
445
|
+
const typePattern = new RegExp(
|
|
446
|
+
`(type\\s+${typeName}(?:\\s+implements\\s+[^{]+)?)(\\s*\\{)`,
|
|
447
|
+
"g"
|
|
448
|
+
);
|
|
449
|
+
result = result.replace(typePattern, `$1 ${directiveStr}$2`);
|
|
450
|
+
const interfacePattern = new RegExp(`(interface\\s+${typeName})(\\s*\\{)`, "g");
|
|
451
|
+
result = result.replace(interfacePattern, `$1 ${directiveStr}$2`);
|
|
452
|
+
const enumPattern = new RegExp(`(enum\\s+${typeName})(\\s*\\{)`, "g");
|
|
453
|
+
result = result.replace(enumPattern, `$1 ${directiveStr}$2`);
|
|
454
|
+
const unionPattern = new RegExp(`(union\\s+${typeName})(\\s*=)`, "g");
|
|
455
|
+
result = result.replace(unionPattern, `$1 ${directiveStr}$2`);
|
|
456
|
+
const inputPattern = new RegExp(`(input\\s+${typeName})(\\s*\\{)`, "g");
|
|
457
|
+
result = result.replace(inputPattern, `$1 ${directiveStr}$2`);
|
|
458
|
+
}
|
|
459
|
+
for (const [typeName, type] of Object.entries(typeMap)) {
|
|
460
|
+
if (typeName.startsWith("__")) continue;
|
|
461
|
+
if (!(type instanceof GraphQLObjectType)) continue;
|
|
462
|
+
const fields = type.getFields();
|
|
463
|
+
for (const [fieldName, field2] of Object.entries(fields)) {
|
|
464
|
+
const fieldDirectives = field2.extensions?.directives;
|
|
465
|
+
if (!fieldDirectives || fieldDirectives.length === 0) continue;
|
|
466
|
+
const directiveStr = fieldDirectives.map(formatDirective).join(" ");
|
|
467
|
+
const typeBlockPattern = new RegExp(
|
|
468
|
+
`(type\\s+${typeName}[^{]*\\{[\\s\\S]*?)(${fieldName}(?:\\([^)]*\\))?:\\s*[^\\n]+?)([\\n}])`,
|
|
469
|
+
"g"
|
|
470
|
+
);
|
|
471
|
+
result = result.replace(typeBlockPattern, `$1$2 ${directiveStr}$3`);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
return result;
|
|
475
|
+
}
|
|
476
|
+
};
|
|
477
|
+
function formatDirective(directive) {
|
|
478
|
+
if (!directive.args || Object.keys(directive.args).length === 0) {
|
|
479
|
+
return `@${directive.name}`;
|
|
480
|
+
}
|
|
481
|
+
const args = Object.entries(directive.args).map(([key2, value]) => {
|
|
482
|
+
if (typeof value === "string") {
|
|
483
|
+
return `${key2}: "${value}"`;
|
|
484
|
+
}
|
|
485
|
+
return `${key2}: ${JSON.stringify(value)}`;
|
|
486
|
+
}).join(", ");
|
|
487
|
+
return `@${directive.name}(${args})`;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// src/directives.ts
|
|
491
|
+
var key = (config) => ({
|
|
492
|
+
_tag: "key",
|
|
493
|
+
fields: config.fields,
|
|
494
|
+
resolvable: config.resolvable
|
|
495
|
+
});
|
|
496
|
+
var shareable = () => ({
|
|
497
|
+
_tag: "shareable"
|
|
498
|
+
});
|
|
499
|
+
var inaccessible = () => ({
|
|
500
|
+
_tag: "inaccessible"
|
|
501
|
+
});
|
|
502
|
+
var interfaceObject = () => ({
|
|
503
|
+
_tag: "interfaceObject"
|
|
504
|
+
});
|
|
505
|
+
var tag = (name) => ({
|
|
506
|
+
_tag: "tag",
|
|
507
|
+
name
|
|
508
|
+
});
|
|
509
|
+
var external = () => ({
|
|
510
|
+
_tag: "external"
|
|
511
|
+
});
|
|
512
|
+
var requires = (config) => ({
|
|
513
|
+
_tag: "requires",
|
|
514
|
+
fields: config.fields
|
|
515
|
+
});
|
|
516
|
+
var provides = (config) => ({
|
|
517
|
+
_tag: "provides",
|
|
518
|
+
fields: config.fields
|
|
519
|
+
});
|
|
520
|
+
var override = (config) => ({
|
|
521
|
+
_tag: "override",
|
|
522
|
+
from: config.from,
|
|
523
|
+
label: config.label
|
|
524
|
+
});
|
|
525
|
+
var entity = (config) => (builder) => builder.entity(config);
|
|
526
|
+
var query = (name, config) => (builder) => builder.query(name, config);
|
|
527
|
+
var mutation = (name, config) => (builder) => builder.mutation(name, config);
|
|
528
|
+
var subscription = (name, config) => (builder) => builder.subscription(name, config);
|
|
529
|
+
var objectType = (config) => (builder) => builder.objectType(config);
|
|
530
|
+
var interfaceType = (config) => (builder) => builder.interfaceType(config);
|
|
531
|
+
var enumType = (config) => (builder) => builder.enumType(config);
|
|
532
|
+
var unionType = (config) => (builder) => builder.unionType(config);
|
|
533
|
+
var inputType = (config) => (builder) => builder.inputType(config);
|
|
534
|
+
var field = (typeName, fieldName, config) => (builder) => builder.field(typeName, fieldName, config);
|
|
535
|
+
var externalField = (config) => ({
|
|
536
|
+
type: config.type,
|
|
537
|
+
description: config.description,
|
|
538
|
+
directives: [{ name: "external" }],
|
|
539
|
+
resolve: (parent) => Effect.succeed(parent)
|
|
540
|
+
});
|
|
541
|
+
var requiresField = (config) => ({
|
|
542
|
+
type: config.type,
|
|
543
|
+
description: config.description,
|
|
544
|
+
directives: [{ name: "requires", args: { fields: config.fields } }],
|
|
545
|
+
resolve: config.resolve
|
|
546
|
+
});
|
|
547
|
+
var providesField = (config) => ({
|
|
548
|
+
type: config.type,
|
|
549
|
+
description: config.description,
|
|
550
|
+
directives: [{ name: "provides", args: { fields: config.fields } }],
|
|
551
|
+
resolve: config.resolve
|
|
552
|
+
});
|
|
553
|
+
var overrideField = (config) => ({
|
|
554
|
+
type: config.type,
|
|
555
|
+
description: config.description,
|
|
556
|
+
directives: [
|
|
557
|
+
{
|
|
558
|
+
name: "override",
|
|
559
|
+
args: {
|
|
560
|
+
from: config.from,
|
|
561
|
+
...config.label !== void 0 ? { label: config.label } : {}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
],
|
|
565
|
+
resolve: config.resolve
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
export { AnyScalar, FederatedSchemaBuilder, FieldSetScalar, entity, enumType, external, externalField, field, inaccessible, inputType, interfaceObject, interfaceType, key, mutation, objectType, override, overrideField, provides, providesField, query, requires, requiresField, shareable, subscription, tag, toDirectiveApplication, unionType };
|
|
569
|
+
//# sourceMappingURL=index.js.map
|
|
570
|
+
//# sourceMappingURL=index.js.map
|