Skip to content

Commit fbe38d6

Browse files
authored
Merge pull request #729 from aws-amplify/main
Release Codegen
2 parents d469484 + 9c9e1ba commit fbe38d6

File tree

9 files changed

+199
-8
lines changed

9 files changed

+199
-8
lines changed

packages/amplify-codegen/src/utils/getRelativeTypesPath.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ const path = require('path');
22

33
function getRelativeTypesPath(opsGenDirectory, generatedFileName) {
44
if (generatedFileName) {
5-
const relativePath = path.relative(opsGenDirectory, generatedFileName);
5+
const relativePath = path
6+
.relative(opsGenDirectory, generatedFileName)
7+
// ensure posix path separators are used
8+
.split(path.win32.sep)
9+
.join(path.posix.sep);
610

711
// generatedFileName is in same directory as opsGenDirectory
812
// i.e. generatedFileName: src/graphql/API.ts, opsGenDirectory: src/graphql

packages/amplify-codegen/tests/commands/mock-fs-setup.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ const { getOutputFileName } = require('@aws-amplify/graphql-types-generator');
77
* Mocks existence of `schema.json` using mocks fs
88
* Mocks existence of `.graphqlconfig.yml` by mocking return value for loadConfig utility
99
*/
10-
function setupMocks(mockFs, loadConfig, apiId, frontend, target) {
10+
function setupMocks(mockFs, loadConfig, apiId, frontend, target, generatedFileNameOverride, extendMockFs) {
1111
mockFs.restore();
1212
const docsFilePath = {
1313
javascript: 'src/graphql',
1414
android: 'app/src/main/graphql/com/amazonaws/amplify/generated/graphql',
1515
swift: 'graphql',
1616
};
17-
const generatedFileName = getOutputFileName('API', target);
17+
const generatedFileName = generatedFileNameOverride || getOutputFileName('API', target);
1818
const schemaFilePath = 'schema.json';
1919
const nodeModulesPrettier = path.resolve(path.join(__dirname, '../../../../node_modules/prettier'));
2020
const mockedFiles = {
@@ -26,6 +26,7 @@ function setupMocks(mockFs, loadConfig, apiId, frontend, target) {
2626
lazy: true,
2727
}),
2828
[schemaFilePath]: mockFs.load(path.resolve(path.join(__dirname, './blog-introspection-schema.json'))),
29+
...extendMockFs,
2930
};
3031
mockFs(mockedFiles);
3132

packages/amplify-codegen/tests/commands/types-mock-fs.test.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,22 @@ describe('command - types (mock fs)', () => {
9090
});
9191
});
9292

93+
it('should generate multiple swift files if generatedFileName is a dir', async () => {
94+
const generatedFileName = 'api';
95+
setupMocks(mockFs, loadConfig, MOCK_API_ID, 'swift', 'swift', generatedFileName, { [generatedFileName]: {} });
96+
97+
await generateStatements(MOCK_CONTEXT, false);
98+
await generateTypes(MOCK_CONTEXT, false);
99+
100+
expect(fs.existsSync(generatedFileName)).toBeTruthy();
101+
expect(fs.readdirSync(generatedFileName)).toEqual([
102+
'Types.graphql.swift',
103+
'mutations.graphql.swift',
104+
'queries.graphql.swift',
105+
'subscriptions.graphql.swift',
106+
]);
107+
});
108+
93109
it('should not generate types when target is javascript', async () => {
94110
const generatedFileName = setupMocks(mockFs, loadConfig, MOCK_API_ID, 'javascript', 'javascript');
95111

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`TypeScript visitor list enum 1`] = `
4+
"import { ModelInit, MutableModel, PersistentModelConstructor } from \\"@aws-amplify/datastore\\";
5+
import { initSchema } from \\"@aws-amplify/datastore\\";
6+
7+
import { schema } from \\"./schema\\";
8+
9+
export enum DayOfWeek {
10+
MONDAY = \\"MONDAY\\",
11+
TUESDAY = \\"TUESDAY\\",
12+
WEDNESDAY = \\"WEDNESDAY\\",
13+
THURSDAY = \\"THURSDAY\\",
14+
FRIDAY = \\"FRIDAY\\",
15+
SATURDAY = \\"SATURDAY\\",
16+
SUNDAY = \\"SUNDAY\\"
17+
}
18+
19+
20+
21+
type EagerRecurrenceModel = {
22+
readonly daysOfWeek: DayOfWeek[] | Array<keyof typeof DayOfWeek>;
23+
}
24+
25+
type LazyRecurrenceModel = {
26+
readonly daysOfWeek: DayOfWeek[] | Array<keyof typeof DayOfWeek>;
27+
}
28+
29+
export declare type RecurrenceModel = LazyLoading extends LazyLoadingDisabled ? EagerRecurrenceModel : LazyRecurrenceModel
30+
31+
export declare const RecurrenceModel: (new (init: ModelInit<RecurrenceModel>) => RecurrenceModel)
32+
33+
const { Recurrence } = initSchema(schema) as {
34+
Recurrence: PersistentModelConstructor<RecurrenceModel>;
35+
};
36+
37+
export {
38+
39+
};"
40+
`;
41+
42+
exports[`TypeScript visitor singular enum 1`] = `
43+
"import { ModelInit, MutableModel, PersistentModelConstructor } from \\"@aws-amplify/datastore\\";
44+
import { initSchema } from \\"@aws-amplify/datastore\\";
45+
46+
import { schema } from \\"./schema\\";
47+
48+
export enum Frequency {
49+
YEARLY = \\"YEARLY\\",
50+
WEEKLY = \\"WEEKLY\\"
51+
}
52+
53+
54+
55+
type EagerRecurrenceModel = {
56+
readonly frequency: Frequency | keyof typeof Frequency;
57+
}
58+
59+
type LazyRecurrenceModel = {
60+
readonly frequency: Frequency | keyof typeof Frequency;
61+
}
62+
63+
export declare type RecurrenceModel = LazyLoading extends LazyLoadingDisabled ? EagerRecurrenceModel : LazyRecurrenceModel
64+
65+
export declare const RecurrenceModel: (new (init: ModelInit<RecurrenceModel>) => RecurrenceModel)
66+
67+
const { Recurrence } = initSchema(schema) as {
68+
Recurrence: PersistentModelConstructor<RecurrenceModel>;
69+
};
70+
71+
export {
72+
73+
};"
74+
`;
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { buildSchema, GraphQLSchema, parse, visit } from 'graphql';
2+
import { validateTs } from '@graphql-codegen/testing';
3+
import { TYPESCRIPT_SCALAR_MAP } from '../../scalars';
4+
import { directives, scalars } from '../../scalars/supported-directives';
5+
import { AppSyncModelTypeScriptVisitor } from '../../visitors/appsync-typescript-visitor';
6+
7+
const buildSchemaWithDirectives = (schema: String): GraphQLSchema => {
8+
return buildSchema([schema, directives, scalars].join('\n'));
9+
};
10+
const getVisitor = (schema: string): AppSyncModelTypeScriptVisitor => {
11+
const ast = parse(schema);
12+
const builtSchema = buildSchemaWithDirectives(schema);
13+
const visitor = new AppSyncModelTypeScriptVisitor(
14+
builtSchema,
15+
{ directives, target: 'typescript', scalars: TYPESCRIPT_SCALAR_MAP, codegenVersion: '3.3.4' },
16+
{},
17+
);
18+
visit(ast, { leave: visitor });
19+
return visitor;
20+
};
21+
22+
describe('TypeScript visitor', () => {
23+
test('singular enum', () => {
24+
const schema = /* GraphQL */ `
25+
enum Frequency {
26+
YEARLY
27+
WEEKLY
28+
}
29+
30+
type Recurrence {
31+
frequency: Frequency!
32+
}
33+
`;
34+
const visitor = getVisitor(schema);
35+
expect(visitor.generate()).toMatchSnapshot();
36+
});
37+
38+
test('list enum', () => {
39+
const schema = /* GraphQL */ `
40+
enum DayOfWeek {
41+
MONDAY
42+
TUESDAY
43+
WEDNESDAY
44+
THURSDAY
45+
FRIDAY
46+
SATURDAY
47+
SUNDAY
48+
}
49+
50+
type Recurrence {
51+
daysOfWeek: [DayOfWeek!]!
52+
}
53+
`;
54+
const visitor = getVisitor(schema);
55+
expect(visitor.generate()).toMatchSnapshot();
56+
});
57+
});

packages/appsync-modelgen-plugin/src/visitors/appsync-typescript-visitor.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export class AppSyncModelTypeScriptVisitor<
4848
this.processDirectives(
4949
shouldUseModelNameFieldInHasManyAndBelongsTo,
5050
shouldImputeKeyForUniDirectionalHasMany,
51-
shouldUseFieldsInAssociatedWithInHasOne
51+
shouldUseFieldsInAssociatedWithInHasOne,
5252
);
5353
const imports = this.generateImports();
5454
const enumDeclarations = Object.values(this.enumMap)
@@ -320,7 +320,9 @@ export class AppSyncModelTypeScriptVisitor<
320320
let nativeType = super.getNativeType(field);
321321

322322
if (this.isEnumType(field)) {
323-
nativeType = `${nativeType} | keyof typeof ${this.getEnumName(this.enumMap[typeName])}`;
323+
const baseEnumType = `keyof typeof ${this.getEnumName(this.enumMap[typeName])}`;
324+
const enumType = field.isList ? `Array<${baseEnumType}>` : baseEnumType;
325+
nativeType = `${nativeType} | ${enumType}`;
324326
}
325327

326328
nativeType = nativeType + nullableTypeUnion;

packages/graphql-generator/src/__tests__/utils/GraphQLStatementsFormatter.test.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,16 @@ describe('GraphQL statements Formatter', () => {
2626
expect(formattedOutput).toMatchSnapshot();
2727
});
2828

29-
it('Generates formatted output for TS frontend', () => {
29+
it('Generates formatted output for TS frontend with posix path', () => {
3030
const formattedOutput = new GraphQLStatementsFormatter('typescript', 'queries', '../API.ts').format(statements);
3131
expect(formattedOutput).toMatchSnapshot();
3232
});
3333

34+
it('Generates formatted output for TS frontend with windows path', () => {
35+
const formattedOutput = new GraphQLStatementsFormatter('typescript', 'queries', '..\\API.ts').format(statements);
36+
expect(formattedOutput).toMatchSnapshot();
37+
});
38+
3439
it('Generates formatted output for Flow frontend', () => {
3540
const formattedOutput = new GraphQLStatementsFormatter('flow').format(statements);
3641
expect(formattedOutput).toMatchSnapshot();

packages/graphql-generator/src/__tests__/utils/__snapshots__/GraphQLStatementsFormatter.test.ts.snap

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,33 @@ export const getProject = /* GraphQL */ \`
6262
"
6363
`;
6464

65-
exports[`GraphQL statements Formatter Generates formatted output for TS frontend 1`] = `
65+
exports[`GraphQL statements Formatter Generates formatted output for TS frontend with posix path 1`] = `
66+
"/* tslint:disable */
67+
/* eslint-disable */
68+
// this is an auto generated file. This will be overwritten
69+
70+
import * as APITypes from \\"../API\\";
71+
type GeneratedQuery<InputType, OutputType> = string & {
72+
__generatedQueryInput: InputType;
73+
__generatedQueryOutput: OutputType;
74+
};
75+
76+
export const getProject = /* GraphQL */ \`query GetProject($id: ID!) {
77+
getProject(id: $id) {
78+
id
79+
name
80+
createdAt
81+
updatedAt
82+
}
83+
}
84+
\` as GeneratedQuery<
85+
APITypes.GetProjectQueryVariables,
86+
APITypes.GetProjectQuery
87+
>;
88+
"
89+
`;
90+
91+
exports[`GraphQL statements Formatter Generates formatted output for TS frontend with windows path 1`] = `
6692
"/* tslint:disable */
6793
/* eslint-disable */
6894
// this is an auto generated file. This will be overwritten

packages/graphql-generator/src/utils/GraphQLStatementsFormatter.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import * as path from 'path';
12
import prettier, { BuiltInParserName } from 'prettier';
23
import {
34
interfaceNameFromOperation,
@@ -34,7 +35,12 @@ export class GraphQLStatementsFormatter {
3435
}[operation];
3536
this.lintOverrides = [];
3637
this.headerComments = [];
37-
this.typesPath = typesPath ? typesPath.replace(/.ts/i, '') : null;
38+
this.typesPath = typesPath
39+
? typesPath.replace(/.ts/i, '')
40+
// ensure posix path separators are used
41+
.split(path.win32.sep)
42+
.join(path.posix.sep)
43+
: null;
3844
this.includeTypeScriptTypes = !!(this.language === 'typescript' && this.opTypeName && this.typesPath);
3945
}
4046

0 commit comments

Comments
 (0)