lambda-live-debugger
Version:
Debug Lambda functions locally like it is running in the cloud
147 lines (146 loc) • 5.09 kB
JavaScript
import fs from 'fs/promises';
import path from 'path';
import { parse, printParseErrorCode, applyEdits, modify, } from 'jsonc-parser';
import { getProjectDirname } from './getDirname.mjs';
import { Logger } from './logger.mjs';
import { getRuntimeExecutableForIde } from './utils/getRuntimeExecutableForIde.mjs';
async function getVsCodeLaunchConfig() {
const runtimeExecutable = await getRuntimeExecutableForIde();
const config = {
version: '0.2.0',
configurations: [
{
name: 'Lambda Live Debugger',
type: 'node',
request: 'launch',
runtimeExecutable: runtimeExecutable,
runtimeArgs: [],
console: 'integratedTerminal',
skipFiles: ['<node_internals>/**'],
env: {},
},
],
};
return config;
}
async function readLaunchJson(filePath) {
try {
const jsonString = await fs.readFile(filePath, 'utf-8');
const errors = [];
const json = parse(jsonString, errors, {
allowTrailingComma: true,
allowEmptyContent: true,
});
if (errors.length) {
errors.forEach((error) => {
Logger.error(`Error at offset ${error.offset}: ${printParseErrorCode(error.error)}`);
});
}
else {
return { json, jsonString };
}
}
catch (err) {
Logger.error(err);
}
throw new Error(`Error reading the file: ${filePath}`);
}
async function writeConfiguration(filePath, jsonString, changes, position) {
try {
const formattingOptions = {
insertSpaces: true,
tabSize: 2,
};
// Apply changes to the original JSON string
const edits = modify(jsonString, ['configurations', position], changes, {
formattingOptions,
});
const modifiedJsonString = applyEdits(jsonString, edits);
// Write the modified JSON string back to the file
Logger.verbose(`Adding to VsCode configuration file: ${filePath}`);
await fs.writeFile(filePath, modifiedJsonString, 'utf-8');
}
catch (err) {
Logger.error(`Error writing the file: ${err}`);
throw err;
}
}
async function getCurrentState() {
const filePath = path.join(getProjectDirname(), '.vscode/launch.json');
let createNewFile = false;
// does file exist
try {
await fs.access(filePath, fs.constants.F_OK);
}
catch {
createNewFile = true;
}
if (!createNewFile) {
const { json, jsonString } = await readLaunchJson(filePath);
const existingConfig = json;
// does configurations exist
const vsCodeLaunchConfig = await getVsCodeLaunchConfig();
const exists = !!existingConfig.configurations?.find((c) => {
return c.name === vsCodeLaunchConfig.configurations[0].name;
});
if (!exists) {
Logger.verbose(`${filePath} exists but configuration does not exist!`);
return {
state: 'FILE_EXISTS_CONFIGURATION_DOES_NOT_EXIST',
jsonString,
configurationsLength: existingConfig.configurations?.length || 0,
filePath,
};
}
else {
Logger.verbose(`Configuration already exists in ${filePath}`);
return {
state: 'FILE_EXISTS_CONFIGURATION_EXISTS',
};
}
}
else {
Logger.verbose(`${filePath} does not exist!`);
return {
state: 'FILE_DOES_NOT_EXIST',
filePath,
};
}
}
async function isConfigured() {
try {
const state = await getCurrentState();
if (state.state === 'FILE_EXISTS_CONFIGURATION_EXISTS') {
return true;
}
return false;
}
catch (err) {
Logger.error('Error checking if configuration exists in .vscode/launch.json', err);
return true;
}
}
async function addConfiguration() {
try {
Logger.log('Adding configuration to .vscode/launch.json');
const state = await getCurrentState();
const config = await getVsCodeLaunchConfig();
if (state.state === 'FILE_EXISTS_CONFIGURATION_DOES_NOT_EXIST') {
const { jsonString, filePath, configurationsLength } = state;
await writeConfiguration(filePath, jsonString, config.configurations[0], configurationsLength);
}
else if (state.state === 'FILE_DOES_NOT_EXIST') {
// crete folder of filePath recursive if not exists
await fs.mkdir(path.dirname(state.filePath), { recursive: true });
Logger.verbose(`Creating VsCode configuration file: ${state.filePath}`);
await fs.writeFile(state.filePath, JSON.stringify(config, null, 2), 'utf-8');
}
}
catch (err) {
Logger.error('Error adding configuration to .vscode/launch.json', err);
}
}
export const VsCode = {
isConfigured,
addConfiguration,
};