diff --git a/.github/workflows/CodeQuality.yml b/.github/workflows/CodeQuality.yml
index 9cbf3532..3b922640 100644
--- a/.github/workflows/CodeQuality.yml
+++ b/.github/workflows/CodeQuality.yml
@@ -13,6 +13,15 @@ jobs:
build:
name: Build
runs-on: ubuntu-latest
+ env:
+ # Use cached CRL data only for cert revocation checks. Works around
+ # NU3012 ("certificate revoked") for transitive ReactiveUI / Splat 19.3.1
+ # packages whose author certificate (Glenn Watson) was revoked at the CA
+ # in 2026-Q2. `signatureValidationMode=accept` in NuGet.Config does NOT
+ # cover this case because it only relaxes the "require signature" check,
+ # not the chain-validation step that NU3012 fires from. Revert this env
+ # var once the affected packages are re-signed and re-published.
+ NUGET_CERT_REVOCATION_MODE: offline
steps:
- uses: actions/checkout@v6.0.2
with:
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 65ec8ac0..6df417a6 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -11,6 +11,13 @@ jobs:
runs-on: ubuntu-latest
+ env:
+ # Use cached CRL data only for cert revocation checks. Works around
+ # NU3012 ("certificate revoked") for transitive ReactiveUI / Splat 19.3.1
+ # packages whose author certificate was revoked at the CA in 2026-Q2.
+ # Revert this env var once the affected packages are re-signed.
+ NUGET_CERT_REVOCATION_MODE: offline
+
steps:
- name: Checkout repository
uses: actions/checkout@v6.0.2
diff --git a/Nuget.Config b/Nuget.Config
index 03f17c31..6cf91eb6 100644
--- a/Nuget.Config
+++ b/Nuget.Config
@@ -1,7 +1,7 @@
-
+
\ No newline at end of file
diff --git a/SysML2.NET.CodeGenerator/HandleBarHelpers/RuleGenerationContext.cs b/SysML2.NET.CodeGenerator/HandleBarHelpers/RuleGenerationContext.cs
index 32303edb..a7836f6c 100644
--- a/SysML2.NET.CodeGenerator/HandleBarHelpers/RuleGenerationContext.cs
+++ b/SysML2.NET.CodeGenerator/HandleBarHelpers/RuleGenerationContext.cs
@@ -106,6 +106,16 @@ public TextualNotationRule FindRule(string ruleName)
///
public string PendingCursorMove { get; set; }
+ ///
+ /// Monotonically-incrementing counter used to produce unique narrowed-type-check pattern
+ /// variable names (e.g. owningMembership0, owningMembership1) across the
+ /// emission of a single rule body. Required because C# pattern-matching variables share
+ /// the enclosing method scope, so emitting more than one
+ /// is IOwningMembership owningMembership in distinct guards of the same generated
+ /// method would collide (CS0136). Incremented by the narrowed-type-check emitter.
+ ///
+ public int NarrowedTypeCheckCounter { get; set; }
+
///
/// Determines whether the next sibling element is a terminal that uses AppendLine
/// (e.g., {, }, ;), in which case a trailing space would be unnecessary.
diff --git a/SysML2.NET.CodeGenerator/HandleBarHelpers/RuleProcessor.CollectionProcessing.cs b/SysML2.NET.CodeGenerator/HandleBarHelpers/RuleProcessor.CollectionProcessing.cs
index 011354d0..8a7b68b0 100644
--- a/SysML2.NET.CodeGenerator/HandleBarHelpers/RuleProcessor.CollectionProcessing.cs
+++ b/SysML2.NET.CodeGenerator/HandleBarHelpers/RuleProcessor.CollectionProcessing.cs
@@ -72,9 +72,9 @@ private void EmitCollectionNonTerminalLoop(EncodedTextWriter writer, IClass umlC
cursorVariableName = cursorDefinition.CursorVariableName;
}
- var perItemCall = this.ResolveBuilderCall(umlClass, nonTerminalElement, typeTarget, ruleGenerationContext);
+ var perItemCall = ResolveBuilderCall(umlClass, nonTerminalElement, typeTarget, ruleGenerationContext);
- var whileTypeExclusion = this.ResolveCollectionWhileTypeCondition(cursorVariableName, umlClass, referencedRule, ruleGenerationContext);
+ var whileTypeExclusion = ResolveCollectionWhileTypeCondition(cursorVariableName, umlClass, referencedRule, ruleGenerationContext);
string whileCondition;
@@ -84,23 +84,23 @@ private void EmitCollectionNonTerminalLoop(EncodedTextWriter writer, IClass umlC
}
else
{
- var allElements = referencedRule?.Alternatives.SelectMany(alt => alt.Elements).ToList();
+ var allElements = referencedRule.Alternatives.SelectMany(alt => alt.Elements).ToList();
- var hasNonAssignmentElements = allElements?.Any(element =>
- element is NonTerminalElement or GroupElement) == true;
+ var hasNonAssignmentElements = allElements.Any(element =>
+ element is NonTerminalElement or GroupElement);
List assignmentTargetTypes = null;
if (!hasNonAssignmentElements)
{
- assignmentTargetTypes = allElements?
+ assignmentTargetTypes = allElements
.OfType()
.Where(assignmentElement => assignmentElement.Operator == "+=" && assignmentElement.Value is NonTerminalElement)
.Select(assignmentElement =>
{
var valueNonTerminal = (NonTerminalElement)assignmentElement.Value;
var refRule = ruleGenerationContext.FindRule(valueNonTerminal.Name);
- var targetName = refRule != null ? refRule.EffectiveTarget : null;
+ var targetName = refRule?.EffectiveTarget;
if (targetName != null)
{
@@ -165,14 +165,14 @@ private void EmitCollectionNonTerminalLoop(EncodedTextWriter writer, IClass umlC
var handCodedRuleName = nonTerminalElement.TextualNotationRule?.RuleName ?? nonTerminalElement.Name;
- this.EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext, true);
+ EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext, true);
writer.WriteSafeString(Environment.NewLine);
}
///
/// Resolves the type condition for a collection while loop.
///
- private string ResolveCollectionWhileTypeCondition(string cursorVariableName, IClass umlClass, TextualNotationRule collectionRule, RuleGenerationContext ruleGenerationContext)
+ private static string ResolveCollectionWhileTypeCondition(string cursorVariableName, IClass umlClass, TextualNotationRule collectionRule, RuleGenerationContext ruleGenerationContext)
{
var siblings = ruleGenerationContext.CurrentSiblingElements;
var currentIndex = ruleGenerationContext.CurrentElementIndex;
@@ -347,7 +347,7 @@ private string ResolveContentTypeGuard(string cursorVariableName, TextualNotatio
///
/// Resolves the builder method call string for a non-terminal element.
///
- private string ResolveBuilderCall(IClass umlClass, NonTerminalElement nonTerminalElement, string typeTarget, RuleGenerationContext ruleGenerationContext)
+ private static string ResolveBuilderCall(IClass umlClass, NonTerminalElement nonTerminalElement, string typeTarget, RuleGenerationContext ruleGenerationContext)
{
if (typeTarget == ruleGenerationContext.NamedElementToGenerate.Name)
{
@@ -386,7 +386,7 @@ private string ResolveBuilderCall(IClass umlClass, NonTerminalElement nonTermina
/// The current
/// The variable name from which the property is accessed (typically poco)
/// The condition expression, or null when no property names are referenced
- private string GenerateInlineOptionalCondition(EncodedTextWriter writer, TextualNotationRule referencedRule, IClass targetClass, RuleGenerationContext ruleGenerationContext, string variableName)
+ private static string GenerateInlineOptionalCondition(EncodedTextWriter writer, TextualNotationRule referencedRule, IClass targetClass, RuleGenerationContext ruleGenerationContext, string variableName)
{
var propertyNames = referencedRule.QueryAllReferencedPropertyNames(ruleGenerationContext.AllRules);
@@ -469,35 +469,70 @@ private static string TryBuildCursorTypedCheck(EncodedTextWriter writer, Textual
return null;
}
- var resolvedTypeNames = new List();
+ // Each entry: (WrapperType, InnerType). InnerType is non-null when the assignment's
+ // referenced rule is a "thin owning wrapper" (target=OwningMembership wrapping a
+ // single ownedRelatedElement += T); the inner type T then provides the narrowing
+ // discriminator that distinguishes the wrapper from sibling OwningMembership
+ // subtypes (e.g. EndFeatureMembership) that share the cursor's collection.
+ var resolvedTypes = new List<(string Wrapper, string Inner)>();
foreach (var assignmentElement in collectionAssignments)
{
- var typeName = ResolveAssignmentTargetTypeName(assignmentElement, targetClass, ruleGenerationContext);
+ var wrapperType = ResolveAssignmentTargetTypeName(assignmentElement, targetClass, ruleGenerationContext);
- if (typeName == null)
+ if (wrapperType == null)
{
return null;
}
- if (!resolvedTypeNames.Contains(typeName))
+ var innerType = TryResolveWrappedInnerTypeName(assignmentElement, targetClass, ruleGenerationContext);
+ var entry = (Wrapper: wrapperType, Inner: innerType);
+
+ if (!resolvedTypes.Contains(entry))
{
- resolvedTypeNames.Add(typeName);
+ resolvedTypes.Add(entry);
}
}
var cursorVariableName = EnsureCursorDeclared(writer, property, ruleGenerationContext);
- if (resolvedTypeNames.Count == 1)
+ if (resolvedTypes.Count == 1)
{
- return $"{cursorVariableName}.Current is {resolvedTypeNames[0]}";
+ return BuildTypeCheck(cursorVariableName, resolvedTypes[0].Wrapper, resolvedTypes[0].Inner, ruleGenerationContext);
}
- var typeChecks = resolvedTypeNames.Select(typeName => $"{cursorVariableName}.Current is {typeName}");
+ var typeChecks = resolvedTypes.Select(entry => BuildTypeCheck(cursorVariableName, entry.Wrapper, entry.Inner, ruleGenerationContext));
return $"({string.Join(" || ", typeChecks)})";
}
+ ///
+ /// Builds a single cursor-typed boolean check. When is
+ /// supplied the check narrows from a bare cursor.Current is Wrapper to
+ /// (cursor.Current is Wrapper owningMembershipN && owningMembershipN.OwnedRelatedElement.OfType<Inner>().Any())
+ /// so the discriminator is precise enough to distinguish a thin owning wrapper from
+ /// sibling subtypes of the same wrapper class. The pattern-variable suffix is drawn from
+ /// so multiple narrowed
+ /// checks in the same generated method do not collide on the C# scope (CS0136).
+ ///
+ /// The cursor variable name in scope at the emission site.
+ /// The fully-qualified wrapper type name.
+ /// The fully-qualified inner element type name when narrowing applies; otherwise .
+ /// The current providing the per-rule counter for unique pattern-variable names.
+ /// The C# boolean expression to emit.
+ private static string BuildTypeCheck(string cursorVariableName, string wrapperType, string innerType, RuleGenerationContext ruleGenerationContext)
+ {
+ if (innerType == null)
+ {
+ return $"{cursorVariableName}.Current is {wrapperType}";
+ }
+
+ var patternVariableName = $"owningMembership{ruleGenerationContext.NarrowedTypeCheckCounter}";
+ ruleGenerationContext.NarrowedTypeCheckCounter++;
+
+ return $"({cursorVariableName}.Current is {wrapperType} {patternVariableName} && {patternVariableName}.OwnedRelatedElement.OfType<{innerType}>().Any())";
+ }
+
///
/// Returns the cursor variable name for , reusing an
/// already-declared cursor when one is present in
@@ -532,7 +567,7 @@ private static string EnsureCursorDeclared(EncodedTextWriter writer, IProperty p
///
/// Emits an optional condition wrapping block for an optional NonTerminal element.
///
- private bool TryEmitOptionalCondition(EncodedTextWriter writer, NonTerminalElement nonTerminalElement, TextualNotationRule referencedRule, IClass targetClass, RuleGenerationContext ruleGenerationContext, string variableName)
+ private static bool TryEmitOptionalCondition(EncodedTextWriter writer, NonTerminalElement nonTerminalElement, TextualNotationRule referencedRule, IClass targetClass, RuleGenerationContext ruleGenerationContext, string variableName)
{
if (!nonTerminalElement.IsOptional || nonTerminalElement.IsCollection)
{
@@ -544,7 +579,7 @@ private bool TryEmitOptionalCondition(EncodedTextWriter writer, NonTerminalEleme
return false;
}
- var condition = this.GenerateInlineOptionalCondition(writer, referencedRule, targetClass, ruleGenerationContext, variableName);
+ var condition = GenerateInlineOptionalCondition(writer, referencedRule, targetClass, ruleGenerationContext, variableName);
if (condition == null)
{
diff --git a/SysML2.NET.CodeGenerator/HandleBarHelpers/RuleProcessor.ElementProcessing.cs b/SysML2.NET.CodeGenerator/HandleBarHelpers/RuleProcessor.ElementProcessing.cs
index aa9458a6..2268fd97 100644
--- a/SysML2.NET.CodeGenerator/HandleBarHelpers/RuleProcessor.ElementProcessing.cs
+++ b/SysML2.NET.CodeGenerator/HandleBarHelpers/RuleProcessor.ElementProcessing.cs
@@ -198,13 +198,13 @@ internal void ProcessRuleElement(EncodedTextWriter writer, IClass umlClass, Rule
else
{
var handCodedRuleName = groupElement.TextualNotationRule?.RuleName ?? "Unknown";
- this.EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
+ EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
}
}
else
{
var handCodedRuleName = groupElement.TextualNotationRule?.RuleName ?? "Unknown";
- this.EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
+ EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
}
}
else
@@ -237,7 +237,7 @@ internal void ProcessRuleElement(EncodedTextWriter writer, IClass umlClass, Rule
else
{
var handCodedRuleName = textualRuleElement.TextualNotationRule?.RuleName ?? "Unknown";
- this.EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
+ EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
}
break;
@@ -313,7 +313,7 @@ internal void ProcessAssignmentElement(EncodedTextWriter writer, IClass umlClass
else
{
var handCodedRuleName = assignmentElement.TextualNotationRule?.RuleName ?? "Unknown";
- this.EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
+ EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
}
}
else
@@ -396,7 +396,47 @@ internal void ProcessAssignmentElement(EncodedTextWriter writer, IClass umlClass
{
var previousCaller = ruleGenerationContext.CallerRule;
ruleGenerationContext.CallerRule = nonTerminalElement;
- ruleGenerationContext.CurrentVariableName = $"poco.{targetPropertyName}";
+
+ // Thin `[QualifiedName]` wrapper inlining: when the referenced rule's body is
+ // just `[QualifiedName]` (e.g. FeatureReference, InstantiatedTypeReference) the
+ // generated `Build{Wrapper}` method receives the target POCO as both target AND
+ // source for name resolution, which loses the reference site. Inline the
+ // AppendQualifiedName call here with the OUTER `poco` as the source context so
+ // imports declared in the source's enclosing namespace can resolve to the
+ // short / unqualified name.
+ var referencedRule = ruleGenerationContext.FindRule(nonTerminalElement.Name);
+
+ if (IsThinQualifiedNameWrapperRule(referencedRule))
+ {
+ writer.WriteSafeString($"{Environment.NewLine}if (poco.{targetPropertyName} != null){Environment.NewLine}{{{Environment.NewLine}");
+ writer.WriteSafeString($"SharedTextualNotationBuilder.AppendQualifiedName(stringBuilder, poco.{targetPropertyName}, writerContext, poco);{Environment.NewLine}");
+ writer.WriteSafeString($"stringBuilder.Append(' ');{Environment.NewLine}");
+ writer.WriteSafeString($"}}{Environment.NewLine}");
+ ruleGenerationContext.CallerRule = previousCaller;
+ break;
+ }
+
+ // Polymorphic `ownedMemberFeature` access on IFeatureMembership: the runtime
+ // POCO may also be an IParameterMembership (the form used to model operands
+ // of every InvocationExpression / OperatorExpression per KerML §8.2.5.8.2
+ // Notes 1-2 — see Resources/KerML-textual-bnf.kebnf:1176-1178). In that
+ // shape the operand expression lives under ownedMemberFeature → FeatureValue
+ // → value rather than directly under ownedMemberFeature. Route the access
+ // through SharedTextualNotationBuilder.QueryEffectiveOwnedMemberFeature
+ // which transparently normalises both runtime shapes into a single feature
+ // reference downstream code can type-test as before.
+ if (string.Equals(targetProperty.Name, "ownedMemberFeature", StringComparison.Ordinal)
+ && QueryIsAssignableToFeatureMembership(umlClass))
+ {
+ const string effectiveVariableName = "effectiveOwnedMemberFeature";
+ writer.WriteSafeString($"var {effectiveVariableName} = SysML2.NET.Serializer.TextualNotation.Writers.SharedTextualNotationBuilder.QueryEffectiveOwnedMemberFeature(poco);{Environment.NewLine}");
+ ruleGenerationContext.CurrentVariableName = effectiveVariableName;
+ }
+ else
+ {
+ ruleGenerationContext.CurrentVariableName = $"poco.{targetPropertyName}";
+ }
+
this.ProcessNonTerminalElement(writer, targetProperty.Type as IClass, nonTerminalElement, ruleGenerationContext, isPartOfMultipleAlternative);
ruleGenerationContext.CurrentVariableName = "poco";
ruleGenerationContext.CallerRule = previousCaller;
@@ -429,7 +469,7 @@ internal void ProcessAssignmentElement(EncodedTextWriter writer, IClass umlClass
break;
default:
var handCodedRuleName = assignmentElement.TextualNotationRule?.RuleName ?? "Unknown";
- this.EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
+ EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
break;
}
}
@@ -448,7 +488,7 @@ internal void ProcessAssignmentElement(EncodedTextWriter writer, IClass umlClass
// Delegate to the HandCoded sibling per the documented convention rather
// than emitting a name-collision-prone `Build{Property}(poco, …)` call.
var handCodedRuleName = assignmentElement.TextualNotationRule?.RuleName ?? "Unknown";
- this.EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
+ EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
}
}
@@ -521,7 +561,7 @@ internal void ProcessNonTerminalElement(EncodedTextWriter writer, IClass umlClas
writer.WriteSafeString($"{{{Environment.NewLine}");
}
- var emittedCondition = this.TryEmitOptionalCondition(writer, nonTerminalElement, referencedRule, targetClass, ruleGenerationContext, ruleGenerationContext.CurrentVariableName);
+ var emittedCondition = TryEmitOptionalCondition(writer, nonTerminalElement, referencedRule, targetClass, ruleGenerationContext, ruleGenerationContext.CurrentVariableName);
writer.WriteSafeString($"{targetType.Name}TextualNotationBuilder.Build{nonTerminalElement.Name}({ruleGenerationContext.CurrentVariableName}, writerContext, stringBuilder);");
@@ -556,7 +596,7 @@ internal void ProcessNonTerminalElement(EncodedTextWriter writer, IClass umlClas
{
if (NoTargetRuleResolver.IsSharedRule(referencedRule, umlClass))
{
- this.EmitSharedNoTargetRuleCall(writer, umlClass, nonTerminalElement, referencedRule, ruleGenerationContext);
+ EmitSharedNoTargetRuleCall(writer, umlClass, nonTerminalElement, referencedRule, ruleGenerationContext);
}
else
{
@@ -574,7 +614,7 @@ internal void ProcessNonTerminalElement(EncodedTextWriter writer, IClass umlClas
{
var variableToUse = referencedRule != null ? ruleGenerationContext.CurrentVariableName : "poco";
- var emittedSameClassCondition = this.TryEmitOptionalCondition(writer, nonTerminalElement, referencedRule, umlClass, ruleGenerationContext, variableToUse);
+ var emittedSameClassCondition = TryEmitOptionalCondition(writer, nonTerminalElement, referencedRule, umlClass, ruleGenerationContext, variableToUse);
writer.WriteSafeString($"Build{nonTerminalElement.Name}({variableToUse}, writerContext, stringBuilder);");
@@ -652,7 +692,7 @@ internal void DeclareCursorIfRequired(EncodedTextWriter writer, IClass umlClass,
/// The being processed
/// The referenced shared no-target
/// The current
- private void EmitSharedNoTargetRuleCall(EncodedTextWriter writer, IClass umlClass, NonTerminalElement nonTerminalElement, TextualNotationRule referencedRule, RuleGenerationContext ruleGenerationContext)
+ private static void EmitSharedNoTargetRuleCall(EncodedTextWriter writer, IClass umlClass, NonTerminalElement nonTerminalElement, TextualNotationRule referencedRule, RuleGenerationContext ruleGenerationContext)
{
var effectiveTarget = NoTargetRuleResolver.ResolveEffectiveTarget(referencedRule, ruleGenerationContext.AllRules, umlClass);
@@ -668,7 +708,7 @@ private void EmitSharedNoTargetRuleCall(EncodedTextWriter writer, IClass umlClas
}
var emittedCondition = effectiveTarget != null
- && this.TryEmitOptionalCondition(writer, nonTerminalElement, referencedRule, effectiveTarget, ruleGenerationContext, ruleGenerationContext.CurrentVariableName);
+ && TryEmitOptionalCondition(writer, nonTerminalElement, referencedRule, effectiveTarget, ruleGenerationContext, ruleGenerationContext.CurrentVariableName);
writer.WriteSafeString($"{RulesHelper.SharedBuilderClassName}.Build{nonTerminalElement.Name}({variableExpression}, writerContext, stringBuilder);");
@@ -677,5 +717,60 @@ private void EmitSharedNoTargetRuleCall(EncodedTextWriter writer, IClass umlClas
writer.WriteSafeString($"{Environment.NewLine}}}");
}
}
+
+ ///
+ /// Returns when IS-A
+ /// FeatureMembership — used to gate the polymorphic ownedMemberFeature
+ /// access path that normalises pure IFeatureMembership and
+ /// IParameterMembership runtime shapes.
+ ///
+ /// The under test.
+ /// if the class IS-A FeatureMembership.
+ private static bool QueryIsAssignableToFeatureMembership(IClass umlClass)
+ {
+ if (umlClass == null)
+ {
+ return false;
+ }
+
+ return string.Equals(umlClass.Name, "FeatureMembership", StringComparison.Ordinal)
+ || umlClass.QueryAllGeneralClassifiers().Any(c => string.Equals(c.Name, "FeatureMembership", StringComparison.Ordinal));
+ }
+
+ ///
+ /// Returns when is a "thin
+ /// [QualifiedName] wrapper" — i.e. its body is a single alternative containing a
+ /// single element that is a [QualifiedName] resolution. Examples in the KerML
+ /// grammar (Resources/KerML-textual-bnf.kebnf): FeatureReference : Feature =
+ /// [QualifiedName] (line 1201) and InstantiatedTypeReference : Type =
+ /// [QualifiedName] (line 1229).
+ ///
+ /// When a caller-rule's assignment-element references such a wrapper as its value, the
+ /// generated Build{Wrapper} method receives the target as both target AND source
+ /// for name resolution, which loses the syntactic reference site (the caller's
+ /// poco) needed to honour imports declared in the source's enclosing scope chain.
+ /// The codegen inlines the AppendQualifiedName call at the caller's emission point
+ /// instead so the OUTER poco serves as the resolution source.
+ ///
+ ///
+ /// The under test; may be .
+ /// if the rule is a thin [QualifiedName] wrapper.
+ private static bool IsThinQualifiedNameWrapperRule(TextualNotationRule rule)
+ {
+ if (rule == null || rule.Alternatives.Count != 1)
+ {
+ return false;
+ }
+
+ var alternative = rule.Alternatives[0];
+
+ if (alternative.Elements.Count != 1)
+ {
+ return false;
+ }
+
+ return alternative.Elements[0] is ValueLiteralElement valueLiteralElement
+ && valueLiteralElement.QueryIsQualifiedName();
+ }
}
}
diff --git a/SysML2.NET.CodeGenerator/HandleBarHelpers/RuleProcessor.PatternHandlers.cs b/SysML2.NET.CodeGenerator/HandleBarHelpers/RuleProcessor.PatternHandlers.cs
index 10d0e11f..8bbb6f10 100644
--- a/SysML2.NET.CodeGenerator/HandleBarHelpers/RuleProcessor.PatternHandlers.cs
+++ b/SysML2.NET.CodeGenerator/HandleBarHelpers/RuleProcessor.PatternHandlers.cs
@@ -60,14 +60,14 @@ private bool TryHandleOperatorLiteralAlternation(EncodedTextWriter writer, IClas
return false;
}
- var literals = this.ExtractLiteralAlternation(operatorAssignment.Value, ruleGenerationContext.AllRules);
+ var literals = ExtractLiteralAlternation(operatorAssignment.Value, ruleGenerationContext.AllRules);
if (literals == null || literals.Count == 0)
{
return false;
}
- if (!this.AreAlternativeTailElementsProcessable(alternative.Elements, umlClass, ruleGenerationContext))
+ if (!AreAlternativeTailElementsProcessable(alternative.Elements, umlClass, ruleGenerationContext))
{
return false;
}
@@ -237,7 +237,7 @@ private bool TryHandleEmptyVsNonEmptyMembership(EncodedTextWriter writer, IClass
///
/// Pattern C: detects poco-runtime-type dispatch with compound alternatives.
///
- private bool TryHandlePocoTypeDispatchWithCompoundAlternatives(EncodedTextWriter writer, IClass umlClass, IReadOnlyCollection alternatives, RuleGenerationContext ruleGenerationContext)
+ private static bool TryHandlePocoTypeDispatchWithCompoundAlternatives(EncodedTextWriter writer, IClass umlClass, IReadOnlyCollection alternatives, RuleGenerationContext ruleGenerationContext)
{
if (alternatives.Count < 2)
{
@@ -296,7 +296,7 @@ private bool TryHandlePocoTypeDispatchWithCompoundAlternatives(EncodedTextWriter
var orderedBranches = branches
.Where(branch => branch.TargetClass != umlClass)
- .OrderByDescending(branch => branch.TargetClass.QueryAllGeneralClassifiers().Count())
+ .OrderByDescending(branch => branch.TargetClass.QueryAllGeneralClassifiers().Count)
.ToList();
writer.WriteSafeString($"switch (poco){Environment.NewLine}");
@@ -306,14 +306,14 @@ private bool TryHandlePocoTypeDispatchWithCompoundAlternatives(EncodedTextWriter
{
var caseVarName = $"poco{targetClass.Name}";
writer.WriteSafeString($"case {targetClass.QueryFullyQualifiedTypeName()} {caseVarName}:{Environment.NewLine}");
- this.EmitCompoundPocoTypeBranch(writer, umlClass, leadingNonTerminal, alternative, targetClass, caseVarName, ruleGenerationContext);
+ EmitCompoundPocoTypeBranch(writer, umlClass, leadingNonTerminal, alternative, targetClass, caseVarName);
writer.WriteSafeString($"break;{Environment.NewLine}");
}
if (defaultBranch.NonTerminal != null)
{
writer.WriteSafeString($"default:{Environment.NewLine}");
- this.EmitCompoundPocoTypeBranch(writer, umlClass, defaultBranch.NonTerminal, defaultBranch.Alternative, defaultBranch.TargetClass, "poco", ruleGenerationContext);
+ EmitCompoundPocoTypeBranch(writer, umlClass, defaultBranch.NonTerminal, defaultBranch.Alternative, defaultBranch.TargetClass, "poco");
writer.WriteSafeString($"break;{Environment.NewLine}");
}
@@ -428,7 +428,7 @@ private bool TryHandleReferenceOrInline(EncodedTextWriter writer, IClass umlClas
///
/// Validates that tail elements of an alternative resolve to existing target classes.
///
- private bool AreAlternativeTailElementsProcessable(IReadOnlyList elements, IClass umlClass, RuleGenerationContext ruleGenerationContext)
+ private static bool AreAlternativeTailElementsProcessable(IReadOnlyList elements, IClass umlClass, RuleGenerationContext ruleGenerationContext)
{
for (var elementIndex = 1; elementIndex < elements.Count; elementIndex++)
{
@@ -462,7 +462,7 @@ private bool AreAlternativeTailElementsProcessable(IReadOnlyList el
///
/// Extracts literal terminal values from a grammar value element.
///
- private List ExtractLiteralAlternation(RuleElement value, IReadOnlyList allRules)
+ private static List ExtractLiteralAlternation(RuleElement value, IReadOnlyList allRules)
{
switch (value)
{
@@ -479,9 +479,9 @@ private List ExtractLiteralAlternation(RuleElement value, IReadOnlyList<
var literals = new List();
- foreach (var ruleAlternative in referencedRule.Alternatives)
+ foreach (var ruleAlternativeElements in referencedRule.Alternatives.Select(x => x.Elements))
{
- if (ruleAlternative.Elements.Count != 1 || ruleAlternative.Elements[0] is not TerminalElement nestedTerminal)
+ if (ruleAlternativeElements.Count != 1 || ruleAlternativeElements[0] is not TerminalElement nestedTerminal)
{
return null;
}
@@ -499,10 +499,10 @@ private List ExtractLiteralAlternation(RuleElement value, IReadOnlyList<
///
/// Handles alternatives targeting multiple collection properties by falling back to HandCoded.
///
- private void ProcessMultiCollectionAssignment(EncodedTextWriter writer, IClass umlClass, IReadOnlyCollection alternatives, RuleGenerationContext ruleGenerationContext)
+ private static void ProcessMultiCollectionAssignment(EncodedTextWriter writer, IReadOnlyCollection alternatives, RuleGenerationContext ruleGenerationContext)
{
var handCodedRuleName = alternatives.ElementAt(0).TextualNotationRule.RuleName;
- this.EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
+ EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
}
///
@@ -535,11 +535,11 @@ private void ProcessUnitypedAlternativesWithOneElement(EncodedTextWriter writer,
var elementBoolProps = new List<(NonTerminalElement RuleElement, List BoolProps)>();
- foreach (var element in duplicateGroup.Value)
+ foreach (var ruleElement in duplicateGroup.Value.Select(x => x.RuleElement))
{
- var referencedRule = ruleGenerationContext.AllRules.Single(x => x.RuleName == element.RuleElement.Name);
+ var referencedRule = ruleGenerationContext.AllRules.Single(x => x.RuleName == ruleElement.Name);
var booleanProperties = RuleQueryUtilities.QueryBooleanAssignmentProperties(referencedRule, ruleGenerationContext.AllRules);
- elementBoolProps.Add((element.RuleElement, booleanProperties));
+ elementBoolProps.Add((ruleElement, booleanProperties));
}
for (var elementIndex = 0; elementIndex < elementBoolProps.Count; elementIndex++)
@@ -793,8 +793,8 @@ private void ProcessUnitypedAlternativesWithOneElement(EncodedTextWriter writer,
return -1;
}
- var depthA = a.UmlClass.QueryAllGeneralClassifiers().Count();
- var depthB = b.UmlClass.QueryAllGeneralClassifiers().Count();
+ var depthA = a.UmlClass.QueryAllGeneralClassifiers().Count;
+ var depthB = b.UmlClass.QueryAllGeneralClassifiers().Count;
return depthB.CompareTo(depthA);
});
@@ -821,7 +821,7 @@ private void ProcessUnitypedAlternativesWithOneElement(EncodedTextWriter writer,
{
var handCodedRuleName = alternatives.ElementAt(0).TextualNotationRule?.RuleName ?? "Unknown";
- this.EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext, true);
+ EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext, true);
break;
}
@@ -1028,7 +1028,7 @@ private void ProcessUnitypedAlternativesWithOneElement(EncodedTextWriter writer,
default:
{
var defaultHandCodedRuleName = alternatives.ElementAt(0).TextualNotationRule.RuleName;
- this.EmitHandCodedFallback(writer, defaultHandCodedRuleName, ruleGenerationContext);
+ EmitHandCodedFallback(writer, defaultHandCodedRuleName, ruleGenerationContext);
break;
}
}
@@ -1037,7 +1037,7 @@ private void ProcessUnitypedAlternativesWithOneElement(EncodedTextWriter writer,
///
/// Emits a single type-dispatched branch body.
///
- private void EmitCompoundPocoTypeBranch(EncodedTextWriter writer, IClass umlClass, NonTerminalElement leadingNonTerminal, Alternatives alternative, IClass targetClass, string variableName, RuleGenerationContext ruleGenerationContext)
+ private static void EmitCompoundPocoTypeBranch(EncodedTextWriter writer, IClass umlClass, NonTerminalElement leadingNonTerminal, Alternatives alternative, IClass targetClass, string variableName)
{
string builderCall;
diff --git a/SysML2.NET.CodeGenerator/HandleBarHelpers/RuleProcessor.cs b/SysML2.NET.CodeGenerator/HandleBarHelpers/RuleProcessor.cs
index 94a5d3e5..db10565e 100644
--- a/SysML2.NET.CodeGenerator/HandleBarHelpers/RuleProcessor.cs
+++ b/SysML2.NET.CodeGenerator/HandleBarHelpers/RuleProcessor.cs
@@ -127,7 +127,7 @@ internal void DeclareAllRequiredCursors(EncodedTextWriter writer, IClass umlClas
/// When true, suppress duplicate emissions via
///
///
- private void EmitHandCodedFallback(EncodedTextWriter writer, string ruleName, RuleGenerationContext ruleGenerationContext, bool deduplicate = false)
+ private static void EmitHandCodedFallback(EncodedTextWriter writer, string ruleName, RuleGenerationContext ruleGenerationContext, bool deduplicate = false)
{
if (deduplicate && !ruleGenerationContext.EmittedHandCodedCalls.Add(ruleName))
{
@@ -268,6 +268,61 @@ private static string ResolveAssignmentTargetTypeName(AssignmentElement assignme
return targetClass?.QueryFullyQualifiedTypeName();
}
+ ///
+ /// Resolves the fully-qualified runtime type name of the inner element a "thin owning
+ /// wrapper" rule wraps. A thin owning wrapper is a rule whose target is
+ /// OwningMembership and whose body is a single
+ /// ownedRelatedElement += SomeNonTerminal assignment (e.g.
+ /// OwnedMultiplicity : OwningMembership = ownedRelatedElement += MultiplicityRange).
+ /// In such cases the wrapper type (IOwningMembership) is too coarse a discriminator
+ /// because every OwningMembership subtype (e.g. EndFeatureMembership) also
+ /// satisfies it; narrowing the check to the wrapped inner element type
+ /// (IMultiplicityRange) gives the precision the optional-group guard needs.
+ /// Returns when the assignment's referenced rule does not match
+ /// the thin-wrapper shape.
+ ///
+ /// The += assignment whose referenced rule is inspected.
+ /// The class hosting the current rule (provides the UML cache).
+ /// The current .
+ /// The fully-qualified inner-element type name, or if the rule is not a thin wrapper.
+ private static string TryResolveWrappedInnerTypeName(AssignmentElement assignmentElement, IClass umlClass, RuleGenerationContext ruleGenerationContext)
+ {
+ if (assignmentElement.Value is not NonTerminalElement nonTerminalElement)
+ {
+ return null;
+ }
+
+ var referencedRule = ruleGenerationContext.FindRule(nonTerminalElement.Name);
+
+ if (referencedRule == null
+ || !string.Equals(referencedRule.EffectiveTarget, "OwningMembership", StringComparison.Ordinal)
+ || referencedRule.Alternatives.Count != 1)
+ {
+ return null;
+ }
+
+ var alternative = referencedRule.Alternatives[0];
+
+ if (alternative.Elements.Count != 1
+ || alternative.Elements[0] is not AssignmentElement innerAssignment
+ || !string.Equals(innerAssignment.Property, "ownedRelatedElement", StringComparison.OrdinalIgnoreCase)
+ || innerAssignment.Value is not NonTerminalElement innerNonTerminal)
+ {
+ return null;
+ }
+
+ var innerRule = ruleGenerationContext.FindRule(innerNonTerminal.Name);
+ var innerTypeTarget = innerRule?.EffectiveTarget ?? innerNonTerminal.Name;
+
+ if (string.IsNullOrWhiteSpace(innerTypeTarget))
+ {
+ return null;
+ }
+
+ var innerClass = RuleQueryUtilities.FindClass(umlClass.Cache, innerTypeTarget);
+ return innerClass?.QueryFullyQualifiedTypeName();
+ }
+
///
/// Processes a single alternative (no branching needed). Handles optional guard emission
/// and iterates through the alternative's elements.
@@ -372,7 +427,7 @@ private void ProcessSingleAlternative(EncodedTextWriter writer, IClass umlClass,
if (referencedRule != null)
{
- var condition = this.GenerateInlineOptionalCondition(writer, referencedRule, umlClass, ruleGenerationContext, "poco");
+ var condition = GenerateInlineOptionalCondition(writer, referencedRule, umlClass, ruleGenerationContext, "poco");
if (condition != null)
{
@@ -444,7 +499,7 @@ private void ProcessSingleElementAlternatives(EncodedTextWriter writer, IClass u
{
if (alternatives.ElementAt(0).Elements[0].TextualNotationRule.IsMultiCollectionAssignment)
{
- this.ProcessMultiCollectionAssignment(writer, umlClass, alternatives, ruleGenerationContext);
+ ProcessMultiCollectionAssignment(writer, alternatives, ruleGenerationContext);
return;
}
@@ -546,7 +601,7 @@ private void ProcessMixedTypeSingleElementAlternatives(EncodedTextWriter writer,
{
var handCodedRuleName = alternatives.ElementAt(0).TextualNotationRule.RuleName;
- this.EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext, true);
+ EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext, true);
}
}
@@ -568,7 +623,7 @@ private void EmitNonTerminalThenAssignmentDispatch(EncodedTextWriter writer, ICl
if (referencedAssignmentNonTerminals.Count != assignmentElements.Count)
{
var handCodedRuleName = alternatives.ElementAt(0).TextualNotationRule.RuleName;
- this.EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
+ EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
return;
}
@@ -626,7 +681,7 @@ private void EmitNonTerminalThenAssignmentDispatch(EncodedTextWriter writer, ICl
? nonTerminalReferencedRule.EffectiveTarget
: umlClass.Name;
- var nonTerminalCall = this.ResolveBuilderCall(umlClass, nonTerminalElement, nonTerminalTypeTarget, ruleGenerationContext);
+ var nonTerminalCall = ResolveBuilderCall(umlClass, nonTerminalElement, nonTerminalTypeTarget, ruleGenerationContext);
if (nonTerminalCall != null)
{
@@ -658,12 +713,12 @@ private void ProcessMultiElementAlternatives(EncodedTextWriter writer, IClass um
// When all alternatives consist exclusively of terminal elements (and optionally non-parsing assignments), handle via code-gen
if (alternatives.All(alt => alt.Elements.Count > 0 && alt.Elements.All(element => element is TerminalElement or NonParsingAssignmentElement)))
{
- this.EmitTerminalOnlyAlternatives(writer, umlClass, alternatives, ruleGenerationContext);
+ EmitTerminalOnlyAlternatives(writer, umlClass, alternatives, ruleGenerationContext);
return;
}
// Detect pattern: property=[QualifiedName] | property=NonTerminal{containment+=property}
- if (alternatives.Count == 2 && this.TryEmitQualifiedNameOrChainAlternatives(writer, umlClass, alternatives, ruleGenerationContext))
+ if (alternatives.Count == 2 && TryEmitQualifiedNameOrChainAlternatives(writer, umlClass, alternatives, ruleGenerationContext))
{
return;
}
@@ -689,7 +744,7 @@ private void ProcessMultiElementAlternatives(EncodedTextWriter writer, IClass um
return;
}
- if (this.TryHandlePocoTypeDispatchWithCompoundAlternatives(writer, umlClass, alternatives, ruleGenerationContext))
+ if (TryHandlePocoTypeDispatchWithCompoundAlternatives(writer, umlClass, alternatives, ruleGenerationContext))
{
return;
}
@@ -701,7 +756,7 @@ private void ProcessMultiElementAlternatives(EncodedTextWriter writer, IClass um
var handCodedRuleName = alternatives.ElementAt(0).TextualNotationRule.RuleName;
- this.EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext, true);
+ EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext, true);
}
}
@@ -714,7 +769,7 @@ private void ProcessMultiElementAlternatives(EncodedTextWriter writer, IClass um
/// The related
/// The grammar alternatives to process
/// The current
- private void EmitTerminalOnlyAlternatives(EncodedTextWriter writer, IClass umlClass, IReadOnlyCollection alternatives, RuleGenerationContext ruleGenerationContext)
+ private static void EmitTerminalOnlyAlternatives(EncodedTextWriter writer, IClass umlClass, IReadOnlyCollection alternatives, RuleGenerationContext ruleGenerationContext)
{
var nonParsingAssignments = alternatives
.SelectMany(alt => alt.Elements.OfType())
@@ -741,10 +796,10 @@ private void EmitTerminalOnlyAlternatives(EncodedTextWriter writer, IClass umlCl
writer.WriteSafeString($"switch ({ruleGenerationContext.CurrentVariableName ?? "poco"}.{targetPropertyName}){Environment.NewLine}");
writer.WriteSafeString($"{{{Environment.NewLine}");
- foreach (var alternative in alternatives)
+ foreach (var alternativeElements in alternatives.Select(x => x.Elements))
{
- var nonParsingAssignment = alternative.Elements.OfType().Single();
- var terminals = alternative.Elements.OfType().ToList();
+ var nonParsingAssignment = alternativeElements.OfType().Single();
+ var terminals = alternativeElements.OfType().ToList();
var enumValueName = nonParsingAssignment.Value.Trim('\'').CapitalizeFirstLetter();
writer.WriteSafeString($"case {targetProperty.Type.QueryFullyQualifiedTypeName()}.{enumValueName}:{Environment.NewLine}");
@@ -781,7 +836,7 @@ private void EmitTerminalOnlyAlternatives(EncodedTextWriter writer, IClass umlCl
/// The grammar alternatives to process
/// The current
/// true if the pattern matched and code was emitted; false otherwise
- private bool TryEmitQualifiedNameOrChainAlternatives(EncodedTextWriter writer, IClass umlClass, IReadOnlyCollection alternatives, RuleGenerationContext ruleGenerationContext)
+ private static bool TryEmitQualifiedNameOrChainAlternatives(EncodedTextWriter writer, IClass umlClass, IReadOnlyCollection alternatives, RuleGenerationContext ruleGenerationContext)
{
var qualifiedNameAlt = alternatives.FirstOrDefault(alt =>
alt.Elements.Count == 1
@@ -905,7 +960,7 @@ private void EmitTerminalVsBodyAlternatives(EncodedTextWriter writer, IClass uml
else
{
var handCodedRuleName = firstAlt.TextualNotationRule.RuleName;
- this.EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
+ EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
}
}
}
@@ -943,7 +998,7 @@ private void EmitTerminalVsBodyWithCollectionAssignments(EncodedTextWriter write
else
{
var handCodedRuleName = firstAlt.TextualNotationRule.RuleName;
- this.EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
+ EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
}
}
@@ -958,7 +1013,7 @@ private void EmitTerminalVsBodyWithCollectionNonTerminals(EncodedTextWriter writ
if (nonTerminalRule == null)
{
var handCodedRuleName = firstAlt.TextualNotationRule.RuleName;
- this.EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
+ EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
return;
}
@@ -967,7 +1022,7 @@ private void EmitTerminalVsBodyWithCollectionNonTerminals(EncodedTextWriter writ
if (collectionPropertyNames.Count == 0)
{
var handCodedRuleName = firstAlt.TextualNotationRule.RuleName;
- this.EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
+ EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
return;
}
@@ -978,7 +1033,7 @@ private void EmitTerminalVsBodyWithCollectionNonTerminals(EncodedTextWriter writ
if (targetProperty == null)
{
var handCodedRuleName = firstAlt.TextualNotationRule.RuleName;
- this.EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
+ EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
return;
}
@@ -1006,7 +1061,7 @@ private void EmitTerminalVsBodyWithCollectionNonTerminals(EncodedTextWriter writ
? referencedRule.EffectiveTarget
: umlClass.Name;
- var perItemCall = this.ResolveBuilderCall(umlClass, collectionNonTerminal, typeTarget, ruleGenerationContext);
+ var perItemCall = ResolveBuilderCall(umlClass, collectionNonTerminal, typeTarget, ruleGenerationContext);
writer.WriteSafeString($"while ({cursorVarName}.Current != null){Environment.NewLine}");
writer.WriteSafeString($"{{{Environment.NewLine}");
@@ -1047,7 +1102,7 @@ private void EmitTerminalVsBodyWithSingleNonTerminal(EncodedTextWriter writer, I
if (nonTerminalRule == null)
{
var handCodedRuleName = firstAlt.TextualNotationRule.RuleName;
- this.EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
+ EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
return;
}
@@ -1056,7 +1111,7 @@ private void EmitTerminalVsBodyWithSingleNonTerminal(EncodedTextWriter writer, I
if (collectionPropertyNames.Count == 0)
{
var handCodedRuleName = firstAlt.TextualNotationRule.RuleName;
- this.EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
+ EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
return;
}
@@ -1067,7 +1122,7 @@ private void EmitTerminalVsBodyWithSingleNonTerminal(EncodedTextWriter writer, I
if (targetProperty == null)
{
var handCodedRuleName = firstAlt.TextualNotationRule.RuleName;
- this.EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
+ EmitHandCodedFallback(writer, handCodedRuleName, ruleGenerationContext);
return;
}
@@ -1094,7 +1149,7 @@ private void EmitTerminalVsBodyWithSingleNonTerminal(EncodedTextWriter writer, I
? referencedRule.EffectiveTarget
: umlClass.Name;
- var perItemCall = this.ResolveBuilderCall(umlClass, singleNonTerminal, typeTarget, ruleGenerationContext);
+ var perItemCall = ResolveBuilderCall(umlClass, singleNonTerminal, typeTarget, ruleGenerationContext);
writer.WriteSafeString($"if ({cursorVarName}.Current != null){Environment.NewLine}");
writer.WriteSafeString($"{{{Environment.NewLine}");
diff --git a/SysML2.NET.CodeGenerator/TEXTUAL_NOTATION_CODEGEN.md b/SysML2.NET.CodeGenerator/TEXTUAL_NOTATION_CODEGEN.md
index 9f34bbb4..be44a645 100644
--- a/SysML2.NET.CodeGenerator/TEXTUAL_NOTATION_CODEGEN.md
+++ b/SysML2.NET.CodeGenerator/TEXTUAL_NOTATION_CODEGEN.md
@@ -447,6 +447,26 @@ When the generator detects an unsupported rule shape it emits a delegating call:
Build{RuleName}HandCoded(poco, writerContext, stringBuilder);
```
+### 13.1 Polymorphic `ownedMemberFeature` access on `IFeatureMembership`
+
+Independent of the per-rule fallback, the generator transparently normalises the two runtime shapes an `IFeatureMembership` can take whenever a rule body accesses the `ownedMemberFeature` scalar property:
+
+- **Pure `IFeatureMembership` shape** — `membership.ownedMemberFeature` is directly the target feature (typically the rule's expected `IExpression` subtype). This matches the parser-direction production literally (e.g. `SequenceExpressionListMember : FeatureMembership = ownedMemberFeature = SequenceExpressionList`).
+- **`IParameterMembership` shape** — used to model the operands of every `InvocationExpression` / `OperatorExpression` per KerML §8.2.5.8.2 Notes 1-2 (`Resources/KerML-textual-bnf.kebnf:1176-1178`, "primary expressions provide additional shorthand notations for certain kinds of InvocationExpressions"). Here `ownedMemberFeature` is the parameter `Feature`; the operand expression lives one level deeper, under that feature's `FeatureValue.value`.
+
+Because `IParameterMembership : IFeatureMembership`, both shapes pass the rule's `is IFeatureMembership` test but produce structurally different `ownedMemberFeature` trees. The literal codegen produced by `RuleProcessor.ProcessAssignmentElement` would emit `poco.ownedMemberFeature is IExpression …` — a check that silently fails on the parameter-membership shape, dropping the operand.
+
+To avoid this, `RuleProcessor.ProcessAssignmentElement` (`SysML2.NET.CodeGenerator/HandleBarHelpers/RuleProcessor.ElementProcessing.cs`) detects the case `targetProperty.Name == "ownedMemberFeature"` AND `umlClass` IS-A `FeatureMembership`, and emits a local-variable declaration at the access point:
+
+```csharp
+var effectiveOwnedMemberFeature = SharedTextualNotationBuilder.QueryEffectiveOwnedMemberFeature(poco);
+if (effectiveOwnedMemberFeature is IExpectedExpressionType …) { … }
+```
+
+`SharedTextualNotationBuilder.QueryEffectiveOwnedMemberFeature` (`SysML2.NET.Serializer.TextualNotation/Writers/SharedTextualNotationBuilder.cs`) handles the polymorphism: for an `IParameterMembership` it unwraps `ownedMemberFeature.OwnedRelationship.OfType().value`; for the pure shape it returns `ownedMemberFeature` as-is. Downstream type tests in the generated code are unchanged.
+
+This is a structural fix — not a per-rule allowlist — so every current and future rule whose body accesses `ownedMemberFeature` (`SequenceExpressionListMember`, `OwnedExpressionMember`, `FunctionReferenceMember`, `BodyArgumentMember`, etc.) is corrected uniformly.
+
The hand-coded partial must:
1. Live in `SysML2.NET.Serializer.TextualNotation/Writers/{ClassName}TextualNotationBuilder.cs` — the file **next to** (not inside) `AutoGenTextualNotationBuilder/`.
@@ -459,7 +479,7 @@ Every hand-coded implementation must be reviewed against the same four invariant
1. **Cursor advancement (§7)** — exactly one `Move()` per `+=` processed; never a `Move()` after a callee that already advanced the cursor.
2. **Quantifier semantics (§12)** — `?` is a single `if`, `*` is a `while` that may execute zero times, `+` is one unconditional emission followed by the same `while`.
-3. **Type discriminator correctness (§9)** — the value pattern-matched in a `switch` must be the *actual* element on the cursor (e.g. an `ISpecialization` directly, not the `IOwningMembership` wrapping it).
+3. **Type discriminator correctness (§9)** — the value pattern-matched in a `switch` must be the *actual* element on the cursor (e.g. an `ISpecialization` directly, not the `IOwningMembership` wrapping it). The optional-group guard generator now applies this invariant automatically: when an assignment's referenced rule is a "thin owning wrapper" of shape `: OwningMembership = ownedRelatedElement += T`, the emitter narrows the bare `cursor.Current is IOwningMembership` to `(cursor.Current is IOwningMembership om && om.OwnedRelatedElement.OfType().Any())` so a sibling `EndFeatureMembership` (also `IOwningMembership`) cannot spuriously satisfy the guard. The canonical case is `OwnedMultiplicity : OwningMembership = ownedRelatedElement += MultiplicityRange`; the narrowing was added after `BuildBindingConnectorAsUsage` was found emitting a spurious `binding ` prefix because its first ownedRelationship (an `EndFeatureMembership`) was passing `is IOwningMembership`.
4. **Grammar fidelity** — the element order, alternatives, and target metaclass of the hand-coded method must match the KEBNF rule verbatim.
Bugs in any of these four areas were the dominant source of regressions during the migration from purely hand-coded builders to the generator-first approach, and they remain the costliest to diagnose because they fail silently rather than throwing.
diff --git a/SysML2.NET.Serializer.TextualNotation.Tests/SysML2.NET.Serializer.TextualNotation.Tests.csproj b/SysML2.NET.Serializer.TextualNotation.Tests/SysML2.NET.Serializer.TextualNotation.Tests.csproj
index a52cbed3..c8742c0f 100644
--- a/SysML2.NET.Serializer.TextualNotation.Tests/SysML2.NET.Serializer.TextualNotation.Tests.csproj
+++ b/SysML2.NET.Serializer.TextualNotation.Tests/SysML2.NET.Serializer.TextualNotation.Tests.csproj
@@ -36,6 +36,8 @@
+
+
@@ -49,4 +51,16 @@
+
+
+ Always
+
+
+ Always
+
+
+ Always
+
+
+
diff --git a/SysML2.NET.Serializer.TextualNotation.Tests/Validation/01-Parts Tree/1a-Parts Tree.sysmlx b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/01-Parts Tree/1a-Parts Tree.sysmlx
new file mode 100644
index 00000000..4ac4c4a7
--- /dev/null
+++ b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/01-Parts Tree/1a-Parts Tree.sysmlx
@@ -0,0 +1,414 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SysML2.NET.Serializer.TextualNotation.Tests/Validation/01-Parts Tree/1c-Parts Tree Redefinition.sysmlx b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/01-Parts Tree/1c-Parts Tree Redefinition.sysmlx
new file mode 100644
index 00000000..4e7e596d
--- /dev/null
+++ b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/01-Parts Tree/1c-Parts Tree Redefinition.sysmlx
@@ -0,0 +1,363 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SysML2.NET.Serializer.TextualNotation.Tests/Validation/01-Parts Tree/1d-Parts Tree with Reference.sysmlx b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/01-Parts Tree/1d-Parts Tree with Reference.sysmlx
new file mode 100644
index 00000000..898555b5
--- /dev/null
+++ b/SysML2.NET.Serializer.TextualNotation.Tests/Validation/01-Parts Tree/1d-Parts Tree with Reference.sysmlx
@@ -0,0 +1,147 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SysML2.NET.Serializer.TextualNotation.Tests/Wrapper/LibraryRedirectingExternalReferenceService.cs b/SysML2.NET.Serializer.TextualNotation.Tests/Wrapper/LibraryRedirectingExternalReferenceService.cs
new file mode 100644
index 00000000..1a1e8b74
--- /dev/null
+++ b/SysML2.NET.Serializer.TextualNotation.Tests/Wrapper/LibraryRedirectingExternalReferenceService.cs
@@ -0,0 +1,166 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright (C) 2022-2026 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.Serializer.TextualNotation.Tests.Wrapper
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+
+ using Microsoft.Extensions.Logging;
+
+ using SysML2.NET.Serializer.Xmi;
+
+ ///
+ /// Test-only that redirects href references
+ /// originally generated against a sysml.library/ tree (pilot-implementation layout)
+ /// to a locally available copy of those library files — typically the
+ /// SysML2.NET.Serializer.Xmi.Tests/Resources tree mirrored into the test output
+ /// folder by the test project's csproj.
+ ///
+ /// The sysmlx / kermlx files under test are generated by the pilot implementation
+ /// and emit hrefs of the form ../../../../sysml.library/Domain%20Libraries/.../SI.sysmlx.
+ /// Those paths do not exist on the test machine. Rather than editing the generated files,
+ /// this service intercepts each href, detects the sysml.library/ marker segment, and
+ /// rebuilds the absolute path against , preserving everything
+ /// after the marker. Hrefs without the marker fall back to the standard relative-to-current
+ /// resolution used by .
+ ///
+ ///
+ public sealed class LibraryRedirectingExternalReferenceService : IExternalReferenceService
+ {
+ ///
+ /// Marker substring identifying the pilot-implementation library root inside an href.
+ /// Everything after this segment is treated as a path relative to .
+ ///
+ private const string LibraryMarker = "sysml.library/";
+
+ ///
+ /// External references queued for processing.
+ ///
+ private readonly HashSet pendingReferences = [];
+
+ ///
+ /// External references already returned via .
+ ///
+ private readonly HashSet processedReferences = [];
+
+ ///
+ /// The local folder that mirrors the pilot-implementation sysml.library tree —
+ /// typically the test output Resources folder.
+ ///
+ private readonly string libraryRoot;
+
+ ///
+ /// The injected logger used to surface redirect and dedupe events.
+ ///
+ private readonly ILogger logger;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// Absolute path to the local folder that mirrors the pilot-implementation
+ /// sysml.library tree (e.g. the test output Resources folder).
+ ///
+ /// The injected producing logs.
+ /// When is .
+ public LibraryRedirectingExternalReferenceService(string libraryRoot, ILogger logger)
+ {
+ this.libraryRoot = libraryRoot ?? throw new ArgumentNullException(nameof(libraryRoot));
+ this.logger = logger;
+ }
+
+ ///
+ /// Resolves against ,
+ /// redirecting any path containing the sysml.library/ marker to
+ /// , and queues the resulting absolute for
+ /// processing. Already-processed references are skipped.
+ ///
+ /// The of the file currently being read.
+ /// The raw href value (without fragment) emitted by the reader.
+ public void AddExternalReferenceToProcess(Uri currentLocation, string externalReference)
+ {
+ var unescaped = Uri.UnescapeDataString(externalReference);
+ var resolvedUri = this.Redirect(currentLocation, unescaped);
+
+ if (!this.processedReferences.Contains(resolvedUri))
+ {
+ this.pendingReferences.Add(resolvedUri);
+ }
+ else
+ {
+ if (this.logger?.IsEnabled(LogLevel.Information) == true)
+ {
+ this.logger.LogInformation("File {FileName} already processed", new FileInfo(resolvedUri.LocalPath).Name);
+ }
+ }
+ }
+
+ ///
+ /// Returns the queued references and marks them as processed so a subsequent
+ /// call for the same target is deduped.
+ ///
+ /// The references to deserialize next.
+ public IReadOnlyCollection GetExternalReferencesToProcess()
+ {
+ var toBeProcessed = new List(this.pendingReferences);
+
+ foreach (var uri in toBeProcessed)
+ {
+ this.processedReferences.Add(uri);
+ }
+
+ this.pendingReferences.Clear();
+ return toBeProcessed;
+ }
+
+ ///
+ /// Computes the absolute for an href: when the href contains the
+ /// sysml.library/ marker, the redirect replaces the marker prefix with
+ /// ; otherwise the href is resolved against
+ /// using the standard constructor —
+ /// matching the production behavior so secondary
+ /// library-to-library hrefs (already relative to the local libraryRoot layout) resolve naturally.
+ ///
+ /// The of the file currently being read.
+ /// The href value already unescaped via .
+ /// The absolute to the file to deserialize.
+ private Uri Redirect(Uri currentLocation, string unescapedHref)
+ {
+ var markerIndex = unescapedHref.IndexOf(LibraryMarker, StringComparison.Ordinal);
+
+ if (markerIndex < 0)
+ {
+ return new Uri(currentLocation, unescapedHref);
+ }
+
+ var subPath = unescapedHref.Substring(markerIndex + LibraryMarker.Length);
+ var redirectedPath = Path.GetFullPath(Path.Combine(this.libraryRoot, subPath));
+
+ if (this.logger?.IsEnabled(LogLevel.Information) == true)
+ {
+ this.logger.LogInformation("Redirected href '{Href}' to '{Redirected}'", unescapedHref, redirectedPath);
+ }
+
+ return new Uri(redirectedPath);
+ }
+ }
+}
diff --git a/SysML2.NET.Serializer.TextualNotation.Tests/Writers/TextualNotationValidationTestFixture.cs b/SysML2.NET.Serializer.TextualNotation.Tests/Writers/TextualNotationValidationTestFixture.cs
new file mode 100644
index 00000000..d446ba58
--- /dev/null
+++ b/SysML2.NET.Serializer.TextualNotation.Tests/Writers/TextualNotationValidationTestFixture.cs
@@ -0,0 +1,86 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright (C) 2022-2026 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.Serializer.TextualNotation.Tests.Writers
+{
+ using System;
+ using System.IO;
+ using System.Linq;
+ using System.Text;
+ using System.Threading;
+ using System.Threading.Tasks;
+
+ using Microsoft.Extensions.Logging;
+
+ using NUnit.Framework;
+
+ using SysML2.NET.Serializer.TextualNotation.Tests.Wrapper;
+ using SysML2.NET.Serializer.TextualNotation.Writers;
+ using SysML2.NET.Serializer.Xmi;
+
+ [TestFixture]
+ public class TextualNotationValidationTestFixture
+ {
+ [Test]
+ [TestCase("01-Parts Tree", "1a-Parts Tree.sysmlx")]
+ [TestCase("01-Parts Tree", "1c-Parts Tree Redefinition.sysmlx")]
+ [TestCase("01-Parts Tree", "1d-Parts Tree with Reference.sysmlx")]
+ public async Task VerifyValidationTextualNotationXmi(string folderName, string fileName)
+ {
+ var loggerFactory = LoggerFactory.Create(builder =>
+ {
+ builder.AddConsole();
+ builder.SetMinimumLevel(LogLevel.Warning);
+ });
+
+ var libraryRoot = Path.Combine(TestContext.CurrentContext.TestDirectory, "Resources");
+
+ var redirectingService = new LibraryRedirectingExternalReferenceService(
+ libraryRoot,
+ loggerFactory.CreateLogger());
+
+ var deSerializer = new DeSerializer(loggerFactory, redirectingService);
+
+ var filePath = Path.Combine(TestContext.CurrentContext.TestDirectory, "Validation", folderName, fileName);
+
+ var rootNamespace = await deSerializer.DeSerializeAsync(new Uri(filePath));
+
+ using var writerContext = new TextualNotationWriterContext(rootNamespace);
+ writerContext.EmitOperatorParentheses = false;
+ var stringBuilder = new StringBuilder();
+
+ try
+ {
+ NamespaceTextualNotationBuilder.BuildRootNamespace(rootNamespace, writerContext, stringBuilder);
+ }
+ catch (System.Exception exception)
+ {
+ TestContext.WriteLine($"Builder stopped early due to: {exception.Message}, {exception.StackTrace}");
+ }
+
+ var textualNotation = stringBuilder.ToString();
+
+ Assert.That(textualNotation, Is.Not.Empty);
+ TestContext.WriteLine("=== Textual Notation Output ===");
+ TestContext.WriteLine(textualNotation);
+ TestContext.WriteLine("=== End ===");
+ }
+ }
+}
diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/AcceptActionUsageTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/AcceptActionUsageTextualNotationBuilder.cs
index 3a47c88f..3bea6ae7 100644
--- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/AcceptActionUsageTextualNotationBuilder.cs
+++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/AcceptActionUsageTextualNotationBuilder.cs
@@ -60,7 +60,7 @@ public static void BuildAcceptNodeDeclaration(SysML2.NET.Core.POCO.Systems.Actio
{
var ownedRelationshipCursor = writerContext.CursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship);
- if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership) || poco.IsOrdered)
+ if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership owningMembership0 && owningMembership0.OwnedRelatedElement.OfType().Any())) || poco.IsOrdered)
{
ActionUsageTextualNotationBuilder.BuildActionNodeUsageDeclaration(poco, writerContext, stringBuilder);
}
diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ActionUsageTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ActionUsageTextualNotationBuilder.cs
index a72e1d18..87e5b459 100644
--- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ActionUsageTextualNotationBuilder.cs
+++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ActionUsageTextualNotationBuilder.cs
@@ -104,7 +104,7 @@ public static void BuildActionNodeUsageDeclaration(SysML2.NET.Core.POCO.Systems.
stringBuilder.Append("action ");
var ownedRelationshipCursor = writerContext.CursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship);
- if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership) || poco.IsOrdered)
+ if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership owningMembership0 && owningMembership0.OwnedRelatedElement.OfType().Any())) || poco.IsOrdered)
{
UsageTextualNotationBuilder.BuildUsageDeclaration(poco, writerContext, stringBuilder);
}
@@ -123,7 +123,7 @@ public static void BuildActionNodePrefix(SysML2.NET.Core.POCO.Systems.Actions.IA
OccurrenceUsageTextualNotationBuilder.BuildOccurrenceUsagePrefix(poco, writerContext, stringBuilder);
var ownedRelationshipCursor = writerContext.CursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship);
- if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership) || poco.IsOrdered)
+ if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership owningMembership0 && owningMembership0.OwnedRelatedElement.OfType().Any())) || poco.IsOrdered)
{
BuildActionNodeUsageDeclaration(poco, writerContext, stringBuilder);
}
@@ -141,7 +141,7 @@ public static void BuildAssignmentNodeDeclaration(SysML2.NET.Core.POCO.Systems.A
{
var ownedRelationshipCursor = writerContext.CursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship);
- if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership) || poco.IsOrdered)
+ if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership owningMembership0 && owningMembership0.OwnedRelatedElement.OfType().Any())) || poco.IsOrdered)
{
BuildActionNodeUsageDeclaration(poco, writerContext, stringBuilder);
stringBuilder.Append(' ');
@@ -196,11 +196,11 @@ public static void BuildActionBodyParameter(SysML2.NET.Core.POCO.Systems.Actions
{
var ownedRelationshipCursor = writerContext.CursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship);
- if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership) || poco.IsOrdered)
+ if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership owningMembership0 && owningMembership0.OwnedRelatedElement.OfType().Any())) || poco.IsOrdered)
{
stringBuilder.Append("action ");
- if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership) || poco.IsOrdered)
+ if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership owningMembership1 && owningMembership1.OwnedRelatedElement.OfType().Any())) || poco.IsOrdered)
{
UsageTextualNotationBuilder.BuildUsageDeclaration(poco, writerContext, stringBuilder);
}
diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/AssertConstraintUsageTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/AssertConstraintUsageTextualNotationBuilder.cs
index a736c77b..9f361192 100644
--- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/AssertConstraintUsageTextualNotationBuilder.cs
+++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/AssertConstraintUsageTextualNotationBuilder.cs
@@ -67,7 +67,7 @@ public static void BuildAssertConstraintUsage(SysML2.NET.Core.POCO.Systems.Const
}
}
- if ((ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership) || poco.IsOrdered)
+ if ((ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership owningMembership0 && owningMembership0.OwnedRelatedElement.OfType().Any())) || poco.IsOrdered)
{
FeatureTextualNotationBuilder.BuildFeatureSpecializationPart(poco, writerContext, stringBuilder);
}
diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/BindingConnectorAsUsageTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/BindingConnectorAsUsageTextualNotationBuilder.cs
index 559f6b51..b90a5f7c 100644
--- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/BindingConnectorAsUsageTextualNotationBuilder.cs
+++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/BindingConnectorAsUsageTextualNotationBuilder.cs
@@ -46,7 +46,7 @@ public static void BuildBindingConnectorAsUsage(SysML2.NET.Core.POCO.Systems.Con
var ownedRelationshipCursor = writerContext.CursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship);
UsageTextualNotationBuilder.BuildUsagePrefix(poco, writerContext, stringBuilder);
- if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership) || poco.IsOrdered)
+ if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership owningMembership0 && owningMembership0.OwnedRelatedElement.OfType().Any())) || poco.IsOrdered)
{
stringBuilder.Append("binding ");
UsageTextualNotationBuilder.BuildUsageDeclaration(poco, writerContext, stringBuilder);
diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ConnectorTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ConnectorTextualNotationBuilder.cs
index 22e1a092..48997eea 100644
--- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ConnectorTextualNotationBuilder.cs
+++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ConnectorTextualNotationBuilder.cs
@@ -104,7 +104,7 @@ public static void BuildNaryConnectorDeclaration(SysML2.NET.Core.POCO.Kernel.Con
var ownedRelationshipCursor = writerContext.CursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship);
var ownedTypeFeaturingCursor = writerContext.CursorCache.GetOrCreateCursor(poco.Id, "ownedTypeFeaturing", poco.ownedTypeFeaturing);
- if (poco.IsSufficient || !string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Types.IConjugation || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Types.IDisjoining || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Types.IUnioning || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Types.IIntersecting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Types.IDifferencing || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureChaining || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureInverting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ITypeFeaturing) || poco.IsOrdered || ownedTypeFeaturingCursor.Current is SysML2.NET.Core.POCO.Core.Features.ITypeFeaturing)
+ if (poco.IsSufficient || !string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership owningMembership0 && owningMembership0.OwnedRelatedElement.OfType().Any()) || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Types.IConjugation || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Types.IDisjoining || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Types.IUnioning || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Types.IIntersecting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Types.IDifferencing || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureChaining || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureInverting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ITypeFeaturing) || poco.IsOrdered || ownedTypeFeaturingCursor.Current is SysML2.NET.Core.POCO.Core.Features.ITypeFeaturing)
{
FeatureTextualNotationBuilder.BuildFeatureDeclaration(poco, writerContext, stringBuilder);
}
diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/EventOccurrenceUsageTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/EventOccurrenceUsageTextualNotationBuilder.cs
index 1a5cd12a..525a3040 100644
--- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/EventOccurrenceUsageTextualNotationBuilder.cs
+++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/EventOccurrenceUsageTextualNotationBuilder.cs
@@ -84,7 +84,7 @@ public static void BuildEventOccurrenceUsage(SysML2.NET.Core.POCO.Systems.Occurr
}
}
- if ((ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership) || poco.IsOrdered)
+ if ((ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership owningMembership0 && owningMembership0.OwnedRelatedElement.OfType().Any())) || poco.IsOrdered)
{
FeatureTextualNotationBuilder.BuildFeatureSpecializationPart(poco, writerContext, stringBuilder);
}
@@ -93,7 +93,7 @@ public static void BuildEventOccurrenceUsage(SysML2.NET.Core.POCO.Systems.Occurr
{
stringBuilder.Append("occurrence ");
- if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership) || poco.IsOrdered)
+ if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership owningMembership1 && owningMembership1.OwnedRelatedElement.OfType().Any())) || poco.IsOrdered)
{
UsageTextualNotationBuilder.BuildUsageDeclaration(poco, writerContext, stringBuilder);
}
diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ExhibitStateUsageTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ExhibitStateUsageTextualNotationBuilder.cs
index aa34003f..a9b08d7f 100644
--- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ExhibitStateUsageTextualNotationBuilder.cs
+++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ExhibitStateUsageTextualNotationBuilder.cs
@@ -60,7 +60,7 @@ public static void BuildExhibitStateUsage(SysML2.NET.Core.POCO.Systems.States.IE
}
}
- if ((ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership) || poco.IsOrdered)
+ if ((ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership owningMembership0 && owningMembership0.OwnedRelatedElement.OfType().Any())) || poco.IsOrdered)
{
FeatureTextualNotationBuilder.BuildFeatureSpecializationPart(poco, writerContext, stringBuilder);
}
diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/FeatureMembershipTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/FeatureMembershipTextualNotationBuilder.cs
index 4cacd4ad..1026926b 100644
--- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/FeatureMembershipTextualNotationBuilder.cs
+++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/FeatureMembershipTextualNotationBuilder.cs
@@ -468,14 +468,11 @@ public static void BuildTargetTransitionUsageMember(SysML2.NET.Core.POCO.Core.Ty
/// The that contains the entire textual notation
public static void BuildMetadataBodyUsageMember(SysML2.NET.Core.POCO.Core.Types.IFeatureMembership poco, TextualNotationWriterContext writerContext, StringBuilder stringBuilder)
{
+ var effectiveOwnedMemberFeature = SysML2.NET.Serializer.TextualNotation.Writers.SharedTextualNotationBuilder.QueryEffectiveOwnedMemberFeature(poco);
- if (poco.ownedMemberFeature != null)
+ if (effectiveOwnedMemberFeature is SysML2.NET.Core.POCO.Systems.DefinitionAndUsage.IReferenceUsage elementAsReferenceUsage)
{
-
- if (poco.ownedMemberFeature is SysML2.NET.Core.POCO.Systems.DefinitionAndUsage.IReferenceUsage elementAsReferenceUsage)
- {
- ReferenceUsageTextualNotationBuilder.BuildMetadataBodyUsage(elementAsReferenceUsage, writerContext, stringBuilder);
- }
+ ReferenceUsageTextualNotationBuilder.BuildMetadataBodyUsage(elementAsReferenceUsage, writerContext, stringBuilder);
}
}
@@ -551,14 +548,11 @@ public static void BuildOwnedExpressionMember(SysML2.NET.Core.POCO.Core.Types.IF
/// The that contains the entire textual notation
public static void BuildSequenceExpressionListMember(SysML2.NET.Core.POCO.Core.Types.IFeatureMembership poco, TextualNotationWriterContext writerContext, StringBuilder stringBuilder)
{
+ var effectiveOwnedMemberFeature = SysML2.NET.Serializer.TextualNotation.Writers.SharedTextualNotationBuilder.QueryEffectiveOwnedMemberFeature(poco);
- if (poco.ownedMemberFeature != null)
+ if (effectiveOwnedMemberFeature is SysML2.NET.Core.POCO.Kernel.Functions.IExpression elementAsExpression)
{
-
- if (poco.ownedMemberFeature is SysML2.NET.Core.POCO.Kernel.Functions.IExpression elementAsExpression)
- {
- ExpressionTextualNotationBuilder.BuildSequenceExpressionList(elementAsExpression, writerContext, stringBuilder);
- }
+ ExpressionTextualNotationBuilder.BuildSequenceExpressionList(elementAsExpression, writerContext, stringBuilder);
}
}
@@ -572,14 +566,11 @@ public static void BuildSequenceExpressionListMember(SysML2.NET.Core.POCO.Core.T
/// The that contains the entire textual notation
public static void BuildFunctionReferenceMember(SysML2.NET.Core.POCO.Core.Types.IFeatureMembership poco, TextualNotationWriterContext writerContext, StringBuilder stringBuilder)
{
+ var effectiveOwnedMemberFeature = SysML2.NET.Serializer.TextualNotation.Writers.SharedTextualNotationBuilder.QueryEffectiveOwnedMemberFeature(poco);
- if (poco.ownedMemberFeature != null)
+ if (effectiveOwnedMemberFeature is SysML2.NET.Core.POCO.Kernel.Functions.IExpression elementAsExpression)
{
-
- if (poco.ownedMemberFeature is SysML2.NET.Core.POCO.Kernel.Functions.IExpression elementAsExpression)
- {
- ExpressionTextualNotationBuilder.BuildFunctionReference(elementAsExpression, writerContext, stringBuilder);
- }
+ ExpressionTextualNotationBuilder.BuildFunctionReference(elementAsExpression, writerContext, stringBuilder);
}
}
@@ -593,11 +584,8 @@ public static void BuildFunctionReferenceMember(SysML2.NET.Core.POCO.Core.Types.
/// The that contains the entire textual notation
public static void BuildNamedArgumentMember(SysML2.NET.Core.POCO.Core.Types.IFeatureMembership poco, TextualNotationWriterContext writerContext, StringBuilder stringBuilder)
{
-
- if (poco.ownedMemberFeature != null)
- {
- FeatureTextualNotationBuilder.BuildNamedArgument(poco.ownedMemberFeature, writerContext, stringBuilder);
- }
+ var effectiveOwnedMemberFeature = SysML2.NET.Serializer.TextualNotation.Writers.SharedTextualNotationBuilder.QueryEffectiveOwnedMemberFeature(poco);
+ FeatureTextualNotationBuilder.BuildNamedArgument(effectiveOwnedMemberFeature, writerContext, stringBuilder);
}
@@ -610,14 +598,11 @@ public static void BuildNamedArgumentMember(SysML2.NET.Core.POCO.Core.Types.IFea
/// The that contains the entire textual notation
public static void BuildExpressionBodyMember(SysML2.NET.Core.POCO.Core.Types.IFeatureMembership poco, TextualNotationWriterContext writerContext, StringBuilder stringBuilder)
{
+ var effectiveOwnedMemberFeature = SysML2.NET.Serializer.TextualNotation.Writers.SharedTextualNotationBuilder.QueryEffectiveOwnedMemberFeature(poco);
- if (poco.ownedMemberFeature != null)
+ if (effectiveOwnedMemberFeature is SysML2.NET.Core.POCO.Kernel.Functions.IExpression elementAsExpression)
{
-
- if (poco.ownedMemberFeature is SysML2.NET.Core.POCO.Kernel.Functions.IExpression elementAsExpression)
- {
- ExpressionTextualNotationBuilder.BuildExpressionBody(elementAsExpression, writerContext, stringBuilder);
- }
+ ExpressionTextualNotationBuilder.BuildExpressionBody(elementAsExpression, writerContext, stringBuilder);
}
}
@@ -655,11 +640,8 @@ public static void BuildPayloadFeatureMember(SysML2.NET.Core.POCO.Core.Types.IFe
/// The that contains the entire textual notation
public static void BuildMetadataBodyFeatureMember(SysML2.NET.Core.POCO.Core.Types.IFeatureMembership poco, TextualNotationWriterContext writerContext, StringBuilder stringBuilder)
{
-
- if (poco.ownedMemberFeature != null)
- {
- FeatureTextualNotationBuilder.BuildMetadataBodyFeature(poco.ownedMemberFeature, writerContext, stringBuilder);
- }
+ var effectiveOwnedMemberFeature = SysML2.NET.Serializer.TextualNotation.Writers.SharedTextualNotationBuilder.QueryEffectiveOwnedMemberFeature(poco);
+ FeatureTextualNotationBuilder.BuildMetadataBodyFeature(effectiveOwnedMemberFeature, writerContext, stringBuilder);
}
}
diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/FeatureTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/FeatureTextualNotationBuilder.cs
index 6faeca91..c7a4f18a 100644
--- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/FeatureTextualNotationBuilder.cs
+++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/FeatureTextualNotationBuilder.cs
@@ -1178,7 +1178,7 @@ public static void BuildMetadataBodyFeature(SysML2.NET.Core.POCO.Core.Features.I
}
}
- if ((ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership) || poco.IsOrdered)
+ if ((ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership owningMembership0 && owningMembership0.OwnedRelatedElement.OfType().Any())) || poco.IsOrdered)
{
BuildFeatureSpecializationPart(poco, writerContext, stringBuilder);
}
diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/IncludeUseCaseUsageTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/IncludeUseCaseUsageTextualNotationBuilder.cs
index b3d20776..ce9d48a5 100644
--- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/IncludeUseCaseUsageTextualNotationBuilder.cs
+++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/IncludeUseCaseUsageTextualNotationBuilder.cs
@@ -60,7 +60,7 @@ public static void BuildIncludeUseCaseUsage(SysML2.NET.Core.POCO.Systems.UseCase
}
}
- if ((ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership) || poco.IsOrdered)
+ if ((ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership owningMembership0 && owningMembership0.OwnedRelatedElement.OfType().Any())) || poco.IsOrdered)
{
FeatureTextualNotationBuilder.BuildFeatureSpecializationPart(poco, writerContext, stringBuilder);
}
diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/MembershipTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/MembershipTextualNotationBuilder.cs
index 06d506d8..9d807724 100644
--- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/MembershipTextualNotationBuilder.cs
+++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/MembershipTextualNotationBuilder.cs
@@ -136,13 +136,11 @@ public static void BuildFeatureReferenceMember(SysML2.NET.Core.POCO.Root.Namespa
if (poco.MemberElement != null)
{
-
- if (poco.MemberElement is SysML2.NET.Core.POCO.Core.Features.IFeature elementAsFeature)
- {
- FeatureTextualNotationBuilder.BuildFeatureReference(elementAsFeature, writerContext, stringBuilder);
- }
+ SharedTextualNotationBuilder.AppendQualifiedName(stringBuilder, poco.MemberElement, writerContext, poco);
+ stringBuilder.Append(' ');
}
+
}
///
@@ -176,10 +174,12 @@ public static void BuildInstantiatedTypeMember(SysML2.NET.Core.POCO.Root.Namespa
if (poco.MemberElement != null)
{
- if (poco.MemberElement is SysML2.NET.Core.POCO.Core.Types.IType elementAsType)
+ if (poco.MemberElement != null)
{
- TypeTextualNotationBuilder.BuildInstantiatedTypeReference(elementAsType, writerContext, stringBuilder);
+ SharedTextualNotationBuilder.AppendQualifiedName(stringBuilder, poco.MemberElement, writerContext, poco);
+ stringBuilder.Append(' ');
}
+
}
else
{
diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ParameterMembershipTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ParameterMembershipTextualNotationBuilder.cs
index e1bc58f3..d79e8327 100644
--- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ParameterMembershipTextualNotationBuilder.cs
+++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ParameterMembershipTextualNotationBuilder.cs
@@ -300,11 +300,8 @@ public static void BuildMetadataArgumentMember(SysML2.NET.Core.POCO.Kernel.Behav
/// The that contains the entire textual notation
public static void BuildTypeReferenceMember(SysML2.NET.Core.POCO.Kernel.Behaviors.IParameterMembership poco, TextualNotationWriterContext writerContext, StringBuilder stringBuilder)
{
-
- if (poco.ownedMemberFeature != null)
- {
- FeatureTextualNotationBuilder.BuildTypeReference(poco.ownedMemberFeature, writerContext, stringBuilder);
- }
+ var effectiveOwnedMemberFeature = SysML2.NET.Serializer.TextualNotation.Writers.SharedTextualNotationBuilder.QueryEffectiveOwnedMemberFeature(poco);
+ FeatureTextualNotationBuilder.BuildTypeReference(effectiveOwnedMemberFeature, writerContext, stringBuilder);
}
diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/PerformActionUsageTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/PerformActionUsageTextualNotationBuilder.cs
index c1aafdb3..13ffbfb7 100644
--- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/PerformActionUsageTextualNotationBuilder.cs
+++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/PerformActionUsageTextualNotationBuilder.cs
@@ -58,7 +58,7 @@ public static void BuildPerformActionUsageDeclaration(SysML2.NET.Core.POCO.Syste
}
}
- if ((ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership) || poco.IsOrdered)
+ if ((ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership owningMembership0 && owningMembership0.OwnedRelatedElement.OfType().Any())) || poco.IsOrdered)
{
FeatureTextualNotationBuilder.BuildFeatureSpecializationPart(poco, writerContext, stringBuilder);
}
diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ReferenceUsageTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ReferenceUsageTextualNotationBuilder.cs
index 258d547f..35dce30b 100644
--- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ReferenceUsageTextualNotationBuilder.cs
+++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ReferenceUsageTextualNotationBuilder.cs
@@ -365,7 +365,7 @@ public static void BuildMetadataBodyUsage(SysML2.NET.Core.POCO.Systems.Definitio
}
}
- if ((ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership) || poco.IsOrdered)
+ if ((ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership owningMembership0 && owningMembership0.OwnedRelatedElement.OfType().Any())) || poco.IsOrdered)
{
FeatureTextualNotationBuilder.BuildFeatureSpecializationPart(poco, writerContext, stringBuilder);
}
diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/SatisfyRequirementUsageTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/SatisfyRequirementUsageTextualNotationBuilder.cs
index 9ab5c9a0..9ea997a7 100644
--- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/SatisfyRequirementUsageTextualNotationBuilder.cs
+++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/SatisfyRequirementUsageTextualNotationBuilder.cs
@@ -67,7 +67,7 @@ public static void BuildSatisfyRequirementUsage(SysML2.NET.Core.POCO.Systems.Req
}
}
- if ((ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership) || poco.IsOrdered)
+ if ((ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership owningMembership0 && owningMembership0.OwnedRelatedElement.OfType().Any())) || poco.IsOrdered)
{
FeatureTextualNotationBuilder.BuildFeatureSpecializationPart(poco, writerContext, stringBuilder);
}
diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/SendActionUsageTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/SendActionUsageTextualNotationBuilder.cs
index d21d6f0a..c855fd28 100644
--- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/SendActionUsageTextualNotationBuilder.cs
+++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/SendActionUsageTextualNotationBuilder.cs
@@ -46,7 +46,7 @@ public static void BuildSendNode(SysML2.NET.Core.POCO.Systems.Actions.ISendActio
var ownedRelationshipCursor = writerContext.CursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship);
OccurrenceUsageTextualNotationBuilder.BuildOccurrenceUsagePrefix(poco, writerContext, stringBuilder);
- if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Kernel.FeatureValues.IFeatureValue) || poco.IsOrdered || poco.Direction.HasValue || poco.IsDerived || poco.IsAbstract || poco.IsVariation || poco.IsConstant || poco.IsEnd || poco.isReference || poco.IsIndividual || poco.PortionKind.HasValue || poco.IsComposite || poco.IsPortion || poco.IsVariable || poco.IsSufficient)
+ if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership owningMembership0 && owningMembership0.OwnedRelatedElement.OfType().Any()) || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Kernel.FeatureValues.IFeatureValue) || poco.IsOrdered || poco.Direction.HasValue || poco.IsDerived || poco.IsAbstract || poco.IsVariation || poco.IsConstant || poco.IsEnd || poco.isReference || poco.IsIndividual || poco.PortionKind.HasValue || poco.IsComposite || poco.IsPortion || poco.IsVariable || poco.IsSufficient)
{
ActionUsageTextualNotationBuilder.BuildActionUsageDeclaration(poco, writerContext, stringBuilder);
}
@@ -67,7 +67,7 @@ public static void BuildSendNodeDeclaration(SysML2.NET.Core.POCO.Systems.Actions
{
var ownedRelationshipCursor = writerContext.CursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship);
- if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership) || poco.IsOrdered)
+ if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership owningMembership0 && owningMembership0.OwnedRelatedElement.OfType().Any())) || poco.IsOrdered)
{
ActionUsageTextualNotationBuilder.BuildActionNodeUsageDeclaration(poco, writerContext, stringBuilder);
}
diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/SuccessionAsUsageTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/SuccessionAsUsageTextualNotationBuilder.cs
index ac3a8205..be31241f 100644
--- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/SuccessionAsUsageTextualNotationBuilder.cs
+++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/SuccessionAsUsageTextualNotationBuilder.cs
@@ -106,7 +106,7 @@ public static void BuildSuccessionAsUsage(SysML2.NET.Core.POCO.Systems.Connectio
var ownedRelationshipCursor = writerContext.CursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship);
UsageTextualNotationBuilder.BuildUsagePrefix(poco, writerContext, stringBuilder);
- if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership) || poco.IsOrdered)
+ if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership owningMembership0 && owningMembership0.OwnedRelatedElement.OfType().Any())) || poco.IsOrdered)
{
stringBuilder.Append("succession ");
UsageTextualNotationBuilder.BuildUsageDeclaration(poco, writerContext, stringBuilder);
diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/TerminateActionUsageTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/TerminateActionUsageTextualNotationBuilder.cs
index b2d22066..a1b5a151 100644
--- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/TerminateActionUsageTextualNotationBuilder.cs
+++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/TerminateActionUsageTextualNotationBuilder.cs
@@ -46,7 +46,7 @@ public static void BuildTerminateNode(SysML2.NET.Core.POCO.Systems.Actions.ITerm
var ownedRelationshipCursor = writerContext.CursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship);
OccurrenceUsageTextualNotationBuilder.BuildOccurrenceUsagePrefix(poco, writerContext, stringBuilder);
- if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership) || poco.IsOrdered)
+ if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership owningMembership0 && owningMembership0.OwnedRelatedElement.OfType().Any())) || poco.IsOrdered)
{
ActionUsageTextualNotationBuilder.BuildActionNodeUsageDeclaration(poco, writerContext, stringBuilder);
}
diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/TransitionUsageTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/TransitionUsageTextualNotationBuilder.cs
index 4f601269..0a23c5e6 100644
--- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/TransitionUsageTextualNotationBuilder.cs
+++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/TransitionUsageTextualNotationBuilder.cs
@@ -106,7 +106,7 @@ public static void BuildGuardedSuccession(SysML2.NET.Core.POCO.Systems.States.IT
{
var ownedRelationshipCursor = writerContext.CursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship);
- if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership) || poco.IsOrdered)
+ if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership owningMembership0 && owningMembership0.OwnedRelatedElement.OfType().Any())) || poco.IsOrdered)
{
stringBuilder.Append("succession ");
UsageTextualNotationBuilder.BuildUsageDeclaration(poco, writerContext, stringBuilder);
@@ -202,7 +202,7 @@ public static void BuildTransitionUsage(SysML2.NET.Core.POCO.Systems.States.ITra
var ownedRelationshipCursor = writerContext.CursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship);
stringBuilder.Append("transition ");
- if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership) || poco.IsOrdered)
+ if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership owningMembership0 && owningMembership0.OwnedRelatedElement.OfType().Any())) || poco.IsOrdered)
{
UsageTextualNotationBuilder.BuildUsageDeclaration(poco, writerContext, stringBuilder);
stringBuilder.Append("first ");
diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/UsageTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/UsageTextualNotationBuilder.cs
index 0f5ba1a2..4166c00e 100644
--- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/UsageTextualNotationBuilder.cs
+++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/UsageTextualNotationBuilder.cs
@@ -225,7 +225,7 @@ public static void BuildUsageDeclaration(SysML2.NET.Core.POCO.Systems.Definition
ElementTextualNotationBuilder.BuildIdentification(poco, writerContext, stringBuilder);
var ownedRelationshipCursor = writerContext.CursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship);
- if ((ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership) || poco.IsOrdered)
+ if ((ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership owningMembership0 && owningMembership0.OwnedRelatedElement.OfType().Any())) || poco.IsOrdered)
{
FeatureTextualNotationBuilder.BuildFeatureSpecializationPart(poco, writerContext, stringBuilder);
}
diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ViewUsageTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ViewUsageTextualNotationBuilder.cs
index 1203ff75..41e5d998 100644
--- a/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ViewUsageTextualNotationBuilder.cs
+++ b/SysML2.NET.Serializer.TextualNotation/Writers/AutoGenTextualNotationBuilder/ViewUsageTextualNotationBuilder.cs
@@ -106,7 +106,7 @@ public static void BuildViewUsage(SysML2.NET.Core.POCO.Systems.Views.IViewUsage
stringBuilder.Append("view ");
var ownedRelationshipCursor = writerContext.CursorCache.GetOrCreateCursor(poco.Id, "ownedRelationship", poco.OwnedRelationship);
- if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership) || poco.IsOrdered)
+ if (!string.IsNullOrWhiteSpace(poco.DeclaredShortName) || !string.IsNullOrWhiteSpace(poco.DeclaredName) || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IFeatureTyping || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ISubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IReferenceSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.ICrossSubsetting || ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Core.Features.IRedefinition || (ownedRelationshipCursor.Current is SysML2.NET.Core.POCO.Root.Namespaces.IOwningMembership owningMembership0 && owningMembership0.OwnedRelatedElement.OfType().Any())) || poco.IsOrdered)
{
UsageTextualNotationBuilder.BuildUsageDeclaration(poco, writerContext, stringBuilder);
}
diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/NameResolutionCache.cs b/SysML2.NET.Serializer.TextualNotation/Writers/NameResolutionCache.cs
index 988b1682..0d4c6257 100644
--- a/SysML2.NET.Serializer.TextualNotation/Writers/NameResolutionCache.cs
+++ b/SysML2.NET.Serializer.TextualNotation/Writers/NameResolutionCache.cs
@@ -118,9 +118,17 @@ public string Resolve(IElement target, IElement sourcePoco)
case null:
return string.Empty;
- // Short-circuit 1 — IMembership targets: import declarations keep their full path.
+ // Short-circuit 1 — IMembership targets: import declarations keep the full path,
+ // but use the SHORTEST declared name available at each owner-chain segment.
+ // IElement.qualifiedName walks via EscapedName() which prefers `name` over
+ // `shortName`; that is the inverse of what import declarations need. The SysML
+ // Textual Notation tutorial and the pilot implementation consistently emit
+ // imports using shortNames where declared (e.g. `import SI::kg` not
+ // `import SI::kilogram`).
case IMembership membership:
- return membership.MemberElement?.qualifiedName ?? string.Empty;
+ return membership.MemberElement != null
+ ? QueryShortQualifiedName(membership.MemberElement)
+ : string.Empty;
}
// Short-circuit 2 — no usable simple name on the target: emit the qualified name.
@@ -169,9 +177,12 @@ private string ResolveFresh(IElement target, IElement sourcePoco, INamespace sou
var rawName = target.name;
var rawShortName = target.shortName;
- var escapedShortName = string.IsNullOrWhiteSpace(rawShortName)
- ? null
- : (rawShortName.QueryIsValidBasicName() ? rawShortName : rawShortName.ToUnrestrictedName());
+ string escapedShortName = null;
+
+ if (!string.IsNullOrWhiteSpace(rawShortName))
+ {
+ escapedShortName = rawShortName.QueryIsValidBasicName() ? rawShortName : rawShortName.ToUnrestrictedName();
+ }
// Walk the cached source-scope chain. First hit wins.
foreach (var scope in this.GetSourceScopeChain(sourcePoco, sourceLocalScope))
@@ -285,6 +296,66 @@ private static IReadOnlyList BuildChain(INamespace start)
return chain;
}
+ ///
+ /// Walks up via owningNamespace and builds the
+ /// qualified name using the SHORTEST declared name at each segment — the
+ /// when non-blank, otherwise the
+ /// . Each segment is escaped through the KEBNF
+ /// unrestricted-name rules ('…' quoting for non-basic identifiers) so the
+ /// result is parser-roundtrip safe.
+ ///
+ /// Used by the short-circuit in for
+ /// import declarations, where the pilot implementation's reference text uses short
+ /// forms (e.g. SI::kg) but returns the
+ /// long form (SI::kilogram) because it goes through EscapedName() which
+ /// prefers name over shortName.
+ ///
+ /// Mirrors the cycle-and-null-safety pattern of : stops
+ /// on owningNamespace and swallows
+ /// from unimplemented derived properties.
+ ///
+ /// The leaf to qualify; must be non-null.
+ /// The short-form qualified name (e.g. "SI::kg"), or the empty string
+ /// when no segment carries a usable name.
+ private static string QueryShortQualifiedName(IElement element)
+ {
+ var segments = new Stack();
+ var current = element;
+
+ while (current != null)
+ {
+ var preferred = !string.IsNullOrWhiteSpace(current.shortName)
+ ? current.shortName
+ : current.name;
+
+ if (string.IsNullOrWhiteSpace(preferred))
+ {
+ break;
+ }
+
+ var escaped = preferred.QueryIsValidBasicName()
+ ? preferred
+ : preferred.ToUnrestrictedName();
+
+ segments.Push(escaped);
+
+ INamespace next;
+
+ try
+ {
+ next = current.owningNamespace;
+ }
+ catch (NotSupportedException)
+ {
+ break;
+ }
+
+ current = next;
+ }
+
+ return string.Join("::", segments);
+ }
+
///
/// Resolves the local scope of : the first
/// reached by climbing
@@ -306,13 +377,57 @@ private INamespace GetSourceLocalScope(IElement sourcePoco)
while (current != null && visited.Add(current))
{
- switch (current)
+ if (current is IRelationship { OwningRelatedElement: not null } relationship)
+ {
+ current = relationship.OwningRelatedElement;
+ continue;
+ }
+
+ if (current is INamespace asNamespace)
{
- case INamespace asNamespace:
+ // A Namespace is the local scope only when it has a proper upward
+ // owningNamespace chain. Anonymous nested namespaces (e.g. an
+ // OwnedFeatureChain Feature owned via Specialization rather than
+ // Membership) have a null `owningNamespace`; returning such a namespace
+ // here gives BuildChain a one-element chain that never reaches the
+ // reference site's enclosing scope, so name resolution falls through
+ // to qualifiedName. In that case keep walking via `owner` (which follows
+ // the owningRelationship → OwningRelatedElement path) to find the
+ // enclosing reference-site namespace.
+ INamespace asNamespaceUpward = null;
+
+ try
+ {
+ asNamespaceUpward = asNamespace.owningNamespace;
+ }
+ catch (NotSupportedException)
+ {
+ // owningNamespace not implemented — treat as no upward chain.
+ }
+
+ if (asNamespaceUpward != null || ReferenceEquals(asNamespace, this.RootNamespace))
+ {
+ return asNamespace;
+ }
+
+ IElement asNamespaceOwner;
+
+ try
+ {
+ asNamespaceOwner = asNamespace.owner;
+ }
+ catch (NotSupportedException)
+ {
+ asNamespaceOwner = null;
+ }
+
+ if (asNamespaceOwner == null)
+ {
return asNamespace;
- case IRelationship { OwningRelatedElement: not null } relationship:
- current = relationship.OwningRelatedElement;
- continue;
+ }
+
+ current = asNamespaceOwner;
+ continue;
}
INamespace owningNs = null;
@@ -350,9 +465,15 @@ private INamespace GetSourceLocalScope(IElement sourcePoco)
///
/// Tests the simple-name index of for a hit on
- /// . Tries the raw name key first, then the raw
- /// shortName key. On a hit, receives the
+ /// . Tries the raw shortName key first, then the raw
+ /// name key. On a hit, receives the
/// corresponding escaped form.
+ ///
+ /// The short form is tried first so the emitter prefers it whenever both forms are
+ /// reachable — the SysML v2 Textual Notation tutorial consistently uses short forms in
+ /// quantity literals ([kg], [m/s], [s]) and the pilot
+ /// implementation's reference output matches that convention.
+ ///
///
/// The scope whose index is inspected.
/// The element to look up.
@@ -366,14 +487,6 @@ private bool TryResolveSimpleNameInScope(INamespace scope, IElement target, stri
{
var index = this.GetSimpleNameIndex(scope);
- if (!string.IsNullOrWhiteSpace(rawName)
- && index.TryGetValue(rawName, out var elements)
- && elements.Contains(target))
- {
- matchedSimpleName = escapedName;
- return true;
- }
-
if (!string.IsNullOrWhiteSpace(rawShortName)
&& index.TryGetValue(rawShortName, out var shortElements)
&& shortElements.Contains(target))
@@ -382,6 +495,14 @@ private bool TryResolveSimpleNameInScope(INamespace scope, IElement target, stri
return true;
}
+ if (!string.IsNullOrWhiteSpace(rawName)
+ && index.TryGetValue(rawName, out var elements)
+ && elements.Contains(target))
+ {
+ matchedSimpleName = escapedName;
+ return true;
+ }
+
matchedSimpleName = null;
return false;
}
@@ -563,10 +684,19 @@ private static void BuildInheritedEntries(IType type, Dictionary
/// Adds the of
- /// to under both its
- /// and , and enqueues the target onto
- /// if it is itself an (so nested
- /// namespaces are indexed too).
+ /// to under both its short and long name and enqueues the
+ /// target onto if it is itself an
+ /// (so nested namespaces are indexed too).
+ ///
+ /// Per the metamodel, and
+ /// are explicit overrides of the member element's
+ /// declared names within the owning namespace. When the membership does not carry an
+ /// override (the pilot implementation's XMI never emits memberName /
+ /// memberShortName on Membership elements), fall back to the target's own
+ /// / so the simple-name
+ /// index remains reachable by simple name (e.g. kg, kilogram) for
+ /// references to imported library elements.
+ ///
///
/// The destination index.
/// The membership whose target is indexed.
@@ -580,8 +710,15 @@ private static void AddMembershipEntry(Dictionary> ind
return;
}
- AddIndexEntry(index, membership.MemberShortName, target);
- AddIndexEntry(index, membership.MemberName, target);
+ var shortName = !string.IsNullOrWhiteSpace(membership.MemberShortName)
+ ? membership.MemberShortName
+ : target.shortName;
+ var longName = !string.IsNullOrWhiteSpace(membership.MemberName)
+ ? membership.MemberName
+ : target.name;
+
+ AddIndexEntry(index, shortName, target);
+ AddIndexEntry(index, longName, target);
if (target is INamespace targetAsNamespace)
{
diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/NamespaceImportTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/NamespaceImportTextualNotationBuilder.cs
index f15d2af4..81d95edc 100644
--- a/SysML2.NET.Serializer.TextualNotation/Writers/NamespaceImportTextualNotationBuilder.cs
+++ b/SysML2.NET.Serializer.TextualNotation/Writers/NamespaceImportTextualNotationBuilder.cs
@@ -46,13 +46,15 @@ private static void BuildNamespaceImportHandCoded(INamespaceImport poco, Textual
}
else if (poco.ImportedNamespace != null)
{
- stringBuilder.Append(poco.ImportedNamespace.qualifiedName);
- stringBuilder.Append("::* ");
+ SharedTextualNotationBuilder.AppendQualifiedName(stringBuilder, poco.ImportedNamespace, writerContext, poco);
+ stringBuilder.Append("::*");
if (poco.IsRecursive)
{
- stringBuilder.Append("::** ");
+ stringBuilder.Append("::**");
}
+
+ stringBuilder.Append(' ');
}
}
}
diff --git a/SysML2.NET.Serializer.TextualNotation/Writers/SharedTextualNotationBuilder.cs b/SysML2.NET.Serializer.TextualNotation/Writers/SharedTextualNotationBuilder.cs
index 0b061e82..2c1eb432 100644
--- a/SysML2.NET.Serializer.TextualNotation/Writers/SharedTextualNotationBuilder.cs
+++ b/SysML2.NET.Serializer.TextualNotation/Writers/SharedTextualNotationBuilder.cs
@@ -177,9 +177,9 @@ private static void BuildNonBehaviorBodyItemHandCoded(IElement poco, TextualNota
/// POCO; this method simply emits it as a string.
///
/// The that holds the real value expression
- /// The used to get access to CursorCollection for the current
+ /// The used to get access to CursorCollection for the current
/// The that contains the entire textual notation
- private static void BuildRealValueHandCoded(IExpression poco, TextualNotationWriterContext writerContext, StringBuilder stringBuilder)
+ private static void BuildRealValueHandCoded(IExpression poco, TextualNotationWriterContext _, StringBuilder stringBuilder)
{
if (poco is ILiteralRational literalRational)
{
@@ -639,5 +639,42 @@ internal static void AppendQualifiedName(StringBuilder stringBuilder, IElement t
stringBuilder.Append(writerContext.NameResolutionCache.Resolve(target, sourcePoco));
}
+
+ ///
+ /// Returns the effective ownedMemberFeature of ,
+ /// normalising the two runtime shapes a can take.
+ ///
+ /// The pure- shape stores the feature directly:
+ /// membership.ownedMemberFeature IS the target feature (typically an
+ /// ) and is returned as-is. The
+ /// shape — used to model operands of every InvocationExpression /
+ /// OperatorExpression per KerML §8.2.5.8.2 Notes 1-2
+ /// (Resources/KerML-textual-bnf.kebnf:1176-1178) — stores a parameter
+ /// Feature in ownedMemberFeature and carries the operand expression one
+ /// level deeper, under that feature's FeatureValue.value. This helper transparently
+ /// unwraps that extra indirection so every code-generated builder that consumes
+ /// ownedMemberFeature works uniformly against either shape.
+ ///
+ /// Falls back to the direct ownedMemberFeature when the inner unwrap fails
+ /// (missing or non-feature value), so behaviour is never worse than the literal access.
+ ///
+ /// The feature membership; may be .
+ /// The effective feature, or when none is available.
+ internal static IFeature QueryEffectiveOwnedMemberFeature(IFeatureMembership membership)
+ {
+ var direct = membership?.ownedMemberFeature;
+
+ if (membership is IParameterMembership && direct != null)
+ {
+ var featureValue = direct.OwnedRelationship.OfType().FirstOrDefault();
+
+ if (featureValue?.value is IFeature wrappedExpression)
+ {
+ return wrappedExpression;
+ }
+ }
+
+ return direct;
+ }
}
}
diff --git a/SysML2.NET.Serializer.Xmi/DeSerializer.cs b/SysML2.NET.Serializer.Xmi/DeSerializer.cs
index 116df4ab..af029412 100644
--- a/SysML2.NET.Serializer.Xmi/DeSerializer.cs
+++ b/SysML2.NET.Serializer.Xmi/DeSerializer.cs
@@ -60,7 +60,7 @@ public class DeSerializer : IDeSerializer
///
/// The injected providing external reference file resolve
///
- private readonly ExternalReferenceService externalReferenceService;
+ private readonly IExternalReferenceService externalReferenceService;
///
/// The injected providing resolve feature based on XMI row type
@@ -70,13 +70,30 @@ public class DeSerializer : IDeSerializer
/// Initializes a new instance of the class.
/// The injected used to set up logging
public DeSerializer(ILoggerFactory loggerFactory)
+ : this(loggerFactory, null)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with a caller-supplied
+ /// . Use this overload to override how
+ /// href="..." values are resolved against the deserialized file's location
+ /// (for example to redirect references away from their original on-disk layout).
+ ///
+ /// The injected used to set up logging
+ ///
+ /// The used to register and resolve external href
+ /// references. When , a default is created.
+ ///
+ public DeSerializer(ILoggerFactory loggerFactory, IExternalReferenceService externalReferenceService)
{
this.loggerFactory = loggerFactory ?? NullLoggerFactory.Instance;
this.logger = this.loggerFactory.CreateLogger();
-
- this.externalReferenceService = new ExternalReferenceService(this.loggerFactory.CreateLogger());
+
+ this.externalReferenceService = externalReferenceService
+ ?? new ExternalReferenceService(this.loggerFactory.CreateLogger());
this.cache = new XmiDataCache(new PocoReferenceResolveExtensionsFacade(), this.loggerFactory.CreateLogger());
-
+
this.xmiDataReaderFacade = new XmiDataReaderFacade();
}