sysml-diagram 0.32.0 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/out/main.js CHANGED
@@ -164097,7 +164097,7 @@ function boundValue(bound) {
164097
164097
  function declaredMultiplicity(node) {
164098
164098
  const feature = node;
164099
164099
  const body = feature.members?.find((member) => member.$type === "MultiplicityDecl");
164100
- const written = feature.multiplicity ?? body?.multiplicity;
164100
+ const written = feature.multiplicity ?? body?.multiplicity ?? feature.innerMultiplicity ?? feature.endMultiplicity;
164101
164101
  if (!written) {
164102
164102
  for (const relationship of relationshipsOf(node)) {
164103
164103
  const tail = relationship.targets?.at(-1);
@@ -165375,6 +165375,264 @@ function eventReferenceOf(node) {
165375
165375
  return { kind: "self", node };
165376
165376
  }
165377
165377
 
165378
+ // ../language-server/out/src/services/individuals.js
165379
+ var INDIVIDUAL_MULTIPLICITY = "[1]";
165380
+ var MAX_TYPE_DEPTH = 32;
165381
+ function modifiersOf(node) {
165382
+ const decl = node;
165383
+ const own = Array.isArray(decl.modifiers) ? decl.modifiers : [];
165384
+ const post = Array.isArray(decl.postModifiers) ? decl.postModifiers : [];
165385
+ const wrapper = prefixMetadataModifiersOf(node);
165386
+ if (post.length === 0 && wrapper.length === 0)
165387
+ return own;
165388
+ return [...own, ...post, ...wrapper];
165389
+ }
165390
+ function prefixMetadataModifiersOf(node) {
165391
+ const container = node.$container;
165392
+ if (!container || container.$type !== "PrefixMetadataMember")
165393
+ return [];
165394
+ if (container.element !== node)
165395
+ return [];
165396
+ return Array.isArray(container.modifiers) ? container.modifiers : [];
165397
+ }
165398
+ function isIndividualDecl(node) {
165399
+ return modifiersOf(node).includes("individual");
165400
+ }
165401
+ function portionKindOf(node) {
165402
+ return modifiersOf(node).find((m) => m === "timeslice" || m === "snapshot");
165403
+ }
165404
+ function isDefinitionDecl(node) {
165405
+ return node.isDef === true || node.$type === "BareDefDecl";
165406
+ }
165407
+ var NON_OCCURRENCE_DECL_TYPES = /* @__PURE__ */ new Set([
165408
+ "AttributeDecl",
165409
+ "EnumDecl",
165410
+ "EnumValueDecl",
165411
+ "MetadataDecl",
165412
+ "MultiplicityDecl",
165413
+ // A KerML `datatype` IS the data-valued root an attribute is typed by
165414
+ // (KerML 8.3.4 DataType, which Occurrence deliberately does not specialize),
165415
+ // so it has no life either. Its siblings stay OUT: a KerML `class` is by
165416
+ // definition a classifier whose instances are occurrences, and `struct`,
165417
+ // `assoc struct`, `behavior`, `function` and `predicate` all specialize it.
165418
+ "DatatypeDecl"
165419
+ ]);
165420
+ var NAMESPACE_DECL_TYPES = /* @__PURE__ */ new Set([
165421
+ // Every name here is a real `$type` from the generated AST. `PackageDecl` and
165422
+ // `ImportDecl` were both invented: the rules are `Package` and `Import`, so
165423
+ // those two entries matched nothing and claimed a coverage they did not have.
165424
+ "Package",
165425
+ "NamespaceDecl",
165426
+ "Document",
165427
+ "AliasDecl",
165428
+ "Import"
165429
+ ]);
165430
+ var NON_OCCURRENCE_LABELS = {
165431
+ AttributeDecl: "an attribute",
165432
+ EnumDecl: "an enumeration",
165433
+ EnumValueDecl: "an enumeration value",
165434
+ MetadataDecl: "a metadata usage",
165435
+ MultiplicityDecl: "a multiplicity",
165436
+ DatatypeDecl: "a datatype",
165437
+ Package: "a package",
165438
+ NamespaceDecl: "a namespace",
165439
+ AliasDecl: "an alias",
165440
+ Import: "an import"
165441
+ };
165442
+ function nonOccurrenceLabel(node) {
165443
+ return NON_OCCURRENCE_LABELS[node.$type] ?? "not an occurrence";
165444
+ }
165445
+ function isOccurrenceShapedDecl(node) {
165446
+ return !NON_OCCURRENCE_DECL_TYPES.has(node.$type) && !NAMESPACE_DECL_TYPES.has(node.$type);
165447
+ }
165448
+ function writtenTypesOf(node) {
165449
+ const decl = node;
165450
+ const out = [];
165451
+ for (const typing of [decl.typing, ...decl.moreTypings ?? []]) {
165452
+ if (!typing)
165453
+ continue;
165454
+ const conjugated = typing.conjugate === true;
165455
+ for (const ref of [typing.type, ...typing.moreTypes ?? []]) {
165456
+ const text = ref?.$refText?.trim();
165457
+ if (text)
165458
+ out.push({ text, ref: ref?.ref, conjugated });
165459
+ }
165460
+ }
165461
+ return out;
165462
+ }
165463
+ function candidatesOf(node) {
165464
+ const out = [];
165465
+ for (const written of writtenTypesOf(node)) {
165466
+ if (written.conjugated)
165467
+ continue;
165468
+ out.push({ text: written.text, ref: written.ref });
165469
+ }
165470
+ for (const target of specializationTargetsOf(node))
165471
+ out.push({ text: target });
165472
+ return out;
165473
+ }
165474
+ var TRANSPARENT_WRAPPER_TYPES = /* @__PURE__ */ new Set([
165475
+ "PrefixMetadataMember",
165476
+ "MemberPrefixDecl",
165477
+ "ThenActionMember"
165478
+ ]);
165479
+ var OWNER_WALK_STOPS = /* @__PURE__ */ new Set([
165480
+ "Package",
165481
+ "PackageDecl",
165482
+ "NamespaceDecl",
165483
+ "Document"
165484
+ ]);
165485
+ function owningOccurrenceOf(node) {
165486
+ let owner = node.$container;
165487
+ while (owner && TRANSPARENT_WRAPPER_TYPES.has(owner.$type))
165488
+ owner = owner.$container;
165489
+ if (!owner || OWNER_WALK_STOPS.has(owner.$type))
165490
+ return void 0;
165491
+ return NON_OCCURRENCE_DECL_TYPES.has(owner.$type) ? void 0 : owner;
165492
+ }
165493
+ var MAX_ALIAS_HOPS = 8;
165494
+ var SPECIALIZATION_KINDS3 = /* @__PURE__ */ new Set([
165495
+ ":>",
165496
+ "subsets",
165497
+ ":>>",
165498
+ "redefines",
165499
+ "specializes",
165500
+ "subtype"
165501
+ ]);
165502
+ function specializationTargetsOf(node) {
165503
+ const decl = node;
165504
+ const out = [];
165505
+ for (const rel2 of [...decl.preRelationships ?? [], ...decl.relationships ?? []]) {
165506
+ if (!rel2.kind || !SPECIALIZATION_KINDS3.has(rel2.kind))
165507
+ continue;
165508
+ for (const target of rel2.targets ?? []) {
165509
+ const text = target.trim();
165510
+ if (text)
165511
+ out.push(text);
165512
+ }
165513
+ }
165514
+ return out;
165515
+ }
165516
+ function linkedIndividualDefinitionsOf(node) {
165517
+ return individualClosureOf(node, documentLocalResolverFor(node)).definitions;
165518
+ }
165519
+ function documentLocalResolverFor(node) {
165520
+ const resolve8 = localResolverFor(node);
165521
+ return (name) => {
165522
+ const candidates = resolve8(name, node).filter((candidate) => candidate.node);
165523
+ return candidates.length === 1 ? candidates[0].node : void 0;
165524
+ };
165525
+ }
165526
+ function individualClosureOf(node, resolve8) {
165527
+ const definitions = [];
165528
+ const seenNodes = /* @__PURE__ */ new Set([node]);
165529
+ let complete = true;
165530
+ const record = (text, target) => {
165531
+ if (!isIndividualDecl(target) || !isDefinitionDecl(target))
165532
+ return;
165533
+ if (definitions.some((each) => each.node === target))
165534
+ return;
165535
+ definitions.push({ text, node: target });
165536
+ };
165537
+ const targetOf = (candidate) => dealias(candidate.ref ?? resolve8(candidate.text));
165538
+ const dealias = (target) => {
165539
+ let current2 = target;
165540
+ for (let hop = 0; current2?.$type === "AliasDecl" && hop < MAX_ALIAS_HOPS; hop++) {
165541
+ const to = current2.target;
165542
+ current2 = to ? resolve8(to) : void 0;
165543
+ }
165544
+ return current2?.$type === "AliasDecl" ? void 0 : current2;
165545
+ };
165546
+ const walk = (current2, depth) => {
165547
+ if (depth > MAX_TYPE_DEPTH) {
165548
+ complete = false;
165549
+ return;
165550
+ }
165551
+ const ordinaryDefinition = isDefinitionDecl(current2) && !isIndividualDecl(current2);
165552
+ for (const candidate of candidatesOf(current2)) {
165553
+ const target = targetOf(candidate);
165554
+ if (!target) {
165555
+ if (!ordinaryDefinition)
165556
+ complete = false;
165557
+ continue;
165558
+ }
165559
+ record(candidate.text, target);
165560
+ if (seenNodes.has(target))
165561
+ continue;
165562
+ seenNodes.add(target);
165563
+ walk(target, depth + 1);
165564
+ }
165565
+ };
165566
+ walk(node, 0);
165567
+ if (portionKindOf(node)) {
165568
+ const owner = owningOccurrenceOf(node);
165569
+ if (owner) {
165570
+ const inherited = individualClosureOf(owner, resolve8);
165571
+ for (const each of inherited.definitions)
165572
+ record(each.text, each.node);
165573
+ if (!inherited.complete)
165574
+ complete = false;
165575
+ }
165576
+ }
165577
+ const direct = [];
165578
+ for (const written of writtenTypesOf(node)) {
165579
+ if (written.conjugated)
165580
+ continue;
165581
+ const target = targetOf(written);
165582
+ if (!target || !isIndividualDecl(target) || !isDefinitionDecl(target))
165583
+ continue;
165584
+ if (direct.some((each) => each.node === target))
165585
+ continue;
165586
+ direct.push({ text: written.text, node: target });
165587
+ }
165588
+ return { definitions, direct, complete };
165589
+ }
165590
+ function identityOf(node) {
165591
+ if (!isIndividualDecl(node) && !portionKindOf(node))
165592
+ return void 0;
165593
+ return effectiveIndividualOf(node, linkedIndividualDefinitionsOf(node));
165594
+ }
165595
+ function effectiveIndividualOf(node, definitions = []) {
165596
+ const explicit = isIndividualDecl(node);
165597
+ const portion = portionKindOf(node);
165598
+ if (!explicit && !portion)
165599
+ return void 0;
165600
+ return {
165601
+ explicit,
165602
+ portion,
165603
+ definition: definitions[0]?.text,
165604
+ multiplicity: writtenMultiplicityTextOf(node) ?? INDIVIDUAL_MULTIPLICITY
165605
+ };
165606
+ }
165607
+ function boundTextOf(bound) {
165608
+ if (!bound)
165609
+ return void 0;
165610
+ if (bound.star)
165611
+ return "*";
165612
+ if (typeof bound.intVal === "number")
165613
+ return String(bound.intVal);
165614
+ return bound.bound;
165615
+ }
165616
+ function writtenMultiplicityTextOf(node) {
165617
+ const decl = node;
165618
+ const mult = decl.multiplicity ?? decl.innerMultiplicity ?? decl.endMultiplicity;
165619
+ if (!mult)
165620
+ return void 0;
165621
+ const lo = boundTextOf(mult.lower);
165622
+ const hi = boundTextOf(mult.upper);
165623
+ if (lo === void 0 && hi === void 0)
165624
+ return void 0;
165625
+ return hi === void 0 || hi === lo ? `[${lo}]` : `[${lo}..${hi}]`;
165626
+ }
165627
+ function individualModifierCarrier(node) {
165628
+ const own = node;
165629
+ if ((own.modifiers ?? []).includes("individual"))
165630
+ return node;
165631
+ if ((own.postModifiers ?? []).includes("individual"))
165632
+ return node;
165633
+ return prefixMetadataModifiersOf(node).includes("individual") ? node.$container : void 0;
165634
+ }
165635
+
165378
165636
  // ../language-server/out/src/services/diagram-model-provider.js
165379
165637
  var lastSeg = (name) => {
165380
165638
  const i = Math.max(name.lastIndexOf("::"), name.lastIndexOf("."));
@@ -165762,12 +166020,12 @@ var withoutCompartments = (compartments, ...titles) => {
165762
166020
  const kept = (compartments ?? []).filter((compartment) => !titles.includes(compartment.title));
165763
166021
  return kept.length ? kept : void 0;
165764
166022
  };
165765
- var modifiersOf = (node) => {
166023
+ var modifiersOf2 = (node) => {
165766
166024
  const mods = node.modifiers;
165767
166025
  return Array.isArray(mods) ? mods : [];
165768
166026
  };
165769
166027
  var ANONYMOUS_INTERFACE_NAME = "(anonymous)";
165770
- var isEndMember = (node) => node.$type === "EndDecl" || modifiersOf(node).includes("end");
166028
+ var isEndMember = (node) => node.$type === "EndDecl" || modifiersOf2(node).includes("end");
165771
166029
  function endRowText(node) {
165772
166030
  const end = node;
165773
166031
  const name = nameOf2(node) ?? end.innerName;
@@ -165778,9 +166036,28 @@ function endRowText(node) {
165778
166036
  return void 0;
165779
166037
  return `${head2}${mult ? ` ${mult}` : ""}`;
165780
166038
  }
165781
- var portionKindOf = (node) => modifiersOf(node).find((m) => m === "timeslice" || m === "snapshot");
165782
- var isIndividualOccurrence = (node) => modifiersOf(node).includes("individual");
166039
+ var isIndividualOccurrence = isIndividualDecl;
165783
166040
  var isOccurrenceModified = (node) => portionKindOf(node) !== void 0 || isIndividualOccurrence(node);
166041
+ var mergedIndividualMeta = (node, existing) => {
166042
+ const identity6 = individualMetaOf(node);
166043
+ if (!identity6)
166044
+ return {};
166045
+ return { meta: { ...identity6, ...existing ?? {} } };
166046
+ };
166047
+ var individualMetaOf = (node) => {
166048
+ const effective = identityOf(node);
166049
+ if (!effective)
166050
+ return void 0;
166051
+ const isDef = isDefinitionDecl(node);
166052
+ return {
166053
+ individual: {
166054
+ explicit: effective.explicit,
166055
+ ...isDef ? {} : { multiplicity: effective.multiplicity },
166056
+ ...!isDef && effective.definition ? { definition: effective.definition } : {},
166057
+ ...effective.portion ? { portion: effective.portion } : {}
166058
+ }
166059
+ };
166060
+ };
165784
166061
  var redefinedNameOf = (node) => {
165785
166062
  const names = effectiveNamesOf(node, localResolverFor(node));
165786
166063
  return names.origin === "derived" || names.origin === "written" ? names.name ?? names.shortName : void 0;
@@ -167111,7 +167388,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
167111
167388
  isInheritedLibraryBackboneFeature(source, usage, index2) {
167112
167389
  if (!isLibraryDocument(ast_utils_exports.getDocument(usage)))
167113
167390
  return false;
167114
- if (modifiersOf(usage).includes("abstract"))
167391
+ if (modifiersOf2(usage).includes("abstract"))
167115
167392
  return true;
167116
167393
  const ownerType = source.isDef === true ? source : this.resolveType(source, index2);
167117
167394
  const usageType = this.resolveType(usage, index2);
@@ -167280,7 +167557,10 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
167280
167557
  compartments: extra?.compartments ?? this.compartmentsFor(n2, uri, index2, shape === "box"),
167281
167558
  ...packageOf2(n2),
167282
167559
  source: sourceOf2(n2, uri),
167283
- ...extra
167560
+ ...extra,
167561
+ // issue #162 — identity meta merges UNDER whatever the caller
167562
+ // passes, so a caller's own `meta` never loses a key to it.
167563
+ ...mergedIndividualMeta(n2, extra?.meta)
167284
167564
  });
167285
167565
  };
167286
167566
  for (const n2 of defNodes)
@@ -167819,7 +168099,7 @@ ${edge.to}`));
167819
168099
  gvTypeInherited: usage && !typeText(original) && !!definition || void 0,
167820
168100
  // REQ-405 - Tree alias suppression follows an explicit ref.
167821
168101
  // Intrinsic references such as package parts remain visible.
167822
- gvTreeExcluded: modifiersOf(original).includes("ref") && (!valueTextOf(original) || isPathExpr(original.value) || !!referenceTarget && belongsToDrawnFeatureTree(referenceTarget)) || void 0,
168102
+ gvTreeExcluded: modifiersOf2(original).includes("ref") && (!valueTextOf(original) || isPathExpr(original.value) || !!referenceTarget && belongsToDrawnFeatureTree(referenceTarget)) || void 0,
167823
168103
  ...directionOf(original) ? { direction: directionOf(original) } : {}
167824
168104
  };
167825
168105
  if (!ownerId || !byId.has(ownerId) || ownerId === node.id)
@@ -174588,7 +174868,7 @@ function outlineGroupForType(astType) {
174588
174868
  }
174589
174869
 
174590
174870
  // ../language-server/out/src/services/document-symbol-provider.js
174591
- var SPECIALIZATION_KINDS3 = /* @__PURE__ */ new Set([":>", "specializes"]);
174871
+ var SPECIALIZATION_KINDS4 = /* @__PURE__ */ new Set([":>", "specializes"]);
174592
174872
  var REDEFINITION_KINDS2 = /* @__PURE__ */ new Set([":>>", "redefines"]);
174593
174873
  var INHERITABLE_FEATURE_TYPES = /* @__PURE__ */ new Set([
174594
174874
  "ActionDecl",
@@ -174660,7 +174940,7 @@ function specializationTargets2(node) {
174660
174940
  const n2 = node;
174661
174941
  const out = [];
174662
174942
  for (const rel2 of [...n2.preRelationships ?? [], ...n2.relationships ?? []]) {
174663
- if (rel2.kind && SPECIALIZATION_KINDS3.has(rel2.kind))
174943
+ if (rel2.kind && SPECIALIZATION_KINDS4.has(rel2.kind))
174664
174944
  out.push(...rel2.targets ?? []);
174665
174945
  }
174666
174946
  return out;
@@ -175587,6 +175867,73 @@ function implicitSpecializationsFor(shared) {
175587
175867
  return created;
175588
175868
  }
175589
175869
 
175870
+ // ../language-server/out/src/services/modifier-order.js
175871
+ var MODIFIER_RANK = /* @__PURE__ */ new Map([
175872
+ ["public", 0],
175873
+ ["private", 0],
175874
+ ["protected", 0],
175875
+ ["in", 1],
175876
+ ["out", 1],
175877
+ ["inout", 1],
175878
+ ["derived", 2],
175879
+ ["abstract", 3],
175880
+ ["variation", 4],
175881
+ ["variant", 4],
175882
+ ["composite", 5],
175883
+ ["constant", 6],
175884
+ ["const", 6],
175885
+ ["ref", 7],
175886
+ ["var", 8],
175887
+ ["individual", 9],
175888
+ ["snapshot", 10],
175889
+ ["timeslice", 10]
175890
+ ]);
175891
+ var CANONICAL_MODIFIER_ORDER = "visibility, direction, derived, abstract, variation, composite, constant, ref, var, individual, then the portion kind";
175892
+ function isRankedRun(modifiers2) {
175893
+ return modifiers2.every((m) => MODIFIER_RANK.has(m));
175894
+ }
175895
+ function firstMisplacedModifier(modifiers2) {
175896
+ if (modifiers2.length < 2 || !isRankedRun(modifiers2))
175897
+ return void 0;
175898
+ for (let index2 = 1; index2 < modifiers2.length; index2++) {
175899
+ const rank = MODIFIER_RANK.get(modifiers2[index2]);
175900
+ for (let before = 0; before < index2; before++) {
175901
+ if (MODIFIER_RANK.get(modifiers2[before]) > rank)
175902
+ return { index: index2, before };
175903
+ }
175904
+ }
175905
+ return void 0;
175906
+ }
175907
+ var MODIFIER_PROPERTIES = ["modifiers", "postModifiers"];
175908
+ function modifierRunsOf(node) {
175909
+ const runs = [];
175910
+ if (!node.$cstNode)
175911
+ return runs;
175912
+ for (const property3 of MODIFIER_PROPERTIES) {
175913
+ const modifiers2 = node[property3];
175914
+ if (!Array.isArray(modifiers2) || modifiers2.length < 2)
175915
+ continue;
175916
+ if (!modifiers2.every((m) => typeof m === "string"))
175917
+ continue;
175918
+ if (!isRankedRun(modifiers2))
175919
+ continue;
175920
+ const nodes = grammar_utils_exports.findNodesForProperty(node.$cstNode, property3);
175921
+ if (nodes.length !== modifiers2.length)
175922
+ continue;
175923
+ if (nodes.some((cst, index2) => cst.text !== modifiers2[index2]))
175924
+ continue;
175925
+ runs.push({ property: property3, modifiers: modifiers2, nodes });
175926
+ }
175927
+ return runs;
175928
+ }
175929
+ function isRewritableRun(source, run) {
175930
+ const written = source.slice(run.nodes[0].offset, run.nodes[run.nodes.length - 1].end);
175931
+ return new RegExp(`^${run.modifiers.join("[ \\t]+")}$`, "u").test(written);
175932
+ }
175933
+ function canonicalModifierOrder(modifiers2) {
175934
+ return modifiers2.map((modifier, index2) => ({ modifier, index: index2, rank: MODIFIER_RANK.get(modifier) ?? 0 })).sort((a2, b) => a2.rank - b.rank || a2.index - b.index).map((entry) => entry.modifier);
175935
+ }
175936
+
175590
175937
  // ../language-server/out/src/messages.js
175591
175938
  var DIAGNOSTIC_MESSAGES = {
175592
175939
  // REQ-006 - a broad diagram anchor cannot prove which typed occurrence owns
@@ -175600,6 +175947,10 @@ var DIAGNOSTIC_MESSAGES = {
175600
175947
  LEX004_INVALID_STRING_ESCAPE: (escape) => `Invalid escape '\\${escape}'. KerML Table 4 permits \\' \\" \\b \\f \\t \\n and \\\\.`,
175601
175948
  LEX008_NON_ASCII_IDENTIFIER: (name) => `Identifier '${name}' contains a non-ASCII character. Wrap it in single quotes ('${name}') to use it as an unrestricted name.`,
175602
175949
  LEX009_TRAILING_WHITESPACE: "Trailing whitespace.",
175950
+ // issue #163: SYN025. The grammar accepts any permutation of the leading
175951
+ // modifiers so a mis-ordered declaration still parses; this names the one word
175952
+ // that is out of place and shows the whole prefix as the BNF writes it.
175953
+ SYN025_MODIFIER_ORDER: (modifier, before, canonical) => `Modifier '${modifier}' must be written before '${before}'. The canonical declaration prefix order is ${CANONICAL_MODIFIER_ORDER}; write '${canonical}'.`,
175603
175954
  // REQ-385 — OMG SysML v2 Part 1 §7.17.3 restricts control nodes to the body of
175604
175955
  // an action definition or usage. Successions are NOT covered (§7.13.5 sanctions
175605
175956
  // `first a then b;` and the `then` occurrence shorthand in a part), so the
@@ -175737,6 +176088,13 @@ var DIAGNOSTIC_MESSAGES = {
175737
176088
  SSM025_ACTION_PARAMETER_DIRECTION: (position, mine, typeName, theirs) => `Parameter ${position} is '${mine}' but the corresponding parameter of '${typeName}' is '${theirs}'. Positional correspondence redefines that parameter, and a redefinition cannot reverse a parameter's direction.`,
175738
176089
  SSM026_REDEFINITION_DIRECTION: (feature, mine, theirs) => `Direction '${mine}' reverses the redefined feature '${feature}', which is '${theirs}'. A redefinition refines a feature \u2014 it cannot turn an input into an output.`,
175739
176090
  SSM027_INTERFACE_END_TYPE: (position, endType, definition, expected) => `End ${position} is a '${endType}', but '${definition}' declares that end as '${expected}'. An interface usage connects through the ends its definition declares.`,
176091
+ // issue #162 — individual identity (OMG SysML v2 Part 1 §7.9.4 Individuals).
176092
+ // Each message names the life the model claims and the thing that cannot have
176093
+ // one, because the fix is always to move the keyword or to name the definition
176094
+ // that carries the identity.
176095
+ SSM040_INDIVIDUAL_NOT_OCCURRENCE: (name, kind) => `'individual' names one occurrence with an identity of its own, and ${name} is ${kind}, which has no life to identify. Remove 'individual', or move it to the occurrence this belongs to.`,
176096
+ SSM041_INDIVIDUAL_MULTIPLE_DEFINITIONS: (name, first2, second) => `${name} is typed by two individual definitions, '${first2}' and '${second}'. An individual usage names ONE life, so at most one of its types may be an 'individual def'.`,
176097
+ SSM042_INDIVIDUAL_WITHOUT_DEFINITION: (name) => `${name} is declared 'individual' but names no individual definition. An individual usage is typed by exactly one 'individual def' - the definition that carries the identity it names.`,
175740
176098
  // REQ-392 — a `sysml-format` comment the formatter cannot act on. Advisory:
175741
176099
  // the directive is inert, and saying so beats leaving the author to wonder
175742
176100
  // why their layout was reformatted anyway.
@@ -176390,6 +176748,9 @@ ${headerLines.join("\n")}
176390
176748
  if (composition.isFeature) {
176391
176749
  parts.push(`*Ownership:* ${composition.isComposite ? "Composite feature" : "Referential feature"}`);
176392
176750
  }
176751
+ const individual = individualSection(node);
176752
+ if (individual)
176753
+ parts.push(individual);
176393
176754
  const subject = subjectInheritanceSection(node);
176394
176755
  if (subject)
176395
176756
  parts.push(subject);
@@ -176404,6 +176765,23 @@ ${headerLines.join("\n")}
176404
176765
  parts.push(sourceFooter(nodeSource(node)));
176405
176766
  return parts.join("\n\n");
176406
176767
  }
176768
+ function writesOwnMultiplicity(node) {
176769
+ const n2 = node;
176770
+ return n2.multiplicity !== void 0 || n2.innerMultiplicity !== void 0 || n2.endMultiplicity !== void 0;
176771
+ }
176772
+ function individualSection(node) {
176773
+ const effective = identityOf(node);
176774
+ if (!effective)
176775
+ return void 0;
176776
+ if (isDefinitionDecl(node)) {
176777
+ return effective.explicit ? "*Individual:* one life. Every usage of this definition is a portion of the same occurrence." : void 0;
176778
+ }
176779
+ if (!effective.explicit && !effective.definition)
176780
+ return void 0;
176781
+ const identity6 = effective.definition ? `the life of \`${effective.definition}\`` : "one life";
176782
+ const what = effective.portion ? `A \`${effective.portion}\` of ${identity6}` : `Identifies ${identity6}`;
176783
+ return writesOwnMultiplicity(node) ? `*Individual:* ${what}.` : `*Individual:* ${what}, so it has multiplicity \`${effective.multiplicity}\`.`;
176784
+ }
176407
176785
  function subjectInheritanceSection(node) {
176408
176786
  const effective = resolveEffectiveSubject(node);
176409
176787
  if (!effective || !effective.inherited)
@@ -178295,7 +178673,7 @@ var import_vscode_languageserver16 = __toESM(require_main4(), 1);
178295
178673
 
178296
178674
  // ../language-server/out/src/services/metadata-filter.js
178297
178675
  var INCONCLUSIVE2 = { kind: "inconclusive" };
178298
- var SPECIALIZATION_KINDS4 = /* @__PURE__ */ new Set([":>", "specializes", ":>>", "redefines", "subsets"]);
178676
+ var SPECIALIZATION_KINDS5 = /* @__PURE__ */ new Set([":>", "specializes", ":>>", "redefines", "subsets"]);
178299
178677
  var MAX_SPECIALIZATION_DEPTH = 32;
178300
178678
  var MAX_VALUE_DEPTH = 16;
178301
178679
  function evaluateFilterCondition(condition, element, options) {
@@ -178398,7 +178776,7 @@ function declaresFeature2(node, name) {
178398
178776
  if (node.name === name)
178399
178777
  return true;
178400
178778
  for (const rel2 of [...node.preRelationships ?? [], ...node.relationships ?? []]) {
178401
- if (rel2.kind && SPECIALIZATION_KINDS4.has(rel2.kind) && (rel2.targets ?? []).includes(name))
178779
+ if (rel2.kind && SPECIALIZATION_KINDS5.has(rel2.kind) && (rel2.targets ?? []).includes(name))
178402
178780
  return true;
178403
178781
  }
178404
178782
  return false;
@@ -178565,7 +178943,7 @@ function nameScope(ctx, depth = 0) {
178565
178943
  function specializationTargets3(node) {
178566
178944
  const targets = [];
178567
178945
  for (const rel2 of [...node.preRelationships ?? [], ...node.relationships ?? []]) {
178568
- if (rel2.kind && SPECIALIZATION_KINDS4.has(rel2.kind))
178946
+ if (rel2.kind && SPECIALIZATION_KINDS5.has(rel2.kind))
178569
178947
  targets.push(...rel2.targets ?? []);
178570
178948
  }
178571
178949
  return targets;
@@ -179356,7 +179734,7 @@ function maskNonCode(text) {
179356
179734
  }
179357
179735
  return out.join("");
179358
179736
  }
179359
- var SPECIALIZATION_KINDS5 = /* @__PURE__ */ new Set([":>", ":>>", "specializes", "subsets", "redefines"]);
179737
+ var SPECIALIZATION_KINDS6 = /* @__PURE__ */ new Set([":>", ":>>", "specializes", "subsets", "redefines"]);
179360
179738
  var CONSTRAINT_SIDE_EFFECT_TYPES = /* @__PURE__ */ new Set([
179361
179739
  "AssignNode",
179362
179740
  "SendNode",
@@ -179421,12 +179799,6 @@ function actionOnlyConstruct(node) {
179421
179799
  const keyword = CONTROL_NODE_KEYWORDS[node.$type];
179422
179800
  return keyword ? { construct: `A '${keyword}' control node`, clause: "7.17.3" } : void 0;
179423
179801
  }
179424
- function portionKindOf2(node) {
179425
- const mods = node.modifiers;
179426
- if (!Array.isArray(mods))
179427
- return void 0;
179428
- return mods.find((m) => m === "timeslice" || m === "snapshot");
179429
- }
179430
179802
  var NAMESPACE_ONLY_TYPES = /* @__PURE__ */ new Set(["Package", "Document", "NamespaceDecl"]);
179431
179803
  function owningTypeOf(node) {
179432
179804
  let owner = node.$container;
@@ -179841,6 +180213,7 @@ var SysmlValidator = class _SysmlValidator {
179841
180213
  this.checkActionFlowStyle(node, accept);
179842
180214
  this.checkKeywordOrdering(node, accept);
179843
180215
  this.checkModifierPlacement(node, accept);
180216
+ this.checkModifierOrder(node, accept);
179844
180217
  this.checkEnumerations(node, accept);
179845
180218
  this.checkVariability(node, accept);
179846
180219
  this.checkMultiplicities(node, accept);
@@ -179854,6 +180227,7 @@ var SysmlValidator = class _SysmlValidator {
179854
180227
  this.checkKermlWellFormedness(node, accept);
179855
180228
  this.checkFilterExpressions(node, accept);
179856
180229
  this.checkOccurrencePortions(node, accept);
180230
+ this.checkIndividualDeclarations(node, accept);
179857
180231
  this.checkCrossReferences(node, accept);
179858
180232
  this.checkAutoImportSuggestions(node, accept);
179859
180233
  this.checkUnits(node, accept);
@@ -180648,6 +181022,46 @@ ${baseIndent}}`;
180648
181022
  }
180649
181023
  }
180650
181024
  }
181025
+ // REQ-413 — SYN025 canonical order of the leading declaration modifiers.
181026
+ //
181027
+ // `DeclarationPrefix` accepts any permutation so that a mis-ordered prefix
181028
+ // still parses; this is the rule that then says the order is wrong, and the
181029
+ // only place that knows it is `modifier-order.ts`, shared with the quick fix
181030
+ // and the formatter.
181031
+ //
181032
+ // Read off the parsed AST rather than the text, so a modifier word inside a
181033
+ // comment, a string, a documentation body or a name can never reach it. A run
181034
+ // holding a modifier with no canonical position is skipped whole
181035
+ // (`UNRANKED_MODIFIERS`). One diagnostic per RUN, not per declaration: an end
181036
+ // writes two prefixes (`end ref constant a;`), each with its own fix, but the
181037
+ // fix rewrites a whole run, so a second squiggle within one run would name work
181038
+ // the first has already done.
181039
+ checkModifierOrder(node, accept) {
181040
+ const source = ast_utils_exports.getDocument(node)?.textDocument.getText();
181041
+ for (const child of ast_utils_exports.streamAllContents(node)) {
181042
+ for (const run of modifierRunsOf(child)) {
181043
+ const misplaced = firstMisplacedModifier(run.modifiers);
181044
+ if (!misplaced)
181045
+ continue;
181046
+ const canonical = canonicalModifierOrder(run.modifiers).join(" ");
181047
+ const first2 = run.nodes[0];
181048
+ const last2 = run.nodes[run.nodes.length - 1];
181049
+ accept(severity("SYN025", "warning"), DIAGNOSTIC_MESSAGES.SYN025_MODIFIER_ORDER(run.modifiers[misplaced.index], run.modifiers[misplaced.before], canonical), {
181050
+ node: child,
181051
+ range: run.nodes[misplaced.index].range,
181052
+ code: "SYN025",
181053
+ // The fix rewrites the whole run, so offer it only where a
181054
+ // one-line replacement loses nothing.
181055
+ ...source !== void 0 && isRewritableRun(source, run) ? {
181056
+ data: {
181057
+ replacement: canonical,
181058
+ range: { start: first2.range.start, end: last2.range.end }
181059
+ }
181060
+ } : {}
181061
+ });
181062
+ }
181063
+ }
181064
+ }
180651
181065
  // REQ-409 - Enumeration definitions and usages specialize the general
180652
181066
  // variation, attribute and reference rules with a closed value inventory.
180653
181067
  checkEnumerations(node, accept) {
@@ -180784,7 +181198,7 @@ ${baseIndent}}`;
180784
181198
  accept(severity("SYN019", "error"), DIAGNOSTIC_MESSAGES.SYN019_ABSTRACT_VARIATION, { node: child, code: "SYN019" });
180785
181199
  }
180786
181200
  for (const relation of [...decl.preRelationships ?? [], ...decl.relationships ?? []]) {
180787
- if (!relation.kind || !SPECIALIZATION_KINDS5.has(relation.kind))
181201
+ if (!relation.kind || !SPECIALIZATION_KINDS6.has(relation.kind))
180788
181202
  continue;
180789
181203
  for (let index2 = 0; index2 < (relation.targets?.length ?? 0); index2 += 1) {
180790
181204
  const resolution = this.featurePaths.resolvePropertyPath(relation, "targets", index2);
@@ -181224,6 +181638,49 @@ ${baseIndent}}`;
181224
181638
  this.checkActionParameterCorrespondence(decl, model, accept);
181225
181639
  this.checkRedefinitionDirection(decl, index2, accept);
181226
181640
  this.checkInterfaceEndTypes(decl, model, index2, accept);
181641
+ this.checkIndividualDefinitions(decl, model, accept);
181642
+ }
181643
+ }
181644
+ // issue #162 — SSM041 / SSM042: the identity an individual usage names.
181645
+ //
181646
+ // OMG SysML v2 Part 1 §7.9.4 derives `OccurrenceUsage::individualDefinition`
181647
+ // as the usage's types that are individual occurrence definitions, and
181648
+ // constrains it twice: at most one for ANY occurrence usage, and exactly one
181649
+ // for a usage written `individual`. Both say the same thing — an individual
181650
+ // usage names ONE life — from the two sides.
181651
+ //
181652
+ // SSM041 — two individual definitions written on the same usage. Judged on the
181653
+ // DIRECTLY written types only, exactly as the metamodel derives them:
181654
+ // reaching a second identity through a supertype is how the canonical
181655
+ // models legitimately relate an individual to the family it belongs to.
181656
+ // SSM042 — an `individual` usage that reaches no individual definition at all.
181657
+ // Judged over the whole type-and-specialization walk, because a usage
181658
+ // inherits identity (`individual timeslice t :> ind;` takes its
181659
+ // definition from the `ind` it subsets), and only when that walk was
181660
+ // COMPLETE: an unread supertype may never be read as an absence.
181661
+ // issue #162 — the node whose own text contains the `individual` keyword. It is
181662
+ // the declaration itself, unless an enclosing `#Tag` wrapper carries the prefix.
181663
+ // REQ-412 — SSM041/SSM042: the identity an individual usage names
181664
+ checkIndividualDefinitions(decl, model, accept) {
181665
+ if (decl.isDef === true || decl.$type === "BareDefDecl")
181666
+ return;
181667
+ if (!isOccurrenceShapedDecl(decl))
181668
+ return;
181669
+ const explicit = isIndividualDecl(decl);
181670
+ if (!explicit && writtenTypesOf(decl).filter((each) => !each.conjugated).length < 2)
181671
+ return;
181672
+ const closure2 = individualClosureOf(decl, (name) => model.declarationOf(name));
181673
+ const label = decl.name ? `'${decl.name}'` : `This '${kindLabel2(decl)}'`;
181674
+ if (closure2.direct.length > 1) {
181675
+ accept(severity("SSM041", "error"), DIAGNOSTIC_MESSAGES.SSM041_INDIVIDUAL_MULTIPLE_DEFINITIONS(label, closure2.direct[0].text, closure2.direct[1].text), {
181676
+ node: decl,
181677
+ code: "SSM041",
181678
+ relatedInformation: declarationSite(closure2.direct[1].node, closure2.direct[1].text)
181679
+ });
181680
+ return;
181681
+ }
181682
+ if (explicit && closure2.definitions.length === 0 && closure2.complete) {
181683
+ accept(severity("SSM042", "error"), DIAGNOSTIC_MESSAGES.SSM042_INDIVIDUAL_WITHOUT_DEFINITION(label), { node: decl, code: "SSM042" });
181227
181684
  }
181228
181685
  }
181229
181686
  // REQ-390 — SSM017: a redefining feature narrows the feature it redefines, so
@@ -181553,8 +182010,9 @@ ${baseIndent}}`;
181553
182010
  // SysML usage kind IS an OccurrenceUsage (part, item, action, state, port,
181554
182011
  // connection, case, …) while the data-valued ones are few and closed: an
181555
182012
  // AttributeUsage is typed by a DataType and an enumeration is a special attribute,
181556
- // neither of which has a life to carve up.
181557
- static NON_OCCURRENCE_OWNER_TYPES = /* @__PURE__ */ new Set(["AttributeDecl", "EnumDecl", "EnumValueDecl", "MetadataDecl", "MultiplicityDecl"]);
182013
+ // neither of which has a life to carve up. issue #162 — SSM040 judges an
182014
+ // `individual` against the same list, so the two share one spelling of it.
182015
+ static NON_OCCURRENCE_OWNER_TYPES = NON_OCCURRENCE_DECL_TYPES;
181558
182016
  // REQ-160 — OMG SysML v2 §8.2.2.9 (Occurrences) with the Kernel Semantic Library
181559
182017
  // `Occurrences::TimeSlice` / `Occurrences::Snapshot`:
181560
182018
  //
@@ -181570,7 +182028,7 @@ ${baseIndent}}`;
181570
182028
  // without resolving a single cross-reference.
181571
182029
  checkOccurrencePortions(node, accept) {
181572
182030
  for (const child of ast_utils_exports.streamAllContents(node)) {
181573
- const kind = portionKindOf2(child);
182031
+ const kind = portionKindOf(child);
181574
182032
  if (!kind)
181575
182033
  continue;
181576
182034
  const label = declLabel(child, kind);
@@ -181583,11 +182041,36 @@ ${baseIndent}}`;
181583
182041
  accept(severity("SSM015", "error"), `A '${kind}' is a portion of an occurrence's life, and '${owner.name ?? owner.$type}' is not an occurrence.`, { node: child, code: "SSM015" });
181584
182042
  continue;
181585
182043
  }
181586
- if (kind === "timeslice" && portionKindOf2(owner) === "snapshot") {
182044
+ if (kind === "timeslice" && portionKindOf(owner) === "snapshot") {
181587
182045
  accept(severity("SSM016", "error"), `A 'snapshot' is a zero-duration timeslice, so ${label} cannot be a timeslice of it - a portion of an instant is itself a snapshot.`, { node: child, code: "SSM016" });
181588
182046
  }
181589
182047
  }
181590
182048
  }
182049
+ // ══════════════════════════════════════════════════════════════════════
182050
+ // issue #162 — SSM040: `individual` presupposes an occurrence
182051
+ // ══════════════════════════════════════════════════════════════════════
182052
+ // OMG SysML v2 Part 1 §7.9.4 puts `isIndividual` on OccurrenceDefinition and
182053
+ // OccurrenceUsage, and nowhere else. An attribute is typed by a DataType and
182054
+ // has no life; a package is a namespace and is not a type at all. Writing
182055
+ // `individual` there claims an identity over time for something that has none.
182056
+ //
182057
+ // Structural: it reads the modifier and the declaration kind only, so it holds
182058
+ // with nothing resolved. The quick fix removes the keyword.
182059
+ // REQ-412 — SSM040: `individual` on a declaration that is not an occurrence
182060
+ checkIndividualDeclarations(node, accept) {
182061
+ for (const child of ast_utils_exports.streamAllContents(node)) {
182062
+ if (!isIndividualDecl(child) || isOccurrenceShapedDecl(child))
182063
+ continue;
182064
+ const name = child.name;
182065
+ const carrier = individualModifierCarrier(child);
182066
+ accept(severity("SSM040", "error"), DIAGNOSTIC_MESSAGES.SSM040_INDIVIDUAL_NOT_OCCURRENCE(name ? `'${name}'` : "this declaration", nonOccurrenceLabel(child)), {
182067
+ node: child,
182068
+ code: "SSM040",
182069
+ data: { individualModifier: true },
182070
+ ...carrier?.$cstNode ? { range: carrier.$cstNode.range } : {}
182071
+ });
182072
+ }
182073
+ }
181591
182074
  // REQ-328 — KSM008: a `filter` membership condition must be Boolean. Only a
181592
182075
  // *definitely* non-Boolean expression is flagged — a string or numeric/quantity
181593
182076
  // literal, or an arithmetic/range binary expression. A bare feature path is left
@@ -182621,7 +183104,7 @@ function specializationTargets4(node) {
182621
183104
  ...node.relationships ?? []
182622
183105
  ];
182623
183106
  for (const rel2 of rels) {
182624
- if (rel2.kind && SPECIALIZATION_KINDS5.has(rel2.kind))
183107
+ if (rel2.kind && SPECIALIZATION_KINDS6.has(rel2.kind))
182625
183108
  out.push(...rel2.targets);
182626
183109
  }
182627
183110
  return out;
@@ -183397,12 +183880,12 @@ function importSignature(imp) {
183397
183880
  const segments = imp.segs.map((seg) => `${seg.name ?? ""}${seg.star ? "*" : ""}${seg.recursive ? "**" : ""}`);
183398
183881
  return `${importVisibility(imp)} ${imp.head}::${segments.join("::")}${imp.alias ? ` as ${imp.alias}` : ""}`;
183399
183882
  }
183400
- var SPECIALIZATION_KINDS6 = /* @__PURE__ */ new Set([":>", ":>>", "specializes", "subsets", "redefines"]);
183883
+ var SPECIALIZATION_KINDS7 = /* @__PURE__ */ new Set([":>", ":>>", "specializes", "subsets", "redefines"]);
183401
183884
  function specializationTargets5(node) {
183402
183885
  const n2 = node;
183403
183886
  const out = [];
183404
183887
  for (const rel2 of [...n2.preRelationships ?? [], ...n2.relationships ?? []]) {
183405
- if (rel2.kind && SPECIALIZATION_KINDS6.has(rel2.kind))
183888
+ if (rel2.kind && SPECIALIZATION_KINDS7.has(rel2.kind))
183406
183889
  out.push(...rel2.targets ?? []);
183407
183890
  }
183408
183891
  return out;
@@ -183690,12 +184173,12 @@ function directImportEntries(imp, descriptions) {
183690
184173
  }
183691
184174
  return applyFilters(imp, selectMemberships(path10, form, descriptions), options);
183692
184175
  }
183693
- var SPECIALIZATION_KINDS7 = /* @__PURE__ */ new Set([":>", ":>>", "specializes", "subsets", "redefines"]);
184176
+ var SPECIALIZATION_KINDS8 = /* @__PURE__ */ new Set([":>", ":>>", "specializes", "subsets", "redefines"]);
183694
184177
  function specializationTargets6(node) {
183695
184178
  const value = node;
183696
184179
  const targets = [];
183697
184180
  for (const relationship of [...value.preRelationships ?? [], ...value.relationships ?? []]) {
183698
- if (relationship.kind && SPECIALIZATION_KINDS7.has(relationship.kind)) {
184181
+ if (relationship.kind && SPECIALIZATION_KINDS8.has(relationship.kind)) {
183699
184182
  targets.push(...relationship.targets ?? []);
183700
184183
  }
183701
184184
  }
@@ -184022,6 +184505,16 @@ function isAliasFixData(data) {
184022
184505
  function isReplacementFixData(data) {
184023
184506
  return typeof data === "object" && data !== null && typeof data.replacement === "string";
184024
184507
  }
184508
+ function isReorderFixData(data) {
184509
+ if (typeof data !== "object" || data === null)
184510
+ return false;
184511
+ const { replacement, range } = data;
184512
+ if (typeof replacement !== "string" || typeof range !== "object" || range === null)
184513
+ return false;
184514
+ const { start: start2, end } = range;
184515
+ const isPosition = (p) => typeof p === "object" && p !== null && typeof p.line === "number" && typeof p.character === "number";
184516
+ return isPosition(start2) && isPosition(end);
184517
+ }
184025
184518
  function leafAtOffset2(node, offset2) {
184026
184519
  if (isLeafCstNode(node)) {
184027
184520
  return node.offset <= offset2 && offset2 < node.offset + node.length ? node : void 0;
@@ -184192,6 +184685,18 @@ var SysmlCodeActionProvider = class {
184192
184685
  });
184193
184686
  }
184194
184687
  }
184688
+ if (code === "SYN025" && isReorderFixData(diagnostic.data)) {
184689
+ actions.push({
184690
+ title: `Reorder modifiers to '${diagnostic.data.replacement}'`,
184691
+ kind: import_vscode_languageserver18.CodeActionKind.QuickFix,
184692
+ diagnostics: [diagnostic],
184693
+ edit: {
184694
+ changes: {
184695
+ [uri]: [import_vscode_languageserver18.TextEdit.replace(diagnostic.data.range, diagnostic.data.replacement)]
184696
+ }
184697
+ }
184698
+ });
184699
+ }
184195
184700
  if (code === "RES021") {
184196
184701
  actions.push({
184197
184702
  title: "Make this root import 'private'",
@@ -184314,6 +184819,26 @@ ${indent}}`)]
184314
184819
  }
184315
184820
  });
184316
184821
  }
184822
+ if (code === "SSM040" && diagnostic.data && diagnostic.data.individualModifier === true) {
184823
+ const declText = document2.textDocument.getText(diagnostic.range);
184824
+ const match = /\bindividual\b[ \t]*/u.exec(declText);
184825
+ if (match) {
184826
+ const start2 = document2.textDocument.offsetAt(diagnostic.range.start) + match.index;
184827
+ actions.push({
184828
+ title: "Remove 'individual'",
184829
+ kind: import_vscode_languageserver18.CodeActionKind.QuickFix,
184830
+ diagnostics: [diagnostic],
184831
+ edit: {
184832
+ changes: {
184833
+ [uri]: [import_vscode_languageserver18.TextEdit.replace({
184834
+ start: document2.textDocument.positionAt(start2),
184835
+ end: document2.textDocument.positionAt(start2 + match[0].length)
184836
+ }, "")]
184837
+ }
184838
+ }
184839
+ });
184840
+ }
184841
+ }
184317
184842
  if (code === "STYL006") {
184318
184843
  const suffix = document2.textDocument.getText(diagnostic.range).replace(/\s+/gu, "");
184319
184844
  if (suffix === "::**") {
@@ -184900,6 +185425,25 @@ ${line2.indent}${unit}`
184900
185425
  });
184901
185426
  }
184902
185427
  }
185428
+ function modifierOrderRewrites(document2, out) {
185429
+ const root4 = document2.parseResult?.value;
185430
+ if (!root4)
185431
+ return;
185432
+ const source = document2.textDocument.getText();
185433
+ for (const node of ast_utils_exports.streamAllContents(root4)) {
185434
+ for (const run of modifierRunsOf(node)) {
185435
+ if (!firstMisplacedModifier(run.modifiers))
185436
+ continue;
185437
+ if (!isRewritableRun(source, run))
185438
+ continue;
185439
+ out.push({
185440
+ offset: run.nodes[0].offset,
185441
+ end: run.nodes[run.nodes.length - 1].end,
185442
+ newText: canonicalModifierOrder(run.modifiers).join(" ")
185443
+ });
185444
+ }
185445
+ }
185446
+ }
184903
185447
  function withinRange(document2, rewrite, range) {
184904
185448
  if (!range)
184905
185449
  return true;
@@ -184909,25 +185453,26 @@ function withinRange(document2, rewrite, range) {
184909
185453
  function styleEdits(input) {
184910
185454
  const { document: document2, settings, options, baseEdits, protectedRanges, range, reservedKeywords } = input;
184911
185455
  const wantsRewrite = settings.emptyBody !== "preserve" || settings.quotedNames !== "preserve" || settings.documentationIndent !== "preserve" || settings.keywords !== "preserve" || settings.lineWidth > 0;
184912
- if (!wantsRewrite)
184913
- return [];
184914
185456
  const leaves = leavesOf(document2);
184915
185457
  if (leaves.length === 0)
184916
185458
  return [];
184917
- const projection2 = projectFormatted(document2, baseEdits);
184918
185459
  const rewrites = [];
184919
- if (settings.keywords === "symbolic")
184920
- keywordRewrites(leaves, rewrites);
184921
- if (settings.emptyBody !== "preserve") {
184922
- emptyBodyRewrites(document2, leaves, projection2, settings, options, rewrites);
184923
- }
184924
- if (settings.quotedNames === "unquoteSafe")
184925
- quotedNameRewrites(leaves, reservedKeywords, rewrites);
184926
- if (settings.documentationIndent === "align") {
184927
- documentationRewrites(document2, leaves, projection2, options, rewrites);
184928
- }
184929
- if (settings.lineWidth > 0)
184930
- wrapRewrites(leaves, projection2, options, settings.lineWidth, rewrites);
185460
+ modifierOrderRewrites(document2, rewrites);
185461
+ if (wantsRewrite) {
185462
+ const projection2 = projectFormatted(document2, baseEdits);
185463
+ if (settings.keywords === "symbolic")
185464
+ keywordRewrites(leaves, rewrites);
185465
+ if (settings.emptyBody !== "preserve") {
185466
+ emptyBodyRewrites(document2, leaves, projection2, settings, options, rewrites);
185467
+ }
185468
+ if (settings.quotedNames === "unquoteSafe")
185469
+ quotedNameRewrites(leaves, reservedKeywords, rewrites);
185470
+ if (settings.documentationIndent === "align") {
185471
+ documentationRewrites(document2, leaves, projection2, options, rewrites);
185472
+ }
185473
+ if (settings.lineWidth > 0)
185474
+ wrapRewrites(leaves, projection2, options, settings.lineWidth, rewrites);
185475
+ }
184931
185476
  const doc = document2.textDocument;
184932
185477
  const source = doc.getText();
184933
185478
  const accepted = [];
@@ -184952,8 +185497,8 @@ function styleEdits(input) {
184952
185497
 
184953
185498
  // ../language-server/out/src/services/formatter.js
184954
185499
  var INDENT = Formatting.indent({ allowMore: true });
184955
- var DEDENT = Formatting.noIndent();
184956
185500
  var NL = Formatting.newLine();
185501
+ var DEDENT_NL = { options: {}, moves: [{ lines: 1, tabs: -1 }] };
184957
185502
  var SPACE = Formatting.oneSpace();
184958
185503
  var NO_SPACE = Formatting.noSpace();
184959
185504
  var SysmlFormatter = class extends AbstractFormatter {
@@ -185079,14 +185624,15 @@ var SysmlFormatter = class extends AbstractFormatter {
185079
185624
  * leaves every other hidden-node path untouched.
185080
185625
  */
185081
185626
  createTextEdit(a2, b, formatting, context) {
185082
- const edits = super.createTextEdit(a2, b, formatting, context);
185627
+ const action = formatting === DEDENT_NL && context.indentation <= 0 ? NL : formatting;
185628
+ const edits = super.createTextEdit(a2, b, action, context);
185083
185629
  if (!b.hidden)
185084
185630
  return edits;
185085
185631
  const startRange = {
185086
185632
  start: { line: b.range.start.line, character: 0 },
185087
185633
  end: b.range.start
185088
185634
  };
185089
- context.indentation += this.findFittingMove(startRange, formatting.moves, context)?.tabs ?? 0;
185635
+ context.indentation += this.findFittingMove(startRange, action.moves, context)?.tabs ?? 0;
185090
185636
  return edits;
185091
185637
  }
185092
185638
  // REQ-259 — Dispatch formatting from AST node kind
@@ -185215,10 +185761,10 @@ var SysmlFormatter = class extends AbstractFormatter {
185215
185761
  fmtBlock(node, keyword) {
185216
185762
  const f = this.getNodeFormatter(node);
185217
185763
  if (!isDocument(node.$container)) {
185218
- f.keyword(keyword).prepend(Formatting.newLines(1 + this.active.blankLines));
185764
+ this.lineAnchor(node, f, keyword).prepend(Formatting.newLines(1 + this.active.blankLines));
185219
185765
  }
185220
185766
  f.keyword(keyword).append(SPACE);
185221
- this.fmtBraces(f);
185767
+ this.fmtBraces(node, f);
185222
185768
  }
185223
185769
  // REQ-355 — Filtered imports keep the `[@Meta]` condition tight against the path
185224
185770
  fmtImport(node) {
@@ -185234,11 +185780,26 @@ var SysmlFormatter = class extends AbstractFormatter {
185234
185780
  ff.keyword("@@").append(NO_SPACE);
185235
185781
  }
185236
185782
  }
185783
+ /**
185784
+ * REQ-258 — Where a member's line break belongs.
185785
+ *
185786
+ * A declaration's kind keyword is NOT always its first token: a leading
185787
+ * modifier (`derived ref attribute a;`), a visibility (`private package P;`)
185788
+ * or a `standard library` marker is written ahead of it. Prepending the
185789
+ * newline to the keyword split such a declaration over two lines. Ask the CST
185790
+ * where the node actually starts rather than listing the words that can come
185791
+ * first, so a grammar change cannot quietly reintroduce the split.
185792
+ */
185793
+ lineAnchor(node, f, keyword) {
185794
+ const start2 = node.$cstNode?.offset;
185795
+ const at = grammar_utils_exports.findNodeForKeyword(node.$cstNode, keyword)?.offset;
185796
+ return start2 !== void 0 && at !== void 0 && at > start2 ? f.node(node) : f.keyword(keyword);
185797
+ }
185237
185798
  // REQ-258, REQ-260 — Format one element per line with canonical keyword spacing
185238
185799
  fmtElement(node, keyword) {
185239
185800
  const f = this.getNodeFormatter(node);
185240
185801
  if (!isDocument(node.$container))
185241
- f.keyword(keyword).prepend(NL);
185802
+ this.lineAnchor(node, f, keyword).prepend(NL);
185242
185803
  f.keyword(keyword).append(SPACE);
185243
185804
  if (node.isDef) {
185244
185805
  f.keyword("def").prepend(SPACE).append(SPACE);
@@ -185248,50 +185809,59 @@ var SysmlFormatter = class extends AbstractFormatter {
185248
185809
  f.keyword(":>>").surround(SPACE);
185249
185810
  f.keyword("=").surround(SPACE);
185250
185811
  f.keyword(";").prepend(NO_SPACE);
185251
- this.fmtBraces(f);
185812
+ this.fmtBraces(node, f);
185252
185813
  }
185253
185814
  // REQ-260 — Keep multi-word `verification case` keyword phrase together
185254
185815
  fmtVerificationCase(node) {
185255
185816
  const f = this.getNodeFormatter(node);
185256
185817
  if (!isDocument(node.$container))
185257
- f.keyword("verification").prepend(NL);
185818
+ this.lineAnchor(node, f, "verification").prepend(NL);
185258
185819
  f.keyword("verification").append(SPACE);
185259
185820
  f.keyword("case").append(SPACE);
185260
185821
  if (node.isDef)
185261
185822
  f.keyword("def").append(SPACE);
185262
185823
  f.keyword(":").surround(SPACE);
185263
185824
  f.keyword(";").prepend(NO_SPACE);
185264
- this.fmtBraces(f);
185825
+ this.fmtBraces(node, f);
185265
185826
  }
185266
185827
  // REQ-260 — Keep multi-word `analysis case` keyword phrase together
185267
185828
  fmtAnalysisCase(node) {
185268
185829
  const f = this.getNodeFormatter(node);
185269
185830
  if (!isDocument(node.$container))
185270
- f.keyword("analysis").prepend(NL);
185831
+ this.lineAnchor(node, f, "analysis").prepend(NL);
185271
185832
  f.keyword("analysis").append(SPACE);
185272
185833
  f.keyword("case").append(SPACE);
185273
185834
  if (node.isDef)
185274
185835
  f.keyword("def").append(SPACE);
185275
185836
  f.keyword(":").surround(SPACE);
185276
185837
  f.keyword(";").prepend(NO_SPACE);
185277
- this.fmtBraces(f);
185838
+ this.fmtBraces(node, f);
185278
185839
  }
185279
185840
  // REQ-260 — Keep multi-word `use case` keyword phrase together
185280
185841
  fmtUseCase(node) {
185281
185842
  const f = this.getNodeFormatter(node);
185282
185843
  if (!isDocument(node.$container))
185283
- f.keyword("use").prepend(NL);
185844
+ this.lineAnchor(node, f, "use").prepend(NL);
185284
185845
  f.keyword("use").append(SPACE);
185285
185846
  f.keyword("case").append(SPACE);
185286
185847
  if (node.isDef)
185287
185848
  f.keyword("def").append(SPACE);
185288
185849
  f.keyword(":").surround(SPACE);
185289
185850
  f.keyword(";").prepend(NO_SPACE);
185290
- this.fmtBraces(f);
185851
+ this.fmtBraces(node, f);
185291
185852
  }
185292
- fmtBraces(f) {
185853
+ /**
185854
+ * REQ-258 — A block's braces.
185855
+ *
185856
+ * The closing brace steps back out only when the body actually stepped in.
185857
+ * An EMPTY body never opened a level (`{` and `}` are adjacent, and the
185858
+ * indent `{` appends is spent on `}` itself), so dedenting it would take the
185859
+ * brace one level below its owner.
185860
+ */
185861
+ fmtBraces(node, f) {
185293
185862
  f.keyword("{").surround(SPACE).append(INDENT);
185294
- f.keyword("}").prepend(DEDENT).prepend(NL);
185863
+ const members = node.members;
185864
+ f.keyword("}").prepend(members && members.length > 0 ? DEDENT_NL : NL);
185295
185865
  }
185296
185866
  };
185297
185867
 
@@ -210237,7 +210807,7 @@ async function runExport(command) {
210237
210807
  }
210238
210808
 
210239
210809
  // src/main.ts
210240
- var VERSION2 = true ? "0.32.0" : "dev";
210810
+ var VERSION2 = true ? "0.34.0" : "dev";
210241
210811
  function display(file) {
210242
210812
  const rel2 = path9.relative(process.cwd(), file);
210243
210813
  return rel2 && !rel2.startsWith("..") ? rel2.split(path9.sep).join("/") : file;