initial commit

This commit is contained in:
PwLDev 2026-04-28 13:11:03 -07:00
commit 18255ce4cd
21 changed files with 1244 additions and 0 deletions

163
scripts/bindgen.js Normal file
View file

@ -0,0 +1,163 @@
import { XMLParser } from "fast-xml-parser";
import { createWriteStream } from "node:fs";
import { createRequire } from "node:module";
const { upstream } = createRequire(import.meta.url)("../package.json");
const source =
"https://forgejo.nishi.boats/api/v1/repos/pyrite-dev/milsko/tags";
// Out files
const structsOut = createWriteStream("lib/structs.ts");
const enumsOut = createWriteStream("lib/enums.ts");
const constantsOut = createWriteStream("lib/constants.ts");
function toCamelCase(input) {
const split = input.split("_");
for (let i = 0; i < split.length; i++) {
const firstChar =
i <= 0
? split[i].charAt(0).toLowerCase()
: split[i].charAt(0).toUpperCase();
split[i] = firstChar + split[i].slice(1);
}
return split.join("");
}
function typeToTypescript(type) {
switch (type) {
case "integer":
return "number";
case "short":
return "number";
case "string":
return "string";
default:
"any";
}
}
function scanStructs(root) {
const list = root["structs"]["struct"];
for (const struct of list) {
console.log(struct);
const structName = struct["@_name"];
structsOut.write("export interface " + structName + " {\n");
for (const [type, children] of Object.entries(struct)) {
// attributes start with @_
if (!type.startsWith("@_") && Array.isArray(children)) {
for (const child of children) {
const attributeName = toCamelCase(child["@_name"]);
structsOut.write(
attributeName + ": " + typeToTypescript(type) + ";\n"
);
}
}
}
structsOut.write("}\n\n");
}
structsOut.end();
}
function scanEnumerations(root) {
const list = root["enumerations"]["enumeration"];
for (const enumeration of list) {
const enumName = enumeration["@_name"];
enumsOut.write("export enum " + enumName + " {\n");
for (const [type, children] of Object.entries(enumeration)) {
// attributes start with @_
if (!type.startsWith("@_")) {
for (const child of children) {
const attributeName = child["@_name"];
const attributeValue = child["#text"];
enumsOut.write(attributeName);
if (attributeValue) enumsOut.write(" = " + attributeValue);
enumsOut.write(",\n");
}
}
}
enumsOut.write("}\n\n");
}
enumsOut.end();
}
function scanConstants(root) {
const list = root["constants"];
for (const [type, children] of Object.entries(list)) {
for (const child of children) {
const constName = child["@_name"];
const constValue = child["#text"];
constantsOut.write(
"export const " +
constName +
": " +
typeToTypescript(type) +
" = " +
constValue +
";\n"
);
}
}
constantsOut.end();
}
async function bindgen() {
const parser = new XMLParser({
attributeNamePrefix: "@_",
ignoreAttributes: false,
parseAttributeValue: true
});
const response = await fetch(source);
if (!response.ok) {
throw new Error(
"Failed to fetch the Milsko repository tags, try running npm run install or npm run update again (" +
response.status +
")"
);
}
const tags = await response.json();
const match = tags.find((k) => k.name == upstream);
if (!match) {
throw new Error(
"Could not find a tag that matches the upstream version " + upstream
);
}
const commitHash = match["id"]
const specURL = "https://forgejo.nishi.boats/pyrite-dev/milsko/raw/commit/" +
commitHash + "/milsko.xml";
const spac = await fetch(specURL);
if (!spac.ok) {
throw new Error(
"Failed to fetch the XML API specification with status code " +
spac.status
);
}
const raw = await spac.text();
const root = parser.parse(raw)["milsko"];
scanStructs(root);
scanEnumerations(root);
scanConstants(root);
}
bindgen();

59
scripts/download.js Normal file
View file

@ -0,0 +1,59 @@
import { execSync } from "node:child_process";
import { createWriteStream, mkdirSync } from "node:fs";
import { createRequire } from "node:module";
import { join, resolve } from "node:path";
import { Readable } from "node:stream";
import { pipeline } from "node:stream/promises";
import { t, extract as tarExtract } from "tar";
const extractDir = resolve("deps");
const fileName = "milsko.tar.gz";
const source =
"https://forgejo.nishi.boats/api/v1/repos/pyrite-dev/milsko/tags";
const require = createRequire(import.meta.url);
const { upstream } = require("../package.json");
export async function download() {
console.log("[Mw] Fetching Milsko release tags from", source);
const response = await fetch(source);
if (!response.ok) {
throw new Error(
"Failed to fetch the Milsko repository tags, try running npm run install or npm run update again (" +
response.status +
")"
);
}
const tags = await response.json();
const match = tags.find((k) => k.name == upstream);
if (!match) {
throw new Error(
"Could not find a tag that matches the upstream version " + upstream
);
}
const tarUrl = match["tarball_url"];
console.log("[Mw] Fetching tarball from " + tarUrl);
const tarball = await fetch(tarUrl);
const filePath = join(extractDir, fileName);
mkdirSync(extractDir, { recursive: true }); // mkdir -p
const tarStream = Readable.fromWeb(tarball.body);
const fileStream = createWriteStream(filePath);
await pipeline(tarStream, fileStream);
await tarExtract({
file: filePath,
cwd: extractDir
});
console.log("[Mw] Milsko library successfully installed!");
}
if (import.meta.main)
download();

31
scripts/install.js Normal file
View file

@ -0,0 +1,31 @@
import { execSync } from "node:child_process"
import { createRequire } from "node:module";
import { download } from "./download";
const require = createRequire(import.meta.url);
const forceBuild = process.env["npm_config_build_from_source"] == "true";
function hasPrebuilt() {
let prebuilt = false;
try {
require("node-gyp-build")("..");
prebuilt = true;
} catch (error) {
prebuilt = false;
}
return prebuilt;
}
async function install() {
console.log("[Mw] Downloading Milsko library...");
await download();
console.log("[Mw] Building from source...");
execSync("npx node-gyp rebuild", { stdio: "inherit" });
}
if (forceBuild || !hasPrebuilt()) {
install();
}