/** * 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 strict-local * @format */ 'use strict'; const path = require('path'); import type Bundler from '../Bundler'; import type {TransformOptions} from '../DeltaBundler/Worker'; import type DeltaBundler, {TransformFn} from '../DeltaBundler'; import type {Type} from '../JSTransformer/worker'; import type {ConfigT} from 'metro-config/src/configTypes.flow'; type InlineRequiresRaw = {+blacklist: {[string]: true}} | boolean; export type TransformInputOptions = $Diff< TransformOptions, { inlineRequires: boolean, }, >; type TransformOptionsWithRawInlines = {| ...TransformOptions, +inlineRequires: InlineRequiresRaw, |}; async function calcTransformerOptions( entryFiles: $ReadOnlyArray<string>, bundler: Bundler, deltaBundler: DeltaBundler<>, config: ConfigT, options: TransformInputOptions, ): Promise<TransformOptionsWithRawInlines> { const baseOptions = { customTransformOptions: options.customTransformOptions, dev: options.dev, hot: options.hot, inlineRequires: false, minify: options.minify, platform: options.platform, }; // When we're processing scripts, we don't need to calculate any // inlineRequires information, since scripts by definition don't have // requires(). if (options.type === 'script') { return { ...baseOptions, type: 'script', }; } const getDependencies = async path => { const {dependencies} = await deltaBundler.buildGraph([path], { resolve: await getResolveDependencyFn(bundler, options.platform), transform: await getTransformFn([path], bundler, deltaBundler, config, { ...options, minify: false, }), onProgress: null, }); return Array.from(dependencies.keys()); }; const {transform} = await config.transformer.getTransformOptions( entryFiles, {dev: options.dev, hot: options.hot, platform: options.platform}, getDependencies, ); return { ...baseOptions, inlineRequires: transform.inlineRequires || false, experimentalImportSupport: transform.experimentalImportSupport || false, type: 'module', }; } function removeInlineRequiresBlacklistFromOptions( path: string, inlineRequires: InlineRequiresRaw, ): boolean { if (typeof inlineRequires === 'object') { return !(path in inlineRequires.blacklist); } return inlineRequires; } async function getTransformFn( entryFiles: $ReadOnlyArray<string>, bundler: Bundler, deltaBundler: DeltaBundler<>, config: ConfigT, options: TransformInputOptions, ): Promise<TransformFn<>> { const {inlineRequires, ...transformOptions} = await calcTransformerOptions( entryFiles, bundler, deltaBundler, config, options, ); return async (path: string) => { return await bundler.transformFile(path, { ...transformOptions, type: getType(transformOptions.type, path, config.resolver.assetExts), inlineRequires: removeInlineRequiresBlacklistFromOptions( path, inlineRequires, ), }); }; } function getType( type: string, filePath: string, assetExts: $ReadOnlyArray<string>, ): Type { if (type === 'script') { return type; } if (assetExts.indexOf(path.extname(filePath).slice(1)) !== -1) { return 'asset'; } return 'module'; } async function getResolveDependencyFn( bundler: Bundler, platform: ?string, ): Promise<(from: string, to: string) => string> { const dependencyGraph = await bundler.getDependencyGraph(); return (from: string, to: string) => dependencyGraph.resolveDependency(from, to, platform); } module.exports = { getTransformFn, getResolveDependencyFn, };