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-28 16:04:58 +08:00
/** @typedef {import("./target").ApiTargetProperties} ApiTargetProperties */
2020-09-28 15:57:29 +08:00
/** @typedef {import("./target").EcmaTargetProperties} EcmaTargetProperties */
2020-09-28 16:04:58 +08:00
/** @typedef {import("./target").PlatformTargetProperties} PlatformTargetProperties */
2020-09-28 15:57:29 +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
2020-09-28 16:52:52 +08:00
* @ property { string = } configPath
* @ property { string = } env
* @ property { string = } query
2020-09-24 19:33:09 +08:00
* /
/ * *
* @ param { string } input input string
2020-09-28 16:52:52 +08:00
* @ param { string } context the context directory
2020-09-28 16:05:29 +08:00
* @ returns { BrowserslistHandlerConfig } config
2020-09-24 19:33:09 +08:00
* /
2020-09-28 16:52:52 +08:00
const parse = ( input , context ) => {
2020-09-24 19:33:09 +08:00
if ( ! input ) {
2020-09-28 16:05:29 +08:00
return { } ;
2020-09-24 19:33:09 +08:00
}
2020-09-24 20:41:54 +08:00
if ( path . isAbsolute ( input ) ) {
const [ , configPath , env ] = inputRx . exec ( input ) || [ ] ;
return { configPath , env } ;
}
2020-09-28 16:52:52 +08:00
const config = browserslist . findConfig ( context ) ;
2020-09-24 20:41:54 +08:00
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
} ;
2020-09-28 16:52:52 +08:00
/ * *
* @ param { string } input input string
* @ param { string } context the context directory
2020-09-28 17:09:07 +08:00
* @ returns { string [ ] | undefined } selected browsers
2020-09-28 16:52:52 +08:00
* /
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 ) ;
} ;
2020-09-24 19:33:09 +08:00
/ * *
* @ param { string [ ] } browsers supported browsers list
2020-09-28 16:04:58 +08:00
* @ returns { EcmaTargetProperties & PlatformTargetProperties & ApiTargetProperties } target properties
2020-09-24 19:33:09 +08:00
* /
2020-09-28 16:52:52 +08:00
const resolve = browsers => {
2020-09-28 15:57:29 +08:00
/ * *
* Checks all against a version number
2020-09-28 17:09:07 +08:00
* @ param { Record < string , number | [ number , number ] > } versions first supported version
2020-09-28 15:57:29 +08:00
* @ returns { boolean } true if supports
* /
const rawChecker = versions => {
return browsers . every ( v => {
2020-10-31 21:54:47 +08:00
const [ name , parsedVersion ] = v . split ( " " ) ;
if ( ! name ) return false ;
const requiredVersion = versions [ name ] ;
if ( ! requiredVersion ) return false ;
2020-10-31 22:03:54 +08:00
const [ parsedMajor , parserMinor ] =
// safari TP supports all features for normal safari
parsedVersion === "TP"
? [ Infinity , Infinity ]
: parsedVersion . split ( "." ) ;
2020-10-31 21:54:47 +08:00
if ( typeof requiredVersion === "number" ) {
return + parsedMajor >= requiredVersion ;
}
return requiredVersion [ 0 ] === + parsedMajor
? + parserMinor >= requiredVersion [ 1 ]
: + parsedMajor > requiredVersion [ 0 ] ;
2020-09-28 15:57:29 +08:00
} ) ;
} ;
2020-09-28 16:04:58 +08:00
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 ;
2020-11-03 00:08:06 +08:00
// Internet Explorer Mobile, Blackberry browser and Opera Mini are very old browsers, they do not support new features
2020-10-31 21:54:47 +08:00
const es6DynamicImport = rawChecker ( {
chrome : 63 ,
2020-10-31 22:17:47 +08:00
and _chr : 63 ,
2020-10-31 21:54:47 +08:00
edge : 79 ,
firefox : 67 ,
2020-10-31 22:17:47 +08:00
and _ff : 67 ,
2020-11-03 00:08:06 +08:00
// ie: Not supported
2020-10-31 21:54:47 +08:00
opera : 50 ,
2020-11-02 23:21:37 +08:00
op _mob : 46 ,
2020-10-31 21:54:47 +08:00
safari : [ 11 , 1 ] ,
2020-10-31 22:17:47 +08:00
ios _saf : [ 11 , 3 ] ,
2020-11-03 00:08:06 +08:00
samsung : [ 8 , 2 ] ,
2020-11-02 23:21:37 +08:00
android : 63 ,
2020-11-03 00:08:06 +08:00
and _qq : [ 10 , 4 ] ,
// baidu: Not supported
// and_uc: Not supported
// kaios: Not supported
2020-11-02 23:21:37 +08:00
// Since Node.js 13.14.0 no warning about usage, but it was added 8.5.0 with some limitations and it was improved in 12.0.0 and 13.2.0
node : [ 13 , 14 ]
2020-10-31 21:54:47 +08:00
} ) ;
2020-09-28 15:57:29 +08:00
return {
2020-10-31 21:54:47 +08:00
const : rawChecker ( {
2020-11-03 00:08:06 +08:00
chrome : 49 ,
and _chr : 49 ,
2020-10-31 21:54:47 +08:00
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 ,
2020-10-31 22:17:47 +08:00
and _ff : 36 ,
2020-11-02 23:21:37 +08:00
// Not supported in for-in and for-of loops
// ie: Not supported
2020-11-03 00:08:06 +08:00
opera : 36 ,
op _mob : 36 ,
safari : [ 10 , 0 ] ,
ios _saf : [ 10 , 0 ] ,
2020-11-02 23:21:37 +08:00
// Before 5.0 supported correctly in strict mode, otherwise supported without block scope
samsung : [ 5 , 0 ] ,
android : 37 ,
2020-11-03 00:08:06 +08:00
and _qq : [ 10 , 4 ] ,
// Supported correctly in strict mode, otherwise supported without block scope
// baidu: Not supported
and _uc : [ 12 , 12 ] ,
kaios : [ 2 , 5 ] ,
2020-11-02 23:21:37 +08:00
node : [ 6 , 0 ]
2020-10-31 21:54:47 +08:00
} ) ,
arrowFunction : rawChecker ( {
chrome : 45 ,
2020-10-31 22:17:47 +08:00
and _chr : 45 ,
2020-10-31 21:54:47 +08:00
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 ,
2020-10-31 22:17:47 +08:00
and _ff : 39 ,
2020-10-31 21:54:47 +08:00
// ie: Not supported,
opera : 32 ,
2020-11-02 23:21:37 +08:00
op _mob : 32 ,
2020-10-31 21:54:47 +08:00
safari : 10 ,
2020-10-31 22:17:47 +08:00
ios _saf : 10 ,
samsung : [ 5 , 0 ] ,
2020-11-02 23:21:37 +08:00
android : 45 ,
2020-11-03 00:08:06 +08:00
and _qq : [ 10 , 4 ] ,
baidu : [ 7 , 12 ] ,
and _uc : [ 12 , 12 ] ,
kaios : [ 2 , 5 ] ,
2020-11-02 23:21:37 +08:00
node : [ 6 , 0 ]
2020-10-31 21:54:47 +08:00
} ) ,
2020-10-31 01:24:42 +08:00
forOf : rawChecker ( {
chrome : 38 ,
2020-10-31 22:17:47 +08:00
and _chr : 38 ,
2020-10-31 01:24:42 +08:00
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 ,
2020-10-31 22:17:47 +08:00
and _ff : 51 ,
2020-10-31 01:24:42 +08:00
// ie: Not supported,
opera : 25 ,
2020-11-02 23:21:37 +08:00
op _mob : 25 ,
2020-10-31 01:24:42 +08:00
safari : 7 ,
2020-10-31 22:17:47 +08:00
ios _saf : 7 ,
samsung : [ 3 , 0 ] ,
2020-11-02 23:21:37 +08:00
android : 38 ,
2020-11-03 00:08:06 +08:00
// and_qq: Unknown support
// baidu: Unknown support
// and_uc: Unknown support
// kaios: Unknown support
2020-11-02 23:21:37 +08:00
node : [ 0 , 12 ]
2020-10-31 01:24:42 +08:00
} ) ,
destructuring : rawChecker ( {
chrome : 49 ,
2020-10-31 22:17:47 +08:00
and _chr : 49 ,
2020-10-31 01:24:42 +08:00
edge : 14 ,
firefox : 41 ,
2020-10-31 22:17:47 +08:00
and _ff : 41 ,
2020-10-31 01:24:42 +08:00
// ie: Not supported,
opera : 36 ,
2020-11-02 23:21:37 +08:00
op _mob : 36 ,
2020-10-31 01:24:42 +08:00
safari : 8 ,
2020-10-31 22:17:47 +08:00
ios _saf : 8 ,
samsung : [ 5 , 0 ] ,
2020-11-02 23:21:37 +08:00
android : 49 ,
2020-11-03 00:08:06 +08:00
// and_qq: Unknown support
// baidu: Unknown support
// and_uc: Unknown support
// kaios: Unknown support
2020-11-02 23:21:37 +08:00
node : [ 6 , 0 ]
2020-10-31 01:24:42 +08:00
} ) ,
2020-10-31 21:54:47 +08:00
bigIntLiteral : rawChecker ( {
chrome : 67 ,
2020-10-31 22:17:47 +08:00
and _chr : 67 ,
2020-10-31 21:54:47 +08:00
edge : 79 ,
firefox : 68 ,
2020-10-31 22:17:47 +08:00
and _ff : 68 ,
2020-10-31 21:54:47 +08:00
// ie: Not supported,
opera : 54 ,
2020-11-02 23:21:37 +08:00
op _mob : 48 ,
2020-10-31 21:54:47 +08:00
safari : 14 ,
2020-10-31 22:17:47 +08:00
ios _saf : 14 ,
2020-11-03 00:08:06 +08:00
samsung : [ 9 , 2 ] ,
2020-11-02 23:21:37 +08:00
android : 67 ,
2020-11-03 00:08:06 +08:00
// and_qq: Not supported
// baidu: Not supported
// and_uc: Not supported
// kaios: Not supported
2020-11-02 23:21:37 +08:00
node : [ 10 , 4 ]
2020-10-31 21:54:47 +08:00
} ) ,
// Support syntax `import` and `export` and no limitations and bugs on Node.js
// Not include `export * as namespace`
module : rawChecker ( {
chrome : 61 ,
2020-10-31 22:17:47 +08:00
and _chr : 61 ,
2020-10-31 21:54:47 +08:00
edge : 16 ,
firefox : 60 ,
2020-10-31 22:17:47 +08:00
and _ff : 60 ,
2020-10-31 21:54:47 +08:00
// ie: Not supported,
opera : 48 ,
2020-11-02 23:21:37 +08:00
op _mob : 45 ,
2020-10-31 21:54:47 +08:00
safari : [ 10 , 1 ] ,
2020-10-31 22:17:47 +08:00
ios _saf : [ 10 , 3 ] ,
2020-11-02 23:21:37 +08:00
samsung : [ 8 , 0 ] ,
2020-11-03 00:08:06 +08:00
android : 61 ,
and _qq : [ 10 , 4 ] ,
// baidu: Not supported
// and_uc: Not supported
// kaios: Not supported
2020-11-02 23:21:37 +08:00
// Since Node.js 13.14.0 no warning about usage, but it was added 8.5.0 with some limitations and it was improved in 12.0.0 and 13.2.0
node : [ 13 , 14 ]
2020-10-31 21:54:47 +08:00
} ) ,
dynamicImport : es6DynamicImport ,
dynamicImportInWorker : es6DynamicImport && ! anyNode ,
2020-09-28 15:57:29 +08:00
// browserslist does not have info about globalThis
// so this is based on mdn-browser-compat-data
globalThis : rawChecker ( {
chrome : 71 ,
2020-10-31 22:17:47 +08:00
and _chr : 71 ,
2020-09-28 15:57:29 +08:00
edge : 79 ,
firefox : 65 ,
2020-10-31 22:17:47 +08:00
and _ff : 65 ,
2020-09-28 15:57:29 +08:00
// ie: Not supported,
opera : 58 ,
2020-11-02 23:21:37 +08:00
op _mob : 50 ,
2020-09-28 15:57:29 +08:00
safari : [ 12 , 1 ] ,
2020-10-31 22:17:47 +08:00
ios _saf : [ 12 , 2 ] ,
2020-11-03 00:08:06 +08:00
samsung : [ 10 , 1 ] ,
2020-11-02 23:21:37 +08:00
android : 71 ,
2020-11-03 00:08:06 +08:00
// and_qq: Unknown support
// baidu: Unknown support
// and_uc: Unknown support
// kaios: Unknown support
2020-11-02 23:21:37 +08:00
node : [ 12 , 0 ]
2020-09-28 16:04:58 +08:00
} ) ,
2021-11-22 01:51:36 +08:00
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
} ) ,
2020-09-28 16:04:58 +08:00
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
2020-09-24 19:33:09 +08:00
} ;
} ;
module . exports = {
resolve ,
2020-09-28 16:52:52 +08:00
load
2020-09-24 19:33:09 +08:00
} ;