mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-10-23 10:13:13 +02:00
7a384d53f4
* Types for InternalFunction and ExternalFunction have been modified to actually typecheck ns functions against docs. * Internal functions are required to use unknown for any params on the inner function. * Return types for internal function inner-function must match the respective external function. * Added new typecheck assertion function for asserting dynamic object types, to allow unknownifying params that were previously hardcoded objec structures. * Because type assertion for parameter types and return types is enforced by InternalAPI, removed all duplicate type declarations on NetscriptFunction params and returns.
110 lines
3.2 KiB
TypeScript
110 lines
3.2 KiB
TypeScript
import { getRamCost } from "./RamCostGenerator";
|
|
import type { WorkerScript } from "./WorkerScript";
|
|
import { helpers } from "./NetscriptHelpers";
|
|
import { ScriptArg } from "./ScriptArg";
|
|
import { NSEnums } from "src/ScriptEditor/NetscriptDefinitions";
|
|
import { NSFull } from "src/NetscriptFunctions";
|
|
|
|
type ExternalFunction = (...args: any[]) => void;
|
|
|
|
export type ExternalAPILayer = {
|
|
[key: string]: ExternalAPILayer | ExternalFunction | ScriptArg[];
|
|
};
|
|
|
|
type InternalFunction<F extends ExternalFunction> = (
|
|
ctx: NetscriptContext,
|
|
) => ((...args: unknown[]) => ReturnType<F>) & F;
|
|
|
|
export type InternalAPI<API> = {
|
|
[Property in keyof API]: API[Property] extends ExternalFunction
|
|
? InternalFunction<API[Property]>
|
|
: API[Property] extends NSEnums
|
|
? NSEnums
|
|
: API[Property] extends ScriptArg[]
|
|
? ScriptArg[]
|
|
: API[Property] extends object
|
|
? InternalAPI<API[Property]>
|
|
: never;
|
|
};
|
|
|
|
export type NetscriptContext = {
|
|
workerScript: WorkerScript;
|
|
function: string;
|
|
functionPath: string;
|
|
};
|
|
|
|
function wrapFunction(
|
|
wrappedAPI: ExternalAPILayer,
|
|
workerScript: WorkerScript,
|
|
func: (_ctx: NetscriptContext) => (...args: unknown[]) => unknown,
|
|
...tree: string[]
|
|
): void {
|
|
const functionPath = tree.join(".");
|
|
const functionName = tree.pop();
|
|
if (typeof functionName !== "string") {
|
|
throw helpers.makeBasicErrorMsg(workerScript, "Failure occurred while wrapping netscript api", "INITIALIZATION");
|
|
}
|
|
const ctx = {
|
|
workerScript,
|
|
function: functionName,
|
|
functionPath,
|
|
};
|
|
function wrappedFunction(...args: unknown[]): unknown {
|
|
helpers.checkEnvFlags(ctx);
|
|
helpers.updateDynamicRam(ctx, getRamCost(...tree, ctx.function));
|
|
return func(ctx)(...args);
|
|
}
|
|
const parent = getNestedProperty(wrappedAPI, tree);
|
|
Object.defineProperty(parent, functionName, {
|
|
value: wrappedFunction,
|
|
writable: true,
|
|
enumerable: true,
|
|
});
|
|
}
|
|
|
|
export function wrapAPI(workerScript: WorkerScript, namespace: object, args: ScriptArg[]): NSFull {
|
|
const wrappedAPI = wrapAPILayer({}, workerScript, namespace);
|
|
wrappedAPI.args = args;
|
|
return wrappedAPI as unknown as NSFull;
|
|
}
|
|
|
|
export function wrapAPILayer(
|
|
wrappedAPI: ExternalAPILayer,
|
|
workerScript: WorkerScript,
|
|
namespace: object,
|
|
...tree: string[]
|
|
) {
|
|
for (const [key, value] of Object.entries(namespace)) {
|
|
if (typeof value === "function") {
|
|
wrapFunction(wrappedAPI, workerScript, value, ...tree, key);
|
|
} else if (Array.isArray(value)) {
|
|
setNestedProperty(wrappedAPI, value.slice(), key);
|
|
} else if (typeof value === "object") {
|
|
wrapAPILayer(wrappedAPI, workerScript, value, ...tree, key);
|
|
} else {
|
|
setNestedProperty(wrappedAPI, value, ...tree, key);
|
|
}
|
|
}
|
|
return wrappedAPI;
|
|
}
|
|
|
|
function setNestedProperty(root: any, value: unknown, ...tree: string[]): void {
|
|
let target = root;
|
|
const key = tree.pop();
|
|
if (!key) throw new Error("Failure occurred while wrapping netscript api (setNestedProperty)");
|
|
for (const branch of tree) {
|
|
target[branch] ??= {};
|
|
target = target[branch];
|
|
}
|
|
target[key] = value;
|
|
}
|
|
|
|
function getNestedProperty(root: any, tree: string[]): unknown {
|
|
let target = root;
|
|
for (const branch of tree) {
|
|
target[branch] ??= {};
|
|
target = target[branch];
|
|
}
|
|
return target;
|
|
}
|