/** * 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 nullthrows = require('nullthrows'); const parseCustomTransformOptions = require('./parseCustomTransformOptions'); const parsePlatformFilePath = require('../node-haste/lib/parsePlatformFilePath'); const url = require('url'); const {revisionIdFromString} = require('../IncrementalBundler'); import type {RevisionId} from '../IncrementalBundler'; import type {BundleOptions} from '../shared/types.flow'; function getBoolOptionFromQuery( query: {[string]: string}, opt: string, defaultVal: boolean, ): boolean { if (query[opt] == null) { return defaultVal; } return query[opt] === 'true' || query[opt] === '1'; } function parseOptionsFromUrl( reqUrl: string, platforms: Set<string>, ): {| revisionId: ?RevisionId, options: BundleOptions, |} { // `true` to parse the query param as an object. const urlObj = nullthrows(url.parse(reqUrl, true)); const urlQuery = nullthrows(urlObj.query); const pathname = urlObj.pathname != null ? decodeURIComponent(urlObj.pathname) : ''; let bundleType = 'bundle'; // Backwards compatibility. Options used to be as added as '.' to the // entry module name. We can safely remove these options. const entryFileRelativeToProjectRoot = pathname .replace(/^(?:\.?\/)?/, './') // We want to produce a relative path to project root .split('.') .filter((part, i) => { if (part === 'delta' || part === 'map' || part === 'meta') { bundleType = part; return false; } if ( part === 'includeRequire' || part === 'runModule' || part === 'bundle' || part === 'assets' ) { return false; } return true; }) .join('.'); // try to get the platform from the url const platform = urlQuery.platform || parsePlatformFilePath(pathname, platforms).platform; const revisionId = urlQuery.revisionId || urlQuery.deltaBundleId || null; const dev = getBoolOptionFromQuery(urlQuery, 'dev', true); const minify = getBoolOptionFromQuery(urlQuery, 'minify', false); const excludeSource = getBoolOptionFromQuery( urlQuery, 'excludeSource', false, ); const inlineSourceMap = getBoolOptionFromQuery( urlQuery, 'inlineSourceMap', false, ); const runModule = getBoolOptionFromQuery(urlQuery, 'runModule', true); const customTransformOptions = parseCustomTransformOptions(urlObj); return { revisionId: revisionId != null ? revisionIdFromString(revisionId) : null, options: { customTransformOptions, dev, hot: true, minify, platform, onProgress: null, entryFile: entryFileRelativeToProjectRoot, bundleType, sourceMapUrl: url.format({ ...urlObj, // The remote chrome debugger loads bundles via Blob urls, whose // protocol is blob:http. This breaks loading source maps through // protocol-relative URLs, which is why we must force the HTTP protocol // when loading the bundle for either iOS or Android. protocol: platform != null && platform.match(/^(android|ios)$/) ? 'http' : '', pathname: pathname.replace(/\.(bundle|delta)$/, '.map'), }), runModule, excludeSource, inlineSourceMap, }, }; } module.exports = parseOptionsFromUrl;