/// This writes out the IR, editor state cache, and potentially component templates
        /// for a single top level control, such as the App object, a screen, or component
        /// Name refers to the control name
        private static void WriteTopParent(
            DirectoryWriter dir,
            CanvasDocument app,
            string name,
            BlockNode ir,
            string subDir)
        {
            var controlName = name;
            var text        = PAWriterVisitor.PrettyPrint(ir);

            string filename = controlName + ".pa.yaml";


            dir.WriteAllText(subDir, filename, text);

            var extraData = new Dictionary <string, ControlState>();

            foreach (var item in app._editorStateStore.GetControlsWithTopParent(controlName))
            {
                extraData.Add(item.Name, item);
            }

            // Write out of all the other state for roundtripping
            string extraContent = controlName + ".editorstate.json";

            dir.WriteAllJson(EditorStateDir, extraContent, extraData);

            // Write out component templates next to the component
            if (app._templateStore.TryGetTemplate(name, out var templateState))
            {
                dir.WriteAllJson(subDir, controlName + ".json", templateState);
            }
        }
        /// This writes out the IR, editor state cache, and potentially component templates
        /// for a single top level control, such as the App object, a screen, or component
        /// Name refers to the control name
        /// Only in case of AppTest, the topParentName is passed down, since for AppTest the TestSuites are sharded into individual files.
        /// We truncate the control names to limit it to 50 charactes length (escaped name).
        private static void WriteTopParent(
            DirectoryWriter dir,
            CanvasDocument app,
            string name,
            BlockNode ir,
            string subDir,
            string topParentName = null)
        {
            var controlName    = name;
            var newControlName = Utilities.TruncateNameIfTooLong(controlName);

            string filename = newControlName + ".fx.yaml";

            // For AppTest control shard each test suite into individual files.
            if (controlName == AppTestControlName)
            {
                foreach (var child in ir.Children)
                {
                    WriteTopParent(dir, app, child.Properties.FirstOrDefault(x => x.Identifier == "DisplayName").Expression.Expression.Trim(new char[] { '"' }), child, subDir, controlName);
                }

                // Clear the children since they have already been sharded into their individual files.
                ir.Children.Clear();
            }

            var text = PAWriterVisitor.PrettyPrint(ir);

            dir.WriteAllText(subDir, filename, text);

            // For TestSuite controls, only the top parent control has an editor state created.
            // For other control types, create an editor state.
            if (string.IsNullOrEmpty(topParentName))
            {
                string editorStateFilename = $"{newControlName}.editorstate.json";

                var controlStates = new Dictionary <string, ControlState>();
                foreach (var item in app._editorStateStore.GetControlsWithTopParent(controlName))
                {
                    controlStates.Add(item.Name, item);
                }

                ControlTreeState editorState = new ControlTreeState
                {
                    ControlStates = controlStates,
                    TopParentName = controlName
                };

                // Write out of all the other state properties on the control for roundtripping.
                dir.WriteAllJson(EditorStateDir, editorStateFilename, editorState);
            }

            // Write out component templates next to the component
            if (app._templateStore.TryGetTemplate(name, out var templateState))
            {
                dir.WriteAllJson(subDir, newControlName + ".json", templateState);
            }
        }
        /// This writes out the IR, editor state cache, and potentially component templates
        /// for a single top level control, such as the App object, a screen, or component
        /// Name refers to the control name
        /// Only in case of AppTest, the topParentName is passed down, since for AppTest the TestSuites are sharded into individual files.
        /// We truncate the control names to limit it to 50 charactes length (escaped name).
        private static void WriteTopParent(
            DirectoryWriter dir,
            CanvasDocument app,
            string name,
            BlockNode ir,
            string subDir,
            string topParentname = null)
        {
            var controlName    = name;
            var newControlName = Utilities.TruncateNameIfTooLong(controlName);

            string filename = newControlName + ".fx.yaml";

            // For AppTest control shard each test suite into individual file.
            if (controlName == AppTestControlName)
            {
                foreach (var child in ir.Children)
                {
                    WriteTopParent(dir, app, child.Properties.FirstOrDefault(x => x.Identifier == "DisplayName").Expression.Expression.Trim(new char[] { '"' }), child, subDir, controlName);
                }

                // Clear the children since they have already been sharded into their individual files.
                ir.Children.Clear();
            }

            var text = PAWriterVisitor.PrettyPrint(ir);

            dir.WriteAllText(subDir, filename, text);

            var extraData = new Dictionary <string, ControlState>();

            foreach (var item in app._editorStateStore.GetControlsWithTopParent(topParentname ?? controlName))
            {
                extraData.Add(item.Name, item);
            }

            // Write out of all the other state for roundtripping
            string extraContent = (topParentname ?? newControlName) + ".editorstate.json";

            // We write editorstate.json file per top parent control, and hence for the TestSuite control since it is not a top parent
            // use the top parent name (i.e. Test_7F478737223C4B69) to create the editorstate.json file.
            if (!dir.FileExists(EditorStateDir, extraContent))
            {
                dir.WriteAllJson(EditorStateDir, extraContent, extraData);
            }

            // Write out component templates next to the component
            if (app._templateStore.TryGetTemplate(name, out var templateState))
            {
                dir.WriteAllJson(subDir, newControlName + ".json", templateState);
            }
        }
        public static string PrettyPrint(IRNode node)
        {
            StringWriter    sw     = new StringWriter();
            var             yaml   = new YamlWriter(sw);
            PAWriterVisitor pretty = new PAWriterVisitor();

            var context = new Context
            {
                _yaml = yaml
            };

            node.Accept(pretty, context);

            return(sw.ToString());
        }