// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System; using System.Collections.Generic; using System.Collections.ObjectModel; namespace Microsoft.ReactNative.Managed { public class JSValueTreeWriter : IJSValueWriter { private State m_state = State.Start; private readonly Stack m_stack = new Stack(); private object m_dynamic; private string m_propertyName; private JSValue m_result; public JSValue TakeValue() { return m_result; } public void WriteNull() { WriteValue(new JSValue()); } public void WriteBoolean(bool value) { WriteValue(new JSValue(value)); } public void WriteInt64(long value) { WriteValue(new JSValue(value)); } public void WriteDouble(double value) { WriteValue(new JSValue(value)); } public void WriteString(string value) { WriteValue(new JSValue(value)); } public void WriteObjectBegin() { if (m_state == State.PropertyValue) { m_stack.Push(new StackEntry(m_state, (Dictionary)m_dynamic, m_propertyName)); } else if (m_state == State.Array) { m_stack.Push(new StackEntry(m_state, (List)m_dynamic)); } else if (m_state != State.Start) { throw new InvalidOperationException(); } m_dynamic = new Dictionary(); m_state = State.PropertyName; } public void WritePropertyName(string name) { if (m_state == State.PropertyName) { m_propertyName = name; m_state = State.PropertyValue; } else { throw new InvalidOperationException(); } } public void WriteObjectEnd() { if (m_state == State.PropertyName) { var obj = new JSValue(new ReadOnlyDictionary((Dictionary)m_dynamic)); if (m_stack.Count == 0) { m_result = obj; m_state = State.Finish; return; } else { StackEntry entry = m_stack.Pop(); if (entry.State == State.PropertyValue) { ((Dictionary)entry.Dynamic)[entry.PropertyName] = obj; m_dynamic = entry.Dynamic; m_state = State.PropertyName; return; } else if (entry.State == State.Array) { ((List)entry.Dynamic).Add(obj); m_dynamic = entry.Dynamic; m_state = State.Array; return; } } } throw new InvalidOperationException(); } public void WriteArrayBegin() { if (m_state == State.PropertyValue) { m_stack.Push(new StackEntry(m_state, (Dictionary)m_dynamic, m_propertyName)); } else if (m_state == State.Array) { m_stack.Push(new StackEntry(m_state, (List)m_dynamic)); } else if (m_state != State.Start) { throw new InvalidOperationException(); } m_dynamic = new List(); m_state = State.Array; } public void WriteArrayEnd() { if (m_state == State.Array) { var arr = new JSValue(new ReadOnlyCollection((List)m_dynamic)); if (m_stack.Count == 0) { m_result = arr; m_state = State.Finish; return; } else { StackEntry entry = m_stack.Pop(); if (entry.State == State.PropertyValue) { ((Dictionary)entry.Dynamic)[entry.PropertyName] = arr; m_dynamic = entry.Dynamic; m_state = State.PropertyName; return; } else if (entry.State == State.Array) { ((List)entry.Dynamic).Add(arr); m_dynamic = entry.Dynamic; m_state = State.Array; return; } } } throw new InvalidOperationException(); } private enum State { Start, PropertyName, PropertyValue, Array, Finish }; private class StackEntry { public State State; public object Dynamic; public string PropertyName; public StackEntry(State state, Dictionary obj, string propertyName) { State = state; Dynamic = obj; PropertyName = propertyName; } public StackEntry(State state, List arr) { State = state; Dynamic = arr; PropertyName = null; } } private void WriteValue(JSValue value) { if (m_state == State.PropertyValue) { ((Dictionary)m_dynamic)[m_propertyName] = value; m_state = State.PropertyName; } else if (m_state == State.Array) { ((List)m_dynamic).Add(value); } else { m_result = value; } } } }