import QueryError from "../../errors/QueryError.js";
import NeighborhoodOptic from "./NeighborhoodOptic.js";
import NodePropertyOptic from "./NodePropertyOptic.js";
import Optic from "./Optic.js";
import OpticSupportRule from "./OpticSupportRule.js";
import TraversalOptic from "./TraversalOptic.js";
const NODE_OPTIC_KIND = 'node';
export default class NodeOptic {
    _optic;
    _locator;
    constructor(options) {
        this._optic = validateNodeOptic(options.optic);
        this._locator = options.locator;
        Object.freeze(this);
    }
    toOptic() {
        return this._optic;
    }
    async read() {
        return await this._locator.readNode(this._optic);
    }
    prop(key) {
        return new NodePropertyOptic({
            optic: this._optic.nodeProperty(key),
            locator: this._locator,
        });
    }
    neighbors() {
        return new NeighborhoodOptic({
            optic: this._optic.neighborhood(),
            locator: this._locator,
        });
    }
    traverse() {
        return new TraversalOptic({
            optic: this._optic.traversal(OpticSupportRule.globalDiscoveryRefused()),
            locator: this._locator,
        });
    }
}
function validateNodeOptic(optic) {
    if (!(optic instanceof Optic) || optic.target.opticKind !== NODE_OPTIC_KIND) {
        throwNodeOpticError('optic', 'invalid-optic');
    }
    return optic;
}
function throwNodeOpticError(field, reason) {
    throw new QueryError('Node optic is invalid.', {
        code: 'E_NODE_OPTIC',
        context: { field, reason },
    });
}
