mirror of https://github.com/status-im/metro.git
Remove HasteMap
Reviewed By: davidaurelio Differential Revision: D5803275 fbshipit-source-id: 2e64733d8ef400a61d116b21cd53185934dd3d57
This commit is contained in:
parent
61a0116dd4
commit
b3e817285b
|
@ -18,7 +18,7 @@ import type ModuleCache from './ModuleCache';
|
|||
module.exports = class Module {
|
||||
hasteID: ?string;
|
||||
moduleCache: ModuleCache;
|
||||
name: Promise<string>;
|
||||
name: string;
|
||||
path: string;
|
||||
type: 'Module';
|
||||
|
||||
|
@ -29,7 +29,7 @@ module.exports = class Module {
|
|||
) {
|
||||
this.hasteID = info.hasteID;
|
||||
this.moduleCache = moduleCache;
|
||||
this.name = Promise.resolve(this.hasteID || getName(path));
|
||||
this.name = this.hasteID || getName(path);
|
||||
this.path = path;
|
||||
this.type = 'Module';
|
||||
}
|
||||
|
@ -42,8 +42,8 @@ module.exports = class Module {
|
|||
return Promise.reject(new Error('not implemented'));
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this.name;
|
||||
getName(): Promise<string> {
|
||||
return Promise.resolve(this.name);
|
||||
}
|
||||
|
||||
getPackage() {
|
||||
|
|
|
@ -16,21 +16,20 @@ const AssetResolutionCache = require('../../node-haste/AssetResolutionCache');
|
|||
const DependencyGraphHelpers = require('../../node-haste/DependencyGraph/DependencyGraphHelpers');
|
||||
const FilesByDirNameIndex = require('../../node-haste/FilesByDirNameIndex');
|
||||
const HasteFS = require('./HasteFS');
|
||||
const HasteMap = require('../../node-haste/DependencyGraph/HasteMap');
|
||||
const Module = require('./Module');
|
||||
const ModuleCache = require('./ModuleCache');
|
||||
const ResolutionRequest = require('../../node-haste/DependencyGraph/ResolutionRequest');
|
||||
|
||||
const defaults = require('../../defaults');
|
||||
const parsePlatformFilePath = require('../../node-haste/lib/parsePlatformFilePath');
|
||||
const path = require('path');
|
||||
|
||||
const {
|
||||
ModuleResolver,
|
||||
} = require('../../node-haste/DependencyGraph/ModuleResolution');
|
||||
const {ModuleMap} = require('jest-haste-map');
|
||||
|
||||
import type {
|
||||
Moduleish,
|
||||
Packageish,
|
||||
} from '../../node-haste/DependencyGraph/ResolutionRequest';
|
||||
import type {Moduleish} from '../../node-haste/DependencyGraph/ResolutionRequest';
|
||||
import type {ResolveFn, TransformedCodeFile} from '../types.flow';
|
||||
import type {
|
||||
// eslint-disable-line sort-requires
|
||||
|
@ -47,25 +46,9 @@ type ResolveOptions = {|
|
|||
|
||||
const platforms = new Set(defaults.platforms);
|
||||
|
||||
/**
|
||||
* We don't need to crawl the filesystem all over again so we just mock
|
||||
* a jest-haste-map's ModuleMap instance. Eventually, though, we'll
|
||||
* want to figure out how to reunify and get rid of `HasteMap`.
|
||||
*/
|
||||
function getFakeModuleMap(hasteMap: HasteMap<Module, Packageish>) {
|
||||
return {
|
||||
getModule(name: string, platform: ?string): ?string {
|
||||
const module = hasteMap.getModule(name, platform);
|
||||
return module && module.type === 'Module' ? module.path : null;
|
||||
},
|
||||
getPackage(name: string, platform: ?string): ?string {
|
||||
const pkg = hasteMap.getPackage(name);
|
||||
return pkg && pkg.path;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const nullModule: Moduleish = {
|
||||
const GENERIC_PLATFORM = 'g';
|
||||
const PACKAGE_JSON = path.sep + 'package.json';
|
||||
const NULL_MODULE: Moduleish = {
|
||||
path: '/',
|
||||
getPackage() {},
|
||||
hash() {
|
||||
|
@ -85,9 +68,49 @@ const nullModule: Moduleish = {
|
|||
},
|
||||
};
|
||||
|
||||
exports.createResolveFn = function(
|
||||
options: ResolveOptions,
|
||||
): Promise<ResolveFn> {
|
||||
// This function maps the ModuleGraph data structure to jest-haste-map's ModuleMap
|
||||
const createModuleMap = ({files, helpers, moduleCache, sourceExts}) => {
|
||||
const map = Object.create(null);
|
||||
files.forEach(filePath => {
|
||||
if (!helpers.isNodeModulesDir(filePath)) {
|
||||
let id;
|
||||
let module;
|
||||
if (filePath.endsWith(PACKAGE_JSON)) {
|
||||
module = moduleCache.getPackage(filePath);
|
||||
id = module.data.name;
|
||||
} else if (sourceExts.indexOf(path.extname(filePath).substr(1)) !== -1) {
|
||||
module = moduleCache.getModule(filePath);
|
||||
id = module.name;
|
||||
}
|
||||
|
||||
if (id && module && module.isHaste()) {
|
||||
if (!map[id]) {
|
||||
map[id] = Object.create(null);
|
||||
}
|
||||
const platform =
|
||||
parsePlatformFilePath(filePath, platforms).platform ||
|
||||
GENERIC_PLATFORM;
|
||||
|
||||
const existingModule = map[id][platform];
|
||||
// 0 = Module, 1 = Package in jest-haste-map
|
||||
map[id][platform] = [filePath, module.type === 'Package' ? 1 : 0];
|
||||
|
||||
if (existingModule && existingModule.path !== filePath) {
|
||||
throw new Error(
|
||||
`@providesModule naming collision:\n` +
|
||||
` Duplicate module name: ${id}\n` +
|
||||
` Paths: ${filePath} collides with ${existingModule.path}\n\n` +
|
||||
'This error is caused by a @providesModule declaration ' +
|
||||
'with the same name across two different files.',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return map;
|
||||
};
|
||||
|
||||
exports.createResolveFn = function(options: ResolveOptions): ResolveFn {
|
||||
const {assetExts, extraNodeModules, transformedFiles, sourceExts} = options;
|
||||
const files = Object.keys(transformedFiles);
|
||||
function getTransformedFile(path) {
|
||||
|
@ -108,18 +131,9 @@ exports.createResolveFn = function(
|
|||
filePath => hasteFS.closest(filePath, 'package.json'),
|
||||
getTransformedFile,
|
||||
);
|
||||
const hasteMap = new HasteMap({
|
||||
extensions: sourceExts,
|
||||
files,
|
||||
helpers,
|
||||
moduleCache,
|
||||
platforms,
|
||||
preferNativePlatform: true,
|
||||
});
|
||||
|
||||
const hasteMapBuilt = hasteMap.build();
|
||||
const resolutionRequests = {};
|
||||
const filesByDirNameIndex = new FilesByDirNameIndex(hasteMap.getAllFiles());
|
||||
const filesByDirNameIndex = new FilesByDirNameIndex(files);
|
||||
const assetResolutionCache = new AssetResolutionCache({
|
||||
assetExtensions: new Set(assetExts),
|
||||
getDirFiles: dirPath => filesByDirNameIndex.getAllFiles(dirPath),
|
||||
|
@ -131,14 +145,18 @@ exports.createResolveFn = function(
|
|||
extraNodeModules,
|
||||
helpers,
|
||||
moduleCache,
|
||||
moduleMap: getFakeModuleMap(hasteMap),
|
||||
moduleMap: new ModuleMap({
|
||||
duplicates: Object.create(null),
|
||||
map: createModuleMap({files, helpers, moduleCache, sourceExts}),
|
||||
mocks: Object.create(null),
|
||||
}),
|
||||
preferNativePlatform: true,
|
||||
resolveAsset: (dirPath, assetName, platform) =>
|
||||
assetResolutionCache.resolve(dirPath, assetName, platform),
|
||||
sourceExts,
|
||||
});
|
||||
|
||||
return hasteMapBuilt.then(() => (id, source, platform, _, callback) => {
|
||||
return (id, sourcePath, platform, _, callback) => {
|
||||
let resolutionRequest = resolutionRequests[platform];
|
||||
if (!resolutionRequest) {
|
||||
resolutionRequest = resolutionRequests[platform] = new ResolutionRequest({
|
||||
|
@ -151,9 +169,9 @@ exports.createResolveFn = function(
|
|||
}
|
||||
|
||||
const from =
|
||||
source != null
|
||||
? new Module(source, moduleCache, getTransformedFile(source))
|
||||
: nullModule;
|
||||
sourcePath != null
|
||||
? new Module(sourcePath, moduleCache, getTransformedFile(sourcePath))
|
||||
: NULL_MODULE;
|
||||
return resolutionRequest.resolveDependency(from, id).path;
|
||||
});
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,243 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @flow
|
||||
* @format
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const EventEmitter = require('events');
|
||||
|
||||
const parsePlatformFilePath = require('../lib/parsePlatformFilePath');
|
||||
const path = require('path');
|
||||
const throat = require('throat');
|
||||
|
||||
const GENERIC_PLATFORM = 'generic';
|
||||
const NATIVE_PLATFORM = 'native';
|
||||
const PACKAGE_JSON = path.sep + 'package.json';
|
||||
|
||||
import type {Moduleish, Packageish, ModuleishCache} from './ResolutionRequest';
|
||||
import type DependencyGraphHelpers from './DependencyGraphHelpers';
|
||||
|
||||
type Options<TModule, TPackage> = {|
|
||||
extensions: Array<string>,
|
||||
files: Array<string>,
|
||||
helpers: DependencyGraphHelpers,
|
||||
moduleCache: ModuleishCache<TModule, TPackage>,
|
||||
platforms: Set<string>,
|
||||
preferNativePlatform: boolean,
|
||||
|};
|
||||
|
||||
class HasteMap<TModule: Moduleish, TPackage: Packageish> extends EventEmitter {
|
||||
_extensions: Array<string>;
|
||||
_files: Array<string>;
|
||||
_helpers: DependencyGraphHelpers;
|
||||
_map: {};
|
||||
_moduleCache: ModuleishCache<TModule, TPackage>;
|
||||
_packages: {};
|
||||
_platforms: Set<string>;
|
||||
_preferNativePlatform: boolean;
|
||||
|
||||
constructor({
|
||||
extensions,
|
||||
files,
|
||||
helpers,
|
||||
moduleCache,
|
||||
platforms,
|
||||
preferNativePlatform,
|
||||
}: Options<TModule, TPackage>) {
|
||||
super();
|
||||
this._extensions = extensions;
|
||||
this._files = files;
|
||||
this._helpers = helpers;
|
||||
this._moduleCache = moduleCache;
|
||||
this._platforms = platforms;
|
||||
this._preferNativePlatform = preferNativePlatform;
|
||||
|
||||
(this: any)._processHastePackage = throat(
|
||||
1,
|
||||
this._processHastePackage.bind(this),
|
||||
);
|
||||
(this: any)._processHasteModule = throat(
|
||||
1,
|
||||
this._processHasteModule.bind(this),
|
||||
);
|
||||
}
|
||||
|
||||
build() {
|
||||
this._map = Object.create(null);
|
||||
this._packages = Object.create(null);
|
||||
const promises = [];
|
||||
this._files.forEach(filePath => {
|
||||
if (!this._helpers.isNodeModulesDir(filePath)) {
|
||||
if (filePath.endsWith(PACKAGE_JSON)) {
|
||||
promises.push(this._processHastePackage(filePath));
|
||||
} else if (
|
||||
this._extensions.indexOf(path.extname(filePath).substr(1)) !== -1
|
||||
) {
|
||||
promises.push(this._processHasteModule(filePath));
|
||||
}
|
||||
}
|
||||
});
|
||||
/* $FlowFixMe(>=0.54.0 site=react_native_fb) This comment suppresses an
|
||||
* error found when Flow v0.54 was deployed. To see the error delete this
|
||||
* comment and run Flow. */
|
||||
return Promise.all(promises).then(() => this._map);
|
||||
}
|
||||
|
||||
getAllFiles(): Array<string> {
|
||||
return this._files;
|
||||
}
|
||||
|
||||
processFileChange(type: string, absPath: string) {
|
||||
/* $FlowFixMe(>=0.54.0 site=react_native_fb) This comment suppresses an
|
||||
* error found when Flow v0.54 was deployed. To see the error delete this
|
||||
* comment and run Flow. */
|
||||
return Promise.resolve().then(() => {
|
||||
/*eslint no-labels: 0 */
|
||||
let invalidated;
|
||||
if (type === 'delete' || type === 'change') {
|
||||
loop: for (const name in this._map) {
|
||||
const modulesMap = this._map[name];
|
||||
for (const platform in modulesMap) {
|
||||
const module = modulesMap[platform];
|
||||
if (module.path === absPath) {
|
||||
delete modulesMap[platform];
|
||||
invalidated = name;
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type === 'delete') {
|
||||
if (invalidated) {
|
||||
this.emit('change');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
type !== 'delete' &&
|
||||
this._extensions.indexOf(this._helpers.extname(absPath)) !== -1
|
||||
) {
|
||||
if (path.basename(absPath) === 'package.json') {
|
||||
return this._processHastePackage(absPath, invalidated);
|
||||
} else {
|
||||
return this._processHasteModule(absPath, invalidated);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
getModule(name: string, platform: ?string): ?TModule {
|
||||
const modulesMap = this._map[name];
|
||||
if (modulesMap == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// If platform is 'ios', we prefer .ios.js to .native.js which we prefer to
|
||||
// a plain .js file.
|
||||
let module;
|
||||
if (module == null && platform != null) {
|
||||
module = modulesMap[platform];
|
||||
}
|
||||
if (module == null && this._preferNativePlatform) {
|
||||
module = modulesMap[NATIVE_PLATFORM];
|
||||
}
|
||||
if (module == null) {
|
||||
module = modulesMap[GENERIC_PLATFORM];
|
||||
}
|
||||
return module;
|
||||
}
|
||||
|
||||
getPackage(name: string): TPackage {
|
||||
return this._packages[name];
|
||||
}
|
||||
|
||||
_processHasteModule(file: string, previousName: ?string) {
|
||||
const module = this._moduleCache.getModule(file);
|
||||
/* $FlowFixMe(>=0.54.0 site=react_native_fb) This comment suppresses an
|
||||
* error found when Flow v0.54 was deployed. To see the error delete this
|
||||
* comment and run Flow. */
|
||||
return Promise.resolve().then(() => {
|
||||
const isHaste = module.isHaste();
|
||||
return (
|
||||
isHaste &&
|
||||
module.getName().then(name => {
|
||||
const result = this._updateHasteMap(name, module);
|
||||
if (previousName && name !== previousName) {
|
||||
this.emit('change');
|
||||
}
|
||||
return result;
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
_processHastePackage(file: string, previousName: ?string) {
|
||||
const p = this._moduleCache.getPackage(file);
|
||||
/* $FlowFixMe(>=0.54.0 site=react_native_fb) This comment suppresses an
|
||||
* error found when Flow v0.54 was deployed. To see the error delete this
|
||||
* comment and run Flow. */
|
||||
return Promise.resolve()
|
||||
.then(() => {
|
||||
const isHaste = p.isHaste();
|
||||
return (
|
||||
isHaste &&
|
||||
p.getName().then(name => {
|
||||
const result = this._updateHasteMap(name, p);
|
||||
if (previousName && name !== previousName) {
|
||||
this.emit('change');
|
||||
}
|
||||
return result;
|
||||
})
|
||||
);
|
||||
})
|
||||
.catch(e => {
|
||||
if (e instanceof SyntaxError) {
|
||||
// Malformed package.json.
|
||||
return;
|
||||
}
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
|
||||
_updateHasteMap(name: string, mod: TModule | TPackage) {
|
||||
let existingModule;
|
||||
|
||||
if (mod.type === 'Package') {
|
||||
existingModule = this._packages[name];
|
||||
this._packages[name] = mod;
|
||||
} else {
|
||||
if (this._map[name] == null) {
|
||||
this._map[name] = Object.create(null);
|
||||
}
|
||||
const moduleMap = this._map[name];
|
||||
const modulePlatform =
|
||||
parsePlatformFilePath(mod.path, this._platforms).platform ||
|
||||
GENERIC_PLATFORM;
|
||||
existingModule = moduleMap[modulePlatform];
|
||||
moduleMap[modulePlatform] = mod;
|
||||
}
|
||||
|
||||
if (existingModule && existingModule.path !== mod.path) {
|
||||
throw new Error(
|
||||
`@providesModule naming collision:\n` +
|
||||
` Duplicate module name: ${name}\n` +
|
||||
` Paths: ${mod.path} collides with ${existingModule.path}\n\n` +
|
||||
'This error is caused by a @providesModule declaration ' +
|
||||
'with the same name across two different files.',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = HasteMap;
|
|
@ -30,12 +30,12 @@ export type ModuleMap = {
|
|||
getModule(
|
||||
name: string,
|
||||
platform: string | null,
|
||||
supportsNativePlatform: boolean,
|
||||
supportsNativePlatform: ?boolean,
|
||||
): ?string,
|
||||
getPackage(
|
||||
name: string,
|
||||
platform: string | null,
|
||||
supportsNativePlatform: boolean,
|
||||
supportsNativePlatform: ?boolean,
|
||||
): ?string,
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue