UNPKG

@jsonurl/jsonurl

Version:

JSON->URL defines a text format for the JSON data model suitable for use within a URL/URI (as described by RFC3986).

7 lines (6 loc) 14.9 kB
/*! * jsonurl.js v1.1.8 * (c) 2024 David MacCormack * Released under the MIT License. */ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).JsonURL=t()}(this,(function(){"use strict";const e="JSON->URL: expected literal value",t="JSON->URL: unexpected character",r="JSON->URL: unexpected end of text inside composite",s="JSON->URL: unexpected text after composite",i="JSON->URL: the empty string is not allowed",n="JSON->URL: invalid escape sequence",a="JSON->URL: invalid percent-encoded sequence",o="JSON->URL: expected object value";function p(e,t){return void 0===t?e:e+" at position "+t}const c=16,u=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,6,6,48,10,20,20,6,6,20,6,6,6,6,6,6,6,6,6,6,6,6,6,20,6,0,48,0,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,0,0,0,0,6,0,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,0,0,0,6,0];function h(e){return e>127?0:u[e]}class l{constructor(e){this.setOrDefault(e,"allowEmptyUnquotedValues"),this.setOrDefault(e,"allowEmptyUnquotedKeys"),this.setOrDefault(e,"AQF"),this.setOrDefault(e,"coerceNullToEmptyString"),this.setOrDefault(e,"ignoreNullArrayMembers"),this.setOrDefault(e,"ignoreNullObjectMembers"),this.setOrDefault(e,"impliedArray"),this.setOrDefault(e,"impliedObject"),this.setOrDefault(e,"impliedStringLiterals"),this.setOrDefault(e,"noEmptyComposite"),this.setOrDefault(e,"wwwFormUrlEncoded")}setOrDefault(e,t,r){void 0!==e&&t in e?t in this||(this[t]=e[t]):void 0===r||t in this||(this[t]=r)}setOverride(e,t){void 0!==e&&t in e&&(this[t]=e[t])}setOrDefaultInt(e,t,r){this.setOrDefault(e,t,void 0===r?r:parseInt(r))}isPresentAndTrue(e){return e in this&&this[e]}}class d extends l{constructor(e,t){super(e),this.setOrDefault(e,"emptyValue"),this.setOrDefault(t,"emptyValue",{}),this.setOverride(e,"getMissingValue"),this.setOrDefaultInt(e,"maxParseChars"),this.setOrDefaultInt(t,"maxParseChars",32768),this.setOrDefaultInt(e,"maxParseDepth"),this.setOrDefaultInt(t,"maxParseDepth",32),this.setOrDefaultInt(e,"maxParseValues"),this.setOrDefaultInt(t,"maxParseValues",4096),this.setOrDefault(e,"nullValue"),this.setOrDefault(t,"nullValue",null)}getMissingValue(e,t){throw new SyntaxError(p(o,t))}}class f extends l{constructor(e){super(e);const t=!(void 0===e||!("impliedStringLiterals"in e)||!e.impliedStringLiterals)||void 0;this.setOrDefault(e,"allowEmptyUnquotedValues",t),this.setOrDefault(e,"allowEmptyUnquotedKeys",t),this.setOrDefault(e,"callFunctions"),this.setOrDefault(e,"isImplied"),this.setOrDefault(e,"ignoreNullArrayMembers",t),this.setOrDefault(e,"ignoreNullObjectMembers",t),this.setOrDefault(e,"ignoreUndefinedArrayMembers",t),this.setOrDefault(e,"ignoreUndefinedObjectMembers",t),this.isImplied=this.isImplied||this.impliedArray||this.impliedObject}}const w=/\+/g,m=/(![\s\S]?)/g,y=40,x=41,O=44,A=58,E=38,S=48,V=65,b=97,g=new Array(111);g[33]="!",g[40]="(",g[41]=")",g[43]="+",g[44]=",",g[45]=",",g[S]="0",g[S+1]="1",g[S+2]="2",g[S+3]="3",g[S+4]="4",g[S+5]="5",g[S+6]="6",g[S+7]="7",g[S+8]="8",g[S+9]="9",g[58]=":",g[116]="t",g[102]="f",g[110]="n";const D="",L="!e";function C(e,t){switch(t){case S:return 0;case S+1:return 1;case S+2:return 2;case S+3:return 3;case S+4:return 4;case S+5:return 5;case S+6:return 6;case S+7:return 7;case S+8:return 8;case S+9:return 9;case V:case b:return 10;case V+1:case b+1:return 11;case V+2:case b+2:return 12;case V+3:case b+3:return 13;case V+4:case b+4:return 14;case V+5:case b+5:return 15;default:throw new SyntaxError(p(a,e))}}function U(e){if(e.coerceNullToEmptyString)return function(e,t){const r=e.allowEmptyUnquotedValues;if(r)return D;if(e.AQF)return L;if(e.impliedStringLiterals)throw new SyntaxError(i);return"''"}(e);if(e.impliedStringLiterals)throw new SyntaxError("JSON->URL: can not represent null with implied strings");return"null"}class v{constructor(e,t,r,s){this.text=e,this.pos=this.markPos=t,this.end=r,this.options=s}skipAmps(e=!1){const t=this.text,r=this.end;let s=this.pos;if(e)for(;s<r&&t.charCodeAt(s)===E;)s++;else if(s<r&&t.charCodeAt(s)===E){for(s++;s<r&&t.charCodeAt(s)===E;s++);s!==r&&s--}this.pos=s}structChar(e=!1){if(this.options.wwwFormUrlEncoded){const t=this.text.charCodeAt(this.pos);switch(t){case E:case 61:if(e)return;return this.pos++,t}}const t=this.pos,r=this.ordinal();switch(r){case O:case A:if(e)return void(this.pos=t);case y:case x:return r;default:return void(this.pos=t)}}ordinal(e){return void 0!==e?this.text.charCodeAt(e):this.text.charCodeAt(this.pos++)}accept(e){const t=this.pos;return this.ordinal()===e||(this.pos=t,!1)}acceptPlus(){return 43==this.text.charCodeAt(this.pos)&&(this.pos++,!0)}done(){return this.end<=this.pos}validateLiteral(e,r){const s=this.text,i=this.end;for(;e<i;e++){switch(h(s.charCodeAt(e))&r){case 0:throw new SyntaxError(p(t,e));case c:return e;case 8:return e+1;default:continue}}}findLiteralEnd(){const e=this.text,t=this.end;let r=this.pos;const s=39===e.charCodeAt(r);s&&r++;const i=s?28:18;if(r=this.validateLiteral(r,i),void 0!==r)return r;if(s)throw new SyntaxError(p("JSON->URL: quoted string still open",r));return t}isEmptyObject(){if(this.options.noEmptyComposite){const e=this.pos;if(!this.accept(A))return!1;const t=this.pos,r=this.accept(x);return this.pos=r?t:e,r}return!1}parseLiteral(e){const t=this.pos,r=this.options,s=this.findLiteralEnd();if(void 0===e&&(e=this.ordinal(s)==A),s<=t){return function(e,t){if(t)return D;throw new SyntaxError(p(i,e))}(t,e?this.options.allowEmptyUnquotedKeys:this.options.allowEmptyUnquotedValues)}if(!0===r.impliedStringLiterals)return this.parseStringLiteral(s,!0);const n=this.parseTrueFalseNull(s,e);if(void 0!==n)return n;const a=this.parseNumberLiteral(s,e);return void 0!==a?a:this.parseStringLiteral(s,!1)}parseDigits(e){let t,r=!1;for(;this.pos<e;)switch(this.ordinal()){case S:case S+1:case S+2:case S+3:case S+4:case S+5:case S+6:case S+7:case S+8:case S+9:t=this.pos,r=!0;continue;default:return this.pos=t,r}return this.pos=t,r}parseExponentValue(e){return!(e<=this.pos)&&(this.acceptPlus()||this.accept(45),this.parseDigits(e))}parseExponent(e){const t=this.pos;switch(this.ordinal()){case 69:case 101:if(this.parseExponentValue(e))return!0}return this.pos=t,!1}parseFraction(e){const t=this.pos;return!(e<=t)&&(!(!this.accept(46)||!this.parseDigits(e))||(this.pos=t,!1))}parseInteger(e){return!(e<=this.pos)&&(!!this.accept(S)||this.parseDigits(e))}parseNumberLiteral(e,t){const r=this.text,s=this.pos;if(this.accept(45),this.parseInteger(e)&&(this.parseFraction(e),this.parseExponent(e),this.pos===e)){const i=decodeURIComponent(r.substring(s,e));return t?i:Number(i)}this.pos=s}parseStringLiteral(e,t){const r=this.text,s=this.pos;let i=t||39!==r.charCodeAt(s)?r.substring(s,e):r.substring(s+1,e-1);return i=decodeURIComponent(i.replace(w," ")),this.pos=e,i}parseTrueFalseNull(e,t){const r=this.text,s=this.pos;let i,n,a,o,p;switch(e-s){case 4:if(i=r.charCodeAt(s),n=r.charCodeAt(s+1),a=r.charCodeAt(s+2),o=r.charCodeAt(s+3),116===i&&114===n&&117===a&&101===o)return this.pos=e,!t||"true";if(110===i&&117===n&&108===a&&108===o)return this.pos=e,t?"null":this.newNullValue();break;case 5:if(i=r.charCodeAt(s),n=r.charCodeAt(s+1),a=r.charCodeAt(s+2),o=r.charCodeAt(s+3),p=r.charCodeAt(s+4),102===i&&n===b&&108===a&&115===o&&101===p)return this.pos=e,!!t&&"false"}}newEmptyValue(){const e=this.options;if(e.noEmptyComposite)return[];const t=e.emptyValue;return"function"==typeof t?t():t}newNullValue(){const e=this.options;let t=e.nullValue;return"function"==typeof t&&(t=t()),null==t&&e.coerceNullToEmptyString&&(t=D),t}}class N extends v{constructor(e,t,r,s){super(e,t,r,s)}ordinal(e){const t=e||this.pos,r=this.text.charCodeAt(t);let s,i;return 37===r?(s=function(e,t,r){if(r<=t+1)throw new SyntaxError(p(a,t));return C(t,e.charCodeAt(t))<<4|C(t,e.charCodeAt(t+1))}(this.text,t+1,this.end),i=3):(s=r,i=1),void 0===e&&(this.pos+=i),s}findLiteralEnd(){const e=this.end,r=this.pos,s=this.text;let i=r;for(;;){if(e<=this.pos)return this.pos=r,e;switch(50&h(s.charCodeAt(this.pos))){case 48:if(this.options.wwwFormUrlEncoded)return i=this.pos,this.pos=r,i;case 0:throw new SyntaxError(p(t,i))}switch(this.ordinal()){case y:case x:case A:case O:return this.pos=r,i;case 33:if(this.pos===e)throw new SyntaxError(p(n,i));this.ordinal(),i=this.pos;break;default:i=this.pos}}}parseStringLiteral(e){const t=this.text,r=this.pos,s=decodeURIComponent(t.substring(r,e).replace(w,(function(e,s){return 0!==s&&function(e,t){return 33===e.charCodeAt(t-1)||t>2&&37===e.charCodeAt(t-3)&&e.charCodeAt(t-2)===S+2&&e.charCodeAt(t-1)===S+1}(t,r+s)?"+":" "})));return this.pos=e,"!e"===s?D:s.replace(m,(function(e,t,s){if(2===e.length){const t=e.charCodeAt(1),r=g[t];if(void 0!==r)return r}throw new SyntaxError(p(n,r+s))}))}}class j extends Array{constructor(e){super(),this.limits=e,this.parseDepth=0}replaceAndPush(e,t,r){if(this[this.parseDepth]=t,++this.parseDepth>=this.limits.maxParseDepth)throw new Error(p("JSON->URL: MaxParseDepth exceeded",e));this.push(r)}replace(e){this[this.parseDepth]=e}depth(e=!1){return e&&(this.parseDepth--,this.pop()),this.parseDepth}}class P extends Array{constructor(e){super(),this.limits=e,this.numValues=0}popObjectValue(e){let t=this.pop(),r=this.pop(),s=this[this.length-1];return null===t&&e.isPresentAndTrue("ignoreNullObjectMembers")||(s[r]=t),s}popArrayValue(e){let t=this.pop(),r=this[this.length-1];return null===t&&e.isPresentAndTrue("ignoreNullArrayMembers")||r.push(t),r}checkValueLimit(e,t=1){if(this.numValues+=t,this.numValues>this.limits.maxParseValues+1)throw new Error(p("JSON->URL: MaxParseValues exceeded",e))}appendArrayValue(e,t,r=1){this.checkValueLimit(e,r),this.push(t)}}function R(e){for(;"function"==typeof e;)e=e();return e}function I(e,t,r,s){return"number"==typeof e?"number"!=typeof t&&(r=t):r=e,(r=R(r))instanceof d||(r=new d(r,s)),r}function J(e,t,r,s){return s.AQF?new N(e,t,r,s):new v(e,t,r,s)}function k(e,t){return"number"==typeof e?e:t}function F(i,n,a,c,u){if(void 0===i)return;c=I(n,a,c,u),i=String(i);const h=k(n,0),l=k(a,i.length);if(l<=h){if(void 0!==c.impliedArray)return c.impliedArray;if(void 0!==c.impliedObject)return c.impliedObject;throw new SyntaxError(p("JSON->URL: expected value",0))}if(l>c.maxParseChars)throw new Error("JSON->URL: MaxParseChars exceeded");const d=c.wwwFormUrlEncoded&&(c.impliedObject||c.impliedArray),f=new P(c),w=new j(c),m=J(i,h,l,c);if(void 0!==c.impliedObject)f.push(c.impliedObject),w.push(6);else if(void 0!==c.impliedArray)f.push(c.impliedArray),w.push(2);else{if(m.structChar(!0)!==y){const t=m.parseLiteral(!1);if(m.done())return t;throw new SyntaxError(p(e,0))}w.push(1)}for(d&&m.skipAmps(!0);;){if(m.done())throw new SyntaxError(p(r,m.pos));let i,n,a;switch(w[w.depth()]){case 1:switch(m.structChar(!0)){case y:f.appendArrayValue(m.pos,[]),w.replaceAndPush(m.pos,3,1);continue;case x:if(-1===w.depth(!0)){if(m.done())return m.newEmptyValue();throw new SyntaxError(p(s,m.pos))}if(f.appendArrayValue(m.pos,m.newEmptyValue()),0===w.depth()&&(d&&m.skipAmps(),m.done())){if(c.impliedArray)return f.popArrayValue(c);if(c.impliedObject)return f.popObjectValue(c);throw new SyntaxError(p(r,m.pos))}continue}switch(f.checkValueLimit(m.pos),n=m.isEmptyObject(),i=n?{}:m.parseLiteral(),a=m.pos,m.structChar()){case E:if(!c.wwwFormUrlEncoded||w.depth()>0)throw new SyntaxError(p(t,a));case O:w.replace(2),f.appendArrayValue(a,[]),f.push(i),f.popArrayValue(c);continue;case x:switch(n?f.push({}):f.appendArrayValue(a,[i]),w.depth(!0)){case-1:if(m.pos===l)return f[0];throw new SyntaxError(p(s,a));case 0:if(d&&m.skipAmps(),m.done()){if(c.impliedArray)return f.popArrayValue(c);if(c.impliedObject)return f.popObjectValue(c);throw new SyntaxError(p(r,a))}}continue;case 61:if(!c.wwwFormUrlEncoded||w.depth()>0)throw new SyntaxError(p(t,a));case A:w.replace(4),f.push({},i);continue;default:throw new SyntaxError(p(e,a))}case 2:if(m.accept(y)){w.replaceAndPush(m.pos,3,1);continue}if(f.checkValueLimit(m.pos),i=m.parseLiteral(!1),d&&m.skipAmps(),m.done()){if(0===w.depth()&&c.impliedArray)return f.push(i),f.popArrayValue(c);throw new SyntaxError(p(r,l))}w.replace(3),f.push(i);continue;case 3:switch(f.popArrayValue(c),m.structChar()){case E:if(!c.wwwFormUrlEncoded||w.depth()>0)throw new SyntaxError(p(t,m.pos));case O:w.replace(2);continue;case x:switch(w.depth(!0)){case-1:if(m.done()&&!c.impliedArray)return f[0];throw new SyntaxError(p(s,m.pos));case 0:if(d&&m.skipAmps(),m.done()){if(c.impliedArray)return f.popArrayValue(c);if(c.impliedObject)return f.popObjectValue(c);throw new SyntaxError(p(r,m.pos))}}continue}throw new SyntaxError(p("JSON->URL: expected comma or close paren",m.pos));case 4:if(m.accept(y)){w.replaceAndPush(m.pos,5,1);continue}if(f.checkValueLimit(m.pos),i=m.parseLiteral(!1),d&&m.skipAmps(),m.done()){if(0===w.depth()&&c.impliedObject)return f.push(i),f.popObjectValue(c);throw new SyntaxError(p(r,l))}w.replace(5),f.push(i);continue;case 5:switch(f.popObjectValue(c),a=m.pos,m.structChar()){case E:if(!c.wwwFormUrlEncoded||w.depth()>0)throw new SyntaxError(p(t,a));case O:w.replace(6);continue;case x:switch(w.depth(!0)){case-1:if(m.done()&&!c.impliedObject)return f[0];throw new SyntaxError(p(s,m.pos));case 0:if(d&&m.skipAmps(),m.done()){if(c.impliedArray)return f.popArrayValue(c);if(c.impliedObject)return f.popObjectValue(c);throw new SyntaxError(p(s,m.pos))}}continue}throw new SyntaxError(p("JSON->URL: expected comma, open paren, or close paren",m.pos));case 6:if(i=m.parseLiteral(!0),d&&m.skipAmps(),m.done()){if(c.impliedObject&&0==w.depth())return f.push(i,c.getMissingValue(i)),f.popObjectValue(c);throw new SyntaxError(p(r,l))}switch(m.structChar()){case 61:if(!c.wwwFormUrlEncoded||w.depth()>0)throw new SyntaxError(p(t,m.pos));case A:break;case E:if(!c.wwwFormUrlEncoded||w.depth()>0)throw new SyntaxError(p(t,m.pos));case O:if(c.impliedObject&&0==w.depth()){f.push(i,c.getMissingValue(i)),f.popObjectValue(c);continue}default:throw new SyntaxError(p(o,m.pos))}w.replace(4),f.push(i);continue;default:throw new SyntaxError(p("JSON->URL: internal error",m.pos))}}}return class{constructor(e){for(;"function"==typeof e;)e=e();void 0===e&&(e={}),this.maxParseDepth="number"==typeof e.maxParseDepth?parseInt(e.maxParseDepth):32,this.maxParseValues="number"==typeof e.maxParseValues?parseInt(e.maxParseValues):4096,this.maxParseChars="number"==typeof e.maxParseChars?parseInt(e.maxParseChars):32768,this.emptyValue=void 0===e.emptyValue?{}:e.emptyValue,this.nullValue=void 0===e.nullValue?null:e.nullValue}parseLiteral(e,t=0,r=void 0,s=!1,i){void 0!==e&&(e=String(e)),void 0===r&&(r=e.length);return J(e,t,r,I(i)).parseLiteral(s)}static parse(e,t,r,s){return F(e,t,r,s,void 0)}parse(e,t,r,s){return F(e,t,r,s,this)}static stringify(e,t){if(void 0!==e)return t=new f(R(t)),null===e?U(t):e.toJsonURLText(t,0)}}}));