diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4196d78..8c57ef6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,22 +13,21 @@ jobs: with: persist-credentials: false - name: Install Deno 🦕 - uses: denoland/setup-deno@v1 + uses: denoland/setup-deno@v2 with: - deno-version: v1.x + deno-version: v2.x - name: 'Build Executable' run: deno task build - name: Upload Executables as Artifacts if: github.ref_type == 'branch' uses: actions/upload-artifact@v4 with: - name: ${{ format('dash-{0}-{1}-{2}', github.run_id, github.run_number, github.run_attempt) }} - path: 'executables/*' + name: ${{ format('dash-{0}-{1}-{2}', github.run_id, github.run_number, github.run_attempt) }} + path: 'executables/*' - name: Upload Executables as Release if: github.ref_type == 'tag' uses: AButler/upload-release-assets@v3.0 with: - files: 'executables/*' - release-tag: ${{ github.ref_name }} - repo-token: ${{ secrets.GITHUB_TOKEN }} - + files: 'executables/*' + release-tag: ${{ github.ref_name }} + repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.vscode/settings.json b/.vscode/settings.json index 43df84f..1365173 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { - "deno.enable": true + "deno.enable": true, + "deno.lint": true } diff --git a/README.md b/README.md index 4e0108d..9de17d4 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Releases page](https://github.com/bridge-core/deno-dash-compiler/releases). Open your terminal and run: ```shell -deno install -A -f --reload -n dash_compiler https://raw.githubusercontent.com/bridge-core/deno-dash-compiler/main/mod.ts +deno install -A --global -f --reload -n dash_compiler https://raw.githubusercontent.com/bridge-core/deno-dash-compiler/main/mod.ts ``` #### Via Deno's Task Runner diff --git a/deno.json b/deno.json index b618a48..ab936fc 100644 --- a/deno.json +++ b/deno.json @@ -1,29 +1,33 @@ { - "importMap": "importMap.json", + "imports": { + "@bridge-editor/common-utils": "npm:@bridge-editor/common-utils@^0.3.3", + "@bridge-editor/mc-project-core": "npm:@bridge-editor/mc-project-core@^0.4.0", + "@std/async": "jsr:@std/async@^1.0.7", + "@std/path": "jsr:@std/path@^1.0.7", + "@std/semver": "jsr:@std/semver@^1.0.3", + "dash-compiler-local": "../dash-compiler/dist/dash-compiler.bundled.es.js" + }, + "version": "1.0.0", "tasks": { - "install": "deno install -A -f -n dash_compiler ./mod.ts", - "install:full": "deno install -A --reload -f -n dash_compiler ./mod.ts", + "install": "deno install --global -A -f -n dash_compiler ./mod.ts", + "install:full": "deno install --global -A --reload -f -n dash_compiler ./mod.ts", "build": "deno task build:apple-x86 && deno task build:apple-aarch64 && deno task build:windows-x86", "build:apple-x86": "deno compile --target x86_64-apple-darwin --output ./executables/dash-apple-x64 -A ./mod.ts", "build:apple-aarch64": "deno compile --target aarch64-apple-darwin --output ./executables/dash-apple-aarch64 -A ./mod.ts", "build:windows-x86": "deno compile --target x86_64-pc-windows-msvc --output ./executables/dash.exe -A ./mod.ts" }, "fmt": { - "files": { - "include": ["*.json", "*.ts", "*.tsx", "src/"] - }, - "options": { - "useTabs": true, - "lineWidth": 80, - "indentWidth": 4, - "singleQuote": true - } + "include": ["*.json", "*.ts", "*.tsx", "src/"], + "exclude": ["dist/", ".vscode/", ".github/", "README.md", "deno.lock"], + "useTabs": true, + "lineWidth": 80, + "semiColons": false, + "indentWidth": 4, + "singleQuote": true }, "lint": { - "files": { - "include": ["*.ts", "src/"], - "exclude": ["dist/", ".vscode/", ".github/"] - }, + "include": ["*.ts", "src/"], + "exclude": ["dist/", ".vscode/", ".github/"], "rules": { "tags": ["recommended"], "include": ["ban-untagged-todo"], diff --git a/deno.lock b/deno.lock new file mode 100644 index 0000000..00c1232 --- /dev/null +++ b/deno.lock @@ -0,0 +1,86 @@ +{ + "version": "4", + "specifiers": { + "jsr:@std/async@*": "1.0.8", + "jsr:@std/async@^1.0.7": "1.0.8", + "jsr:@std/path@*": "1.0.8", + "jsr:@std/path@^1.0.7": "1.0.8", + "jsr:@std/semver@^1.0.3": "1.0.3", + "npm:@bridge-editor/common-utils@~0.3.3": "0.3.3", + "npm:@bridge-editor/mc-project-core@0.4": "0.4.0", + "npm:@types/node@*": "22.5.4" + }, + "jsr": { + "@std/async@1.0.8": { + "integrity": "c057c5211a0f1d12e7dcd111ab430091301b8d64b4250052a79d277383bc3ba7" + }, + "@std/path@1.0.8": { + "integrity": "548fa456bb6a04d3c1a1e7477986b6cffbce95102d0bb447c67c4ee70e0364be" + }, + "@std/semver@1.0.3": { + "integrity": "7c139c6076a080eeaa4252c78b95ca5302818d7eafab0470d34cafd9930c13c8" + } + }, + "npm": { + "@bridge-editor/common-utils@0.3.3": { + "integrity": "sha512-EaOpPNoZvO7LM9lPPoT7hMb8WJrx73Wkk//V3xKgbPVPDrQHSoJyd3b1E2sARSu2UZhVo9L7Lnj13DQ2O+FAgw==", + "dependencies": [ + "compare-versions" + ] + }, + "@bridge-editor/mc-project-core@0.4.0": { + "integrity": "sha512-QwkJhYrjN09gAaVQGSaoVUgnvxOL1PptJC7sqqb3FaBHoUEZ6+8W1PNwxeO8RCPftq0aewcKJp6pAn9ss7UYqA==", + "dependencies": [ + "@bridge-editor/common-utils", + "json5", + "path-browserify" + ] + }, + "@types/node@22.5.4": { + "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", + "dependencies": [ + "undici-types" + ] + }, + "compare-versions@4.1.4": { + "integrity": "sha512-FemMreK9xNyL8gQevsdRMrvO4lFCkQP7qbuktn1q8ndcNk1+0mz7lgE7b/sNvbhVgY4w6tMN1FDp6aADjqw2rw==" + }, + "json5@2.2.3": { + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" + }, + "path-browserify@1.0.1": { + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" + }, + "undici-types@6.19.8": { + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" + } + }, + "remote": { + "https://esm.sh/@bridge-editor/dash-compiler@0.11.7": "9022b115079e7eba6c29b2ce64e5cce3f4609bf37ae75be70dcceff20ee0931c", + "https://esm.sh/@bridge-editor/mc-project-core@0.4.0": "27c4799364c6e73715f317323db6ede7c0d6d7430d17ef7d13521a5d84e331b8", + "https://esm.sh/json5@2.2.3": "56ad046eba99c091fcb546d9ec3ab3463e9a889f5d52b818c91c5f2e793dbefd", + "https://esm.sh/v135/@bridge-editor/common-utils@0.3.3/denonext/common-utils.mjs": "36d6ab2b43f9988e23a1acede1870472ce46289166c2350f1d3d7c64ffd7f799", + "https://esm.sh/v135/@bridge-editor/dash-compiler@0.11.7/denonext/dash-compiler.mjs": "e16980e14a7fab10a171e9f6321407a797598f5a6dd25fc513a8c4a2967c7711", + "https://esm.sh/v135/@bridge-editor/js-runtime@0.4.5/denonext/js-runtime.mjs": "5e904804cb222a9e0fd6ad7994d9c4b72ffff247392e02381ae09621c06e9c30", + "https://esm.sh/v135/@bridge-editor/mc-project-core@0.4.0/denonext/mc-project-core.mjs": "d19bba5f627d72a8b1ffdd55bec418fbdcec588b0298a9bfe1afb24b164e7992", + "https://esm.sh/v135/@bridge-editor/molang@2.0.2/denonext/molang.mjs": "0e11083e84d6c9c12636d6090fc171db45701afb7d2bf7f80643e00fd00ccebd", + "https://esm.sh/v135/@swc/wasm-web@1.6.5/denonext/wasm-web.mjs": "328d0bd0fc0e62914ccd85d4001bbeb2f5354c0638a53a26dec9f0d62c74e947", + "https://esm.sh/v135/is-extglob@2.1.1/denonext/is-extglob.mjs": "43b399da3b6384e348c08e894003bd598e511c77e6079e76328085d7081a9595", + "https://esm.sh/v135/is-glob@4.0.3/denonext/is-glob.mjs": "f2ee9ce4250a5727fb81e5a0c96efa7f0566166a4d9ac6acb3107821b9f5f52d", + "https://esm.sh/v135/json5@2.2.3/denonext/json5.mjs": "2124ca68e182d9de859a72e9415bbc4702b8f0bb002a7a22ea06d6684a3e562b", + "https://esm.sh/v135/magic-string@0.26.7/denonext/magic-string.mjs": "7ab76b1d4f529e3321e4696c66e3beabc6ada3f3d8ddb8d585c884e9e8fecc31", + "https://esm.sh/v135/path-browserify@1.0.1/denonext/path-browserify.mjs": "397babbb819658714128c4dade6867153fe2a18115391c845369924aa0e3eb20", + "https://esm.sh/v135/sourcemap-codec@1.4.8/denonext/sourcemap-codec.mjs": "4fe24182fb99746cc4fe4092e0f78eca97819fe99b9b9c097ccdd86d07da3551", + "https://unpkg.com/@bridge-editor/dash-compiler@0.11.7/dist/dash-compiler.bundled.es.js": "fffac9708805c765df2d2b4276b90ed1aad2ceb0d8a1cf506babeca2dc131dcc", + "https://unpkg.com/@bridge-editor/dash-compiler@0.11.7/package.json": "19ea2b4b03fbe3eec35f2980ba3e67df3946880e21faad3fa4032509c93957fa" + }, + "workspace": { + "dependencies": [ + "jsr:@std/async@^1.0.7", + "jsr:@std/path@^1.0.7", + "jsr:@std/semver@^1.0.3", + "npm:@bridge-editor/common-utils@~0.3.3", + "npm:@bridge-editor/mc-project-core@0.4" + ] + } +} diff --git a/importMap.json b/importMap.json deleted file mode 100644 index c5afc13..0000000 --- a/importMap.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "imports": { - "dash-compiler": "https://raw.githubusercontent.com/bridge-core/dash-compiler/main/dist/dash-compiler.bundled.es.js", - "dash-compiler-local": "../dash-compiler/dist/dash-compiler.bundled.es.js", - "mc-project-core": "npm:mc-project-core", - "semver": "jsr:@std/semver@^1.0.3" - } -} diff --git a/mod.ts b/mod.ts index 9545cd1..a13bf91 100644 --- a/mod.ts +++ b/mod.ts @@ -1,20 +1,12 @@ // deno-lint-ignore-file no-explicit-any import { CLI } from './src/CLI.ts' -import yargs from 'https://deno.land/x/yargs@v17.5.1-deno/deno.ts' -import { parse as semverParse, compare as semverCompare } from "jsr:@std/semver"; +import yargs from 'https://deno.land/x/yargs@v17.7.2-deno/deno.ts' +import { parse as semverParse, compare as semverCompare } from 'jsr:@std/semver' import { comMojangFolder } from './src/comMojangFolder.ts' import { initRuntimes, swcVersion } from './src/deps.ts' -// @ts-ignore: Required by some of our dependencies -window.global = window -// @ts-ignore: Required by some of our dependencies -window.process = { - cwd: () => '', - env: {}, -} - type YargsInstance = ReturnType -const CURRENT_VERSION = `0.4.7` +const CURRENT_VERSION = `1.0.0` async function fetchLatestVersion(): Promise { try { diff --git a/src/FileSystem.ts b/src/FileSystem.ts index cb4abdd..8c0819d 100644 --- a/src/FileSystem.ts +++ b/src/FileSystem.ts @@ -30,7 +30,7 @@ export class DenoFileSystem extends FileSystem { await Deno.writeTextFile(this.resolvePath(filePath), content) else return Deno.writeFile(this.resolvePath(filePath), content) } - async readJson(filePath: string) { + override async readJson(filePath: string) { const fileContent = await Deno.readTextFile(this.resolvePath(filePath)) return json5.parse(fileContent) } @@ -42,14 +42,14 @@ export class DenoFileSystem extends FileSystem { for await (const entry of Deno.readDir(this.resolvePath(path))) { entries.push({ - name: entry.name, - kind: entry.isDirectory ? 'directory' : 'file', + name: entry.name, + kind: entry.isDirectory ? 'directory' : 'file', }) } return entries } - async copyFile(from: string, to: string, destFs = this) { + override async copyFile(from: string, to: string, destFs = this) { // Fallback to slow path if destination fs !== this if (destFs !== this) return super.copyFile(from, to, destFs) diff --git a/src/McProjectCore.ts b/src/McProjectCore.ts index 061fc78..c62aac6 100644 --- a/src/McProjectCore.ts +++ b/src/McProjectCore.ts @@ -17,13 +17,13 @@ export class FileTypeImpl extends FileType { ).then((resp) => resp.json()) } - addPluginFileType(fileDef: IFileType) { + override addPluginFileType(fileDef: IFileType) { this._cache.clear() return super.addPluginFileType(fileDef) } - get(filePath?: string, searchFileType?: string, checkFileExtension = true) { + override get(filePath?: string, searchFileType?: string, checkFileExtension = true) { if (!filePath || !checkFileExtension || searchFileType !== undefined) { return super.get(filePath, searchFileType, checkFileExtension) } diff --git a/src/WebSocket.ts b/src/WebSocket.ts index 3ebe54b..e4687ac 100644 --- a/src/WebSocket.ts +++ b/src/WebSocket.ts @@ -1,102 +1,100 @@ export class WebSocketServer { - protected socket?: WebSocket + protected socket?: WebSocket - /** - * Whether the WebSocket is open - */ - get isStarted() { - return (this.socket?.readyState === WebSocket.OPEN) - } + /** + * Whether the WebSocket is open + */ + get isStarted() { + return (this.socket?.readyState === WebSocket.OPEN) + } - /** - * Open a WebSocket on localhost - * @param port Network port to open the socket on - */ - start(port: number) { - this.setLoopbackExemption() + /** + * Open a WebSocket on localhost + * @param port Network port to open the socket on + */ + start(port: number) { + this.setLoopbackExemption() - const listener = Deno.listen({ port }) - listener.accept().then(async (connection) => { - const httpConnection = Deno.serveHttp(connection) - for await (const event of httpConnection) { - const { socket, response } = Deno.upgradeWebSocket(event.request) - this.socket = socket - await event.respondWith(response) - console.log('WebSocket connection established!') - const intervalId = this.keepAlive() - this.socket.onclose = () => { - clearInterval(intervalId) - console.log('WebSocket connection closed!') - } - } - }) - } + Deno.serve({ port: port }, (req) => { + if (req.headers.get('upgrade') != 'websocket') { + console.log('Websocket connection: Upgrade header not found') + } + const { socket, response } = Deno.upgradeWebSocket(req) + this.socket = socket + const intervalId = this.keepAlive() + socket.addEventListener('close', () => { + clearInterval(intervalId) + console.log('WebSocket connection closed!') + }) + return response + }) + } - /** - * Runs a console command inside of Minecraft, if the WebSocket is still open - * @param command The command to be run (without the slash) - * @returns The response from Minecraft after requesting the command to be run - */ - runCommand(command: string) { - const requestId = crypto.randomUUID() - const data = JSON.stringify({ - header: { - version: 1, - requestId, - messageType: 'commandRequest', - messagePurpose: 'commandRequest', - }, - body: { - commandLine: command, - }, - }) - if (this.socket && this.isStarted) { - this.socket.send(data) - return new Promise<{ message: string, status: number }>((resolve) => { - this.socket?.addEventListener('message', (event) => { - const res = JSON.parse(event.data.toString()) - if (res.header.requestId === requestId) - resolve({ - message: res.body.statusMessage, - status: res.body.statusCode, - }) - }) - }) - } - } + /** + * Runs a console command inside of Minecraft, if the WebSocket is still open + * @param command The command to be run (without the slash) + * @returns The response from Minecraft after requesting the command to be run + */ + runCommand(command: string) { + const requestId = crypto.randomUUID() + const data = JSON.stringify({ + header: { + version: 1, + requestId, + messageType: 'commandRequest', + messagePurpose: 'commandRequest', + }, + body: { + commandLine: command, + }, + }) + if (this.socket && this.isStarted) { + this.socket.send(data) + return new Promise<{ message: string, status: number }>((resolve) => { + this.socket?.addEventListener('message', (event) => { + const res = JSON.parse(event.data.toString()) + if (res.header.requestId === requestId) { + resolve({ + message: res.body.statusMessage, + status: res.body.statusCode, + }) + } + }) + } + ) + } + } - /** - * Runs console commands to set both Minecraft retail and preview clients to be exempt from UWP network loopback restrictions so that the clients can connect to a local WebSocket - */ - async setLoopbackExemption() { - // Minecraft Retail Build - const retail = Deno.run({ - cmd: ['CheckNetIsolation.exe', 'LoopbackExempt', '-a', '-n=microsoft.minecraftuwp_8wekyb3d8bbwe'], - stdout: 'null', - }) - const retailStat = await retail.status() - if (retailStat.code !== 0) - console.log('Unable to set network loopback exemption for Minecraft retail build.') - retail.close() + /** + * Runs console commands to set both Minecraft retail and preview clients to be exempt from UWP network loopback restrictions so that the clients can connect to a local WebSocket + */ + async setLoopbackExemption() { + // Minecraft Retail Build + const retailCommand = new Deno.Command('CheckNetIsolation.exe', { + args: ['LoopbackExempt', '-a', '-n=microsoft.minecraftuwp_8wekyb3d8bbwe'] + }) + const { success: retailSuccess } = await retailCommand.output() + if (!retailSuccess) { + console.log('Unable to set network loopback exemption for Minecraft retail build.') + } - // Minecraft Preview Build - const preview = Deno.run({ - cmd: ['CheckNetIsolation.exe', 'LoopbackExempt', '-a', '-n=Microsoft.MinecraftWindowsBeta_8wekyb3d8bbwe'], - stdout: 'null', - }) - const previewStat = await preview.status() - if (previewStat.code !== 0) - console.log('Unable to set network loopback exemption for Minecraft preview build.') - preview.close() - } + // Minecraft Preview Build + const previewCommand = new Deno.Command('CheckNetIsolation.exe', { + args: ['LoopbackExempt', '-a', '-n=Microsoft.MinecraftWindowsBeta_8wekyb3d8bbwe'] + }) + const { success: previewSuccess } = await previewCommand.output() + if (!previewSuccess) { + console.log('Unable to set network loopback exemption for Minecraft preview build.') + } + } - /** - * Sends empty requests to the client every 25 seconds to stop the connection from timing out - * @returns The interval id (use to cancel when WebSocket is closed) - */ - keepAlive() { - return setInterval(() => { - this.socket?.send('') - }, 25000) - } + /** + * Sends empty requests to the client every 25 seconds to stop the connection from timing out + * @returns The interval id (use to cancel when WebSocket is closed) + */ + keepAlive() { + return setInterval(() => { + this.socket?.send('') + }, 25000) + } } diff --git a/src/deps.ts b/src/deps.ts index 83c1a6f..0afe4fa 100644 --- a/src/deps.ts +++ b/src/deps.ts @@ -1,21 +1,20 @@ -export * as flags from 'https://deno.land/std@0.121.0/flags/mod.ts' -export * as path from 'https://deno.land/std@0.121.0/path/mod.ts' +export * as path from 'jsr:@std/path' export { FileType, PackType, ProjectConfig, type IFileType, -} from 'https://esm.sh/mc-project-core@0.3.21' -export { isMatch } from 'https://esm.sh/bridge-common-utils@0.3.3' -// @deno-types="https://esm.sh/dash-compiler@0.10.4" +} from 'https://esm.sh/@bridge-editor/mc-project-core@0.4.0' +export { isMatch } from 'npm:@bridge-editor/common-utils' +// @deno-types="https://esm.sh/@bridge-editor/dash-compiler@0.11.7" export { Dash, FileSystem, initRuntimes, -} from 'https://raw.githubusercontent.com/bridge-core/dash-compiler/main/dist/dash-compiler.bundled.es.js' -export { default as json5 } from 'https://esm.sh/json5@2.2.1' -export { debounce } from 'https://deno.land/std@0.156.0/async/mod.ts?s=debounce' -import { default as dashPackageJson } from 'https://raw.githubusercontent.com/bridge-core/dash-compiler/main/package.json' with { type: 'json' } +} from 'https://unpkg.com/@bridge-editor/dash-compiler@0.11.7/dist/dash-compiler.bundled.es.js' +export { default as json5 } from 'https://esm.sh/json5@2.2.3' +export { debounce } from 'jsr:@std/async' +import { default as dashPackageJson } from 'https://unpkg.com/@bridge-editor/dash-compiler@0.11.7/package.json' with { type: 'json' } let swcVersion = dashPackageJson.dependencies['@swc/wasm-web'] if (swcVersion.startsWith('^')) swcVersion = swcVersion.slice(1)