feat(agent): add experimental postprocess limit scope by syntax. (#758)
* feat(agent): add tree-sitter parser. * feat(agent): make parser updating tree cache optional. * feat(agent): add experimental limit scopy by syntax. * test(agent): update unit test for limitScopeBySyntax.extract-routes
parent
d7180ec7b9
commit
568b7b41a5
|
|
@ -18,6 +18,8 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
lfs: true
|
||||||
- name: Setup JDK
|
- name: Setup JDK
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
lfs: true
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,8 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
lfs: true
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
*.wasm filter=lfs diff=lfs merge=lfs -text
|
||||||
|
|
@ -23,11 +23,11 @@
|
||||||
"@types/node": "^18.12.0",
|
"@types/node": "^18.12.0",
|
||||||
"chai": "^4.3.7",
|
"chai": "^4.3.7",
|
||||||
"dedent": "^0.7.0",
|
"dedent": "^0.7.0",
|
||||||
|
"esbuild-plugin-copy": "^2.1.1",
|
||||||
"esbuild-plugin-polyfill-node": "^0.3.0",
|
"esbuild-plugin-polyfill-node": "^0.3.0",
|
||||||
"mocha": "^10.2.0",
|
"mocha": "^10.2.0",
|
||||||
"openapi-typescript": "^6.6.1",
|
"openapi-typescript": "^6.6.1",
|
||||||
"prettier": "^3.0.0",
|
"prettier": "^3.0.0",
|
||||||
"rimraf": "^5.0.1",
|
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"tsup": "^7.1.0",
|
"tsup": "^7.1.0",
|
||||||
"typescript": "^5.0.3"
|
"typescript": "^5.0.3"
|
||||||
|
|
@ -47,6 +47,7 @@
|
||||||
"rotating-file-stream": "^3.1.0",
|
"rotating-file-stream": "^3.1.0",
|
||||||
"stats-logscale": "^1.0.7",
|
"stats-logscale": "^1.0.7",
|
||||||
"toml": "^3.0.0",
|
"toml": "^3.0.0",
|
||||||
"uuid": "^9.0.0"
|
"uuid": "^9.0.0",
|
||||||
|
"web-tree-sitter": "^0.20.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,15 @@ export type AgentConfig = {
|
||||||
timeout: number;
|
timeout: number;
|
||||||
};
|
};
|
||||||
postprocess: {
|
postprocess: {
|
||||||
limitScopeByIndentation: {
|
limitScope: {
|
||||||
// When completion is continuing the current line, limit the scope to:
|
// Prefer to use syntax parser than indentation
|
||||||
// false(default): the line scope, meaning use the next indent level as the limit.
|
experimentalSyntax: boolean;
|
||||||
// true: the block scope, meaning use the current indent level as the limit.
|
indentation: {
|
||||||
experimentalKeepBlockScopeWhenCompletingLine: boolean;
|
// When completion is continuing the current line, limit the scope to:
|
||||||
|
// false(default): the line scope, meaning use the next indent level as the limit.
|
||||||
|
// true: the block scope, meaning use the current indent level as the limit.
|
||||||
|
experimentalKeepBlockScopeWhenCompletingLine: boolean;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
logs: {
|
logs: {
|
||||||
|
|
@ -66,8 +70,11 @@ export const defaultAgentConfig: AgentConfig = {
|
||||||
timeout: 4000, // ms
|
timeout: 4000, // ms
|
||||||
},
|
},
|
||||||
postprocess: {
|
postprocess: {
|
||||||
limitScopeByIndentation: {
|
limitScope: {
|
||||||
experimentalKeepBlockScopeWhenCompletingLine: false,
|
experimentalSyntax: false,
|
||||||
|
indentation: {
|
||||||
|
experimentalKeepBlockScopeWhenCompletingLine: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
logs: {
|
logs: {
|
||||||
|
|
|
||||||
|
|
@ -529,7 +529,7 @@ export class TabbyAgent extends EventEmitter implements Agent {
|
||||||
throw options.signal.reason;
|
throw options.signal.reason;
|
||||||
}
|
}
|
||||||
// Build cache
|
// Build cache
|
||||||
this.completionCache.buildCache(context, completionResponse);
|
this.completionCache.buildCache(context, JSON.parse(JSON.stringify(completionResponse)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Postprocess (post-cache)
|
// Postprocess (post-cache)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { applyFilter } from "./base";
|
||||||
import { removeRepetitiveBlocks } from "./removeRepetitiveBlocks";
|
import { removeRepetitiveBlocks } from "./removeRepetitiveBlocks";
|
||||||
import { removeRepetitiveLines } from "./removeRepetitiveLines";
|
import { removeRepetitiveLines } from "./removeRepetitiveLines";
|
||||||
import { removeLineEndsWithRepetition } from "./removeLineEndsWithRepetition";
|
import { removeLineEndsWithRepetition } from "./removeLineEndsWithRepetition";
|
||||||
import { limitScopeByIndentation } from "./limitScopeByIndentation";
|
import { limitScope } from "./limitScope";
|
||||||
import { trimSpace } from "./trimSpace";
|
import { trimSpace } from "./trimSpace";
|
||||||
import { dropDuplicated } from "./dropDuplicated";
|
import { dropDuplicated } from "./dropDuplicated";
|
||||||
import { dropBlank } from "./dropBlank";
|
import { dropBlank } from "./dropBlank";
|
||||||
|
|
@ -30,7 +30,7 @@ export async function postCacheProcess(
|
||||||
return Promise.resolve(response)
|
return Promise.resolve(response)
|
||||||
.then(applyFilter(removeRepetitiveBlocks(context), context))
|
.then(applyFilter(removeRepetitiveBlocks(context), context))
|
||||||
.then(applyFilter(removeRepetitiveLines(context), context))
|
.then(applyFilter(removeRepetitiveLines(context), context))
|
||||||
.then(applyFilter(limitScopeByIndentation(context, config["limitScopeByIndentation"]), context))
|
.then(applyFilter(limitScope(context, config["limitScope"]), context))
|
||||||
.then(applyFilter(dropDuplicated(context), context))
|
.then(applyFilter(dropDuplicated(context), context))
|
||||||
.then(applyFilter(trimSpace(context), context))
|
.then(applyFilter(trimSpace(context), context))
|
||||||
.then(applyFilter(dropBlank(), context));
|
.then(applyFilter(dropBlank(), context));
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { CompletionContext } from "../Agent";
|
||||||
|
import { AgentConfig } from "../AgentConfig";
|
||||||
|
import { isBrowser } from "../env";
|
||||||
|
import { PostprocessFilter } from "./base";
|
||||||
|
import { limitScopeByIndentation } from "./limitScopeByIndentation";
|
||||||
|
import { limitScopeBySyntax, supportedLanguages } from "./limitScopeBySyntax";
|
||||||
|
|
||||||
|
export function limitScope(
|
||||||
|
context: CompletionContext,
|
||||||
|
config: AgentConfig["postprocess"]["limitScope"],
|
||||||
|
): PostprocessFilter {
|
||||||
|
return isBrowser
|
||||||
|
? (input) => {
|
||||||
|
// syntax parser is not supported in browser yet
|
||||||
|
return limitScopeByIndentation(context, config["indentation"])(input);
|
||||||
|
}
|
||||||
|
: (input) => {
|
||||||
|
if (config.experimentalSyntax && supportedLanguages.indexOf(context.language) >= 0) {
|
||||||
|
return limitScopeBySyntax(context)(input);
|
||||||
|
} else {
|
||||||
|
return limitScopeByIndentation(context, config["indentation"])(input);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -18,7 +18,7 @@ function processContext(
|
||||||
lines: string[],
|
lines: string[],
|
||||||
prefixLines: string[],
|
prefixLines: string[],
|
||||||
suffixLines: string[],
|
suffixLines: string[],
|
||||||
config: AgentConfig["postprocess"]["limitScopeByIndentation"],
|
config: AgentConfig["postprocess"]["limitScope"]["indentation"],
|
||||||
): { indentLevelLimit: number; allowClosingLine: (closingLine: string) => boolean } {
|
): { indentLevelLimit: number; allowClosingLine: (closingLine: string) => boolean } {
|
||||||
let allowClosingLine = false;
|
let allowClosingLine = false;
|
||||||
let result = { indentLevelLimit: 0, allowClosingLine: (closingLine: string) => allowClosingLine };
|
let result = { indentLevelLimit: 0, allowClosingLine: (closingLine: string) => allowClosingLine };
|
||||||
|
|
@ -103,14 +103,14 @@ function processContext(
|
||||||
|
|
||||||
export function limitScopeByIndentation(
|
export function limitScopeByIndentation(
|
||||||
context: CompletionContext,
|
context: CompletionContext,
|
||||||
config: AgentConfig["postprocess"]["limitScopeByIndentation"],
|
config: AgentConfig["postprocess"]["limitScope"]["indentation"],
|
||||||
): PostprocessFilter {
|
): PostprocessFilter {
|
||||||
return (input) => {
|
return (input) => {
|
||||||
const { prefix, suffix, prefixLines, suffixLines } = context;
|
const { prefixLines, suffixLines } = context;
|
||||||
const inputLines = splitLines(input);
|
const inputLines = splitLines(input);
|
||||||
if (context.mode === "fill-in-line") {
|
if (context.mode === "fill-in-line") {
|
||||||
if (inputLines.length > 1) {
|
if (inputLines.length > 1) {
|
||||||
logger.debug({ input, prefix, suffix }, "Drop content with multiple lines");
|
logger.debug({ inputLines, prefixLines, suffixLines }, "Drop content with multiple lines");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -139,7 +139,10 @@ export function limitScopeByIndentation(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (index < inputLines.length) {
|
if (index < inputLines.length) {
|
||||||
logger.debug({ input, prefix, suffix, scopeEndAt: index }, "Remove content out of scope");
|
logger.debug(
|
||||||
|
{ inputLines, prefixLines, suffixLines, scopeLineCount: index },
|
||||||
|
"Remove content out of indent scope",
|
||||||
|
);
|
||||||
return inputLines.slice(0, index).join("").trimEnd();
|
return inputLines.slice(0, index).join("").trimEnd();
|
||||||
}
|
}
|
||||||
return input;
|
return input;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,409 @@
|
||||||
|
import { expect } from "chai";
|
||||||
|
import { documentContext, inline } from "./testUtils";
|
||||||
|
import { limitScopeBySyntax } from "./limitScopeBySyntax";
|
||||||
|
|
||||||
|
describe("postprocess", () => {
|
||||||
|
describe("limitScopeBySyntax javascript", () => {
|
||||||
|
it("should limit scope at function_declaration.", async () => {
|
||||||
|
const context = {
|
||||||
|
...documentContext`
|
||||||
|
function findMax(arr) {║}
|
||||||
|
`,
|
||||||
|
language: "javascript",
|
||||||
|
};
|
||||||
|
const completion = inline`
|
||||||
|
├
|
||||||
|
let max = arr[0];
|
||||||
|
for (let i = 1; i < arr.length; i++) {
|
||||||
|
if (arr[i] > max) {
|
||||||
|
max = arr[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
console.log(findMax([1, 2, 3, 4, 5]));┤
|
||||||
|
`;
|
||||||
|
const expected = inline`
|
||||||
|
├
|
||||||
|
let max = arr[0];
|
||||||
|
for (let i = 1; i < arr.length; i++) {
|
||||||
|
if (arr[i] > max) {
|
||||||
|
max = arr[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max;
|
||||||
|
}┤
|
||||||
|
`;
|
||||||
|
expect(await limitScopeBySyntax(context)(completion)).to.eq(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should limit scope at function_declaration", async () => {
|
||||||
|
const context = {
|
||||||
|
...documentContext`
|
||||||
|
function findMax(arr) {
|
||||||
|
let max = arr[0];║
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
language: "javascript",
|
||||||
|
};
|
||||||
|
const completion = inline`
|
||||||
|
├
|
||||||
|
for (let i = 1; i < arr.length; i++) {
|
||||||
|
if (arr[i] > max) {
|
||||||
|
max = arr[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max;
|
||||||
|
}┤
|
||||||
|
`;
|
||||||
|
expect(await limitScopeBySyntax(context)(completion)).to.eq(completion);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should limit scope at function_declaration", async () => {
|
||||||
|
const context = {
|
||||||
|
...documentContext`
|
||||||
|
function findMax(arr) {
|
||||||
|
let max = arr[0];
|
||||||
|
for (let i = 1; i < arr.length; i++) {
|
||||||
|
if (arr[i] > max) {
|
||||||
|
max = arr[i];
|
||||||
|
}
|
||||||
|
}║
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
language: "javascript",
|
||||||
|
};
|
||||||
|
const completion = inline`
|
||||||
|
├
|
||||||
|
return max;
|
||||||
|
}┤
|
||||||
|
`;
|
||||||
|
expect(await limitScopeBySyntax(context)(completion)).to.eq(completion);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should limit scope at for_statement.", async () => {
|
||||||
|
const context = {
|
||||||
|
...documentContext`
|
||||||
|
function findMax(arr) {
|
||||||
|
let max = arr[0];
|
||||||
|
for║
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
language: "javascript",
|
||||||
|
};
|
||||||
|
const completion = inline`
|
||||||
|
├ (let i = 1; i < arr.length; i++) {
|
||||||
|
if (arr[i] > max) {
|
||||||
|
max = arr[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
console.log(findMax([1, 2, 3, 4, 5]));┤
|
||||||
|
`;
|
||||||
|
const expected = inline`
|
||||||
|
├ (let i = 1; i < arr.length; i++) {
|
||||||
|
if (arr[i] > max) {
|
||||||
|
max = arr[i];
|
||||||
|
}
|
||||||
|
}┤
|
||||||
|
┴┴
|
||||||
|
`;
|
||||||
|
expect(await limitScopeBySyntax(context)(completion)).to.eq(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should limit scope at current node if no parent scope found.", async () => {
|
||||||
|
const context = {
|
||||||
|
...documentContext`
|
||||||
|
let a =║
|
||||||
|
`,
|
||||||
|
language: "javascript",
|
||||||
|
};
|
||||||
|
const completion = inline`
|
||||||
|
├ 1;
|
||||||
|
let b = 2;┤
|
||||||
|
`;
|
||||||
|
const expected = inline`
|
||||||
|
├ 1;┤
|
||||||
|
`;
|
||||||
|
expect(await limitScopeBySyntax(context)(completion)).to.eq(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle the bad case of limitScopeByIndentation", async () => {
|
||||||
|
const context = {
|
||||||
|
...documentContext`
|
||||||
|
function sortWords(input) {
|
||||||
|
const output = input.trim()
|
||||||
|
.split("\n")
|
||||||
|
.map((line) => line.split(" "))
|
||||||
|
║
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
language: "javascript",
|
||||||
|
};
|
||||||
|
const completion = inline`
|
||||||
|
├.flat()
|
||||||
|
.sort()
|
||||||
|
.join(" ");
|
||||||
|
console.log(output);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
sortWord("world hello");┤
|
||||||
|
`;
|
||||||
|
const expected = inline`
|
||||||
|
├.flat()
|
||||||
|
.sort()
|
||||||
|
.join(" ");
|
||||||
|
console.log(output);
|
||||||
|
return output;
|
||||||
|
};┤
|
||||||
|
`;
|
||||||
|
expect(await limitScopeBySyntax(context)(completion)).not.to.eq(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("limitScopeBySyntax python", () => {
|
||||||
|
it("should limit scope at function_definition.", async () => {
|
||||||
|
const context = {
|
||||||
|
...documentContext`
|
||||||
|
def find_min(arr):║
|
||||||
|
`,
|
||||||
|
language: "python",
|
||||||
|
};
|
||||||
|
const completion = inline`
|
||||||
|
├
|
||||||
|
min = arr[0]
|
||||||
|
for i in range(1, len(arr)):
|
||||||
|
if arr[i] < min:
|
||||||
|
min = arr[i]
|
||||||
|
return min
|
||||||
|
print(find_min([1, 2, 3, 4, 5]))┤
|
||||||
|
`;
|
||||||
|
const expected = inline`
|
||||||
|
├
|
||||||
|
min = arr[0]
|
||||||
|
for i in range(1, len(arr)):
|
||||||
|
if arr[i] < min:
|
||||||
|
min = arr[i]
|
||||||
|
return min┤
|
||||||
|
┴┴
|
||||||
|
`;
|
||||||
|
expect(await limitScopeBySyntax(context)(completion)).to.eq(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should limit scope at function_definition.", async () => {
|
||||||
|
const context = {
|
||||||
|
...documentContext`
|
||||||
|
def find_min(arr):
|
||||||
|
min = arr[0]║
|
||||||
|
`,
|
||||||
|
language: "python",
|
||||||
|
};
|
||||||
|
const completion = inline`
|
||||||
|
├
|
||||||
|
for i in range(1, len(arr)):
|
||||||
|
if arr[i] < min:
|
||||||
|
min = arr[i]
|
||||||
|
return min
|
||||||
|
print(find_min([1, 2, 3, 4, 5]))┤
|
||||||
|
`;
|
||||||
|
const expected = inline`
|
||||||
|
├
|
||||||
|
for i in range(1, len(arr)):
|
||||||
|
if arr[i] < min:
|
||||||
|
min = arr[i]
|
||||||
|
return min┤
|
||||||
|
┴┴
|
||||||
|
`;
|
||||||
|
expect(await limitScopeBySyntax(context)(completion)).to.eq(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should limit scope at function_definition.", async () => {
|
||||||
|
const context = {
|
||||||
|
...documentContext`
|
||||||
|
def find_min(arr):
|
||||||
|
min = arr[0]
|
||||||
|
for i in range(1, len(arr)):
|
||||||
|
if arr[i] < min:
|
||||||
|
min = arr[i]║
|
||||||
|
`,
|
||||||
|
language: "python",
|
||||||
|
};
|
||||||
|
const completion = inline`
|
||||||
|
├
|
||||||
|
return min┤
|
||||||
|
`;
|
||||||
|
expect(await limitScopeBySyntax(context)(completion)).to.eq(completion);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should limit scope at for_statement.", async () => {
|
||||||
|
const context = {
|
||||||
|
...documentContext`
|
||||||
|
def find_min(arr):
|
||||||
|
max = arr[0]
|
||||||
|
for║
|
||||||
|
`,
|
||||||
|
language: "python",
|
||||||
|
};
|
||||||
|
const completion = inline`
|
||||||
|
├ i in range(1, len(arr)):
|
||||||
|
if arr[i] < min:
|
||||||
|
min = arr[i]
|
||||||
|
return min
|
||||||
|
┤
|
||||||
|
`;
|
||||||
|
const expected = inline`
|
||||||
|
├ i in range(1, len(arr)):
|
||||||
|
if arr[i] < min:
|
||||||
|
min = arr[i]┤
|
||||||
|
┴┴┴┴
|
||||||
|
`;
|
||||||
|
expect(await limitScopeBySyntax(context)(completion)).to.eq(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle the bad case of limitScopeByIndentation", async () => {
|
||||||
|
const context = {
|
||||||
|
...documentContext`
|
||||||
|
def findMax(arr):
|
||||||
|
║
|
||||||
|
`,
|
||||||
|
language: "python",
|
||||||
|
};
|
||||||
|
const completion = inline`
|
||||||
|
├max = arr[0]
|
||||||
|
for i in range(1, len(arr)):
|
||||||
|
if arr[i] > max:
|
||||||
|
max = arr[i]
|
||||||
|
return max
|
||||||
|
findMax([1, 2, 3, 4, 5])┤
|
||||||
|
`;
|
||||||
|
const expected = inline`
|
||||||
|
├max = arr[0]
|
||||||
|
for i in range(1, len(arr)):
|
||||||
|
if arr[i] > max:
|
||||||
|
max = arr[i]
|
||||||
|
return max┤
|
||||||
|
`;
|
||||||
|
expect(await limitScopeBySyntax(context)(completion)).not.to.eq(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("limitScopeBySyntax go", () => {
|
||||||
|
it("should limit scope at function_declaration.", async () => {
|
||||||
|
const context = {
|
||||||
|
...documentContext`
|
||||||
|
func findMin(arr []int) int {║}
|
||||||
|
`,
|
||||||
|
language: "go",
|
||||||
|
};
|
||||||
|
const completion = inline`
|
||||||
|
├
|
||||||
|
min := math.MaxInt64
|
||||||
|
for _, v := range arr {
|
||||||
|
if v < min {
|
||||||
|
min = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return min
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
arr := []int{5, 2, 9, 8, 1, 3}
|
||||||
|
fmt.Println(findMin(arr)) // Output: 1
|
||||||
|
}┤
|
||||||
|
`;
|
||||||
|
const expected = inline`
|
||||||
|
├
|
||||||
|
min := math.MaxInt64
|
||||||
|
for _, v := range arr {
|
||||||
|
if v < min {
|
||||||
|
min = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return min
|
||||||
|
}┤
|
||||||
|
`;
|
||||||
|
expect(await limitScopeBySyntax(context)(completion)).to.eq(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should limit scope at for_statement.", async () => {
|
||||||
|
const context = {
|
||||||
|
...documentContext`
|
||||||
|
func findMin(arr []int) int {
|
||||||
|
min := math.MaxInt64
|
||||||
|
for║
|
||||||
|
`,
|
||||||
|
language: "go",
|
||||||
|
};
|
||||||
|
const completion = inline`
|
||||||
|
├ _, v := range arr {
|
||||||
|
if v < min {
|
||||||
|
min = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return min
|
||||||
|
}┤
|
||||||
|
`;
|
||||||
|
const expected = inline`
|
||||||
|
├ _, v := range arr {
|
||||||
|
if v < min {
|
||||||
|
min = v
|
||||||
|
}
|
||||||
|
}┤
|
||||||
|
┴┴
|
||||||
|
`;
|
||||||
|
expect(await limitScopeBySyntax(context)(completion)).to.eq(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("limitScopeBySyntax rust", () => {
|
||||||
|
it("should limit scope at function_item.", async () => {
|
||||||
|
const context = {
|
||||||
|
...documentContext`
|
||||||
|
fn find_min(arr: &[i32]) -> i32 {║}
|
||||||
|
`,
|
||||||
|
language: "rust",
|
||||||
|
};
|
||||||
|
const completion = inline`
|
||||||
|
├
|
||||||
|
*arr.iter().min().unwrap()
|
||||||
|
}
|
||||||
|
fn main() {
|
||||||
|
let arr = vec![5, 2, 9, 8, 1, 3];
|
||||||
|
println!("{}", find_min(&arr)); // Output: 1
|
||||||
|
}┤
|
||||||
|
`;
|
||||||
|
const expected = inline`
|
||||||
|
├
|
||||||
|
*arr.iter().min().unwrap()
|
||||||
|
}┤
|
||||||
|
`;
|
||||||
|
expect(await limitScopeBySyntax(context)(completion)).to.eq(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("limitScopeBySyntax ruby", () => {
|
||||||
|
it("should limit scope at for.", async () => {
|
||||||
|
const context = {
|
||||||
|
...documentContext`
|
||||||
|
def fibonacci(n)║
|
||||||
|
`,
|
||||||
|
language: "ruby",
|
||||||
|
};
|
||||||
|
const completion = inline`
|
||||||
|
├
|
||||||
|
return n if n <= 1
|
||||||
|
fibonacci(n - 1) + fibonacci(n - 2)
|
||||||
|
end
|
||||||
|
puts fibonacci(10)┤
|
||||||
|
`;
|
||||||
|
const expected = inline`
|
||||||
|
├
|
||||||
|
return n if n <= 1
|
||||||
|
fibonacci(n - 1) + fibonacci(n - 2)
|
||||||
|
end┤
|
||||||
|
`;
|
||||||
|
expect(await limitScopeBySyntax(context)(completion)).to.eq(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
import type TreeSitterParser from "web-tree-sitter";
|
||||||
|
import { getParser, languagesConfigs } from "../syntax/parser";
|
||||||
|
import { typeList } from "../syntax/typeList";
|
||||||
|
import { CompletionContext } from "../Agent";
|
||||||
|
import { PostprocessFilter, logger } from "./base";
|
||||||
|
|
||||||
|
export const supportedLanguages = Object.keys(languagesConfigs);
|
||||||
|
|
||||||
|
function findLineBegin(text: string, position: number): number {
|
||||||
|
let lastNonBlankCharPos = position - 1;
|
||||||
|
while (lastNonBlankCharPos >= 0 && text[lastNonBlankCharPos].match(/\s/)) {
|
||||||
|
lastNonBlankCharPos--;
|
||||||
|
}
|
||||||
|
if (lastNonBlankCharPos < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const lineBegin = text.lastIndexOf("\n", lastNonBlankCharPos);
|
||||||
|
if (lineBegin < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const line = text.slice(lineBegin + 1, position);
|
||||||
|
const indentation = line.search(/\S/);
|
||||||
|
return lineBegin + 1 + indentation;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findLineEnd(text: string, position: number): number {
|
||||||
|
let firstNonBlankCharPos = position;
|
||||||
|
while (firstNonBlankCharPos < text.length && text[firstNonBlankCharPos].match(/\s/)) {
|
||||||
|
firstNonBlankCharPos++;
|
||||||
|
}
|
||||||
|
if (firstNonBlankCharPos >= text.length) {
|
||||||
|
return text.length;
|
||||||
|
}
|
||||||
|
const lineEnd = text.indexOf("\n", firstNonBlankCharPos);
|
||||||
|
if (lineEnd < 0) {
|
||||||
|
return text.length;
|
||||||
|
}
|
||||||
|
return lineEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findScope(node: TreeSitterParser.SyntaxNode, typeList: string[][]): TreeSitterParser.SyntaxNode {
|
||||||
|
for (const types of typeList) {
|
||||||
|
let scope = node;
|
||||||
|
while (scope) {
|
||||||
|
if (types.indexOf(scope.type) >= 0) {
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
|
scope = scope.parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function limitScopeBySyntax(context: CompletionContext): PostprocessFilter {
|
||||||
|
return async (input) => {
|
||||||
|
const { position, text, language, prefix, suffix } = context;
|
||||||
|
if (supportedLanguages.indexOf(language) < 0) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
const languageConfig = languagesConfigs[language];
|
||||||
|
const parser = await getParser(languageConfig);
|
||||||
|
|
||||||
|
const updatedText = prefix + input + suffix;
|
||||||
|
const updatedTree = parser.parse(updatedText);
|
||||||
|
const lineBegin = findLineBegin(updatedText, position);
|
||||||
|
const lineEnd = findLineEnd(updatedText, position);
|
||||||
|
const scope = findScope(updatedTree.rootNode.namedDescendantForIndex(lineBegin, lineEnd), typeList[languageConfig]);
|
||||||
|
|
||||||
|
if (scope.endIndex < position + input.length) {
|
||||||
|
logger.debug(
|
||||||
|
{
|
||||||
|
languageConfig,
|
||||||
|
text,
|
||||||
|
updatedText,
|
||||||
|
position,
|
||||||
|
lineBegin,
|
||||||
|
lineEnd,
|
||||||
|
scope: { type: scope.type, start: scope.startIndex, end: scope.endIndex },
|
||||||
|
},
|
||||||
|
"Remove content out of syntax scope",
|
||||||
|
);
|
||||||
|
return input.slice(0, scope.endIndex - position);
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
import dedent from "dedent";
|
import dedent from "dedent";
|
||||||
|
import { v4 as uuid } from "uuid";
|
||||||
import { CompletionContext } from "../CompletionContext";
|
import { CompletionContext } from "../CompletionContext";
|
||||||
|
|
||||||
// `║` is the cursor position
|
// `║` is the cursor position
|
||||||
export function documentContext(strings): CompletionContext {
|
export function documentContext(strings): CompletionContext {
|
||||||
const doc = dedent(strings);
|
const doc = dedent(strings);
|
||||||
return new CompletionContext({
|
return new CompletionContext({
|
||||||
filepath: null,
|
filepath: uuid(),
|
||||||
language: null,
|
language: "",
|
||||||
text: doc.replace(/║/, ""),
|
text: doc.replace(/║/, ""),
|
||||||
position: doc.indexOf("║"),
|
position: doc.indexOf("║"),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
import TreeSitterParser from "web-tree-sitter";
|
||||||
|
import { isTest } from "../env";
|
||||||
|
|
||||||
|
// https://code.visualstudio.com/docs/languages/identifiers
|
||||||
|
export const languagesConfigs: Record<string, string> = {
|
||||||
|
javascript: "tsx",
|
||||||
|
typescript: "tsx",
|
||||||
|
javascriptreact: "tsx",
|
||||||
|
typescriptreact: "tsx",
|
||||||
|
python: "python",
|
||||||
|
go: "go",
|
||||||
|
rust: "rust",
|
||||||
|
ruby: "ruby",
|
||||||
|
};
|
||||||
|
|
||||||
|
var treeSitterInitialized = false;
|
||||||
|
|
||||||
|
async function createParser(languageConfig: string): Promise<TreeSitterParser> {
|
||||||
|
if (!treeSitterInitialized) {
|
||||||
|
await TreeSitterParser.init({
|
||||||
|
locateFile(scriptName: string, scriptDirectory: string) {
|
||||||
|
const paths = isTest ? [scriptDirectory, scriptName] : [scriptDirectory, "wasm", scriptName];
|
||||||
|
return require("path").join(...paths);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
treeSitterInitialized = true;
|
||||||
|
}
|
||||||
|
const parser = new TreeSitterParser();
|
||||||
|
const langWasmPaths = isTest
|
||||||
|
? [process.cwd(), "wasm", `tree-sitter-${languageConfig}.wasm`]
|
||||||
|
: [__dirname, "wasm", `tree-sitter-${languageConfig}.wasm`];
|
||||||
|
parser.setLanguage(await TreeSitterParser.Language.load(require("path").join(...langWasmPaths)));
|
||||||
|
return parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsers = new Map<string, TreeSitterParser>();
|
||||||
|
|
||||||
|
export async function getParser(languageConfig: string): Promise<TreeSitterParser> {
|
||||||
|
let parser = parsers.get(languageConfig);
|
||||||
|
if (!parser) {
|
||||||
|
parser = await createParser(languageConfig);
|
||||||
|
parsers.set(languageConfig, parser);
|
||||||
|
}
|
||||||
|
return parser;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
// https://github.com/tree-sitter/tree-sitter-typescript/blob/master/src/node-types.json
|
||||||
|
export const typeList = {
|
||||||
|
tsx: [
|
||||||
|
[
|
||||||
|
"jsx_element",
|
||||||
|
"jsx_self_closing_element",
|
||||||
|
|
||||||
|
// exclude sentence level nodes for now
|
||||||
|
// "expression_statement",
|
||||||
|
// "lexical_declaration",
|
||||||
|
|
||||||
|
"for_statement",
|
||||||
|
"for_in_statement",
|
||||||
|
"if_statement",
|
||||||
|
"while_statement",
|
||||||
|
"do_statement",
|
||||||
|
"switch_statement",
|
||||||
|
"try_statement",
|
||||||
|
"with_statement",
|
||||||
|
"labeled_statement",
|
||||||
|
|
||||||
|
"class_declaration",
|
||||||
|
"abstract_class_declaration",
|
||||||
|
"interface_declaration",
|
||||||
|
"enum_declaration",
|
||||||
|
"type_alias_declaration",
|
||||||
|
"function_declaration",
|
||||||
|
"generator_function_declaration",
|
||||||
|
"ambient_declaration",
|
||||||
|
|
||||||
|
"method_definition",
|
||||||
|
|
||||||
|
"import_statement",
|
||||||
|
"export_statement",
|
||||||
|
"module",
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
// https://github.com/tree-sitter/tree-sitter-python/blob/master/src/node-types.json
|
||||||
|
python: [
|
||||||
|
[
|
||||||
|
"for_statement",
|
||||||
|
"if_statement",
|
||||||
|
"while_statement",
|
||||||
|
"match_statement",
|
||||||
|
"try_statement",
|
||||||
|
"with_statement",
|
||||||
|
|
||||||
|
"function_definition",
|
||||||
|
"decorated_definition",
|
||||||
|
"class_definition",
|
||||||
|
|
||||||
|
"import_statement",
|
||||||
|
"import_from_statement",
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
// https://github.com/tree-sitter/tree-sitter-go/blob/master/src/node-types.json
|
||||||
|
go: [
|
||||||
|
[
|
||||||
|
"for_statement",
|
||||||
|
"if_statement",
|
||||||
|
"expression_switch_statement",
|
||||||
|
"type_switch_statement",
|
||||||
|
"select_statement",
|
||||||
|
"labeled_statement",
|
||||||
|
|
||||||
|
"function_declaration",
|
||||||
|
"method_declaration",
|
||||||
|
"type_declaration",
|
||||||
|
|
||||||
|
"import_declaration",
|
||||||
|
"package_clause",
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
// https://github.com/tree-sitter/tree-sitter-rust/blob/master/src/node-types.json
|
||||||
|
rust: [
|
||||||
|
[
|
||||||
|
"for_expression",
|
||||||
|
"if_expression",
|
||||||
|
"while_expression",
|
||||||
|
"loop_expression",
|
||||||
|
"match_expression",
|
||||||
|
"try_expression",
|
||||||
|
|
||||||
|
"function_item",
|
||||||
|
"type_item",
|
||||||
|
"enum_item",
|
||||||
|
"struct_item",
|
||||||
|
"union_item",
|
||||||
|
"trait_item",
|
||||||
|
"impl_item",
|
||||||
|
|
||||||
|
"use_declaration",
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
// https://github.com/tree-sitter/tree-sitter-ruby/blob/master/src/node-types.json
|
||||||
|
ruby: [
|
||||||
|
[
|
||||||
|
"for",
|
||||||
|
"if",
|
||||||
|
"unless",
|
||||||
|
"while",
|
||||||
|
"until",
|
||||||
|
"case",
|
||||||
|
|
||||||
|
"class",
|
||||||
|
"singleton_class",
|
||||||
|
"method",
|
||||||
|
"singleton_method",
|
||||||
|
"module",
|
||||||
|
],
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
@ -81,7 +81,10 @@ describe("agent golden test", () => {
|
||||||
timeout: 4000,
|
timeout: 4000,
|
||||||
},
|
},
|
||||||
postprocess: {
|
postprocess: {
|
||||||
limitScopeByIndentation: { experimentalKeepBlockScopeWhenCompletingLine: false },
|
limitScope: {
|
||||||
|
experimentalSyntax: false,
|
||||||
|
indentation: { experimentalKeepBlockScopeWhenCompletingLine: false },
|
||||||
|
},
|
||||||
},
|
},
|
||||||
logs: { level: "debug" },
|
logs: { level: "debug" },
|
||||||
anonymousUsageTracking: { disable: true },
|
anonymousUsageTracking: { disable: true },
|
||||||
|
|
@ -111,7 +114,7 @@ describe("agent golden test", () => {
|
||||||
absolutePath: path.join(__dirname, "golden", file),
|
absolutePath: path.join(__dirname, "golden", file),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
goldenFiles.forEach((goldenFile, index) => {
|
goldenFiles.forEach((goldenFile) => {
|
||||||
it(goldenFile.path, async () => {
|
it(goldenFile.path, async () => {
|
||||||
const test = await createGoldenTest(goldenFile.absolutePath);
|
const test = await createGoldenTest(goldenFile.absolutePath);
|
||||||
requestId++;
|
requestId++;
|
||||||
|
|
@ -130,7 +133,7 @@ describe("agent golden test", () => {
|
||||||
absolutePath: path.join(__dirname, "bad_cases", file),
|
absolutePath: path.join(__dirname, "bad_cases", file),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
badCasesFiles.forEach((goldenFile, index) => {
|
badCasesFiles.forEach((goldenFile) => {
|
||||||
it(goldenFile.path, async () => {
|
it(goldenFile.path, async () => {
|
||||||
const test = await createGoldenTest(goldenFile.absolutePath);
|
const test = await createGoldenTest(goldenFile.absolutePath);
|
||||||
requestId++;
|
requestId++;
|
||||||
|
|
@ -143,6 +146,35 @@ describe("agent golden test", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("updateConfig experimental", async () => {
|
||||||
|
requestId++;
|
||||||
|
const updateConfigRequest = [
|
||||||
|
requestId,
|
||||||
|
{
|
||||||
|
func: "updateConfig",
|
||||||
|
args: ["postprocess.limitScope.experimentalSyntax", true],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
agent.stdin.write(JSON.stringify(updateConfigRequest) + "\n");
|
||||||
|
await waitForResponse(requestId);
|
||||||
|
const expectedConfig = { ...config };
|
||||||
|
expectedConfig.postprocess.limitScope.experimentalSyntax = true;
|
||||||
|
expect(output.shift()).to.deep.equal([0, { event: "configUpdated", config: expectedConfig }]);
|
||||||
|
expect(output.shift()).to.deep.equal([requestId, true]);
|
||||||
|
});
|
||||||
|
badCasesFiles.forEach((goldenFile) => {
|
||||||
|
it("experimental: " + goldenFile.path, async () => {
|
||||||
|
const test = await createGoldenTest(goldenFile.absolutePath);
|
||||||
|
requestId++;
|
||||||
|
const request = [requestId, { func: "provideCompletions", args: [test.request] }];
|
||||||
|
agent.stdin.write(JSON.stringify(request) + "\n");
|
||||||
|
await waitForResponse(requestId);
|
||||||
|
const response = output.shift();
|
||||||
|
expect(response[0]).to.equal(requestId);
|
||||||
|
expect(response[1].choices).to.deep.equal(test.expected.choices);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
after(() => {
|
after(() => {
|
||||||
agent.kill();
|
agent.kill();
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { defineConfig } from "tsup";
|
import { defineConfig } from "tsup";
|
||||||
|
import { copy } from "esbuild-plugin-copy";
|
||||||
import { polyfillNode } from "esbuild-plugin-polyfill-node";
|
import { polyfillNode } from "esbuild-plugin-polyfill-node";
|
||||||
import { dependencies } from "./package.json";
|
import { dependencies } from "./package.json";
|
||||||
|
|
||||||
|
|
@ -16,6 +17,7 @@ export default async () => [
|
||||||
name: "node-cjs",
|
name: "node-cjs",
|
||||||
entry: ["src/index.ts"],
|
entry: ["src/index.ts"],
|
||||||
platform: "node",
|
platform: "node",
|
||||||
|
target: "node18",
|
||||||
format: ["cjs"],
|
format: ["cjs"],
|
||||||
sourcemap: true,
|
sourcemap: true,
|
||||||
esbuildOptions(options) {
|
esbuildOptions(options) {
|
||||||
|
|
@ -71,10 +73,21 @@ export default async () => [
|
||||||
name: "cli",
|
name: "cli",
|
||||||
entry: ["src/cli.ts"],
|
entry: ["src/cli.ts"],
|
||||||
platform: "node",
|
platform: "node",
|
||||||
|
target: "node18",
|
||||||
noExternal: Object.keys(dependencies),
|
noExternal: Object.keys(dependencies),
|
||||||
treeshake: "smallest",
|
treeshake: "smallest",
|
||||||
minify: true,
|
minify: true,
|
||||||
sourcemap: true,
|
sourcemap: true,
|
||||||
|
esbuildPlugins: [
|
||||||
|
copy({
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
from: "./wasm/*",
|
||||||
|
to: "./wasm",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
esbuildOptions(options) {
|
esbuildOptions(options) {
|
||||||
defineEnvs(options, { browser: false });
|
defineEnvs(options, { browser: false });
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:1b69c5af834fd23053238e484c7fe9ed2f121d5b1fe32242af78576d67e49f1e
|
||||||
|
size 240169
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:72d0f97ba6c3134d7873ec5c9d0fd3c1f5137f4eac4dda0709993d92809e62b6
|
||||||
|
size 474189
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:1190cddd839b78c2aec737573399a71c23fe9a546d3543f86304c4c68ca73852
|
||||||
|
size 990787
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:273f9ce6f2c595ad4e63b3195513b61974ae1ec513efcce39da1afa90574ef38
|
||||||
|
size 844087
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:060422a330f9c819a10e7310788d336dbcb53cc6a4be0e91d40f644564080f97
|
||||||
|
size 1182114
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:17382e1a69bd628107e8dfe37d31d57f7ba948e5f2da77e56a8aa010488dc5ae
|
||||||
|
size 186526
|
||||||
|
|
@ -208,6 +208,7 @@
|
||||||
"@vscode/test-web": "^0.0.44",
|
"@vscode/test-web": "^0.0.44",
|
||||||
"@vscode/vsce": "^2.15.0",
|
"@vscode/vsce": "^2.15.0",
|
||||||
"assert": "^2.0.0",
|
"assert": "^2.0.0",
|
||||||
|
"esbuild-plugin-copy": "^2.1.1",
|
||||||
"esbuild-plugin-polyfill-node": "^0.3.0",
|
"esbuild-plugin-polyfill-node": "^0.3.0",
|
||||||
"eslint": "^8.20.0",
|
"eslint": "^8.20.0",
|
||||||
"glob": "^8.0.3",
|
"glob": "^8.0.3",
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { defineConfig } from "tsup";
|
import { defineConfig } from "tsup";
|
||||||
|
import { copy } from "esbuild-plugin-copy";
|
||||||
import { polyfillNode } from "esbuild-plugin-polyfill-node";
|
import { polyfillNode } from "esbuild-plugin-polyfill-node";
|
||||||
import { dependencies } from "./package.json";
|
import { dependencies } from "./package.json";
|
||||||
|
|
||||||
|
|
@ -8,8 +9,19 @@ export default () => [
|
||||||
entry: ["src/extension.ts"],
|
entry: ["src/extension.ts"],
|
||||||
outDir: "dist/node",
|
outDir: "dist/node",
|
||||||
platform: "node",
|
platform: "node",
|
||||||
|
target: "node18",
|
||||||
external: ["vscode"],
|
external: ["vscode"],
|
||||||
noExternal: Object.keys(dependencies),
|
noExternal: Object.keys(dependencies),
|
||||||
|
esbuildPlugins: [
|
||||||
|
copy({
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
from: "../tabby-agent/dist/wasm/*.wasm",
|
||||||
|
to: "./wasm",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
clean: true,
|
clean: true,
|
||||||
}),
|
}),
|
||||||
defineConfig({
|
defineConfig({
|
||||||
|
|
|
||||||
26
yarn.lock
26
yarn.lock
|
|
@ -900,7 +900,7 @@ chalk@^2.4.2:
|
||||||
escape-string-regexp "^1.0.5"
|
escape-string-regexp "^1.0.5"
|
||||||
supports-color "^5.3.0"
|
supports-color "^5.3.0"
|
||||||
|
|
||||||
chalk@^4.0.0, chalk@^4.1.0:
|
chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2:
|
||||||
version "4.1.2"
|
version "4.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
|
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
|
||||||
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
|
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
|
||||||
|
|
@ -1390,6 +1390,16 @@ es-get-iterator@^1.1.3:
|
||||||
isarray "^2.0.5"
|
isarray "^2.0.5"
|
||||||
stop-iteration-iterator "^1.0.0"
|
stop-iteration-iterator "^1.0.0"
|
||||||
|
|
||||||
|
esbuild-plugin-copy@^2.1.1:
|
||||||
|
version "2.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/esbuild-plugin-copy/-/esbuild-plugin-copy-2.1.1.tgz#638308ecfd679e4c7c76b71c62f7dd9a4cc7f901"
|
||||||
|
integrity sha512-Bk66jpevTcV8KMFzZI1P7MZKZ+uDcrZm2G2egZ2jNIvVnivDpodZI+/KnpL3Jnap0PBdIHU7HwFGB8r+vV5CVw==
|
||||||
|
dependencies:
|
||||||
|
chalk "^4.1.2"
|
||||||
|
chokidar "^3.5.3"
|
||||||
|
fs-extra "^10.0.1"
|
||||||
|
globby "^11.0.3"
|
||||||
|
|
||||||
esbuild-plugin-polyfill-node@^0.3.0:
|
esbuild-plugin-polyfill-node@^0.3.0:
|
||||||
version "0.3.0"
|
version "0.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/esbuild-plugin-polyfill-node/-/esbuild-plugin-polyfill-node-0.3.0.tgz#e7e3804b8272df51ae4f8ebfb7445a03712504cb"
|
resolved "https://registry.yarnpkg.com/esbuild-plugin-polyfill-node/-/esbuild-plugin-polyfill-node-0.3.0.tgz#e7e3804b8272df51ae4f8ebfb7445a03712504cb"
|
||||||
|
|
@ -1706,6 +1716,15 @@ fs-constants@^1.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
|
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
|
||||||
integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
|
integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
|
||||||
|
|
||||||
|
fs-extra@^10.0.1:
|
||||||
|
version "10.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf"
|
||||||
|
integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==
|
||||||
|
dependencies:
|
||||||
|
graceful-fs "^4.2.0"
|
||||||
|
jsonfile "^6.0.1"
|
||||||
|
universalify "^2.0.0"
|
||||||
|
|
||||||
fs-extra@^11.1.1:
|
fs-extra@^11.1.1:
|
||||||
version "11.1.1"
|
version "11.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.1.1.tgz#da69f7c39f3b002378b0954bb6ae7efdc0876e2d"
|
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.1.1.tgz#da69f7c39f3b002378b0954bb6ae7efdc0876e2d"
|
||||||
|
|
@ -4117,6 +4136,11 @@ vscode-uri@^3.0.7:
|
||||||
resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.7.tgz#6d19fef387ee6b46c479e5fb00870e15e58c1eb8"
|
resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.0.7.tgz#6d19fef387ee6b46c479e5fb00870e15e58c1eb8"
|
||||||
integrity sha512-eOpPHogvorZRobNqJGhapa0JdwaxpjVvyBp0QIUMRMSf8ZAlqOdEquKuRmw9Qwu0qXtJIWqFtMkmvJjUZmMjVA==
|
integrity sha512-eOpPHogvorZRobNqJGhapa0JdwaxpjVvyBp0QIUMRMSf8ZAlqOdEquKuRmw9Qwu0qXtJIWqFtMkmvJjUZmMjVA==
|
||||||
|
|
||||||
|
web-tree-sitter@^0.20.8:
|
||||||
|
version "0.20.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/web-tree-sitter/-/web-tree-sitter-0.20.8.tgz#1e371cb577584789cadd75cb49c7ddfbc99d04c8"
|
||||||
|
integrity sha512-weOVgZ3aAARgdnb220GqYuh7+rZU0Ka9k9yfKtGAzEYMa6GgiCzW9JjQRJyCJakvibQW+dfjJdihjInKuuCAUQ==
|
||||||
|
|
||||||
webidl-conversions@^4.0.2:
|
webidl-conversions@^4.0.2:
|
||||||
version "4.0.2"
|
version "4.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
|
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue