scim2-ast
v0.3.2
Published
SCIM 2.0 filter parser with extended support for custom operators like in, nin, any, all, etc.
Maintainers
Readme
scim2-ast
SCIM 2.0 filter parser and serializer for Node.js and the browser.
This package is an updated version of scim2-parse-filter (which itself was a fork of scim2-filter), modernized with new tooling, comprehensive tests, and extended with custom operators.
This library implements the filter syntax defined in RFC 7644 Section 3.4.2.2 (Filtering).
Features
- Parse: Convert SCIM 2.0 filter strings into a typed Abstract Syntax Tree (AST).
- Filter: Execute the AST against JSON objects to filter results in memory.
- Stringify: Convert an AST back into a valid SCIM 2.0 filter string.
- Extended Operators: Support for
in,nin,any,all,regexp, andnil(null) values. - Adapters: Connect SCIM filters to various databases (e.g. MongoDB).
- Modern Tooling: Built with TypeScript and tested with Vitest.
Installation
pnpm add scim2-ast
# or
npm install scim2-ast
# or
yarn add scim2-astUsage
Parsing a Filter
Convert a SCIM filter string into an AST object.
import { parse } from 'scim2-ast';
const ast = parse('userName eq "bjensen"');
console.log(ast);
/*
Output:
{
op: "eq",
attrPath: "userName",
compValue: "bjensen"
}
*/Filtering Data
Compile a parsed AST into a predicate function to filter arrays of objects.
import { parse, filter } from 'scim2-ast';
const users = [
{ userName: 'bjensen', active: true },
{ userName: 'jsmith', active: false }
];
const ast = parse('active eq true');
const predicate = filter(ast);
const activeUsers = users.filter(predicate);
// Result: [{ userName: 'bjensen', active: true }]Stringifying an AST
Convert an AST object back into a SCIM filter string.
import { stringify } from 'scim2-ast';
const ast = {
op: "eq",
attrPath: "userName",
compValue: "bjensen"
};
const filterString = stringify(ast);
// Result: 'userName eq "bjensen"'Supported Operators
Standard SCIM 2.0 Operators
The following operators are defined in RFC 7644 Section 3.4.2.2.
| Operator | Description | Example String | Example AST |
|----------|-------------|----------------|-------------|
| eq | Equal | userName eq "bjensen" | { op: "eq", attrPath: "userName", compValue: "bjensen" } |
| ne | Not Equal | active ne false | { op: "ne", attrPath: "active", compValue: false } |
| co | Contains | title co "Manager" | { op: "co", attrPath: "title", compValue: "Manager" } |
| sw | Starts With | userName sw "b" | { op: "sw", attrPath: "userName", compValue: "b" } |
| ew | Ends With | userName ew "n" | { op: "ew", attrPath: "userName", compValue: "n" } |
| gt | Greater Than | meta.lastModified gt "2011-05-13" | { op: "gt", attrPath: "meta.lastModified", compValue: "2011-05-13" } |
| ge | Greater or Equal | age ge 18 | { op: "ge", attrPath: "age", compValue: 18 } |
| lt | Less Than | priority lt 5 | { op: "lt", attrPath: "priority", compValue: 5 } |
| le | Less or Equal | count le 10 | { op: "le", attrPath: "count", compValue: 10 } |
| pr | Present (Has value) | title pr | { op: "pr", attrPath: "title" } |
| and | Logical AND | title pr and active eq true | { op: "and", filters: [...] } |
| or | Logical OR | title pr or active eq true | { op: "or", filters: [...] } |
| not | Logical NOT | not (userType eq "Employee") | { op: "not", filter: { ... } } |
Array Handling
eq: If the attribute is an array,eqchecks if the comparison value exists within that array (standard SCIM behavior for multi-valued attributes).pr: Returnsfalseif the attribute is an empty array[](treats empty arrays as "not present").
Extended Operators
These operators are not part of the standard SCIM 2.0 spec but are supported by this library for enhanced filtering capabilities.
in
Checks if the attribute value exists in the provided array.
parse('userType in ["Employee", "Contractor"]');
// AST:
// {
// op: "in",
// attrPath: "userType",
// compValue: ["Employee", "Contractor"]
// }nin (Not In)
Checks if the attribute value does NOT exist in the provided array.
parse('userType nin ["Guest", "External"]');
// AST:
// {
// op: "nin",
// attrPath: "userType",
// compValue: ["Guest", "External"]
// }any
Checks if the array attribute has any intersection with the provided array (at least one match).
// Assuming 'roles' is an array like ["admin", "editor"]
parse('roles any ["admin", "root"]');
// AST:
// {
// op: "any",
// attrPath: "roles",
// compValue: ["admin", "root"]
// }all
Checks if the array attribute contains all of the values in the provided array.
// Assuming 'tags' is an array like ["red", "blue", "green"]
parse('tags all ["red", "blue"]');
// AST:
// {
// op: "all",
// attrPath: "tags",
// compValue: ["red", "blue"]
// }regexp
Checks if the attribute matches the regular expression pattern.
parse('userName regexp "^[a-z]+\\.[a-z]+$"');
// AST:
// {
// op: "regexp",
// attrPath: "userName",
// compValue: "^[a-z]+\\.[a-z]+$"
// }nil (Null) Support
You can explicitly compare against nil (which parses to null).
parse('name.middleName eq nil');
// AST:
// {
// op: "eq",
// attrPath: "name.middleName",
// compValue: null
// }Adapters
This library is designed to be extensible. Adapters allow you to convert SCIM ASTs into database specific queries.
| Adapter | Status | Description |
| :--- | :--- | :--- |
| scim2-ast-mongo | ✅ Available | Convert SCIM filters to MongoDB / Mongoose queries |
Contributing
Build
pnpm buildTest
pnpm testLicense
MIT
Attributions
This project is an evolution of:
