diff --git a/package-lock.json b/package-lock.json index b29017842..df02b8bb7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,10 +17,8 @@ "@rollup/plugin-typescript": "^11.0.0", "@rollup/plugin-url": "^8.0.1", "@types/glob": "^8.1.0", - "@types/react-dom": "^18.0.5", "glob": "^10.3.4", - "react": "^18.1.0", - "react-dom": "^18.1.0", + "preact-render-to-string": "^6.2.1", "rehype": "^13.0.0", "rehype-highlight": "^7.0.0", "rehype-react": "^8.0.0", @@ -635,38 +633,6 @@ "integrity": "sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==", "dev": true }, - "node_modules/@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "dev": true - }, - "node_modules/@types/react": { - "version": "18.2.21", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.21.tgz", - "integrity": "sha512-neFKG/sBAwGxHgXiIxnbm3/AAVQ/cMRS93hvBpg8xYRbeQSPVABp9U2bRnPf0iI4+Ucdv3plSxKK+3CW2ENJxA==", - "dev": true, - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.2.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz", - "integrity": "sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==", - "dev": true, - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/scheduler": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==", - "dev": true - }, "node_modules/@types/unist": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.0.tgz", @@ -824,12 +790,6 @@ "node": ">= 8" } }, - "node_modules/csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", - "dev": true - }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -1288,24 +1248,6 @@ "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, "node_modules/lowlight": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-3.0.0.tgz", @@ -1554,6 +1496,24 @@ "url": "https://opencollective.com/preact" } }, + "node_modules/preact-render-to-string": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.2.1.tgz", + "integrity": "sha512-5t7nFeMUextd53igL3GAakAAMaUD+dVWDHaRYaeh1tbPIjQIBtgJnMw6vf8VS/lviV0ggFtkgebatPxvtJsXyQ==", + "dev": true, + "dependencies": { + "pretty-format": "^3.8.0" + }, + "peerDependencies": { + "preact": ">=10" + } + }, + "node_modules/pretty-format": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz", + "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==", + "dev": true + }, "node_modules/property-information": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.3.0.tgz", @@ -1573,31 +1533,6 @@ "safe-buffer": "^5.1.0" } }, - "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dev": true, - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "dev": true, - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" - }, - "peerDependencies": { - "react": "^18.2.0" - } - }, "node_modules/rehype": { "version": "13.0.1", "resolved": "https://registry.npmjs.org/rehype/-/rehype-13.0.1.tgz", @@ -1751,15 +1686,6 @@ } ] }, - "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dev": true, - "dependencies": { - "loose-envify": "^1.1.0" - } - }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", diff --git a/package.json b/package.json index a5b01307d..b3eb6d7a9 100644 --- a/package.json +++ b/package.json @@ -14,13 +14,11 @@ "@rollup/plugin-typescript": "^11.0.0", "@rollup/plugin-url": "^8.0.1", "@types/glob": "^8.1.0", - "@types/react-dom": "^18.0.5", "glob": "^10.3.4", - "react-dom": "^18.1.0", - "react": "^18.1.0", + "preact-render-to-string": "^6.2.1", + "rehype": "^13.0.0", "rehype-highlight": "^7.0.0", "rehype-react": "^8.0.0", - "rehype": "^13.0.0", "requirejs": "^2.3.6", "rollup": "^3.19.1", "tsx": "^3.12.10", diff --git a/projects/core/src/main/resources/data/computercraft/lua/bios.lua b/projects/core/src/main/resources/data/computercraft/lua/bios.lua index 917b69862..eab182375 100644 --- a/projects/core/src/main/resources/data/computercraft/lua/bios.lua +++ b/projects/core/src/main/resources/data/computercraft/lua/bios.lua @@ -687,7 +687,7 @@ settings.define("paint.default_extension", { settings.define("list.show_hidden", { default = false, - description = [[Show hidden files (those starting with "." in the Lua REPL).]], + description = [[Whether the list program show hidden files (those starting with ".").]], type = "boolean", }) diff --git a/projects/web/rollup.config.js b/projects/web/rollup.config.js index 958c37ccc..41b5864f6 100644 --- a/projects/web/rollup.config.js +++ b/projects/web/rollup.config.js @@ -5,13 +5,14 @@ import { readFileSync } from "fs"; import path from "path"; -import typescript from "@rollup/plugin-typescript"; -import url from '@rollup/plugin-url'; import terser from "@rollup/plugin-terser"; +import typescript from "@rollup/plugin-typescript"; +import url from "@rollup/plugin-url"; const input = "src"; const requirejs = readFileSync("../../node_modules/requirejs/require.js"); +/** @type import("rollup").RollupOptions */ export default { input: [`${input}/index.tsx`], output: { @@ -54,7 +55,7 @@ export default { async transform(code, file) { // Allow loading files in /mount. const ext = path.extname(file); - return ext != '.dfpwm' && path.dirname(file) === path.resolve(`${input}/mount`) + return ext != ".dfpwm" && path.dirname(file) === path.resolve(`${input}/mount`) ? `export default ${JSON.stringify(code)};\n` : null; }, diff --git a/projects/web/src/components/Recipe.tsx b/projects/web/src/components/Recipe.tsx index a35ca651e..78c261013 100644 --- a/projects/web/src/components/Recipe.tsx +++ b/projects/web/src/components/Recipe.tsx @@ -2,8 +2,7 @@ // // SPDX-License-Identifier: MPL-2.0 -import type { FunctionComponent } from "react"; -import { createElement as h } from "react"; +import { h, type FunctionComponent, type JSX } from "preact"; import useExport from "./WithExport"; const Item: FunctionComponent<{ item: string }> = ({ item }) => { diff --git a/projects/web/src/components/WithExport.tsx b/projects/web/src/components/WithExport.tsx index a80c50553..937bd9799 100644 --- a/projects/web/src/components/WithExport.tsx +++ b/projects/web/src/components/WithExport.tsx @@ -2,7 +2,8 @@ // // SPDX-License-Identifier: MPL-2.0 -import { createElement as h, useContext, createContext, type FunctionComponent, type ReactNode } from "react"; +import { h, createContext, type FunctionComponent, type VNode } from "preact"; +import { useContext } from "preact/hooks"; export type DataExport = { readonly itemNames: Record, @@ -23,5 +24,5 @@ const DataExport = createContext({ export const useExport = () => useContext(DataExport); export default useExport; -export const WithExport: FunctionComponent<{ data: DataExport, children: ReactNode }> = - ({ data, children }) => {children}; +export const WithExport: FunctionComponent<{ data: DataExport, children: VNode }> = + ({ data, children }) => {children}; diff --git a/projects/web/src/components/support.tsx b/projects/web/src/components/support.tsx index 63a576b37..a1197f6ee 100644 --- a/projects/web/src/components/support.tsx +++ b/projects/web/src/components/support.tsx @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: MPL-2.0 -import type { FunctionComponent } from "react"; +import { type FunctionComponent } from "preact"; /** * Wrap a component and ensure that no children are passed to it. @@ -20,7 +20,7 @@ export const noChildren = function (component: FunctionComponent): Functio const name = component.displayName ?? component.name; const wrapped: FunctionComponent = props => { - if ((props as any).children) throw Error("Unexpected children in " + name); + if (props.children) throw Error("Unexpected children in " + name); return component(props); }; diff --git a/projects/web/src/index.tsx b/projects/web/src/index.tsx index 8938c47f6..ca1c1f446 100644 --- a/projects/web/src/index.tsx +++ b/projects/web/src/index.tsx @@ -2,18 +2,18 @@ // // SPDX-License-Identifier: MPL-2.0 -import { render, h, Component, Computer, type PeripheralKind } from "copycat/embed"; -import type { ComponentChild } from "preact"; +import { Component, Computer, h, render, type PeripheralKind } from "copycat/embed"; +import type { ComponentChild, FunctionalComponent } from "preact"; import settingsFile from "./mount/.settings"; -import startupFile from "./mount/startup.lua"; -import exprTemplate from "./mount/expr_template.lua"; +import exampleAudioUrl from "./mount/example.dfpwm"; +import exampleAudioLicense from "./mount/example.dfpwm.license"; import exampleNfp from "./mount/example.nfp"; import exampleNft from "./mount/example.nft"; -import exampleAudioLicense from "./mount/example.dfpwm.license"; -import exampleAudioUrl from "./mount/example.dfpwm"; +import exprTemplate from "./mount/expr_template.lua"; +import startupFile from "./mount/startup.lua"; -const defaultFiles: { [filename: string]: string } = { +const defaultFiles: Record = { ".settings": settingsFile, "startup.lua": startupFile, @@ -36,13 +36,13 @@ const download = async (url: string): Promise => { let dfpwmAudio: Promise | null = null; -const Click = (options: { run: () => void }) => - +const Click: FunctionalComponent<{ run: () => void }> = ({ run }) => + type WindowProps = {}; type Example = { - files: { [file: string]: string | Uint8Array }, + files: Record, peripheral: PeripheralKind | null, } @@ -105,8 +105,8 @@ class Window extends Component {
+ ...defaultFiles, ...example.files, + }} peripherals={{ back: example.peripheral }} />
:
; @@ -120,7 +120,7 @@ class Window extends Component { this.top = 20; } - const files: { [file: string]: string | Uint8Array } = { "example.lua": example }; + const files: Record = { "example.lua": example }; if (mount !== null) { for (const toMount of mount.split(",")) { const [name, path] = toMount.split(":", 2); diff --git a/projects/web/src/transform.tsx b/projects/web/src/transform.tsx index 98fa0bfe3..f1ce6d441 100644 --- a/projects/web/src/transform.tsx +++ b/projects/web/src/transform.tsx @@ -10,20 +10,20 @@ * * Yes, this would be so much nicer with next.js. */ -import * as fs from "fs/promises"; +import fs from "fs/promises"; import { glob } from "glob"; -import * as path from "path"; -import { createElement as h } from 'react'; -import runtime from 'react/jsx-runtime'; -import { renderToStaticMarkup } from "react-dom/server"; -import rehypeHighlight from "rehype-highlight"; -import rehypeParse from 'rehype-parse'; -import rehypeReact, { type Options as ReactOptions } from 'rehype-react'; -import { unified } from 'unified'; +import path from "path"; +import { h, type JSX } from "preact"; +import renderToStaticMarkup from "preact-render-to-string"; +import * as runtime from "preact/jsx-runtime"; +import rehypeHighlight, { type Options as HighlightOptions } from "rehype-highlight"; +import rehypeParse from "rehype-parse"; +import rehypeReact, { type Options as ReactOptions } from "rehype-react"; +import { unified, type Plugin } from "unified"; // Our components import Recipe from "./components/Recipe"; import { noChildren } from "./components/support"; -import { type DataExport, WithExport } from "./components/WithExport"; +import { WithExport, type DataExport } from "./components/WithExport"; (async () => { const base = "build/illuaminate"; @@ -31,19 +31,19 @@ import { type DataExport, WithExport } from "./components/WithExport"; const reactOptions: ReactOptions = { ...(runtime as ReactOptions), components: { - ['mc-recipe']: noChildren(Recipe), - ['mcrecipe']: noChildren(Recipe), + ["mc-recipe"]: noChildren(Recipe), + ["mcrecipe"]: noChildren(Recipe), // Wrap example snippets in a
...
, so we can inject a // Run button into them. - ['pre']: (args: JSX.IntrinsicElements["pre"] & { "data-lua-kind"?: undefined }) => { + ["pre"]: (args: JSX.IntrinsicElements["pre"] & { "data-lua-kind"?: undefined }) => { const element =
;
                 return args["data-lua-kind"] ? 
{element}
: element } - } as any + } }; const processor = unified() .use(rehypeParse, { emitParseErrors: true }) - .use(rehypeHighlight, { prefix: "" }) + .use(rehypeHighlight as unknown as Plugin<[HighlightOptions], import("hast").Root>, { prefix: "" }) .use(rehypeReact, reactOptions); const dataExport = JSON.parse(await fs.readFile("src/export/index.json", "utf-8")) as DataExport;