All files index.ts

74.07% Statements 20/27
72.22% Branches 13/18
85.71% Functions 6/7
72% Lines 18/25

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52    1x 1x   1x       4x 4x 4x   4x   4x       1x   1x   1x 1x     1x 1x 1x                       1x 1x     1x            
import { Union } from './types';
 
export class AccessControl<T, R, P> {
  #roles: Union<T, R, P>;
  constructor(roles: Union<T, R, P>) {
    this.#roles = roles;
  }
 
  can(role: keyof T, action: keyof P, resource: keyof R) {
    const selectedRole = this.#roles[role as string];
    const hasResource = !!selectedRole && !!selectedRole[resource];
    const hasAction = hasResource && !!selectedRole[resource][action];
    const isActionActive =
      hasAction && !!selectedRole[resource][action].enabled;
 
    return !!selectedRole && hasResource && hasAction && isActionActive;
  }
 
  filter(role: keyof T, action: keyof P, resource: keyof R) {
    const can = this.can(role, action, resource);
    const attributes =
      (this.#roles[role as string][resource][action].attributes as string[]) ||
      [];
    return async <T>(res: T | Promise<T>): Promise<T> => {
      Iif (!can) {
        return res;
      }
      let data = (await res) as T | T[];
      const attrArray = Object.keys(attributes).filter((a) => !attributes[a]);
      Iif (Array.isArray(data)) {
        data = data.map((a) => {
          for (const attr of attrArray) {
            if (Array.isArray(a[attr])) {
              a[attr] = [];
            } else {
              delete a[attr];
            }
          }
          return a;
        });
      } else {
        for (const attr of attrArray) {
          delete data[attr];
        }
      }
      return data as T;
    };
  }
}
 
export * from './types';