From f7d221d9376d200d900defa90500d99c5388f73f Mon Sep 17 00:00:00 2001 From: Patrick Quist Date: Fri, 6 Jan 2023 16:13:40 +0100 Subject: [PATCH] Revert "Tsify rison.js (#4510)" (#4549) This reverts commit e1cc30941d68aed64440b1aa0172029b48d639a7. --- lib/common-utils.ts | 34 --- static/rison.js | 516 ++++++++++++++++++++++++++++++++++++++++++++ static/rison.ts | 456 --------------------------------------- static/url.ts | 5 +- 4 files changed, 518 insertions(+), 493 deletions(-) delete mode 100644 lib/common-utils.ts create mode 100644 static/rison.js delete mode 100644 static/rison.ts diff --git a/lib/common-utils.ts b/lib/common-utils.ts deleted file mode 100644 index 76aa049cf5a..00000000000 --- a/lib/common-utils.ts +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2022, Compiler Explorer Authors -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. - -export function isString(x: any): x is string { - return typeof x === 'string' || x instanceof String; -} - -// Object.keys is typed as returning :string[] for some reason -// This util is for cases where the key is a union of a few possible keys and we -// want the resulting array properly typed. -export function keys(o: Record): K[] { - return Object.keys(o) as K[]; -} diff --git a/static/rison.js b/static/rison.js new file mode 100644 index 00000000000..7945668c806 --- /dev/null +++ b/static/rison.js @@ -0,0 +1,516 @@ +/* eslint-disable */ +// Taken from https://github.com/Nanonid/rison at e64af6c096fd30950ec32cfd48526ca6ee21649d (Jun 9, 2017) +// Uses CommonJS, AMD or browser globals to create a module. +// Based on: https://github.com/umdjs/umd/blob/master/commonjsStrict.js +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['exports'], factory); + } else if (typeof exports === 'object') { + // CommonJS + factory(exports); + } else { + // Browser globals + factory((root.rison = {})); + } +})(this, function (exports) { + var rison = exports; + + ////////////////////////////////////////////////// + // + // the stringifier is based on + // http://json.org/json.js as of 2006-04-28 from json.org + // the parser is based on + // http://osteele.com/sources/openlaszlo/json + // + + if (typeof rison == 'undefined') window.rison = {}; + + /** + * rules for an uri encoder that is more tolerant than encodeURIComponent + * + * encodeURIComponent passes ~!*()-_.' + * + * we also allow ,:@$/ + * + */ + rison.uri_ok = { + // ok in url paths and in form query args + '~': true, + '!': true, + '*': true, + '(': true, + ')': true, + '-': true, + _: true, + '.': true, + ',': true, + ':': true, + '@': true, + $: true, + "'": true, + '/': true, + }; + + /* + * we divide the uri-safe glyphs into three sets + * - used by rison ' ! : ( ) , + * - not common in strings, reserved * @ $ & ; = + * + * we define as anything that's not forbidden + */ + + /** + * punctuation characters that are legal inside ids. + */ + // this var isn't actually used + //rison.idchar_punctuation = "_-./~"; + + (function () { + var l = []; + for (var hi = 0; hi < 16; hi++) { + for (var lo = 0; lo < 16; lo++) { + if (hi + lo === 0) continue; + var c = String.fromCharCode(hi * 16 + lo); + if (!/\w|[-_.\/~]/.test(c)) l.push('\\u00' + hi.toString(16) + lo.toString(16)); + } + } + /** + * characters that are illegal inside ids. + * and classes are illegal in ids. + * + */ + rison.not_idchar = l.join(''); + //idcrx = new RegExp('[' + rison.not_idchar + ']'); + //console.log('NOT', (idcrx.test(' ')) ); + })(); + //rison.not_idchar = " \t\r\n\"<>[]{}'!=:(),*@$;&"; + rison.not_idchar = " '!:(),*@$"; + + /** + * characters that are illegal as the start of an id + * this is so ids can't look like numbers. + */ + rison.not_idstart = '-0123456789'; + + (function () { + var idrx = '[^' + rison.not_idstart + rison.not_idchar + '][^' + rison.not_idchar + ']*'; + + rison.id_ok = new RegExp('^' + idrx + '$'); + + // regexp to find the end of an id when parsing + // g flag on the regexp is necessary for iterative regexp.exec() + rison.next_id = new RegExp(idrx, 'g'); + })(); + + /** + * this is like encodeURIComponent() but quotes fewer characters. + * + * @see rison.uri_ok + * + * encodeURIComponent passes ~!*()-_.' + * rison.quote also passes ,:@$/ + * and quotes " " as "+" instead of "%20" + */ + rison.quote = function (x) { + if (/^[-A-Za-z0-9~!*()_.',:@$\/]*$/.test(x)) return x; + + return encodeURIComponent(x) + .replace(/%2C/g, ',') + .replace(/%3A/g, ':') + .replace(/%40/g, '@') + .replace(/%24/g, '$') + .replace(/%2F/g, '/') + .replace(/%20/g, '+'); + }; + + // + // based on json.js 2006-04-28 from json.org + // license: http://www.json.org/license.html + // + // hacked by nix for use in uris. + // + + (function () { + var sq = { + // url-ok but quoted in strings + "'": true, + '!': true, + }, + enc = function (v) { + if (v && typeof v.toJSON === 'function') v = v.toJSON(); + var fn = s[typeof v]; + if (fn) return fn(v); + }, + s = { + array: function (x) { + var a = ['!('], + b, + f, + i, + l = x.length, + v; + for (i = 0; i < l; i += 1) { + v = enc(x[i]); + if (typeof v == 'string') { + if (b) { + a[a.length] = ','; + } + a[a.length] = v; + b = true; + } + } + a[a.length] = ')'; + return a.join(''); + }, + boolean: function (x) { + if (x) return '!t'; + return '!f'; + }, + null: function () { + return '!n'; + }, + number: function (x) { + if (!isFinite(x)) return '!n'; + // strip '+' out of exponent, '-' is ok though + return String(x).replace(/\+/, ''); + }, + object: function (x) { + if (x) { + if (x instanceof Array) { + return s.array(x); + } + // WILL: will this work on non-Firefox browsers? + if (typeof x.__prototype__ === 'object' && typeof x.__prototype__.encode_rison !== 'undefined') + return x.encode_rison(); + + var a = ['('], + b, + i, + v, + k, + ki, + ks = []; + for (i in x) ks[ks.length] = i; + ks.sort(); + for (ki = 0; ki < ks.length; ki++) { + i = ks[ki]; + v = enc(x[i]); + if (typeof v == 'string') { + if (b) { + a[a.length] = ','; + } + k = isNaN(parseInt(i)) ? s.string(i) : s.number(i); + a.push(k, ':', v); + b = true; + } + } + a[a.length] = ')'; + return a.join(''); + } + return '!n'; + }, + string: function (x) { + if (x === '') return "''"; + + if (rison.id_ok.test(x)) return x; + + x = x.replace(/(['!])/g, function (a, b) { + if (sq[b]) return '!' + b; + return b; + }); + return "'" + x + "'"; + }, + undefined: function () { + // ignore undefined just like JSON + return; + }, + }; + + /** + * rison-encode a javascript structure + * + * implemementation based on Douglas Crockford's json.js: + * http://json.org/json.js as of 2006-04-28 from json.org + * + */ + rison.encode = function (v) { + return enc(v); + }; + + /** + * rison-encode a javascript object without surrounding parens + * + */ + rison.encode_object = function (v) { + if (typeof v != 'object' || v === null || v instanceof Array) + throw new Error('rison.encode_object expects an object argument'); + var r = s[typeof v](v); + return r.substring(1, r.length - 1); + }; + + /** + * rison-encode a javascript array without surrounding parens + * + */ + rison.encode_array = function (v) { + if (!(v instanceof Array)) throw new Error('rison.encode_array expects an array argument'); + var r = s[typeof v](v); + return r.substring(2, r.length - 1); + }; + + /** + * rison-encode and uri-encode a javascript structure + * + */ + rison.encode_uri = function (v) { + return rison.quote(s[typeof v](v)); + }; + })(); + + // + // based on openlaszlo-json and hacked by nix for use in uris. + // + // Author: Oliver Steele + // Copyright: Copyright 2006 Oliver Steele. All rights reserved. + // Homepage: http://osteele.com/sources/openlaszlo/json + // License: MIT License. + // Version: 1.0 + + /** + * parse a rison string into a javascript structure. + * + * this is the simplest decoder entry point. + * + * based on Oliver Steele's OpenLaszlo-JSON + * http://osteele.com/sources/openlaszlo/json + */ + rison.decode = function (r) { + var errcb = function (e) { + throw Error('rison decoder error: ' + e); + }; + var p = new rison.parser(errcb); + return p.parse(r); + }; + + /** + * parse an o-rison string into a javascript structure. + * + * this simply adds parentheses around the string before parsing. + */ + rison.decode_object = function (r) { + return rison.decode('(' + r + ')'); + }; + + /** + * parse an a-rison string into a javascript structure. + * + * this simply adds array markup around the string before parsing. + */ + rison.decode_array = function (r) { + return rison.decode('!(' + r + ')'); + }; + + /** + * construct a new parser object for reuse. + * + * @constructor + * @class A Rison parser class. You should probably + * use rison.decode instead. + * @see rison.decode + */ + rison.parser = function (errcb) { + this.errorHandler = errcb; + }; + + /** + * a string containing acceptable whitespace characters. + * by default the rison decoder tolerates no whitespace. + * to accept whitespace set rison.parser.WHITESPACE = " \t\n\r\f"; + */ + rison.parser.WHITESPACE = ''; + + // expose this as-is? + rison.parser.prototype.setOptions = function (options) { + if (options['errorHandler']) this.errorHandler = options.errorHandler; + }; + + /** + * parse a rison string into a javascript structure. + */ + rison.parser.prototype.parse = function (str) { + this.string = str; + this.index = 0; + this.message = null; + var value = this.readValue(); + if (!this.message && this.next()) + value = this.error("unable to parse string as rison: '" + rison.encode(str) + "'"); + if (this.message && this.errorHandler) this.errorHandler(this.message, this.index); + return value; + }; + + rison.parser.prototype.error = function (message) { + if (typeof console != 'undefined') console.log('rison parser error: ', message); + this.message = message; + return undefined; + }; + + rison.parser.prototype.readValue = function () { + var c = this.next(); + var fn = c && this.table[c]; + + if (fn) return fn.apply(this); + + // fell through table, parse as an id + + var s = this.string; + var i = this.index - 1; + + // Regexp.lastIndex may not work right in IE before 5.5? + // g flag on the regexp is also necessary + rison.next_id.lastIndex = i; + var m = rison.next_id.exec(s); + + // console.log('matched id', i, r.lastIndex); + + if (m.length > 0) { + var id = m[0]; + this.index = i + id.length; + return id; // a string + } + + if (c) return this.error("invalid character: '" + c + "'"); + return this.error('empty expression'); + }; + + rison.parser.parse_array = function (parser) { + var ar = []; + var c; + while ((c = parser.next()) !== ')') { + if (!c) return parser.error("unmatched '!('"); + if (ar.length) { + if (c !== ',') parser.error("missing ','"); + } else if (c === ',') { + return parser.error("extra ','"); + } else --parser.index; + var n = parser.readValue(); + if (typeof n == 'undefined') return undefined; + ar.push(n); + } + return ar; + }; + + rison.parser.bangs = { + t: true, + f: false, + n: null, + '(': rison.parser.parse_array, + }; + + rison.parser.prototype.table = { + '!': function () { + var s = this.string; + var c = s.charAt(this.index++); + if (!c) return this.error('"!" at end of input'); + var x = rison.parser.bangs[c]; + if (typeof x == 'function') { + return x.call(null, this); + } else if (typeof x == 'undefined') { + return this.error('unknown literal: "!' + c + '"'); + } + return x; + }, + '(': function () { + var o = {}; + var c; + var count = 0; + while ((c = this.next()) !== ')') { + if (count) { + if (c !== ',') this.error("missing ','"); + } else if (c === ',') { + return this.error("extra ','"); + } else --this.index; + var k = this.readValue(); + if (typeof k == 'undefined') return undefined; + if (this.next() !== ':') return this.error("missing ':'"); + var v = this.readValue(); + if (typeof v == 'undefined') return undefined; + o[k] = v; + count++; + } + return o; + }, + "'": function () { + var s = this.string; + var i = this.index; + var start = i; + var segments = []; + var c; + while ((c = s.charAt(i++)) !== "'") { + //if (i == s.length) return this.error('unmatched "\'"'); + if (!c) return this.error('unmatched "\'"'); + if (c === '!') { + if (start < i - 1) segments.push(s.slice(start, i - 1)); + c = s.charAt(i++); + if ("!'".indexOf(c) >= 0) { + segments.push(c); + } else { + return this.error('invalid string escape: "!' + c + '"'); + } + start = i; + } + } + if (start < i - 1) segments.push(s.slice(start, i - 1)); + this.index = i; + return segments.length === 1 ? segments[0] : segments.join(''); + }, + // Also any digit. The statement that follows this table + // definition fills in the digits. + '-': function () { + var s = this.string; + var i = this.index; + var start = i - 1; + var state = 'int'; + var permittedSigns = '-'; + var transitions = { + 'int+.': 'frac', + 'int+e': 'exp', + 'frac+e': 'exp', + }; + do { + var c = s.charAt(i++); + if (!c) break; + if ('0' <= c && c <= '9') continue; + if (permittedSigns.indexOf(c) >= 0) { + permittedSigns = ''; + continue; + } + state = transitions[state + '+' + c.toLowerCase()]; + if (state === 'exp') permittedSigns = '-'; + } while (state); + this.index = --i; + s = s.slice(start, i); + if (s === '-') return this.error('invalid number'); + return Number(s); + }, + }; + // copy table['-'] to each of table[i] | i <- '0'..'9': + (function (table) { + for (var i = 0; i <= 9; i++) table[String(i)] = table['-']; + })(rison.parser.prototype.table); + + // return the next non-whitespace character, or undefined + rison.parser.prototype.next = function () { + var c; + var s = this.string; + var i = this.index; + do { + if (i === s.length) return undefined; + c = s.charAt(i++); + } while (rison.parser.WHITESPACE.indexOf(c) >= 0); + this.index = i; + return c; + }; + + // End of UMD module wrapper +}); diff --git a/static/rison.ts b/static/rison.ts deleted file mode 100644 index 735dceaddcf..00000000000 --- a/static/rison.ts +++ /dev/null @@ -1,456 +0,0 @@ -// Based on https://github.com/Nanonid/rison at e64af6c096fd30950ec32cfd48526ca6ee21649d (Jun 9, 2017) - -import {assert, unwrap} from './assert'; - -import {isString} from '../lib/common-utils'; - -////////////////////////////////////////////////// -// -// the stringifier is based on -// http://json.org/json.js as of 2006-04-28 from json.org -// the parser is based on -// http://osteele.com/sources/openlaszlo/json -// - -/* - * we divide the uri-safe glyphs into three sets - * - used by rison ' ! : ( ) , - * - not common in strings, reserved * @ $ & ; = - * - * we define as anything that's not forbidden - */ - -/** - * punctuation characters that are legal inside ids. - */ -// this var isn't actually used -//rison.idchar_punctuation = "_-./~"; - -const not_idchar = " '!:(),*@$"; - -/** - * characters that are illegal as the start of an id - * this is so ids can't look like numbers. - */ -const not_idstart = '-0123456789'; - -const [id_ok, next_id] = (() => { - const _idrx = '[^' + not_idstart + not_idchar + '][^' + not_idchar + ']*'; - return [ - new RegExp('^' + _idrx + '$'), - // regexp to find the end of an id when parsing - // g flag on the regexp is necessary for iterative regexp.exec() - new RegExp(_idrx, 'g'), - ]; -})(); - -/** - * this is like encodeURIComponent() but quotes fewer characters. - * - * @see rison.uri_ok - * - * encodeURIComponent passes ~!*()-_.' - * rison.quote also passes ,:@$/ - * and quotes " " as "+" instead of "%20" - */ -export function quote(x: string) { - if (/^[-A-Za-z0-9~!*()_.',:@$/]*$/.test(x)) return x; - - return encodeURIComponent(x) - .replace(/%2C/g, ',') - .replace(/%3A/g, ':') - .replace(/%40/g, '@') - .replace(/%24/g, '$') - .replace(/%2F/g, '/') - .replace(/%20/g, '+'); -} - -// -// based on json.js 2006-04-28 from json.org -// license: http://www.json.org/license.html -// -// hacked by nix for use in uris. -// -// url-ok but quoted in strings -const string_table = { - "'": true, - '!': true, -}; - -class Encoders { - static array(x: JSONValue[]) { - const a = ['!(']; - let b; - let i; - const l = x.length; - let v; - for (i = 0; i < l; i += 1) { - v = enc(x[i]); - if (typeof v == 'string') { - if (b) { - a[a.length] = ','; - } - a[a.length] = v; - b = true; - } - } - a[a.length] = ')'; - return a.join(''); - } - static boolean(x: boolean) { - if (x) return '!t'; - return '!f'; - } - static null() { - return '!n'; - } - static number(x: number) { - if (!isFinite(x)) return '!n'; - // strip '+' out of exponent, '-' is ok though - return String(x).replace(/\+/, ''); - } - static object(x: Record | null) { - if (x) { - // because typeof null === 'object' - if (x instanceof Array) { - return Encoders.array(x); - } - - const a = ['(']; - let b = false; - let i: string; - let v: string | undefined; - let k: string; - let ki: number; - const ks: string[] = []; - for (const i in x) ks[ks.length] = i; - ks.sort(); - for (ki = 0; ki < ks.length; ki++) { - i = ks[ki]; - v = enc(x[i]); - if (typeof v == 'string') { - if (b) { - a[a.length] = ','; - } - k = isNaN(parseInt(i)) ? Encoders.string(i) : Encoders.number(parseInt(i)); - a.push(k, ':', v); - b = true; - } - } - a[a.length] = ')'; - return a.join(''); - } - return '!n'; - } - static string(x: string) { - if (x === '') return "''"; - - if (id_ok.test(x)) return x; - - x = x.replace(/(['!])/g, function (a, b) { - if (string_table[b]) return '!' + b; - return b; - }); - return "'" + x + "'"; - } - static undefined() { - // ignore undefined just like JSON - return undefined; - } -} - -const encode_table: Record string | undefined> = { - array: Encoders.array, - object: Encoders.object, - boolean: Encoders.boolean, - string: Encoders.string, - number: Encoders.number, - null: Encoders.null, - undefined: Encoders.undefined, -}; - -function enc(v: JSONValue | (JSONValue & {toJSON?: () => string})) { - if (v && typeof v === 'object' && 'toJSON' in v && typeof v.toJSON === 'function') v = v.toJSON(); - if (typeof v in encode_table) { - return encode_table[typeof v](v); - } -} - -/** - * rison-encode a javascript structure - * - * implemementation based on Douglas Crockford's json.js: - * http://json.org/json.js as of 2006-04-28 from json.org - * - */ -export function encode(v: JSONValue | (JSONValue & {toJSON?: () => string})) { - return enc(v); -} - -/** - * rison-encode a javascript object without surrounding parens - * - */ -export function encode_object(v: JSONValue) { - if (typeof v != 'object' || v === null || v instanceof Array) - throw new Error('rison.encode_object expects an object argument'); - const r = unwrap(encode_table[typeof v](v)); - return r.substring(1, r.length - 1); -} - -/** - * rison-encode a javascript array without surrounding parens - * - */ -export function encode_array(v: JSONValue) { - if (!(v instanceof Array)) throw new Error('rison.encode_array expects an array argument'); - const r = unwrap(encode_table[typeof v](v)); - return r.substring(2, r.length - 1); -} - -/** - * rison-encode and uri-encode a javascript structure - * - */ -export function encode_uri(v: JSONValue) { - return quote(unwrap(encode_table[typeof v](v))); -} - -// -// based on openlaszlo-json and hacked by nix for use in uris. -// -// Author: Oliver Steele -// Copyright: Copyright 2006 Oliver Steele. All rights reserved. -// Homepage: http://osteele.com/sources/openlaszlo/json -// License: MIT License. -// Version: 1.0 - -/** - * parse a rison string into a javascript structure. - * - * this is the simplest decoder entry point. - * - * based on Oliver Steele's OpenLaszlo-JSON - * http://osteele.com/sources/openlaszlo/json - */ -export function decode(r: string) { - const p = new Parser(); - return p.parse(r); -} - -/** - * parse an o-rison string into a javascript structure. - * - * this simply adds parentheses around the string before parsing. - */ -export function decode_object(r: string) { - return decode('(' + r + ')'); -} - -/** - * parse an a-rison string into a javascript structure. - * - * this simply adds array markup around the string before parsing. - */ -export function decode_array(r: string) { - return decode('!(' + r + ')'); -} - -// prettier-ignore -export type JSONValue = - | string - | number - | boolean - | null - | undefined - | {[x: string]: JSONValue} - | Array; - -class Parser { - /** - * a string containing acceptable whitespace characters. - * by default the rison decoder tolerates no whitespace. - * to accept whitespace set rison.parser.WHITESPACE = " \t\n\r\f"; - */ - static WHITESPACE = ''; - - static readonly bangs = { - t: true, - f: false, - n: null, - '(': Parser.parse_array, - }; - - string: string; - index: number; - readonly table: Record JSONValue>; - - constructor() { - this.string = ''; - this.index = -1; - this.table = { - '!': () => { - const s = this.string; - const c = s.charAt(this.index++); - if (!c) return this.error('"!" at end of input'); - const x = Parser.bangs[c]; - if (typeof x == 'function') { - // eslint-disable-next-line no-useless-call - return x.call(null, this); - } else if (typeof x === 'undefined') { - return this.error('unknown literal: "!' + c + '"'); - } - return x; - }, - '(': () => { - const o: JSONValue = {}; - let c; - let count = 0; - while ((c = this.next()) !== ')') { - if (count) { - if (c !== ',') this.error("missing ','"); - } else if (c === ',') { - this.error("extra ','"); - } else --this.index; - const k = this.readValue(); - if (typeof k == 'undefined') return undefined; - if (this.next() !== ':') this.error("missing ':'"); - const v = this.readValue(); - if (typeof v == 'undefined') return undefined; - assert(isString(k)); - o[k] = v; - count++; - } - return o; - }, - "'": () => { - const s = this.string; - let i = this.index; - let start = i; - const segments: string[] = []; - let c; - while ((c = s.charAt(i++)) !== "'") { - //if (i == s.length) return this.error('unmatched "\'"'); - if (!c) this.error('unmatched "\'"'); - if (c === '!') { - if (start < i - 1) segments.push(s.slice(start, i - 1)); - c = s.charAt(i++); - if ("!'".indexOf(c) >= 0) { - segments.push(c); - } else { - this.error('invalid string escape: "!' + c + '"'); - } - start = i; - } - } - if (start < i - 1) segments.push(s.slice(start, i - 1)); - this.index = i; - return segments.length === 1 ? segments[0] : segments.join(''); - }, - // Also any digit. The statement that follows this table - // definition fills in the digits. - '-': () => { - let s = this.string; - let i = this.index; - const start = i - 1; - let state = 'int'; - let permittedSigns = '-'; - const transitions = { - 'int+.': 'frac', - 'int+e': 'exp', - 'frac+e': 'exp', - }; - do { - const c = s.charAt(i++); - if (!c) break; - if ('0' <= c && c <= '9') continue; - if (permittedSigns.indexOf(c) >= 0) { - permittedSigns = ''; - continue; - } - state = transitions[state + '+' + c.toLowerCase()]; - if (state === 'exp') permittedSigns = '-'; - } while (state); - this.index = --i; - s = s.slice(start, i); - if (s === '-') this.error('invalid number'); - return Number(s); - }, - }; - // copy table['-'] to each of table[i] | i <- '0'..'9': - for (let i = 0; i <= 9; i++) this.table[String(i)] = this.table['-']; - } - - /** - * parse a rison string into a javascript structure. - */ - parse(str: string): JSONValue { - this.string = str; - this.index = 0; - const value = this.readValue(); - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - if (this.next()) this.error("unable to parse string as rison: '" + encode(str) + "'"); - return value; - } - - error(message: string): never { - throw new Error('rison parser error: ' + message); - } - - readValue(): JSONValue { - const c = this.next(); - const fn = c && this.table[c]; - - if (fn) return fn.apply(this); - - // fell through table, parse as an id - - const s = this.string; - const i = this.index - 1; - - // Regexp.lastIndex may not work right in IE before 5.5? - // g flag on the regexp is also necessary - next_id.lastIndex = i; - const m = unwrap(next_id.exec(s)); - - // console.log('matched id', i, r.lastIndex); - - if (m.length > 0) { - const id = m[0]; - this.index = i + id.length; - return id; // a string - } - - if (c) this.error("invalid character: '" + c + "'"); - this.error('empty expression'); - } - - next(): string | undefined { - let c: string; - const s = this.string; - let i = this.index; - do { - if (i === s.length) return undefined; - c = s.charAt(i++); - } while (Parser.WHITESPACE.indexOf(c) >= 0); - this.index = i; - return c; - } - - static parse_array(parser: Parser): JSONValue[] | undefined { - const ar: JSONValue[] = []; - let c; - while ((c = parser.next()) !== ')') { - if (!c) return parser.error("unmatched '!('"); - if (ar.length) { - if (c !== ',') parser.error("missing ','"); - } else if (c === ',') { - return parser.error("extra ','"); - } else --parser.index; - const n = parser.readValue(); - if (n === undefined) return undefined; - ar.push(n); - } - return ar; - } -} diff --git a/static/url.ts b/static/url.ts index 811f22e5750..ba94dfcc67a 100644 --- a/static/url.ts +++ b/static/url.ts @@ -26,10 +26,9 @@ import _ from 'underscore'; import GoldenLayout from 'golden-layout'; const lzstring = require('lz-string'); +const rison = require('rison'); const Components = require('./components'); -import * as rison from './rison'; - export function convertOldState(state: any): any { const sc = state.compilers[0]; if (!sc) throw new Error('Unable to determine compiler from old state'); @@ -75,7 +74,7 @@ export function loadState(state: any): any { return state; } -export function risonify(obj: rison.JSONValue): string { +export function risonify(obj: object): string { return rison.quote(rison.encode_object(obj)); }