diff --git a/uml4net.Extensions.Tests/ClassExtensionsTestFixture.cs b/uml4net.Extensions.Tests/ClassExtensionsTestFixture.cs
index 1128c5ab..5e7f3f08 100644
--- a/uml4net.Extensions.Tests/ClassExtensionsTestFixture.cs
+++ b/uml4net.Extensions.Tests/ClassExtensionsTestFixture.cs
@@ -584,5 +584,135 @@ public void Verify_that_QueryAllDescendantSpecializations_returns_expected_resul
Assert.That(descendants.Any(x => x.Name == "Activity"), Is.True);
}
}
+
+ [Test]
+ public void Verify_that_QueryAllNonDerivedProperties_returns_the_properties_that_are_not_derived()
+ {
+ var dependency = this.QueryClass("CommonStructure", "Dependency");
+
+ var properties = dependency.QueryAllNonDerivedProperties();
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(properties, Is.Not.Empty);
+ Assert.That(properties.Any(x => x.IsDerived), Is.False);
+ Assert.That(properties, Is.EqualTo(dependency.QueryAllProperties().Where(x => !x.IsDerived)));
+ Assert.That(properties.Select(x => x.XmiId), Does.Contain("Dependency-client"));
+ Assert.That(properties.Select(x => x.XmiId), Does.Not.Contain("Element-ownedElement"), "ownedElement is a derived union");
+ Assert.That(() => ClassExtensions.QueryAllNonDerivedProperties(null), Throws.ArgumentNullException);
+ }
+ }
+
+ [Test]
+ public void Verify_that_QueryAllNonDerivedNonRedefinedProperties_leaves_out_the_properties_that_are_redefined_in_the_class()
+ {
+ var @class = this.QueryClass("StructuredClassifiers", "Class");
+
+ var nonDerived = @class.QueryAllNonDerivedProperties().Select(x => x.XmiId).ToList();
+ var nonDerivedNonRedefined = @class.QueryAllNonDerivedNonRedefinedProperties().Select(x => x.XmiId).ToList();
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(nonDerived, Does.Contain("NamedElement-visibility"));
+ Assert.That(nonDerivedNonRedefined, Does.Not.Contain("NamedElement-visibility"), "redefined by PackageableElement::visibility");
+ Assert.That(nonDerivedNonRedefined, Does.Contain("PackageableElement-visibility"));
+ Assert.That(nonDerivedNonRedefined, Is.SubsetOf(nonDerived));
+ Assert.That(() => ClassExtensions.QueryAllNonDerivedNonRedefinedProperties(null), Throws.ArgumentNullException);
+ }
+ }
+
+ [Test]
+ public void Verify_that_QueryIsSubclassOf_returns_expected_result()
+ {
+ var dependency = this.QueryClass("CommonStructure", "Dependency");
+ var packageableElement = this.QueryClass("CommonStructure", "PackageableElement");
+ var element = this.QueryClass("CommonStructure", "Element");
+ var comment = this.QueryClass("CommonStructure", "Comment");
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(dependency.QueryIsSubclassOf(packageableElement), Is.True, "a direct general class");
+ Assert.That(dependency.QueryIsSubclassOf(element), Is.True, "an indirect general class");
+ Assert.That(dependency.QueryIsSubclassOf(dependency), Is.False, "a class is not a subclass of itself");
+ Assert.That(dependency.QueryIsSubclassOf(comment), Is.False);
+ Assert.That(element.QueryIsSubclassOf(dependency), Is.False);
+
+ Assert.That(dependency.QueryIsSubclassOf("PackageableElement"), Is.True);
+ Assert.That(dependency.QueryIsSubclassOf("Element"), Is.True);
+ Assert.That(dependency.QueryIsSubclassOf("Dependency"), Is.False, "a class is not a subclass of itself");
+ Assert.That(dependency.QueryIsSubclassOf("Comment"), Is.False);
+ Assert.That(dependency.QueryIsSubclassOf("element"), Is.False, "the name is case-sensitive");
+ }
+ }
+
+ [Test]
+ public void Verify_that_QueryIsSubclassOf_throws_for_missing_arguments()
+ {
+ var dependency = new Class { Name = "Dependency" };
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(() => ClassExtensions.QueryIsSubclassOf(null, dependency), Throws.ArgumentNullException);
+ Assert.That(() => dependency.QueryIsSubclassOf((IClass)null), Throws.ArgumentNullException);
+ Assert.That(() => ClassExtensions.QueryIsSubclassOf(null, "Element"), Throws.ArgumentNullException);
+ Assert.That(() => dependency.QueryIsSubclassOf((string)null), Throws.ArgumentException);
+ Assert.That(() => dependency.QueryIsSubclassOf(" "), Throws.ArgumentException);
+ }
+ }
+
+ [Test]
+ public void Verify_that_QueryReferencingProperties_returns_the_properties_that_are_typed_by_the_class()
+ {
+ var comment = this.QueryClass("CommonStructure", "Comment");
+
+ var referencingProperties = comment.QueryReferencingProperties();
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(referencingProperties, Is.Not.Empty);
+ Assert.That(referencingProperties.Select(x => x.Type), Is.All.SameAs(comment));
+ Assert.That(referencingProperties.Select(x => x.XmiId), Does.Contain("Element-ownedComment"));
+ Assert.That(referencingProperties, Is.Unique);
+
+ Assert.That(new Class { Name = "Detached" }.QueryReferencingProperties(), Is.Empty, "a class without a root package");
+ Assert.That(() => ClassExtensions.QueryReferencingProperties(null), Throws.ArgumentNullException);
+ }
+ }
+
+ [Test]
+ public void Verify_that_QueryOwnedManyToManyProperties_returns_expected_result()
+ {
+ var dependency = this.QueryClass("CommonStructure", "Dependency");
+ var comment = this.QueryClass("CommonStructure", "Comment");
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(dependency.QueryOwnedManyToManyProperties().Select(x => x.Name), Is.EqualTo(new[] { "client", "supplier" }));
+ Assert.That(comment.QueryOwnedManyToManyProperties().Select(x => x.Name), Is.EqualTo(new[] { "annotatedElement" }), "body is not a reference property");
+ Assert.That(dependency.QueryOwnedManyToManyProperties().All(x => x.QueryIsMemberOfManyToMany()), Is.True);
+ Assert.That(() => ClassExtensions.QueryOwnedManyToManyProperties(null), Throws.ArgumentNullException);
+ }
+ }
+
+ ///
+ /// Queries the with the specified name from the specified package of the UML metamodel
+ ///
+ ///
+ /// The name of the package that contains the class
+ ///
+ ///
+ /// The name of the class
+ ///
+ ///
+ /// The
+ ///
+ private IClass QueryClass(string packageName, string className)
+ {
+ var root = this.xmiReaderResult.QueryRoot(xmiId: "_0", name: "UML");
+
+ var package = root.NestedPackage.Single(x => x.Name == packageName);
+
+ return package.PackagedElement.OfType().Single(x => x.Name == className);
+ }
}
}
diff --git a/uml4net.Extensions.Tests/ClassifierExtensionsTestFixture.cs b/uml4net.Extensions.Tests/ClassifierExtensionsTestFixture.cs
index f83e0504..c593098a 100644
--- a/uml4net.Extensions.Tests/ClassifierExtensionsTestFixture.cs
+++ b/uml4net.Extensions.Tests/ClassifierExtensionsTestFixture.cs
@@ -126,5 +126,39 @@ public void Verify_that_QueryContainers_throws_when_classifier_is_null()
{
Assert.That(() => ClassifierExtensions.QueryContainers(null), Throws.ArgumentNullException);
}
+
+ [Test]
+ public void Verify_that_QueryConformsTo_returns_expected_result()
+ {
+ var root = this.xmiReaderResult.QueryRoot(xmiId: "_0", name: "UML");
+
+ var commonStructurePackage = root.NestedPackage.Single(x => x.Name == "CommonStructure");
+
+ var dependency = commonStructurePackage.PackagedElement.OfType().Single(x => x.Name == "Dependency");
+ var packageableElement = commonStructurePackage.PackagedElement.OfType().Single(x => x.Name == "PackageableElement");
+ var element = commonStructurePackage.PackagedElement.OfType().Single(x => x.Name == "Element");
+ var comment = commonStructurePackage.PackagedElement.OfType().Single(x => x.Name == "Comment");
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(dependency.QueryConformsTo(dependency), Is.True, "a classifier conforms to itself");
+ Assert.That(dependency.QueryConformsTo(packageableElement), Is.True, "a direct general classifier");
+ Assert.That(dependency.QueryConformsTo(element), Is.True, "an indirect general classifier");
+ Assert.That(dependency.QueryConformsTo(comment), Is.False);
+ Assert.That(element.QueryConformsTo(dependency), Is.False);
+ }
+ }
+
+ [Test]
+ public void Verify_that_QueryConformsTo_throws_for_missing_arguments()
+ {
+ var classifier = new Class { Name = "Classifier" };
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(() => ClassifierExtensions.QueryConformsTo(null, classifier), Throws.ArgumentNullException);
+ Assert.That(() => classifier.QueryConformsTo(null), Throws.ArgumentNullException);
+ }
+ }
}
}
diff --git a/uml4net.Extensions/ClassExtensions.cs b/uml4net.Extensions/ClassExtensions.cs
index 943071af..bbeeaa91 100644
--- a/uml4net.Extensions/ClassExtensions.cs
+++ b/uml4net.Extensions/ClassExtensions.cs
@@ -366,5 +366,184 @@ public static ReadOnlyCollection QueryAllOperations(this IClass @cla
return result.Distinct().OrderBy(x => x.Name).ToList().AsReadOnly();
}
+
+ ///
+ /// Queries all the properties of the , including the inherited ones, that are not derived
+ ///
+ ///
+ /// The from which to query the properties
+ ///
+ ///
+ /// The properties of for which Property::isDerived is false, in the
+ /// same order
+ ///
+ public static ReadOnlyCollection QueryAllNonDerivedProperties(this IClass @class)
+ {
+ if (@class == null)
+ {
+ throw new ArgumentNullException(nameof(@class));
+ }
+
+ return @class.QueryAllProperties()
+ .Where(x => !x.IsDerived)
+ .ToList()
+ .AsReadOnly();
+ }
+
+ ///
+ /// Queries all the properties of the , including the inherited ones, that are not derived
+ /// and that are not redefined in the context of the
+ ///
+ ///
+ /// The from which to query the properties
+ ///
+ ///
+ /// The properties of for which
+ /// finds no redefining property in the
+ /// , in the same order
+ ///
+ public static ReadOnlyCollection QueryAllNonDerivedNonRedefinedProperties(this IClass @class)
+ {
+ if (@class == null)
+ {
+ throw new ArgumentNullException(nameof(@class));
+ }
+
+ return @class.QueryAllNonDerivedProperties()
+ .Where(x => !x.TryQueryRedefinedByProperty(@class, out _))
+ .ToList()
+ .AsReadOnly();
+ }
+
+ ///
+ /// Queries whether the is a direct or indirect subclass of the
+ ///
+ ///
+ /// The subject
+ ///
+ ///
+ /// The that is expected to be a direct or indirect general class
+ ///
+ ///
+ /// true when the is one of the direct or indirect general classifiers of the
+ /// , false otherwise. A class is not a subclass of itself; use
+ /// for the test that includes the class itself.
+ ///
+ public static bool QueryIsSubclassOf(this IClass @class, IClass superClass)
+ {
+ if (@class == null)
+ {
+ throw new ArgumentNullException(nameof(@class));
+ }
+
+ if (superClass == null)
+ {
+ throw new ArgumentNullException(nameof(superClass));
+ }
+
+ return !ReferenceEquals(@class, superClass) && @class.QueryAllGeneralClassifiers().Contains(superClass);
+ }
+
+ ///
+ /// Queries whether the is a direct or indirect subclass of a class with the specified name
+ ///
+ ///
+ /// The subject
+ ///
+ ///
+ /// The name of the that is expected to be a direct or indirect general class
+ ///
+ ///
+ /// true when one of the direct or indirect general classes of the has the
+ /// as name, false otherwise. The itself is not
+ /// taken into account.
+ ///
+ ///
+ /// The comparison is on the name only, it is case-sensitive and does not take the package into account. Two
+ /// classes that have the same name in different packages are not told apart; use the overload that takes an
+ /// when that matters.
+ ///
+ public static bool QueryIsSubclassOf(this IClass @class, string superClassName)
+ {
+ if (@class == null)
+ {
+ throw new ArgumentNullException(nameof(@class));
+ }
+
+ if (string.IsNullOrWhiteSpace(superClassName))
+ {
+ throw new ArgumentException("The name of the super class may not be null or empty", nameof(superClassName));
+ }
+
+ return @class.QueryAllGeneralClassifiers()
+ .OfType()
+ .Any(x => !ReferenceEquals(x, @class) && x.Name == superClassName);
+ }
+
+ ///
+ /// Queries the properties in the model that refer to the : the properties that have the
+ /// as type
+ ///
+ ///
+ /// The subject
+ ///
+ ///
+ /// The owned attributes that are typed by the , of the classes that are packaged
+ /// elements of the root package of the , of its nested packages and of the packages
+ /// that these import (see ). An empty
+ /// collection when the has no root package.
+ ///
+ ///
+ /// Only the owned attributes of classes that are directly contained by a package are searched. An association
+ /// end that is owned by the association, and an attribute of a nested class, an interface or a data type, are
+ /// not returned.
+ ///
+ public static ReadOnlyCollection QueryReferencingProperties(this IClass @class)
+ {
+ if (@class == null)
+ {
+ throw new ArgumentNullException(nameof(@class));
+ }
+
+ var rootPackage = @class.QueryRootPackage();
+
+ if (rootPackage == null)
+ {
+ return new List().AsReadOnly();
+ }
+
+ return rootPackage.QueryAllNestedAndImportedPackages()
+ .SelectMany(x => x.PackagedElement.OfType())
+ .SelectMany(x => x.OwnedAttribute)
+ .Where(x => ReferenceEquals(x.Type, @class))
+ .Distinct()
+ .ToList()
+ .AsReadOnly();
+ }
+
+ ///
+ /// Queries the owned attributes of the that take part in a many-to-many relationship
+ ///
+ ///
+ /// The subject
+ ///
+ ///
+ /// The owned attributes for which is true, ordered
+ /// by name
+ ///
+ public static ReadOnlyCollection QueryOwnedManyToManyProperties(this IClass @class)
+ {
+ if (@class == null)
+ {
+ throw new ArgumentNullException(nameof(@class));
+ }
+
+ return @class.OwnedAttribute
+ .Where(x => x.QueryIsMemberOfManyToMany())
+ .OrderBy(x => x.Name, StringComparer.Ordinal)
+ .Distinct()
+ .ToList()
+ .AsReadOnly();
+ }
}
}
diff --git a/uml4net.Extensions/ClassifierExtensions.cs b/uml4net.Extensions/ClassifierExtensions.cs
index 074e5b69..17a83de6 100644
--- a/uml4net.Extensions/ClassifierExtensions.cs
+++ b/uml4net.Extensions/ClassifierExtensions.cs
@@ -26,6 +26,7 @@ namespace uml4net.Extensions
using System.Linq;
using uml4net.Classification;
+ using uml4net.CommonStructure;
///
/// The class provides extensions methods for the
@@ -124,5 +125,35 @@ public static ReadOnlyCollection QueryContainers(this IClassifier s
.ToList()
.AsReadOnly();
}
+
+ ///
+ /// Queries whether the conforms to the ,
+ /// as specified by the operation Classifier::conformsTo of UML 2.5.1
+ ///
+ ///
+ /// The subject
+ ///
+ ///
+ /// The to which the is expected to conform
+ ///
+ ///
+ /// true when the is the itself or one of its direct or
+ /// indirect general classifiers; false otherwise, and when the is not an
+ ///
+ ///
+ public static bool QueryConformsTo(this IClassifier classifier, IType other)
+ {
+ if (classifier == null)
+ {
+ throw new ArgumentNullException(nameof(classifier));
+ }
+
+ if (other == null)
+ {
+ throw new ArgumentNullException(nameof(other));
+ }
+
+ return other is IClassifier otherClassifier && classifier.QueryAllGeneralClassifiers().Contains(otherClassifier);
+ }
}
}
diff --git a/uml4net.HandleBars.Tests/ClassHelperTestFixture.cs b/uml4net.HandleBars.Tests/ClassHelperTestFixture.cs
index 381804a0..85138768 100644
--- a/uml4net.HandleBars.Tests/ClassHelperTestFixture.cs
+++ b/uml4net.HandleBars.Tests/ClassHelperTestFixture.cs
@@ -345,5 +345,93 @@ public void Verify_that_WriteDerivedPropertyCasesForXmiReader_throws_when_not_pr
Assert.That(() => actionWithoutArguments(new Class()), Throws.InstanceOf());
}
+
+ [Test]
+ public void Verify_that_QueryAllNonDerivedNonRedefinedProperties_returns_expected_result()
+ {
+ var template = "{{#each (#Class.QueryAllNonDerivedNonRedefinedProperties this) as | property |}}{{ property.XmiId }};{{/each}}";
+
+ var action = this.handlebarsContext.Compile(template);
+
+ var root = this.xmiReaderResult.QueryRoot(xmiId: "_0", name: "UML");
+
+ var @class = root.NestedPackage.Single(x => x.Name == "StructuredClassifiers").PackagedElement.OfType().Single(x => x.Name == "Class");
+
+ var result = action(@class);
+
+ var names = @class.QueryAllNonDerivedNonRedefinedProperties().OrderBy(x => x.Name).Select(x => x.XmiId);
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(result, Is.EqualTo(string.Concat(names.Select(x => $"{x};"))), "ordered by name");
+ Assert.That(result, Does.Contain("PackageableElement-visibility;"));
+ Assert.That(result, Does.Not.Contain("NamedElement-visibility;"));
+ Assert.That(() => action(new Dependency()), Throws.ArgumentException);
+ }
+ }
+
+ [Test]
+ public void Verify_that_QueryIsSubclassOf_returns_expected_result()
+ {
+ var template = "{{#if (#Class.QueryIsSubclassOf this.Class this.SuperClass)}}subclass{{else}}not a subclass{{/if}}";
+
+ var action = this.handlebarsContext.Compile(template);
+
+ var root = this.xmiReaderResult.QueryRoot(xmiId: "_0", name: "UML");
+
+ var commonStructurePackage = root.NestedPackage.Single(x => x.Name == "CommonStructure");
+ var dependency = commonStructurePackage.PackagedElement.OfType().Single(x => x.Name == "Dependency");
+ var element = commonStructurePackage.PackagedElement.OfType().Single(x => x.Name == "Element");
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(action(new { Class = dependency, SuperClass = element }), Is.EqualTo("subclass"));
+ Assert.That(action(new { Class = element, SuperClass = dependency }), Is.EqualTo("not a subclass"));
+ Assert.That(action(new { Class = dependency, SuperClass = dependency }), Is.EqualTo("not a subclass"));
+ Assert.That(action(new { Class = dependency, SuperClass = "Element" }), Is.EqualTo("subclass"));
+ Assert.That(action(new { Class = dependency, SuperClass = "Comment" }), Is.EqualTo("not a subclass"));
+
+ Assert.That(() => action(new { Class = "Dependency", SuperClass = element }), Throws.ArgumentException);
+ Assert.That(() => action(new { Class = dependency, SuperClass = 1 }), Throws.ArgumentException);
+ Assert.That(() => this.handlebarsContext.Compile("{{#if (#Class.QueryIsSubclassOf this)}}subclass{{/if}}")(dependency), Throws.TypeOf());
+ }
+ }
+
+ [Test]
+ public void Verify_that_QueryReferencingProperties_returns_expected_result()
+ {
+ var template = "{{#each (#Class.QueryReferencingProperties this) as | property |}}{{ property.XmiId }};{{/each}}";
+
+ var action = this.handlebarsContext.Compile(template);
+
+ var root = this.xmiReaderResult.QueryRoot(xmiId: "_0", name: "UML");
+
+ var comment = root.NestedPackage.Single(x => x.Name == "CommonStructure").PackagedElement.OfType().Single(x => x.Name == "Comment");
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(action(comment), Does.Contain("Element-ownedComment;"));
+ Assert.That(action(new Class { Name = "Detached" }), Is.Empty);
+ Assert.That(() => action(new Dependency()), Throws.ArgumentException);
+ }
+ }
+
+ [Test]
+ public void Verify_that_QueryOwnedManyToManyProperties_returns_expected_result()
+ {
+ var template = "{{#each (#Class.QueryOwnedManyToManyProperties this) as | property |}}{{ property.Name }};{{/each}}";
+
+ var action = this.handlebarsContext.Compile(template);
+
+ var root = this.xmiReaderResult.QueryRoot(xmiId: "_0", name: "UML");
+
+ var dependency = root.NestedPackage.Single(x => x.Name == "CommonStructure").PackagedElement.OfType().Single(x => x.Name == "Dependency");
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(action(dependency), Is.EqualTo("client;supplier;"));
+ Assert.That(() => action(new Dependency()), Throws.ArgumentException);
+ }
+ }
}
}
diff --git a/uml4net.HandleBars.Tests/ClassifierHelperTestFixture.cs b/uml4net.HandleBars.Tests/ClassifierHelperTestFixture.cs
index 9e99bfb9..25870713 100644
--- a/uml4net.HandleBars.Tests/ClassifierHelperTestFixture.cs
+++ b/uml4net.HandleBars.Tests/ClassifierHelperTestFixture.cs
@@ -106,5 +106,30 @@ public void Verify_that_QueryContainers_throws_when_context_is_invalid()
Assert.That(() => action(5), Throws.ArgumentException);
}
+
+ [Test]
+ public void Verify_that_QueryConformsTo_returns_expected_result()
+ {
+ var template = "{{#if (#Classifier.QueryConformsTo this.Classifier this.Other)}}conforms{{else}}does not conform{{/if}}";
+
+ var action = this.handlebarsContext.Compile(template);
+
+ var root = this.xmiReaderResult.QueryRoot(xmiId: "_0", name: "UML");
+
+ var commonStructurePackage = root.NestedPackage.Single(x => x.Name == "CommonStructure");
+ var dependency = commonStructurePackage.PackagedElement.OfType().Single(x => x.Name == "Dependency");
+ var element = commonStructurePackage.PackagedElement.OfType().Single(x => x.Name == "Element");
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(action(new { Classifier = dependency, Other = element }), Is.EqualTo("conforms"));
+ Assert.That(action(new { Classifier = dependency, Other = dependency }), Is.EqualTo("conforms"));
+ Assert.That(action(new { Classifier = element, Other = dependency }), Is.EqualTo("does not conform"));
+
+ Assert.That(() => action(new { Classifier = 5, Other = element }), Throws.ArgumentException);
+ Assert.That(() => action(new { Classifier = dependency, Other = "Element" }), Throws.ArgumentException);
+ Assert.That(() => this.handlebarsContext.Compile("{{#if (#Classifier.QueryConformsTo this)}}conforms{{/if}}")(dependency), Throws.TypeOf());
+ }
+ }
}
}
diff --git a/uml4net.HandleBars/ClassHelper.cs b/uml4net.HandleBars/ClassHelper.cs
index e859428c..a703da2b 100644
--- a/uml4net.HandleBars/ClassHelper.cs
+++ b/uml4net.HandleBars/ClassHelper.cs
@@ -134,13 +134,74 @@ public static void RegisterClassHelper(this IHandlebars handlebars)
throw new ArgumentException("supposed to be IClass");
}
- var properties = @class.QueryAllProperties()
- .Where(x => !x.IsDerived)
+ var properties = @class.QueryAllNonDerivedProperties()
.OrderBy(x => x.Name);
return properties;
});
+ // Queries all the properties of the class, including the inherited ones, that are not derived and that are
+ // not redefined in the context of the class
+ handlebars.RegisterHelper("Class.QueryAllNonDerivedNonRedefinedProperties", (context, _) =>
+ {
+ if (!(context.Value is IClass @class))
+ {
+ throw new ArgumentException("supposed to be IClass");
+ }
+
+ var properties = @class.QueryAllNonDerivedNonRedefinedProperties()
+ .OrderBy(x => x.Name);
+
+ return properties;
+ });
+
+ // Queries whether the class is a direct or indirect subclass of the class, or of the class with the name,
+ // that is provided as second argument
+ handlebars.RegisterHelper("Class.QueryIsSubclassOf", (_, arguments) =>
+ {
+ if (arguments.Length != 2)
+ {
+ throw new HandlebarsException("{{#Class.QueryIsSubclassOf}} helper must have exactly two arguments");
+ }
+
+ if (!(arguments[0] is IClass @class))
+ {
+ throw new ArgumentException("{{#Class.QueryIsSubclassOf}} - the first argument is supposed to be an IClass");
+ }
+
+ switch (arguments[1])
+ {
+ case IClass superClass:
+ return @class.QueryIsSubclassOf(superClass);
+ case string superClassName:
+ return @class.QueryIsSubclassOf(superClassName);
+ default:
+ throw new ArgumentException("{{#Class.QueryIsSubclassOf}} - the second argument is supposed to be an IClass or the name of a class");
+ }
+ });
+
+ // Queries the properties in the model that have the class as type
+ handlebars.RegisterHelper("Class.QueryReferencingProperties", (context, _) =>
+ {
+ if (!(context.Value is IClass @class))
+ {
+ throw new ArgumentException("supposed to be IClass");
+ }
+
+ return @class.QueryReferencingProperties();
+ });
+
+ // Queries the owned attributes of the class that take part in a many-to-many relationship
+ handlebars.RegisterHelper("Class.QueryOwnedManyToManyProperties", (context, _) =>
+ {
+ if (!(context.Value is IClass @class))
+ {
+ throw new ArgumentException("supposed to be IClass");
+ }
+
+ return @class.QueryOwnedManyToManyProperties();
+ });
+
handlebars.RegisterHelper("Class.QueryAllNonDerivedNonReadOnlyProperties", (context, _) =>
{
if (!(context.Value is IClass @class))
diff --git a/uml4net.HandleBars/ClassifierHelper.cs b/uml4net.HandleBars/ClassifierHelper.cs
index 62cea21b..9b1b18f9 100644
--- a/uml4net.HandleBars/ClassifierHelper.cs
+++ b/uml4net.HandleBars/ClassifierHelper.cs
@@ -25,6 +25,7 @@ namespace uml4net.HandleBars
using Classification;
using HandlebarsDotNet;
+ using uml4net.CommonStructure;
using uml4net.Extensions;
using uml4net.StructuredClassifiers;
@@ -53,6 +54,28 @@ public static void RegisterClassifierHelper(this IHandlebars handlebars)
return containers;
});
+
+ // Queries whether the classifier conforms to the type that is provided as second argument: whether that
+ // type is the classifier itself or one of its direct or indirect general classifiers
+ handlebars.RegisterHelper("Classifier.QueryConformsTo", (_, arguments) =>
+ {
+ if (arguments.Length != 2)
+ {
+ throw new HandlebarsException("{{#Classifier.QueryConformsTo}} helper must have exactly two arguments");
+ }
+
+ if (!(arguments[0] is IClassifier classifier))
+ {
+ throw new ArgumentException("{{#Classifier.QueryConformsTo}} - the first argument is supposed to be an IClassifier");
+ }
+
+ if (!(arguments[1] is IType other))
+ {
+ throw new ArgumentException("{{#Classifier.QueryConformsTo}} - the second argument is supposed to be an IType");
+ }
+
+ return classifier.QueryConformsTo(other);
+ });
}
}
}