@atlaspack/utils 3.1.2-dev-compiled-hash-e5f8a1735.0 → 3.1.2
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.
- package/CHANGELOG.md +13 -0
- package/dist/schema.js +144 -143
- package/lib/schema.js +126 -142
- package/package.json +13 -14
- package/src/schema.ts +176 -157
- package/tsconfig.tsbuildinfo +1 -1
- package/LICENSE +0 -201
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @atlaspack/utils
|
|
2
2
|
|
|
3
|
+
## 3.1.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#853](https://github.com/atlassian-labs/atlaspack/pull/853) [`7d7a55d`](https://github.com/atlassian-labs/atlaspack/commit/7d7a55dd6395ec391a2e4c33b3dec0d1ea477d4c) Thanks [@marcins](https://github.com/marcins)! - Fixes TypeScript errors in schema validation utils
|
|
8
|
+
|
|
9
|
+
- Updated dependencies [[`ec3abe4`](https://github.com/atlassian-labs/atlaspack/commit/ec3abe4dffc98560a850fd2f71fb566577e6c99c), [`c7fe3f7`](https://github.com/atlassian-labs/atlaspack/commit/c7fe3f76f247e9e20299e205e2df0a16c418eaf2), [`cfb4707`](https://github.com/atlassian-labs/atlaspack/commit/cfb4707087498e4fa4dcf10753fe984a248d196b), [`1468695`](https://github.com/atlassian-labs/atlaspack/commit/1468695fc0c9d06f060a6da9e9b0e154f11dff34), [`f31b041`](https://github.com/atlassian-labs/atlaspack/commit/f31b04107e9077c9946aadb99f6f91bb69703bb7), [`8180981`](https://github.com/atlassian-labs/atlaspack/commit/8180981be14c00f9570adb70d3f350bd91d6ec0a), [`ae77e74`](https://github.com/atlassian-labs/atlaspack/commit/ae77e7452a466b43b3fa5bed24d4ba26345ed765), [`f0a496f`](https://github.com/atlassian-labs/atlaspack/commit/f0a496f70fc8652e090cf1b3f6260e8cfbb796e2), [`540f253`](https://github.com/atlassian-labs/atlaspack/commit/540f253dfdcd1a5caebbdc0b197319d439404aae)]:
|
|
10
|
+
- @atlaspack/feature-flags@2.26.2
|
|
11
|
+
- @atlaspack/rust@3.10.0
|
|
12
|
+
- @atlaspack/types-internal@2.20.8
|
|
13
|
+
- @atlaspack/logger@2.14.30
|
|
14
|
+
- @atlaspack/codeframe@2.13.20
|
|
15
|
+
|
|
3
16
|
## 3.1.1
|
|
4
17
|
|
|
5
18
|
### Patch Changes
|
package/dist/schema.js
CHANGED
|
@@ -41,11 +41,9 @@ const diagnostic_1 = __importStar(require("@atlaspack/diagnostic"));
|
|
|
41
41
|
const nullthrows_1 = __importDefault(require("nullthrows"));
|
|
42
42
|
const levenshtein = __importStar(require("fastest-levenshtein"));
|
|
43
43
|
function validateSchema(schema, data) {
|
|
44
|
-
function walk(
|
|
45
|
-
// @ts-expect-error TS7006
|
|
46
|
-
schemaAncestors, dataNode, dataPath) {
|
|
44
|
+
function walk(schemaAncestors, dataNode, dataPath) {
|
|
47
45
|
let [schemaNode] = schemaAncestors;
|
|
48
|
-
if (schemaNode.type) {
|
|
46
|
+
if ('type' in schemaNode && schemaNode.type) {
|
|
49
47
|
let type = Array.isArray(dataNode) ? 'array' : typeof dataNode;
|
|
50
48
|
if (schemaNode.type !== type) {
|
|
51
49
|
return {
|
|
@@ -54,19 +52,18 @@ function validateSchema(schema, data) {
|
|
|
54
52
|
dataPath,
|
|
55
53
|
expectedTypes: [schemaNode.type],
|
|
56
54
|
ancestors: schemaAncestors,
|
|
57
|
-
prettyType: schemaNode.__type,
|
|
55
|
+
prettyType: '__type' in schemaNode ? schemaNode.__type : undefined,
|
|
58
56
|
};
|
|
59
57
|
}
|
|
60
58
|
else {
|
|
61
59
|
switch (schemaNode.type) {
|
|
62
60
|
case 'array': {
|
|
63
|
-
if (
|
|
61
|
+
if ('items' in schemaNode &&
|
|
62
|
+
schemaNode.items &&
|
|
63
|
+
Array.isArray(dataNode)) {
|
|
64
64
|
let results = [];
|
|
65
|
-
// @ts-expect-error TS18046
|
|
66
65
|
for (let i = 0; i < dataNode.length; i++) {
|
|
67
|
-
let result = walk([schemaNode.items].concat(schemaAncestors),
|
|
68
|
-
// @ts-expect-error TS18046
|
|
69
|
-
dataNode[i], dataPath + '/' + i);
|
|
66
|
+
let result = walk([schemaNode.items].concat(schemaAncestors), dataNode[i], dataPath + '/' + i);
|
|
70
67
|
if (result)
|
|
71
68
|
results.push(result);
|
|
72
69
|
}
|
|
@@ -76,131 +73,124 @@ function validateSchema(schema, data) {
|
|
|
76
73
|
break;
|
|
77
74
|
}
|
|
78
75
|
case 'string': {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
76
|
+
if (typeof dataNode === 'string') {
|
|
77
|
+
let value = dataNode;
|
|
78
|
+
if ('enum' in schemaNode && schemaNode.enum) {
|
|
79
|
+
if (!schemaNode.enum.includes(value)) {
|
|
80
|
+
return {
|
|
81
|
+
type: 'enum',
|
|
82
|
+
dataType: 'value',
|
|
83
|
+
dataPath,
|
|
84
|
+
expectedValues: schemaNode.enum,
|
|
85
|
+
actualValue: value,
|
|
86
|
+
ancestors: schemaAncestors,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
91
89
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
90
|
+
else if ('__validate' in schemaNode && schemaNode.__validate) {
|
|
91
|
+
let validationError = schemaNode.__validate(value);
|
|
92
|
+
if (typeof validationError == 'string') {
|
|
93
|
+
return {
|
|
94
|
+
type: 'other',
|
|
95
|
+
dataType: 'value',
|
|
96
|
+
dataPath,
|
|
97
|
+
message: validationError,
|
|
98
|
+
actualValue: value,
|
|
99
|
+
ancestors: schemaAncestors,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
104
102
|
}
|
|
105
103
|
}
|
|
106
104
|
break;
|
|
107
105
|
}
|
|
108
106
|
case 'number': {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
107
|
+
if (typeof dataNode === 'number') {
|
|
108
|
+
let value = dataNode;
|
|
109
|
+
if ('enum' in schemaNode && schemaNode.enum) {
|
|
110
|
+
if (!schemaNode.enum.includes(value)) {
|
|
111
|
+
return {
|
|
112
|
+
type: 'enum',
|
|
113
|
+
dataType: 'value',
|
|
114
|
+
dataPath,
|
|
115
|
+
expectedValues: schemaNode.enum,
|
|
116
|
+
actualValue: value,
|
|
117
|
+
ancestors: schemaAncestors,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
121
120
|
}
|
|
122
121
|
}
|
|
123
122
|
break;
|
|
124
123
|
}
|
|
125
124
|
case 'object': {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
let
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
let { additionalProperties = true } = schemaNode;
|
|
165
|
-
// @ts-expect-error TS2407
|
|
166
|
-
for (let k in dataNode) {
|
|
167
|
-
if (invalidProps && invalidProps.includes(k)) {
|
|
168
|
-
// Don't check type on forbidden props
|
|
169
|
-
continue;
|
|
170
|
-
}
|
|
171
|
-
else if (k in schemaNode.properties) {
|
|
172
|
-
let result = walk([schemaNode.properties[k]].concat(schemaAncestors),
|
|
173
|
-
// @ts-expect-error TS18046
|
|
174
|
-
dataNode[k], dataPath + '/' + (0, diagnostic_1.encodeJSONKeyComponent)(k));
|
|
175
|
-
if (result)
|
|
176
|
-
results.push(result);
|
|
177
|
-
}
|
|
178
|
-
else {
|
|
179
|
-
if (typeof additionalProperties === 'boolean') {
|
|
180
|
-
if (!additionalProperties) {
|
|
181
|
-
results.push({
|
|
182
|
-
type: 'enum',
|
|
183
|
-
dataType: 'key',
|
|
184
|
-
dataPath: dataPath + '/' + (0, diagnostic_1.encodeJSONKeyComponent)(k),
|
|
185
|
-
expectedValues: Object.keys(schemaNode.properties).filter((p) => !(p in dataNode)),
|
|
186
|
-
actualValue: k,
|
|
187
|
-
ancestors: schemaAncestors,
|
|
188
|
-
prettyType: schemaNode.__type,
|
|
189
|
-
});
|
|
190
|
-
}
|
|
125
|
+
if (typeof dataNode === 'object' &&
|
|
126
|
+
dataNode !== null &&
|
|
127
|
+
!Array.isArray(dataNode)) {
|
|
128
|
+
let results = [];
|
|
129
|
+
let invalidProps;
|
|
130
|
+
if ('__forbiddenProperties' in schemaNode &&
|
|
131
|
+
schemaNode.__forbiddenProperties) {
|
|
132
|
+
let keys = Object.keys(dataNode);
|
|
133
|
+
invalidProps = schemaNode.__forbiddenProperties.filter((val) => keys.includes(val));
|
|
134
|
+
results.push(...invalidProps.map((k) => ({
|
|
135
|
+
type: 'forbidden-prop',
|
|
136
|
+
dataPath: dataPath + '/' + (0, diagnostic_1.encodeJSONKeyComponent)(k),
|
|
137
|
+
dataType: 'key',
|
|
138
|
+
prop: k,
|
|
139
|
+
expectedProps: Object.keys(schemaNode.properties),
|
|
140
|
+
actualProps: keys,
|
|
141
|
+
ancestors: schemaAncestors,
|
|
142
|
+
})));
|
|
143
|
+
}
|
|
144
|
+
if ('required' in schemaNode && schemaNode.required) {
|
|
145
|
+
let keys = Object.keys(dataNode);
|
|
146
|
+
let missingKeys = schemaNode.required.filter((val) => !keys.includes(val));
|
|
147
|
+
results.push(...missingKeys.map((k) => ({
|
|
148
|
+
type: 'missing-prop',
|
|
149
|
+
dataPath,
|
|
150
|
+
dataType: 'value',
|
|
151
|
+
prop: k,
|
|
152
|
+
expectedProps: schemaNode.required,
|
|
153
|
+
actualProps: keys,
|
|
154
|
+
ancestors: schemaAncestors,
|
|
155
|
+
})));
|
|
156
|
+
}
|
|
157
|
+
if ('properties' in schemaNode && schemaNode.properties) {
|
|
158
|
+
let { additionalProperties = true } = schemaNode;
|
|
159
|
+
for (let k in dataNode) {
|
|
160
|
+
if (invalidProps && invalidProps.includes(k)) {
|
|
161
|
+
// Don't check type on forbidden props
|
|
162
|
+
continue;
|
|
191
163
|
}
|
|
192
|
-
else {
|
|
193
|
-
let result = walk([
|
|
194
|
-
// @ts-expect-error TS18046
|
|
195
|
-
dataNode[k], dataPath + '/' + (0, diagnostic_1.encodeJSONKeyComponent)(k));
|
|
164
|
+
else if (k in schemaNode.properties) {
|
|
165
|
+
let result = walk([schemaNode.properties[k]].concat(schemaAncestors), dataNode[k], dataPath + '/' + (0, diagnostic_1.encodeJSONKeyComponent)(k));
|
|
196
166
|
if (result)
|
|
197
167
|
results.push(result);
|
|
198
168
|
}
|
|
169
|
+
else {
|
|
170
|
+
if (typeof additionalProperties === 'boolean') {
|
|
171
|
+
if (!additionalProperties) {
|
|
172
|
+
results.push({
|
|
173
|
+
type: 'enum',
|
|
174
|
+
dataType: 'key',
|
|
175
|
+
dataPath: dataPath + '/' + (0, diagnostic_1.encodeJSONKeyComponent)(k),
|
|
176
|
+
expectedValues: Object.keys(schemaNode.properties).filter((p) => !(p in dataNode)),
|
|
177
|
+
actualValue: k,
|
|
178
|
+
ancestors: schemaAncestors,
|
|
179
|
+
prettyType: schemaNode.__type,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
let result = walk([additionalProperties].concat(schemaAncestors), dataNode[k], dataPath + '/' + (0, diagnostic_1.encodeJSONKeyComponent)(k));
|
|
185
|
+
if (result)
|
|
186
|
+
results.push(result);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
199
189
|
}
|
|
200
190
|
}
|
|
191
|
+
if (results.length)
|
|
192
|
+
return results.reduce((acc, v) => acc.concat(v), []);
|
|
201
193
|
}
|
|
202
|
-
if (results.length)
|
|
203
|
-
return results.reduce((acc, v) => acc.concat(v), []);
|
|
204
194
|
break;
|
|
205
195
|
}
|
|
206
196
|
case 'boolean':
|
|
@@ -212,7 +202,9 @@ function validateSchema(schema, data) {
|
|
|
212
202
|
}
|
|
213
203
|
}
|
|
214
204
|
else {
|
|
215
|
-
if (
|
|
205
|
+
if ('enum' in schemaNode &&
|
|
206
|
+
schemaNode.enum &&
|
|
207
|
+
!schemaNode.enum.includes(dataNode)) {
|
|
216
208
|
return {
|
|
217
209
|
type: 'enum',
|
|
218
210
|
dataType: 'value',
|
|
@@ -222,15 +214,19 @@ function validateSchema(schema, data) {
|
|
|
222
214
|
ancestors: schemaAncestors,
|
|
223
215
|
};
|
|
224
216
|
}
|
|
225
|
-
if (
|
|
226
|
-
let list =
|
|
217
|
+
if ('oneOf' in schemaNode || 'allOf' in schemaNode) {
|
|
218
|
+
let list = 'oneOf' in schemaNode
|
|
219
|
+
? schemaNode.oneOf
|
|
220
|
+
: 'allOf' in schemaNode
|
|
221
|
+
? schemaNode.allOf
|
|
222
|
+
: [];
|
|
227
223
|
let results = [];
|
|
228
224
|
for (let f of list) {
|
|
229
225
|
let result = walk([f].concat(schemaAncestors), dataNode, dataPath);
|
|
230
226
|
if (result)
|
|
231
227
|
results.push(result);
|
|
232
228
|
}
|
|
233
|
-
if (schemaNode
|
|
229
|
+
if ('oneOf' in schemaNode
|
|
234
230
|
? results.length == schemaNode.oneOf.length
|
|
235
231
|
: results.length > 0) {
|
|
236
232
|
// return the result with more values / longer key
|
|
@@ -246,10 +242,9 @@ function validateSchema(schema, data) {
|
|
|
246
242
|
return results[0];
|
|
247
243
|
}
|
|
248
244
|
}
|
|
249
|
-
else if (schemaNode.not) {
|
|
245
|
+
else if ('not' in schemaNode && schemaNode.not) {
|
|
250
246
|
let result = walk([schemaNode.not].concat(schemaAncestors), dataNode, dataPath);
|
|
251
|
-
|
|
252
|
-
if (!result || result.length == 0) {
|
|
247
|
+
if (!result || (Array.isArray(result) && result.length == 0)) {
|
|
253
248
|
return {
|
|
254
249
|
type: 'other',
|
|
255
250
|
dataPath,
|
|
@@ -272,11 +267,8 @@ function fuzzySearch(expectedValues, actualValue) {
|
|
|
272
267
|
.map((exp) => [exp, levenshtein.distance(exp, actualValue)])
|
|
273
268
|
.filter(
|
|
274
269
|
// Remove if more than half of the string would need to be changed
|
|
275
|
-
// @ts-expect-error TS2769
|
|
276
270
|
([, d]) => d * 2 < actualValue.length);
|
|
277
|
-
// @ts-expect-error TS2345
|
|
278
271
|
result.sort(([, a], [, b]) => a - b);
|
|
279
|
-
// @ts-expect-error TS2345
|
|
280
272
|
return result.map(([v]) => v);
|
|
281
273
|
}
|
|
282
274
|
validateSchema.diagnostic = function (schema, data, origin, message) {
|
|
@@ -298,12 +290,19 @@ validateSchema.diagnostic = function (schema, data, origin, message) {
|
|
|
298
290
|
}
|
|
299
291
|
return loadedSource;
|
|
300
292
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
293
|
+
let object;
|
|
294
|
+
if ('map' in data && data.map) {
|
|
295
|
+
object = data.map.data;
|
|
296
|
+
}
|
|
297
|
+
else if ('data' in data && data.data !== undefined) {
|
|
298
|
+
object = data.data;
|
|
299
|
+
}
|
|
300
|
+
else if ('source' in data && data.source) {
|
|
301
|
+
object = JSON.parse(loadSource(data.source) || '');
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
throw new Error('Unable to get object from data');
|
|
305
|
+
}
|
|
307
306
|
let errors = validateSchema(schema, object);
|
|
308
307
|
if (errors.length) {
|
|
309
308
|
let keys = errors.map((e) => {
|
|
@@ -366,24 +365,27 @@ validateSchema.diagnostic = function (schema, data, origin, message) {
|
|
|
366
365
|
return { key: e.dataPath, type: e.dataType, message };
|
|
367
366
|
});
|
|
368
367
|
let map, code;
|
|
369
|
-
|
|
370
|
-
if (data.map) {
|
|
371
|
-
// @ts-expect-error TS2339
|
|
368
|
+
if ('map' in data && data.map) {
|
|
372
369
|
map = data.map;
|
|
373
|
-
code = loadSource(data.source);
|
|
370
|
+
code = loadSource(data.source) ?? '';
|
|
374
371
|
}
|
|
375
372
|
else {
|
|
376
|
-
|
|
377
|
-
loadSource(data.source) ??
|
|
378
|
-
|
|
379
|
-
|
|
373
|
+
if ('source' in data && data.source) {
|
|
374
|
+
map = loadSource(data.source) ?? '';
|
|
375
|
+
}
|
|
376
|
+
else if ('data' in data && data.data !== undefined) {
|
|
377
|
+
map = JSON.stringify((0, nullthrows_1.default)(data.data), null, '\t');
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
map = '';
|
|
381
|
+
}
|
|
380
382
|
code = map;
|
|
381
383
|
}
|
|
382
384
|
let codeFrames = [
|
|
383
385
|
{
|
|
384
386
|
filePath: data.filePath ?? undefined,
|
|
385
387
|
language: 'json',
|
|
386
|
-
code,
|
|
388
|
+
code: code ?? '',
|
|
387
389
|
codeHighlights: (0, diagnostic_1.generateJSONCodeHighlights)(map, keys.map(({ key, type, message }) => ({
|
|
388
390
|
key: (data.prependKey ?? '') + key,
|
|
389
391
|
type: type,
|
|
@@ -395,7 +397,6 @@ validateSchema.diagnostic = function (schema, data, origin, message) {
|
|
|
395
397
|
diagnostic: {
|
|
396
398
|
message: message,
|
|
397
399
|
origin,
|
|
398
|
-
// @ts-expect-error TS2322
|
|
399
400
|
codeFrames,
|
|
400
401
|
},
|
|
401
402
|
});
|