@redocly/openapi-core 1.0.0-beta.101 → 1.0.0-beta.104

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.
Files changed (56) hide show
  1. package/lib/config/config.d.ts +3 -3
  2. package/lib/config/load.d.ts +1 -1
  3. package/lib/config/load.js +15 -2
  4. package/lib/config/rules.d.ts +1 -1
  5. package/lib/config/types.d.ts +4 -2
  6. package/lib/decorators/common/filters/filter-helper.d.ts +3 -0
  7. package/lib/decorators/common/filters/filter-helper.js +67 -0
  8. package/lib/decorators/common/filters/filter-in.d.ts +2 -0
  9. package/lib/decorators/common/filters/filter-in.js +17 -0
  10. package/lib/decorators/common/filters/filter-out.d.ts +2 -0
  11. package/lib/decorators/common/filters/filter-out.js +17 -0
  12. package/lib/decorators/oas2/index.d.ts +2 -0
  13. package/lib/decorators/oas2/index.js +5 -1
  14. package/lib/decorators/oas3/index.d.ts +2 -0
  15. package/lib/decorators/oas3/index.js +5 -1
  16. package/lib/index.d.ts +1 -1
  17. package/lib/lint.d.ts +2 -0
  18. package/lib/lint.js +2 -2
  19. package/lib/redocly/registry-api-types.d.ts +2 -0
  20. package/lib/redocly/registry-api.d.ts +1 -1
  21. package/lib/redocly/registry-api.js +3 -1
  22. package/lib/rules/ajv.d.ts +1 -1
  23. package/lib/rules/ajv.js +1 -1
  24. package/lib/rules/common/assertions/asserts.d.ts +6 -1
  25. package/lib/rules/common/assertions/asserts.js +81 -51
  26. package/lib/rules/common/assertions/utils.d.ts +2 -1
  27. package/lib/rules/common/assertions/utils.js +27 -8
  28. package/lib/types/redocly-yaml.js +317 -27
  29. package/lib/utils.d.ts +2 -1
  30. package/lib/utils.js +5 -1
  31. package/lib/walk.d.ts +4 -14
  32. package/lib/walk.js +35 -26
  33. package/package.json +3 -2
  34. package/src/__tests__/lint.test.ts +17 -4
  35. package/src/config/__tests__/load.test.ts +6 -0
  36. package/src/config/load.ts +28 -5
  37. package/src/config/types.ts +6 -5
  38. package/src/decorators/__tests__/filter-in.test.ts +310 -0
  39. package/src/decorators/__tests__/filter-out.test.ts +331 -0
  40. package/src/decorators/common/filters/filter-helper.ts +72 -0
  41. package/src/decorators/common/filters/filter-in.ts +18 -0
  42. package/src/decorators/common/filters/filter-out.ts +18 -0
  43. package/src/decorators/oas2/index.ts +5 -1
  44. package/src/decorators/oas3/index.ts +5 -1
  45. package/src/index.ts +1 -0
  46. package/src/lint.ts +4 -3
  47. package/src/redocly/registry-api-types.ts +2 -0
  48. package/src/redocly/registry-api.ts +4 -0
  49. package/src/rules/ajv.ts +4 -4
  50. package/src/rules/common/assertions/__tests__/asserts.test.ts +149 -146
  51. package/src/rules/common/assertions/asserts.ts +97 -52
  52. package/src/rules/common/assertions/utils.ts +41 -16
  53. package/src/types/redocly-yaml.ts +322 -34
  54. package/src/utils.ts +10 -7
  55. package/src/walk.ts +59 -47
  56. package/tsconfig.tsbuildinfo +1 -1
@@ -1,5 +1,9 @@
1
+ import { Location } from '../../../../ref-utils';
2
+ import { Source } from '../../../../resolve';
1
3
  import { asserts } from '../asserts';
2
4
 
5
+ let baseLocation = new Location(jest.fn() as any as Source, 'pointer');
6
+
3
7
  describe('oas3 assertions', () => {
4
8
  describe('generic rules', () => {
5
9
  const fakeNode = {
@@ -10,232 +14,231 @@ describe('oas3 assertions', () => {
10
14
 
11
15
  describe('pattern', () => {
12
16
  it('value should match regex pattern', () => {
13
- expect(asserts.pattern('test string', '/test/')).toBeTruthy();
14
- expect(asserts.pattern('test string', '/test me/')).toBeFalsy();
15
- expect(asserts.pattern(['test string', 'test me'], '/test/')).toBeTruthy();
16
- expect(asserts.pattern(['test string', 'test me'], '/test me/')).toBeFalsy();
17
+ expect(asserts.pattern('test string', '/test/', baseLocation)).toEqual({ isValid: true });
18
+ expect(asserts.pattern('test string', '/test me/', baseLocation)).toEqual({ isValid: false, location: baseLocation });
19
+ expect(asserts.pattern(['test string', 'test me'], '/test/', baseLocation)).toEqual({ isValid: true });
20
+ expect(asserts.pattern(['test string', 'test me'], '/test me/', baseLocation)).toEqual({ isValid: false, location: baseLocation.key() });
21
+ expect(asserts.pattern('./components/smth/test.yaml', '/^(./)?components/.*.yaml$/', baseLocation)).toEqual({ isValid: true });
22
+ expect(asserts.pattern('./other.yaml', '/^(./)?components/.*.yaml$/', baseLocation)).toEqual({ isValid: false, location: baseLocation });
23
+ });
24
+ });
25
+
26
+ describe('ref', () => {
27
+ it('value should have ref', () => {
28
+ expect(asserts.ref({ $ref: 'text' }, true, baseLocation, { $ref: 'text' })).toEqual({ isValid: true, location: baseLocation });
29
+ expect(asserts.ref({}, true, baseLocation, {})).toEqual({ isValid: false, location: baseLocation.key() });
30
+ });
31
+
32
+ it('value should not have ref', () => {
33
+ expect(asserts.ref({ $ref: 'text' }, false, baseLocation, { $ref: 'text' })).toEqual({ isValid: false, location: baseLocation });
34
+ expect(asserts.ref({}, false, baseLocation, {})).toEqual({ isValid: true, location: baseLocation.key() });
35
+ });
36
+
37
+ it('value should match regex pattern', () => {
38
+ expect(asserts.ref({ $ref: 'test string' }, '/test/', baseLocation, { $ref: 'test string' })).toEqual({ isValid: true, location: baseLocation });
39
+ expect(asserts.ref({ $ref: 'test string' }, '/test me/', baseLocation, { $ref: 'test string' })).toEqual({ isValid: false, location: baseLocation });
40
+ expect(asserts.ref({ $ref: './components/smth/test.yaml' }, '/^(./)?components/.*.yaml$/', baseLocation, { $ref: './components/smth/test.yaml' })).toEqual({ isValid: true, location: baseLocation });
41
+ expect(asserts.ref({ $ref: './paths/smth/test.yaml' }, '/^(./)?components/.*.yaml$/', baseLocation, { $ref: './paths/smth/test.yaml' })).toEqual({ isValid: false, location: baseLocation });
17
42
  });
18
43
  });
19
44
 
20
45
  describe('enum', () => {
21
46
  it('value should be among predefined keys', () => {
22
- expect(asserts.enum('test', ['test', 'example'])).toBeTruthy();
23
- expect(asserts.enum(['test'], ['test', 'example'])).toBeTruthy();
24
- expect(asserts.enum(['test', 'example'], ['test', 'example'])).toBeTruthy();
25
- expect(asserts.enum(['test', 'example', 'foo'], ['test', 'example'])).toBeFalsy();
26
- expect(asserts.enum('test', ['foo', 'example'])).toBeFalsy();
27
- expect(asserts.enum(['test', 'foo'], ['test', 'example'])).toBeFalsy();
47
+ expect(asserts.enum('test', ['test', 'example'], baseLocation)).toEqual({ isValid: true });
48
+ expect(asserts.enum(['test'], ['test', 'example'], baseLocation)).toEqual({ isValid: true });
49
+ expect(asserts.enum(['test', 'example'], ['test', 'example'], baseLocation)).toEqual({ isValid: true });
50
+ expect(asserts.enum(['test', 'example', 'foo'], ['test', 'example'], baseLocation)).toEqual({ isValid: false, location: baseLocation.child('foo').key() });
51
+ expect(asserts.enum('test', ['foo', 'example'], baseLocation)).toEqual({ isValid: false, location: baseLocation });
52
+ expect(asserts.enum(['test', 'foo'], ['test', 'example'], baseLocation)).toEqual({ isValid: false, location: baseLocation.child('foo').key() });
28
53
  });
29
54
  });
30
55
 
31
56
  describe('defined', () => {
32
57
  it('value should be defined', () => {
33
- expect(asserts.defined('test', true)).toBeTruthy();
34
- expect(asserts.defined(undefined, true)).toBeFalsy();
58
+ expect(asserts.defined('test', true, baseLocation)).toEqual({ isValid: true, location: baseLocation });
59
+ expect(asserts.defined(undefined, true, baseLocation)).toEqual({ isValid: false, location: baseLocation });
35
60
  });
36
61
  it('value should be undefined', () => {
37
- expect(asserts.defined(undefined, false)).toBeTruthy();
38
- expect(asserts.defined('test', false)).toBeFalsy();
62
+ expect(asserts.defined(undefined, false, baseLocation)).toEqual({ isValid: true, location: baseLocation });
63
+ expect(asserts.defined('test', false, baseLocation)).toEqual({ isValid: false, location: baseLocation });
39
64
  });
40
65
  });
41
66
 
42
67
  describe('undefined', () => {
43
68
  it('value should be undefined', () => {
44
- expect(asserts.undefined(undefined, true)).toBeTruthy();
45
- expect(asserts.undefined('test', true)).toBeFalsy();
69
+ expect(asserts.undefined(undefined, true, baseLocation)).toEqual({ isValid: true, location: baseLocation });
70
+ expect(asserts.undefined('test', true, baseLocation)).toEqual({ isValid: false, location: baseLocation });
46
71
  });
47
72
  it('value should be defined', () => {
48
- expect(asserts.undefined('test', false)).toBeTruthy();
49
- expect(asserts.undefined(undefined, false)).toBeFalsy();
73
+ expect(asserts.undefined('test', false, baseLocation)).toEqual({ isValid: true, location: baseLocation });
74
+ expect(asserts.undefined(undefined, false, baseLocation)).toEqual({ isValid: false, location: baseLocation });
50
75
  });
51
76
  });
52
77
 
53
78
  describe('required', () => {
54
79
  it('values should be required', () => {
55
- expect(asserts.required(['one', 'two', 'three'], ['one', 'two'])).toBeTruthy();
56
- expect(asserts.required(['one', 'two'], ['one', 'two', 'three'])).toBeFalsy();
80
+ expect(asserts.required(['one', 'two', 'three'], ['one', 'two'], baseLocation)).toEqual({ isValid: true });
81
+ expect(asserts.required(['one', 'two'], ['one', 'two', 'three'], baseLocation)).toEqual({ isValid: false, location: baseLocation.key() });
57
82
  });
58
83
  });
59
84
 
60
85
  describe('nonEmpty', () => {
61
86
  it('value should not be empty', () => {
62
- expect(asserts.nonEmpty('test', true)).toBeTruthy();
63
- expect(asserts.nonEmpty('', true)).toBeFalsy();
64
- expect(asserts.nonEmpty(null, true)).toBeFalsy();
65
- expect(asserts.nonEmpty(undefined, true)).toBeFalsy();
87
+ expect(asserts.nonEmpty('test', true, baseLocation)).toEqual({ isValid: true, location: baseLocation });
88
+ expect(asserts.nonEmpty('', true, baseLocation)).toEqual({ isValid: false, location: baseLocation });
89
+ expect(asserts.nonEmpty(null, true, baseLocation)).toEqual({ isValid: false, location: baseLocation });
90
+ expect(asserts.nonEmpty(undefined, true, baseLocation)).toEqual({ isValid: false, location: baseLocation });
66
91
  });
67
92
  it('value should be empty', () => {
68
- expect(asserts.nonEmpty('', false)).toBeTruthy();
69
- expect(asserts.nonEmpty(null, false)).toBeTruthy();
70
- expect(asserts.nonEmpty(undefined, false)).toBeTruthy();
71
- expect(asserts.nonEmpty('test', false)).toBeFalsy();
93
+ expect(asserts.nonEmpty('', false, baseLocation)).toEqual({ isValid: true, location: baseLocation });
94
+ expect(asserts.nonEmpty(null, false, baseLocation)).toEqual({ isValid: true, location: baseLocation });
95
+ expect(asserts.nonEmpty(undefined, false, baseLocation)).toEqual({ isValid: true, location: baseLocation });
96
+ expect(asserts.nonEmpty('test', false, baseLocation)).toEqual({ isValid: false, location: baseLocation });
72
97
  });
73
98
  });
74
99
 
75
100
  describe('minLength', () => {
76
101
  it('value should have less or equal than 5 symbols length', () => {
77
- expect(asserts.minLength('test', 5)).toBeFalsy();
78
- expect(asserts.minLength([1, 2, 3, 4], 5)).toBeFalsy();
79
- expect(asserts.minLength([1, 2, 3, 4, 5], 5)).toBeTruthy();
80
- expect(asserts.minLength([1, 2, 3, 4, 5, 6], 5)).toBeTruthy();
81
- expect(asserts.minLength('example', 5)).toBeTruthy();
82
- expect(asserts.minLength([], 5)).toBeFalsy();
83
- expect(asserts.minLength('', 5)).toBeFalsy();
102
+ expect(asserts.minLength('test', 5, baseLocation)).toEqual({ isValid: false, location: baseLocation });
103
+ expect(asserts.minLength([1, 2, 3, 4], 5, baseLocation)).toEqual({ isValid: false, location: baseLocation });
104
+ expect(asserts.minLength([1, 2, 3, 4, 5], 5, baseLocation)).toEqual({ isValid: true, location: baseLocation });
105
+ expect(asserts.minLength([1, 2, 3, 4, 5, 6], 5, baseLocation)).toEqual({ isValid: true, location: baseLocation });
106
+ expect(asserts.minLength('example', 5, baseLocation)).toEqual({ isValid: true, location: baseLocation });
107
+ expect(asserts.minLength([], 5, baseLocation)).toEqual({ isValid: false, location: baseLocation });
108
+ expect(asserts.minLength('', 5, baseLocation)).toEqual({ isValid: false, location: baseLocation });
84
109
  });
85
110
  });
86
111
 
87
112
  describe('maxLength', () => {
88
113
  it('value should have more or equal than 5 symbols length', () => {
89
- expect(asserts.maxLength('test', 5)).toBeTruthy();
90
- expect(asserts.maxLength([1, 2, 3, 4], 5)).toBeTruthy();
91
- expect(asserts.maxLength([1, 2, 3, 4, 5], 5)).toBeTruthy();
92
- expect(asserts.maxLength([1, 2, 3, 4, 5, 6], 5)).toBeFalsy();
93
- expect(asserts.maxLength('example', 5)).toBeFalsy();
94
- expect(asserts.maxLength([], 5)).toBeTruthy();
95
- expect(asserts.maxLength('', 5)).toBeTruthy();
114
+ expect(asserts.maxLength('test', 5, baseLocation)).toEqual({ isValid: true, location: baseLocation });
115
+ expect(asserts.maxLength([1, 2, 3, 4], 5, baseLocation)).toEqual({ isValid: true, location: baseLocation });
116
+ expect(asserts.maxLength([1, 2, 3, 4, 5], 5, baseLocation)).toEqual({ isValid: true, location: baseLocation });
117
+ expect(asserts.maxLength([1, 2, 3, 4, 5, 6], 5, baseLocation)).toEqual({ isValid: false, location: baseLocation });
118
+ expect(asserts.maxLength('example', 5, baseLocation)).toEqual({ isValid: false, location: baseLocation });
119
+ expect(asserts.maxLength([], 5, baseLocation)).toEqual({ isValid: true, location: baseLocation });
120
+ expect(asserts.maxLength('', 5, baseLocation)).toEqual({ isValid: true, location: baseLocation });
96
121
  });
97
122
  });
98
123
 
99
124
  describe('casing', () => {
100
125
  it('value should be camelCase', () => {
101
- expect(asserts.casing(['testExample', 'fooBar'], 'camelCase')).toBeTruthy();
102
- expect(asserts.casing(['testExample', 'FooBar'], 'camelCase')).toBeFalsy();
103
- expect(asserts.casing('testExample', 'camelCase')).toBeTruthy();
104
- expect(asserts.casing('TestExample', 'camelCase')).toBeFalsy();
105
- expect(asserts.casing('test-example', 'camelCase')).toBeFalsy();
106
- expect(asserts.casing('test_example', 'camelCase')).toBeFalsy();
126
+ expect(asserts.casing(['testExample', 'fooBar'], 'camelCase', baseLocation)).toEqual({ isValid: true });
127
+ expect(asserts.casing(['testExample', 'FooBar'], 'camelCase', baseLocation)).toEqual({ isValid: false, location: baseLocation.child('FooBar').key() });
128
+ expect(asserts.casing('testExample', 'camelCase', baseLocation)).toEqual({ isValid: true });
129
+ expect(asserts.casing('TestExample', 'camelCase', baseLocation)).toEqual({ isValid: false, location: baseLocation });
130
+ expect(asserts.casing('test-example', 'camelCase', baseLocation)).toEqual({ isValid: false, location: baseLocation });
131
+ expect(asserts.casing('test_example', 'camelCase', baseLocation)).toEqual({ isValid: false, location: baseLocation });
107
132
  });
108
133
  it('value should be PascalCase', () => {
109
- expect(asserts.casing('TestExample', 'PascalCase')).toBeTruthy();
110
- expect(asserts.casing(['TestExample', 'FooBar'], 'PascalCase')).toBeTruthy();
111
- expect(asserts.casing(['TestExample', 'fooBar'], 'PascalCase')).toBeFalsy();
112
- expect(asserts.casing('testExample', 'PascalCase')).toBeFalsy();
113
- expect(asserts.casing('test-example', 'PascalCase')).toBeFalsy();
114
- expect(asserts.casing('test_example', 'PascalCase')).toBeFalsy();
134
+ expect(asserts.casing('TestExample', 'PascalCase', baseLocation)).toEqual({ isValid: true });
135
+ expect(asserts.casing(['TestExample', 'FooBar'], 'PascalCase', baseLocation)).toEqual({ isValid: true });
136
+ expect(asserts.casing(['TestExample', 'fooBar'], 'PascalCase', baseLocation)).toEqual({ isValid: false, location: baseLocation.child('fooBar').key() });
137
+ expect(asserts.casing('testExample', 'PascalCase', baseLocation)).toEqual({ isValid: false, location: baseLocation });
138
+ expect(asserts.casing('test-example', 'PascalCase', baseLocation)).toEqual({ isValid: false, location: baseLocation });
139
+ expect(asserts.casing('test_example', 'PascalCase', baseLocation)).toEqual({ isValid: false, location: baseLocation });
115
140
  });
116
141
  it('value should be kebab-case', () => {
117
- expect(asserts.casing('test-example', 'kebab-case')).toBeTruthy();
118
- expect(asserts.casing(['test-example', 'foo-bar'], 'kebab-case')).toBeTruthy();
119
- expect(asserts.casing(['test-example', 'foo_bar'], 'kebab-case')).toBeFalsy();
120
- expect(asserts.casing('testExample', 'kebab-case')).toBeFalsy();
121
- expect(asserts.casing('TestExample', 'kebab-case')).toBeFalsy();
122
- expect(asserts.casing('test_example', 'kebab-case')).toBeFalsy();
142
+ expect(asserts.casing('test-example', 'kebab-case', baseLocation)).toEqual({ isValid: true });
143
+ expect(asserts.casing(['test-example', 'foo-bar'], 'kebab-case', baseLocation)).toEqual({ isValid: true });
144
+ expect(asserts.casing(['test-example', 'foo_bar'], 'kebab-case', baseLocation)).toEqual({ isValid: false, location: baseLocation.child('foo_bar').key() });
145
+ expect(asserts.casing('testExample', 'kebab-case', baseLocation)).toEqual({ isValid: false, location: baseLocation });
146
+ expect(asserts.casing('TestExample', 'kebab-case', baseLocation)).toEqual({ isValid: false, location: baseLocation });
147
+ expect(asserts.casing('test_example', 'kebab-case', baseLocation)).toEqual({ isValid: false, location: baseLocation });
123
148
  });
124
149
  it('value should be snake_case', () => {
125
- expect(asserts.casing('test_example', 'snake_case')).toBeTruthy();
126
- expect(asserts.casing(['test_example', 'foo_bar'], 'snake_case')).toBeTruthy();
127
- expect(asserts.casing(['test_example', 'foo-bar'], 'snake_case')).toBeFalsy();
128
- expect(asserts.casing('testExample', 'snake_case')).toBeFalsy();
129
- expect(asserts.casing('TestExample', 'snake_case')).toBeFalsy();
130
- expect(asserts.casing('test-example', 'snake_case')).toBeFalsy();
150
+ expect(asserts.casing('test_example', 'snake_case', baseLocation)).toEqual({ isValid: true });
151
+ expect(asserts.casing(['test_example', 'foo_bar'], 'snake_case', baseLocation)).toEqual({ isValid: true });
152
+ expect(asserts.casing(['test_example', 'foo-bar'], 'snake_case', baseLocation)).toEqual({ isValid: false, location: baseLocation.child('foo-bar').key() });
153
+ expect(asserts.casing('testExample', 'snake_case', baseLocation)).toEqual({ isValid: false, location: baseLocation });
154
+ expect(asserts.casing('TestExample', 'snake_case', baseLocation)).toEqual({ isValid: false, location: baseLocation });
155
+ expect(asserts.casing('test-example', 'snake_case', baseLocation)).toEqual({ isValid: false, location: baseLocation });
131
156
  });
132
157
  it('value should be MACRO_CASE', () => {
133
- expect(asserts.casing('TEST_EXAMPLE', 'MACRO_CASE')).toBeTruthy();
134
- expect(asserts.casing(['TEST_EXAMPLE', 'FOO_BAR'], 'MACRO_CASE')).toBeTruthy();
135
- expect(asserts.casing(['TEST_EXAMPLE', 'FOO-BAR'], 'MACRO_CASE')).toBeFalsy();
136
- expect(asserts.casing('TEST_EXAMPLE_', 'MACRO_CASE')).toBeFalsy();
137
- expect(asserts.casing('_TEST_EXAMPLE', 'MACRO_CASE')).toBeFalsy();
138
- expect(asserts.casing('TEST__EXAMPLE', 'MACRO_CASE')).toBeFalsy();
139
- expect(asserts.casing('TEST-EXAMPLE', 'MACRO_CASE')).toBeFalsy();
140
- expect(asserts.casing('testExample', 'MACRO_CASE')).toBeFalsy();
141
- expect(asserts.casing('TestExample', 'MACRO_CASE')).toBeFalsy();
142
- expect(asserts.casing('test-example', 'MACRO_CASE')).toBeFalsy();
158
+ expect(asserts.casing('TEST_EXAMPLE', 'MACRO_CASE', baseLocation)).toEqual({ isValid: true });
159
+ expect(asserts.casing(['TEST_EXAMPLE', 'FOO_BAR'], 'MACRO_CASE', baseLocation)).toEqual({ isValid: true });
160
+ expect(asserts.casing(['TEST_EXAMPLE', 'FOO-BAR'], 'MACRO_CASE', baseLocation)).toEqual({ isValid: false, location: baseLocation.child('FOO-BAR').key() });
161
+ expect(asserts.casing('TEST_EXAMPLE_', 'MACRO_CASE', baseLocation)).toEqual({ isValid: false, location: baseLocation });
162
+ expect(asserts.casing('_TEST_EXAMPLE', 'MACRO_CASE', baseLocation)).toEqual({ isValid: false, location: baseLocation });
163
+ expect(asserts.casing('TEST__EXAMPLE', 'MACRO_CASE', baseLocation)).toEqual({ isValid: false, location: baseLocation });
164
+ expect(asserts.casing('TEST-EXAMPLE', 'MACRO_CASE', baseLocation)).toEqual({ isValid: false, location: baseLocation });
165
+ expect(asserts.casing('testExample', 'MACRO_CASE', baseLocation)).toEqual({ isValid: false, location: baseLocation });
166
+ expect(asserts.casing('TestExample', 'MACRO_CASE', baseLocation)).toEqual({ isValid: false, location: baseLocation });
167
+ expect(asserts.casing('test-example', 'MACRO_CASE', baseLocation)).toEqual({ isValid: false, location: baseLocation });
143
168
  });
144
169
  it('value should be COBOL-CASE', () => {
145
- expect(asserts.casing('TEST-EXAMPLE', 'COBOL-CASE')).toBeTruthy();
146
- expect(asserts.casing(['TEST-EXAMPLE', 'FOO-BAR'], 'COBOL-CASE')).toBeTruthy();
147
- expect(asserts.casing(['TEST-EXAMPLE', 'FOO_BAR'], 'COBOL-CASE')).toBeFalsy();
148
- expect(asserts.casing('TEST-EXAMPLE-', 'COBOL-CASE')).toBeFalsy();
149
- expect(asserts.casing('0TEST-EXAMPLE', 'COBOL-CASE')).toBeFalsy();
150
- expect(asserts.casing('-TEST-EXAMPLE', 'COBOL-CASE')).toBeFalsy();
151
- expect(asserts.casing('TEST--EXAMPLE', 'COBOL-CASE')).toBeFalsy();
152
- expect(asserts.casing('TEST_EXAMPLE', 'COBOL-CASE')).toBeFalsy();
153
- expect(asserts.casing('testExample', 'COBOL-CASE')).toBeFalsy();
154
- expect(asserts.casing('TestExample', 'COBOL-CASE')).toBeFalsy();
155
- expect(asserts.casing('test-example', 'COBOL-CASE')).toBeFalsy();
170
+ expect(asserts.casing('TEST-EXAMPLE', 'COBOL-CASE', baseLocation)).toEqual({ isValid: true });
171
+ expect(asserts.casing(['TEST-EXAMPLE', 'FOO-BAR'], 'COBOL-CASE', baseLocation)).toEqual({ isValid: true });
172
+ expect(asserts.casing(['TEST-EXAMPLE', 'FOO_BAR'], 'COBOL-CASE', baseLocation)).toEqual({ isValid: false, location: baseLocation.child('FOO_BAR').key() });
173
+ expect(asserts.casing('TEST-EXAMPLE-', 'COBOL-CASE', baseLocation)).toEqual({ isValid: false, location: baseLocation });
174
+ expect(asserts.casing('0TEST-EXAMPLE', 'COBOL-CASE', baseLocation)).toEqual({ isValid: false, location: baseLocation });
175
+ expect(asserts.casing('-TEST-EXAMPLE', 'COBOL-CASE', baseLocation)).toEqual({ isValid: false, location: baseLocation });
176
+ expect(asserts.casing('TEST--EXAMPLE', 'COBOL-CASE', baseLocation)).toEqual({ isValid: false, location: baseLocation });
177
+ expect(asserts.casing('TEST_EXAMPLE', 'COBOL-CASE', baseLocation)).toEqual({ isValid: false, location: baseLocation });
178
+ expect(asserts.casing('testExample', 'COBOL-CASE', baseLocation)).toEqual({ isValid: false, location: baseLocation });
179
+ expect(asserts.casing('TestExample', 'COBOL-CASE', baseLocation)).toEqual({ isValid: false, location: baseLocation });
180
+ expect(asserts.casing('test-example', 'COBOL-CASE', baseLocation)).toEqual({ isValid: false, location: baseLocation });
156
181
  });
157
182
  it('value should be flatcase', () => {
158
- expect(asserts.casing('testexample', 'flatcase')).toBeTruthy();
159
- expect(asserts.casing(['testexample', 'foobar'], 'flatcase')).toBeTruthy();
160
- expect(asserts.casing(['testexample', 'foo_bar'], 'flatcase')).toBeFalsy();
161
- expect(asserts.casing('testexample_', 'flatcase')).toBeFalsy();
162
- expect(asserts.casing('0testexample', 'flatcase')).toBeFalsy();
163
- expect(asserts.casing('testExample', 'flatcase')).toBeFalsy();
164
- expect(asserts.casing('TestExample', 'flatcase')).toBeFalsy();
165
- expect(asserts.casing('test-example', 'flatcase')).toBeFalsy();
183
+ expect(asserts.casing('testexample', 'flatcase', baseLocation)).toEqual({ isValid: true });
184
+ expect(asserts.casing(['testexample', 'foobar'], 'flatcase', baseLocation)).toEqual({ isValid: true });
185
+ expect(asserts.casing(['testexample', 'foo_bar'], 'flatcase', baseLocation)).toEqual({ isValid: false, location: baseLocation.child('foo_bar').key() });
186
+ expect(asserts.casing('testexample_', 'flatcase', baseLocation)).toEqual({ isValid: false, location: baseLocation });
187
+ expect(asserts.casing('0testexample', 'flatcase', baseLocation)).toEqual({ isValid: false, location: baseLocation });
188
+ expect(asserts.casing('testExample', 'flatcase', baseLocation)).toEqual({ isValid: false, location: baseLocation });
189
+ expect(asserts.casing('TestExample', 'flatcase', baseLocation)).toEqual({ isValid: false, location: baseLocation });
190
+ expect(asserts.casing('test-example', 'flatcase', baseLocation)).toEqual({ isValid: false, location: baseLocation });
166
191
  });
167
192
  });
168
193
 
169
194
  describe.skip('sortOrder', () => {
170
195
  it('value should be ordered in ASC direction', () => {
171
- expect(asserts.sortOrder(['example', 'foo', 'test'], 'asc')).toBeTruthy();
172
- expect(asserts.sortOrder(['example', 'foo', 'test'], { direction: 'asc' })).toBeTruthy();
173
- expect(asserts.sortOrder(['example'], 'asc')).toBeTruthy();
174
- expect(asserts.sortOrder(['example', 'test', 'foo'], 'asc')).toBeFalsy();
175
- expect(asserts.sortOrder(['example', 'foo', 'test'], 'desc')).toBeFalsy();
176
- expect(
177
- asserts.sortOrder([{ name: 'bar' }, { name: 'baz' }, { name: 'foo' }], {
178
- direction: 'asc',
179
- property: 'name',
180
- }),
181
- ).toBeTruthy();
182
- expect(
183
- asserts.sortOrder([{ name: 'bar' }, { name: 'baz' }, { name: 'foo' }], {
184
- direction: 'desc',
185
- property: 'name',
186
- }),
187
- ).toBeFalsy();
196
+ expect(asserts.sortOrder(['example', 'foo', 'test'], 'asc', baseLocation)).toEqual({ isValid: true, location: baseLocation });
197
+ expect(asserts.sortOrder(['example', 'foo', 'test'], { direction: 'asc' }, baseLocation)).toEqual({ isValid: true, location: baseLocation });
198
+ expect(asserts.sortOrder(['example'], 'asc', baseLocation)).toEqual({ isValid: true, location: baseLocation });
199
+ expect(asserts.sortOrder(['example', 'test', 'foo'], 'asc', baseLocation)).toEqual({ isValid: false, location: baseLocation });
200
+ expect(asserts.sortOrder(['example', 'foo', 'test'], 'desc', baseLocation)).toEqual({ isValid: false, location: baseLocation });
201
+ expect(asserts.sortOrder([{ name: 'bar' }, { name: 'baz' }, { name: 'foo' }], { direction: 'asc', property: 'name' }, baseLocation)).toEqual({ isValid: true, location: baseLocation });
202
+ expect(asserts.sortOrder([{ name: 'bar' }, { name: 'baz' }, { name: 'foo' }], { direction: 'desc', property: 'name' }, baseLocation)).toEqual({ isValid: false, location: baseLocation });
188
203
  });
189
204
  it('value should be ordered in DESC direction', () => {
190
- expect(asserts.sortOrder(['test', 'foo', 'example'], 'desc')).toBeTruthy();
191
- expect(asserts.sortOrder(['test', 'foo', 'example'], { direction: 'desc' })).toBeTruthy();
192
- expect(asserts.sortOrder(['example'], 'desc')).toBeTruthy();
193
- expect(asserts.sortOrder(['example', 'test', 'foo'], 'desc')).toBeFalsy();
194
- expect(asserts.sortOrder(['test', 'foo', 'example'], 'asc')).toBeFalsy();
195
- expect(
196
- asserts.sortOrder([{ name: 'foo' }, { name: 'baz' }, { name: 'bar' }], {
197
- direction: 'desc',
198
- property: 'name',
199
- }),
200
- ).toBeTruthy();
201
- expect(
202
- asserts.sortOrder([{ name: 'foo' }, { name: 'baz' }, { name: 'bar' }], {
203
- direction: 'asc',
204
- property: 'name',
205
- }),
206
- ).toBeFalsy();
205
+ expect(asserts.sortOrder(['test', 'foo', 'example'], 'desc', baseLocation)).toEqual({ isValid: true, location: baseLocation });
206
+ expect(asserts.sortOrder(['test', 'foo', 'example'], { direction: 'desc' }, baseLocation)).toEqual({ isValid: true, location: baseLocation });
207
+ expect(asserts.sortOrder(['example'], 'desc', baseLocation)).toEqual({ isValid: true, location: baseLocation });
208
+ expect(asserts.sortOrder(['example', 'test', 'foo'], 'desc', baseLocation)).toEqual({ isValid: false, location: baseLocation });
209
+ expect(asserts.sortOrder(['test', 'foo', 'example'], 'asc', baseLocation)).toEqual({ isValid: false, location: baseLocation });
210
+ expect(asserts.sortOrder([{ name: 'foo' }, { name: 'baz' }, { name: 'bar' }], { direction: 'desc', property: 'name' }, baseLocation)).toEqual({ isValid: true, location: baseLocation });
211
+ expect(asserts.sortOrder([{ name: 'foo' }, { name: 'baz' }, { name: 'bar' }], { direction: 'asc', property: 'name' }, baseLocation)).toEqual({ isValid: false, location: baseLocation });
207
212
  });
208
213
  });
209
214
 
210
215
  describe('mutuallyExclusive', () => {
211
216
  it('node should not have more than one property from predefined list', () => {
212
- expect(asserts.mutuallyExclusive(Object.keys(fakeNode), ['foo', 'test'])).toBeTruthy();
213
- expect(asserts.mutuallyExclusive(Object.keys(fakeNode), [])).toBeTruthy();
214
- expect(asserts.mutuallyExclusive(Object.keys(fakeNode), ['foo', 'bar'])).toBeFalsy();
215
- expect(
216
- asserts.mutuallyExclusive(Object.keys(fakeNode), ['foo', 'bar', 'test']),
217
- ).toBeFalsy();
217
+ expect(asserts.mutuallyExclusive(Object.keys(fakeNode), ['foo', 'test'], baseLocation)).toEqual({ isValid: true, location: baseLocation.key() });
218
+ expect(asserts.mutuallyExclusive(Object.keys(fakeNode), [], baseLocation)).toEqual({ isValid: true, location: baseLocation.key() });
219
+ expect(asserts.mutuallyExclusive(Object.keys(fakeNode), ['foo', 'bar'], baseLocation)).toEqual({ isValid: false, location: baseLocation.key() });
220
+ expect(asserts.mutuallyExclusive(Object.keys(fakeNode), ['foo', 'bar', 'test'], baseLocation)).toEqual({ isValid: false, location: baseLocation.key() });
218
221
  });
219
222
  });
220
223
 
221
224
  describe('mutuallyRequired', () => {
222
225
  it('node should have all the properties from predefined list', () => {
223
- expect(asserts.mutuallyRequired(Object.keys(fakeNode), ['foo', 'bar'])).toBeTruthy();
224
- expect(asserts.mutuallyRequired(Object.keys(fakeNode), ['foo', 'bar', 'baz'])).toBeTruthy();
225
- expect(asserts.mutuallyRequired(Object.keys(fakeNode), [])).toBeTruthy();
226
- expect(asserts.mutuallyRequired(Object.keys(fakeNode), ['foo', 'test'])).toBeFalsy();
227
- expect(asserts.mutuallyRequired(Object.keys(fakeNode), ['foo', 'bar', 'test'])).toBeFalsy();
226
+ expect(asserts.mutuallyRequired(Object.keys(fakeNode), ['foo', 'bar'], baseLocation)).toEqual({ isValid: true, location: baseLocation.key() });
227
+ expect(asserts.mutuallyRequired(Object.keys(fakeNode), ['foo', 'bar', 'baz'], baseLocation)).toEqual({ isValid: true, location: baseLocation.key() });
228
+ expect(asserts.mutuallyRequired(Object.keys(fakeNode), [], baseLocation)).toEqual({ isValid: true, location: baseLocation.key() });
229
+ expect(asserts.mutuallyRequired(Object.keys(fakeNode), ['foo', 'test'], baseLocation)).toEqual({ isValid: false, location: baseLocation.key() });
230
+ expect(asserts.mutuallyRequired(Object.keys(fakeNode), ['foo', 'bar', 'test'], baseLocation)).toEqual({ isValid: false, location: baseLocation.key() });
228
231
  });
229
232
  });
230
233
 
231
234
  describe('requireAny', () => {
232
235
  it('node must have at least one property from predefined list', () => {
233
- expect(asserts.requireAny(Object.keys(fakeNode), ['foo', 'test'])).toBeTruthy();
234
- expect(asserts.requireAny(Object.keys(fakeNode), ['test', 'bar'])).toBeTruthy();
235
- expect(asserts.requireAny(Object.keys(fakeNode), [])).toBeFalsy();
236
- expect(asserts.requireAny(Object.keys(fakeNode), ['test', 'test1'])).toBeFalsy();
237
- expect(asserts.requireAny(Object.keys(fakeNode), ['foo', 'bar'])).toBeTruthy();
238
- expect(asserts.requireAny(Object.keys(fakeNode), ['foo', 'bar', 'test'])).toBeTruthy();
236
+ expect(asserts.requireAny(Object.keys(fakeNode), ['foo', 'test'], baseLocation)).toEqual({ isValid: true, location: baseLocation.key() });
237
+ expect(asserts.requireAny(Object.keys(fakeNode), ['test', 'bar'], baseLocation)).toEqual({ isValid: true, location: baseLocation.key() });
238
+ expect(asserts.requireAny(Object.keys(fakeNode), [], baseLocation)).toEqual({ isValid: false, location: baseLocation.key() });
239
+ expect(asserts.requireAny(Object.keys(fakeNode), ['test', 'test1'], baseLocation)).toEqual({ isValid: false, location: baseLocation.key() });
240
+ expect(asserts.requireAny(Object.keys(fakeNode), ['foo', 'bar'], baseLocation)).toEqual({ isValid: true, location: baseLocation.key() });
241
+ expect(asserts.requireAny(Object.keys(fakeNode), ['foo', 'bar', 'test'], baseLocation)).toEqual({ isValid: true, location: baseLocation.key() });
239
242
  });
240
243
  });
241
244
  });
@@ -1,6 +1,18 @@
1
- import { OrderOptions, OrderDirection, isOrdered, getIntersectionLength } from './utils';
1
+ import { Location } from '../../../ref-utils';
2
+ import { isString as runOnValue } from '../../../utils';
3
+ import {
4
+ OrderOptions,
5
+ OrderDirection,
6
+ isOrdered,
7
+ getIntersectionLength,
8
+ regexFromString,
9
+ } from './utils';
2
10
 
3
- type Asserts = Record<string, (value: any, condition: any) => boolean>;
11
+ type AssertResult = { isValid: boolean; location?: Location };
12
+ type Asserts = Record<
13
+ string,
14
+ (value: any, condition: any, baseLocation: Location, rawValue?: any) => AssertResult
15
+ >;
4
16
 
5
17
  export const runOnKeysSet = new Set([
6
18
  'mutuallyExclusive',
@@ -13,6 +25,8 @@ export const runOnKeysSet = new Set([
13
25
  'sortOrder',
14
26
  'disallowed',
15
27
  'required',
28
+ 'requireAny',
29
+ 'ref',
16
30
  ]);
17
31
  export const runOnValuesSet = new Set([
18
32
  'pattern',
@@ -24,73 +38,82 @@ export const runOnValuesSet = new Set([
24
38
  'maxLength',
25
39
  'casing',
26
40
  'sortOrder',
41
+ 'ref',
27
42
  ]);
28
43
 
29
44
  export const asserts: Asserts = {
30
- pattern: (value: string | string[], condition: string): boolean => {
31
- if (typeof value === 'undefined') return true; // property doesn't exist, no need to lint it with this assert
32
- const values = typeof value === 'string' ? [value] : value;
33
- const regexOptions = condition.match(/(\b\/\b)(.+)/g) || ['/'];
34
- condition = condition.slice(1).replace(regexOptions[0], '');
35
- const regx = new RegExp(condition, regexOptions[0].slice(1));
45
+ pattern: (value: string | string[], condition: string, baseLocation: Location) => {
46
+ if (typeof value === 'undefined') return { isValid: true }; // property doesn't exist, no need to lint it with this assert
47
+ const values = runOnValue(value) ? [value] : value;
48
+ const regx = regexFromString(condition);
36
49
  for (let _val of values) {
37
- if (!_val.match(regx)) {
38
- return false;
50
+ if (!regx?.test(_val)) {
51
+ return { isValid: false, location: runOnValue(value) ? baseLocation : baseLocation.key() };
39
52
  }
40
53
  }
41
- return true;
54
+ return { isValid: true };
42
55
  },
43
- enum: (value: string | string[], condition: string[]): boolean => {
44
- if (typeof value === 'undefined') return true; // property doesn't exist, no need to lint it with this assert
45
- const values = typeof value === 'string' ? [value] : value;
56
+ enum: (value: string | string[], condition: string[], baseLocation: Location) => {
57
+ if (typeof value === 'undefined') return { isValid: true }; // property doesn't exist, no need to lint it with this assert
58
+ const values = runOnValue(value) ? [value] : value;
46
59
  for (let _val of values) {
47
60
  if (!condition.includes(_val)) {
48
- return false;
61
+ return {
62
+ isValid: false,
63
+ location: runOnValue(value) ? baseLocation : baseLocation.child(_val).key(),
64
+ };
49
65
  }
50
66
  }
51
- return true;
67
+ return { isValid: true };
52
68
  },
53
- defined: (value: string | undefined, condition: boolean = true): boolean => {
69
+ defined: (value: string | undefined, condition: boolean = true, baseLocation: Location) => {
54
70
  const isDefined = typeof value !== 'undefined';
55
- return condition ? isDefined : !isDefined;
71
+ return { isValid: condition ? isDefined : !isDefined, location: baseLocation };
56
72
  },
57
- required: (value: string[], keys: string[]): boolean => {
73
+ required: (value: string[], keys: string[], baseLocation: Location) => {
58
74
  for (const requiredKey of keys) {
59
75
  if (!value.includes(requiredKey)) {
60
- return false;
76
+ return { isValid: false, location: baseLocation.key() };
61
77
  }
62
78
  }
63
- return true;
79
+ return { isValid: true };
64
80
  },
65
- disallowed: (value: string | string[], condition: string[]): boolean => {
66
- if (typeof value === 'undefined') return true; // property doesn't exist, no need to lint it with this assert
67
- const values = typeof value === 'string' ? [value] : value;
81
+ disallowed: (value: string | string[], condition: string[], baseLocation: Location) => {
82
+ if (typeof value === 'undefined') return { isValid: true }; // property doesn't exist, no need to lint it with this assert
83
+ const values = runOnValue(value) ? [value] : value;
68
84
  for (let _val of values) {
69
85
  if (condition.includes(_val)) {
70
- return false;
86
+ return {
87
+ isValid: false,
88
+ location: runOnValue(value) ? baseLocation : baseLocation.child(_val).key(),
89
+ };
71
90
  }
72
91
  }
73
- return true;
92
+ return { isValid: true };
74
93
  },
75
- undefined: (value: any, condition: boolean = true): boolean => {
94
+ undefined: (value: any, condition: boolean = true, baseLocation: Location) => {
76
95
  const isUndefined = typeof value === 'undefined';
77
- return condition ? isUndefined : !isUndefined;
96
+ return { isValid: condition ? isUndefined : !isUndefined, location: baseLocation };
78
97
  },
79
- nonEmpty: (value: string | undefined | null, condition: boolean = true): boolean => {
98
+ nonEmpty: (
99
+ value: string | undefined | null,
100
+ condition: boolean = true,
101
+ baseLocation: Location
102
+ ) => {
80
103
  const isEmpty = typeof value === 'undefined' || value === null || value === '';
81
- return condition ? !isEmpty : isEmpty;
104
+ return { isValid: condition ? !isEmpty : isEmpty, location: baseLocation };
82
105
  },
83
- minLength: (value: string | any[], condition: number): boolean => {
84
- if (typeof value === 'undefined') return true; // property doesn't exist, no need to lint it with this assert
85
- return value.length >= condition;
106
+ minLength: (value: string | any[], condition: number, baseLocation: Location) => {
107
+ if (typeof value === 'undefined') return { isValid: true }; // property doesn't exist, no need to lint it with this assert
108
+ return { isValid: value.length >= condition, location: baseLocation };
86
109
  },
87
- maxLength: (value: string | any[], condition: number): boolean => {
88
- if (typeof value === 'undefined') return true; // property doesn't exist, no need to lint it with this assert
89
- return value.length <= condition;
110
+ maxLength: (value: string | any[], condition: number, baseLocation: Location) => {
111
+ if (typeof value === 'undefined') return { isValid: true }; // property doesn't exist, no need to lint it with this assert
112
+ return { isValid: value.length <= condition, location: baseLocation };
90
113
  },
91
- casing: (value: string | string[], condition: string): boolean => {
92
- if (typeof value === 'undefined') return true; // property doesn't exist, no need to lint it with this assert
93
- const values = typeof value === 'string' ? [value] : value;
114
+ casing: (value: string | string[], condition: string, baseLocation: Location) => {
115
+ if (typeof value === 'undefined') return { isValid: true }; // property doesn't exist, no need to lint it with this assert
116
+ const values: string[] = runOnValue(value) ? [value] : value;
94
117
  for (let _val of values) {
95
118
  let matchCase = false;
96
119
  switch (condition) {
@@ -117,24 +140,46 @@ export const asserts: Asserts = {
117
140
  break;
118
141
  }
119
142
  if (!matchCase) {
120
- return false;
143
+ return {
144
+ isValid: false,
145
+ location: runOnValue(value) ? baseLocation : baseLocation.child(_val).key(),
146
+ };
121
147
  }
122
148
  }
123
- return true;
149
+ return { isValid: true };
124
150
  },
125
- sortOrder: (value: any[], condition: OrderOptions | OrderDirection): boolean => {
126
- if (typeof value === 'undefined') return true;
127
- return isOrdered(value, condition);
151
+ sortOrder: (value: any[], condition: OrderOptions | OrderDirection, baseLocation: Location) => {
152
+ if (typeof value === 'undefined') return { isValid: true };
153
+ return { isValid: isOrdered(value, condition), location: baseLocation };
128
154
  },
129
- mutuallyExclusive: (value: string[], condition: string[]): boolean => {
130
- return getIntersectionLength(value, condition) < 2;
155
+ mutuallyExclusive: (value: string[], condition: string[], baseLocation: Location) => {
156
+ return { isValid: getIntersectionLength(value, condition) < 2, location: baseLocation.key() };
131
157
  },
132
- mutuallyRequired: (value: string[], condition: string[]): boolean => {
133
- return getIntersectionLength(value, condition) > 0
134
- ? getIntersectionLength(value, condition) === condition.length
135
- : true;
158
+ mutuallyRequired: (value: string[], condition: string[], baseLocation: Location) => {
159
+ return {
160
+ isValid:
161
+ getIntersectionLength(value, condition) > 0
162
+ ? getIntersectionLength(value, condition) === condition.length
163
+ : true,
164
+ location: baseLocation.key(),
165
+ };
136
166
  },
137
- requireAny: (value: string[], condition: string[]): boolean => {
138
- return getIntersectionLength(value, condition) >= 1;
167
+ requireAny: (value: string[], condition: string[], baseLocation: Location) => {
168
+ return { isValid: getIntersectionLength(value, condition) >= 1, location: baseLocation.key() };
169
+ },
170
+ ref: (_value: any, condition: string | boolean, baseLocation, rawValue: any) => {
171
+ if (typeof rawValue === 'undefined') return { isValid: true }; // property doesn't exist, no need to lint it with this assert
172
+ const hasRef = rawValue.hasOwnProperty('$ref');
173
+ if (typeof condition === 'boolean') {
174
+ return {
175
+ isValid: condition ? hasRef : !hasRef,
176
+ location: hasRef ? baseLocation : baseLocation.key(),
177
+ };
178
+ }
179
+ const regex = regexFromString(condition);
180
+ return {
181
+ isValid: hasRef && regex?.test(rawValue['$ref']),
182
+ location: hasRef ? baseLocation : baseLocation.key(),
183
+ };
139
184
  },
140
185
  };