{
  "version": 3,
  "sources": ["../src/policy.ts"],
  "sourcesContent": ["import type { Statement, Policy } from './types.js'\n\n/**\n * Resolves a selector string against a data object, inspired by jq.\n *\n * @returns The selected value, or null if the selection fails at an optional part.\n * @throws Error if the selection fails at a non-optional part.\n */\nfunction resolveSelector (data:unknown, selector:string):unknown {\n    if (selector === '.') {\n        return data\n    }\n\n    // This regex is a simplified parser for the selector syntax.\n    const partsRegex = /(\\.[\\w_]+|\\[-?\\d*:-?\\d*\\]|\\[-?\\d+\\]|\\[\\]|\\?)/g\n    const parts = selector.match(partsRegex) || []\n\n    let currentData = data\n\n    for (let part of parts) {\n        let isOptional = false\n        if (part.endsWith('?')) {\n            isOptional = true\n            part = part.slice(0, -1)\n        }\n\n        try {\n            if (currentData === undefined || currentData === null) {\n                throw new Error(\n          `Cannot process part \"${part}\" on null or undefined value.`\n                )\n            }\n\n            if (part.startsWith('.')) {\n                const key = part.substring(1)\n                if (typeof currentData !== 'object' || Array.isArray(currentData)) {\n                    throw new Error(`Cannot access key \"${key}\" on non-object.`)\n                }\n                currentData = (currentData as Record<string, unknown>)[key]\n            } else if (part === '[]') {\n                if (Array.isArray(currentData)) {\n                    // No-op for arrays, the quantifier will iterate over it.\n                } else if (typeof currentData === 'object') {\n                    currentData = Object.values(currentData as Record<string, unknown>)\n                } else {\n                    throw new Error('Cannot extract values from non-collection.')\n                }\n            } else if (part.startsWith('[') && part.includes(':')) {\n                // Slice\n                if (!Array.isArray(currentData)) {\n                    throw new Error('Slice can only be applied to arrays.')\n                }\n                const [start, end] = part\n                    .substring(1, part.length - 1)\n                    .split(':')\n                    .map((s) => (s ? Number.parseInt(s, 10) : undefined))\n                currentData = currentData.slice(start, end)\n            } else if (part.startsWith('[')) {\n                // Index\n                if (!Array.isArray(currentData)) {\n                    throw new Error('Index can only be applied to arrays.')\n                }\n                const index = Number.parseInt(part.substring(1, part.length - 1), 10)\n                currentData =\n          currentData[index < 0 ? currentData.length + index : index]\n            }\n\n            if (currentData === undefined) {\n                throw new Error(`Path segment returned undefined: ${part}`)\n            }\n        } catch (e) {\n            if (isOptional) {\n                return null\n            }\n            // Re-throw if not optional, to be caught by evaluateStatement\n            throw e\n        }\n    }\n\n    return currentData\n}\n\n/**\n * Performs a deep equality check between two values.\n */\nfunction deepEqual (a:unknown, b:unknown):boolean {\n    if (a === b) return true\n    if (a && b && typeof a === 'object' && typeof b === 'object') {\n        if (a.constructor !== b.constructor) return false\n        if (Array.isArray(a)) {\n            if (a.length !== (b as unknown[]).length) return false\n            for (let i = 0; i < a.length; i++) {\n                if (!deepEqual(a[i], (b as unknown[])[i])) return false\n            }\n            return true\n        }\n        const keys = Object.keys(a)\n        if (keys.length !== Object.keys(b).length) return false\n\n        for (const key of keys) {\n            const isEq = ((b as Record<string, unknown>)\n                .hasOwnProperty(key) ||  // eslint-disable-line\n                !deepEqual(\n                    (a as Record<string, unknown>)[key],\n                    (b as Record<string, unknown>)[key]\n                ))\n\n            if (!isEq) {\n                return false\n            }\n        }\n        return true\n    }\n    return false\n}\n\n/**\n * Converts a UCAN glob pattern to a regular expression.\n */\nfunction likeRegex (pattern:string):RegExp {\n    // Convert UCAN glob pattern to a regular expression.\n    // The glob pattern has `*` as a wildcard (zero or more chars)\n    // and `\\*` as an escape for a literal asterisk.\n    let regexString = '^'\n    let i = 0\n    while (i < pattern.length) {\n        const char = pattern[i]\n\n        if (char === '\\\\') {\n            // Handle escape sequence\n            if (i + 1 < pattern.length) {\n                const nextChar = pattern[i + 1]\n                if (nextChar === '*') {\n                    // This is an escaped asterisk `\\*`. Match a literal `*`.\n                    regexString += '\\\\*'\n                    i += 2 // Move past both `\\` and `*`\n                } else {\n                    // This is another escape, like `\\\\`. Treat the `\\` as a literal character.\n                    regexString += '\\\\\\\\'\n                    i++\n                }\n            } else {\n                // Trailing backslash. Treat as a literal `\\`.\n                regexString += '\\\\\\\\'\n                i++\n            }\n        } else if (char === '*') {\n            // This is a wildcard `*`. Match zero or more characters.\n            regexString += '.*'\n            i++\n        } else {\n            // This is a regular character. Escape it if it's a special regex metacharacter.\n            regexString += char.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&')\n            i++\n        }\n    }\n    regexString += '$'\n\n    return new RegExp(regexString)\n}\n\n/**\n * Evaluates a single policy statement against the invocation args.\n *\n * @returns The result of the evaluation.\n */\nfunction evaluateStatement<Args> (args:Args, statement:Statement<Args>):boolean {\n    const [op, ...params] = statement\n\n    try {\n        switch (op) {\n            // Comparisons\n            case '==': {\n                const [selector, value] = params as [string, unknown]\n\n                return deepEqual(resolveSelector(args, selector), value)\n            }\n            case '!=': {\n                const [selector, value] = params as [string, unknown]\n                return !deepEqual(resolveSelector(args, selector), value)\n            }\n            case '>':\n            case '>=':\n            case '<':\n            case '<=': {\n                const [selector, value] = params as [string, number]\n                const selected = resolveSelector(args, selector)\n                if (typeof selected !== 'number' || typeof value !== 'number') { return false }\n                if (op === '>') return selected > value\n                if (op === '>=') return selected >= value\n                if (op === '<') return selected < value\n                if (op === '<=') return selected <= value\n                break\n            }\n            // Glob Matching\n            case 'like': {\n                const [selector, pattern] = params as [string, string]\n                const selected = resolveSelector(args, selector)\n                if (typeof selected !== 'string') return false\n                const regex = likeRegex(pattern)\n                return regex.test(selected)\n            }\n            // Connectives\n            case 'and': {\n                const [statements] = params as [Statement<Args>[]]\n                return statements.every((stmt) => evaluateStatement(args, stmt))\n            }\n            case 'or': {\n                const [statements] = params as [Statement<Args>[]]\n                if (statements.length === 0) return true\n                return statements.some((stmt) => evaluateStatement(args, stmt))\n            }\n            case 'not': {\n                const [statement] = params as [Statement<Args>]\n                return !evaluateStatement(args, statement)\n            }\n            // Quantification\n            case 'all':\n            case 'any': {\n                const [selector, innerStmt] =\n                params as [string, Statement<unknown>]\n                let collection = resolveSelector(args, selector)\n\n                if ((innerStmt as Statement<unknown>)[0] === 'any' || (innerStmt as Statement<unknown>)[0] === 'all') {\n                    return evaluateStatement(collection, innerStmt)\n                }\n\n                if (\n                    collection &&\n          typeof collection === 'object' &&\n          !Array.isArray(collection)\n                ) {\n                    collection = Object.values(collection as Record<string, unknown>)\n                }\n                if (!Array.isArray(collection)) return false\n                if (collection.length === 0) return true\n                if (op === 'all') {\n                    return collection.every((item) => {\n                        return evaluateStatement(item, innerStmt)\n                    })\n                }\n                // any\n                return collection.some((item) => evaluateStatement(item, innerStmt))\n            }\n            default:\n                return false // Unknown operator\n        }\n    } catch {\n    // As per the spec, if a selector cannot be resolved, the statement MUST return false.\n        return false\n    }\n    return false\n}\n\n/**\n * Validates invocation arguments against a UCAN policy.\n *\n * @returns True if the args are valid according to the policy, false otherwise.\n */\nexport function validate<Args> (args:Args, policy:Policy<Args>):boolean {\n    // The top-level policy is an implicit 'and'.\n    return policy.every((statement) => evaluateStatement(args, statement))\n}\n"],
  "mappings": "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",
  "names": ["statement"]
}
