Skip to content
This repository was archived by the owner on Jun 27, 2025. It is now read-only.

Commit 5a17818

Browse files
authored
Feat: Upgrade AJV from 6 to 8 (#31)
Also drop support for node 14.x
1 parent 447a1c4 commit 5a17818

31 files changed

+6746
-6810
lines changed

.github/workflows/build-and-test.yml

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
runs-on: macos-latest
1212
strategy:
1313
matrix:
14-
node-version: [14.x, 16.x, 18.x]
14+
node-version: [16.x, 18.x]
1515

1616
steps:
1717
- uses: actions/checkout@v3
@@ -28,7 +28,7 @@ jobs:
2828
runs-on: ubuntu-latest
2929
strategy:
3030
matrix:
31-
node-version: [14.x, 16.x, 18.x]
31+
node-version: [16.x, 18.x]
3232

3333
steps:
3434
- uses: actions/checkout@v3
@@ -40,24 +40,3 @@ jobs:
4040
node-version: ${{ matrix.node-version }}
4141
- run: ./scripts/build.sh
4242
shell: bash
43-
44-
# Fails
45-
# [10:27:19] Error: Command failed: ./node_modules/.bin/conventional-changelog-lint --from=HEAD~20 --preset angular
46-
# ['.' is not recognized as an internal or external command,
47-
# [operable program or batch file.
48-
# build-and-test-windows:
49-
# runs-on: windows-latest
50-
# strategy:
51-
# matrix:
52-
# node-version: [12.x, 14.x, 16.x]
53-
54-
# steps:
55-
# - uses: actions/checkout@v3
56-
# with:
57-
# fetch-depth: 0
58-
# - name: Use Node.js ${{ matrix.node-version }}
59-
# uses: actions/setup-node@v3
60-
# with:
61-
# node-version: ${{ matrix.node-version }}
62-
# - run: ./bin/build.sh
63-
# shell: bash

jasmine.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@
66
"../test/helpers/**/*.ts"
77
],
88
"stopSpecOnExpectationFailure": false,
9-
"random": true
9+
"random": false
1010
}
Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import {ParsedSpecJsonSchemaCore, ParsedSpecOperation, ParsedSpecParameter} from '../../parsed-spec';
2-
import {Header, Parameter} from '../openapi3';
1+
import { ParsedSpecJsonSchemaCore, ParsedSpecOperation, ParsedSpecParameter } from '../../parsed-spec';
2+
import { Header, Parameter } from '../openapi3';
33

44
interface ToParsedSpecParameterOptions {
55
parameter: Header | Parameter;
@@ -8,26 +8,39 @@ interface ToParsedSpecParameterOptions {
88
location: string;
99
}
1010

11-
const isParameterSchemaUndefined = (schema?: ParsedSpecJsonSchemaCore): schema is undefined =>
12-
schema === undefined;
11+
const isParameterSchemaUndefined = (schema?: ParsedSpecJsonSchemaCore): schema is undefined => schema === undefined;
1312

1413
const isParameterSchemaUnsupported = (schema: ParsedSpecJsonSchemaCore): boolean =>
1514
schema.type === 'object' || schema.type === 'array';
1615

16+
// draft-06 onwards converts exclusiveMinimum and exclusiveMaximum to numbers
17+
const upgradeSchema = (schema: ParsedSpecJsonSchemaCore): ParsedSpecJsonSchemaCore => {
18+
if (schema.exclusiveMaximum) {
19+
schema.exclusiveMaximum = schema.maximum;
20+
}
21+
if (schema.exclusiveMinimum) {
22+
schema.exclusiveMinimum = schema.minimum;
23+
}
24+
return schema;
25+
};
26+
1727
const getParameterSchema = (parameter: Header | Parameter): ParsedSpecJsonSchemaCore =>
1828
isParameterSchemaUndefined(parameter.schema) || isParameterSchemaUnsupported(parameter.schema)
19-
? {}
20-
: parameter.schema;
29+
? {}
30+
: upgradeSchema(parameter.schema);
2131

22-
export const toParsedSpecParameter = (
23-
{parameter, name, parentOperation, location}: ToParsedSpecParameterOptions
24-
): ParsedSpecParameter => {
32+
export const toParsedSpecParameter = ({
33+
parameter,
34+
name,
35+
parentOperation,
36+
location,
37+
}: ToParsedSpecParameterOptions): ParsedSpecParameter => {
2538
return {
2639
location,
2740
name,
2841
parentOperation,
2942
required: parameter.required || false,
3043
schema: getParameterSchema(parameter),
31-
value: parameter
44+
value: parameter,
3245
};
3346
};

lib/swagger-mock-validator/spec-parser/parsed-spec.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ interface ParsedSpecJsonSchemaBooleanKeywords {
6060
interface ParsedSpecJsonSchemaValue {
6161
additionalProperties?: boolean | ParsedSpecJsonSchema;
6262
enum?: any[];
63-
exclusiveMaximum?: boolean;
64-
exclusiveMinimum?: boolean;
63+
exclusiveMaximum?: number;
64+
exclusiveMinimum?: number;
6565
format?: ParsedSpecSchemaFormat;
6666
items?: ParsedSpecJsonSchema;
6767
maxItems?: number;

lib/swagger-mock-validator/spec-parser/swagger2/swagger2-parser.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ const toParsedParameter = (
8585
required: (parameter.value as SwaggerHeaderPathOrQueryParameter).required || false,
8686
schema: {
8787
enum: parameter.value.enum,
88-
exclusiveMaximum: parameter.value.exclusiveMaximum,
89-
exclusiveMinimum: parameter.value.exclusiveMinimum,
88+
exclusiveMaximum: parameter.value.exclusiveMaximum ? parameter.value.maximum : undefined,
89+
exclusiveMinimum: parameter.value.exclusiveMinimum ? parameter.value.minimum : undefined,
9090
format: parameter.value.format,
9191
items: parameter.value.items,
9292
maxItems: parameter.value.maxItems,
Lines changed: 12 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,128 +1,21 @@
1-
import Ajv from 'ajv';
2-
import _ from 'lodash';
3-
import {traverseJsonSchema} from '../common/traverse-json-schema';
4-
import {ParsedSpecJsonSchema, ParsedSpecJsonSchemaCore} from '../spec-parser/parsed-spec';
5-
import {isBinary} from './validate-json/binary';
6-
import {isByte} from './validate-json/byte';
7-
import {doubleAjvKeyword, formatForDoubleNumbers, isDouble} from './validate-json/double';
8-
import {floatAjvKeyword, formatForFloatNumbers, isFloat} from './validate-json/float';
9-
import {formatForInt32Numbers, int32AjvKeyword, isInt32} from './validate-json/int32';
10-
import {formatForInt64Numbers, int64AjvKeyword, isInt64} from './validate-json/int64';
11-
import { formatForString, isString, stringAjvKeyword } from './validate-json/string';
12-
import {isPassword} from './validate-json/password';
13-
import draft4MetaSchema from 'ajv/lib/refs/json-schema-draft-04.json';
14-
15-
const removeLeadingDotIfPresent = (dataPath: string): string =>
16-
dataPath.replace(/^\./, '');
17-
18-
const getRawValueFromJson = (rawJson: any, dataPath?: string): any =>
19-
dataPath ? _.get(rawJson, removeLeadingDotIfPresent(dataPath)) : rawJson;
20-
21-
const addSwaggerFormatsAndKeywords = (ajv: Ajv.Ajv, rawJson: any) => {
22-
ajv.addFormat('binary', isBinary);
23-
ajv.addFormat('byte', isByte);
24-
ajv.addFormat('password', isPassword);
25-
ajv.addKeyword(doubleAjvKeyword, {
26-
type: 'number',
27-
validate: (_schema: any, _data: number, _parentSchema: any, dataPath?: string) => {
28-
const rawValue = getRawValueFromJson(rawJson, dataPath);
29-
return isDouble(rawValue);
30-
}
31-
});
32-
ajv.addKeyword(floatAjvKeyword, {
33-
type: 'number',
34-
validate: (_schema: any, _data: number, _parentSchema: any, dataPath?: string) => {
35-
const rawValue = getRawValueFromJson(rawJson, dataPath);
36-
return isFloat(rawValue);
37-
}
38-
});
39-
ajv.addKeyword(int32AjvKeyword, {
40-
type: 'integer',
41-
validate: (_schema: any, _data: number, _parentSchema: any, dataPath?: string) => {
42-
const rawValue = getRawValueFromJson(rawJson, dataPath);
43-
return isInt32(rawValue);
44-
}
45-
});
46-
ajv.addKeyword(int64AjvKeyword, {
47-
type: 'integer',
48-
validate: (_schema: any, _data: number, _parentSchema: any, dataPath?: string) => {
49-
const rawValue = getRawValueFromJson(rawJson, dataPath);
50-
return isInt64(rawValue);
51-
}
52-
});
53-
ajv.addKeyword(stringAjvKeyword, {
54-
type: 'string',
55-
validate: (_schema: any, _data: string, _parentSchema: any, dataPath?: string) => {
56-
const rawValue = getRawValueFromJson(rawJson, dataPath);
57-
return isString(rawValue);
58-
}
59-
});
60-
};
61-
62-
const nonSwaggerAjvFormats = [
63-
'email',
64-
'hostname',
65-
'ipv4',
66-
'ipv6',
67-
'json-pointer',
68-
'regex',
69-
'relative-json-pointer',
70-
'time',
71-
'uri',
72-
'uuid',
73-
'url',
74-
'uri-template',
75-
'uri-reference'
76-
];
77-
78-
const alwaysTrue = () => true;
79-
80-
const removeNonSwaggerAjvFormats = (ajv: Ajv.Ajv) => {
81-
nonSwaggerAjvFormats.forEach((formatName) => {
82-
ajv.addFormat(formatName, alwaysTrue);
83-
});
84-
};
85-
86-
const updateSchemaPropertyToDraft4 = (schema: ParsedSpecJsonSchema) => {
87-
(schema as any).$schema = 'http://json-schema.org/draft-04/schema';
88-
};
89-
90-
const changeTypeToKeywordForCustomFormats = (schema?: ParsedSpecJsonSchema) => {
91-
traverseJsonSchema(schema, (mutableSchema: ParsedSpecJsonSchemaCore) => {
92-
formatForDoubleNumbers(mutableSchema);
93-
formatForFloatNumbers(mutableSchema);
94-
formatForInt32Numbers(mutableSchema);
95-
formatForInt64Numbers(mutableSchema);
96-
formatForString(mutableSchema);
97-
});
98-
};
99-
const createAjvForDraft4 = (userOptions: Ajv.Options) => {
100-
const optionsRequiredForDraft4 = {
101-
logger: false,
102-
schemaId: 'id'
103-
};
104-
105-
const options: Ajv.Options = _.defaultsDeep({}, userOptions, optionsRequiredForDraft4);
106-
107-
const ajv = new Ajv(options);
108-
ajv.addMetaSchema(draft4MetaSchema);
109-
110-
return ajv;
111-
};
1+
import Ajv from 'ajv';
2+
import addFormats from "ajv-formats"
3+
import {ParsedSpecJsonSchema} from '../spec-parser/parsed-spec';
1124

1135
export const validateJson = (jsonSchema: ParsedSpecJsonSchema, json: any, numbersSentAsStrings?: boolean) => {
114-
const ajv = createAjvForDraft4({
6+
const ajv = new Ajv({
1157
allErrors: true,
1168
coerceTypes: numbersSentAsStrings || false,
117-
verbose: true
9+
logger: false,
10+
strictSchema: false,
11+
});
12+
addFormats(ajv);
13+
ajv.addKeyword({
14+
keyword: 'collectionFormat',
15+
type: 'array',
11816
});
11917

120-
addSwaggerFormatsAndKeywords(ajv, json);
121-
removeNonSwaggerAjvFormats(ajv);
18+
ajv.validate(jsonSchema, json);
12219

123-
const ajvCompatibleJsonSchema = _.cloneDeep(jsonSchema);
124-
changeTypeToKeywordForCustomFormats(ajvCompatibleJsonSchema);
125-
updateSchemaPropertyToDraft4(ajvCompatibleJsonSchema);
126-
ajv.validate(ajvCompatibleJsonSchema, _.cloneDeep(json));
12720
return ajv.errors || [];
12821
};

lib/swagger-mock-validator/validate-spec-and-mock/validate-json/binary.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

lib/swagger-mock-validator/validate-spec-and-mock/validate-json/byte.ts

Lines changed: 0 additions & 5 deletions
This file was deleted.

lib/swagger-mock-validator/validate-spec-and-mock/validate-json/double.ts

Lines changed: 0 additions & 22 deletions
This file was deleted.

lib/swagger-mock-validator/validate-spec-and-mock/validate-json/float.ts

Lines changed: 0 additions & 22 deletions
This file was deleted.

lib/swagger-mock-validator/validate-spec-and-mock/validate-json/int32.ts

Lines changed: 0 additions & 24 deletions
This file was deleted.

lib/swagger-mock-validator/validate-spec-and-mock/validate-json/int64.ts

Lines changed: 0 additions & 24 deletions
This file was deleted.

lib/swagger-mock-validator/validate-spec-and-mock/validate-json/is-type-supported.ts

Lines changed: 0 additions & 9 deletions
This file was deleted.

lib/swagger-mock-validator/validate-spec-and-mock/validate-json/password.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)