Skip to content

Commit 9f55941

Browse files
authored
fix: use standalone ajv validation for model introspection schema (#807)
* fix: use standalone ajv validation for model introspection schema * test: add unit tests for validator
1 parent a9e6cbd commit 9f55941

File tree

8 files changed

+74
-17
lines changed

8 files changed

+74
-17
lines changed

.eslintrc.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,9 @@ module.exports = {
268268
'/packages/*/CHANGELOG.md',
269269

270270
// Ignore lint in e2e test apps
271-
'test-apps'
271+
'test-apps',
272+
273+
// Ignore lint for standalone JSON validation function
274+
'/packages/appsync-modelgen-plugin/src/validate-cjs.js'
272275
]
273276
};

packages/appsync-modelgen-plugin/package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,18 @@
1818
"codegen"
1919
],
2020
"scripts": {
21-
"build": "tsc",
21+
"build": "yarn generate-schemas && yarn generate-standalone-validation-function && tsc",
2222
"watch": "tsc -w",
2323
"test-watch": "jest --watch",
2424
"test": "jest",
25-
"generate-schemas": "ts-node ./scripts/generateSchemas.ts",
25+
"generate-schemas": "ts-node ./scripts/generateSchemas.ts --overwrite",
26+
"generate-standalone-validation-function": "ts-node ./scripts/generateStandaloneValidationFunction.ts",
2627
"extract-api": "ts-node ../../scripts/extract-api.ts"
2728
},
2829
"dependencies": {
2930
"@graphql-codegen/plugin-helpers": "^1.18.8",
3031
"@graphql-codegen/visitor-plugin-common": "^1.22.0",
3132
"@graphql-tools/utils": "^6.0.18",
32-
"ajv": "^6.10.0",
3333
"chalk": "^3.0.0",
3434
"change-case": "^4.1.1",
3535
"graphql-transformer-common": "^4.25.1",
@@ -45,6 +45,7 @@
4545
"@types/fs-extra": "^8.1.2",
4646
"@types/node": "^12.12.6",
4747
"@types/pluralize": "0.0.29",
48+
"ajv": "^8.12.0",
4849
"graphql": "^15.5.0",
4950
"java-ast": "^0.3.0",
5051
"ts-json-schema-generator": "1.0.0"
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import Ajv from 'ajv';
2+
import modelIntrospectionSchemaDefinition from '../schemas/introspection/1/ModelIntrospectionSchema.json'
3+
import { join } from 'path';
4+
import { writeFileSync } from 'fs';
5+
6+
const standaloneCode = require("ajv/dist/standalone").default
7+
8+
const ajv = new Ajv({ code: { source: true } });
9+
const validate = ajv.compile(modelIntrospectionSchemaDefinition);
10+
11+
let moduleCode = standaloneCode(ajv, validate)
12+
13+
// Now you can write the module code to file
14+
writeFileSync(join(__dirname, "../src/validate-cjs.js"), moduleCode)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
const validateModelIntrospectionSchema = require('../validate-cjs');
2+
import { ModelIntrospectionSchema } from '../interfaces/introspection'
3+
4+
describe('Standalone validation function', () => {
5+
const validSchema: ModelIntrospectionSchema = {
6+
version: 1,
7+
models: {},
8+
nonModels: {},
9+
enums: {},
10+
}
11+
it('should pass on the valid schema', () => {
12+
const result = validateModelIntrospectionSchema(validSchema);
13+
expect(result).toBe(true);
14+
});
15+
describe('should fail on the invalid schema', () => {
16+
it('invalid version', () => {
17+
const schema = {
18+
...validSchema,
19+
version: 100,
20+
};
21+
const result = validateModelIntrospectionSchema(schema);
22+
expect(result).toBe(false);
23+
});
24+
it('invalid fields', () => {
25+
const schema = {
26+
...validSchema,
27+
invalidField: {}
28+
};
29+
const result = validateModelIntrospectionSchema(schema);
30+
expect(result).toBe(false);
31+
});
32+
it('missing required fields', () => {
33+
const schema = {
34+
...validSchema,
35+
};
36+
delete (schema as any).models;
37+
const result = validateModelIntrospectionSchema(schema);
38+
expect(result).toBe(false);
39+
});
40+
});
41+
});

packages/appsync-modelgen-plugin/src/validate-cjs.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/appsync-modelgen-plugin/src/visitors/appsync-model-introspection-visitor.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@ import { GraphQLSchema } from "graphql";
33
import { Argument, AssociationType, Field, Fields, FieldType, ModelAttribute, ModelIntrospectionSchema, PrimaryKeyInfo, SchemaEnum, SchemaModel, SchemaMutation, SchemaNonModel, SchemaQuery, SchemaSubscription, Input, InputFieldType } from "../interfaces/introspection";
44
import { METADATA_SCALAR_MAP } from "../scalars";
55
import { CodeGenConnectionType } from "../utils/process-connections";
6-
import { RawAppSyncModelConfig, ParsedAppSyncModelConfig, AppSyncModelVisitor, CodeGenEnum, CodeGenField, CodeGenModel, CodeGenPrimaryKeyType, CodeGenQuery, CodeGenSubscription, CodeGenMutation, CodeGenInputObject, CodeGenUnion, CodeGenInterface } from "./appsync-visitor";
7-
import fs from 'fs';
8-
import path from 'path';
9-
import Ajv from 'ajv';
6+
import { RawAppSyncModelConfig, ParsedAppSyncModelConfig, AppSyncModelVisitor, CodeGenEnum, CodeGenField, CodeGenModel, CodeGenPrimaryKeyType, CodeGenQuery, CodeGenSubscription, CodeGenMutation, CodeGenInputObject } from "./appsync-visitor";
7+
8+
const validateModelIntrospectionSchema = require('../validate-cjs');
109

1110
type UnionFieldType = { union: string };
1211
type InterfaceFieldType = { interface: string };
@@ -18,17 +17,13 @@ export class AppSyncModelIntrospectionVisitor<
1817
TPluginConfig extends ParsedAppSyncModelIntrospectionConfig = ParsedAppSyncModelIntrospectionConfig
1918
> extends AppSyncModelVisitor<TRawConfig, TPluginConfig> {
2019
private readonly introspectionVersion = 1;
21-
private schemaValidator: Ajv.ValidateFunction;
2220
constructor(
2321
schema: GraphQLSchema,
2422
rawConfig: TRawConfig,
2523
additionalConfig: Partial<TPluginConfig>,
2624
defaultScalars: NormalizedScalarsMap = DEFAULT_SCALARS,
2725
) {
2826
super(schema, rawConfig, additionalConfig, defaultScalars);
29-
const modelIntrospectionSchemaText = fs.readFileSync(path.join(__dirname, '..', '..', 'schemas', 'introspection', this.introspectionVersion.toString(), 'ModelIntrospectionSchema.json'), 'utf8');
30-
const modelIntrospectionSchema = JSON.parse(modelIntrospectionSchemaText);
31-
this.schemaValidator = new Ajv().compile(modelIntrospectionSchema);
3227
}
3328

3429
generate(): string {
@@ -43,8 +38,8 @@ export class AppSyncModelIntrospectionVisitor<
4338
);
4439

4540
const modelIntrosepctionSchema = this.generateModelIntrospectionSchema();
46-
if (!this.schemaValidator(modelIntrosepctionSchema)) {
47-
throw new Error(`Data did not validate against the supplied schema. Underlying errors were ${JSON.stringify(this.schemaValidator.errors)}`);
41+
if (!validateModelIntrospectionSchema(modelIntrosepctionSchema)) {
42+
throw new Error(`Data did not validate against the supplied schema. Underlying errors were ${JSON.stringify(validateModelIntrospectionSchema.errors)}`);
4843
}
4944
return JSON.stringify(modelIntrosepctionSchema, null, 4);
5045
}

packages/appsync-modelgen-plugin/tsconfig.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
"extends": "../../tsconfig.base.json",
33
"compilerOptions": {
44
"rootDir": "src",
5-
"outDir": "lib"
5+
"outDir": "lib",
6+
"allowJs": true,
67
},
78
"exclude": [
89
"scripts",
910
"schemas",
1011
"lib",
11-
"src/__tests__"
12+
"src/__tests__",
13+
"coverage",
1214
]
1315
}

yarn.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6125,7 +6125,7 @@ ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.6, ajv@~6.12.6:
61256125
json-schema-traverse "^0.4.1"
61266126
uri-js "^4.2.2"
61276127

6128-
ajv@^8.0.1, ajv@^8.11.0:
6128+
ajv@^8.0.1, ajv@^8.11.0, ajv@^8.12.0:
61296129
version "8.12.0"
61306130
resolved "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1"
61316131
integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==

0 commit comments

Comments
 (0)