@parcel/utils 2.0.0-nightly.137 → 2.0.0-nightly.1370
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/.eslintrc.js +6 -6
- package/lib/index.js +37566 -307
- package/lib/index.js.map +1 -0
- package/package.json +45 -20
- package/src/BitSet.js +126 -0
- package/src/DefaultMap.js +1 -1
- package/src/PromiseQueue.js +16 -12
- package/src/alternatives.js +145 -0
- package/src/ansi-html.js +2 -2
- package/src/blob.js +2 -1
- package/src/bundle-url.js +1 -1
- package/src/collection.js +35 -15
- package/src/config.js +132 -45
- package/src/countLines.js +5 -2
- package/src/debounce.js +1 -1
- package/src/dependency-location.js +11 -6
- package/src/generateBuildMetrics.js +158 -0
- package/src/generateCertificate.js +1 -1
- package/src/getCertificate.js +1 -1
- package/src/getExisting.js +1 -4
- package/src/getModuleParts.js +23 -0
- package/src/getRootDir.js +1 -2
- package/src/glob.js +51 -10
- package/src/hash.js +49 -0
- package/src/http-server.js +29 -19
- package/src/index.js +69 -21
- package/src/is-url.js +1 -1
- package/src/isDirectoryInside.js +11 -0
- package/src/openInBrowser.js +64 -0
- package/src/path.js +38 -6
- package/src/prettyDiagnostic.js +74 -24
- package/src/progress-message.js +22 -0
- package/src/relativeBundlePath.js +8 -13
- package/src/replaceBundleReferences.js +85 -41
- package/src/schema.js +100 -44
- package/src/shared-buffer.js +23 -0
- package/src/sourcemap.js +138 -0
- package/src/stream.js +31 -1
- package/src/urlJoin.js +3 -1
- package/test/BitSet.test.js +119 -0
- package/test/DefaultMap.test.js +7 -4
- package/test/collection.test.js +13 -1
- package/test/config.test.js +98 -0
- package/test/input/config/.testrc +3 -0
- package/test/input/config/config.cjs +3 -0
- package/test/input/config/config.js +3 -0
- package/test/input/config/config.json +3 -0
- package/test/input/config/empty.json +0 -0
- package/test/input/config/empty.toml +0 -0
- package/test/input/sourcemap/referenced-min.js +2 -0
- package/test/input/sourcemap/referenced-min.js.map +6 -0
- package/test/input/sourcemap/source-root.js +2 -0
- package/test/input/sourcemap/source-root.js.map +7 -0
- package/test/replaceBundleReferences.test.js +268 -0
- package/test/sourcemap.test.js +207 -0
- package/test/throttle.test.js +1 -2
- package/test/urlJoin.test.js +37 -0
- package/lib/DefaultMap.js +0 -64
- package/lib/Deferred.js +0 -26
- package/lib/PromiseQueue.js +0 -133
- package/lib/TapStream.js +0 -41
- package/lib/ansi-html.js +0 -16
- package/lib/blob.js +0 -31
- package/lib/bundle-url.js +0 -43
- package/lib/collection.js +0 -62
- package/lib/config.js +0 -88
- package/lib/countLines.js +0 -18
- package/lib/debounce.js +0 -20
- package/lib/dependency-location.js +0 -21
- package/lib/escape-html.js +0 -24
- package/lib/generateBundleReport.js +0 -38
- package/lib/generateCertificate.js +0 -124
- package/lib/getCertificate.js +0 -19
- package/lib/getExisting.js +0 -23
- package/lib/getRootDir.js +0 -55
- package/lib/glob.js +0 -76
- package/lib/http-server.js +0 -64
- package/lib/is-url.js +0 -17
- package/lib/loadSourceMapUrl.js +0 -33
- package/lib/md5.js +0 -35
- package/lib/objectHash.js +0 -26
- package/lib/parseCSSImport.js +0 -16
- package/lib/path.js +0 -22
- package/lib/prettifyTime.js +0 -10
- package/lib/prettyDiagnostic.js +0 -57
- package/lib/promisify.js +0 -13
- package/lib/relativeBundlePath.js +0 -24
- package/lib/relativeUrl.js +0 -16
- package/lib/replaceBundleReferences.js +0 -151
- package/lib/resolve.js +0 -93
- package/lib/schema.js +0 -320
- package/lib/serializeObject.js +0 -28
- package/lib/stream.js +0 -51
- package/lib/throttle.js +0 -16
- package/lib/urlJoin.js +0 -27
- package/src/.babelrc +0 -3
- package/src/generateBundleReport.js +0 -51
- package/src/loadSourceMapUrl.js +0 -33
- package/src/md5.js +0 -44
- package/src/promisify.js +0 -13
- package/src/resolve.js +0 -135
- package/src/serializeObject.js +0 -22
- package/test/input/sourcemap/referenced.js +0 -7
- package/test/loadSourceMapUrl.test.js +0 -37
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
// @flow strict-local
|
|
2
2
|
|
|
3
3
|
import type SourceMap from '@parcel/source-map';
|
|
4
|
-
import type {
|
|
4
|
+
import type {
|
|
5
|
+
Async,
|
|
6
|
+
Blob,
|
|
7
|
+
Bundle,
|
|
8
|
+
BundleGraph,
|
|
9
|
+
Dependency,
|
|
10
|
+
NamedBundle,
|
|
11
|
+
} from '@parcel/types';
|
|
5
12
|
|
|
6
13
|
import {Readable} from 'stream';
|
|
7
14
|
import nullthrows from 'nullthrows';
|
|
15
|
+
import invariant from 'assert';
|
|
8
16
|
import URL from 'url';
|
|
9
|
-
import {bufferStream, relativeBundlePath, urlJoin} from '
|
|
17
|
+
import {bufferStream, relativeBundlePath, urlJoin} from './';
|
|
10
18
|
|
|
11
19
|
type ReplacementMap = Map<
|
|
12
20
|
string /* dependency id */,
|
|
@@ -15,7 +23,7 @@ type ReplacementMap = Map<
|
|
|
15
23
|
|
|
16
24
|
/*
|
|
17
25
|
* Replaces references to dependency ids for URL dependencies with:
|
|
18
|
-
* - in the case of an unresolvable url dependency, the original
|
|
26
|
+
* - in the case of an unresolvable url dependency, the original specifier.
|
|
19
27
|
* These are external requests that Parcel did not bundle.
|
|
20
28
|
* - in the case of a reference to another bundle, the relative url to that
|
|
21
29
|
* bundle from the current bundle.
|
|
@@ -25,44 +33,55 @@ export function replaceURLReferences({
|
|
|
25
33
|
bundleGraph,
|
|
26
34
|
contents,
|
|
27
35
|
map,
|
|
36
|
+
getReplacement = s => s,
|
|
28
37
|
relative = true,
|
|
29
38
|
}: {|
|
|
30
|
-
bundle:
|
|
31
|
-
bundleGraph: BundleGraph
|
|
39
|
+
bundle: NamedBundle,
|
|
40
|
+
bundleGraph: BundleGraph<NamedBundle>,
|
|
32
41
|
contents: string,
|
|
33
42
|
relative?: boolean,
|
|
34
43
|
map?: ?SourceMap,
|
|
44
|
+
getReplacement?: string => string,
|
|
35
45
|
|}): {|+contents: string, +map: ?SourceMap|} {
|
|
36
46
|
let replacements = new Map();
|
|
47
|
+
let urlDependencies = [];
|
|
48
|
+
bundle.traverse(node => {
|
|
49
|
+
if (node.type === 'dependency' && node.value.specifierType === 'url') {
|
|
50
|
+
urlDependencies.push(node.value);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
37
53
|
|
|
38
|
-
for (let dependency of
|
|
39
|
-
if (
|
|
54
|
+
for (let dependency of urlDependencies) {
|
|
55
|
+
if (dependency.specifierType !== 'url') {
|
|
40
56
|
continue;
|
|
41
57
|
}
|
|
42
58
|
|
|
43
|
-
let
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
59
|
+
let placeholder = dependency.meta?.placeholder ?? dependency.id;
|
|
60
|
+
invariant(typeof placeholder === 'string');
|
|
61
|
+
|
|
62
|
+
let resolved = bundleGraph.getReferencedBundle(dependency, bundle);
|
|
63
|
+
if (resolved == null) {
|
|
64
|
+
replacements.set(placeholder, {
|
|
65
|
+
from: placeholder,
|
|
66
|
+
to: getReplacement(dependency.specifier),
|
|
48
67
|
});
|
|
49
68
|
continue;
|
|
50
69
|
}
|
|
51
70
|
|
|
52
|
-
|
|
53
|
-
if (entryBundle.isInline) {
|
|
71
|
+
if (resolved.bundleBehavior === 'inline') {
|
|
54
72
|
// If a bundle is inline, it should be replaced with inline contents,
|
|
55
73
|
// not a URL.
|
|
56
74
|
continue;
|
|
57
75
|
}
|
|
58
76
|
|
|
59
77
|
replacements.set(
|
|
60
|
-
|
|
78
|
+
placeholder,
|
|
61
79
|
getURLReplacement({
|
|
62
80
|
dependency,
|
|
63
81
|
fromBundle: bundle,
|
|
64
|
-
toBundle:
|
|
82
|
+
toBundle: resolved,
|
|
65
83
|
relative,
|
|
84
|
+
getReplacement,
|
|
66
85
|
}),
|
|
67
86
|
);
|
|
68
87
|
}
|
|
@@ -83,7 +102,7 @@ export async function replaceInlineReferences({
|
|
|
83
102
|
getInlineBundleContents,
|
|
84
103
|
}: {|
|
|
85
104
|
bundle: Bundle,
|
|
86
|
-
bundleGraph: BundleGraph
|
|
105
|
+
bundleGraph: BundleGraph<NamedBundle>,
|
|
87
106
|
contents: string,
|
|
88
107
|
getInlineReplacement: (
|
|
89
108
|
Dependency,
|
|
@@ -92,20 +111,22 @@ export async function replaceInlineReferences({
|
|
|
92
111
|
) => {|from: string, to: string|},
|
|
93
112
|
getInlineBundleContents: (
|
|
94
113
|
Bundle,
|
|
95
|
-
BundleGraph
|
|
96
|
-
) => Async<{|contents: Blob
|
|
114
|
+
BundleGraph<NamedBundle>,
|
|
115
|
+
) => Async<{|contents: Blob|}>,
|
|
97
116
|
map?: ?SourceMap,
|
|
98
117
|
|}): Promise<{|+contents: string, +map: ?SourceMap|}> {
|
|
99
118
|
let replacements = new Map();
|
|
100
119
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (
|
|
104
|
-
|
|
120
|
+
let dependencies = [];
|
|
121
|
+
bundle.traverse(node => {
|
|
122
|
+
if (node.type === 'dependency') {
|
|
123
|
+
dependencies.push(node.value);
|
|
105
124
|
}
|
|
125
|
+
});
|
|
106
126
|
|
|
107
|
-
|
|
108
|
-
|
|
127
|
+
for (let dependency of dependencies) {
|
|
128
|
+
let entryBundle = bundleGraph.getReferencedBundle(dependency, bundle);
|
|
129
|
+
if (entryBundle?.bundleBehavior !== 'inline') {
|
|
109
130
|
continue;
|
|
110
131
|
}
|
|
111
132
|
|
|
@@ -113,15 +134,18 @@ export async function replaceInlineReferences({
|
|
|
113
134
|
entryBundle,
|
|
114
135
|
bundleGraph,
|
|
115
136
|
);
|
|
116
|
-
let packagedContents = (
|
|
117
|
-
|
|
118
|
-
|
|
137
|
+
let packagedContents = (
|
|
138
|
+
packagedBundle.contents instanceof Readable
|
|
139
|
+
? await bufferStream(packagedBundle.contents)
|
|
140
|
+
: packagedBundle.contents
|
|
119
141
|
).toString();
|
|
120
142
|
|
|
121
143
|
let inlineType = nullthrows(entryBundle.getMainEntry()).meta.inlineType;
|
|
122
144
|
if (inlineType == null || inlineType === 'string') {
|
|
145
|
+
let placeholder = dependency.meta?.placeholder ?? dependency.id;
|
|
146
|
+
invariant(typeof placeholder === 'string');
|
|
123
147
|
replacements.set(
|
|
124
|
-
|
|
148
|
+
placeholder,
|
|
125
149
|
getInlineReplacement(dependency, inlineType, packagedContents),
|
|
126
150
|
);
|
|
127
151
|
}
|
|
@@ -130,32 +154,52 @@ export async function replaceInlineReferences({
|
|
|
130
154
|
return performReplacement(replacements, contents, map);
|
|
131
155
|
}
|
|
132
156
|
|
|
133
|
-
function getURLReplacement({
|
|
157
|
+
export function getURLReplacement({
|
|
134
158
|
dependency,
|
|
135
159
|
fromBundle,
|
|
136
160
|
toBundle,
|
|
137
161
|
relative,
|
|
162
|
+
getReplacement,
|
|
138
163
|
}: {|
|
|
139
164
|
dependency: Dependency,
|
|
140
|
-
fromBundle:
|
|
141
|
-
toBundle:
|
|
165
|
+
fromBundle: NamedBundle,
|
|
166
|
+
toBundle: NamedBundle,
|
|
142
167
|
relative: boolean,
|
|
143
|
-
|
|
144
|
-
|
|
168
|
+
getReplacement?: string => string,
|
|
169
|
+
|}): {|from: string, to: string|} {
|
|
145
170
|
let to;
|
|
171
|
+
|
|
172
|
+
let orig = URL.parse(dependency.specifier);
|
|
173
|
+
|
|
146
174
|
if (relative) {
|
|
147
|
-
|
|
148
|
-
|
|
175
|
+
to = URL.format({
|
|
176
|
+
pathname: relativeBundlePath(fromBundle, toBundle, {
|
|
177
|
+
leadingDotSlash: false,
|
|
178
|
+
}),
|
|
179
|
+
hash: orig.hash,
|
|
149
180
|
});
|
|
150
|
-
|
|
181
|
+
|
|
182
|
+
// If the resulting path includes a colon character and doesn't start with a ./ or ../
|
|
183
|
+
// we need to add one so that the first part before the colon isn't parsed as a URL protocol.
|
|
184
|
+
if (to.includes(':') && !to.startsWith('./') && !to.startsWith('../')) {
|
|
185
|
+
to = './' + to;
|
|
186
|
+
}
|
|
151
187
|
} else {
|
|
152
|
-
|
|
153
|
-
|
|
188
|
+
to = urlJoin(
|
|
189
|
+
toBundle.target.publicUrl,
|
|
190
|
+
URL.format({
|
|
191
|
+
pathname: nullthrows(toBundle.name),
|
|
192
|
+
hash: orig.hash,
|
|
193
|
+
}),
|
|
194
|
+
);
|
|
154
195
|
}
|
|
155
196
|
|
|
197
|
+
let placeholder = dependency.meta?.placeholder ?? dependency.id;
|
|
198
|
+
invariant(typeof placeholder === 'string');
|
|
199
|
+
|
|
156
200
|
return {
|
|
157
|
-
from:
|
|
158
|
-
to,
|
|
201
|
+
from: placeholder,
|
|
202
|
+
to: getReplacement ? getReplacement(to) : to,
|
|
159
203
|
};
|
|
160
204
|
}
|
|
161
205
|
|
package/src/schema.js
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
// @flow strict-local
|
|
2
2
|
import ThrowableDiagnostic, {
|
|
3
3
|
generateJSONCodeHighlights,
|
|
4
|
+
escapeMarkdown,
|
|
5
|
+
encodeJSONKeyComponent,
|
|
4
6
|
} from '@parcel/diagnostic';
|
|
5
|
-
|
|
6
|
-
import
|
|
7
|
+
import type {Mapping} from '@mischnic/json-sourcemap';
|
|
8
|
+
import nullthrows from 'nullthrows';
|
|
9
|
+
import * as levenshtein from 'fastest-levenshtein';
|
|
7
10
|
|
|
8
11
|
export type SchemaEntity =
|
|
9
12
|
| SchemaObject
|
|
10
13
|
| SchemaArray
|
|
11
14
|
| SchemaBoolean
|
|
12
15
|
| SchemaString
|
|
16
|
+
| SchemaNumber
|
|
13
17
|
| SchemaEnum
|
|
14
18
|
| SchemaOneOf
|
|
15
19
|
| SchemaAllOf
|
|
@@ -40,6 +44,11 @@ export type SchemaString = {|
|
|
|
40
44
|
__validate?: (val: string) => ?string,
|
|
41
45
|
__type?: string,
|
|
42
46
|
|};
|
|
47
|
+
export type SchemaNumber = {|
|
|
48
|
+
type: 'number',
|
|
49
|
+
enum?: Array<number>,
|
|
50
|
+
__type?: string,
|
|
51
|
+
|};
|
|
43
52
|
export type SchemaEnum = {|
|
|
44
53
|
enum: Array<mixed>,
|
|
45
54
|
|};
|
|
@@ -88,7 +97,7 @@ export type SchemaError =
|
|
|
88
97
|
prop: string,
|
|
89
98
|
expectedProps: Array<string>,
|
|
90
99
|
actualProps: Array<string>,
|
|
91
|
-
dataType:
|
|
100
|
+
dataType: 'key' | 'value',
|
|
92
101
|
|
|
93
102
|
dataPath: string,
|
|
94
103
|
ancestors: Array<SchemaEntity>,
|
|
@@ -99,7 +108,6 @@ export type SchemaError =
|
|
|
99
108
|
actualValue: mixed,
|
|
100
109
|
dataType: ?'key' | 'value',
|
|
101
110
|
message?: string,
|
|
102
|
-
|
|
103
111
|
dataPath: string,
|
|
104
112
|
ancestors: Array<SchemaEntity>,
|
|
105
113
|
|};
|
|
@@ -159,8 +167,7 @@ function validateSchema(schema: SchemaEntity, data: mixed): Array<SchemaError> {
|
|
|
159
167
|
}
|
|
160
168
|
} else if (schemaNode.__validate) {
|
|
161
169
|
let validationError = schemaNode.__validate(value);
|
|
162
|
-
|
|
163
|
-
if (validationError) {
|
|
170
|
+
if (typeof validationError == 'string') {
|
|
164
171
|
return {
|
|
165
172
|
type: 'other',
|
|
166
173
|
dataType: 'value',
|
|
@@ -173,6 +180,23 @@ function validateSchema(schema: SchemaEntity, data: mixed): Array<SchemaError> {
|
|
|
173
180
|
}
|
|
174
181
|
break;
|
|
175
182
|
}
|
|
183
|
+
case 'number': {
|
|
184
|
+
// $FlowFixMe type was already checked
|
|
185
|
+
let value: number = dataNode;
|
|
186
|
+
if (schemaNode.enum) {
|
|
187
|
+
if (!schemaNode.enum.includes(value)) {
|
|
188
|
+
return {
|
|
189
|
+
type: 'enum',
|
|
190
|
+
dataType: 'value',
|
|
191
|
+
dataPath,
|
|
192
|
+
expectedValues: schemaNode.enum,
|
|
193
|
+
actualValue: value,
|
|
194
|
+
ancestors: schemaAncestors,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
176
200
|
case 'object': {
|
|
177
201
|
let results: Array<Array<SchemaError> | SchemaError> = [];
|
|
178
202
|
let invalidProps;
|
|
@@ -187,7 +211,7 @@ function validateSchema(schema: SchemaEntity, data: mixed): Array<SchemaError> {
|
|
|
187
211
|
k =>
|
|
188
212
|
({
|
|
189
213
|
type: 'forbidden-prop',
|
|
190
|
-
dataPath: dataPath + '/' + k,
|
|
214
|
+
dataPath: dataPath + '/' + encodeJSONKeyComponent(k),
|
|
191
215
|
dataType: 'key',
|
|
192
216
|
prop: k,
|
|
193
217
|
expectedProps: Object.keys(schemaNode.properties),
|
|
@@ -209,7 +233,7 @@ function validateSchema(schema: SchemaEntity, data: mixed): Array<SchemaError> {
|
|
|
209
233
|
({
|
|
210
234
|
type: 'missing-prop',
|
|
211
235
|
dataPath,
|
|
212
|
-
dataType:
|
|
236
|
+
dataType: 'value',
|
|
213
237
|
prop: k,
|
|
214
238
|
expectedProps: schemaNode.required,
|
|
215
239
|
actualProps: keys,
|
|
@@ -230,7 +254,7 @@ function validateSchema(schema: SchemaEntity, data: mixed): Array<SchemaError> {
|
|
|
230
254
|
[schemaNode.properties[k]].concat(schemaAncestors),
|
|
231
255
|
// $FlowFixMe type was already checked
|
|
232
256
|
dataNode[k],
|
|
233
|
-
dataPath + '/' + k,
|
|
257
|
+
dataPath + '/' + encodeJSONKeyComponent(k),
|
|
234
258
|
);
|
|
235
259
|
if (result) results.push(result);
|
|
236
260
|
} else {
|
|
@@ -239,7 +263,7 @@ function validateSchema(schema: SchemaEntity, data: mixed): Array<SchemaError> {
|
|
|
239
263
|
results.push({
|
|
240
264
|
type: 'enum',
|
|
241
265
|
dataType: 'key',
|
|
242
|
-
dataPath: dataPath + '/' + k,
|
|
266
|
+
dataPath: dataPath + '/' + encodeJSONKeyComponent(k),
|
|
243
267
|
expectedValues: Object.keys(
|
|
244
268
|
schemaNode.properties,
|
|
245
269
|
).filter(
|
|
@@ -256,7 +280,7 @@ function validateSchema(schema: SchemaEntity, data: mixed): Array<SchemaError> {
|
|
|
256
280
|
[additionalProperties].concat(schemaAncestors),
|
|
257
281
|
// $FlowFixMe type was already checked
|
|
258
282
|
dataNode[k],
|
|
259
|
-
dataPath + '/' + k,
|
|
283
|
+
dataPath + '/' + encodeJSONKeyComponent(k),
|
|
260
284
|
);
|
|
261
285
|
if (result) results.push(result);
|
|
262
286
|
}
|
|
@@ -339,9 +363,12 @@ function validateSchema(schema: SchemaEntity, data: mixed): Array<SchemaError> {
|
|
|
339
363
|
}
|
|
340
364
|
export default validateSchema;
|
|
341
365
|
|
|
342
|
-
function fuzzySearch(
|
|
366
|
+
export function fuzzySearch(
|
|
367
|
+
expectedValues: Array<string>,
|
|
368
|
+
actualValue: string,
|
|
369
|
+
): Array<string> {
|
|
343
370
|
let result = expectedValues
|
|
344
|
-
.map(exp => [exp,
|
|
371
|
+
.map(exp => [exp, levenshtein.distance(exp, actualValue)])
|
|
345
372
|
.filter(
|
|
346
373
|
// Remove if more than half of the string would need to be changed
|
|
347
374
|
([, d]) => d * 2 < actualValue.length,
|
|
@@ -350,22 +377,43 @@ function fuzzySearch(expectedValues: Array<string>, actualValue: string) {
|
|
|
350
377
|
return result.map(([v]) => v);
|
|
351
378
|
}
|
|
352
379
|
|
|
353
|
-
validateSchema.diagnostic = function(
|
|
380
|
+
validateSchema.diagnostic = function (
|
|
354
381
|
schema: SchemaEntity,
|
|
355
|
-
data:
|
|
356
|
-
|
|
357
|
-
|
|
382
|
+
data: {|
|
|
383
|
+
...
|
|
384
|
+
| {|
|
|
385
|
+
source?: ?string,
|
|
386
|
+
data?: mixed,
|
|
387
|
+
|}
|
|
388
|
+
| {|
|
|
389
|
+
source: string,
|
|
390
|
+
map: {|
|
|
391
|
+
data: mixed,
|
|
392
|
+
pointers: {|[key: string]: Mapping|},
|
|
393
|
+
|},
|
|
394
|
+
|},
|
|
395
|
+
filePath?: ?string,
|
|
396
|
+
prependKey?: ?string,
|
|
397
|
+
|},
|
|
358
398
|
origin: string,
|
|
359
|
-
prependKey: string,
|
|
360
399
|
message: string,
|
|
361
400
|
): void {
|
|
362
|
-
|
|
401
|
+
if (
|
|
402
|
+
'source' in data &&
|
|
403
|
+
'data' in data &&
|
|
404
|
+
typeof data.source !== 'string' &&
|
|
405
|
+
!data
|
|
406
|
+
) {
|
|
407
|
+
throw new Error(
|
|
408
|
+
'At least one of data.source and data.data must be defined!',
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
let object = data.map
|
|
412
|
+
? data.map.data
|
|
413
|
+
: // $FlowFixMe we can assume it's a JSON object
|
|
414
|
+
data.data ?? JSON.parse(data.source);
|
|
415
|
+
let errors = validateSchema(schema, object);
|
|
363
416
|
if (errors.length) {
|
|
364
|
-
let dataContentsString: string =
|
|
365
|
-
typeof dataContents === 'string'
|
|
366
|
-
? dataContents
|
|
367
|
-
: // $FlowFixMe
|
|
368
|
-
JSON.stringify(dataContents, null, '\t');
|
|
369
417
|
let keys = errors.map(e => {
|
|
370
418
|
let message;
|
|
371
419
|
if (e.type === 'enum') {
|
|
@@ -403,10 +451,8 @@ validateSchema.diagnostic = function(
|
|
|
403
451
|
let {prop, actualProps} = e;
|
|
404
452
|
let likely = fuzzySearch(actualProps, prop);
|
|
405
453
|
if (likely.length > 0) {
|
|
406
|
-
message = `Did you mean ${
|
|
407
|
-
|
|
408
|
-
.join(', ')}?`;
|
|
409
|
-
e.dataPath += '/' + prop;
|
|
454
|
+
message = `Did you mean ${JSON.stringify(prop)}?`;
|
|
455
|
+
e.dataPath += '/' + likely[0];
|
|
410
456
|
e.dataType = 'key';
|
|
411
457
|
} else {
|
|
412
458
|
message = `Missing property ${prop}`;
|
|
@@ -422,26 +468,36 @@ validateSchema.diagnostic = function(
|
|
|
422
468
|
}
|
|
423
469
|
return {key: e.dataPath, type: e.dataType, message};
|
|
424
470
|
});
|
|
425
|
-
let
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
471
|
+
let map, code;
|
|
472
|
+
if (data.map) {
|
|
473
|
+
map = data.map;
|
|
474
|
+
code = data.source;
|
|
475
|
+
} else {
|
|
476
|
+
// $FlowFixMe we can assume that data is valid JSON
|
|
477
|
+
map = data.source ?? JSON.stringify(nullthrows(data.data), 0, '\t');
|
|
478
|
+
code = map;
|
|
479
|
+
}
|
|
480
|
+
let codeFrames = [
|
|
481
|
+
{
|
|
482
|
+
filePath: data.filePath ?? undefined,
|
|
483
|
+
language: 'json',
|
|
484
|
+
code,
|
|
485
|
+
codeHighlights: generateJSONCodeHighlights(
|
|
486
|
+
map,
|
|
487
|
+
keys.map(({key, type, message}) => ({
|
|
488
|
+
key: (data.prependKey ?? '') + key,
|
|
489
|
+
type: type,
|
|
490
|
+
message: message != null ? escapeMarkdown(message) : message,
|
|
491
|
+
})),
|
|
492
|
+
),
|
|
493
|
+
},
|
|
494
|
+
];
|
|
436
495
|
|
|
437
496
|
throw new ThrowableDiagnostic({
|
|
438
497
|
diagnostic: {
|
|
439
|
-
message,
|
|
498
|
+
message: message,
|
|
440
499
|
origin,
|
|
441
|
-
|
|
442
|
-
filePath: dataContentsPath || undefined,
|
|
443
|
-
language: 'json',
|
|
444
|
-
codeFrame,
|
|
500
|
+
codeFrames,
|
|
445
501
|
},
|
|
446
502
|
});
|
|
447
503
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
export let SharedBuffer: Class<ArrayBuffer> | Class<SharedArrayBuffer>;
|
|
4
|
+
|
|
5
|
+
// $FlowFixMe[prop-missing]
|
|
6
|
+
if (process.browser) {
|
|
7
|
+
SharedBuffer = ArrayBuffer;
|
|
8
|
+
// Safari has removed the constructor
|
|
9
|
+
if (typeof SharedArrayBuffer !== 'undefined') {
|
|
10
|
+
let channel = new MessageChannel();
|
|
11
|
+
try {
|
|
12
|
+
// Firefox might throw when sending the Buffer over a MessagePort
|
|
13
|
+
channel.port1.postMessage(new SharedArrayBuffer(0));
|
|
14
|
+
SharedBuffer = SharedArrayBuffer;
|
|
15
|
+
} catch (_) {
|
|
16
|
+
// NOOP
|
|
17
|
+
}
|
|
18
|
+
channel.port1.close();
|
|
19
|
+
channel.port2.close();
|
|
20
|
+
}
|
|
21
|
+
} else {
|
|
22
|
+
SharedBuffer = SharedArrayBuffer;
|
|
23
|
+
}
|
package/src/sourcemap.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import type {SourceLocation} from '@parcel/types';
|
|
3
|
+
import type {FileSystem} from '@parcel/fs';
|
|
4
|
+
import SourceMap from '@parcel/source-map';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import {normalizeSeparators, isAbsolute} from './path';
|
|
7
|
+
|
|
8
|
+
export const SOURCEMAP_RE: RegExp =
|
|
9
|
+
/(?:\/\*|\/\/)\s*[@#]\s*sourceMappingURL\s*=\s*([^\s*]+)(?:\s*\*\/)?\s*$/;
|
|
10
|
+
const DATA_URL_RE = /^data:[^;]+(?:;charset=[^;]+)?;base64,(.*)/;
|
|
11
|
+
export const SOURCEMAP_EXTENSIONS: Set<string> = new Set<string>([
|
|
12
|
+
'css',
|
|
13
|
+
'es',
|
|
14
|
+
'es6',
|
|
15
|
+
'js',
|
|
16
|
+
'jsx',
|
|
17
|
+
'mjs',
|
|
18
|
+
'ts',
|
|
19
|
+
'tsx',
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
export function matchSourceMappingURL(
|
|
23
|
+
contents: string,
|
|
24
|
+
): null | RegExp$matchResult {
|
|
25
|
+
return contents.match(SOURCEMAP_RE);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function loadSourceMapUrl(
|
|
29
|
+
fs: FileSystem,
|
|
30
|
+
filename: string,
|
|
31
|
+
contents: string,
|
|
32
|
+
): Promise<?{|filename: string, map: any, url: string|}> {
|
|
33
|
+
let match = matchSourceMappingURL(contents);
|
|
34
|
+
if (match) {
|
|
35
|
+
let url = match[1].trim();
|
|
36
|
+
let dataURLMatch = url.match(DATA_URL_RE);
|
|
37
|
+
|
|
38
|
+
let mapFilePath;
|
|
39
|
+
if (dataURLMatch) {
|
|
40
|
+
mapFilePath = filename;
|
|
41
|
+
} else {
|
|
42
|
+
mapFilePath = url.replace(/^file:\/\//, '');
|
|
43
|
+
mapFilePath = isAbsolute(mapFilePath)
|
|
44
|
+
? mapFilePath
|
|
45
|
+
: path.join(path.dirname(filename), mapFilePath);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
url,
|
|
50
|
+
filename: mapFilePath,
|
|
51
|
+
map: JSON.parse(
|
|
52
|
+
dataURLMatch
|
|
53
|
+
? Buffer.from(dataURLMatch[1], 'base64').toString()
|
|
54
|
+
: await fs.readFile(mapFilePath, 'utf8'),
|
|
55
|
+
),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export async function loadSourceMap(
|
|
61
|
+
filename: string,
|
|
62
|
+
contents: string,
|
|
63
|
+
options: {fs: FileSystem, projectRoot: string, ...},
|
|
64
|
+
): Promise<?SourceMap> {
|
|
65
|
+
let foundMap = await loadSourceMapUrl(options.fs, filename, contents);
|
|
66
|
+
if (foundMap) {
|
|
67
|
+
let mapSourceRoot = path.dirname(filename);
|
|
68
|
+
if (
|
|
69
|
+
foundMap.map.sourceRoot &&
|
|
70
|
+
!normalizeSeparators(foundMap.map.sourceRoot).startsWith('/')
|
|
71
|
+
) {
|
|
72
|
+
mapSourceRoot = path.join(mapSourceRoot, foundMap.map.sourceRoot);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
let sourcemapInstance = new SourceMap(options.projectRoot);
|
|
76
|
+
sourcemapInstance.addVLQMap({
|
|
77
|
+
...foundMap.map,
|
|
78
|
+
sources: foundMap.map.sources.map(s => {
|
|
79
|
+
return path.join(mapSourceRoot, s);
|
|
80
|
+
}),
|
|
81
|
+
});
|
|
82
|
+
return sourcemapInstance;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function remapSourceLocation(
|
|
87
|
+
loc: SourceLocation,
|
|
88
|
+
originalMap: SourceMap,
|
|
89
|
+
): SourceLocation {
|
|
90
|
+
let {
|
|
91
|
+
filePath,
|
|
92
|
+
start: {line: startLine, column: startCol},
|
|
93
|
+
end: {line: endLine, column: endCol},
|
|
94
|
+
} = loc;
|
|
95
|
+
let lineDiff = endLine - startLine;
|
|
96
|
+
let colDiff = endCol - startCol;
|
|
97
|
+
let start = originalMap.findClosestMapping(startLine, startCol - 1);
|
|
98
|
+
let end = originalMap.findClosestMapping(endLine, endCol - 1);
|
|
99
|
+
|
|
100
|
+
if (start?.original) {
|
|
101
|
+
if (start.source) {
|
|
102
|
+
filePath = start.source;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
({line: startLine, column: startCol} = start.original);
|
|
106
|
+
startCol++; // source map columns are 0-based
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (end?.original) {
|
|
110
|
+
({line: endLine, column: endCol} = end.original);
|
|
111
|
+
endCol++; // source map columns are 0-based
|
|
112
|
+
|
|
113
|
+
if (endLine < startLine) {
|
|
114
|
+
endLine = startLine;
|
|
115
|
+
endCol = startCol;
|
|
116
|
+
} else if (endLine === startLine && endCol < startCol && lineDiff === 0) {
|
|
117
|
+
endCol = startCol + colDiff;
|
|
118
|
+
} else if (endLine === startLine && startCol === endCol && lineDiff === 0) {
|
|
119
|
+
// Prevent 0-length ranges
|
|
120
|
+
endCol = startCol + 1;
|
|
121
|
+
}
|
|
122
|
+
} else {
|
|
123
|
+
endLine = startLine;
|
|
124
|
+
endCol = startCol;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
filePath,
|
|
129
|
+
start: {
|
|
130
|
+
line: startLine,
|
|
131
|
+
column: startCol,
|
|
132
|
+
},
|
|
133
|
+
end: {
|
|
134
|
+
line: endLine,
|
|
135
|
+
column: endCol,
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
}
|
package/src/stream.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @flow strict-local
|
|
2
2
|
|
|
3
|
-
import {Readable} from 'stream';
|
|
3
|
+
import {Readable, PassThrough} from 'stream';
|
|
4
4
|
import type {Blob} from '@parcel/types';
|
|
5
5
|
|
|
6
6
|
export function measureStreamLength(stream: Readable): Promise<number> {
|
|
@@ -42,3 +42,33 @@ export function blobToStream(blob: Blob): Readable {
|
|
|
42
42
|
|
|
43
43
|
return readableFromStringOrBuffer(blob);
|
|
44
44
|
}
|
|
45
|
+
|
|
46
|
+
export function streamFromPromise(promise: Promise<Blob>): Readable {
|
|
47
|
+
const stream = new PassThrough();
|
|
48
|
+
promise.then(blob => {
|
|
49
|
+
if (blob instanceof Readable) {
|
|
50
|
+
blob.pipe(stream);
|
|
51
|
+
} else {
|
|
52
|
+
stream.end(blob);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return stream;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function fallbackStream(
|
|
60
|
+
stream: Readable,
|
|
61
|
+
fallback: () => Readable,
|
|
62
|
+
): Readable {
|
|
63
|
+
const res = new PassThrough();
|
|
64
|
+
stream.on('error', err => {
|
|
65
|
+
if (err.code === 'ENOENT') {
|
|
66
|
+
fallback().pipe(res);
|
|
67
|
+
} else {
|
|
68
|
+
res.emit('error', err);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
stream.pipe(res);
|
|
73
|
+
return res;
|
|
74
|
+
}
|