@stackone/expressions 0.26.0 → 0.28.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/README.md CHANGED
@@ -764,6 +764,57 @@ Extracts a query parameter value from a URL string. Useful for parsing paginatio
764
764
  "{{urlParam(nextUrl, 'page') != null ? urlParam(nextUrl, 'page') : null}}";
765
765
  ```
766
766
 
767
+ ##### Crypto Functions
768
+
769
+ ###### sha256(value, encoding?)
770
+
771
+ Computes the SHA-256 hash of a string value.
772
+
773
+ - `value` (string): The string to hash
774
+ - `encoding` (string, optional): Output encoding — `'hex'` (default) or `'base64'`
775
+ - Returns: hashed string, or empty string for invalid input
776
+
777
+ ```js
778
+ "{{sha256('hello')}}" // Returns "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
779
+ "{{sha256('hello', 'base64')}}" // Returns "LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ="
780
+
781
+ // Hash from context variable
782
+ "{{sha256($.body)}}"
783
+ ```
784
+
785
+ ###### hmacSha256(value, key, encoding?)
786
+
787
+ Computes an HMAC-SHA256 of a value using a secret key. Useful for webhook signature verification and API request signing.
788
+
789
+ - `value` (string): The string to sign
790
+ - `key` (string): The secret key
791
+ - `encoding` (string, optional): Output encoding — `'hex'` (default) or `'base64'`
792
+ - Returns: HMAC digest, or empty string for invalid input
793
+
794
+ ```js
795
+ "{{hmacSha256('hello', 'secret')}}" // Returns "88aab3ede8d3adf94d26ab90d3bafd4a2083070c3bcce9c014ee04a443847c0b"
796
+ "{{hmacSha256('hello', 'secret', 'base64')}}" // Returns base64-encoded HMAC
797
+
798
+ // Sign from context variables
799
+ "{{hmacSha256($.body, $.signingSecret)}}"
800
+ ```
801
+
802
+ ###### md5(value, encoding?)
803
+
804
+ Computes the MD5 hash of a string value.
805
+
806
+ - `value` (string): The string to hash
807
+ - `encoding` (string, optional): Output encoding — `'hex'` (default) or `'base64'`
808
+ - Returns: MD5 hash, or empty string for invalid input
809
+
810
+ ```js
811
+ "{{md5('hello')}}" // Returns "5d41402abc4b2a76b9719d911017c592"
812
+ "{{md5('hello', 'base64')}}" // Returns "XUFAKrxLKna5cZ2REBfFkg=="
813
+
814
+ // Hash from context variable
815
+ "{{md5($.body, 'base64')}}"
816
+ ```
817
+
767
818
  For more information on the JEXL syntax, refer to the [JEXL Syntax documentation](https://commons.apache.org/proper/commons-jexl/reference/syntax.html).
768
819
 
769
820
  ### String Interpolation
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- var e=Object.create,t=Object.defineProperty,__name=(e,n)=>t(e,`name`,{value:n,configurable:!0}),n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,__copyProps=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},__toESM=(n,r,a)=>(a=n==null?{}:e(i(n)),__copyProps(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let o=require(`@stackone/utils`),s=require(`jexl`);s=__toESM(s);let c=require(`jsonpath-plus`);const l=`capitalize`,capitalize=(e,t=`first`)=>(0,o.isMissing)(e)||typeof e!=`string`?``:(t===`each`?`each`:`first`)==`each`?e.split(/(\s+)/).map(e=>e.trim()?e.charAt(0).toUpperCase()+e.slice(1):e).join(``):e.charAt(0).toUpperCase()+e.slice(1),u=`decodeUri`,decodeUri=e=>{if((0,o.isMissing)(e)||typeof e!=`string`)return``;try{return decodeURIComponent(e)}catch{return e}},d=`dedupe`,toCanonicalKey=e=>{if(e===null)return`null:null`;if(e===void 0)return`undefined:undefined`;if(typeof e!=`object`)return`${typeof e}:${String(e)}`;try{return`object:${stableStringify(e)}`}catch{return`unserializable:${Math.random()}`}},stableStringify=e=>typeof e!=`object`||!e?JSON.stringify(e):Array.isArray(e)?`[${e.map(stableStringify).join(`,`)}]`:`{${Object.keys(e).sort().map(t=>{let n=e[t];return`${JSON.stringify(t)}:${stableStringify(n)}`}).join(`,`)}}`,dedupe=e=>{if((0,o.isMissing)(e)||!Array.isArray(e))return[];let t=new Set,n=[];for(let r of e){let e=toCanonicalKey(r);t.has(e)||(t.add(e),n.push(r))}return n},f=`groupBy`,groupBy=(e,t)=>{if((0,o.isMissing)(e)||!Array.isArray(e)||(0,o.isMissing)(t)||typeof t!=`string`)return{};let n=Object.create(null);for(let r of e){if((0,o.isMissing)(r)||typeof r!=`object`||Array.isArray(r))continue;let e=r[t],i=(0,o.isMissing)(e)?`__missing__`:String(e);Object.prototype.hasOwnProperty.call(n,i)||(n[i]=[]),n[i].push(r)}return n},p=`join`,join=(e,t=`,`)=>{if(!(0,o.notMissing)(e)||!Array.isArray(e)||e.length===0)return``;let n=typeof t==`string`?t:`,`;return e.filter(e=>(0,o.notMissing)(e)).map(e=>String(e)).join(n)},m=`min`,min=(...e)=>{let t=e.length===1&&Array.isArray(e[0])?e[0]:e,n=[];for(let e of t)if(!(0,o.isMissing)(e)){if(typeof e==`number`&&!Number.isNaN(e))n.push(e);else if(typeof e==`string`){let t=Number(e);Number.isNaN(t)||n.push(t)}}return n.length===0?null:Math.min(...n)},h=`padStart`,padStart=(e,t,n=` `)=>{if(e==null)return``;let r=String(e);if((0,o.isMissing)(t)||typeof t!=`number`||t<0)return r;let i=typeof n==`string`?n:` `;return r.padStart(t,i)},g=`reduce`,_=[`sum`,`avg`,`count`,`min`,`max`,`concat`,`flatten`],reduce=(e,t,n)=>{if((0,o.isMissing)(e)||!Array.isArray(e)||(0,o.isMissing)(t)||typeof t!=`string`)return null;let r=t;if(!_.includes(r))return null;if(r===`count`)return e.length;let i=extractValues(e,n);switch(r){case`sum`:return numericReduce(i,e=>e.reduce((e,t)=>e+t,0));case`avg`:return numericReduce(i,e=>e.length>0?e.reduce((e,t)=>e+t,0)/e.length:null);case`min`:return numericReduce(i,e=>e.length>0?Math.min(...e):null);case`max`:return numericReduce(i,e=>e.length>0?Math.max(...e):null);case`concat`:case`flatten`:return i.reduce((e,t)=>Array.isArray(t)?e.concat(t):(e.push(t),e),[]);default:return null}},extractValues=(e,t)=>(0,o.isMissing)(t)||typeof t!=`string`?e:e.filter(e=>!(0,o.isMissing)(e)&&typeof e==`object`&&!Array.isArray(e)).map(e=>e[t]),numericReduce=(e,t)=>t(e.filter(e=>typeof e==`number`&&!Number.isNaN(e))),v=`regexMatch`,regexMatch=(e,t,n=1)=>{if((0,o.isMissing)(e)||typeof e!=`string`||(0,o.isMissing)(t)||typeof t!=`string`||t.length===0)return null;let r=typeof n==`number`?n:1;if(r<0)return null;try{let n=new RegExp(t),i=e.match(n);if(!i)return null;let a=i[r];return a===void 0?null:a}catch{return null}},y=`replace`,replace=(e,t,n,r=!1)=>{if((0,o.isMissing)(e)||typeof e!=`string`)return``;if(typeof t!=`string`)return e;let i=typeof n==`string`?n:``;return r===!0?e.replaceAll(t,i):e.replace(t,i)},b=`truncate`,truncate=(e,t,n=`...`)=>{if((0,o.isMissing)(e)||typeof e!=`string`)return``;if((0,o.isMissing)(t)||typeof t!=`number`||t<0)return e;let r=typeof n==`string`?n:`...`;if(e.length<=t)return e;let i=Math.max(0,t-r.length);return i<=0?e.slice(0,t):e.slice(0,i)+r},x=`urlParam`,urlParam=(e,t)=>{if((0,o.isMissing)(e)||typeof e!=`string`||(0,o.isMissing)(t)||typeof t!=`string`)return null;try{return new URL(e).searchParams.get(t)}catch{return null}},S=`zipObject`,zipObject=(e,t)=>{if((0,o.isMissing)(e)||!Array.isArray(e)||(0,o.isMissing)(t)||!Array.isArray(t))return{};let n=Math.min(e.length,t.length),r=[];for(let i=0;i<n;i++){let n=e[i];typeof n==`string`&&r.push([n,t[i]])}return Object.fromEntries(r)},createExpressionHandler=(e=()=>new s.Jexl)=>{let t=e();return t.addFunction(`nextAnniversary`,(e,t)=>(0,o.calculateNextAnniversary)({initialDate:e,format:t})),t.addFunction(`yearsElapsed`,(e,t,n)=>(0,o.calculateYearsElapsed)({startDate:e,endDate:n,format:t})),t.addFunction(`hasPassed`,(e,t,n)=>(0,o.dateHasPassed)({date:e,yearsToAdd:n,format:t})),t.addFunction(`now`,()=>new Date().toISOString()),t.addFunction(`includes`,(e,t)=>(0,o.isMissing)(e)||!Array.isArray(e)||e.length===0||(0,o.isMissing)(t)?!1:Array.isArray(t)?t.every(t=>e.includes(t)):e.includes(t)),t.addFunction(`includesSome`,(e,t)=>(0,o.isMissing)(e)||!Array.isArray(e)||e.length===0||(0,o.isMissing)(t)?!1:Array.isArray(t)?t.some(t=>e.includes(t)):e.includes(t)),t.addFunction(`present`,e=>(0,o.notMissing)(e)),t.addFunction(`missing`,e=>(0,o.isMissing)(e)),t.addFunction(`keys`,e=>(0,o.isMissing)(e)?[]:typeof e==`object`&&!Array.isArray(e)?Object.keys(e):[]),t.addFunction(`values`,e=>(0,o.isMissing)(e)?[]:typeof e==`object`&&!Array.isArray(e)?Object.values(e):[]),t.addFunction(`decodeBase64`,e=>{if((0,o.isMissing)(e)||typeof e!=`string`)return``;try{return(0,o.decodeFromBase64)(e)}catch{return``}}),t.addFunction(`encodeBase64`,e=>{if((0,o.isMissing)(e)||typeof e!=`string`)return``;try{return(0,o.encodeToBase64)(e)}catch{return``}}),t.addFunction(`deltaFromNowMs`,(e,t)=>{let n=Date.now(),r;if(typeof e==`number`)r=t===`seconds`?e*1e3:e;else if(typeof e==`string`)r=t===`timestamp`?parseInt(e,10):t===`seconds`?parseFloat(e)*1e3:new Date(e).getTime();else throw Error(`Unsupported date input type`);return r-n}),t.addBinaryOp(`??`,0,(e,t)=>(0,o.isMissing)(e)?t:(0,o.isMissing)(t)?e:e??t),t.addFunction(`capitalize`,capitalize),t.addFunction(`decodeUri`,decodeUri),t.addFunction(`dedupe`,dedupe),t.addFunction(`groupBy`,groupBy),t.addFunction(`join`,join),t.addFunction(`min`,min),t.addFunction(`padStart`,padStart),t.addFunction(`zipObject`,zipObject),t.addFunction(`reduce`,reduce),t.addFunction(`regexMatch`,regexMatch),t.addFunction(`replace`,replace),t.addFunction(`truncate`,truncate),t.addFunction(`urlParam`,urlParam),t},C=/\${([^}]+)}/g,cleanExpression=e=>e.replace(/\$\./g,``).trim(),extractLeadingFunctionCall=e=>{let t=e.match(/^\w+\(/);if(!t)return null;let n=0;for(let r=t[0].length-1;r<e.length;r++)if(e[r]===`(`?n++:e[r]===`)`&&n--,n===0)return e.slice(r+1).trimStart().startsWith(`?`)?e.slice(0,r+1):null;return null},tryCompile=(e,t)=>{try{return e.compile(t)}catch{return null}},compileExpression=(e,t)=>{let n=tryCompile(e,t);if(n)return n;let r=extractLeadingFunctionCall(t);return r?tryCompile(e,`(${r})${t.slice(r.length)}`):null},extractExpressionBetweenDoubleCurlyBraces=e=>{if(e.startsWith(`{{`)&&e.endsWith(`}}`))return e.slice(2,-2)},evaluateJsonPath=(e,t)=>{try{if(!e.startsWith(`$`))throw Error(`JSONPath expression must start with '$': ${e}`);if(e.includes(`$_`)||e.match(/\$[^.[]/g)||e.includes(`[`)&&!e.includes(`]`)||e.includes(` `)&&!e.includes(`[`))throw Error(`Invalid JSONPath expression: ${e}`);let n=(0,c.JSONPath)({path:e,json:t});return n.length===0?void 0:n.length===1?n[0]:n}catch{throw Error(`Invalid JSONPath expression: ${e}`)}},replaceInterpolation=(e,t,n)=>e.replace(t,String(n)),handleSingleInterpolation=(e,t,n,r)=>{let i=e.path.trim();if(!i)return r;try{let a=compileExpression(t,i);if(a){let t=a.evalSync(n);if(t!==void 0)return replaceInterpolation(r,e.toReplace,t)}let s=evaluateJsonPathIncremental(`$.${i}`,n).value;return(0,o.notMissing)(s)?replaceInterpolation(r,e.toReplace,s):r}catch{return r}},evaluateStringInterpolations=(e,t,n)=>{let r=e.match(C);if(!r)return;let i=r.length,a=Array(i);for(let e=0;e<i;e++)a[e]={toReplace:r[e],path:r[e].slice(2,-1)};return a.reduce((e,r)=>handleSingleInterpolation(r,n,t,e),String(e))},handleSegmentPathError=(e,t,n,r)=>{if(Array.isArray(t)){let e=parseInt(n,10);if(!isNaN(e)&&(e<0||e>=t.length))return{value:void 0,error:`Invalid array index '${n}' at '${r}'`,availableKeys:t.map((e,t)=>t.toString())}}return(0,o.isObject)(t)?{value:void 0,error:`Key '${n}' not found at '${r}'`,availableKeys:Object.keys(t)}:{value:void 0,error:`${e} at '${r}'`,availableKeys:[]}},handleJsonPathSegments=(e,t)=>{if(e[0]!==`$`)return{value:void 0,error:`JSON path must start with $`};let n=t,r=`$`;for(let t=1;t<e.length;t++){let i=e[t],a=i.startsWith(`[`)?`${r}${i}`:`${r}.${i}`;if(Array.isArray(n)){let e=parseInt(i,10);if(isNaN(e)||e<0||e>=n.length)return handleSegmentPathError(`Invalid array index`,n,i,r);n=n[e],r=a}else if((0,o.isObject)(n)){if(!Object.prototype.hasOwnProperty.call(n,i))return handleSegmentPathError(`Key not found`,n,i,r);n=n[i],r=a}else return{value:void 0,error:`Cannot access '${i}' at '${r}' - parent is not an object`,availableKeys:[]}}return{value:n}},evaluateJsonPathIncremental=(e,t)=>{let n=/(\.\.)|(\[\*\])|(\[\?\()|(\[\d+:\d+\])/;try{if(n.test(e)){let n=evaluateJsonPath(e,t);return n===void 0?{value:void 0,error:`Invalid or empty JSONPath: '${e}'`}:{value:n}}return handleJsonPathSegments((e.match(/\$|(?:\['([^']+)'\])|(?:\["([^"]+)"\])|\[\d+\]|[^[\].]+/g)||[]).map(e=>e.replace(/^\['([^']+)'\]$/,`$1`).replace(/^\["([^"]+)"\]$/,`$1`).replace(/^\[(\d+)\]$/,`$1`)),t)}catch(e){return{value:void 0,error:`Something went wrong with evaluation of JSON path: ${String(e)}`}}},handleIncrementalJsonPath=(e,t)=>{let n=evaluateJsonPathIncremental(e,t);if(n.error)throw Error(`${n.error}${n.availableKeys?.length?`. Available keys: ${n.availableKeys.join(`, `)}`:``}`);return n.value},handleNormalJsonPath=(e,t)=>{try{return evaluateJsonPath(e,t)}catch{throw Error(`Invalid JSON path: "${e}"`)}},evaluateExpression=(e,t,n)=>{let r=e?.trim();if(r==null||r===``)throw Error(`Empty expression`);let i=(0,o.isObject)(t)?t:{},a=createExpressionHandler(),s=extractExpressionBetweenDoubleCurlyBraces(r),c=cleanExpression(s??r),l=evaluateStringInterpolations(c,i,a);if(l)return l;if(!s&&r.startsWith(`$`))return n?.incrementalJsonPath?handleIncrementalJsonPath(r,i):handleNormalJsonPath(r,i);if(!l&&!s)return e;let u=compileExpression(a,c);if(!u||c===`.`)throw Error(`Invalid expression: "${r}"`);try{return u.evalSync(i)}catch{return}},safeEvaluateExpression=(e,t)=>{try{return evaluateExpression(e,t)}catch{return null}},safeEvaluateRecord=(e,t)=>{let evaluateValue=e=>Array.isArray(e)?e.map(evaluateValue):typeof e==`object`&&e?safeEvaluateRecord(e,t):typeof e==`string`?safeEvaluateExpression(e,t):e;return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,evaluateValue(t)]))},isValidExpression=e=>{try{return evaluateExpression(e),!0}catch{return!1}};exports.evaluate=evaluateExpression,exports.isValidExpression=isValidExpression,exports.safeEvaluate=safeEvaluateExpression,exports.safeEvaluateRecord=safeEvaluateRecord;
1
+ var e=Object.create,t=Object.defineProperty,__name=(e,n)=>t(e,`name`,{value:n,configurable:!0}),n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,__copyProps=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},__toESM=(n,r,a)=>(a=n==null?{}:e(i(n)),__copyProps(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let o=require(`@stackone/utils`),s=require(`jexl`);s=__toESM(s);let c=require(`crypto`),l=require(`jsonpath-plus`);const u=`capitalize`,capitalize=(e,t=`first`)=>(0,o.isMissing)(e)||typeof e!=`string`?``:(t===`each`?`each`:`first`)==`each`?e.split(/(\s+)/).map(e=>e.trim()?e.charAt(0).toUpperCase()+e.slice(1):e).join(``):e.charAt(0).toUpperCase()+e.slice(1),d=`decodeUri`,decodeUri=e=>{if((0,o.isMissing)(e)||typeof e!=`string`)return``;try{return decodeURIComponent(e)}catch{return e}},f=`dedupe`,toCanonicalKey=e=>{if(e===null)return`null:null`;if(e===void 0)return`undefined:undefined`;if(typeof e!=`object`)return`${typeof e}:${String(e)}`;try{return`object:${stableStringify(e)}`}catch{return`unserializable:${Math.random()}`}},stableStringify=e=>typeof e!=`object`||!e?JSON.stringify(e):Array.isArray(e)?`[${e.map(stableStringify).join(`,`)}]`:`{${Object.keys(e).sort().map(t=>{let n=e[t];return`${JSON.stringify(t)}:${stableStringify(n)}`}).join(`,`)}}`,dedupe=e=>{if((0,o.isMissing)(e)||!Array.isArray(e))return[];let t=new Set,n=[];for(let r of e){let e=toCanonicalKey(r);t.has(e)||(t.add(e),n.push(r))}return n},p=`groupBy`,groupBy=(e,t)=>{if((0,o.isMissing)(e)||!Array.isArray(e)||(0,o.isMissing)(t)||typeof t!=`string`)return{};let n=Object.create(null);for(let r of e){if((0,o.isMissing)(r)||typeof r!=`object`||Array.isArray(r))continue;let e=r[t],i=(0,o.isMissing)(e)?`__missing__`:String(e);Object.prototype.hasOwnProperty.call(n,i)||(n[i]=[]),n[i].push(r)}return n},m=`hmacSha256`,hmacSha256=(e,t,n=`hex`)=>{if(e==null||typeof e!=`string`||t==null||typeof t!=`string`)return``;let r=n===`base64`?`base64`:`hex`;try{return(0,c.createHmac)(`sha256`,t).update(e).digest(r)}catch{return``}},h=`join`,join=(e,t=`,`)=>{if(!(0,o.notMissing)(e)||!Array.isArray(e)||e.length===0)return``;let n=typeof t==`string`?t:`,`;return e.filter(e=>(0,o.notMissing)(e)).map(e=>String(e)).join(n)},g=`md5`,md5=(e,t=`hex`)=>{if(e==null||typeof e!=`string`)return``;let n=t===`base64`?`base64`:`hex`;try{return(0,c.createHash)(`md5`).update(e).digest(n)}catch{return``}},_=`min`,min=(...e)=>{let t=e.length===1&&Array.isArray(e[0])?e[0]:e,n=[];for(let e of t)if(!(0,o.isMissing)(e)){if(typeof e==`number`&&!Number.isNaN(e))n.push(e);else if(typeof e==`string`){let t=Number(e);Number.isNaN(t)||n.push(t)}}return n.length===0?null:Math.min(...n)},v=`padStart`,padStart=(e,t,n=` `)=>{if(e==null)return``;let r=String(e);if((0,o.isMissing)(t)||typeof t!=`number`||t<0)return r;let i=typeof n==`string`?n:` `;return r.padStart(t,i)},y=`reduce`,b=[`sum`,`avg`,`count`,`min`,`max`,`concat`,`flatten`],reduce=(e,t,n)=>{if((0,o.isMissing)(e)||!Array.isArray(e)||(0,o.isMissing)(t)||typeof t!=`string`)return null;let r=t;if(!b.includes(r))return null;if(r===`count`)return e.length;let i=extractValues(e,n);switch(r){case`sum`:return numericReduce(i,e=>e.reduce((e,t)=>e+t,0));case`avg`:return numericReduce(i,e=>e.length>0?e.reduce((e,t)=>e+t,0)/e.length:null);case`min`:return numericReduce(i,e=>e.length>0?Math.min(...e):null);case`max`:return numericReduce(i,e=>e.length>0?Math.max(...e):null);case`concat`:case`flatten`:return i.reduce((e,t)=>Array.isArray(t)?e.concat(t):(e.push(t),e),[]);default:return null}},extractValues=(e,t)=>(0,o.isMissing)(t)||typeof t!=`string`?e:e.filter(e=>!(0,o.isMissing)(e)&&typeof e==`object`&&!Array.isArray(e)).map(e=>e[t]),numericReduce=(e,t)=>t(e.filter(e=>typeof e==`number`&&!Number.isNaN(e))),x=`regexMatch`,regexMatch=(e,t,n=1)=>{if((0,o.isMissing)(e)||typeof e!=`string`||(0,o.isMissing)(t)||typeof t!=`string`||t.length===0)return null;let r=typeof n==`number`?n:1;if(r<0)return null;try{let n=new RegExp(t),i=e.match(n);if(!i)return null;let a=i[r];return a===void 0?null:a}catch{return null}},S=`replace`,replace=(e,t,n,r=!1)=>{if((0,o.isMissing)(e)||typeof e!=`string`)return``;if(typeof t!=`string`)return e;let i=typeof n==`string`?n:``;return r===!0?e.replaceAll(t,i):e.replace(t,i)},C=`sha256`,sha256=(e,t=`hex`)=>{if(e==null||typeof e!=`string`)return``;let n=t===`base64`?`base64`:`hex`;try{return(0,c.createHash)(`sha256`).update(e).digest(n)}catch{return``}},w=`truncate`,truncate=(e,t,n=`...`)=>{if((0,o.isMissing)(e)||typeof e!=`string`)return``;if((0,o.isMissing)(t)||typeof t!=`number`||t<0)return e;let r=typeof n==`string`?n:`...`;if(e.length<=t)return e;let i=Math.max(0,t-r.length);return i<=0?e.slice(0,t):e.slice(0,i)+r},T=`urlParam`,urlParam=(e,t)=>{if((0,o.isMissing)(e)||typeof e!=`string`||(0,o.isMissing)(t)||typeof t!=`string`)return null;try{return new URL(e).searchParams.get(t)}catch{return null}},E=`zipObject`,zipObject=(e,t)=>{if((0,o.isMissing)(e)||!Array.isArray(e)||(0,o.isMissing)(t)||!Array.isArray(t))return{};let n=Math.min(e.length,t.length),r=[];for(let i=0;i<n;i++){let n=e[i];typeof n==`string`&&r.push([n,t[i]])}return Object.fromEntries(r)},createExpressionHandler=(e=()=>new s.Jexl)=>{let t=e();return t.addFunction(`nextAnniversary`,(e,t)=>(0,o.calculateNextAnniversary)({initialDate:e,format:t})),t.addFunction(`yearsElapsed`,(e,t,n)=>(0,o.calculateYearsElapsed)({startDate:e,endDate:n,format:t})),t.addFunction(`hasPassed`,(e,t,n)=>(0,o.dateHasPassed)({date:e,yearsToAdd:n,format:t})),t.addFunction(`now`,()=>new Date().toISOString()),t.addFunction(`includes`,(e,t)=>(0,o.isMissing)(e)||!Array.isArray(e)||e.length===0||(0,o.isMissing)(t)?!1:Array.isArray(t)?t.every(t=>e.includes(t)):e.includes(t)),t.addFunction(`includesSome`,(e,t)=>(0,o.isMissing)(e)||!Array.isArray(e)||e.length===0||(0,o.isMissing)(t)?!1:Array.isArray(t)?t.some(t=>e.includes(t)):e.includes(t)),t.addFunction(`present`,e=>(0,o.notMissing)(e)),t.addFunction(`missing`,e=>(0,o.isMissing)(e)),t.addFunction(`keys`,e=>(0,o.isMissing)(e)?[]:typeof e==`object`&&!Array.isArray(e)?Object.keys(e):[]),t.addFunction(`values`,e=>(0,o.isMissing)(e)?[]:typeof e==`object`&&!Array.isArray(e)?Object.values(e):[]),t.addFunction(`decodeBase64`,e=>{if((0,o.isMissing)(e)||typeof e!=`string`)return``;try{return(0,o.decodeFromBase64)(e)}catch{return``}}),t.addFunction(`encodeBase64`,e=>{if((0,o.isMissing)(e)||typeof e!=`string`)return``;try{return(0,o.encodeToBase64)(e)}catch{return``}}),t.addFunction(`deltaFromNowMs`,(e,t)=>{let n=Date.now(),r;if(typeof e==`number`)r=t===`seconds`?e*1e3:e;else if(typeof e==`string`)r=t===`timestamp`?parseInt(e,10):t===`seconds`?parseFloat(e)*1e3:new Date(e).getTime();else throw Error(`Unsupported date input type`);return r-n}),t.addBinaryOp(`??`,0,(e,t)=>(0,o.isMissing)(e)?t:(0,o.isMissing)(t)?e:e??t),t.addFunction(`capitalize`,capitalize),t.addFunction(`hmacSha256`,hmacSha256),t.addFunction(`md5`,md5),t.addFunction(`sha256`,sha256),t.addFunction(`decodeUri`,decodeUri),t.addFunction(`dedupe`,dedupe),t.addFunction(`groupBy`,groupBy),t.addFunction(`join`,join),t.addFunction(`min`,min),t.addFunction(`padStart`,padStart),t.addFunction(`zipObject`,zipObject),t.addFunction(`reduce`,reduce),t.addFunction(`regexMatch`,regexMatch),t.addFunction(`replace`,replace),t.addFunction(`truncate`,truncate),t.addFunction(`urlParam`,urlParam),t},D=/\${([^}]+)}/g,cleanExpression=e=>e.replace(/\$\./g,``).trim(),extractLeadingFunctionCall=e=>{let t=e.match(/^\w+\(/);if(!t)return null;let n=0;for(let r=t[0].length-1;r<e.length;r++)if(e[r]===`(`?n++:e[r]===`)`&&n--,n===0)return e.slice(r+1).trimStart().startsWith(`?`)?e.slice(0,r+1):null;return null},tryCompile=(e,t)=>{try{return e.compile(t)}catch{return null}},compileExpression=(e,t)=>{let n=tryCompile(e,t);if(n)return n;let r=extractLeadingFunctionCall(t);return r?tryCompile(e,`(${r})${t.slice(r.length)}`):null},extractExpressionBetweenDoubleCurlyBraces=e=>{if(e.startsWith(`{{`)&&e.endsWith(`}}`))return e.slice(2,-2)},evaluateJsonPath=(e,t)=>{try{if(!e.startsWith(`$`))throw Error(`JSONPath expression must start with '$': ${e}`);if(e.includes(`$_`)||e.match(/\$[^.[]/g)||e.includes(`[`)&&!e.includes(`]`)||e.includes(` `)&&!e.includes(`[`))throw Error(`Invalid JSONPath expression: ${e}`);let n=(0,l.JSONPath)({path:e,json:t});return n.length===0?void 0:n.length===1?n[0]:n}catch{throw Error(`Invalid JSONPath expression: ${e}`)}},replaceInterpolation=(e,t,n)=>e.replace(t,String(n)),handleSingleInterpolation=(e,t,n,r)=>{let i=e.path.trim();if(!i)return r;try{let a=compileExpression(t,i);if(a){let t=a.evalSync(n);if(t!==void 0)return replaceInterpolation(r,e.toReplace,t)}let s=evaluateJsonPathIncremental(`$.${i}`,n).value;return(0,o.notMissing)(s)?replaceInterpolation(r,e.toReplace,s):r}catch{return r}},evaluateStringInterpolations=(e,t,n)=>{let r=e.match(D);if(!r)return;let i=r.length,a=Array(i);for(let e=0;e<i;e++)a[e]={toReplace:r[e],path:r[e].slice(2,-1)};return a.reduce((e,r)=>handleSingleInterpolation(r,n,t,e),String(e))},handleSegmentPathError=(e,t,n,r)=>{if(Array.isArray(t)){let e=parseInt(n,10);if(!isNaN(e)&&(e<0||e>=t.length))return{value:void 0,error:`Invalid array index '${n}' at '${r}'`,availableKeys:t.map((e,t)=>t.toString())}}return(0,o.isObject)(t)?{value:void 0,error:`Key '${n}' not found at '${r}'`,availableKeys:Object.keys(t)}:{value:void 0,error:`${e} at '${r}'`,availableKeys:[]}},handleJsonPathSegments=(e,t)=>{if(e[0]!==`$`)return{value:void 0,error:`JSON path must start with $`};let n=t,r=`$`;for(let t=1;t<e.length;t++){let i=e[t],a=i.startsWith(`[`)?`${r}${i}`:`${r}.${i}`;if(Array.isArray(n)){let e=parseInt(i,10);if(isNaN(e)||e<0||e>=n.length)return handleSegmentPathError(`Invalid array index`,n,i,r);n=n[e],r=a}else if((0,o.isObject)(n)){if(!Object.prototype.hasOwnProperty.call(n,i))return handleSegmentPathError(`Key not found`,n,i,r);n=n[i],r=a}else return{value:void 0,error:`Cannot access '${i}' at '${r}' - parent is not an object`,availableKeys:[]}}return{value:n}},evaluateJsonPathIncremental=(e,t)=>{let n=/(\.\.)|(\[\*\])|(\[\?\()|(\[\d+:\d+\])/;try{if(n.test(e)){let n=evaluateJsonPath(e,t);return n===void 0?{value:void 0,error:`Invalid or empty JSONPath: '${e}'`}:{value:n}}return handleJsonPathSegments((e.match(/\$|(?:\['([^']+)'\])|(?:\["([^"]+)"\])|\[\d+\]|[^[\].]+/g)||[]).map(e=>e.replace(/^\['([^']+)'\]$/,`$1`).replace(/^\["([^"]+)"\]$/,`$1`).replace(/^\[(\d+)\]$/,`$1`)),t)}catch(e){return{value:void 0,error:`Something went wrong with evaluation of JSON path: ${String(e)}`}}},handleIncrementalJsonPath=(e,t)=>{let n=evaluateJsonPathIncremental(e,t);if(n.error)throw Error(`${n.error}${n.availableKeys?.length?`. Available keys: ${n.availableKeys.join(`, `)}`:``}`);return n.value},handleNormalJsonPath=(e,t)=>{try{return evaluateJsonPath(e,t)}catch{throw Error(`Invalid JSON path: "${e}"`)}},evaluateExpression=(e,t,n)=>{let r=e?.trim();if(r==null||r===``)throw Error(`Empty expression`);let i=(0,o.isObject)(t)?t:{},a=createExpressionHandler();a.addTransform(`key`,e=>typeof e!=`string`||!Object.prototype.hasOwnProperty.call(i,e)?null:i[e]);let s=extractExpressionBetweenDoubleCurlyBraces(r),c=cleanExpression(s??r),l=evaluateStringInterpolations(c,i,a);if(l)return l;if(!s&&r.startsWith(`$`))return n?.incrementalJsonPath?handleIncrementalJsonPath(r,i):handleNormalJsonPath(r,i);if(!l&&!s)return e;let u=compileExpression(a,c);if(!u||c===`.`)throw Error(`Invalid expression: "${r}"`);try{return u.evalSync(i)}catch{return}},safeEvaluateExpression=(e,t)=>{try{return evaluateExpression(e,t)}catch{return null}},safeEvaluateRecord=(e,t)=>{let evaluateValue=e=>Array.isArray(e)?e.map(evaluateValue):typeof e==`object`&&e?safeEvaluateRecord(e,t):typeof e==`string`?safeEvaluateExpression(e,t):e;return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,evaluateValue(t)]))},isValidExpression=e=>{try{return evaluateExpression(e),!0}catch{return!1}};exports.evaluate=evaluateExpression,exports.isValidExpression=isValidExpression,exports.safeEvaluate=safeEvaluateExpression,exports.safeEvaluateRecord=safeEvaluateRecord;
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{t as e}from"./chunk-Cfxk5zVN.mjs";import{calculateNextAnniversary as t,calculateYearsElapsed as n,dateHasPassed as r,decodeFromBase64 as i,encodeToBase64 as a,isMissing as o,isObject as s,notMissing as c}from"@stackone/utils";import*as l from"jexl";import{JSONPath as u}from"jsonpath-plus";const capitalize=(e,t=`first`)=>o(e)||typeof e!=`string`?``:(t===`each`?`each`:`first`)==`each`?e.split(/(\s+)/).map(e=>e.trim()?e.charAt(0).toUpperCase()+e.slice(1):e).join(``):e.charAt(0).toUpperCase()+e.slice(1),decodeUri=e=>{if(o(e)||typeof e!=`string`)return``;try{return decodeURIComponent(e)}catch{return e}},toCanonicalKey=e=>{if(e===null)return`null:null`;if(e===void 0)return`undefined:undefined`;if(typeof e!=`object`)return`${typeof e}:${String(e)}`;try{return`object:${stableStringify(e)}`}catch{return`unserializable:${Math.random()}`}},stableStringify=e=>typeof e!=`object`||!e?JSON.stringify(e):Array.isArray(e)?`[${e.map(stableStringify).join(`,`)}]`:`{${Object.keys(e).sort().map(t=>{let n=e[t];return`${JSON.stringify(t)}:${stableStringify(n)}`}).join(`,`)}}`,dedupe=e=>{if(o(e)||!Array.isArray(e))return[];let t=new Set,n=[];for(let r of e){let e=toCanonicalKey(r);t.has(e)||(t.add(e),n.push(r))}return n},groupBy=(e,t)=>{if(o(e)||!Array.isArray(e)||o(t)||typeof t!=`string`)return{};let n=Object.create(null);for(let r of e){if(o(r)||typeof r!=`object`||Array.isArray(r))continue;let e=r[t],i=o(e)?`__missing__`:String(e);Object.prototype.hasOwnProperty.call(n,i)||(n[i]=[]),n[i].push(r)}return n},join=(e,t=`,`)=>{if(!c(e)||!Array.isArray(e)||e.length===0)return``;let n=typeof t==`string`?t:`,`;return e.filter(e=>c(e)).map(e=>String(e)).join(n)},min=(...e)=>{let t=e.length===1&&Array.isArray(e[0])?e[0]:e,n=[];for(let e of t)if(!o(e)){if(typeof e==`number`&&!Number.isNaN(e))n.push(e);else if(typeof e==`string`){let t=Number(e);Number.isNaN(t)||n.push(t)}}return n.length===0?null:Math.min(...n)},padStart=(e,t,n=` `)=>{if(e==null)return``;let r=String(e);if(o(t)||typeof t!=`number`||t<0)return r;let i=typeof n==`string`?n:` `;return r.padStart(t,i)},d=[`sum`,`avg`,`count`,`min`,`max`,`concat`,`flatten`],reduce=(e,t,n)=>{if(o(e)||!Array.isArray(e)||o(t)||typeof t!=`string`)return null;let r=t;if(!d.includes(r))return null;if(r===`count`)return e.length;let i=extractValues(e,n);switch(r){case`sum`:return numericReduce(i,e=>e.reduce((e,t)=>e+t,0));case`avg`:return numericReduce(i,e=>e.length>0?e.reduce((e,t)=>e+t,0)/e.length:null);case`min`:return numericReduce(i,e=>e.length>0?Math.min(...e):null);case`max`:return numericReduce(i,e=>e.length>0?Math.max(...e):null);case`concat`:case`flatten`:return i.reduce((e,t)=>Array.isArray(t)?e.concat(t):(e.push(t),e),[]);default:return null}},extractValues=(e,t)=>o(t)||typeof t!=`string`?e:e.filter(e=>!o(e)&&typeof e==`object`&&!Array.isArray(e)).map(e=>e[t]),numericReduce=(e,t)=>t(e.filter(e=>typeof e==`number`&&!Number.isNaN(e))),regexMatch=(e,t,n=1)=>{if(o(e)||typeof e!=`string`||o(t)||typeof t!=`string`||t.length===0)return null;let r=typeof n==`number`?n:1;if(r<0)return null;try{let n=new RegExp(t),i=e.match(n);if(!i)return null;let a=i[r];return a===void 0?null:a}catch{return null}},replace=(e,t,n,r=!1)=>{if(o(e)||typeof e!=`string`)return``;if(typeof t!=`string`)return e;let i=typeof n==`string`?n:``;return r===!0?e.replaceAll(t,i):e.replace(t,i)},truncate=(e,t,n=`...`)=>{if(o(e)||typeof e!=`string`)return``;if(o(t)||typeof t!=`number`||t<0)return e;let r=typeof n==`string`?n:`...`;if(e.length<=t)return e;let i=Math.max(0,t-r.length);return i<=0?e.slice(0,t):e.slice(0,i)+r},urlParam=(e,t)=>{if(o(e)||typeof e!=`string`||o(t)||typeof t!=`string`)return null;try{return new URL(e).searchParams.get(t)}catch{return null}},zipObject=(e,t)=>{if(o(e)||!Array.isArray(e)||o(t)||!Array.isArray(t))return{};let n=Math.min(e.length,t.length),r=[];for(let i=0;i<n;i++){let n=e[i];typeof n==`string`&&r.push([n,t[i]])}return Object.fromEntries(r)},createExpressionHandler=(e=()=>new l.Jexl)=>{let s=e();return s.addFunction(`nextAnniversary`,(e,n)=>t({initialDate:e,format:n})),s.addFunction(`yearsElapsed`,(e,t,r)=>n({startDate:e,endDate:r,format:t})),s.addFunction(`hasPassed`,(e,t,n)=>r({date:e,yearsToAdd:n,format:t})),s.addFunction(`now`,()=>new Date().toISOString()),s.addFunction(`includes`,(e,t)=>o(e)||!Array.isArray(e)||e.length===0||o(t)?!1:Array.isArray(t)?t.every(t=>e.includes(t)):e.includes(t)),s.addFunction(`includesSome`,(e,t)=>o(e)||!Array.isArray(e)||e.length===0||o(t)?!1:Array.isArray(t)?t.some(t=>e.includes(t)):e.includes(t)),s.addFunction(`present`,e=>c(e)),s.addFunction(`missing`,e=>o(e)),s.addFunction(`keys`,e=>o(e)?[]:typeof e==`object`&&!Array.isArray(e)?Object.keys(e):[]),s.addFunction(`values`,e=>o(e)?[]:typeof e==`object`&&!Array.isArray(e)?Object.values(e):[]),s.addFunction(`decodeBase64`,e=>{if(o(e)||typeof e!=`string`)return``;try{return i(e)}catch{return``}}),s.addFunction(`encodeBase64`,e=>{if(o(e)||typeof e!=`string`)return``;try{return a(e)}catch{return``}}),s.addFunction(`deltaFromNowMs`,(e,t)=>{let n=Date.now(),r;if(typeof e==`number`)r=t===`seconds`?e*1e3:e;else if(typeof e==`string`)r=t===`timestamp`?parseInt(e,10):t===`seconds`?parseFloat(e)*1e3:new Date(e).getTime();else throw Error(`Unsupported date input type`);return r-n}),s.addBinaryOp(`??`,0,(e,t)=>o(e)?t:o(t)?e:e??t),s.addFunction(`capitalize`,capitalize),s.addFunction(`decodeUri`,decodeUri),s.addFunction(`dedupe`,dedupe),s.addFunction(`groupBy`,groupBy),s.addFunction(`join`,join),s.addFunction(`min`,min),s.addFunction(`padStart`,padStart),s.addFunction(`zipObject`,zipObject),s.addFunction(`reduce`,reduce),s.addFunction(`regexMatch`,regexMatch),s.addFunction(`replace`,replace),s.addFunction(`truncate`,truncate),s.addFunction(`urlParam`,urlParam),s},f=/\${([^}]+)}/g,cleanExpression=e=>e.replace(/\$\./g,``).trim(),extractLeadingFunctionCall=e=>{let t=e.match(/^\w+\(/);if(!t)return null;let n=0;for(let r=t[0].length-1;r<e.length;r++)if(e[r]===`(`?n++:e[r]===`)`&&n--,n===0)return e.slice(r+1).trimStart().startsWith(`?`)?e.slice(0,r+1):null;return null},tryCompile=(e,t)=>{try{return e.compile(t)}catch{return null}},compileExpression=(e,t)=>{let n=tryCompile(e,t);if(n)return n;let r=extractLeadingFunctionCall(t);return r?tryCompile(e,`(${r})${t.slice(r.length)}`):null},extractExpressionBetweenDoubleCurlyBraces=e=>{if(e.startsWith(`{{`)&&e.endsWith(`}}`))return e.slice(2,-2)},evaluateJsonPath=(e,t)=>{try{if(!e.startsWith(`$`))throw Error(`JSONPath expression must start with '$': ${e}`);if(e.includes(`$_`)||e.match(/\$[^.[]/g)||e.includes(`[`)&&!e.includes(`]`)||e.includes(` `)&&!e.includes(`[`))throw Error(`Invalid JSONPath expression: ${e}`);let n=u({path:e,json:t});return n.length===0?void 0:n.length===1?n[0]:n}catch{throw Error(`Invalid JSONPath expression: ${e}`)}},replaceInterpolation=(e,t,n)=>e.replace(t,String(n)),handleSingleInterpolation=(e,t,n,r)=>{let i=e.path.trim();if(!i)return r;try{let a=compileExpression(t,i);if(a){let t=a.evalSync(n);if(t!==void 0)return replaceInterpolation(r,e.toReplace,t)}let o=evaluateJsonPathIncremental(`$.${i}`,n).value;return c(o)?replaceInterpolation(r,e.toReplace,o):r}catch{return r}},evaluateStringInterpolations=(e,t,n)=>{let r=e.match(f);if(!r)return;let i=r.length,a=Array(i);for(let e=0;e<i;e++)a[e]={toReplace:r[e],path:r[e].slice(2,-1)};return a.reduce((e,r)=>handleSingleInterpolation(r,n,t,e),String(e))},handleSegmentPathError=(e,t,n,r)=>{if(Array.isArray(t)){let e=parseInt(n,10);if(!isNaN(e)&&(e<0||e>=t.length))return{value:void 0,error:`Invalid array index '${n}' at '${r}'`,availableKeys:t.map((e,t)=>t.toString())}}return s(t)?{value:void 0,error:`Key '${n}' not found at '${r}'`,availableKeys:Object.keys(t)}:{value:void 0,error:`${e} at '${r}'`,availableKeys:[]}},handleJsonPathSegments=(e,t)=>{if(e[0]!==`$`)return{value:void 0,error:`JSON path must start with $`};let n=t,r=`$`;for(let t=1;t<e.length;t++){let i=e[t],a=i.startsWith(`[`)?`${r}${i}`:`${r}.${i}`;if(Array.isArray(n)){let e=parseInt(i,10);if(isNaN(e)||e<0||e>=n.length)return handleSegmentPathError(`Invalid array index`,n,i,r);n=n[e],r=a}else if(s(n)){if(!Object.prototype.hasOwnProperty.call(n,i))return handleSegmentPathError(`Key not found`,n,i,r);n=n[i],r=a}else return{value:void 0,error:`Cannot access '${i}' at '${r}' - parent is not an object`,availableKeys:[]}}return{value:n}},evaluateJsonPathIncremental=(e,t)=>{let n=/(\.\.)|(\[\*\])|(\[\?\()|(\[\d+:\d+\])/;try{if(n.test(e)){let n=evaluateJsonPath(e,t);return n===void 0?{value:void 0,error:`Invalid or empty JSONPath: '${e}'`}:{value:n}}return handleJsonPathSegments((e.match(/\$|(?:\['([^']+)'\])|(?:\["([^"]+)"\])|\[\d+\]|[^[\].]+/g)||[]).map(e=>e.replace(/^\['([^']+)'\]$/,`$1`).replace(/^\["([^"]+)"\]$/,`$1`).replace(/^\[(\d+)\]$/,`$1`)),t)}catch(e){return{value:void 0,error:`Something went wrong with evaluation of JSON path: ${String(e)}`}}},handleIncrementalJsonPath=(e,t)=>{let n=evaluateJsonPathIncremental(e,t);if(n.error)throw Error(`${n.error}${n.availableKeys?.length?`. Available keys: ${n.availableKeys.join(`, `)}`:``}`);return n.value},handleNormalJsonPath=(e,t)=>{try{return evaluateJsonPath(e,t)}catch{throw Error(`Invalid JSON path: "${e}"`)}},evaluateExpression=(e,t,n)=>{let r=e?.trim();if(r==null||r===``)throw Error(`Empty expression`);let i=s(t)?t:{},a=createExpressionHandler(),o=extractExpressionBetweenDoubleCurlyBraces(r),c=cleanExpression(o??r),l=evaluateStringInterpolations(c,i,a);if(l)return l;if(!o&&r.startsWith(`$`))return n?.incrementalJsonPath?handleIncrementalJsonPath(r,i):handleNormalJsonPath(r,i);if(!l&&!o)return e;let u=compileExpression(a,c);if(!u||c===`.`)throw Error(`Invalid expression: "${r}"`);try{return u.evalSync(i)}catch{return}},safeEvaluateExpression=(e,t)=>{try{return evaluateExpression(e,t)}catch{return null}},safeEvaluateRecord=(e,t)=>{let evaluateValue=e=>Array.isArray(e)?e.map(evaluateValue):typeof e==`object`&&e?safeEvaluateRecord(e,t):typeof e==`string`?safeEvaluateExpression(e,t):e;return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,evaluateValue(t)]))},isValidExpression=e=>{try{return evaluateExpression(e),!0}catch{return!1}};export{evaluateExpression as evaluate,isValidExpression,safeEvaluateExpression as safeEvaluate,safeEvaluateRecord};
1
+ import{t as e}from"./chunk-Cfxk5zVN.mjs";import{calculateNextAnniversary as t,calculateYearsElapsed as n,dateHasPassed as r,decodeFromBase64 as i,encodeToBase64 as a,isMissing as o,isObject as s,notMissing as c}from"@stackone/utils";import*as l from"jexl";import{createHash as u,createHmac as d}from"crypto";import{JSONPath as f}from"jsonpath-plus";const capitalize=(e,t=`first`)=>o(e)||typeof e!=`string`?``:(t===`each`?`each`:`first`)==`each`?e.split(/(\s+)/).map(e=>e.trim()?e.charAt(0).toUpperCase()+e.slice(1):e).join(``):e.charAt(0).toUpperCase()+e.slice(1),decodeUri=e=>{if(o(e)||typeof e!=`string`)return``;try{return decodeURIComponent(e)}catch{return e}},toCanonicalKey=e=>{if(e===null)return`null:null`;if(e===void 0)return`undefined:undefined`;if(typeof e!=`object`)return`${typeof e}:${String(e)}`;try{return`object:${stableStringify(e)}`}catch{return`unserializable:${Math.random()}`}},stableStringify=e=>typeof e!=`object`||!e?JSON.stringify(e):Array.isArray(e)?`[${e.map(stableStringify).join(`,`)}]`:`{${Object.keys(e).sort().map(t=>{let n=e[t];return`${JSON.stringify(t)}:${stableStringify(n)}`}).join(`,`)}}`,dedupe=e=>{if(o(e)||!Array.isArray(e))return[];let t=new Set,n=[];for(let r of e){let e=toCanonicalKey(r);t.has(e)||(t.add(e),n.push(r))}return n},groupBy=(e,t)=>{if(o(e)||!Array.isArray(e)||o(t)||typeof t!=`string`)return{};let n=Object.create(null);for(let r of e){if(o(r)||typeof r!=`object`||Array.isArray(r))continue;let e=r[t],i=o(e)?`__missing__`:String(e);Object.prototype.hasOwnProperty.call(n,i)||(n[i]=[]),n[i].push(r)}return n},hmacSha256=(e,t,n=`hex`)=>{if(e==null||typeof e!=`string`||t==null||typeof t!=`string`)return``;let r=n===`base64`?`base64`:`hex`;try{return d(`sha256`,t).update(e).digest(r)}catch{return``}},join=(e,t=`,`)=>{if(!c(e)||!Array.isArray(e)||e.length===0)return``;let n=typeof t==`string`?t:`,`;return e.filter(e=>c(e)).map(e=>String(e)).join(n)},md5=(e,t=`hex`)=>{if(e==null||typeof e!=`string`)return``;let n=t===`base64`?`base64`:`hex`;try{return u(`md5`).update(e).digest(n)}catch{return``}},min=(...e)=>{let t=e.length===1&&Array.isArray(e[0])?e[0]:e,n=[];for(let e of t)if(!o(e)){if(typeof e==`number`&&!Number.isNaN(e))n.push(e);else if(typeof e==`string`){let t=Number(e);Number.isNaN(t)||n.push(t)}}return n.length===0?null:Math.min(...n)},padStart=(e,t,n=` `)=>{if(e==null)return``;let r=String(e);if(o(t)||typeof t!=`number`||t<0)return r;let i=typeof n==`string`?n:` `;return r.padStart(t,i)},p=[`sum`,`avg`,`count`,`min`,`max`,`concat`,`flatten`],reduce=(e,t,n)=>{if(o(e)||!Array.isArray(e)||o(t)||typeof t!=`string`)return null;let r=t;if(!p.includes(r))return null;if(r===`count`)return e.length;let i=extractValues(e,n);switch(r){case`sum`:return numericReduce(i,e=>e.reduce((e,t)=>e+t,0));case`avg`:return numericReduce(i,e=>e.length>0?e.reduce((e,t)=>e+t,0)/e.length:null);case`min`:return numericReduce(i,e=>e.length>0?Math.min(...e):null);case`max`:return numericReduce(i,e=>e.length>0?Math.max(...e):null);case`concat`:case`flatten`:return i.reduce((e,t)=>Array.isArray(t)?e.concat(t):(e.push(t),e),[]);default:return null}},extractValues=(e,t)=>o(t)||typeof t!=`string`?e:e.filter(e=>!o(e)&&typeof e==`object`&&!Array.isArray(e)).map(e=>e[t]),numericReduce=(e,t)=>t(e.filter(e=>typeof e==`number`&&!Number.isNaN(e))),regexMatch=(e,t,n=1)=>{if(o(e)||typeof e!=`string`||o(t)||typeof t!=`string`||t.length===0)return null;let r=typeof n==`number`?n:1;if(r<0)return null;try{let n=new RegExp(t),i=e.match(n);if(!i)return null;let a=i[r];return a===void 0?null:a}catch{return null}},replace=(e,t,n,r=!1)=>{if(o(e)||typeof e!=`string`)return``;if(typeof t!=`string`)return e;let i=typeof n==`string`?n:``;return r===!0?e.replaceAll(t,i):e.replace(t,i)},sha256=(e,t=`hex`)=>{if(e==null||typeof e!=`string`)return``;let n=t===`base64`?`base64`:`hex`;try{return u(`sha256`).update(e).digest(n)}catch{return``}},truncate=(e,t,n=`...`)=>{if(o(e)||typeof e!=`string`)return``;if(o(t)||typeof t!=`number`||t<0)return e;let r=typeof n==`string`?n:`...`;if(e.length<=t)return e;let i=Math.max(0,t-r.length);return i<=0?e.slice(0,t):e.slice(0,i)+r},urlParam=(e,t)=>{if(o(e)||typeof e!=`string`||o(t)||typeof t!=`string`)return null;try{return new URL(e).searchParams.get(t)}catch{return null}},zipObject=(e,t)=>{if(o(e)||!Array.isArray(e)||o(t)||!Array.isArray(t))return{};let n=Math.min(e.length,t.length),r=[];for(let i=0;i<n;i++){let n=e[i];typeof n==`string`&&r.push([n,t[i]])}return Object.fromEntries(r)},createExpressionHandler=(e=()=>new l.Jexl)=>{let s=e();return s.addFunction(`nextAnniversary`,(e,n)=>t({initialDate:e,format:n})),s.addFunction(`yearsElapsed`,(e,t,r)=>n({startDate:e,endDate:r,format:t})),s.addFunction(`hasPassed`,(e,t,n)=>r({date:e,yearsToAdd:n,format:t})),s.addFunction(`now`,()=>new Date().toISOString()),s.addFunction(`includes`,(e,t)=>o(e)||!Array.isArray(e)||e.length===0||o(t)?!1:Array.isArray(t)?t.every(t=>e.includes(t)):e.includes(t)),s.addFunction(`includesSome`,(e,t)=>o(e)||!Array.isArray(e)||e.length===0||o(t)?!1:Array.isArray(t)?t.some(t=>e.includes(t)):e.includes(t)),s.addFunction(`present`,e=>c(e)),s.addFunction(`missing`,e=>o(e)),s.addFunction(`keys`,e=>o(e)?[]:typeof e==`object`&&!Array.isArray(e)?Object.keys(e):[]),s.addFunction(`values`,e=>o(e)?[]:typeof e==`object`&&!Array.isArray(e)?Object.values(e):[]),s.addFunction(`decodeBase64`,e=>{if(o(e)||typeof e!=`string`)return``;try{return i(e)}catch{return``}}),s.addFunction(`encodeBase64`,e=>{if(o(e)||typeof e!=`string`)return``;try{return a(e)}catch{return``}}),s.addFunction(`deltaFromNowMs`,(e,t)=>{let n=Date.now(),r;if(typeof e==`number`)r=t===`seconds`?e*1e3:e;else if(typeof e==`string`)r=t===`timestamp`?parseInt(e,10):t===`seconds`?parseFloat(e)*1e3:new Date(e).getTime();else throw Error(`Unsupported date input type`);return r-n}),s.addBinaryOp(`??`,0,(e,t)=>o(e)?t:o(t)?e:e??t),s.addFunction(`capitalize`,capitalize),s.addFunction(`hmacSha256`,hmacSha256),s.addFunction(`md5`,md5),s.addFunction(`sha256`,sha256),s.addFunction(`decodeUri`,decodeUri),s.addFunction(`dedupe`,dedupe),s.addFunction(`groupBy`,groupBy),s.addFunction(`join`,join),s.addFunction(`min`,min),s.addFunction(`padStart`,padStart),s.addFunction(`zipObject`,zipObject),s.addFunction(`reduce`,reduce),s.addFunction(`regexMatch`,regexMatch),s.addFunction(`replace`,replace),s.addFunction(`truncate`,truncate),s.addFunction(`urlParam`,urlParam),s},m=/\${([^}]+)}/g,cleanExpression=e=>e.replace(/\$\./g,``).trim(),extractLeadingFunctionCall=e=>{let t=e.match(/^\w+\(/);if(!t)return null;let n=0;for(let r=t[0].length-1;r<e.length;r++)if(e[r]===`(`?n++:e[r]===`)`&&n--,n===0)return e.slice(r+1).trimStart().startsWith(`?`)?e.slice(0,r+1):null;return null},tryCompile=(e,t)=>{try{return e.compile(t)}catch{return null}},compileExpression=(e,t)=>{let n=tryCompile(e,t);if(n)return n;let r=extractLeadingFunctionCall(t);return r?tryCompile(e,`(${r})${t.slice(r.length)}`):null},extractExpressionBetweenDoubleCurlyBraces=e=>{if(e.startsWith(`{{`)&&e.endsWith(`}}`))return e.slice(2,-2)},evaluateJsonPath=(e,t)=>{try{if(!e.startsWith(`$`))throw Error(`JSONPath expression must start with '$': ${e}`);if(e.includes(`$_`)||e.match(/\$[^.[]/g)||e.includes(`[`)&&!e.includes(`]`)||e.includes(` `)&&!e.includes(`[`))throw Error(`Invalid JSONPath expression: ${e}`);let n=f({path:e,json:t});return n.length===0?void 0:n.length===1?n[0]:n}catch{throw Error(`Invalid JSONPath expression: ${e}`)}},replaceInterpolation=(e,t,n)=>e.replace(t,String(n)),handleSingleInterpolation=(e,t,n,r)=>{let i=e.path.trim();if(!i)return r;try{let a=compileExpression(t,i);if(a){let t=a.evalSync(n);if(t!==void 0)return replaceInterpolation(r,e.toReplace,t)}let o=evaluateJsonPathIncremental(`$.${i}`,n).value;return c(o)?replaceInterpolation(r,e.toReplace,o):r}catch{return r}},evaluateStringInterpolations=(e,t,n)=>{let r=e.match(m);if(!r)return;let i=r.length,a=Array(i);for(let e=0;e<i;e++)a[e]={toReplace:r[e],path:r[e].slice(2,-1)};return a.reduce((e,r)=>handleSingleInterpolation(r,n,t,e),String(e))},handleSegmentPathError=(e,t,n,r)=>{if(Array.isArray(t)){let e=parseInt(n,10);if(!isNaN(e)&&(e<0||e>=t.length))return{value:void 0,error:`Invalid array index '${n}' at '${r}'`,availableKeys:t.map((e,t)=>t.toString())}}return s(t)?{value:void 0,error:`Key '${n}' not found at '${r}'`,availableKeys:Object.keys(t)}:{value:void 0,error:`${e} at '${r}'`,availableKeys:[]}},handleJsonPathSegments=(e,t)=>{if(e[0]!==`$`)return{value:void 0,error:`JSON path must start with $`};let n=t,r=`$`;for(let t=1;t<e.length;t++){let i=e[t],a=i.startsWith(`[`)?`${r}${i}`:`${r}.${i}`;if(Array.isArray(n)){let e=parseInt(i,10);if(isNaN(e)||e<0||e>=n.length)return handleSegmentPathError(`Invalid array index`,n,i,r);n=n[e],r=a}else if(s(n)){if(!Object.prototype.hasOwnProperty.call(n,i))return handleSegmentPathError(`Key not found`,n,i,r);n=n[i],r=a}else return{value:void 0,error:`Cannot access '${i}' at '${r}' - parent is not an object`,availableKeys:[]}}return{value:n}},evaluateJsonPathIncremental=(e,t)=>{let n=/(\.\.)|(\[\*\])|(\[\?\()|(\[\d+:\d+\])/;try{if(n.test(e)){let n=evaluateJsonPath(e,t);return n===void 0?{value:void 0,error:`Invalid or empty JSONPath: '${e}'`}:{value:n}}return handleJsonPathSegments((e.match(/\$|(?:\['([^']+)'\])|(?:\["([^"]+)"\])|\[\d+\]|[^[\].]+/g)||[]).map(e=>e.replace(/^\['([^']+)'\]$/,`$1`).replace(/^\["([^"]+)"\]$/,`$1`).replace(/^\[(\d+)\]$/,`$1`)),t)}catch(e){return{value:void 0,error:`Something went wrong with evaluation of JSON path: ${String(e)}`}}},handleIncrementalJsonPath=(e,t)=>{let n=evaluateJsonPathIncremental(e,t);if(n.error)throw Error(`${n.error}${n.availableKeys?.length?`. Available keys: ${n.availableKeys.join(`, `)}`:``}`);return n.value},handleNormalJsonPath=(e,t)=>{try{return evaluateJsonPath(e,t)}catch{throw Error(`Invalid JSON path: "${e}"`)}},evaluateExpression=(e,t,n)=>{let r=e?.trim();if(r==null||r===``)throw Error(`Empty expression`);let i=s(t)?t:{},a=createExpressionHandler();a.addTransform(`key`,e=>typeof e!=`string`||!Object.prototype.hasOwnProperty.call(i,e)?null:i[e]);let o=extractExpressionBetweenDoubleCurlyBraces(r),c=cleanExpression(o??r),l=evaluateStringInterpolations(c,i,a);if(l)return l;if(!o&&r.startsWith(`$`))return n?.incrementalJsonPath?handleIncrementalJsonPath(r,i):handleNormalJsonPath(r,i);if(!l&&!o)return e;let u=compileExpression(a,c);if(!u||c===`.`)throw Error(`Invalid expression: "${r}"`);try{return u.evalSync(i)}catch{return}},safeEvaluateExpression=(e,t)=>{try{return evaluateExpression(e,t)}catch{return null}},safeEvaluateRecord=(e,t)=>{let evaluateValue=e=>Array.isArray(e)?e.map(evaluateValue):typeof e==`object`&&e?safeEvaluateRecord(e,t):typeof e==`string`?safeEvaluateExpression(e,t):e;return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,evaluateValue(t)]))},isValidExpression=e=>{try{return evaluateExpression(e),!0}catch{return!1}};export{evaluateExpression as evaluate,isValidExpression,safeEvaluateExpression as safeEvaluate,safeEvaluateRecord};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackone/expressions",
3
- "version": "0.26.0",
3
+ "version": "0.28.0",
4
4
  "description": "",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",