@parcel/utils 2.0.0-nightly.140 → 2.0.0-nightly.1404

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/.eslintrc.js +6 -6
  2. package/lib/index.js +37475 -307
  3. package/lib/index.js.map +1 -0
  4. package/package.json +45 -20
  5. package/src/DefaultMap.js +1 -1
  6. package/src/PromiseQueue.js +16 -12
  7. package/src/alternatives.js +145 -0
  8. package/src/ansi-html.js +2 -2
  9. package/src/blob.js +2 -1
  10. package/src/bundle-url.js +1 -1
  11. package/src/collection.js +35 -15
  12. package/src/config.js +132 -45
  13. package/src/countLines.js +5 -2
  14. package/src/debounce.js +1 -1
  15. package/src/dependency-location.js +11 -6
  16. package/src/generateBuildMetrics.js +158 -0
  17. package/src/generateCertificate.js +1 -1
  18. package/src/getCertificate.js +1 -1
  19. package/src/getExisting.js +1 -4
  20. package/src/getModuleParts.js +23 -0
  21. package/src/getRootDir.js +1 -2
  22. package/src/glob.js +51 -10
  23. package/src/hash.js +49 -0
  24. package/src/http-server.js +29 -19
  25. package/src/index.js +68 -21
  26. package/src/is-url.js +1 -1
  27. package/src/isDirectoryInside.js +11 -0
  28. package/src/openInBrowser.js +64 -0
  29. package/src/path.js +38 -6
  30. package/src/prettyDiagnostic.js +74 -24
  31. package/src/progress-message.js +22 -0
  32. package/src/relativeBundlePath.js +8 -13
  33. package/src/replaceBundleReferences.js +85 -41
  34. package/src/schema.js +100 -44
  35. package/src/shared-buffer.js +23 -0
  36. package/src/sourcemap.js +138 -0
  37. package/src/stream.js +31 -1
  38. package/src/urlJoin.js +3 -1
  39. package/test/DefaultMap.test.js +7 -4
  40. package/test/collection.test.js +13 -1
  41. package/test/config.test.js +98 -0
  42. package/test/input/config/.testrc +3 -0
  43. package/test/input/config/config.cjs +3 -0
  44. package/test/input/config/config.js +3 -0
  45. package/test/input/config/config.json +3 -0
  46. package/test/input/config/empty.json +0 -0
  47. package/test/input/config/empty.toml +0 -0
  48. package/test/input/sourcemap/referenced-min.js +2 -0
  49. package/test/input/sourcemap/referenced-min.js.map +6 -0
  50. package/test/input/sourcemap/source-root.js +2 -0
  51. package/test/input/sourcemap/source-root.js.map +7 -0
  52. package/test/replaceBundleReferences.test.js +268 -0
  53. package/test/sourcemap.test.js +207 -0
  54. package/test/throttle.test.js +1 -2
  55. package/test/urlJoin.test.js +37 -0
  56. package/lib/DefaultMap.js +0 -64
  57. package/lib/Deferred.js +0 -26
  58. package/lib/PromiseQueue.js +0 -133
  59. package/lib/TapStream.js +0 -41
  60. package/lib/ansi-html.js +0 -16
  61. package/lib/blob.js +0 -31
  62. package/lib/bundle-url.js +0 -43
  63. package/lib/collection.js +0 -62
  64. package/lib/config.js +0 -88
  65. package/lib/countLines.js +0 -18
  66. package/lib/debounce.js +0 -20
  67. package/lib/dependency-location.js +0 -21
  68. package/lib/escape-html.js +0 -24
  69. package/lib/generateBundleReport.js +0 -38
  70. package/lib/generateCertificate.js +0 -124
  71. package/lib/getCertificate.js +0 -19
  72. package/lib/getExisting.js +0 -23
  73. package/lib/getRootDir.js +0 -55
  74. package/lib/glob.js +0 -76
  75. package/lib/http-server.js +0 -64
  76. package/lib/is-url.js +0 -17
  77. package/lib/loadSourceMapUrl.js +0 -33
  78. package/lib/md5.js +0 -35
  79. package/lib/objectHash.js +0 -26
  80. package/lib/parseCSSImport.js +0 -16
  81. package/lib/path.js +0 -22
  82. package/lib/prettifyTime.js +0 -10
  83. package/lib/prettyDiagnostic.js +0 -57
  84. package/lib/promisify.js +0 -13
  85. package/lib/relativeBundlePath.js +0 -24
  86. package/lib/relativeUrl.js +0 -16
  87. package/lib/replaceBundleReferences.js +0 -151
  88. package/lib/resolve.js +0 -93
  89. package/lib/schema.js +0 -320
  90. package/lib/serializeObject.js +0 -28
  91. package/lib/stream.js +0 -51
  92. package/lib/throttle.js +0 -16
  93. package/lib/urlJoin.js +0 -27
  94. package/src/.babelrc +0 -3
  95. package/src/generateBundleReport.js +0 -51
  96. package/src/loadSourceMapUrl.js +0 -33
  97. package/src/md5.js +0 -44
  98. package/src/promisify.js +0 -13
  99. package/src/resolve.js +0 -135
  100. package/src/serializeObject.js +0 -22
  101. package/test/input/sourcemap/referenced.js +0 -7
  102. package/test/loadSourceMapUrl.test.js +0 -37
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 COMMON_SEPARATORS = ['/', '\\'];
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
- let ret = filePath;
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
- for (let separator of COMMON_SEPARATORS) {
12
- ret = ret.split(separator).join(path.sep);
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 ret;
47
+ return normalizePath(path.relative(from, to), leadingDotSlash);
16
48
  }
@@ -1,61 +1,105 @@
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
+ // $FlowFixMe
10
+ import terminalLink from 'terminal-link';
11
+
12
+ export type FormattedCodeFrame = {|
13
+ location: string,
14
+ code: string,
15
+ |};
8
16
 
9
17
  export type AnsiDiagnosticResult = {|
10
18
  message: string,
11
19
  stack: string,
20
+ /** A formatted string containing all code frames, including their file locations. */
12
21
  codeframe: string,
22
+ /** A list of code frames with highlighted code and file locations separately. */
23
+ frames: Array<FormattedCodeFrame>,
13
24
  hints: Array<string>,
25
+ documentation: string,
14
26
  |};
15
27
 
16
- export default function prettyDiagnostic(
28
+ export default async function prettyDiagnostic(
17
29
  diagnostic: Diagnostic,
18
- ): AnsiDiagnosticResult {
30
+ options?: PluginOptions,
31
+ terminalWidth?: number,
32
+ ): Promise<AnsiDiagnosticResult> {
19
33
  let {
20
34
  origin,
21
35
  message,
22
36
  stack,
23
- codeFrame,
37
+ codeFrames,
24
38
  hints,
25
- filePath,
26
- language,
27
39
  skipFormatting,
40
+ documentationURL,
28
41
  } = diagnostic;
29
42
 
30
43
  let result = {
31
44
  message:
32
45
  mdAnsi(`**${origin ?? 'unknown'}**: `) +
33
46
  (skipFormatting ? message : mdAnsi(message)),
34
- stack: stack ?? filePath ?? '',
47
+ stack: '',
35
48
  codeframe: '',
49
+ frames: [],
36
50
  hints: [],
51
+ documentation: '',
37
52
  };
38
53
 
39
- if (codeFrame !== undefined) {
40
- let highlights = Array.isArray(codeFrame.codeHighlights)
41
- ? codeFrame.codeHighlights
42
- : [codeFrame.codeHighlights];
54
+ if (codeFrames != null) {
55
+ for (let codeFrame of codeFrames) {
56
+ let filePath = codeFrame.filePath;
57
+ if (filePath != null && options && !path.isAbsolute(filePath)) {
58
+ filePath = path.join(options.projectRoot, filePath);
59
+ }
43
60
 
44
- let formattedCodeFrame = formatCodeFrame(codeFrame.code, highlights, {
45
- useColor: true,
46
- syntaxHighlighting: true,
47
- language:
48
- // $FlowFixMe sketchy null checks do not matter here...
49
- language || (filePath ? path.extname(filePath).substr(1) : undefined),
50
- });
61
+ let highlights = codeFrame.codeHighlights;
62
+ let code = codeFrame.code;
63
+ if (code == null && options && filePath != null) {
64
+ code = await options.inputFS.readFile(filePath, 'utf8');
65
+ }
66
+
67
+ let formattedCodeFrame = '';
68
+ if (code != null) {
69
+ formattedCodeFrame = formatCodeFrame(code, highlights, {
70
+ useColor: true,
71
+ syntaxHighlighting: true,
72
+ language:
73
+ // $FlowFixMe sketchy null checks do not matter here...
74
+ codeFrame.language ||
75
+ (filePath != null ? path.extname(filePath).substr(1) : undefined),
76
+ terminalWidth,
77
+ });
78
+ }
79
+
80
+ let location;
81
+ if (typeof filePath !== 'string') {
82
+ location = '';
83
+ } else if (highlights.length === 0) {
84
+ location = filePath;
85
+ } else {
86
+ location = `${filePath}:${highlights[0].start.line}:${highlights[0].start.column}`;
87
+ }
88
+ result.codeframe += location ? chalk.gray.underline(location) + '\n' : '';
89
+ result.codeframe += formattedCodeFrame;
90
+ if (codeFrame !== codeFrames[codeFrames.length - 1]) {
91
+ result.codeframe += '\n\n';
92
+ }
51
93
 
52
- result.codeframe +=
53
- typeof filePath !== 'string'
54
- ? ''
55
- : chalk.underline(
56
- `${filePath}:${highlights[0].start.line}:${highlights[0].start.column}\n`,
57
- );
58
- result.codeframe += formattedCodeFrame;
94
+ result.frames.push({
95
+ location,
96
+ code: formattedCodeFrame,
97
+ });
98
+ }
99
+ }
100
+
101
+ if (stack != null) {
102
+ result.stack = stack;
59
103
  }
60
104
 
61
105
  if (Array.isArray(hints) && hints.length) {
@@ -64,5 +108,11 @@ export default function prettyDiagnostic(
64
108
  });
65
109
  }
66
110
 
111
+ if (documentationURL != null) {
112
+ result.documentation = terminalLink('Learn more', documentationURL, {
113
+ fallback: (text, url) => `${text}: ${url}`,
114
+ });
115
+ }
116
+
67
117
  return result;
68
118
  }
@@ -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
+ }
@@ -1,21 +1,16 @@
1
1
  // @flow strict-local
2
2
 
3
- import type {Bundle} from '@parcel/types';
3
+ import type {FilePath, NamedBundle} from '@parcel/types';
4
4
 
5
5
  import path from 'path';
6
- import nullthrows from 'nullthrows';
6
+ import {relativePath} from './path';
7
7
 
8
8
  export function relativeBundlePath(
9
- from: Bundle,
10
- to: Bundle,
9
+ from: NamedBundle,
10
+ to: NamedBundle,
11
11
  opts: {|leadingDotSlash: boolean|} = {leadingDotSlash: true},
12
- ) {
13
- let p = path
14
- .relative(path.dirname(nullthrows(from.filePath)), nullthrows(to.filePath))
15
- .replace(/\\/g, '/');
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 {Async, Blob, Bundle, BundleGraph, Dependency} from '@parcel/types';
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 moduleSpecifier.
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: 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 bundleGraph.getExternalDependencies(bundle)) {
39
- if (!dependency.isURL) {
54
+ for (let dependency of urlDependencies) {
55
+ if (dependency.specifierType !== 'url') {
40
56
  continue;
41
57
  }
42
58
 
43
- let bundleGroup = bundleGraph.resolveExternalDependency(dependency);
44
- if (bundleGroup == null) {
45
- replacements.set(dependency.id, {
46
- from: dependency.id,
47
- to: dependency.moduleSpecifier,
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
- let [entryBundle] = bundleGraph.getBundlesInBundleGroup(bundleGroup);
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
- dependency.id,
78
+ placeholder,
61
79
  getURLReplacement({
62
80
  dependency,
63
81
  fromBundle: bundle,
64
- toBundle: entryBundle,
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, map: ?(Readable | string)|}>,
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
- for (let dependency of bundleGraph.getExternalDependencies(bundle)) {
102
- let bundleGroup = bundleGraph.resolveExternalDependency(dependency);
103
- if (bundleGroup == null) {
104
- continue;
120
+ let dependencies = [];
121
+ bundle.traverse(node => {
122
+ if (node.type === 'dependency') {
123
+ dependencies.push(node.value);
105
124
  }
125
+ });
106
126
 
107
- let [entryBundle] = bundleGraph.getBundlesInBundleGroup(bundleGroup);
108
- if (!entryBundle.isInline) {
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 = (packagedBundle.contents instanceof Readable
117
- ? await bufferStream(packagedBundle.contents)
118
- : packagedBundle.contents
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
- dependency.id,
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: Bundle,
141
- toBundle: Bundle,
165
+ fromBundle: NamedBundle,
166
+ toBundle: NamedBundle,
142
167
  relative: boolean,
143
- |}) {
144
- let url = URL.parse(dependency.moduleSpecifier);
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
- url.pathname = relativeBundlePath(fromBundle, toBundle, {
148
- leadingDotSlash: false,
175
+ to = URL.format({
176
+ pathname: relativeBundlePath(fromBundle, toBundle, {
177
+ leadingDotSlash: false,
178
+ }),
179
+ hash: orig.hash,
149
180
  });
150
- to = URL.format(url);
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
- url.pathname = nullthrows(toBundle.name);
153
- to = urlJoin(toBundle.target.publicUrl, URL.format(url));
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: dependency.id,
158
- to,
201
+ from: placeholder,
202
+ to: getReplacement ? getReplacement(to) : to,
159
203
  };
160
204
  }
161
205