@parcel/utils 2.0.0-nightly.92 → 2.0.0-nightly.934
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/DefaultMap.js +26 -5
- package/lib/Deferred.js +10 -2
- package/lib/PromiseQueue.js +21 -30
- package/lib/TapStream.js +10 -10
- package/lib/alternatives.js +134 -0
- package/lib/ansi-html.js +10 -2
- package/lib/blob.js +14 -6
- package/lib/collection.js +0 -11
- package/lib/config.js +107 -34
- package/lib/countLines.js +2 -2
- package/lib/dependency-location.js +3 -3
- package/lib/generateBuildMetrics.js +148 -0
- package/lib/generateCertificate.js +33 -8
- package/lib/getExisting.js +11 -3
- package/lib/getRootDir.js +18 -7
- package/lib/glob.js +53 -19
- package/lib/hash.js +44 -0
- package/lib/http-server.js +48 -10
- package/lib/index.js +280 -222
- package/lib/is-url.js +12 -2
- package/lib/isDirectoryInside.js +24 -0
- package/lib/objectHash.js +10 -2
- package/lib/openInBrowser.js +94 -0
- package/lib/path.js +33 -6
- package/lib/prettyDiagnostic.js +107 -25
- package/lib/relativeBundlePath.js +13 -7
- package/lib/relativeUrl.js +19 -3
- package/lib/replaceBundleReferences.js +91 -35
- package/lib/schema.js +104 -33
- package/lib/sourcemap.js +147 -0
- package/lib/stream.js +38 -3
- package/lib/urlJoin.js +25 -6
- package/package.json +22 -16
- package/src/DefaultMap.js +25 -1
- package/src/PromiseQueue.js +16 -12
- package/src/alternatives.js +143 -0
- package/src/ansi-html.js +2 -2
- package/src/blob.js +3 -3
- package/src/bundle-url.js +1 -1
- package/src/collection.js +2 -14
- package/src/config.js +67 -34
- 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/getRootDir.js +1 -2
- package/src/glob.js +29 -11
- package/src/hash.js +34 -0
- package/src/http-server.js +10 -12
- package/src/index.js +49 -23
- 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 +59 -28
- package/src/relativeBundlePath.js +8 -13
- package/src/replaceBundleReferences.js +75 -39
- package/src/schema.js +101 -44
- package/src/sourcemap.js +135 -0
- package/src/stream.js +31 -1
- package/src/urlJoin.js +3 -1
- package/test/DefaultMap.test.js +8 -5
- 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/objectHash.test.js +33 -0
- package/test/prettifyTime.test.js +17 -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/generateBundleReport.js +0 -38
- package/lib/loadSourceMapUrl.js +0 -33
- package/lib/md5.js +0 -35
- package/lib/prettyError.js +0 -43
- package/lib/promisify.js +0 -13
- package/lib/resolve.js +0 -93
- package/lib/serializeObject.js +0 -28
- package/src/generateBundleReport.js +0 -51
- package/src/loadSourceMapUrl.js +0 -33
- package/src/md5.js +0 -44
- package/src/prettyError.js +0 -54
- package/src/promisify.js +0 -13
- package/src/resolve.js +0 -123
- package/src/serializeObject.js +0 -22
- package/test/input/sourcemap/referenced.js +0 -7
- package/test/loadSourceMapUrl.test.js +0 -37
- package/test/prettyError.test.js +0 -104
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
|
@@ -9,7 +9,7 @@ import type {FileSystem} from '@parcel/fs';
|
|
|
9
9
|
import http from 'http';
|
|
10
10
|
import https from 'https';
|
|
11
11
|
import nullthrows from 'nullthrows';
|
|
12
|
-
import {getCertificate, generateCertificate} from '
|
|
12
|
+
import {getCertificate, generateCertificate} from './';
|
|
13
13
|
|
|
14
14
|
type CreateHTTPServerOpts = {|
|
|
15
15
|
https: ?(HTTPSOptions | boolean),
|
|
@@ -34,19 +34,17 @@ export async function createHTTPServer(
|
|
|
34
34
|
if (!options.https) {
|
|
35
35
|
server = http.createServer(options.listener);
|
|
36
36
|
} else if (options.https === true) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
options.host,
|
|
42
|
-
),
|
|
43
|
-
options.listener,
|
|
37
|
+
let {cert, key} = await generateCertificate(
|
|
38
|
+
options.outputFS,
|
|
39
|
+
options.cacheDir,
|
|
40
|
+
options.host,
|
|
44
41
|
);
|
|
42
|
+
|
|
43
|
+
server = https.createServer({cert, key}, options.listener);
|
|
45
44
|
} else {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
);
|
|
45
|
+
let {cert, key} = await getCertificate(options.inputFS, options.https);
|
|
46
|
+
|
|
47
|
+
server = https.createServer({cert, key}, options.listener);
|
|
50
48
|
}
|
|
51
49
|
|
|
52
50
|
// HTTPServer#close only stops accepting new connections, and does not close existing ones.
|
package/src/index.js
CHANGED
|
@@ -1,43 +1,69 @@
|
|
|
1
1
|
// @flow strict-local
|
|
2
|
-
export type * from './
|
|
3
|
-
export type * from './
|
|
2
|
+
export type * from './config';
|
|
3
|
+
export type * from './Deferred';
|
|
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
|
-
export {default as
|
|
8
|
-
export {default as generateBundleReport} from './generateBundleReport';
|
|
11
|
+
export {default as generateBuildMetrics} from './generateBuildMetrics';
|
|
9
12
|
export {default as generateCertificate} from './generateCertificate';
|
|
10
13
|
export {default as getCertificate} from './getCertificate';
|
|
11
14
|
export {default as getRootDir} from './getRootDir';
|
|
15
|
+
export {default as isDirectoryInside} from './isDirectoryInside';
|
|
12
16
|
export {default as isURL} from './is-url';
|
|
13
17
|
export {default as objectHash} from './objectHash';
|
|
14
18
|
export {default as prettifyTime} from './prettifyTime';
|
|
15
|
-
export {default as prettyError} from './prettyError';
|
|
16
19
|
export {default as prettyDiagnostic} from './prettyDiagnostic';
|
|
17
20
|
export {default as PromiseQueue} from './PromiseQueue';
|
|
18
|
-
// $FlowFixMe this is untyped
|
|
19
|
-
export {default as promisify} from './promisify';
|
|
20
21
|
export {default as validateSchema} from './schema';
|
|
21
22
|
export {default as TapStream} from './TapStream';
|
|
22
23
|
export {default as urlJoin} from './urlJoin';
|
|
23
|
-
export {default as loadSourceMapUrl} from './loadSourceMapUrl';
|
|
24
24
|
export {default as relativeUrl} from './relativeUrl';
|
|
25
25
|
export {default as createDependencyLocation} from './dependency-location';
|
|
26
26
|
export {default as debounce} from './debounce';
|
|
27
27
|
export {default as throttle} from './throttle';
|
|
28
|
+
export {default as openInBrowser} from './openInBrowser';
|
|
28
29
|
|
|
29
|
-
export *
|
|
30
|
-
export
|
|
31
|
-
export
|
|
32
|
-
export
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
export
|
|
39
|
-
export
|
|
40
|
-
export
|
|
41
|
-
export
|
|
42
|
-
export
|
|
43
|
-
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
|
+
} from './collection';
|
|
39
|
+
export {resolveConfig, resolveConfigSync, loadConfig} from './config';
|
|
40
|
+
export {DefaultMap, DefaultWeakMap} from './DefaultMap';
|
|
41
|
+
export {makeDeferredWithPromise} from './Deferred';
|
|
42
|
+
export {isGlob, isGlobMatch, globSync, glob} from './glob';
|
|
43
|
+
export {hashStream, hashObject, hashFile} from './hash';
|
|
44
|
+
export {fuzzySearch} from './schema';
|
|
45
|
+
export {createHTTPServer} from './http-server';
|
|
46
|
+
export {normalizePath, normalizeSeparators, relativePath} from './path';
|
|
47
|
+
export {
|
|
48
|
+
replaceURLReferences,
|
|
49
|
+
replaceInlineReferences,
|
|
50
|
+
} from './replaceBundleReferences';
|
|
51
|
+
export {
|
|
52
|
+
measureStreamLength,
|
|
53
|
+
readableFromStringOrBuffer,
|
|
54
|
+
bufferStream,
|
|
55
|
+
blobToStream,
|
|
56
|
+
streamFromPromise,
|
|
57
|
+
fallbackStream,
|
|
58
|
+
} from './stream';
|
|
59
|
+
export {relativeBundlePath} from './relativeBundlePath';
|
|
60
|
+
export {ansiHtml} from './ansi-html';
|
|
61
|
+
export {escapeHTML} from './escape-html';
|
|
62
|
+
export {
|
|
63
|
+
SOURCEMAP_RE,
|
|
64
|
+
SOURCEMAP_EXTENSIONS,
|
|
65
|
+
matchSourceMappingURL,
|
|
66
|
+
loadSourceMapUrl,
|
|
67
|
+
loadSourceMap,
|
|
68
|
+
remapSourceLocation,
|
|
69
|
+
} from './sourcemap';
|
package/src/is-url.js
CHANGED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// @flow strict-local
|
|
2
|
+
import type {FilePath} from '@parcel/types';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
export default function isDirectoryInside(
|
|
6
|
+
child: FilePath,
|
|
7
|
+
parent: FilePath,
|
|
8
|
+
): boolean {
|
|
9
|
+
const relative = path.relative(parent, child);
|
|
10
|
+
return !relative.startsWith('..') && !path.isAbsolute(relative);
|
|
11
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import open from 'open';
|
|
4
|
+
import {execSync} from 'child_process';
|
|
5
|
+
import logger from '@parcel/logger';
|
|
6
|
+
|
|
7
|
+
// Chrome app name is platform dependent. we should not hard code it.
|
|
8
|
+
// https://github.com/react-native-community/cli/blob/e2be8a905285d9b37512fc78c9755b9635ecf805/packages/cli/src/commands/server/launchDebugger.ts#L28
|
|
9
|
+
function getChromeAppName(): string {
|
|
10
|
+
switch (process.platform) {
|
|
11
|
+
case 'darwin':
|
|
12
|
+
return 'google chrome';
|
|
13
|
+
case 'win32':
|
|
14
|
+
return 'chrome';
|
|
15
|
+
case 'linux':
|
|
16
|
+
if (commandExistsUnixSync('google-chrome')) {
|
|
17
|
+
return 'google-chrome';
|
|
18
|
+
}
|
|
19
|
+
if (commandExistsUnixSync('chromium-browser')) {
|
|
20
|
+
return 'chromium-browser';
|
|
21
|
+
}
|
|
22
|
+
return 'chromium';
|
|
23
|
+
|
|
24
|
+
default:
|
|
25
|
+
return 'google-chrome';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function commandExistsUnixSync(commandName: string) {
|
|
30
|
+
try {
|
|
31
|
+
const stdout = execSync(
|
|
32
|
+
`command -v ${commandName} 2>/dev/null` +
|
|
33
|
+
` && { echo >&1 '${commandName} found'; exit 0; }`,
|
|
34
|
+
);
|
|
35
|
+
return !!stdout;
|
|
36
|
+
} catch (error) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function getAppName(appName: string): string {
|
|
42
|
+
if (['google', 'chrome'].includes(appName)) {
|
|
43
|
+
return getChromeAppName();
|
|
44
|
+
} else if (['brave', 'Brave'].includes(appName)) {
|
|
45
|
+
return 'Brave Browser';
|
|
46
|
+
} else return appName;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export default async function openInBrowser(url: string, browser: string) {
|
|
50
|
+
try {
|
|
51
|
+
const options =
|
|
52
|
+
typeof browser === 'string' && browser.length > 0
|
|
53
|
+
? {app: [getAppName(browser)]}
|
|
54
|
+
: undefined;
|
|
55
|
+
|
|
56
|
+
await open(url, options);
|
|
57
|
+
} catch (err) {
|
|
58
|
+
logger.error(
|
|
59
|
+
`Unexpected error while opening in browser: ${browser}`,
|
|
60
|
+
'@parcel/utils',
|
|
61
|
+
);
|
|
62
|
+
logger.error(err, '@parcel/utils');
|
|
63
|
+
}
|
|
64
|
+
}
|
package/src/path.js
CHANGED
|
@@ -1,16 +1,48 @@
|
|
|
1
1
|
// @flow strict-local
|
|
2
|
-
|
|
3
2
|
import type {FilePath} from '@parcel/types';
|
|
4
3
|
import path from 'path';
|
|
5
4
|
|
|
6
|
-
const
|
|
5
|
+
const ABSOLUTE_PATH_REGEX = /^([a-zA-Z]:){0,1}[\\/]+/;
|
|
6
|
+
const SEPARATOR_REGEX = /[\\]+/g;
|
|
7
|
+
|
|
8
|
+
export function isAbsolute(filepath: string): boolean {
|
|
9
|
+
return ABSOLUTE_PATH_REGEX.test(filepath);
|
|
10
|
+
}
|
|
7
11
|
|
|
8
12
|
export function normalizeSeparators(filePath: FilePath): FilePath {
|
|
9
|
-
|
|
13
|
+
return filePath.replace(SEPARATOR_REGEX, '/');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type PathOptions = {
|
|
17
|
+
noLeadingDotSlash?: boolean,
|
|
18
|
+
...
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export function normalizePath(
|
|
22
|
+
filePath: FilePath,
|
|
23
|
+
leadingDotSlash: boolean = true,
|
|
24
|
+
): FilePath {
|
|
25
|
+
if (
|
|
26
|
+
leadingDotSlash &&
|
|
27
|
+
(filePath[0] !== '.' ||
|
|
28
|
+
(filePath[1] !== '.' && filePath[1] !== '/' && filePath[1] !== '\\')) &&
|
|
29
|
+
!path.isAbsolute(filePath)
|
|
30
|
+
) {
|
|
31
|
+
return normalizeSeparators('./' + filePath);
|
|
32
|
+
} else {
|
|
33
|
+
return normalizeSeparators(filePath);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
10
36
|
|
|
11
|
-
|
|
12
|
-
|
|
37
|
+
export function relativePath(
|
|
38
|
+
from: string,
|
|
39
|
+
to: string,
|
|
40
|
+
leadingDotSlash: boolean = true,
|
|
41
|
+
): FilePath {
|
|
42
|
+
// Fast path
|
|
43
|
+
if (to.startsWith(from + '/')) {
|
|
44
|
+
return (leadingDotSlash ? './' : '') + to.slice(from.length + 1);
|
|
13
45
|
}
|
|
14
46
|
|
|
15
|
-
return
|
|
47
|
+
return normalizePath(path.relative(from, to), leadingDotSlash);
|
|
16
48
|
}
|
package/src/prettyDiagnostic.js
CHANGED
|
@@ -1,64 +1,89 @@
|
|
|
1
1
|
// @flow strict-local
|
|
2
2
|
import type {Diagnostic} from '@parcel/diagnostic';
|
|
3
|
+
import type {PluginOptions} from '@parcel/types';
|
|
3
4
|
|
|
4
5
|
import formatCodeFrame from '@parcel/codeframe';
|
|
5
6
|
import mdAnsi from '@parcel/markdown-ansi';
|
|
6
7
|
import chalk from 'chalk';
|
|
7
8
|
import path from 'path';
|
|
9
|
+
import nullthrows from 'nullthrows';
|
|
10
|
+
// $FlowFixMe
|
|
11
|
+
import terminalLink from 'terminal-link';
|
|
8
12
|
|
|
9
13
|
export type AnsiDiagnosticResult = {|
|
|
10
14
|
message: string,
|
|
11
15
|
stack: string,
|
|
12
16
|
codeframe: string,
|
|
13
17
|
hints: Array<string>,
|
|
18
|
+
documentation: string,
|
|
14
19
|
|};
|
|
15
20
|
|
|
16
|
-
export default function prettyDiagnostic(
|
|
21
|
+
export default async function prettyDiagnostic(
|
|
17
22
|
diagnostic: Diagnostic,
|
|
18
|
-
|
|
23
|
+
options?: PluginOptions,
|
|
24
|
+
terminalWidth?: number,
|
|
25
|
+
): Promise<AnsiDiagnosticResult> {
|
|
19
26
|
let {
|
|
20
27
|
origin,
|
|
21
28
|
message,
|
|
22
29
|
stack,
|
|
23
|
-
|
|
30
|
+
codeFrames,
|
|
24
31
|
hints,
|
|
25
|
-
filePath,
|
|
26
|
-
language,
|
|
27
32
|
skipFormatting,
|
|
33
|
+
documentationURL,
|
|
28
34
|
} = diagnostic;
|
|
29
35
|
|
|
30
36
|
let result = {
|
|
31
|
-
message:
|
|
37
|
+
message:
|
|
38
|
+
mdAnsi(`**${origin ?? 'unknown'}**: `) +
|
|
39
|
+
(skipFormatting ? message : mdAnsi(message)),
|
|
32
40
|
stack: '',
|
|
33
41
|
codeframe: '',
|
|
34
42
|
hints: [],
|
|
43
|
+
documentation: '',
|
|
35
44
|
};
|
|
36
45
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
+
}
|
|
41
52
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
53
|
+
let highlights = codeFrame.codeHighlights;
|
|
54
|
+
let code =
|
|
55
|
+
codeFrame.code ??
|
|
56
|
+
(options &&
|
|
57
|
+
(await options.inputFS.readFile(nullthrows(filePath), 'utf8')));
|
|
46
58
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
+
}
|
|
71
|
+
|
|
72
|
+
result.codeframe +=
|
|
73
|
+
typeof filePath !== 'string'
|
|
74
|
+
? ''
|
|
75
|
+
: chalk.gray.underline(
|
|
76
|
+
`${filePath}:${highlights[0].start.line}:${highlights[0].start.column}\n`,
|
|
77
|
+
);
|
|
78
|
+
result.codeframe += formattedCodeFrame;
|
|
79
|
+
if (codeFrame !== codeFrames[codeFrames.length - 1]) {
|
|
80
|
+
result.codeframe += '\n\n';
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
54
84
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
? ''
|
|
58
|
-
: chalk.underline(
|
|
59
|
-
`${filePath}:${highlights[0].start.line}:${highlights[0].start.column}\n`,
|
|
60
|
-
);
|
|
61
|
-
result.codeframe += formattedCodeFrame;
|
|
85
|
+
if (stack != null) {
|
|
86
|
+
result.stack = stack;
|
|
62
87
|
}
|
|
63
88
|
|
|
64
89
|
if (Array.isArray(hints) && hints.length) {
|
|
@@ -67,5 +92,11 @@ export default function prettyDiagnostic(
|
|
|
67
92
|
});
|
|
68
93
|
}
|
|
69
94
|
|
|
95
|
+
if (documentationURL != null) {
|
|
96
|
+
result.documentation = terminalLink('Learn more', documentationURL, {
|
|
97
|
+
fallback: (text, url) => `${text}: ${url}`,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
70
101
|
return result;
|
|
71
102
|
}
|
|
@@ -1,21 +1,16 @@
|
|
|
1
1
|
// @flow strict-local
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type {FilePath, NamedBundle} from '@parcel/types';
|
|
4
4
|
|
|
5
5
|
import path from 'path';
|
|
6
|
-
import
|
|
6
|
+
import {relativePath} from './path';
|
|
7
7
|
|
|
8
8
|
export function relativeBundlePath(
|
|
9
|
-
from:
|
|
10
|
-
to:
|
|
9
|
+
from: NamedBundle,
|
|
10
|
+
to: NamedBundle,
|
|
11
11
|
opts: {|leadingDotSlash: boolean|} = {leadingDotSlash: true},
|
|
12
|
-
) {
|
|
13
|
-
let
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if (opts.leadingDotSlash && p[0] !== '.') {
|
|
17
|
-
p = './' + p;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return p;
|
|
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);
|
|
21
16
|
}
|
|
@@ -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.
|
|
@@ -27,41 +35,49 @@ export function replaceURLReferences({
|
|
|
27
35
|
map,
|
|
28
36
|
relative = true,
|
|
29
37
|
}: {|
|
|
30
|
-
bundle:
|
|
31
|
-
bundleGraph: BundleGraph
|
|
38
|
+
bundle: NamedBundle,
|
|
39
|
+
bundleGraph: BundleGraph<NamedBundle>,
|
|
32
40
|
contents: string,
|
|
33
41
|
relative?: boolean,
|
|
34
42
|
map?: ?SourceMap,
|
|
35
43
|
|}): {|+contents: string, +map: ?SourceMap|} {
|
|
36
44
|
let replacements = new Map();
|
|
45
|
+
let urlDependencies = [];
|
|
46
|
+
bundle.traverse(node => {
|
|
47
|
+
if (node.type === 'dependency' && node.value.specifierType === 'url') {
|
|
48
|
+
urlDependencies.push(node.value);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
37
51
|
|
|
38
|
-
for (let dependency of
|
|
39
|
-
if (
|
|
52
|
+
for (let dependency of urlDependencies) {
|
|
53
|
+
if (dependency.specifierType !== 'url') {
|
|
40
54
|
continue;
|
|
41
55
|
}
|
|
42
56
|
|
|
43
|
-
let
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
57
|
+
let placeholder = dependency.meta?.placeholder ?? dependency.id;
|
|
58
|
+
invariant(typeof placeholder === 'string');
|
|
59
|
+
|
|
60
|
+
let resolved = bundleGraph.getReferencedBundle(dependency, bundle);
|
|
61
|
+
if (resolved == null) {
|
|
62
|
+
replacements.set(placeholder, {
|
|
63
|
+
from: placeholder,
|
|
64
|
+
to: dependency.specifier,
|
|
48
65
|
});
|
|
49
66
|
continue;
|
|
50
67
|
}
|
|
51
68
|
|
|
52
|
-
|
|
53
|
-
if (entryBundle.isInline) {
|
|
69
|
+
if (!resolved || resolved.bundleBehavior === 'inline') {
|
|
54
70
|
// If a bundle is inline, it should be replaced with inline contents,
|
|
55
71
|
// not a URL.
|
|
56
72
|
continue;
|
|
57
73
|
}
|
|
58
74
|
|
|
59
75
|
replacements.set(
|
|
60
|
-
|
|
76
|
+
placeholder,
|
|
61
77
|
getURLReplacement({
|
|
62
78
|
dependency,
|
|
63
79
|
fromBundle: bundle,
|
|
64
|
-
toBundle:
|
|
80
|
+
toBundle: resolved,
|
|
65
81
|
relative,
|
|
66
82
|
}),
|
|
67
83
|
);
|
|
@@ -83,7 +99,7 @@ export async function replaceInlineReferences({
|
|
|
83
99
|
getInlineBundleContents,
|
|
84
100
|
}: {|
|
|
85
101
|
bundle: Bundle,
|
|
86
|
-
bundleGraph: BundleGraph
|
|
102
|
+
bundleGraph: BundleGraph<NamedBundle>,
|
|
87
103
|
contents: string,
|
|
88
104
|
getInlineReplacement: (
|
|
89
105
|
Dependency,
|
|
@@ -92,20 +108,22 @@ export async function replaceInlineReferences({
|
|
|
92
108
|
) => {|from: string, to: string|},
|
|
93
109
|
getInlineBundleContents: (
|
|
94
110
|
Bundle,
|
|
95
|
-
BundleGraph
|
|
96
|
-
) => Async<{|contents: Blob
|
|
111
|
+
BundleGraph<NamedBundle>,
|
|
112
|
+
) => Async<{|contents: Blob|}>,
|
|
97
113
|
map?: ?SourceMap,
|
|
98
114
|
|}): Promise<{|+contents: string, +map: ?SourceMap|}> {
|
|
99
115
|
let replacements = new Map();
|
|
100
116
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (
|
|
104
|
-
|
|
117
|
+
let dependencies = [];
|
|
118
|
+
bundle.traverse(node => {
|
|
119
|
+
if (node.type === 'dependency') {
|
|
120
|
+
dependencies.push(node.value);
|
|
105
121
|
}
|
|
122
|
+
});
|
|
106
123
|
|
|
107
|
-
|
|
108
|
-
|
|
124
|
+
for (let dependency of dependencies) {
|
|
125
|
+
let entryBundle = bundleGraph.getReferencedBundle(dependency, bundle);
|
|
126
|
+
if (entryBundle?.bundleBehavior !== 'inline') {
|
|
109
127
|
continue;
|
|
110
128
|
}
|
|
111
129
|
|
|
@@ -113,9 +131,10 @@ export async function replaceInlineReferences({
|
|
|
113
131
|
entryBundle,
|
|
114
132
|
bundleGraph,
|
|
115
133
|
);
|
|
116
|
-
let packagedContents = (
|
|
117
|
-
|
|
118
|
-
|
|
134
|
+
let packagedContents = (
|
|
135
|
+
packagedBundle.contents instanceof Readable
|
|
136
|
+
? await bufferStream(packagedBundle.contents)
|
|
137
|
+
: packagedBundle.contents
|
|
119
138
|
).toString();
|
|
120
139
|
|
|
121
140
|
let inlineType = nullthrows(entryBundle.getMainEntry()).meta.inlineType;
|
|
@@ -130,31 +149,48 @@ export async function replaceInlineReferences({
|
|
|
130
149
|
return performReplacement(replacements, contents, map);
|
|
131
150
|
}
|
|
132
151
|
|
|
133
|
-
function getURLReplacement({
|
|
152
|
+
export function getURLReplacement({
|
|
134
153
|
dependency,
|
|
135
154
|
fromBundle,
|
|
136
155
|
toBundle,
|
|
137
156
|
relative,
|
|
138
157
|
}: {|
|
|
139
158
|
dependency: Dependency,
|
|
140
|
-
fromBundle:
|
|
141
|
-
toBundle:
|
|
159
|
+
fromBundle: NamedBundle,
|
|
160
|
+
toBundle: NamedBundle,
|
|
142
161
|
relative: boolean,
|
|
143
|
-
|}) {
|
|
144
|
-
let url = URL.parse(dependency.moduleSpecifier);
|
|
162
|
+
|}): {|from: string, to: string|} {
|
|
145
163
|
let to;
|
|
164
|
+
|
|
165
|
+
let orig = URL.parse(dependency.specifier);
|
|
166
|
+
|
|
146
167
|
if (relative) {
|
|
147
|
-
|
|
148
|
-
|
|
168
|
+
to = URL.format({
|
|
169
|
+
pathname: relativeBundlePath(fromBundle, toBundle, {
|
|
170
|
+
leadingDotSlash: false,
|
|
171
|
+
}),
|
|
172
|
+
hash: orig.hash,
|
|
149
173
|
});
|
|
150
|
-
|
|
174
|
+
|
|
175
|
+
// If the resulting path includes a colon character and doesn't start with a ./ or ../
|
|
176
|
+
// we need to add one so that the first part before the colon isn't parsed as a URL protocol.
|
|
177
|
+
if (to.includes(':') && !to.startsWith('./') && !to.startsWith('../')) {
|
|
178
|
+
to = './' + to;
|
|
179
|
+
}
|
|
151
180
|
} else {
|
|
152
|
-
|
|
153
|
-
|
|
181
|
+
to = urlJoin(
|
|
182
|
+
toBundle.target.publicUrl,
|
|
183
|
+
URL.format({
|
|
184
|
+
pathname: nullthrows(toBundle.name),
|
|
185
|
+
hash: orig.hash,
|
|
186
|
+
}),
|
|
187
|
+
);
|
|
154
188
|
}
|
|
155
189
|
|
|
190
|
+
let placeholder = dependency.meta?.placeholder ?? dependency.id;
|
|
191
|
+
invariant(typeof placeholder === 'string');
|
|
156
192
|
return {
|
|
157
|
-
from:
|
|
193
|
+
from: placeholder,
|
|
158
194
|
to,
|
|
159
195
|
};
|
|
160
196
|
}
|