packager: get rid of type `any` in ResolutionRequest

Summary:
One of my changeset broke the "ModuleGraph" code without warning earlier because we are using `any`, that equivalent to having no typing at all. This changeset fixes the types so that `ResolutionRequest` is exactly what it actually is: a class usable for any `Module`-looking class, including the normal one, and the "ModuleGraph" one used for Buck builds. That way, the ModuleGraph's `Module` is typechecked against `Moduleish`.

Concretely this change mostly migrates the `Module` to its generic parameter counterpart `TModule` inside `ResolutionRequest`.

Reviewed By: kentaromiura

Differential Revision: D4826256

fbshipit-source-id: fcd7ca08ac6c35e4e9ca983e2aab260e352bcb4e
This commit is contained in:
Jean Lauliac 2017-04-04 07:06:25 -07:00 committed by Facebook Github Bot
parent fc8c5130be
commit c1a2a5e942
10 changed files with 64 additions and 41 deletions

View File

@ -322,12 +322,12 @@ class Bundler {
moduleSystemDeps?: Array<Module>,
onProgress?: () => void,
platform?: ?string,
resolutionResponse?: ResolutionResponse,
resolutionResponse?: ResolutionResponse<Module>,
runBeforeMainModule?: boolean,
runModule?: boolean,
unbundle?: boolean,
}) {
const onResolutionResponse = (response: ResolutionResponse) => {
const onResolutionResponse = (response: ResolutionResponse<Module>) => {
/* $FlowFixMe: looks like ResolutionResponse is monkey-patched
* with `getModuleId`. */
bundle.setMainModuleId(response.getModuleId(getMainModule(response)));
@ -342,7 +342,7 @@ class Bundler {
const finalizeBundle = ({bundle: finalBundle, transformedModules, response, modulesByName}: {
bundle: Bundle,
transformedModules: Array<{module: Module, transformed: ModuleTransport}>,
response: ResolutionResponse,
response: ResolutionResponse<Module>,
modulesByName: {[name: string]: Module},
}) =>
this._resolverPromise.then(resolver => Promise.all(

View File

@ -44,6 +44,10 @@ module.exports = class Module {
isHaste() {
return this.hasteID.then(Boolean);
}
hash() {
throw new Error('not implemented');
}
};
function getName(path) {

View File

@ -101,7 +101,7 @@ class Resolver {
transformOptions: TransformOptions,
onProgress?: ?(finishedModules: number, totalModules: number) => mixed,
getModuleId: mixed,
): Promise<ResolutionResponse> {
): Promise<ResolutionResponse<Module>> {
const {platform, recursive = true} = options;
return this._depGraph.getDependencies({
entryPath,
@ -151,7 +151,7 @@ class Resolver {
}
resolveRequires(
resolutionResponse: ResolutionResponse,
resolutionResponse: ResolutionResponse<Module>,
module: Module,
code: string,
dependencyOffsets: Array<number> = [],
@ -195,7 +195,7 @@ class Resolver {
dev = true,
minify = false,
}: {
resolutionResponse: ResolutionResponse,
resolutionResponse: ResolutionResponse<Module>,
module: Module,
name: string,
map: SourceMap,

View File

@ -309,7 +309,7 @@ class Server {
getDependencies(options: {
entryFile: string,
platform: ?string,
}): Promise<ResolutionResponse> {
}): Promise<ResolutionResponse<Module>> {
return Promise.resolve().then(() => {
if (!options.platform) {
options.platform = getPlatformExtension(options.entryFile);

View File

@ -23,8 +23,6 @@ const getAssetDataFromName = require('../lib/getAssetDataFromName');
import type {HasteFS} from '../types';
import type DependencyGraphHelpers from './DependencyGraphHelpers';
import type Module from '../Module';
import type ModuleCache from '../ModuleCache';
import type ResolutionResponse from './ResolutionResponse';
type DirExistsFn = (filePath: string) => boolean;
@ -37,14 +35,31 @@ export type ModuleMap = {
getPackage(name: string, platform: string, supportsNativePlatform: boolean): ?string,
};
type Options = {
type Packageish = {
redirectRequire(toModuleName: string): string | false,
getMain(): string,
+root: string,
};
type Moduleish = {
+path: string,
getPackage(): ?Packageish,
hash(): string,
};
type ModuleishCache<TModule, TPackage> = {
getPackage(name: string, platform?: string, supportsNativePlatform?: boolean): TPackage,
getModule(path: string): TModule,
getAssetModule(path: string): TModule,
};
type Options<TModule, TPackage> = {
dirExists: DirExistsFn,
entryPath: string,
extraNodeModules: ?Object,
hasteFS: HasteFS,
helpers: DependencyGraphHelpers,
// TODO(cpojer): Remove 'any' type. This is used for ModuleGraph/node-haste
moduleCache: ModuleCache | any,
moduleCache: ModuleishCache<TModule, TPackage>,
moduleMap: ModuleMap,
platform: string,
platforms: Set<string>,
@ -67,14 +82,14 @@ function tryResolveSync<T>(action: () => T, secondaryAction: () => T): T {
}
}
class ResolutionRequest {
class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
_dirExists: DirExistsFn;
_entryPath: string;
_extraNodeModules: ?Object;
_hasteFS: HasteFS;
_helpers: DependencyGraphHelpers;
_immediateResolutionCache: {[key: string]: Module};
_moduleCache: ModuleCache;
_immediateResolutionCache: {[key: string]: TModule};
_moduleCache: ModuleishCache<TModule, TPackage>;
_moduleMap: ModuleMap;
_platform: string;
_platforms: Set<string>;
@ -92,7 +107,7 @@ class ResolutionRequest {
platform,
platforms,
preferNativePlatform,
}: Options) {
}: Options<TModule, TPackage>) {
this._dirExists = dirExists;
this._entryPath = entryPath;
this._extraNodeModules = extraNodeModules;
@ -115,8 +130,7 @@ class ResolutionRequest {
});
}
// TODO(cpojer): Remove 'any' type. This is used for ModuleGraph/node-haste
resolveDependency(fromModule: Module | any, toModuleName: string): Module {
resolveDependency(fromModule: TModule, toModuleName: string): TModule {
const resHash = resolutionHash(fromModule.path, toModuleName);
const immediateResolution = this._immediateResolutionCache[resHash];
@ -141,7 +155,10 @@ class ResolutionRequest {
return cacheResult(this._resolveNodeDependency(fromModule, toModuleName));
}
resolveModuleDependencies(module: Module, dependencyNames: Array<string>): [Array<string>, Array<Module>] {
resolveModuleDependencies(
module: TModule,
dependencyNames: Array<string>,
): [Array<string>, Array<TModule>] {
const dependencies = dependencyNames.map(name => this.resolveDependency(module, name));
return [dependencyNames, dependencies];
}
@ -152,7 +169,7 @@ class ResolutionRequest {
onProgress,
recursive = true,
}: {
response: ResolutionResponse,
response: ResolutionResponse<TModule>,
transformOptions: Object,
onProgress?: ?(finishedModules: number, totalModules: number) => mixed,
recursive: boolean,
@ -250,13 +267,14 @@ class ResolutionRequest {
});
}
_resolveHasteDependency(fromModule: Module, toModuleName: string): Module {
_resolveHasteDependency(fromModule: TModule, toModuleName: string): TModule {
toModuleName = normalizePath(toModuleName);
const pck = fromModule.getPackage();
let realModuleName;
if (pck) {
realModuleName = pck.redirectRequire(toModuleName);
/* $FlowFixMe: redirectRequire can actually return `false` for exclusions */
realModuleName = (pck.redirectRequire(toModuleName): string);
} else {
realModuleName = toModuleName;
}
@ -308,7 +326,7 @@ class ResolutionRequest {
);
}
_redirectRequire(fromModule: Module, modulePath: string): string | false {
_redirectRequire(fromModule: TModule, modulePath: string): string | false {
const pck = fromModule.getPackage();
if (pck) {
return pck.redirectRequire(modulePath);
@ -316,7 +334,7 @@ class ResolutionRequest {
return modulePath;
}
_resolveFileOrDir(fromModule: Module, toModuleName: string): Module {
_resolveFileOrDir(fromModule: TModule, toModuleName: string): TModule {
const potentialModulePath = isAbsolutePath(toModuleName) ?
resolveWindowsPath(toModuleName) :
path.join(path.dirname(fromModule.path), toModuleName);
@ -336,7 +354,7 @@ class ResolutionRequest {
);
}
_resolveNodeDependency(fromModule: Module, toModuleName: string): Module {
_resolveNodeDependency(fromModule: TModule, toModuleName: string): TModule {
if (isRelativeImport(toModuleName) || isAbsolutePath(toModuleName)) {
return this._resolveFileOrDir(fromModule, toModuleName);
}
@ -408,7 +426,7 @@ class ResolutionRequest {
* This is written as a separate function because "try..catch" blocks cause
* the entire surrounding function to be deoptimized.
*/
_tryResolveNodeDep(searchPath: string, fromModule: Module, toModuleName: string): ?Module {
_tryResolveNodeDep(searchPath: string, fromModule: TModule, toModuleName: string): ?TModule {
try {
return tryResolveSync(
() => this._loadAsFile(searchPath, fromModule, toModuleName),
@ -422,7 +440,7 @@ class ResolutionRequest {
}
}
_loadAsFile(potentialModulePath: string, fromModule: Module, toModule: string): Module {
_loadAsFile(potentialModulePath: string, fromModule: TModule, toModule: string): TModule {
if (this._helpers.isAssetFile(potentialModulePath)) {
let dirname = path.dirname(potentialModulePath);
if (!this._dirExists(dirname)) {
@ -480,7 +498,7 @@ class ResolutionRequest {
return this._moduleCache.getModule(file);
}
_loadAsDir(potentialDirPath: string, fromModule: Module, toModule: string): Module {
_loadAsDir(potentialDirPath: string, fromModule: TModule, toModule: string): TModule {
if (!this._dirExists(potentialDirPath)) {
throw new UnableToResolveError(
fromModule,

View File

@ -16,10 +16,10 @@ import type Module from '../Module';
const NO_OPTIONS = {};
class ResolutionResponse {
class ResolutionResponse<TModule: {hash(): string}> {
transformOptions: TransformOptions;
dependencies: Array<Module>;
dependencies: Array<TModule>;
mainModuleId: ?(number | string);
mocks: mixed;
numPrependedDependencies: number;
@ -29,7 +29,7 @@ class ResolutionResponse {
_mappings: {};
_finalized: boolean;
_mainModule: ?Module;
_mainModule: ?TModule;
constructor({transformOptions}: {transformOptions: TransformOptions}) {
this.transformOptions = transformOptions;
@ -42,10 +42,10 @@ class ResolutionResponse {
}
copy(properties: {
dependencies?: Array<Module>,
dependencies?: Array<TModule>,
mainModuleId?: number,
mocks?: mixed,
}): ResolutionResponse {
}): ResolutionResponse<TModule> {
const {
dependencies = this.dependencies,
mainModuleId = this.mainModuleId,
@ -80,7 +80,7 @@ class ResolutionResponse {
}
}
finalize(): ResolutionResponse {
finalize(): ResolutionResponse<TModule> {
/* $FlowFixMe: _mainModule is not initialized in the constructor. */
return this._mainModule.getName().then(id => {
this.mainModuleId = id;
@ -89,7 +89,7 @@ class ResolutionResponse {
});
}
pushDependency(module: Module) {
pushDependency(module: TModule) {
this._assertNotFinalized();
if (this.dependencies.length === 0) {
this._mainModule = module;
@ -98,7 +98,7 @@ class ResolutionResponse {
this.dependencies.push(module);
}
prependDependency(module: Module) {
prependDependency(module: TModule) {
this._assertNotFinalized();
this.dependencies.unshift(module);
this.numPrependedDependencies += 1;
@ -122,7 +122,7 @@ class ResolutionResponse {
this.mocks = mocks;
}
getResolvedDependencyPairs(module: Module) {
getResolvedDependencyPairs(module: TModule) {
this._assertFinalized();
return this._mappings[module.hash()];
}

View File

@ -226,7 +226,8 @@ class Module {
if (hasteImpl !== undefined) {
const {enforceHasteNameMatches} = hasteImpl;
if (enforceHasteNameMatches) {
/* $FlowFixMe: this rely on the above if being executed, that is fragile. Rework the algo. */
/* $FlowFixMe: this rely on the above if being executed, that is fragile.
* Rework the algo. */
enforceHasteNameMatches(this.path, this._hasteNameCache.hasteName);
}
this._hasteNameCache = {hasteName: hasteImpl.getHasteName(this.path)};

View File

@ -114,7 +114,7 @@ class ModuleCache {
return this._moduleCache[filePath];
}
getPackage(filePath: string) {
getPackage(filePath: string): Package {
if (!this._packageCache[filePath]) {
this._packageCache[filePath] = new Package({
file: filePath,

View File

@ -44,7 +44,7 @@ class Package {
this._content = null;
}
getMain() {
getMain(): string {
const json = this.read();
var replacements = getReplacements(json);
if (typeof replacements === 'string') {

View File

@ -211,7 +211,7 @@ class DependencyGraph extends EventEmitter {
transformOptions: TransformOptions,
onProgress?: ?(finishedModules: number, totalModules: number) => mixed,
recursive: boolean,
}): Promise<ResolutionResponse> {
}): Promise<ResolutionResponse<Module>> {
platform = this._getRequestPlatform(entryPath, platform);
const absPath = this._getAbsolutePath(entryPath);
const dirExists = filePath => {