Skip to content

Commit

Permalink
documentation: add code comments to enforceEager
Browse files Browse the repository at this point in the history
  • Loading branch information
ealush committed Jul 15, 2022
1 parent e4590ac commit a9070d9
Showing 1 changed file with 20 additions and 0 deletions.
20 changes: 20 additions & 0 deletions packages/n4s/src/runtime/enforceEager.ts
Expand Up @@ -8,19 +8,30 @@ import { transformResult } from 'transformResult';

type IRules = n4s.IRules<Record<string, any>>;

// eslint-disable-next-line max-lines-per-function
export default function enforceEager(value: RuleValue): IRules {
const target = {} as IRules;

// This condition is for when we don't have proxy support (ES5).
// In this case, we need to manually assign the rules to the target object on runtime.
// The follow up proxy block is used in case we do have proxy support, and we can assign each rule upon invocation.
if (!isProxySupported()) {
// We iterate over each of the rules, and add them to the target object being return by enforce
eachEnforceRule((ruleName: KBaseRules, ruleFn) => {
// We then wrap the rule with `genRuleCall` that adds the base enforce behavior
target[ruleName] = genRuleCall(target, ruleFn, ruleName);
});

return target;
}

// We create a proxy intercepting access to the target object (which is empty).
const proxy: IRules = new Proxy(target, {
get: (_, ruleName: string) => {
// On property access, we identify if it is a rule or not.
const rule = getRule(ruleName);

// If it is a rule, we wrap it with `genRuleCall` that adds the base enforce behavior
if (rule) {
return genRuleCall(proxy, rule, ruleName);
}
Expand All @@ -29,12 +40,21 @@ export default function enforceEager(value: RuleValue): IRules {

return proxy;

// This function is used to wrap a rule with the base enforce behavior
// It takes the target object, the rule function, and the rule name
// It then returns the rule, in a manner that can be used by enforce
function genRuleCall(target: IRules, rule: RuleBase, ruleName: string) {
return function ruleCall(...args: Args) {
// Order of operation:
// 1. Create a context with the value being enforced
// 2. Call the rule within the context, and pass over the arguments passed to it
// 3. Transform the result to the correct output format
const transformedResult = ctx.run({ value }, () =>
transformResult(rule(value, ...args), ruleName, value, ...args)
);

// On rule failure (the result is false), we either throw an error
// or throw a string value if the rule has a message defined in it.
invariant(
transformedResult.pass,
isNullish(transformedResult.message)
Expand Down

0 comments on commit a9070d9

Please sign in to comment.