import { SetPropertyCommand } from "./commands/SetPropertyCommand.js";
export class InspectorModel {
    describe(target) {
        return this.describeObject(target);
    }
    createSetPropertyCommand(target, path, value) {
        const property = this.describe(target).find((descriptor) => samePath(descriptor.path, path));
        if (!property) {
            throw new Error(`Inspector property path does not exist: ${path.join(".")}`);
        }
        if (!property.editable) {
            throw new Error(`Inspector property is not editable: ${path.join(".")}`);
        }
        this.assertValueMatchesProperty(property, value);
        return new SetPropertyCommand(target, path, value);
    }
    describeObject(target, prefix = []) {
        const properties = [];
        for (const [key, value] of Object.entries(target)) {
            const path = [...prefix, key];
            const type = this.propertyType(value);
            properties.push({
                path,
                type,
                value,
                editable: type !== "object"
            });
            if (type === "object" && typeof value === "object" && value !== null && !Array.isArray(value)) {
                properties.push(...this.describeObject(value, path));
            }
        }
        return properties;
    }
    propertyType(value) {
        const valueType = typeof value;
        if (valueType === "number" || valueType === "string" || valueType === "boolean") {
            return valueType;
        }
        return "object";
    }
    assertValueMatchesProperty(property, value) {
        if (property.type === "number" && !Number.isFinite(value)) {
            throw new Error(`Inspector property ${property.path.join(".")} expected a finite number.`);
        }
        if (typeof value !== property.type) {
            throw new Error(`Inspector property ${property.path.join(".")} expected ${property.type}, got ${typeof value}.`);
        }
    }
}
function samePath(left, right) {
    return left.length === right.length && left.every((segment, index) => segment === right[index]);
}
//# sourceMappingURL=InspectorModel.js.map