| 1 | /*
|
|---|
| 2 | MIT License http://www.opensource.org/licenses/mit-license.php
|
|---|
| 3 | Author Sergey Melyukov @smelukov
|
|---|
| 4 | */
|
|---|
| 5 |
|
|---|
| 6 | "use strict";
|
|---|
| 7 |
|
|---|
| 8 | const path = require("path");
|
|---|
| 9 | const browserslist = require("browserslist");
|
|---|
| 10 |
|
|---|
| 11 | /** @typedef {import("./target").ApiTargetProperties} ApiTargetProperties */
|
|---|
| 12 | /** @typedef {import("./target").EcmaTargetProperties} EcmaTargetProperties */
|
|---|
| 13 | /** @typedef {import("./target").PlatformTargetProperties} PlatformTargetProperties */
|
|---|
| 14 |
|
|---|
| 15 | // [[C:]/path/to/config][:env]
|
|---|
| 16 | const inputRx = /^(?:((?:[A-Z]:)?[/\\].*?))?(?::(.+?))?$/i;
|
|---|
| 17 |
|
|---|
| 18 | /**
|
|---|
| 19 | * Returns selected browsers.
|
|---|
| 20 | * @param {string | null | undefined} input input string
|
|---|
| 21 | * @param {string} context the context directory
|
|---|
| 22 | * @returns {string[] | undefined} selected browsers
|
|---|
| 23 | */
|
|---|
| 24 | const load = (input, context) => {
|
|---|
| 25 | // browserslist:path-to-config
|
|---|
| 26 | // browserslist:path-to-config:env
|
|---|
| 27 | if (input && path.isAbsolute(input)) {
|
|---|
| 28 | const [, configPath, env] = inputRx.exec(input) || [];
|
|---|
| 29 |
|
|---|
| 30 | const config = browserslist.loadConfig({
|
|---|
| 31 | config: configPath,
|
|---|
| 32 | env
|
|---|
| 33 | });
|
|---|
| 34 |
|
|---|
| 35 | return browserslist(config, { env });
|
|---|
| 36 | }
|
|---|
| 37 |
|
|---|
| 38 | const env = input || undefined;
|
|---|
| 39 |
|
|---|
| 40 | const config = browserslist.loadConfig({
|
|---|
| 41 | path: context,
|
|---|
| 42 | env
|
|---|
| 43 | });
|
|---|
| 44 |
|
|---|
| 45 | // browserslist
|
|---|
| 46 | // browserslist:env
|
|---|
| 47 | if (config) {
|
|---|
| 48 | try {
|
|---|
| 49 | return browserslist(config, { env, throwOnMissing: true });
|
|---|
| 50 | } catch (_err) {
|
|---|
| 51 | // Nothing, no `env` was found in browserslist, maybe input is `queries`
|
|---|
| 52 | }
|
|---|
| 53 | }
|
|---|
| 54 |
|
|---|
| 55 | // browserslist:query
|
|---|
| 56 | if (env) {
|
|---|
| 57 | return browserslist(env);
|
|---|
| 58 | }
|
|---|
| 59 | };
|
|---|
| 60 |
|
|---|
| 61 | /**
|
|---|
| 62 | * Returns target properties.
|
|---|
| 63 | * @param {string[]} browsers supported browsers list
|
|---|
| 64 | * @returns {EcmaTargetProperties & PlatformTargetProperties & ApiTargetProperties} target properties
|
|---|
| 65 | */
|
|---|
| 66 | const resolve = (browsers) => {
|
|---|
| 67 | /**
|
|---|
| 68 | * Checks all against a version number
|
|---|
| 69 | * @param {Record<string, number | [number, number]>} versions first supported version
|
|---|
| 70 | * @returns {boolean} true if supports
|
|---|
| 71 | */
|
|---|
| 72 | const rawChecker = (versions) =>
|
|---|
| 73 | browsers.every((v) => {
|
|---|
| 74 | const [name, parsedVersion] = v.split(" ");
|
|---|
| 75 | if (!name) return false;
|
|---|
| 76 | const requiredVersion = versions[name];
|
|---|
| 77 | if (!requiredVersion) return false;
|
|---|
| 78 | const [parsedMajor, parserMinor] =
|
|---|
| 79 | // safari TP supports all features for normal safari
|
|---|
| 80 | parsedVersion === "TP"
|
|---|
| 81 | ? [Infinity, Infinity]
|
|---|
| 82 | : parsedVersion.includes("-")
|
|---|
| 83 | ? parsedVersion.split("-")[0].split(".")
|
|---|
| 84 | : parsedVersion.split(".");
|
|---|
| 85 | if (typeof requiredVersion === "number") {
|
|---|
| 86 | return Number(parsedMajor) >= requiredVersion;
|
|---|
| 87 | }
|
|---|
| 88 | return requiredVersion[0] === Number(parsedMajor)
|
|---|
| 89 | ? Number(parserMinor) >= requiredVersion[1]
|
|---|
| 90 | : Number(parsedMajor) > requiredVersion[0];
|
|---|
| 91 | });
|
|---|
| 92 | const anyNode = browsers.some((b) => b.startsWith("node "));
|
|---|
| 93 | const anyBrowser = browsers.some((b) => /^(?!node)/.test(b));
|
|---|
| 94 | const browserProperty = !anyBrowser ? false : anyNode ? null : true;
|
|---|
| 95 | const nodeProperty = !anyNode ? false : anyBrowser ? null : true;
|
|---|
| 96 |
|
|---|
| 97 | return {
|
|---|
| 98 | /* eslint-disable camelcase */
|
|---|
| 99 | const: rawChecker({
|
|---|
| 100 | chrome: 49,
|
|---|
| 101 | and_chr: 49,
|
|---|
| 102 | edge: 12,
|
|---|
| 103 | // Prior to Firefox 13, <code>const</code> is implemented, but re-assignment is not failing.
|
|---|
| 104 | // Prior to Firefox 46, a <code>TypeError</code> was thrown on redeclaration instead of a <code>SyntaxError</code>.
|
|---|
| 105 | firefox: 36,
|
|---|
| 106 | and_ff: 36,
|
|---|
| 107 | // Not supported in for-in and for-of loops
|
|---|
| 108 | // ie: Not supported
|
|---|
| 109 | opera: 36,
|
|---|
| 110 | op_mob: 36,
|
|---|
| 111 | safari: [10, 0],
|
|---|
| 112 | ios_saf: [10, 0],
|
|---|
| 113 | // Before 5.0 supported correctly in strict mode, otherwise supported without block scope
|
|---|
| 114 | samsung: [5, 0],
|
|---|
| 115 | android: 37,
|
|---|
| 116 | and_qq: [10, 4],
|
|---|
| 117 | // Supported correctly in strict mode, otherwise supported without block scope
|
|---|
| 118 | baidu: [13, 18],
|
|---|
| 119 | and_uc: [12, 12],
|
|---|
| 120 | kaios: [2, 5],
|
|---|
| 121 | node: [6, 0]
|
|---|
| 122 | }),
|
|---|
| 123 | methodShorthand: rawChecker({
|
|---|
| 124 | chrome: 47,
|
|---|
| 125 | and_chr: 47,
|
|---|
| 126 | edge: 12,
|
|---|
| 127 | firefox: 34,
|
|---|
| 128 | and_ff: 34,
|
|---|
| 129 | // ie: Not supported,
|
|---|
| 130 | opera: 34,
|
|---|
| 131 | op_mob: 34,
|
|---|
| 132 | safari: 9,
|
|---|
| 133 | ios_saf: 9,
|
|---|
| 134 | samsung: 5,
|
|---|
| 135 | android: 47,
|
|---|
| 136 | // baidu: Not tracked,
|
|---|
| 137 | and_qq: [14, 9],
|
|---|
| 138 | and_uc: [15, 5],
|
|---|
| 139 | kaios: [2, 5],
|
|---|
| 140 | node: [4, 9]
|
|---|
| 141 | }),
|
|---|
| 142 | arrowFunction: rawChecker({
|
|---|
| 143 | chrome: 45,
|
|---|
| 144 | and_chr: 45,
|
|---|
| 145 | edge: 12,
|
|---|
| 146 | // 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.
|
|---|
| 147 | // 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.
|
|---|
| 148 | firefox: 39,
|
|---|
| 149 | and_ff: 39,
|
|---|
| 150 | // ie: Not supported,
|
|---|
| 151 | opera: 32,
|
|---|
| 152 | op_mob: 32,
|
|---|
| 153 | safari: 10,
|
|---|
| 154 | ios_saf: 10,
|
|---|
| 155 | samsung: [5, 0],
|
|---|
| 156 | android: 45,
|
|---|
| 157 | and_qq: [10, 4],
|
|---|
| 158 | baidu: [7, 12],
|
|---|
| 159 | and_uc: [12, 12],
|
|---|
| 160 | kaios: [2, 5],
|
|---|
| 161 | node: [6, 0]
|
|---|
| 162 | }),
|
|---|
| 163 | forOf: rawChecker({
|
|---|
| 164 | chrome: 38,
|
|---|
| 165 | and_chr: 38,
|
|---|
| 166 | edge: 12,
|
|---|
| 167 | // Prior to Firefox 51, using the for...of loop construct with the const keyword threw a SyntaxError ("missing = in const declaration").
|
|---|
| 168 | firefox: 51,
|
|---|
| 169 | and_ff: 51,
|
|---|
| 170 | // ie: Not supported,
|
|---|
| 171 | opera: 25,
|
|---|
| 172 | op_mob: 25,
|
|---|
| 173 | safari: 7,
|
|---|
| 174 | ios_saf: 7,
|
|---|
| 175 | samsung: [3, 0],
|
|---|
| 176 | android: 38,
|
|---|
| 177 | and_qq: [10, 4],
|
|---|
| 178 | // baidu: Unknown support
|
|---|
| 179 | and_uc: [12, 12],
|
|---|
| 180 | kaios: [3, 0],
|
|---|
| 181 | node: [0, 12]
|
|---|
| 182 | }),
|
|---|
| 183 | destructuring: rawChecker({
|
|---|
| 184 | chrome: 49,
|
|---|
| 185 | and_chr: 49,
|
|---|
| 186 | edge: 14,
|
|---|
| 187 | firefox: 41,
|
|---|
| 188 | and_ff: 41,
|
|---|
| 189 | // ie: Not supported,
|
|---|
| 190 | opera: 36,
|
|---|
| 191 | op_mob: 36,
|
|---|
| 192 | safari: 8,
|
|---|
| 193 | ios_saf: 8,
|
|---|
| 194 | samsung: [5, 0],
|
|---|
| 195 | android: 49,
|
|---|
| 196 | and_qq: [10, 4],
|
|---|
| 197 | // baidu: Unknown support
|
|---|
| 198 | and_uc: [12, 12],
|
|---|
| 199 | kaios: [2, 5],
|
|---|
| 200 | node: [6, 0]
|
|---|
| 201 | }),
|
|---|
| 202 | bigIntLiteral: rawChecker({
|
|---|
| 203 | chrome: 67,
|
|---|
| 204 | and_chr: 67,
|
|---|
| 205 | edge: 79,
|
|---|
| 206 | firefox: 68,
|
|---|
| 207 | and_ff: 68,
|
|---|
| 208 | // ie: Not supported,
|
|---|
| 209 | opera: 54,
|
|---|
| 210 | op_mob: 48,
|
|---|
| 211 | safari: 14,
|
|---|
| 212 | ios_saf: 14,
|
|---|
| 213 | samsung: [9, 2],
|
|---|
| 214 | android: 67,
|
|---|
| 215 | and_qq: [13, 1],
|
|---|
| 216 | baidu: [13, 18],
|
|---|
| 217 | and_uc: [15, 5],
|
|---|
| 218 | kaios: [3, 0],
|
|---|
| 219 | node: [10, 4]
|
|---|
| 220 | }),
|
|---|
| 221 | // Support syntax `import` and `export` and no limitations and bugs on Node.js
|
|---|
| 222 | // Not include `export * as namespace`
|
|---|
| 223 | module: rawChecker({
|
|---|
| 224 | chrome: 61,
|
|---|
| 225 | and_chr: 61,
|
|---|
| 226 | edge: 16,
|
|---|
| 227 | firefox: 60,
|
|---|
| 228 | and_ff: 60,
|
|---|
| 229 | // ie: Not supported,
|
|---|
| 230 | opera: 48,
|
|---|
| 231 | op_mob: 45,
|
|---|
| 232 | safari: [10, 1],
|
|---|
| 233 | ios_saf: [10, 3],
|
|---|
| 234 | samsung: [8, 0],
|
|---|
| 235 | android: 61,
|
|---|
| 236 | and_qq: [10, 4],
|
|---|
| 237 | baidu: [13, 18],
|
|---|
| 238 | and_uc: [15, 5],
|
|---|
| 239 | kaios: [3, 0],
|
|---|
| 240 | node: [12, 17]
|
|---|
| 241 | }),
|
|---|
| 242 | dynamicImport: rawChecker({
|
|---|
| 243 | chrome: 63,
|
|---|
| 244 | and_chr: 63,
|
|---|
| 245 | edge: 79,
|
|---|
| 246 | firefox: 67,
|
|---|
| 247 | and_ff: 67,
|
|---|
| 248 | // ie: Not supported
|
|---|
| 249 | opera: 50,
|
|---|
| 250 | op_mob: 46,
|
|---|
| 251 | safari: [11, 1],
|
|---|
| 252 | ios_saf: [11, 3],
|
|---|
| 253 | samsung: [8, 2],
|
|---|
| 254 | android: 63,
|
|---|
| 255 | and_qq: [10, 4],
|
|---|
| 256 | baidu: [13, 18],
|
|---|
| 257 | and_uc: [15, 5],
|
|---|
| 258 | kaios: [3, 0],
|
|---|
| 259 | node: [12, 17]
|
|---|
| 260 | }),
|
|---|
| 261 | dynamicImportInWorker: rawChecker({
|
|---|
| 262 | chrome: 80,
|
|---|
| 263 | and_chr: 80,
|
|---|
| 264 | edge: 80,
|
|---|
| 265 | firefox: 114,
|
|---|
| 266 | and_ff: 114,
|
|---|
| 267 | // ie: Not supported
|
|---|
| 268 | opera: 67,
|
|---|
| 269 | op_mob: 57,
|
|---|
| 270 | safari: [15, 0],
|
|---|
| 271 | ios_saf: [15, 0],
|
|---|
| 272 | samsung: [13, 0],
|
|---|
| 273 | android: 80,
|
|---|
| 274 | and_qq: [10, 4],
|
|---|
| 275 | baidu: [13, 18],
|
|---|
| 276 | and_uc: [15, 5],
|
|---|
| 277 | kaios: [3, 0],
|
|---|
| 278 | node: [12, 17]
|
|---|
| 279 | }),
|
|---|
| 280 | // browserslist does not have info about globalThis
|
|---|
| 281 | // so this is based on mdn-browser-compat-data
|
|---|
| 282 | globalThis: rawChecker({
|
|---|
| 283 | chrome: 71,
|
|---|
| 284 | and_chr: 71,
|
|---|
| 285 | edge: 79,
|
|---|
| 286 | firefox: 65,
|
|---|
| 287 | and_ff: 65,
|
|---|
| 288 | // ie: Not supported,
|
|---|
| 289 | opera: 58,
|
|---|
| 290 | op_mob: 50,
|
|---|
| 291 | safari: [12, 1],
|
|---|
| 292 | ios_saf: [12, 2],
|
|---|
| 293 | samsung: [10, 1],
|
|---|
| 294 | android: 71,
|
|---|
| 295 | and_qq: [13, 1],
|
|---|
| 296 | // baidu: Unknown support
|
|---|
| 297 | and_uc: [15, 5],
|
|---|
| 298 | kaios: [3, 0],
|
|---|
| 299 | node: 12
|
|---|
| 300 | }),
|
|---|
| 301 | optionalChaining: rawChecker({
|
|---|
| 302 | chrome: 80,
|
|---|
| 303 | and_chr: 80,
|
|---|
| 304 | edge: 80,
|
|---|
| 305 | firefox: 74,
|
|---|
| 306 | and_ff: 79,
|
|---|
| 307 | // ie: Not supported,
|
|---|
| 308 | opera: 67,
|
|---|
| 309 | op_mob: 64,
|
|---|
| 310 | safari: [13, 1],
|
|---|
| 311 | ios_saf: [13, 4],
|
|---|
| 312 | samsung: 13,
|
|---|
| 313 | android: 80,
|
|---|
| 314 | and_qq: [13, 1],
|
|---|
| 315 | // baidu: Not supported
|
|---|
| 316 | and_uc: [15, 5],
|
|---|
| 317 | kaios: [3, 0],
|
|---|
| 318 | node: 14
|
|---|
| 319 | }),
|
|---|
| 320 | templateLiteral: rawChecker({
|
|---|
| 321 | chrome: 41,
|
|---|
| 322 | and_chr: 41,
|
|---|
| 323 | edge: 13,
|
|---|
| 324 | firefox: 34,
|
|---|
| 325 | and_ff: 34,
|
|---|
| 326 | // ie: Not supported,
|
|---|
| 327 | opera: 29,
|
|---|
| 328 | op_mob: 64,
|
|---|
| 329 | safari: [9, 1],
|
|---|
| 330 | ios_saf: 9,
|
|---|
| 331 | samsung: 4,
|
|---|
| 332 | android: 41,
|
|---|
| 333 | and_qq: [10, 4],
|
|---|
| 334 | baidu: [7, 12],
|
|---|
| 335 | and_uc: [12, 12],
|
|---|
| 336 | kaios: [2, 5],
|
|---|
| 337 | node: 4
|
|---|
| 338 | }),
|
|---|
| 339 | asyncFunction: rawChecker({
|
|---|
| 340 | chrome: 55,
|
|---|
| 341 | and_chr: 55,
|
|---|
| 342 | edge: 15,
|
|---|
| 343 | firefox: 52,
|
|---|
| 344 | and_ff: 52,
|
|---|
| 345 | // ie: Not supported,
|
|---|
| 346 | opera: 42,
|
|---|
| 347 | op_mob: 42,
|
|---|
| 348 | safari: 11,
|
|---|
| 349 | ios_saf: 11,
|
|---|
| 350 | samsung: [6, 2],
|
|---|
| 351 | android: 55,
|
|---|
| 352 | and_qq: [10, 4],
|
|---|
| 353 | baidu: [13, 18],
|
|---|
| 354 | and_uc: [12, 12],
|
|---|
| 355 | kaios: 3,
|
|---|
| 356 | node: [7, 6]
|
|---|
| 357 | }),
|
|---|
| 358 | /* eslint-enable camelcase */
|
|---|
| 359 | browser: browserProperty,
|
|---|
| 360 | electron: false,
|
|---|
| 361 | node: nodeProperty,
|
|---|
| 362 | nwjs: false,
|
|---|
| 363 | web: browserProperty,
|
|---|
| 364 | webworker: false,
|
|---|
| 365 |
|
|---|
| 366 | document: browserProperty,
|
|---|
| 367 | fetchWasm: browserProperty,
|
|---|
| 368 | global: nodeProperty,
|
|---|
| 369 | importScripts: false,
|
|---|
| 370 | importScriptsInWorker: Boolean(browserProperty),
|
|---|
| 371 | nodeBuiltins: nodeProperty,
|
|---|
| 372 | nodePrefixForCoreModules:
|
|---|
| 373 | nodeProperty &&
|
|---|
| 374 | !browsers.some((b) => b.startsWith("node 15")) &&
|
|---|
| 375 | rawChecker({
|
|---|
| 376 | node: [14, 18]
|
|---|
| 377 | }),
|
|---|
| 378 | importMetaDirnameAndFilename:
|
|---|
| 379 | nodeProperty &&
|
|---|
| 380 | rawChecker({
|
|---|
| 381 | node: [22, 16]
|
|---|
| 382 | }),
|
|---|
| 383 | require: nodeProperty
|
|---|
| 384 | };
|
|---|
| 385 | };
|
|---|
| 386 |
|
|---|
| 387 | module.exports = {
|
|---|
| 388 | load,
|
|---|
| 389 | resolve
|
|---|
| 390 | };
|
|---|