Skip to content

Commit f1abc6a

Browse files
committed
support moonbit language
1 parent 586b3e4 commit f1abc6a

File tree

5 files changed

+101
-9
lines changed

5 files changed

+101
-9
lines changed

package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+21-4
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@
33
"displayName": "LeetCode",
44
"description": "Solve LeetCode problems in VS Code",
55
"version": "0.18.4",
6-
"author": "LeetCode",
7-
"publisher": "LeetCode",
6+
"author": "A-23187",
7+
"publisher": "A-23187",
88
"license": "MIT",
99
"icon": "resources/LeetCode.png",
1010
"engines": {
1111
"vscode": "^1.57.0"
1212
},
1313
"repository": {
1414
"type": "git",
15-
"url": "https://github.com/LeetCode-OpenSource/vscode-leetcode"
15+
"url": "https://github.com/A-23187/vscode-leetcode"
1616
},
17-
"homepage": "https://github.com/LeetCode-OpenSource/vscode-leetcode/blob/master/README.md",
17+
"homepage": "https://github.com/A-23187/vscode-leetcode/blob/master/README.md",
1818
"categories": [
1919
"Other",
2020
"Snippets"
@@ -310,6 +310,7 @@
310310
"java",
311311
"javascript",
312312
"kotlin",
313+
"moonbit",
313314
"mysql",
314315
"php",
315316
"python",
@@ -523,6 +524,18 @@
523524
},
524525
"minProperties": 1
525526
},
527+
"moonbit": {
528+
"type": "object",
529+
"properties": {
530+
"folder": {
531+
"type": "string"
532+
},
533+
"filename": {
534+
"type": "string"
535+
}
536+
},
537+
"minProperties": 1
538+
},
526539
"mysql": {
527540
"type": "object",
528541
"properties": {
@@ -636,6 +649,10 @@
636649
"default": {
637650
"folder": "",
638651
"filename": "${id}.${kebab-case-name}.${ext}"
652+
},
653+
"moonbit": {
654+
"folder": "moonbit",
655+
"filename": "${id}/${id}.${ext}"
639656
}
640657
}
641658
},

src/leetCodeExecutor.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { executeCommand, executeCommandWithProgress } from "./utils/cpUtils";
1313
import { DialogOptions, openUrl } from "./utils/uiUtils";
1414
import * as wsl from "./utils/wslUtils";
1515
import { toWslPath, useWsl } from "./utils/wslUtils";
16+
import { genMoonbitCodeTemplateAndWrite, isMoonbitFile, moonbitBuild } from "./utils/moonbitUtils";
1617

1718
class LeetCodeExecutor implements Disposable {
1819
private leetCodeRootPath: string;
@@ -102,7 +103,7 @@ class LeetCodeExecutor implements Disposable {
102103

103104
public async showProblem(problemNode: IProblem, language: string, filePath: string, showDescriptionInComment: boolean = false, needTranslation: boolean): Promise<void> {
104105
const templateType: string = showDescriptionInComment ? "-cx" : "-c";
105-
const cmd: string[] = [await this.getLeetCodeBinaryPath(), "show", problemNode.id, templateType, "-l", language];
106+
const cmd: string[] = [await this.getLeetCodeBinaryPath(), "show", problemNode.id, templateType, "-l", language === "moonbit" ? "javascript" : language];
106107

107108
if (!needTranslation) {
108109
cmd.push("-T"); // use -T to force English version
@@ -111,6 +112,9 @@ class LeetCodeExecutor implements Disposable {
111112
if (!await fse.pathExists(filePath)) {
112113
await fse.createFile(filePath);
113114
const codeTemplate: string = await this.executeCommandWithProgressEx("Fetching problem data...", this.nodeExecutable, cmd);
115+
if (isMoonbitFile(filePath, language)) {
116+
return await genMoonbitCodeTemplateAndWrite(codeTemplate, filePath);
117+
}
114118
await fse.writeFile(filePath, codeTemplate);
115119
}
116120
}
@@ -163,6 +167,9 @@ class LeetCodeExecutor implements Disposable {
163167
}
164168

165169
public async submitSolution(filePath: string): Promise<string> {
170+
if (isMoonbitFile(filePath, null)) {
171+
filePath = await moonbitBuild(filePath);
172+
}
166173
try {
167174
return await this.executeCommandWithProgressEx("Submitting to LeetCode...", this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "submit", `"${filePath}"`]);
168175
} catch (error) {
@@ -174,6 +181,9 @@ class LeetCodeExecutor implements Disposable {
174181
}
175182

176183
public async testSolution(filePath: string, testString?: string): Promise<string> {
184+
if (isMoonbitFile(filePath, null)) {
185+
filePath = await moonbitBuild(filePath);
186+
}
177187
if (testString) {
178188
return await this.executeCommandWithProgressEx("Submitting to LeetCode...", this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "test", `"${filePath}"`, "-t", `${testString}`]);
179189
}

src/shared.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export const languages: string[] = [
2828
"java",
2929
"javascript",
3030
"kotlin",
31+
"moonbit",
3132
"mysql",
3233
"php",
3334
"python",
@@ -48,6 +49,7 @@ export const langExt: Map<string, string> = new Map([
4849
["java", "java"],
4950
["javascript", "js"],
5051
["kotlin", "kt"],
52+
["moonbit", "mbt"],
5153
["mysql", "sql"],
5254
["php", "php"],
5355
["python", "py"],
@@ -133,7 +135,7 @@ export const urls = {
133135
graphql: "https://leetcode.com/graphql",
134136
userGraphql: "https://leetcode.com/graphql",
135137
login: "https://leetcode.com/accounts/login/",
136-
authLoginUrl: `https://leetcode.com/authorize-login/${protocol}/?path=leetcode.vscode-leetcode`,
138+
authLoginUrl: `https://leetcode.com/authorize-login/${protocol}/?path=A-23187.vscode-leetcode`,
137139
};
138140

139141
export const urlsCn = {
@@ -142,7 +144,7 @@ export const urlsCn = {
142144
graphql: "https://leetcode.cn/graphql",
143145
userGraphql: "https://leetcode.cn/graphql/",
144146
login: "https://leetcode.cn/accounts/login/",
145-
authLoginUrl: `https://leetcode.cn/authorize-login/${protocol}/?path=leetcode.vscode-leetcode`,
147+
authLoginUrl: `https://leetcode.cn/authorize-login/${protocol}/?path=A-23187.vscode-leetcode`,
146148
};
147149

148150
export const getUrl = (key: string) => {

src/utils/moonbitUtils.ts

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import * as fse from "fs-extra";
2+
import * as path from "path";
3+
import { WorkspaceConfiguration } from "vscode";
4+
import { executeCommand } from "./cpUtils";
5+
import { getNodeIdFromFile } from "./problemUtils";
6+
import { getWorkspaceConfiguration, getWorkspaceFolder } from "./settingUtils";
7+
import { langExt } from "../shared";
8+
9+
export function getMoonbitFolder(): string {
10+
const leetCodeConfig: WorkspaceConfiguration = getWorkspaceConfiguration();
11+
return path.join(getWorkspaceFolder(),
12+
leetCodeConfig.get<string>("filePath.moonbit.folder", leetCodeConfig.get<string>("filePath.default.folder", "")));
13+
}
14+
15+
export function getMoonbitExt(): string {
16+
return langExt.get("moonbit") || ".mbt";
17+
}
18+
19+
export function isMoonbitFile(filePath: string, language: string | null): boolean {
20+
return filePath.startsWith(getMoonbitFolder()) && filePath.endsWith(`.${getMoonbitExt()}`)
21+
&& (language == null || language === "moonbit");
22+
}
23+
24+
export async function writeMoonbitModuleJson(): Promise<void> {
25+
const modJsonPath: string = path.join(getMoonbitFolder(), "moon.mod.json");
26+
if (await fse.pathExists(modJsonPath)) {
27+
return;
28+
}
29+
await fse.createFile(modJsonPath);
30+
await fse.writeFile(modJsonPath, `{"name":"moonbit-leetcode","source":"."}`);
31+
}
32+
33+
export async function genMoonbitCodeTemplateAndWrite(jsCodeTemplate: string, moonbitFilePath: string): Promise<void> {
34+
const functionReg: RegExp = /^\s*var\s+([^\s]+)\s*=\s*function\s*\((.*)\)/;
35+
let functionName: string = "functionName";
36+
let functionParam: string = "";
37+
const lines: string[] = [];
38+
for (const line of jsCodeTemplate.split("\n")) {
39+
const match: RegExpMatchArray | null = line.match(functionReg);
40+
if (match && match.length === 3) {
41+
functionName = match[1];
42+
functionParam = match[2];
43+
}
44+
if (line && line.indexOf("@lc code=end") < 0) {
45+
lines.push(`// ${line}`);
46+
}
47+
}
48+
// TODO support functionParam with type and return type
49+
lines.push(`pub fn ${functionName}(${functionParam}) -> Unit {\n}\n// @lc code=end\n`);
50+
await writeMoonbitModuleJson();
51+
await fse.writeFile(moonbitFilePath, lines.join("\n"));
52+
await fse.writeFile(path.join(path.dirname(moonbitFilePath), "moon.pkg.json"),
53+
`{"is-main":false,"link":{"js":{"exports":["${functionName}"],"format":"iife"}}}`);
54+
}
55+
56+
export async function moonbitBuild(moonbitFilePath: string): Promise<string> {
57+
const moonbitFolder: string = getMoonbitFolder();
58+
const moonbitExt: string = getMoonbitExt();
59+
await executeCommand("moon", ["build", "--release", "--target", "js", "--directory", moonbitFolder, "--verbose"]);
60+
const jsFilePath: string = path.join(moonbitFolder, "target", "js", "release", "build", `${moonbitFilePath.substring(moonbitFolder.length, moonbitFilePath.length - moonbitExt.length)}js`);
61+
await fse.appendFile(jsFilePath, `// @lc app=leetcode.cn id=${await getNodeIdFromFile(moonbitFilePath)} lang=javascript`);
62+
return jsFilePath;
63+
}

0 commit comments

Comments
 (0)