{"_id":"@campino/rule","name":"@campino/rule","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@campino/rule","version":"1.0.0","description":"A rule builder library for creating and evaluating rules in a structured manner.","keywords":["campino","hynek","hynek-shop"],"homepage":"https://github.com/hynek-systems/hynek-shop-rule#readme","bugs":{"url":"https://github.com/hynek-systems/hynek-shop-rule/issues"},"license":"MIT","author":{"name":"Henric Söderlind","email":"henric.soderlind@outlook.com"},"repository":{"type":"git","url":"git+https://github.com/hynek-systems/hynek-shop-rule.git"},"type":"module","exports":{".":"./dist/index.mjs","./package.json":"./package.json"},"publishConfig":{"access":"public"},"scripts":{"build":"vp pack","benchmark":"vp pack && node benchmarks/rule-tree.mjs","dev":"vp pack --watch","test":"vp test","test:package":"vp pack && node tests/package-consumer.mjs","check":"vp check","prepublishOnly":"vp check && vp test && vp run test:package && vp run benchmark","prepare":"vp config","release":"bumpp --all"},"dependencies":{"uuid":"^14.0.1"},"devDependencies":{"@types/node":"^25.6.2","@typescript/native-preview":"7.0.0-dev.20260509.2","bumpp":"^11.1.0","typescript":"^6.0.3","vite-plus":"^0.1.20"},"overrides":{"vite":"npm:@voidzero-dev/vite-plus-core@0.2.4"},"engines":{"node":">=22.12.0"},"packageManager":"npm@12.0.1","gitHead":"9402c1d62e78c0bd065be03036138e30245be6d5","_id":"@campino/rule@1.0.0","_nodeVersion":"24.18.0","_npmVersion":"12.0.1","dist":{"integrity":"sha512-FFdlliheDdudhV0U3i/RV/wYwvZveDJnsOFdDuw1uUkV1luylKKw2+aeaoQQhbbUe0TW+Aj2ImgP7rCUUeie7w==","shasum":"c403e4ed0ac7adc72bdb484dfb8633516451cd9b","tarball":"https://registry.npmjs.org/@campino/rule/-/rule-1.0.0.tgz","fileCount":12,"unpackedSize":64952,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIGUa9i2KNdAlMqQvTnpOq4HJVl4XPeRCzfxDWImhg4KfAiEAownF+4hewXlkvwnOgdTLtWilNOPtFEue3696dlP4Qug="}]},"_npmUser":{"name":"campino","email":"henric.soderlind@outlook.com"},"directories":{},"maintainers":[{"name":"campino","email":"henric.soderlind@outlook.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/rule_1.0.0_1785257291417_0.7978477544890421"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-28T16:48:11.258Z","1.0.0":"2026-07-28T16:48:11.565Z","modified":"2026-07-28T16:48:11.792Z"},"maintainers":[{"name":"campino","email":"henric.soderlind@outlook.com"}],"description":"A rule builder library for creating and evaluating rules in a structured manner.","homepage":"https://github.com/hynek-systems/hynek-shop-rule#readme","keywords":["campino","hynek","hynek-shop"],"repository":{"type":"git","url":"git+https://github.com/hynek-systems/hynek-shop-rule.git"},"author":{"name":"Henric Söderlind","email":"henric.soderlind@outlook.com"},"bugs":{"url":"https://github.com/hynek-systems/hynek-shop-rule/issues"},"license":"MIT","readme":"# @campino/rule\n\nA typed TypeScript library for building, validating, evaluating, cloning, and\nserializing rule trees.\n\n## Installation\n\n```bash\nnpm install @campino/rule\n```\n\nThe package is ESM-only and includes TypeScript declarations.\n\n## Quick start\n\n```ts\nimport {\n  AndOperator,\n  EqualsOperator,\n  Field,\n  GreaterThanOperator,\n  NumberFieldType,\n  ObjectFieldResolver,\n  Rule,\n  RuleContext,\n  RuleEvaluator,\n  RuleTree,\n  RuleTreeCloner,\n  RuleTreeValidator,\n  StringFieldType,\n} from \"@campino/rule\";\n\nconst context = new RuleContext();\n\ncontext.groupOperators.register(new AndOperator());\ncontext.ruleOperators.register(new EqualsOperator());\ncontext.ruleOperators.register(new GreaterThanOperator());\n\ncontext.fields.register(new Field(\"country\", \"Country\", StringFieldType));\ncontext.fields.register(new Field(\"price\", \"Price\", NumberFieldType));\n\nconst tree = new RuleTree();\n\ntree.root.append(Rule.field<string>(\"country\").equals(\"SE\"));\ntree.root.append(Rule.field<number>(\"price\").greaterThan(100));\n\nconst errors = new RuleTreeValidator().validate(tree);\n\nif (errors.length > 0) {\n  throw new Error(errors.map((error) => error.message).join(\"\\n\"));\n}\n\nconst evaluator = new RuleEvaluator(new ObjectFieldResolver());\nconst matches = evaluator.evaluate(tree, { country: \"SE\", price: 150 });\n\nconst dto = tree.toJSON();\nconst restored = context.fromJSON(dto);\nconst copy = new RuleTreeCloner().clone(restored);\n\nconsole.log(matches); // true\nconsole.log(copy.toString());\n```\n\n`RuleContext` must contain every group and rule operator referenced by a DTO\nbefore calling `fromJSON`. Register fields when the context is also used to\ndrive a rule editor or to look up the operators available for a field.\n\n## Core concepts\n\n- `RuleTree` owns a root `Group`. The root uses `AndOperator` by default.\n- `Rule.field<T>()` creates a typed expression builder for a field or field ID.\n- `Group` combines child results with an `AndOperator` or `OrOperator`.\n- `RuleTreeValidator` reports structural errors such as empty groups and rules\n  without a field ID.\n- `RuleEvaluator` evaluates a tree using a `FieldResolver`. The included\n  `ObjectFieldResolver` reads direct properties from plain objects.\n- `RuleTree.toJSON()` and `RuleContext.fromJSON()` provide the supported\n  persistence round trip.\n\n## Built-in field types\n\n| Export             | Value type | Default control | Configured operator IDs                                                                          |\n| ------------------ | ---------- | --------------- | ------------------------------------------------------------------------------------------------ |\n| `StringFieldType`  | `string`   | text            | `=`, `!=`, `contains`, `starts_with`, `ends_with`                                                |\n| `NumberFieldType`  | `number`   | number          | `=`, `!=`, `greater_than`, `greater_than_or_equal`, `less_than`, `less_than_or_equal`, `between` |\n| `BooleanFieldType` | `boolean`  | boolean         | none                                                                                             |\n| `DateFieldType`    | `Date`     | date            | `=`, `!=`, `before`, `after`, `between`                                                          |\n\nA field can override its type's operator IDs:\n\n```ts\nconst status = new Field(\"status\", \"Status\", StringFieldType, {\n  operators: [\"=\", \"!=\"],\n});\n```\n\n## Built-in operators\n\nRule operators:\n\n- Equality: `EqualsOperator`, `NotEqualsOperator`\n- Strings: `ContainsOperator`, `StartsWithOperator`, `EndsWithOperator`\n- Numbers: `GreaterThanOperator`, `GreaterThanOrEqualOperator`,\n  `LessThanOperator`, `LessThanOrEqualOperator`\n- Numbers and dates: `BetweenOperator`\n- Dates: `BeforeOperator`, `AfterOperator`\n\nGroup operators: `AndOperator` and `OrOperator`.\n\nRegister every operator that a `RuleContext` should expose or deserialize:\n\n```ts\ncontext.ruleOperators.register(new EqualsOperator());\n```\n\nDuplicate IDs and lookups of unknown IDs throw an error.\n\n## Custom field resolution\n\nImplement `FieldResolver<T>` when values are nested, computed, or fetched from\nanother data model:\n\n```ts\nimport type { FieldResolver } from \"@campino/rule\";\n\ninterface Product {\n  attributes: Record<string, unknown>;\n}\n\nclass ProductFieldResolver implements FieldResolver<Product> {\n  resolve(product: Product, field: string): unknown {\n    return product.attributes[field];\n  }\n}\n```\n\n## Development\n\nInstall dependencies and run the release checks with Vite+:\n\n```bash\nvp install\nvp check\nvp test\nvp pack\n```\n\nSee [ROADMAP.md](ROADMAP.md) for planned API stabilization and release goals.\nThe persisted DTO format and compatibility policy are documented in\n[docs/serialization.md](docs/serialization.md).\nSupported customization APIs are documented in\n[docs/extensions.md](docs/extensions.md).\nRelease operations are documented in [docs/releasing.md](docs/releasing.md), and\nvulnerability reporting is covered by [SECURITY.md](SECURITY.md).\nPerformance baselines and budgets are documented in\n[docs/performance.md](docs/performance.md).\nPublic compatibility guarantees are documented in\n[docs/api-stability.md](docs/api-stability.md).\n","readmeFilename":"README.md","_rev":"1-baa1446ce6eaf909e9c6a8b8565cd73a"}