diff --git a/packages/relay-compiler/bin/RelayCompilerBin.js b/packages/relay-compiler/bin/RelayCompilerBin.js index 89d40b86985bd..4ba2cf538dd0f 100644 --- a/packages/relay-compiler/bin/RelayCompilerBin.js +++ b/packages/relay-compiler/bin/RelayCompilerBin.js @@ -60,6 +60,7 @@ async function run(options: { schema: string, src: string, extensions: Array, + transform: Array, watch?: ?boolean, }) { const schemaPath = path.resolve(process.cwd(), options.schema); @@ -87,7 +88,7 @@ Ensure that one such file exists in ${srcDir} or its parents. default: { baseDir: srcDir, getFileFilter: RelayFileIRParser.getFileFilter, - getParser: RelayFileIRParser.getParser, + getParser: RelayFileIRParser.getParser(options.transform), getSchema: () => getSchema(schemaPath), watchmanExpression: buildWatchExpression(options), }, @@ -193,6 +194,11 @@ const argv = yargs describe: 'File extensions to compile (--extensions js jsx)', type: 'string', }, + 'transform': { + array: true, + describe: 'Use a transform module on top-level files', + type: 'string', + }, 'watch': { describe: 'If specified, watches files and regenerates on changes', type: 'boolean', diff --git a/packages/relay-compiler/core/RelayFileIRParser.js b/packages/relay-compiler/core/RelayFileIRParser.js index e658a9a174545..69b2e5142ac72 100644 --- a/packages/relay-compiler/core/RelayFileIRParser.js +++ b/packages/relay-compiler/core/RelayFileIRParser.js @@ -24,8 +24,7 @@ import type {FileFilter} from 'RelayCodegenWatcher'; import type {DocumentNode} from 'graphql'; // Throws an error if parsing the file fails -function parseFile(file: string): ?DocumentNode { - const text = fs.readFileSync(file, 'utf8'); +function parseFile(file: string, text: string): ?DocumentNode { const moduleName = path.basename(file, path.extname(file)); invariant( @@ -71,11 +70,46 @@ function parseFile(file: string): ?DocumentNode { }; } -function getParser(baseDir: string): FileParser { - return new FileParser({ - baseDir, - parse: parseFile, - }); +type TransformFactory = (baseDir: string) => (filename: string, text: string) => string +type TransformModule = { default: TransformFactory } + +function getParser(transformModules: Array = []) { + return (baseDir: string): FileParser => { + const transformer = getTransformer(baseDir, transformModules) + return new FileParser({ + baseDir, + parse: (filename: string) => { + const text = fs.readFileSync(filename, 'utf8'); + return parseFile(filename, transformer(filename, text)) + }, + }); + } +} + +function getTransformer(baseDir: string, transformModules: Array = []) { + let transformer = (filename: string, text: string) => text + if (transformModules.length) { + transformModules.forEach(moduleName => { + let moduleImpl: TransformFactory + try { + // $FlowFixMe flow doesn't know about __non_webpack_require__ + moduleImpl = (__non_webpack_require__(moduleName): TransformFactory) + invariant( + moduleImpl.default, + 'Transformer module "' + moduleName + '" should have a default export' + ); + } catch (e) { + throw new Error( + 'Can not resolve transformer module "' + moduleName + '"' + ); + } + const transformerImpl = moduleImpl.default(baseDir) + const prevTransformer = transformer + transformer = (filename: string, text: string) => transformerImpl(filename, prevTransformer(filename, text)) + }) + } + + return transformer } function getFileFilter(baseDir: string): FileFilter {