public AddTemplate(string name, CombinedTemplateState templateState, PcfControl pcfTemplate)
 {
     _name        = name;
     _template    = templateState;
     _pcfTemplate = pcfTemplate;
     _isPcf       = true;
 }
 public AddTemplate(string name, CombinedTemplateState templateState, TemplatesJson.TemplateJson jsonTemplate)
 {
     _name         = name;
     _template     = templateState;
     _jsonTemplate = jsonTemplate;
     _isPcf        = false;
 }
        public static PcfControl GetPowerAppsControlFromJson(CombinedTemplateState template)
        {
            var pcfControl = new PcfControl()
            {
                Name = template.TemplateDisplayName, Version = template.Version
            };

            var dynamicControlDefinition = Utilities.JsonParse <PcfControlDoublyEncoded>(template.DynamicControlDefinitionJson);

            pcfControl.ControlNamespace   = dynamicControlDefinition.ControlNamespace;
            pcfControl.DisplayNameKey     = dynamicControlDefinition.DisplayNameKey;
            pcfControl.ControlConstructor = dynamicControlDefinition.ControlConstructor;
            pcfControl.Resources          = dynamicControlDefinition.Resources != null?Utilities.JsonParse <Resource[]>(dynamicControlDefinition.Resources) : null;

            pcfControl.Properties = dynamicControlDefinition.Properties != null?Utilities.JsonParse <IEnumerable <Property> >(dynamicControlDefinition.Properties) : null;

            pcfControl.AuthConfigProperties = dynamicControlDefinition.AuthConfigProperties != null?GetAutConfigProperties(dynamicControlDefinition.AuthConfigProperties) : null;

            pcfControl.DataConnectors = dynamicControlDefinition.DataConnectors != null?Utilities.JsonParse <IEnumerable <DataConnectorMetadata> >(dynamicControlDefinition.DataConnectors) : null;

            pcfControl.SubscribedFunctionalities = dynamicControlDefinition.SubscribedFunctionalities != null?Utilities.JsonParse <Dictionary <string, string> >(dynamicControlDefinition.SubscribedFunctionalities) : null;

            pcfControl.IncludedProperties = dynamicControlDefinition.IncludedProperties != null?Utilities.JsonParse <IEnumerable <Property> >(dynamicControlDefinition.IncludedProperties) : null;

            pcfControl.Events = dynamicControlDefinition.Events != null?Utilities.JsonParse <IEnumerable <Event> >(dynamicControlDefinition.Events) : null;

            pcfControl.CommonEvents = dynamicControlDefinition.CommonEvents != null?Utilities.JsonParse <IEnumerable <Event> >(dynamicControlDefinition.CommonEvents) : null;

            pcfControl.PropertyDependencies = dynamicControlDefinition.PropertyDependencies != null?Utilities.JsonParse <IEnumerable <PropertyDependency> >(dynamicControlDefinition.PropertyDependencies) : null;

            pcfControl.ExtensionData = dynamicControlDefinition.ExtensionData;

            return(pcfControl);
        }
        private static void RepopulateTemplateCustomProperties(FunctionNode func, CombinedTemplateState templateState, ErrorContainer errors, Entropy entropy)
        {
            var funcName   = func.Identifier;
            var customProp = templateState.CustomProperties.FirstOrDefault(prop => prop.Name == funcName);

            if (customProp == default)
            {
                errors.ParseError(func.SourceSpan.GetValueOrDefault(), "Functions are not yet supported without corresponding custom properties in ControlTemplates.json");
                throw new DocumentException();
            }

            var scopeArgs = customProp.PropertyScopeKey.PropertyScopeRulesKey.ToDictionary(scope => scope.Name);
            var argTypes  = func.Args.ToDictionary(arg => arg.Identifier, arg => arg.Kind.TypeName);

            int i = 1;

            foreach (var arg in func.Metadata)
            {
                if (arg.Identifier == PAConstants.ThisPropertyIdentifier)
                {
                    continue;
                }

                var propertyName = funcName + "_" + arg.Identifier;
                var defaultRule  = entropy.GetDefaultScript(propertyName, arg.Default.Expression);

                if (!scopeArgs.TryGetValue(propertyName, out var propScopeRule))
                {
                    errors.ParseError(func.SourceSpan.GetValueOrDefault(), "Functions are not yet supported without corresponding custom properties in ControlTemplates.json");
                    throw new DocumentException();
                }
                if (!argTypes.TryGetValue(arg.Identifier, out var propType) || !Enum.TryParse <PropertyDataType>(propType, out var propTypeEnum))
                {
                    errors.ParseError(func.SourceSpan.GetValueOrDefault(), "Function metadata blocks must correspond to a function parameter with a valid type");
                    throw new DocumentException();
                }

                propScopeRule.ScopeVariableInfo.DefaultRule           = defaultRule;
                propScopeRule.ScopeVariableInfo.ParameterIndex        = i;
                propScopeRule.ScopeVariableInfo.ParentPropertyName    = funcName;
                propScopeRule.ScopeVariableInfo.ScopePropertyDataType = (int)propTypeEnum;

                ++i;
            }
        }
        private static void SplitIRAndState(ControlInfoJson.Item control, string topParentName, int index, EditorStateStore stateStore, TemplateStore templateStore, Entropy entropy, out BlockNode controlIR)
        {
            // Bottom up, recursively process children
            var children   = new List <BlockNode>();
            var childIndex = 0;

            foreach (var child in control.Children)
            {
                SplitIRAndState(child, topParentName, childIndex, stateStore, templateStore, entropy, out var childBlock);
                children.Add(childBlock);
                ++childIndex;
            }
            var isComponentDef = control.Template.IsComponentDefinition ?? false;

            var customPropsToHide = new HashSet <string>();
            var functions         = new List <FunctionNode>();

            if (control.Template.CustomProperties?.Any() ?? false)
            {
                if (!isComponentDef)
                {
                    // Skip component property params on instances
                    customPropsToHide = new HashSet <string>(control.Template.CustomProperties
                                                             .Where(customProp => customProp.IsFunctionProperty)
                                                             .SelectMany(customProp =>
                                                                         customProp.PropertyScopeKey.PropertyScopeRulesKey
                                                                         .Select(propertyScopeRule => propertyScopeRule.Name)));
                }
                else
                {
                    // Create FunctionNodes on def
                    foreach (var customProp in control.Template.CustomProperties.Where(prop => prop.IsFunctionProperty))
                    {
                        var name = customProp.Name;
                        customPropsToHide.Add(name);
                        var rule = control.Rules.FirstOrDefault(rule => rule.Property == name);
                        if (rule == null)
                        {
                            // Control does not have a rule for the custom property.
                            continue;
                        }
                        var expression     = rule.InvariantScript;
                        var expressionNode = new ExpressionNode()
                        {
                            Expression = expression
                        };

                        var resultType = new TypeNode()
                        {
                            TypeName = customProp.PropertyDataTypeKey
                        };

                        var args        = new List <TypedNameNode>();
                        var argMetadata = new List <ArgMetadataBlockNode>();
                        foreach (var arg in customProp.PropertyScopeKey.PropertyScopeRulesKey)
                        {
                            customPropsToHide.Add(arg.Name);
                            args.Add(new TypedNameNode()
                            {
                                Identifier = arg.ScopeVariableInfo.ScopeVariableName,
                                Kind       = new TypeNode()
                                {
                                    TypeName = ((PropertyDataType)arg.ScopeVariableInfo.ScopePropertyDataType).ToString()
                                }
                            });

                            var invariantScript = control.Rules.First(rule => rule.Property == arg.Name)?.InvariantScript;
                            argMetadata.Add(new ArgMetadataBlockNode()
                            {
                                Identifier = arg.ScopeVariableInfo.ScopeVariableName,
                                Default    = new ExpressionNode()
                                {
                                    Expression = invariantScript ?? arg.ScopeVariableInfo.DefaultRule
                                },
                            });

                            // Handle the case where invariantScript value of the property is not same as the default script.
                            if (invariantScript != null && invariantScript != arg.ScopeVariableInfo.DefaultRule)
                            {
                                entropy.FunctionParamsInvariantScripts.Add(arg.Name, new string[] { arg.ScopeVariableInfo.DefaultRule, invariantScript });
                            }

                            arg.ScopeVariableInfo.DefaultRule           = null;
                            arg.ScopeVariableInfo.ScopePropertyDataType = null;
                            arg.ScopeVariableInfo.ParameterIndex        = null;
                            arg.ScopeVariableInfo.ParentPropertyName    = null;
                        }

                        argMetadata.Add(new ArgMetadataBlockNode()
                        {
                            Identifier = PAConstants.ThisPropertyIdentifier,
                            Default    = new ExpressionNode()
                            {
                                Expression = expression,
                            },
                        });

                        functions.Add(new FunctionNode()
                        {
                            Args       = args,
                            Metadata   = argMetadata,
                            Identifier = name
                        });
                    }
                }
            }

            var properties    = new List <PropertyNode>();
            var propStates    = new List <PropertyState>();
            var dynPropStates = new List <DynamicPropertyState>();

            foreach (var property in control.Rules)
            {
                var(prop, state) = SplitProperty(property);
                propStates.Add(state);

                if (customPropsToHide.Contains(property.Property))
                {
                    continue;
                }

                properties.Add(prop);
            }

            foreach (var property in control.DynamicProperties ?? Enumerable.Empty <ControlInfoJson.DynamicPropertyJson>())
            {
                if (property.Rule == null)
                {
                    dynPropStates.Add(new DynamicPropertyState()
                    {
                        PropertyName = property.PropertyName
                    });
                    continue;
                }

                var(prop, state) = SplitDynamicProperty(property);
                dynPropStates.Add(state);
                properties.Add(prop);
            }

            controlIR = new BlockNode()
            {
                Name = new TypedNameNode()
                {
                    Identifier = control.Name,
                    Kind       = new TypeNode()
                    {
                        TypeName        = control.Template.TemplateDisplayName ?? control.Template.Name,
                        OptionalVariant = string.IsNullOrEmpty(control.VariantName) ? null : control.VariantName
                    }
                },
                Children   = children.ToList(),
                Properties = properties,
                Functions  = functions,
            };


            if (templateStore.TryGetTemplate(control.Template.Name, out var templateState))
            {
                if (isComponentDef)
                {
                    templateState.IsComponentTemplate = true;
                    templateState.CustomProperties    = control.Template.CustomProperties;
                }
            }
            else
            {
                templateState = new CombinedTemplateState(control.Template);
                templateState.ComponentDefinitionInfo = null;
                var templateName = templateState.TemplateDisplayName ?? templateState.Name;
                templateStore.AddTemplate(templateName, templateState);
            }

            SplitCustomTemplates(entropy, control.Template, control.Name);

            entropy.ControlUniqueIds.Add(control.Name, int.Parse(control.ControlUniqueId));
            var controlState = new ControlState()
            {
                Name                  = control.Name,
                TopParentName         = topParentName,
                Properties            = propStates,
                DynamicProperties     = dynPropStates.Any() ? dynPropStates : null,
                HasDynamicProperties  = control.HasDynamicProperties,
                StyleName             = control.StyleName,
                IsGroupControl        = control.IsGroupControl,
                GroupedControlsKey    = control.GroupedControlsKey,
                ExtensionData         = control.ExtensionData,
                ParentIndex           = index,
                AllowAccessToGlobals  = control.AllowAccessToGlobals,
                IsComponentDefinition = control.Template.IsComponentDefinition,
            };

            stateStore.TryAddControl(controlState);
        }
        private static void SplitIRAndState(ControlInfoJson.Item control, string topParentName, int index, EditorStateStore stateStore, TemplateStore templateStore, Entropy entropy, out BlockNode controlIR)
        {
            // Bottom up, recursively process children
            var childrenWithZIndex = new List <KeyValuePair <BlockNode, double> >();
            var childIndex         = 0;

            foreach (var child in control.Children)
            {
                SplitIRAndState(child, topParentName, childIndex, stateStore, templateStore, entropy, out var childBlock);
                childrenWithZIndex.Add(new KeyValuePair <BlockNode, double>(childBlock, GetControlZIndex(child)));
                ++childIndex;
            }
            var children       = childrenWithZIndex.OrderBy(kvp => kvp.Value).Select(kvp => kvp.Key);
            var isComponentDef = control.Template.IsComponentDefinition ?? false;

            var customPropsToHide = new HashSet <string>();
            var functions         = new List <FunctionNode>();

            if (control.Template.CustomProperties?.Any() ?? false)
            {
                if (!isComponentDef)
                {
                    // Skip component property params on instances
                    customPropsToHide = new HashSet <string>(control.Template.CustomProperties
                                                             .Where(customProp => customProp.IsFunctionProperty)
                                                             .SelectMany(customProp =>
                                                                         customProp.PropertyScopeKey.PropertyScopeRulesKey
                                                                         .Select(propertyScopeRule => propertyScopeRule.Name)
                                                                         ));
                }
                else
                {
                    // Create FunctionNodes on def
                    foreach (var customProp in control.Template.CustomProperties.Where(prop => prop.IsFunctionProperty))
                    {
                        var name = customProp.Name;
                        customPropsToHide.Add(name);
                        var expression     = control.Rules.First(rule => rule.Property == name).InvariantScript;
                        var expressionNode = new ExpressionNode()
                        {
                            Expression = expression
                        };

                        var resultType = new TypeNode()
                        {
                            TypeName = customProp.PropertyDataTypeKey
                        };

                        var args        = new List <TypedNameNode>();
                        var argMetadata = new List <ArgMetadataBlockNode>();
                        foreach (var arg in customProp.PropertyScopeKey.PropertyScopeRulesKey)
                        {
                            customPropsToHide.Add(arg.Name);
                            args.Add(new TypedNameNode()
                            {
                                Identifier = arg.ScopeVariableInfo.ScopeVariableName,
                                Kind       = new TypeNode()
                                {
                                    TypeName = ((PropertyDataType)arg.ScopeVariableInfo.ScopePropertyDataType).ToString()
                                }
                            });

                            argMetadata.Add(new ArgMetadataBlockNode()
                            {
                                Identifier = arg.ScopeVariableInfo.ScopeVariableName,
                                Default    = new ExpressionNode()
                                {
                                    Expression = arg.ScopeVariableInfo.DefaultRule.Replace("\r\n", "\n").Replace("\r", "\n").TrimStart()
                                },
                            });

                            arg.ScopeVariableInfo.DefaultRule           = null;
                            arg.ScopeVariableInfo.ScopePropertyDataType = null;
                            arg.ScopeVariableInfo.ParameterIndex        = null;
                            arg.ScopeVariableInfo.ParentPropertyName    = null;
                        }

                        argMetadata.Add(new ArgMetadataBlockNode()
                        {
                            Identifier = PAConstants.ThisPropertyIdentifier,
                            Default    = new ExpressionNode()
                            {
                                Expression = expression.Replace("\r\n", "\n").Replace("\r", "\n").TrimStart(),
                            },
                        });

                        functions.Add(new FunctionNode()
                        {
                            Args       = args,
                            Metadata   = argMetadata,
                            Identifier = name
                        });
                    }
                }
            }

            var properties = new List <PropertyNode>();
            var propStates = new List <PropertyState>();

            foreach (var property in control.Rules)
            {
                var(prop, state) = SplitProperty(property);
                propStates.Add(state);

                if (customPropsToHide.Contains(property.Property))
                {
                    continue;
                }

                properties.Add(prop);
            }

            controlIR = new BlockNode()
            {
                Name = new TypedNameNode()
                {
                    Identifier = control.Name,
                    Kind       = new TypeNode()
                    {
                        TypeName        = control.Template.TemplateDisplayName ?? control.Template.Name,
                        OptionalVariant = string.IsNullOrEmpty(control.VariantName) ? null : control.VariantName
                    }
                },
                Children   = children.ToList(),
                Properties = properties,
                Functions  = functions,
            };


            if (templateStore.TryGetTemplate(control.Template.Name, out var templateState))
            {
                if (isComponentDef)
                {
                    templateState.IsComponentTemplate = true;
                    templateState.CustomProperties    = control.Template.CustomProperties;
                }
            }
            else
            {
                templateState = new CombinedTemplateState(control.Template);
                templateState.ComponentDefinitionInfo = null;
                var templateName = templateState.TemplateDisplayName ?? templateState.Name;
                templateStore.AddTemplate(templateName, templateState);
            }

            entropy.ControlUniqueIds.Add(control.Name, int.Parse(control.ControlUniqueId));
            var controlState = new ControlState()
            {
                Name = control.Name,
                PublishOrderIndex     = control.PublishOrderIndex,
                TopParentName         = topParentName,
                Properties            = propStates,
                StyleName             = control.StyleName,
                ExtensionData         = control.ExtensionData,
                ParentIndex           = index,
                IsComponentDefinition = control.Template.IsComponentDefinition,
            };

            stateStore.TryAddControl(controlState);
        }