mirror of https://github.com/status-im/metro.git
metro-bundler: @format lib/
Reviewed By: cpojer Differential Revision: D5493458 fbshipit-source-id: 05ac2895125b1419996a66f3ef155bc2cec11c02
This commit is contained in:
parent
521e25bded
commit
14b88b6ad4
|
@ -7,13 +7,16 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const invariant = require('fbjs/lib/invariant');
|
||||
|
||||
type ProcessBatch<TItem, TResult> = (batch: Array<TItem>) => Promise<Array<TResult>>;
|
||||
type ProcessBatch<TItem, TResult> = (
|
||||
batch: Array<TItem>,
|
||||
) => Promise<Array<TResult>>;
|
||||
|
||||
type BatchProcessorOptions = {
|
||||
maximumDelayMs: number,
|
||||
|
@ -35,14 +38,16 @@ type QueueItem<TItem, TResult> = {
|
|||
* processing right away.
|
||||
*/
|
||||
class BatchProcessor<TItem, TResult> {
|
||||
|
||||
_currentProcessCount: number;
|
||||
_options: BatchProcessorOptions;
|
||||
_processBatch: ProcessBatch<TItem, TResult>;
|
||||
_queue: Array<QueueItem<TItem, TResult>>;
|
||||
_timeoutHandle: ?number;
|
||||
|
||||
constructor(options: BatchProcessorOptions, processBatch: ProcessBatch<TItem, TResult>) {
|
||||
constructor(
|
||||
options: BatchProcessorOptions,
|
||||
processBatch: ProcessBatch<TItem, TResult>,
|
||||
) {
|
||||
this._options = options;
|
||||
this._processBatch = processBatch;
|
||||
this._queue = [];
|
||||
|
@ -56,7 +61,10 @@ class BatchProcessor<TItem, TResult> {
|
|||
this._processQueueOnceReady();
|
||||
}
|
||||
|
||||
_onBatchResults(jobs: Array<QueueItem<TItem, TResult>>, results: Array<TResult>) {
|
||||
_onBatchResults(
|
||||
jobs: Array<QueueItem<TItem, TResult>>,
|
||||
results: Array<TResult>,
|
||||
) {
|
||||
invariant(results.length === jobs.length, 'Not enough results returned.');
|
||||
for (let i = 0; i < jobs.length; ++i) {
|
||||
jobs[i].resolve(results[i]);
|
||||
|
@ -104,7 +112,6 @@ class BatchProcessor<TItem, TResult> {
|
|||
this._processQueueOnceReady();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = BatchProcessor;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
@ -76,7 +77,6 @@ type URI = string;
|
|||
* ensures we do a single request at a time to avoid pressuring the I/O.
|
||||
*/
|
||||
class KeyURIFetcher {
|
||||
|
||||
_batchProcessor: BatchProcessor<string, ?URI>;
|
||||
_fetchResultURIs: FetchResultURIs;
|
||||
|
||||
|
@ -96,24 +96,27 @@ class KeyURIFetcher {
|
|||
|
||||
constructor(fetchResultURIs: FetchResultURIs) {
|
||||
this._fetchResultURIs = fetchResultURIs;
|
||||
this._batchProcessor = new BatchProcessor({
|
||||
maximumDelayMs: 10,
|
||||
maximumItems: 500,
|
||||
concurrency: 2,
|
||||
}, this._processKeys.bind(this));
|
||||
this._batchProcessor = new BatchProcessor(
|
||||
{
|
||||
maximumDelayMs: 10,
|
||||
maximumItems: 500,
|
||||
concurrency: 2,
|
||||
},
|
||||
this._processKeys.bind(this),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type KeyedResult = {key: string, result: CachedResult};
|
||||
|
||||
class KeyResultStore {
|
||||
|
||||
_storeResults: StoreResults;
|
||||
_batchProcessor: BatchProcessor<KeyedResult, void>;
|
||||
|
||||
async _processResults(keyResults: Array<KeyedResult>): Promise<Array<void>> {
|
||||
const resultsByKey = new Map(keyResults.map(pair => [pair.key, pair.result]));
|
||||
const resultsByKey = new Map(
|
||||
keyResults.map(pair => [pair.key, pair.result]),
|
||||
);
|
||||
await this._storeResults(resultsByKey);
|
||||
return new Array(keyResults.length);
|
||||
}
|
||||
|
@ -124,16 +127,22 @@ class KeyResultStore {
|
|||
|
||||
constructor(storeResults: StoreResults) {
|
||||
this._storeResults = storeResults;
|
||||
this._batchProcessor = new BatchProcessor({
|
||||
maximumDelayMs: 1000,
|
||||
maximumItems: 100,
|
||||
concurrency: 10,
|
||||
}, this._processResults.bind(this));
|
||||
this._batchProcessor = new BatchProcessor(
|
||||
{
|
||||
maximumDelayMs: 1000,
|
||||
maximumItems: 100,
|
||||
concurrency: 10,
|
||||
},
|
||||
this._processResults.bind(this),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export type TransformProfile = {+dev: boolean, +minify: boolean, +platform: ?string};
|
||||
export type TransformProfile = {
|
||||
+dev: boolean,
|
||||
+minify: boolean,
|
||||
+platform: ?string,
|
||||
};
|
||||
|
||||
function profileKey({dev, minify, platform}: TransformProfile): string {
|
||||
return jsonStableStringify({dev, minify, platform});
|
||||
|
@ -157,14 +166,14 @@ class TransformProfileSet {
|
|||
}
|
||||
|
||||
type FetchFailedDetails =
|
||||
{
|
||||
+statusCode: number,
|
||||
+statusText: string,
|
||||
+type: 'unhandled_http_status',
|
||||
+uri: string,
|
||||
} |
|
||||
{+type: 'invalid_data'} |
|
||||
{+type: 'invalid_key_data', key: string};
|
||||
| {
|
||||
+statusCode: number,
|
||||
+statusText: string,
|
||||
+type: 'unhandled_http_status',
|
||||
+uri: string,
|
||||
}
|
||||
| {+type: 'invalid_data'}
|
||||
| {+type: 'invalid_key_data', key: string};
|
||||
|
||||
class FetchFailedError extends Error {
|
||||
/** Separate object for details allows us to have a type union. */
|
||||
|
@ -179,8 +188,8 @@ class FetchFailedError extends Error {
|
|||
if (details.type === 'unhandled_http_status') {
|
||||
return (
|
||||
`Unexpected HTTP status: ${details.statusCode} ` +
|
||||
JSON.stringify(details.statusText) +
|
||||
` while fetching \`${details.uri}\``
|
||||
JSON.stringify(details.statusText) +
|
||||
` while fetching \`${details.uri}\``
|
||||
);
|
||||
}
|
||||
if (details.type === 'invalid_key_data') {
|
||||
|
@ -210,7 +219,6 @@ function validateCachedResult(cachedResult: mixed): ?CachedResult {
|
|||
}
|
||||
|
||||
class URIBasedGlobalTransformCache {
|
||||
|
||||
_fetcher: KeyURIFetcher;
|
||||
_fetchResultFromURI: FetchResultFromURI;
|
||||
_profileSet: TransformProfileSet;
|
||||
|
@ -249,7 +257,9 @@ class URIBasedGlobalTransformCache {
|
|||
keyOf(props: FetchProps) {
|
||||
const hash = crypto.createHash('sha1');
|
||||
const {sourceCode, localPath, transformOptions} = props;
|
||||
hash.update(this._optionsHasher.getTransformWorkerOptionsDigest(transformOptions));
|
||||
hash.update(
|
||||
this._optionsHasher.getTransformWorkerOptionsDigest(transformOptions),
|
||||
);
|
||||
const cacheKey = props.getTransformCacheKey(transformOptions);
|
||||
hash.update(JSON.stringify(cacheKey));
|
||||
hash.update(JSON.stringify(localPath));
|
||||
|
@ -287,7 +297,9 @@ class URIBasedGlobalTransformCache {
|
|||
* waiting a little time before retring if experience shows it's useful.
|
||||
*/
|
||||
static _fetchResultFromURIWithRetry(uri: string): Promise<CachedResult> {
|
||||
return URIBasedGlobalTransformCache._fetchResultFromURI(uri).catch(error => {
|
||||
return URIBasedGlobalTransformCache._fetchResultFromURI(
|
||||
uri,
|
||||
).catch(error => {
|
||||
if (!URIBasedGlobalTransformCache.shouldRetryAfterThatError(error)) {
|
||||
throw error;
|
||||
}
|
||||
|
@ -311,11 +323,10 @@ class URIBasedGlobalTransformCache {
|
|||
*/
|
||||
static shouldRetryAfterThatError(error: mixed): boolean {
|
||||
return (
|
||||
error instanceof FetchError && error.type === 'request-timeout' || (
|
||||
error instanceof FetchFailedError &&
|
||||
(error instanceof FetchError && error.type === 'request-timeout') ||
|
||||
(error instanceof FetchFailedError &&
|
||||
error.details.type === 'unhandled_http_status' &&
|
||||
(error.details.statusCode === 503 || error.details.statusCode === 502)
|
||||
)
|
||||
(error.details.statusCode === 503 || error.details.statusCode === 502))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -340,11 +351,12 @@ class URIBasedGlobalTransformCache {
|
|||
this._store.store(this.keyOf(props), result);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
URIBasedGlobalTransformCache.fetchResultFromURI =
|
||||
throat(500, URIBasedGlobalTransformCache._fetchResultFromURIWithRetry);
|
||||
URIBasedGlobalTransformCache.fetchResultFromURI = throat(
|
||||
500,
|
||||
URIBasedGlobalTransformCache._fetchResultFromURIWithRetry,
|
||||
);
|
||||
|
||||
class OptionsHasher {
|
||||
_rootPath: string;
|
||||
|
@ -383,15 +395,20 @@ class OptionsHasher {
|
|||
* many different fields including the optional Babel fields, and some serious
|
||||
* cleanup will be necessary to enable rock-solid typing.
|
||||
*/
|
||||
hashTransformWorkerOptions(hash: crypto$Hash, options: TransformWorkerOptions): crypto$Hash {
|
||||
hashTransformWorkerOptions(
|
||||
hash: crypto$Hash,
|
||||
options: TransformWorkerOptions,
|
||||
): crypto$Hash {
|
||||
const {dev, minify, platform, transform, ...unknowns} = options;
|
||||
const unknownKeys = Object.keys(unknowns);
|
||||
if (unknownKeys.length > 0) {
|
||||
const message = `these worker option fields are unknown: ${JSON.stringify(unknownKeys)}`;
|
||||
const message = `these worker option fields are unknown: ${JSON.stringify(
|
||||
unknownKeys,
|
||||
)}`;
|
||||
throw new CannotHashOptionsError(message);
|
||||
}
|
||||
// eslint-disable-next-line no-undef, no-bitwise
|
||||
hash.update(new Buffer([+dev | +minify << 1]));
|
||||
hash.update(new Buffer([+dev | (+minify << 1)]));
|
||||
hash.update(JSON.stringify(platform));
|
||||
return this.hashTransformOptions(hash, transform);
|
||||
}
|
||||
|
@ -404,25 +421,45 @@ class OptionsHasher {
|
|||
* of the cache key as they should not affect the transformation of a single
|
||||
* particular file.
|
||||
*/
|
||||
hashTransformOptions(hash: crypto$Hash, options: TransformOptionsStrict): crypto$Hash {
|
||||
hashTransformOptions(
|
||||
hash: crypto$Hash,
|
||||
options: TransformOptionsStrict,
|
||||
): crypto$Hash {
|
||||
const {
|
||||
generateSourceMaps, dev, hot, inlineRequires, platform, projectRoot,
|
||||
generateSourceMaps,
|
||||
dev,
|
||||
hot,
|
||||
inlineRequires,
|
||||
platform,
|
||||
projectRoot,
|
||||
...unknowns
|
||||
} = options;
|
||||
const unknownKeys = Object.keys(unknowns);
|
||||
if (unknownKeys.length > 0) {
|
||||
const message = `these transform option fields are unknown: ${JSON.stringify(unknownKeys)}`;
|
||||
const message = `these transform option fields are unknown: ${JSON.stringify(
|
||||
unknownKeys,
|
||||
)}`;
|
||||
throw new CannotHashOptionsError(message);
|
||||
}
|
||||
|
||||
hash.update(new Buffer([
|
||||
// eslint-disable-next-line no-bitwise
|
||||
+dev | +generateSourceMaps << 1 | +hot << 2 | +!!inlineRequires << 3,
|
||||
]));
|
||||
hash.update(
|
||||
new Buffer([
|
||||
// eslint-disable-next-line no-bitwise
|
||||
+dev |
|
||||
// eslint-disable-next-line no-bitwise
|
||||
(+generateSourceMaps << 1) |
|
||||
// eslint-disable-next-line no-bitwise
|
||||
(+hot << 2) |
|
||||
// eslint-disable-next-line no-bitwise
|
||||
(+!!inlineRequires << 3),
|
||||
]),
|
||||
);
|
||||
hash.update(JSON.stringify(platform));
|
||||
let blacklistWithLocalPaths = [];
|
||||
if (typeof inlineRequires === 'object') {
|
||||
blacklistWithLocalPaths = this.pathsToLocal(Object.keys(inlineRequires.blacklist));
|
||||
blacklistWithLocalPaths = this.pathsToLocal(
|
||||
Object.keys(inlineRequires.blacklist),
|
||||
);
|
||||
}
|
||||
const localProjectRoot = this.toLocalPath(projectRoot);
|
||||
const optionTuple = [blacklistWithLocalPaths, localProjectRoot];
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
@ -14,7 +15,6 @@
|
|||
import {Writable} from 'stream';
|
||||
|
||||
class JsonReporter<TEvent: {}> {
|
||||
|
||||
_stream: Writable;
|
||||
|
||||
constructor(stream: Writable) {
|
||||
|
@ -37,7 +37,6 @@ class JsonReporter<TEvent: {}> {
|
|||
}
|
||||
this._stream.write(JSON.stringify(event) + '\n');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = JsonReporter;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
@ -24,7 +25,6 @@ type Metadata = {
|
|||
};
|
||||
|
||||
class ModuleTransport {
|
||||
|
||||
name: string;
|
||||
id: number;
|
||||
code: string;
|
||||
|
@ -67,7 +67,6 @@ class ModuleTransport {
|
|||
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = ModuleTransport;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
@ -32,7 +33,7 @@ export type FBIndexMap = IndexMap & FBExtensions;
|
|||
export type SourceMap = IndexMap | MappingsMap;
|
||||
export type FBSourceMap = FBIndexMap | (MappingsMap & FBExtensions);
|
||||
|
||||
function isMappingsMap(map: SourceMap)/*: %checks*/ {
|
||||
function isMappingsMap(map: SourceMap): %checks {
|
||||
return map.mappings !== undefined;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
@ -49,12 +50,14 @@ function getProgressBar(ratio: number, length: number) {
|
|||
);
|
||||
}
|
||||
|
||||
export type TerminalReportableEvent = ReportableEvent | {
|
||||
buildID: string,
|
||||
type: 'bundle_transform_progressed_throttled',
|
||||
transformedFileCount: number,
|
||||
totalFileCount: number,
|
||||
};
|
||||
export type TerminalReportableEvent =
|
||||
| ReportableEvent
|
||||
| {
|
||||
buildID: string,
|
||||
type: 'bundle_transform_progressed_throttled',
|
||||
transformedFileCount: number,
|
||||
totalFileCount: number,
|
||||
};
|
||||
|
||||
type BuildPhase = 'in_progress' | 'done' | 'failed';
|
||||
|
||||
|
@ -63,7 +66,6 @@ type BuildPhase = 'in_progress' | 'done' | 'failed';
|
|||
* This implements the `Reporter` interface from the './reporting' module.
|
||||
*/
|
||||
class TerminalReporter {
|
||||
|
||||
/**
|
||||
* The bundle builds for which we are actively maintaining the status on the
|
||||
* terminal, ie. showing a progress bar. There can be several bundles being
|
||||
|
@ -115,7 +117,7 @@ class TerminalReporter {
|
|||
(100 * ratio).toFixed(1),
|
||||
transformedFileCount,
|
||||
totalFileCount,
|
||||
phase === 'done' ? ', done.' : (phase === 'failed' ? ', failed.' : ''),
|
||||
phase === 'done' ? ', done.' : phase === 'failed' ? ', failed.' : '',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -142,11 +144,14 @@ class TerminalReporter {
|
|||
_logBundleBuildDone(buildID: string) {
|
||||
const progress = this._activeBundles.get(buildID);
|
||||
if (progress != null) {
|
||||
const msg = this._getBundleStatusMessage({
|
||||
...progress,
|
||||
ratio: 1,
|
||||
transformedFileCount: progress.totalFileCount,
|
||||
}, 'done');
|
||||
const msg = this._getBundleStatusMessage(
|
||||
{
|
||||
...progress,
|
||||
ratio: 1,
|
||||
transformedFileCount: progress.totalFileCount,
|
||||
},
|
||||
'done',
|
||||
);
|
||||
this.terminal.log(msg);
|
||||
}
|
||||
}
|
||||
|
@ -166,21 +171,21 @@ class TerminalReporter {
|
|||
port +
|
||||
'.\n\n' +
|
||||
'Keep this packager running while developing on any JS projects. ' +
|
||||
'Feel free to close this tab and run your own packager instance if you ' +
|
||||
'prefer.\n\n' +
|
||||
'Feel free to close this tab and run your own packager instance ' +
|
||||
'if you prefer.\n\n' +
|
||||
'https://github.com/facebook/react-native',
|
||||
{
|
||||
marginLeft: 1,
|
||||
marginRight: 1,
|
||||
paddingBottom: 1,
|
||||
}
|
||||
)
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
this.terminal.log(
|
||||
'Looking for JS files in\n ',
|
||||
chalk.dim(projectRoots.join('\n ')),
|
||||
'\n'
|
||||
'\n',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -188,9 +193,11 @@ class TerminalReporter {
|
|||
if (error.code === 'EADDRINUSE') {
|
||||
this.terminal.log(
|
||||
chalk.bgRed.bold(' ERROR '),
|
||||
chalk.red("Packager can't listen on port", chalk.bold(port))
|
||||
chalk.red("Packager can't listen on port", chalk.bold(port)),
|
||||
);
|
||||
this.terminal.log(
|
||||
'Most likely another process is already using this port',
|
||||
);
|
||||
this.terminal.log('Most likely another process is already using this port');
|
||||
this.terminal.log('Run the following command to find out which process:');
|
||||
this.terminal.log('\n ', chalk.bold('lsof -i :' + port), '\n');
|
||||
this.terminal.log('Then, you can either shut down the other process:');
|
||||
|
@ -258,9 +265,9 @@ class TerminalReporter {
|
|||
const he = error.hasteError;
|
||||
const message =
|
||||
'ambiguous resolution: module `' +
|
||||
`${error.fromModulePath}\` tries to require \`${he.hasteName}\`, but ` +
|
||||
`there are several files providing this module. You can delete or ` +
|
||||
'fix them: \n\n' +
|
||||
`${error.fromModulePath}\` tries to require \`${he.hasteName}\`, ` +
|
||||
`but there are several files providing this module. You can delete ` +
|
||||
'or fix them: \n\n' +
|
||||
Object.keys(he.duplicatesSet)
|
||||
.sort()
|
||||
.map(dupFilePath => ` * \`${dupFilePath}\`\n`)
|
||||
|
@ -269,10 +276,11 @@ class TerminalReporter {
|
|||
return;
|
||||
}
|
||||
|
||||
let message = (error.snippet == null && error.stack != null)
|
||||
? error.stack
|
||||
//$FlowFixMe T19379628
|
||||
: error.message;
|
||||
let message =
|
||||
error.snippet == null && error.stack != null
|
||||
? error.stack
|
||||
: //$FlowFixMe T19379628
|
||||
error.message;
|
||||
//$FlowFixMe T19379628
|
||||
if (error.filename && !message.includes(error.filename)) {
|
||||
//$FlowFixMe T19379628
|
||||
|
@ -305,13 +313,15 @@ class TerminalReporter {
|
|||
* we know the `totalCount` is going to progressively increase as well. We
|
||||
* also prevent the ratio from going backwards.
|
||||
*/
|
||||
_updateBundleProgress(
|
||||
{buildID, transformedFileCount, totalFileCount}: {
|
||||
buildID: string,
|
||||
transformedFileCount: number,
|
||||
totalFileCount: number,
|
||||
},
|
||||
) {
|
||||
_updateBundleProgress({
|
||||
buildID,
|
||||
transformedFileCount,
|
||||
totalFileCount,
|
||||
}: {
|
||||
buildID: string,
|
||||
transformedFileCount: number,
|
||||
totalFileCount: number,
|
||||
}) {
|
||||
const currentProgress = this._activeBundles.get(buildID);
|
||||
if (currentProgress == null) {
|
||||
return;
|
||||
|
@ -377,12 +387,14 @@ class TerminalReporter {
|
|||
* different callsites overriding each other status messages.
|
||||
*/
|
||||
_getStatusMessage(): string {
|
||||
return [
|
||||
this._getDepGraphStatusMessage(),
|
||||
].concat(Array.from(this._activeBundles.entries()).map(
|
||||
([_, progress]) =>
|
||||
this._getBundleStatusMessage(progress, 'in_progress'),
|
||||
)).filter(str => str != null).join('\n');
|
||||
return [this._getDepGraphStatusMessage()]
|
||||
.concat(
|
||||
Array.from(this._activeBundles.entries()).map(([_, progress]) =>
|
||||
this._getBundleStatusMessage(progress, 'in_progress'),
|
||||
),
|
||||
)
|
||||
.filter(str => str != null)
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -394,7 +406,6 @@ class TerminalReporter {
|
|||
this._updateState(event);
|
||||
this.terminal.status(this._getStatusMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = TerminalReporter;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
@ -15,14 +17,22 @@ const jsonStableStringify = require('json-stable-stringify');
|
|||
const transformCache = new Map();
|
||||
|
||||
const transformCacheKeyOf = props =>
|
||||
props.filePath + '-' + crypto.createHash('md5')
|
||||
props.filePath +
|
||||
'-' +
|
||||
crypto
|
||||
.createHash('md5')
|
||||
.update(props.sourceCode)
|
||||
.update(props.getTransformCacheKey(props.sourceCode, props.filePath, props.transformOptions))
|
||||
.update(
|
||||
props.getTransformCacheKey(
|
||||
props.sourceCode,
|
||||
props.filePath,
|
||||
props.transformOptions,
|
||||
),
|
||||
)
|
||||
.update(jsonStableStringify(props.transformOptions || {}))
|
||||
.digest('hex');
|
||||
|
||||
class TransformCacheMock {
|
||||
|
||||
constructor() {
|
||||
this.mock = {
|
||||
lastWrite: null,
|
||||
|
@ -39,9 +49,11 @@ class TransformCacheMock {
|
|||
}
|
||||
|
||||
readSync(props) {
|
||||
return {result: transformCache.get(transformCacheKeyOf(props)), outdatedDependencies: []};
|
||||
return {
|
||||
result: transformCache.get(transformCacheKeyOf(props)),
|
||||
outdatedDependencies: [],
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = {mocked: () => new TransformCacheMock()};
|
||||
|
|
|
@ -5,7 +5,10 @@
|
|||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = function(declared) {
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
@ -14,7 +16,6 @@ jest.useRealTimers();
|
|||
const BatchProcessor = require('../BatchProcessor');
|
||||
|
||||
describe('BatchProcessor', () => {
|
||||
|
||||
const options = {
|
||||
maximumDelayMs: 500,
|
||||
maximumItems: 3,
|
||||
|
@ -27,40 +28,50 @@ describe('BatchProcessor', () => {
|
|||
const batches = [];
|
||||
let concurrency = 0;
|
||||
let maxConcurrency = 0;
|
||||
const bp = new BatchProcessor(options, items => new Promise(resolve => {
|
||||
++concurrency;
|
||||
expect(concurrency).toBeLessThanOrEqual(options.concurrency);
|
||||
maxConcurrency = Math.max(maxConcurrency, concurrency);
|
||||
batches.push(items);
|
||||
setTimeout(() => {
|
||||
resolve(items.map(transform));
|
||||
--concurrency;
|
||||
}, 0);
|
||||
}));
|
||||
const bp = new BatchProcessor(
|
||||
options,
|
||||
items =>
|
||||
new Promise(resolve => {
|
||||
++concurrency;
|
||||
expect(concurrency).toBeLessThanOrEqual(options.concurrency);
|
||||
maxConcurrency = Math.max(maxConcurrency, concurrency);
|
||||
batches.push(items);
|
||||
setTimeout(() => {
|
||||
resolve(items.map(transform));
|
||||
--concurrency;
|
||||
}, 0);
|
||||
}),
|
||||
);
|
||||
const results = [];
|
||||
await Promise.all(input.map(e => bp.queue(e).then(
|
||||
res => results.push(res),
|
||||
error => process.nextTick(() => { throw error; }),
|
||||
)));
|
||||
expect(batches).toEqual([
|
||||
[1, 2, 3],
|
||||
[4, 5, 6],
|
||||
[7, 8],
|
||||
]);
|
||||
await Promise.all(
|
||||
input.map(e =>
|
||||
bp.queue(e).then(
|
||||
res => results.push(res),
|
||||
error =>
|
||||
process.nextTick(() => {
|
||||
throw error;
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
expect(batches).toEqual([[1, 2, 3], [4, 5, 6], [7, 8]]);
|
||||
expect(maxConcurrency).toEqual(options.concurrency);
|
||||
expect(results).toEqual(input.map(transform));
|
||||
});
|
||||
|
||||
it('report errors', async () => {
|
||||
const error = new Error('oh noes');
|
||||
const bp = new BatchProcessor(options, items => new Promise((_, reject) => {
|
||||
setTimeout(reject.bind(null, error), 0);
|
||||
}));
|
||||
let receivedError;
|
||||
await bp.queue('foo').catch(
|
||||
err => { receivedError = err; },
|
||||
const bp = new BatchProcessor(
|
||||
options,
|
||||
items =>
|
||||
new Promise((_, reject) => {
|
||||
setTimeout(reject.bind(null, error), 0);
|
||||
}),
|
||||
);
|
||||
let receivedError;
|
||||
await bp.queue('foo').catch(err => {
|
||||
receivedError = err;
|
||||
});
|
||||
expect(receivedError).toBe(error);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
@ -18,7 +20,9 @@ const {URIBasedGlobalTransformCache} = require('../GlobalTransformCache');
|
|||
const FetchError = require('node-fetch/lib/fetch-error');
|
||||
const path = require('path');
|
||||
|
||||
async function fetchResultURIs(keys: Array<string>): Promise<Map<string, string>> {
|
||||
async function fetchResultURIs(
|
||||
keys: Array<string>,
|
||||
): Promise<Map<string, string>> {
|
||||
return new Map(keys.map(key => [key, `http://globalcache.com/${key}`]));
|
||||
}
|
||||
|
||||
|
@ -31,7 +35,6 @@ async function fetchResultFromURI(uri: string): Promise<?CachedResult> {
|
|||
}
|
||||
|
||||
describe('GlobalTransformCache', () => {
|
||||
|
||||
it('fetches results', async () => {
|
||||
const cache = new URIBasedGlobalTransformCache({
|
||||
fetchResultFromURI,
|
||||
|
@ -53,22 +56,24 @@ describe('GlobalTransformCache', () => {
|
|||
projectRoot: path.join(__dirname, 'root'),
|
||||
},
|
||||
};
|
||||
const result = await Promise.all([cache.fetch({
|
||||
localPath: 'some/where/foo.js',
|
||||
sourceCode: '/* beep */',
|
||||
getTransformCacheKey: () => 'abcd',
|
||||
transformOptions,
|
||||
}), cache.fetch({
|
||||
localPath: 'some/where/else/bar.js',
|
||||
sourceCode: '/* boop */',
|
||||
getTransformCacheKey: () => 'abcd',
|
||||
transformOptions,
|
||||
})]);
|
||||
const result = await Promise.all([
|
||||
cache.fetch({
|
||||
localPath: 'some/where/foo.js',
|
||||
sourceCode: '/* beep */',
|
||||
getTransformCacheKey: () => 'abcd',
|
||||
transformOptions,
|
||||
}),
|
||||
cache.fetch({
|
||||
localPath: 'some/where/else/bar.js',
|
||||
sourceCode: '/* boop */',
|
||||
getTransformCacheKey: () => 'abcd',
|
||||
transformOptions,
|
||||
}),
|
||||
]);
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('fetchResultFromURI', () => {
|
||||
|
||||
const defaultFetchMockImpl = async uri => ({
|
||||
status: 200,
|
||||
json: async () => ({
|
||||
|
@ -84,8 +89,9 @@ describe('GlobalTransformCache', () => {
|
|||
|
||||
it('fetches result', async () => {
|
||||
mockFetch.mockImplementation(defaultFetchMockImpl);
|
||||
const result = await URIBasedGlobalTransformCache
|
||||
.fetchResultFromURI('http://globalcache.com/foo');
|
||||
const result = await URIBasedGlobalTransformCache.fetchResultFromURI(
|
||||
'http://globalcache.com/foo',
|
||||
);
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
@ -94,11 +100,10 @@ describe('GlobalTransformCache', () => {
|
|||
mockFetch.mockImplementation(defaultFetchMockImpl);
|
||||
throw new FetchError('timeout!', 'request-timeout');
|
||||
});
|
||||
const result = await URIBasedGlobalTransformCache
|
||||
.fetchResultFromURI('http://globalcache.com/foo');
|
||||
const result = await URIBasedGlobalTransformCache.fetchResultFromURI(
|
||||
'http://globalcache.com/foo',
|
||||
);
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
@ -12,10 +14,13 @@
|
|||
jest.mock('readline', () => ({
|
||||
moveCursor: (stream, dx, dy) => {
|
||||
const {cursor, columns} = stream;
|
||||
stream.cursor = Math.max(cursor - cursor % columns, cursor + dx) + dy * columns;
|
||||
stream.cursor =
|
||||
Math.max(cursor - cursor % columns, cursor + dx) + dy * columns;
|
||||
},
|
||||
clearLine: (stream, dir) => {
|
||||
if (dir !== 0) {throw new Error('unsupported');}
|
||||
if (dir !== 0) {
|
||||
throw new Error('unsupported');
|
||||
}
|
||||
const {cursor, columns} = stream;
|
||||
const curLine = cursor - cursor % columns;
|
||||
const nextLine = curLine + columns;
|
||||
|
@ -26,7 +31,6 @@ jest.mock('readline', () => ({
|
|||
}));
|
||||
|
||||
describe('Terminal', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
});
|
||||
|
@ -46,7 +50,7 @@ describe('Terminal', () => {
|
|||
write(str) {
|
||||
for (let i = 0; i < str.length; ++i) {
|
||||
if (str[i] === '\n') {
|
||||
this.cursor = this.cursor - (this.cursor % columns) + columns;
|
||||
this.cursor = this.cursor - this.cursor % columns + columns;
|
||||
} else {
|
||||
this.buffer[this.cursor] = str[i];
|
||||
++this.cursor;
|
||||
|
@ -81,10 +85,14 @@ describe('Terminal', () => {
|
|||
terminal.status('status2');
|
||||
terminal.log('bar');
|
||||
jest.runAllTimers();
|
||||
expect(stream.buffer.join('').trim()).toEqual('foo bar status2');
|
||||
expect(stream.buffer.join('').trim()).toEqual(
|
||||
'foo bar status2',
|
||||
);
|
||||
terminal.log('beep');
|
||||
jest.runAllTimers();
|
||||
expect(stream.buffer.join('').trim()).toEqual('foo bar beep status2');
|
||||
expect(stream.buffer.join('').trim()).toEqual(
|
||||
'foo bar beep status2',
|
||||
);
|
||||
});
|
||||
|
||||
it('updates status when logging, multi-line', () => {
|
||||
|
@ -93,8 +101,9 @@ describe('Terminal', () => {
|
|||
terminal.status('status\nanother');
|
||||
terminal.log('bar');
|
||||
jest.runAllTimers();
|
||||
expect(stream.buffer.join('').trim())
|
||||
.toEqual('foo bar status another');
|
||||
expect(stream.buffer.join('').trim()).toEqual(
|
||||
'foo bar status another',
|
||||
);
|
||||
});
|
||||
|
||||
it('persists status', () => {
|
||||
|
@ -106,5 +115,4 @@ describe('Terminal', () => {
|
|||
jest.runAllTimers();
|
||||
expect(stream.buffer.join('').trim()).toEqual('foo status bar');
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
@ -43,13 +45,14 @@ function cartesianProductOf(a1, a2) {
|
|||
}
|
||||
|
||||
describe('TransformCaching.FileBasedCache', () => {
|
||||
|
||||
let transformCache;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
mockFS.clear();
|
||||
transformCache = new (require('../TransformCaching').FileBasedCache)('/cache');
|
||||
transformCache = new (require('../TransformCaching')).FileBasedCache(
|
||||
'/cache',
|
||||
);
|
||||
});
|
||||
|
||||
it('is caching different files and options separately', () => {
|
||||
|
@ -60,8 +63,10 @@ describe('TransformCaching.FileBasedCache', () => {
|
|||
getTransformCacheKey: () => 'abcdef',
|
||||
filePath,
|
||||
transformOptions,
|
||||
transformOptionsKey: crypto.createHash('md5')
|
||||
.update(jsonStableStringify(transformOptions)).digest('hex'),
|
||||
transformOptionsKey: crypto
|
||||
.createHash('md5')
|
||||
.update(jsonStableStringify(transformOptions))
|
||||
.digest('hex'),
|
||||
result: {
|
||||
code: `/* result for ${key} */`,
|
||||
dependencies: ['foo', `dep of ${key}`],
|
||||
|
@ -74,9 +79,7 @@ describe('TransformCaching.FileBasedCache', () => {
|
|||
['/some/project/sub/dir/file.js', '/some/project/other.js'],
|
||||
[{foo: 1}, {foo: 2}],
|
||||
);
|
||||
allCases.forEach(
|
||||
entry => transformCache.writeSync(argsFor(entry)),
|
||||
);
|
||||
allCases.forEach(entry => transformCache.writeSync(argsFor(entry)));
|
||||
allCases.forEach(entry => {
|
||||
const args = argsFor(entry);
|
||||
const {result} = args;
|
||||
|
@ -129,5 +132,4 @@ describe('TransformCaching.FileBasedCache', () => {
|
|||
expect(cachedResult.outdatedDependencies).toEqual(['foo', 'bar']);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -5,7 +5,10 @@
|
|||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
|
@ -82,12 +85,20 @@ function formatBanner(message, options) {
|
|||
|
||||
var horizontalBorderLine = repeatString(
|
||||
HORIZONTAL_LINE,
|
||||
width - marginLeft - marginRight - 2
|
||||
width - marginLeft - marginRight - 2,
|
||||
);
|
||||
var top = spaces(marginLeft) + TOP_LEFT + horizontalBorderLine + TOP_RIGHT +
|
||||
var top =
|
||||
spaces(marginLeft) +
|
||||
TOP_LEFT +
|
||||
horizontalBorderLine +
|
||||
TOP_RIGHT +
|
||||
spaces(marginRight);
|
||||
var bottom =
|
||||
spaces(marginLeft) +
|
||||
BOTTOM_LEFT +
|
||||
horizontalBorderLine +
|
||||
BOTTOM_RIGHT +
|
||||
spaces(marginRight);
|
||||
var bottom = spaces(marginLeft) + BOTTOM_LEFT + horizontalBorderLine +
|
||||
BOTTOM_RIGHT + spaces(marginRight);
|
||||
return _.flattenDeep([top, bodyLines, bottom]).join('\n');
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
@ -17,7 +18,10 @@ const {isMappingsMap} = require('./SourceMap');
|
|||
|
||||
import type {SourceMap} from './SourceMap';
|
||||
|
||||
function relativizeSourceMapInternal(sourceMap: SourceMap, sourcesRoot: string) {
|
||||
function relativizeSourceMapInternal(
|
||||
sourceMap: SourceMap,
|
||||
sourcesRoot: string,
|
||||
) {
|
||||
if (!isMappingsMap(sourceMap)) {
|
||||
for (let i = 0; i < sourceMap.sections.length; i++) {
|
||||
relativizeSourceMapInternal(sourceMap.sections[i].map, sourcesRoot);
|
||||
|
@ -29,7 +33,10 @@ function relativizeSourceMapInternal(sourceMap: SourceMap, sourcesRoot: string)
|
|||
}
|
||||
}
|
||||
|
||||
function relativizeSourceMap(sourceMap: SourceMap, sourcesRoot?: string): SourceMap {
|
||||
function relativizeSourceMap(
|
||||
sourceMap: SourceMap,
|
||||
sourcesRoot?: string,
|
||||
): SourceMap {
|
||||
if (!sourcesRoot) {
|
||||
return sourceMap;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
@ -23,53 +24,68 @@ export type GlobalCacheDisabledReason = 'too_many_errors' | 'too_many_misses';
|
|||
* A tagged union of all the actions that may happen and we may want to
|
||||
* report to the tool user.
|
||||
*/
|
||||
export type ReportableEvent = {
|
||||
port: number,
|
||||
projectRoots: $ReadOnlyArray<string>,
|
||||
type: 'initialize_packager_started',
|
||||
} | {
|
||||
type: 'initialize_packager_done',
|
||||
} | {
|
||||
type: 'initialize_packager_failed',
|
||||
port: number,
|
||||
error: Error,
|
||||
} | {
|
||||
buildID: string,
|
||||
type: 'bundle_build_done',
|
||||
} | {
|
||||
buildID: string,
|
||||
type: 'bundle_build_failed',
|
||||
} | {
|
||||
buildID: string,
|
||||
bundleOptions: BundleOptions,
|
||||
type: 'bundle_build_started',
|
||||
} | {
|
||||
error: Error,
|
||||
type: 'bundling_error',
|
||||
} | {
|
||||
type: 'dep_graph_loading',
|
||||
} | {
|
||||
type: 'dep_graph_loaded',
|
||||
} | {
|
||||
buildID: string,
|
||||
type: 'bundle_transform_progressed',
|
||||
transformedFileCount: number,
|
||||
totalFileCount: number,
|
||||
} | {
|
||||
type: 'global_cache_error',
|
||||
error: Error,
|
||||
} | {
|
||||
type: 'global_cache_disabled',
|
||||
reason: GlobalCacheDisabledReason,
|
||||
} | {
|
||||
type: 'transform_cache_reset',
|
||||
} | {
|
||||
type: 'worker_stdout_chunk',
|
||||
chunk: string,
|
||||
} | {
|
||||
type: 'worker_stderr_chunk',
|
||||
chunk: string,
|
||||
};
|
||||
export type ReportableEvent =
|
||||
| {
|
||||
port: number,
|
||||
projectRoots: $ReadOnlyArray<string>,
|
||||
type: 'initialize_packager_started',
|
||||
}
|
||||
| {
|
||||
type: 'initialize_packager_done',
|
||||
}
|
||||
| {
|
||||
type: 'initialize_packager_failed',
|
||||
port: number,
|
||||
error: Error,
|
||||
}
|
||||
| {
|
||||
buildID: string,
|
||||
type: 'bundle_build_done',
|
||||
}
|
||||
| {
|
||||
buildID: string,
|
||||
type: 'bundle_build_failed',
|
||||
}
|
||||
| {
|
||||
buildID: string,
|
||||
bundleOptions: BundleOptions,
|
||||
type: 'bundle_build_started',
|
||||
}
|
||||
| {
|
||||
error: Error,
|
||||
type: 'bundling_error',
|
||||
}
|
||||
| {
|
||||
type: 'dep_graph_loading',
|
||||
}
|
||||
| {
|
||||
type: 'dep_graph_loaded',
|
||||
}
|
||||
| {
|
||||
buildID: string,
|
||||
type: 'bundle_transform_progressed',
|
||||
transformedFileCount: number,
|
||||
totalFileCount: number,
|
||||
}
|
||||
| {
|
||||
type: 'global_cache_error',
|
||||
error: Error,
|
||||
}
|
||||
| {
|
||||
type: 'global_cache_disabled',
|
||||
reason: GlobalCacheDisabledReason,
|
||||
}
|
||||
| {
|
||||
type: 'transform_cache_reset',
|
||||
}
|
||||
| {
|
||||
type: 'worker_stdout_chunk',
|
||||
chunk: string,
|
||||
}
|
||||
| {
|
||||
type: 'worker_stderr_chunk',
|
||||
chunk: string,
|
||||
};
|
||||
|
||||
/**
|
||||
* Code across the application takes a reporter as an option and calls the
|
||||
|
@ -99,7 +115,11 @@ export type Reporter = {
|
|||
* calling this, add a new type of ReportableEvent instead, and implement a
|
||||
* proper handler in the reporter(s).
|
||||
*/
|
||||
function logWarning(terminal: Terminal, format: string, ...args: Array<mixed>): void {
|
||||
function logWarning(
|
||||
terminal: Terminal,
|
||||
format: string,
|
||||
...args: Array<mixed>
|
||||
): void {
|
||||
const str = util.format(format, ...args);
|
||||
terminal.log('%s: %s', chalk.yellow('warning'), str);
|
||||
}
|
||||
|
@ -107,7 +127,11 @@ function logWarning(terminal: Terminal, format: string, ...args: Array<mixed>):
|
|||
/**
|
||||
* Similar to `logWarning`, but for messages that require the user to act.
|
||||
*/
|
||||
function logError(terminal: Terminal, format: string, ...args: Array<mixed>): void {
|
||||
function logError(
|
||||
terminal: Terminal,
|
||||
format: string,
|
||||
...args: Array<mixed>
|
||||
): void {
|
||||
const str = util.format(format, ...args);
|
||||
terminal.log('%s: %s', chalk.red('error'), str);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
|
Loading…
Reference in New Issue