UNPKG

@casl/ability

Version:

CASL is an isomorphic authorization JavaScript library which restricts what resources a given user is allowed to access

1 lines 8.9 kB
{"version":3,"file":"utils-DKsJWNoq.cjs","names":[],"sources":["../../src/utils.ts"],"sourcesContent":["import { AnyObject, Subject, SubjectType, SubjectClass, ForcedSubject, AliasesMap } from './types';\n\nconst hasOwn: (o: object, v: PropertyKey) => boolean = Object.hasOwn ||\n ((obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop));\n\nexport function wrapArray<T>(value: T[] | T): T[] {\n return Array.isArray(value) ? value : [value];\n}\n\nconst FORBIDDEN_PROPERTIES = new Set(['__proto__', 'constructor', 'prototype']);\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 if (FORBIDDEN_PROPERTIES.has(prop)) return res;\n res[prop] = res[prop] || {};\n return res[prop] as AnyObject;\n }, object);\n }\n\n if (!FORBIDDEN_PROPERTIES.has(lastKey)) {\n ref[lastKey] = value;\n }\n}\n\nconst TYPE_FIELD = '__caslSubjectType__';\nexport function setSubjectType<\n T extends string,\n U extends Record<PropertyKey, any>\n>(type: T, object: U): U & ForcedSubject<T> {\n if (object) {\n if (!hasOwn(object, 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<T>;\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 function getSubjectTypeName(value: SubjectType) {\n return typeof value === 'string' ? value : getSubjectClassName(value);\n}\n\nexport function detectSubjectType(object: Exclude<Subject, SubjectType>): string {\n if (hasOwn(object, TYPE_FIELD)) {\n return object[TYPE_FIELD];\n }\n\n return getSubjectClassName(object.constructor as SubjectClass);\n}\n\nexport const DETECT_SUBJECT_TYPE_STRATEGY = {\n function: (object: Exclude<Subject, SubjectType>) => object.constructor as SubjectClass,\n string: detectSubjectType\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 (hasOwn(aliasMap, 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<T>(dest: T[], target: readonly T[], start: number) {\n for (let i = start; i < target.length; i++) {\n dest.push(target[i]);\n }\n}\n\nexport function mergePrioritized<T extends { priority: number }>(\n array?: readonly T[],\n anotherArray?: readonly T[]\n): readonly 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 if (array[i].priority > anotherArray[j].priority) {\n merged.push(anotherArray[j]);\n j++;\n } else {\n // rule priority is unique, if it's equal then it's the exact same rule, so we skip the duplicate\n merged.push(array[i]);\n i++;\n j++;\n }\n }\n\n copyArrayTo(merged, array, i);\n copyArrayTo(merged, anotherArray, j);\n\n return merged;\n}\n\nexport function getOrDefault<K, V>(map: Map<K, V>, 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 = <T>(x: T) => x;\n\nexport function filterWithLazyAllocation<T>(array: T[], predicate: (item: T) => boolean): T[] {\n let result: T[] | undefined;\n for (let i = 0; i < array.length; i++) {\n const matches = predicate(array[i]);\n if (result && matches) {\n result.push(array[i]);\n }\n if (!matches) {\n result ??= array.slice(0, i);\n }\n }\n\n return result || array;\n}\n"],"mappings":"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"}