Skip to content

Instantly share code, notes, and snippets.

@danield137
Created July 9, 2019 06:58
Show Gist options
  • Select an option

  • Save danield137/229139b0a7431ca4f15bcb79622b17ee to your computer and use it in GitHub Desktop.

Select an option

Save danield137/229139b0a7431ca4f15bcb79622b17ee to your computer and use it in GitHub Desktop.
Javascript partial json parsing
import Clarinet from 'clarinet';
class TrackingObject {
data: { [key: string]: any } | null = null;
path: string = '';
depth: number = 0;
stack: StackItem[] = [];
expandArray(key: string) {
this.stack.push({ type: 'Array', key, value: null });
}
expandObject(key: string | null) {
this.stack.push({ type: 'Object', key, value: null });
}
pushValue(key: string | null, value: any) {
if (key === null) {
this.stack.push({ type: 'Value', key, value });
} else {
this.stack.push({ type: 'KeyValue', key, value });
}
}
foldArray(key: string | null) {
const agg = [];
let current: StackItem | undefined = this.stack.pop();
while (current !== undefined && current.type !== 'Array') {
agg.push(current.value);
current = this.stack.pop();
}
if (current !== undefined && key == null) {
key = current.key;
}
if (this.isClosed()) {
// reverse due to working with stack
this.data = agg.reverse();
} else {
this.pushValue(key, agg.reverse());
}
}
foldObject(key: string | null) {
const agg: { [key: string]: any } = {};
let current: StackItem | undefined = this.stack.pop();
while (current !== undefined && current.type !== 'Object') {
let k: string = current!.key!;
agg[k] = current.value;
current = this.stack.pop();
}
if (current !== undefined && key == null) {
key = current.key;
}
if (this.isClosed()) {
this.data = agg;
} else {
this.pushValue(key, agg);
}
}
isClosed(): Boolean {
return this.stack.length === 0;
}
}
// Usage with clarient to build partial objects
export async function extractItemsFromPartialJson(partial: string): Promise<object[]> {
return new Promise<object[]>((resolve, reject) => {
let parser = Clarinet.parser();
let items: object[] | null = [];
let currentObj: TrackingObject | null = null;
let currentKey: string | null = null;
parser.onvalue = (v: any) => {
currentObj!.pushValue(currentKey!, v);
currentKey = null;
};
parser.onopenobject = (key: string) => {
if (currentObj === null) {
currentObj = new TrackingObject();
}
currentObj.expandObject(currentKey);
currentKey = key;
};
parser.onkey = (key: string) => {
currentKey = key;
};
parser.oncloseobject = () => {
currentObj!.foldObject(currentKey!);
if (currentObj!.isClosed()) {
items!.push(currentObj!.data!);
currentObj = null;
currentKey = null;
}
};
parser.onopenarray = () => {
if (currentObj !== null) {
currentObj!.expandArray(currentKey!);
currentKey = null;
}
};
parser.onclosearray = () => {
if (currentObj !== null) {
currentObj!.foldArray(currentKey!);
currentKey = null;
}
};
parser.onend = () => {
resolve(items || []);
};
parser.write(partial).close();
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment