summaryrefslogtreecommitdiff
path: root/src/config/funcs.ts
diff options
context:
space:
mode:
author2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-03-23 17:47:33 +1100
committer2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-03-23 17:47:33 +1100
commit9f6e227d7ba421fca2a60996cb7b7e560dd92d90 (patch)
tree71a5322e1eb904317c7fba132f951e439567b126 /src/config/funcs.ts
parentconfig: refactor (diff)
downloadcaelestia-shell-9f6e227d7ba421fca2a60996cb7b7e560dd92d90.tar.gz
caelestia-shell-9f6e227d7ba421fca2a60996cb7b7e560dd92d90.tar.bz2
caelestia-shell-9f6e227d7ba421fca2a60996cb7b7e560dd92d90.zip
config: validate values
Validate values for keys with literal types, also better validation for array types
Diffstat (limited to 'src/config/funcs.ts')
-rw-r--r--src/config/funcs.ts59
1 files changed, 53 insertions, 6 deletions
diff --git a/src/config/funcs.ts b/src/config/funcs.ts
index bc0a7d1..473c502 100644
--- a/src/config/funcs.ts
+++ b/src/config/funcs.ts
@@ -2,23 +2,70 @@ import { GLib, monitorFile, readFileAsync, Variable } from "astal";
import config from ".";
import { loadStyleAsync } from "../../app";
import defaults from "./defaults";
+import types from "./types";
type Settings<T> = { [P in keyof T]: T[P] extends object & { length?: never } ? Settings<T[P]> : Variable<T[P]> };
const CONFIG = `${GLib.get_user_config_dir()}/caelestia/shell.json`;
-const isObject = (o: any) => typeof o === "object" && o !== null && !Array.isArray(o);
+const isObject = (o: any): o is object => typeof o === "object" && o !== null && !Array.isArray(o);
+
+const isCorrectType = (v: any, type: string | string[] | number[], path: string) => {
+ if (Array.isArray(type)) {
+ // type is array of valid values
+ if (!type.includes(v as never)) {
+ console.warn(`Invalid value for ${path}: ${v} != ${type.map(v => `"${v}"`).join(" | ")}`);
+ return false;
+ }
+ } else if (type.startsWith("array of ")) {
+ // Array of ...
+ if (Array.isArray(v)) {
+ // Remove invalid items but always return true
+ const arrType = type.slice(9);
+ try {
+ // Recursively check type
+ const type = JSON.parse(arrType);
+ const valid = v.filter((item, i) =>
+ Object.entries(type).some(([k, t]) => {
+ if (!item[k]) {
+ console.warn(`Invalid shape for ${path}[${i}]: ${JSON.stringify(item)} != ${arrType}`);
+ return false;
+ }
+ return !isCorrectType(item[k], t as any, `${path}[${i}].${k}`);
+ })
+ );
+ v.splice(0, v.length, ...valid); // In-place filter
+ } catch {
+ const valid = v.filter((item, i) => {
+ if (typeof item !== arrType) {
+ console.warn(`Invalid type for ${path}[${i}]: ${typeof item} != ${arrType}`);
+ return false;
+ }
+ return true;
+ });
+ v.splice(0, v.length, ...valid); // In-place filter
+ }
+ } else {
+ // Type is array but value is not
+ console.warn(`Invalid type for ${path}: ${typeof v} != ${type}`);
+ return false;
+ }
+ } else if (typeof v !== type) {
+ // Value is not correct type
+ console.warn(`Invalid type for ${path}: ${typeof v} != ${type}`);
+ return false;
+ }
+
+ return true;
+};
const deepMerge = <T extends object, U extends object>(a: T, b: U, path = ""): T & U => {
const merged: { [k: string]: any } = { ...b };
for (const [k, v] of Object.entries(a)) {
if (b.hasOwnProperty(k)) {
const bv = b[k as keyof U];
- if (isObject(v) && isObject(bv)) merged[k] = deepMerge(v, bv as object, `${path}${k}.`);
- else if (typeof v !== typeof bv) {
- console.warn(`Invalid type for ${path}${k}: ${typeof v} != ${typeof bv}`);
- merged[k] = v;
- }
+ if (isObject(v) && isObject(bv)) merged[k] = deepMerge(v, bv, `${path}${k}.`);
+ else if (!isCorrectType(bv, types[path + k], path + k)) merged[k] = v;
} else merged[k] = v;
}
return merged as any;