Permalink
Browse files

Stronger typing for transformers

Reviewed By: jeanlauliac

Differential Revision: D5006679

fbshipit-source-id: 795c60db363fb53bc74697e4befe50995e9b97a7
  • Loading branch information...
davidaurelio authored and facebook-github-bot committed May 9, 2017
1 parent 3dfed2e commit 73fc439bc03b457d7bcebdb3fd230e470af52e38
View
@@ -51,13 +51,14 @@ type GeneratorOptions = {
};
type InlinePlugin = string | {} | () => {};
type _Plugins = Array<string | Object | [InlinePlugin] | [InlinePlugin, mixed]>;
// based on https://babeljs.io/docs/usage/options/ -- 2016-11-11
type __TransformOptions = {
filename?: string,
filenameRelative?: string,
presets?: Array<string | Object>,
plugins?: Array<string | Object | [InlinePlugin] | [InlinePlugin, mixed]>,
plugins?: _Plugins,
parserOpts?: BabylonOptions,
generatorOpts?: GeneratorOptions,
highlightCode?: boolean,
@@ -92,11 +93,13 @@ declare class _Ast {}
type TransformResult = {
ast: _Ast,
code: ?string,
ignored: boolean,
map: ?_SourceMap,
};
type VisitFn = <State>(path: Object, state: State) => any;
declare module 'babel-core' {
declare type Plugins = _Plugins;
declare type SourceMap = _SourceMap;
declare type Ast = _Ast;
declare type TransformOptions = _TransformOptions;
View
@@ -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.
*
* @flow
*/
'use strict';
@@ -24,15 +26,20 @@ babelRegisterOnly([]);
const transformer = require('../packager/transformer.js');
module.exports = {
process(src, file) {
process(src/*: string*/, file/*: string*/) {
if (nodeFiles.test(file)) { // node specific transforms only
return babel.transform(
src,
Object.assign({filename: file}, nodeOptions)
).code;
}
return transformer.transform(src, file, {inlineRequires: true}).code;
return transformer.transform(src, file, {
dev: true,
inlineRequires: true,
platform: '',
projectRoot: '',
}).code;
},
getCacheKey: createCacheKeyFunction([
@@ -138,6 +138,8 @@ type Options = {|
+watch: boolean,
|};
const {hasOwnProperty} = Object;
class Bundler {
_opts: Options;
@@ -673,7 +675,7 @@ class Bundler {
const preloaded =
module.path === entryFilePath ||
isPolyfill ||
preloadedModules && preloadedModules.hasOwnProperty(module.path);
preloadedModules && hasOwnProperty.call(preloadedModules, module.path);
return new ModuleTransport({
name,
@@ -20,7 +20,7 @@ const path = require('path');
const util = require('util');
const workerFarm = require('../worker-farm');
import type {Data as TransformData, Options as TransformOptions} from './worker/worker';
import type {Data as TransformData, Options as WorkerOptions} from './worker/worker';
import type {MappingsMap} from '../lib/SourceMap';
// Avoid memory leaks caused in workers. This number seems to be a good enough number
@@ -63,7 +63,7 @@ class Transformer {
transform: string,
filename: string,
sourceCode: string,
options: ?TransformOptions,
options: ?WorkerOptions,
) => Promise<TransformData>;
minify: (
filename: string,
@@ -97,7 +97,7 @@ class Transformer {
this._workers && workerFarm.end(this._workers);
}
transformFile(fileName: string, code: string, options: TransformOptions) {
transformFile(fileName: string, code: string, options: WorkerOptions) {
if (!this._transform) {
return Promise.reject(new Error('No transform module'));
}
@@ -11,14 +11,15 @@
'use strict';
const babelRegisterOnly = require('../../../babelRegisterOnly');
const constantFolding = require('./constant-folding');
const extractDependencies = require('./extract-dependencies');
const inline = require('./inline');
const invariant = require('fbjs/lib/invariant');
const minify = require('./minify');
import type {LogEntry} from '../../Logger/Types';
import type {Ast, SourceMap as MappingsMap} from 'babel-core';
import type {Ast, Plugins as BabelPlugins, SourceMap as MappingsMap} from 'babel-core';
export type TransformedCode = {
code: string,
@@ -27,15 +28,18 @@ export type TransformedCode = {
map?: ?MappingsMap,
};
type Transformer = {
export type Transformer<ExtraOptions: {} = {}> = {
transform: (
filename: string,
sourceCode: string,
options: ?{},
) => {ast: ?Ast, code: string, map: ?MappingsMap}
options: ExtraOptions & TransformOptions,
plugins?: BabelPlugins,
) => {ast: ?Ast, code: string, map: ?MappingsMap},
getCacheKey: TransformOptionsStrict => string,
};
export type TransformOptions = {|
export type TransformOptionsStrict = {|
+dev: boolean,
+generateSourceMaps: boolean,
+hot: boolean,
@@ -44,11 +48,20 @@ export type TransformOptions = {|
+projectRoot: string,
|};
export type TransformOptions = {
+dev?: boolean,
+generateSourceMaps?: boolean,
+hot?: boolean,
+inlineRequires?: {+blacklist: {[string]: true}} | boolean,
+platform: string,
+projectRoot: string,
};
export type Options = {|
+dev: boolean,
+minify: boolean,
+platform: string,
+transform: TransformOptions,
+transform: TransformOptionsStrict,
|};
export type Data = {
@@ -63,7 +76,7 @@ type Callback = (
) => mixed;
function transformCode(
transformer: Transformer,
transformer: Transformer<*>,
filename: string,
sourceCode: string,
options: Options,
@@ -144,8 +157,9 @@ exports.transformAndExtractDependencies = (
options: Options,
callback: Callback,
) => {
babelRegisterOnly([transform]);
/* $FlowFixMe: impossible to type a dynamic require */
const transformModule = require(transform);
const transformModule: Transformer<*> = require(transform);
transformCode(transformModule, filename, sourceCode, options, callback);
};
@@ -13,6 +13,7 @@
import type {MappingsMap, SourceMap} from '../lib/SourceMap';
import type {Ast} from 'babel-core';
import type {Console} from 'console';
export type {Transformer} from '../JSTransformer/worker/worker.js';
export type Callback<A = void, B = void>
= (Error => void)
@@ -105,15 +106,6 @@ export type TransformerResult = {|
map: ?MappingsMap,
|};
export type Transformer = {
transform: (
sourceCode: string,
filename: string,
options: ?{},
plugins?: Array<string | Object | [string | Object, any]>,
) => {ast: ?Ast, code: string, map: ?MappingsMap}
};
export type TransformResult = {|
code: string,
dependencies: Array<string>,
@@ -80,16 +80,25 @@ describe('transforming JS modules:', () => {
});
});
const defaults = {
dev: false,
generateSourceMaps: true,
hot: false,
inlineRequires: false,
platform: '',
projectRoot: '',
};
it('calls the passed-in transform function with code, file name, and options ' +
'for all passed in variants',
done => {
const variants = {dev: {dev: true}, prod: {dev: false}};
transformModule(sourceCode, options(variants), () => {
expect(transformer.transform)
.toBeCalledWith(sourceCode, filename, variants.dev);
.toBeCalledWith(sourceCode, filename, {...defaults, ...variants.dev});
expect(transformer.transform)
.toBeCalledWith(sourceCode, filename, variants.prod);
.toBeCalledWith(sourceCode, filename, {...defaults, ...variants.prod});
done();
});
},
@@ -12,6 +12,7 @@
const JsFileWrapping = require('./JsFileWrapping');
const asyncify = require('async/asyncify');
const collectDependencies = require('./collect-dependencies');
const defaults = require('../../../defaults');
const docblock = require('../../node-haste/DependencyGraph/docblock');
@@ -34,10 +35,18 @@ import type {
export type TransformOptions = {|
filename: string,
polyfill?: boolean,
transformer: Transformer,
transformer: Transformer<*>,
variants?: TransformVariants,
|};
const defaultTransformOptions = {
dev: true,
generateSourceMaps: true,
hot: false,
inlineRequires: false,
platform: '',
projectRoot: '',
};
const defaultVariants = {default: {}};
const ASSET_EXTENSIONS = new Set(defaults.assetExts);
@@ -61,17 +70,12 @@ function transformModule(
const {filename, transformer, variants = defaultVariants} = options;
const tasks = {};
Object.keys(variants).forEach(name => {
tasks[name] = cb => {
try {
cb(null, transformer.transform(
code,
filename,
variants[name],
));
} catch (error) {
cb(error, null);
}
};
tasks[name] = asyncify(() => transformer.transform(
code,
filename,
{...defaultTransformOptions, ...variants[name]},
)
);
});
series(tasks, (error, results: {[key: string]: TransformerResult}) => {
@@ -24,7 +24,7 @@ const throat = require('throat');
import type {
Options as TransformWorkerOptions,
TransformOptions,
TransformOptionsStrict,
} from '../JSTransformer/worker/worker';
import type {CachedResult, GetTransformCacheKey} from './TransformCache';
@@ -381,7 +381,7 @@ class OptionsHasher {
* of the cache key as they should not affect the transformation of a single
* particular file.
*/
hashTransformOptions(hash: crypto$Hash, options: TransformOptions): crypto$Hash {
hashTransformOptions(hash: crypto$Hash, options: TransformOptionsStrict): crypto$Hash {
const {
generateSourceMaps, dev, hot, inlineRequires, platform, projectRoot,
...unknowns,
@@ -20,7 +20,7 @@ const rimraf = require('rimraf');
const terminal = require('../lib/terminal');
const writeFileAtomicSync = require('write-file-atomic').sync;
import type {Options as TransformOptions} from '../JSTransformer/worker/worker';
import type {Options as WorkerOptions} from '../JSTransformer/worker/worker';
import type {MappingsMap} from './SourceMap';
import type {Reporter} from './reporting';
@@ -58,7 +58,7 @@ function hashSourceCode(props: {
filePath: string,
sourceCode: string,
getTransformCacheKey: GetTransformCacheKey,
transformOptions: TransformOptions,
transformOptions: WorkerOptions,
transformOptionsKey: string,
}): string {
return crypto.createHash('sha1')
@@ -134,7 +134,7 @@ function writeSync(props: {
filePath: string,
sourceCode: string,
getTransformCacheKey: GetTransformCacheKey,
transformOptions: TransformOptions,
transformOptions: WorkerOptions,
transformOptionsKey: string,
result: CachedResult,
}): void {
@@ -326,7 +326,7 @@ function readMetadataFileSync(
export type ReadTransformProps = {
filePath: string,
sourceCode: string,
transformOptions: TransformOptions,
transformOptions: WorkerOptions,
transformOptionsKey: string,
getTransformCacheKey: GetTransformCacheKey,
cacheOptions: CacheOptions,
Oops, something went wrong.

0 comments on commit 73fc439

Please sign in to comment.