@parcel/utils 2.0.0-beta.3 → 2.0.0-dev.1510
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/lib/index.js +37516 -542
- package/lib/index.js.map +1 -0
- package/package.json +41 -18
- package/src/DefaultMap.js +1 -1
- package/src/PromiseQueue.js +13 -0
- package/src/alternatives.js +21 -6
- package/src/ansi-html.js +1 -1
- package/src/blob.js +1 -0
- package/src/collection.js +35 -3
- package/src/config.js +77 -22
- package/src/debounce.js +1 -1
- package/src/dependency-location.js +5 -5
- package/src/getExisting.js +1 -4
- package/src/getModuleParts.js +23 -0
- package/src/glob.js +26 -3
- package/src/hash.js +49 -0
- package/src/http-server.js +19 -7
- package/src/index.js +25 -10
- package/src/path.js +11 -1
- package/src/prettyDiagnostic.js +90 -40
- package/src/progress-message.js +22 -0
- package/src/replaceBundleReferences.js +49 -25
- package/src/schema.js +20 -19
- package/src/shared-buffer.js +23 -0
- package/src/sourcemap.js +13 -7
- package/src/urlJoin.js +3 -1
- package/test/DefaultMap.test.js +7 -4
- package/test/PromiseQueue.test.js +28 -0
- 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/replaceBundleReferences.test.js +88 -4
- package/test/throttle.test.js +1 -1
- package/test/urlJoin.test.js +11 -0
- package/lib/DefaultMap.js +0 -64
- package/lib/Deferred.js +0 -34
- package/lib/PromiseQueue.js +0 -144
- package/lib/TapStream.js +0 -46
- package/lib/alternatives.js +0 -151
- package/lib/ansi-html.js +0 -32
- package/lib/blob.js +0 -47
- package/lib/bundle-url.js +0 -43
- package/lib/collection.js +0 -51
- package/lib/config.js +0 -159
- 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/generateBuildMetrics.js +0 -156
- package/lib/generateCertificate.js +0 -149
- package/lib/getCertificate.js +0 -19
- package/lib/getExisting.js +0 -31
- package/lib/getRootDir.js +0 -74
- package/lib/glob.js +0 -118
- package/lib/http-server.js +0 -110
- package/lib/is-url.js +0 -27
- package/lib/isDirectoryInside.js +0 -24
- package/lib/md5.js +0 -61
- package/lib/objectHash.js +0 -34
- package/lib/openInBrowser.js +0 -94
- package/lib/parseCSSImport.js +0 -16
- package/lib/path.js +0 -44
- package/lib/prettifyTime.js +0 -10
- package/lib/prettyDiagnostic.js +0 -119
- package/lib/relativeBundlePath.js +0 -38
- package/lib/relativeUrl.js +0 -32
- package/lib/replaceBundleReferences.js +0 -184
- package/lib/schema.js +0 -391
- package/lib/sourcemap.js +0 -155
- package/lib/stream.js +0 -86
- package/lib/throttle.js +0 -16
- package/lib/urlJoin.js +0 -43
- package/src/.babelrc +0 -3
- package/src/md5.js +0 -56
package/src/index.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
// @flow strict-local
|
|
2
2
|
export type * from './config';
|
|
3
|
+
export type * from './Deferred';
|
|
3
4
|
export type * from './generateBuildMetrics';
|
|
5
|
+
export type * from './http-server';
|
|
6
|
+
export type * from './path';
|
|
4
7
|
export type * from './prettyDiagnostic';
|
|
5
8
|
export type * from './schema';
|
|
6
|
-
export type * from './http-server';
|
|
7
9
|
|
|
8
10
|
export {default as countLines} from './countLines';
|
|
9
11
|
export {default as generateBuildMetrics} from './generateBuildMetrics';
|
|
10
12
|
export {default as generateCertificate} from './generateCertificate';
|
|
11
13
|
export {default as getCertificate} from './getCertificate';
|
|
14
|
+
export {default as getModuleParts} from './getModuleParts';
|
|
12
15
|
export {default as getRootDir} from './getRootDir';
|
|
13
16
|
export {default as isDirectoryInside} from './isDirectoryInside';
|
|
14
17
|
export {default as isURL} from './is-url';
|
|
@@ -33,21 +36,32 @@ export {
|
|
|
33
36
|
objectSortedEntries,
|
|
34
37
|
objectSortedEntriesDeep,
|
|
35
38
|
setDifference,
|
|
39
|
+
setEqual,
|
|
40
|
+
setIntersect,
|
|
41
|
+
setUnion,
|
|
36
42
|
} from './collection';
|
|
37
|
-
export {
|
|
43
|
+
export {
|
|
44
|
+
resolveConfig,
|
|
45
|
+
resolveConfigSync,
|
|
46
|
+
loadConfig,
|
|
47
|
+
readConfig,
|
|
48
|
+
} from './config';
|
|
38
49
|
export {DefaultMap, DefaultWeakMap} from './DefaultMap';
|
|
39
50
|
export {makeDeferredWithPromise} from './Deferred';
|
|
40
|
-
export {
|
|
51
|
+
export {getProgressMessage} from './progress-message.js';
|
|
41
52
|
export {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
53
|
+
isGlob,
|
|
54
|
+
isGlobMatch,
|
|
55
|
+
globMatch,
|
|
56
|
+
globSync,
|
|
57
|
+
glob,
|
|
58
|
+
globToRegex,
|
|
59
|
+
} from './glob';
|
|
60
|
+
export {hashStream, hashObject, hashFile} from './hash';
|
|
61
|
+
export {SharedBuffer} from './shared-buffer';
|
|
48
62
|
export {fuzzySearch} from './schema';
|
|
49
63
|
export {createHTTPServer} from './http-server';
|
|
50
|
-
export {
|
|
64
|
+
export {normalizePath, normalizeSeparators, relativePath} from './path';
|
|
51
65
|
export {
|
|
52
66
|
replaceURLReferences,
|
|
53
67
|
replaceInlineReferences,
|
|
@@ -71,3 +85,4 @@ export {
|
|
|
71
85
|
loadSourceMap,
|
|
72
86
|
remapSourceLocation,
|
|
73
87
|
} from './sourcemap';
|
|
88
|
+
export {default as stripAnsi} from 'strip-ansi';
|
package/src/path.js
CHANGED
|
@@ -22,7 +22,12 @@ export function normalizePath(
|
|
|
22
22
|
filePath: FilePath,
|
|
23
23
|
leadingDotSlash: boolean = true,
|
|
24
24
|
): FilePath {
|
|
25
|
-
if (
|
|
25
|
+
if (
|
|
26
|
+
leadingDotSlash &&
|
|
27
|
+
(filePath[0] !== '.' ||
|
|
28
|
+
(filePath[1] !== '.' && filePath[1] !== '/' && filePath[1] !== '\\')) &&
|
|
29
|
+
!path.isAbsolute(filePath)
|
|
30
|
+
) {
|
|
26
31
|
return normalizeSeparators('./' + filePath);
|
|
27
32
|
} else {
|
|
28
33
|
return normalizeSeparators(filePath);
|
|
@@ -34,5 +39,10 @@ export function relativePath(
|
|
|
34
39
|
to: string,
|
|
35
40
|
leadingDotSlash: boolean = true,
|
|
36
41
|
): FilePath {
|
|
42
|
+
// Fast path
|
|
43
|
+
if (to.startsWith(from + '/')) {
|
|
44
|
+
return (leadingDotSlash ? './' : '') + to.slice(from.length + 1);
|
|
45
|
+
}
|
|
46
|
+
|
|
37
47
|
return normalizePath(path.relative(from, to), leadingDotSlash);
|
|
38
48
|
}
|
package/src/prettyDiagnostic.js
CHANGED
|
@@ -3,86 +3,136 @@ import type {Diagnostic} from '@parcel/diagnostic';
|
|
|
3
3
|
import type {PluginOptions} from '@parcel/types';
|
|
4
4
|
|
|
5
5
|
import formatCodeFrame from '@parcel/codeframe';
|
|
6
|
-
import
|
|
7
|
-
import
|
|
6
|
+
import _mdAnsi from '@parcel/markdown-ansi';
|
|
7
|
+
import _chalk from 'chalk';
|
|
8
8
|
import path from 'path';
|
|
9
|
-
|
|
9
|
+
// $FlowFixMe
|
|
10
|
+
import _terminalLink from 'terminal-link';
|
|
11
|
+
|
|
12
|
+
/* eslint-disable import/no-extraneous-dependencies */
|
|
13
|
+
// $FlowFixMe
|
|
14
|
+
import snarkdown from 'snarkdown';
|
|
15
|
+
/* eslint-enable import/no-extraneous-dependencies */
|
|
16
|
+
|
|
17
|
+
export type FormattedCodeFrame = {|
|
|
18
|
+
location: string,
|
|
19
|
+
code: string,
|
|
20
|
+
|};
|
|
10
21
|
|
|
11
22
|
export type AnsiDiagnosticResult = {|
|
|
12
23
|
message: string,
|
|
13
24
|
stack: string,
|
|
25
|
+
/** A formatted string containing all code frames, including their file locations. */
|
|
14
26
|
codeframe: string,
|
|
27
|
+
/** A list of code frames with highlighted code and file locations separately. */
|
|
28
|
+
frames: Array<FormattedCodeFrame>,
|
|
15
29
|
hints: Array<string>,
|
|
30
|
+
documentation: string,
|
|
16
31
|
|};
|
|
17
32
|
|
|
18
33
|
export default async function prettyDiagnostic(
|
|
19
34
|
diagnostic: Diagnostic,
|
|
20
35
|
options?: PluginOptions,
|
|
21
36
|
terminalWidth?: number,
|
|
37
|
+
format: 'ansi' | 'html' = 'ansi',
|
|
22
38
|
): Promise<AnsiDiagnosticResult> {
|
|
23
39
|
let {
|
|
24
40
|
origin,
|
|
25
41
|
message,
|
|
26
42
|
stack,
|
|
27
|
-
|
|
43
|
+
codeFrames,
|
|
28
44
|
hints,
|
|
29
|
-
filePath,
|
|
30
|
-
language,
|
|
31
45
|
skipFormatting,
|
|
46
|
+
documentationURL,
|
|
32
47
|
} = diagnostic;
|
|
33
48
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
49
|
+
const md = format === 'ansi' ? _mdAnsi : snarkdown;
|
|
50
|
+
const terminalLink =
|
|
51
|
+
format === 'ansi'
|
|
52
|
+
? _terminalLink
|
|
53
|
+
: // eslint-disable-next-line no-unused-vars
|
|
54
|
+
(text, url, _) => `<a href="${url}">${text}</a>`;
|
|
55
|
+
const chalk =
|
|
56
|
+
format === 'ansi'
|
|
57
|
+
? _chalk
|
|
58
|
+
: {
|
|
59
|
+
gray: {
|
|
60
|
+
underline: v =>
|
|
61
|
+
`<span style="color: grey; text-decoration: underline;">${v}</span>`,
|
|
62
|
+
},
|
|
63
|
+
};
|
|
37
64
|
|
|
38
65
|
let result = {
|
|
39
66
|
message:
|
|
40
|
-
|
|
41
|
-
(skipFormatting ? message :
|
|
67
|
+
md(`**${origin ?? 'unknown'}**: `) +
|
|
68
|
+
(skipFormatting ? message : md(message)),
|
|
42
69
|
stack: '',
|
|
43
70
|
codeframe: '',
|
|
71
|
+
frames: [],
|
|
44
72
|
hints: [],
|
|
73
|
+
documentation: '',
|
|
45
74
|
};
|
|
46
75
|
|
|
47
|
-
if (
|
|
48
|
-
let
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
76
|
+
if (codeFrames != null) {
|
|
77
|
+
for (let codeFrame of codeFrames) {
|
|
78
|
+
let filePath = codeFrame.filePath;
|
|
79
|
+
if (filePath != null && options && !path.isAbsolute(filePath)) {
|
|
80
|
+
filePath = path.join(options.projectRoot, filePath);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
let highlights = codeFrame.codeHighlights;
|
|
84
|
+
let code = codeFrame.code;
|
|
85
|
+
if (code == null && options && filePath != null) {
|
|
86
|
+
code = await options.inputFS.readFile(filePath, 'utf8');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
let formattedCodeFrame = '';
|
|
90
|
+
if (code != null) {
|
|
91
|
+
formattedCodeFrame = formatCodeFrame(code, highlights, {
|
|
92
|
+
useColor: true,
|
|
93
|
+
syntaxHighlighting: true,
|
|
94
|
+
language:
|
|
95
|
+
// $FlowFixMe sketchy null checks do not matter here...
|
|
96
|
+
codeFrame.language ||
|
|
97
|
+
(filePath != null ? path.extname(filePath).substr(1) : undefined),
|
|
98
|
+
terminalWidth,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
let location;
|
|
103
|
+
if (typeof filePath !== 'string') {
|
|
104
|
+
location = '';
|
|
105
|
+
} else if (highlights.length === 0) {
|
|
106
|
+
location = filePath;
|
|
107
|
+
} else {
|
|
108
|
+
location = `${filePath}:${highlights[0].start.line}:${highlights[0].start.column}`;
|
|
109
|
+
}
|
|
110
|
+
result.codeframe += location ? chalk.gray.underline(location) + '\n' : '';
|
|
111
|
+
result.codeframe += formattedCodeFrame;
|
|
112
|
+
if (codeFrame !== codeFrames[codeFrames.length - 1]) {
|
|
113
|
+
result.codeframe += '\n\n';
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
result.frames.push({
|
|
117
|
+
location,
|
|
118
|
+
code: formattedCodeFrame,
|
|
63
119
|
});
|
|
64
120
|
}
|
|
65
|
-
|
|
66
|
-
result.codeframe +=
|
|
67
|
-
typeof filePath !== 'string'
|
|
68
|
-
? ''
|
|
69
|
-
: chalk.underline(
|
|
70
|
-
`${filePath}:${highlights[0].start.line}:${highlights[0].start.column}\n`,
|
|
71
|
-
);
|
|
72
|
-
result.codeframe += formattedCodeFrame;
|
|
73
|
-
} else if (typeof filePath === 'string') {
|
|
74
|
-
result.codeframe += chalk.underline(filePath);
|
|
75
121
|
}
|
|
76
122
|
|
|
77
123
|
if (stack != null) {
|
|
78
124
|
result.stack = stack;
|
|
79
|
-
} else if (filePath != null && result.codeframe == null) {
|
|
80
|
-
result.stack = filePath;
|
|
81
125
|
}
|
|
82
126
|
|
|
83
127
|
if (Array.isArray(hints) && hints.length) {
|
|
84
128
|
result.hints = hints.map(h => {
|
|
85
|
-
return
|
|
129
|
+
return md(h);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (documentationURL != null) {
|
|
134
|
+
result.documentation = terminalLink('Learn more', documentationURL, {
|
|
135
|
+
fallback: (text, url) => `${text}: ${url}`,
|
|
86
136
|
});
|
|
87
137
|
}
|
|
88
138
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// @flow strict-local
|
|
2
|
+
import type {BuildProgressEvent} from '@parcel/types';
|
|
3
|
+
|
|
4
|
+
import path from 'path';
|
|
5
|
+
|
|
6
|
+
export function getProgressMessage(event: BuildProgressEvent): ?string {
|
|
7
|
+
switch (event.phase) {
|
|
8
|
+
case 'transforming':
|
|
9
|
+
return `Building ${path.basename(event.filePath)}...`;
|
|
10
|
+
|
|
11
|
+
case 'bundling':
|
|
12
|
+
return 'Bundling...';
|
|
13
|
+
|
|
14
|
+
case 'packaging':
|
|
15
|
+
return `Packaging ${event.bundle.displayName}...`;
|
|
16
|
+
|
|
17
|
+
case 'optimizing':
|
|
18
|
+
return `Optimizing ${event.bundle.displayName}...`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
|
|
13
13
|
import {Readable} from 'stream';
|
|
14
14
|
import nullthrows from 'nullthrows';
|
|
15
|
+
import invariant from 'assert';
|
|
15
16
|
import URL from 'url';
|
|
16
17
|
import {bufferStream, relativeBundlePath, urlJoin} from './';
|
|
17
18
|
|
|
@@ -22,7 +23,7 @@ type ReplacementMap = Map<
|
|
|
22
23
|
|
|
23
24
|
/*
|
|
24
25
|
* Replaces references to dependency ids for URL dependencies with:
|
|
25
|
-
* - in the case of an unresolvable url dependency, the original
|
|
26
|
+
* - in the case of an unresolvable url dependency, the original specifier.
|
|
26
27
|
* These are external requests that Parcel did not bundle.
|
|
27
28
|
* - in the case of a reference to another bundle, the relative url to that
|
|
28
29
|
* bundle from the current bundle.
|
|
@@ -32,6 +33,7 @@ export function replaceURLReferences({
|
|
|
32
33
|
bundleGraph,
|
|
33
34
|
contents,
|
|
34
35
|
map,
|
|
36
|
+
getReplacement = s => s,
|
|
35
37
|
relative = true,
|
|
36
38
|
}: {|
|
|
37
39
|
bundle: NamedBundle,
|
|
@@ -39,42 +41,47 @@ export function replaceURLReferences({
|
|
|
39
41
|
contents: string,
|
|
40
42
|
relative?: boolean,
|
|
41
43
|
map?: ?SourceMap,
|
|
44
|
+
getReplacement?: string => string,
|
|
42
45
|
|}): {|+contents: string, +map: ?SourceMap|} {
|
|
43
46
|
let replacements = new Map();
|
|
44
47
|
let urlDependencies = [];
|
|
45
48
|
bundle.traverse(node => {
|
|
46
|
-
if (node.type === 'dependency' && node.value.
|
|
49
|
+
if (node.type === 'dependency' && node.value.specifierType === 'url') {
|
|
47
50
|
urlDependencies.push(node.value);
|
|
48
51
|
}
|
|
49
52
|
});
|
|
50
53
|
|
|
51
54
|
for (let dependency of urlDependencies) {
|
|
52
|
-
if (
|
|
55
|
+
if (dependency.specifierType !== 'url') {
|
|
53
56
|
continue;
|
|
54
57
|
}
|
|
55
58
|
|
|
59
|
+
let placeholder = dependency.meta?.placeholder ?? dependency.id;
|
|
60
|
+
invariant(typeof placeholder === 'string');
|
|
61
|
+
|
|
56
62
|
let resolved = bundleGraph.getReferencedBundle(dependency, bundle);
|
|
57
63
|
if (resolved == null) {
|
|
58
|
-
replacements.set(
|
|
59
|
-
from:
|
|
60
|
-
to: dependency.
|
|
64
|
+
replacements.set(placeholder, {
|
|
65
|
+
from: placeholder,
|
|
66
|
+
to: getReplacement(dependency.specifier),
|
|
61
67
|
});
|
|
62
68
|
continue;
|
|
63
69
|
}
|
|
64
70
|
|
|
65
|
-
if (
|
|
71
|
+
if (resolved.bundleBehavior === 'inline') {
|
|
66
72
|
// If a bundle is inline, it should be replaced with inline contents,
|
|
67
73
|
// not a URL.
|
|
68
74
|
continue;
|
|
69
75
|
}
|
|
70
76
|
|
|
71
77
|
replacements.set(
|
|
72
|
-
|
|
78
|
+
placeholder,
|
|
73
79
|
getURLReplacement({
|
|
74
80
|
dependency,
|
|
75
81
|
fromBundle: bundle,
|
|
76
82
|
toBundle: resolved,
|
|
77
83
|
relative,
|
|
84
|
+
getReplacement,
|
|
78
85
|
}),
|
|
79
86
|
);
|
|
80
87
|
}
|
|
@@ -119,7 +126,7 @@ export async function replaceInlineReferences({
|
|
|
119
126
|
|
|
120
127
|
for (let dependency of dependencies) {
|
|
121
128
|
let entryBundle = bundleGraph.getReferencedBundle(dependency, bundle);
|
|
122
|
-
if (
|
|
129
|
+
if (entryBundle?.bundleBehavior !== 'inline') {
|
|
123
130
|
continue;
|
|
124
131
|
}
|
|
125
132
|
|
|
@@ -127,16 +134,18 @@ export async function replaceInlineReferences({
|
|
|
127
134
|
entryBundle,
|
|
128
135
|
bundleGraph,
|
|
129
136
|
);
|
|
130
|
-
let packagedContents = (
|
|
131
|
-
|
|
132
|
-
|
|
137
|
+
let packagedContents = (
|
|
138
|
+
packagedBundle.contents instanceof Readable
|
|
139
|
+
? await bufferStream(packagedBundle.contents)
|
|
140
|
+
: packagedBundle.contents
|
|
133
141
|
).toString();
|
|
134
142
|
|
|
135
|
-
let inlineType = nullthrows(entryBundle.
|
|
136
|
-
.inlineType;
|
|
143
|
+
let inlineType = nullthrows(entryBundle.getMainEntry()).meta.inlineType;
|
|
137
144
|
if (inlineType == null || inlineType === 'string') {
|
|
145
|
+
let placeholder = dependency.meta?.placeholder ?? dependency.id;
|
|
146
|
+
invariant(typeof placeholder === 'string');
|
|
138
147
|
replacements.set(
|
|
139
|
-
|
|
148
|
+
placeholder,
|
|
140
149
|
getInlineReplacement(dependency, inlineType, packagedContents),
|
|
141
150
|
);
|
|
142
151
|
}
|
|
@@ -150,32 +159,47 @@ export function getURLReplacement({
|
|
|
150
159
|
fromBundle,
|
|
151
160
|
toBundle,
|
|
152
161
|
relative,
|
|
162
|
+
getReplacement,
|
|
153
163
|
}: {|
|
|
154
164
|
dependency: Dependency,
|
|
155
165
|
fromBundle: NamedBundle,
|
|
156
166
|
toBundle: NamedBundle,
|
|
157
167
|
relative: boolean,
|
|
168
|
+
getReplacement?: string => string,
|
|
158
169
|
|}): {|from: string, to: string|} {
|
|
159
170
|
let to;
|
|
160
171
|
|
|
172
|
+
let orig = URL.parse(dependency.specifier);
|
|
173
|
+
|
|
161
174
|
if (relative) {
|
|
162
|
-
to = URL.format(
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
175
|
+
to = URL.format({
|
|
176
|
+
pathname: relativeBundlePath(fromBundle, toBundle, {
|
|
177
|
+
leadingDotSlash: false,
|
|
178
|
+
}),
|
|
179
|
+
hash: orig.hash,
|
|
180
|
+
});
|
|
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
|
+
}
|
|
169
187
|
} else {
|
|
170
188
|
to = urlJoin(
|
|
171
189
|
toBundle.target.publicUrl,
|
|
172
|
-
URL.format(
|
|
190
|
+
URL.format({
|
|
191
|
+
pathname: nullthrows(toBundle.name),
|
|
192
|
+
hash: orig.hash,
|
|
193
|
+
}),
|
|
173
194
|
);
|
|
174
195
|
}
|
|
175
196
|
|
|
197
|
+
let placeholder = dependency.meta?.placeholder ?? dependency.id;
|
|
198
|
+
invariant(typeof placeholder === 'string');
|
|
199
|
+
|
|
176
200
|
return {
|
|
177
|
-
from:
|
|
178
|
-
to,
|
|
201
|
+
from: placeholder,
|
|
202
|
+
to: getReplacement ? getReplacement(to) : to,
|
|
179
203
|
};
|
|
180
204
|
}
|
|
181
205
|
|
package/src/schema.js
CHANGED
|
@@ -4,10 +4,9 @@ import ThrowableDiagnostic, {
|
|
|
4
4
|
escapeMarkdown,
|
|
5
5
|
encodeJSONKeyComponent,
|
|
6
6
|
} from '@parcel/diagnostic';
|
|
7
|
-
import type {Mapping} from 'json-
|
|
7
|
+
import type {Mapping} from '@mischnic/json-sourcemap';
|
|
8
8
|
import nullthrows from 'nullthrows';
|
|
9
|
-
|
|
10
|
-
import levenshtein from 'fastest-levenshtein';
|
|
9
|
+
import * as levenshtein from 'fastest-levenshtein';
|
|
11
10
|
|
|
12
11
|
export type SchemaEntity =
|
|
13
12
|
| SchemaObject
|
|
@@ -378,7 +377,7 @@ export function fuzzySearch(
|
|
|
378
377
|
return result.map(([v]) => v);
|
|
379
378
|
}
|
|
380
379
|
|
|
381
|
-
validateSchema.diagnostic = function(
|
|
380
|
+
validateSchema.diagnostic = function (
|
|
382
381
|
schema: SchemaEntity,
|
|
383
382
|
data: {|
|
|
384
383
|
...
|
|
@@ -406,7 +405,7 @@ validateSchema.diagnostic = function(
|
|
|
406
405
|
!data
|
|
407
406
|
) {
|
|
408
407
|
throw new Error(
|
|
409
|
-
'At least one of data.source and data.
|
|
408
|
+
'At least one of data.source and data.data must be defined!',
|
|
410
409
|
);
|
|
411
410
|
}
|
|
412
411
|
let object = data.map
|
|
@@ -478,25 +477,27 @@ validateSchema.diagnostic = function(
|
|
|
478
477
|
map = data.source ?? JSON.stringify(nullthrows(data.data), 0, '\t');
|
|
479
478
|
code = map;
|
|
480
479
|
}
|
|
481
|
-
let
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
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
|
+
];
|
|
492
495
|
|
|
493
496
|
throw new ThrowableDiagnostic({
|
|
494
497
|
diagnostic: {
|
|
495
498
|
message: message,
|
|
496
499
|
origin,
|
|
497
|
-
|
|
498
|
-
language: 'json',
|
|
499
|
-
codeFrame,
|
|
500
|
+
codeFrames,
|
|
500
501
|
},
|
|
501
502
|
});
|
|
502
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
CHANGED
|
@@ -5,15 +5,18 @@ import SourceMap from '@parcel/source-map';
|
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import {normalizeSeparators, isAbsolute} from './path';
|
|
7
7
|
|
|
8
|
-
export const SOURCEMAP_RE: RegExp =
|
|
8
|
+
export const SOURCEMAP_RE: RegExp =
|
|
9
|
+
/(?:\/\*|\/\/)\s*[@#]\s*sourceMappingURL\s*=\s*([^\s*]+)(?:\s*\*\/)?\s*$/;
|
|
9
10
|
const DATA_URL_RE = /^data:[^;]+(?:;charset=[^;]+)?;base64,(.*)/;
|
|
10
11
|
export const SOURCEMAP_EXTENSIONS: Set<string> = new Set<string>([
|
|
12
|
+
'css',
|
|
13
|
+
'es',
|
|
14
|
+
'es6',
|
|
11
15
|
'js',
|
|
12
16
|
'jsx',
|
|
13
17
|
'mjs',
|
|
14
|
-
'
|
|
15
|
-
'
|
|
16
|
-
'css',
|
|
18
|
+
'ts',
|
|
19
|
+
'tsx',
|
|
17
20
|
]);
|
|
18
21
|
|
|
19
22
|
export function matchSourceMappingURL(
|
|
@@ -91,8 +94,8 @@ export function remapSourceLocation(
|
|
|
91
94
|
} = loc;
|
|
92
95
|
let lineDiff = endLine - startLine;
|
|
93
96
|
let colDiff = endCol - startCol;
|
|
94
|
-
let start = originalMap.findClosestMapping(startLine, startCol);
|
|
95
|
-
let end = originalMap.findClosestMapping(endLine, endCol);
|
|
97
|
+
let start = originalMap.findClosestMapping(startLine, startCol - 1);
|
|
98
|
+
let end = originalMap.findClosestMapping(endLine, endCol - 1);
|
|
96
99
|
|
|
97
100
|
if (start?.original) {
|
|
98
101
|
if (start.source) {
|
|
@@ -105,13 +108,16 @@ export function remapSourceLocation(
|
|
|
105
108
|
|
|
106
109
|
if (end?.original) {
|
|
107
110
|
({line: endLine, column: endCol} = end.original);
|
|
108
|
-
endCol++;
|
|
111
|
+
endCol++; // source map columns are 0-based
|
|
109
112
|
|
|
110
113
|
if (endLine < startLine) {
|
|
111
114
|
endLine = startLine;
|
|
112
115
|
endCol = startCol;
|
|
113
116
|
} else if (endLine === startLine && endCol < startCol && lineDiff === 0) {
|
|
114
117
|
endCol = startCol + colDiff;
|
|
118
|
+
} else if (endLine === startLine && startCol === endCol && lineDiff === 0) {
|
|
119
|
+
// Prevent 0-length ranges
|
|
120
|
+
endCol = startCol + 1;
|
|
115
121
|
}
|
|
116
122
|
} else {
|
|
117
123
|
endLine = startLine;
|
package/src/urlJoin.js
CHANGED
|
@@ -9,7 +9,9 @@ import path from 'path';
|
|
|
9
9
|
*/
|
|
10
10
|
export default function urlJoin(publicURL: string, assetPath: string): string {
|
|
11
11
|
const url = URL.parse(publicURL, false, true);
|
|
12
|
-
|
|
12
|
+
// Leading / ensures that paths with colons are not parsed as a protocol.
|
|
13
|
+
let p = assetPath.startsWith('/') ? assetPath : '/' + assetPath;
|
|
14
|
+
const assetUrl = URL.parse(p);
|
|
13
15
|
url.pathname = path.posix.join(url.pathname, assetUrl.pathname);
|
|
14
16
|
url.search = assetUrl.search;
|
|
15
17
|
url.hash = assetUrl.hash;
|
package/test/DefaultMap.test.js
CHANGED
|
@@ -5,10 +5,13 @@ import {DefaultMap} from '../src/DefaultMap';
|
|
|
5
5
|
|
|
6
6
|
describe('DefaultMap', () => {
|
|
7
7
|
it('constructs with entries just like Map', () => {
|
|
8
|
-
let map = new DefaultMap(
|
|
9
|
-
|
|
10
|
-
[
|
|
11
|
-
|
|
8
|
+
let map = new DefaultMap(
|
|
9
|
+
k => k,
|
|
10
|
+
[
|
|
11
|
+
[1, 3],
|
|
12
|
+
[2, 27],
|
|
13
|
+
],
|
|
14
|
+
);
|
|
12
15
|
assert.equal(map.get(1), 3);
|
|
13
16
|
assert.deepEqual(Array.from(map.entries()), [
|
|
14
17
|
[1, 3],
|
|
@@ -3,6 +3,7 @@ import assert from 'assert';
|
|
|
3
3
|
import randomInt from 'random-int';
|
|
4
4
|
|
|
5
5
|
import PromiseQueue from '../src/PromiseQueue';
|
|
6
|
+
import sinon from 'sinon';
|
|
6
7
|
|
|
7
8
|
describe('PromiseQueue', () => {
|
|
8
9
|
it('run() should resolve when all async functions in queue have completed', async () => {
|
|
@@ -72,4 +73,31 @@ describe('PromiseQueue', () => {
|
|
|
72
73
|
|
|
73
74
|
await queue.run();
|
|
74
75
|
});
|
|
76
|
+
|
|
77
|
+
it('.add() should notify subscribers', async () => {
|
|
78
|
+
const queue = new PromiseQueue();
|
|
79
|
+
|
|
80
|
+
const subscribedFn = sinon.spy();
|
|
81
|
+
queue.subscribeToAdd(subscribedFn);
|
|
82
|
+
|
|
83
|
+
const promise = queue.add(() => Promise.resolve());
|
|
84
|
+
await queue.run();
|
|
85
|
+
await promise;
|
|
86
|
+
|
|
87
|
+
assert(subscribedFn.called);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('.subscribeToAdd() should allow unsubscribing', async () => {
|
|
91
|
+
const queue = new PromiseQueue();
|
|
92
|
+
|
|
93
|
+
const subscribedFn = sinon.spy();
|
|
94
|
+
const unsubscribe = queue.subscribeToAdd(subscribedFn);
|
|
95
|
+
unsubscribe();
|
|
96
|
+
|
|
97
|
+
const promise = queue.add(() => Promise.resolve());
|
|
98
|
+
await queue.run();
|
|
99
|
+
await promise;
|
|
100
|
+
|
|
101
|
+
assert(!subscribedFn.called);
|
|
102
|
+
});
|
|
75
103
|
});
|