@inixiative/json-rules 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 inixiative
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,340 @@
1
+ # @inixiative/json-rules
2
+
3
+ [![npm version](https://badge.fury.io/js/@inixiative%2Fjson-rules.svg)](https://www.npmjs.com/package/@inixiative/json-rules)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ A powerful, type-safe JSON-based rules engine for TypeScript/JavaScript applications. Define complex validation and business logic rules using simple JSON structures.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm install @inixiative/json-rules
12
+ # or
13
+ yarn add @inixiative/json-rules
14
+ # or
15
+ bun add @inixiative/json-rules
16
+ ```
17
+
18
+ ## Features
19
+
20
+ - 🎯 **Type-safe**: Full TypeScript support with strict type checking
21
+ - 🔧 **Flexible**: 22 standard operators, 8 array operators, and 8 date operators
22
+ - 🌳 **Composable**: Nest rules with logical operators (all/any) and conditional logic (if-then-else)
23
+ - 📊 **Array validation**: Rich array validation with element-wise conditions
24
+ - 📅 **Date handling**: Comprehensive date comparison with timezone support
25
+ - 🔍 **Path-based access**: Reference values from anywhere in your data structure
26
+ - 💬 **Custom errors**: Every rule supports custom error messages
27
+
28
+ ## Installation
29
+
30
+ ```bash
31
+ npm install json-rules
32
+ # or
33
+ yarn add json-rules
34
+ # or
35
+ bun add json-rules
36
+ ```
37
+
38
+ ## Quick Start
39
+
40
+ ```typescript
41
+ import { check, Operator } from 'json-rules';
42
+
43
+ // Simple rule
44
+ const rule = {
45
+ field: 'age',
46
+ operator: Operator.greaterThanEqual,
47
+ value: 18,
48
+ error: 'Must be 18 or older'
49
+ };
50
+
51
+ const result = check(rule, { age: 21 }); // returns true
52
+ const result2 = check(rule, { age: 16 }); // returns "Must be 18 or older"
53
+ ```
54
+
55
+ ## Operators
56
+
57
+ ### Standard Operators (22)
58
+
59
+ #### Comparison
60
+ - `equal` - Exact equality check
61
+ - `notEqual` - Not equal check
62
+ - `lessThan` - Less than comparison
63
+ - `lessThanEqual` - Less than or equal
64
+ - `greaterThan` - Greater than comparison
65
+ - `greaterThanEqual` - Greater than or equal
66
+
67
+ #### Range
68
+ - `between` - Value within range (inclusive)
69
+ - `notBetween` - Value outside range
70
+
71
+ #### Membership
72
+ - `in` - Value in array
73
+ - `notIn` - Value not in array
74
+ - `contains` - Array/string contains value
75
+ - `notContains` - Array/string doesn't contain value
76
+
77
+ #### String
78
+ - `startsWith` - String starts with value
79
+ - `endsWith` - String ends with value
80
+
81
+ #### Pattern
82
+ - `match` - Regex pattern match
83
+ - `notMatch` - Regex pattern doesn't match
84
+
85
+ #### Existence
86
+ - `isEmpty` - Check if value is empty (null, undefined, "", [], {})
87
+ - `notEmpty` - Check if value is not empty
88
+ - `exists` - Field exists (not undefined)
89
+ - `notExists` - Field doesn't exist (undefined)
90
+
91
+ ### Array Operators (8)
92
+
93
+ - `all` - All elements match condition
94
+ - `any` - At least one element matches
95
+ - `none` - No elements match
96
+ - `atLeast` - At least X elements match
97
+ - `atMost` - At most X elements match
98
+ - `exactly` - Exactly X elements match
99
+ - `empty` - Array is empty
100
+ - `notEmpty` - Array has elements
101
+
102
+ ### Date Operators (8)
103
+
104
+ - `before` - Date is before comparison date
105
+ - `after` - Date is after comparison date
106
+ - `onOrBefore` - Date is on or before
107
+ - `onOrAfter` - Date is on or after
108
+ - `between` - Date is between two dates
109
+ - `notBetween` - Date is outside range
110
+ - `dayIn` - Day of week is in list
111
+ - `dayNotIn` - Day of week is not in list
112
+
113
+ #### Timezone Handling
114
+
115
+ Date comparisons are timezone-aware:
116
+
117
+ 1. **When condition value has no timezone** (e.g., `'2025-01-20'`), it's interpreted in the field's timezone:
118
+ ```typescript
119
+ // Field: Jan 20 10:00 AM Sydney time
120
+ { eventDate: '2025-01-20T10:00:00+11:00' }
121
+ // Condition: on or after Jan 20 (interpreted as Jan 20 in Sydney)
122
+ { dateOperator: 'onOrAfter', value: '2025-01-20' } // ✓ passes
123
+ ```
124
+
125
+ 2. **When condition value has timezone** (e.g., `'2025-01-20T00:00:00Z'`), it's used as-is:
126
+ ```typescript
127
+ // Condition: after midnight UTC specifically
128
+ { dateOperator: 'after', value: '2025-01-20T00:00:00Z' }
129
+ ```
130
+
131
+ 3. **Fields without timezone** are treated as local time (UTC offset 0)
132
+
133
+ ## Rule Types
134
+
135
+ ### Basic Rule
136
+
137
+ ```typescript
138
+ {
139
+ field: 'status',
140
+ operator: Operator.equal,
141
+ value: 'active'
142
+ }
143
+ ```
144
+
145
+ ### Logical Operators
146
+
147
+ ```typescript
148
+ // All conditions must pass (AND)
149
+ {
150
+ all: [
151
+ { field: 'age', operator: Operator.greaterThanEqual, value: 18 },
152
+ { field: 'hasLicense', operator: Operator.equal, value: true }
153
+ ]
154
+ }
155
+
156
+ // At least one must pass (OR)
157
+ {
158
+ any: [
159
+ { field: 'role', operator: Operator.equal, value: 'admin' },
160
+ { field: 'isOwner', operator: Operator.equal, value: true }
161
+ ]
162
+ }
163
+ ```
164
+
165
+ ### Conditional Logic (If-Then-Else)
166
+
167
+ ```typescript
168
+ {
169
+ if: { field: 'type', operator: Operator.equal, value: 'premium' },
170
+ then: { field: 'discount', operator: Operator.greaterThan, value: 0 },
171
+ else: { field: 'discount', operator: Operator.equal, value: 0 }
172
+ }
173
+ ```
174
+
175
+ ### Array Validation
176
+
177
+ ```typescript
178
+ {
179
+ field: 'orders',
180
+ arrayOperator: ArrayOperator.all,
181
+ condition: {
182
+ field: 'total',
183
+ operator: Operator.lessThan,
184
+ value: 1000
185
+ }
186
+ }
187
+ ```
188
+
189
+ ### Date Validation
190
+
191
+ ```typescript
192
+ {
193
+ field: 'expiryDate',
194
+ dateOperator: DateOperator.after,
195
+ value: '2024-12-31'
196
+ }
197
+ ```
198
+
199
+ ## Advanced Features
200
+
201
+ ### Path-Based Value Resolution
202
+
203
+ Compare fields against each other using paths:
204
+
205
+ ```typescript
206
+ {
207
+ field: 'confirmPassword',
208
+ operator: Operator.equal,
209
+ path: 'password' // Compare against another field
210
+ }
211
+ ```
212
+
213
+ ### Array Element Context
214
+
215
+ Use `$.` prefix to reference the current array element:
216
+
217
+ ```typescript
218
+ {
219
+ field: 'items',
220
+ arrayOperator: ArrayOperator.all,
221
+ condition: {
222
+ field: 'price',
223
+ operator: Operator.lessThan,
224
+ path: '$.maxPrice' // Reference field on current array element
225
+ }
226
+ }
227
+ ```
228
+
229
+ ### Custom Error Messages
230
+
231
+ Every rule supports custom error messages:
232
+
233
+ ```typescript
234
+ {
235
+ field: 'email',
236
+ operator: Operator.match,
237
+ value: /^[^@]+@[^@]+\.[^@]+$/,
238
+ error: 'Please enter a valid email address'
239
+ }
240
+ ```
241
+
242
+ ## Complex Example
243
+
244
+ ```typescript
245
+ const rule = {
246
+ all: [
247
+ // User must be active
248
+ { field: 'status', operator: Operator.equal, value: 'active' },
249
+
250
+ // Age requirement
251
+ { field: 'age', operator: Operator.between, value: [18, 65] },
252
+
253
+ // Must have at least one verified email
254
+ {
255
+ field: 'emails',
256
+ arrayOperator: ArrayOperator.any,
257
+ condition: { field: 'verified', operator: Operator.equal, value: true }
258
+ },
259
+
260
+ // Conditional premium features
261
+ {
262
+ if: { field: 'subscription', operator: Operator.equal, value: 'premium' },
263
+ then: {
264
+ field: 'features',
265
+ arrayOperator: ArrayOperator.all,
266
+ condition: { field: 'enabled', operator: Operator.equal, value: true }
267
+ }
268
+ }
269
+ ]
270
+ };
271
+
272
+ const userData = {
273
+ status: 'active',
274
+ age: 25,
275
+ emails: [
276
+ { address: 'user@example.com', verified: true },
277
+ { address: 'alt@example.com', verified: false }
278
+ ],
279
+ subscription: 'premium',
280
+ features: [
281
+ { name: 'advanced', enabled: true },
282
+ { name: 'analytics', enabled: true }
283
+ ]
284
+ };
285
+
286
+ const result = check(rule, userData); // returns true
287
+ ```
288
+
289
+ ## API Reference
290
+
291
+ ### `check(condition: Condition, data: any, context?: any): boolean | string`
292
+
293
+ The main validation function.
294
+
295
+ - **condition**: The rule to evaluate
296
+ - **data**: The data to validate against
297
+ - **context**: Optional context (defaults to data)
298
+ - **Returns**: `true` if validation passes, error string if it fails
299
+
300
+ ### Types
301
+
302
+ ```typescript
303
+ type Condition = Rule | ArrayRule | DateRule | All | Any | IfThenElse | boolean;
304
+
305
+ type Rule = {
306
+ field: string;
307
+ operator: Operator;
308
+ value?: any;
309
+ path?: string;
310
+ error?: string;
311
+ };
312
+
313
+ type ArrayRule = {
314
+ field: string;
315
+ arrayOperator: ArrayOperator;
316
+ condition?: Condition;
317
+ count?: number;
318
+ error?: string;
319
+ };
320
+
321
+ type DateRule = {
322
+ field: string;
323
+ dateOperator: DateOperator;
324
+ value?: any;
325
+ path?: string;
326
+ error?: string;
327
+ };
328
+ ```
329
+
330
+ ## Error Handling
331
+
332
+ The engine throws errors for:
333
+ - Invalid array fields when using array operators
334
+ - Missing required parameters (e.g., count for atLeast)
335
+ - Invalid dates in date comparisons
336
+ - Primitive arrays with array operators (use `contains` or `in` instead)
337
+
338
+ ## License
339
+
340
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ 'use strict';var lodash=require('lodash'),m=require('dayjs'),A=require('dayjs/plugin/utc'),B=require('dayjs/plugin/timezone'),D=require('dayjs/plugin/isSameOrBefore'),I=require('dayjs/plugin/isSameOrAfter');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var m__default=/*#__PURE__*/_interopDefault(m);var A__default=/*#__PURE__*/_interopDefault(A);var B__default=/*#__PURE__*/_interopDefault(B);var D__default=/*#__PURE__*/_interopDefault(D);var I__default=/*#__PURE__*/_interopDefault(I);var b=(f=>(f.equal="equal",f.notEqual="notEqual",f.lessThan="lessThan",f.lessThanEqual="lessThanEqual",f.greaterThan="greaterThan",f.greaterThanEqual="greaterThanEqual",f.contains="contains",f.notContains="notContains",f.in="in",f.notIn="notIn",f.match="match",f.notMatch="notMatch",f.between="between",f.notBetween="notBetween",f.isEmpty="isEmpty",f.notEmpty="notEmpty",f.exists="exists",f.notExists="notExists",f.startsWith="startsWith",f.endsWith="endsWith",f))(b||{}),E=(n=>(n.all="all",n.any="any",n.none="none",n.atLeast="atLeast",n.atMost="atMost",n.exactly="exactly",n.empty="empty",n.notEmpty="notEmpty",n))(E||{}),$=(n=>(n.before="before",n.after="after",n.onOrBefore="onOrBefore",n.onOrAfter="onOrAfter",n.between="between",n.notBetween="notBetween",n.dayIn="dayIn",n.dayNotIn="dayNotIn",n))($||{});m__default.default.extend(A__default.default);m__default.default.extend(B__default.default);m__default.default.extend(D__default.default);m__default.default.extend(I__default.default);var q=(e,o,u)=>{let a=lodash.get(o,e.field);if(!a)throw new Error(`${e.field} is null or undefined`);let r=m__default.default(a);if(!r.isValid())throw new Error(`${e.field} is not a valid date: ${a}`);let l=i=>e.error||`${e.field} ${i}`,s=j(e,o,u,r,a),t=s[0],n=s[1];switch(e.dateOperator){case "before":return r.isBefore(t)||l(`must be before ${t.format()}`);case "after":return r.isAfter(t)||l(`must be after ${t.format()}`);case "onOrBefore":return r.isSameOrBefore(t)||l(`must be on or before ${t.format()}`);case "onOrAfter":return r.isSameOrAfter(t)||l(`must be on or after ${t.format()}`);case "between":return r.isSameOrAfter(t)&&r.isSameOrBefore(n)||l(`must be between ${t.format()} and ${n.format()}`);case "notBetween":return r.isBefore(t)||r.isAfter(n)||l(`must not be between ${t.format()} and ${n.format()}`);case "dayIn":if(!Array.isArray(e.value))throw new Error("dayIn operator requires an array of day names");let i=r.format("dddd").toLowerCase(),h=e.value.map(c=>c.toLowerCase());return h.includes(i)||l(`must be on ${h.join(" or ")}`);case "dayNotIn":if(!Array.isArray(e.value))throw new Error("dayNotIn operator requires an array of day names");let x=r.format("dddd").toLowerCase(),g=e.value.map(c=>c.toLowerCase());return !g.includes(x)||l(`must not be on ${g.join(" or ")}`);default:throw new Error("Unknown date operator")}},j=(e,o,u,a,r)=>{if(["between","notBetween"].includes(e.dateOperator)){if(!Array.isArray(e.value)||e.value.length!==2)throw new Error(`${e.dateOperator} operator requires an array of two dates`);let t=p(e.value[0],r),n=p(e.value[1],r);if(!t.isValid())throw new Error(`Invalid start date: ${e.value[0]}`);if(!n.isValid())throw new Error(`Invalid end date: ${e.value[1]}`);return [t,n]}if(["before","after","onOrBefore","onOrAfter"].includes(e.dateOperator)){let t;if(e.value!==void 0)t=e.value;else if(e.path)e.path.startsWith("$.")?t=lodash.get(o,e.path.substring(2)):t=lodash.get(u,e.path);else throw new Error("No value or path specified for date comparison");let n=p(t,r);if(!n.isValid())throw new Error(`Invalid comparison date: ${t}`);return [n,void 0]}return [m__default.default(),void 0]},p=(e,o)=>{let u=String(e);if(u.includes("Z")||u.includes("T")&&(u.includes("+")||u.match(/T.*-\d{2}:/)))return m__default.default(e);let r=String(o),l=0;if(r.includes("+")||r.includes("T")&&r.match(/T.*-\d{2}:/)){let t=r.match(/([+-])(\d{2}):(\d{2})/);t&&(l=(t[1]==="+"?1:-1)*(parseInt(t[2])*60+parseInt(t[3])));}else r.includes("Z")||(l=0);return u.match(/^\d{4}-\d{2}-\d{2}$/)?m__default.default(e+"T00:00:00").subtract(l,"minute"):m__default.default(e).subtract(l,"minute")};var T=(e,o,u)=>{let a=lodash.get(o,e.field),l=!["isEmpty","notEmpty","exists","notExists"].includes(e.operator),s=l?C(e,o,u):void 0,t=n=>e.error||`${e.field} ${n}${l?" "+JSON.stringify(s):""}`;switch(e.operator){case "equal":return a===s||t("must equal");case "notEqual":return a!==s||t("must not equal");case "lessThan":return a<s||t("must be less than");case "lessThanEqual":return a<=s||t("must be less than or equal to");case "greaterThan":return a>s||t("must be greater than");case "greaterThanEqual":return a>=s||t("must be greater than or equal to");case "in":return s?.includes(a)||t("must be one of");case "notIn":return !s?.includes(a)||t("must not be one of");case "contains":return a?.includes(s)||t("must contain");case "notContains":return !a?.includes(s)||t("must not contain");case "match":return !!a?.match(s)||t("must match pattern");case "notMatch":return !a?.match(s)||t("must not match pattern");case "between":if(!Array.isArray(s)||s.length!==2)throw new Error("between operator requires an array of two values");return a>=s[0]&&a<=s[1]||t("must be between");case "notBetween":if(!Array.isArray(s)||s.length!==2)throw new Error("notBetween operator requires an array of two values");return a<s[0]||a>s[1]||t("must not be between");case "isEmpty":return lodash.isEmpty(a)||t("must be empty");case "notEmpty":return !lodash.isEmpty(a)||t("must not be empty");case "exists":return a!==void 0||t("must exist");case "notExists":return a===void 0||t("must not exist");case "startsWith":return a?.startsWith?.(s)||t("must start with");case "endsWith":return a?.endsWith?.(s)||t("must end with");default:throw new Error("Unknown operator")}},C=(e,o,u)=>{if(e.value!==void 0)return e.value;if(e.path)return e.path.startsWith("$.")?lodash.get(o,e.path.substring(2)):lodash.get(u,e.path);throw new Error("No value or path specified")};var y=(e,o,u=o)=>typeof e=="boolean"?e:"all"in e?W(e.all,o,u,e.error):"any"in e?M(e.any,o,u,e.error):"arrayOperator"in e?N(e,o,u):"dateOperator"in e?q(e,o,u):"field"in e?T(e,o,u):"if"in e?L(e,o,u):false,W=(e,o,u,a)=>{let r=[];for(let l of e){let s=y(l,o,u);s!==true&&(typeof s=="string"?r.push(s):r.push("false"));}return r.length?a||(r.length===1?r[0]:`All conditions must pass: ${r.join(" AND ")}`):true},M=(e,o,u,a)=>{let r=[];for(let l of e){let s=y(l,o,u);if(typeof s!="string")return true;r.push(s);}return a||(r.length===1?r[0]:`At least one condition must pass: ${r.join(" OR ")}`)},L=(e,o,u)=>y(e.if,o,u)===true?y(e.then,o,u):e.else?y(e.else,o,u):true,N=(e,o,u)=>{let a=lodash.get(u,e.field);if(!Array.isArray(a))throw new Error(`${e.field} must be an array`);let r=i=>e.error||`${e.field} ${i}`,l=["all","any","none","atLeast","atMost","exactly"],s=["atLeast","atMost","exactly"];if(l.includes(e.arrayOperator)&&!e.condition)throw new Error(`${e.arrayOperator} requires a condition to check against array elements`);if(s.includes(e.arrayOperator)&&e.count===void 0)throw new Error(`${e.arrayOperator} requires a count`);let t=0,n=0;if(l.includes(e.arrayOperator)){if(!lodash.some(a,lodash.isObject))throw new Error(`${e.field} contains only primitive values. Use 'in' or 'contains' operators instead of array operators for primitive arrays`);let i=a.map(h=>y(e.condition,h,u));t=i.filter(h=>h===true).length,n=i.filter(h=>typeof h=="string").length;}switch(e.arrayOperator){case "empty":return !a.length||r("must be empty");case "notEmpty":return !!a.length||r("must not be empty");case "all":return t===a.length||r(`all elements must match (${n} failed)`);case "any":return !!t||r("at least one element must match");case "none":return !t||r(`no elements should match (${t} matched)`);case "atLeast":return t>=e.count||r(`at least ${e.count} elements must match (${t} matched)`);case "atMost":return t<=e.count||r(`at most ${e.count} elements must match (${t} matched)`);case "exactly":return t===e.count||r(`exactly ${e.count} elements must match (${t} matched)`);default:throw new Error("Unknown array operator")}};exports.ArrayOperator=E;exports.DateOperator=$;exports.Operator=b;exports.check=y;//# sourceMappingURL=index.cjs.map
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/operator.ts","../src/date.ts","../src/field.ts","../src/check.ts"],"names":["Operator","ArrayOperator","DateOperator","dayjs","utc","timezone","isSameOrBefore","isSameOrAfter","checkDate","condition","data","context","fieldValue","get","fieldDate","getError","op","dates","parseCompareDates","compareDate","endDate","dayName","allowedDays","d","day","excludedDays","startDate","parseDateWithTimezone","value","date","valueStr","fieldStr","offset","match","checkField","needsValue","getValue","isEmpty","check","conditions","all","any","checkArray","checkIfThenElse","error","errors","result","arrayValue","defaultMsg","requiresCondition","requiresCount","matches","failures","some","isObject","results","item","r"],"mappings":"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","file":"index.cjs","sourcesContent":["export enum Operator {\n equal = 'equal',\n notEqual = 'notEqual',\n lessThan = 'lessThan',\n lessThanEqual = 'lessThanEqual',\n greaterThan = 'greaterThan',\n greaterThanEqual = 'greaterThanEqual',\n contains = 'contains',\n notContains = 'notContains',\n in = 'in',\n notIn = 'notIn',\n match = 'match',\n notMatch = 'notMatch',\n between = 'between',\n notBetween = 'notBetween',\n isEmpty = 'isEmpty',\n notEmpty = 'notEmpty',\n exists = 'exists',\n notExists = 'notExists',\n startsWith = 'startsWith',\n endsWith = 'endsWith',\n}\n\nexport enum ArrayOperator {\n all = 'all',\n any = 'any',\n none = 'none',\n atLeast = 'atLeast',\n atMost = 'atMost',\n exactly = 'exactly',\n empty = 'empty',\n notEmpty = 'notEmpty',\n}\n\nexport enum DateOperator {\n before = 'before',\n after = 'after',\n onOrBefore = 'onOrBefore',\n onOrAfter = 'onOrAfter',\n between = 'between',\n notBetween = 'notBetween',\n dayIn = 'dayIn', // e.g., ['monday', 'tuesday', 'friday']\n dayNotIn = 'dayNotIn',\n}\n","import { get } from 'lodash';\nimport dayjs from 'dayjs';\nimport utc from 'dayjs/plugin/utc';\nimport timezone from 'dayjs/plugin/timezone';\nimport isSameOrBefore from 'dayjs/plugin/isSameOrBefore';\nimport isSameOrAfter from 'dayjs/plugin/isSameOrAfter';\nimport type { DateRule } from './types';\nimport { DateOperator } from './operator';\n\ndayjs.extend(utc);\ndayjs.extend(timezone);\ndayjs.extend(isSameOrBefore);\ndayjs.extend(isSameOrAfter);\n\nexport const checkDate = (condition: DateRule, data: any, context: any): boolean | string => {\n const fieldValue = get(data, condition.field);\n \n if (!fieldValue) throw new Error(`${condition.field} is null or undefined`);\n \n const fieldDate = dayjs(fieldValue);\n \n if (!fieldDate.isValid()) throw new Error(`${condition.field} is not a valid date: ${fieldValue}`);\n \n const getError = (op: string) => condition.error || `${condition.field} ${op}`;\n \n // Parse comparison dates with timezone context - pass the original string to preserve offset info\n const dates = parseCompareDates(condition, data, context, fieldDate, fieldValue);\n const compareDate = dates[0];\n const endDate = dates[1];\n \n switch (condition.dateOperator) {\n case DateOperator.before:\n return fieldDate.isBefore(compareDate) || getError(`must be before ${compareDate.format()}`);\n \n case DateOperator.after:\n return fieldDate.isAfter(compareDate) || getError(`must be after ${compareDate.format()}`);\n \n case DateOperator.onOrBefore:\n return fieldDate.isSameOrBefore(compareDate) || getError(`must be on or before ${compareDate.format()}`);\n \n case DateOperator.onOrAfter:\n return fieldDate.isSameOrAfter(compareDate) || getError(`must be on or after ${compareDate.format()}`);\n \n case DateOperator.between:\n return (fieldDate.isSameOrAfter(compareDate) && fieldDate.isSameOrBefore(endDate!)) || \n getError(`must be between ${compareDate.format()} and ${endDate!.format()}`);\n \n case DateOperator.notBetween:\n return (fieldDate.isBefore(compareDate) || fieldDate.isAfter(endDate!)) || \n getError(`must not be between ${compareDate.format()} and ${endDate!.format()}`);\n \n case DateOperator.dayIn:\n if (!Array.isArray(condition.value)) throw new Error('dayIn operator requires an array of day names');\n const dayName = fieldDate.format('dddd').toLowerCase();\n const allowedDays = condition.value.map(d => d.toLowerCase());\n return allowedDays.includes(dayName) || getError(`must be on ${allowedDays.join(' or ')}`);\n \n case DateOperator.dayNotIn:\n if (!Array.isArray(condition.value)) throw new Error('dayNotIn operator requires an array of day names');\n const day = fieldDate.format('dddd').toLowerCase();\n const excludedDays = condition.value.map(d => d.toLowerCase());\n return !excludedDays.includes(day) || getError(`must not be on ${excludedDays.join(' or ')}`);\n \n default:\n throw new Error('Unknown date operator');\n }\n}\n\nconst parseCompareDates = (condition: DateRule, data: any, context: any, fieldDate: dayjs.Dayjs, fieldValue: string): [dayjs.Dayjs, dayjs.Dayjs | undefined] => {\n const requiresTwoDates = [DateOperator.between, DateOperator.notBetween];\n \n if (requiresTwoDates.includes(condition.dateOperator)) {\n if (!Array.isArray(condition.value) || condition.value.length !== 2) \n throw new Error(`${condition.dateOperator} operator requires an array of two dates`);\n const startDate = parseDateWithTimezone(condition.value[0], fieldValue);\n const endDate = parseDateWithTimezone(condition.value[1], fieldValue);\n if (!startDate.isValid()) throw new Error(`Invalid start date: ${condition.value[0]}`);\n if (!endDate.isValid()) throw new Error(`Invalid end date: ${condition.value[1]}`);\n return [startDate, endDate];\n }\n \n const requiresOneDate = [\n DateOperator.before,\n DateOperator.after,\n DateOperator.onOrBefore,\n DateOperator.onOrAfter\n ];\n \n if (requiresOneDate.includes(condition.dateOperator)) {\n let value;\n if (condition.value !== undefined) {\n value = condition.value;\n } else if (condition.path) {\n // Support $.path for current element\n if (condition.path.startsWith('$.')) {\n value = get(data, condition.path.substring(2));\n } else {\n value = get(context, condition.path);\n }\n } else {\n throw new Error('No value or path specified for date comparison');\n }\n const date = parseDateWithTimezone(value, fieldValue);\n if (!date.isValid()) throw new Error(`Invalid comparison date: ${value}`);\n return [date, undefined];\n }\n \n return [dayjs(), undefined]; // Won't be used for dayIn/dayNotIn\n}\n\nconst parseDateWithTimezone = (value: any, fieldValue: string): dayjs.Dayjs => {\n const valueStr = String(value);\n \n // Check if value has explicit timezone information\n const hasTimezone = valueStr.includes('Z') || \n (valueStr.includes('T') && (valueStr.includes('+') || valueStr.match(/T.*-\\d{2}:/)));\n \n if (hasTimezone) return dayjs(value);\n \n // No timezone info in value - interpret in field's timezone\n // Extract offset from field value\n const fieldStr = String(fieldValue);\n let offset = 0;\n \n if (fieldStr.includes('+') || (fieldStr.includes('T') && fieldStr.match(/T.*-\\d{2}:/))) {\n // Field has explicit offset like +11:00 or -08:00\n const match = fieldStr.match(/([+-])(\\d{2}):(\\d{2})/);\n if (match) {\n const sign = match[1] === '+' ? 1 : -1;\n offset = sign * (parseInt(match[2]) * 60 + parseInt(match[3]));\n }\n } else if (!fieldStr.includes('Z')) {\n // Field has no timezone, assume local time (offset 0)\n offset = 0;\n }\n // If field has Z, it's UTC (offset 0)\n \n // Create a date representing the same local time as the field's timezone\n if (valueStr.match(/^\\d{4}-\\d{2}-\\d{2}$/)) {\n // For date-only, we want midnight in the field's timezone\n const localMidnight = dayjs(value + 'T00:00:00');\n return localMidnight.subtract(offset, 'minute');\n }\n \n // For datetime without timezone, interpret as local time in field's timezone\n const localTime = dayjs(value);\n return localTime.subtract(offset, 'minute');\n}","import { get, isEmpty } from 'lodash';\nimport type { Rule } from './types';\nimport { Operator } from './operator';\n\nexport const checkField = (condition: Rule, data: any, context: any): boolean | string => {\n // Use data for field access (current element) but context remains available for path references\n const fieldValue = get(data, condition.field);\n \n // Operators that don't need a value\n const noValueOps = [Operator.isEmpty, Operator.notEmpty, Operator.exists, Operator.notExists];\n const needsValue = !noValueOps.includes(condition.operator);\n const value = needsValue ? getValue(condition, data, context) : undefined;\n \n const getError = (op: string) => condition.error || `${condition.field} ${op}${needsValue ? ' ' + JSON.stringify(value) : ''}`;\n\n switch (condition.operator) {\n case Operator.equal:\n return fieldValue === value || getError(`must equal`);\n case Operator.notEqual:\n return fieldValue !== value || getError(`must not equal`);\n case Operator.lessThan:\n return fieldValue < value || getError(`must be less than`);\n case Operator.lessThanEqual:\n return fieldValue <= value || getError(`must be less than or equal to`);\n case Operator.greaterThan:\n return fieldValue > value || getError(`must be greater than`);\n case Operator.greaterThanEqual:\n return fieldValue >= value || getError(`must be greater than or equal to`);\n case Operator.in:\n return value?.includes(fieldValue) || getError(`must be one of`);\n case Operator.notIn:\n return !value?.includes(fieldValue) || getError(`must not be one of`);\n case Operator.contains:\n return fieldValue?.includes(value) || getError(`must contain`);\n case Operator.notContains:\n return !fieldValue?.includes(value) || getError(`must not contain`);\n case Operator.match:\n return !!fieldValue?.match(value) || getError(`must match pattern`);\n case Operator.notMatch:\n return !fieldValue?.match(value) || getError(`must not match pattern`);\n case Operator.between:\n if (!Array.isArray(value) || value.length !== 2) \n throw new Error('between operator requires an array of two values');\n return (fieldValue >= value[0] && fieldValue <= value[1]) || getError(`must be between`);\n case Operator.notBetween:\n if (!Array.isArray(value) || value.length !== 2) \n throw new Error('notBetween operator requires an array of two values');\n return (fieldValue < value[0] || fieldValue > value[1]) || getError(`must not be between`);\n case Operator.isEmpty:\n return isEmpty(fieldValue) || getError(`must be empty`);\n case Operator.notEmpty:\n return !isEmpty(fieldValue) || getError(`must not be empty`);\n case Operator.exists:\n return fieldValue !== undefined || getError(`must exist`);\n case Operator.notExists:\n return fieldValue === undefined || getError(`must not exist`);\n case Operator.startsWith:\n return fieldValue?.startsWith?.(value) || getError(`must start with`);\n case Operator.endsWith:\n return fieldValue?.endsWith?.(value) || getError(`must end with`);\n default:\n throw new Error('Unknown operator');\n }\n};\n\nconst getValue = (condition: Rule, data: any, context: any): any => {\n if (condition.value !== undefined) return condition.value;\n if (condition.path) {\n // Special case: if path starts with \"$.\" use data (current element)\n if (condition.path.startsWith('$.')) {\n return get(data, condition.path.substring(2));\n }\n // Otherwise use context (root data)\n return get(context, condition.path);\n }\n throw new Error('No value or path specified');\n};","import { get, some, isObject } from 'lodash';\nimport type { Condition, ArrayRule } from './types';\nimport { ArrayOperator } from './operator';\nimport { checkDate } from './date';\nimport { checkField } from './field';\n\nexport const check = (conditions: Condition, data: any, context: any = data): boolean | string => {\n if (typeof conditions === 'boolean') return conditions;\n if ('all' in conditions) return all(conditions.all, data, context, conditions.error);\n if ('any' in conditions) return any(conditions.any, data, context, conditions.error);\n if ('arrayOperator' in conditions) return checkArray(conditions, data, context);\n if ('dateOperator' in conditions) return checkDate(conditions, data, context);\n if ('field' in conditions) return checkField(conditions, data, context);\n if ('if' in conditions) return checkIfThenElse(conditions, data, context);\n\n return false;\n}\n\nconst all = (conditions: Condition[], data: any, context: any, error?: string): boolean | string => {\n const errors: string[] = [];\n \n for (const condition of conditions) {\n const result = check(condition, data, context);\n if (result !== true) {\n // Handle both string errors and false boolean results\n if (typeof result === 'string') {\n errors.push(result);\n } else {\n // For boolean false, include it in the error message\n errors.push('false');\n }\n }\n }\n\n if (!errors.length) return true;\n if (error) return error;\n if (errors.length === 1) return errors[0];\n return `All conditions must pass: ${errors.join(' AND ')}`;\n}\n\nconst any = (conditions: Condition[], data: any, context: any, error?: string): boolean | string => {\n const errors: string[] = [];\n\n for (const condition of conditions) {\n const result = check(condition, data, context);\n if (typeof result !== 'string') return true;\n errors.push(result);\n }\n\n if (error) return error;\n if (errors.length === 1) return errors[0];\n return `At least one condition must pass: ${errors.join(' OR ')}`;\n}\n\nconst checkIfThenElse = (condition: any, data: any, context: any): boolean | string => {\n const ifResult = check(condition.if, data, context);\n \n if (ifResult === true) return check(condition.then, data, context);\n return condition.else ? check(condition.else, data, context) : true;\n}\n\nconst checkArray = (condition: ArrayRule, data: any, context: any): boolean | string => {\n const arrayValue = get(context, condition.field);\n \n if (!Array.isArray(arrayValue)) throw new Error(`${condition.field} must be an array`);\n \n const getError = (defaultMsg: string) => condition.error || `${condition.field} ${defaultMsg}`;\n \n // Operators that require a condition\n const requiresCondition = [\n ArrayOperator.all, \n ArrayOperator.any, \n ArrayOperator.none,\n ArrayOperator.atLeast,\n ArrayOperator.atMost,\n ArrayOperator.exactly\n ];\n \n // Operators that require a count\n const requiresCount = [\n ArrayOperator.atLeast,\n ArrayOperator.atMost,\n ArrayOperator.exactly\n ];\n \n if (requiresCondition.includes(condition.arrayOperator) && !condition.condition) \n throw new Error(`${condition.arrayOperator} requires a condition to check against array elements`);\n \n if (requiresCount.includes(condition.arrayOperator) && condition.count === undefined) \n throw new Error(`${condition.arrayOperator} requires a count`);\n \n // For operators that check elements, compute matches\n let matches = 0;\n let failures = 0;\n \n if (requiresCondition.includes(condition.arrayOperator)) {\n // Check if array contains any objects\n if (!some(arrayValue, isObject)) \n throw new Error(`${condition.field} contains only primitive values. Use 'in' or 'contains' operators instead of array operators for primitive arrays`);\n \n // Pass item as data (for relative field access) but keep original context (for path access)\n const results = arrayValue.map(item => check(condition.condition!, item, context));\n matches = results.filter(r => r === true).length;\n failures = results.filter(r => typeof r === 'string').length;\n }\n \n switch (condition.arrayOperator) {\n case ArrayOperator.empty:\n return !arrayValue.length || getError('must be empty');\n \n case ArrayOperator.notEmpty:\n return !!arrayValue.length || getError('must not be empty');\n \n case ArrayOperator.all:\n return matches === arrayValue.length || getError(`all elements must match (${failures} failed)`);\n \n case ArrayOperator.any:\n return !!matches || getError('at least one element must match');\n \n case ArrayOperator.none:\n return !matches || getError(`no elements should match (${matches} matched)`);\n \n case ArrayOperator.atLeast:\n return matches >= condition.count! || getError(`at least ${condition.count} elements must match (${matches} matched)`);\n \n case ArrayOperator.atMost:\n return matches <= condition.count! || getError(`at most ${condition.count} elements must match (${matches} matched)`);\n \n case ArrayOperator.exactly:\n return matches === condition.count! || getError(`exactly ${condition.count} elements must match (${matches} matched)`);\n \n default:\n throw new Error('Unknown array operator');\n }\n}"]}
@@ -0,0 +1,83 @@
1
+ declare enum Operator {
2
+ equal = "equal",
3
+ notEqual = "notEqual",
4
+ lessThan = "lessThan",
5
+ lessThanEqual = "lessThanEqual",
6
+ greaterThan = "greaterThan",
7
+ greaterThanEqual = "greaterThanEqual",
8
+ contains = "contains",
9
+ notContains = "notContains",
10
+ in = "in",
11
+ notIn = "notIn",
12
+ match = "match",
13
+ notMatch = "notMatch",
14
+ between = "between",
15
+ notBetween = "notBetween",
16
+ isEmpty = "isEmpty",
17
+ notEmpty = "notEmpty",
18
+ exists = "exists",
19
+ notExists = "notExists",
20
+ startsWith = "startsWith",
21
+ endsWith = "endsWith"
22
+ }
23
+ declare enum ArrayOperator {
24
+ all = "all",
25
+ any = "any",
26
+ none = "none",
27
+ atLeast = "atLeast",
28
+ atMost = "atMost",
29
+ exactly = "exactly",
30
+ empty = "empty",
31
+ notEmpty = "notEmpty"
32
+ }
33
+ declare enum DateOperator {
34
+ before = "before",
35
+ after = "after",
36
+ onOrBefore = "onOrBefore",
37
+ onOrAfter = "onOrAfter",
38
+ between = "between",
39
+ notBetween = "notBetween",
40
+ dayIn = "dayIn",// e.g., ['monday', 'tuesday', 'friday']
41
+ dayNotIn = "dayNotIn"
42
+ }
43
+
44
+ type Rule = {
45
+ field: string;
46
+ operator: Operator;
47
+ value?: any;
48
+ path?: string;
49
+ error?: string;
50
+ };
51
+ type ArrayRule = {
52
+ field: string;
53
+ arrayOperator: ArrayOperator;
54
+ condition?: Condition;
55
+ count?: number;
56
+ error?: string;
57
+ };
58
+ type DateRule = {
59
+ field: string;
60
+ dateOperator: DateOperator;
61
+ value?: any;
62
+ path?: string;
63
+ error?: string;
64
+ };
65
+ type All = {
66
+ all: Condition[];
67
+ error?: string;
68
+ };
69
+ type Any = {
70
+ any: Condition[];
71
+ error?: string;
72
+ };
73
+ type IfThenElse = {
74
+ if: Condition;
75
+ then: Condition;
76
+ else?: Condition;
77
+ error?: string;
78
+ };
79
+ type Condition = Rule | ArrayRule | DateRule | All | Any | IfThenElse | boolean;
80
+
81
+ declare const check: (conditions: Condition, data: any, context?: any) => boolean | string;
82
+
83
+ export { type All, type Any, ArrayOperator, type ArrayRule, type Condition, DateOperator, type DateRule, type IfThenElse, Operator, type Rule, check };
@@ -0,0 +1,83 @@
1
+ declare enum Operator {
2
+ equal = "equal",
3
+ notEqual = "notEqual",
4
+ lessThan = "lessThan",
5
+ lessThanEqual = "lessThanEqual",
6
+ greaterThan = "greaterThan",
7
+ greaterThanEqual = "greaterThanEqual",
8
+ contains = "contains",
9
+ notContains = "notContains",
10
+ in = "in",
11
+ notIn = "notIn",
12
+ match = "match",
13
+ notMatch = "notMatch",
14
+ between = "between",
15
+ notBetween = "notBetween",
16
+ isEmpty = "isEmpty",
17
+ notEmpty = "notEmpty",
18
+ exists = "exists",
19
+ notExists = "notExists",
20
+ startsWith = "startsWith",
21
+ endsWith = "endsWith"
22
+ }
23
+ declare enum ArrayOperator {
24
+ all = "all",
25
+ any = "any",
26
+ none = "none",
27
+ atLeast = "atLeast",
28
+ atMost = "atMost",
29
+ exactly = "exactly",
30
+ empty = "empty",
31
+ notEmpty = "notEmpty"
32
+ }
33
+ declare enum DateOperator {
34
+ before = "before",
35
+ after = "after",
36
+ onOrBefore = "onOrBefore",
37
+ onOrAfter = "onOrAfter",
38
+ between = "between",
39
+ notBetween = "notBetween",
40
+ dayIn = "dayIn",// e.g., ['monday', 'tuesday', 'friday']
41
+ dayNotIn = "dayNotIn"
42
+ }
43
+
44
+ type Rule = {
45
+ field: string;
46
+ operator: Operator;
47
+ value?: any;
48
+ path?: string;
49
+ error?: string;
50
+ };
51
+ type ArrayRule = {
52
+ field: string;
53
+ arrayOperator: ArrayOperator;
54
+ condition?: Condition;
55
+ count?: number;
56
+ error?: string;
57
+ };
58
+ type DateRule = {
59
+ field: string;
60
+ dateOperator: DateOperator;
61
+ value?: any;
62
+ path?: string;
63
+ error?: string;
64
+ };
65
+ type All = {
66
+ all: Condition[];
67
+ error?: string;
68
+ };
69
+ type Any = {
70
+ any: Condition[];
71
+ error?: string;
72
+ };
73
+ type IfThenElse = {
74
+ if: Condition;
75
+ then: Condition;
76
+ else?: Condition;
77
+ error?: string;
78
+ };
79
+ type Condition = Rule | ArrayRule | DateRule | All | Any | IfThenElse | boolean;
80
+
81
+ declare const check: (conditions: Condition, data: any, context?: any) => boolean | string;
82
+
83
+ export { type All, type Any, ArrayOperator, type ArrayRule, type Condition, DateOperator, type DateRule, type IfThenElse, Operator, type Rule, check };
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import {get,isEmpty,some,isObject}from'lodash';import m from'dayjs';import A from'dayjs/plugin/utc';import B from'dayjs/plugin/timezone';import D from'dayjs/plugin/isSameOrBefore';import I from'dayjs/plugin/isSameOrAfter';var b=(f=>(f.equal="equal",f.notEqual="notEqual",f.lessThan="lessThan",f.lessThanEqual="lessThanEqual",f.greaterThan="greaterThan",f.greaterThanEqual="greaterThanEqual",f.contains="contains",f.notContains="notContains",f.in="in",f.notIn="notIn",f.match="match",f.notMatch="notMatch",f.between="between",f.notBetween="notBetween",f.isEmpty="isEmpty",f.notEmpty="notEmpty",f.exists="exists",f.notExists="notExists",f.startsWith="startsWith",f.endsWith="endsWith",f))(b||{}),E=(n=>(n.all="all",n.any="any",n.none="none",n.atLeast="atLeast",n.atMost="atMost",n.exactly="exactly",n.empty="empty",n.notEmpty="notEmpty",n))(E||{}),$=(n=>(n.before="before",n.after="after",n.onOrBefore="onOrBefore",n.onOrAfter="onOrAfter",n.between="between",n.notBetween="notBetween",n.dayIn="dayIn",n.dayNotIn="dayNotIn",n))($||{});m.extend(A);m.extend(B);m.extend(D);m.extend(I);var q=(e,o,u)=>{let a=get(o,e.field);if(!a)throw new Error(`${e.field} is null or undefined`);let r=m(a);if(!r.isValid())throw new Error(`${e.field} is not a valid date: ${a}`);let l=i=>e.error||`${e.field} ${i}`,s=j(e,o,u,r,a),t=s[0],n=s[1];switch(e.dateOperator){case "before":return r.isBefore(t)||l(`must be before ${t.format()}`);case "after":return r.isAfter(t)||l(`must be after ${t.format()}`);case "onOrBefore":return r.isSameOrBefore(t)||l(`must be on or before ${t.format()}`);case "onOrAfter":return r.isSameOrAfter(t)||l(`must be on or after ${t.format()}`);case "between":return r.isSameOrAfter(t)&&r.isSameOrBefore(n)||l(`must be between ${t.format()} and ${n.format()}`);case "notBetween":return r.isBefore(t)||r.isAfter(n)||l(`must not be between ${t.format()} and ${n.format()}`);case "dayIn":if(!Array.isArray(e.value))throw new Error("dayIn operator requires an array of day names");let i=r.format("dddd").toLowerCase(),h=e.value.map(c=>c.toLowerCase());return h.includes(i)||l(`must be on ${h.join(" or ")}`);case "dayNotIn":if(!Array.isArray(e.value))throw new Error("dayNotIn operator requires an array of day names");let x=r.format("dddd").toLowerCase(),g=e.value.map(c=>c.toLowerCase());return !g.includes(x)||l(`must not be on ${g.join(" or ")}`);default:throw new Error("Unknown date operator")}},j=(e,o,u,a,r)=>{if(["between","notBetween"].includes(e.dateOperator)){if(!Array.isArray(e.value)||e.value.length!==2)throw new Error(`${e.dateOperator} operator requires an array of two dates`);let t=p(e.value[0],r),n=p(e.value[1],r);if(!t.isValid())throw new Error(`Invalid start date: ${e.value[0]}`);if(!n.isValid())throw new Error(`Invalid end date: ${e.value[1]}`);return [t,n]}if(["before","after","onOrBefore","onOrAfter"].includes(e.dateOperator)){let t;if(e.value!==void 0)t=e.value;else if(e.path)e.path.startsWith("$.")?t=get(o,e.path.substring(2)):t=get(u,e.path);else throw new Error("No value or path specified for date comparison");let n=p(t,r);if(!n.isValid())throw new Error(`Invalid comparison date: ${t}`);return [n,void 0]}return [m(),void 0]},p=(e,o)=>{let u=String(e);if(u.includes("Z")||u.includes("T")&&(u.includes("+")||u.match(/T.*-\d{2}:/)))return m(e);let r=String(o),l=0;if(r.includes("+")||r.includes("T")&&r.match(/T.*-\d{2}:/)){let t=r.match(/([+-])(\d{2}):(\d{2})/);t&&(l=(t[1]==="+"?1:-1)*(parseInt(t[2])*60+parseInt(t[3])));}else r.includes("Z")||(l=0);return u.match(/^\d{4}-\d{2}-\d{2}$/)?m(e+"T00:00:00").subtract(l,"minute"):m(e).subtract(l,"minute")};var T=(e,o,u)=>{let a=get(o,e.field),l=!["isEmpty","notEmpty","exists","notExists"].includes(e.operator),s=l?C(e,o,u):void 0,t=n=>e.error||`${e.field} ${n}${l?" "+JSON.stringify(s):""}`;switch(e.operator){case "equal":return a===s||t("must equal");case "notEqual":return a!==s||t("must not equal");case "lessThan":return a<s||t("must be less than");case "lessThanEqual":return a<=s||t("must be less than or equal to");case "greaterThan":return a>s||t("must be greater than");case "greaterThanEqual":return a>=s||t("must be greater than or equal to");case "in":return s?.includes(a)||t("must be one of");case "notIn":return !s?.includes(a)||t("must not be one of");case "contains":return a?.includes(s)||t("must contain");case "notContains":return !a?.includes(s)||t("must not contain");case "match":return !!a?.match(s)||t("must match pattern");case "notMatch":return !a?.match(s)||t("must not match pattern");case "between":if(!Array.isArray(s)||s.length!==2)throw new Error("between operator requires an array of two values");return a>=s[0]&&a<=s[1]||t("must be between");case "notBetween":if(!Array.isArray(s)||s.length!==2)throw new Error("notBetween operator requires an array of two values");return a<s[0]||a>s[1]||t("must not be between");case "isEmpty":return isEmpty(a)||t("must be empty");case "notEmpty":return !isEmpty(a)||t("must not be empty");case "exists":return a!==void 0||t("must exist");case "notExists":return a===void 0||t("must not exist");case "startsWith":return a?.startsWith?.(s)||t("must start with");case "endsWith":return a?.endsWith?.(s)||t("must end with");default:throw new Error("Unknown operator")}},C=(e,o,u)=>{if(e.value!==void 0)return e.value;if(e.path)return e.path.startsWith("$.")?get(o,e.path.substring(2)):get(u,e.path);throw new Error("No value or path specified")};var y=(e,o,u=o)=>typeof e=="boolean"?e:"all"in e?W(e.all,o,u,e.error):"any"in e?M(e.any,o,u,e.error):"arrayOperator"in e?N(e,o,u):"dateOperator"in e?q(e,o,u):"field"in e?T(e,o,u):"if"in e?L(e,o,u):false,W=(e,o,u,a)=>{let r=[];for(let l of e){let s=y(l,o,u);s!==true&&(typeof s=="string"?r.push(s):r.push("false"));}return r.length?a||(r.length===1?r[0]:`All conditions must pass: ${r.join(" AND ")}`):true},M=(e,o,u,a)=>{let r=[];for(let l of e){let s=y(l,o,u);if(typeof s!="string")return true;r.push(s);}return a||(r.length===1?r[0]:`At least one condition must pass: ${r.join(" OR ")}`)},L=(e,o,u)=>y(e.if,o,u)===true?y(e.then,o,u):e.else?y(e.else,o,u):true,N=(e,o,u)=>{let a=get(u,e.field);if(!Array.isArray(a))throw new Error(`${e.field} must be an array`);let r=i=>e.error||`${e.field} ${i}`,l=["all","any","none","atLeast","atMost","exactly"],s=["atLeast","atMost","exactly"];if(l.includes(e.arrayOperator)&&!e.condition)throw new Error(`${e.arrayOperator} requires a condition to check against array elements`);if(s.includes(e.arrayOperator)&&e.count===void 0)throw new Error(`${e.arrayOperator} requires a count`);let t=0,n=0;if(l.includes(e.arrayOperator)){if(!some(a,isObject))throw new Error(`${e.field} contains only primitive values. Use 'in' or 'contains' operators instead of array operators for primitive arrays`);let i=a.map(h=>y(e.condition,h,u));t=i.filter(h=>h===true).length,n=i.filter(h=>typeof h=="string").length;}switch(e.arrayOperator){case "empty":return !a.length||r("must be empty");case "notEmpty":return !!a.length||r("must not be empty");case "all":return t===a.length||r(`all elements must match (${n} failed)`);case "any":return !!t||r("at least one element must match");case "none":return !t||r(`no elements should match (${t} matched)`);case "atLeast":return t>=e.count||r(`at least ${e.count} elements must match (${t} matched)`);case "atMost":return t<=e.count||r(`at most ${e.count} elements must match (${t} matched)`);case "exactly":return t===e.count||r(`exactly ${e.count} elements must match (${t} matched)`);default:throw new Error("Unknown array operator")}};export{E as ArrayOperator,$ as DateOperator,b as Operator,y as check};//# sourceMappingURL=index.js.map
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/operator.ts","../src/date.ts","../src/field.ts","../src/check.ts"],"names":["Operator","ArrayOperator","DateOperator","dayjs","utc","timezone","isSameOrBefore","isSameOrAfter","checkDate","condition","data","context","fieldValue","get","fieldDate","getError","op","dates","parseCompareDates","compareDate","endDate","dayName","allowedDays","d","day","excludedDays","startDate","parseDateWithTimezone","value","date","valueStr","fieldStr","offset","match","checkField","needsValue","getValue","isEmpty","check","conditions","all","any","checkArray","checkIfThenElse","error","errors","result","arrayValue","defaultMsg","requiresCondition","requiresCount","matches","failures","some","isObject","results","item","r"],"mappings":"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","file":"index.js","sourcesContent":["export enum Operator {\n equal = 'equal',\n notEqual = 'notEqual',\n lessThan = 'lessThan',\n lessThanEqual = 'lessThanEqual',\n greaterThan = 'greaterThan',\n greaterThanEqual = 'greaterThanEqual',\n contains = 'contains',\n notContains = 'notContains',\n in = 'in',\n notIn = 'notIn',\n match = 'match',\n notMatch = 'notMatch',\n between = 'between',\n notBetween = 'notBetween',\n isEmpty = 'isEmpty',\n notEmpty = 'notEmpty',\n exists = 'exists',\n notExists = 'notExists',\n startsWith = 'startsWith',\n endsWith = 'endsWith',\n}\n\nexport enum ArrayOperator {\n all = 'all',\n any = 'any',\n none = 'none',\n atLeast = 'atLeast',\n atMost = 'atMost',\n exactly = 'exactly',\n empty = 'empty',\n notEmpty = 'notEmpty',\n}\n\nexport enum DateOperator {\n before = 'before',\n after = 'after',\n onOrBefore = 'onOrBefore',\n onOrAfter = 'onOrAfter',\n between = 'between',\n notBetween = 'notBetween',\n dayIn = 'dayIn', // e.g., ['monday', 'tuesday', 'friday']\n dayNotIn = 'dayNotIn',\n}\n","import { get } from 'lodash';\nimport dayjs from 'dayjs';\nimport utc from 'dayjs/plugin/utc';\nimport timezone from 'dayjs/plugin/timezone';\nimport isSameOrBefore from 'dayjs/plugin/isSameOrBefore';\nimport isSameOrAfter from 'dayjs/plugin/isSameOrAfter';\nimport type { DateRule } from './types';\nimport { DateOperator } from './operator';\n\ndayjs.extend(utc);\ndayjs.extend(timezone);\ndayjs.extend(isSameOrBefore);\ndayjs.extend(isSameOrAfter);\n\nexport const checkDate = (condition: DateRule, data: any, context: any): boolean | string => {\n const fieldValue = get(data, condition.field);\n \n if (!fieldValue) throw new Error(`${condition.field} is null or undefined`);\n \n const fieldDate = dayjs(fieldValue);\n \n if (!fieldDate.isValid()) throw new Error(`${condition.field} is not a valid date: ${fieldValue}`);\n \n const getError = (op: string) => condition.error || `${condition.field} ${op}`;\n \n // Parse comparison dates with timezone context - pass the original string to preserve offset info\n const dates = parseCompareDates(condition, data, context, fieldDate, fieldValue);\n const compareDate = dates[0];\n const endDate = dates[1];\n \n switch (condition.dateOperator) {\n case DateOperator.before:\n return fieldDate.isBefore(compareDate) || getError(`must be before ${compareDate.format()}`);\n \n case DateOperator.after:\n return fieldDate.isAfter(compareDate) || getError(`must be after ${compareDate.format()}`);\n \n case DateOperator.onOrBefore:\n return fieldDate.isSameOrBefore(compareDate) || getError(`must be on or before ${compareDate.format()}`);\n \n case DateOperator.onOrAfter:\n return fieldDate.isSameOrAfter(compareDate) || getError(`must be on or after ${compareDate.format()}`);\n \n case DateOperator.between:\n return (fieldDate.isSameOrAfter(compareDate) && fieldDate.isSameOrBefore(endDate!)) || \n getError(`must be between ${compareDate.format()} and ${endDate!.format()}`);\n \n case DateOperator.notBetween:\n return (fieldDate.isBefore(compareDate) || fieldDate.isAfter(endDate!)) || \n getError(`must not be between ${compareDate.format()} and ${endDate!.format()}`);\n \n case DateOperator.dayIn:\n if (!Array.isArray(condition.value)) throw new Error('dayIn operator requires an array of day names');\n const dayName = fieldDate.format('dddd').toLowerCase();\n const allowedDays = condition.value.map(d => d.toLowerCase());\n return allowedDays.includes(dayName) || getError(`must be on ${allowedDays.join(' or ')}`);\n \n case DateOperator.dayNotIn:\n if (!Array.isArray(condition.value)) throw new Error('dayNotIn operator requires an array of day names');\n const day = fieldDate.format('dddd').toLowerCase();\n const excludedDays = condition.value.map(d => d.toLowerCase());\n return !excludedDays.includes(day) || getError(`must not be on ${excludedDays.join(' or ')}`);\n \n default:\n throw new Error('Unknown date operator');\n }\n}\n\nconst parseCompareDates = (condition: DateRule, data: any, context: any, fieldDate: dayjs.Dayjs, fieldValue: string): [dayjs.Dayjs, dayjs.Dayjs | undefined] => {\n const requiresTwoDates = [DateOperator.between, DateOperator.notBetween];\n \n if (requiresTwoDates.includes(condition.dateOperator)) {\n if (!Array.isArray(condition.value) || condition.value.length !== 2) \n throw new Error(`${condition.dateOperator} operator requires an array of two dates`);\n const startDate = parseDateWithTimezone(condition.value[0], fieldValue);\n const endDate = parseDateWithTimezone(condition.value[1], fieldValue);\n if (!startDate.isValid()) throw new Error(`Invalid start date: ${condition.value[0]}`);\n if (!endDate.isValid()) throw new Error(`Invalid end date: ${condition.value[1]}`);\n return [startDate, endDate];\n }\n \n const requiresOneDate = [\n DateOperator.before,\n DateOperator.after,\n DateOperator.onOrBefore,\n DateOperator.onOrAfter\n ];\n \n if (requiresOneDate.includes(condition.dateOperator)) {\n let value;\n if (condition.value !== undefined) {\n value = condition.value;\n } else if (condition.path) {\n // Support $.path for current element\n if (condition.path.startsWith('$.')) {\n value = get(data, condition.path.substring(2));\n } else {\n value = get(context, condition.path);\n }\n } else {\n throw new Error('No value or path specified for date comparison');\n }\n const date = parseDateWithTimezone(value, fieldValue);\n if (!date.isValid()) throw new Error(`Invalid comparison date: ${value}`);\n return [date, undefined];\n }\n \n return [dayjs(), undefined]; // Won't be used for dayIn/dayNotIn\n}\n\nconst parseDateWithTimezone = (value: any, fieldValue: string): dayjs.Dayjs => {\n const valueStr = String(value);\n \n // Check if value has explicit timezone information\n const hasTimezone = valueStr.includes('Z') || \n (valueStr.includes('T') && (valueStr.includes('+') || valueStr.match(/T.*-\\d{2}:/)));\n \n if (hasTimezone) return dayjs(value);\n \n // No timezone info in value - interpret in field's timezone\n // Extract offset from field value\n const fieldStr = String(fieldValue);\n let offset = 0;\n \n if (fieldStr.includes('+') || (fieldStr.includes('T') && fieldStr.match(/T.*-\\d{2}:/))) {\n // Field has explicit offset like +11:00 or -08:00\n const match = fieldStr.match(/([+-])(\\d{2}):(\\d{2})/);\n if (match) {\n const sign = match[1] === '+' ? 1 : -1;\n offset = sign * (parseInt(match[2]) * 60 + parseInt(match[3]));\n }\n } else if (!fieldStr.includes('Z')) {\n // Field has no timezone, assume local time (offset 0)\n offset = 0;\n }\n // If field has Z, it's UTC (offset 0)\n \n // Create a date representing the same local time as the field's timezone\n if (valueStr.match(/^\\d{4}-\\d{2}-\\d{2}$/)) {\n // For date-only, we want midnight in the field's timezone\n const localMidnight = dayjs(value + 'T00:00:00');\n return localMidnight.subtract(offset, 'minute');\n }\n \n // For datetime without timezone, interpret as local time in field's timezone\n const localTime = dayjs(value);\n return localTime.subtract(offset, 'minute');\n}","import { get, isEmpty } from 'lodash';\nimport type { Rule } from './types';\nimport { Operator } from './operator';\n\nexport const checkField = (condition: Rule, data: any, context: any): boolean | string => {\n // Use data for field access (current element) but context remains available for path references\n const fieldValue = get(data, condition.field);\n \n // Operators that don't need a value\n const noValueOps = [Operator.isEmpty, Operator.notEmpty, Operator.exists, Operator.notExists];\n const needsValue = !noValueOps.includes(condition.operator);\n const value = needsValue ? getValue(condition, data, context) : undefined;\n \n const getError = (op: string) => condition.error || `${condition.field} ${op}${needsValue ? ' ' + JSON.stringify(value) : ''}`;\n\n switch (condition.operator) {\n case Operator.equal:\n return fieldValue === value || getError(`must equal`);\n case Operator.notEqual:\n return fieldValue !== value || getError(`must not equal`);\n case Operator.lessThan:\n return fieldValue < value || getError(`must be less than`);\n case Operator.lessThanEqual:\n return fieldValue <= value || getError(`must be less than or equal to`);\n case Operator.greaterThan:\n return fieldValue > value || getError(`must be greater than`);\n case Operator.greaterThanEqual:\n return fieldValue >= value || getError(`must be greater than or equal to`);\n case Operator.in:\n return value?.includes(fieldValue) || getError(`must be one of`);\n case Operator.notIn:\n return !value?.includes(fieldValue) || getError(`must not be one of`);\n case Operator.contains:\n return fieldValue?.includes(value) || getError(`must contain`);\n case Operator.notContains:\n return !fieldValue?.includes(value) || getError(`must not contain`);\n case Operator.match:\n return !!fieldValue?.match(value) || getError(`must match pattern`);\n case Operator.notMatch:\n return !fieldValue?.match(value) || getError(`must not match pattern`);\n case Operator.between:\n if (!Array.isArray(value) || value.length !== 2) \n throw new Error('between operator requires an array of two values');\n return (fieldValue >= value[0] && fieldValue <= value[1]) || getError(`must be between`);\n case Operator.notBetween:\n if (!Array.isArray(value) || value.length !== 2) \n throw new Error('notBetween operator requires an array of two values');\n return (fieldValue < value[0] || fieldValue > value[1]) || getError(`must not be between`);\n case Operator.isEmpty:\n return isEmpty(fieldValue) || getError(`must be empty`);\n case Operator.notEmpty:\n return !isEmpty(fieldValue) || getError(`must not be empty`);\n case Operator.exists:\n return fieldValue !== undefined || getError(`must exist`);\n case Operator.notExists:\n return fieldValue === undefined || getError(`must not exist`);\n case Operator.startsWith:\n return fieldValue?.startsWith?.(value) || getError(`must start with`);\n case Operator.endsWith:\n return fieldValue?.endsWith?.(value) || getError(`must end with`);\n default:\n throw new Error('Unknown operator');\n }\n};\n\nconst getValue = (condition: Rule, data: any, context: any): any => {\n if (condition.value !== undefined) return condition.value;\n if (condition.path) {\n // Special case: if path starts with \"$.\" use data (current element)\n if (condition.path.startsWith('$.')) {\n return get(data, condition.path.substring(2));\n }\n // Otherwise use context (root data)\n return get(context, condition.path);\n }\n throw new Error('No value or path specified');\n};","import { get, some, isObject } from 'lodash';\nimport type { Condition, ArrayRule } from './types';\nimport { ArrayOperator } from './operator';\nimport { checkDate } from './date';\nimport { checkField } from './field';\n\nexport const check = (conditions: Condition, data: any, context: any = data): boolean | string => {\n if (typeof conditions === 'boolean') return conditions;\n if ('all' in conditions) return all(conditions.all, data, context, conditions.error);\n if ('any' in conditions) return any(conditions.any, data, context, conditions.error);\n if ('arrayOperator' in conditions) return checkArray(conditions, data, context);\n if ('dateOperator' in conditions) return checkDate(conditions, data, context);\n if ('field' in conditions) return checkField(conditions, data, context);\n if ('if' in conditions) return checkIfThenElse(conditions, data, context);\n\n return false;\n}\n\nconst all = (conditions: Condition[], data: any, context: any, error?: string): boolean | string => {\n const errors: string[] = [];\n \n for (const condition of conditions) {\n const result = check(condition, data, context);\n if (result !== true) {\n // Handle both string errors and false boolean results\n if (typeof result === 'string') {\n errors.push(result);\n } else {\n // For boolean false, include it in the error message\n errors.push('false');\n }\n }\n }\n\n if (!errors.length) return true;\n if (error) return error;\n if (errors.length === 1) return errors[0];\n return `All conditions must pass: ${errors.join(' AND ')}`;\n}\n\nconst any = (conditions: Condition[], data: any, context: any, error?: string): boolean | string => {\n const errors: string[] = [];\n\n for (const condition of conditions) {\n const result = check(condition, data, context);\n if (typeof result !== 'string') return true;\n errors.push(result);\n }\n\n if (error) return error;\n if (errors.length === 1) return errors[0];\n return `At least one condition must pass: ${errors.join(' OR ')}`;\n}\n\nconst checkIfThenElse = (condition: any, data: any, context: any): boolean | string => {\n const ifResult = check(condition.if, data, context);\n \n if (ifResult === true) return check(condition.then, data, context);\n return condition.else ? check(condition.else, data, context) : true;\n}\n\nconst checkArray = (condition: ArrayRule, data: any, context: any): boolean | string => {\n const arrayValue = get(context, condition.field);\n \n if (!Array.isArray(arrayValue)) throw new Error(`${condition.field} must be an array`);\n \n const getError = (defaultMsg: string) => condition.error || `${condition.field} ${defaultMsg}`;\n \n // Operators that require a condition\n const requiresCondition = [\n ArrayOperator.all, \n ArrayOperator.any, \n ArrayOperator.none,\n ArrayOperator.atLeast,\n ArrayOperator.atMost,\n ArrayOperator.exactly\n ];\n \n // Operators that require a count\n const requiresCount = [\n ArrayOperator.atLeast,\n ArrayOperator.atMost,\n ArrayOperator.exactly\n ];\n \n if (requiresCondition.includes(condition.arrayOperator) && !condition.condition) \n throw new Error(`${condition.arrayOperator} requires a condition to check against array elements`);\n \n if (requiresCount.includes(condition.arrayOperator) && condition.count === undefined) \n throw new Error(`${condition.arrayOperator} requires a count`);\n \n // For operators that check elements, compute matches\n let matches = 0;\n let failures = 0;\n \n if (requiresCondition.includes(condition.arrayOperator)) {\n // Check if array contains any objects\n if (!some(arrayValue, isObject)) \n throw new Error(`${condition.field} contains only primitive values. Use 'in' or 'contains' operators instead of array operators for primitive arrays`);\n \n // Pass item as data (for relative field access) but keep original context (for path access)\n const results = arrayValue.map(item => check(condition.condition!, item, context));\n matches = results.filter(r => r === true).length;\n failures = results.filter(r => typeof r === 'string').length;\n }\n \n switch (condition.arrayOperator) {\n case ArrayOperator.empty:\n return !arrayValue.length || getError('must be empty');\n \n case ArrayOperator.notEmpty:\n return !!arrayValue.length || getError('must not be empty');\n \n case ArrayOperator.all:\n return matches === arrayValue.length || getError(`all elements must match (${failures} failed)`);\n \n case ArrayOperator.any:\n return !!matches || getError('at least one element must match');\n \n case ArrayOperator.none:\n return !matches || getError(`no elements should match (${matches} matched)`);\n \n case ArrayOperator.atLeast:\n return matches >= condition.count! || getError(`at least ${condition.count} elements must match (${matches} matched)`);\n \n case ArrayOperator.atMost:\n return matches <= condition.count! || getError(`at most ${condition.count} elements must match (${matches} matched)`);\n \n case ArrayOperator.exactly:\n return matches === condition.count! || getError(`exactly ${condition.count} elements must match (${matches} matched)`);\n \n default:\n throw new Error('Unknown array operator');\n }\n}"]}
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@inixiative/json-rules",
3
+ "version": "1.0.0",
4
+ "description": "TypeScript-first JSON rules engine with intuitive syntax and detailed error messages",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "type": "module",
9
+ "files": [
10
+ "dist",
11
+ "README.md",
12
+ "LICENSE"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsup",
16
+ "test": "bun test",
17
+ "prepublishOnly": "bun run build"
18
+ },
19
+ "keywords": [
20
+ "json",
21
+ "rules",
22
+ "engine",
23
+ "validation",
24
+ "typescript",
25
+ "rules-engine",
26
+ "business-rules"
27
+ ],
28
+ "author": "Aron Greenspan",
29
+ "license": "MIT",
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "https://github.com/inixiative/json-rules"
33
+ },
34
+ "devDependencies": {
35
+ "@types/bun": "latest",
36
+ "@types/lodash": "^4.17.20",
37
+ "tsup": "^8.5.0",
38
+ "typescript": "^5.0.0"
39
+ },
40
+ "peerDependencies": {
41
+ "typescript": "^5.0.0"
42
+ },
43
+ "peerDependenciesMeta": {
44
+ "typescript": {
45
+ "optional": true
46
+ }
47
+ },
48
+ "dependencies": {
49
+ "dayjs": "^1.11.13",
50
+ "lodash": "^4.17.21"
51
+ },
52
+ "exports": {
53
+ ".": {
54
+ "types": "./dist/index.d.ts",
55
+ "import": "./dist/index.mjs",
56
+ "require": "./dist/index.js"
57
+ }
58
+ }
59
+ }