webpack/lib/config/browserslistTargetHandler.js

108 lines
2.5 KiB
JavaScript
Raw Normal View History

2020-09-24 19:33:09 +08:00
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Sergey Melyukov @smelukov
*/
2020-09-24 19:42:27 +08:00
"use strict";
2020-09-24 19:33:09 +08:00
const browserslist = require("browserslist");
2020-09-24 20:46:28 +08:00
const path = require("path");
2020-09-24 19:33:09 +08:00
2020-09-25 04:10:33 +08:00
// [[C:]/path/to/config][:env]
2020-09-25 04:44:41 +08:00
const inputRx = /^(?:((?:[A-Z]:)?[/\\].*?))?(?::(.+?))?$/i;
2020-09-24 19:33:09 +08:00
/**
* @typedef {Object} BrowserslistHandlerConfig
* @property {string} [configPath]
* @property {string} [env]
* @property {string} [query]
*/
/**
* @param {BrowserslistHandlerConfig|null} handlerConfig config
* @returns {import("./target").EcmaTargetProperties} es features
*/
const resolve = handlerConfig => {
const { configPath, env, query } = handlerConfig || {};
2020-09-24 19:33:09 +08:00
// 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({
2020-09-24 19:33:09 +08:00
config: configPath,
env
})
: browserslist.loadConfig({ path: process.cwd(), env });
2020-09-24 19:33:09 +08:00
const browsers = browserslist(config);
const checker = createChecker(browsers);
2020-09-24 19:33:09 +08:00
return resolveESFeatures(checker);
};
/**
* @param {string} input input string
* @returns {BrowserslistHandlerConfig|null} config
*/
const parse = input => {
if (!input) {
return null;
}
2020-09-24 20:41:54 +08:00
if (path.isAbsolute(input)) {
const [, configPath, env] = inputRx.exec(input) || [];
return { configPath, env };
}
const config = browserslist.findConfig(process.cwd());
2020-09-25 04:10:33 +08:00
if (config && Object.keys(config).includes(input)) {
return { env: input };
2020-09-24 20:41:54 +08:00
}
2020-09-24 19:33:09 +08:00
2020-09-25 04:10:33 +08:00
return { query: input };
2020-09-24 19:33:09 +08:00
};
/**
* @param {function(string): boolean} checker checker function
* @returns {import("./target").EcmaTargetProperties} es features
*/
const resolveESFeatures = checker => {
return {
const: checker("es6"),
arrowFunction: checker("es6"),
forOf: checker("es6"),
destructuring: checker("es6"),
bigIntLiteral: checker("bigint"),
module: checker("es6-module"),
dynamicImport: checker("es6-module-dynamic-import"),
dynamicImportInWorker: checker("es6-module-dynamic-import"),
// browserslist does not have info about globalThis
globalThis: undefined
};
};
/**
* Create browserslist checker
* @param {string[]} browsers supported browsers list
* @returns {function(string):boolean} checker
*/
const createChecker = browsers => {
2020-09-24 19:33:09 +08:00
/**
* @param {string} feature an ES feature to test
* @returns {boolean} true if supports
*/
return feature => {
const supportsFeature = browserslist(`supports ${feature}`);
return browsers.every(v => supportsFeature.includes(v));
};
};
module.exports = {
resolve,
parse
};