{"version":3,"file":"extra.mjs","sources":["../../src/utils.ts","../../src/extra.ts"],"sourcesContent":["import { AnyObject, Subject, SubjectType, SubjectClass, ForcedSubject, AliasesMap } from './types';\n\nexport function wrapArray(value: T[] | T): T[] {\n return Array.isArray(value) ? value : [value];\n}\n\nexport function setByPath(object: AnyObject, path: string, value: unknown): void {\n let ref = object;\n let lastKey = path;\n\n if (path.indexOf('.') !== -1) {\n const keys = path.split('.');\n\n lastKey = keys.pop()!;\n ref = keys.reduce((res, prop) => {\n res[prop] = res[prop] || {};\n return res[prop] as AnyObject;\n }, object);\n }\n\n ref[lastKey] = value;\n}\n\nconst TYPE_FIELD = '__caslSubjectType__';\nexport function setSubjectType<\n T extends string,\n U extends Record\n>(type: T, object: U): U & ForcedSubject {\n if (object) {\n if (!object.hasOwnProperty(TYPE_FIELD)) {\n Object.defineProperty(object, TYPE_FIELD, { value: type });\n } else if (type !== object[TYPE_FIELD]) {\n throw new Error(`Trying to cast object to subject type ${type} but previously it was casted to ${object[TYPE_FIELD]}`);\n }\n }\n\n return object as U & ForcedSubject;\n}\n\nexport const isSubjectType = (value: unknown): value is SubjectType => {\n const type = typeof value;\n return type === 'string' || type === 'function';\n};\n\nconst getSubjectClassName = (value: SubjectClass) => value.modelName || value.name;\nexport const getSubjectTypeName = (value: SubjectType) => {\n return typeof value === 'string' ? value : getSubjectClassName(value);\n};\n\nexport function detectSubjectType(subject: Exclude): string {\n if (subject.hasOwnProperty(TYPE_FIELD)) {\n return (subject as any)[TYPE_FIELD];\n }\n\n return getSubjectClassName(subject.constructor as SubjectClass);\n}\n\ntype AliasMerge = (actions: string[], action: string | string[]) => string[];\nfunction expandActions(aliasMap: AliasesMap, rawActions: string | string[], merge: AliasMerge) {\n let actions = wrapArray(rawActions);\n let i = 0;\n\n while (i < actions.length) {\n const action = actions[i++];\n\n if (aliasMap.hasOwnProperty(action)) {\n actions = merge(actions, aliasMap[action]);\n }\n }\n\n return actions;\n}\n\nfunction findDuplicate(actions: string[], actionToFind: string | string[]) {\n if (typeof actionToFind === 'string' && actions.indexOf(actionToFind) !== -1) {\n return actionToFind;\n }\n\n for (let i = 0; i < actionToFind.length; i++) {\n if (actions.indexOf(actionToFind[i]) !== -1) return actionToFind[i];\n }\n\n return null;\n}\n\nconst defaultAliasMerge: AliasMerge = (actions, action) => actions.concat(action);\nfunction validateForCycles(aliasMap: AliasesMap, reservedAction: string) {\n if (reservedAction in aliasMap) {\n throw new Error(`Cannot use \"${reservedAction}\" as an alias because it's reserved action.`);\n }\n\n const keys = Object.keys(aliasMap);\n const mergeAliasesAndDetectCycles: AliasMerge = (actions, action) => {\n const duplicate = findDuplicate(actions, action);\n if (duplicate) throw new Error(`Detected cycle ${duplicate} -> ${actions.join(', ')}`);\n\n const isUsingReservedAction = typeof action === 'string' && action === reservedAction\n || actions.indexOf(reservedAction) !== -1\n || Array.isArray(action) && action.indexOf(reservedAction) !== -1;\n if (isUsingReservedAction) throw new Error(`Cannot make an alias to \"${reservedAction}\" because this is reserved action`);\n\n return actions.concat(action);\n };\n\n for (let i = 0; i < keys.length; i++) {\n expandActions(aliasMap, keys[i], mergeAliasesAndDetectCycles);\n }\n}\n\nexport type AliasResolverOptions = { skipValidate?: boolean; anyAction?: string };\nexport function createAliasResolver(aliasMap: AliasesMap, options?: AliasResolverOptions) {\n if (!options || options.skipValidate !== false) {\n validateForCycles(aliasMap, options && options.anyAction || 'manage');\n }\n\n return (action: string | string[]) => expandActions(aliasMap, action, defaultAliasMerge);\n}\n\nfunction copyArrayTo(dest: T[], target: T[], start: number) {\n for (let i = start; i < target.length; i++) {\n dest.push(target[i]);\n }\n}\n\nexport function mergePrioritized(\n array?: T[],\n anotherArray?: T[]\n): T[] {\n if (!array || !array.length) {\n return anotherArray || [];\n }\n\n if (!anotherArray || !anotherArray.length) {\n return array || [];\n }\n\n let i = 0;\n let j = 0;\n const merged: T[] = [];\n\n while (i < array.length && j < anotherArray.length) {\n if (array[i].priority < anotherArray[j].priority) {\n merged.push(array[i]);\n i++;\n } else {\n merged.push(anotherArray[j]);\n j++;\n }\n }\n\n copyArrayTo(merged, array, i);\n copyArrayTo(merged, anotherArray, j);\n\n return merged;\n}\n\nexport function getOrDefault(map: Map, key: K, defaultValue: () => V) {\n let value = map.get(key);\n\n if (!value) {\n value = defaultValue();\n map.set(key, value);\n }\n\n return value;\n}\n\nexport const identity = (x: T) => x;\n","import { Condition, buildAnd, buildOr } from '@ucast/mongo2js';\nimport { PureAbility, AnyAbility } from './PureAbility';\nimport { RuleOf } from './RuleIndex';\nimport { RawRule } from './RawRule';\nimport { Rule } from './Rule';\nimport { setByPath, wrapArray } from './utils';\nimport { AnyObject, SubjectType, ExtractSubjectType } from './types';\n\nexport type RuleToQueryConverter = (rule: RuleOf) => object;\nexport interface AbilityQuery {\n $or?: T[]\n $and?: T[]\n}\n\nexport function rulesToQuery(\n ability: T,\n action: Parameters[0],\n subjectType: ExtractSubjectType[1]>,\n convert: RuleToQueryConverter\n): AbilityQuery | null {\n const query: AbilityQuery = {};\n const rules = ability.rulesFor(action, subjectType);\n\n for (let i = 0; i < rules.length; i++) {\n const rule = rules[i];\n const op = rule.inverted ? '$and' : '$or';\n\n if (!rule.conditions) {\n if (rule.inverted) {\n break;\n } else {\n delete query[op];\n return query;\n }\n } else {\n query[op] = query[op] || [];\n query[op]!.push(convert(rule));\n }\n }\n\n return query.$or ? query : null;\n}\n\nfunction ruleToAST(rule: RuleOf): Condition {\n if (!rule.ast) {\n throw new Error(`Ability rule \"${JSON.stringify(rule)}\" does not have \"ast\" property. So, cannot be used to generate AST`);\n }\n return rule.ast;\n}\n\nexport function rulesToAST(\n ability: T,\n action: Parameters[0],\n subjectType: ExtractSubjectType[1]>,\n): Condition | null {\n const query = rulesToQuery(ability, action, subjectType, ruleToAST) as AbilityQuery;\n\n if (query === null) {\n return null;\n }\n\n if (!query.$and) {\n return query.$or ? buildOr(query.$or) : buildAnd([]);\n }\n\n if (query.$or) {\n query.$and.push(buildOr(query.$or));\n }\n\n return buildAnd(query.$and);\n}\n\nexport function rulesToFields>(\n ability: T,\n action: Parameters[0],\n subjectType: ExtractSubjectType[1]>,\n): AnyObject {\n return ability.rulesFor(action, subjectType)\n .reduce((values, rule) => {\n if (rule.inverted || !rule.conditions) {\n return values;\n }\n\n return Object.keys(rule.conditions).reduce((fields, fieldName) => {\n const value = rule.conditions![fieldName];\n\n if (!value || (value as any).constructor !== Object) {\n setByPath(fields, fieldName, value);\n }\n\n return fields;\n }, values);\n }, {} as AnyObject);\n}\n\nexport type GetRuleFields> = (rule: R) => string[];\n\nexport interface PermittedFieldsOptions {\n fieldsFrom: GetRuleFields>\n}\n\nexport function permittedFieldsOf(\n ability: T,\n action: Parameters[0],\n subject: Parameters[1],\n options: PermittedFieldsOptions\n): string[] {\n const subjectType = ability.detectSubjectType(subject);\n const rules = ability.possibleRulesFor(action, subjectType);\n const uniqueFields = new Set();\n const deleteItem = uniqueFields.delete.bind(uniqueFields);\n const addItem = uniqueFields.add.bind(uniqueFields);\n let i = rules.length;\n\n while (i--) {\n const rule = rules[i];\n if (rule.matchesConditions(subject)) {\n const toggle = rule.inverted ? deleteItem : addItem;\n options.fieldsFrom(rule).forEach(toggle);\n }\n }\n\n return Array.from(uniqueFields);\n}\n\nconst joinIfArray = (value: string | string[]) => Array.isArray(value) ? value.join(',') : value;\n\nexport type PackRule> =\n [string, string] |\n [string, string, T['conditions']] |\n [string, string, T['conditions'] | 0, 1] |\n [string, string, T['conditions'] | 0, 1 | 0, string] |\n [string, string, T['conditions'] | 0, 1 | 0, string | 0, string];\n\nexport type PackSubjectType = (type: T) => string;\n\nexport function packRules>(\n rules: T[],\n packSubject?: PackSubjectType\n): PackRule[] {\n return rules.map((rule) => { // eslint-disable-line\n const packedRule: PackRule = [\n joinIfArray((rule as any).action || (rule as any).actions),\n typeof packSubject === 'function'\n ? wrapArray(rule.subject).map(packSubject).join(',')\n : joinIfArray(rule.subject),\n rule.conditions || 0,\n rule.inverted ? 1 : 0,\n rule.fields ? joinIfArray(rule.fields) : 0,\n rule.reason || ''\n ];\n\n while (!packedRule[packedRule.length - 1]) packedRule.pop();\n\n return packedRule;\n });\n}\n\nexport type UnpackSubjectType = (type: string) => T;\n\nexport function unpackRules>(\n rules: PackRule[],\n unpackSubject?: UnpackSubjectType\n): T[] {\n return rules.map(([action, subject, conditions, inverted, fields, reason]) => {\n const subjects = subject.split(',');\n const rule = {\n inverted: !!inverted,\n action: action.split(','),\n subject: typeof unpackSubject === 'function'\n ? subjects.map(unpackSubject)\n : subjects\n } as T;\n\n if (conditions) {\n rule.conditions = conditions;\n }\n\n if (fields) {\n rule.fields = fields.split(',');\n }\n\n if (reason) {\n rule.reason = reason;\n }\n\n return rule;\n });\n}\n"],"names":["wrapArray","value","Array","isArray","setByPath","object","path","ref","lastKey","indexOf","keys","split","pop","reduce","res","prop","rulesToQuery","ability","action","subjectType","convert","query","rules","rulesFor","i","length","rule","op","inverted","conditions","push","$or","ruleToAST","ast","Error","JSON","stringify","rulesToAST","$and","buildOr","buildAnd","rulesToFields","values","Object","fields","fieldName","constructor","permittedFieldsOf","subject","options","detectSubjectType","possibleRulesFor","uniqueFields","Set","deleteItem","delete","bind","addItem","add","matchesConditions","toggle","fieldsFrom","forEach","from","joinIfArray","join","packRules","packSubject","map","packedRule","actions","reason","unpackRules","unpackSubject","subjects"],"mappings":"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"}