mirror of https://github.com/webpack/webpack.git
				
				
				
			
		
			
				
	
	
		
			334 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			334 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
/*
 | 
						|
	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
						|
	Author Sergey Melyukov @smelukov
 | 
						|
*/
 | 
						|
 | 
						|
"use strict";
 | 
						|
 | 
						|
const browserslist = require("browserslist");
 | 
						|
const path = require("path");
 | 
						|
 | 
						|
/** @typedef {import("./target").ApiTargetProperties} ApiTargetProperties */
 | 
						|
/** @typedef {import("./target").EcmaTargetProperties} EcmaTargetProperties */
 | 
						|
/** @typedef {import("./target").PlatformTargetProperties} PlatformTargetProperties */
 | 
						|
 | 
						|
// [[C:]/path/to/config][:env]
 | 
						|
const inputRx = /^(?:((?:[A-Z]:)?[/\\].*?))?(?::(.+?))?$/i;
 | 
						|
 | 
						|
/**
 | 
						|
 * @typedef {Object} BrowserslistHandlerConfig
 | 
						|
 * @property {string=} configPath
 | 
						|
 * @property {string=} env
 | 
						|
 * @property {string=} query
 | 
						|
 */
 | 
						|
 | 
						|
/**
 | 
						|
 * @param {string} input input string
 | 
						|
 * @param {string} context the context directory
 | 
						|
 * @returns {BrowserslistHandlerConfig} config
 | 
						|
 */
 | 
						|
const parse = (input, context) => {
 | 
						|
	if (!input) {
 | 
						|
		return {};
 | 
						|
	}
 | 
						|
 | 
						|
	if (path.isAbsolute(input)) {
 | 
						|
		const [, configPath, env] = inputRx.exec(input) || [];
 | 
						|
		return { configPath, env };
 | 
						|
	}
 | 
						|
 | 
						|
	const config = browserslist.findConfig(context);
 | 
						|
 | 
						|
	if (config && Object.keys(config).includes(input)) {
 | 
						|
		return { env: input };
 | 
						|
	}
 | 
						|
 | 
						|
	return { query: input };
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * @param {string} input input string
 | 
						|
 * @param {string} context the context directory
 | 
						|
 * @returns {string[] | undefined} selected browsers
 | 
						|
 */
 | 
						|
const load = (input, context) => {
 | 
						|
	const { configPath, env, query } = parse(input, context);
 | 
						|
 | 
						|
	// if a query is specified, then use it, else
 | 
						|
	// if a path to a config is specified then load it, else
 | 
						|
	// find a nearest config
 | 
						|
	const config = query
 | 
						|
		? query
 | 
						|
		: configPath
 | 
						|
		? browserslist.loadConfig({
 | 
						|
				config: configPath,
 | 
						|
				env
 | 
						|
		  })
 | 
						|
		: browserslist.loadConfig({ path: context, env });
 | 
						|
 | 
						|
	if (!config) return null;
 | 
						|
	return browserslist(config);
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * @param {string[]} browsers supported browsers list
 | 
						|
 * @returns {EcmaTargetProperties & PlatformTargetProperties & ApiTargetProperties} target properties
 | 
						|
 */
 | 
						|
const resolve = browsers => {
 | 
						|
	/**
 | 
						|
	 * Checks all against a version number
 | 
						|
	 * @param {Record<string, number | [number, number]>} versions first supported version
 | 
						|
	 * @returns {boolean} true if supports
 | 
						|
	 */
 | 
						|
	const rawChecker = versions => {
 | 
						|
		return browsers.every(v => {
 | 
						|
			const [name, parsedVersion] = v.split(" ");
 | 
						|
			if (!name) return false;
 | 
						|
			const requiredVersion = versions[name];
 | 
						|
			if (!requiredVersion) return false;
 | 
						|
			const [parsedMajor, parserMinor] =
 | 
						|
				// safari TP supports all features for normal safari
 | 
						|
				parsedVersion === "TP"
 | 
						|
					? [Infinity, Infinity]
 | 
						|
					: parsedVersion.split(".");
 | 
						|
			if (typeof requiredVersion === "number") {
 | 
						|
				return +parsedMajor >= requiredVersion;
 | 
						|
			}
 | 
						|
			return requiredVersion[0] === +parsedMajor
 | 
						|
				? +parserMinor >= requiredVersion[1]
 | 
						|
				: +parsedMajor > requiredVersion[0];
 | 
						|
		});
 | 
						|
	};
 | 
						|
	const anyNode = browsers.some(b => /^node /.test(b));
 | 
						|
	const anyBrowser = browsers.some(b => /^(?!node)/.test(b));
 | 
						|
	const browserProperty = !anyBrowser ? false : anyNode ? null : true;
 | 
						|
	const nodeProperty = !anyNode ? false : anyBrowser ? null : true;
 | 
						|
	// Internet Explorer Mobile, Blackberry browser and Opera Mini are very old browsers, they do not support new features
 | 
						|
	const es6DynamicImport = rawChecker({
 | 
						|
		chrome: 63,
 | 
						|
		and_chr: 63,
 | 
						|
		edge: 79,
 | 
						|
		firefox: 67,
 | 
						|
		and_ff: 67,
 | 
						|
		// ie: Not supported
 | 
						|
		opera: 50,
 | 
						|
		op_mob: 46,
 | 
						|
		safari: [11, 1],
 | 
						|
		ios_saf: [11, 3],
 | 
						|
		samsung: [8, 2],
 | 
						|
		android: 63,
 | 
						|
		and_qq: [10, 4],
 | 
						|
		// baidu: Not supported
 | 
						|
		// and_uc: Not supported
 | 
						|
		// kaios: Not supported
 | 
						|
		node: [12, 17]
 | 
						|
	});
 | 
						|
 | 
						|
	return {
 | 
						|
		const: rawChecker({
 | 
						|
			chrome: 49,
 | 
						|
			and_chr: 49,
 | 
						|
			edge: 12,
 | 
						|
			// Prior to Firefox 13, <code>const</code> is implemented, but re-assignment is not failing.
 | 
						|
			// Prior to Firefox 46, a <code>TypeError</code> was thrown on redeclaration instead of a <code>SyntaxError</code>.
 | 
						|
			firefox: 36,
 | 
						|
			and_ff: 36,
 | 
						|
			// Not supported in for-in and for-of loops
 | 
						|
			// ie: Not supported
 | 
						|
			opera: 36,
 | 
						|
			op_mob: 36,
 | 
						|
			safari: [10, 0],
 | 
						|
			ios_saf: [10, 0],
 | 
						|
			// Before 5.0 supported correctly in strict mode, otherwise supported without block scope
 | 
						|
			samsung: [5, 0],
 | 
						|
			android: 37,
 | 
						|
			and_qq: [10, 4],
 | 
						|
			// Supported correctly in strict mode, otherwise supported without block scope
 | 
						|
			// baidu: Not supported
 | 
						|
			and_uc: [12, 12],
 | 
						|
			kaios: [2, 5],
 | 
						|
			node: [6, 0]
 | 
						|
		}),
 | 
						|
		arrowFunction: rawChecker({
 | 
						|
			chrome: 45,
 | 
						|
			and_chr: 45,
 | 
						|
			edge: 12,
 | 
						|
			// The initial implementation of arrow functions in Firefox made them automatically strict. This has been changed as of Firefox 24. The use of <code>'use strict';</code> is now required.
 | 
						|
			// Prior to Firefox 39, a line terminator (<code>\\n</code>) was incorrectly allowed after arrow function arguments. This has been fixed to conform to the ES2015 specification and code like <code>() \\n => {}</code> will now throw a <code>SyntaxError</code> in this and later versions.
 | 
						|
			firefox: 39,
 | 
						|
			and_ff: 39,
 | 
						|
			// ie: Not supported,
 | 
						|
			opera: 32,
 | 
						|
			op_mob: 32,
 | 
						|
			safari: 10,
 | 
						|
			ios_saf: 10,
 | 
						|
			samsung: [5, 0],
 | 
						|
			android: 45,
 | 
						|
			and_qq: [10, 4],
 | 
						|
			baidu: [7, 12],
 | 
						|
			and_uc: [12, 12],
 | 
						|
			kaios: [2, 5],
 | 
						|
			node: [6, 0]
 | 
						|
		}),
 | 
						|
		forOf: rawChecker({
 | 
						|
			chrome: 38,
 | 
						|
			and_chr: 38,
 | 
						|
			edge: 12,
 | 
						|
			// Prior to Firefox 51, using the for...of loop construct with the const keyword threw a SyntaxError ("missing = in const declaration").
 | 
						|
			firefox: 51,
 | 
						|
			and_ff: 51,
 | 
						|
			// ie: Not supported,
 | 
						|
			opera: 25,
 | 
						|
			op_mob: 25,
 | 
						|
			safari: 7,
 | 
						|
			ios_saf: 7,
 | 
						|
			samsung: [3, 0],
 | 
						|
			android: 38,
 | 
						|
			// and_qq: Unknown support
 | 
						|
			// baidu: Unknown support
 | 
						|
			// and_uc: Unknown support
 | 
						|
			// kaios: Unknown support
 | 
						|
			node: [0, 12]
 | 
						|
		}),
 | 
						|
		destructuring: rawChecker({
 | 
						|
			chrome: 49,
 | 
						|
			and_chr: 49,
 | 
						|
			edge: 14,
 | 
						|
			firefox: 41,
 | 
						|
			and_ff: 41,
 | 
						|
			// ie: Not supported,
 | 
						|
			opera: 36,
 | 
						|
			op_mob: 36,
 | 
						|
			safari: 8,
 | 
						|
			ios_saf: 8,
 | 
						|
			samsung: [5, 0],
 | 
						|
			android: 49,
 | 
						|
			// and_qq: Unknown support
 | 
						|
			// baidu: Unknown support
 | 
						|
			// and_uc: Unknown support
 | 
						|
			// kaios: Unknown support
 | 
						|
			node: [6, 0]
 | 
						|
		}),
 | 
						|
		bigIntLiteral: rawChecker({
 | 
						|
			chrome: 67,
 | 
						|
			and_chr: 67,
 | 
						|
			edge: 79,
 | 
						|
			firefox: 68,
 | 
						|
			and_ff: 68,
 | 
						|
			// ie: Not supported,
 | 
						|
			opera: 54,
 | 
						|
			op_mob: 48,
 | 
						|
			safari: 14,
 | 
						|
			ios_saf: 14,
 | 
						|
			samsung: [9, 2],
 | 
						|
			android: 67,
 | 
						|
			// and_qq: Not supported
 | 
						|
			// baidu: Not supported
 | 
						|
			// and_uc: Not supported
 | 
						|
			// kaios: Not supported
 | 
						|
			node: [10, 4]
 | 
						|
		}),
 | 
						|
		// Support syntax `import` and `export` and no limitations and bugs on Node.js
 | 
						|
		// Not include `export * as namespace`
 | 
						|
		module: rawChecker({
 | 
						|
			chrome: 61,
 | 
						|
			and_chr: 61,
 | 
						|
			edge: 16,
 | 
						|
			firefox: 60,
 | 
						|
			and_ff: 60,
 | 
						|
			// ie: Not supported,
 | 
						|
			opera: 48,
 | 
						|
			op_mob: 45,
 | 
						|
			safari: [10, 1],
 | 
						|
			ios_saf: [10, 3],
 | 
						|
			samsung: [8, 0],
 | 
						|
			android: 61,
 | 
						|
			and_qq: [10, 4],
 | 
						|
			// baidu: Not supported
 | 
						|
			// and_uc: Not supported
 | 
						|
			// kaios: Not supported
 | 
						|
			node: [12, 17]
 | 
						|
		}),
 | 
						|
		dynamicImport: es6DynamicImport,
 | 
						|
		dynamicImportInWorker: es6DynamicImport && !anyNode,
 | 
						|
		// browserslist does not have info about globalThis
 | 
						|
		// so this is based on mdn-browser-compat-data
 | 
						|
		globalThis: rawChecker({
 | 
						|
			chrome: 71,
 | 
						|
			and_chr: 71,
 | 
						|
			edge: 79,
 | 
						|
			firefox: 65,
 | 
						|
			and_ff: 65,
 | 
						|
			// ie: Not supported,
 | 
						|
			opera: 58,
 | 
						|
			op_mob: 50,
 | 
						|
			safari: [12, 1],
 | 
						|
			ios_saf: [12, 2],
 | 
						|
			samsung: [10, 1],
 | 
						|
			android: 71,
 | 
						|
			// and_qq: Unknown support
 | 
						|
			// baidu: Unknown support
 | 
						|
			// and_uc: Unknown support
 | 
						|
			// kaios: Unknown support
 | 
						|
			node: 12
 | 
						|
		}),
 | 
						|
		optionalChaining: rawChecker({
 | 
						|
			chrome: 80,
 | 
						|
			and_chr: 80,
 | 
						|
			edge: 80,
 | 
						|
			firefox: 74,
 | 
						|
			and_ff: 79,
 | 
						|
			// ie: Not supported,
 | 
						|
			opera: 67,
 | 
						|
			op_mob: 64,
 | 
						|
			safari: [13, 1],
 | 
						|
			ios_saf: [13, 4],
 | 
						|
			samsung: 13,
 | 
						|
			android: 80,
 | 
						|
			// and_qq: Not supported
 | 
						|
			// baidu: Not supported
 | 
						|
			// and_uc: Not supported
 | 
						|
			// kaios: Not supported
 | 
						|
			node: 14
 | 
						|
		}),
 | 
						|
		templateLiteral: rawChecker({
 | 
						|
			chrome: 41,
 | 
						|
			and_chr: 41,
 | 
						|
			edge: 13,
 | 
						|
			firefox: 34,
 | 
						|
			and_ff: 34,
 | 
						|
			// ie: Not supported,
 | 
						|
			opera: 29,
 | 
						|
			op_mob: 64,
 | 
						|
			safari: [9, 1],
 | 
						|
			ios_saf: 9,
 | 
						|
			samsung: 4,
 | 
						|
			android: 41,
 | 
						|
			and_qq: [10, 4],
 | 
						|
			baidu: [7, 12],
 | 
						|
			and_uc: [12, 12],
 | 
						|
			kaios: [2, 5],
 | 
						|
			node: 4
 | 
						|
		}),
 | 
						|
		browser: browserProperty,
 | 
						|
		electron: false,
 | 
						|
		node: nodeProperty,
 | 
						|
		nwjs: false,
 | 
						|
		web: browserProperty,
 | 
						|
		webworker: false,
 | 
						|
 | 
						|
		document: browserProperty,
 | 
						|
		fetchWasm: browserProperty,
 | 
						|
		global: nodeProperty,
 | 
						|
		importScripts: false,
 | 
						|
		importScriptsInWorker: true,
 | 
						|
		nodeBuiltins: nodeProperty,
 | 
						|
		require: nodeProperty
 | 
						|
	};
 | 
						|
};
 | 
						|
 | 
						|
module.exports = {
 | 
						|
	resolve,
 | 
						|
	load
 | 
						|
};
 |