Example #1
0
        /// <summary>
        /// Write metadata common to all value representations, like properties and method parameters.
        /// </summary>
        private void WriteValueCommonMetadata(TypeScriptCodeBuilder b, IValueViewModel value)
        {
            b.StringProp("name", value.JsVariable);
            b.StringProp("displayName", value.DisplayName);

            WriteTypeCommonMetadata(b, value.Type);
        }
Example #2
0
        /// <summary>
        /// Write metadata common to all type representations,
        /// like properties, method parameters, method returns, etc.
        /// </summary>
        private void WriteTypeCommonMetadata(TypeScriptCodeBuilder b, TypeViewModel type)
        {
            void WriteTypeDiscriminator(string propName, TypeViewModel t)
            {
                var kind = t.TsTypeKind;

                switch (kind)
                {
                case TypeDiscriminator.Unknown:
                    // We assume any unknown props are strings.
                    b.Line("// Type not supported natively by Coalesce - falling back to string.");
                    b.StringProp(propName, "string");
                    break;

                default:
                    b.StringProp(propName, kind.ToString().ToLowerInvariant());
                    break;
                }
            }

            void WriteTypeDef(string propName, TypeViewModel t)
            {
                var kind = t.TsTypeKind;

                switch (kind)
                {
                case TypeDiscriminator.Enum:
                    b.Line($"get {propName}() {{ return domain.enums.{t.Name} }},");
                    break;

                case TypeDiscriminator.Model:
                case TypeDiscriminator.Object:
                    b.Line($"get {propName}() {{ return {GetClassMetadataRef(t.ClassViewModel)} }},");
                    break;
                }
            }

            WriteTypeDiscriminator("type", type);
            WriteTypeDef("typeDef", type);

            // For collections, write the references to the underlying type.
            if (type.TsTypeKind == TypeDiscriminator.Collection)
            {
                if (type.PureType.TsTypeKind == TypeDiscriminator.Collection)
                {
                    throw new InvalidOperationException("Collections of collections aren't supported by Coalesce as exposed types");
                }

                using (b.Block($"itemType:", ','))
                {
                    b.StringProp("name", "$collectionItem");
                    b.StringProp("displayName", "");
                    b.StringProp("role", "value");
                    WriteTypeCommonMetadata(b, type.PureType);
                }
            }
        }
Example #3
0
 private void WriteCommonClassMetadata(TypeScriptCodeBuilder b, ClassViewModel model)
 {
     b.StringProp("name", model.ClientTypeName.ToCamelCase());
     b.StringProp("displayName", model.DisplayName);
     if (model.ListTextProperty != null)
     {
         // This might not be defined for external types, because sometimes it just doesn't make sense. We'll accommodate on the client.
         b.Line($"get displayProp() {{ return this.props.{model.ListTextProperty.JsVariable} }}, ");
     }
 }
Example #4
0
        private void WriteServiceMetadata(TypeScriptCodeBuilder b, ClassViewModel model)
        {
            using (b.Block($"export const {model.ClientTypeName} = domain.services.{model.ClientTypeName} ="))
            {
                b.StringProp("name", model.ClientTypeName.ToCamelCase());
                b.StringProp("displayName", model.DisplayName);

                b.StringProp("type", "service");
                b.StringProp("controllerRoute", model.ApiRouteControllerPart);

                WriteClassMethodMetadata(b, model);
            }
        }
Example #5
0
        private void WriteClassPropertyMetadata(TypeScriptCodeBuilder b, ClassViewModel model, PropertyViewModel prop)
        {
            using (b.Block($"{prop.JsVariable}:", ','))
            {
                WriteValueCommonMetadata(b, prop);

                switch (prop.Role)
                {
                case PropertyRole.PrimaryKey:
                    // TS Type: "PrimaryKeyProperty"
                    b.StringProp("role", "primaryKey");
                    break;

                case PropertyRole.ForeignKey:
                    // TS Type: "ForeignKeyProperty"
                    var navProp = prop.ReferenceNavigationProperty;
                    b.StringProp("role", "foreignKey");
                    b.Line($"get principalKey() {{ return {GetClassMetadataRef(navProp.Object)}.props.{navProp.Object.PrimaryKey.JsVariable} as PrimaryKeyProperty }},");
                    b.Line($"get principalType() {{ return {GetClassMetadataRef(navProp.Object)} }},");
                    b.Line($"get navigationProp() {{ return {GetClassMetadataRef(model)}.props.{navProp.JsVariable} as ModelReferenceNavigationProperty }},");
                    break;

                case PropertyRole.ReferenceNavigation:
                    // TS Type: "ModelReferenceNavigationProperty"
                    b.StringProp("role", "referenceNavigation");
                    b.Line($"get foreignKey() {{ return {GetClassMetadataRef(model)}.props.{prop.ForeignKeyProperty.JsVariable} as ForeignKeyProperty }},");
                    b.Line($"get principalKey() {{ return {GetClassMetadataRef(prop.Object)}.props.{prop.Object.PrimaryKey.JsVariable} as PrimaryKeyProperty }},");
                    break;

                case PropertyRole.CollectionNavigation:
                    // TS Type: "ModelCollectionNavigationProperty"
                    b.StringProp("role", "collectionNavigation");
                    b.Line($"get foreignKey() {{ return {GetClassMetadataRef(prop.Object)}.props.{prop.InverseProperty.ForeignKeyProperty.JsVariable} as ForeignKeyProperty }},");
                    break;

                default:
                    b.StringProp("role", "value");
                    break;
                }

                // We store the negative case instead of the positive
                // because there are likely going to be more that are serializable than not.
                if (!prop.IsClientSerializable)
                {
                    b.Line("dontSerialize: true,");
                }
            }
        }
Example #6
0
        private void WriteApiBackedTypeMetadata(TypeScriptCodeBuilder b, ClassViewModel model)
        {
            using (b.Block($"export const {model.ViewModelClassName} = domain.types.{model.ViewModelClassName} ="))
            {
                WriteCommonClassMetadata(b, model);
                b.StringProp("type", "model");
                b.StringProp("controllerRoute", model.ApiRouteControllerPart);
                b.Line($"get keyProp() {{ return this.props.{model.PrimaryKey.JsVariable} }}, ");

                WriteClassPropertiesMetadata(b, model);

                WriteClassMethodMetadata(b, model);

                WriteDataSourcesMetadata(b, model);
            }
        }
Example #7
0
 /// <summary>
 /// Write the metadata for a specific parameter to a specific method
 /// </summary>
 private void WriteMethodParameterMetadata(TypeScriptCodeBuilder b, MethodViewModel method, ParameterViewModel parameter)
 {
     using (b.Block($"{parameter.JsVariable}:", ','))
     {
         WriteValueCommonMetadata(b, parameter);
         b.StringProp("role", "value");
     }
 }
Example #8
0
        private void WriteEnumMetadata(TypeScriptCodeBuilder b, TypeViewModel model)
        {
            using (b.Block($"export const {model.Name} = domain.enums.{model.Name} ="))
            {
                b.StringProp("name", model.Name.ToCamelCase());
                b.StringProp("displayName", model.DisplayName);
                b.StringProp("type", "enum");

                string enumShape = string.Join("|", model.EnumValues.Select(ev => $"\"{ev.Value}\""));
                b.Line($"...getEnumMeta<{enumShape}>([");
                foreach (var value in model.EnumValues)
                {
                    // TODO: allow for localization of displayName
                    b.Indented($"{{ value: {value.Key}, strValue: '{value.Value}', displayName: '{value.Value.ToProperCase()}' }},");
                }
                b.Line("]),");
            }
        }
Example #9
0
        private void WriteExternalTypeMetadata(TypeScriptCodeBuilder b, ClassViewModel model)
        {
            using (b.Block($"export const {model.ViewModelClassName} = domain.types.{model.ViewModelClassName} ="))
            {
                WriteCommonClassMetadata(b, model);
                b.StringProp("type", "object");

                WriteClassPropertiesMetadata(b, model);
            }
        }
Example #10
0
        /// <summary>
        /// Write the metadata for an entire method
        /// </summary>
        private void WriteClassMethodMetadata(TypeScriptCodeBuilder b, ClassViewModel model, MethodViewModel method)
        {
            using (b.Block($"{method.JsVariable}:", ','))
            {
                b.StringProp("name", method.JsVariable);
                b.StringProp("displayName", method.DisplayName);
                b.StringProp("transportType", method.TransportType.ToString().Replace("Result", "").ToLower());
                b.StringProp("httpMethod", method.ApiActionHttpMethod.ToString().ToUpperInvariant());

                using (b.Block("params:", ','))
                {
                    // TODO: should we be writing out the implicit 'id' param as metadata? Or handling some other way?
                    // If we do keep it as metadata, should probably add some prop to mark it as what it is.
                    if (method.IsModelInstanceMethod)
                    {
                        using (b.Block($"id:", ','))
                        {
                            b.StringProp("name", "id");
                            b.StringProp("displayName", "Primary Key"); // TODO: Is this what we want? Also, i18n.
                            b.StringProp("role", "value");
                            WriteTypeCommonMetadata(b, model.PrimaryKey.Type);
                        }
                    }

                    foreach (var param in method.ClientParameters)
                    {
                        WriteMethodParameterMetadata(b, method, param);
                    }
                }

                using (b.Block("return:", ','))
                {
                    b.StringProp("name", "$return");
                    b.StringProp("displayName", "Result"); // TODO: i18n
                    b.StringProp("role", "value");
                    WriteTypeCommonMetadata(b, method.ResultType);
                }
            }
        }
Example #11
0
        /// <summary>
        /// Write the metadata for all data sources of a class
        /// </summary>
        private void WriteDataSourceMetadata(TypeScriptCodeBuilder b, ClassViewModel model, ClassViewModel source)
        {
            // TODO: Should we be camel-casing the names of data sources in the metadata?
            // TODO: OR, should we be not camel casing the members we place on the domain[key: string] objects?
            using (b.Block($"{source.ClientTypeName.ToCamelCase()}:", ','))
            {
                b.StringProp("type", "dataSource");

                WriteCommonClassMetadata(b, source);

                if (source.IsDefaultDataSource)
                {
                    b.Line("isDefault: true,");
                }

                using (b.Block("params:", ','))
                {
                    foreach (var prop in source.DataSourceParameters)
                    {
                        WriteClassPropertyMetadata(b, model, prop);
                    }
                }
            }
        }