{"version":3,"file":"rules.mjs","names":[],"sources":["../../src/shield/rules.ts"],"sourcesContent":["/* -------------------------------------------------------------------\n\n                       🗲 Storm Software - Stryke\n\n This code was released as part of the Stryke project. Stryke\n is maintained by Storm Software under the Apache-2.0 license, and is\n free for commercial and private use. For more information, please visit\n our licensing page at https://stormsoftware.com/licenses/projects/stryke.\n\n Website:                  https://stormsoftware.com\n Repository:               https://github.com/storm-software/stryke\n Documentation:            https://docs.stormsoftware.com/projects/stryke\n Contact:                  https://stormsoftware.com/contact\n\n SPDX-License-Identifier:  Apache-2.0\n\n ------------------------------------------------------------------- */\n\nimport type {\n  LogicRuleInterface,\n  OptionsInterface,\n  RuleFunctionInterface,\n  RuleInterface,\n  RuleResultInterface,\n  ShieldRule\n} from \"./types\";\n\nexport class Rule<\n  TContext extends Record<string, any>\n> implements RuleInterface<TContext> {\n  readonly name: string;\n\n  func?: RuleFunctionInterface<TContext>;\n\n  constructor(name: string, func?: RuleFunctionInterface<TContext>) {\n    this.name = name;\n    this.func = func;\n  }\n\n  async resolve(\n    ctx: TContext,\n    type: string,\n    path: string,\n    input: { [name: string]: any },\n    rawInput: unknown,\n    options: OptionsInterface<TContext>\n  ): Promise<RuleResultInterface> {\n    try {\n      /* Resolve */\n      const res = await this.executeRule(\n        ctx,\n        type,\n        path,\n        input,\n        rawInput,\n        options\n      );\n\n      if (res instanceof Error) {\n        return res;\n      } else if (typeof res === \"string\") {\n        return new Error(res);\n      } else if (res === true) {\n        return true;\n      } else {\n        return false;\n      }\n    } catch (err) {\n      if (options.debug) {\n        throw err;\n      } else {\n        return false;\n      }\n    }\n  }\n\n  /**\n   *\n   * Compares a given rule with the current one\n   * and checks whether their functions are equal.\n   *\n   */\n  equals(rule: Rule<TContext>): boolean {\n    return this.func === rule.func;\n  }\n\n  executeRule<TContext extends Record<string, any>>(\n    ctx: TContext,\n    type: string,\n    path: string,\n    input: { [name: string]: any },\n    rawInput: unknown,\n    options: OptionsInterface<TContext>\n  ): string | boolean | Error | Promise<RuleResultInterface> {\n    // @ts-ignore\n    return this.func(ctx, type, path, input, rawInput, options);\n  }\n}\n\nexport class LogicRule<TContext extends Record<string, any>>\n  extends Rule<TContext>\n  implements LogicRuleInterface<TContext>\n{\n  private rules: ShieldRule<TContext>[];\n\n  constructor(rules: ShieldRule<TContext>[]) {\n    super(\"LogicRule\");\n\n    this.rules = rules;\n  }\n\n  /**\n   * By default logic rule resolves to false.\n   */\n  override async resolve(\n    _ctx: TContext,\n    _type: string,\n    _path: string,\n    _input: { [name: string]: any },\n    _rawInput: unknown,\n    _options: OptionsInterface<TContext>\n  ): Promise<RuleResultInterface> {\n    return false;\n  }\n\n  /**\n   * Evaluates all the rules.\n   */\n  async evaluate(\n    ctx: TContext,\n    type: string,\n    path: string,\n    input: { [name: string]: any },\n    rawInput: unknown,\n    options: OptionsInterface<TContext>\n  ): Promise<RuleResultInterface[]> {\n    const rules = this.getRules();\n    const tasks = rules.map(async rule =>\n      rule.resolve(ctx, type, path, input, rawInput, options)\n    );\n\n    return Promise.all(tasks);\n  }\n\n  /**\n   * Returns rules in a logic rule.\n   */\n  getRules() {\n    return this.rules;\n  }\n}\n\n// Extended Types\n\nexport class RuleOr<\n  TContext extends Record<string, any>\n> extends LogicRule<TContext> {\n  constructor(rules: ShieldRule<TContext>[]) {\n    super(rules);\n  }\n\n  /**\n   * Makes sure that at least one of them has evaluated to true.\n   */\n  override async resolve(\n    ctx: TContext,\n    type: string,\n    path: string,\n    input: { [name: string]: any },\n    rawInput: unknown,\n    options: OptionsInterface<TContext>\n  ): Promise<RuleResultInterface> {\n    const result = await this.evaluate(\n      ctx,\n      type,\n      path,\n      input,\n      rawInput,\n      options\n    );\n\n    if (result.every(res => res !== true)) {\n      const customError = result.find(res => res instanceof Error);\n\n      return customError ?? false;\n    } else {\n      return true;\n    }\n  }\n}\n\nexport class RuleAnd<\n  TContext extends Record<string, any>\n> extends LogicRule<TContext> {\n  constructor(rules: ShieldRule<TContext>[]) {\n    super(rules);\n  }\n\n  /**\n   * Makes sure that all of them have resolved to true.\n   */\n  override async resolve(\n    ctx: TContext,\n    type: string,\n    path: string,\n    input: { [name: string]: any },\n    rawInput: unknown,\n    options: OptionsInterface<TContext>\n  ): Promise<RuleResultInterface> {\n    const result = await this.evaluate(\n      ctx,\n      type,\n      path,\n      input,\n      rawInput,\n      options\n    );\n\n    if (result.some(res => res !== true)) {\n      const customError = result.find(res => res instanceof Error);\n\n      return customError ?? false;\n    } else {\n      return true;\n    }\n  }\n}\n\nexport class RuleChain<\n  TContext extends Record<string, any>\n> extends LogicRule<TContext> {\n  constructor(rules: ShieldRule<TContext>[]) {\n    super(rules);\n  }\n\n  /**\n   * Makes sure that all of them have resolved to true.\n   */\n  override async resolve(\n    ctx: TContext,\n    type: string,\n    path: string,\n    input: { [name: string]: any },\n    rawInput: unknown,\n    options: OptionsInterface<TContext>\n  ): Promise<RuleResultInterface> {\n    const result = await this.evaluate(\n      ctx,\n      type,\n      path,\n      input,\n      rawInput,\n      options\n    );\n\n    if (result.some(res => res !== true)) {\n      const customError = result.find(res => res instanceof Error);\n\n      return customError ?? false;\n    } else {\n      return true;\n    }\n  }\n\n  /**\n   * Evaluates all the rules.\n   */\n  override async evaluate(\n    ctx: TContext,\n    type: string,\n    path: string,\n    input: { [name: string]: any },\n    rawInput: unknown,\n    options: OptionsInterface<TContext>\n  ): Promise<RuleResultInterface[]> {\n    const rules = this.getRules();\n\n    return iterate(rules);\n\n    async function iterate([\n      rule,\n      ...otherRules\n    ]: ShieldRule<TContext>[]): Promise<RuleResultInterface[]> {\n      if (rule === undefined) return [];\n      return rule\n        .resolve(ctx, type, path, input, rawInput, options)\n        .then(async res => {\n          if (res !== true) {\n            return [res];\n          } else {\n            return iterate(otherRules).then(ress => ress.concat(res));\n          }\n        });\n    }\n  }\n}\n\nexport class RuleRace<\n  TContext extends Record<string, any>\n> extends LogicRule<TContext> {\n  constructor(rules: ShieldRule<TContext>[]) {\n    super(rules);\n  }\n\n  /**\n   * Makes sure that at least one of them resolved to true.\n   */\n  override async resolve(\n    ctx: TContext,\n    type: string,\n    path: string,\n    input: { [name: string]: any },\n    rawInput: unknown,\n    options: OptionsInterface<TContext>\n  ): Promise<RuleResultInterface> {\n    const result = await this.evaluate(\n      ctx,\n      type,\n      path,\n      input,\n      rawInput,\n      options\n    );\n\n    if (result.includes(true)) {\n      return true;\n    } else {\n      const customError = result.find(res => res instanceof Error);\n\n      return customError ?? false;\n    }\n  }\n\n  /**\n   * Evaluates all the rules.\n   */\n  override async evaluate(\n    ctx: TContext,\n    type: string,\n    path: string,\n    input: { [name: string]: any },\n    rawInput: unknown,\n    options: OptionsInterface<TContext>\n  ): Promise<RuleResultInterface[]> {\n    const rules = this.getRules();\n\n    return iterate(rules);\n\n    async function iterate([\n      rule,\n      ...otherRules\n    ]: ShieldRule<TContext>[]): Promise<RuleResultInterface[]> {\n      if (rule === undefined) return [];\n      return rule\n        .resolve(ctx, type, path, input, rawInput, options)\n        .then(async res => {\n          if (res === true) {\n            return [res];\n          } else {\n            return iterate(otherRules).then(ress => ress.concat(res));\n          }\n        });\n    }\n  }\n}\n\nexport class RuleNot<TContext extends Record<string, any>>\n  extends LogicRule<TContext>\n  implements LogicRuleInterface<TContext>\n{\n  error?: Error;\n\n  override name: string = \"RuleNot\";\n\n  override equals!: (rule: RuleInterface<TContext>) => boolean;\n\n  constructor(rule: ShieldRule<TContext>, error?: Error) {\n    super([rule]);\n    this.error = error;\n  }\n\n  /**\n   * Negates the result.\n   */\n  override async resolve(\n    ctx: TContext,\n    type: string,\n    path: string,\n    input: { [name: string]: any },\n    rawInput: unknown,\n    options: OptionsInterface<TContext>\n  ): Promise<RuleResultInterface> {\n    const [res] = await this.evaluate(\n      ctx,\n      type,\n      path,\n      input,\n      rawInput,\n      options\n    );\n\n    if (res instanceof Error) {\n      return true;\n    } else if (res !== true) {\n      return true;\n    } else {\n      if (this.error) return this.error;\n      return false;\n    }\n  }\n}\n\nexport class RuleTrue<TContext extends Record<string, any>>\n  extends LogicRule<TContext>\n  implements LogicRuleInterface<TContext>\n{\n  override name: string = \"RuleTrue\";\n\n  override equals!: (rule: RuleInterface<TContext>) => boolean;\n\n  constructor() {\n    super([]);\n  }\n\n  /**\n   *\n   * Always true.\n   *\n   */\n  override async resolve(): Promise<RuleResultInterface> {\n    return true;\n  }\n}\n\nexport class RuleFalse<TContext extends Record<string, any>>\n  extends LogicRule<TContext>\n  implements LogicRuleInterface<TContext>\n{\n  override name: string = \"RuleTrue\";\n\n  override equals!: (rule: RuleInterface<TContext>) => boolean;\n\n  constructor() {\n    super([]);\n  }\n\n  /**\n   *\n   * Always false.\n   *\n   */\n  override async resolve(): Promise<RuleResultInterface> {\n    return false;\n  }\n}\n"],"mappings":"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"}