From c3e31eb64383e552749bc352a29fbdebe816dfd7 Mon Sep 17 00:00:00 2001 From: SirEdvin Date: Thu, 16 Jul 2026 10:09:45 +0000 Subject: [PATCH] docs: replace TypeDoc with MkDocs --- .github/scripts/docs-site.mjs | 24 +- .github/scripts/docs-site.test.mjs | 19 +- .github/workflows/docs-check.yml | 12 +- .github/workflows/docs-pages.yml | 11 + .../typed-peripheral-digitalitems/.gitignore | 1 + .../build.gradle.kts | 6 +- .../documentation/generate-docs.mjs | 196 ++++++ .../documentation/generate-docs.test.mjs | 34 + .../documentation/guides/advanced-items.md | 4 +- .../documentation/guides/basic-digitizer.md | 4 +- .../documentation/index.md | 8 +- .../documentation/theme/digitalitems.css | 633 ++---------------- .../documentation/theme/digitalitems.js | 77 +-- .../documentation/theme/plugin.mjs | 67 -- .../typed-peripheral-digitalitems/mkdocs.yml | 65 ++ .../package-lock.json | 259 ------- .../package.json | 5 +- .../requirements-docs.txt | 1 + .../tsconfig.docs.json | 7 - .../typedoc.json | 87 --- projects/typescript-tests/package-lock.json | 1 - 21 files changed, 443 insertions(+), 1078 deletions(-) create mode 100644 projects/typed-peripheral-digitalitems/documentation/generate-docs.mjs create mode 100644 projects/typed-peripheral-digitalitems/documentation/generate-docs.test.mjs delete mode 100644 projects/typed-peripheral-digitalitems/documentation/theme/plugin.mjs create mode 100644 projects/typed-peripheral-digitalitems/mkdocs.yml create mode 100644 projects/typed-peripheral-digitalitems/requirements-docs.txt delete mode 100644 projects/typed-peripheral-digitalitems/tsconfig.docs.json delete mode 100644 projects/typed-peripheral-digitalitems/typedoc.json diff --git a/.github/scripts/docs-site.mjs b/.github/scripts/docs-site.mjs index cc9a3f4..9965456 100644 --- a/.github/scripts/docs-site.mjs +++ b/.github/scripts/docs-site.mjs @@ -5,20 +5,21 @@ import { spawnSync } from "node:child_process"; import { dirname, isAbsolute, relative, resolve, sep } from "node:path"; import { fileURLToPath } from "node:url"; -export const REQUIRED_DOC_FILES = [ +export const COMMON_DOC_FILES = [ "projects/typed-peripheral-digitalitems/build.gradle.kts", "projects/typed-peripheral-digitalitems/package.json", "projects/typed-peripheral-digitalitems/package-lock.json", - "projects/typed-peripheral-digitalitems/typedoc.json", - "projects/typed-peripheral-digitalitems/tsconfig.docs.json", "projects/typed-peripheral-digitalitems/shared.ts", "projects/typed-peripheral-digitalitems/digitizer.ts", "projects/typed-peripheral-digitalitems/advanced_digitizer.ts", "projects/typed-peripheral-digitalitems/documentation/index.md", - "projects/typed-peripheral-digitalitems/documentation/theme/plugin.mjs", "projects/typed-peripheral-digitalitems/documentation/theme/digitalitems.css", "projects/typed-peripheral-digitalitems/documentation/theme/digitalitems.js", ]; +const DOC_GENERATORS = [ + ["projects/typed-peripheral-digitalitems/typedoc.json", "projects/typed-peripheral-digitalitems/documentation/theme/plugin.mjs"], + ["projects/typed-peripheral-digitalitems/mkdocs.yml", "projects/typed-peripheral-digitalitems/requirements-docs.txt", "projects/typed-peripheral-digitalitems/documentation/generate-docs.mjs"], +]; const BRANCHES = ["1.20", "1.21"]; const TAG_RE = /^v\d+(?:\.\d+)+(?:-[0-9A-Za-z]+(?:[.-][0-9A-Za-z]+)*)?$/; @@ -119,9 +120,10 @@ function show(repository, ref, path) { } function refHasDocs(repository, ref) { - return REQUIRED_DOC_FILES.every((path) => - git(repository, ["cat-file", "-e", `${ref}:${path}`], true).status === 0 - ) && /\bgenerateDocs\b/.test(show(repository, ref, REQUIRED_DOC_FILES[0])); + const has = (path) => git(repository, ["cat-file", "-e", `${ref}:${path}`], true).status === 0; + return COMMON_DOC_FILES.every(has) + && DOC_GENERATORS.some((files) => files.every(has)) + && /\bgenerateDocs\b/.test(show(repository, ref, COMMON_DOC_FILES[0])); } function metadata(repository, ref) { @@ -265,7 +267,10 @@ function localTarget(root, html, rawLink) { fail(`Malformed local link in ${html}: ${rawLink}`); } if (pathname.includes("\\") || pathname.includes("\0")) fail(`Unsafe local link in ${html}: ${rawLink}`); - const target = pathname.startsWith("/") ? resolve(root, `.${pathname}`) : resolve(dirname(html), pathname); + const versionedPath = pathname.match(/^\/.*?\/((?:branch|tag)\/.*)$/)?.[1]; + const target = pathname.startsWith("/") + ? resolve(root, versionedPath ?? `.${pathname}`) + : resolve(dirname(html), pathname); if (!within(root, target)) fail(`Local link escapes site in ${html}: ${rawLink}`); return target; } @@ -290,9 +295,6 @@ export async function validateSite(site) { for (const entry of plan) { const versionRoot = resolve(root, entry.path); await regularFile(resolve(versionRoot, "index.html"), `${entry.path} index.html`); - for (const asset of ["search.js", "navigation.js", "custom.css", "custom.js"]) { - await regularFile(resolve(versionRoot, "assets", asset), `${entry.path} ${asset}`); - } } const canonicalRoot = await realpath(root); for (const html of await htmlFiles(root)) { diff --git a/.github/scripts/docs-site.test.mjs b/.github/scripts/docs-site.test.mjs index 33f96cf..5e4a8f8 100644 --- a/.github/scripts/docs-site.test.mjs +++ b/.github/scripts/docs-site.test.mjs @@ -23,11 +23,11 @@ function entry(kind, name, sha = SHA_A) { }; } -async function fragment(root, path, html = 'asset') { +async function fragment(root, path, html = '') { const directory = join(root, path); await mkdir(join(directory, "assets"), { recursive: true }); await writeFile(join(directory, "index.html"), html); - for (const asset of ["main.js", "search.js", "navigation.js", "custom.css", "custom.js"]) { + for (const asset of ["main.js", "main.css"]) { await writeFile(join(directory, "assets", asset), "// docs\n"); } } @@ -107,14 +107,23 @@ test("validate rejects links escaping the site", async () => { await assert.rejects(validateSite(output), /escapes site/); }); -test("validate rejects missing TypeDoc assets", async () => { +test("validate resolves hosted version paths below the Pages project prefix", async () => { + const root = await mkdtemp(join(tmpdir(), "docs-site-prefix-")); + const input = join(root, "input"); + const output = join(root, "output"); + await fragment(input, "branch/1.20", ''); + await assembleSite({ input, output, plan: [entry("branch", "1.20")] }); + await validateSite(output); +}); + +test("validate rejects a missing linked asset", async () => { const root = await mkdtemp(join(tmpdir(), "docs-site-assets-")); const input = join(root, "input"); const output = join(root, "output"); await fragment(input, "branch/1.20"); await assembleSite({ input, output, plan: [entry("branch", "1.20")] }); - await unlink(join(output, "branch", "1.20", "assets", "search.js")); - await assert.rejects(validateSite(output), /Missing branch\/1.20 search.js/); + await unlink(join(output, "branch", "1.20", "assets", "main.css")); + await assert.rejects(validateSite(output), /Broken local link.*assets\/main.css/); }); test("assemble rejects a symlinked output ancestor", async () => { diff --git a/.github/workflows/docs-check.yml b/.github/workflows/docs-check.yml index a253169..90c0ea2 100644 --- a/.github/workflows/docs-check.yml +++ b/.github/workflows/docs-check.yml @@ -42,6 +42,16 @@ jobs: - name: Set up Gradle uses: gradle/actions/setup-gradle@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: pip + cache-dependency-path: projects/typed-peripheral-digitalitems/requirements-docs.txt + + - name: Install documentation dependencies + run: timeout --foreground 120s python -m pip install -r projects/typed-peripheral-digitalitems/requirements-docs.txt + - name: Build package and documentation run: timeout --foreground 600s ./gradlew :typed-peripheral-digitalitems:compileTypeScript :typed-peripheral-digitalitems:generateDocs --no-daemon @@ -55,7 +65,7 @@ jobs: run: | set -euo pipefail NODE="$PWD/.gradle/nodejs/node-v22.14.0-linux-x64/bin/node" - timeout --foreground 60s "$NODE" --test .github/scripts/docs-site.test.mjs + timeout --foreground 60s "$NODE" --test .github/scripts/docs-site.test.mjs projects/typed-peripheral-digitalitems/documentation/generate-docs.test.mjs mkdir -p build/docs-fragments/branch/1.20 cp -a projects/typed-peripheral-digitalitems/docs/. build/docs-fragments/branch/1.20/ timeout --foreground 60s "$NODE" .github/scripts/docs-site.mjs assemble --input build/docs-fragments --output build/docs-site --plan-json "$DOCS_PLAN" diff --git a/.github/workflows/docs-pages.yml b/.github/workflows/docs-pages.yml index ffc47e6..67cdb2c 100644 --- a/.github/workflows/docs-pages.yml +++ b/.github/workflows/docs-pages.yml @@ -67,6 +67,17 @@ jobs: - name: Set up Gradle uses: gradle/actions/setup-gradle@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install MkDocs for migrated refs + run: | + if [[ -f projects/typed-peripheral-digitalitems/requirements-docs.txt ]]; then + timeout --foreground 120s python -m pip install -r projects/typed-peripheral-digitalitems/requirements-docs.txt + fi + - name: Generate documentation with ref-owned task env: DOCS_PATH: ${{ matrix.path }} diff --git a/projects/typed-peripheral-digitalitems/.gitignore b/projects/typed-peripheral-digitalitems/.gitignore index b4504e2..dff745a 100644 --- a/projects/typed-peripheral-digitalitems/.gitignore +++ b/projects/typed-peripheral-digitalitems/.gitignore @@ -2,3 +2,4 @@ *.d.ts node_modules/ docs/ +.mkdocs-build/ diff --git a/projects/typed-peripheral-digitalitems/build.gradle.kts b/projects/typed-peripheral-digitalitems/build.gradle.kts index 0eaa4b2..ba09555 100644 --- a/projects/typed-peripheral-digitalitems/build.gradle.kts +++ b/projects/typed-peripheral-digitalitems/build.gradle.kts @@ -54,10 +54,11 @@ val generateDocs by tasks.registering(NpmTask::class) { "package.json", "package-lock.json", "tsconfig.json", - "tsconfig.docs.json", - "typedoc.json", + "mkdocs.yml", + "requirements-docs.txt", "*.ts", "documentation/**/*.md", + "documentation/**/*.mjs", "documentation/theme/**", ) exclude("node_modules/**", "*.d.ts") @@ -71,6 +72,7 @@ tasks.assemble { tasks.clean { delete(file("docs")) + delete(file(".mkdocs-build")) delete(fileTree(projectDir) { include("*.d.ts", "*.lua") }) diff --git a/projects/typed-peripheral-digitalitems/documentation/generate-docs.mjs b/projects/typed-peripheral-digitalitems/documentation/generate-docs.mjs new file mode 100644 index 0000000..8cbcc97 --- /dev/null +++ b/projects/typed-peripheral-digitalitems/documentation/generate-docs.mjs @@ -0,0 +1,196 @@ +import { cp, mkdir, readFile, rm, writeFile } from "node:fs/promises"; +import { spawnSync } from "node:child_process"; +import { dirname, relative, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import ts from "typescript"; + +const projectRoot = resolve(dirname(fileURLToPath(import.meta.url)), ".."); +const peripherals = [ + { interfaceName: "Digitizer", page: "guides/basic-digitizer.md" }, + { interfaceName: "AdvancedDigitizer", page: "guides/advanced-items.md" }, +]; + +function text(parts) { + return ts.displayPartsToString(parts).trim(); +} + +function tagsFor(signature, checker) { + const result = { params: new Map(), returns: "", throws: [] }; + for (const tag of signature.getJsDocTags(checker)) { + const value = text(tag.text); + if (tag.name === "param") { + const match = /^(\S+)\s*-?\s*(.*)$/s.exec(value); + if (match) result.params.set(match[1], match[2]); + } else if (tag.name === "returns" || tag.name === "return") result.returns = value; + else if (tag.name === "throws") result.throws.push(value); + } + return result; +} + +function sourceInterface(symbol) { + const declaration = symbol.valueDeclaration ?? symbol.declarations?.[0]; + let current = declaration; + while (current && !ts.isInterfaceDeclaration(current)) current = current.parent; + return current?.name.text; +} + +export function extractPeripheral(program, interfaceName) { + const checker = program.getTypeChecker(); + const matches = []; + for (const sourceFile of program.getSourceFiles()) { + if (sourceFile.isDeclarationFile && sourceFile.fileName.includes("typescript/lib/")) continue; + ts.forEachChild(sourceFile, (node) => { + if (ts.isInterfaceDeclaration(node) && node.name.text === interfaceName) matches.push(node); + }); + } + if (matches.length !== 1) throw new Error(`Expected one ${interfaceName} interface, found ${matches.length}`); + const declaration = matches[0]; + let peripheralType = null; + for (const sourceFile of program.getSourceFiles()) { + const visit = (node) => { + if (ts.isNewExpression(node) + && node.typeArguments?.[0]?.getText() === interfaceName + && node.arguments?.[0] + && ts.isStringLiteral(node.arguments[0])) { + peripheralType = node.arguments[0].text; + } + ts.forEachChild(node, visit); + }; + ts.forEachChild(sourceFile, visit); + } + if (!peripheralType) throw new Error(`No peripheral provider found for ${interfaceName}`); + const type = checker.getTypeAtLocation(declaration); + const methods = checker.getPropertiesOfType(type).flatMap((symbol) => { + const methodType = checker.getTypeOfSymbolAtLocation(symbol, declaration); + const signatures = checker.getSignaturesOfType(methodType, ts.SignatureKind.Call); + if (!signatures.length) return []; + return [{ + name: symbol.name, + inheritedFrom: sourceInterface(symbol) === interfaceName ? null : sourceInterface(symbol), + signatures: signatures.map((signature) => { + const tags = tagsFor(signature, checker); + const parameters = signature.getParameters().map((parameter) => { + const parameterDeclaration = parameter.valueDeclaration ?? parameter.declarations?.[0] ?? declaration; + return { + name: parameter.name, + type: checker.typeToString(checker.getTypeOfSymbolAtLocation(parameter, parameterDeclaration), declaration, ts.TypeFormatFlags.NoTruncation), + optional: Boolean(parameter.flags & ts.SymbolFlags.Optional) || Boolean(parameterDeclaration.questionToken), + description: tags.params.get(parameter.name) ?? "", + }; + }); + return { + signature: `${symbol.name}${checker.signatureToString(signature, declaration, ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.UseAliasDefinedOutsideCurrentScope)}`, + summary: text(signature.getDocumentationComment(checker)), + parameters, + returns: tags.returns, + throws: tags.throws, + }; + }), + }]; + }); + if (!methods.length) throw new Error(`${interfaceName} has no methods`); + return { interfaceName, peripheralType, methods }; +} + +function escapeCell(value) { + return value.replaceAll("|", "\\|").replaceAll("\n", " "); +} + +export function renderPeripheral(peripheral, revision = "") { + const lines = [ + "## Peripheral methods", + "", + "The reference below is generated from the published TypeScript interface.", + "", + ]; + for (const method of peripheral.methods) { + lines.push(`### \`${method.name}\``, ""); + if (method.inheritedFrom) lines.push(`*Inherited from \`${method.inheritedFrom}\`.*`, ""); + for (const [index, signature] of method.signatures.entries()) { + if (method.signatures.length > 1) lines.push(`#### Overload ${index + 1}`, ""); + lines.push("```typescript", signature.signature, "```", ""); + if (signature.summary) lines.push(signature.summary, ""); + if (signature.parameters.length) { + lines.push("| Parameter | Type | Description |", "| --- | --- | --- |"); + for (const parameter of signature.parameters) { + const name = `\`${parameter.name}${parameter.optional ? "?" : ""}\``; + lines.push(`| ${name} | \`${escapeCell(parameter.type)}\` | ${escapeCell(parameter.description)} |`); + } + lines.push(""); + } + if (signature.returns) lines.push(`**Returns:** ${signature.returns}`, ""); + for (const error of signature.throws) lines.push(`**Throws:** ${error}`, ""); + } + } + if (revision) lines.push(`[View TypeScript source](https://github.com/SirEdvin/DigitalItems/tree/${revision}/projects/typed-peripheral-digitalitems)`, ""); + return lines.join("\n"); +} + +function options(args) { + const result = { out: resolve(projectRoot, "docs"), revision: "", siteUrl: "" }; + for (let index = 0; index < args.length; index += 2) { + const value = args[index + 1]; + if (!value) throw new Error(`Missing value for ${args[index]}`); + if (args[index] === "--out") result.out = resolve(value); + else if (args[index] === "--gitRevision") result.revision = value; + else if (args[index] === "--hostedBaseUrl") result.siteUrl = value; + else throw new Error(`Unknown option: ${args[index]}`); + } + return result; +} + +export async function buildDocs(args = []) { + const config = options(args); + const buildRoot = resolve(projectRoot, ".mkdocs-build"); + await rm(buildRoot, { recursive: true, force: true }); + await cp(resolve(projectRoot, "documentation"), buildRoot, { + recursive: true, + filter: (path) => !path.endsWith("generate-docs.mjs") && !path.endsWith("generate-docs.test.mjs") && !path.includes("/theme/"), + }); + await mkdir(resolve(buildRoot, "assets/peripherals"), { recursive: true }); + const textureRoot = resolve(projectRoot, "../core/src/main/resources/assets/digitalitems/textures/block"); + await cp(resolve(textureRoot, "digitizer_front_on.png"), resolve(buildRoot, "assets/peripherals/digitizer.png")); + await cp(resolve(textureRoot, "advanced_digitizer_front_on.png"), resolve(buildRoot, "assets/peripherals/advanced_digitizer.png")); + await mkdir(resolve(buildRoot, "assets/stylesheets"), { recursive: true }); + await mkdir(resolve(buildRoot, "assets/javascripts"), { recursive: true }); + await cp(resolve(projectRoot, "documentation/theme/digitalitems.css"), resolve(buildRoot, "assets/stylesheets/digitalitems.css")); + await cp(resolve(projectRoot, "documentation/theme/digitalitems.js"), resolve(buildRoot, "assets/javascripts/digitalitems.js")); + await cp(resolve(projectRoot, "documentation/theme/favicon.svg"), resolve(buildRoot, "assets/favicon.svg")); + + const parsed = ts.parseJsonConfigFileContent( + ts.readConfigFile(resolve(projectRoot, "tsconfig.json"), ts.sys.readFile).config, + ts.sys, + projectRoot, + { noEmit: true, strictNullChecks: true }, + ); + const program = ts.createProgram(parsed.fileNames, parsed.options); + const errors = ts.getPreEmitDiagnostics(program); + if (errors.length) throw new Error(ts.formatDiagnosticsWithColorAndContext(errors, { + getCanonicalFileName: (name) => name, + getCurrentDirectory: () => projectRoot, + getNewLine: () => "\n", + })); + for (const peripheral of peripherals) { + const path = resolve(buildRoot, peripheral.page); + const markdown = await readFile(path, "utf8"); + const extracted = extractPeripheral(program, peripheral.interfaceName); + await writeFile(path, `${markdown.replaceAll("{{ peripheralType }}", extracted.peripheralType).trim()}\n\n${renderPeripheral(extracted, config.revision)}\n`); + } + + await rm(config.out, { recursive: true, force: true }); + const result = spawnSync("python3", ["-m", "mkdocs", "build", "--strict", "--clean", "--site-dir", config.out], { + cwd: projectRoot, + env: config.siteUrl ? { ...process.env, DOCS_SITE_URL: config.siteUrl } : process.env, + encoding: "utf8", + }); + if (result.status !== 0) throw new Error((result.stderr || result.stdout).trim()); + await rm(buildRoot, { recursive: true, force: true }); + return relative(projectRoot, config.out); +} + +if (resolve(process.argv[1] ?? "") === fileURLToPath(import.meta.url)) { + buildDocs(process.argv.slice(2)).catch((error) => { + process.stderr.write(`generate-docs: ${error.message}\n`); + process.exitCode = 1; + }); +} diff --git a/projects/typed-peripheral-digitalitems/documentation/generate-docs.test.mjs b/projects/typed-peripheral-digitalitems/documentation/generate-docs.test.mjs new file mode 100644 index 0000000..6c111e6 --- /dev/null +++ b/projects/typed-peripheral-digitalitems/documentation/generate-docs.test.mjs @@ -0,0 +1,34 @@ +import assert from "node:assert/strict"; +import { resolve } from "node:path"; +import test from "node:test"; +import ts from "typescript"; +import { extractPeripheral, renderPeripheral } from "./generate-docs.mjs"; + +const root = resolve(import.meta.dirname, ".."); +const parsed = ts.parseJsonConfigFileContent( + ts.readConfigFile(resolve(root, "tsconfig.json"), ts.sys.readFile).config, + ts.sys, + root, + { noEmit: true, strictNullChecks: true }, +); +const program = ts.createProgram(parsed.fileNames, parsed.options); + +test("extracts direct, inherited, and generic digitizer methods", () => { + const peripheral = extractPeripheral(program, "Digitizer"); + assert.equal(peripheral.peripheralType, "digitizer"); + assert.equal(peripheral.methods.length, 15); + assert.match(peripheral.methods.find(({ name }) => name === "getConfiguration").signatures[0].signature, /DigitizerConfiguration/); + assert.equal(peripheral.methods.find(({ name }) => name === "size").inheritedFrom, "InventoryViewAPI"); + assert.match(renderPeripheral(peripheral), /\*\*Throws:\*\* A Lua error if the slot is empty/); +}); + +test("preserves advanced digitizer overloads and nullable tuple unions", () => { + const peripheral = extractPeripheral(program, "AdvancedDigitizer"); + assert.equal(peripheral.peripheralType, "advanced_digitizer"); + assert.equal(peripheral.methods.length, 11); + assert.equal(peripheral.methods.find(({ name }) => name === "digitize").signatures.length, 2); + assert.equal(peripheral.methods.find(({ name }) => name === "get").signatures.length, 3); + const markdown = renderPeripheral(peripheral); + assert.match(markdown, /filter\?: number \| string \| LuaTable \| null/); + assert.match(markdown, /LuaMultiReturn<\[null, string\] \| \[number, null\]>/); +}); diff --git a/projects/typed-peripheral-digitalitems/documentation/guides/advanced-items.md b/projects/typed-peripheral-digitalitems/documentation/guides/advanced-items.md index 42faf03..00d5cd1 100644 --- a/projects/typed-peripheral-digitalitems/documentation/guides/advanced-items.md +++ b/projects/typed-peripheral-digitalitems/documentation/guides/advanced-items.md @@ -5,8 +5,8 @@ peripheralInterface: AdvancedDigitizer # Advanced Digitizer
-
Advanced digitizer block
-
MULTI-STORAGE PERIPHERAL

The advanced digitizer moves items, fluids, and energy between attached storage and durable digital identifiers.

Peripheral type
advanced_digitizer
Storage
Items, fluids, energy
Failure style
Recoverable result pairs
+
Advanced digitizer block
+
MULTI-STORAGE PERIPHERAL

The advanced digitizer moves items, fluids, and energy between attached storage and durable digital identifiers.

Peripheral type
{{ peripheralType }}
Storage
Items, fluids, energy
Failure style
Recoverable result pairs
The advanced digitizer can extract from its internal inventory with source diff --git a/projects/typed-peripheral-digitalitems/documentation/guides/basic-digitizer.md b/projects/typed-peripheral-digitalitems/documentation/guides/basic-digitizer.md index b3eb5c6..ad1a08a 100644 --- a/projects/typed-peripheral-digitalitems/documentation/guides/basic-digitizer.md +++ b/projects/typed-peripheral-digitalitems/documentation/guides/basic-digitizer.md @@ -5,8 +5,8 @@ peripheralInterface: Digitizer # Basic Digitizer
-
Digitizer block
-
ITEM PERIPHERAL

The basic digitizer turns physical item stacks into portable digital identifiers and restores them through its internal inventory.

Peripheral type
digitizer
Storage
Items
Failure style
Lua errors
+
Digitizer block
+
ITEM PERIPHERAL

The basic digitizer turns physical item stacks into portable digital identifiers and restores them through its internal inventory.

Peripheral type
{{ peripheralType }}
Storage
Items
Failure style
Lua errors
Slots are one-based and default to slot 1. `digitize()` removes the complete diff --git a/projects/typed-peripheral-digitalitems/documentation/index.md b/projects/typed-peripheral-digitalitems/documentation/index.md index c3dd707..a216b0d 100644 --- a/projects/typed-peripheral-digitalitems/documentation/index.md +++ b/projects/typed-peripheral-digitalitems/documentation/index.md @@ -7,12 +7,12 @@ TypeScript with TypeScriptToLua. ## Choose your digitizer
- - Digitizer block + + Digitizer block DigitizerPeripheral type: digitizerDigitize and restore items through a simple internal inventory.Open peripheral guide → - - Advanced digitizer block + + Advanced digitizer block Advanced DigitizerPeripheral type: advanced_digitizerMove items, fluids, and energy between remote storage and digital IDs.Open peripheral guide →
diff --git a/projects/typed-peripheral-digitalitems/documentation/theme/digitalitems.css b/projects/typed-peripheral-digitalitems/documentation/theme/digitalitems.css index bba38b1..5b4ff27 100644 --- a/projects/typed-peripheral-digitalitems/documentation/theme/digitalitems.css +++ b/projects/typed-peripheral-digitalitems/documentation/theme/digitalitems.css @@ -1,271 +1,17 @@ -@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap"); +@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;600&family=Manrope:wght@400;600;700;800&display=swap"); :root { - --di-accent: #4f46e5; - --di-accent-hover: #4338ca; - --di-accent-dark: #3730a3; - --di-accent-subtle: rgba(79, 70, 229, 0.06); - --di-bg: #ffffff; - --di-bg-secondary: #f8fafc; - --di-bg-elevated: #eef2ff; - --di-bg-code: #f1f5f9; - --di-border: rgba(79, 70, 229, 0.1); - --di-border-subtle: rgba(148, 163, 184, 0.12); - --di-text-primary: #0f172a; - --di-text-secondary: #475569; - --di-text-muted: #94a3b8; - --di-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04); - --di-shadow-md: 0 2px 8px rgba(0, 0, 0, 0.06); - --color-background: var(--di-bg); - --color-background-secondary: var(--di-bg-secondary); - --color-background-active: var(--di-bg-elevated); - --color-accent: var(--di-accent); - --color-text: var(--di-text-primary); - --color-text-aside: var(--di-text-secondary); - --color-link: #4f46e5; - --color-ts-keyword: #c084fc; - --color-ts-string: #34d399; - --color-ts-number: #fb923c; + --md-text-font: "Manrope"; + --md-code-font: "IBM Plex Mono"; + --di-line: color-mix(in srgb, var(--md-primary-fg-color) 28%, transparent); + --di-panel: color-mix(in srgb, var(--md-primary-fg-color) 7%, var(--md-default-bg-color)); + --di-warm: #e29a32; } -html[data-theme="dark"] { - --di-accent: #6366f1; - --di-accent-hover: #818cf8; - --di-accent-dark: #4f46e5; - --di-accent-subtle: rgba(99, 102, 241, 0.08); - --di-bg: #0c0e16; - --di-bg-secondary: #141622; - --di-bg-elevated: #1a1d2e; - --di-bg-code: #111322; - --di-border: rgba(99, 102, 241, 0.12); - --di-border-subtle: rgba(148, 163, 184, 0.08); - --di-text-primary: #e2e8f0; - --di-text-secondary: #8892b0; - --di-text-muted: #5a6380; - --di-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.12); - --di-shadow-md: 0 2px 8px rgba(0, 0, 0, 0.18); - --color-text: var(--di-text-primary); - --color-link: #818cf8; -} - -@media (prefers-color-scheme: dark) { - html[data-theme="os"] { - --di-accent: #6366f1; - --di-accent-hover: #818cf8; - --di-accent-dark: #4f46e5; - --di-accent-subtle: rgba(99, 102, 241, 0.08); - --di-bg: #0c0e16; - --di-bg-secondary: #141622; - --di-bg-elevated: #1a1d2e; - --di-bg-code: #111322; - --di-border: rgba(99, 102, 241, 0.12); - --di-border-subtle: rgba(148, 163, 184, 0.08); - --di-text-primary: #e2e8f0; - --di-text-secondary: #8892b0; - --di-text-muted: #5a6380; - --di-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.12); - --di-shadow-md: 0 2px 8px rgba(0, 0, 0, 0.18); - --color-text: var(--di-text-primary); - --color-link: #818cf8; - } -} - -body { - font-family: "Inter", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - line-height: 1.6; - background-color: var(--di-bg); -} - -.container-main { - backdrop-filter: none; -} - -.col-content { - position: relative; - max-width: 920px; -} - -.col-content::before { - content: none; - display: none; -} - -h1, h2, h3, h4, h5, h6, -.site-menu, -.tsd-page-title { - font-family: "Inter", system-ui, -apple-system, sans-serif; - letter-spacing: -0.025em; -} - -h1 { - font-weight: 800; - font-size: 2rem; - line-height: 1.25; - text-wrap: balance; - margin-bottom: 1rem; -} - -h2 { - font-weight: 700; - font-size: 1.5rem; - line-height: 1.3; - border-bottom: 1px solid var(--di-border); - padding-bottom: 0.5rem; - margin-top: 2.5rem; - margin-bottom: 1rem; -} - -h3 { - font-weight: 600; - font-size: 1.25rem; - line-height: 1.4; - margin-top: 1.75rem; - margin-bottom: 0.75rem; -} - -h4 { - font-weight: 600; - font-size: 1.1rem; - margin-top: 1.5rem; - margin-bottom: 0.5rem; -} - -p { - margin-bottom: 1rem; -} - -ul, ol { - margin-bottom: 1rem; - padding-left: 1.5rem; -} - -li { - margin-bottom: 0.35rem; -} - -.tsd-panel { - border: 1px solid var(--di-border); - border-radius: 10px; - box-shadow: var(--di-shadow-sm); - background: var(--di-bg-secondary); -} - -.tsd-member { - border: 1px solid var(--di-border); - border-radius: 10px; - box-shadow: var(--di-shadow-sm); -} - -.tsd-signature, -code, -pre { - font-family: "JetBrains Mono", "Fira Code", "Cascadia Code", Consolas, monospace; -} - -code { - background: var(--di-bg-code); - border: 1px solid var(--di-border-subtle); - border-radius: 5px; - padding: 0.1em 0.4em; - font-size: 0.875em; - color: var(--di-accent-hover); -} - -html[data-theme="light"] code { - color: var(--di-accent); -} - -pre { - background: var(--di-bg-code); - border: 1px solid var(--di-border); - border-radius: 10px; - padding: 1rem 1.25rem; - overflow-x: auto; - box-shadow: var(--di-shadow-sm); -} - -pre code { - background: none; - border: none; - padding: 0; - font-size: 0.85rem; - line-height: 1.65; - color: var(--di-text-primary); -} - -a { - color: var(--color-link); - text-decoration: none; - text-underline-offset: 0.2em; - transition: color 0.15s ease; -} - -a:hover { - color: var(--di-accent-hover); -} - -table { - border: 1px solid var(--di-border); - border-radius: 10px; - overflow: hidden; - box-shadow: var(--di-shadow-sm); -} - -th, td { - border-color: var(--di-border-subtle); -} - -.tsd-page-toolbar { - background: var(--di-bg); - border-bottom: 1px solid var(--di-border); -} - -.tsd-page-toolbar .title { - font-family: "Inter", system-ui, sans-serif; - font-weight: 700; - color: var(--di-text-primary); -} - -.di-signal-line { - display: none !important; -} - -.col-content p, -.col-content li { - max-width: 78ch; -} - -.col-content table { - width: 100%; - border-collapse: collapse; - overflow: hidden; -} - -.col-content th { - color: var(--di-accent-hover); - background: var(--di-bg-elevated); - text-align: left; -} - -.col-content th, -.col-content td { - padding: 0.8rem 1rem; - border-bottom: 1px solid var(--di-border-subtle); - vertical-align: top; -} - -.col-content blockquote { - margin: 1.5rem 0; - padding: 0.8rem 1.1rem; - border-left: 4px solid var(--color-ts-number); - background: color-mix(in srgb, var(--color-ts-number) 7%, var(--di-bg-secondary)); -} - -.col-content blockquote p { - margin: 0; -} +.md-grid { max-width: 78rem; } +.md-typeset h1 { font-weight: 800; letter-spacing: -.04em; } +.md-typeset h2 { margin-top: 2.5em; padding-bottom: .35em; border-bottom: 1px solid var(--di-line); } +.md-typeset h3 code { font-size: .9em; color: var(--md-accent-fg-color); } .di-peripheral-grid { display: grid; @@ -276,329 +22,72 @@ th, td { .di-peripheral-card, .di-peripheral-hero { - border: 1px solid var(--di-border); - background: linear-gradient(145deg, var(--di-bg-elevated), var(--di-bg-secondary)); + border: 1px solid var(--di-line); + background: linear-gradient(145deg, var(--di-panel), var(--md-default-bg-color)); + box-shadow: 0 14px 35px rgba(0, 0, 0, .08); } .di-peripheral-card { display: flex; gap: 1.2rem; - min-height: 190px; - padding: 1.25rem; - border-radius: 10px; - color: var(--color-text); - text-decoration: none; - transition: border-color 160ms ease, transform 160ms ease; + min-height: 11rem; + padding: 1.2rem; + border-radius: .55rem; + color: var(--md-default-fg-color) !important; + transition: transform 160ms ease, border-color 160ms ease; } -.di-peripheral-card:hover { - border-color: var(--di-accent-hover); - color: var(--color-text); - transform: translateY(-3px); -} - -.di-peripheral-card--advanced, -.di-peripheral-hero--advanced { - border-color: color-mix(in srgb, var(--color-ts-number) 35%, transparent); -} +.di-peripheral-card:hover { transform: translateY(-3px); border-color: var(--md-accent-fg-color); } +.di-peripheral-card--advanced, .di-peripheral-hero--advanced { border-color: color-mix(in srgb, var(--di-warm) 45%, transparent); } .di-peripheral-image { display: grid; - flex: 0 0 128px; - min-height: 128px; + flex: 0 0 7rem; + min-height: 7rem; place-items: center; - border-radius: 6px; - background-color: #0a1114; - background-image: linear-gradient(45deg, rgba(255,255,255,.035) 25%, transparent 25%, transparent 75%, rgba(255,255,255,.035) 75%), linear-gradient(45deg, rgba(255,255,255,.035) 25%, transparent 25%, transparent 75%, rgba(255,255,255,.035) 75%); - background-position: 0 0, 8px 8px; - background-size: 16px 16px; + border-radius: .35rem; + background: #091114 repeating-conic-gradient(rgba(255,255,255,.035) 0 25%, transparent 0 50%) 0 / 16px 16px; } -.di-peripheral-image img { - width: 112px; - height: 112px; - image-rendering: pixelated; -} - -.di-peripheral-copy { - display: flex; - flex-direction: column; -} - -.di-peripheral-copy strong { - font-size: 1.25rem; -} - -.di-peripheral-copy small { - margin: 0.25rem 0 0.75rem; - color: var(--di-text-secondary); -} - -.di-peripheral-copy b { - margin-top: auto; - color: var(--di-accent-hover); - font-size: 0.82rem; -} +.di-peripheral-image img { width: 6rem; height: 6rem; image-rendering: pixelated; } +.di-peripheral-copy { display: flex; flex-direction: column; } +.di-peripheral-copy strong { font-size: 1.15rem; } +.di-peripheral-copy small { margin: .25rem 0 .65rem; opacity: .72; } +.di-peripheral-copy b { margin-top: auto; color: var(--md-accent-fg-color); font-size: .78rem; } .di-peripheral-hero { display: grid; - grid-template-columns: 176px minmax(0, 1fr); - gap: 1.75rem; + grid-template-columns: 10rem minmax(0, 1fr); + gap: 1.5rem; margin: 1rem 0 2rem; - padding: 1.5rem; - border-radius: 10px; -} - -.di-peripheral-hero .di-peripheral-image { - min-height: 176px; -} - -.di-peripheral-hero .di-peripheral-image img { - width: 144px; - height: 144px; -} - -.di-eyebrow { - color: var(--color-ts-number); - font: 700 0.7rem/1 "Lucida Console", Monaco, monospace; - letter-spacing: 0.12em; -} - -.di-peripheral-hero p { - margin: 0.55rem 0 1rem; - font-size: 1.05rem; -} - -.di-peripheral-hero dl { - display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 0.7rem; - margin: 0; -} - -.di-peripheral-hero dl div { - min-width: 0; -} - -.di-peripheral-hero dt { - color: var(--di-text-secondary); - font-size: 0.68rem; - text-transform: uppercase; - letter-spacing: 0.06em; -} - -.di-peripheral-hero dd { - margin: 0.2rem 0 0; - overflow-wrap: anywhere; - font-weight: 650; -} - -.di-method-reference { - margin-top: 3rem; -} - -.di-generated-note { - margin-bottom: 1.25rem; - color: var(--di-text-secondary); - font-size: 0.9rem; -} - -.di-method-card { - margin: 1rem 0; - border: 1px solid var(--di-border); - border-radius: 8px; - background: var(--di-bg-secondary); - box-shadow: 0 8px 22px rgba(0, 0, 0, 0.1); - overflow: hidden; -} - -.di-method-card > h3 { - margin: 0; - padding: 0.75rem 1rem; - border-bottom: 1px solid var(--di-border); - background: var(--di-bg-elevated); - color: var(--di-accent-hover); - font-size: 1rem; -} - -.di-method-overload { - padding: 1rem; -} - -.di-method-overload + .di-method-overload { - border-top: 1px dashed var(--di-border); -} - -.di-method-overload .tsd-signature { - margin: 0 0 1rem; - padding: 0.8rem; - box-shadow: none; - overflow-x: auto; -} - -.di-method-overload .tsd-comment { - margin: 0.75rem 0; -} - -.di-method-overload h4 { - margin: 1rem 0 0.35rem; - color: var(--di-text-secondary); - font-size: 0.78rem; - letter-spacing: 0.05em; - text-transform: uppercase; -} - -.di-version-panel { - margin: 0.5rem 0 1rem; - padding: 0.6rem 0.75rem; - border: 1px solid var(--di-border); - border-radius: 8px; - background: var(--di-bg-secondary); -} - -.di-version-label { - display: block; - margin-bottom: 0.3rem; - color: var(--di-accent); - font: 600 0.68rem/1.2 "Inter", system-ui, sans-serif; - letter-spacing: 0.05em; - text-transform: uppercase; -} - -#di-version-select { - width: 100%; - padding: 0.35rem 0.5rem; - border: 1px solid var(--di-border); - border-radius: 6px; - color: var(--di-text-primary); - background: var(--di-bg); - font-family: "Inter", system-ui, sans-serif; - font-size: 0.82rem; -} - -#di-version-select:focus-visible { - outline: 2px solid var(--di-accent); - outline-offset: 1px; -} - -.tsd-typography { - line-height: 1.7; -} - -.tsd-anchor-link { - color: var(--di-accent); -} - -.tsd-anchor-link:hover { - color: var(--di-accent-hover); -} - -.tsd-kind-icon { - color: var(--di-accent); -} - -.tsd-navigation a, -.tsd-nav-link { - font-family: "Inter", system-ui, sans-serif; -} - -.tsd-accordion-summary { - font-family: "Inter", system-ui, sans-serif; -} - -.tsd-filter-visibility .settings-label { - font-family: "Inter", system-ui, sans-serif; - font-weight: 600; - font-size: 0.8rem; - letter-spacing: 0.03em; - text-transform: uppercase; - color: var(--di-text-secondary); -} - -#tsd-theme { - font-family: "Inter", system-ui, sans-serif; - border: 1px solid var(--di-border); - border-radius: 6px; - padding: 0.3rem 0.5rem; - background: var(--di-bg); - color: var(--di-text-primary); - font-size: 0.82rem; -} - -.tsd-search-input { - font-family: "Inter", system-ui, sans-serif; - border: 1px solid var(--di-border); - border-radius: 8px; -} - -.tsd-generator { - border-top: 1px solid var(--di-border); - padding-top: 1rem; - margin-top: 2rem; - color: var(--di-text-muted); - font-size: 0.82rem; -} - -footer { - border-top: 1px solid var(--di-border); -} - -@media (prefers-reduced-motion: no-preference) { - .col-content > * { - animation: di-fade-in 180ms ease-out both; - } - - @keyframes di-fade-in { - from { - opacity: 0; - transform: translateY(3px); - } - } - - a, .tsd-panel, .tsd-member { - transition: all 0.15s ease; - } -} - -@media (max-width: 769px) { - h1 { font-size: 1.5rem; } - h2 { font-size: 1.25rem; } - h3 { font-size: 1.1rem; } - - .tsd-signature, - pre, - table { - max-width: 100%; - overflow-x: auto; - } - - .di-peripheral-grid { - grid-template-columns: 1fr; - } - - .di-peripheral-hero { - grid-template-columns: 1fr; - } - - .di-peripheral-hero .di-peripheral-image { - min-height: 144px; - } - - .di-peripheral-hero dl { - grid-template-columns: 1fr 1fr; - } -} - -@media (max-width: 480px) { - .di-peripheral-card { - flex-direction: column; - } - - .di-peripheral-image { - flex-basis: auto; - } - - .di-peripheral-hero dl { - grid-template-columns: 1fr; - } + padding: 1.4rem; + border-radius: .55rem; +} + +.di-peripheral-hero .di-peripheral-image { min-height: 10rem; } +.di-peripheral-hero .di-peripheral-image img { width: 8rem; height: 8rem; } +.di-eyebrow { color: var(--di-warm); font: 600 .66rem/1 "IBM Plex Mono"; letter-spacing: .12em; } +.di-peripheral-hero p { margin: .55rem 0 1rem; font-size: .95rem; } +.di-peripheral-hero dl { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .7rem; margin: 0; } +.di-peripheral-hero dt { opacity: .65; font-size: .62rem; text-transform: uppercase; letter-spacing: .06em; } +.di-peripheral-hero dd { margin: .15rem 0 0; overflow-wrap: anywhere; font-weight: 700; } + +.md-typeset h2#peripheral-methods ~ h3 { + margin: 1.4rem 0 0; + padding: .75rem 1rem; + border: 1px solid var(--di-line); + border-bottom: 0; + border-radius: .45rem .45rem 0 0; + background: var(--di-panel); +} + +.md-typeset table:not([class]) { display: table; width: 100%; } +.md-typeset table:not([class]) th { background: var(--di-panel); } +#di-version-select { max-width: 15rem; padding: .28rem .5rem; border: 1px solid var(--di-line); border-radius: .25rem; color: inherit; background: var(--md-default-bg-color); font: 600 .65rem "IBM Plex Mono"; } + +@media (max-width: 760px) { + .di-peripheral-grid { grid-template-columns: 1fr; } + .di-peripheral-hero { grid-template-columns: 1fr; } + .di-peripheral-hero dl { grid-template-columns: 1fr; } + .di-peripheral-hero .di-peripheral-image { min-height: 9rem; } } diff --git a/projects/typed-peripheral-digitalitems/documentation/theme/digitalitems.js b/projects/typed-peripheral-digitalitems/documentation/theme/digitalitems.js index 5e11b2e..9e1f407 100644 --- a/projects/typed-peripheral-digitalitems/documentation/theme/digitalitems.js +++ b/projects/typed-peripheral-digitalitems/documentation/theme/digitalitems.js @@ -1,28 +1,18 @@ -(() => { - const themeSelector = document.querySelector("#tsd-theme"); - if (themeSelector instanceof HTMLSelectElement) { - const systemOption = themeSelector.querySelector('option[value="os"]'); - if (systemOption) systemOption.textContent = "System"; - } - - const selector = document.querySelector("#di-version-select"); - if (!(selector instanceof HTMLSelectElement)) return; - - const script = document.currentScript ?? [...document.scripts].find((entry) => - entry.src.endsWith("/custom.js") - ); +document.addEventListener("DOMContentLoaded", () => { + const script = [...document.scripts].find((entry) => entry.src.endsWith("/assets/javascripts/digitalitems.js")); if (!script) return; - const scriptUrl = new URL(script.src); - const versionRoot = scriptUrl.pathname.match( - /^(.*\/)(?:branch|tag)\/[^/]+\/assets\/custom\.js$/ - ); - if (!versionRoot) return; - - const siteRoot = new URL(versionRoot[1], scriptUrl.origin); - const currentPath = decodeURIComponent( - scriptUrl.pathname.slice(versionRoot[1].length).replace(/assets\/custom\.js$/, "") - ); + const match = scriptUrl.pathname.match(/^(.*\/)((?:branch|tag)\/[^/]+)\/assets\/javascripts\/digitalitems\.js$/); + if (!match) return; + + const siteRoot = new URL(match[1], scriptUrl.origin); + const currentVersion = `${decodeURIComponent(match[2])}/`; + const select = document.createElement("select"); + select.id = "di-version-select"; + select.ariaLabel = "Documentation version"; + select.disabled = true; + select.append(new Option("Loading versions...")); + document.querySelector(".md-header__inner")?.append(select); fetch(new URL("versions.json", siteRoot)) .then((response) => { @@ -30,38 +20,15 @@ return response.json(); }) .then((manifest) => { - if (!manifest || !Array.isArray(manifest.versions)) { - throw new Error("Unsupported version manifest"); - } - - selector.replaceChildren(); - const groups = new Map([ - ["branch", document.createElement("optgroup")], - ["tag", document.createElement("optgroup")], - ]); - groups.get("branch").label = "Development branches"; - groups.get("tag").label = "Releases"; - - for (const entry of manifest.versions) { - if (!entry || !groups.has(entry.kind) || typeof entry.path !== "string") continue; - const option = document.createElement("option"); - option.value = entry.path; - option.textContent = entry.label || entry.name; - option.selected = entry.path === currentPath; - groups.get(entry.kind).append(option); - } - - for (const group of groups.values()) { - if (group.children.length > 0) selector.append(group); + select.replaceChildren(); + for (const entry of manifest.versions ?? []) { + const option = new Option(entry.label || entry.name, entry.path); + option.selected = entry.path === currentVersion; + select.append(option); } - selector.disabled = selector.options.length === 0; + select.disabled = select.options.length === 0; }) - .catch(() => { - selector.options[0].textContent = "Version list unavailable"; - }); + .catch(() => { select.options[0].textContent = "Versions unavailable"; }); - selector.addEventListener("change", () => { - if (!selector.value) return; - window.location.assign(new URL(selector.value, siteRoot)); - }); -})(); + select.addEventListener("change", () => window.location.assign(new URL(select.value, siteRoot))); +}); diff --git a/projects/typed-peripheral-digitalitems/documentation/theme/plugin.mjs b/projects/typed-peripheral-digitalitems/documentation/theme/plugin.mjs deleted file mode 100644 index 294aa81..0000000 --- a/projects/typed-peripheral-digitalitems/documentation/theme/plugin.mjs +++ /dev/null @@ -1,67 +0,0 @@ -import { JSX, ReflectionKind } from "typedoc"; - -function renderPeripheralMethods(context) { - if (!context.model.isDocument()) return; - - const interfaceName = context.model.frontmatter.peripheralInterface; - if (typeof interfaceName !== "string") return; - - const peripheral = context.page.project - .getReflectionsByKind(ReflectionKind.Interface) - .find((reflection) => reflection.name === interfaceName); - if (!peripheral?.children) return; - - const methods = peripheral.children.filter( - (reflection) => reflection.kindOf(ReflectionKind.Method) && reflection.signatures?.length - ); - if (methods.length === 0) return; - - context.page.pageHeadings.push({ - link: "#peripheral-methods", - text: "Peripheral methods", - level: 2, - }); - - return JSX.createElement( - "section", - { class: "di-method-reference", "aria-labelledby": "peripheral-methods" }, - JSX.createElement("h2", { id: "peripheral-methods" }, "Peripheral methods"), - JSX.createElement( - "p", - { class: "di-generated-note" }, - "Generated from the TypeScript interface. Signatures, parameters, return values, and errors stay synchronized with the published API." - ), - ...methods.map((method) => - JSX.createElement( - "article", - { class: "di-method-card" }, - JSX.createElement("h3", null, method.name), - ...method.signatures.map((signature) => - JSX.createElement( - "div", - { class: "di-method-overload" }, - context.memberSignatureTitle(signature), - context.memberSignatureBody(signature, { hideSources: true }) - ) - ) - ) - ) - ); -} - -export function load(app) { - app.renderer.hooks.on("sidebar.begin", () => - JSX.createElement( - "section", - { class: "di-version-panel", "aria-label": "Documentation version" }, - JSX.createElement("span", { class: "di-version-label" }, "Version"), - JSX.createElement( - "select", - { id: "di-version-select", disabled: true }, - JSX.createElement("option", null, "Local build") - ) - ) - ); - - app.renderer.hooks.on("content.end", renderPeripheralMethods); -} diff --git a/projects/typed-peripheral-digitalitems/mkdocs.yml b/projects/typed-peripheral-digitalitems/mkdocs.yml new file mode 100644 index 0000000..6c1f4a6 --- /dev/null +++ b/projects/typed-peripheral-digitalitems/mkdocs.yml @@ -0,0 +1,65 @@ +site_name: Digital Items Peripheral API +site_description: TypeScript and Lua reference for Digital Items peripherals +site_url: !ENV [DOCS_SITE_URL, "https://siredvin.github.io/DigitalItems/branch/1.20/"] +repo_url: https://github.com/SirEdvin/DigitalItems +repo_name: SirEdvin/DigitalItems +docs_dir: .mkdocs-build +site_dir: docs +strict: true + +theme: + name: material + logo: assets/favicon.svg + favicon: assets/favicon.svg + palette: + - media: "(prefers-color-scheme: light)" + scheme: default + primary: teal + accent: amber + toggle: + icon: material/weather-night + name: Use dark mode + - media: "(prefers-color-scheme: dark)" + scheme: slate + primary: teal + accent: amber + toggle: + icon: material/weather-sunny + name: Use light mode + features: + - content.code.copy + - navigation.footer + - navigation.indexes + - navigation.sections + - navigation.top + - search.highlight + +nav: + - Overview: index.md + - Getting started: getting-started.md + - Digital identifiers: digital-identifiers.md + - Peripherals: + - Basic digitizer: guides/basic-digitizer.md + - Advanced digitizer: guides/advanced-items.md + - Guides: + - Fluids and energy: guides/fluids-and-energy.md + +markdown_extensions: + - admonition + - attr_list + - md_in_html + - pymdownx.details + - pymdownx.highlight: + anchor_linenums: true + - pymdownx.superfences + - toc: + permalink: true + +extra_css: + - assets/stylesheets/digitalitems.css +extra_javascript: + - assets/javascripts/digitalitems.js +extra: + social: + - icon: fontawesome/brands/github + link: https://github.com/SirEdvin/DigitalItems diff --git a/projects/typed-peripheral-digitalitems/package-lock.json b/projects/typed-peripheral-digitalitems/package-lock.json index 5cac6cb..82e3e95 100644 --- a/projects/typed-peripheral-digitalitems/package-lock.json +++ b/projects/typed-peripheral-digitalitems/package-lock.json @@ -17,80 +17,16 @@ "@siredvin/typed-peripheral-base": "*" }, "devDependencies": { - "typedoc": "0.28.20", "typescript": "5.7.2", "typescript-to-lua": "1.29.1" } }, - "node_modules/@gerrit0/mini-shiki": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.23.0.tgz", - "integrity": "sha512-bEMORlG0cqdjVyCEuU0cDQbORWX+kYCeo0kV1lbxF5bt4r7SID2l9bqsxJEM0zndaxpOUT7riCyIVEuqq/Ynxg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@shikijs/engine-oniguruma": "^3.23.0", - "@shikijs/langs": "^3.23.0", - "@shikijs/themes": "^3.23.0", - "@shikijs/types": "^3.23.0", - "@shikijs/vscode-textmate": "^10.0.2" - } - }, "node_modules/@jackmacwindows/lua-types": { "version": "2.13.2", "resolved": "https://registry.npmjs.org/@jackmacwindows/lua-types/-/lua-types-2.13.2.tgz", "integrity": "sha512-XoqHmgtG1SLWzmMx8wQc0sJtPmrzjCFbiwNiBIZE7HOEXWdJi7NDKVlE1nl9A5745Yb5jIkfz2deOzMtHiHVcQ==", "license": "MIT" }, - "node_modules/@shikijs/engine-oniguruma": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.23.0.tgz", - "integrity": "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.23.0", - "@shikijs/vscode-textmate": "^10.0.2" - } - }, - "node_modules/@shikijs/langs": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.23.0.tgz", - "integrity": "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.23.0" - } - }, - "node_modules/@shikijs/themes": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.23.0.tgz", - "integrity": "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.23.0" - } - }, - "node_modules/@shikijs/types": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.23.0.tgz", - "integrity": "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.4" - } - }, - "node_modules/@shikijs/vscode-textmate": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", - "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", - "dev": true, - "license": "MIT" - }, "node_modules/@siredvin/api-types": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@siredvin/api-types/-/api-types-1.1.0.tgz", @@ -134,23 +70,6 @@ "@siredvin/craftos-types": "1.2.0" } }, - "node_modules/@types/hast": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.5.tgz", - "integrity": "sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "dev": true, - "license": "MIT" - }, "node_modules/@typescript-to-lua/language-extensions": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/@typescript-to-lua/language-extensions/-/language-extensions-1.19.0.tgz", @@ -158,36 +77,6 @@ "dev": true, "license": "MIT" }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/brace-expansion": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", - "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, "node_modules/enhanced-resolve": { "version": "5.8.2", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.2.tgz", @@ -202,19 +91,6 @@ "node": ">=10.13.0" } }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/es-errors": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", @@ -271,84 +147,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/linkify-it": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.2.tgz", - "integrity": "sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/markdown-it" - } - ], - "license": "MIT", - "dependencies": { - "uc.micro": "^2.0.0" - } - }, - "node_modules/lunr": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", - "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", - "dev": true, - "license": "MIT" - }, - "node_modules/markdown-it": { - "version": "14.3.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.3.0.tgz", - "integrity": "sha512-RCEsPjR+sr0x+AuYp601tKTkgFG4YEPLCzHST3cQ/fhlJkqAkz1L2/Qbp1j9qw5SBwQHFBoW8+hoN5xssOF0Tw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/markdown-it" - } - ], - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1", - "entities": "^4.5.0", - "linkify-it": "^5.0.2", - "mdurl": "^2.0.0", - "punycode.js": "^2.3.1", - "uc.micro": "^2.1.0" - }, - "bin": { - "markdown-it": "bin/markdown-it.mjs" - } - }, - "node_modules/mdurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", - "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", - "dev": true, - "license": "MIT" - }, - "node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", @@ -369,16 +167,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/punycode.js": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", - "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/resolve": { "version": "1.22.12", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", @@ -438,30 +226,6 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/typedoc": { - "version": "0.28.20", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.28.20.tgz", - "integrity": "sha512-uSKqkh8Cr48vllnEy+jdaAgOeR6Y+QCBW7usgUsKj7gJEfR7stw9U/fE49LBnj2tPRKPY0c0EBJSWe9Appmplg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@gerrit0/mini-shiki": "^3.23.0", - "lunr": "^2.3.9", - "markdown-it": "^14.3.0", - "minimatch": "^10.2.5", - "yaml": "^2.9.0" - }, - "bin": { - "typedoc": "bin/typedoc" - }, - "engines": { - "node": ">= 18", - "pnpm": ">= 10" - }, - "peerDependencies": { - "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x || 6.0.x" - } - }, "node_modules/typescript": { "version": "5.7.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", @@ -498,29 +262,6 @@ "peerDependencies": { "typescript": "5.7.2" } - }, - "node_modules/uc.micro": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", - "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", - "dev": true, - "license": "MIT" - }, - "node_modules/yaml": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", - "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", - "dev": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } } } } diff --git a/projects/typed-peripheral-digitalitems/package.json b/projects/typed-peripheral-digitalitems/package.json index 0a8ab07..1741f11 100644 --- a/projects/typed-peripheral-digitalitems/package.json +++ b/projects/typed-peripheral-digitalitems/package.json @@ -14,8 +14,8 @@ "scripts": { "build": "tstl", "clean": "rm -f *.lua *.d.ts", - "docs": "typedoc", - "docs:watch": "typedoc --watch" + "docs": "node documentation/generate-docs.mjs", + "docs:test": "node --test documentation/generate-docs.test.mjs" }, "dependencies": { "@jackmacwindows/lua-types": "^2.13.1", @@ -26,7 +26,6 @@ "@siredvin/typed-peripheral-base": "*" }, "devDependencies": { - "typedoc": "0.28.20", "typescript": "5.7.2", "typescript-to-lua": "1.29.1" } diff --git a/projects/typed-peripheral-digitalitems/requirements-docs.txt b/projects/typed-peripheral-digitalitems/requirements-docs.txt new file mode 100644 index 0000000..c8de0c5 --- /dev/null +++ b/projects/typed-peripheral-digitalitems/requirements-docs.txt @@ -0,0 +1 @@ +mkdocs-material==9.6.14 diff --git a/projects/typed-peripheral-digitalitems/tsconfig.docs.json b/projects/typed-peripheral-digitalitems/tsconfig.docs.json deleted file mode 100644 index 35b63ea..0000000 --- a/projects/typed-peripheral-digitalitems/tsconfig.docs.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "skipLibCheck": true - }, - "include": ["./*.ts"] -} diff --git a/projects/typed-peripheral-digitalitems/typedoc.json b/projects/typed-peripheral-digitalitems/typedoc.json deleted file mode 100644 index 9a3b9c5..0000000 --- a/projects/typed-peripheral-digitalitems/typedoc.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "$schema": "https://typedoc.org/schema.json", - "entryPoints": ["./shared.ts", "./digitizer.ts", "./advanced_digitizer.ts"], - "tsconfig": "./tsconfig.docs.json", - "out": "./docs", - "name": "@siredvin/typed-peripheral-digitalitems", - "readme": "./documentation/index.md", - "projectDocuments": [ - "./documentation/getting-started.md", - "./documentation/digital-identifiers.md", - "./documentation/guides/*.md" - ], - "plugin": ["./documentation/theme/plugin.mjs"], - "customCss": "./documentation/theme/digitalitems.css", - "customJs": "./documentation/theme/digitalitems.js", - "favicon": "./documentation/theme/favicon.svg", - "lightHighlightTheme": "material-theme-lighter", - "darkHighlightTheme": "material-theme-darker", - "highlightLanguages": ["typescript", "lua", "json", "bash"], - "excludeExternals": true, - "basePath": "../..", - "sourceLinkTemplate": "https://github.com/SirEdvin/DigitalItems/blob/{gitRevision}/{path}#L{line}", - "navigationLinks": { - "GitHub": "https://github.com/SirEdvin/DigitalItems" - }, - "blockTags": [ - "@defaultValue", - "@deprecated", - "@example", - "@jsx", - "@param", - "@privateRemarks", - "@remarks", - "@returns", - "@see", - "@throws", - "@typeParam", - "@author", - "@callback", - "@category", - "@categoryDescription", - "@default", - "@document", - "@extends", - "@augments", - "@yields", - "@group", - "@groupDescription", - "@import", - "@inheritDoc", - "@license", - "@module", - "@mergeModuleWith", - "@prop", - "@property", - "@return", - "@satisfies", - "@since", - "@sortStrategy", - "@template", - "@this", - "@type", - "@typedef", - "@summary", - "@preventInline", - "@inlineType", - "@preventExpand", - "@expandType", - "@noSelf" - ], - "excludeTags": [ - "@override", - "@virtual", - "@privateRemarks", - "@satisfies", - "@overload", - "@inline", - "@inlineType", - "@noSelf" - ], - "validation": { - "notDocumented": true, - "invalidLink": true, - "notExported": true - }, - "treatWarningsAsErrors": true -} diff --git a/projects/typescript-tests/package-lock.json b/projects/typescript-tests/package-lock.json index 9eae9f0..fa73958 100644 --- a/projects/typescript-tests/package-lock.json +++ b/projects/typescript-tests/package-lock.json @@ -35,7 +35,6 @@ "@siredvin/typed-peripheral-base": "*" }, "devDependencies": { - "typedoc": "^0.28.16", "typescript": "5.7.2", "typescript-to-lua": "1.29.1" }