refactor: remove any types from nitro editor dialog
CI / check (push) Successful in 25s
CI / release (push) Skipped
CI / deploy (push) Successful in 1m2s

This commit is contained in:
openhands committed 2026-08-09 12:27:13 +02:00
1 parent 4993b75608
commit 6549ae1959
1 file changed
+48 -25
@@ -39,28 +39,56 @@ interface NitroEditorDialogProps {
onOpenChange: (open: boolean) => void; onOpenChange: (open: boolean) => void;
} }
// Keep these helpers on `any` — Next's build-time checker has repeatedly interface NitroVisualization {
// disagreed with `tsc` on stricter JSON typings for this editor. size?: number;
// biome-ignore lint/suspicious/noExplicitAny: metadata tree is untyped JSON layers?: Record<string, { z?: number; alpha?: number; ink?: string }>;
function updateNested(obj: any, path: string, value: unknown): any { colors?: Record<string, Record<string, { color: number }>>;
const clone = JSON.parse(JSON.stringify(obj)); animations?: Record<string, unknown>;
}
// 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
// traverse arbitrary nested keys.
interface NitroMetadata {
visualizationType?: string;
logicType?: string;
logic?: {
model?: {
dimensions?: { x: number; y: number; z: number };
directions?: number[];
};
};
visualizations?: NitroVisualization[];
[key: string]: unknown;
}
type JsonObject = Record<string, unknown>;
function updateNested<T extends JsonObject>(
obj: T,
path: string,
value: unknown,
): T {
const clone: T = JSON.parse(JSON.stringify(obj));
const keys = path.split("."); const keys = path.split(".");
let current = clone; let current: JsonObject = clone;
for (let i = 0; i < keys.length - 1; i++) { for (let i = 0; i < keys.length - 1; i++) {
if (!current[keys[i]]) current[keys[i]] = {}; const next = current[keys[i]];
current = current[keys[i]]; if (!next || typeof next !== "object" || Array.isArray(next)) {
current[keys[i]] = {};
}
current = current[keys[i]] as JsonObject;
} }
current[keys[keys.length - 1]] = value; current[keys[keys.length - 1]] = value;
return clone; return clone;
} }
// biome-ignore lint/suspicious/noExplicitAny: metadata tree is untyped JSON function getNested(obj: unknown, path: string, fallback?: unknown): unknown {
function getNested(obj: any, path: string, fallback?: unknown): any {
const keys = path.split("."); const keys = path.split(".");
let current = 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[key]; current = (current as JsonObject)[key];
} }
return current ?? fallback; return current ?? fallback;
} }
@@ -99,10 +127,9 @@ export function NitroEditorDialog({
open, open,
onOpenChange, onOpenChange,
}: NitroEditorDialogProps) { }: NitroEditorDialogProps) {
// biome-ignore lint/suspicious/noExplicitAny: explicitly chosen here, see surrounding code const [metadata, setMetadata] = useState<NitroMetadata | null>(null);
const [metadata, setMetadata] = useState<any>(null); const [originalMetadata, setOriginalMetadata] =
// biome-ignore lint/suspicious/noExplicitAny: explicitly chosen here, see surrounding code useState<NitroMetadata | null>(null);
const [originalMetadata, setOriginalMetadata] = useState<any>(null);
const [jsonText, setJsonText] = useState(""); const [jsonText, setJsonText] = useState("");
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [saving, setSaving] = useState(false); const [saving, setSaving] = useState(false);
@@ -120,10 +147,9 @@ export function NitroEditorDialog({
const [jsonError, setJsonError] = useState<string | null>(null); const [jsonError, setJsonError] = useState<string | null>(null);
const patchMeta = (path: string, value: unknown) => { const patchMeta = (path: string, value: unknown) => {
// Explicit any avoids noImplicitAny on updater params and dodges setMetadata((prev) =>
// Next build's stricter JSON inference that disagreed with tsc. prev == null ? prev : updateNested(prev, path, value),
// biome-ignore lint/suspicious/noExplicitAny: metadata tree is untyped JSON );
setMetadata((prev: any) => updateNested(prev, path, value));
}; };
const fetchMetadata = useCallback(async () => { const fetchMetadata = useCallback(async () => {
@@ -258,12 +284,9 @@ export function NitroEditorDialog({
}; };
// Get visualization with size=64 for layer/color editing // Get visualization with size=64 for layer/color editing
// biome-ignore lint/suspicious/noExplicitAny: explicitly chosen here, see surrounding code const viz64 = metadata?.visualizations?.find((v) => v.size === 64);
const viz64 = metadata?.visualizations?.find((v: any) => v.size === 64);
const viz64Index = const viz64Index =
metadata?.visualizations?.findIndex( metadata?.visualizations?.findIndex((v) => v.size === 64) ?? -1;
(v: { size: number }) => v.size === 64,
) ?? -1;
const layerCount = viz64?.layers ? Object.keys(viz64.layers).length : 0; const layerCount = viz64?.layers ? Object.keys(viz64.layers).length : 0;
const colorCount = viz64?.colors ? Object.keys(viz64.colors).length : 0; const colorCount = viz64?.colors ? Object.keys(viz64.colors).length : 0;