diff --git a/react-packager/src/ModuleGraph/node-haste/FastFS.js b/react-packager/src/ModuleGraph/node-haste/FastFS.js index 1378debf..a1db35fe 100644 --- a/react-packager/src/ModuleGraph/node-haste/FastFS.js +++ b/react-packager/src/ModuleGraph/node-haste/FastFS.js @@ -11,7 +11,7 @@ 'use strict'; -const {dirname, parse} = require('path'); +const {dirname, join, parse} = require('path'); module.exports = class FastFS { directories: Set; @@ -24,6 +24,18 @@ module.exports = class FastFS { this.files = new Set(files); } + closest(path: string, fileName: string): ?string { + let {dir, root} = parse(path); + do { + const candidate = join(dir, fileName); + if (this.files.has(candidate)) { + return candidate; + } + dir = dirname(dir); + } while (dir !== '.' && dir !== root); + return null; + } + dirExists(path: string) { return this.directories.has(path); } @@ -47,8 +59,8 @@ function buildDirectorySet(files) { files.forEach(path => { let {dir, root} = parse(path); while (dir !== '.' && dir !== root && !directories.has(dir)) { - directories.add(path); - dir = dirname(path); + directories.add(dir); + dir = dirname(dir); } }); return directories; diff --git a/react-packager/src/ModuleGraph/node-haste/Module.js b/react-packager/src/ModuleGraph/node-haste/Module.js index fac654d9..13719de0 100644 --- a/react-packager/src/ModuleGraph/node-haste/Module.js +++ b/react-packager/src/ModuleGraph/node-haste/Module.js @@ -12,15 +12,22 @@ 'use strict'; import type {TransformedFile} from '../types.flow'; +import type {ModuleCache} from './node-haste.flow'; module.exports = class Module { hasteID: Promise; + moduleCache: ModuleCache; name: Promise; path: string; type: 'Module'; - constructor(path: string, info: Promise) { + constructor( + path: string, + moduleCache: ModuleCache, + info: Promise, + ) { this.hasteID = info.then(({hasteID}) => hasteID); + this.moduleCache = moduleCache; this.name = this.hasteID.then(name => name || getName(path)); this.path = path; this.type = 'Module'; @@ -30,6 +37,10 @@ module.exports = class Module { return this.name; } + getPackage() { + return this.moduleCache.getPackageOf(this.path); + } + isHaste() { return this.hasteID.then(Boolean); } diff --git a/react-packager/src/ModuleGraph/node-haste/ModuleCache.js b/react-packager/src/ModuleGraph/node-haste/ModuleCache.js index 91de8307..6c75fdc9 100644 --- a/react-packager/src/ModuleGraph/node-haste/ModuleCache.js +++ b/react-packager/src/ModuleGraph/node-haste/ModuleCache.js @@ -15,16 +15,19 @@ const Module = require('./Module'); const Package = require('./Package'); import type {PackageData, TransformedFile} from '../types.flow'; +import type {FastFS} from './node-haste.flow'; type GetFn = (path: string) => Promise; module.exports = class ModuleCache { + fastfs: FastFS; getPackageData: GetFn; getTransformedFile: GetFn; modules: Map; packages: Map; - constructor(getTransformedFile: GetFn) { + constructor(fastfs: FastFS, getTransformedFile: GetFn) { + this.fastfs = fastfs; this.getTransformedFile = getTransformedFile; this.getPackageData = path => getTransformedFile(path).then( f => f.package || Promise.reject(new Error(`"${path}" does not exist`)) @@ -40,7 +43,7 @@ module.exports = class ModuleCache { getModule(path: string) { let m = this.modules.get(path); if (!m) { - m = new Module(path, this.getTransformedFile(path)); + m = new Module(path, this, this.getTransformedFile(path)); this.modules.set(path, m); } return m; @@ -54,4 +57,9 @@ module.exports = class ModuleCache { } return p; } + + getPackageOf(filePath: string) { + const candidate = this.fastfs.closest(filePath, 'package.json'); + return candidate != null ? this.getPackage(candidate) : null; + } }; diff --git a/react-packager/src/ModuleGraph/node-haste/Package.js b/react-packager/src/ModuleGraph/node-haste/Package.js index a9639361..861a15f2 100644 --- a/react-packager/src/ModuleGraph/node-haste/Package.js +++ b/react-packager/src/ModuleGraph/node-haste/Package.js @@ -17,11 +17,13 @@ import type {PackageData} from '../types.flow'; module.exports = class Package { data: Promise; + path: string; root: string; type: 'Package'; constructor(packagePath: string, data: Promise) { this.data = data; + this.path = packagePath; this.root = path.dirname(packagePath); this.type = 'Package'; } @@ -52,6 +54,10 @@ module.exports = class Package { return this.data.then(p => p.name); } + isHaste() { + return this.data.then(p => !!p.name); + } + redirectRequire(name: string) { // Copied from node-haste/Package.js return this.data.then(data => { diff --git a/react-packager/src/ModuleGraph/node-haste/node-haste.flow.js b/react-packager/src/ModuleGraph/node-haste/node-haste.flow.js index 9d0cf00b..5ac11395 100644 --- a/react-packager/src/ModuleGraph/node-haste/node-haste.flow.js +++ b/react-packager/src/ModuleGraph/node-haste/node-haste.flow.js @@ -24,14 +24,17 @@ export type Module = { path: Path, type: 'Module', getName(): Promise, + getPackage(): ?Package, isHaste(): Promise, }; export type Package = { - type: 'Package', + path: Path, root: Path, + type: 'Package', getMain(): Promise, getName(): Promise, + isHaste(): Promise, redirectRequire(id: ModuleID): Promise, }; @@ -40,10 +43,12 @@ export interface ModuleCache { getAssetModule(path: Path): Module, getModule(path: Path): Module, getPackage(path: Path): Package, + getPackageOf(path: Path): ?Package, } export type FastFS = { dirExists(path: Path): boolean, + closest(path: string, fileName: string): ?string, fileExists(path: Path): boolean, getAllFiles(): Array, matches(directory: Path, pattern: RegExp): Array, @@ -63,17 +68,19 @@ declare class DeprecatedAssetMap { export type DeprecatedAssetMapT = DeprecatedAssetMap; type HasteMapOptions = {| + allowRelativePaths: boolean, extensions: Extensions, fastfs: FastFS, - moduleCache: ModuleCache, - preferNativePlatform: true, helpers: DependencyGraphHelpers, + moduleCache: ModuleCache, platforms: Platforms, + preferNativePlatform: true, |}; declare class HasteMap { // node-haste/DependencyGraph/HasteMap.js constructor(options: HasteMapOptions): void, + build(): Promise, } export type HasteMapT = HasteMap; diff --git a/react-packager/src/ModuleGraph/node-haste/node-haste.js b/react-packager/src/ModuleGraph/node-haste/node-haste.js index 8a0ff3b9..5eaaf14e 100644 --- a/react-packager/src/ModuleGraph/node-haste/node-haste.js +++ b/react-packager/src/ModuleGraph/node-haste/node-haste.js @@ -31,22 +31,21 @@ const HasteMap: Class = require('../../node-haste/DependencyGraph/Has const Module = require('./Module'); const ModuleCache = require('./ModuleCache'); const ResolutionRequest: Class = require('../../node-haste/DependencyGraph/ResolutionRequest'); +const defaults = require('../../../../defaults'); -type ResolveOptions = { +type ResolveOptions = {| assetExts: Extensions, extraNodeModules: {[id: string]: string}, - providesModuleNodeModules: Array, transformedFiles: {[path: Path]: TransformedFile}, -}; +|}; -const platforms = new Set(['android', 'ios']); +const platforms = new Set(defaults.platforms); const returnTrue = () => true; exports.createResolveFn = function(options: ResolveOptions): ResolveFn { const { assetExts, extraNodeModules, - providesModuleNodeModules, transformedFiles, } = options; const files = Object.keys(transformedFiles); @@ -57,7 +56,7 @@ exports.createResolveFn = function(options: ResolveOptions): ResolveFn { const helpers = new DependencyGraphHelpers({ assetExts, - providesModuleNodeModules, + providesModuleNodeModules: defaults.providesModuleNodeModules, }); const deprecatedAssetMap = new DeprecatedAssetMap({ assetExts, @@ -67,8 +66,9 @@ exports.createResolveFn = function(options: ResolveOptions): ResolveFn { }); const fastfs = new FastFS(files); - const moduleCache = new ModuleCache(getTransformedFile); + const moduleCache = new ModuleCache(fastfs, getTransformedFile); const hasteMap = new HasteMap({ + allowRelativePaths: true, extensions: ['js', 'json'], fastfs, helpers, @@ -77,6 +77,7 @@ exports.createResolveFn = function(options: ResolveOptions): ResolveFn { preferNativePlatform: true, }); + const hasteMapBuilt = hasteMap.build(); const resolutionRequests = {}; return (id, source, platform, _, callback) => { let resolutionRequest = resolutionRequests[platform]; @@ -95,11 +96,13 @@ exports.createResolveFn = function(options: ResolveOptions): ResolveFn { }); } - const from = new Module(source, getTransformedFile(source)); - resolutionRequest.resolveDependency(from, id).then( - // nextTick to escape promise error handling - module => process.nextTick(callback, null, module.path), - error => process.nextTick(callback, error), - ); + const from = new Module(source, moduleCache, getTransformedFile(source)); + hasteMapBuilt + .then(() => resolutionRequest.resolveDependency(from, id)) + .then( + // nextTick to escape promise error handling + module => process.nextTick(callback, null, module.path), + error => process.nextTick(callback, error), + ); }; };