@parcel/utils 2.0.0-beta.1 → 2.0.0-nightly.1002
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 +35850 -337
- package/lib/index.js.map +1 -0
- package/package.json +42 -20
- package/src/DefaultMap.js +1 -1
- package/src/PromiseQueue.js +16 -12
- package/src/alternatives.js +143 -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 +14 -14
- package/src/config.js +93 -53
- package/src/countLines.js +5 -2
- package/src/debounce.js +1 -1
- package/src/dependency-location.js +11 -6
- package/src/generateBuildMetrics.js +5 -5
- package/src/generateCertificate.js +1 -1
- package/src/getCertificate.js +1 -1
- package/src/getExisting.js +1 -4
- package/src/getRootDir.js +1 -2
- package/src/glob.js +36 -5
- package/src/hash.js +34 -0
- package/src/http-server.js +4 -11
- package/src/index.js +47 -20
- package/src/is-url.js +1 -1
- package/src/isDirectoryInside.js +4 -1
- package/src/openInBrowser.js +3 -1
- package/src/path.js +17 -2
- package/src/prettyDiagnostic.js +39 -27
- package/src/relativeBundlePath.js +5 -7
- package/src/replaceBundleReferences.js +50 -34
- package/src/schema.js +96 -42
- package/src/shared-buffer.js +24 -0
- package/src/sourcemap.js +84 -10
- package/src/urlJoin.js +3 -1
- package/test/DefaultMap.test.js +7 -4
- package/test/config.test.js +50 -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 +1 -1
- package/test/replaceBundleReferences.test.js +268 -0
- package/test/sourcemap.test.js +5 -9
- 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 -38
- 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 -109
- 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/escape-markdown.js +0 -15
- package/lib/generateBuildMetrics.js +0 -124
- 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 -69
- package/lib/http-server.js +0 -81
- package/lib/is-url.js +0 -17
- package/lib/isDirectoryInside.js +0 -16
- package/lib/md5.js +0 -40
- package/lib/objectHash.js +0 -26
- package/lib/openInBrowser.js +0 -70
- package/lib/parseCSSImport.js +0 -16
- package/lib/path.js +0 -30
- package/lib/prettifyTime.js +0 -10
- package/lib/prettyDiagnostic.js +0 -75
- package/lib/promisify.js +0 -13
- package/lib/relativeBundlePath.js +0 -18
- package/lib/relativeUrl.js +0 -16
- package/lib/replaceBundleReferences.js +0 -166
- package/lib/resolve.js +0 -108
- package/lib/schema.js +0 -321
- package/lib/serializeObject.js +0 -28
- package/lib/sourcemap.js +0 -58
- package/lib/stream.js +0 -78
- package/lib/throttle.js +0 -16
- package/lib/urlJoin.js +0 -27
- package/src/.babelrc +0 -3
- package/src/escape-markdown.js +0 -10
- package/src/md5.js +0 -49
- package/src/promisify.js +0 -13
- package/src/resolve.js +0 -216
- package/src/serializeObject.js +0 -22
- package/test/escapeMarkdown.test.js +0 -29
package/src/getCertificate.js
CHANGED
|
@@ -5,7 +5,7 @@ import type {FileSystem} from '@parcel/fs';
|
|
|
5
5
|
export default async function getCertificate(
|
|
6
6
|
fs: FileSystem,
|
|
7
7
|
options: HTTPSOptions,
|
|
8
|
-
) {
|
|
8
|
+
): Promise<{|cert: Buffer, key: Buffer|}> {
|
|
9
9
|
try {
|
|
10
10
|
let cert = await fs.readFile(options.cert);
|
|
11
11
|
let key = await fs.readFile(options.key);
|
package/src/getExisting.js
CHANGED
|
@@ -14,10 +14,7 @@ export default function getExisting(
|
|
|
14
14
|
return {
|
|
15
15
|
source,
|
|
16
16
|
minified: fs.existsSync(minifiedPath)
|
|
17
|
-
? fs
|
|
18
|
-
.readFileSync(minifiedPath, 'utf8')
|
|
19
|
-
.trim()
|
|
20
|
-
.replace(/;$/, '')
|
|
17
|
+
? fs.readFileSync(minifiedPath, 'utf8').trim().replace(/;$/, '')
|
|
21
18
|
: source,
|
|
22
19
|
};
|
|
23
20
|
}
|
package/src/getRootDir.js
CHANGED
package/src/glob.js
CHANGED
|
@@ -5,21 +5,52 @@ import type {FileSystem} from '@parcel/fs';
|
|
|
5
5
|
|
|
6
6
|
import _isGlob from 'is-glob';
|
|
7
7
|
import fastGlob, {type FastGlobOptions} from 'fast-glob';
|
|
8
|
-
import {isMatch} from 'micromatch';
|
|
8
|
+
import {isMatch, makeRe, type Options} from 'micromatch';
|
|
9
9
|
import {normalizeSeparators} from './path';
|
|
10
10
|
|
|
11
|
-
export function isGlob(p: FilePath) {
|
|
11
|
+
export function isGlob(p: FilePath): any {
|
|
12
12
|
return _isGlob(normalizeSeparators(p));
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
export function isGlobMatch(
|
|
16
|
-
|
|
15
|
+
export function isGlobMatch(
|
|
16
|
+
filePath: FilePath,
|
|
17
|
+
glob: Glob | Array<Glob>,
|
|
18
|
+
opts?: Options,
|
|
19
|
+
): any {
|
|
20
|
+
glob = Array.isArray(glob)
|
|
21
|
+
? glob.map(normalizeSeparators)
|
|
22
|
+
: normalizeSeparators(glob);
|
|
23
|
+
return isMatch(filePath, glob, opts);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function globToRegex(glob: Glob, opts?: Options): RegExp {
|
|
27
|
+
return makeRe(glob, opts);
|
|
17
28
|
}
|
|
18
29
|
|
|
19
30
|
export function globSync(
|
|
20
31
|
p: FilePath,
|
|
21
|
-
|
|
32
|
+
fs: FileSystem,
|
|
33
|
+
options?: FastGlobOptions<FilePath>,
|
|
22
34
|
): Array<FilePath> {
|
|
35
|
+
// $FlowFixMe
|
|
36
|
+
options = {
|
|
37
|
+
...options,
|
|
38
|
+
fs: {
|
|
39
|
+
statSync: p => {
|
|
40
|
+
return fs.statSync(p);
|
|
41
|
+
},
|
|
42
|
+
lstatSync: p => {
|
|
43
|
+
// Our FileSystem interface doesn't have lstat support at the moment,
|
|
44
|
+
// but this is fine for our purposes since we follow symlinks by default.
|
|
45
|
+
return fs.statSync(p);
|
|
46
|
+
},
|
|
47
|
+
readdirSync: (p, opts) => {
|
|
48
|
+
return fs.readdirSync(p, opts);
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// $FlowFixMe
|
|
23
54
|
return fastGlob.sync(normalizeSeparators(p), options);
|
|
24
55
|
}
|
|
25
56
|
|
package/src/hash.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// @flow strict-local
|
|
2
|
+
|
|
3
|
+
import type {Readable} from 'stream';
|
|
4
|
+
import type {FileSystem} from '@parcel/fs';
|
|
5
|
+
|
|
6
|
+
import {objectSortedEntriesDeep} from './collection';
|
|
7
|
+
import {hashString, Hash} from '@parcel/hash';
|
|
8
|
+
|
|
9
|
+
export function hashStream(stream: Readable): Promise<string> {
|
|
10
|
+
let hash = new Hash();
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
stream.on('error', err => {
|
|
13
|
+
reject(err);
|
|
14
|
+
});
|
|
15
|
+
stream
|
|
16
|
+
.on('data', chunk => {
|
|
17
|
+
hash.writeBuffer(chunk);
|
|
18
|
+
})
|
|
19
|
+
.on('end', function () {
|
|
20
|
+
resolve(hash.finish());
|
|
21
|
+
})
|
|
22
|
+
.on('error', err => {
|
|
23
|
+
reject(err);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function hashObject(obj: {+[string]: mixed, ...}): string {
|
|
29
|
+
return hashString(JSON.stringify(objectSortedEntriesDeep(obj)));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function hashFile(fs: FileSystem, filePath: string): Promise<string> {
|
|
33
|
+
return hashStream(fs.createReadStream(filePath));
|
|
34
|
+
}
|
package/src/http-server.js
CHANGED
|
@@ -7,10 +7,9 @@ import type {FilePath, HTTPSOptions} from '@parcel/types';
|
|
|
7
7
|
import type {FileSystem} from '@parcel/fs';
|
|
8
8
|
|
|
9
9
|
import http from 'http';
|
|
10
|
-
|
|
11
|
-
import {createSecureServer} from 'http2';
|
|
10
|
+
import https from 'https';
|
|
12
11
|
import nullthrows from 'nullthrows';
|
|
13
|
-
import {getCertificate, generateCertificate} from '
|
|
12
|
+
import {getCertificate, generateCertificate} from './';
|
|
14
13
|
|
|
15
14
|
type CreateHTTPServerOpts = {|
|
|
16
15
|
https: ?(HTTPSOptions | boolean),
|
|
@@ -41,17 +40,11 @@ export async function createHTTPServer(
|
|
|
41
40
|
options.host,
|
|
42
41
|
);
|
|
43
42
|
|
|
44
|
-
server =
|
|
45
|
-
{cert, key, allowHTTP1: true},
|
|
46
|
-
options.listener,
|
|
47
|
-
);
|
|
43
|
+
server = https.createServer({cert, key}, options.listener);
|
|
48
44
|
} else {
|
|
49
45
|
let {cert, key} = await getCertificate(options.inputFS, options.https);
|
|
50
46
|
|
|
51
|
-
server =
|
|
52
|
-
{cert, key, allowHTTP1: true},
|
|
53
|
-
options.listener,
|
|
54
|
-
);
|
|
47
|
+
server = https.createServer({cert, key}, options.listener);
|
|
55
48
|
}
|
|
56
49
|
|
|
57
50
|
// HTTPServer#close only stops accepting new connections, and does not close existing ones.
|
package/src/index.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
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';
|
|
8
|
+
export type * from './schema';
|
|
5
9
|
|
|
6
10
|
export {default as countLines} from './countLines';
|
|
7
11
|
export {default as generateBuildMetrics} from './generateBuildMetrics';
|
|
@@ -14,8 +18,6 @@ export {default as objectHash} from './objectHash';
|
|
|
14
18
|
export {default as prettifyTime} from './prettifyTime';
|
|
15
19
|
export {default as prettyDiagnostic} from './prettyDiagnostic';
|
|
16
20
|
export {default as PromiseQueue} from './PromiseQueue';
|
|
17
|
-
// flowlint-next-line untyped-import:off
|
|
18
|
-
export {default as promisify} from './promisify';
|
|
19
21
|
export {default as validateSchema} from './schema';
|
|
20
22
|
export {default as TapStream} from './TapStream';
|
|
21
23
|
export {default as urlJoin} from './urlJoin';
|
|
@@ -25,21 +27,46 @@ export {default as debounce} from './debounce';
|
|
|
25
27
|
export {default as throttle} from './throttle';
|
|
26
28
|
export {default as openInBrowser} from './openInBrowser';
|
|
27
29
|
|
|
28
|
-
export *
|
|
29
|
-
export
|
|
30
|
-
export
|
|
31
|
-
export
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
export
|
|
40
|
-
export
|
|
41
|
-
export
|
|
42
|
-
export
|
|
43
|
-
export
|
|
44
|
-
export
|
|
45
|
-
export
|
|
30
|
+
// Explicit re-exports instead of export * for lazy require performance
|
|
31
|
+
export {findAlternativeNodeModules, findAlternativeFiles} from './alternatives';
|
|
32
|
+
export {blobToBuffer, blobToString} from './blob';
|
|
33
|
+
export {
|
|
34
|
+
unique,
|
|
35
|
+
objectSortedEntries,
|
|
36
|
+
objectSortedEntriesDeep,
|
|
37
|
+
setDifference,
|
|
38
|
+
setIntersect,
|
|
39
|
+
setUnion,
|
|
40
|
+
} from './collection';
|
|
41
|
+
export {resolveConfig, resolveConfigSync, loadConfig} from './config';
|
|
42
|
+
export {DefaultMap, DefaultWeakMap} from './DefaultMap';
|
|
43
|
+
export {makeDeferredWithPromise} from './Deferred';
|
|
44
|
+
export {isGlob, isGlobMatch, globSync, glob, globToRegex} from './glob';
|
|
45
|
+
export {hashStream, hashObject, hashFile} from './hash';
|
|
46
|
+
export {SharedBuffer} from './shared-buffer';
|
|
47
|
+
export {fuzzySearch} from './schema';
|
|
48
|
+
export {createHTTPServer} from './http-server';
|
|
49
|
+
export {normalizePath, normalizeSeparators, relativePath} from './path';
|
|
50
|
+
export {
|
|
51
|
+
replaceURLReferences,
|
|
52
|
+
replaceInlineReferences,
|
|
53
|
+
} from './replaceBundleReferences';
|
|
54
|
+
export {
|
|
55
|
+
measureStreamLength,
|
|
56
|
+
readableFromStringOrBuffer,
|
|
57
|
+
bufferStream,
|
|
58
|
+
blobToStream,
|
|
59
|
+
streamFromPromise,
|
|
60
|
+
fallbackStream,
|
|
61
|
+
} from './stream';
|
|
62
|
+
export {relativeBundlePath} from './relativeBundlePath';
|
|
63
|
+
export {ansiHtml} from './ansi-html';
|
|
64
|
+
export {escapeHTML} from './escape-html';
|
|
65
|
+
export {
|
|
66
|
+
SOURCEMAP_RE,
|
|
67
|
+
SOURCEMAP_EXTENSIONS,
|
|
68
|
+
matchSourceMappingURL,
|
|
69
|
+
loadSourceMapUrl,
|
|
70
|
+
loadSourceMap,
|
|
71
|
+
remapSourceLocation,
|
|
72
|
+
} from './sourcemap';
|
package/src/is-url.js
CHANGED
package/src/isDirectoryInside.js
CHANGED
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
import type {FilePath} from '@parcel/types';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
|
|
5
|
-
export default function isDirectoryInside(
|
|
5
|
+
export default function isDirectoryInside(
|
|
6
|
+
child: FilePath,
|
|
7
|
+
parent: FilePath,
|
|
8
|
+
): boolean {
|
|
6
9
|
const relative = path.relative(parent, child);
|
|
7
10
|
return !relative.startsWith('..') && !path.isAbsolute(relative);
|
|
8
11
|
}
|
package/src/openInBrowser.js
CHANGED
|
@@ -49,7 +49,9 @@ function getAppName(appName: string): string {
|
|
|
49
49
|
export default async function openInBrowser(url: string, browser: string) {
|
|
50
50
|
try {
|
|
51
51
|
const options =
|
|
52
|
-
typeof browser === 'string'
|
|
52
|
+
typeof browser === 'string' && browser.length > 0
|
|
53
|
+
? {app: [getAppName(browser)]}
|
|
54
|
+
: undefined;
|
|
53
55
|
|
|
54
56
|
await open(url, options);
|
|
55
57
|
} catch (err) {
|
package/src/path.js
CHANGED
|
@@ -2,8 +2,13 @@
|
|
|
2
2
|
import type {FilePath} from '@parcel/types';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
|
|
5
|
+
const ABSOLUTE_PATH_REGEX = /^([a-zA-Z]:){0,1}[\\/]+/;
|
|
5
6
|
const SEPARATOR_REGEX = /[\\]+/g;
|
|
6
7
|
|
|
8
|
+
export function isAbsolute(filepath: string): boolean {
|
|
9
|
+
return ABSOLUTE_PATH_REGEX.test(filepath);
|
|
10
|
+
}
|
|
11
|
+
|
|
7
12
|
export function normalizeSeparators(filePath: FilePath): FilePath {
|
|
8
13
|
return filePath.replace(SEPARATOR_REGEX, '/');
|
|
9
14
|
}
|
|
@@ -17,7 +22,12 @@ export function normalizePath(
|
|
|
17
22
|
filePath: FilePath,
|
|
18
23
|
leadingDotSlash: boolean = true,
|
|
19
24
|
): FilePath {
|
|
20
|
-
if (
|
|
25
|
+
if (
|
|
26
|
+
leadingDotSlash &&
|
|
27
|
+
(filePath[0] !== '.' ||
|
|
28
|
+
(filePath[1] !== '.' && filePath[1] !== '/' && filePath[1] !== '\\')) &&
|
|
29
|
+
!path.isAbsolute(filePath)
|
|
30
|
+
) {
|
|
21
31
|
return normalizeSeparators('./' + filePath);
|
|
22
32
|
} else {
|
|
23
33
|
return normalizeSeparators(filePath);
|
|
@@ -28,6 +38,11 @@ export function relativePath(
|
|
|
28
38
|
from: string,
|
|
29
39
|
to: string,
|
|
30
40
|
leadingDotSlash: boolean = true,
|
|
31
|
-
) {
|
|
41
|
+
): FilePath {
|
|
42
|
+
// Fast path
|
|
43
|
+
if (to.startsWith(from + '/')) {
|
|
44
|
+
return (leadingDotSlash ? './' : '') + to.slice(from.length + 1);
|
|
45
|
+
}
|
|
46
|
+
|
|
32
47
|
return normalizePath(path.relative(from, to), leadingDotSlash);
|
|
33
48
|
}
|
package/src/prettyDiagnostic.js
CHANGED
|
@@ -7,12 +7,15 @@ import mdAnsi from '@parcel/markdown-ansi';
|
|
|
7
7
|
import chalk from 'chalk';
|
|
8
8
|
import path from 'path';
|
|
9
9
|
import nullthrows from 'nullthrows';
|
|
10
|
+
// $FlowFixMe
|
|
11
|
+
import terminalLink from 'terminal-link';
|
|
10
12
|
|
|
11
13
|
export type AnsiDiagnosticResult = {|
|
|
12
14
|
message: string,
|
|
13
15
|
stack: string,
|
|
14
16
|
codeframe: string,
|
|
15
17
|
hints: Array<string>,
|
|
18
|
+
documentation: string,
|
|
16
19
|
|};
|
|
17
20
|
|
|
18
21
|
export default async function prettyDiagnostic(
|
|
@@ -24,17 +27,12 @@ export default async function prettyDiagnostic(
|
|
|
24
27
|
origin,
|
|
25
28
|
message,
|
|
26
29
|
stack,
|
|
27
|
-
|
|
30
|
+
codeFrames,
|
|
28
31
|
hints,
|
|
29
|
-
filePath,
|
|
30
|
-
language,
|
|
31
32
|
skipFormatting,
|
|
33
|
+
documentationURL,
|
|
32
34
|
} = diagnostic;
|
|
33
35
|
|
|
34
|
-
if (filePath != null && options && !path.isAbsolute(filePath)) {
|
|
35
|
-
filePath = path.join(options.projectRoot, filePath);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
36
|
let result = {
|
|
39
37
|
message:
|
|
40
38
|
mdAnsi(`**${origin ?? 'unknown'}**: `) +
|
|
@@ -42,42 +40,50 @@ export default async function prettyDiagnostic(
|
|
|
42
40
|
stack: '',
|
|
43
41
|
codeframe: '',
|
|
44
42
|
hints: [],
|
|
43
|
+
documentation: '',
|
|
45
44
|
};
|
|
46
45
|
|
|
47
|
-
if (
|
|
48
|
-
let
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
if (codeFrames != null) {
|
|
47
|
+
for (let codeFrame of codeFrames) {
|
|
48
|
+
let filePath = codeFrame.filePath;
|
|
49
|
+
if (filePath != null && options && !path.isAbsolute(filePath)) {
|
|
50
|
+
filePath = path.join(options.projectRoot, filePath);
|
|
51
|
+
}
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
(
|
|
53
|
+
let highlights = codeFrame.codeHighlights;
|
|
54
|
+
let code =
|
|
55
|
+
codeFrame.code ??
|
|
56
|
+
(options &&
|
|
57
|
+
(await options.inputFS.readFile(nullthrows(filePath), 'utf8')));
|
|
56
58
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
59
|
+
let formattedCodeFrame = '';
|
|
60
|
+
if (code != null) {
|
|
61
|
+
formattedCodeFrame = formatCodeFrame(code, highlights, {
|
|
62
|
+
useColor: true,
|
|
63
|
+
syntaxHighlighting: true,
|
|
64
|
+
language:
|
|
65
|
+
// $FlowFixMe sketchy null checks do not matter here...
|
|
66
|
+
codeFrame.language ||
|
|
67
|
+
(filePath != null ? path.extname(filePath).substr(1) : undefined),
|
|
68
|
+
terminalWidth,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
66
71
|
|
|
67
72
|
result.codeframe +=
|
|
68
73
|
typeof filePath !== 'string'
|
|
69
74
|
? ''
|
|
70
|
-
: chalk.underline(
|
|
75
|
+
: chalk.gray.underline(
|
|
71
76
|
`${filePath}:${highlights[0].start.line}:${highlights[0].start.column}\n`,
|
|
72
77
|
);
|
|
73
78
|
result.codeframe += formattedCodeFrame;
|
|
79
|
+
if (codeFrame !== codeFrames[codeFrames.length - 1]) {
|
|
80
|
+
result.codeframe += '\n\n';
|
|
81
|
+
}
|
|
74
82
|
}
|
|
75
83
|
}
|
|
76
84
|
|
|
77
85
|
if (stack != null) {
|
|
78
86
|
result.stack = stack;
|
|
79
|
-
} else if (filePath != null && result.codeframe == null) {
|
|
80
|
-
result.stack = filePath;
|
|
81
87
|
}
|
|
82
88
|
|
|
83
89
|
if (Array.isArray(hints) && hints.length) {
|
|
@@ -86,5 +92,11 @@ export default async function prettyDiagnostic(
|
|
|
86
92
|
});
|
|
87
93
|
}
|
|
88
94
|
|
|
95
|
+
if (documentationURL != null) {
|
|
96
|
+
result.documentation = terminalLink('Learn more', documentationURL, {
|
|
97
|
+
fallback: (text, url) => `${text}: ${url}`,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
89
101
|
return result;
|
|
90
102
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @flow strict-local
|
|
2
2
|
|
|
3
|
-
import type {NamedBundle} from '@parcel/types';
|
|
3
|
+
import type {FilePath, NamedBundle} from '@parcel/types';
|
|
4
4
|
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import {relativePath} from './path';
|
|
@@ -9,10 +9,8 @@ export function relativeBundlePath(
|
|
|
9
9
|
from: NamedBundle,
|
|
10
10
|
to: NamedBundle,
|
|
11
11
|
opts: {|leadingDotSlash: boolean|} = {leadingDotSlash: true},
|
|
12
|
-
) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
opts.leadingDotSlash,
|
|
17
|
-
);
|
|
12
|
+
): FilePath {
|
|
13
|
+
let fromPath = path.join(from.target.distDir, from.name);
|
|
14
|
+
let toPath = path.join(to.target.distDir, to.name);
|
|
15
|
+
return relativePath(path.dirname(fromPath), toPath, opts.leadingDotSlash);
|
|
18
16
|
}
|
|
@@ -10,11 +10,11 @@ import type {
|
|
|
10
10
|
NamedBundle,
|
|
11
11
|
} from '@parcel/types';
|
|
12
12
|
|
|
13
|
-
import invariant from 'assert';
|
|
14
13
|
import {Readable} from 'stream';
|
|
15
14
|
import nullthrows from 'nullthrows';
|
|
15
|
+
import invariant from 'assert';
|
|
16
16
|
import URL from 'url';
|
|
17
|
-
import {bufferStream, relativeBundlePath, urlJoin} from '
|
|
17
|
+
import {bufferStream, relativeBundlePath, urlJoin} from './';
|
|
18
18
|
|
|
19
19
|
type ReplacementMap = Map<
|
|
20
20
|
string /* dependency id */,
|
|
@@ -23,7 +23,7 @@ type ReplacementMap = Map<
|
|
|
23
23
|
|
|
24
24
|
/*
|
|
25
25
|
* Replaces references to dependency ids for URL dependencies with:
|
|
26
|
-
* - in the case of an unresolvable url dependency, the original
|
|
26
|
+
* - in the case of an unresolvable url dependency, the original specifier.
|
|
27
27
|
* These are external requests that Parcel did not bundle.
|
|
28
28
|
* - in the case of a reference to another bundle, the relative url to that
|
|
29
29
|
* bundle from the current bundle.
|
|
@@ -44,39 +44,40 @@ export function replaceURLReferences({
|
|
|
44
44
|
let replacements = new Map();
|
|
45
45
|
let urlDependencies = [];
|
|
46
46
|
bundle.traverse(node => {
|
|
47
|
-
if (node.type === 'dependency' && node.value.
|
|
47
|
+
if (node.type === 'dependency' && node.value.specifierType === 'url') {
|
|
48
48
|
urlDependencies.push(node.value);
|
|
49
49
|
}
|
|
50
50
|
});
|
|
51
51
|
|
|
52
52
|
for (let dependency of urlDependencies) {
|
|
53
|
-
if (
|
|
53
|
+
if (dependency.specifierType !== 'url') {
|
|
54
54
|
continue;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
let
|
|
57
|
+
let placeholder = dependency.meta?.placeholder ?? dependency.id;
|
|
58
|
+
invariant(typeof placeholder === 'string');
|
|
59
|
+
|
|
60
|
+
let resolved = bundleGraph.getReferencedBundle(dependency, bundle);
|
|
58
61
|
if (resolved == null) {
|
|
59
|
-
replacements.set(
|
|
60
|
-
from:
|
|
61
|
-
to: dependency.
|
|
62
|
+
replacements.set(placeholder, {
|
|
63
|
+
from: placeholder,
|
|
64
|
+
to: dependency.specifier,
|
|
62
65
|
});
|
|
63
66
|
continue;
|
|
64
67
|
}
|
|
65
68
|
|
|
66
|
-
|
|
67
|
-
let entryBundle = bundleGraph.getBundlesInBundleGroup(resolved.value).pop();
|
|
68
|
-
if (entryBundle.isInline) {
|
|
69
|
+
if (resolved.bundleBehavior === 'inline') {
|
|
69
70
|
// If a bundle is inline, it should be replaced with inline contents,
|
|
70
71
|
// not a URL.
|
|
71
72
|
continue;
|
|
72
73
|
}
|
|
73
74
|
|
|
74
75
|
replacements.set(
|
|
75
|
-
|
|
76
|
+
placeholder,
|
|
76
77
|
getURLReplacement({
|
|
77
78
|
dependency,
|
|
78
79
|
fromBundle: bundle,
|
|
79
|
-
toBundle:
|
|
80
|
+
toBundle: resolved,
|
|
80
81
|
relative,
|
|
81
82
|
}),
|
|
82
83
|
);
|
|
@@ -121,13 +122,8 @@ export async function replaceInlineReferences({
|
|
|
121
122
|
});
|
|
122
123
|
|
|
123
124
|
for (let dependency of dependencies) {
|
|
124
|
-
let
|
|
125
|
-
if (
|
|
126
|
-
continue;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
let [entryBundle] = bundleGraph.getBundlesInBundleGroup(resolved.value);
|
|
130
|
-
if (!entryBundle.isInline) {
|
|
125
|
+
let entryBundle = bundleGraph.getReferencedBundle(dependency, bundle);
|
|
126
|
+
if (entryBundle?.bundleBehavior !== 'inline') {
|
|
131
127
|
continue;
|
|
132
128
|
}
|
|
133
129
|
|
|
@@ -135,15 +131,18 @@ export async function replaceInlineReferences({
|
|
|
135
131
|
entryBundle,
|
|
136
132
|
bundleGraph,
|
|
137
133
|
);
|
|
138
|
-
let packagedContents = (
|
|
139
|
-
|
|
140
|
-
|
|
134
|
+
let packagedContents = (
|
|
135
|
+
packagedBundle.contents instanceof Readable
|
|
136
|
+
? await bufferStream(packagedBundle.contents)
|
|
137
|
+
: packagedBundle.contents
|
|
141
138
|
).toString();
|
|
142
139
|
|
|
143
140
|
let inlineType = nullthrows(entryBundle.getMainEntry()).meta.inlineType;
|
|
144
141
|
if (inlineType == null || inlineType === 'string') {
|
|
142
|
+
let placeholder = dependency.meta?.placeholder ?? dependency.id;
|
|
143
|
+
invariant(typeof placeholder === 'string');
|
|
145
144
|
replacements.set(
|
|
146
|
-
|
|
145
|
+
placeholder,
|
|
147
146
|
getInlineReplacement(dependency, inlineType, packagedContents),
|
|
148
147
|
);
|
|
149
148
|
}
|
|
@@ -152,7 +151,7 @@ export async function replaceInlineReferences({
|
|
|
152
151
|
return performReplacement(replacements, contents, map);
|
|
153
152
|
}
|
|
154
153
|
|
|
155
|
-
function getURLReplacement({
|
|
154
|
+
export function getURLReplacement({
|
|
156
155
|
dependency,
|
|
157
156
|
fromBundle,
|
|
158
157
|
toBundle,
|
|
@@ -162,21 +161,38 @@ function getURLReplacement({
|
|
|
162
161
|
fromBundle: NamedBundle,
|
|
163
162
|
toBundle: NamedBundle,
|
|
164
163
|
relative: boolean,
|
|
165
|
-
|}) {
|
|
166
|
-
let url = URL.parse(dependency.moduleSpecifier);
|
|
164
|
+
|}): {|from: string, to: string|} {
|
|
167
165
|
let to;
|
|
166
|
+
|
|
167
|
+
let orig = URL.parse(dependency.specifier);
|
|
168
|
+
|
|
168
169
|
if (relative) {
|
|
169
|
-
|
|
170
|
-
|
|
170
|
+
to = URL.format({
|
|
171
|
+
pathname: relativeBundlePath(fromBundle, toBundle, {
|
|
172
|
+
leadingDotSlash: false,
|
|
173
|
+
}),
|
|
174
|
+
hash: orig.hash,
|
|
171
175
|
});
|
|
172
|
-
|
|
176
|
+
|
|
177
|
+
// If the resulting path includes a colon character and doesn't start with a ./ or ../
|
|
178
|
+
// we need to add one so that the first part before the colon isn't parsed as a URL protocol.
|
|
179
|
+
if (to.includes(':') && !to.startsWith('./') && !to.startsWith('../')) {
|
|
180
|
+
to = './' + to;
|
|
181
|
+
}
|
|
173
182
|
} else {
|
|
174
|
-
|
|
175
|
-
|
|
183
|
+
to = urlJoin(
|
|
184
|
+
toBundle.target.publicUrl,
|
|
185
|
+
URL.format({
|
|
186
|
+
pathname: nullthrows(toBundle.name),
|
|
187
|
+
hash: orig.hash,
|
|
188
|
+
}),
|
|
189
|
+
);
|
|
176
190
|
}
|
|
177
191
|
|
|
192
|
+
let placeholder = dependency.meta?.placeholder ?? dependency.id;
|
|
193
|
+
invariant(typeof placeholder === 'string');
|
|
178
194
|
return {
|
|
179
|
-
from:
|
|
195
|
+
from: placeholder,
|
|
180
196
|
to,
|
|
181
197
|
};
|
|
182
198
|
}
|