@atlaspack/utils 2.14.5-canary.33 → 2.14.5-canary.330

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 (197) hide show
  1. package/CHANGELOG.md +413 -0
  2. package/benchmark.js +23 -0
  3. package/dist/DefaultMap.js +41 -0
  4. package/dist/Deferred.js +16 -0
  5. package/dist/PromiseQueue.js +107 -0
  6. package/dist/TapStream.js +23 -0
  7. package/dist/alternatives.js +97 -0
  8. package/dist/ansi-html.js +12 -0
  9. package/dist/blob.js +29 -0
  10. package/dist/bundle-url.js +32 -0
  11. package/dist/collection.js +106 -0
  12. package/dist/config.js +138 -0
  13. package/dist/countLines.js +12 -0
  14. package/dist/debounce.js +15 -0
  15. package/dist/debug-tools.js +39 -0
  16. package/dist/dependency-location.js +22 -0
  17. package/dist/escape-html.js +19 -0
  18. package/dist/generateBuildMetrics.js +111 -0
  19. package/dist/generateCertificate.js +124 -0
  20. package/dist/getCertificate.js +13 -0
  21. package/dist/getExisting.js +20 -0
  22. package/dist/getModuleParts.js +27 -0
  23. package/dist/getRootDir.js +46 -0
  24. package/dist/getTimeId.js +13 -0
  25. package/dist/glob.js +129 -0
  26. package/dist/hash.js +45 -0
  27. package/dist/http-server.js +55 -0
  28. package/dist/index.js +148 -0
  29. package/dist/is-url.js +15 -0
  30. package/dist/isDirectoryInside.js +11 -0
  31. package/dist/objectHash.js +20 -0
  32. package/dist/openInBrowser.js +61 -0
  33. package/dist/parseCSSImport.js +14 -0
  34. package/dist/path.js +36 -0
  35. package/dist/prettifyTime.js +6 -0
  36. package/dist/prettyDiagnostic.js +104 -0
  37. package/dist/progress-message.js +31 -0
  38. package/dist/relativeBundlePath.js +13 -0
  39. package/dist/relativeUrl.js +11 -0
  40. package/dist/replaceBundleReferences.js +131 -0
  41. package/dist/schema.js +404 -0
  42. package/dist/shared-buffer.js +24 -0
  43. package/dist/sourcemap.js +121 -0
  44. package/dist/stream.js +69 -0
  45. package/dist/throttle.js +12 -0
  46. package/dist/urlJoin.js +22 -0
  47. package/lib/DefaultMap.js +42 -0
  48. package/lib/Deferred.js +30 -0
  49. package/lib/PromiseQueue.js +112 -0
  50. package/lib/TapStream.js +34 -0
  51. package/lib/alternatives.js +116 -0
  52. package/lib/ansi-html.js +20 -0
  53. package/lib/blob.js +40 -0
  54. package/lib/bundle-url.js +34 -0
  55. package/lib/collection.js +111 -0
  56. package/lib/config.js +174 -0
  57. package/lib/countLines.js +15 -0
  58. package/lib/debounce.js +18 -0
  59. package/lib/debug-tools.js +40 -0
  60. package/lib/dependency-location.js +21 -0
  61. package/lib/escape-html.js +22 -0
  62. package/lib/generateBuildMetrics.js +121 -0
  63. package/lib/generateCertificate.js +129 -0
  64. package/lib/getCertificate.js +18 -0
  65. package/lib/getExisting.js +25 -0
  66. package/lib/getModuleParts.js +30 -0
  67. package/lib/getRootDir.js +52 -0
  68. package/lib/getTimeId.js +10 -0
  69. package/lib/glob.js +110 -0
  70. package/lib/hash.js +50 -0
  71. package/lib/http-server.js +85 -0
  72. package/lib/index.js +643 -37310
  73. package/lib/is-url.js +24 -0
  74. package/lib/isDirectoryInside.js +18 -0
  75. package/lib/objectHash.js +26 -0
  76. package/lib/openInBrowser.js +74 -0
  77. package/lib/parseCSSImport.js +15 -0
  78. package/lib/path.js +39 -0
  79. package/lib/prettifyTime.js +9 -0
  80. package/lib/prettyDiagnostic.js +150 -0
  81. package/lib/progress-message.js +39 -0
  82. package/lib/relativeBundlePath.js +22 -0
  83. package/lib/relativeUrl.js +24 -0
  84. package/lib/replaceBundleReferences.js +182 -0
  85. package/lib/schema.js +353 -0
  86. package/lib/shared-buffer.js +31 -0
  87. package/lib/sourcemap.js +138 -0
  88. package/lib/stream.js +76 -0
  89. package/lib/throttle.js +15 -0
  90. package/lib/types/DefaultMap.d.ts +13 -0
  91. package/lib/types/Deferred.d.ts +8 -0
  92. package/lib/types/PromiseQueue.d.ts +25 -0
  93. package/lib/types/TapStream.d.ts +6 -0
  94. package/lib/types/alternatives.d.ts +3 -0
  95. package/lib/types/ansi-html.d.ts +1 -0
  96. package/lib/types/blob.d.ts +4 -0
  97. package/lib/types/bundle-url.d.ts +4 -0
  98. package/lib/types/collection.d.ts +33 -0
  99. package/lib/types/config.d.ts +17 -0
  100. package/lib/types/countLines.d.ts +1 -0
  101. package/lib/types/debounce.d.ts +1 -0
  102. package/lib/types/debug-tools.d.ts +8 -0
  103. package/lib/types/dependency-location.d.ts +14 -0
  104. package/lib/types/escape-html.d.ts +1 -0
  105. package/lib/types/generateBuildMetrics.d.ts +18 -0
  106. package/lib/types/generateCertificate.d.ts +5 -0
  107. package/lib/types/getCertificate.d.ts +5 -0
  108. package/lib/types/getExisting.d.ts +8 -0
  109. package/lib/types/getModuleParts.d.ts +4 -0
  110. package/lib/types/getRootDir.d.ts +2 -0
  111. package/lib/types/getTimeId.d.ts +1 -0
  112. package/lib/types/glob.d.ts +9 -0
  113. package/lib/types/hash.d.ts +7 -0
  114. package/lib/types/http-server.d.ts +19 -0
  115. package/lib/types/index.d.ts +49 -0
  116. package/lib/types/is-url.d.ts +1 -0
  117. package/lib/types/isDirectoryInside.d.ts +2 -0
  118. package/lib/types/objectHash.d.ts +3 -0
  119. package/lib/types/openInBrowser.d.ts +1 -0
  120. package/lib/types/parseCSSImport.d.ts +1 -0
  121. package/lib/types/path.d.ts +8 -0
  122. package/lib/types/prettifyTime.d.ts +1 -0
  123. package/lib/types/prettyDiagnostic.d.ts +17 -0
  124. package/lib/types/progress-message.d.ts +3 -0
  125. package/lib/types/relativeBundlePath.d.ts +4 -0
  126. package/lib/types/relativeUrl.d.ts +1 -0
  127. package/lib/types/replaceBundleReferences.d.ts +39 -0
  128. package/lib/types/schema.d.ts +107 -0
  129. package/lib/types/shared-buffer.d.ts +2 -0
  130. package/lib/types/sourcemap.d.ts +15 -0
  131. package/lib/types/stream.d.ts +8 -0
  132. package/lib/types/throttle.d.ts +1 -0
  133. package/lib/types/urlJoin.d.ts +5 -0
  134. package/lib/urlJoin.js +35 -0
  135. package/package.json +27 -18
  136. package/src/{DefaultMap.js → DefaultMap.ts} +8 -12
  137. package/src/Deferred.ts +26 -0
  138. package/src/{PromiseQueue.js → PromiseQueue.ts} +40 -35
  139. package/src/{TapStream.js → TapStream.ts} +8 -7
  140. package/src/{alternatives.js → alternatives.ts} +15 -16
  141. package/src/{ansi-html.js → ansi-html.ts} +1 -1
  142. package/src/{blob.js → blob.ts} +3 -5
  143. package/src/{bundle-url.js → bundle-url.ts} +3 -5
  144. package/src/{collection.js → collection.ts} +23 -20
  145. package/src/{config.js → config.ts} +20 -21
  146. package/src/{countLines.js → countLines.ts} +0 -2
  147. package/src/{debounce.js → debounce.ts} +3 -5
  148. package/src/debug-tools.ts +48 -0
  149. package/src/{dependency-location.js → dependency-location.ts} +15 -11
  150. package/src/{escape-html.js → escape-html.ts} +5 -3
  151. package/src/{generateBuildMetrics.js → generateBuildMetrics.ts} +19 -21
  152. package/src/{generateCertificate.js → generateCertificate.ts} +8 -6
  153. package/src/{getCertificate.js → getCertificate.ts} +6 -5
  154. package/src/{getExisting.js → getExisting.ts} +4 -3
  155. package/src/{getModuleParts.js → getModuleParts.ts} +3 -2
  156. package/src/{getRootDir.js → getRootDir.ts} +1 -3
  157. package/src/getTimeId.ts +12 -0
  158. package/src/{glob.js → glob.ts} +13 -14
  159. package/src/{hash.js → hash.ts} +23 -18
  160. package/src/{http-server.js → http-server.ts} +34 -40
  161. package/src/{index.js → index.ts} +14 -10
  162. package/src/{is-url.js → is-url.ts} +1 -2
  163. package/src/{isDirectoryInside.js → isDirectoryInside.ts} +1 -2
  164. package/src/{objectHash.js → objectHash.ts} +1 -4
  165. package/src/{openInBrowser.js → openInBrowser.ts} +2 -4
  166. package/src/{parseCSSImport.js → parseCSSImport.ts} +0 -2
  167. package/src/{path.js → path.ts} +2 -4
  168. package/src/{prettifyTime.js → prettifyTime.ts} +0 -2
  169. package/src/{prettyDiagnostic.js → prettyDiagnostic.ts} +34 -22
  170. package/src/progress-message.ts +43 -0
  171. package/src/{relativeBundlePath.js → relativeBundlePath.ts} +4 -4
  172. package/src/{relativeUrl.js → relativeUrl.ts} +0 -1
  173. package/src/{replaceBundleReferences.js → replaceBundleReferences.ts} +67 -51
  174. package/src/schema.ts +552 -0
  175. package/src/{shared-buffer.js → shared-buffer.ts} +5 -3
  176. package/src/{sourcemap.js → sourcemap.ts} +28 -10
  177. package/src/{stream.js → stream.ts} +30 -22
  178. package/src/throttle.ts +13 -0
  179. package/src/{urlJoin.js → urlJoin.ts} +1 -3
  180. package/test/{DefaultMap.test.js → DefaultMap.test.ts} +4 -6
  181. package/test/{PromiseQueue.test.js → PromiseQueue.test.ts} +5 -6
  182. package/test/{collection.test.js → collection.test.ts} +0 -2
  183. package/test/{config.test.js → config.test.ts} +0 -3
  184. package/test/{objectHash.test.js → objectHash.test.ts} +4 -5
  185. package/test/{prettifyTime.test.js → prettifyTime.test.ts} +0 -1
  186. package/test/{replaceBundleReferences.test.js → replaceBundleReferences.test.ts} +0 -32
  187. package/test/schema.test.ts +748 -0
  188. package/test/{sourcemap.test.js → sourcemap.test.ts} +0 -1
  189. package/test/{throttle.test.js → throttle.test.ts} +1 -3
  190. package/test/{urlJoin.test.js → urlJoin.test.ts} +0 -2
  191. package/tsconfig.json +36 -0
  192. package/tsconfig.tsbuildinfo +1 -0
  193. package/lib/index.js.map +0 -1
  194. package/src/Deferred.js +0 -23
  195. package/src/progress-message.js +0 -22
  196. package/src/schema.js +0 -504
  197. package/src/throttle.js +0 -15
package/src/schema.ts ADDED
@@ -0,0 +1,552 @@
1
+ import ThrowableDiagnostic, {
2
+ generateJSONCodeHighlights,
3
+ escapeMarkdown,
4
+ encodeJSONKeyComponent,
5
+ } from '@atlaspack/diagnostic';
6
+ import type {Mapping} from '@mischnic/json-sourcemap';
7
+ import nullthrows from 'nullthrows';
8
+ import * as levenshtein from 'fastest-levenshtein';
9
+
10
+ export type SchemaEntity =
11
+ | SchemaObject
12
+ | SchemaArray
13
+ | SchemaBoolean
14
+ | SchemaString
15
+ | SchemaNumber
16
+ | SchemaEnum
17
+ | SchemaOneOf
18
+ | SchemaAllOf
19
+ | SchemaNot
20
+ | SchemaAny;
21
+ export type SchemaArray = {
22
+ type: 'array';
23
+ items?: SchemaEntity;
24
+ __type?: string;
25
+ };
26
+ export type SchemaBoolean = {
27
+ type: 'boolean';
28
+ __type?: string;
29
+ };
30
+ export type SchemaOneOf = {
31
+ oneOf: Array<SchemaEntity>;
32
+ };
33
+ export type SchemaAllOf = {
34
+ allOf: Array<SchemaEntity>;
35
+ };
36
+ export type SchemaNot = {
37
+ not: SchemaEntity;
38
+ __message: string;
39
+ };
40
+ export type SchemaString = {
41
+ type: 'string';
42
+ enum?: Array<string>;
43
+ __validate?: (val: string) => string | null | undefined;
44
+ __type?: string;
45
+ };
46
+ export type SchemaNumber = {
47
+ type: 'number';
48
+ enum?: Array<number>;
49
+ __type?: string;
50
+ };
51
+ export type SchemaEnum = {
52
+ enum: Array<unknown>;
53
+ };
54
+ export type SchemaObject = {
55
+ type: 'object';
56
+ properties: {
57
+ [key: string]: SchemaEntity;
58
+ };
59
+ additionalProperties?: boolean | SchemaEntity;
60
+ required?: Array<string>;
61
+ __forbiddenProperties?: Array<string>;
62
+ __type?: string;
63
+ };
64
+ export type SchemaAny = Record<any, any>;
65
+ export type SchemaError =
66
+ | {
67
+ type: 'type';
68
+ expectedTypes: Array<string>;
69
+ dataType: 'key' | null | undefined | 'value';
70
+ dataPath: string;
71
+ ancestors: Array<SchemaEntity>;
72
+ prettyType?: string;
73
+ }
74
+ | {
75
+ type: 'enum';
76
+ expectedValues: Array<unknown>;
77
+ dataType: 'key' | 'value';
78
+ actualValue: unknown;
79
+ dataPath: string;
80
+ ancestors: Array<SchemaEntity>;
81
+ prettyType?: string;
82
+ }
83
+ | {
84
+ type: 'forbidden-prop';
85
+ prop: string;
86
+ expectedProps: Array<string>;
87
+ actualProps: Array<string>;
88
+ dataType: 'key';
89
+ dataPath: string;
90
+ ancestors: Array<SchemaEntity>;
91
+ prettyType?: string;
92
+ }
93
+ | {
94
+ type: 'missing-prop';
95
+ prop: string;
96
+ expectedProps: Array<string>;
97
+ actualProps: Array<string>;
98
+ dataType: 'key' | 'value';
99
+ dataPath: string;
100
+ ancestors: Array<SchemaEntity>;
101
+ prettyType?: string;
102
+ }
103
+ | {
104
+ type: 'other';
105
+ actualValue: unknown;
106
+ dataType: 'key' | null | undefined | 'value';
107
+ message?: string;
108
+ dataPath: string;
109
+ ancestors: Array<SchemaEntity>;
110
+ };
111
+
112
+ function validateSchema(
113
+ schema: SchemaEntity,
114
+ data: unknown,
115
+ ): Array<SchemaError> {
116
+ function walk(
117
+ schemaAncestors: Array<SchemaEntity>,
118
+ dataNode: unknown,
119
+ dataPath: string,
120
+ ): SchemaError | null | undefined | Array<SchemaError> {
121
+ let [schemaNode] = schemaAncestors;
122
+
123
+ if ('type' in schemaNode && schemaNode.type) {
124
+ let type = Array.isArray(dataNode) ? 'array' : typeof dataNode;
125
+ if (schemaNode.type !== type) {
126
+ return {
127
+ type: 'type',
128
+ dataType: 'value',
129
+ dataPath,
130
+ expectedTypes: [schemaNode.type],
131
+ ancestors: schemaAncestors,
132
+ prettyType: '__type' in schemaNode ? schemaNode.__type : undefined,
133
+ };
134
+ } else {
135
+ switch (schemaNode.type) {
136
+ case 'array': {
137
+ if (
138
+ 'items' in schemaNode &&
139
+ schemaNode.items &&
140
+ Array.isArray(dataNode)
141
+ ) {
142
+ let results: Array<SchemaError | Array<SchemaError>> = [];
143
+ for (let i = 0; i < dataNode.length; i++) {
144
+ let result = walk(
145
+ [schemaNode.items].concat(schemaAncestors),
146
+ dataNode[i],
147
+ dataPath + '/' + i,
148
+ );
149
+ if (result) results.push(result);
150
+ }
151
+ if (results.length)
152
+ return results.reduce<Array<any>>(
153
+ (acc, v) => acc.concat(v),
154
+ [],
155
+ );
156
+ }
157
+ break;
158
+ }
159
+ case 'string': {
160
+ if (typeof dataNode === 'string') {
161
+ let value: string = dataNode;
162
+ if ('enum' in schemaNode && schemaNode.enum) {
163
+ if (!schemaNode.enum.includes(value)) {
164
+ return {
165
+ type: 'enum',
166
+ dataType: 'value',
167
+ dataPath,
168
+ expectedValues: schemaNode.enum,
169
+ actualValue: value,
170
+ ancestors: schemaAncestors,
171
+ };
172
+ }
173
+ } else if ('__validate' in schemaNode && schemaNode.__validate) {
174
+ let validationError = schemaNode.__validate(value);
175
+ if (typeof validationError == 'string') {
176
+ return {
177
+ type: 'other',
178
+ dataType: 'value',
179
+ dataPath,
180
+ message: validationError,
181
+ actualValue: value,
182
+ ancestors: schemaAncestors,
183
+ };
184
+ }
185
+ }
186
+ }
187
+ break;
188
+ }
189
+ case 'number': {
190
+ if (typeof dataNode === 'number') {
191
+ let value: number = dataNode;
192
+ if ('enum' in schemaNode && schemaNode.enum) {
193
+ if (!schemaNode.enum.includes(value)) {
194
+ return {
195
+ type: 'enum',
196
+ dataType: 'value',
197
+ dataPath,
198
+ expectedValues: schemaNode.enum,
199
+ actualValue: value,
200
+ ancestors: schemaAncestors,
201
+ };
202
+ }
203
+ }
204
+ }
205
+ break;
206
+ }
207
+ case 'object': {
208
+ if (
209
+ typeof dataNode === 'object' &&
210
+ dataNode !== null &&
211
+ !Array.isArray(dataNode)
212
+ ) {
213
+ let results: Array<Array<SchemaError> | SchemaError> = [];
214
+ let invalidProps;
215
+ if (
216
+ '__forbiddenProperties' in schemaNode &&
217
+ schemaNode.__forbiddenProperties
218
+ ) {
219
+ let keys = Object.keys(dataNode);
220
+ invalidProps = schemaNode.__forbiddenProperties.filter(
221
+ (val: string) => keys.includes(val),
222
+ );
223
+ results.push(
224
+ ...invalidProps.map(
225
+ (k: string) =>
226
+ ({
227
+ type: 'forbidden-prop',
228
+ dataPath: dataPath + '/' + encodeJSONKeyComponent(k),
229
+ dataType: 'key',
230
+ prop: k,
231
+ expectedProps: Object.keys(schemaNode.properties),
232
+ actualProps: keys,
233
+ ancestors: schemaAncestors,
234
+ }) as SchemaError,
235
+ ),
236
+ );
237
+ }
238
+ if ('required' in schemaNode && schemaNode.required) {
239
+ let keys = Object.keys(dataNode);
240
+ let missingKeys = schemaNode.required.filter(
241
+ (val: string) => !keys.includes(val),
242
+ );
243
+ results.push(
244
+ ...missingKeys.map(
245
+ (k: string) =>
246
+ ({
247
+ type: 'missing-prop',
248
+ dataPath,
249
+ dataType: 'value',
250
+ prop: k,
251
+ expectedProps: schemaNode.required,
252
+ actualProps: keys,
253
+ ancestors: schemaAncestors,
254
+ }) as SchemaError,
255
+ ),
256
+ );
257
+ }
258
+ if ('properties' in schemaNode && schemaNode.properties) {
259
+ let {additionalProperties = true} = schemaNode;
260
+ for (let k in dataNode) {
261
+ if (invalidProps && invalidProps.includes(k)) {
262
+ // Don't check type on forbidden props
263
+ continue;
264
+ } else if (k in schemaNode.properties) {
265
+ let result = walk(
266
+ [schemaNode.properties[k]].concat(schemaAncestors),
267
+ (dataNode as Record<string, unknown>)[k],
268
+ dataPath + '/' + encodeJSONKeyComponent(k),
269
+ );
270
+ if (result) results.push(result);
271
+ } else {
272
+ if (typeof additionalProperties === 'boolean') {
273
+ if (!additionalProperties) {
274
+ results.push({
275
+ type: 'enum',
276
+ dataType: 'key',
277
+ dataPath: dataPath + '/' + encodeJSONKeyComponent(k),
278
+ expectedValues: Object.keys(
279
+ schemaNode.properties,
280
+ ).filter((p) => !(p in dataNode)),
281
+ actualValue: k,
282
+ ancestors: schemaAncestors,
283
+ prettyType: schemaNode.__type,
284
+ });
285
+ }
286
+ } else {
287
+ let result = walk(
288
+ [additionalProperties].concat(schemaAncestors),
289
+ (dataNode as Record<string, unknown>)[k],
290
+ dataPath + '/' + encodeJSONKeyComponent(k),
291
+ );
292
+ if (result) results.push(result);
293
+ }
294
+ }
295
+ }
296
+ }
297
+ if (results.length)
298
+ return results.reduce<Array<any>>(
299
+ (acc, v) => acc.concat(v),
300
+ [],
301
+ );
302
+ }
303
+ break;
304
+ }
305
+ case 'boolean':
306
+ // NOOP, type was checked already
307
+ break;
308
+ default:
309
+ throw new Error(`Unimplemented schema type ${type}?`);
310
+ }
311
+ }
312
+ } else {
313
+ if (
314
+ 'enum' in schemaNode &&
315
+ schemaNode.enum &&
316
+ !schemaNode.enum.includes(dataNode)
317
+ ) {
318
+ return {
319
+ type: 'enum',
320
+ dataType: 'value',
321
+ dataPath: dataPath,
322
+ expectedValues: schemaNode.enum,
323
+ actualValue: schemaNode,
324
+ ancestors: schemaAncestors,
325
+ };
326
+ }
327
+
328
+ if ('oneOf' in schemaNode || 'allOf' in schemaNode) {
329
+ let list =
330
+ 'oneOf' in schemaNode
331
+ ? schemaNode.oneOf
332
+ : 'allOf' in schemaNode
333
+ ? schemaNode.allOf
334
+ : [];
335
+ let results: Array<SchemaError | Array<SchemaError>> = [];
336
+ for (let f of list) {
337
+ let result = walk([f].concat(schemaAncestors), dataNode, dataPath);
338
+ if (result) results.push(result);
339
+ }
340
+ if (
341
+ 'oneOf' in schemaNode
342
+ ? results.length == schemaNode.oneOf.length
343
+ : results.length > 0
344
+ ) {
345
+ // return the result with more values / longer key
346
+ results.sort((a, b) =>
347
+ Array.isArray(a) || Array.isArray(b)
348
+ ? Array.isArray(a) && !Array.isArray(b)
349
+ ? -1
350
+ : !Array.isArray(a) && Array.isArray(b)
351
+ ? 1
352
+ : Array.isArray(a) && Array.isArray(b)
353
+ ? b.length - a.length
354
+ : 0
355
+ : b.dataPath.length - a.dataPath.length,
356
+ );
357
+ return results[0];
358
+ }
359
+ } else if ('not' in schemaNode && schemaNode.not) {
360
+ let result = walk(
361
+ [schemaNode.not].concat(schemaAncestors),
362
+ dataNode,
363
+ dataPath,
364
+ );
365
+ if (!result || (Array.isArray(result) && result.length == 0)) {
366
+ return {
367
+ type: 'other',
368
+ dataPath,
369
+ dataType: null,
370
+ message: schemaNode.__message,
371
+ actualValue: dataNode,
372
+ ancestors: schemaAncestors,
373
+ };
374
+ }
375
+ }
376
+ }
377
+
378
+ return undefined;
379
+ }
380
+
381
+ let result = walk([schema], data, '');
382
+ return Array.isArray(result) ? result : result ? [result] : [];
383
+ }
384
+ export default validateSchema;
385
+
386
+ export function fuzzySearch(
387
+ expectedValues: Array<string>,
388
+ actualValue: string,
389
+ ): Array<string> {
390
+ let result = expectedValues
391
+ .map(
392
+ (exp) =>
393
+ [exp, levenshtein.distance(exp, actualValue)] as [string, number],
394
+ )
395
+ .filter(
396
+ // Remove if more than half of the string would need to be changed
397
+ ([, d]: [string, number]) => d * 2 < actualValue.length,
398
+ );
399
+ result.sort(([, a]: [string, number], [, b]: [string, number]) => a - b);
400
+ return result.map(([v]: [string, number]) => v);
401
+ }
402
+
403
+ validateSchema.diagnostic = function (
404
+ schema: SchemaEntity,
405
+ data: (
406
+ | {
407
+ source?: (() => string) | string | null | undefined;
408
+ data?: unknown;
409
+ }
410
+ | {
411
+ source: string | (() => string);
412
+ map: {
413
+ data: unknown;
414
+ pointers: {
415
+ [key: string]: Mapping;
416
+ };
417
+ };
418
+ }
419
+ ) & {
420
+ filePath?: string | null | undefined;
421
+ prependKey?: string | null | undefined;
422
+ },
423
+ origin: string,
424
+ message: string,
425
+ ): undefined {
426
+ if (!('map' in data) && !('source' in data || 'data' in data)) {
427
+ throw new Error(
428
+ 'At least one of data.source, data.data, or data.map must be defined!',
429
+ );
430
+ }
431
+ let loadedSource: string | null | undefined;
432
+ function loadSource(
433
+ loader: string | (() => string) | null | undefined,
434
+ ): string | null | undefined {
435
+ if (loadedSource !== undefined) {
436
+ return loadedSource;
437
+ } else if (typeof loader === 'function') {
438
+ loadedSource = loader();
439
+ return loadedSource;
440
+ } else if (typeof loader === 'string') {
441
+ loadedSource = loader;
442
+ return loadedSource;
443
+ }
444
+ return loadedSource;
445
+ }
446
+
447
+ let object: unknown;
448
+ if ('map' in data && data.map) {
449
+ object = data.map.data;
450
+ } else if ('data' in data && data.data !== undefined) {
451
+ object = data.data;
452
+ } else if ('source' in data && data.source) {
453
+ object = JSON.parse(loadSource(data.source) || '');
454
+ } else {
455
+ throw new Error('Unable to get object from data');
456
+ }
457
+
458
+ let errors = validateSchema(schema, object);
459
+ if (errors.length) {
460
+ let keys = errors.map((e) => {
461
+ let message;
462
+ if (e.type === 'enum') {
463
+ let {actualValue} = e;
464
+ let expectedValues = e.expectedValues.map(String);
465
+ let likely =
466
+ actualValue != null
467
+ ? fuzzySearch(expectedValues, String(actualValue))
468
+ : [];
469
+
470
+ if (likely.length > 0) {
471
+ message = `Did you mean ${likely
472
+ .map((v) => JSON.stringify(v))
473
+ .join(', ')}?`;
474
+ } else if (expectedValues.length > 0) {
475
+ message = `Possible values: ${expectedValues
476
+ .map((v) => JSON.stringify(v))
477
+ .join(', ')}`;
478
+ } else {
479
+ message = 'Unexpected value';
480
+ }
481
+ } else if (e.type === 'forbidden-prop') {
482
+ let {prop, expectedProps, actualProps} = e;
483
+ let likely = fuzzySearch(expectedProps, prop).filter(
484
+ (v) => !actualProps.includes(v),
485
+ );
486
+ if (likely.length > 0) {
487
+ message = `Did you mean ${likely
488
+ .map((v) => JSON.stringify(v))
489
+ .join(', ')}?`;
490
+ } else {
491
+ message = 'Unexpected property';
492
+ }
493
+ } else if (e.type === 'missing-prop') {
494
+ let {prop, actualProps} = e;
495
+ let likely = fuzzySearch(actualProps, prop);
496
+ if (likely.length > 0) {
497
+ message = `Did you mean ${JSON.stringify(prop)}?`;
498
+ e.dataPath += '/' + likely[0];
499
+ e.dataType = 'key';
500
+ } else {
501
+ message = `Missing property ${prop}`;
502
+ }
503
+ } else if (e.type === 'type') {
504
+ if (e.prettyType != null) {
505
+ message = `Expected ${e.prettyType}`;
506
+ } else {
507
+ message = `Expected type ${e.expectedTypes.join(', ')}`;
508
+ }
509
+ } else {
510
+ message = e.message;
511
+ }
512
+ return {key: e.dataPath, type: e.dataType, message};
513
+ });
514
+ let map, code;
515
+ if ('map' in data && data.map) {
516
+ map = data.map;
517
+ code = loadSource(data.source) ?? '';
518
+ } else {
519
+ if ('source' in data && data.source) {
520
+ map = loadSource(data.source) ?? '';
521
+ } else if ('data' in data && data.data !== undefined) {
522
+ map = JSON.stringify(nullthrows(data.data), null, '\t');
523
+ } else {
524
+ map = '';
525
+ }
526
+ code = map;
527
+ }
528
+ let codeFrames = [
529
+ {
530
+ filePath: data.filePath ?? undefined,
531
+ language: 'json' as const,
532
+ code: code ?? '',
533
+ codeHighlights: generateJSONCodeHighlights(
534
+ map,
535
+ keys.map(({key, type, message}) => ({
536
+ key: (data.prependKey ?? '') + key,
537
+ type: type,
538
+ message: message != null ? escapeMarkdown(message) : message,
539
+ })),
540
+ ),
541
+ },
542
+ ];
543
+
544
+ throw new ThrowableDiagnostic({
545
+ diagnostic: {
546
+ message: message,
547
+ origin,
548
+ codeFrames,
549
+ },
550
+ });
551
+ }
552
+ };
@@ -1,8 +1,10 @@
1
- // @flow
1
+ // flow-to-ts helpers
2
+ export type Class<T> = new (...args: any[]) => T;
3
+ // /flow-to-ts helpers
2
4
 
3
5
  export let SharedBuffer: Class<ArrayBuffer> | Class<SharedArrayBuffer>;
4
6
 
5
- // $FlowFixMe[prop-missing]
7
+ // @ts-expect-error process.browser is a browser-specific property
6
8
  if (process.browser) {
7
9
  SharedBuffer = ArrayBuffer;
8
10
  // Safari has removed the constructor
@@ -12,7 +14,7 @@ if (process.browser) {
12
14
  // Firefox might throw when sending the Buffer over a MessagePort
13
15
  channel.port1.postMessage(new SharedArrayBuffer(0));
14
16
  SharedBuffer = SharedArrayBuffer;
15
- } catch (_) {
17
+ } catch (_: any) {
16
18
  // NOOP
17
19
  }
18
20
  channel.port1.close();
@@ -1,7 +1,6 @@
1
- // @flow
2
- import type {SourceLocation} from '@atlaspack/types';
3
- import type {FileSystem} from '@atlaspack/fs';
4
- import SourceMap from '@parcel/source-map';
1
+ import type {SourceLocation, FileSystem} from '@atlaspack/types-internal';
2
+ import {getFeatureFlag} from '@atlaspack/feature-flags';
3
+ import SourceMap from '@atlaspack/source-map';
5
4
  import path from 'path';
6
5
  import {normalizeSeparators, isAbsolute} from './path';
7
6
 
@@ -21,7 +20,7 @@ export const SOURCEMAP_EXTENSIONS: Set<string> = new Set<string>([
21
20
 
22
21
  export function matchSourceMappingURL(
23
22
  contents: string,
24
- ): null | RegExp$matchResult {
23
+ ): RegExpMatchArray | null {
25
24
  return contents.match(SOURCEMAP_RE);
26
25
  }
27
26
 
@@ -29,7 +28,15 @@ export async function loadSourceMapUrl(
29
28
  fs: FileSystem,
30
29
  filename: string,
31
30
  contents: string,
32
- ): Promise<?{|filename: string, map: any, url: string|}> {
31
+ ): Promise<
32
+ | {
33
+ filename: string;
34
+ map: any;
35
+ url: string;
36
+ }
37
+ | null
38
+ | undefined
39
+ > {
33
40
  let match = matchSourceMappingURL(contents);
34
41
  if (match) {
35
42
  let url = match[1].trim();
@@ -60,8 +67,11 @@ export async function loadSourceMapUrl(
60
67
  export async function loadSourceMap(
61
68
  filename: string,
62
69
  contents: string,
63
- options: {fs: FileSystem, projectRoot: string, ...},
64
- ): Promise<?SourceMap> {
70
+ options: {
71
+ fs: FileSystem;
72
+ projectRoot: string;
73
+ },
74
+ ): Promise<SourceMap | null | undefined> {
65
75
  let foundMap = await loadSourceMapUrl(options.fs, filename, contents);
66
76
  if (foundMap) {
67
77
  let mapSourceRoot = path.dirname(filename);
@@ -75,7 +85,7 @@ export async function loadSourceMap(
75
85
  let sourcemapInstance = new SourceMap(options.projectRoot);
76
86
  sourcemapInstance.addVLQMap({
77
87
  ...foundMap.map,
78
- sources: foundMap.map.sources.map((s) => {
88
+ sources: foundMap.map.sources.map((s: string) => {
79
89
  return path.join(mapSourceRoot, s);
80
90
  }),
81
91
  });
@@ -86,6 +96,7 @@ export async function loadSourceMap(
86
96
  export function remapSourceLocation(
87
97
  loc: SourceLocation,
88
98
  originalMap: SourceMap,
99
+ projectRoot: string,
89
100
  ): SourceLocation {
90
101
  let {
91
102
  filePath,
@@ -99,7 +110,14 @@ export function remapSourceLocation(
99
110
 
100
111
  if (start?.original) {
101
112
  if (start.source) {
102
- filePath = start.source;
113
+ if (
114
+ getFeatureFlag('symbolLocationFix') &&
115
+ !path.isAbsolute(start.source)
116
+ ) {
117
+ filePath = path.join(projectRoot, start.source);
118
+ } else {
119
+ filePath = start.source;
120
+ }
103
121
  }
104
122
 
105
123
  ({line: startLine, column: startCol} = start.original);