Skip to content

Commit 0390097

Browse files
authored
feat(playground): add support local require VSCODE-468 (#718)
* support local require when running playground * pr feedback * add test for local require
1 parent 3bc8428 commit 0390097

File tree

6 files changed

+75
-12
lines changed

6 files changed

+75
-12
lines changed

src/editors/playgroundController.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,7 @@ export default class PlaygroundController {
449449
result = await this._languageServerController.evaluate({
450450
codeToEvaluate,
451451
connectionId,
452+
filePath: vscode.window.activeTextEditor?.document.uri.fsPath,
452453
});
453454
} catch (error) {
454455
const msg =

src/language/languageServerController.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ export default class LanguageServerController {
186186
): Promise<ShellEvaluateResult> {
187187
log.info('Running a playground...', {
188188
connectionId: playgroundExecuteParameters.connectionId,
189+
filePath: playgroundExecuteParameters.filePath,
189190
inputLength: playgroundExecuteParameters.codeToEvaluate.length,
190191
});
191192
this._isExecutingInProgress = true;

src/language/mongoDBService.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ export default class MongoDBService {
296296
name: ServerCommands.EXECUTE_CODE_FROM_PLAYGROUND,
297297
data: {
298298
codeToEvaluate: params.codeToEvaluate,
299+
filePath: params.filePath,
299300
connectionString: this.connectionString,
300301
connectionOptions: this.connectionOptions,
301302
},

src/language/worker.ts

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,25 @@ const getLanguage = (evaluationResult: EvaluationResult) => {
3636
return 'plaintext';
3737
};
3838

39+
type ExecuteCodeOptions = {
40+
codeToEvaluate: string;
41+
connectionString: string;
42+
connectionOptions: MongoClientOptions;
43+
filePath?: string;
44+
};
45+
3946
/**
4047
* Execute code from a playground.
4148
*/
42-
const execute = async (
43-
codeToEvaluate: string,
44-
connectionString: string,
45-
connectionOptions: MongoClientOptions
46-
): Promise<{ data?: ShellEvaluateResult; error?: any }> => {
49+
const execute = async ({
50+
codeToEvaluate,
51+
connectionString,
52+
connectionOptions,
53+
filePath,
54+
}: ExecuteCodeOptions): Promise<{
55+
data?: ShellEvaluateResult;
56+
error?: any;
57+
}> => {
4758
const serviceProvider = await CliServiceProvider.connect(
4859
connectionString,
4960
connectionOptions
@@ -67,6 +78,19 @@ const execute = async (
6778
},
6879
});
6980

81+
// In order to support local require directly from the file where code lives, we can not wrap the
82+
// whole code in a function for two reasons:
83+
// 1. We need to return the response and can not simply add return. And
84+
// 2. We can not use eval to evaluate the *codeToEvaluate* as mongosh async-rewriter can’t see into the eval.
85+
// We are also not directly concatenating the require with the code either due to "use strict"
86+
if (filePath) {
87+
await runtime.evaluate(`(function () {
88+
globalThis.require = require('module').createRequire(${JSON.stringify(
89+
filePath
90+
)});
91+
} ())`);
92+
}
93+
7094
// Evaluate a playground content.
7195
const { source, type, printable } = await runtime.evaluate(codeToEvaluate);
7296
const namespace =
@@ -94,11 +118,7 @@ const handleMessageFromParentPort = async ({ name, data }): Promise<void> => {
94118
if (name === ServerCommands.EXECUTE_CODE_FROM_PLAYGROUND) {
95119
parentPort?.postMessage({
96120
name: ServerCommands.CODE_EXECUTION_RESULT,
97-
payload: await execute(
98-
data.codeToEvaluate,
99-
data.connectionString,
100-
data.connectionOptions
101-
),
121+
payload: await execute(data),
102122
});
103123
}
104124
};

src/test/suite/language/mongoDBService.test.ts

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import {
1010
import type { CompletionItem } from 'vscode-languageclient/node';
1111
import chai from 'chai';
1212
import { createConnection } from 'vscode-languageserver/node';
13-
import fs from 'fs';
13+
import fs from 'fs/promises';
14+
import os from 'os';
1415
import path from 'path';
1516
import { TextDocument } from 'vscode-languageserver-textdocument';
1617
import type { Db } from 'mongodb';
@@ -45,7 +46,7 @@ suite('MongoDBService Test Suite', () => {
4546
'dist',
4647
languageServerWorkerFileName
4748
);
48-
await fs.promises.stat(languageServerModuleBundlePath);
49+
await fs.stat(languageServerModuleBundlePath);
4950
});
5051

5152
suite('Extension path', () => {
@@ -3008,6 +3009,44 @@ suite('MongoDBService Test Suite', () => {
30083009
expect(result).to.deep.equal(expectedResult);
30093010
});
30103011
});
3012+
3013+
suite('evaluate allows to import local files', function () {
3014+
let tmpDir: string;
3015+
beforeEach(async () => {
3016+
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'local-import'));
3017+
await fs.writeFile(
3018+
path.join(tmpDir, 'utils.js'),
3019+
`module.exports.add = function (a, b) {
3020+
return a + b;
3021+
};
3022+
`
3023+
);
3024+
});
3025+
afterEach(async () => {
3026+
await fs.rm(tmpDir, { recursive: true });
3027+
});
3028+
test('evaluate allows to import file', async () => {
3029+
const source = new CancellationTokenSource();
3030+
const result = await testMongoDBService.evaluate(
3031+
{
3032+
connectionId: 'pineapple',
3033+
codeToEvaluate: 'const { add } = require("./utils.js"); add(1, 2);',
3034+
filePath: path.join(tmpDir, 'utils.js'),
3035+
},
3036+
source.token
3037+
);
3038+
const expectedResult = {
3039+
result: {
3040+
namespace: null,
3041+
type: 'number',
3042+
content: 3,
3043+
language: 'plaintext',
3044+
},
3045+
};
3046+
3047+
expect(result).to.deep.equal(expectedResult);
3048+
});
3049+
});
30113050
});
30123051

30133052
suite('Export to language mode', function () {

src/types/playgroundType.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export type ShellEvaluateResult =
2121
export type PlaygroundEvaluateParams = {
2222
codeToEvaluate: string;
2323
connectionId: string;
24+
filePath?: string;
2425
};
2526

2627
export interface ExportToLanguageAddons {

0 commit comments

Comments
 (0)