Add client: VSCode. (#21)
parent
c990ba843f
commit
e992a0144b
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"root": true,
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 6,
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"plugins": ["@typescript-eslint"],
|
||||||
|
"rules": {
|
||||||
|
"@typescript-eslint/naming-convention": "warn",
|
||||||
|
"@typescript-eslint/semi": "warn",
|
||||||
|
"curly": "warn",
|
||||||
|
"eqeqeq": "warn",
|
||||||
|
"no-throw-literal": "warn",
|
||||||
|
"semi": "off"
|
||||||
|
},
|
||||||
|
"ignorePatterns": ["out", "dist", "**/*.d.ts"]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
out
|
||||||
|
dist
|
||||||
|
node_modules
|
||||||
|
.vscode-test/
|
||||||
|
*.vsix
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||||
|
// for the documentation about the extensions.json format
|
||||||
|
"recommendations": ["dbaeumer.vscode-eslint", "amodio.tsl-problem-matcher"]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
// A launch configuration that compiles the extension and then opens it inside a new window
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Run Extension without Local Extentions",
|
||||||
|
"type": "extensionHost",
|
||||||
|
"request": "launch",
|
||||||
|
"args": ["--extensionDevelopmentPath=${workspaceFolder}", "--disable-extensions"],
|
||||||
|
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
|
||||||
|
"preLaunchTask": "${defaultBuildTask}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Run Extension",
|
||||||
|
"type": "extensionHost",
|
||||||
|
"request": "launch",
|
||||||
|
"args": ["--extensionDevelopmentPath=${workspaceFolder}"],
|
||||||
|
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
|
||||||
|
"preLaunchTask": "${defaultBuildTask}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Extension Tests",
|
||||||
|
"type": "extensionHost",
|
||||||
|
"request": "launch",
|
||||||
|
"args": [
|
||||||
|
"--extensionDevelopmentPath=${workspaceFolder}",
|
||||||
|
"--extensionTestsPath=${workspaceFolder}/out/test/suite/index"
|
||||||
|
],
|
||||||
|
"outFiles": ["${workspaceFolder}/out/**/*.js", "${workspaceFolder}/dist/**/*.js"],
|
||||||
|
"preLaunchTask": "tasks: watch-tests"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
// Place your settings in this file to overwrite default and user settings.
|
||||||
|
{
|
||||||
|
"files.exclude": {
|
||||||
|
"out": false, // set this to true to hide the "out" folder with the compiled JS files
|
||||||
|
"dist": false // set this to true to hide the "dist" folder with the compiled JS files
|
||||||
|
},
|
||||||
|
"search.exclude": {
|
||||||
|
"out": true, // set this to false to include "out" folder in search results
|
||||||
|
"dist": true // set this to false to include "dist" folder in search results
|
||||||
|
},
|
||||||
|
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
|
||||||
|
"typescript.tsc.autoDetect": "off",
|
||||||
|
"terminal.integrated.profiles.windows": {
|
||||||
|
"PowerShell": {
|
||||||
|
"source": "PowerShell",
|
||||||
|
"icon": "terminal-powershell"
|
||||||
|
},
|
||||||
|
"Command Prompt": {
|
||||||
|
"path": ["${env:windir}\\Sysnative\\cmd.exe", "${env:windir}\\System32\\cmd.exe"],
|
||||||
|
"args": [],
|
||||||
|
"icon": "terminal-cmd"
|
||||||
|
},
|
||||||
|
"Git Bash": {
|
||||||
|
"source": "Git Bash"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
|
// for the documentation about the tasks.json format
|
||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"type": "npm",
|
||||||
|
"script": "watch",
|
||||||
|
"problemMatcher": "$ts-webpack-watch",
|
||||||
|
"isBackground": true,
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "never",
|
||||||
|
"group": "watchers"
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "npm",
|
||||||
|
"script": "watch-tests",
|
||||||
|
"problemMatcher": "$tsc-watch",
|
||||||
|
"isBackground": true,
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "never",
|
||||||
|
"group": "watchers"
|
||||||
|
},
|
||||||
|
"group": "build"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "tasks: watch-tests",
|
||||||
|
"dependsOn": ["npm: watch", "npm: watch-tests"],
|
||||||
|
"problemMatcher": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
.vscode/**
|
||||||
|
.vscode-test/**
|
||||||
|
out/**
|
||||||
|
node_modules/**
|
||||||
|
src/**
|
||||||
|
.gitignore
|
||||||
|
.yarnrc
|
||||||
|
webpack.config.js
|
||||||
|
**/tsconfig.json
|
||||||
|
**/.eslintrc.json
|
||||||
|
**/*.map
|
||||||
|
**/*.ts
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
# TODO
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
{
|
||||||
|
"name": "vscode-tabby",
|
||||||
|
"displayName": "Tabby",
|
||||||
|
"description": "Get completions from Tabby server",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"keywords": [
|
||||||
|
"code-suggestion",
|
||||||
|
"copilot",
|
||||||
|
"code-inference",
|
||||||
|
"tabby"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"vscode": "^1.70.0"
|
||||||
|
},
|
||||||
|
"categories": [
|
||||||
|
"Other"
|
||||||
|
],
|
||||||
|
"activationEvents": [
|
||||||
|
"onStartupFinished"
|
||||||
|
],
|
||||||
|
"main": "./dist/extension.js",
|
||||||
|
"contributes": {
|
||||||
|
"commands": [
|
||||||
|
{
|
||||||
|
"command": "tabby.toggleEnabled",
|
||||||
|
"title": "Tabby: Toggle Code Suggestion On/Off"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "tabby.setServerUrl",
|
||||||
|
"title": "Tabby: Set URL of Tabby Server"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"configuration": {
|
||||||
|
"title": "Tabby",
|
||||||
|
"properties": {
|
||||||
|
"tabby.enabled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "Enable Tabby code suggestion or not."
|
||||||
|
},
|
||||||
|
"tabby.serverUrl": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "http://127.0.0.1:5000",
|
||||||
|
"markdownDescription": "Specifies the url of [Tabby Server](https://github.com/TabbyML/tabby)."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"vscode:prepublish": "yarn package",
|
||||||
|
"compile": "webpack",
|
||||||
|
"watch": "webpack --watch",
|
||||||
|
"package": "webpack --mode production --devtool hidden-source-map",
|
||||||
|
"compile-tests": "tsc -p . --outDir out",
|
||||||
|
"watch-tests": "tsc -p . -w --outDir out",
|
||||||
|
"pretest": "yarn compile-tests && yarn compile && yarn lint",
|
||||||
|
"lint": "eslint src --ext ts",
|
||||||
|
"test": "node ./out/test/runTest.js",
|
||||||
|
"vscode:package": "vsce package",
|
||||||
|
"vscode:publish": "vsce publish"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/glob": "^7.2.0",
|
||||||
|
"@types/mocha": "^9.1.1",
|
||||||
|
"@types/node": "16.x",
|
||||||
|
"@types/vscode": "^1.70.0",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.31.0",
|
||||||
|
"@typescript-eslint/parser": "^5.31.0",
|
||||||
|
"@vscode/test-electron": "^2.1.5",
|
||||||
|
"eslint": "^8.20.0",
|
||||||
|
"glob": "^8.0.3",
|
||||||
|
"mocha": "^10.0.0",
|
||||||
|
"ts-loader": "^9.3.1",
|
||||||
|
"typescript": "^4.7.4",
|
||||||
|
"webpack": "^5.74.0",
|
||||||
|
"webpack-cli": "^4.10.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.3.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
import { ConfigurationTarget, workspace, window, commands } from "vscode";
|
||||||
|
import { EventHandler } from "./EventHandler";
|
||||||
|
|
||||||
|
const target = ConfigurationTarget.Global;
|
||||||
|
|
||||||
|
type Command = {
|
||||||
|
command: string;
|
||||||
|
callback: (...args: any[]) => any;
|
||||||
|
thisArg?: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
const toogleEnabled: Command = {
|
||||||
|
command: "tabby.toggleEnabled",
|
||||||
|
callback: () => {
|
||||||
|
const configuration = workspace.getConfiguration("tabby");
|
||||||
|
const enabled = configuration.get("enabled", true);
|
||||||
|
console.debug(`Toggle Enabled: ${enabled} -> ${!enabled}.`);
|
||||||
|
configuration.update("enabled", !enabled, target, false);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const setServerUrl: Command = {
|
||||||
|
command: "tabby.setServerUrl",
|
||||||
|
callback: () => {
|
||||||
|
const configuration = workspace.getConfiguration("tabby");
|
||||||
|
window
|
||||||
|
.showInputBox({
|
||||||
|
prompt: "Enter the URL of your Tabby Server",
|
||||||
|
value: configuration.get("serverUrl", ""),
|
||||||
|
})
|
||||||
|
.then((url) => {
|
||||||
|
if (url) {
|
||||||
|
console.debug("Set Tabby Server URL: ", url);
|
||||||
|
configuration.update("serverUrl", url, target, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const eventHandler = new EventHandler();
|
||||||
|
const emitEvent: Command = {
|
||||||
|
command: "tabby.emitEvent",
|
||||||
|
callback: (event) => {
|
||||||
|
eventHandler.handle(event);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const tabbyCommands = [toogleEnabled, setServerUrl, emitEvent].map((command) =>
|
||||||
|
commands.registerCommand(command.command, command.callback, command.thisArg)
|
||||||
|
);
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
import { workspace } from "vscode";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export enum EventType {
|
||||||
|
InlineCompletionDisplayed,
|
||||||
|
InlineCompletionAccepted,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Event {
|
||||||
|
type: EventType,
|
||||||
|
id?: string,
|
||||||
|
index?: number,
|
||||||
|
}
|
||||||
|
|
||||||
|
export class EventHandler {
|
||||||
|
private tabbyServerUrl: string = "";
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.updateConfiguration();
|
||||||
|
workspace.onDidChangeConfiguration((event) => {
|
||||||
|
if (event.affectsConfiguration("tabby")) {
|
||||||
|
this.updateConfiguration();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handle(event: Event) {
|
||||||
|
console.debug("Event: ", event);
|
||||||
|
switch (event.type) {
|
||||||
|
case EventType.InlineCompletionDisplayed:
|
||||||
|
axios.post(`${this.tabbyServerUrl}/v1/completions/${event.id}/choices/${event.index}/view`);
|
||||||
|
break;
|
||||||
|
case EventType.InlineCompletionAccepted:
|
||||||
|
axios.post(`${this.tabbyServerUrl}/v1/completions/${event.id}/choices/${event.index}/select`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateConfiguration() {
|
||||||
|
const configuration = workspace.getConfiguration("tabby");
|
||||||
|
this.tabbyServerUrl = configuration.get("serverUrl", "http://127.0.0.1:5000");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,134 @@
|
||||||
|
import {
|
||||||
|
CancellationToken,
|
||||||
|
InlineCompletionContext,
|
||||||
|
InlineCompletionItem,
|
||||||
|
InlineCompletionItemProvider,
|
||||||
|
InlineCompletionList,
|
||||||
|
Position,
|
||||||
|
ProviderResult,
|
||||||
|
Range,
|
||||||
|
TextDocument,
|
||||||
|
workspace,
|
||||||
|
} from "vscode";
|
||||||
|
import axios, { AxiosResponse } from "axios";
|
||||||
|
import { EventType } from "./EventHandler";
|
||||||
|
|
||||||
|
export class TabbyCompletionProvider implements InlineCompletionItemProvider {
|
||||||
|
private uuid = Date.now();
|
||||||
|
private latestTimestamp: number = 0;
|
||||||
|
|
||||||
|
// User Settings
|
||||||
|
private enabled: boolean = true;
|
||||||
|
private tabbyServerUrl: string = "";
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.updateConfiguration();
|
||||||
|
workspace.onDidChangeConfiguration((event) => {
|
||||||
|
if (event.affectsConfiguration("tabby")) {
|
||||||
|
this.updateConfiguration();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//@ts-ignore because ASYNC and PROMISE
|
||||||
|
//prettier-ignore
|
||||||
|
public async provideInlineCompletionItems(document: TextDocument, position: Position, context: InlineCompletionContext, token: CancellationToken): ProviderResult<InlineCompletionItem[] | InlineCompletionList> {
|
||||||
|
const emptyResponse = Promise.resolve([] as InlineCompletionItem[]);
|
||||||
|
if (!this.enabled) {
|
||||||
|
console.debug("Extension not enabled, skipping.");
|
||||||
|
return emptyResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
const prompt = this.getPrompt(document, position);
|
||||||
|
if (this.isNil(prompt)) {
|
||||||
|
console.debug("Prompt is empty, skipping");
|
||||||
|
return emptyResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentTimestamp = Date.now();
|
||||||
|
this.latestTimestamp = currentTimestamp;
|
||||||
|
|
||||||
|
const suggestionDelay = 150;
|
||||||
|
await this.sleep(suggestionDelay);
|
||||||
|
if (currentTimestamp < this.latestTimestamp) {
|
||||||
|
return emptyResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.debug(
|
||||||
|
"Requesting: ",
|
||||||
|
{
|
||||||
|
uuid: this.uuid,
|
||||||
|
timestamp: currentTimestamp,
|
||||||
|
prompt
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// Prompt is already nil-checked
|
||||||
|
const response = await this.getCompletions(prompt as String);
|
||||||
|
|
||||||
|
const hasSuffixParen = this.hasSuffixParen(document, position);
|
||||||
|
const replaceRange = hasSuffixParen
|
||||||
|
? new Range(
|
||||||
|
position.line,
|
||||||
|
position.character,
|
||||||
|
position.line,
|
||||||
|
position.character + 1
|
||||||
|
)
|
||||||
|
: new Range(position, position);
|
||||||
|
const completions = this.toInlineCompletions(response.data, replaceRange);
|
||||||
|
console.debug("Result completions: ", completions);
|
||||||
|
return Promise.resolve(completions);
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateConfiguration() {
|
||||||
|
const configuration = workspace.getConfiguration("tabby");
|
||||||
|
this.enabled = configuration.get("enabled", true);
|
||||||
|
this.tabbyServerUrl = configuration.get("serverUrl", "http://127.0.0.1:5000");
|
||||||
|
}
|
||||||
|
|
||||||
|
private getPrompt(document: TextDocument, position: Position): String | undefined {
|
||||||
|
const maxLines = 20;
|
||||||
|
const firstLine = Math.max(position.line - maxLines, 0);
|
||||||
|
|
||||||
|
return document.getText(new Range(firstLine, 0, position.line, position.character));
|
||||||
|
}
|
||||||
|
|
||||||
|
private isNil(value: String | undefined | null): boolean {
|
||||||
|
return value === undefined || value === null || value.length === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private sleep(milliseconds: number) {
|
||||||
|
return new Promise((r) => setTimeout(r, milliseconds));
|
||||||
|
}
|
||||||
|
|
||||||
|
private toInlineCompletions(value: any, range: Range): InlineCompletionItem[] {
|
||||||
|
return (
|
||||||
|
value.choices?.map(
|
||||||
|
(choice: any) =>
|
||||||
|
new InlineCompletionItem(choice.text, range, {
|
||||||
|
title: "Tabby: Emit Event",
|
||||||
|
command: "tabby.emitEvent",
|
||||||
|
arguments: [
|
||||||
|
{
|
||||||
|
type: EventType.InlineCompletionAccepted,
|
||||||
|
id: value.id,
|
||||||
|
index: choice.index,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
) || []
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getCompletions(prompt: String): Promise<AxiosResponse<any, any>> {
|
||||||
|
return axios.post(`${this.tabbyServerUrl}/v1/completions`, {
|
||||||
|
prompt,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private hasSuffixParen(document: TextDocument, position: Position) {
|
||||||
|
const suffix = document.getText(
|
||||||
|
new Range(position.line, position.character, position.line, position.character + 1)
|
||||||
|
);
|
||||||
|
return ")]}".indexOf(suffix) > -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
// The module 'vscode' contains the VS Code extensibility API
|
||||||
|
// Import the module and reference it with the alias vscode in your code below
|
||||||
|
import { ExtensionContext, languages } from "vscode";
|
||||||
|
import { tabbyCommands } from "./Commands";
|
||||||
|
import { TabbyCompletionProvider } from "./TabbyCompletionProvider";
|
||||||
|
|
||||||
|
// this method is called when your extension is activated
|
||||||
|
// your extension is activated the very first time the command is executed
|
||||||
|
export function activate(context: ExtensionContext) {
|
||||||
|
console.debug("Activating Tabby extension", new Date());
|
||||||
|
context.subscriptions.push(
|
||||||
|
languages.registerInlineCompletionItemProvider(
|
||||||
|
{ pattern: "**" },
|
||||||
|
new TabbyCompletionProvider()
|
||||||
|
),
|
||||||
|
...tabbyCommands
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// this method is called when your extension is deactivated
|
||||||
|
export function deactivate() {
|
||||||
|
console.debug("Deactivating Tabby extension", new Date());
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
import * as path from "path";
|
||||||
|
|
||||||
|
import { runTests } from "@vscode/test-electron";
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
try {
|
||||||
|
// The folder containing the Extension Manifest package.json
|
||||||
|
// Passed to `--extensionDevelopmentPath`
|
||||||
|
const extensionDevelopmentPath = path.resolve(__dirname, "../../");
|
||||||
|
|
||||||
|
// The path to test runner
|
||||||
|
// Passed to --extensionTestsPath
|
||||||
|
const extensionTestsPath = path.resolve(__dirname, "./suite/index");
|
||||||
|
|
||||||
|
// Download VS Code, unzip it and run the integration test
|
||||||
|
await runTests({ extensionDevelopmentPath, extensionTestsPath });
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Failed to run tests");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
import * as assert from "assert";
|
||||||
|
|
||||||
|
// You can import and use all API from the 'vscode' module
|
||||||
|
// as well as import your extension to test it
|
||||||
|
import * as vscode from "vscode";
|
||||||
|
// import * as myExtension from '../../extension';
|
||||||
|
|
||||||
|
suite("Extension Test Suite", () => {
|
||||||
|
vscode.window.showInformationMessage("Start all tests.");
|
||||||
|
|
||||||
|
test("Sample test", () => {
|
||||||
|
assert.strictEqual(-1, [1, 2, 3].indexOf(5));
|
||||||
|
assert.strictEqual(-1, [1, 2, 3].indexOf(0));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
import * as path from "path";
|
||||||
|
import * as Mocha from "mocha";
|
||||||
|
import * as glob from "glob";
|
||||||
|
|
||||||
|
export function run(): Promise<void> {
|
||||||
|
// Create the mocha test
|
||||||
|
const mocha = new Mocha({
|
||||||
|
ui: "tdd",
|
||||||
|
color: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const testsRoot = path.resolve(__dirname, "..");
|
||||||
|
|
||||||
|
return new Promise((c, e) => {
|
||||||
|
glob("**/**.test.js", { cwd: testsRoot }, (err, files) => {
|
||||||
|
if (err) {
|
||||||
|
return e(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add files to the test suite
|
||||||
|
files.forEach((f) => mocha.addFile(path.resolve(testsRoot, f)));
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Run the mocha test
|
||||||
|
mocha.run((failures) => {
|
||||||
|
if (failures > 0) {
|
||||||
|
e(new Error(`${failures} tests failed.`));
|
||||||
|
} else {
|
||||||
|
c();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
e(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "ES2020",
|
||||||
|
"lib": ["ES2020"],
|
||||||
|
"sourceMap": true,
|
||||||
|
"rootDir": "src",
|
||||||
|
"strict": true /* enable all strict type-checking options */,
|
||||||
|
/* Additional Checks */
|
||||||
|
"noImplicitReturns": true /* Report error when not all code paths in function return a value. */,
|
||||||
|
"noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */,
|
||||||
|
"noUnusedParameters": true /* Report errors on unused parameters. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
//@ts-check
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
//@ts-check
|
||||||
|
/** @typedef {import('webpack').Configuration} WebpackConfig **/
|
||||||
|
|
||||||
|
/** @type WebpackConfig */
|
||||||
|
const extensionConfig = {
|
||||||
|
target: 'node', // VS Code extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/
|
||||||
|
mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production')
|
||||||
|
|
||||||
|
entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/
|
||||||
|
output: {
|
||||||
|
// the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/
|
||||||
|
path: path.resolve(__dirname, 'dist'),
|
||||||
|
filename: 'extension.js',
|
||||||
|
libraryTarget: 'commonjs2'
|
||||||
|
},
|
||||||
|
externals: {
|
||||||
|
vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/
|
||||||
|
// modules added here also need to be added in the .vscodeignore file
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
// support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader
|
||||||
|
extensions: ['.ts', '.js']
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.ts$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'ts-loader'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
devtool: 'nosources-source-map',
|
||||||
|
infrastructureLogging: {
|
||||||
|
level: "log", // enables logging required for problem matchers
|
||||||
|
},
|
||||||
|
};
|
||||||
|
module.exports = [ extensionConfig ];
|
||||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue