Skip to content

Best Practices

Every method except filter() mutates the source. If the object is shared (a cache entry, a request body, app state), clone() first:

const safe = Notation.create(shared).clone().set('seen', true).value;

Silent undefined is convenient until it hides a typo in a path that gates access or billing. Turn on strict so missing paths and blocked writes throw:

const n = Notation.create(record, { strict: true });

When shaping data you send to a client, prefer an explicit allow-list over a deny-list — a new sensitive field added later stays hidden by default:

// safer: only these escape
Notation.create(user).filter(['id', 'name', 'profile.*']).value;
// riskier: everything escapes unless you remember to deny it
Notation.create(user).filter(['*', '!passwordHash']).value;

If you must use a deny-list, keep it in restrictive mode so negations can’t be re-included.

!x removes x; !x.* empties it. Using !x.* against a non-object throws an integrity error. Pick the one that matches the value’s type.

Don’t concatenate glob arrays by hand — let NotationGlob.union() merge and normalize them so redundant and contradictory patterns resolve correctly:

const globs = NotationGlob.union(roleA, roleB);

If a notation comes from outside, check it before use — and pick the right validator for the context:

Notation.isValid(input); // regular notation (no wildcards)
NotationGlob.isValid(input); // glob (allows * and !)

A small alias keeps call sites readable:

const notate = Notation.create;
notate(obj).get('a.b.c');