From 234f4f538d40b5ae558f056f6eeae65cd6e44bf0 Mon Sep 17 00:00:00 2001 From: Bhuwan Khattar Date: Mon, 27 Feb 2017 10:48:17 -0800 Subject: [PATCH] Introduce HasteImpl Summary: Similar to https://github.com/facebook/jest/pull/2877, this introduces an optional config `HasteImpl` of type `{getHasteName(filePath: string): (string|void)}` that returns the haste name for a module at filePath if it is a haste module or undefined otherwise. This allows us to inject a custom implementation of haste's module id resolution rather than only relying on `providesModule` annotations Reviewed By: davidaurelio Differential Revision: D4589372 fbshipit-source-id: 4d1983dfbf09c9d67faf725e86ae86ab42433b7d --- local-cli/bundle/buildBundle.js | 1 + local-cli/core/index.js | 8 ++++ local-cli/dependencies/dependencies.js | 1 + local-cli/server/runServer.js | 1 + packager/react-packager.js | 3 ++ packager/src/Bundler/index.js | 4 +- packager/src/Resolver/index.js | 4 +- packager/src/Server/index.js | 5 +- packager/src/node-haste/Module.js | 66 ++++++++++++++++++++------ 9 files changed, 75 insertions(+), 18 deletions(-) diff --git a/local-cli/bundle/buildBundle.js b/local-cli/bundle/buildBundle.js index df038d3e930..a1ac7c7d1df 100644 --- a/local-cli/bundle/buildBundle.js +++ b/local-cli/bundle/buildBundle.js @@ -76,6 +76,7 @@ function buildBundle( extraNodeModules: config.extraNodeModules, getTransformOptions: config.getTransformOptions, globalTransformCache: null, + hasteImpl: config.hasteImpl, platforms: defaultPlatforms.concat(platforms), projectRoots: config.getProjectRoots(), providesModuleNodeModules: providesModuleNodeModules, diff --git a/local-cli/core/index.js b/local-cli/core/index.js index 899985334c6..6809c47e0a0 100644 --- a/local-cli/core/index.js +++ b/local-cli/core/index.js @@ -16,6 +16,7 @@ const defaultConfig = require('./default.config'); const minimist = require('minimist'); import type {GetTransformOptions} from '../../packager/src/Bundler'; +import type {HasteImpl} from '../../packager/src/node-haste/Module'; import type {CommandT} from '../commands'; /** @@ -66,6 +67,13 @@ export type ConfigT = { * Returns dependency config from /packageName */ getDependencyConfig(pkgName: string): Object, + + /** + * A module that exports: + * - a `getHasteName(filePath)` method that returns `hasteName` for module at + * `filePath`, or undefined if `filePath` is not a haste module. + */ + hasteImpl?: HasteImpl, }; /** diff --git a/local-cli/dependencies/dependencies.js b/local-cli/dependencies/dependencies.js index 45ff7a9508e..4e722383af0 100644 --- a/local-cli/dependencies/dependencies.js +++ b/local-cli/dependencies/dependencies.js @@ -29,6 +29,7 @@ function dependencies(argv, config, args, packagerInstance) { projectRoots: config.getProjectRoots(), blacklistRE: config.getBlacklistRE(), getTransformOptions: config.getTransformOptions, + hasteImpl: config.hasteImpl, transformModulePath: transformModulePath, extraNodeModules: config.extraNodeModules, verbose: config.verbose, diff --git a/local-cli/server/runServer.js b/local-cli/server/runServer.js index 1ae3a63366b..09501018b65 100644 --- a/local-cli/server/runServer.js +++ b/local-cli/server/runServer.js @@ -94,6 +94,7 @@ function getPackagerServer(args, config) { cacheVersion: '3', extraNodeModules: config.extraNodeModules, getTransformOptions: config.getTransformOptions, + hasteImpl: config.hasteImpl, platforms: defaultPlatforms.concat(args.platforms), projectRoots: args.projectRoots, providesModuleNodeModules: providesModuleNodeModules, diff --git a/packager/react-packager.js b/packager/react-packager.js index b3676770307..1e95d24ed1b 100644 --- a/packager/react-packager.js +++ b/packager/react-packager.js @@ -18,11 +18,13 @@ const invariant = require('fbjs/lib/invariant'); import type GlobalTransformCache from './src/lib/GlobalTransformCache'; import type {Reporter} from './src/lib/reporting'; +import type {HasteImpl} from './src/node-haste/Module'; exports.createServer = createServer; exports.Logger = Logger; type Options = { + hasteImpl?: HasteImpl, globalTransformCache: ?GlobalTransformCache, nonPersistent?: boolean, projectRoots: Array, @@ -31,6 +33,7 @@ type Options = { }; type StrictOptions = { + hasteImpl?: HasteImpl, globalTransformCache: ?GlobalTransformCache, nonPersistent?: boolean, projectRoots: Array, diff --git a/packager/src/Bundler/index.js b/packager/src/Bundler/index.js index 126c3e79b5e..b51230a3eac 100644 --- a/packager/src/Bundler/index.js +++ b/packager/src/Bundler/index.js @@ -36,7 +36,7 @@ const { const VERSION = require('../../package.json').version; import type AssetServer from '../AssetServer'; -import type Module from '../node-haste/Module'; +import type Module, {HasteImpl} from '../node-haste/Module'; import type ResolutionResponse from '../node-haste/DependencyGraph/ResolutionResponse'; import type {Options as JSTransformerOptions, TransformOptions} from '../JSTransformer/worker/worker'; import type {Reporter} from '../lib/reporting'; @@ -86,6 +86,7 @@ type Options = { extraNodeModules: {}, getTransformOptions?: GetTransformOptions, globalTransformCache: ?GlobalTransformCache, + hasteImpl?: HasteImpl, moduleFormat: string, platforms: Array, polyfillModuleNames: Array, @@ -172,6 +173,7 @@ class Bundler { extraNodeModules: opts.extraNodeModules, getTransformCacheKey, globalTransformCache: opts.globalTransformCache, + hasteImpl: opts.hasteImpl, minifyCode: this._transformer.minify, moduleFormat: opts.moduleFormat, platforms: opts.platforms, diff --git a/packager/src/Resolver/index.js b/packager/src/Resolver/index.js index 36f85f962ad..971262fb974 100644 --- a/packager/src/Resolver/index.js +++ b/packager/src/Resolver/index.js @@ -17,7 +17,7 @@ const defaults = require('../../defaults'); const pathJoin = require('path').join; import type ResolutionResponse from '../node-haste/DependencyGraph/ResolutionResponse'; -import type Module from '../node-haste/Module'; +import type Module, {HasteImpl} from '../node-haste/Module'; import type {SourceMap} from '../lib/SourceMap'; import type {Options as TransformOptions} from '../JSTransformer/worker/worker'; import type {Reporter} from '../lib/reporting'; @@ -36,6 +36,7 @@ type Options = { extraNodeModules?: {}, getTransformCacheKey: GetTransformCacheKey, globalTransformCache: ?GlobalTransformCache, + hasteImpl?: HasteImpl, minifyCode: MinifyCode, platforms: Array, polyfillModuleNames?: Array, @@ -70,6 +71,7 @@ class Resolver { maxWorkers: null, moduleOptions: { cacheTransformResults: true, + hasteImpl: opts.hasteImpl, resetCache: opts.resetCache, }, platforms: new Set(opts.platforms), diff --git a/packager/src/Server/index.js b/packager/src/Server/index.js index f661403ace0..89f86d8f880 100644 --- a/packager/src/Server/index.js +++ b/packager/src/Server/index.js @@ -26,7 +26,7 @@ const url = require('url'); const debug = require('debug')('RNP:Server'); -import type Module from '../node-haste/Module'; +import type Module, {HasteImpl} from '../node-haste/Module'; import type {Stats} from 'fs'; import type {IncomingMessage, ServerResponse} from 'http'; import type ResolutionResponse from '../node-haste/DependencyGraph/ResolutionResponse'; @@ -62,6 +62,7 @@ type Options = { extraNodeModules?: {}, getTransformOptions?: GetTransformOptions, globalTransformCache: ?GlobalTransformCache, + hasteImpl?: HasteImpl, moduleFormat?: string, platforms?: Array, polyfillModuleNames?: Array, @@ -178,6 +179,7 @@ class Server { cacheVersion: string, extraNodeModules: {}, getTransformOptions?: GetTransformOptions, + hasteImpl?: HasteImpl, moduleFormat: string, platforms: Array, polyfillModuleNames: Array, @@ -212,6 +214,7 @@ class Server { extraNodeModules: options.extraNodeModules || {}, getTransformOptions: options.getTransformOptions, globalTransformCache: options.globalTransformCache, + hasteImpl: options.hasteImpl, moduleFormat: options.moduleFormat != null ? options.moduleFormat : 'haste', platforms: options.platforms || defaults.platforms, polyfillModuleNames: options.polyfillModuleNames || [], diff --git a/packager/src/node-haste/Module.js b/packager/src/node-haste/Module.js index 40118ec88c4..6f05271016d 100644 --- a/packager/src/node-haste/Module.js +++ b/packager/src/node-haste/Module.js @@ -46,9 +46,20 @@ export type TransformCode = ( transformOptions: TransformOptions, ) => Promise; +export type HasteImpl = { + getHasteName(filePath: string): (string | void), + // This exists temporarily to enforce consistency while we deprecate + // @providesModule. + enforceHasteNameMatches?: ( + filePath: string, + expectedName: (string | void), + ) => void, +}; + export type Options = { - resetCache?: boolean, cacheTransformResults?: boolean, + hasteImpl?: HasteImpl, + resetCache?: boolean, }; export type ConstructorArgs = { @@ -191,21 +202,46 @@ class Module { return this._docBlock; } - _getHasteName() { + _getHasteName(): Promise { if (!this._hasteName) { - // Extract an id for the module if it's using @providesModule syntax - // and if it's NOT in node_modules (and not a whitelisted node_module). - // This handles the case where a project may have a dep that has @providesModule - // docblock comments, but doesn't want it to conflict with whitelisted @providesModule - // modules, such as react-haste, fbjs-haste, or react-native or with non-dependency, - // project-specific code that is using @providesModule. - this._hasteName = this._readDocBlock().then(moduleDocBlock => { - const {providesModule} = moduleDocBlock; - return providesModule - && !this._depGraphHelpers.isNodeModulesDir(this.path) - ? /^\S+/.exec(providesModule)[0] - : undefined; - }); + const hasteImpl = this._options.hasteImpl; + if (hasteImpl === undefined || hasteImpl.enforceHasteNameMatches) { + this._hasteName = this._readDocBlock().then(moduleDocBlock => { + const {providesModule} = moduleDocBlock; + return providesModule + && !this._depGraphHelpers.isNodeModulesDir(this.path) + ? /^\S+/.exec(providesModule)[0] + : undefined; + }); + } + if (hasteImpl !== undefined) { + const {enforceHasteNameMatches} = hasteImpl; + if (enforceHasteNameMatches) { + this._hasteName = this._hasteName.then(providesModule => { + enforceHasteNameMatches( + this.path, + providesModule, + ); + return hasteImpl.getHasteName(this.path); + }); + } else { + this._hasteName = Promise.resolve(hasteImpl.getHasteName(this.path)); + } + } else { + // Extract an id for the module if it's using @providesModule syntax + // and if it's NOT in node_modules (and not a whitelisted node_module). + // This handles the case where a project may have a dep that has @providesModule + // docblock comments, but doesn't want it to conflict with whitelisted @providesModule + // modules, such as react-haste, fbjs-haste, or react-native or with non-dependency, + // project-specific code that is using @providesModule. + this._hasteName = this._readDocBlock().then(moduleDocBlock => { + const {providesModule} = moduleDocBlock; + return providesModule + && !this._depGraphHelpers.isNodeModulesDir(this.path) + ? /^\S+/.exec(providesModule)[0] + : undefined; + }); + } } return this._hasteName; }