Skip to content

Commit 00d9090

Browse files
authored
Merge pull request #7 from mesarth/relative-paths
implement relative path support for input files (new default)
2 parents e8767c2 + 890bb90 commit 00d9090

10 files changed

+271
-65
lines changed

package.json

+14-1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,16 @@
6868
"command": "jsonpath-notebook.openNewNotebook"
6969
}
7070
]
71+
},
72+
"configuration": {
73+
"title": "JSONPath Notebook",
74+
"properties": {
75+
"jsonpath-notebook.useRelativePaths": {
76+
"type": "boolean",
77+
"default": true,
78+
"description": "Save relative paths instead of absolute paths for input .json files (context) in notebook file."
79+
}
80+
}
7181
}
7282
},
7383
"scripts": {
@@ -95,5 +105,8 @@
95105
"glob": "^8.1.0",
96106
"mocha": "^10.2.0",
97107
"typescript": "^5.1.3"
108+
},
109+
"dependencies": {
110+
"upath": "^2.0.1"
98111
}
99-
}
112+
}

src/CellStatusProvider.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import path = require('path');
1+
const path = require('upath');
22
import * as vscode from 'vscode';
33
import { EXTENSION_ID } from './utils';
44

src/Controller.ts

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import * as vscode from 'vscode';
2-
import jsonPath from './lib/jsonpath';
3-
import { LANGUAGE_ID, NOTEBOOK_TYPE, showChangeContextQuickPick } from './utils';
4-
import { join } from 'path';
2+
import { LANGUAGE_ID, NOTEBOOK_TYPE, showChangeContextQuickPick, getContextUriFromCell } from './utils';
3+
import { join } from 'upath';
54
// eslint-disable-next-line @typescript-eslint/naming-convention
65
const { Worker, isMainThread } = require('worker_threads');
76

@@ -44,20 +43,21 @@ export class Controller {
4443

4544
let inputContent = {};
4645

46+
// ask for input file if not already selected
4747
if (!cell.metadata.selectedFileUri) {
4848
await showChangeContextQuickPick(cell.index, true);
4949
}
5050

51-
let selectedFileUri = vscode.Uri.parse(cell.metadata.selectedFileUri);
52-
//check if file still exists
51+
let selectedFileUri = getContextUriFromCell(cell);
5352
try {
53+
//check if file still exists
5454
await vscode.workspace.fs.stat(selectedFileUri);
5555
} catch {
5656
//file does not exist, ask user to select a different file
5757
const result = await vscode.window.showErrorMessage(`File ${selectedFileUri.fsPath} does not exist`, { modal: true, detail: 'The context file for this cell was not found at the saved path. It was probably moved or deleted.' }, 'Select different file');
5858
if (result) {
5959
await showChangeContextQuickPick(cell.index);
60-
selectedFileUri = vscode.Uri.parse(cell.metadata.selectedFileUri);
60+
selectedFileUri = getContextUriFromCell(cell);
6161
}
6262
else {
6363
//canceled by user, exit execution
@@ -66,6 +66,7 @@ export class Controller {
6666
}
6767
}
6868

69+
// read context file and parse as JSON
6970
const document = await vscode.workspace.openTextDocument(selectedFileUri);
7071
try {
7172
inputContent = JSON.parse(document.getText());
@@ -80,6 +81,7 @@ export class Controller {
8081
return;
8182
}
8283

84+
// execute JSONPath query in worker thread
8385
if (isMainThread) {
8486
const worker = new Worker(join(__filename, '../worker.js'), {
8587
workerData: {

src/test/runTest.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as path from 'path';
1+
import * as path from 'upath';
22

33
import { runTests } from '@vscode/test-electron';
44

src/test/suite/extension.test.ts renamed to src/test/suite/command.test.ts

+4-41
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,23 @@
33
import * as vscode from 'vscode';
44
import { assert, expect } from 'chai';
55
import { EXTENSION_ID, LANGUAGE_ID, NOTEBOOK_TYPE, getContext } from '../../utils';
6-
import path = require('path');
6+
const path = require('upath');
77
// import * as myExtension from '../../extension';
88

99
const getTestFileUri = (relativePath: string) => {
1010
const workspacePath = __dirname + '../../../..//src/test/suite/files/';
1111
return vscode.Uri.file(path.join(workspacePath, relativePath));
1212
};
1313

14-
const delay = (ms: number) => new Promise(res => setTimeout(res, ms));
15-
16-
describe('Extension Test Suite', async () => {
14+
describe('Command Tests', async () => {
1715
vscode.window.showInformationMessage('Start all tests.');
1816

1917
beforeEach(async () => {
2018
//close all open tabs
2119
await vscode.commands.executeCommand('workbench.action.closeAllEditors');
2220
});
2321

24-
describe('Command[openNewNotebook]', async () => {
22+
describe('openNewNotebook', async () => {
2523
it('is correct NotebookType', async () => {
2624
await vscode.commands.executeCommand(`${EXTENSION_ID}.openNewNotebook`);
2725
assert.equal(NOTEBOOK_TYPE, vscode.window.activeNotebookEditor?.notebook.notebookType);
@@ -40,7 +38,7 @@ describe('Extension Test Suite', async () => {
4038
});
4139
});
4240

43-
it('Command[openOutput]', async () => {
41+
it('openOutput', async () => {
4442
const uri = getTestFileUri('/notebooks/cellOutput.jsonpath-notebook');
4543
const document = await vscode.workspace.openNotebookDocument(uri);
4644

@@ -53,39 +51,4 @@ describe('Extension Test Suite', async () => {
5351
const openedOutput = JSON.parse(vscode.window.activeTextEditor?.document.getText() ?? "null");
5452
expect(openedOutput).to.deep.equal(output);
5553
});
56-
57-
it('Run basic query', async () => {
58-
const inputDocumentUri = getTestFileUri('/input/bookstore.json');
59-
await vscode.workspace.openTextDocument(inputDocumentUri);
60-
61-
//prepare notebook
62-
const notebookData = new vscode.NotebookData([
63-
{
64-
kind: vscode.NotebookCellKind.Code,
65-
languageId: LANGUAGE_ID,
66-
value: '$..book[?(@.price<10)]',
67-
metadata: {
68-
"selectedFileUri": inputDocumentUri.path
69-
}
70-
}
71-
]);
72-
const document = await vscode.workspace.openNotebookDocument(NOTEBOOK_TYPE, notebookData);
73-
await vscode.window.showNotebookDocument(document);
74-
75-
//execute first cell
76-
await vscode.commands.executeCommand('notebook.execute', document.uri);
77-
78-
//delay is needed afaik there is no way to check if a cell is finished executing
79-
await delay(1000);
80-
81-
//check output
82-
const output = new TextDecoder().decode(vscode.window.activeNotebookEditor?.notebook.cellAt(0).outputs[0].items[0].data);
83-
84-
//get expected output content from from ./files/output/basic.json
85-
const expectedDocumentPath = getTestFileUri('output/basic.json');
86-
const expectedOutput = await vscode.workspace.openTextDocument(expectedDocumentPath);
87-
const expectedOutputContent = expectedOutput.getText();
88-
89-
expect(JSON.parse(expectedOutputContent)).to.deep.equal(JSON.parse(output));
90-
});
9154
});

src/test/suite/e2e.test.ts

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// You can import and use all API from the 'vscode' module
2+
// as well as import your extension to test it
3+
import * as vscode from 'vscode';
4+
import { expect } from 'chai';
5+
import { LANGUAGE_ID, NOTEBOOK_TYPE } from '../../utils';
6+
const path = require('upath');
7+
// import * as myExtension from '../../extension';
8+
9+
const getTestFileUri = (relativePath: string) => {
10+
const workspacePath = __dirname + '../../../..//src/test/suite/files/';
11+
return vscode.Uri.file(path.join(workspacePath, relativePath));
12+
};
13+
14+
const delay = (ms: number) => new Promise(res => setTimeout(res, ms));
15+
16+
describe('E2E Tests', async () => {
17+
vscode.window.showInformationMessage('Start all tests.');
18+
19+
beforeEach(async () => {
20+
//close all open tabs
21+
await vscode.commands.executeCommand('workbench.action.closeAllEditors');
22+
});
23+
24+
it('Run basic query', async () => {
25+
const inputDocumentUri = getTestFileUri('/input/bookstore.json');
26+
await vscode.workspace.openTextDocument(inputDocumentUri);
27+
28+
//prepare notebook
29+
const notebookData = new vscode.NotebookData([
30+
{
31+
kind: vscode.NotebookCellKind.Code,
32+
languageId: LANGUAGE_ID,
33+
value: '$..book[?(@.price<10)]',
34+
metadata: {
35+
"selectedFileUri": inputDocumentUri.path
36+
}
37+
}
38+
]);
39+
const document = await vscode.workspace.openNotebookDocument(NOTEBOOK_TYPE, notebookData);
40+
await vscode.window.showNotebookDocument(document);
41+
42+
//execute first cell
43+
await vscode.commands.executeCommand('notebook.execute', document.uri);
44+
45+
//delay is needed afaik there is no way to check if a cell is finished executing
46+
await delay(1000);
47+
48+
//check output
49+
const output = new TextDecoder().decode(vscode.window.activeNotebookEditor?.notebook.cellAt(0).outputs[0].items[0].data);
50+
51+
//get expected output content from from ./files/output/basic.json
52+
const expectedDocumentPath = getTestFileUri('output/basic.json');
53+
const expectedOutput = await vscode.workspace.openTextDocument(expectedDocumentPath);
54+
const expectedOutputContent = expectedOutput.getText();
55+
56+
expect(JSON.parse(expectedOutputContent)).to.deep.equal(JSON.parse(output));
57+
});
58+
});

src/test/suite/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as path from 'path';
1+
import * as path from 'upath';
22
import * as Mocha from 'mocha';
33
import * as glob from 'glob';
44

src/test/suite/path-type.test.ts

+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// You can import and use all API from the 'vscode' module
2+
// as well as import your extension to test it
3+
import * as vscode from 'vscode';
4+
import { LANGUAGE_ID, NOTEBOOK_TYPE, getContextUriFromCell, getPreferredPathFormatFromUri } from '../../utils';
5+
import { expect } from 'chai';
6+
const path = require('upath');
7+
// import * as myExtension from '../../extension';
8+
9+
const getTestFileUri = (relativePath: string) => {
10+
const workspacePath = __dirname + '../../../..//src/test/suite/files/';
11+
return vscode.Uri.file(path.join(workspacePath, relativePath));
12+
};
13+
14+
const delay = (ms: number) => new Promise(res => setTimeout(res, ms));
15+
16+
describe('Path Type Tests', async () => {
17+
vscode.window.showInformationMessage('Start all tests.');
18+
19+
beforeEach(async () => {
20+
//close all open tabs
21+
await vscode.commands.executeCommand('workbench.action.closeAllEditors');
22+
});
23+
24+
it('getPreferredPathFormatFromUri: Use relative path for file context when useRelativePaths set to true (default)', async () => {
25+
const notebookUri = getTestFileUri('/notebooks/empty.jsonpath-notebook');
26+
const notebook = await vscode.workspace.openNotebookDocument(notebookUri);
27+
await vscode.workspace.getConfiguration('jsonpath-notebook').update('useRelativePaths', true, true);
28+
await vscode.window.showNotebookDocument(notebook);
29+
30+
const contextUri = getTestFileUri('/input/bookstore.json');
31+
32+
const expectedPath = '../input/bookstore.json';
33+
const actualPath = getPreferredPathFormatFromUri(contextUri);
34+
35+
expect(actualPath).to.equal(expectedPath);
36+
});
37+
38+
it('getPreferredPathFormatFromUri: Use absolute path for file context when useRelativePaths set to true but no notebook is open', async () => {
39+
const contextUri = getTestFileUri('/input/bookstore.json');
40+
41+
const expectedPath = contextUri.path;
42+
const actualPath = getPreferredPathFormatFromUri(contextUri);
43+
44+
expect(actualPath).to.equal(expectedPath);
45+
});
46+
47+
it('getPreferredPathFormatFromUri: Use absolute path for file context when useRelativePaths set to true but is on different drive', async function () {
48+
if (process.platform !== 'win32') { this.skip(); }
49+
50+
const notebookUri = getTestFileUri('/notebooks/empty.jsonpath-notebook');
51+
const notebook = await vscode.workspace.openNotebookDocument(notebookUri);
52+
await vscode.window.showNotebookDocument(notebook);
53+
await vscode.workspace.getConfiguration('jsonpath-notebook').update('useRelativePaths', true, true);
54+
55+
const contextUri = vscode.Uri.file('Z:\\input\\bookstore.json');
56+
57+
const expectedPath = contextUri.path;
58+
const actualPath = getPreferredPathFormatFromUri(contextUri);
59+
60+
expect(actualPath).to.equal(expectedPath);
61+
});
62+
63+
it('getPreferredPathFormatFromUri: Use absolute path for file context when useRelativePaths set to false', async () => {
64+
const notebookUri = getTestFileUri('/notebooks/empty.jsonpath-notebook');
65+
const notebook = await vscode.workspace.openNotebookDocument(notebookUri);
66+
await vscode.window.showNotebookDocument(notebook);
67+
await vscode.workspace.getConfiguration('jsonpath-notebook').update('useRelativePaths', false, true);
68+
69+
const contextUri = getTestFileUri('/input/bookstore.json');
70+
71+
const expectedPath = contextUri.path;
72+
const actualPath = getPreferredPathFormatFromUri(contextUri);
73+
74+
expect(actualPath).to.equal(expectedPath);
75+
});
76+
77+
it('getContextUriFromCell: Returns correct uri when metadata selectedFileUri is relative path', async () => {
78+
const notebookUri = getTestFileUri('/notebooks/empty.jsonpath-notebook');
79+
const notebook = await vscode.workspace.openNotebookDocument(notebookUri);
80+
81+
await vscode.window.showNotebookDocument(notebook);
82+
83+
//add cell with metadata
84+
const edit = new vscode.WorkspaceEdit();
85+
const nbEdit = vscode.NotebookEdit.insertCells(0, [{
86+
kind: vscode.NotebookCellKind.Code,
87+
languageId: LANGUAGE_ID,
88+
value: '$..book[?(@.price<10)]',
89+
metadata: {
90+
"selectedFileUri": "../input/bookstore.json"
91+
}
92+
}]);
93+
edit.set(notebook.uri, [nbEdit]);
94+
await vscode.workspace.applyEdit(edit);
95+
96+
const cell = notebook.cellAt(0);
97+
if (!cell) { return; }
98+
const expectedUri = getTestFileUri('/input/bookstore.json');
99+
const actualUri = getContextUriFromCell(cell);
100+
expect(actualUri).to.deep.equal(expectedUri);
101+
});
102+
103+
it('getContextUriFromCell: Returns correct uri when metadata selectedFileUri is absolute', async () => {
104+
const notebookUri = getTestFileUri('/notebooks/empty.jsonpath-notebook');
105+
const notebook = await vscode.workspace.openNotebookDocument(notebookUri);
106+
107+
await vscode.window.showNotebookDocument(notebook);
108+
109+
//add cell with metadata
110+
const edit = new vscode.WorkspaceEdit();
111+
const nbEdit = vscode.NotebookEdit.insertCells(0, [{
112+
kind: vscode.NotebookCellKind.Code,
113+
languageId: LANGUAGE_ID,
114+
value: '$..book[?(@.price<10)]',
115+
metadata: {
116+
"selectedFileUri": getTestFileUri('/input/bookstore.json').path
117+
}
118+
}]);
119+
edit.set(notebook.uri, [nbEdit]);
120+
await vscode.workspace.applyEdit(edit);
121+
122+
const cell = notebook.cellAt(0);
123+
if (!cell) { return; }
124+
const expectedUri = getTestFileUri('/input/bookstore.json');
125+
const actualUri = getContextUriFromCell(cell);
126+
expect(actualUri).to.deep.equal(expectedUri);
127+
});
128+
});

0 commit comments

Comments
 (0)