import { get, set } from '@dikolab/private-parts'; import type { AnyBoundary } from '../../boundary/types/utility.type'; import { BOUNDARY_KEY, NAME_KEY, } from '../../utils/constants/symbol-keys.constant'; import type { Goal } from '../../goal/classes/goal.class'; import { defineGoal } from '../../goal/functions/define-goal.function'; import type { AnyRole, ResolveRoleNames, } from '../../actor/types/utility.type'; import { Role } from '../../actor/classes/role.class'; import { AsChain } from './as-chain.class'; /** * Provides a scoped context for defining goals * and use cases within a boundary */ export class Scope { get [BOUNDARY_KEY](): Boundary { // eslint-disable-next-line @typescript-eslint/no-unsafe-return return get(this, BOUNDARY_KEY); } constructor(boundary: Boundary) { set(this, BOUNDARY_KEY, boundary); } /** * Creates Goal to be used for declaring a Use-case * * @param title Unique goal title of what you want to achieve. * @returns Goal */ defineGoal( title: Title, ): Goal<Title, Boundary> { return defineGoal(title, this[BOUNDARY_KEY]); } /** * Creates declaration of Roles that guards the Use-case execution * * @param roles Role names or Roles included in the context * @returns declaration chain object */ as<Targets extends readonly (string | AnyRole)[]>( ...roles: Targets ) { const roleNames = roles.map((roleOrName) => { if (typeof roleOrName === 'string') { return roleOrName; } if (roleOrName instanceof Role) { return roleOrName[NAME_KEY]; } throw new TypeError('Role parameter is invalid.'); }) as ResolveRoleNames<Targets>; return new AsChain(this[BOUNDARY_KEY], roleNames); } }