src/core/transform.ts (82 lines of code) (raw):

/** * MIT License * * Copyright (c) 2020-present, Elastic NV * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * */ import { addHook } from 'pirates'; import { transformSync, Loader, CommonOptions, TransformOptions, } from 'esbuild'; import path from 'path'; import sourceMapSupport from 'source-map-support'; // Cache that holds the sourcemap content for each file const sourceMaps: Map<string, string> = new Map(); // Register the source-map-support library to resolve the sourcemaps // for the files that are transpiled by esbuild /** * Register the source-map-support library to resolve the sourcemaps * for the files that are transpiled by esbuild and cache the sourcemaps * for each file. * * Caching the sourcemap file is important, as it is used by the Synthetics agent * to resolve the stack traces of journey, monitor and step functions. */ sourceMapSupport.install({ environment: 'node', handleUncaughtExceptions: false, retrieveSourceMap(source) { if (!sourceMaps.has(source)) return null; return { map: JSON.parse(sourceMaps.get(source)), url: source, }; }, }); /** * Default list of files and corresponding loaders we support * while pushing project based monitors */ const LOADERS: Record<string, Loader> = { '.ts': 'ts', '.js': 'js', '.mjs': 'js', '.cjs': 'js', }; const getLoader = (filename: string) => { const ext = path.extname(filename); return LOADERS[ext] || 'default'; }; export function commonOptions(): CommonOptions { /** * We are not minifying the code as we want it to be in sync with previous * transformation phase and introduce it later. */ return { minify: false, sourcemap: 'both', sourcesContent: false, platform: 'node', logLevel: 'silent', format: 'cjs', target: `node${process.version.slice(1)}`, }; } /** * Transform the given code using esbuild and save the corresponding * map file in memory to be retrived later. */ export function transform( code: string, filename: string, options: TransformOptions = {} ) { const result = transformSync(code, { ...commonOptions(), sourcefile: filename, loader: getLoader(filename), /** * Add this only for the transformation phase, using it on * bundling phase would disable tree shaking and uncessary bloat * * Ensures backwards compatability with tsc's implicit strict behaviour */ tsconfigRaw: { compilerOptions: { alwaysStrict: true, }, }, ...options, }); const warnings = result.warnings; if (warnings && warnings.length > 0) { for (const warning of warnings) { console.log(warning.location); console.log(warning.text); } } /** * Cache the sourcemap contents in memory, so we can look it up * later when we try to resolve the sourcemap for a given file. * * Every time the synthetics agent is started, we register the source-map-support * library to resolve the sourcemaps for the files that are transpiled by esbuild. */ if (result.map) { sourceMaps.set(filename, result.map); } return result; } /** * Install the pirates hook to transform the code on the fly * for all of the imported files. */ export function installTransform() { const revertPirates = addHook( (source: string, filename: string) => { const { code } = transform(source, filename); return code; }, { exts: ['.ts', '.js', '.mjs', '.cjs'] } ); return () => { revertPirates(); }; }