@xmcl/mod-parser
Version:
The utilities to parse Forge/Liteloader/Fabric/Quilt mod metadata.
1,517 lines (1,496 loc) • 58.3 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// index.ts
var mod_parser_exports = {};
__export(mod_parser_exports, {
CorruptedForgeConfigError: () => CorruptedForgeConfigError,
ForgeConfig: () => ForgeConfig,
ForgeModParseFailedError: () => ForgeModParseFailedError,
readFabricMod: () => readFabricMod,
readForgeMod: () => readForgeMod,
readForgeModAsm: () => readForgeModAsm,
readForgeModJson: () => readForgeModJson,
readForgeModManifest: () => readForgeModManifest,
readForgeModToml: () => readForgeModToml,
readLiteloaderMod: () => readLiteloaderMod,
readQuiltMod: () => readQuiltMod
});
module.exports = __toCommonJS(mod_parser_exports);
// forge.ts
var import_system = require("@xmcl/system");
// ../../node_modules/.pnpm/smol-toml@1.4.1/node_modules/smol-toml/dist/error.js
function getLineColFromPtr(string, ptr) {
let lines = string.slice(0, ptr).split(/\r\n|\n|\r/g);
return [lines.length, lines.pop().length + 1];
}
function makeCodeBlock(string, line, column) {
let lines = string.split(/\r\n|\n|\r/g);
let codeblock = "";
let numberLen = (Math.log10(line + 1) | 0) + 1;
for (let i = line - 1; i <= line + 1; i++) {
let l = lines[i - 1];
if (!l)
continue;
codeblock += i.toString().padEnd(numberLen, " ");
codeblock += ": ";
codeblock += l;
codeblock += "\n";
if (i === line) {
codeblock += " ".repeat(numberLen + column + 2);
codeblock += "^\n";
}
}
return codeblock;
}
var TomlError = class extends Error {
line;
column;
codeblock;
constructor(message, options) {
const [line, column] = getLineColFromPtr(options.toml, options.ptr);
const codeblock = makeCodeBlock(options.toml, line, column);
super(`Invalid TOML document: ${message}
${codeblock}`, options);
this.line = line;
this.column = column;
this.codeblock = codeblock;
}
};
// ../../node_modules/.pnpm/smol-toml@1.4.1/node_modules/smol-toml/dist/util.js
function indexOfNewline(str, start = 0, end = str.length) {
let idx = str.indexOf("\n", start);
if (str[idx - 1] === "\r")
idx--;
return idx <= end ? idx : -1;
}
function skipComment(str, ptr) {
for (let i = ptr; i < str.length; i++) {
let c = str[i];
if (c === "\n")
return i;
if (c === "\r" && str[i + 1] === "\n")
return i + 1;
if (c < " " && c !== " " || c === "\x7F") {
throw new TomlError("control characters are not allowed in comments", {
toml: str,
ptr
});
}
}
return str.length;
}
function skipVoid(str, ptr, banNewLines, banComments) {
let c;
while ((c = str[ptr]) === " " || c === " " || !banNewLines && (c === "\n" || c === "\r" && str[ptr + 1] === "\n"))
ptr++;
return banComments || c !== "#" ? ptr : skipVoid(str, skipComment(str, ptr), banNewLines);
}
function skipUntil(str, ptr, sep, end, banNewLines = false) {
if (!end) {
ptr = indexOfNewline(str, ptr);
return ptr < 0 ? str.length : ptr;
}
for (let i = ptr; i < str.length; i++) {
let c = str[i];
if (c === "#") {
i = indexOfNewline(str, i);
} else if (c === sep) {
return i + 1;
} else if (c === end || banNewLines && (c === "\n" || c === "\r" && str[i + 1] === "\n")) {
return i;
}
}
throw new TomlError("cannot find end of structure", {
toml: str,
ptr
});
}
function getStringEnd(str, seek) {
let first = str[seek];
let target = first === str[seek + 1] && str[seek + 1] === str[seek + 2] ? str.slice(seek, seek + 3) : first;
seek += target.length - 1;
do
seek = str.indexOf(target, ++seek);
while (seek > -1 && first !== "'" && str[seek - 1] === "\\" && (str[seek - 2] !== "\\" || str[seek - 3] === "\\"));
if (seek > -1) {
seek += target.length;
if (target.length > 1) {
if (str[seek] === first)
seek++;
if (str[seek] === first)
seek++;
}
}
return seek;
}
// ../../node_modules/.pnpm/smol-toml@1.4.1/node_modules/smol-toml/dist/date.js
var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}:\d{2}(?:\.\d+)?)?(Z|[-+]\d{2}:\d{2})?$/i;
var TomlDate = class extends Date {
#hasDate = false;
#hasTime = false;
#offset = null;
constructor(date) {
let hasDate = true;
let hasTime = true;
let offset = "Z";
if (typeof date === "string") {
let match = date.match(DATE_TIME_RE);
if (match) {
if (!match[1]) {
hasDate = false;
date = `0000-01-01T${date}`;
}
hasTime = !!match[2];
hasTime && date[10] === " " && (date = date.replace(" ", "T"));
if (match[2] && +match[2] > 23) {
date = "";
} else {
offset = match[3] || null;
date = date.toUpperCase();
if (!offset && hasTime)
date += "Z";
}
} else {
date = "";
}
}
super(date);
if (!isNaN(this.getTime())) {
this.#hasDate = hasDate;
this.#hasTime = hasTime;
this.#offset = offset;
}
}
isDateTime() {
return this.#hasDate && this.#hasTime;
}
isLocal() {
return !this.#hasDate || !this.#hasTime || !this.#offset;
}
isDate() {
return this.#hasDate && !this.#hasTime;
}
isTime() {
return this.#hasTime && !this.#hasDate;
}
isValid() {
return this.#hasDate || this.#hasTime;
}
toISOString() {
let iso = super.toISOString();
if (this.isDate())
return iso.slice(0, 10);
if (this.isTime())
return iso.slice(11, 23);
if (this.#offset === null)
return iso.slice(0, -1);
if (this.#offset === "Z")
return iso;
let offset = +this.#offset.slice(1, 3) * 60 + +this.#offset.slice(4, 6);
offset = this.#offset[0] === "-" ? offset : -offset;
let offsetDate = new Date(this.getTime() - offset * 6e4);
return offsetDate.toISOString().slice(0, -1) + this.#offset;
}
static wrapAsOffsetDateTime(jsDate, offset = "Z") {
let date = new TomlDate(jsDate);
date.#offset = offset;
return date;
}
static wrapAsLocalDateTime(jsDate) {
let date = new TomlDate(jsDate);
date.#offset = null;
return date;
}
static wrapAsLocalDate(jsDate) {
let date = new TomlDate(jsDate);
date.#hasTime = false;
date.#offset = null;
return date;
}
static wrapAsLocalTime(jsDate) {
let date = new TomlDate(jsDate);
date.#hasDate = false;
date.#offset = null;
return date;
}
};
// ../../node_modules/.pnpm/smol-toml@1.4.1/node_modules/smol-toml/dist/primitive.js
var INT_REGEX = /^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/;
var FLOAT_REGEX = /^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/;
var LEADING_ZERO = /^[+-]?0[0-9_]/;
var ESCAPE_REGEX = /^[0-9a-f]{4,8}$/i;
var ESC_MAP = {
b: "\b",
t: " ",
n: "\n",
f: "\f",
r: "\r",
'"': '"',
"\\": "\\"
};
function parseString(str, ptr = 0, endPtr = str.length) {
let isLiteral = str[ptr] === "'";
let isMultiline = str[ptr++] === str[ptr] && str[ptr] === str[ptr + 1];
if (isMultiline) {
endPtr -= 2;
if (str[ptr += 2] === "\r")
ptr++;
if (str[ptr] === "\n")
ptr++;
}
let tmp = 0;
let isEscape;
let parsed = "";
let sliceStart = ptr;
while (ptr < endPtr - 1) {
let c = str[ptr++];
if (c === "\n" || c === "\r" && str[ptr] === "\n") {
if (!isMultiline) {
throw new TomlError("newlines are not allowed in strings", {
toml: str,
ptr: ptr - 1
});
}
} else if (c < " " && c !== " " || c === "\x7F") {
throw new TomlError("control characters are not allowed in strings", {
toml: str,
ptr: ptr - 1
});
}
if (isEscape) {
isEscape = false;
if (c === "u" || c === "U") {
let code = str.slice(ptr, ptr += c === "u" ? 4 : 8);
if (!ESCAPE_REGEX.test(code)) {
throw new TomlError("invalid unicode escape", {
toml: str,
ptr: tmp
});
}
try {
parsed += String.fromCodePoint(parseInt(code, 16));
} catch {
throw new TomlError("invalid unicode escape", {
toml: str,
ptr: tmp
});
}
} else if (isMultiline && (c === "\n" || c === " " || c === " " || c === "\r")) {
ptr = skipVoid(str, ptr - 1, true);
if (str[ptr] !== "\n" && str[ptr] !== "\r") {
throw new TomlError("invalid escape: only line-ending whitespace may be escaped", {
toml: str,
ptr: tmp
});
}
ptr = skipVoid(str, ptr);
} else if (c in ESC_MAP) {
parsed += ESC_MAP[c];
} else {
throw new TomlError("unrecognized escape sequence", {
toml: str,
ptr: tmp
});
}
sliceStart = ptr;
} else if (!isLiteral && c === "\\") {
tmp = ptr - 1;
isEscape = true;
parsed += str.slice(sliceStart, tmp);
}
}
return parsed + str.slice(sliceStart, endPtr - 1);
}
function parseValue(value, toml, ptr, integersAsBigInt) {
if (value === "true")
return true;
if (value === "false")
return false;
if (value === "-inf")
return -Infinity;
if (value === "inf" || value === "+inf")
return Infinity;
if (value === "nan" || value === "+nan" || value === "-nan")
return NaN;
if (value === "-0")
return integersAsBigInt ? 0n : 0;
let isInt = INT_REGEX.test(value);
if (isInt || FLOAT_REGEX.test(value)) {
if (LEADING_ZERO.test(value)) {
throw new TomlError("leading zeroes are not allowed", {
toml,
ptr
});
}
value = value.replace(/_/g, "");
let numeric = +value;
if (isNaN(numeric)) {
throw new TomlError("invalid number", {
toml,
ptr
});
}
if (isInt) {
if ((isInt = !Number.isSafeInteger(numeric)) && !integersAsBigInt) {
throw new TomlError("integer value cannot be represented losslessly", {
toml,
ptr
});
}
if (isInt || integersAsBigInt === true)
numeric = BigInt(value);
}
return numeric;
}
const date = new TomlDate(value);
if (!date.isValid()) {
throw new TomlError("invalid value", {
toml,
ptr
});
}
return date;
}
// ../../node_modules/.pnpm/smol-toml@1.4.1/node_modules/smol-toml/dist/extract.js
function sliceAndTrimEndOf(str, startPtr, endPtr, allowNewLines) {
let value = str.slice(startPtr, endPtr);
let commentIdx = value.indexOf("#");
if (commentIdx > -1) {
skipComment(str, commentIdx);
value = value.slice(0, commentIdx);
}
let trimmed = value.trimEnd();
if (!allowNewLines) {
let newlineIdx = value.indexOf("\n", trimmed.length);
if (newlineIdx > -1) {
throw new TomlError("newlines are not allowed in inline tables", {
toml: str,
ptr: startPtr + newlineIdx
});
}
}
return [trimmed, commentIdx];
}
function extractValue(str, ptr, end, depth, integersAsBigInt) {
if (depth === 0) {
throw new TomlError("document contains excessively nested structures. aborting.", {
toml: str,
ptr
});
}
let c = str[ptr];
if (c === "[" || c === "{") {
let [value, endPtr2] = c === "[" ? parseArray(str, ptr, depth, integersAsBigInt) : parseInlineTable(str, ptr, depth, integersAsBigInt);
let newPtr = end ? skipUntil(str, endPtr2, ",", end) : endPtr2;
if (endPtr2 - newPtr && end === "}") {
let nextNewLine = indexOfNewline(str, endPtr2, newPtr);
if (nextNewLine > -1) {
throw new TomlError("newlines are not allowed in inline tables", {
toml: str,
ptr: nextNewLine
});
}
}
return [value, newPtr];
}
let endPtr;
if (c === '"' || c === "'") {
endPtr = getStringEnd(str, ptr);
let parsed = parseString(str, ptr, endPtr);
if (end) {
endPtr = skipVoid(str, endPtr, end !== "]");
if (str[endPtr] && str[endPtr] !== "," && str[endPtr] !== end && str[endPtr] !== "\n" && str[endPtr] !== "\r") {
throw new TomlError("unexpected character encountered", {
toml: str,
ptr: endPtr
});
}
endPtr += +(str[endPtr] === ",");
}
return [parsed, endPtr];
}
endPtr = skipUntil(str, ptr, ",", end);
let slice = sliceAndTrimEndOf(str, ptr, endPtr - +(str[endPtr - 1] === ","), end === "]");
if (!slice[0]) {
throw new TomlError("incomplete key-value declaration: no value specified", {
toml: str,
ptr
});
}
if (end && slice[1] > -1) {
endPtr = skipVoid(str, ptr + slice[1]);
endPtr += +(str[endPtr] === ",");
}
return [
parseValue(slice[0], str, ptr, integersAsBigInt),
endPtr
];
}
// ../../node_modules/.pnpm/smol-toml@1.4.1/node_modules/smol-toml/dist/struct.js
var KEY_PART_RE = /^[a-zA-Z0-9-_]+[ \t]*$/;
function parseKey(str, ptr, end = "=") {
let dot = ptr - 1;
let parsed = [];
let endPtr = str.indexOf(end, ptr);
if (endPtr < 0) {
throw new TomlError("incomplete key-value: cannot find end of key", {
toml: str,
ptr
});
}
do {
let c = str[ptr = ++dot];
if (c !== " " && c !== " ") {
if (c === '"' || c === "'") {
if (c === str[ptr + 1] && c === str[ptr + 2]) {
throw new TomlError("multiline strings are not allowed in keys", {
toml: str,
ptr
});
}
let eos = getStringEnd(str, ptr);
if (eos < 0) {
throw new TomlError("unfinished string encountered", {
toml: str,
ptr
});
}
dot = str.indexOf(".", eos);
let strEnd = str.slice(eos, dot < 0 || dot > endPtr ? endPtr : dot);
let newLine = indexOfNewline(strEnd);
if (newLine > -1) {
throw new TomlError("newlines are not allowed in keys", {
toml: str,
ptr: ptr + dot + newLine
});
}
if (strEnd.trimStart()) {
throw new TomlError("found extra tokens after the string part", {
toml: str,
ptr: eos
});
}
if (endPtr < eos) {
endPtr = str.indexOf(end, eos);
if (endPtr < 0) {
throw new TomlError("incomplete key-value: cannot find end of key", {
toml: str,
ptr
});
}
}
parsed.push(parseString(str, ptr, eos));
} else {
dot = str.indexOf(".", ptr);
let part = str.slice(ptr, dot < 0 || dot > endPtr ? endPtr : dot);
if (!KEY_PART_RE.test(part)) {
throw new TomlError("only letter, numbers, dashes and underscores are allowed in keys", {
toml: str,
ptr
});
}
parsed.push(part.trimEnd());
}
}
} while (dot + 1 && dot < endPtr);
return [parsed, skipVoid(str, endPtr + 1, true, true)];
}
function parseInlineTable(str, ptr, depth, integersAsBigInt) {
let res = {};
let seen = /* @__PURE__ */ new Set();
let c;
let comma = 0;
ptr++;
while ((c = str[ptr++]) !== "}" && c) {
let err = { toml: str, ptr: ptr - 1 };
if (c === "\n") {
throw new TomlError("newlines are not allowed in inline tables", err);
} else if (c === "#") {
throw new TomlError("inline tables cannot contain comments", err);
} else if (c === ",") {
throw new TomlError("expected key-value, found comma", err);
} else if (c !== " " && c !== " ") {
let k;
let t = res;
let hasOwn = false;
let [key, keyEndPtr] = parseKey(str, ptr - 1);
for (let i = 0; i < key.length; i++) {
if (i)
t = hasOwn ? t[k] : t[k] = {};
k = key[i];
if ((hasOwn = Object.hasOwn(t, k)) && (typeof t[k] !== "object" || seen.has(t[k]))) {
throw new TomlError("trying to redefine an already defined value", {
toml: str,
ptr
});
}
if (!hasOwn && k === "__proto__") {
Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
}
}
if (hasOwn) {
throw new TomlError("trying to redefine an already defined value", {
toml: str,
ptr
});
}
let [value, valueEndPtr] = extractValue(str, keyEndPtr, "}", depth - 1, integersAsBigInt);
seen.add(value);
t[k] = value;
ptr = valueEndPtr;
comma = str[ptr - 1] === "," ? ptr - 1 : 0;
}
}
if (comma) {
throw new TomlError("trailing commas are not allowed in inline tables", {
toml: str,
ptr: comma
});
}
if (!c) {
throw new TomlError("unfinished table encountered", {
toml: str,
ptr
});
}
return [res, ptr];
}
function parseArray(str, ptr, depth, integersAsBigInt) {
let res = [];
let c;
ptr++;
while ((c = str[ptr++]) !== "]" && c) {
if (c === ",") {
throw new TomlError("expected value, found comma", {
toml: str,
ptr: ptr - 1
});
} else if (c === "#")
ptr = skipComment(str, ptr);
else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") {
let e = extractValue(str, ptr - 1, "]", depth - 1, integersAsBigInt);
res.push(e[0]);
ptr = e[1];
}
}
if (!c) {
throw new TomlError("unfinished array encountered", {
toml: str,
ptr
});
}
return [res, ptr];
}
// ../../node_modules/.pnpm/smol-toml@1.4.1/node_modules/smol-toml/dist/parse.js
function peekTable(key, table, meta, type) {
var _a, _b;
let t = table;
let m = meta;
let k;
let hasOwn = false;
let state;
for (let i = 0; i < key.length; i++) {
if (i) {
t = hasOwn ? t[k] : t[k] = {};
m = (state = m[k]).c;
if (type === 0 && (state.t === 1 || state.t === 2)) {
return null;
}
if (state.t === 2) {
let l = t.length - 1;
t = t[l];
m = m[l].c;
}
}
k = key[i];
if ((hasOwn = Object.hasOwn(t, k)) && ((_a = m[k]) == null ? void 0 : _a.t) === 0 && ((_b = m[k]) == null ? void 0 : _b.d)) {
return null;
}
if (!hasOwn) {
if (k === "__proto__") {
Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
Object.defineProperty(m, k, { enumerable: true, configurable: true, writable: true });
}
m[k] = {
t: i < key.length - 1 && type === 2 ? 3 : type,
d: false,
i: 0,
c: {}
};
}
}
state = m[k];
if (state.t !== type && !(type === 1 && state.t === 3)) {
return null;
}
if (type === 2) {
if (!state.d) {
state.d = true;
t[k] = [];
}
t[k].push(t = {});
state.c[state.i++] = state = { t: 1, d: false, i: 0, c: {} };
}
if (state.d) {
return null;
}
state.d = true;
if (type === 1) {
t = hasOwn ? t[k] : t[k] = {};
} else if (type === 0 && hasOwn) {
return null;
}
return [k, t, state.c];
}
function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
let res = {};
let meta = {};
let tbl = res;
let m = meta;
for (let ptr = skipVoid(toml, 0); ptr < toml.length; ) {
if (toml[ptr] === "[") {
let isTableArray = toml[++ptr] === "[";
let k = parseKey(toml, ptr += +isTableArray, "]");
if (isTableArray) {
if (toml[k[1] - 1] !== "]") {
throw new TomlError("expected end of table declaration", {
toml,
ptr: k[1] - 1
});
}
k[1]++;
}
let p = peekTable(
k[0],
res,
meta,
isTableArray ? 2 : 1
/* Type.EXPLICIT */
);
if (!p) {
throw new TomlError("trying to redefine an already defined table or value", {
toml,
ptr
});
}
m = p[2];
tbl = p[1];
ptr = k[1];
} else {
let k = parseKey(toml, ptr);
let p = peekTable(
k[0],
tbl,
m,
0
/* Type.DOTTED */
);
if (!p) {
throw new TomlError("trying to redefine an already defined table or value", {
toml,
ptr
});
}
let v = extractValue(toml, k[1], void 0, maxDepth, integersAsBigInt);
p[1][p[0]] = v[0];
ptr = v[1];
}
ptr = skipVoid(toml, ptr, true);
if (toml[ptr] && toml[ptr] !== "\n" && toml[ptr] !== "\r") {
throw new TomlError("each key-value declaration must be followed by an end-of-line", {
toml,
ptr
});
}
ptr = skipVoid(toml, ptr);
}
return res;
}
// forge.ts
var import_asm = require("@xmcl/asm");
var ModAnnotationVisitor = class extends import_asm.AnnotationVisitor {
constructor(map) {
super(import_asm.Opcodes.ASM5);
this.map = map;
}
visit(s, o) {
if (s === "value") {
this.map.modid = o;
} else {
this.map[s] = o;
}
}
};
var McVersionAnnotationVisitor = class extends import_asm.AnnotationVisitor {
constructor(map) {
super(import_asm.Opcodes.ASM5);
this.map = map;
}
visit(s, o) {
if (s === "value") {
this.map(o);
}
}
};
var DummyModConstructorVisitor = class extends import_asm.MethodVisitor {
constructor(parent, api) {
super(api);
this.parent = parent;
}
stack = [];
visitLdcInsn(value) {
this.stack.push(value);
}
visitFieldInsn(opcode, owner, name, desc) {
if (opcode === import_asm.Opcodes.PUTFIELD) {
const last = this.stack.pop();
if (last) {
if (name === "modId") {
this.parent.guess.modid = last;
} else if (name === "version") {
this.parent.guess.version = last;
} else if (name === "name") {
this.parent.guess.name = last;
} else if (name === "url") {
this.parent.guess.url = last;
} else if (name === "parent") {
this.parent.guess.parent = last;
} else if (name === "mcversion") {
this.parent.guess.mcversion = last;
}
}
}
}
};
var ModClassVisitor = class extends import_asm.ClassVisitor {
constructor(result, guess, corePlugin) {
super(import_asm.Opcodes.ASM5);
this.result = result;
this.guess = guess;
this.corePlugin = corePlugin;
}
fields = {};
className = "";
isDummyModContainer = false;
isPluginClass = false;
mcVersionInPlugin = "";
pluginName = "";
validateType(desc) {
if (desc.indexOf("net/minecraftforge") !== -1) {
this.result.usedForgePackage = true;
}
if (desc.indexOf("net/minecraft") !== -1) {
this.result.usedMinecraftPackage = true;
}
if (desc.indexOf("cpw/mods/fml") !== -1) {
this.result.usedLegacyFMLPackage = true;
}
if (desc.indexOf("net/minecraft/client") !== -1) {
this.result.usedMinecraftClientPackage = true;
}
}
visit(version, access, name, signature, superName, interfaces) {
this.className = name;
this.isPluginClass = name === this.corePlugin;
if (superName === "net/minecraftforge/fml/common/DummyModContainer") {
this.isDummyModContainer = true;
}
this.validateType(superName);
for (const intef of interfaces) {
this.validateType(intef);
if (intef.indexOf("net/minecraftforge/fml/relauncher/IFMLLoadingPlugin") !== -1) {
this.result.fmlPluginClassName = name;
}
}
}
visitMethod(access, name, desc, signature, exceptions) {
if (this.isDummyModContainer && name === "<init>") {
return new DummyModConstructorVisitor(this, import_asm.Opcodes.ASM5);
}
this.validateType(desc);
return null;
}
visitField(access, name, desc, signature, value) {
this.fields[name] = value;
return null;
}
visitAnnotation(desc, visible) {
if (desc === "Lnet/minecraftforge/fml/common/Mod;" || desc === "Lcpw/mods/fml/common/Mod;") {
const annotationData = {
modid: "",
name: "",
version: "",
dependencies: "",
useMetadata: true,
clientSideOnly: false,
serverSideOnly: false,
acceptedMinecraftVersions: "",
acceptableRemoteVersions: "",
acceptableSaveVersions: "",
modLanguage: "java",
modLanguageAdapter: "",
value: ""
};
this.result.modAnnotations.push(annotationData);
return new ModAnnotationVisitor(annotationData);
} else if (desc === "Lnet/minecraftforge/fml/relauncher/IFMLLoadingPlugin$MCVersion;") {
return new McVersionAnnotationVisitor((v) => {
this.result.fmlPluginMcVersion = v;
});
}
return null;
}
visitEnd() {
if ((this.className === "Config" || this.className === "net/optifine/Config" || this.className === "notch/net/optifine/Config") && this.fields && this.fields.OF_NAME) {
this.result.modAnnotations.push({
modid: this.fields.OF_NAME,
name: this.fields.OF_NAME,
mcversion: this.fields.MC_VERSION,
version: `${this.fields.OF_EDITION}_${this.fields.OF_RELEASE}`,
description: "OptiFine is a Minecraft optimization mod. It allows Minecraft to run faster and look better with full support for HD textures and many configuration options.",
authorList: ["sp614x"],
url: "https://optifine.net",
clientSideOnly: true,
serverSideOnly: false,
value: "",
dependencies: "",
useMetadata: false,
acceptableRemoteVersions: "",
acceptableSaveVersions: "",
acceptedMinecraftVersions: `[${this.fields.MC_VERSION}]`,
modLanguage: "java",
modLanguageAdapter: ""
});
}
for (const [k, v] of Object.entries(this.fields)) {
switch (k.toUpperCase()) {
case "MODID":
case "MOD_ID":
this.guess.modid = this.guess.modid || v;
break;
case "MODNAME":
case "MOD_NAME":
this.guess.name = this.guess.name || v;
break;
case "VERSION":
case "MOD_VERSION":
this.guess.version = this.guess.version || v;
break;
case "MCVERSION":
this.guess.mcversion = this.guess.mcversion || v;
break;
}
}
}
};
async function readForgeModManifest(mod, manifestStore = {}) {
const fs = await (0, import_system.resolveFileSystem)(mod);
if (!await fs.existsFile("META-INF/MANIFEST.MF")) {
return void 0;
}
const data = await fs.readFile("META-INF/MANIFEST.MF");
const manifest = data.toString().split("\n").map((l) => l.trim()).filter((l) => l.length > 0).map((l) => l.split(":").map((s) => s.trim())).reduce((a, b) => ({ ...a, [b[0]]: b[1] }), {});
Object.assign(manifestStore, manifest);
const metadata = {
modid: "",
name: "",
authors: [],
version: "",
description: "",
url: ""
};
if (typeof manifest.TweakName === "string") {
metadata.modid = manifest.TweakName;
metadata.name = manifest.TweakName;
}
if (typeof manifest.TweakAuthor === "string") {
metadata.authors = [manifest.TweakAuthor];
}
if (typeof manifest.TweakVersion === "string") {
metadata.version = manifest.TweakVersion;
}
if (manifest.TweakMetaFile) {
const file = manifest.TweakMetaFile;
if (await fs.existsFile(`META-INF/${file}`)) {
const metadataContent = await fs.readFile(`META-INF/${file}`, "utf-8").then((s) => s.replace(/^\uFEFF/, "")).then(JSON.parse);
if (metadataContent.id) {
metadata.modid = metadataContent.id;
}
if (metadataContent.name) {
metadata.name = metadataContent.name;
}
if (metadataContent.version) {
metadata.version = metadataContent.version;
}
if (metadataContent.authors) {
metadata.authors = metadataContent.authors;
}
if (metadataContent.description) {
metadata.description = metadataContent.description;
}
if (metadataContent.url) {
metadata.url = metadataContent.url;
}
}
}
return metadata;
}
async function readForgeModToml(mod, manifest, fileName = "mods.toml") {
const fs = await (0, import_system.resolveFileSystem)(mod);
const existed = await fs.existsFile("META-INF/" + fileName);
const all = [];
if (existed) {
const str = await fs.readFile("META-INF/" + fileName, "utf-8");
const root = parse(str);
if (root.mods instanceof Array) {
for (const mod2 of root.mods) {
const tomlMod = mod2;
if (typeof tomlMod === "object" && !(tomlMod instanceof TomlDate) && !(tomlMod instanceof Array)) {
const modObject = {
modid: tomlMod.modId ?? "",
authors: tomlMod.authors ?? root.authors ?? "",
// eslint-disable-next-line no-template-curly-in-string
version: tomlMod.version === "${file.jarVersion}" && typeof (manifest == null ? void 0 : manifest["Implementation-Version"]) === "string" ? manifest == null ? void 0 : manifest["Implementation-Version"] : tomlMod.version,
displayName: tomlMod.displayName ?? "",
description: tomlMod.description ?? "",
displayURL: tomlMod.displayURL ?? root.displayURL ?? "",
updateJSONURL: tomlMod.updateJSONURL ?? root.updateJSONURL ?? "",
provides: tomlMod.provides ?? [],
dependencies: [],
logoFile: tomlMod.logoFile ?? "",
credits: tomlMod.credits ?? "",
loaderVersion: root.loaderVersion ?? "",
modLoader: root.modLoader ?? "",
issueTrackerURL: root.issueTrackerURL ?? ""
};
all.push(modObject);
}
}
}
if (typeof root.dependencies === "object") {
for (const mod2 of all) {
const dep = root.dependencies[mod2.modid];
if (dep) {
mod2.dependencies = dep;
}
}
}
}
return all;
}
async function readForgeModAsm(mod, manifest = {}) {
const fs = await (0, import_system.resolveFileSystem)(mod);
let corePluginClass;
if (manifest) {
if (typeof manifest.FMLCorePlugin === "string") {
const clazz = manifest.FMLCorePlugin.replace(/\./g, "/");
if (await fs.existsFile(clazz) || await fs.existsFile(`/${clazz}`) || await fs.existsFile(`/${clazz}.class`) || await fs.existsFile(clazz + ".class")) {
corePluginClass = clazz;
}
}
}
const result = {
usedForgePackage: false,
usedLegacyFMLPackage: false,
usedMinecraftClientPackage: false,
usedMinecraftPackage: false,
modAnnotations: []
};
const guessing = {};
await fs.walkFiles("/", async (f) => {
if (!f.endsWith(".class")) {
return;
}
const data = await fs.readFile(f);
const visitor = new ModClassVisitor(result, guessing, corePluginClass);
new import_asm.ClassReader(data).accept(visitor);
});
if (result.modAnnotations.length === 0 && guessing.modid && (result.usedForgePackage || result.usedLegacyFMLPackage)) {
result.modAnnotations.push({
modid: guessing.modid ?? "",
name: guessing.name ?? "",
version: guessing.version ?? "",
dependencies: guessing.dependencies ?? "",
useMetadata: guessing.useMetadata ?? false,
clientSideOnly: guessing.clientSideOnly ?? false,
serverSideOnly: guessing.serverSideOnly ?? false,
acceptedMinecraftVersions: guessing.acceptedMinecraftVersions ?? "",
acceptableRemoteVersions: guessing.acceptableRemoteVersions ?? "",
acceptableSaveVersions: guessing.acceptableSaveVersions ?? "",
modLanguage: guessing.modLanguage ?? "java",
modLanguageAdapter: guessing.modLanguageAdapter ?? "",
value: guessing.value ?? ""
});
}
return result;
}
async function readForgeModJson(mod) {
const fs = await (0, import_system.resolveFileSystem)(mod);
const all = [];
function normalize(json) {
const metadata = {
modid: "",
name: "",
description: "",
version: "",
mcversion: "",
url: "",
updateUrl: "",
updateJSON: "",
authorList: [],
credits: "",
logoFile: "",
screenshots: [],
parent: "",
useDependencyInformation: false,
requiredMods: [],
dependencies: [],
dependants: []
};
metadata.modid = json.modid ?? metadata.modid;
metadata.name = json.name ?? metadata.name;
metadata.description = json.description ?? metadata.description;
metadata.version = json.version ?? metadata.version;
metadata.mcversion = json.mcversion ?? metadata.mcversion;
metadata.url = json.url ?? metadata.url;
metadata.updateUrl = json.updateUrl ?? metadata.updateUrl;
metadata.updateJSON = json.updateJSON ?? metadata.updateJSON;
metadata.authorList = json.authorList ?? metadata.authorList;
metadata.credits = json.credits ?? metadata.credits;
metadata.logoFile = json.logoFile ?? metadata.logoFile;
metadata.screenshots = json.screenshots ?? metadata.screenshots;
metadata.parent = json.parent ?? metadata.parent;
metadata.useDependencyInformation = json.useDependencyInformation ?? metadata.useDependencyInformation;
metadata.requiredMods = json.requiredMods ?? metadata.requiredMods;
metadata.dependencies = json.dependencies ?? metadata.dependencies;
metadata.dependants = json.dependants ?? metadata.dependants;
return metadata;
}
function readJsonMetadata(json) {
const modList = [];
if (json instanceof Array) {
modList.push(...json);
} else if (json.modList instanceof Array) {
modList.push(...json.modList);
} else if (json.modid) {
modList.push(json);
}
all.push(...modList.map(normalize));
}
if (await fs.existsFile("mcmod.info")) {
try {
const json = JSON.parse((await fs.readFile("mcmod.info", "utf-8")).replace(/^\uFEFF/, ""));
readJsonMetadata(json);
} catch (e) {
}
} else if (await fs.existsFile("cccmod.info")) {
try {
const text = (await fs.readFile("cccmod.info", "utf-8")).replace(/^\uFEFF/, "").replace(/\n\n/g, "\\n").replace(/\n/g, "");
const json = JSON.parse(text);
readJsonMetadata(json);
} catch (e) {
}
} else if (await fs.existsFile("neimod.info")) {
try {
const text = (await fs.readFile("neimod.info", "utf-8")).replace(/^\uFEFF/, "").replace(/\n\n/g, "\\n").replace(/\n/g, "");
const json = JSON.parse(text);
readJsonMetadata(json);
} catch (e) {
}
} else {
const files = await fs.listFiles("./");
const infoFile = files.find((f) => f.endsWith(".info"));
if (infoFile) {
try {
const text = (await fs.readFile(infoFile, "utf-8")).replace(/^\uFEFF/, "").replace(/\n\n/g, "\\n").replace(/\n/g, "");
const json = JSON.parse(text);
readJsonMetadata(json);
} catch (e) {
}
}
}
return all;
}
async function readForgeMod(mod) {
const fs = await (0, import_system.resolveFileSystem)(mod);
try {
const jsons = await readForgeModJson(fs);
const manifest = {};
const manifestMetadata = await readForgeModManifest(fs, manifest);
const tomls = await readForgeModToml(fs, manifest);
const base = await readForgeModAsm(fs, manifest).catch(() => ({
usedLegacyFMLPackage: false,
usedForgePackage: false,
usedMinecraftPackage: false,
usedMinecraftClientPackage: false,
modAnnotations: []
}));
if (jsons.length === 0 && (!manifestMetadata || !manifestMetadata.modid) && tomls.length === 0 && base.modAnnotations.length === 0) {
throw new ForgeModParseFailedError(mod, base, manifest);
}
const result = {
mcmodInfo: jsons,
manifest,
manifestMetadata: (manifestMetadata == null ? void 0 : manifestMetadata.modid) ? manifestMetadata : void 0,
modsToml: tomls,
...base
};
return result;
} finally {
if (mod !== fs)
fs.close();
}
}
var ForgeModParseFailedError = class extends Error {
constructor(mod, asm, manifest) {
super("Cannot find the mod metadata in the mod!");
this.mod = mod;
this.asm = asm;
this.manifest = manifest;
this.name = "ForgeModParseFailedError";
}
};
// forgeConfig.ts
var CorruptedForgeConfigError = class extends Error {
constructor(reason, line) {
super(`CorruptedForgeConfigError by ${reason}: ${line}`);
this.reason = reason;
this.line = line;
}
name = "CorruptedForgeConfigError";
};
var ForgeConfig;
((ForgeConfig2) => {
function stringify2(config) {
let content = "# Configuration file\n\n\n";
const propIndent = " ";
const arrIndent = " ";
Object.keys(config).forEach((cat) => {
content += `${cat} {
`;
config[cat].properties.forEach((prop) => {
if (prop.comment) {
const lines = prop.comment.split("\n");
for (const l of lines) {
content += `${propIndent}# ${l}
`;
}
}
if (prop.value instanceof Array) {
content += `${propIndent}${prop.type}:${prop.name} <
`;
prop.value.forEach((v) => {
content += `${arrIndent}${v}
`;
});
content += `${propIndent}>
`;
} else {
content += `${propIndent}${prop.type}:${prop.name}=${prop.value}
`;
}
content += "\n";
});
content += "}\n\n";
});
return content;
}
ForgeConfig2.stringify = stringify2;
function parse2(body) {
const lines = body.split("\n").map((s) => s.trim()).filter((s) => s.length !== 0);
let category;
let pendingCategory;
const parseVal = (type, value) => {
const map = {
I: Number.parseInt,
D: Number.parseFloat,
S: (s) => s,
B: (s) => s === "true"
};
const handler = map[type];
return handler(value);
};
const config = {};
let inlist = false;
let comment;
let last;
const readProp = (type, line) => {
line = line.substring(line.indexOf(":") + 1, line.length);
const pair = line.split("=");
if (pair.length === 0 || pair.length === 1) {
let value;
let name;
if (line.endsWith(" <")) {
value = [];
name = line.substring(0, line.length - 2);
inlist = true;
}
if (!category) {
throw new CorruptedForgeConfigError("MissingCategory", line);
}
config[category].properties.push(last = { name, type, value, comment });
} else {
inlist = false;
if (!category) {
throw new CorruptedForgeConfigError("MissingCategory", line);
}
config[category].properties.push({ name: pair[0], value: parseVal(type, pair[1]), type, comment });
}
comment = void 0;
};
for (const line of lines) {
if (inlist) {
if (!last) {
throw new CorruptedForgeConfigError("CorruptedList", line);
}
if (line === ">") {
inlist = false;
} else if (line.endsWith(" >")) {
last.value.push(parseVal(last.type, line.substring(0, line.length - 2)));
inlist = false;
} else {
last.value.push(parseVal(last.type, line));
}
continue;
}
switch (line.charAt(0)) {
case "#":
if (!comment) {
comment = line.substring(1, line.length).trim();
} else {
comment = comment.concat("\n", line.substring(1, line.length).trim());
}
break;
case "I":
case "D":
case "S":
case "B":
readProp(line.charAt(0), line);
break;
case "<":
break;
case "{":
if (pendingCategory) {
category = pendingCategory;
config[category] = { comment, properties: [] };
comment = void 0;
} else {
throw new CorruptedForgeConfigError("MissingCategory", line);
}
break;
case "}":
category = void 0;
break;
default:
if (!category) {
if (line.endsWith("{")) {
category = line.substring(0, line.length - 1).trim();
config[category] = { comment, properties: [] };
comment = void 0;
} else {
pendingCategory = line;
}
} else {
throw new CorruptedForgeConfigError("Duplicated", line);
}
}
}
return config;
}
ForgeConfig2.parse = parse2;
})(ForgeConfig || (ForgeConfig = {}));
// liteloader.ts
var import_system2 = require("@xmcl/system");
async function readLiteloaderMod(mod) {
const fs = await (0, import_system2.resolveFileSystem)(mod);
try {
const text = await fs.readFile("litemod.json", "utf-8").then((s) => s.replace(/^\uFEFF/, "")).catch(() => void 0);
if (!text) {
throw Object.assign(new Error("Illegal input type! Expect a jar file contains litemod.json"), {
mod,
name: "IllegalInputType"
});
}
const metadata = JSON.parse(text.trim(), (key, value) => key === "revision" ? Number.parseInt(value, 10) : value);
if (!metadata.version) {
metadata.version = `${metadata.mcversion}:${metadata.revision || 0}`;
}
return metadata;
} finally {
if (fs !== mod)
fs.close();
}
}
// fabric.ts
var import_system3 = require("@xmcl/system");
async function readFabricMod(file) {
const fs = await (0, import_system3.resolveFileSystem)(file);
try {
const content = await fs.readFile("fabric.mod.json", "utf-8");
return JSON.parse(content.replace(/^\uFEFF/g, "").replace(/\n/g, ""));
} finally {
if (file !== fs)
fs.close();
}
}
// quilt.ts
var import_system4 = require("@xmcl/system");
async function readQuiltMod(file) {
const fs = await (0, import_system4.resolveFileSystem)(file);
try {
const content = await fs.readFile("quilt.mod.json", "utf-8");
return JSON.parse(content.replace(/^\uFEFF/g, "").replace(/\n/g, ""));
} finally {
if (fs !== file)
fs.close();
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
CorruptedForgeConfigError,
ForgeConfig,
ForgeModParseFailedError,
readFabricMod,
readForgeMod,
readForgeModAsm,
readForgeModJson,
readForgeModManifest,
readForgeModToml,
readLiteloaderMod,
readQuiltMod
});
/*! Bundled license information:
smol-toml/dist/error.js:
(*!
* Copyright (c) Squirrel Chat et al., All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*)
smol-toml/dist/util.js:
(*!
* Copyright (c) Squirrel Chat et al., All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*)
smol-toml/dist/date.js:
(*!
* Copyright (c) Squirrel Chat et al., All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*)
smol-toml/dist/primitive.js:
(*!
* Copyright (c) Squirrel Chat et al., All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*)
smol-toml/dist/extract.js:
(*!
* Copyright (c) Squirrel Chat et al., All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*
* Redistribution and use in source and b