@axinom/mosaic-graphql-codegen-plugins 0.5.0-rc.2 → 0.5.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.
|
@@ -44,20 +44,27 @@ exports.plugin = plugin;
|
|
|
44
44
|
function resolveFields(fields, action, postfix = '') {
|
|
45
45
|
const resultingFields = {};
|
|
46
46
|
Object.keys(fields).map((fieldName) => {
|
|
47
|
+
var _a, _b;
|
|
47
48
|
const field = fields[fieldName];
|
|
48
49
|
let type = field.type.toString();
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
.
|
|
56
|
-
|
|
57
|
-
[name]
|
|
50
|
+
try {
|
|
51
|
+
// Handle list of composite types
|
|
52
|
+
const fields = (_b = (_a = field.type.ofType) === null || _a === void 0 ? void 0 : _a.getFields) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
53
|
+
if (fields && typeof fields === 'object') {
|
|
54
|
+
const compositeType = {};
|
|
55
|
+
Object.keys(fields).forEach((key) => {
|
|
56
|
+
const name = fields[key].name;
|
|
57
|
+
const type = fields[key].type;
|
|
58
|
+
compositeType[name] = type;
|
|
58
59
|
});
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
type = [compositeType];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
// If we encounter an unknown type structure, fall back to toString()
|
|
65
|
+
// eslint-disable-next-line no-console
|
|
66
|
+
console.warn(`Warning: Unable to resolve type structure for field "${fieldName}". Using toString() representation.`, error);
|
|
67
|
+
type = field.type.toString();
|
|
61
68
|
}
|
|
62
69
|
resultingFields[postfix ? `${fieldName}${postfix}` : fieldName] = {
|
|
63
70
|
type: type,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axinom/mosaic-graphql-codegen-plugins",
|
|
3
|
-
"version": "0.5.0
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Library of graphql-codegen plugins for Mosaic workflows",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "tsc -w",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"build": "yarn clean && tsc --project tsconfig.build.json",
|
|
9
9
|
"build:ci": "yarn workspaces focus && yarn build",
|
|
10
10
|
"test": "jest --silent",
|
|
11
|
+
"test:watch": "jest --watch",
|
|
11
12
|
"lint": "eslint . --ext .ts,.tsx,.js --color --cache"
|
|
12
13
|
},
|
|
13
14
|
"author": "Axinom",
|
|
@@ -43,5 +44,5 @@
|
|
|
43
44
|
"publishConfig": {
|
|
44
45
|
"access": "public"
|
|
45
46
|
},
|
|
46
|
-
"gitHead": "
|
|
47
|
+
"gitHead": "b48ca504a563d87a93d0b577c20e52175a90179f"
|
|
47
48
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
GraphQLInputObjectType,
|
|
3
|
+
GraphQLList,
|
|
4
|
+
GraphQLNonNull,
|
|
3
5
|
GraphQLObjectType,
|
|
4
6
|
GraphQLSchema,
|
|
5
7
|
GraphQLString,
|
|
@@ -69,6 +71,213 @@ describe('generate-bulk-edit-ui-config plugin', () => {
|
|
|
69
71
|
expect(result).toContain('mutation');
|
|
70
72
|
});
|
|
71
73
|
|
|
74
|
+
it('should generate valid config structure with correct keys and mutation name', () => {
|
|
75
|
+
const result = plugin(schema, [], {}) as string;
|
|
76
|
+
|
|
77
|
+
// Check the config contains the header comment
|
|
78
|
+
expect(result).toContain('/** Bulk Edit Configurations **/');
|
|
79
|
+
|
|
80
|
+
// Check bulkEditEntity config structure
|
|
81
|
+
expect(result).toContain('export const BulkEditEntityFormFieldsConfig');
|
|
82
|
+
expect(result).toContain("mutation: 'bulkEditEntity'");
|
|
83
|
+
expect(result).toContain(
|
|
84
|
+
"keys: { add: 'relatedEntitiesToAdd', remove: 'relatedEntitiesToRemove', set: 'set', filter: 'filter' }",
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
// Validate the config contains proper JSON structure for fields
|
|
88
|
+
const fieldsMatch = result.match(/fields: (\{[\s\S]*?\})\};/);
|
|
89
|
+
expect(fieldsMatch).toBeTruthy();
|
|
90
|
+
expect(fieldsMatch).not.toBeNull();
|
|
91
|
+
|
|
92
|
+
// Parse and validate the JSON structure
|
|
93
|
+
const fieldsJson = JSON.parse(fieldsMatch![1]);
|
|
94
|
+
expect(fieldsJson).toBeDefined();
|
|
95
|
+
expect(typeof fieldsJson).toBe('object');
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should generate field configs with correct structure for relatedEntitiesToAdd', () => {
|
|
99
|
+
const result = plugin(schema, [], {});
|
|
100
|
+
|
|
101
|
+
// Should include fields from RelatedEntitiesInput with "Add" postfix
|
|
102
|
+
expect(result).toContain('"idAdd"');
|
|
103
|
+
expect(result).toContain('"nameAdd"');
|
|
104
|
+
expect(result).toContain('"label": "Id (Add)"');
|
|
105
|
+
expect(result).toContain('"label": "Name (Add)"');
|
|
106
|
+
expect(result).toContain('"action": "relatedEntitiesToAdd"');
|
|
107
|
+
expect(result).toContain('"originalFieldName": "id"');
|
|
108
|
+
expect(result).toContain('"originalFieldName": "name"');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should generate field configs with correct structure for relatedEntitiesToRemove', () => {
|
|
112
|
+
const result = plugin(schema, [], {});
|
|
113
|
+
|
|
114
|
+
// Should include fields from RelatedEntitiesInput with "Remove" postfix
|
|
115
|
+
expect(result).toContain('"idRemove"');
|
|
116
|
+
expect(result).toContain('"nameRemove"');
|
|
117
|
+
expect(result).toContain('"label": "Id (Remove)"');
|
|
118
|
+
expect(result).toContain('"label": "Name (Remove)"');
|
|
119
|
+
expect(result).toContain('"action": "relatedEntitiesToRemove"');
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('should generate field configs with correct structure for set', () => {
|
|
123
|
+
const result = plugin(schema, [], {});
|
|
124
|
+
|
|
125
|
+
// Should include fields from SetInput without postfix
|
|
126
|
+
expect(result).toContain('"status"');
|
|
127
|
+
expect(result).toContain('"label": "Status"');
|
|
128
|
+
expect(result).toContain('"action": "set"');
|
|
129
|
+
expect(result).toContain('"originalFieldName": "status"');
|
|
130
|
+
expect(result).toContain('"type": "String"');
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should handle list/array fields of primitive types (e.g., [String])', () => {
|
|
134
|
+
// Create a schema with primitive array fields
|
|
135
|
+
const PrimitiveArrayInputType = new GraphQLInputObjectType({
|
|
136
|
+
name: 'PrimitiveArrayInput',
|
|
137
|
+
fields: {
|
|
138
|
+
tags: { type: new GraphQLList(GraphQLString) },
|
|
139
|
+
categories: {
|
|
140
|
+
type: new GraphQLList(new GraphQLNonNull(GraphQLString)),
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const SetInputType = new GraphQLInputObjectType({
|
|
146
|
+
name: 'SetInputType',
|
|
147
|
+
fields: {
|
|
148
|
+
title: { type: GraphQLString },
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
const MutationTypeWithPrimitiveArrays = new GraphQLObjectType({
|
|
153
|
+
name: 'Mutation',
|
|
154
|
+
fields: {
|
|
155
|
+
bulkEditWithPrimitiveArrays: {
|
|
156
|
+
type: GraphQLString,
|
|
157
|
+
args: {
|
|
158
|
+
relatedEntitiesToAdd: { type: PrimitiveArrayInputType },
|
|
159
|
+
relatedEntitiesToRemove: { type: PrimitiveArrayInputType },
|
|
160
|
+
set: { type: SetInputType },
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
const schemaWithPrimitiveArrays = new GraphQLSchema({
|
|
167
|
+
query: new GraphQLObjectType({
|
|
168
|
+
name: 'Query',
|
|
169
|
+
fields: { dummy: { type: GraphQLString } },
|
|
170
|
+
}),
|
|
171
|
+
mutation: MutationTypeWithPrimitiveArrays,
|
|
172
|
+
types: [PrimitiveArrayInputType, SetInputType],
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
const result = plugin(schemaWithPrimitiveArrays, [], {}) as string;
|
|
176
|
+
|
|
177
|
+
// Check that the config is generated
|
|
178
|
+
expect(result).toContain('BulkEditWithPrimitiveArraysFormFieldsConfig');
|
|
179
|
+
|
|
180
|
+
// Check that list fields have "Add" and "Remove" postfixes
|
|
181
|
+
expect(result).toContain('"tagsAdd"');
|
|
182
|
+
expect(result).toContain('"tagsRemove"');
|
|
183
|
+
expect(result).toContain('"categoriesAdd"');
|
|
184
|
+
expect(result).toContain('"categoriesRemove"');
|
|
185
|
+
|
|
186
|
+
// Check labels
|
|
187
|
+
expect(result).toContain('"label": "Tags (Add)"');
|
|
188
|
+
expect(result).toContain('"label": "Tags (Remove)"');
|
|
189
|
+
expect(result).toContain('"label": "Categories (Add)"');
|
|
190
|
+
expect(result).toContain('"label": "Categories (Remove)"');
|
|
191
|
+
|
|
192
|
+
// Check that the type is correctly represented as array string type
|
|
193
|
+
expect(result).toContain('"type": "[String]"');
|
|
194
|
+
expect(result).toContain('"type": "[String!]"');
|
|
195
|
+
|
|
196
|
+
// Check actions
|
|
197
|
+
expect(result).toContain('"action": "relatedEntitiesToAdd"');
|
|
198
|
+
expect(result).toContain('"action": "relatedEntitiesToRemove"');
|
|
199
|
+
|
|
200
|
+
// Check original field names
|
|
201
|
+
expect(result).toContain('"originalFieldName": "tags"');
|
|
202
|
+
expect(result).toContain('"originalFieldName": "categories"');
|
|
203
|
+
|
|
204
|
+
// Verify the complete structure for one field
|
|
205
|
+
expect(result).toMatch(
|
|
206
|
+
/"tagsAdd":\s*\{\s*"type":\s*"\[String\]",\s*"label":\s*"Tags \(Add\)",\s*"originalFieldName":\s*"tags",\s*"action":\s*"relatedEntitiesToAdd"\s*\}/,
|
|
207
|
+
);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('should handle list/array fields (tags) with composite types', () => {
|
|
211
|
+
// Create a schema with list fields similar to the imagesTags field
|
|
212
|
+
const TagInputType = new GraphQLInputObjectType({
|
|
213
|
+
name: 'TagInput',
|
|
214
|
+
fields: {
|
|
215
|
+
name: { type: new GraphQLNonNull(GraphQLString) },
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
const TagsInputType = new GraphQLInputObjectType({
|
|
220
|
+
name: 'TagsInput',
|
|
221
|
+
fields: {
|
|
222
|
+
tags: { type: new GraphQLList(TagInputType) },
|
|
223
|
+
},
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
const SetWithTagsInputType = new GraphQLInputObjectType({
|
|
227
|
+
name: 'SetWithTagsInput',
|
|
228
|
+
fields: {
|
|
229
|
+
title: { type: GraphQLString },
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
const MutationTypeWithTags = new GraphQLObjectType({
|
|
234
|
+
name: 'Mutation',
|
|
235
|
+
fields: {
|
|
236
|
+
bulkEditWithTags: {
|
|
237
|
+
type: GraphQLString,
|
|
238
|
+
args: {
|
|
239
|
+
relatedEntitiesToAdd: { type: TagsInputType },
|
|
240
|
+
relatedEntitiesToRemove: { type: TagsInputType },
|
|
241
|
+
set: { type: SetWithTagsInputType },
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
const schemaWithTags = new GraphQLSchema({
|
|
248
|
+
query: new GraphQLObjectType({
|
|
249
|
+
name: 'Query',
|
|
250
|
+
fields: { dummy: { type: GraphQLString } },
|
|
251
|
+
}),
|
|
252
|
+
mutation: MutationTypeWithTags,
|
|
253
|
+
types: [TagInputType, TagsInputType, SetWithTagsInputType],
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
const result = plugin(schemaWithTags, [], {}) as string;
|
|
257
|
+
|
|
258
|
+
// Check that the config is generated
|
|
259
|
+
expect(result).toContain('BulkEditWithTagsFormFieldsConfig');
|
|
260
|
+
|
|
261
|
+
// Check that list fields have "Add" and "Remove" postfixes
|
|
262
|
+
expect(result).toContain('"tagsAdd"');
|
|
263
|
+
expect(result).toContain('"tagsRemove"');
|
|
264
|
+
|
|
265
|
+
// Check labels
|
|
266
|
+
expect(result).toContain('"label": "Tags (Add)"');
|
|
267
|
+
expect(result).toContain('"label": "Tags (Remove)"');
|
|
268
|
+
|
|
269
|
+
// Check that the type is an array with composite type information
|
|
270
|
+
expect(result).toContain('"type": [');
|
|
271
|
+
expect(result).toContain('"name"');
|
|
272
|
+
|
|
273
|
+
// Check actions
|
|
274
|
+
expect(result).toContain('"action": "relatedEntitiesToAdd"');
|
|
275
|
+
expect(result).toContain('"action": "relatedEntitiesToRemove"');
|
|
276
|
+
|
|
277
|
+
// Check original field names
|
|
278
|
+
expect(result).toContain('"originalFieldName": "tags"');
|
|
279
|
+
});
|
|
280
|
+
|
|
72
281
|
it('should generate config for mutations with only set argument', () => {
|
|
73
282
|
const result = plugin(schema, [], {});
|
|
74
283
|
expect(result).toContain('AnotherMutationFormFieldsConfig');
|
|
@@ -123,4 +332,48 @@ describe('generate-bulk-edit-ui-config plugin', () => {
|
|
|
123
332
|
const result = plugin(schemaWithIrrelevantMutation, [], {});
|
|
124
333
|
expect(result).not.toContain('NoRelevantArgsFormFieldsConfig');
|
|
125
334
|
});
|
|
335
|
+
|
|
336
|
+
it('should handle errors gracefully and fall back to toString()', () => {
|
|
337
|
+
// Create a mock field type that will throw an error when accessing ofType
|
|
338
|
+
const ProblematicInputType = new GraphQLInputObjectType({
|
|
339
|
+
name: 'ProblematicInput',
|
|
340
|
+
fields: {
|
|
341
|
+
normalField: { type: GraphQLString },
|
|
342
|
+
},
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
const MutationTypeWithProblematic = new GraphQLObjectType({
|
|
346
|
+
name: 'Mutation',
|
|
347
|
+
fields: {
|
|
348
|
+
bulkEditProblematic: {
|
|
349
|
+
type: GraphQLString,
|
|
350
|
+
args: {
|
|
351
|
+
set: { type: ProblematicInputType },
|
|
352
|
+
},
|
|
353
|
+
},
|
|
354
|
+
},
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
const schemaWithProblematic = new GraphQLSchema({
|
|
358
|
+
query: new GraphQLObjectType({
|
|
359
|
+
name: 'Query',
|
|
360
|
+
fields: { dummy: { type: GraphQLString } },
|
|
361
|
+
}),
|
|
362
|
+
mutation: MutationTypeWithProblematic,
|
|
363
|
+
types: [ProblematicInputType],
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
// Spy on console.warn to verify it's called if needed
|
|
367
|
+
const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation();
|
|
368
|
+
|
|
369
|
+
const result = plugin(schemaWithProblematic, [], {}) as string;
|
|
370
|
+
|
|
371
|
+
// Should still generate config even if there's an error
|
|
372
|
+
expect(result).toContain('BulkEditProblematicFormFieldsConfig');
|
|
373
|
+
expect(result).toContain('"normalField"');
|
|
374
|
+
expect(result).toContain('"type": "String"');
|
|
375
|
+
|
|
376
|
+
// Restore console.warn
|
|
377
|
+
consoleWarnSpy.mockRestore();
|
|
378
|
+
});
|
|
126
379
|
});
|
|
@@ -102,22 +102,29 @@ function resolveFields(
|
|
|
102
102
|
|
|
103
103
|
let type: string | Data[] = field.type.toString();
|
|
104
104
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
},
|
|
118
|
-
);
|
|
105
|
+
try {
|
|
106
|
+
// Handle list of composite types
|
|
107
|
+
const fields = (field.type as GraphQLList<any>).ofType?.getFields?.();
|
|
108
|
+
|
|
109
|
+
if (fields && typeof fields === 'object') {
|
|
110
|
+
const compositeType: Data = {};
|
|
111
|
+
|
|
112
|
+
Object.keys(fields).forEach((key) => {
|
|
113
|
+
const name = fields[key].name;
|
|
114
|
+
const type = fields[key].type;
|
|
115
|
+
compositeType[name] = type;
|
|
116
|
+
});
|
|
119
117
|
|
|
120
|
-
|
|
118
|
+
type = [compositeType];
|
|
119
|
+
}
|
|
120
|
+
} catch (error) {
|
|
121
|
+
// If we encounter an unknown type structure, fall back to toString()
|
|
122
|
+
// eslint-disable-next-line no-console
|
|
123
|
+
console.warn(
|
|
124
|
+
`Warning: Unable to resolve type structure for field "${fieldName}". Using toString() representation.`,
|
|
125
|
+
error,
|
|
126
|
+
);
|
|
127
|
+
type = field.type.toString();
|
|
121
128
|
}
|
|
122
129
|
|
|
123
130
|
resultingFields[postfix ? `${fieldName}${postfix}` : fieldName] = {
|