@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.
Files changed (79) hide show
  1. package/lib/index.js +37516 -542
  2. package/lib/index.js.map +1 -0
  3. package/package.json +41 -18
  4. package/src/DefaultMap.js +1 -1
  5. package/src/PromiseQueue.js +13 -0
  6. package/src/alternatives.js +21 -6
  7. package/src/ansi-html.js +1 -1
  8. package/src/blob.js +1 -0
  9. package/src/collection.js +35 -3
  10. package/src/config.js +77 -22
  11. package/src/debounce.js +1 -1
  12. package/src/dependency-location.js +5 -5
  13. package/src/getExisting.js +1 -4
  14. package/src/getModuleParts.js +23 -0
  15. package/src/glob.js +26 -3
  16. package/src/hash.js +49 -0
  17. package/src/http-server.js +19 -7
  18. package/src/index.js +25 -10
  19. package/src/path.js +11 -1
  20. package/src/prettyDiagnostic.js +90 -40
  21. package/src/progress-message.js +22 -0
  22. package/src/replaceBundleReferences.js +49 -25
  23. package/src/schema.js +20 -19
  24. package/src/shared-buffer.js +23 -0
  25. package/src/sourcemap.js +13 -7
  26. package/src/urlJoin.js +3 -1
  27. package/test/DefaultMap.test.js +7 -4
  28. package/test/PromiseQueue.test.js +28 -0
  29. package/test/collection.test.js +13 -1
  30. package/test/config.test.js +98 -0
  31. package/test/input/config/.testrc +3 -0
  32. package/test/input/config/config.cjs +3 -0
  33. package/test/input/config/config.js +3 -0
  34. package/test/input/config/config.json +3 -0
  35. package/test/input/config/empty.json +0 -0
  36. package/test/input/config/empty.toml +0 -0
  37. package/test/replaceBundleReferences.test.js +88 -4
  38. package/test/throttle.test.js +1 -1
  39. package/test/urlJoin.test.js +11 -0
  40. package/lib/DefaultMap.js +0 -64
  41. package/lib/Deferred.js +0 -34
  42. package/lib/PromiseQueue.js +0 -144
  43. package/lib/TapStream.js +0 -46
  44. package/lib/alternatives.js +0 -151
  45. package/lib/ansi-html.js +0 -32
  46. package/lib/blob.js +0 -47
  47. package/lib/bundle-url.js +0 -43
  48. package/lib/collection.js +0 -51
  49. package/lib/config.js +0 -159
  50. package/lib/countLines.js +0 -18
  51. package/lib/debounce.js +0 -20
  52. package/lib/dependency-location.js +0 -21
  53. package/lib/escape-html.js +0 -24
  54. package/lib/generateBuildMetrics.js +0 -156
  55. package/lib/generateCertificate.js +0 -149
  56. package/lib/getCertificate.js +0 -19
  57. package/lib/getExisting.js +0 -31
  58. package/lib/getRootDir.js +0 -74
  59. package/lib/glob.js +0 -118
  60. package/lib/http-server.js +0 -110
  61. package/lib/is-url.js +0 -27
  62. package/lib/isDirectoryInside.js +0 -24
  63. package/lib/md5.js +0 -61
  64. package/lib/objectHash.js +0 -34
  65. package/lib/openInBrowser.js +0 -94
  66. package/lib/parseCSSImport.js +0 -16
  67. package/lib/path.js +0 -44
  68. package/lib/prettifyTime.js +0 -10
  69. package/lib/prettyDiagnostic.js +0 -119
  70. package/lib/relativeBundlePath.js +0 -38
  71. package/lib/relativeUrl.js +0 -32
  72. package/lib/replaceBundleReferences.js +0 -184
  73. package/lib/schema.js +0 -391
  74. package/lib/sourcemap.js +0 -155
  75. package/lib/stream.js +0 -86
  76. package/lib/throttle.js +0 -16
  77. package/lib/urlJoin.js +0 -43
  78. package/src/.babelrc +0 -3
  79. package/src/md5.js +0 -56
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parcel/utils",
3
- "version": "2.0.0-beta.3",
3
+ "version": "2.0.0-dev.1510+a9bb85adf",
4
4
  "description": "Blazing fast, zero configuration web application bundler",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -19,30 +19,53 @@
19
19
  "engines": {
20
20
  "node": ">= 12.0.0"
21
21
  },
22
+ "targets": {
23
+ "main": {
24
+ "includeNodeModules": {
25
+ "@parcel/codeframe": false,
26
+ "@parcel/diagnostic": false,
27
+ "@parcel/rust": false,
28
+ "@parcel/logger": false,
29
+ "@parcel/markdown-ansi": false,
30
+ "@parcel/source-map": false,
31
+ "chalk": false
32
+ }
33
+ }
34
+ },
22
35
  "dependencies": {
23
- "@iarna/toml": "^2.2.0",
24
- "@parcel/codeframe": "2.0.0-beta.3",
25
- "@parcel/diagnostic": "2.0.0-beta.3",
26
- "@parcel/logger": "2.0.0-beta.3",
27
- "@parcel/markdown-ansi": "2.0.0-beta.3",
28
- "@parcel/source-map": "2.0.0-rc.1.0",
29
- "ansi-html": "^0.0.7",
36
+ "@parcel/codeframe": "2.0.0-dev.1510+a9bb85adf",
37
+ "@parcel/diagnostic": "2.0.0-dev.1510+a9bb85adf",
38
+ "@parcel/logger": "2.0.0-dev.1510+a9bb85adf",
39
+ "@parcel/markdown-ansi": "2.0.0-dev.1510+a9bb85adf",
40
+ "@parcel/rust": "2.11.1-dev.3133+a9bb85adf",
41
+ "@parcel/source-map": "^2.1.1",
30
42
  "chalk": "^4.1.0",
43
+ "nullthrows": "^1.1.1"
44
+ },
45
+ "devDependencies": {
46
+ "@iarna/toml": "^2.2.0",
47
+ "ansi-html-community": "0.0.8",
31
48
  "clone": "^2.1.1",
32
- "fast-glob": "3.1.1",
33
- "fastest-levenshtein": "^1.0.8",
49
+ "fast-glob": "^3.2.12",
50
+ "fastest-levenshtein": "^1.0.16",
34
51
  "is-glob": "^4.0.0",
35
52
  "is-url": "^1.2.2",
36
- "json5": "^1.0.1",
53
+ "json5": "^2.2.0",
37
54
  "lru-cache": "^6.0.0",
38
- "micromatch": "^4.0.2",
39
- "node-forge": "^0.10.0",
55
+ "micromatch": "^4.0.4",
56
+ "node-forge": "^1.2.1",
40
57
  "nullthrows": "^1.1.1",
41
- "open": "^7.0.3"
58
+ "open": "^7.0.3",
59
+ "random-int": "^1.0.0",
60
+ "snarkdown": "^2.0.0",
61
+ "strip-ansi": "^6.0.0",
62
+ "terminal-link": "^2.1.1"
42
63
  },
43
- "devDependencies": {
44
- "@babel/plugin-transform-flow-strip-types": "^7.2.0",
45
- "random-int": "^1.0.0"
64
+ "browser": {
65
+ "./src/generateCertificate.js": false,
66
+ "./src/http-server.js": false,
67
+ "./src/openInBrowser.js": false,
68
+ "@parcel/markdown-ansi": false
46
69
  },
47
- "gitHead": "bf03f018093f8c7ca4c3a544524e15065a637b3b"
70
+ "gitHead": "a9bb85adf8f3b38631e178b3aacaa30c78696e36"
48
71
  }
package/src/DefaultMap.js CHANGED
@@ -24,7 +24,7 @@ export class DefaultMap<K, V> extends Map<K, V> {
24
24
 
25
25
  // Duplicated from DefaultMap implementation for Flow
26
26
  // Roughly mirrors https://github.com/facebook/flow/blob/2eb5a78d92c167117ba9caae070afd2b9f598599/lib/core.js#L617
27
- export class DefaultWeakMap<K: {...}, V> extends WeakMap<K, V> {
27
+ export class DefaultWeakMap<K: interface {}, V> extends WeakMap<K, V> {
28
28
  _getDefault: K => V;
29
29
 
30
30
  constructor(getDefault: K => V, entries?: Iterable<[K, V]>) {
@@ -13,6 +13,7 @@ export default class PromiseQueue<T> {
13
13
  _error: mixed;
14
14
  _count: number = 0;
15
15
  _results: Array<T> = [];
16
+ _addSubscriptions: Set<() => void> = new Set();
16
17
 
17
18
  constructor(opts: PromiseQueueOpts = {maxConcurrent: Infinity}) {
18
19
  if (opts.maxConcurrent <= 0) {
@@ -43,12 +44,24 @@ export default class PromiseQueue<T> {
43
44
 
44
45
  this._queue.push(wrapped);
45
46
 
47
+ for (const addFn of this._addSubscriptions) {
48
+ addFn();
49
+ }
50
+
46
51
  if (this._numRunning > 0 && this._numRunning < this._maxConcurrent) {
47
52
  this._next();
48
53
  }
49
54
  });
50
55
  }
51
56
 
57
+ subscribeToAdd(fn: () => void): () => void {
58
+ this._addSubscriptions.add(fn);
59
+
60
+ return () => {
61
+ this._addSubscriptions.delete(fn);
62
+ };
63
+ }
64
+
52
65
  run(): Promise<Array<T>> {
53
66
  if (this._runPromise != null) {
54
67
  return this._runPromise;
@@ -42,6 +42,8 @@ export async function findAlternativeNodeModules(
42
42
  potentialModules.push(...orgDirContent.map(i => `${item}/${i}`));
43
43
  }),
44
44
  );
45
+ } else {
46
+ potentialModules.push(...modules);
45
47
  }
46
48
  }
47
49
  } catch (err) {
@@ -62,6 +64,8 @@ async function findAllFilesUp({
62
64
  basedir,
63
65
  maxlength,
64
66
  collected,
67
+ leadingDotSlash = true,
68
+ includeDirectories = true,
65
69
  }: {|
66
70
  fs: FileSystem,
67
71
  dir: string,
@@ -69,16 +73,18 @@ async function findAllFilesUp({
69
73
  basedir: string,
70
74
  maxlength: number,
71
75
  collected: Array<string>,
76
+ leadingDotSlash?: boolean,
77
+ includeDirectories?: boolean,
72
78
  |}): Promise<mixed> {
73
79
  let dirContent = (await fs.readdir(dir)).sort();
74
80
  return Promise.all(
75
81
  dirContent.map(async item => {
76
82
  let fullPath = path.join(dir, item);
77
- let relativeFilePath = relativePath(basedir, fullPath);
83
+ let relativeFilePath = relativePath(basedir, fullPath, leadingDotSlash);
78
84
  if (relativeFilePath.length < maxlength) {
79
85
  let stats = await fs.stat(fullPath);
80
86
  let isDir = stats.isDirectory();
81
- if (isDir || stats.isFile()) {
87
+ if ((isDir && includeDirectories) || stats.isFile()) {
82
88
  collected.push(relativeFilePath);
83
89
  }
84
90
 
@@ -103,6 +109,9 @@ export async function findAlternativeFiles(
103
109
  fileSpecifier: string,
104
110
  dir: string,
105
111
  projectRoot: string,
112
+ leadingDotSlash?: boolean = true,
113
+ includeDirectories?: boolean = true,
114
+ includeExtension?: boolean = false,
106
115
  ): Promise<Array<string>> {
107
116
  let potentialFiles: Array<string> = [];
108
117
  // Find our root, we won't recommend files above the package root as that's bad practise
@@ -112,11 +121,8 @@ export async function findAlternativeFiles(
112
121
  ['package.json'],
113
122
  projectRoot,
114
123
  );
115
- if (!pkg) {
116
- return potentialFiles;
117
- }
118
124
 
119
- let pkgRoot = path.dirname(pkg);
125
+ let pkgRoot = pkg ? path.dirname(pkg) : projectRoot;
120
126
  await findAllFilesUp({
121
127
  fs,
122
128
  dir: pkgRoot,
@@ -124,7 +130,16 @@ export async function findAlternativeFiles(
124
130
  basedir: dir,
125
131
  maxlength: fileSpecifier.length + 10,
126
132
  collected: potentialFiles,
133
+ leadingDotSlash,
134
+ includeDirectories,
127
135
  });
128
136
 
137
+ if (path.extname(fileSpecifier) === '' && !includeExtension) {
138
+ potentialFiles = potentialFiles.map(p => {
139
+ let ext = path.extname(p);
140
+ return ext.length > 0 ? p.slice(0, -ext.length) : p;
141
+ });
142
+ }
143
+
129
144
  return fuzzySearch(potentialFiles, fileSpecifier).slice(0, 2);
130
145
  }
package/src/ansi-html.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // @flow strict-local
2
- import ansiHTML from 'ansi-html';
2
+ import ansiHTML from 'ansi-html-community';
3
3
  import {escapeHTML} from './escape-html';
4
4
 
5
5
  export function ansiHtml(ansi: string): string {
package/src/blob.js CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  import type {Blob} from '@parcel/types';
4
4
 
5
+ import {Buffer} from 'buffer';
5
6
  import {bufferStream} from './';
6
7
  import {Readable} from 'stream';
7
8
 
package/src/collection.js CHANGED
@@ -6,14 +6,14 @@ export function unique<T>(array: Array<T>): Array<T> {
6
6
 
7
7
  export function objectSortedEntries(obj: {
8
8
  +[string]: mixed,
9
- ...,
9
+ ...
10
10
  }): Array<[string, mixed]> {
11
11
  return Object.entries(obj).sort(([keyA], [keyB]) => keyA.localeCompare(keyB));
12
12
  }
13
13
 
14
14
  export function objectSortedEntriesDeep(object: {
15
15
  +[string]: mixed,
16
- ...,
16
+ ...
17
17
  }): Array<[string, mixed]> {
18
18
  let sortedEntries = objectSortedEntries(object);
19
19
  for (let i = 0; i < sortedEntries.length; i++) {
@@ -34,12 +34,44 @@ function sortEntry(entry: mixed) {
34
34
  return entry;
35
35
  }
36
36
 
37
- export function setDifference<T>(a: Set<T>, b: Set<T>): Set<T> {
37
+ export function setDifference<T>(
38
+ a: $ReadOnlySet<T>,
39
+ b: $ReadOnlySet<T>,
40
+ ): Set<T> {
38
41
  let difference = new Set();
39
42
  for (let e of a) {
40
43
  if (!b.has(e)) {
41
44
  difference.add(e);
42
45
  }
43
46
  }
47
+ for (let d of b) {
48
+ if (!a.has(d)) {
49
+ difference.add(d);
50
+ }
51
+ }
44
52
  return difference;
45
53
  }
54
+
55
+ export function setIntersect<T>(a: Set<T>, b: $ReadOnlySet<T>): void {
56
+ for (let entry of a) {
57
+ if (!b.has(entry)) {
58
+ a.delete(entry);
59
+ }
60
+ }
61
+ }
62
+
63
+ export function setUnion<T>(a: Iterable<T>, b: Iterable<T>): Set<T> {
64
+ return new Set([...a, ...b]);
65
+ }
66
+
67
+ export function setEqual<T>(a: $ReadOnlySet<T>, b: $ReadOnlySet<T>): boolean {
68
+ if (a.size != b.size) {
69
+ return false;
70
+ }
71
+ for (let entry of a) {
72
+ if (!b.has(entry)) {
73
+ return false;
74
+ }
75
+ }
76
+ return true;
77
+ }
package/src/config.js CHANGED
@@ -2,9 +2,10 @@
2
2
 
3
3
  import type {ConfigResult, File, FilePath} from '@parcel/types';
4
4
  import type {FileSystem} from '@parcel/fs';
5
+ import ThrowableDiagnostic from '@parcel/diagnostic';
5
6
  import path from 'path';
6
7
  import clone from 'clone';
7
- import {parse as json5} from 'json5';
8
+ import json5 from 'json5';
8
9
  import {parse as toml} from '@iarna/toml';
9
10
  import LRU from 'lru-cache';
10
11
 
@@ -15,6 +16,7 @@ export type ConfigOutput = {|
15
16
 
16
17
  export type ConfigOptions = {|
17
18
  parse?: boolean,
19
+ parser?: string => any,
18
20
  |};
19
21
 
20
22
  const configCache = new LRU<FilePath, ConfigOutput>({max: 500});
@@ -69,10 +71,10 @@ export async function loadConfig(
69
71
 
70
72
  try {
71
73
  let extname = path.extname(configFile).slice(1);
72
- if (extname === 'js') {
74
+ if (extname === 'js' || extname === 'cjs') {
73
75
  let output = {
74
76
  // $FlowFixMe
75
- config: clone(require(configFile)),
77
+ config: clone(module.require(configFile)),
76
78
  files: [{filePath: configFile}],
77
79
  };
78
80
 
@@ -80,24 +82,7 @@ export async function loadConfig(
80
82
  return output;
81
83
  }
82
84
 
83
- let configContent = await fs.readFile(configFile, 'utf8');
84
- if (!configContent) return null;
85
-
86
- let config;
87
- if (parse === false) {
88
- config = configContent;
89
- } else {
90
- let parse = getParser(extname);
91
- config = parse(configContent);
92
- }
93
-
94
- let output = {
95
- config,
96
- files: [{filePath: configFile}],
97
- };
98
-
99
- configCache.set(String(parse) + configFile, output);
100
- return output;
85
+ return readConfig(fs, configFile, opts);
101
86
  } catch (err) {
102
87
  if (err.code === 'MODULE_NOT_FOUND' || err.code === 'ENOENT') {
103
88
  return null;
@@ -115,12 +100,82 @@ loadConfig.clear = () => {
115
100
  resolveCache.clear();
116
101
  };
117
102
 
103
+ export async function readConfig(
104
+ fs: FileSystem,
105
+ configFile: FilePath,
106
+ opts: ?ConfigOptions,
107
+ ): Promise<ConfigOutput | null> {
108
+ let parse = opts?.parse ?? true;
109
+ let cachedOutput = configCache.get(String(parse) + configFile);
110
+ if (cachedOutput) {
111
+ return cachedOutput;
112
+ }
113
+
114
+ try {
115
+ let configContent = await fs.readFile(configFile, 'utf8');
116
+ let config;
117
+ if (parse === false) {
118
+ config = configContent;
119
+ } else {
120
+ let extname = path.extname(configFile).slice(1);
121
+ let parse = opts?.parser ?? getParser(extname);
122
+ try {
123
+ config = parse(configContent);
124
+ } catch (e) {
125
+ if (extname !== '' && extname !== 'json') {
126
+ throw e;
127
+ }
128
+
129
+ let pos = {
130
+ line: e.lineNumber,
131
+ column: e.columnNumber,
132
+ };
133
+
134
+ throw new ThrowableDiagnostic({
135
+ diagnostic: {
136
+ message: `Failed to parse ${path.basename(configFile)}`,
137
+ origin: '@parcel/utils',
138
+ codeFrames: [
139
+ {
140
+ language: 'json5',
141
+ filePath: configFile,
142
+ code: configContent,
143
+ codeHighlights: [
144
+ {
145
+ start: pos,
146
+ end: pos,
147
+ message: e.message,
148
+ },
149
+ ],
150
+ },
151
+ ],
152
+ },
153
+ });
154
+ }
155
+ }
156
+
157
+ let output = {
158
+ config,
159
+ files: [{filePath: configFile}],
160
+ };
161
+
162
+ configCache.set(String(parse) + configFile, output);
163
+ return output;
164
+ } catch (err) {
165
+ if (err.code === 'MODULE_NOT_FOUND' || err.code === 'ENOENT') {
166
+ return null;
167
+ }
168
+
169
+ throw err;
170
+ }
171
+ }
172
+
118
173
  function getParser(extname) {
119
174
  switch (extname) {
120
175
  case 'toml':
121
176
  return toml;
122
177
  case 'json':
123
178
  default:
124
- return json5;
179
+ return json5.parse;
125
180
  }
126
181
  }
package/src/debounce.js CHANGED
@@ -6,7 +6,7 @@ export default function debounce<TArgs: Array<mixed>>(
6
6
  ): (...args: TArgs) => void {
7
7
  let timeout;
8
8
 
9
- return function(...args: TArgs) {
9
+ return function (...args: TArgs) {
10
10
  if (timeout) {
11
11
  clearTimeout(timeout);
12
12
  }
@@ -1,11 +1,11 @@
1
1
  // @flow
2
+
2
3
  export default function createDependencyLocation(
3
- start: {
4
+ start: interface {
4
5
  line: number,
5
6
  column: number,
6
- ...
7
7
  },
8
- moduleSpecifier: string,
8
+ specifier: string,
9
9
  lineOffset: number = 0,
10
10
  columnOffset: number = 0,
11
11
  // Imports are usually wrapped in quotes
@@ -16,7 +16,7 @@ export default function createDependencyLocation(
16
16
  start: {|column: number, line: number|},
17
17
  |} {
18
18
  return {
19
- filePath: moduleSpecifier,
19
+ filePath: specifier,
20
20
  start: {
21
21
  line: start.line + lineOffset,
22
22
  column: start.column + columnOffset,
@@ -25,7 +25,7 @@ export default function createDependencyLocation(
25
25
  line: start.line + lineOffset,
26
26
  column:
27
27
  start.column +
28
- moduleSpecifier.length -
28
+ specifier.length -
29
29
  1 +
30
30
  importWrapperLength +
31
31
  columnOffset,
@@ -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
  }
@@ -0,0 +1,23 @@
1
+ // @flow strict-local
2
+ import path from 'path';
3
+
4
+ import {normalizeSeparators} from './path';
5
+
6
+ /**
7
+ * Returns the package name and the optional subpath
8
+ */
9
+ export default function getModuleParts(_name: string): [string, ?string] {
10
+ let name = path.normalize(_name);
11
+ let splitOn = name.indexOf(path.sep);
12
+ if (name.charAt(0) === '@') {
13
+ splitOn = name.indexOf(path.sep, splitOn + 1);
14
+ }
15
+ if (splitOn < 0) {
16
+ return [normalizeSeparators(name), undefined];
17
+ } else {
18
+ return [
19
+ normalizeSeparators(name.substring(0, splitOn)),
20
+ name.substring(splitOn + 1) || undefined,
21
+ ];
22
+ }
23
+ }
package/src/glob.js CHANGED
@@ -5,15 +5,38 @@ 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 micromatch, {isMatch, makeRe, type Options} from 'micromatch';
9
9
  import {normalizeSeparators} from './path';
10
10
 
11
11
  export function isGlob(p: FilePath): any {
12
12
  return _isGlob(normalizeSeparators(p));
13
13
  }
14
14
 
15
- export function isGlobMatch(filePath: FilePath, glob: Glob): any {
16
- return isMatch(filePath, normalizeSeparators(glob));
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 globMatch(
27
+ values: Array<string>,
28
+ glob: Glob | Array<Glob>,
29
+ opts?: Options,
30
+ ): Array<string> {
31
+ glob = Array.isArray(glob)
32
+ ? glob.map(normalizeSeparators)
33
+ : normalizeSeparators(glob);
34
+
35
+ return micromatch(values, glob, opts);
36
+ }
37
+
38
+ export function globToRegex(glob: Glob, opts?: Options): RegExp {
39
+ return makeRe(glob, opts);
17
40
  }
18
41
 
19
42
  export function globSync(
package/src/hash.js ADDED
@@ -0,0 +1,49 @@
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/rust';
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
+ let testCache: {|[string]: Promise<string>|} = {
33
+ /*:: ...null */
34
+ };
35
+ export function hashFile(fs: FileSystem, filePath: string): Promise<string> {
36
+ if (process.env.PARCEL_BUILD_ENV === 'test') {
37
+ // Development builds of these native modules are especially big and slow to hash.
38
+ if (
39
+ /parcel-swc\.[^\\/]+\.node$|lightningcss.[^\\/]+.node$/.test(filePath)
40
+ ) {
41
+ let cacheEntry = testCache[filePath];
42
+ if (cacheEntry) return cacheEntry;
43
+ let v = hashStream(fs.createReadStream(filePath));
44
+ testCache[filePath] = v;
45
+ return v;
46
+ }
47
+ }
48
+ return hashStream(fs.createReadStream(filePath));
49
+ }
@@ -1,7 +1,15 @@
1
1
  // @flow strict-local
2
2
 
3
- import type {Server as HTTPOnlyServer} from 'http';
4
- import type {Server as HTTPSServer} from 'https';
3
+ import type {
4
+ Server as HTTPOnlyServer,
5
+ IncomingMessage as HTTPRequest,
6
+ ServerResponse as HTTPResponse,
7
+ } from 'http';
8
+ import type {
9
+ Server as HTTPSServer,
10
+ IncomingMessage as HTTPSRequest,
11
+ ServerResponse as HTTPSResponse,
12
+ } from 'https';
5
13
  import type {Socket} from 'net';
6
14
  import type {FilePath, HTTPSOptions} from '@parcel/types';
7
15
  import type {FileSystem} from '@parcel/fs';
@@ -12,12 +20,16 @@ import nullthrows from 'nullthrows';
12
20
  import {getCertificate, generateCertificate} from './';
13
21
 
14
22
  type CreateHTTPServerOpts = {|
15
- https: ?(HTTPSOptions | boolean),
16
- inputFS: FileSystem,
17
- outputFS: FileSystem,
18
- cacheDir: FilePath,
19
- listener?: (mixed, mixed) => void,
23
+ listener?: (HTTPRequest | HTTPSRequest, HTTPResponse | HTTPSResponse) => void,
20
24
  host?: string,
25
+ ...
26
+ | {|
27
+ https: ?(HTTPSOptions | boolean),
28
+ inputFS: FileSystem,
29
+ outputFS: FileSystem,
30
+ cacheDir: FilePath,
31
+ |}
32
+ | {||},
21
33
  |};
22
34
 
23
35
  export type HTTPServer = HTTPOnlyServer | HTTPSServer;