@garyp/common-object-x
Version:
432 lines (347 loc) • 9.05 kB
JavaScript
const { Objectx } = require('./Objectx');
const { Dictionaryx } = require('./Dictionaryx');
//---------------------------------------------------------------------
//---------------------------------------------------------------------
"use strict";
class Jsonx extends Objectx {
constructor() {
super();
this.fObject = this.fObject ?? null;
this.fStrm = this.fStrm ?? null;
}
/* -- static methods --
fromString
nullValueString
on
fromObject
defT
coerceDict
listDelims
coerceDeflatedString
convertDictToString
*/
asString() {
return this.strm().asString();
}
atPut(key, value) {
//Assumes our object is a dic
this.object().atPut(key,value);
this.strm(null);
}
basicDeflate() {
var object;
object = this.object();
if(object.isCollectionStrictly())
return this.deflateCollection(object);
if(object.isDictionary())
return this.deflateDict(object);
return this.deflateValue(object);
}
basicDeflateDict() {
//Object to json string
var strm, index;
strm = this.newStream("");
this.strm(strm);
strm.show("{");
index = 1;
this.object().associationPairs().zzunwrap().forEach(pair => {
var deflatedPair;
deflatedPair = this.deflatePair(pair);
if(index > 1)
strm.show(", ");
strm.show(deflatedPair);
index = index + 1;
});
strm.show("}");
strm.reset();
return strm;
}
basicInflate() {
var strm;
strm = this.strm();
if(this.objectEquals(strm.peek(),'{'))
return this.inflateDict();
if(this.objectEquals(strm.peek(),'['))
{strm.skip();
return this.inflateCollection();}
return this.parseValue();
}
deflate() {
/* Deflate object into json string
We have the object. We'll DEFLATE it. */
this.strm(this.tools().streamClass().coerce(this.basicDeflate()) );
}
deflateDict(aDict) {
var strm, index, dict;
strm = this.newStream("");
this.strm(strm);
strm.show("{");
index = 1;
dict = Dictionaryx.coerce(aDict);
dict.associationPairs().zzunwrap().forEach(pair => {
var deflatedPair;
deflatedPair = this.deflatePair(pair);
if(index > 1)
strm.show(", ");
strm.show(deflatedPair);
index = index + 1;
});
strm.show("}");
strm.reset();
return strm.asString();
}
deflatePair(pair) {
/* ''w'': 10 */
var key, value;
key = pair.first().zzwrap().asDq();
value = this.deflateValue(pair.last());
return (key + ": ") + value.asString();
}
deflateValue(aValue) {
/* 10
10.5
''Hello There''
True,
[10, 10.5, ''Hello There'', True, False] */
var value;
//1) #gpToDo add support for parsing list value
//2) #gpToDo add support for parsing a nested dict value
if(aValue == null)
return "null";
value = aValue.zzunwrap();
//json coding -- <null>
if(aValue == null)
return "null";
if(isNumber(value))
return value.asString();
if(value.isString())
return value.zzwrap().asDq();
if(value.isBoolean())
return value ? "true" : "false";
if(value.isCollectionStrictly())
return this.deflateCollection(value);
if(value.isDictionary())
return this.deflateDict(value);
this.throwError("deflateValue: value");
}
inflate() {
/* Inflate json string into object
We have the stream. We'll INFLATE it. */
this.object(this.basicInflate());
}
inflateCollection() {
/* Inflate (next) collection
deflated:
[10, 10.5, ''Hello There'', true, false] */
var zzstrm, coll, comma, rightCloser;
zzstrm = this.strm();
zzstrm.sw();
coll = this.newOc();
comma = ',';
rightCloser = ']';
if(zzstrm.nextEquals(rightCloser))
{zzstrm.skip();
return coll;}
while(!(zzstrm.atEnd()))
{var value;
value = this.parseValue();
coll.add(value);
zzstrm.sw();
if(zzstrm.nextEquals(rightCloser))
{zzstrm.skip();
return coll;}
if(zzstrm.nextEquals(comma))
zzstrm.skip();}
return coll;
}
inflateDict() {
var dictionary, comma, strm;
dictionary = this.newDict();
comma = ',';
strm = this.strm();
if(strm.nextEquals('{'))
strm.skip();
strm.sw();
while(!(this.objectEquals(strm.peek(),'}')))
{var pair;
pair = this.parsePair();
dictionary.add(pair);
strm.sw();
if(strm.nextEquals(comma))
strm.skip();}
if(this.objectEquals(strm.peek(),'}'))
strm.skip();
return dictionary;
}
newStream() {
return new BabyStream();
}
object(aObject) {
if(aObject !== undefined)
{this.fObject = aObject}
else
{if((this.fObject == null) && this.fStrm != null)
this.inflate();
return this.fObject;}
}
objectWrapped() {
return this.object().zzwrap().wrapRawDeeply();
}
parseKey() {
/* ''w'': 10, */
var strm;
strm = this.strm();
strm.sw();
strm.next();
//skip over dq
return strm.upTo('"');
}
parsePair() {
/* ''w'': 10,
terminator may be
,
]
}
If comma, pass it.
Otherwise stop at it. */
var key, value;
key = this.parseKey();
//Skip over colon
var temp1;
temp1 = this.strm();
temp1.upTo(':');
temp1.sw();
value = this.parseValue();
return this.tools().pairWith(key,value);
}
parseValue() {
/* 10
10.5
''Hello There''
True,
[10, 10.5, ''Hello There'', True, False] */
//1) #gpToDo add support for parsing list value
//2) #gpToDo add support for parsing a nested dict value
var strm, dq, delims, string, num, s1, s2;
strm = this.strm();
strm.sw();
//String
dq = '"';
if(this.objectEquals(strm.peek(),dq))
{strm.skip();
return strm.upTo(dq);}
//Boolean
strm.sw();
if(strm.nextEquals("true"))
{strm.skip(4);
return true;}
if(strm.nextEquals("false"))
{strm.skip(5);
return false;}
//List
if(strm.nextEquals('['))
{var result;
strm.skip();
result = this.inflateCollection();
return result;}
//Dictionary
if(strm.nextEquals('{'))
{strm.skip();
return this.inflateDict();}
delims = this.constructor.listDelims();
string = strm.upToAnyStopping(delims);
//nil
if(this.objectEquals(string,this.constructor.nullValueString()))
return null;
//Number
return this.tools().coerceNumber(string);
}
strm(aStrm) {
if(aStrm !== undefined)
{this.fStrm = aStrm}
else
{//The json string (i.e. deflated object)
if((this.fStrm == null) && this.fObject != null)
this.deflate();
return this.fStrm;}
}
//Class Methods
static listDelims() {
//list (elem) delimiters (candidates)
var temp1;
temp1 = this.tools().collClass();
temp1.with(",");
temp1.with(']');
return temp1.with('}');
}
static coerceDeflatedString(stringOrObject) {
/* Param 'stringOrObject' may be json string (ready as-is),
or object to be deflated.
If string, assume json and just return, else deflate */
return stringOrObject.isString() ? stringOrObject : this.tools().deflateAsJson(stringOrObject.zzwrap());
}
static on(arg) {
/* Python does now allow #from as method name due to it being
reserved word, so we use #on
arg type can be any of:
Json
String
Prim (dictionary, array, etc) */
if(arg.zzunwrap().isString())
return this.fromString(arg);
if(this.tools().isKindOf(arg,this))
return arg;
return this.fromObject(arg);
}
static nullValueString() {
return "null"
}
static defT() {
/* |json obj1 string obj2|
json := Jsonx defT.
obj1 := json object.
string := json asString.
obj2 := (Jsonx on: string) object.
obj2 @= obj1.
Or (make sure Python simulation is on) and do:
obj2 := string zzwrap inflateJson. */
var d;
d = this.newDict();
d.atPut("w",10);
d.atPut("h",2);
d.atPut("a",20);
d.atPut("p",24);
return this.on(d);
}
static coerceDict(stringOrDict) {
/* arg may be:
- object (the inflated object; e.g. say a dict).
- string (deflated json) */
var dictionary;
if(this.tools().isKindOf(stringOrDict,Jsonx))
return stringOrDict.objectWrapped();
dictionary = stringOrDict.zzunwrap().isString() ? stringOrDict.zzwrap().inflateAsJson().objectWrapped() : stringOrDict;
dictionary = Dictionaryx.coerce(dictionary);
dictionary.wrapRawDeeply();
return dictionary;
}
static fromObject(aObject) {
var object;
object = aObject.zzwrap();
object.wrapRawDeeply();
var temp1;
temp1 = new this();
temp1.object(object);
return temp1;
}
static convertDictToString(dic) {
return this.fromObject(dic.zzunwrapDeeply()).asString()
}
static fromString(jsonString) {
var temp1;
temp1 = new this();
temp1.strm(this.newStream(jsonString.asString()) );
return temp1;
}
}
exports.Jsonx = Jsonx;