@stackone/expressions 0.24.0 → 0.25.1

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
@@ -704,6 +704,34 @@ Extracts a value from a string using a regular expression pattern. Returns the s
704
704
  "{{regexMatch($.linkHeader, 'after=([^&>]+)', 1)}}";
705
705
  ```
706
706
 
707
+ ###### urlParam(url, paramName)
708
+
709
+ Extracts a query parameter value from a URL string. Useful for parsing pagination URLs where the next page token is embedded in a full URL.
710
+
711
+ - `url` (string): The URL string to parse
712
+ - `paramName` (string): The name of the query parameter to extract
713
+ - Returns: the parameter value as a string, or null if not found or inputs are invalid
714
+
715
+ ```js
716
+ // Extract page number from pagination URL
717
+ "{{urlParam('https://api.example.com/v1/items?page=2&limit=10', 'page')}}"; // Returns "2"
718
+
719
+ // Extract cursor from next page URL
720
+ "{{urlParam('https://api.example.com/v1/items?cursor=eyJpZCI6MTIzfQ==&limit=50', 'cursor')}}"; // Returns "eyJpZCI6MTIzfQ=="
721
+
722
+ // Extract offset parameter
723
+ "{{urlParam('https://api.example.com/v1/items?offset=100&limit=25', 'offset')}}"; // Returns "100"
724
+
725
+ // Returns null when parameter doesn't exist
726
+ "{{urlParam('https://api.example.com?page=1', 'missing')}}"; // Returns null
727
+
728
+ // From context variable (common pagination use case)
729
+ "{{urlParam($.pagination.next_page, 'page')}}";
730
+
731
+ // Use in conditional for pagination
732
+ "{{urlParam(nextUrl, 'page') != null ? urlParam(nextUrl, 'page') : null}}";
733
+ ```
734
+
707
735
  For more information on the JEXL syntax, refer to the [JEXL Syntax documentation](https://commons.apache.org/proper/commons-jexl/reference/syntax.html).
708
736
 
709
737
  ### 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=`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},d=`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},f=`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)},p=`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)},m=`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)},h=`reduce`,g=[`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(!g.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))),_=`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}},v=`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)},y=`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},b=`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(`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},x=/\${([^}]+)}/g,cleanExpression=e=>e.replace(/\$\./g,``).trim(),compileExpression=(e,t)=>{try{return e.compile(t)}catch{return 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(x);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(`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=`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},d=`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},f=`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)},p=`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)},m=`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)},h=`reduce`,g=[`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(!g.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))),_=`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}},v=`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)},y=`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},b=`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}},x=`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(`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},S=/\${([^}]+)}/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(S);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;
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),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},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(`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},f=/\${([^}]+)}/g,cleanExpression=e=>e.replace(/\$\./g,``).trim(),compileExpression=(e,t)=>{try{return e.compile(t)}catch{return 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{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),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(`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};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackone/expressions",
3
- "version": "0.24.0",
3
+ "version": "0.25.1",
4
4
  "description": "",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",