private void WriteKoProperty(PropertyNode property, StringBuilder result)
        {
            AppendFormatDocumentation(result, property.Documentation);

            result.Append($"{Tab}{property.Name}");

            if (property.IsCollection)
            {
                result.Append(" = ko.observableArray<");
                WriteType(property.Type, result, false, PrefixModules.Views, allowObservable: true);
            }
            else
            {
                result.Append(property.NeedValidation() ? " = validation.validableObservable<" : " = ko.observable<");
                WriteTypedNode(property, result, false, prefixModule: PrefixModules.Views, allowObservable: true);
            }
            result.Append(">()");

            if (property.NeedValidation())
            {
                if (property.IsRequired)
                {
                    result.Append(".addValidator(validation.isRequired)");
                }

                if (property.CompareTo != null)
                {
                    result.Append($".addValidator(validation.areSame(this.{property.CompareTo}))");
                }

                if (property.MinimumLength.HasValue)
                {
                    result.Append($".addValidator(validation.hasMinLength({property.MinimumLength.Value}))");
                }

                if (property.MaximumLength.HasValue)
                {
                    result.Append($".addValidator(validation.hasMinLength({property.MaximumLength.Value}))");
                }

                if (property.Format == Format.Email)
                {
                    result.Append(".addValidator(validation.isEmail)");
                }

                if (property.Maximum != null & property.Maximum != null)
                {
                    result.Append($".addValidator(validation.isInRange({property.Minimum}, {property.Maximum}))");
                }
                else if (property.Maximum != null)
                {
                    result.Append($".addValidator(validation.isAtMost({property.Maximum}))");
                }
                else if (property.Minimum != null)
                {
                    result.Append($".addValidator(validation.isAtLeast({property.Minimum}))");
                }
            }

            result.AppendLine(";");
        }
        private void WriteProperty(PropertyNode property, StringBuilder result, bool edition)
        {
            AppendFormatDocumentation(result, property.Documentation);

            result.Append($"{Tab}{property.Name}");
            if (!property.IsRequired)
            {
                result.Append("?");
            }
            result.Append(": ");
            WriteTypedNode(property, result, edition, prefixModule: PrefixModules.None, allowObservable: false);
            result.AppendLine(";");
        }
        private PropertyNode ReadProperty(PropertyInfo propertyInfo, Type[] newParents, AssemblyNode assembly, string version)
        {
            var propertyType = propertyInfo.PropertyType;
            var propertyNode = new PropertyNode
            {
                Name = StringHelpers.ToCamelCase(propertyInfo.Name),
                IsRequired = RemoveNullable(ref propertyType),
                Documentation = documentation.GetDocumentation(propertyInfo)
            };

            var returnTypeAttributes = propertyInfo.GetCustomAttributes<ReturnTypeAttribute>().ToArray();
            if (returnTypeAttributes.Any())
            {
                if (returnTypeAttributes.Length == 1)
                {
                    FillType(propertyNode, returnTypeAttributes[0].ReturnType, assembly, newParents, version);
                }
                else
                {
                    propertyNode.Type = new TypeNode
                    {
                        Type = TypeIdentifier.Union,
                        Union = returnTypeAttributes.Select(x => ReadType(x.ReturnType, assembly, newParents, version)).ToArray()
                    };
                }
            }
            else
            {
                FillType(propertyNode, propertyType, assembly, newParents, version);
            }

            var readOnly = propertyInfo.GetCustomAttribute<ReadOnlyAttribute>();
            if (readOnly != null && readOnly.IsReadOnly)
            {
                propertyNode.IsReadOnly = true;
            }
            var editable = propertyInfo.GetCustomAttribute<EditableAttribute>();
            if (editable != null && !editable.AllowEdit)
            {
                propertyNode.IsReadOnly = true;
            }

            propertyNode.IsObservable = propertyNode.Name != "id" && !propertyNode.IsReadOnly;

            GetConstraints(propertyInfo.GetCustomAttributes().ToArray(), propertyNode);

            return propertyNode;
        }