index.js
 1  const tests = {
 2    // ECMAScript 2018
 3    "object-rest-spread": ["({ ...{} })", "({ ...x } = {})"], // Babel 7.2.0
 4    "async-generators": ["async function* f() {}"], //  Babel 7.2.0
 5  
 6    // ECMAScript 2019
 7    "optional-catch-binding": ["try {} catch {}"], // Babel 7.2.0
 8    "json-strings": ["'\\u2028'"], // Babel 7.2.0
 9  
10    // ECMAScript 2020
11    "bigint": ["1n"], // Babel 7.8.0
12    "optional-chaining": ["a?.b"], // Babel 7.9.0
13    "nullish-coalescing-operator": ["a ?? b"], // Babel 7.9.0
14    // import.meta is handled manually
15  
16    // Stage 3
17    "numeric-separator": ["1_2"],
18    "class-properties": [
19      "(class { x = 1 })",
20      "(class { #x = 1 })",
21      "(class { #x() {} })",
22    ],
23    "logical-assignment-operators": ["a ||= b", "a &&= b", "a ??= c"],
24  };
25  
26  const plugins = [];
27  const works = (test) => {
28    try {
29      // Wrap the test in a function to only test the syntax, without executing it
30      (0, eval)(`(() => { ${test} })`);
31      return true;
32    } catch (_error) {
33      return false;
34    }
35  };
36  
37  for (const [name, cases] of Object.entries(tests)) {
38    if (cases.some(works)) {
39      plugins.push(require.resolve(`@babel/plugin-syntax-${name}`));
40    }
41  }
42  
43  // import.meta is only allowed in modules, and modules can only be evaluated
44  // synchronously. For this reason, we cannot detect import.meta support at
45  // runtime. It is supported starting from 10.4, so we can check the version.
46  const major = parseInt(process.versions.node, 10);
47  const minor = parseInt(process.versions.node.match(/^\d+\.(\d+)/)[1], 10);
48  if (major > 10 || (major === 10 && minor >= 4)) {
49    plugins.push(require.resolve("@babel/plugin-syntax-import-meta"));
50  }
51  // Same for top level await - it is only supported in modules. It is supported
52  // from 14.3.0
53  if (major > 14 || (major === 14 && minor >= 3)) {
54    plugins.push(require.resolve("@babel/plugin-syntax-top-level-await"));
55  }
56  
57  module.exports = () => ({ plugins });