refactor: tighten nitro editor JSON typing with generic path helpers
This commit is contained in:
1 parent
6549ae1959
commit
ca49c6b5a8
1 file changed
+12
-20
@@ -47,8 +47,7 @@ interface NitroVisualization {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The .nitro metadata is untyped JSON from disk; typed only for the fields the
|
// The .nitro metadata is untyped JSON from disk; typed only for the fields the
|
||||||
// editor reads/writes, with an index signature so the generic path helpers can
|
// editor reads/writes. Unknown keys are traversed via the path helpers below.
|
||||||
// traverse arbitrary nested keys.
|
|
||||||
interface NitroMetadata {
|
interface NitroMetadata {
|
||||||
visualizationType?: string;
|
visualizationType?: string;
|
||||||
logicType?: string;
|
logicType?: string;
|
||||||
@@ -59,19 +58,18 @@ interface NitroMetadata {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
visualizations?: NitroVisualization[];
|
visualizations?: NitroVisualization[];
|
||||||
[key: string]: unknown;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type JsonObject = Record<string, unknown>;
|
type JsonObject = Record<string, unknown>;
|
||||||
|
|
||||||
function updateNested<T extends JsonObject>(
|
function updateNested<T extends object>(
|
||||||
obj: T,
|
obj: T,
|
||||||
path: string,
|
path: string,
|
||||||
value: unknown,
|
value: unknown,
|
||||||
): T {
|
): T {
|
||||||
const clone: T = JSON.parse(JSON.stringify(obj));
|
const clone: T = JSON.parse(JSON.stringify(obj));
|
||||||
const keys = path.split(".");
|
const keys = path.split(".");
|
||||||
let current: JsonObject = clone;
|
let current: JsonObject = clone as JsonObject;
|
||||||
for (let i = 0; i < keys.length - 1; i++) {
|
for (let i = 0; i < keys.length - 1; i++) {
|
||||||
const next = current[keys[i]];
|
const next = current[keys[i]];
|
||||||
if (!next || typeof next !== "object" || Array.isArray(next)) {
|
if (!next || typeof next !== "object" || Array.isArray(next)) {
|
||||||
@@ -83,14 +81,14 @@ function updateNested<T extends JsonObject>(
|
|||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNested(obj: unknown, path: string, fallback?: unknown): unknown {
|
function getNested<T>(obj: unknown, path: string, fallback: T): T {
|
||||||
const keys = path.split(".");
|
const keys = path.split(".");
|
||||||
let current: unknown = obj;
|
let current: unknown = obj;
|
||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
if (current == null || typeof current !== "object") return fallback;
|
if (current == null || typeof current !== "object") return fallback;
|
||||||
current = (current as JsonObject)[key];
|
current = (current as JsonObject)[key];
|
||||||
}
|
}
|
||||||
return current ?? fallback;
|
return current === undefined ? fallback : (current as T);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ALL_DIRECTIONS = [0, 1, 2, 3, 4, 5, 6, 7];
|
const ALL_DIRECTIONS = [0, 1, 2, 3, 4, 5, 6, 7];
|
||||||
@@ -255,14 +253,12 @@ export function NitroEditorDialog({
|
|||||||
|
|
||||||
// ── Visual tab helpers ──
|
// ── Visual tab helpers ──
|
||||||
|
|
||||||
const dims = (
|
const dims = metadata
|
||||||
metadata
|
? getNested(metadata, "logic.model.dimensions", { x: 1, y: 1, z: 0 })
|
||||||
? getNested(metadata, "logic.model.dimensions", { x: 1, y: 1, z: 0 })
|
: { x: 1, y: 1, z: 0 };
|
||||||
: { x: 1, y: 1, z: 0 }
|
const directions = metadata
|
||||||
) as { x: number; y: number; z: number };
|
? getNested(metadata, "logic.model.directions", [0])
|
||||||
const directions = (
|
: [0];
|
||||||
metadata ? getNested(metadata, "logic.model.directions", [0]) : [0]
|
|
||||||
) as number[];
|
|
||||||
|
|
||||||
const setDim = (axis: "x" | "y" | "z", value: string) => {
|
const setDim = (axis: "x" | "y" | "z", value: string) => {
|
||||||
const num =
|
const num =
|
||||||
@@ -271,11 +267,7 @@ export function NitroEditorDialog({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const toggleDirection = (dir: number) => {
|
const toggleDirection = (dir: number) => {
|
||||||
const current = getNested(
|
const current = getNested(metadata, "logic.model.directions", [0]);
|
||||||
metadata,
|
|
||||||
"logic.model.directions",
|
|
||||||
[0],
|
|
||||||
) as number[];
|
|
||||||
const next = current.includes(dir)
|
const next = current.includes(dir)
|
||||||
? current.filter((d: number) => d !== dir)
|
? current.filter((d: number) => d !== dir)
|
||||||
: [...current, dir].sort((a: number, b: number) => a - b);
|
: [...current, dir].sort((a: number, b: number) => a - b);
|
||||||
|
|||||||
Reference in new issue
Block a user