private bool TryResolveRelationship(Entity owner, string key, IType type, out Entity result) { templateRelationship[] relationships = owner.Template().Relationship; templateRelationship relationship = relationships?.FirstOrDefault(r => r.name.Equals(key, StringComparison.OrdinalIgnoreCase)) ?? relationships?.FirstOrDefault( r => r.name.Equals(key.Singular(), StringComparison.OrdinalIgnoreCase)); TemplateDescription relationshipDescription = relationship != null?templateRepository.Template(relationship.type) : null; if (relationshipDescription != null) { IEnumerable <string> names = type.Attributes .Where(a => a.Name.Equals(relationship.name, StringComparison.OrdinalIgnoreCase)) .SelectMany(a => a.Values); result = relationship.GetRelationship(relationshipDescription, owner, names.ToArray()); return(true); } result = null; return(false); }
public override Entity Resolve(Entity owner, string key, bool fallback = false) { TemplateEntity ownerTemplateEntity = TemplateEntity.Decorate(owner); if (key == EntityKeys.FieldArpDataTypeKey && owner.Type == EntityKeys.FormatKey) { return(ResolveArpDataType()); } if (key == EntityKeys.TypeMetaDataFormatKey && owner.Type == EntityKeys.FormatKey) { return(ResolveTypeMetaDataFormat()); } if (key == EntityKeys.ExpandHiddenTypesFormatKey) { return(ExpandHiddenTypes()); } if (key == EntityKeys.FilterHiddenTypesFormatKey) { return(FilterHiddenTypes()); } if (key == EntityKeys.IsFieldKey) { return(owner.Create(key, CodeEntity.Decorate(owner).AsField != null)); } if (key == EntityKeys.IsTypeKey) { return(owner.Create(key, CodeEntity.Decorate(owner).AsType != null)); } if (key == EntityKeys.BigDataProjectKey) { return(GetBigDataProjectEntity()); } if (key == EntityKeys.NormalProjectKey) { return(GetNormalProjectEntity()); } ISymbol symbol = owner.Value <ISymbol>(); if (symbol != null) { Entity result = owner.PropertyValueEntity(key, symbol); if (result != null) { return(result); } throw new ContentProviderException(key, owner); } if (key == EntityKeys.BaseDirectoryKey && HasBaseDirectory(owner, out string baseDirectory)) { return(owner.Create(key, baseDirectory)); } IType type = owner.Value <IType>(); if (type != null) { return(ResolveType()); } IField field = owner.Value <IField>(); if (field != null) { return(ResolveField()); } IDataType dataType = owner.Value <IDataType>(); if (dataType != null) { return(ResolveDataType()); } ICodeModel codeModel = owner.Value <ICodeModel>(); if (codeModel != null) { return(ResolveCodeModel()); } throw new ContentProviderException(key, owner); IEnumerable <CodeEntity> GetPortEnums() { return(GetAllPorts().Concat(GetPortStructures().SelectMany(p => p.Fields)) .Select(f => f.ResolvedType) .Where(t => t.AsEnum != null) .Distinct()); } IEnumerable <CodeEntity> GetAllPorts() { bool IsPort(CodeEntity fieldEntity) { return(fieldEntity.AsField != null && fieldEntity.AsField.HasAttributeWithoutValue(EntityKeys.PortAttributeKey)); } return(TemplateEntity.Decorate(owner).EntityHierarchy .Select(CodeEntity.Decorate) .SelectMany(c => c.Fields) .Where(IsPort)); } IEnumerable <CodeEntity> GetPortStructures() { HashSet <CodeEntity> structures = new HashSet <CodeEntity>(GetAllPorts() .Select(f => f.ResolvedType) .Where(t => t.AsType != null && t.AsEnum == null), new FullNameCodeEntityComparer()); HashSet <CodeEntity> visited = new HashSet <CodeEntity>(new FullNameCodeEntityComparer()); while (structures.Except(visited).Any()) { foreach (CodeEntity structure in structures.Except(visited).ToArray()) { foreach (CodeEntity structureField in structure.Fields) { CodeEntity structureDataType = structureField.ResolvedType; if (structureDataType.AsType != null && structureDataType.AsEnum == null) { structures.Add(structureDataType); } } visited.Add(structure); } } return(structures); } Entity FilterHiddenTypes() { IEnumerable <IType> types = owner.Select(CodeEntity.Decorate) .Where(c => !c.IsHidden()) .Select(c => c.AsType) .ToArray(); string name = owner.FirstOrDefault()?.Name ?? string.Empty; return(owner.Create(key, types.Select(t => owner.Create(name, t.FullName, t)))); } Entity ExpandHiddenTypes() { IEnumerable <CodeEntity> dataSourceFields = owner.Select(CodeEntity.Decorate); dataSourceFields = ExpandHiddenStructureFields(dataSourceFields); string name = owner.FirstOrDefault()?.Name ?? string.Empty; return(owner.Create(key, dataSourceFields.Select(e => e.AsField) .Select(f => owner.Create(name, f.Name, f)))); IEnumerable <CodeEntity> ExpandHiddenStructureFields(IEnumerable <CodeEntity> fields) { foreach (CodeEntity hiddenField in fields) { CodeEntity hiddenType = hiddenField.ResolvedType; if (hiddenType == null || !hiddenType.IsHidden()) { yield return(hiddenField); continue; } foreach (CodeEntity hiddenTypeField in ExpandHiddenStructureFields(hiddenType.Fields)) { yield return(hiddenTypeField); } } } } T ChooseMetaDataTemplate <T>(IEnumerable <(T template, string name, string context)> templates) { return(templates.OrderByDescending(t => ContextComplexity(t.context ?? string.Empty)) .FirstOrDefault(Matches) .template); bool Matches((T template, string name, string context) template) { if (!key.Equals(template.name, StringComparison.OrdinalIgnoreCase)) { return(false); } if (string.IsNullOrEmpty(template.context)) { return(true); } string[] contextPath = template.context.Split(new [] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries) .Reverse().ToArray(); Entity current = owner; foreach (string part in contextPath) { current = current?.Owner; if (current?[$"is{part}"].Value <bool>() != true) { return(false); } } return(true); } int ContextComplexity(string context) { return(context.Count(c => c == '/' || c == '\\')); } } Entity ResolveType() { switch (key) { case EntityKeys.PathKey: { return(owner.Create(key, type.GetFile(owner).Parent.FullName)); } case EntityKeys.FieldsKey: { return(owner.Create(key, type.Fields.Select(f => owner.Create(key.Singular(), f.Name, f)))); } case EntityKeys.FileKey: { VirtualFile file = owner.Root.Value <ICodeModel>() .Types[type]; return(owner.Create(key, file.Name, file)); } case EntityKeys.BaseTypeKey: { IDataType baseType = type.BaseTypes.FirstOrDefault(); return(owner.Create(key, baseType)); } default: { if (TryResolveTypeTemplate(out Entity result)) { return(result); } if (TryResolveProperty(out result)) { return(result); } if (TryResolveFields(out result)) { return(result); } if (TryResolveRelationship(out result)) { return(result); } throw new ContentProviderException(key, owner); } } bool TryResolveTypeTemplate(out Entity result) { Templates.Type.metaDataTemplate typeMetaDataTemplate = ChooseMetaDataTemplate(templateRepository.TypeTemplates .Select(t => (t, t.name, t.context))); if (typeMetaDataTemplate != null) { result = GetTypeTemplateEntity(typeMetaDataTemplate); return(true); } result = null; return(false); Entity GetTypeTemplateEntity(Templates.Type.metaDataTemplate metaDataTemplate) { if (!metaDataTemplate.hasvalue) { bool hasAttribute = type.HasAttributeWithoutValue(metaDataTemplate.name); return(owner.Create(key, new Func <string>(hasAttribute.ToString), hasAttribute)); } (string[] values, CodePosition position) = GetTypeTemplateValue(); IEnumerable <string> formattedValues = VerifyValues().ToArray(); return(metaDataTemplate.multiplicity == Templates.Type.multiplicity.OneOrMore ? owner.Create(key, formattedValues.Select(v => owner.Create(key.Singular(), v))) : owner.Create(key, formattedValues.First())); IEnumerable <string> VerifyValues() { return(values.Select(VerifyValue)); string VerifyValue(string arg) { (bool success, string message, string newValue) = metaDataTemplate.ValueRestriction.Verify(arg); if (!success) { owner.AddCodeException(new FieldAttributeRestrictionException(metaDataTemplate.name, arg, message, position, type.GetFile(owner))); } return(newValue); } } (string[], CodePosition) GetTypeTemplateValue() { IAttribute attribute = type.Attributes.LastOrDefault(a => a.Name.Equals(metaDataTemplate.name, StringComparison.OrdinalIgnoreCase)); string value = attribute?.Values.FirstOrDefault() ?? resolver.Resolve(metaDataTemplate.defaultvalue, owner); return(metaDataTemplate.multiplicity == Templates.Type.multiplicity.OneOrMore ? value.Split(new[] { metaDataTemplate.split }, StringSplitOptions.RemoveEmptyEntries) : new[] { value }, attribute?.Position ?? new CodePosition(0, 0)); } } } bool TryResolveProperty(out Entity result) { result = owner.PropertyValueEntity(key, type); return(result != null); } bool TryResolveFields(out Entity result) { metaDataTemplate metaDataTemplate = templateRepository.FieldTemplates .FirstOrDefault(t => t.name.Plural().Equals(key, StringComparison .OrdinalIgnoreCase)); if (metaDataTemplate != null) { IEnumerable <IField> fields = type.Fields .Where(f => f.Attributes .Any(a => a.Name .Equals(metaDataTemplate.name, StringComparison.OrdinalIgnoreCase))); result = owner.Create(key, fields.Select(f => owner.Create(metaDataTemplate.name, f.Name, f))); return(true); } result = null; return(false); } bool TryResolveRelationship(out Entity result) { templateRelationship[] relationships = owner.Template().Relationship; templateRelationship relationship = relationships?.FirstOrDefault(r => r.name.Equals(key, StringComparison.OrdinalIgnoreCase)) ?? relationships?.FirstOrDefault(r => r.name.Equals(key.Singular(), StringComparison.OrdinalIgnoreCase)); TemplateDescription relationshipDescription = relationship != null?templateRepository.Template(relationship.type) : null; if (relationshipDescription != null) { IEnumerable <string> names = type.Attributes .Where(a => a.Name.Equals(relationship.name, StringComparison.OrdinalIgnoreCase)) .SelectMany(a => a.Values); result = relationship.GetRelationship(relationshipDescription, owner, names.ToArray()); return(true); } result = null; return(false); } } Entity ResolveField() { switch (key) { case EntityKeys.FieldNameKey: { return(owner.Create(key, field.Name)); } case EntityKeys.DataTypeKey: { IDataType fieldDataType = GetRealFieldDataType(); return(owner.Create(key, fieldDataType.Name, fieldDataType)); } case EntityKeys.ResolvedTypeKey: { ICodeModel model = owner.Root.Value <ICodeModel>(); IDataType fieldDataType = field.DataType; IType realType = fieldDataType.PotentialFullNames .Select(model.Type) .FirstOrDefault(t => t != null); return(owner.Create(key, realType?.Name, realType)); } case EntityKeys.MultiplicityKey: { return(owner.Create(key, field.Multiplicity.Select(m => owner.Create(key, new Func <string>(m.ToString), m)))); } default: { metaDataTemplate metaDataTemplate = templateRepository.FieldTemplates .FirstOrDefault(t => t.name.Equals(key, StringComparison.OrdinalIgnoreCase)); if (metaDataTemplate != null) { return(GetFieldTemplateEntity(metaDataTemplate)); } throw new ContentProviderException(key, owner); } } IDataType GetRealFieldDataType() { ICodeModel rootCodeModel = owner.Root.Value <ICodeModel>(); IEnum @enum = field.DataType.PotentialFullNames.Select(n => rootCodeModel.GetEnum(n)).FirstOrDefault(e => e != null); if (@enum != null) { (IDataType enumBaseType, _) = GetEnumBaseType(@enum); return(enumBaseType); } return(field.DataType); } Entity GetFieldTemplateEntity(metaDataTemplate metaDataTemplate) { if (!metaDataTemplate.hasvalue) { bool hasAttribute = field.HasAttributeWithoutValue(metaDataTemplate.name); return(owner.Create(key, new Func <string>(hasAttribute.ToString), hasAttribute)); } (string[] values, CodePosition position) = GetFieldTemplateValue(); IEnumerable <string> formattedValues = VerifyValues().ToArray(); return(metaDataTemplate.multiplicity == multiplicity.OneOrMore ? owner.Create(key, formattedValues.Select(v => owner.Create(key.Singular(), v))) : owner.Create(key, formattedValues.First())); IEnumerable <string> VerifyValues() { return(values.Select(VerifyValue)); string VerifyValue(string arg) { (bool success, string message, string newValue) = metaDataTemplate.ValueRestriction.Verify(arg); if (!success) { owner.AddCodeException(new FieldAttributeRestrictionException(metaDataTemplate.name, arg, message, position, field.GetFile(owner))); } return(newValue); } } (string[], CodePosition) GetFieldTemplateValue() { IAttribute attribute = field.Attributes.LastOrDefault(a => a.Name.Equals(metaDataTemplate.name, StringComparison.OrdinalIgnoreCase)); string value = string.IsNullOrEmpty(attribute?.Values.FirstOrDefault()) ? resolver.Resolve(metaDataTemplate.defaultvalue, owner) : attribute.Values.First(); return(metaDataTemplate.multiplicity == multiplicity.OneOrMore ? value.Split(new[] { metaDataTemplate.split }, StringSplitOptions.RemoveEmptyEntries) : new[] { value }, attribute?.Position ?? new CodePosition(0, 0)); } } } Entity ResolveCodeModel() { switch (key) { case EntityKeys.PortStructsKey: { return(owner.Create(key, GetPortStructures().Select(c => c.Base))); } case EntityKeys.PortEnumsKey: { return(owner.Create(key, GetPortEnums().Select(c => c.Base))); } case EntityKeys.NamespaceKey: { bool prior206Target = CheckProjectTargets(); IEnumerable <string> relevantTypes = TemplateEntity.Decorate(owner).EntityHierarchy .Select(CodeEntity.Decorate) .Where(c => !c.IsRoot()) .Select(c => c.FullName); string ns = prior206Target ? codeModel.RootNamespaceForOldTarget( relevantTypes.ToArray(), GetPortStructures().Concat(GetPortEnums()) .Select(c => c.FullName) .ToArray()) : codeModel.RootNamespace(relevantTypes.ToArray()); if (string.IsNullOrEmpty(ns)) { ns = owner.Name; } return(owner.Create(key, ns)); } default: throw new ContentProviderException(key, owner); } bool CheckProjectTargets() { IEnumerable <TargetEntity> targets = ProjectEntity.Decorate(owner).Targets.Select(t => TargetEntity.Decorate(t)); return(targets.Any(t => t.Version < new Version(20, 6))); } } Entity ResolveDataType() { switch (key) { case EntityKeys.NameKey: return(owner.Create(key, dataType.Name)); case EntityKeys.FullNameKey: string fullName = GetDataTypeFullName(); return(owner.Create(key, fullName)); default: throw new ContentProviderException(key, owner); } string GetDataTypeFullName() { ICodeModel rootCodeModel = owner.Root.Value <ICodeModel>(); return(dataType.PotentialFullNames.FirstOrDefault(fn => rootCodeModel.Type(fn) != null) ?? dataType.Name); } } Entity ResolveTypeMetaDataFormat() { IEntityBase dataSource = ownerTemplateEntity.FormatOrigin; IDataType dataSourceDataType = dataSource.HasValue <IDataType>() ? dataSource.Value <IDataType>() : dataSource.Value <IField>().DataType; ICodeModel rootCodeModel = dataSource.Root.Value <ICodeModel>(); string dataTypeName = string.Empty; if (dataSourceDataType != null) { dataTypeName = dataSourceDataType.PotentialFullNames .Select(n => rootCodeModel.Type(n)) .FirstOrDefault(t => t != null) ?.Name ?? datatypeConversion.Convert(dataSourceDataType); } return(owner.Create(key, dataTypeName)); } Entity ResolveArpDataType() { IEntityBase dataSource = ownerTemplateEntity.FormatOrigin; IField dataSourceField = dataSource.Value <IField>(); if (dataSourceField == null) { throw new FormatTargetMismatchException("arpDataType", "field|port", dataSource.Type); } ICodeModel rootCodeModel = dataSource.Root.Value <ICodeModel>(); bool isStruct = dataSourceField.DataType.PotentialFullNames.Any(n => rootCodeModel.GetClass(n) != null || rootCodeModel.GetStructure(n) != null); IEnum @enum = dataSourceField.DataType.PotentialFullNames.Select(n => rootCodeModel.GetEnum(n)).FirstOrDefault(e => e != null); bool isArray = dataSourceField.Multiplicity.Any(); string arpName = "DataType::" + GetArpDataType(dataSourceField.DataType.Name); return(owner.Create(key, arpName)); string GetArpDataType(string dataTypeName) { string postfix = isArray ? " | DataType::Array" : string.Empty; if (isStruct) { return("Struct" + postfix); } if (@enum != null) { (IDataType enumBaseType, string formattedBaseType) = GetEnumBaseType(@enum); return($"Enum | DataType::{formattedBaseType}" + postfix); } (bool success, string value) = FormatDataType(dataTypeName); if (!success) { throw new UnknownDataTypeException(value); } return(value + postfix); } } (bool success, string value) FormatDataType(string unformattedValue) { if (unformattedValue.Contains('<')) { unformattedValue = unformattedValue.Substring(0, unformattedValue.IndexOf('<')); } string result = owner.Create("temporaryCtnFormatContainer", unformattedValue).Format()["knownDataTypes"].Value <string>(); Match unkownMatch = UnkownDataTypeRegex.Match(result); if (unkownMatch.Success) { return(false, unkownMatch.Groups["dataType"].Value); } return(true, result); } (IDataType, string) GetEnumBaseType(IEnum @enum) { IDataType enumDataType = @enum.BaseTypes.FirstOrDefault(); string enumBaseType = enumDataType?.Name; if (string.IsNullOrEmpty(enumBaseType)) { throw new MissingEnumDataTypeException(@enum); } (bool formatted, string formattedBaseType) = FormatDataType(enumBaseType); if (!formatted) { throw new UnkownEnumDataTypeException(formattedBaseType, @enum); } return(enumDataType, formattedBaseType); } Entity GetBigDataProjectEntity() { if (HasMoreThan1000Fields()) { return(owner.Create(key, "true", true)); } return(owner.Create(key, "false", false)); } Entity GetNormalProjectEntity() { if (HasMoreThan1000Fields()) { return(owner.Create(key, "false", false)); } return(owner.Create(key, "true", true)); } bool HasMoreThan1000Fields() { ICodeModel model = owner.Value <ICodeModel>(); if (model == null || GetAllPorts().Concat(GetPortStructures().SelectMany(s => s.Fields)).Count() <= 1000) { return(false); } return(true); } }
public override Entity Resolve(Entity owner, string key, bool fallback = false) { templateRelationship[] relationships = owner.HasTemplate() ? owner.Template().Relationship : null; templateRelationship relationship = relationships?.FirstOrDefault(r => r.name.Equals(key, StringComparison.OrdinalIgnoreCase)) ?? relationships?.FirstOrDefault(r => r.name.Equals(key.Singular(), StringComparison.OrdinalIgnoreCase)); TemplateDescription relationshipDescription = relationship != null?templateRepository.Template(relationship.type) : null; if (relationshipDescription != null) { return(GetRelationship()); } if (key == EntityKeys.PathKey) { return(GetCommandPath()); } if (key == EntityKeys.FullNameKey) { return(GetFullName()); } return(GetArgument()); Entity GetFullName() { SingleValueArgument nameArgument = owner.Value <CommandDefinition>() .Argument <SingleValueArgument>(EntityKeys.NameKey); SingleValueArgument namespaceArgument = owner.Value <CommandDefinition>() .Argument <SingleValueArgument>(EntityKeys.NamespaceKey); string fullName = codeLanguage.CombineNamespace(Value(namespaceArgument, EntityKeys.NamespaceKey), Value(nameArgument, EntityKeys.NameKey)); return(owner.Create(key, fullName, nameArgument, namespaceArgument)); } Entity GetCommandPath() { SingleValueArgument singleValueArgument = owner.Value <CommandDefinition>() .Argument <SingleValueArgument>(EntityKeys.OutputKey); string basePath = owner.IsRoot() ? string.Empty : owner.Root.Path; string path = fileSystem.GetDirectory(Value(singleValueArgument), basePath, false).FullName; return(owner.Create(key, path, singleValueArgument)); } string Value(Argument arg, string argumentName = null) { if (string.IsNullOrEmpty(argumentName)) { argumentName = key; } if (arg != null && arg is BoolArgument boolArgument) { return(boolArgument.Value.ToString(CultureInfo.InvariantCulture)); } SingleValueArgument singleValueArgument = (SingleValueArgument)arg; if (singleValueArgument?.Value != null) { return(ResolveValue(singleValueArgument.Value)); } if ((arg != null && arg.Name != argumentName && TryGetTemplateDefault(arg.Name, out string result)) || TryGetTemplateDefault(argumentName, out result)) { return(result); } return(string.Empty); } string ResolveValue(string value) { string result = templateResolver.Resolve(value, owner); if (TryGetTemplateFormat(out string format) && !string.IsNullOrEmpty(format)) { Entity temporary = owner.Create(key, result); result = temporary.Format()[format].Value <string>(); } return(result); bool TryGetTemplateFormat(out string formattedValue) { TemplateDescription description = owner.HasTemplate() ? owner.Template() : null; if (description != null) { templateArgumentDefinition templateArgument = description.Arguments.FirstOrDefault(a => a.name == key); if (templateArgument != null) { formattedValue = templateArgument.format; return(true); } } formattedValue = null; return(false); } } bool TryGetTemplateDefault(string argumentName, out string value) { TemplateDescription description = owner.HasTemplate() ? owner.Template() : null; if (description != null) { templateArgumentDefinition templateArgument = description.Arguments.FirstOrDefault(a => a.name == argumentName); if (templateArgument != null) { value = ResolveValue(templateArgument.@default); return(true); } } value = null; return(false); } Entity GetArgument() { Argument argument = owner.Value <CommandDefinition>().Argument <Argument>(key); if (argument == null) { if (TryGetTemplateDefault(key, out string value)) { return(owner.Create(key, value)); } throw new ContentProviderException(key, owner); } switch (argument) { case BoolArgument boolArgument: return(owner.Create(key, Value(argument), boolArgument)); case SingleValueArgument singleValueArgument: return(owner.Create(key, Value(argument), singleValueArgument)); case MultipleValueArgument multipleValueArgument: IEnumerable <Entity> values = Values(multipleValueArgument); return(owner.Create(key, values)); default: throw new InvalidOperationException($"Unkown argument type {argument.GetType()}"); } IEnumerable <Entity> Values(MultipleValueArgument multipleValueArgument) { if (multipleValueArgument.Values != null) { return(multipleValueArgument.Values .Select(s => owner.Create(key, ResolveValue(s), multipleValueArgument))); } if (TryGetTemplateDefault(key, out string result)) { return(new[] { owner.Create(key, result, multipleValueArgument) }); } throw new ContentProviderException(key, owner); } } Entity GetRelationship() { if (relationshipDescription.isRoot) { return(owner.Root); } if (relationship.multiplicity == multiplicity.One) { string name = owner.Value <CommandDefinition>() .Argument <SingleValueArgument>(relationship.name) .Value; return(relationship.GetRelationship(relationshipDescription, owner, name)); } IEnumerable <string> names = owner.Value <CommandDefinition>() .Argument <MultipleValueArgument>(relationship.name) .Values; return(relationship.GetRelationship(relationshipDescription, owner, names.ToArray())); } }