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();
};
}