Skip to content

Commit e7a27a4

Browse files
refactor: Create types for each direction of message transfer (#19)
* refactor: Create types for each direction of message transfer * refactor: Redo build system a bit to allow shared typescript file
1 parent 76e8aa6 commit e7a27a4

File tree

8 files changed

+107
-67
lines changed

8 files changed

+107
-67
lines changed

esbuild.webview.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
require('esbuild').build({
2+
entryPoints: ['src/webview/webview.ts'],
3+
bundle: true,
4+
format: 'iife',
5+
platform: 'browser',
6+
outfile: 'out/webview.js',
7+
sourcemap: true,
8+
minify: true,
9+
}).catch(() => process.exit(1));

package.json

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,12 @@
7575
]
7676
},
7777
"scripts": {
78-
"vscode:prepublish": "rm -rf ./out && mkdir -p ./out/binding/ && cp ./node_modules/duckdb/lib/binding/duckdb.node ./out/binding/ && tsc -p tsconfig.media.json && esbuild ./src/extension.ts --bundle --outfile=out/extension.js --external:vscode --external:nock --external:aws-sdk --external:mock-aws-s3 --format=cjs --platform=node --minify",
79-
"compile": "tsc -p tsconfig.extension.json && tsc -p tsconfig.media.json",
80-
"watch": "tsc -w -p ./",
81-
"lint": "eslint \"src/**/*.ts\""
78+
"build:webview": "node esbuild.webview.js",
79+
"build:extension": "tsc -p .",
80+
"compile": "npm run build:extension && npm run build:webview",
81+
"watch:extension": "tsc -w -p ./",
82+
"lint": "eslint \"src/**/*.ts\"",
83+
"vscode:prepublish": "rm -rf ./out && mkdir -p ./out/binding/ && cp ./node_modules/duckdb/lib/binding/duckdb.node ./out/binding/ && npm run compile && esbuild ./src/extension.ts --bundle --outfile=out/extension.js --external:vscode --external:nock --external:aws-sdk --external:mock-aws-s3 --format=cjs --platform=node --minify"
8284
},
8385
"devDependencies": {
8486
"@types/node": "^16.18.34",

src/parquetDocument.ts

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
11
import * as vscode from 'vscode';
22
import { Disposable } from './dispose';
33
import { getNonce } from './util';
4+
import { BackToFrontMessage, FrontToBackMessage, DescribeColumn } from './shared/messages';
45
import { parse, extname } from "path"
56
import * as duckdb from 'duckdb';
67

78
const CSV_EXTENSIONS = [".csv"];
89
const PARQUET_EXTENSIONS = [".pq", ".parq", ".parquet"];
910

10-
type IMessage = {
11-
type: 'query' | 'more';
12-
success: boolean;
13-
message?: string;
14-
results?: duckdb.TableData;
15-
describe?: duckdb.TableData;
16-
} | { type: 'config', autoQuery: boolean } | { type: 'reloadBaseView' };
1711

1812
/**
1913
* Define the document (the data model) used for table files.
@@ -106,7 +100,7 @@ class ParquetDocument extends Disposable implements vscode.CustomDocument {
106100
return results;
107101
}
108102

109-
runQuery(sql: string, limit: number, callback: (msg: IMessage) => void): void {
103+
runQuery(sql: string, limit: number, callback: (msg: BackToFrontMessage) => void): void {
110104
// Fetch resulting column names and types
111105
this.db.all(
112106
`DESCRIBE (${sql.replace(';', '')});`,
@@ -124,14 +118,19 @@ class ParquetDocument extends Disposable implements vscode.CustomDocument {
124118
callback({ type: 'query', success: false, message: err.message });
125119
return;
126120
}
127-
callback({ type: 'query', success: true, results: this.cleanResults(res), describe: descRes });
121+
callback({
122+
type: 'query',
123+
success: true,
124+
results: this.cleanResults(res),
125+
describe: translateDescribe(descRes)
126+
});
128127
}
129128
);
130129
}
131130
);
132131
}
133132

134-
fetchMore(sql: string, limit: number, offset: number, callback: (msg: IMessage) => void): void {
133+
fetchMore(sql: string, limit: number, offset: number, callback: (msg: BackToFrontMessage) => void): void {
135134
this.db.all(
136135
this.formatSql(sql, limit, offset),
137136
(err, res) => {
@@ -149,6 +148,12 @@ class ParquetDocument extends Disposable implements vscode.CustomDocument {
149148
}
150149
}
151150

151+
function translateDescribe(descRes: duckdb.TableData): DescribeColumn[] {
152+
return descRes.map(row => ({
153+
column_name: String(row.column_name),
154+
column_type: String(row.column_type),
155+
}));
156+
}
152157

153158
export class ParquetDocumentProvider implements vscode.CustomReadonlyEditorProvider<ParquetDocument> {
154159

@@ -219,9 +224,10 @@ export class ParquetDocumentProvider implements vscode.CustomReadonlyEditorProvi
219224
* Get the static HTML used for in our editor's webviews.
220225
*/
221226
private getHtmlForWebview(webview: vscode.Webview, uri: vscode.Uri): string {
222-
// Local path to script and css for the webview
227+
// Local path to script and css for the webview.
223228
const jsUri = webview.asWebviewUri(vscode.Uri.joinPath(
224-
this._context.extensionUri, 'out', 'media', 'flatFileExplorer.js'));
229+
// Compiled from `src/webview/webview.ts`.
230+
this._context.extensionUri, 'out', 'webview.js'));
225231

226232
const cssUri = webview.asWebviewUri(vscode.Uri.joinPath(
227233
this._context.extensionUri, 'media', 'flatFileExplorer.css'));
@@ -335,18 +341,24 @@ export class ParquetDocumentProvider implements vscode.CustomReadonlyEditorProvi
335341
}
336342

337343

338-
private postMessage(panel: vscode.WebviewPanel, message: IMessage): void {
344+
private postMessage(panel: vscode.WebviewPanel, message: BackToFrontMessage): void {
339345
panel.webview.postMessage(message);
340346
}
341347

342348
/** Handle incoming message. */
343-
private onMessage(document: ParquetDocument, panel: vscode.WebviewPanel, message: any) {
349+
private onMessage(document: ParquetDocument, panel: vscode.WebviewPanel, message: FrontToBackMessage) {
344350
switch (message.type) {
345351
case 'query':
346-
document.runQuery(message.sql, message.limit, (msg: IMessage) => this.postMessage(panel, msg));
352+
document.runQuery(
353+
message.sql, message.limit,
354+
(msg: BackToFrontMessage) => this.postMessage(panel, msg)
355+
);
347356
return;
348357
case 'more':
349-
document.fetchMore(message.sql, message.limit, message.offset, (msg: IMessage) => this.postMessage(panel, msg));
358+
document.fetchMore(
359+
message.sql, message.limit, message.offset,
360+
(msg: BackToFrontMessage) => this.postMessage(panel, msg)
361+
);
350362
return;
351363
case 'copy':
352364
let fullQuery = `${document.createViewSql}\n\n${message.sql.trim()}`;

src/shared/messages.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
export interface DescribeColumn {
2+
column_name: string;
3+
column_type: string;
4+
}
5+
6+
interface QueryMessage {
7+
type: "query";
8+
success: boolean;
9+
results?: unknown[];
10+
describe?: DescribeColumn[];
11+
message?: string;
12+
}
13+
14+
interface MoreMessage {
15+
type: "more";
16+
success: boolean;
17+
results?: unknown[];
18+
message?: string;
19+
}
20+
21+
interface ConfigMessage {
22+
type: "config";
23+
autoQuery?: boolean;
24+
}
25+
26+
interface ReloadBaseViewMessage {
27+
type: "reloadBaseView";
28+
}
29+
30+
/** Backend (extension) to Frontend (webview) message. */
31+
export type BackToFrontMessage = QueryMessage | MoreMessage | ConfigMessage | ReloadBaseViewMessage;
32+
33+
34+
35+
/** Frontend (webview) to Backend (extension) message. */
36+
export type FrontToBackMessage = {
37+
type: 'query';
38+
sql: string;
39+
limit: number;
40+
} | {
41+
type: 'more';
42+
sql: string;
43+
limit: number;
44+
offset: number;
45+
} | { type: 'config'; autoQuery: boolean; } | { type: 'reloadBaseView' } | {
46+
type: 'copy';
47+
sql: string;
48+
};
Lines changed: 7 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
import { BackToFrontMessage, FrontToBackMessage, DescribeColumn } from '../shared/messages';
2+
13
// ---------- Utility Types ----------
24

35
type Nullable<T> = T | null;
46

57
// VS Code Webview API
68
interface VSCodeApi<T = unknown> {
7-
postMessage(message: unknown): void;
9+
postMessage(message: FrontToBackMessage): void;
810
getState(): T | undefined;
911
setState(state: T): void;
1012
}
@@ -94,34 +96,6 @@ function getFormatter(columnType: string): Record<string, unknown> {
9496

9597
// ---------- Message Types ----------
9698

97-
interface DescribeColumn {
98-
column_name: string;
99-
column_type: string;
100-
}
101-
102-
interface QueryMessage {
103-
type: "query";
104-
results?: unknown[];
105-
describe?: DescribeColumn[];
106-
message?: string;
107-
}
108-
109-
interface MoreMessage {
110-
type: "more";
111-
results: unknown[];
112-
}
113-
114-
interface ConfigMessage {
115-
type: "config";
116-
autoQuery?: boolean;
117-
}
118-
119-
interface ReloadBaseViewMessage {
120-
type: "reloadBaseView";
121-
}
122-
123-
type IncomingMessage = QueryMessage | MoreMessage | ConfigMessage | ReloadBaseViewMessage;
124-
12599
interface CodeInputElement extends HTMLElement {
126100
value: string;
127101
}
@@ -155,8 +129,8 @@ interface CodeInputElement extends HTMLElement {
155129
// Offset to use when fetching additional results
156130
let scrollOffset = 0;
157131

158-
// Handle messages sent from the extension to the webview
159-
window.addEventListener("message", (event: MessageEvent<IncomingMessage>) => {
132+
// Handle messages sent from the extension to the webview.
133+
window.addEventListener("message", (event: MessageEvent<BackToFrontMessage>) => {
160134
const message = event.data;
161135

162136
switch (message.type) {
@@ -247,11 +221,11 @@ interface CodeInputElement extends HTMLElement {
247221
loadingIconElement!.style.display = "none";
248222
textAreaElement!.disabled = false;
249223

250-
if (message.results.length < CHUNK_SIZE) {
224+
if (message.results && (message.results.length < CHUNK_SIZE)) {
251225
moreToLoad = false;
252226
}
253227

254-
if (message.results.length > 0 && table) {
228+
if (message.results && (message.results.length > 0) && table) {
255229
table.addData(message.results);
256230
}
257231
break;
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@
99

1010
"sourceMap": true
1111
},
12-
"include": ["src/**/*.ts"]
12+
"exclude": ["src/webview"]
1313
}

tsconfig.media.json

Lines changed: 0 additions & 13 deletions
This file was deleted.

tsconfig.webview.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ES2020",
4+
"module": "ESNext",
5+
"lib": ["DOM", "ES2020"],
6+
"strict": true
7+
}
8+
}

0 commit comments

Comments
 (0)