@axinom/mosaic-graphql-codegen-plugins 0.5.0-rc.15 → 0.5.0-rc.16

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
- if (Object.keys(field.type).includes('ofType')) {
50
- const compositeType = [];
51
- Object.keys(field.type.ofType.getFields()).forEach((key) => {
52
- const name = field.type.ofType.getFields()[key]
53
- .name;
54
- const type = field.type.ofType.getFields()[key]
55
- .type;
56
- compositeType.push({
57
- [name]: type,
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
- type = compositeType;
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-rc.15",
3
+ "version": "0.5.0-rc.16",
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": "a90554bb2bfdc4a112fc24983d57e01933121d71"
47
+ "gitHead": "953bb6f0ec82ef5c708a86eeeea66b3882507f0e"
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
- if (Object.keys(field.type).includes('ofType')) {
106
- const compositeType: Data[] = [];
107
-
108
- Object.keys((field.type as GraphQLList<any>).ofType.getFields()).forEach(
109
- (key) => {
110
- const name = (field.type as GraphQLList<any>).ofType.getFields()[key]
111
- .name;
112
- const type = (field.type as GraphQLList<any>).ofType.getFields()[key]
113
- .type;
114
- compositeType.push({
115
- [name]: type,
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
- type = compositeType;
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] = {