feat: vscode extension for evaluate typescript code blocks

This commit is contained in:
LemonNeko
2025-08-02 03:31:50 +08:00
parent 4e48e1ddff
commit e7bb2a7144
11 changed files with 2753 additions and 57 deletions

18
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,18 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "VSCode Factorio RCON Evaluator",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}/packages/vscode-factorio-rcon-evaluator"
],
"outFiles": [
"${workspaceFolder}/packages/vscode-factorio-rcon-evaluator/dist/**/*.js"
],
"preLaunchTask": "npm: build:extension"
}
]
}

23
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,23 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "build:extension",
"presentation": {
"reveal": "never"
},
"problemMatcher": [
{
"base": "$ts-webpack-watch",
"background": {
"activeOnStart": true,
"beginsPattern": "Build start",
"endsPattern": "Build complete"
}
}
],
"group": "build"
}
]
}

View File

@@ -1,41 +1,55 @@
import antfu from '@antfu/eslint-config'
export default antfu({
rules: {
'ts/naming-convention': 'off',
export default antfu(
// #region naming-convention
{
rules: {
'ts/naming-convention': 'off',
},
yaml: false,
markdown: false,
},
yaml: false,
markdown: false,
}, {
rules: {
'ts/naming-convention': 'error',
{
rules: {
'ts/naming-convention': 'error',
},
files: ['**/*.ts'],
ignores: ['eslint.config.ts'],
},
files: ['**/*.ts'],
ignores: ['eslint.config.ts'],
}, {
rules: {
'ts/naming-convention': [
'error',
{
selector: [
'property',
'parameter',
'variable',
],
format: ['snake_case'],
},
],
// rule conflict with ts/naming-convention when using snake_case
'unused-imports/no-unused-vars': [
'error',
{
argsIgnorePattern: '^unused_',
destructuredArrayIgnorePattern: '^unused_',
},
{
rules: {
'ts/naming-convention': [
'error',
{
selector: [
'property',
'parameter',
'variable',
],
format: ['snake_case'],
},
],
// rule conflict with ts/naming-convention when using snake_case
'unused-imports/no-unused-vars': [
'error',
{
argsIgnorePattern: '^unused_',
destructuredArrayIgnorePattern: '^unused_',
},
],
},
files: [
'packages/autorio/**/*.ts',
'packages/tstl-plugin-reload-factorio-mod/example/*.ts',
],
},
files: [
'packages/autorio/**/*.ts',
'packages/tstl-plugin-reload-factorio-mod/example/*.ts',
],
})
// #endregion
// #region no-console
{
rules: {
'no-console': 'off',
},
files: ['packages/vscode-factorio-rcon-evaluator/**/*.ts'],
},
// #endregion
)

View File

@@ -20,6 +20,8 @@
"dev": "pnpm dev:packages",
"build:packages": "pnpm -r --filter=./packages/* run build",
"dev:packages": "pnpm -r --filter=./packages/* run dev",
"dev:extension": "pnpm -r --filter=./packages/vscode-factorio-rcon-evaluator run dev",
"build:extension": "pnpm -r --filter=./packages/vscode-factorio-rcon-evaluator run build",
"lint": "eslint --cache .",
"lint:fix": "eslint --cache --fix .",
"typecheck": "pnpm -r --filter=./packages/* run typecheck",
@@ -34,11 +36,14 @@
"lint-staged": "^16.1.2",
"simple-git-hooks": "^2.13.0",
"taze": "^19.1.0",
"typed-factorio": "^3.26.0",
"typescript": "~5.8.3"
},
"pnpm": {
"onlyBuiltDependencies": [
"@vscode/vsce-sign",
"esbuild",
"keytar",
"simple-git-hooks",
"unrs-resolver"
]

View File

@@ -2,7 +2,6 @@
"name": "@proj-airi/factorio-wrapper",
"type": "module",
"version": "0.1.0",
"packageManager": "pnpm@10.13.1",
"description": "Run factorio server and convert std stream to websocket stream",
"author": "LemonNekoGH",
"license": "MIT",

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024-PRESENT LemonNeko
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,7 @@
# vscode-factorio-rcon-evaluator
## TODO-List
- [ ] One-click evaluation of the current code block
- [ ] Read configurations
- [ ] Better error handling: https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API#a-minimal-compiler

View File

@@ -0,0 +1,86 @@
{
"publisher": "LemonNeko",
"name": "vscode-factorio-rcon-evaluator",
"displayName": "Factorio RCON Evaluator",
"type": "module",
"version": "0.1.0",
"description": "Evaluate factorio lua script via rcon protocol in VSCode",
"author": "LemonNekoGH",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/moeru-ai/airi-factorio",
"directory": "packages/vscode-factorio-rcon-evaluator"
},
"keywords": [
"factorio",
"rcon",
"vscode",
"lua",
"typescript"
],
"preview": true,
"categories": [
"Other"
],
"main": "./dist/index.js",
"files": [
"LICENSE",
"README.md",
"dist",
"package.json"
],
"engines": {
"vscode": "^1.100.0"
},
"activationEvents": [
"onStartupFinished"
],
"contributes": {
"commands": [
{
"command": "factorio-rcon-evaluator.run",
"title": "Evaluate Selected Code"
}
],
"configuration": {
"type": "object",
"properties": {
"rconHost": {
"type": "string",
"default": "localhost",
"description": "The hostname of the Factorio server."
},
"rconPort": {
"type": "number",
"default": 27015,
"description": "The RCON port of the Factorio server."
},
"rconPassword": {
"type": "string",
"default": "",
"description": "The RCON password for the Factorio server."
}
}
}
},
"scripts": {
"build": "tsdown src/index.ts --external vscode",
"dev": "nr build --watch src",
"publish": "nr build && vsce publish --no-dependencies",
"package": "nr build && vsce package --no-dependencies",
"test": "vitest"
},
"dependencies": {
"lua-types": "^2.13.1",
"rcon-client": "^4.2.5",
"typed-factorio": "^3.26.0",
"typescript-to-lua": "^1.31.3"
},
"devDependencies": {
"@types/vscode": "^1.100.0",
"@vscode/vsce": "^3.6.0",
"tsdown": "^0.13.0",
"typescript": "^5.8.3"
}
}

View File

@@ -0,0 +1,89 @@
import type { ExtensionContext, OutputChannel } from 'vscode'
import { Rcon } from 'rcon-client'
import { BuildMode, LuaLibImportKind, LuaTarget, transpileString } from 'typescript-to-lua'
import { commands, window, workspace } from 'vscode'
async function evaluate(channel: OutputChannel) {
const editor = window.activeTextEditor
if (!editor) {
window.showErrorMessage('No active text editor found.')
return
}
const selectedText = editor.document.getText(editor.selection)
if (!selectedText) {
window.showErrorMessage('No text` selected in the editor.')
return
}
const transpileResult = transpileString(
selectedText.trim(),
{
luaTarget: LuaTarget.LuaJIT,
luaLibImport: LuaLibImportKind.Inline,
buildMode: BuildMode.Default,
noCheck: true,
noHeader: true,
noImplicitSelf: true,
},
)
if (transpileResult.diagnostics.length > 0) {
transpileResult.diagnostics.forEach((diagnostic) => {
if (typeof diagnostic.messageText === 'string') {
channel.appendLine(`Error: ${diagnostic.messageText} at ${diagnostic.start}`)
}
else {
channel.appendLine(`Error: ${diagnostic.messageText.messageText} at ${diagnostic.start}`)
}
})
const errMsgResult = await window.showErrorMessage(`Transpilation failed, check the output channel for details.`, 'Open Output Channel')
if (errMsgResult === 'Open Output Channel') {
channel.show()
}
return
}
if (!transpileResult.file || !transpileResult.file.lua) {
window.showErrorMessage('Transpilation did not produce valid Lua code.')
return
}
// send to Factorio RCON
try {
const config = workspace.getConfiguration('factorio-rcon-evaluator')
const host = config.get<string>('rconHost', 'localhost')
const port = config.get<number>('rconPort', 27105)
const password = config.get<string>('rconPassword', '123456')
channel.appendLine(`Connecting to RCON at ${host}:${port} with password ${password ? '***' : 'not set'}`)
const rcon = await Rcon.connect({
host,
port,
password,
})
const response = await rcon.send(`/sc ${transpileResult.file.lua}`)
channel.appendLine(`RCON Response: ${response}`)
channel.show()
await rcon.end()
}
catch (error) {
channel.appendLine(`Error send to RCON: ${error instanceof Error ? error.message : String(error)}`)
window.showErrorMessage(`Failed to send to RCON: ${error instanceof Error ? error.message : String(error)}`)
}
}
export async function activate(ctx: ExtensionContext) {
const channel = window.createOutputChannel('Factorio RCON Evaluator')
channel.appendLine('Congratulations, your extension "vscode-factorio-rcon-evaluator" is now active!')
const disposable = commands.registerCommand('factorio-rcon-evaluator.test', () => evaluate(channel))
ctx.subscriptions.push(disposable)
}
export function deactivate() {}

View File

@@ -0,0 +1,26 @@
{
"compilerOptions": {
"target": "ESNext",
"lib": [
"ESNext"
],
"moduleDetection": "auto",
"module": "ESNext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"strict": true,
"strictNullChecks": true,
"noImplicitAny": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"outDir": "./dist",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"verbatimModuleSyntax": true,
"skipLibCheck": true
},
"include": [
"src/**/*.ts"
]
}

2450
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff