import * as swc from "@swc/core" ; import fs from "fs" ; import deepClone from "lodash.clonedeep" ; import { escapeRegExp , pathPatternToRegex } from "./util" ; import path from "path" ; import { addHook } from "pirates" ; import sourceMapSupport from "source-map-support" ; export interface InputOptions extends TransformOptions { extensions ? : string [ ] ; } /**
 * Babel has built-in ignore & only support while @swc/core doesn't. So let's make our own!
 */ export interface TransformOptions extends swc . Options { only ? : FilePattern ; ignore ? : FilePattern ; } export type FilePattern = ReadonlyArray < string | ( ( filename : string , { dirname } : { dirname : string ; } ) => any ) | RegExp > ; const maps = { } ; let transformOpts = { } ; let piratesRevert = null ; function installSourceMapSupport ( ) { sourceMapSupport . install ( { handleUncaughtExceptions : false , environment : "node" , retrieveSourceMap ( source ) { const map = maps && maps [ source ] ; if ( map ) { return { url : null as any , map : map } ; } else { return null ; } } } ) ; } function mtime ( filename ) { return + fs . statSync ( filename ) . mtime ; } function compile ( code , filename ) { const opts = { sourceRoot : path . dirname ( filename ) + path . sep , ... deepClone ( transformOpts ) , filename } ; if ( typeof code !== "string" ) { code = code . toString ( ) ; } delete opts . only ; delete opts . ignore ; const output = swc . transformSync ( code , { ... opts , sourceMaps : opts . sourceMaps === undefined ? true : opts . sourceMaps } ) ; if ( output . map ) { if ( Object . keys ( maps ) . length === 0 ) { installSourceMapSupport ( ) ; } maps [ filename ] = output . map ; } return output . code ; } let compiling = false ; function compileHook ( code , filename ) { if ( compiling ) return code ; try { compiling = true ; return compile ( code , filename ) ; } finally { compiling = false ; } } function hookExtensions ( exts ) { if ( piratesRevert ) piratesRevert ( ) ; piratesRevert = addHook ( compileHook , { exts : exts as string [ ] , ignoreNodeModules : false , matcher } ) ; } export function revert ( ) { if ( piratesRevert ) piratesRevert ( ) ; } export default function register ( opts = { } ) { opts = { ... opts } ; hookExtensions ( opts . extensions || swc . DEFAULT_EXTENSIONS ) ; delete opts . extensions ; transformOpts = { ... opts , caller : { name : "@swc/register" , ... ( opts . caller || { } ) } } ; let { cwd = "." } = transformOpts ; cwd = transformOpts . cwd = path . resolve ( cwd ) ; if ( transformOpts . ignore === undefined && transformOpts . only === undefined ) { transformOpts . only = [ new RegExp ( "^" + escapeRegExp ( cwd ) , "i" ) ] ; transformOpts . ignore = [ new RegExp ( "^" + escapeRegExp ( cwd ) + "(?:" + path . sep + ".*)?" + escapeRegExp ( path . sep + "node_modules" + path . sep ) , "i" ) ] ; } } /**
 * https://github.com/babel/babel/blob/7acc68a86b70c6aadfef28e10e83d0adb2523807/packages/babel-core/src/config/config-chain.ts
 *
 * Tests if a filename should be ignored based on "ignore" and "only" options.
 */ function matcher ( filename , dirname ? ) { if ( ! dirname ) { dirname = transformOpts . cwd || path . dirname ( filename ) ; } return shouldCompile ( transformOpts . ignore , transformOpts . only , filename , dirname ) ; } function shouldCompile ( ignore , only , filename , dirname ) { if ( ignore && matchPattern ( ignore , dirname , filename ) ) { return false ; } if ( only && ! matchPattern ( only , dirname , filename ) ) { return false ; } return true ; } /**
 * https://github.com/babel/babel/blob/7acc68a86b70c6aadfef28e10e83d0adb2523807/packages/babel-core/src/config/config-chain.ts
 *
 * Returns result of calling function with filename if pattern is a function.
 * Otherwise returns result of matching pattern Regex with filename.
 */ function matchPattern ( patterns , dirname , pathToTest ) { return patterns . some ( pattern => { if ( typeof pattern === "function" ) { return Boolean ( pattern ( pathToTest , { dirname } ) ) ; } if ( typeof pathToTest !== "string" ) { throw new Error ( `Configuration contains string/RegExp file pattern, but no filename was provided.` ) ; } if ( typeof pattern === "string" ) { pattern = pathPatternToRegex ( pattern , dirname ) ; } return pattern . test ( path . resolve ( dirname , pathToTest ) ) ; } ) ; }