@aws-amplify/amplify-util-uibuilder 1.9.4 → 1.10.0-rc.1d07ad8a8b.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.
@@ -3,6 +3,8 @@ import * as utils from '../commands/utils';
3
3
  import { run } from '../commands/generateComponents';
4
4
  import { isDataStoreEnabled } from '@aws-amplify/amplify-category-api';
5
5
  import { getTransformerVersion } from '../commands/utils/featureFlags';
6
+ import { getCodegenConfig } from 'amplify-codegen';
7
+ import { getUiBuilderComponentsPath } from '../commands/utils/getUiBuilderComponentsPath';
6
8
 
7
9
  jest.mock('../commands/utils');
8
10
  jest.mock('@aws-amplify/amplify-cli-core');
@@ -14,11 +16,22 @@ jest.mock('../commands/utils/featureFlags', () => ({
14
16
  ...jest.requireActual('../commands/utils/featureFlags'),
15
17
  getTransformerVersion: jest.fn(),
16
18
  }));
19
+ jest.mock('../commands/utils/getUiBuilderComponentsPath', () => ({
20
+ ...jest.requireActual('../commands/utils/getUiBuilderComponentsPath'),
21
+ getUiBuilderComponentsPath: jest.fn(),
22
+ }));
23
+ jest.mock('amplify-codegen', () => ({
24
+ ...jest.requireActual('amplify-codegen'),
25
+ getCodegenConfig: jest.fn(),
26
+ }));
27
+
17
28
  const awsMock = aws as any;
18
29
  const utilsMock = utils as any;
30
+ const isDataStoreEnabledMocked = isDataStoreEnabled as any;
31
+ const getTransformerVersionMocked = getTransformerVersion as any;
32
+ const getCodegenConfigMocked = getCodegenConfig as any;
33
+ const getUiBuilderComponentsPathMocked = getUiBuilderComponentsPath as any;
19
34
 
20
- const isDataStoreEnabledMocked = jest.mocked(isDataStoreEnabled);
21
- const getTransformerVersionMocked = jest.mocked(getTransformerVersion);
22
35
  utilsMock.shouldRenderComponents = jest.fn().mockReturnValue(true);
23
36
  utilsMock.notifyMissingPackages = jest.fn().mockReturnValue(true);
24
37
  utilsMock.getAmplifyDataSchema = jest.fn().mockReturnValue({});
@@ -32,18 +45,23 @@ jest.mock('../commands/utils/featureFlags', () => ({
32
45
  getTransformerVersion: jest.fn().mockReturnValue(2),
33
46
  }));
34
47
 
48
+ const defaultStudioFeatureFlags = {
49
+ autoGenerateForms: 'true',
50
+ autoGenerateViews: 'true',
51
+ isRelationshipSupported: 'false',
52
+ isNonModelSupported: 'false',
53
+ isGraphQLEnabled: 'true',
54
+ };
55
+
56
+ const projectPath = '/usr/test/test-project';
57
+
35
58
  describe('can generate components', () => {
36
59
  let context: any;
37
60
  let schemas: any;
38
61
  let mockedExport: jest.Mock<any, any>;
39
62
  const getMetadataPromise = jest.fn().mockReturnValue({
40
63
  features: {
41
- autoGenerateForms: 'true',
42
- autoGenerateViews: 'true',
43
- formFeatureFlags: {
44
- isRelationshipSupported: 'false',
45
- isNonModelSupported: 'false',
46
- },
64
+ ...defaultStudioFeatureFlags,
47
65
  },
48
66
  });
49
67
  const startCodegenJobPromise = jest.fn().mockReturnValue({
@@ -53,6 +71,7 @@ describe('can generate components', () => {
53
71
  promise: startCodegenJobPromise,
54
72
  });
55
73
  beforeEach(() => {
74
+ jest.clearAllMocks();
56
75
  isDataStoreEnabledMocked.mockResolvedValue(true);
57
76
  getTransformerVersionMocked.mockResolvedValue(2);
58
77
  context = {
@@ -65,6 +84,11 @@ describe('can generate components', () => {
65
84
  envName: 'testEnvName',
66
85
  },
67
86
  },
87
+ exeInfo: {
88
+ localEnvInfo: {
89
+ projectPath,
90
+ },
91
+ },
68
92
  };
69
93
  schemas = {
70
94
  entities: [
@@ -81,6 +105,16 @@ describe('can generate components', () => {
81
105
  },
82
106
  ],
83
107
  };
108
+
109
+ getCodegenConfigMocked.mockReturnValue({
110
+ getGeneratedTypesPath: jest.fn().mockReturnValue(undefined),
111
+ getGeneratedQueriesPath: jest.fn().mockReturnValue(projectPath + '/src/graphql/queries.js'),
112
+ getGeneratedMutationsPath: jest.fn().mockReturnValue(projectPath + '/src/graphql/mutations.js'),
113
+ getGeneratedSubscriptionsPath: jest.fn().mockReturnValue(projectPath + '/src/graphql/subscriptions.js'),
114
+ getGeneratedFragmentsPath: jest.fn().mockReturnValue(projectPath + '/src/graphql/fragments.js'),
115
+ getQueryMaxDepth: jest.fn().mockReturnValue(3),
116
+ });
117
+
84
118
  mockedExport = jest.fn().mockReturnValue({
85
119
  entities: schemas.entities,
86
120
  });
@@ -105,10 +139,10 @@ describe('can generate components', () => {
105
139
  promise: jest.fn().mockReturnValue({ status: 'succeeded' }),
106
140
  }),
107
141
  });
142
+ getUiBuilderComponentsPathMocked.mockReturnValue(projectPath + '/src/ui-components');
108
143
  utilsMock.generateUiBuilderComponents = jest.fn().mockReturnValue(schemas.entities);
109
144
  utilsMock.generateUiBuilderThemes = jest.fn().mockReturnValue(schemas.entities);
110
145
  utilsMock.generateUiBuilderForms = jest.fn().mockReturnValue(schemas.entities);
111
- utilsMock.getAmplifyDataSchema = jest.fn().mockReturnValue(undefined);
112
146
  utilsMock.generateAmplifyUiBuilderIndexFile = jest.fn().mockReturnValue(true);
113
147
  utilsMock.generateAmplifyUiBuilderUtilFile = jest.fn().mockReturnValue(true);
114
148
  utilsMock.deleteDetachedForms = jest.fn();
@@ -120,7 +154,7 @@ describe('can generate components', () => {
120
154
  expect(mockedExport).toBeCalledTimes(3);
121
155
  expect(startCodegenJobPromise).toBeCalledTimes(1);
122
156
  expect(utilsMock.waitForSucceededJob).toBeCalledTimes(1);
123
- expect(utilsMock.getUiBuilderComponentsPath).toBeCalledTimes(1);
157
+ expect(getUiBuilderComponentsPathMocked).toBeCalledTimes(1);
124
158
  expect(utilsMock.extractUIComponents).toBeCalledTimes(1);
125
159
  expect(utilsMock.deleteDetachedForms).toBeCalledTimes(1);
126
160
  });
@@ -130,34 +164,14 @@ describe('can generate components', () => {
130
164
  getTransformerVersionMocked.mockResolvedValue(2);
131
165
  getMetadataPromise.mockReturnValue({
132
166
  features: {
133
- autoGenerateForms: 'true',
134
- autoGenerateViews: 'true',
135
- formFeatureFlags: {
136
- isRelationshipSupported: 'false',
137
- isNonModelSupported: 'false',
138
- },
167
+ ...defaultStudioFeatureFlags,
139
168
  },
140
169
  });
141
170
  await run(context, 'PostPull');
142
171
  expect(mockStartCodegenJob).toHaveBeenCalledWith({
143
172
  appId: 'testAppId',
144
173
  environmentName: 'testEnvName',
145
- codegenJobToCreate: {
146
- renderConfig: {
147
- react: {
148
- module: 'es2020',
149
- target: 'es2020',
150
- script: 'jsx',
151
- renderTypeDeclarations: true,
152
- },
153
- },
154
- genericDataSchema: undefined,
155
- autoGenerateForms: true,
156
- features: {
157
- isNonModelSupported: false,
158
- isRelationshipSupported: false,
159
- },
160
- },
174
+ codegenJobToCreate: expect.objectContaining({ autoGenerateForms: true }),
161
175
  });
162
176
  });
163
177
 
@@ -166,104 +180,163 @@ describe('can generate components', () => {
166
180
  getTransformerVersionMocked.mockResolvedValue(1);
167
181
  getMetadataPromise.mockReturnValue({
168
182
  features: {
169
- autoGenerateForms: 'true',
170
- autoGenerateViews: 'true',
171
- formFeatureFlags: {
172
- isRelationshipSupported: 'false',
173
- isNonModelSupported: 'false',
174
- },
183
+ ...defaultStudioFeatureFlags,
175
184
  },
176
185
  });
177
186
  await run(context, 'PostPull');
178
187
  expect(mockStartCodegenJob).toHaveBeenCalledWith({
179
188
  appId: 'testAppId',
180
189
  environmentName: 'testEnvName',
181
- codegenJobToCreate: {
182
- renderConfig: {
183
- react: {
184
- module: 'es2020',
185
- target: 'es2020',
186
- script: 'jsx',
187
- renderTypeDeclarations: true,
188
- },
189
- },
190
- genericDataSchema: undefined,
191
- autoGenerateForms: false,
192
- features: {
193
- isNonModelSupported: false,
194
- isRelationshipSupported: false,
195
- },
190
+ codegenJobToCreate: expect.objectContaining({ autoGenerateForms: false }),
191
+ });
192
+ });
193
+
194
+ it('should not autogenerate forms if datastore is not enabled and GraphQL is not enabled', async () => {
195
+ isDataStoreEnabledMocked.mockResolvedValue(false);
196
+ getMetadataPromise.mockReturnValue({
197
+ features: {
198
+ ...defaultStudioFeatureFlags,
199
+ isGraphQLEnabled: 'false',
196
200
  },
197
201
  });
202
+ await run(context, 'PostPull');
203
+ expect(mockStartCodegenJob).toHaveBeenCalledWith({
204
+ appId: 'testAppId',
205
+ environmentName: 'testEnvName',
206
+ codegenJobToCreate: expect.objectContaining({ autoGenerateForms: false }),
207
+ });
198
208
  });
199
209
 
200
- it('should not autogenerate forms if datastore is not enabled', async () => {
210
+ it('should not autogenerate forms if datastore is not enabled and GraphQL is enabled with invalid config', async () => {
201
211
  isDataStoreEnabledMocked.mockResolvedValue(false);
202
212
  getMetadataPromise.mockReturnValue({
203
213
  features: {
204
- autoGenerateForms: 'true',
205
- autoGenerateViews: 'true',
206
- formFeatureFlags: {
207
- isRelationshipSupported: 'false',
208
- isNonModelSupported: 'false',
209
- },
214
+ ...defaultStudioFeatureFlags,
215
+ isGraphQLEnabled: 'true',
210
216
  },
211
217
  });
218
+ getCodegenConfigMocked.mockImplementation(() => {
219
+ throw new Error();
220
+ });
212
221
  await run(context, 'PostPull');
213
222
  expect(mockStartCodegenJob).toHaveBeenCalledWith({
214
223
  appId: 'testAppId',
215
224
  environmentName: 'testEnvName',
216
- codegenJobToCreate: {
217
- renderConfig: {
218
- react: {
219
- module: 'es2020',
220
- target: 'es2020',
221
- script: 'jsx',
222
- renderTypeDeclarations: true,
223
- },
224
- },
225
- genericDataSchema: undefined,
226
- autoGenerateForms: false,
227
- features: {
228
- isNonModelSupported: false,
229
- isRelationshipSupported: false,
230
- },
225
+ codegenJobToCreate: expect.objectContaining({ autoGenerateForms: false }),
226
+ });
227
+ });
228
+
229
+ it('should autogenerate forms if datastore is not enabled and GraphQL is enabled with valid config', async () => {
230
+ isDataStoreEnabledMocked.mockResolvedValue(false);
231
+ getMetadataPromise.mockReturnValue({
232
+ features: {
233
+ ...defaultStudioFeatureFlags,
234
+ isGraphQLEnabled: 'true',
231
235
  },
232
236
  });
237
+ await run(context, 'PostPull');
238
+ expect(mockStartCodegenJob).toHaveBeenCalledWith({
239
+ appId: 'testAppId',
240
+ environmentName: 'testEnvName',
241
+ codegenJobToCreate: expect.objectContaining({ autoGenerateForms: true }),
242
+ });
233
243
  });
234
244
 
235
245
  it('should not autogenerate forms if feature flag is not enabled', async () => {
236
246
  isDataStoreEnabledMocked.mockResolvedValue(true);
237
247
  getMetadataPromise.mockReturnValue({
238
248
  features: {
249
+ ...defaultStudioFeatureFlags,
239
250
  autoGenerateForms: 'false',
240
- autoGenerateViews: 'true',
241
- formFeatureFlags: {
242
- isRelationshipSupported: 'false',
243
- isNonModelSupported: 'false',
244
- },
245
251
  },
246
252
  });
247
253
  await run(context, 'PostPull');
248
254
  expect(mockStartCodegenJob).toHaveBeenCalledWith({
249
255
  appId: 'testAppId',
250
256
  environmentName: 'testEnvName',
251
- codegenJobToCreate: {
252
- renderConfig: {
253
- react: {
254
- module: 'es2020',
255
- target: 'es2020',
256
- script: 'jsx',
257
- renderTypeDeclarations: true,
257
+ codegenJobToCreate: expect.objectContaining({ autoGenerateForms: false }),
258
+ });
259
+ });
260
+
261
+ describe('codegen job creation', () => {
262
+ it('should inclue dataStore configuration when dataStore is enabled', async () => {
263
+ isDataStoreEnabledMocked.mockResolvedValue(true);
264
+ getMetadataPromise.mockReturnValue({
265
+ features: {
266
+ ...defaultStudioFeatureFlags,
267
+ },
268
+ });
269
+ await run(context, 'PostPull');
270
+ expect(mockStartCodegenJob).toHaveBeenCalledWith({
271
+ appId: 'testAppId',
272
+ environmentName: 'testEnvName',
273
+ codegenJobToCreate: expect.objectContaining({
274
+ renderConfig: {
275
+ react: expect.objectContaining({
276
+ apiConfiguration: {
277
+ dataStoreConfig: {},
278
+ },
279
+ }),
258
280
  },
281
+ }),
282
+ });
283
+ });
284
+
285
+ it('should inclue GraphQL configuration when dataStore is disabled and valid api configuration is found', async () => {
286
+ isDataStoreEnabledMocked.mockResolvedValue(false);
287
+ getMetadataPromise.mockReturnValue({
288
+ features: {
289
+ ...defaultStudioFeatureFlags,
290
+ isGraphQLEnabled: 'true',
259
291
  },
260
- genericDataSchema: undefined,
261
- autoGenerateForms: false,
292
+ });
293
+ await run(context, 'PostPull');
294
+ expect(mockStartCodegenJob).toHaveBeenCalledWith({
295
+ appId: 'testAppId',
296
+ environmentName: 'testEnvName',
297
+ codegenJobToCreate: expect.objectContaining({
298
+ renderConfig: {
299
+ react: expect.objectContaining({
300
+ apiConfiguration: {
301
+ graphQLConfig: {
302
+ fragmentsFilePath: '../graphql/fragments.js',
303
+ mutationsFilePath: '../graphql/mutations.js',
304
+ queriesFilePath: '../graphql/queries.js',
305
+ subscriptionsFilePath: '../graphql/subscriptions.js',
306
+ typesFilePath: '',
307
+ },
308
+ },
309
+ }),
310
+ },
311
+ }),
312
+ });
313
+ });
314
+
315
+ it('should inclue noApi configuration when dataStore is disabled and no valid GraphQL Api', async () => {
316
+ isDataStoreEnabledMocked.mockResolvedValue(false);
317
+ getMetadataPromise.mockReturnValue({
262
318
  features: {
263
- isNonModelSupported: false,
264
- isRelationshipSupported: false,
319
+ ...defaultStudioFeatureFlags,
320
+ isGraphQLEnabled: 'true',
265
321
  },
266
- },
322
+ });
323
+ getCodegenConfigMocked.mockImplementation(() => {
324
+ throw new Error();
325
+ });
326
+ await run(context, 'PostPull');
327
+ expect(mockStartCodegenJob).toHaveBeenCalledWith({
328
+ appId: 'testAppId',
329
+ environmentName: 'testEnvName',
330
+ codegenJobToCreate: expect.objectContaining({
331
+ renderConfig: {
332
+ react: expect.objectContaining({
333
+ apiConfiguration: {
334
+ noApiConfig: {},
335
+ },
336
+ }),
337
+ },
338
+ }),
339
+ });
267
340
  });
268
341
  });
269
342
  });
@@ -0,0 +1,41 @@
1
+ import { $TSContext } from '@aws-amplify/amplify-cli-core';
2
+ import { relativeToComponentsPath } from '../../commands/utils/getApiConfiguration';
3
+ import { getUiBuilderComponentsPath } from '../../commands/utils/getUiBuilderComponentsPath';
4
+ import path from 'path';
5
+
6
+ jest.mock('../../commands/utils/getUiBuilderComponentsPath', () => ({
7
+ ...jest.requireActual('../../commands/utils/getUiBuilderComponentsPath'),
8
+ getUiBuilderComponentsPath: jest.fn(),
9
+ }));
10
+
11
+ jest.mock('path', () => ({
12
+ ...jest.requireActual('path'),
13
+ }));
14
+
15
+ const pathMocked = path as any;
16
+
17
+ const getUiBuilderComponentsPathMocked = getUiBuilderComponentsPath as any;
18
+
19
+ describe('relativeToComponentsPath', () => {
20
+ it('should return posix relative path when run in a windows-like environment', () => {
21
+ pathMocked.relative = path.win32.relative;
22
+ pathMocked.sep = path.win32.sep;
23
+ const projectPath = 'c:\\dev\\test\\test-project';
24
+ const toImport = projectPath + '\\src\\graphql\\queries.js';
25
+ getUiBuilderComponentsPathMocked.mockReturnValue(projectPath + '\\src\\ui-components');
26
+
27
+ const response = relativeToComponentsPath(toImport, {} as $TSContext);
28
+
29
+ expect(response).toBe('../graphql/queries.js');
30
+ });
31
+
32
+ it('should return expected relative path', () => {
33
+ const projectPath = '/dev/test/test-project';
34
+ const toImport = projectPath + '/src/graphql/queries.js';
35
+ getUiBuilderComponentsPathMocked.mockReturnValue(projectPath + '/src/ui-components');
36
+
37
+ const response = relativeToComponentsPath(toImport, {} as $TSContext);
38
+
39
+ expect(response).toBe('../graphql/queries.js');
40
+ });
41
+ });
@@ -17,6 +17,7 @@ export type StudioMetadata = {
17
17
  isRelationshipSupported: boolean;
18
18
  isNonModelSupported: boolean;
19
19
  };
20
+ isGraphQLEnabled: boolean;
20
21
  };
21
22
 
22
23
  /**
@@ -122,6 +123,7 @@ export default class AmplifyStudioClient {
122
123
  isRelationshipSupported: false,
123
124
  isNonModelSupported: false,
124
125
  },
126
+ isGraphQLEnabled: false,
125
127
  };
126
128
  }
127
129
 
@@ -145,6 +147,7 @@ export default class AmplifyStudioClient {
145
147
  isRelationshipSupported: response.features?.isRelationshipSupported === 'true',
146
148
  isNonModelSupported: response.features?.isNonModelSupported === 'true',
147
149
  },
150
+ isGraphQLEnabled: response.features?.isGraphQLEnabled === 'true',
148
151
  };
149
152
  } catch (err) {
150
153
  throw new Error(`Failed to load metadata: ${err.message}`);
@@ -12,10 +12,11 @@ import {
12
12
  hasStorageField,
13
13
  mapGenericDataSchemaToCodegen,
14
14
  waitForSucceededJob,
15
- getUiBuilderComponentsPath,
16
15
  extractUIComponents,
17
16
  } from './utils';
17
+ import { getUiBuilderComponentsPath } from './utils/getUiBuilderComponentsPath';
18
18
  import { AmplifyUIBuilder } from 'aws-sdk';
19
+ import { getApiConfiguration, hasDataStoreConfiguration, hasGraphQLConfiguration } from './utils/getApiConfiguration';
19
20
 
20
21
  /**
21
22
  * Pulls ui components from Studio backend and generates the code in the user's file system
@@ -34,10 +35,15 @@ export const run = async (context: $TSContext, eventType: 'PostPush' | 'PostPull
34
35
  studioClient.isGraphQLSupported ? getAmplifyDataSchema(context) : Promise.resolve(undefined),
35
36
  ]);
36
37
 
37
- const nothingWouldAutogenerate =
38
- !dataSchema || !studioClient.metadata.autoGenerateForms || !studioClient.isGraphQLSupported || !studioClient.isDataStoreEnabled;
38
+ const canGenerateDataComponents = dataSchema && studioClient.isGraphQLSupported;
39
39
 
40
- if (nothingWouldAutogenerate && [componentSchemas, themeSchemas, formSchemas].every((group) => !group.entities.length)) {
40
+ const apiConfiguration: AmplifyUIBuilder.ApiConfiguration = canGenerateDataComponents
41
+ ? getApiConfiguration(studioClient, context)
42
+ : { noApiConfig: {} };
43
+ const hasDataAPI = hasDataStoreConfiguration(apiConfiguration) || hasGraphQLConfiguration(apiConfiguration);
44
+ const willAutogenerateItems = canGenerateDataComponents && studioClient.metadata.autoGenerateForms && hasDataAPI;
45
+
46
+ if (!willAutogenerateItems && [componentSchemas, themeSchemas, formSchemas].every((group) => !group.entities.length)) {
41
47
  printer.debug('Skipping UI component generation since none are found.');
42
48
  return;
43
49
  }
@@ -52,9 +58,10 @@ export const run = async (context: $TSContext, eventType: 'PostPush' | 'PostPull
52
58
  target: 'es2020',
53
59
  script: 'jsx',
54
60
  renderTypeDeclarations: true,
55
- },
61
+ apiConfiguration,
62
+ } as AmplifyUIBuilder.ReactStartCodegenJobData,
56
63
  },
57
- autoGenerateForms: studioClient.metadata.autoGenerateForms && studioClient.isGraphQLSupported,
64
+ autoGenerateForms: studioClient.metadata.autoGenerateForms && studioClient.isGraphQLSupported && hasDataAPI,
58
65
  features: studioClient.metadata.formFeatureFlags,
59
66
  };
60
67
  // SDK will throw if this is undefined
@@ -0,0 +1,73 @@
1
+ import { printer } from '@aws-amplify/amplify-prompts';
2
+ import { AmplifyStudioClient } from '../../clients';
3
+ import { $TSContext } from '@aws-amplify/amplify-cli-core';
4
+ import { getUiBuilderComponentsPath } from './getUiBuilderComponentsPath';
5
+ import { getCodegenConfig } from 'amplify-codegen';
6
+ import { ApiConfiguration } from 'aws-sdk/clients/amplifyuibuilder';
7
+ import path from 'path';
8
+
9
+ //a posix formatted relative path must always be returned as the return values are used directly in jsx files as import paths
10
+ export function relativeToComponentsPath(importPath: string, context: $TSContext): string {
11
+ const componentsPath = getUiBuilderComponentsPath(context);
12
+ const segments = path.relative(componentsPath, importPath).split(path.sep);
13
+ return path.posix.join(...segments);
14
+ }
15
+
16
+ export function getApiConfiguration(studioClient: AmplifyStudioClient, context: $TSContext): ApiConfiguration {
17
+ if (studioClient.isDataStoreEnabled) {
18
+ return {
19
+ dataStoreConfig: {},
20
+ };
21
+ }
22
+
23
+ if (studioClient.metadata.isGraphQLEnabled) {
24
+ printer.debug('building graphql config');
25
+ // attempt to get api codegen info
26
+ const projectPath = context.exeInfo.localEnvInfo.projectPath;
27
+ let promptForUpdateCodegen = false;
28
+
29
+ try {
30
+ const codegenConfig = getCodegenConfig(projectPath);
31
+ const typesPath = codegenConfig.getGeneratedTypesPath();
32
+ const apiConfiguration = {
33
+ graphQLConfig: {
34
+ typesFilePath: (typesPath && relativeToComponentsPath(typesPath, context)) || '',
35
+ queriesFilePath: relativeToComponentsPath(codegenConfig.getGeneratedQueriesPath(), context),
36
+ mutationsFilePath: relativeToComponentsPath(codegenConfig.getGeneratedMutationsPath(), context),
37
+ subscriptionsFilePath: relativeToComponentsPath(codegenConfig.getGeneratedSubscriptionsPath(), context),
38
+ fragmentsFilePath: relativeToComponentsPath(codegenConfig.getGeneratedFragmentsPath(), context),
39
+ },
40
+ };
41
+
42
+ const minQueryDepth = 3;
43
+ const isQueryingTooShallow = (codegenConfig.getQueryMaxDepth() || 0) < minQueryDepth;
44
+
45
+ if (studioClient.metadata.formFeatureFlags.isRelationshipSupported && isQueryingTooShallow) {
46
+ promptForUpdateCodegen = true;
47
+ printer.warn(`Forms with relationships require a maximum query depth of at least ${minQueryDepth}.`);
48
+ }
49
+ return apiConfiguration;
50
+ } catch {
51
+ promptForUpdateCodegen = true;
52
+ printer.warn(
53
+ 'Unable to successfully configure component generation for GraphQL. This will impact generating forms and components bound to your data models.',
54
+ );
55
+ } finally {
56
+ if (promptForUpdateCodegen) {
57
+ printer.warn(`Run 'amplify update codegen' to ensure GraphQL configurations for your project are correct.`);
58
+ }
59
+ }
60
+ }
61
+
62
+ return {
63
+ noApiConfig: {},
64
+ };
65
+ }
66
+
67
+ export function hasDataStoreConfiguration(apiConfiguration: ApiConfiguration): boolean {
68
+ return apiConfiguration.dataStoreConfig !== undefined;
69
+ }
70
+
71
+ export function hasGraphQLConfiguration(apiConfiguration: ApiConfiguration): boolean {
72
+ return apiConfiguration.graphQLConfig !== undefined;
73
+ }