import _ts from 'typescript' ; import { NowBuildError } from '@vercel/build-utils' ; import { relative , basename , resolve , dirname } from 'path' ; /**
 * Debugging.
 */ const shouldDebug = false ; const debug = shouldDebug ? console . log . bind ( console , 'ts-node' ) : ( ) => undefined ; const debugFn = shouldDebug ? < T , U > ( key , fn ) => { let i = 0 ; return ( x ) => { debug ( key , x , ++ i ) ; return fn ( x ) ; } ; } : < T , U > ( _ , fn ) => fn ; /**
 * Common TypeScript interfaces between versions.
 */ interface TSCommon { version : typeof _ts . version ; sys : typeof _ts . sys ; ScriptSnapshot : typeof _ts . ScriptSnapshot ; displayPartsToString : typeof _ts . displayPartsToString ; createLanguageService : typeof _ts . createLanguageService ; getDefaultLibFilePath : typeof _ts . getDefaultLibFilePath ; getPreEmitDiagnostics : typeof _ts . getPreEmitDiagnostics ; flattenDiagnosticMessageText : typeof _ts . flattenDiagnosticMessageText ; transpileModule : typeof _ts . transpileModule ; ModuleKind : typeof _ts . ModuleKind ; ScriptTarget : typeof _ts . ScriptTarget ; findConfigFile : typeof _ts . findConfigFile ; readConfigFile : typeof _ts . readConfigFile ; parseJsonConfigFileContent : typeof _ts . parseJsonConfigFileContent ; formatDiagnostics : typeof _ts . formatDiagnostics ; formatDiagnosticsWithColorAndContext : typeof _ts . formatDiagnosticsWithColorAndContext ; } /**
 * Registration options.
 */ interface Options { basePath ? : string ; pretty ? : boolean | null ; logError ? : boolean | null ; files ? : boolean | null ; compiler ? : string ; ignore ? : string [ ] ; project ? : string ; compilerOptions ? : any ; ignoreDiagnostics ? : Array < number | string > ; readFile ? : ( path : string ) => string | undefined ; fileExists ? : ( path : string ) => boolean ; transformers ? : _ts . CustomTransformers ; } /**
 * Track the project information.
 */ class MemoryCache { fileContents = new Map < string , string > ( ) ; fileVersions = new Map < string , number > ( ) ; constructor ( rootFileNames = [ ] ) { for ( const fileName of rootFileNames ) this . fileVersions . set ( fileName , 1 ) ; } } /**
 * Default register options.
 */ const DEFAULTS = { files : null , pretty : null , compiler : undefined , compilerOptions : undefined , ignore : undefined , project : undefined , ignoreDiagnostics : undefined , logError : null , } ; /**
 * Default TypeScript compiler options required by `ts-node`.
 */ const TS_NODE_COMPILER_OPTIONS = { sourceMap : true , inlineSourceMap : false , inlineSources : true , declaration : false , noEmit : false , outDir : '$$ts-node$$' , } ; /**
 * Replace backslashes with forward slashes.
 */ function normalizeSlashes ( value ) { return value . replace ( /\\/g , '/' ) ; } /**
 * Return type for registering `ts-node`.
 */ export type Register = ( code : string , fileName : string , skipTypeCheck ? : boolean ) => SourceOutput ; /**
 * Cached fs operation wrapper.
 */ function cachedLookup < T > ( fn ) { const cache = new Map < string , T > ( ) ; return ( arg ) : T => { if ( ! cache . has ( arg ) ) { cache . set ( arg , fn ( arg ) ) ; } return cache . get ( arg ) as T ; } ; } /**
 * Register TypeScript compiler.
 */ export function register ( opts = { } ) { const options = Object . assign ( { } , DEFAULTS , opts ) ; const ignoreDiagnostics = [ 6059 , 18002 , 18003 , ... ( options . ignoreDiagnostics || [ ] ) , ] . map ( Number ) ; const cwd = options . basePath || process . cwd ( ) ; const nowNodeBase = resolve ( __dirname , '..' , '..' , '..' ) ; let compiler ; const require_ = eval ( 'require' ) ; try { compiler = require_ . resolve ( options . compiler || 'typescript' , { paths : [ options . project || cwd , nowNodeBase ] , } ) ; } catch ( e ) { compiler = 'typescript' ; } const ts = require_ ( compiler ) ; if ( compiler . startsWith ( nowNodeBase ) ) { console . log ( 'Using TypeScript ' + ts . version + ' (no local tsconfig.json)' ) ; } else { console . log ( 'Using TypeScript ' + ts . version + ' (local user-provided)' ) ; } const transformers = options . transformers || undefined ; const readFile = options . readFile || ts . sys . readFile ; const fileExists = options . fileExists || ts . sys . fileExists ; const formatDiagnostics = process . stdout . isTTY || options . pretty ? ts . formatDiagnosticsWithColorAndContext : ts . formatDiagnostics ; const diagnosticHost = { getNewLine : ( ) => ts . sys . newLine , getCurrentDirectory : ( ) => cwd , getCanonicalFileName : path => path , } ; function createTSError ( diagnostics ) { const message = formatDiagnostics ( diagnostics , diagnosticHost ) ; return new NowBuildError ( { code : 'NODE_TYPESCRIPT_ERROR' , message } ) ; } function reportTSError ( diagnostics , shouldExit ) { if ( ! diagnostics || diagnostics . length === 0 ) { return ; } const error = createTSError ( diagnostics ) ; if ( shouldExit ) { throw error ; } else { console . error ( '\x1b[31m%s\x1b[0m' , error ) ; } } const builds = new Map < string , Build > ( ) ; function getBuild ( configFileName = '' ) { let build = builds . get ( configFileName ) ; if ( build ) return build ; const config = readConfig ( configFileName ) ; /**
         * Create the basic required function using transpile mode.
         */ const getOutput = function ( code , fileName ) : SourceOutput { const result = ts . transpileModule ( code , { fileName , transformers , compilerOptions : config . options , reportDiagnostics : true , } ) ; const diagnosticList = result . diagnostics ? filterDiagnostics ( result . diagnostics , ignoreDiagnostics ) : [ ] ; reportTSError ( diagnosticList , config . options . noEmitOnError ) ; return { code : result . outputText , map : result . sourceMapText as string } ; } ; let getOutputTypeCheck ; { const memoryCache = new MemoryCache ( config . fileNames ) ; const cachedReadFile = cachedLookup ( debugFn ( 'readFile' , readFile ) ) ; const serviceHost = { getScriptFileNames : ( ) => Array . from ( memoryCache . fileVersions . keys ( ) ) , getScriptVersion : ( fileName ) => { const version = memoryCache . fileVersions . get ( fileName ) ; return version === undefined ? '' : version . toString ( ) ; } , getScriptSnapshot ( fileName ) { let contents = memoryCache . fileContents . get ( fileName ) ; if ( contents === undefined ) { contents = cachedReadFile ( fileName ) ; if ( contents === undefined ) return ; memoryCache . fileVersions . set ( fileName , 1 ) ; memoryCache . fileContents . set ( fileName , contents ) ; } return ts . ScriptSnapshot . fromString ( contents ) ; } , readFile : cachedReadFile , readDirectory : cachedLookup ( debugFn ( 'readDirectory' , ts . sys . readDirectory ) ) , getDirectories : cachedLookup ( debugFn ( 'getDirectories' , ts . sys . getDirectories ) ) , fileExists : cachedLookup ( debugFn ( 'fileExists' , fileExists ) ) , directoryExists : cachedLookup ( debugFn ( 'directoryExists' , ts . sys . directoryExists ) ) , getNewLine : ( ) => ts . sys . newLine , useCaseSensitiveFileNames : ( ) => ts . sys . useCaseSensitiveFileNames , getCurrentDirectory : ( ) => cwd , getCompilationSettings : ( ) => config . options , getDefaultLibFileName : ( ) => ts . getDefaultLibFilePath ( config . options ) , getCustomTransformers : ( ) => transformers , } ; const registry = ts . createDocumentRegistry ( ts . sys . useCaseSensitiveFileNames , cwd ) ; const service = ts . createLanguageService ( serviceHost , registry ) ; const updateMemoryCache = function ( contents , fileName ) { const fileVersion = memoryCache . fileVersions . get ( fileName ) || 0 ; if ( memoryCache . fileContents . get ( fileName ) === contents ) return ; memoryCache . fileVersions . set ( fileName , fileVersion + 1 ) ; memoryCache . fileContents . set ( fileName , contents ) ; } ; getOutputTypeCheck = function ( code , fileName ) { updateMemoryCache ( code , fileName ) ; const output = service . getEmitOutput ( fileName ) ; const diagnostics = service . getSemanticDiagnostics ( fileName ) . concat ( service . getSyntacticDiagnostics ( fileName ) ) ; const diagnosticList = filterDiagnostics ( diagnostics , ignoreDiagnostics ) ; reportTSError ( diagnosticList , config . options . noEmitOnError ) ; if ( output . emitSkipped ) { throw new TypeError ( `${ relative ( cwd , fileName ) }: Emit skipped` ) ; } if ( output . outputFiles . length === 0 ) { throw new TypeError ( 'Unable to require `.d.ts` file.\n' + 'This is usually the result of a faulty configuration or import. ' + 'Make sure there is a `.js`, `.json` or another executable extension and ' + 'loader (attached before `ts-node`) available alongside ' + `\`${ basename ( fileName ) }\`.` ) ; } return { code : output . outputFiles [ 1 ] . text , map : output . outputFiles [ 0 ] . text , } ; } ; } builds . set ( configFileName , ( build = { getOutput , getOutputTypeCheck , } ) ) ; return build ; } function detectConfig ( ) { let configFileName = undefined ; configFileName = options . project ? ts . findConfigFile ( normalizeSlashes ( options . project ) , fileExists ) : ts . findConfigFile ( normalizeSlashes ( cwd ) , fileExists ) ; if ( configFileName ) return normalizeSlashes ( configFileName ) ; } /**
     * Load TypeScript configuration.
     */ function readConfig ( configFileName ) { let config = { compilerOptions : { } } ; const basePath = normalizeSlashes ( dirname ( configFileName ) ) ; if ( configFileName ) { const result = ts . readConfigFile ( configFileName , readFile ) ; if ( result . error ) { const errorResult = { errors : [ result . error ] , fileNames : [ ] , options : { } , } ; const configDiagnosticList = filterDiagnostics ( errorResult . errors , ignoreDiagnostics ) ; reportTSError ( configDiagnosticList , true ) ; return errorResult ; } config = result . config ; } if ( ! options . files ) { config . files = [ ] ; config . include = [ ] ; } config . compilerOptions = Object . assign ( { } , config . compilerOptions , options . compilerOptions , TS_NODE_COMPILER_OPTIONS ) ; const configResult = fixConfig ( ts , ts . parseJsonConfigFileContent ( config , ts . sys , basePath , undefined , configFileName ) ) ; if ( configFileName ) { const configDiagnosticList = filterDiagnostics ( configResult . errors , ignoreDiagnostics ) ; reportTSError ( configDiagnosticList , configResult . options . noEmitOnError ) ; } return configResult ; } function compile ( code , fileName , skipTypeCheck ? ) { const configFileName = detectConfig ( ) ; const build = getBuild ( configFileName ) ; const { code : value , map : sourceMap } = ( skipTypeCheck ? build . getOutput : build . getOutputTypeCheck ) ( code , fileName ) ; const output = { code : value , map : Object . assign ( JSON . parse ( sourceMap ) , { file : basename ( fileName ) , sources : [ fileName ] , } ) , } ; delete output . map . sourceRoot ; return output ; } return compile ; } interface Build { getOutput ( code , fileName ) : SourceOutput ; getOutputTypeCheck ( code , fileName ) : SourceOutput ; } /**
 * Do post-processing on config options to support `ts-node`.
 */ function fixConfig ( ts , config ) { delete config . options . out ; delete config . options . outFile ; delete config . options . composite ; delete config . options . declarationDir ; delete config . options . declarationMap ; delete config . options . emitDeclarationOnly ; delete config . options . tsBuildInfoFile ; delete config . options . incremental ; if ( config . options . target === undefined ) { config . options . target = ts . ScriptTarget . ESNext ; } if ( config . options . esModuleInterop === undefined ) { config . options . esModuleInterop = true ; } config . options . module = ts . ModuleKind . CommonJS ; return config ; } /**
 * Internal source output.
 */ type SourceOutput = { code : string ; map : string ; } ; /**
 * Filter diagnostics.
 */ function filterDiagnostics ( diagnostics , ignore ) { return diagnostics . filter ( x => ignore . indexOf ( x . code ) === - 1 ) ; }