206 lines
6.1 KiB
JavaScript
206 lines
6.1 KiB
JavaScript
![]() |
//! https://github.com/trisuaso/tetratto
|
||
|
globalThis.ns_config = globalThis.ns_config || {
|
||
|
root: "/static/js/",
|
||
|
version: 0,
|
||
|
verbose: true,
|
||
|
};
|
||
|
|
||
|
globalThis._app_base = globalThis._app_base || { ns_store: {}, classes: {} };
|
||
|
|
||
|
function regns_log(level, ...args) {
|
||
|
if (globalThis.ns_config.verbose) {
|
||
|
console[level](...args);
|
||
|
} else {
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Query an existing namespace
|
||
|
globalThis.ns = (ns) => {
|
||
|
regns_log("info", "namespace query:", ns);
|
||
|
|
||
|
// get namespace from app base
|
||
|
const res = globalThis._app_base.ns_store[`$${ns}`];
|
||
|
|
||
|
if (!res) {
|
||
|
return console.error(
|
||
|
"namespace does not exist, please use one of the following:",
|
||
|
Object.keys(globalThis._app_base.ns_store),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return res;
|
||
|
};
|
||
|
|
||
|
/// Register a new namespace
|
||
|
globalThis.reg_ns = (ns, deps) => {
|
||
|
if (typeof ns !== "string") {
|
||
|
return console.error("type check failed on namespace:", ns);
|
||
|
}
|
||
|
|
||
|
if (!ns) {
|
||
|
return console.error("cannot register invalid namespace!");
|
||
|
}
|
||
|
|
||
|
if (globalThis._app_base.ns_store[`$${ns}`]) {
|
||
|
regns_log("warn", "overwriting existing namespace:", ns);
|
||
|
}
|
||
|
|
||
|
// register new blank namespace
|
||
|
globalThis._app_base.ns_store[`$${ns}`] = {
|
||
|
_ident: ns,
|
||
|
_deps: deps || [],
|
||
|
/// Pull dependencies (other namespaces) as listed in the given `deps` argument
|
||
|
_get_deps: () => {
|
||
|
const self = globalThis._app_base.ns_store[`$${ns}`];
|
||
|
const deps = {};
|
||
|
|
||
|
for (const dep of self._deps) {
|
||
|
const res = globalThis.ns(dep);
|
||
|
|
||
|
if (!res) {
|
||
|
regns_log("warn", "failed to pull dependency:", dep);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
deps[dep] = res;
|
||
|
}
|
||
|
|
||
|
deps.$ = self; // give access to self through $
|
||
|
return deps;
|
||
|
},
|
||
|
/// Store the real versions of functions
|
||
|
_fn_store: {},
|
||
|
/// Call a function in a namespace and load namespace dependencies
|
||
|
define: (name, func, types) => {
|
||
|
const self = globalThis.ns(ns);
|
||
|
self._fn_store[name] = func; // store real function
|
||
|
self[name] = function (...args) {
|
||
|
regns_log("info", "namespace call:", ns, name);
|
||
|
|
||
|
// js doesn't provide type checking, we do
|
||
|
if (types) {
|
||
|
for (const i in args) {
|
||
|
// biome-ignore lint: this is incorrect, you do not need a string literal to use typeof
|
||
|
if (types[i] && typeof args[i] !== types[i]) {
|
||
|
return console.error(
|
||
|
"argument does not pass type check:",
|
||
|
i,
|
||
|
args[i],
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ...
|
||
|
// we MUST return here, otherwise nothing will work in workers
|
||
|
return self._fn_store[name](self._get_deps(), ...args); // call with deps and arguments
|
||
|
};
|
||
|
},
|
||
|
};
|
||
|
|
||
|
regns_log("log", "registered namespace:", ns);
|
||
|
return globalThis._app_base.ns_store[`$${ns}`];
|
||
|
};
|
||
|
|
||
|
/// Call a namespace function quickly
|
||
|
globalThis.trigger = (id, args) => {
|
||
|
// get namespace
|
||
|
const s = id.split("::");
|
||
|
const [namespace, func] = [s[0], s.slice(1, s.length).join("::")];
|
||
|
const self = ns(namespace);
|
||
|
|
||
|
if (!self) {
|
||
|
return console.error("namespace does not exist:", namespace);
|
||
|
}
|
||
|
|
||
|
if (!self[func]) {
|
||
|
return console.error("namespace function does not exist:", id);
|
||
|
}
|
||
|
|
||
|
return self[func](...(args || []));
|
||
|
};
|
||
|
|
||
|
/// Import a namespace from path (relative to ns_config.root)
|
||
|
globalThis.use = (id, callback) => {
|
||
|
let file = id;
|
||
|
|
||
|
if (id.includes(".h.")) {
|
||
|
const split = id.split(".h.");
|
||
|
file = split[1];
|
||
|
}
|
||
|
|
||
|
// check if namespace already exists
|
||
|
const res = globalThis._app_base.ns_store[`$${file}`];
|
||
|
|
||
|
if (res) {
|
||
|
return callback(res);
|
||
|
}
|
||
|
|
||
|
// create script to load
|
||
|
const script = document.createElement("script");
|
||
|
script.src = `${globalThis.ns_config.root}${id}.js?v=${globalThis.ns_config.version}`;
|
||
|
script.id = `${globalThis.ns_config.version}-${file}.js`;
|
||
|
document.head.appendChild(script);
|
||
|
|
||
|
script.setAttribute("data-turbo-permanent", "true");
|
||
|
script.setAttribute("data-registered", new Date().toISOString());
|
||
|
script.setAttribute("data-version", globalThis.ns_config.version);
|
||
|
|
||
|
// run callback once the script loads
|
||
|
script.addEventListener("load", () => {
|
||
|
const res = globalThis._app_base.ns_store[`$${file}`];
|
||
|
|
||
|
if (!res) {
|
||
|
return console.error("imported namespace failed to register:", id);
|
||
|
}
|
||
|
|
||
|
callback(res);
|
||
|
});
|
||
|
};
|
||
|
|
||
|
// classes
|
||
|
|
||
|
/// Import a class from path (relative to ns_config.root/classes)
|
||
|
globalThis.require = (id, callback) => {
|
||
|
let file = id;
|
||
|
|
||
|
if (id.includes(".h.")) {
|
||
|
const split = id.split(".h.");
|
||
|
file = split[1];
|
||
|
}
|
||
|
|
||
|
// check if class already exists
|
||
|
const res = globalThis._app_base.classes[file];
|
||
|
|
||
|
if (res) {
|
||
|
return callback(res);
|
||
|
}
|
||
|
|
||
|
// create script to load
|
||
|
const script = document.createElement("script");
|
||
|
script.src = `${globalThis.ns_config.root}classes/${id}.js?v=${globalThis.ns_config.version}`;
|
||
|
script.id = `${globalThis.ns_config.version}-${file}.class.js`;
|
||
|
document.head.appendChild(script);
|
||
|
|
||
|
script.setAttribute("data-turbo-permanent", "true");
|
||
|
script.setAttribute("data-registered", new Date().toISOString());
|
||
|
script.setAttribute("data-version", globalThis.ns_config.version);
|
||
|
|
||
|
// run callback once the script loads
|
||
|
script.addEventListener("load", () => {
|
||
|
const res = globalThis._app_base.classes[file];
|
||
|
|
||
|
if (!res) {
|
||
|
return console.error("imported class failed to register:", id);
|
||
|
}
|
||
|
|
||
|
callback(res);
|
||
|
});
|
||
|
};
|
||
|
|
||
|
globalThis.define = (class_name, class_) => {
|
||
|
globalThis._app_base.classes[class_name] = class_;
|
||
|
regns_log("log", "registered class:", class_name);
|
||
|
};
|