Skip to content

Commit c82c22a

Browse files
fix: print playground results as ejson or text (VSCODE-203) (#206)
1 parent 24d242d commit c82c22a

File tree

10 files changed

+391
-362
lines changed

10 files changed

+391
-362
lines changed

package-lock.json

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

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -821,9 +821,9 @@
821821
"@fortawesome/free-solid-svg-icons": "^5.13.0",
822822
"@fortawesome/react-fontawesome": "^0.1.9",
823823
"@leafygreen-ui/toggle": "3.0.1",
824-
"@mongosh/browser-runtime-electron": "^0.5.0",
825-
"@mongosh/service-provider-server": "^0.5.0",
826-
"@mongosh/shell-api": "^0.5.0",
824+
"@mongosh/browser-runtime-electron": "^0.5.2",
825+
"@mongosh/service-provider-server": "^0.5.2",
826+
"@mongosh/shell-api": "^0.5.2",
827827
"analytics-node": "^3.4.0-beta.1",
828828
"bson": "^4.0.3",
829829
"classnames": "^2.2.6",

src/editors/playgroundController.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import playgroundCreateIndexTemplate from '../templates/playgroundCreateIndexTem
1313
import { createLogger } from '../logging';
1414
import type { ExecuteAllResult } from '../utils/types';
1515
import { PLAYGROUND_RESULT_SCHEME } from './playgroundResultProvider';
16+
import type { OutputItem } from '../utils/types';
1617

1718
const log = createLogger('playground controller');
1819

@@ -23,7 +24,7 @@ export default class PlaygroundController {
2324
public connectionController: ConnectionController;
2425
public activeTextEditor?: TextEditor;
2526
public partialExecutionCodeLensProvider: PartialExecutionCodeLensProvider;
26-
public playgroundResult?: any;
27+
public playgroundResult?: OutputItem;
2728
private _context: vscode.ExtensionContext;
2829
private _languageServerController: LanguageServerController;
2930
private _telemetryController: TelemetryController;
@@ -290,15 +291,13 @@ export default class PlaygroundController {
290291
});
291292
}
292293

293-
private getVirtualDocumentUri() {
294+
public getVirtualDocumentUri(content?: any) {
294295
let extension = '';
295296

296-
if (this.playgroundResult) {
297-
if (typeof this.playgroundResult === 'object') {
298-
extension = 'json';
299-
} else {
300-
extension = 'txt';
301-
}
297+
if (typeof content === 'object') {
298+
extension = 'json';
299+
} else {
300+
extension = 'txt';
302301
}
303302

304303
return vscode.Uri.parse(
@@ -312,7 +311,9 @@ export default class PlaygroundController {
312311

313312
private openResultAsVirtualDocument(viewColumn) {
314313
vscode.workspace
315-
.openTextDocument(this.getVirtualDocumentUri())
314+
.openTextDocument(
315+
this.getVirtualDocumentUri(this.playgroundResult?.content)
316+
)
316317
.then((doc) => {
317318
this._playgroundResultTextDocument = doc;
318319
vscode.window.showTextDocument(doc, { preview: false, viewColumn });
@@ -359,7 +360,7 @@ export default class PlaygroundController {
359360
return resolve(false);
360361
}
361362

362-
this.playgroundResult = evaluateResponse.result?.content;
363+
this.playgroundResult = evaluateResponse.result;
363364

364365
let viewColumn: vscode.ViewColumn =
365366
this._playgroundResultViewColumn || vscode.ViewColumn.Beside;

src/editors/playgroundResultProvider.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import PlaygroundController from './playgroundController';
44

55
export const PLAYGROUND_RESULT_SCHEME = 'PLAYGROUND_RESULT_SCHEME';
66

7-
export default class PlaygroundResultProvider implements vscode.TextDocumentContentProvider {
7+
export default class PlaygroundResultProvider
8+
implements vscode.TextDocumentContentProvider {
89
_playgroundController: PlaygroundController;
910
_statusView: StatusView;
1011

@@ -23,7 +24,21 @@ export default class PlaygroundResultProvider implements vscode.TextDocumentCont
2324
return new Promise((resolve) => {
2425
this._statusView.showMessage('Getting results...');
2526

26-
return resolve(JSON.stringify(this._playgroundController.playgroundResult, null, 2));
27+
if (
28+
typeof this._playgroundController.playgroundResult?.content ===
29+
'object' ||
30+
this._playgroundController.playgroundResult?.type !== 'string'
31+
) {
32+
return resolve(
33+
JSON.stringify(
34+
this._playgroundController.playgroundResult?.content,
35+
null,
36+
2
37+
)
38+
);
39+
}
40+
41+
return resolve(this._playgroundController.playgroundResult?.content);
2742
});
2843
}
2944
}

src/language/worker.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ import {
44
CliServiceProvider,
55
NodeOptions
66
} from '@mongosh/service-provider-server';
7-
import formatOutput from '../utils/formatOutput';
87
import parseSchema = require('mongodb-schema');
98
import { ServerCommands } from './serverCommands';
109
import { CompletionItemKind } from 'vscode-languageserver';
1110
import type { OutputItem } from '../utils/types';
1211

12+
const { EJSON } = require('bson');
13+
1314
type EvaluationResult = {
1415
printable: any;
1516
type: string | null;
@@ -45,12 +46,13 @@ const executeAll = async (
4546
}
4647
}
4748
});
48-
const { type, printable } = await runtime.evaluate(
49-
codeToEvaluate
50-
);
49+
const { type, printable } = await runtime.evaluate(codeToEvaluate);
5150
const result = {
52-
type,
53-
content: printable
51+
type: type ? type : typeof printable,
52+
content:
53+
typeof printable === 'string'
54+
? printable
55+
: JSON.parse(EJSON.stringify(printable))
5456
};
5557

5658
return [null, { outputLines, result }];

src/test/suite/editors/playgroundController.test.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,66 @@ suite('Playground Controller Test Suite', function () {
323323

324324
expect(isEditprOpened).to.be.equal(true);
325325
});
326+
327+
test('getVirtualDocumentUri should return json uri if content is object', async () => {
328+
await vscode.workspace
329+
.getConfiguration('mdb')
330+
.update('confirmRunAll', false);
331+
const uri = await testPlaygroundController.getVirtualDocumentUri({
332+
test: 'value'
333+
});
334+
335+
expect(uri.scheme).to.be.equal('PLAYGROUND_RESULT_SCHEME');
336+
expect(uri.path).to.be.equal('Playground Result.json');
337+
});
338+
339+
test('getVirtualDocumentUri should return json uri if content is array', async () => {
340+
await vscode.workspace
341+
.getConfiguration('mdb')
342+
.update('confirmRunAll', false);
343+
const uri = await testPlaygroundController.getVirtualDocumentUri([
344+
{ test: 'value' }
345+
]);
346+
347+
expect(uri.scheme).to.be.equal('PLAYGROUND_RESULT_SCHEME');
348+
expect(uri.path).to.be.equal('Playground Result.json');
349+
});
350+
351+
test('getVirtualDocumentUri should return json uri if content is object with BSON value', async () => {
352+
await vscode.workspace
353+
.getConfiguration('mdb')
354+
.update('confirmRunAll', false);
355+
const uri = await testPlaygroundController.getVirtualDocumentUri({
356+
_id: {
357+
$oid: '5d973ae7443762aae72a160'
358+
}
359+
});
360+
361+
expect(uri.scheme).to.be.equal('PLAYGROUND_RESULT_SCHEME');
362+
expect(uri.path).to.be.equal('Playground Result.json');
363+
});
364+
365+
test('getVirtualDocumentUri should return txt uri if content is string', async () => {
366+
await vscode.workspace
367+
.getConfiguration('mdb')
368+
.update('confirmRunAll', false);
369+
const uri = await testPlaygroundController.getVirtualDocumentUri(
370+
'I am a string'
371+
);
372+
373+
expect(uri.scheme).to.be.equal('PLAYGROUND_RESULT_SCHEME');
374+
expect(uri.path).to.be.equal('Playground Result.txt');
375+
});
376+
377+
test('getVirtualDocumentUri should return txt uri if content is number', async () => {
378+
await vscode.workspace
379+
.getConfiguration('mdb')
380+
.update('confirmRunAll', false);
381+
const uri = await testPlaygroundController.getVirtualDocumentUri(12);
382+
383+
expect(uri.scheme).to.be.equal('PLAYGROUND_RESULT_SCHEME');
384+
expect(uri.path).to.be.equal('Playground Result.txt');
385+
});
326386
});
327387
});
328388
});

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

Lines changed: 87 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import MongoDBService, {
1515
import { mdbTestExtension } from '../stubbableMdbExtension';
1616

1717
const expect = chai.expect;
18-
1918
const INCREASED_TEST_TIMEOUT = 5000;
2019

2120
suite('MongoDBService Test Suite', () => {
@@ -992,15 +991,15 @@ suite('MongoDBService Test Suite', () => {
992991
},
993992
source.token
994993
);
995-
const res = {
994+
const expectedResult = {
996995
outputLines: [],
997-
result: { type: null, content: 2 }
996+
result: { type: 'number', content: 2 }
998997
};
999998

1000-
expect(result).to.deep.equal(res);
999+
expect(result).to.deep.equal(expectedResult);
10011000
});
10021001

1003-
test('evaluate multiple commands at once', async function () {
1002+
test('evaluate multiplies commands at once', async function () {
10041003
this.timeout(INCREASED_TEST_TIMEOUT);
10051004

10061005
const source = new CancellationTokenSource();
@@ -1010,12 +1009,12 @@ suite('MongoDBService Test Suite', () => {
10101009
},
10111010
source.token
10121011
);
1013-
const res = {
1012+
const expectedResult = {
10141013
outputLines: [],
1015-
result: { type: null, content: 3 }
1014+
result: { type: 'number', content: 3 }
10161015
};
10171016

1018-
expect(result).to.deep.equal(res);
1017+
expect(result).to.deep.equal(expectedResult);
10191018
});
10201019

10211020
test('create each time a new runtime', async function () {
@@ -1030,7 +1029,7 @@ suite('MongoDBService Test Suite', () => {
10301029
);
10311030
const firstRes = {
10321031
outputLines: [],
1033-
result: { type: null, content: 2 }
1032+
result: { type: 'number', content: 2 }
10341033
};
10351034

10361035
expect(firstEvalResult).to.deep.equal(firstRes);
@@ -1043,12 +1042,87 @@ suite('MongoDBService Test Suite', () => {
10431042
);
10441043
const secondRes = {
10451044
outputLines: [],
1046-
result: { type: null, content: 3 }
1045+
result: { type: 'number', content: 3 }
10471046
};
10481047

10491048
expect(secondEvalResult).to.deep.equal(secondRes);
10501049
});
10511050

1051+
test('evaluate returns valid EJSON', async function () {
1052+
this.timeout(INCREASED_TEST_TIMEOUT);
1053+
1054+
const source = new CancellationTokenSource();
1055+
const result = await testMongoDBService.executeAll(
1056+
{
1057+
codeToEvaluate: `const { ObjectId } = require('bson');
1058+
const x = { _id: new ObjectId('5fb292760ece2dc9c0362075') };
1059+
x`
1060+
},
1061+
source.token
1062+
);
1063+
const expectedResult = {
1064+
outputLines: [],
1065+
result: {
1066+
type: 'object',
1067+
content: {
1068+
_id: {
1069+
$oid: '5fb292760ece2dc9c0362075'
1070+
}
1071+
}
1072+
}
1073+
};
1074+
1075+
expect(result).to.deep.equal(expectedResult);
1076+
});
1077+
1078+
test('evaluate returns single line strings', async function () {
1079+
this.timeout(INCREASED_TEST_TIMEOUT);
1080+
1081+
const source = new CancellationTokenSource();
1082+
const result = await testMongoDBService.executeAll(
1083+
{
1084+
codeToEvaluate: `const x = 'A single line string';
1085+
x`
1086+
},
1087+
source.token
1088+
);
1089+
const expectedResult = {
1090+
outputLines: [],
1091+
result: {
1092+
type: 'string',
1093+
content: 'A single line string'
1094+
}
1095+
};
1096+
1097+
expect(result).to.deep.equal(expectedResult);
1098+
});
1099+
1100+
test('evaluate returns multiline strings', async function () {
1101+
this.timeout(INCREASED_TEST_TIMEOUT);
1102+
1103+
const source = new CancellationTokenSource();
1104+
const result = await testMongoDBService.executeAll(
1105+
{
1106+
codeToEvaluate: `const x = \`vscode
1107+
is
1108+
awesome\`;
1109+
x`
1110+
},
1111+
source.token
1112+
);
1113+
const expectedResult = {
1114+
outputLines: [],
1115+
result: {
1116+
type: 'string',
1117+
content: `vscode
1118+
is
1119+
awesome`
1120+
}
1121+
};
1122+
1123+
expect(result).to.deep.equal(expectedResult);
1124+
});
1125+
10521126
test('includes results from print() and console.log()', async function () {
10531127
this.timeout(INCREASED_TEST_TIMEOUT);
10541128

@@ -1059,17 +1133,17 @@ suite('MongoDBService Test Suite', () => {
10591133
},
10601134
source.token
10611135
);
1062-
const res = {
1136+
const expectedResult = {
10631137
outputLines: [
10641138
{ type: null, content: 'Hello' },
10651139
{ type: null, content: 1 },
10661140
{ type: null, content: 2 },
10671141
{ type: null, content: 3 }
10681142
],
1069-
result: { type: null, content: 42 }
1143+
result: { type: 'number', content: 42 }
10701144
};
10711145

1072-
expect(result).to.deep.equal(res);
1146+
expect(result).to.deep.equal(expectedResult);
10731147
});
10741148
});
10751149
});

0 commit comments

Comments
 (0)