Skip to content

Commit d486224

Browse files
feat: WebStorm support
1 parent 945ea5a commit d486224

File tree

8 files changed

+658
-96
lines changed

8 files changed

+658
-96
lines changed

package-lock.json

Lines changed: 446 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@
115115
"chokidar": "^3.6.0",
116116
"commander": "^13.1.0",
117117
"esbuild": "^0.25.0",
118+
"fast-xml-parser": "^5.0.8",
118119
"inquirer": "^12.4.2",
119120
"jsonc-parser": "^3.3.1",
120121
"node-machine-id": "^1.1.12",
@@ -133,6 +134,7 @@
133134
"aws-iot-device-sdk",
134135
"chokidar",
135136
"commander",
137+
"fast-xml-parser",
136138
"node-machine-id",
137139
"toml",
138140
"yaml",

src/configuration/getConfigFromWizard.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { GitIgnore } from '../gitignore.js';
1717
import { VsCode } from '../vsCode.js';
1818
import { Logger } from '../logger.js';
1919
import { Configuration } from '../configuration.js';
20+
import { WebStorm } from '../webStorm.js';
2021

2122
const configFileName = path.resolve(configFileDefaultName);
2223

@@ -335,6 +336,19 @@ export async function getConfigFromWizard({
335336
answers.vscode = answersVsCode.vscode;
336337
}
337338

339+
if (!(await WebStorm.isConfigured())) {
340+
const answersWebStorm = await inquirer.prompt([
341+
{
342+
type: 'confirm',
343+
name: 'webstorm',
344+
message: `Would you like to add configuration to WebStorm?`,
345+
default: false,
346+
},
347+
]);
348+
349+
answers.webstorm = answersWebStorm.webstorm;
350+
}
351+
338352
const answersVerbose = await inquirer.prompt([
339353
{
340354
type: 'confirm',
@@ -464,6 +478,7 @@ function getConfigFromAnswers(answers: any): LldConfigCliArgs {
464478
interactive: answers.interactive,
465479
gitignore: answers.gitignore,
466480
vscode: answers.vscode,
481+
webstorm: answers.webstorm,
467482
};
468483

469484
//remove undefined and empty strings

src/lldebugger.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { Logger } from './logger.js';
1717
import { getModuleDirname, getProjectDirname } from './getDirname.js';
1818
import { LambdaConnection } from './lambdaConnection.js';
1919
import inquirer from 'inquirer';
20+
import { WebStorm } from './webStorm.js';
2021

2122
/**
2223
* Start the Lambda Live Debugger
@@ -46,6 +47,10 @@ async function run() {
4647
await VsCode.addConfiguration();
4748
}
4849

50+
if (Configuration.config.webstorm) {
51+
await WebStorm.addConfiguration();
52+
}
53+
4954
if (!Configuration.config.start && !Configuration.config.remove) {
5055
return;
5156
}

src/types/lldConfig.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ export type LldConfigBase = {
7878
export type LldConfigCliArgs = {
7979
remove?: 'keep-layer' | 'all';
8080
vscode?: boolean;
81+
webstorm?: boolean;
8182
gitignore?: boolean;
8283
config?: string;
8384
wizard?: boolean;
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import fs from 'fs/promises';
2+
import path from 'path';
3+
import { getModuleDirname, getProjectDirname } from '../getDirname.js';
4+
import { Logger } from '../logger.js';
5+
6+
/**
7+
* Get the runtime executable for the IDE, like WebStorm or VSCode
8+
* @returns
9+
*/
10+
export async function getRuntimeExecutableForIde() {
11+
let runtimeExecutable: string | undefined;
12+
const localRuntimeExecutable = '${workspaceFolder}/node_modules/.bin/lld';
13+
14+
const moduleDirname = getModuleDirname();
15+
const projectDirname = getProjectDirname();
16+
17+
const localFolder = path.resolve(
18+
path.join(projectDirname, 'node_modules/.bin/lld'),
19+
);
20+
21+
//if installed locally
22+
if (moduleDirname.startsWith('/home/')) {
23+
Logger.verbose('Lambda Live Debugger is installed locally');
24+
// check if file exists
25+
try {
26+
Logger.verbose(
27+
'Checking local folder for runtimeExecutable setting for VsCode configuration',
28+
localFolder,
29+
);
30+
await fs.access(localFolder, fs.constants.F_OK);
31+
runtimeExecutable = localRuntimeExecutable;
32+
} catch {
33+
// Not found
34+
}
35+
} else {
36+
Logger.verbose('Lambda Live Debugger is installed globally');
37+
}
38+
39+
if (!runtimeExecutable) {
40+
Logger.verbose(
41+
`Setting absolute path for runtimeExecutable setting for VsCode configuration`,
42+
);
43+
const localFolderSubfolder = path.resolve('node_modules/.bin/lld');
44+
const globalModule1 = path.join(moduleDirname, '..', '..', '.bin/lld');
45+
const globalModule2 = path.join(moduleDirname, '..', '..', 'bin/lld');
46+
const globalModule3 = path.join(
47+
moduleDirname,
48+
'..',
49+
'..',
50+
'..',
51+
'..',
52+
'bin/lld',
53+
);
54+
const possibleFolders = {
55+
[localFolder]: '${workspaceFolder}/node_modules/.bin/lld',
56+
[localFolderSubfolder]: localFolderSubfolder,
57+
[globalModule1]: globalModule1,
58+
[globalModule2]: globalModule2,
59+
[globalModule3]: globalModule3,
60+
};
61+
62+
Logger.verbose(
63+
`Checking the following possible folders for lld executable:`,
64+
JSON.stringify(possibleFolders, null, 2),
65+
);
66+
67+
// check each possible folder and set the runtimeExecutable
68+
for (const folder in possibleFolders) {
69+
try {
70+
//Logger.log("Checking folder", folder);
71+
await fs.access(folder, fs.constants.F_OK);
72+
runtimeExecutable = possibleFolders[folder];
73+
Logger.verbose(`Found folder with lld executable: ${folder}`);
74+
break;
75+
} catch {
76+
// Not found
77+
}
78+
}
79+
80+
if (!runtimeExecutable) {
81+
Logger.error(
82+
`Could not find lld executable. Please check your IDE debugger settings.`,
83+
);
84+
}
85+
}
86+
87+
if (!runtimeExecutable) {
88+
return localRuntimeExecutable;
89+
}
90+
91+
return runtimeExecutable;
92+
}

src/vsCode.ts

Lines changed: 4 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@ import {
99
FormattingOptions,
1010
} from 'jsonc-parser';
1111
import { VsCodeLaunch } from './types/vsCodeConfig.js';
12-
import { getModuleDirname, getProjectDirname } from './getDirname.js';
12+
import { getProjectDirname } from './getDirname.js';
1313
import { Logger } from './logger.js';
14+
import { getRuntimeExecutableForIde } from './utils/getRuntimeExecutableForIde.js';
1415

1516
async function getVsCodeLaunchConfig() {
16-
const localRuntimeExecutable = '${workspaceFolder}/node_modules/.bin/lld';
17+
const runtimeExecutable = await getRuntimeExecutableForIde();
1718

1819
const config: VsCodeLaunch = {
1920
version: '0.2.0',
@@ -22,7 +23,7 @@ async function getVsCodeLaunchConfig() {
2223
name: 'Lambda Live Debugger',
2324
type: 'node',
2425
request: 'launch',
25-
runtimeExecutable: localRuntimeExecutable,
26+
runtimeExecutable: runtimeExecutable,
2627
runtimeArgs: [],
2728
console: 'integratedTerminal',
2829
skipFiles: ['<node_internals>/**'],
@@ -31,86 +32,6 @@ async function getVsCodeLaunchConfig() {
3132
],
3233
};
3334

34-
const moduleDirname = getModuleDirname();
35-
//Logger.log("Module folder", moduleDirname);
36-
const projectDirname = getProjectDirname();
37-
38-
//Logger.log("Current folder", currentFolder);
39-
const localFolder = path.resolve(
40-
path.join(projectDirname, 'node_modules/.bin/lld'),
41-
);
42-
43-
let runtimeExecutableSet = false;
44-
45-
//if installed locally
46-
if (moduleDirname.startsWith('/home/')) {
47-
Logger.verbose('Lambda Live Debugger is installed locally');
48-
// check if file exists
49-
try {
50-
Logger.verbose(
51-
'Checking local folder for runtimeExecutable setting for VsCode configuration',
52-
localFolder,
53-
);
54-
await fs.access(localFolder, fs.constants.F_OK);
55-
config.configurations![0].runtimeExecutable = localRuntimeExecutable;
56-
runtimeExecutableSet = true;
57-
//Logger.log("Found local folder", localFolder);
58-
} catch {
59-
//Logger.log("Not found", localFolder);
60-
}
61-
} else {
62-
Logger.verbose('Lambda Live Debugger is installed globally');
63-
}
64-
65-
if (!runtimeExecutableSet) {
66-
Logger.verbose(
67-
`Setting absolute path for runtimeExecutable setting for VsCode configuration`,
68-
);
69-
const localFolderSubfolder = path.resolve('node_modules/.bin/lld');
70-
const globalModule1 = path.join(moduleDirname, '..', '..', '.bin/lld');
71-
const globalModule2 = path.join(moduleDirname, '..', '..', 'bin/lld');
72-
const globalModule3 = path.join(
73-
moduleDirname,
74-
'..',
75-
'..',
76-
'..',
77-
'..',
78-
'bin/lld',
79-
);
80-
const possibleFolders = {
81-
[localFolder]: '${workspaceFolder}/node_modules/.bin/lld',
82-
[localFolderSubfolder]: localFolderSubfolder,
83-
[globalModule1]: globalModule1,
84-
[globalModule2]: globalModule2,
85-
[globalModule3]: globalModule3,
86-
};
87-
88-
Logger.verbose(
89-
`Checking the following possible folders for lld executable:`,
90-
JSON.stringify(possibleFolders, null, 2),
91-
);
92-
93-
// check each possible folder and set the runtimeExecutable
94-
for (const folder in possibleFolders) {
95-
try {
96-
//Logger.log("Checking folder", folder);
97-
await fs.access(folder, fs.constants.F_OK);
98-
config.configurations![0].runtimeExecutable = possibleFolders[folder];
99-
runtimeExecutableSet = true;
100-
Logger.verbose(`Found folder with lld executable: ${folder}`);
101-
break;
102-
} catch {
103-
// Not found
104-
}
105-
}
106-
107-
if (!runtimeExecutableSet) {
108-
Logger.error(
109-
`Could not find lld executable. Please check the setting runtimeExecutable in '.vscode/launch.json'.`,
110-
);
111-
}
112-
}
113-
11435
return config;
11536
}
11637

src/webStorm.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import fs from 'fs/promises';
2+
import path from 'path';
3+
import { XMLParser, XMLBuilder } from 'fast-xml-parser';
4+
import { getProjectDirname } from './getDirname.js';
5+
import { Logger } from './logger.js';
6+
import { getRuntimeExecutableForIde } from './utils/getRuntimeExecutableForIde.js';
7+
8+
const workspaceFilePath = path.join(getProjectDirname(), '.idea/workspace.xml');
9+
10+
async function getWebStormLaunchConfig() {
11+
let runtimeExecutable = await getRuntimeExecutableForIde();
12+
runtimeExecutable = runtimeExecutable.replace(
13+
'${workspaceFolder}',
14+
'${PROJECT_DIR}',
15+
);
16+
17+
return {
18+
configuration: {
19+
'@type': 'NodeJSConfigurationType',
20+
option: [
21+
{ '@name': 'name', '@value': 'Lambda Live Debugger' },
22+
{ '@name': 'nodejs_interpreter', '@value': runtimeExecutable },
23+
{ '@name': 'work_dir', '@value': getProjectDirname() },
24+
{ '@name': 'node_parameters', '@value': '' },
25+
{ '@name': 'application_parameters', '@value': '' },
26+
{ '@name': 'envs', '@value': '' },
27+
],
28+
},
29+
};
30+
}
31+
32+
async function readWorkspaceXml(): Promise<any> {
33+
try {
34+
const xmlString = await fs.readFile(workspaceFilePath, 'utf-8');
35+
const parser = new XMLParser({ ignoreAttributes: false });
36+
return parser.parse(xmlString);
37+
} catch (err: any) {
38+
Logger.error(`Error reading workspace.xml: ${err}`);
39+
return null;
40+
}
41+
}
42+
43+
async function writeWorkspaceXml(json: any) {
44+
try {
45+
const builder = new XMLBuilder({ ignoreAttributes: false, format: true });
46+
const xmlString = builder.build(json);
47+
await fs.writeFile(workspaceFilePath, xmlString, 'utf-8');
48+
Logger.verbose(`Updated WebStorm configuration in ${workspaceFilePath}`);
49+
} catch (err) {
50+
Logger.error(`Error writing workspace.xml: ${err}`);
51+
throw err;
52+
}
53+
}
54+
55+
async function isConfigured(): Promise<boolean> {
56+
const json = await readWorkspaceXml();
57+
if (!json) return false;
58+
59+
const existingConfigs = json?.project?.component?.find(
60+
(c: any) => c['@name'] === 'RunManager',
61+
);
62+
return existingConfigs?.configuration?.some(
63+
(config: any) => config['@name'] === 'Lambda Live Debugger',
64+
);
65+
}
66+
67+
async function addConfiguration() {
68+
Logger.log('Adding WebStorm debug configuration');
69+
let json = await readWorkspaceXml();
70+
71+
if (!json) {
72+
json = { project: { component: [] } };
73+
}
74+
75+
const runManager = json.project.component.find(
76+
(c: any) => c['@name'] === 'RunManager',
77+
);
78+
if (!runManager) {
79+
json.project.component.push({ '@name': 'RunManager', configuration: [] });
80+
}
81+
82+
const config = await getWebStormLaunchConfig();
83+
json.project.component
84+
.find((c: any) => c['@name'] === 'RunManager')
85+
.configuration.push(config.configuration);
86+
87+
await writeWorkspaceXml(json);
88+
}
89+
90+
export const WebStorm = {
91+
isConfigured,
92+
addConfiguration,
93+
};

0 commit comments

Comments
 (0)