From c81d2b61a6ff0276da8b94762a893a49f73d8988 Mon Sep 17 00:00:00 2001 From: Cooldude2606 <25043174+Cooldude2606@users.noreply.github.com> Date: Mon, 22 Jan 2024 02:47:34 +0000 Subject: [PATCH] Add template copying --- .vscode/settings.json | 3 + packages/create/create.js | 94 ++++++++++++++++++- .../create/templates/plugin-ts/.gitignore | 2 + .../create/templates/plugin-ts/.npmignore | 2 + .../create/templates/plugin-ts/controller.ts | 0 packages/create/templates/plugin-ts/ctl.ts | 0 packages/create/templates/plugin-ts/host.ts | 0 packages/create/templates/plugin-ts/index.ts | 27 ++++++ .../create/templates/plugin-ts/instance.ts | 0 .../create/templates/plugin-ts/messages.ts | 55 +++++++++++ .../templates/plugin-ts/module/control.lua | 0 .../templates/plugin-ts/module/module.json | 12 +++ .../plugin-ts/module/module_exports.lua | 3 + .../create/templates/plugin-ts/package.json | 31 ++++++ .../create/templates/plugin-ts/tsconfig.json | 11 +++ .../templates/plugin-ts/tsconfig.web.json | 11 +++ .../templates/plugin-ts/web/no_plugin.tsx | 0 .../create/templates/plugin-ts/web/plugin.tsx | 0 .../templates/plugin-ts/webpack.config.js | 28 ++++++ 19 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 packages/create/templates/plugin-ts/.gitignore create mode 100644 packages/create/templates/plugin-ts/.npmignore create mode 100644 packages/create/templates/plugin-ts/controller.ts create mode 100644 packages/create/templates/plugin-ts/ctl.ts create mode 100644 packages/create/templates/plugin-ts/host.ts create mode 100644 packages/create/templates/plugin-ts/index.ts create mode 100644 packages/create/templates/plugin-ts/instance.ts create mode 100644 packages/create/templates/plugin-ts/messages.ts create mode 100644 packages/create/templates/plugin-ts/module/control.lua create mode 100644 packages/create/templates/plugin-ts/module/module.json create mode 100644 packages/create/templates/plugin-ts/module/module_exports.lua create mode 100644 packages/create/templates/plugin-ts/package.json create mode 100644 packages/create/templates/plugin-ts/tsconfig.json create mode 100644 packages/create/templates/plugin-ts/tsconfig.web.json create mode 100644 packages/create/templates/plugin-ts/web/no_plugin.tsx create mode 100644 packages/create/templates/plugin-ts/web/plugin.tsx create mode 100644 packages/create/templates/plugin-ts/webpack.config.js diff --git a/.vscode/settings.json b/.vscode/settings.json index 64e9720d..e800d22c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,4 +8,7 @@ "editor.indentSize": 4, "editor.insertSpaces": true, }, + "cSpell.words": [ + "npmignore" + ], } diff --git a/packages/create/create.js b/packages/create/create.js index 668a8179..9fb960ba 100755 --- a/packages/create/create.js +++ b/packages/create/create.js @@ -501,8 +501,99 @@ WantedBy=multi-user.target } } +async function copyPluginTemplateFile(src, dst, props) { + logger.verbose(`Writing ${dst} from template ${src}`); + if (await fs.exists(dst)) { + logger.warn(`Could not create file ${dst} because it already exists`); + return; + } + + const templateData = await fs.readFile(src, "utf8"); + const outputData = templateData.replace(/\/\/ ([a-z_]*) \/\//g, (_, value) => { + if (!props.hasOwnProperty(value)) { + logger.warn(`Unknown property string (${value}) found in template file ${src}`); + return value; + } + + return props[value]; + }); + + await fs.outputFile(dst, outputData); +} + async function copyPluginTemplate(templates) { - logger.info(`Please wait, coping template for ${templates.join(", ")}`); + logger.info(`Please wait, coping templates for ${templates.join(", ")}`); + const noTypescript = templates.includes("js"); + const entryPoints = []; + const files = new Map(); + + let templatePath = "./templates/plugin-ts"; + if (noTypescript) { + templatePath = "./templates/plugin-js"; + logger.error("Javascript only is not currently supported"); + return; + } + + templatePath = path.resolve(__dirname, templatePath); + + // Files includes in all templates (package.json has its own logic) + files.set(".gitignore", path.join(templatePath, ".gitignore")); + files.set(".npmignore", path.join(templatePath, ".npmignore")); + files.set("tsconfig.json", path.join(templatePath, "tsconfig.json")); + files.set("messages.ts", path.join(templatePath, "messages.ts")); + files.set("index.ts", path.join(templatePath, "index.ts")); + + if (templates.includes("controller")) { + entryPoints.push("webEntrypoint: \"./web\","); + entryPoints.push("controllerEntrypoint: \"dist/plugin/controller\","); + files.set("controller.ts", path.join(templatePath, "controller.ts")); + files.set("webpack.config.js", path.join(templatePath, "webpack.config.js")); + files.set("tsconfig.web.json", path.join(templatePath, "tsconfig.web.json")); + files.set("web/index.tsx", path.join(templatePath, + templates.includes("web") ? "web/plugin.tsx" : "web/no_plugin.tsx" + )); + } else if (templates.includes("web")) { + entryPoints.push("webEntrypoint: \"./web\","); + files.set("web/index.tsx", path.join(templatePath, "web/plugin.tsx")); + files.set("webpack.config.js", path.join(templatePath, "webpack.config.js")); + files.set("tsconfig.web.json", path.join(templatePath, "tsconfig.web.json")); + } + + if (templates.includes("host")) { + entryPoints.push("hostEntrypoint: \"dist/plugin/host\","); + files.set("host.ts", path.join(templatePath, "host.ts")); + } + + if (templates.includes("instance")) { + entryPoints.push("instanceEntrypoint: \"dist/plugin/instance\","); + files.set("instance.ts", path.join(templatePath, "instance.ts")); + } + + if (templates.includes("module")) { + files.set("module/module.json", path.join(templatePath, "module/module.json")); + files.set("module/control.lua", path.join(templatePath, "module/control.lua")); + files.set("module/module_exports.lua", path.join(templatePath, "module/module_exports.lua")); + } + + if (templates.includes("ctl")) { + files.set("ctl.ts", path.join(templatePath, "ctl.ts")); + } + + // Props that will be replaced in the template files, found with "// prop_name //" + const props = { + plugin_name: "TBC", + entry_points: entryPoints.join("\n\t"), + }; + + const writes = []; + for (let [dst, src] of files) { + writes.push(copyPluginTemplateFile(src, dst, props)); + } + + // TODO package.json + + await Promise.all(writes); + logger.info("Successfully wrote all template files"); } // eslint-disable-next-line complexity @@ -667,6 +758,7 @@ async function inquirerMissingArgs(args) { { name: "Lua Module", value: "module" }, { name: "Command Line", value: "ctl" }, { name: "Web UI", value: "web" }, + { name: "No Typescript", value: "js" }, ], }, ], answers); diff --git a/packages/create/templates/plugin-ts/.gitignore b/packages/create/templates/plugin-ts/.gitignore new file mode 100644 index 00000000..1eae0cf6 --- /dev/null +++ b/packages/create/templates/plugin-ts/.gitignore @@ -0,0 +1,2 @@ +dist/ +node_modules/ diff --git a/packages/create/templates/plugin-ts/.npmignore b/packages/create/templates/plugin-ts/.npmignore new file mode 100644 index 00000000..ebd99907 --- /dev/null +++ b/packages/create/templates/plugin-ts/.npmignore @@ -0,0 +1,2 @@ +webpack.config.js +dist/web/build diff --git a/packages/create/templates/plugin-ts/controller.ts b/packages/create/templates/plugin-ts/controller.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/create/templates/plugin-ts/ctl.ts b/packages/create/templates/plugin-ts/ctl.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/create/templates/plugin-ts/host.ts b/packages/create/templates/plugin-ts/host.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/create/templates/plugin-ts/index.ts b/packages/create/templates/plugin-ts/index.ts new file mode 100644 index 00000000..2ecceb6a --- /dev/null +++ b/packages/create/templates/plugin-ts/index.ts @@ -0,0 +1,27 @@ +import * as lib from "@clusterio/lib"; + +import { PluginExampleEvent, PluginExampleRequest } from "./messages"; + +lib.definePermission({ + name: "// plugin_name //.example.permission.event", + title: "Example permission event", + description: "My plugin's example permission that I forgot to remove", +}); + +lib.definePermission({ + name: "// plugin_name //.example.permission.request", + title: "Example permission request", + description: "My plugin's example permission that I forgot to remove", +}); + +export const plugin: lib.PluginDeclaration = { + name: "// plugin_name //", + title: "// plugin_name //", + description: "I didn't update my description", + // entry_points // + + messages: [ + PluginExampleEvent, + PluginExampleRequest, + ], +}; diff --git a/packages/create/templates/plugin-ts/instance.ts b/packages/create/templates/plugin-ts/instance.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/create/templates/plugin-ts/messages.ts b/packages/create/templates/plugin-ts/messages.ts new file mode 100644 index 00000000..f207d6a1 --- /dev/null +++ b/packages/create/templates/plugin-ts/messages.ts @@ -0,0 +1,55 @@ +import { plainJson, jsonArray, JsonBoolean, JsonNumber, JsonString, StringEnum } from "@clusterio/lib"; +import { Type, Static } from "@sinclair/typebox"; + +export class PluginExampleEvent { + declare ["constructor"]: typeof PluginExampleEvent; + static type = "event" as const; + static src = ["host"] as const; + static dst = "controller" as const; + static plugin = "// plugin_name //" as const; + static permission = "// plugin_name //.example.permission.event"; + + constructor( + public myString: string, + public myNumberArray: number[], + ) { + } + + static jsonSchema = Type.Object({ + "myString": Type.String(), + "myNumberArray": Type.Array(Type.Number()), + }); + + static fromJson(json: Static) { + return new PluginExampleEvent(json.myString, json.myNumberArray); + } +} + +export class PluginExampleRequest { + declare ["constructor"]: typeof PluginExampleEvent; + static type = "request" as const; + static src = ["host"] as const; + static dst = "controller" as const; + static plugin = "// plugin_name //" as const; + static permission = "// plugin_name //.example.permission.request"; + + constructor( + public myString: string, + public myNumberArray: number[], + ) { + } + + static jsonSchema = Type.Object({ + "myString": Type.String(), + "myNumberArray": Type.Array(Type.Number()), + }); + + static fromJson(json: Static) { + return new PluginExampleEvent(json.myString, json.myNumberArray); + } + + static Response = plainJson(Type.Object({ + "myResponseString": Type.String(), + "myResponseNumbers": Type.Array(Type.Number()), + })); +} diff --git a/packages/create/templates/plugin-ts/module/control.lua b/packages/create/templates/plugin-ts/module/control.lua new file mode 100644 index 00000000..e69de29b diff --git a/packages/create/templates/plugin-ts/module/module.json b/packages/create/templates/plugin-ts/module/module.json new file mode 100644 index 00000000..1edcac37 --- /dev/null +++ b/packages/create/templates/plugin-ts/module/module.json @@ -0,0 +1,12 @@ +{ + "name": "// plugin_name //", + "load": [ + "control.lua" + ], + "require": [ + + ], + "dependencies": [ + + ] +} diff --git a/packages/create/templates/plugin-ts/module/module_exports.lua b/packages/create/templates/plugin-ts/module/module_exports.lua new file mode 100644 index 00000000..29cbb493 --- /dev/null +++ b/packages/create/templates/plugin-ts/module/module_exports.lua @@ -0,0 +1,3 @@ +local Control = require("./control") + +return Control diff --git a/packages/create/templates/plugin-ts/package.json b/packages/create/templates/plugin-ts/package.json new file mode 100644 index 00000000..45b71e49 --- /dev/null +++ b/packages/create/templates/plugin-ts/package.json @@ -0,0 +1,31 @@ +{ + "name": "__plugin_name__", + "version": "0.1.0", + "description": "", + "main": "dist/plugin/index.js", + "scripts": { + "prepare": "tsc --build && webpack-cli --env production" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@clusterio/lib": "^2.0.0-alpha.0" + }, + "devDependencies": { + "@clusterio/lib": "^2.0.0-alpha.14", + "@clusterio/web_ui": "^2.0.0-alpha.14", + "@types/node": "^20.4.5", + "@types/react": "^18.2.21", + "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/packages/create/templates/plugin-ts/tsconfig.json b/packages/create/templates/plugin-ts/tsconfig.json new file mode 100644 index 00000000..087576d6 --- /dev/null +++ b/packages/create/templates/plugin-ts/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.node.json", + "references": [ + { "path": "../../packages/lib" }, + ], + "include": ["./**/*.ts"], + "exclude": ["test/*", "./dist/*"], + "compilerOptions": { + "outDir": "dist/plugin", + }, +} diff --git a/packages/create/templates/plugin-ts/tsconfig.web.json b/packages/create/templates/plugin-ts/tsconfig.web.json new file mode 100644 index 00000000..c37f9141 --- /dev/null +++ b/packages/create/templates/plugin-ts/tsconfig.web.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.web.json", + "references": [ + { "path": "../../packages/lib/tsconfig.web.json" }, + { "path": "../../packages/web_ui/tsconfig.web.json" }, + ], + "include": [ "web/**/*.tsx", "web/**/*.ts", "messages.ts", "package.json" ], + "compilerOptions": { + "outDir": "dist/web/build", + } +} diff --git a/packages/create/templates/plugin-ts/web/no_plugin.tsx b/packages/create/templates/plugin-ts/web/no_plugin.tsx new file mode 100644 index 00000000..e69de29b diff --git a/packages/create/templates/plugin-ts/web/plugin.tsx b/packages/create/templates/plugin-ts/web/plugin.tsx new file mode 100644 index 00000000..e69de29b diff --git a/packages/create/templates/plugin-ts/webpack.config.js b/packages/create/templates/plugin-ts/webpack.config.js new file mode 100644 index 00000000..85da4267 --- /dev/null +++ b/packages/create/templates/plugin-ts/webpack.config.js @@ -0,0 +1,28 @@ +"use strict"; +const path = require("path"); +const webpack = require("webpack"); +const { merge } = require("webpack-merge"); + +const common = require("@clusterio/web_ui/webpack.common"); + +module.exports = (env = {}) => merge(common(env), { + context: __dirname, + entry: "./web/index.tsx", + output: { + path: path.resolve(__dirname, "dist", "web"), + }, + plugins: [ + new webpack.container.ModuleFederationPlugin({ + name: "// plugin_name //", + library: { type: "var", name: "plugin___plugin_name__" }, + exposes: { + "./": "./index.ts", + "./package.json": "./package.json", + }, + shared: { + "@clusterio/lib": { import: false }, + "@clusterio/web_ui": { import: false }, + }, + }), + ], +});