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
This commit is contained in:
Bhuwan Khattar
2017-02-27 10:48:17 -08:00
committed by Facebook Github Bot
parent 4ba983401f
commit 234f4f538d
9 changed files with 75 additions and 18 deletions

View File

@@ -46,9 +46,20 @@ export type TransformCode = (
transformOptions: TransformOptions,
) => Promise<TransformedCode>;
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<string | void> {
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;
}