Skip to content

Commit 29590b5

Browse files
author
Dvir Yitzchaki
committed
extension code + tests
1 parent 436d891 commit 29590b5

File tree

10 files changed

+205
-86
lines changed

10 files changed

+205
-86
lines changed

.vscode/launch.json

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,39 @@
33
// Hover to view descriptions of existing attributes.
44
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
55
{
6-
"version": "0.2.0",
7-
"configurations": [
8-
{
9-
"name": "Extension",
10-
"type": "extensionHost",
11-
"request": "launch",
12-
"runtimeExecutable": "${execPath}",
13-
"args": [
14-
"--extensionDevelopmentPath=${workspaceFolder}"
15-
],
16-
"outFiles": [
17-
"${workspaceFolder}/out/**/*.js"
18-
],
19-
"preLaunchTask": "npm: watch"
20-
},
21-
{
22-
"name": "Extension Tests",
23-
"type": "extensionHost",
24-
"request": "launch",
25-
"runtimeExecutable": "${execPath}",
26-
"args": [
27-
"--extensionDevelopmentPath=${workspaceFolder}",
28-
"--extensionTestsPath=${workspaceFolder}/out/test"
29-
],
30-
"outFiles": [
31-
"${workspaceFolder}/out/test/**/*.js"
32-
],
33-
"preLaunchTask": "npm: watch"
34-
}
35-
]
36-
}
6+
"version": "0.2.0",
7+
"configurations": [
8+
{
9+
"name": "Extension",
10+
"type": "extensionHost",
11+
"request": "launch",
12+
"runtimeExecutable": "${execPath}",
13+
"args": [
14+
"${workspaceFolder}/src/test/workspace/test.code-workspace",
15+
"--extensionDevelopmentPath=${workspaceFolder}"
16+
],
17+
"outFiles": [
18+
"${workspaceFolder}/out/**/*.js"
19+
],
20+
"preLaunchTask": "npm: watch",
21+
"env": {
22+
"PATH": "bla"
23+
}
24+
},
25+
{
26+
"name": "Extension Tests",
27+
"type": "extensionHost",
28+
"request": "launch",
29+
"runtimeExecutable": "${execPath}",
30+
"args": [
31+
"${workspaceFolder}/src/test/workspace/test.code-workspace",
32+
"--extensionDevelopmentPath=${workspaceFolder}",
33+
"--extensionTestsPath=${workspaceFolder}/out/test"
34+
],
35+
"outFiles": [
36+
"${workspaceFolder}/out/test/**/*.js"
37+
],
38+
"preLaunchTask": "npm: watch"
39+
}
40+
]
41+
}

package.json

Lines changed: 47 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,49 @@
11
{
2-
"name": "parquet-viewer",
3-
"displayName": "parquet-viewer",
4-
"description": "View Apache Parquet files as JSON",
5-
"version": "0.0.1",
6-
"engines": {
7-
"vscode": "^1.30.0"
8-
},
9-
"categories": [
10-
"Other"
11-
],
12-
"activationEvents": [
13-
"onCommand:extension.sayHello"
14-
],
15-
"main": "./out/extension",
16-
"contributes": {
17-
"commands": [
18-
{
19-
"command": "extension.sayHello",
20-
"title": "Hello World"
21-
}
2+
"name": "parquet-viewer",
3+
"displayName": "parquet-viewer",
4+
"description": "Views Apache Parquet files as JSON",
5+
"publisher": "dvirtz",
6+
"version": "0.0.1",
7+
"engines": {
8+
"vscode": "^1.30.0"
9+
},
10+
"categories": [
11+
"Other"
12+
],
13+
"activationEvents": [
14+
"onLanguage:parquet",
15+
"onFileSystem:file"
16+
],
17+
"main": "./out/extension",
18+
"contributes": {
19+
"languages": [
20+
{
21+
"id": "parquet",
22+
"extensions": [
23+
".parquet"
2224
]
23-
},
24-
"scripts": {
25-
"vscode:prepublish": "npm run compile",
26-
"compile": "tsc -p ./",
27-
"watch": "tsc -watch -p ./",
28-
"postinstall": "node ./node_modules/vscode/bin/install",
29-
"test": "npm run compile && node ./node_modules/vscode/bin/test"
30-
},
31-
"devDependencies": {
32-
"typescript": "^3.1.4",
33-
"vscode": "^1.1.25",
34-
"tslint": "^5.8.0",
35-
"@types/node": "^8.10.25",
36-
"@types/mocha": "^2.2.42"
37-
}
38-
}
25+
}
26+
],
27+
"commands": [
28+
{
29+
"command": "extension.viewParquetAsJson",
30+
"category": "Parquet",
31+
"title": "View as JSON"
32+
}
33+
]
34+
},
35+
"scripts": {
36+
"vscode:prepublish": "npm run compile",
37+
"compile": "tsc -p ./",
38+
"watch": "tsc -watch -p ./",
39+
"postinstall": "node ./node_modules/vscode/bin/install",
40+
"test": "npm run compile && node ./node_modules/vscode/bin/test"
41+
},
42+
"devDependencies": {
43+
"typescript": "^3.1.4",
44+
"vscode": "^1.1.25",
45+
"tslint": "^5.8.0",
46+
"@types/node": "^8.10.25",
47+
"@types/mocha": "^2.2.42"
48+
}
49+
}

src/extension.ts

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,44 @@
22
// The module 'vscode' contains the VS Code extensibility API
33
// Import the module and reference it with the alias vscode in your code below
44
import * as vscode from 'vscode';
5+
import { ParquetContentProvider } from './parquet_content_provider';
6+
import { execFile } from 'child_process';
57

68
// this method is called when your extension is activated
79
// your extension is activated the very first time the command is executed
810
export function activate(context: vscode.ExtensionContext) {
11+
console.log('parquet-viewer activated');
912

10-
// Use the console to output diagnostic information (console.log) and errors (console.error)
11-
// This line of code will only be executed once when your extension is activated
12-
console.log('Congratulations, your extension "parquet-viewer" is now active!');
13+
execFile('parquet-tools', ['-h'], err => {
14+
vscode.window.showErrorMessage('parquet-tools not in PATH');
15+
});
1316

14-
// The command has been defined in the package.json file
15-
// Now provide the implementation of the command with registerCommand
16-
// The commandId parameter must match the command field in package.json
17-
let disposable = vscode.commands.registerCommand('extension.sayHello', () => {
18-
// The code you place here will be executed every time your command is executed
17+
const scheme = 'parquet';
18+
const provider = new ParquetContentProvider();
1919

20-
// Display a message box to the user
21-
vscode.window.showInformationMessage('Hello World!');
22-
});
20+
context.subscriptions.push(vscode.workspace.registerTextDocumentContentProvider(scheme, provider));
2321

24-
context.subscriptions.push(disposable);
22+
let onFile = function (document: vscode.TextDocument) {
23+
if (document.fileName.endsWith('parquet') && document.uri.scheme !== scheme) {
24+
let uri = vscode.Uri.parse(scheme + '://' + document.uri.path);
25+
vscode.window.showTextDocument(uri, { preview: true, viewColumn: vscode.window.activeTextEditor!.viewColumn });
26+
}
27+
};
28+
29+
context.subscriptions.push(vscode.commands.registerTextEditorCommand('extension.viewParquetAsJson', (textEditor) => {
30+
let document = textEditor.document;
31+
if (!document.fileName.endsWith('parquet')) {
32+
vscode.window.showErrorMessage("Please open a parquet file");
33+
return; // no editor
34+
}
35+
onFile(document);
36+
}));
37+
38+
context.subscriptions.push(vscode.workspace.onDidOpenTextDocument(onFile));
39+
40+
if (vscode.window.activeTextEditor) {
41+
onFile(vscode.window.activeTextEditor.document);
42+
}
2543
}
2644

2745
// this method is called when your extension is deactivated

src/parquet_content_provider.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { TextDocumentContentProvider, EventEmitter, Uri, window } from "vscode";
2+
import { exec } from "child_process";
3+
4+
export class ParquetContentProvider implements TextDocumentContentProvider {
5+
6+
// emitter and its event
7+
onDidChangeEmitter = new EventEmitter<Uri>();
8+
onDidChange = this.onDidChangeEmitter.event;
9+
10+
async provideTextDocumentContent(uri: Uri): Promise<string> {
11+
// simply invoke cowsay, use uri-path as text
12+
return new Promise<string>((resolve, reject) => {
13+
exec('parquet-tools cat -j ' + uri.path, (error, stdout, stderr) => {
14+
if (error) {
15+
const message = `error when running parquet-tools ${error}:\n${stderr}`;
16+
window.showErrorMessage(message);
17+
reject(message);
18+
}
19+
20+
resolve(stdout);
21+
});
22+
});
23+
}
24+
}

src/test/extension.test.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,14 @@ import * as assert from 'assert';
88

99
// You can import and use all API from the 'vscode' module
1010
// as well as import your extension to test it
11-
// import * as vscode from 'vscode';
11+
import * as vscode from 'vscode';
1212
// import * as myExtension from '../extension';
1313

1414
// Defines a Mocha test suite to group tests of similar kind together
15-
suite("Extension Tests", function () {
15+
suite("Parquet extension tests", function () {
1616

17-
// Defines a Mocha unit test
18-
test("Something 1", function() {
19-
assert.equal(-1, [1, 2, 3].indexOf(5));
20-
assert.equal(-1, [1, 2, 3].indexOf(0));
21-
});
17+
test("Should find extension", async () => {
18+
const extension = await vscode.extensions.getExtension("dvirtz.parquet-viewer");
19+
assert(extension);
20+
});
2221
});

src/test/provider.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
import * as assert from 'assert';
3+
4+
import { ParquetContentProvider } from "../parquet_content_provider";
5+
import { getUri, fileRead } from './utils';
6+
import { Uri } from 'vscode';
7+
8+
suite("Provider tests", () => {
9+
10+
test("Parquet to JSON", async () => {
11+
const provider = new ParquetContentProvider();
12+
const json = getUri("small.parquet").then(parquet => {
13+
return provider.provideTextDocumentContent(parquet);
14+
});
15+
const expected = fileRead("small.json");
16+
17+
return Promise.all([json, expected]).then(values => {
18+
assert.strictEqual(values[0], values[1]);
19+
});
20+
});
21+
22+
test("Error on not existing file", async () => {
23+
const provider = new ParquetContentProvider();
24+
25+
return provider.provideTextDocumentContent(Uri.parse("file://.")).then(data => {
26+
assert(false, "should not get here");
27+
}, (error: string) => {
28+
assert(error.indexOf('error when running parquet-tools') !== -1);
29+
});
30+
});
31+
});

src/test/utils.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import * as assert from 'assert';
2+
import { Uri, workspace } from "vscode";
3+
import { readFile } from 'fs';
4+
5+
export async function getUri(fileName: String): Promise<Uri> {
6+
7+
const testFiles = await workspace.findFiles(`**/${fileName}`);
8+
assert.equal(testFiles.length, 1);
9+
return testFiles[0];
10+
}
11+
12+
export async function fileRead(fileName: string): Promise<string> {
13+
return getUri(fileName).then(uri => {
14+
return new Promise<string>(resolve => {
15+
readFile(uri.path, 'utf8', (err, data) => {
16+
assert.ifError(err);
17+
resolve(data);
18+
});
19+
});
20+
});
21+
}

src/test/workspace/small.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
{"number":1,"letter":"a"}
2+
{"number":2,"letter":"b"}

src/test/workspace/small.parquet

549 Bytes
Binary file not shown.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"folders": [
3+
{
4+
"path": "."
5+
}
6+
],
7+
"settings": {}
8+
}

0 commit comments

Comments
 (0)