UNPKG

create-expo-cljs-app

Version:

Create a react native application with Expo and Shadow-CLJS!

183 lines (160 loc) 5.54 kB
/** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow * @format */ 'use strict'; const HasteFS = require('./HasteFS'); const Module = require('./Module'); const ModuleCache = require('./ModuleCache'); const defaults = require('metro-config/src/defaults/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} from '../../node-haste/DependencyGraph/ModuleResolution'; import type {ResolveFn, TransformedCodeFile} from '../types.flow'; import type {Extensions, Path} from './node-haste.flow'; import type {CustomResolver} from 'metro-resolver'; type ResolveOptions = {| +platform: string, +sourceExts: Extensions, assetExts: Extensions, assetResolutions: $ReadOnlyArray<string>, extraNodeModules: {[id: string]: string, ...}, mainFields: $ReadOnlyArray<string>, nodeModulesPaths: $ReadOnlyArray<string>, resolveRequest?: ?CustomResolver, transformedFiles: {[path: Path]: TransformedCodeFile, ...}, |}; const platforms = new Set(defaults.platforms); const GENERIC_PLATFORM = 'g'; const PACKAGE_JSON = path.sep + 'package.json'; const NULL_MODULE: Moduleish = { path: '/', getPackage(): void {}, isHaste() { throw new Error('not implemented'); }, getName() { throw new Error('not implemented'); }, }; const NODE_MODULES = path.sep + 'node_modules' + path.sep; const isNodeModules = file => file.includes(NODE_MODULES); // This function maps the ModuleGraph data structure to jest-haste-map's ModuleMap const createModuleMap = ({files, moduleCache, sourceExts}) => { const map = new Map(); files.forEach((filePath: string) => { if (isNodeModules(filePath)) { return; } 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())) { return; } const mapModule = map.get(id) || Object.create(null); const platform = parsePlatformFilePath(filePath, platforms).platform || GENERIC_PLATFORM; const existingModule = mapModule[platform]; // 0 = Module, 1 = Package in jest-haste-map mapModule[platform] = [filePath, module.type === 'Package' ? 1 : 0]; if (existingModule && existingModule[0] !== filePath) { throw new Error( [ '@providesModule naming collision:', ` Duplicate module name: \`${id}\``, ` Paths: \`${filePath}\` collides with \`${existingModule[0]}\``, '', 'This error is caused by a @providesModule declaration ' + 'with the same name across two different files.', ].join('\n'), ); } map.set(id, mapModule); }); return map; }; exports.createResolveFn = function(options: ResolveOptions): ResolveFn { const { assetExts, assetResolutions, extraNodeModules, transformedFiles, sourceExts, platform, } = options; const files = Object.keys(transformedFiles); function getTransformedFile(path: string): TransformedCodeFile { const result = transformedFiles[path]; if (!result) { throw new Error(`"${path} does not exist`); } return result; } const hasteFS = new HasteFS(files); const moduleCache = new ModuleCache( (filePath: string) => hasteFS.closest(filePath, 'package.json'), getTransformedFile, ); const assetExtensions = new Set(assetExts.map(asset => '.' + asset)); const isAssetFile = file => assetExtensions.has(path.extname(file)); const moduleResolver = new ModuleResolver({ dirExists: (filePath: string): boolean => hasteFS.dirExists(filePath), doesFileExist: (filePath: string): boolean => hasteFS.exists(filePath), extraNodeModules, isAssetFile, mainFields: options.mainFields, // $FlowFixMe -- error revealed by types-first codemod moduleCache, moduleMap: new ModuleMap({ duplicates: new Map(), map: createModuleMap({files, moduleCache, sourceExts}), mocks: new Map(), rootDir: '', }), nodeModulesPaths: options.nodeModulesPaths, preferNativePlatform: true, projectRoot: '', resolveAsset: ( dirPath: string, assetName: string, extension: string, ): ?$ReadOnlyArray<string> => { const basePath = dirPath + path.sep + assetName; const assets = [ basePath + extension, ...assetResolutions.map( resolution => basePath + '@' + resolution + 'x' + extension, ), ].filter(candidate => hasteFS.exists(candidate)); return assets.length ? assets : null; }, resolveRequest: options.resolveRequest, sourceExts, }); return (id: string, sourcePath: ?string) => { const from = sourcePath != null ? new Module(sourcePath, moduleCache, getTransformedFile(sourcePath)) : NULL_MODULE; const allowHaste = !isNodeModules(from.path); // $FlowFixMe -- error revealed by types-first codemod return moduleResolver.resolveDependency(from, id, allowHaste, platform) .path; }; };