Add `js_file` rule
Reviewed By: matryoshcow Differential Revision: D3900455 fbshipit-source-id: 61384ade035db978ef3ca258e4c0109bcb450692
This commit is contained in:
parent
8622998335
commit
aef3d8128f
|
@ -138,6 +138,7 @@
|
|||
"art": "^0.10.0",
|
||||
"async": "^2.0.1",
|
||||
"babel-core": "^6.10.4",
|
||||
"babel-generator": "^6.14.0",
|
||||
"babel-plugin-external-helpers": "^6.8.0",
|
||||
"babel-plugin-syntax-trailing-function-commas": "^6.5.0",
|
||||
"babel-plugin-transform-flow-strip-types": "^6.6.5",
|
||||
|
|
|
@ -36,6 +36,13 @@ const validateOpts = declareOpts({
|
|||
type: 'number',
|
||||
default: DEFAULT_MAX_CALL_TIME,
|
||||
},
|
||||
worker: {
|
||||
type: 'string',
|
||||
},
|
||||
methods: {
|
||||
type: 'array',
|
||||
default: [],
|
||||
},
|
||||
});
|
||||
|
||||
const maxConcurrentWorkers = ((cores, override) => {
|
||||
|
@ -55,28 +62,42 @@ const maxConcurrentWorkers = ((cores, override) => {
|
|||
return cores / 2;
|
||||
})(os.cpus().length, process.env.REACT_NATIVE_MAX_WORKERS);
|
||||
|
||||
function makeFarm(worker, methods, timeout) {
|
||||
return workerFarm(
|
||||
{
|
||||
autoStart: true,
|
||||
maxConcurrentCallsPerWorker: 1,
|
||||
maxConcurrentWorkers: maxConcurrentWorkers,
|
||||
maxCallsPerWorker: MAX_CALLS_PER_WORKER,
|
||||
maxCallTime: timeout,
|
||||
maxRetries: MAX_RETRIES,
|
||||
},
|
||||
worker,
|
||||
methods,
|
||||
);
|
||||
}
|
||||
|
||||
class Transformer {
|
||||
constructor(options) {
|
||||
const opts = this._opts = validateOpts(options);
|
||||
|
||||
const {transformModulePath} = opts;
|
||||
|
||||
if (transformModulePath) {
|
||||
if (opts.worker) {
|
||||
this._workers =
|
||||
makeFarm(opts.worker, opts.methods, opts.transformTimeoutInterval);
|
||||
opts.methods.forEach(name => {
|
||||
this[name] = this._workers[name];
|
||||
});
|
||||
}
|
||||
else if (transformModulePath) {
|
||||
this._transformModulePath = require.resolve(transformModulePath);
|
||||
|
||||
this._workers = workerFarm(
|
||||
{
|
||||
autoStart: true,
|
||||
maxConcurrentCallsPerWorker: 1,
|
||||
maxConcurrentWorkers: maxConcurrentWorkers,
|
||||
maxCallsPerWorker: MAX_CALLS_PER_WORKER,
|
||||
maxCallTime: opts.transformTimeoutInterval,
|
||||
maxRetries: MAX_RETRIES,
|
||||
},
|
||||
this._workers = makeFarm(
|
||||
require.resolve('./worker'),
|
||||
['minify', 'transformAndExtractDependencies']
|
||||
['minify', 'transformAndExtractDependencies'],
|
||||
opts.transformTimeoutInterval,
|
||||
);
|
||||
|
||||
this._transform = Promise.denodeify(this._workers.transformAndExtractDependencies);
|
||||
this.minify = Promise.denodeify(this._workers.minify);
|
||||
}
|
||||
|
@ -111,7 +132,7 @@ class Transformer {
|
|||
const timeoutErr = new Error(
|
||||
`TimeoutError: transforming ${fileName} took longer than ` +
|
||||
`${this._opts.transformTimeoutInterval / 1000} seconds.\n` +
|
||||
`You can adjust timeout via the 'transformTimeoutInterval' option`
|
||||
'You can adjust timeout via the \'transformTimeoutInterval\' option'
|
||||
);
|
||||
timeoutErr.type = 'TimeoutError';
|
||||
throw timeoutErr;
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
// RUNS UNTRANSFORMED IN A WORKER PROCESS. ONLY USE NODE 4 COMPATIBLE FEATURES!
|
||||
|
||||
const {traverse, types} = require('babel-core');
|
||||
|
||||
const isRequireCall = (callee, firstArg) =>
|
||||
callee.type !== 'Identifier' ||
|
||||
callee.name !== 'require' ||
|
||||
!firstArg ||
|
||||
firstArg.type !== 'StringLiteral';
|
||||
|
||||
function collectDependencies(ast, code) {
|
||||
let nextIndex = 0;
|
||||
const dependencyIndexes = new Map();
|
||||
|
||||
function getIndex(depencyId) {
|
||||
let index = dependencyIndexes.get(depencyId);
|
||||
if (index !== undefined) {
|
||||
return index;
|
||||
}
|
||||
|
||||
index = nextIndex++;
|
||||
dependencyIndexes.set(depencyId, index);
|
||||
return index;
|
||||
}
|
||||
|
||||
traverse(ast, {
|
||||
CallExpression(path) {
|
||||
const node = path.node;
|
||||
const arg = node.arguments[0];
|
||||
if (isRequireCall(node.callee, arg)) {
|
||||
return;
|
||||
}
|
||||
|
||||
node.arguments[0] = types.numericLiteral(getIndex(arg.value));
|
||||
}
|
||||
});
|
||||
|
||||
return Array.from(dependencyIndexes.keys());
|
||||
}
|
||||
|
||||
module.exports = collectDependencies;
|
|
@ -0,0 +1,104 @@
|
|||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
// RUNS UNTRANSFORMED IN A WORKER PROCESS. ONLY USE NODE 4 COMPATIBLE FEATURES!
|
||||
|
||||
const fs = require('fs');
|
||||
const dirname = require('path').dirname;
|
||||
|
||||
const babel = require('babel-core');
|
||||
const generate = require('babel-generator').default;
|
||||
const series = require('async/series');
|
||||
const mkdirp = require('mkdirp');
|
||||
|
||||
const collectDependencies = require('../JSTransformer/worker/collect-dependencies');
|
||||
const docblock = require('../node-haste/DependencyGraph/docblock');
|
||||
|
||||
function transformModule(infile, options, outfile, callback) {
|
||||
let code, transform;
|
||||
try {
|
||||
transform = require(options.transform);
|
||||
code = fs.readFileSync(infile, 'utf8');
|
||||
} catch (readError) {
|
||||
callback(readError);
|
||||
return;
|
||||
}
|
||||
|
||||
const filename = options.filename || infile;
|
||||
const variants = options.variants || {default: {}};
|
||||
|
||||
const tasks = {};
|
||||
Object.keys(variants).forEach(name => {
|
||||
tasks[name] = cb => transform({
|
||||
filename,
|
||||
sourceCode: code,
|
||||
options: variants[name],
|
||||
}, cb);
|
||||
});
|
||||
|
||||
series(tasks, (error, transformed) => {
|
||||
if (error) {
|
||||
callback(error);
|
||||
return;
|
||||
}
|
||||
|
||||
Object.keys(transformed).forEach(key => {
|
||||
transformed[key] = makeResult(transformed[key].ast, filename, code);
|
||||
});
|
||||
|
||||
const annotations = docblock.parseAsObject(docblock.extract(code));
|
||||
|
||||
const result = {
|
||||
file: filename,
|
||||
code,
|
||||
transformed,
|
||||
hasteID: annotations.providesModule || annotations.provide || null,
|
||||
};
|
||||
|
||||
try {
|
||||
mkdirp.sync(dirname(outfile));
|
||||
fs.writeFileSync(outfile, JSON.stringify(result), 'utf8');
|
||||
} catch (writeError) {
|
||||
callback(writeError);
|
||||
return;
|
||||
}
|
||||
callback(null);
|
||||
});
|
||||
}
|
||||
|
||||
function makeResult(ast, filename, sourceCode) {
|
||||
const dependencies = collectDependencies(ast);
|
||||
const file = wrapModule(ast);
|
||||
|
||||
const gen = generate(file, {
|
||||
comments: false,
|
||||
compact: true,
|
||||
filename,
|
||||
sourceMaps: true,
|
||||
sourceMapTarget: filename,
|
||||
sourceFileName: filename,
|
||||
}, sourceCode);
|
||||
return {code: gen.code, map: gen.map, dependencies};
|
||||
}
|
||||
|
||||
function wrapModule(file) {
|
||||
const p = file.program;
|
||||
const t = babel.types;
|
||||
const factory = t.functionExpression(t.identifier(''), [
|
||||
t.identifier('require'),
|
||||
t.identifier('module'),
|
||||
t.identifier('global'),
|
||||
t.identifier('exports')
|
||||
], t.blockStatement(p.body, p.directives));
|
||||
const def = t.callExpression(t.identifier('__d'), [factory]);
|
||||
return t.file(t.program([t.expressionStatement(def)]));
|
||||
}
|
||||
|
||||
exports.transformModule = transformModule;
|
Loading…
Reference in New Issue