/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
'use strict';
const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const {stableHash} = require('metro-cache');
import type Transformer, {
JsTransformOptions,
JsTransformerConfig,
} from '../JSTransformer/worker';
import type {TransformResult} from './types.flow';
import type {LogEntry} from 'metro-core/src/Logger';
export type {
JsTransformOptions as TransformOptions,
} from '../JSTransformer/worker';
export type Worker = {|
+transform: typeof transform,
|};
export type TransformerFn = (
string,
Buffer,
JsTransformOptions,
) => Promise<TransformResult<>>;
export type TransformerConfig = {
transformerPath: string,
transformerConfig: JsTransformerConfig,
};
type Data = $ReadOnly<{|
result: TransformResult<>,
sha1: string,
transformFileStartLogEntry: LogEntry,
transformFileEndLogEntry: LogEntry,
|}>;
const transformers: {[string]: Transformer} = {};
function getTransformer(
projectRoot: string,
{transformerPath, transformerConfig}: TransformerConfig,
): Transformer {
const transformerKey = stableHash([
projectRoot,
transformerPath,
transformerConfig,
]).toString('hex');
if (transformers[transformerKey]) {
return transformers[transformerKey];
}
// eslint-disable-next-line lint/flow-no-fixme
// $FlowFixMe Transforming fixed types to generic types during refactor.
const Transformer = require(transformerPath);
transformers[transformerKey] = new Transformer(
projectRoot,
transformerConfig,
);
return transformers[transformerKey];
}
async function transform(
filename: string,
transformOptions: JsTransformOptions,
projectRoot: string,
transformerConfig: TransformerConfig,
): Promise<Data> {
const transformer = getTransformer(projectRoot, transformerConfig);
const transformFileStartLogEntry = {
action_name: 'Transforming file',
action_phase: 'start',
file_name: filename,
log_entry_label: 'Transforming file',
start_timestamp: process.hrtime(),
};
const data = fs.readFileSync(path.resolve(projectRoot, filename));
const sha1 = crypto
.createHash('sha1')
.update(data)
.digest('hex');
const result = await transformer.transform(filename, data, transformOptions);
const transformFileEndLogEntry = getEndLogEntry(
transformFileStartLogEntry,
filename,
);
return {
result,
sha1,
transformFileStartLogEntry,
transformFileEndLogEntry,
};
}
function getEndLogEntry(startLogEntry: LogEntry, filename: string): LogEntry {
const timeDelta = process.hrtime(startLogEntry.start_timestamp);
const duration_ms = Math.round((timeDelta[0] * 1e9 + timeDelta[1]) / 1e6);
return {
action_name: 'Transforming file',
action_phase: 'end',
file_name: filename,
duration_ms,
log_entry_label: 'Transforming file',
};
}
((module.exports = {
transform,
}): Worker);