From 50f12c719b00faa89f0fcd620bf9a954380ce5df Mon Sep 17 00:00:00 2001 From: Luciole <31817566+Luciole0x@users.noreply.github.com> Date: Fri, 18 Aug 2023 00:06:49 +0200 Subject: [PATCH] Port global_chat plugin to typescript (#497) * .js to .ts * translate * update paths to dist/plugin * add "tsc --build" to prepare * use field main in package.json de find info * tsc --build need to append before webpack * update test and use for plugins package.main --- packages/lib/src/plugin_loader.ts | 5 ++- packages/lib/src/shared_commands.ts | 2 +- .../global_chat/{control.js => control.ts} | 14 +++----- plugins/global_chat/info.js | 14 -------- plugins/global_chat/info.ts | 17 +++++++++ .../global_chat/{instance.js => instance.ts} | 36 ++++++++----------- plugins/global_chat/messages.js | 36 ------------------- plugins/global_chat/messages.ts | 23 ++++++++++++ plugins/global_chat/package.json | 8 ++++- plugins/global_chat/test/plugin.js | 6 ++-- plugins/global_chat/tsconfig.json | 16 +++++++++ plugins/global_chat/webpack.config.js | 2 +- plugins/inventory_sync/info.js | 2 +- plugins/inventory_sync/package.json | 1 + plugins/player_auth/info.js | 2 +- plugins/player_auth/package.json | 1 + plugins/player_auth/test/plugin.js | 2 +- plugins/research_sync/info.js | 2 +- plugins/research_sync/package.json | 1 + plugins/statistics_exporter/info.js | 2 +- plugins/statistics_exporter/package.json | 1 + plugins/statistics_exporter/test/plugin.js | 2 +- plugins/subspace_storage/info.js | 2 +- plugins/subspace_storage/package.json | 1 + test/integration/index.js | 2 +- test/lib/plugin_loader.js | 6 ++-- 26 files changed, 104 insertions(+), 102 deletions(-) rename plugins/global_chat/{control.js => control.ts} (65%) delete mode 100644 plugins/global_chat/info.js create mode 100644 plugins/global_chat/info.ts rename plugins/global_chat/{instance.js => instance.ts} (63%) delete mode 100644 plugins/global_chat/messages.js create mode 100644 plugins/global_chat/messages.ts create mode 100644 plugins/global_chat/tsconfig.json diff --git a/packages/lib/src/plugin_loader.ts b/packages/lib/src/plugin_loader.ts index 6c44f897..3122a271 100644 --- a/packages/lib/src/plugin_loader.ts +++ b/packages/lib/src/plugin_loader.ts @@ -24,12 +24,11 @@ export async function loadPluginInfos(pluginList: Map) { let plugins: libPlugin.PluginInfo[] = []; for (let [pluginName, pluginPath] of pluginList) { let pluginInfo: libPlugin.PluginInfo; - let pluginPackage: { version: string }; + let pluginPackage: { version: string, main?: string }; try { - pluginInfo = require(path.posix.join(pluginPath, "info")); + pluginInfo = require(pluginPath).default; pluginPackage = require(path.posix.join(pluginPath, "package.json")); - } catch (err: any) { throw new libErrors.PluginError(pluginName, err); } diff --git a/packages/lib/src/shared_commands.ts b/packages/lib/src/shared_commands.ts index 06fc5f1c..7c959b93 100644 --- a/packages/lib/src/shared_commands.ts +++ b/packages/lib/src/shared_commands.ts @@ -60,7 +60,7 @@ export async function handlePluginCommand( let pluginInfo: { name: string }; try { // eslint-disable-next-line node/global-require - pluginInfo = require(path.posix.join(pluginPath, "info")); + pluginInfo = require(pluginPath).default; } catch (err: any) { logger.error(`Unable to import plugin info from ${args.path}:\n${err.stack}`); process.exitCode = 1; diff --git a/plugins/global_chat/control.js b/plugins/global_chat/control.ts similarity index 65% rename from plugins/global_chat/control.js rename to plugins/global_chat/control.ts index c2ffad66..7213b995 100644 --- a/plugins/global_chat/control.js +++ b/plugins/global_chat/control.ts @@ -1,7 +1,5 @@ -"use strict"; -const { BaseControlPlugin, CommandTree, Command } = require("@clusterio/lib"); -const { ChatEvent } = require("./messages"); - +import { BaseControlPlugin, CommandTree, Command } from "@clusterio/lib"; +import { ChatEvent } from "./messages"; const globalChatCommands = new CommandTree({ name: "global-chat", description: "Global Chat plugin commands", @@ -15,12 +13,8 @@ globalChatCommands.add(new Command({ }, })); -class ControlPlugin extends BaseControlPlugin { - async addCommands(rootCommand) { +export class ControlPlugin extends BaseControlPlugin { + async addCommands(rootCommand: CommandTree) { rootCommand.add(globalChatCommands); } } - -module.exports = { - ControlPlugin, -}; diff --git a/plugins/global_chat/info.js b/plugins/global_chat/info.js deleted file mode 100644 index 875dec62..00000000 --- a/plugins/global_chat/info.js +++ /dev/null @@ -1,14 +0,0 @@ -"use strict"; -const messages = require("./messages"); - -module.exports = { - name: "global_chat", - title: "Global Chat", - description: "Forwards chat between instances.", - instanceEntrypoint: "instance", - controlEntrypoint: "control", - - messages: [ - messages.ChatEvent, - ], -}; diff --git a/plugins/global_chat/info.ts b/plugins/global_chat/info.ts new file mode 100644 index 00000000..d2a16d93 --- /dev/null +++ b/plugins/global_chat/info.ts @@ -0,0 +1,17 @@ +import type { PluginInfo } from "@clusterio/lib"; + +import { ChatEvent } from "./messages"; + +const info: PluginInfo = { + name: "global_chat", + title: "Global Chat", + description: "Forwards chat between instances.", + instanceEntrypoint: "dist/plugin/instance", + controlEntrypoint: "dist/plugin/control", + + messages: [ + ChatEvent, + ], +} + +export default info; diff --git a/plugins/global_chat/instance.js b/plugins/global_chat/instance.ts similarity index 63% rename from plugins/global_chat/instance.js rename to plugins/global_chat/instance.ts index 4eaea8ac..6c605977 100644 --- a/plugins/global_chat/instance.js +++ b/plugins/global_chat/instance.ts @@ -1,28 +1,24 @@ -/** - * @module - */ -"use strict"; -const lib = require("@clusterio/lib"); -const { ChatEvent } = require("./messages"); - +import * as lib from "@clusterio/lib"; +import { ChatEvent } from "./messages"; /** * Removes gps and train tags from messags * - * @param {string} content - string to strip tags from. - * @returns {string} stripped string. + * @param content - string to strip tags from. + * @returns stripped string. */ -function removeTags(content) { +function removeTags(content: string): string { return content.replace(/(\[gps=-?\d+,-?\d+\]|\[train=\d+\])/g, ""); } -class InstancePlugin extends lib.BaseInstancePlugin { +export class InstancePlugin extends lib.BaseInstancePlugin { + messageQueue: string[] = []; + async init() { - this.messageQueue = []; this.instance.handle(ChatEvent, this.handleChatEvent.bind(this)); } - onControllerConnectionEvent(event) { + onControllerConnectionEvent(event: string) { if (event === "connect") { for (let message of this.messageQueue) { this.sendChat(message); @@ -31,17 +27,17 @@ class InstancePlugin extends lib.BaseInstancePlugin { } } - async handleChatEvent(event) { + async handleChatEvent(event: ChatEvent) { // TODO check if cross server chat is enabled let content = `[${event.instanceName}] ${removeTags(event.content)}`; await this.sendRcon(`/sc game.print('${lib.escapeString(content)}')`, true); } - sendChat(message) { + sendChat(message: string) { this.instance.sendTo("allInstances", new ChatEvent(this.instance.name, message)); } - async onOutput(output) { + async onOutput(output: lib.ParsedFactorioOutput) { if (output.type === "action" && output.action === "CHAT") { if (this.host.connector.connected) { this.sendChat(output.message); @@ -54,9 +50,5 @@ class InstancePlugin extends lib.BaseInstancePlugin { // TODO implement info command in lua? } -module.exports = { - InstancePlugin, - - // For testing only - _removeTags: removeTags, -}; +// For testing only +export const _removeTags = removeTags; diff --git a/plugins/global_chat/messages.js b/plugins/global_chat/messages.js deleted file mode 100644 index d233fd98..00000000 --- a/plugins/global_chat/messages.js +++ /dev/null @@ -1,36 +0,0 @@ -"use strict"; - -class ChatEvent { - static type = "event"; - static src = ["control", "instance"]; - static dst = "instance"; - static plugin = "global_chat"; - static permission = null; - - /** @type {string} */ - instanceName; - /** @type {string} */ - content; - - constructor(instanceName, content) { - this.instanceName = instanceName; - this.content = content; - } - - static jsonSchema = { - type: "object", - required: ["instanceName", "content"], - properties: { - instanceName: { type: "string" }, - content: { type: "string" }, - }, - }; - - static fromJSON(json) { - return new this(json.instanceName, json.content); - } -} - -module.exports = { - ChatEvent, -}; diff --git a/plugins/global_chat/messages.ts b/plugins/global_chat/messages.ts new file mode 100644 index 00000000..a7e24e68 --- /dev/null +++ b/plugins/global_chat/messages.ts @@ -0,0 +1,23 @@ +import { Type, Static } from "@sinclair/typebox"; +export class ChatEvent { + static type = "event"; + static src = ["control", "instance"]; + static dst = "instance"; + static plugin = "global_chat"; + static permission = null; + + constructor( + public instanceName: string, + public content: string, + ) { + } + + static jsonSchema = Type.Object({ + "instanceName": Type.String(), + "content": Type.String(), + }); + + static fromJSON(json: Static) { + return new this(json.instanceName, json.content); + } +} diff --git a/plugins/global_chat/package.json b/plugins/global_chat/package.json index 60ecce5f..4a0ac0dd 100644 --- a/plugins/global_chat/package.json +++ b/plugins/global_chat/package.json @@ -6,8 +6,9 @@ "homepage": "https://github.com/clusterio/clusterio#readme", "license": "MIT", "repository": "clusterio/clusterio", + "main": "dist/plugin/info.js", "scripts": { - "prepare": "webpack-cli --env production", + "prepare": "tsc --build && webpack-cli --env production", "test": "echo \"Error: run tests from root\" && exit 1" }, "bugs": { @@ -22,11 +23,16 @@ "devDependencies": { "@clusterio/lib": "^2.0.0-alpha.13", "@clusterio/web_ui": "^2.0.0-alpha.13", + "@types/node": "^20.4.5", + "typescript": "^5.1.6", "webpack": "^5.88.2", "webpack-cli": "^5.1.4", "webpack-merge": "^5.9.0" }, "publishConfig": { "access": "public" + }, + "dependencies": { + "@sinclair/typebox": "^0.30.4" } } diff --git a/plugins/global_chat/test/plugin.js b/plugins/global_chat/test/plugin.js index e0ac9522..0708bbf1 100644 --- a/plugins/global_chat/test/plugin.js +++ b/plugins/global_chat/test/plugin.js @@ -4,9 +4,9 @@ const lib = require("@clusterio/lib"); const mock = require("../../../test/mock"); const lines = require("../../../test/lib/factorio/lines"); -const instance = require("../instance"); -const info = require("../info"); -const { ChatEvent } = require("../messages"); +const instance = require("../dist/plugin/instance"); +const info = require("../dist/plugin/info").default; +const { ChatEvent } = require("../dist/plugin/messages"); describe("global_chat plugin", function() { diff --git a/plugins/global_chat/tsconfig.json b/plugins/global_chat/tsconfig.json new file mode 100644 index 00000000..5408f6b2 --- /dev/null +++ b/plugins/global_chat/tsconfig.json @@ -0,0 +1,16 @@ +{ + "include": ["./**/*.ts"], + "exclude": ["test/*", "./dist/*"], + "compilerOptions": { + "lib": ["es2023"], + "module": "commonjs", + "target": "es2022", + "rootDir": ".", + "outDir": "dist/plugin", + "sourceMap": true, + "strict": true, + "alwaysStrict": true, + "esModuleInterop": true, + "skipLibCheck": true + } +} diff --git a/plugins/global_chat/webpack.config.js b/plugins/global_chat/webpack.config.js index ecba532e..4f084bda 100644 --- a/plugins/global_chat/webpack.config.js +++ b/plugins/global_chat/webpack.config.js @@ -16,7 +16,7 @@ module.exports = (env = {}) => merge(common(env), { name: "global_chat", library: { type: "var", name: "plugin_global_chat" }, exposes: { - "./info": "./info.js", + "./info": "./dist/plugin/info.js", "./package.json": "./package.json", }, shared: { diff --git a/plugins/inventory_sync/info.js b/plugins/inventory_sync/info.js index 30544da5..627b9b41 100644 --- a/plugins/inventory_sync/info.js +++ b/plugins/inventory_sync/info.js @@ -41,7 +41,7 @@ lib.definePermission({ grantByDefault: true, }); -module.exports = { +module.exports.default = { name: "inventory_sync", title: "Inventory sync", description: "Synchronizes players inventories between instances", diff --git a/plugins/inventory_sync/package.json b/plugins/inventory_sync/package.json index ce1a56ea..c47b1cab 100644 --- a/plugins/inventory_sync/package.json +++ b/plugins/inventory_sync/package.json @@ -6,6 +6,7 @@ "homepage": "https://github.com/clusterio/factorioClusterio#readme", "license": "MIT", "repository": "clusterio/factorioClusterio", + "main": "./info.js", "scripts": { "prepare": "webpack-cli --env production", "test": "echo \"Error: run tests from root\" && exit 1" diff --git a/plugins/player_auth/info.js b/plugins/player_auth/info.js index 9de9094c..a04107c1 100644 --- a/plugins/player_auth/info.js +++ b/plugins/player_auth/info.js @@ -22,7 +22,7 @@ ControllerConfigGroup.define({ }); ControllerConfigGroup.finalize(); -module.exports = { +module.exports.default = { name: "player_auth", title: "Player Auth", description: "Provides authentication to the cluster via logging into a Factorio server.", diff --git a/plugins/player_auth/package.json b/plugins/player_auth/package.json index b5a886e8..2e67e6c2 100644 --- a/plugins/player_auth/package.json +++ b/plugins/player_auth/package.json @@ -6,6 +6,7 @@ "homepage": "https://github.com/clusterio/clusterio#readme", "license": "MIT", "repository": "clusterio/clusterio", + "main": "./info.js", "scripts": { "prepare": "webpack-cli --env production", "test": "echo \"Error: run tests from root\" && exit 1" diff --git a/plugins/player_auth/test/plugin.js b/plugins/player_auth/test/plugin.js index d55d12ac..87219c08 100644 --- a/plugins/player_auth/test/plugin.js +++ b/plugins/player_auth/test/plugin.js @@ -7,7 +7,7 @@ const mock = require("../../../test/mock"); const controller = require("../controller"); const instance = require("../instance"); -const info = require("../info"); +const info = require("../info").default; const { FetchPlayerCodeRequest, SetVerifyCodeRequest } = require("../messages"); const lib = require("@clusterio/lib"); diff --git a/plugins/research_sync/info.js b/plugins/research_sync/info.js index c84a2053..b651529b 100644 --- a/plugins/research_sync/info.js +++ b/plugins/research_sync/info.js @@ -1,7 +1,7 @@ "use strict"; const messages = require("./messages"); -module.exports = { +module.exports.default = { name: "research_sync", title: "Research Sync", description: "Synchronises technology research progress between instances.", diff --git a/plugins/research_sync/package.json b/plugins/research_sync/package.json index 80f03da6..43379241 100644 --- a/plugins/research_sync/package.json +++ b/plugins/research_sync/package.json @@ -6,6 +6,7 @@ "homepage": "https://github.com/clusterio/clusterio#readme", "license": "MIT", "repository": "clusterio/clusterio", + "main": "./info.js", "scripts": { "prepare": "webpack-cli --env production", "test": "echo \"Error: run tests from root\" && exit 1" diff --git a/plugins/statistics_exporter/info.js b/plugins/statistics_exporter/info.js index 14f60bee..60a2f6ab 100644 --- a/plugins/statistics_exporter/info.js +++ b/plugins/statistics_exporter/info.js @@ -13,7 +13,7 @@ InstanceConfigGroup.define({ }); InstanceConfigGroup.finalize(); -module.exports = { +module.exports.default = { name: "statistics_exporter", title: "Statistics Exporter", description: diff --git a/plugins/statistics_exporter/package.json b/plugins/statistics_exporter/package.json index f3076d0a..c30ffe1b 100644 --- a/plugins/statistics_exporter/package.json +++ b/plugins/statistics_exporter/package.json @@ -6,6 +6,7 @@ "homepage": "https://github.com/clusterio/clusterio#readme", "license": "MIT", "repository": "clusterio/clusterio", + "main": "./info.js", "scripts": { "prepare": "webpack-cli --env production", "test": "echo \"Error: run tests from root\" && exit 1" diff --git a/plugins/statistics_exporter/test/plugin.js b/plugins/statistics_exporter/test/plugin.js index 56a16b5d..9d9a616c 100644 --- a/plugins/statistics_exporter/test/plugin.js +++ b/plugins/statistics_exporter/test/plugin.js @@ -3,7 +3,7 @@ const assert = require("assert").strict; const mock = require("../../../test/mock"); const instance = require("../instance"); -const info = require("../info"); +const info = require("../info").default; describe("statistics_exporter plugin", function() { diff --git a/plugins/subspace_storage/info.js b/plugins/subspace_storage/info.js index 828ed69a..92876000 100644 --- a/plugins/subspace_storage/info.js +++ b/plugins/subspace_storage/info.js @@ -48,7 +48,7 @@ lib.definePermission({ grantByDefault: true, }); -module.exports = { +module.exports.default = { name: "subspace_storage", title: "Subspace Storage", description: "Provides shared storage across instances for the Subspace Storage mod", diff --git a/plugins/subspace_storage/package.json b/plugins/subspace_storage/package.json index 40748d6a..c4ac748f 100644 --- a/plugins/subspace_storage/package.json +++ b/plugins/subspace_storage/package.json @@ -6,6 +6,7 @@ "homepage": "https://github.com/clusterio/clusterio#readme", "license": "MIT", "repository": "clusterio/clusterio", + "main": "./info.js", "scripts": { "prepare": "webpack-cli --env production", "test": "echo \"Error: run tests from root\" && exit 1" diff --git a/test/integration/index.js b/test/integration/index.js index 61150a2d..2ceb2356 100644 --- a/test/integration/index.js +++ b/test/integration/index.js @@ -12,7 +12,7 @@ const lib = require("@clusterio/lib"); const { LineSplitter, ConsoleTransport, logger } = lib; // Make sure permissions from plugins are loaded -require("../../plugins/global_chat/info"); +require("../../plugins/global_chat/dist/plugin/info"); require("../../plugins/player_auth/info"); require("../../plugins/research_sync/info"); require("../../plugins/statistics_exporter/info"); diff --git a/test/lib/plugin_loader.js b/test/lib/plugin_loader.js index 5632e17d..88e06bea 100644 --- a/test/lib/plugin_loader.js +++ b/test/lib/plugin_loader.js @@ -18,11 +18,11 @@ describe("lib/plugin_loader", function() { async function writePlugin(pluginPath, infoName) { await fs.outputFile( path.join(pluginPath, "info.js"), - `module.exports = { name: "${infoName}" };` + `module.exports.default = { name: "${infoName}" };` ); await fs.outputFile( path.join(pluginPath, "package.json"), - '{ "version": "0.0.1" }' + '{ "version": "0.0.1", "main":"info.js" }' ); } @@ -35,7 +35,7 @@ describe("lib/plugin_loader", function() { it("should throw on missing plugin", async function() { await assert.rejects( lib.loadPluginInfos(new Map([["missing", missingPlugin]]), []), - new RegExp(`^Error: PluginError: Cannot find module '${escapeRegExp(missingPlugin)}/info'`) + new RegExp(`^Error: PluginError: Cannot find module '${escapeRegExp(missingPlugin)}'`) ); }); it("should load test plugin", async function() {