sysml-diagram 0.32.0 → 0.33.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;
@@ -175737,6 +176017,13 @@ var DIAGNOSTIC_MESSAGES = {
175737
176017
  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
176018
  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
176019
  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.`,
176020
+ // issue #162 — individual identity (OMG SysML v2 Part 1 §7.9.4 Individuals).
176021
+ // Each message names the life the model claims and the thing that cannot have
176022
+ // one, because the fix is always to move the keyword or to name the definition
176023
+ // that carries the identity.
176024
+ 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.`,
176025
+ 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'.`,
176026
+ 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
176027
  // REQ-392 — a `sysml-format` comment the formatter cannot act on. Advisory:
175741
176028
  // the directive is inert, and saying so beats leaving the author to wonder
175742
176029
  // why their layout was reformatted anyway.
@@ -176390,6 +176677,9 @@ ${headerLines.join("\n")}
176390
176677
  if (composition.isFeature) {
176391
176678
  parts.push(`*Ownership:* ${composition.isComposite ? "Composite feature" : "Referential feature"}`);
176392
176679
  }
176680
+ const individual = individualSection(node);
176681
+ if (individual)
176682
+ parts.push(individual);
176393
176683
  const subject = subjectInheritanceSection(node);
176394
176684
  if (subject)
176395
176685
  parts.push(subject);
@@ -176404,6 +176694,23 @@ ${headerLines.join("\n")}
176404
176694
  parts.push(sourceFooter(nodeSource(node)));
176405
176695
  return parts.join("\n\n");
176406
176696
  }
176697
+ function writesOwnMultiplicity(node) {
176698
+ const n2 = node;
176699
+ return n2.multiplicity !== void 0 || n2.innerMultiplicity !== void 0 || n2.endMultiplicity !== void 0;
176700
+ }
176701
+ function individualSection(node) {
176702
+ const effective = identityOf(node);
176703
+ if (!effective)
176704
+ return void 0;
176705
+ if (isDefinitionDecl(node)) {
176706
+ return effective.explicit ? "*Individual:* one life. Every usage of this definition is a portion of the same occurrence." : void 0;
176707
+ }
176708
+ if (!effective.explicit && !effective.definition)
176709
+ return void 0;
176710
+ const identity6 = effective.definition ? `the life of \`${effective.definition}\`` : "one life";
176711
+ const what = effective.portion ? `A \`${effective.portion}\` of ${identity6}` : `Identifies ${identity6}`;
176712
+ return writesOwnMultiplicity(node) ? `*Individual:* ${what}.` : `*Individual:* ${what}, so it has multiplicity \`${effective.multiplicity}\`.`;
176713
+ }
176407
176714
  function subjectInheritanceSection(node) {
176408
176715
  const effective = resolveEffectiveSubject(node);
176409
176716
  if (!effective || !effective.inherited)
@@ -178295,7 +178602,7 @@ var import_vscode_languageserver16 = __toESM(require_main4(), 1);
178295
178602
 
178296
178603
  // ../language-server/out/src/services/metadata-filter.js
178297
178604
  var INCONCLUSIVE2 = { kind: "inconclusive" };
178298
- var SPECIALIZATION_KINDS4 = /* @__PURE__ */ new Set([":>", "specializes", ":>>", "redefines", "subsets"]);
178605
+ var SPECIALIZATION_KINDS5 = /* @__PURE__ */ new Set([":>", "specializes", ":>>", "redefines", "subsets"]);
178299
178606
  var MAX_SPECIALIZATION_DEPTH = 32;
178300
178607
  var MAX_VALUE_DEPTH = 16;
178301
178608
  function evaluateFilterCondition(condition, element, options) {
@@ -178398,7 +178705,7 @@ function declaresFeature2(node, name) {
178398
178705
  if (node.name === name)
178399
178706
  return true;
178400
178707
  for (const rel2 of [...node.preRelationships ?? [], ...node.relationships ?? []]) {
178401
- if (rel2.kind && SPECIALIZATION_KINDS4.has(rel2.kind) && (rel2.targets ?? []).includes(name))
178708
+ if (rel2.kind && SPECIALIZATION_KINDS5.has(rel2.kind) && (rel2.targets ?? []).includes(name))
178402
178709
  return true;
178403
178710
  }
178404
178711
  return false;
@@ -178565,7 +178872,7 @@ function nameScope(ctx, depth = 0) {
178565
178872
  function specializationTargets3(node) {
178566
178873
  const targets = [];
178567
178874
  for (const rel2 of [...node.preRelationships ?? [], ...node.relationships ?? []]) {
178568
- if (rel2.kind && SPECIALIZATION_KINDS4.has(rel2.kind))
178875
+ if (rel2.kind && SPECIALIZATION_KINDS5.has(rel2.kind))
178569
178876
  targets.push(...rel2.targets ?? []);
178570
178877
  }
178571
178878
  return targets;
@@ -179356,7 +179663,7 @@ function maskNonCode(text) {
179356
179663
  }
179357
179664
  return out.join("");
179358
179665
  }
179359
- var SPECIALIZATION_KINDS5 = /* @__PURE__ */ new Set([":>", ":>>", "specializes", "subsets", "redefines"]);
179666
+ var SPECIALIZATION_KINDS6 = /* @__PURE__ */ new Set([":>", ":>>", "specializes", "subsets", "redefines"]);
179360
179667
  var CONSTRAINT_SIDE_EFFECT_TYPES = /* @__PURE__ */ new Set([
179361
179668
  "AssignNode",
179362
179669
  "SendNode",
@@ -179421,12 +179728,6 @@ function actionOnlyConstruct(node) {
179421
179728
  const keyword = CONTROL_NODE_KEYWORDS[node.$type];
179422
179729
  return keyword ? { construct: `A '${keyword}' control node`, clause: "7.17.3" } : void 0;
179423
179730
  }
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
179731
  var NAMESPACE_ONLY_TYPES = /* @__PURE__ */ new Set(["Package", "Document", "NamespaceDecl"]);
179431
179732
  function owningTypeOf(node) {
179432
179733
  let owner = node.$container;
@@ -179854,6 +180155,7 @@ var SysmlValidator = class _SysmlValidator {
179854
180155
  this.checkKermlWellFormedness(node, accept);
179855
180156
  this.checkFilterExpressions(node, accept);
179856
180157
  this.checkOccurrencePortions(node, accept);
180158
+ this.checkIndividualDeclarations(node, accept);
179857
180159
  this.checkCrossReferences(node, accept);
179858
180160
  this.checkAutoImportSuggestions(node, accept);
179859
180161
  this.checkUnits(node, accept);
@@ -180784,7 +181086,7 @@ ${baseIndent}}`;
180784
181086
  accept(severity("SYN019", "error"), DIAGNOSTIC_MESSAGES.SYN019_ABSTRACT_VARIATION, { node: child, code: "SYN019" });
180785
181087
  }
180786
181088
  for (const relation of [...decl.preRelationships ?? [], ...decl.relationships ?? []]) {
180787
- if (!relation.kind || !SPECIALIZATION_KINDS5.has(relation.kind))
181089
+ if (!relation.kind || !SPECIALIZATION_KINDS6.has(relation.kind))
180788
181090
  continue;
180789
181091
  for (let index2 = 0; index2 < (relation.targets?.length ?? 0); index2 += 1) {
180790
181092
  const resolution = this.featurePaths.resolvePropertyPath(relation, "targets", index2);
@@ -181224,6 +181526,49 @@ ${baseIndent}}`;
181224
181526
  this.checkActionParameterCorrespondence(decl, model, accept);
181225
181527
  this.checkRedefinitionDirection(decl, index2, accept);
181226
181528
  this.checkInterfaceEndTypes(decl, model, index2, accept);
181529
+ this.checkIndividualDefinitions(decl, model, accept);
181530
+ }
181531
+ }
181532
+ // issue #162 — SSM041 / SSM042: the identity an individual usage names.
181533
+ //
181534
+ // OMG SysML v2 Part 1 §7.9.4 derives `OccurrenceUsage::individualDefinition`
181535
+ // as the usage's types that are individual occurrence definitions, and
181536
+ // constrains it twice: at most one for ANY occurrence usage, and exactly one
181537
+ // for a usage written `individual`. Both say the same thing — an individual
181538
+ // usage names ONE life — from the two sides.
181539
+ //
181540
+ // SSM041 — two individual definitions written on the same usage. Judged on the
181541
+ // DIRECTLY written types only, exactly as the metamodel derives them:
181542
+ // reaching a second identity through a supertype is how the canonical
181543
+ // models legitimately relate an individual to the family it belongs to.
181544
+ // SSM042 — an `individual` usage that reaches no individual definition at all.
181545
+ // Judged over the whole type-and-specialization walk, because a usage
181546
+ // inherits identity (`individual timeslice t :> ind;` takes its
181547
+ // definition from the `ind` it subsets), and only when that walk was
181548
+ // COMPLETE: an unread supertype may never be read as an absence.
181549
+ // issue #162 — the node whose own text contains the `individual` keyword. It is
181550
+ // the declaration itself, unless an enclosing `#Tag` wrapper carries the prefix.
181551
+ // REQ-412 — SSM041/SSM042: the identity an individual usage names
181552
+ checkIndividualDefinitions(decl, model, accept) {
181553
+ if (decl.isDef === true || decl.$type === "BareDefDecl")
181554
+ return;
181555
+ if (!isOccurrenceShapedDecl(decl))
181556
+ return;
181557
+ const explicit = isIndividualDecl(decl);
181558
+ if (!explicit && writtenTypesOf(decl).filter((each) => !each.conjugated).length < 2)
181559
+ return;
181560
+ const closure2 = individualClosureOf(decl, (name) => model.declarationOf(name));
181561
+ const label = decl.name ? `'${decl.name}'` : `This '${kindLabel2(decl)}'`;
181562
+ if (closure2.direct.length > 1) {
181563
+ accept(severity("SSM041", "error"), DIAGNOSTIC_MESSAGES.SSM041_INDIVIDUAL_MULTIPLE_DEFINITIONS(label, closure2.direct[0].text, closure2.direct[1].text), {
181564
+ node: decl,
181565
+ code: "SSM041",
181566
+ relatedInformation: declarationSite(closure2.direct[1].node, closure2.direct[1].text)
181567
+ });
181568
+ return;
181569
+ }
181570
+ if (explicit && closure2.definitions.length === 0 && closure2.complete) {
181571
+ accept(severity("SSM042", "error"), DIAGNOSTIC_MESSAGES.SSM042_INDIVIDUAL_WITHOUT_DEFINITION(label), { node: decl, code: "SSM042" });
181227
181572
  }
181228
181573
  }
181229
181574
  // REQ-390 — SSM017: a redefining feature narrows the feature it redefines, so
@@ -181553,8 +181898,9 @@ ${baseIndent}}`;
181553
181898
  // SysML usage kind IS an OccurrenceUsage (part, item, action, state, port,
181554
181899
  // connection, case, …) while the data-valued ones are few and closed: an
181555
181900
  // 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"]);
181901
+ // neither of which has a life to carve up. issue #162 — SSM040 judges an
181902
+ // `individual` against the same list, so the two share one spelling of it.
181903
+ static NON_OCCURRENCE_OWNER_TYPES = NON_OCCURRENCE_DECL_TYPES;
181558
181904
  // REQ-160 — OMG SysML v2 §8.2.2.9 (Occurrences) with the Kernel Semantic Library
181559
181905
  // `Occurrences::TimeSlice` / `Occurrences::Snapshot`:
181560
181906
  //
@@ -181570,7 +181916,7 @@ ${baseIndent}}`;
181570
181916
  // without resolving a single cross-reference.
181571
181917
  checkOccurrencePortions(node, accept) {
181572
181918
  for (const child of ast_utils_exports.streamAllContents(node)) {
181573
- const kind = portionKindOf2(child);
181919
+ const kind = portionKindOf(child);
181574
181920
  if (!kind)
181575
181921
  continue;
181576
181922
  const label = declLabel(child, kind);
@@ -181583,11 +181929,36 @@ ${baseIndent}}`;
181583
181929
  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
181930
  continue;
181585
181931
  }
181586
- if (kind === "timeslice" && portionKindOf2(owner) === "snapshot") {
181932
+ if (kind === "timeslice" && portionKindOf(owner) === "snapshot") {
181587
181933
  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
181934
  }
181589
181935
  }
181590
181936
  }
181937
+ // ══════════════════════════════════════════════════════════════════════
181938
+ // issue #162 — SSM040: `individual` presupposes an occurrence
181939
+ // ══════════════════════════════════════════════════════════════════════
181940
+ // OMG SysML v2 Part 1 §7.9.4 puts `isIndividual` on OccurrenceDefinition and
181941
+ // OccurrenceUsage, and nowhere else. An attribute is typed by a DataType and
181942
+ // has no life; a package is a namespace and is not a type at all. Writing
181943
+ // `individual` there claims an identity over time for something that has none.
181944
+ //
181945
+ // Structural: it reads the modifier and the declaration kind only, so it holds
181946
+ // with nothing resolved. The quick fix removes the keyword.
181947
+ // REQ-412 — SSM040: `individual` on a declaration that is not an occurrence
181948
+ checkIndividualDeclarations(node, accept) {
181949
+ for (const child of ast_utils_exports.streamAllContents(node)) {
181950
+ if (!isIndividualDecl(child) || isOccurrenceShapedDecl(child))
181951
+ continue;
181952
+ const name = child.name;
181953
+ const carrier = individualModifierCarrier(child);
181954
+ accept(severity("SSM040", "error"), DIAGNOSTIC_MESSAGES.SSM040_INDIVIDUAL_NOT_OCCURRENCE(name ? `'${name}'` : "this declaration", nonOccurrenceLabel(child)), {
181955
+ node: child,
181956
+ code: "SSM040",
181957
+ data: { individualModifier: true },
181958
+ ...carrier?.$cstNode ? { range: carrier.$cstNode.range } : {}
181959
+ });
181960
+ }
181961
+ }
181591
181962
  // REQ-328 — KSM008: a `filter` membership condition must be Boolean. Only a
181592
181963
  // *definitely* non-Boolean expression is flagged — a string or numeric/quantity
181593
181964
  // literal, or an arithmetic/range binary expression. A bare feature path is left
@@ -182621,7 +182992,7 @@ function specializationTargets4(node) {
182621
182992
  ...node.relationships ?? []
182622
182993
  ];
182623
182994
  for (const rel2 of rels) {
182624
- if (rel2.kind && SPECIALIZATION_KINDS5.has(rel2.kind))
182995
+ if (rel2.kind && SPECIALIZATION_KINDS6.has(rel2.kind))
182625
182996
  out.push(...rel2.targets);
182626
182997
  }
182627
182998
  return out;
@@ -183397,12 +183768,12 @@ function importSignature(imp) {
183397
183768
  const segments = imp.segs.map((seg) => `${seg.name ?? ""}${seg.star ? "*" : ""}${seg.recursive ? "**" : ""}`);
183398
183769
  return `${importVisibility(imp)} ${imp.head}::${segments.join("::")}${imp.alias ? ` as ${imp.alias}` : ""}`;
183399
183770
  }
183400
- var SPECIALIZATION_KINDS6 = /* @__PURE__ */ new Set([":>", ":>>", "specializes", "subsets", "redefines"]);
183771
+ var SPECIALIZATION_KINDS7 = /* @__PURE__ */ new Set([":>", ":>>", "specializes", "subsets", "redefines"]);
183401
183772
  function specializationTargets5(node) {
183402
183773
  const n2 = node;
183403
183774
  const out = [];
183404
183775
  for (const rel2 of [...n2.preRelationships ?? [], ...n2.relationships ?? []]) {
183405
- if (rel2.kind && SPECIALIZATION_KINDS6.has(rel2.kind))
183776
+ if (rel2.kind && SPECIALIZATION_KINDS7.has(rel2.kind))
183406
183777
  out.push(...rel2.targets ?? []);
183407
183778
  }
183408
183779
  return out;
@@ -183690,12 +184061,12 @@ function directImportEntries(imp, descriptions) {
183690
184061
  }
183691
184062
  return applyFilters(imp, selectMemberships(path10, form, descriptions), options);
183692
184063
  }
183693
- var SPECIALIZATION_KINDS7 = /* @__PURE__ */ new Set([":>", ":>>", "specializes", "subsets", "redefines"]);
184064
+ var SPECIALIZATION_KINDS8 = /* @__PURE__ */ new Set([":>", ":>>", "specializes", "subsets", "redefines"]);
183694
184065
  function specializationTargets6(node) {
183695
184066
  const value = node;
183696
184067
  const targets = [];
183697
184068
  for (const relationship of [...value.preRelationships ?? [], ...value.relationships ?? []]) {
183698
- if (relationship.kind && SPECIALIZATION_KINDS7.has(relationship.kind)) {
184069
+ if (relationship.kind && SPECIALIZATION_KINDS8.has(relationship.kind)) {
183699
184070
  targets.push(...relationship.targets ?? []);
183700
184071
  }
183701
184072
  }
@@ -184314,6 +184685,26 @@ ${indent}}`)]
184314
184685
  }
184315
184686
  });
184316
184687
  }
184688
+ if (code === "SSM040" && diagnostic.data && diagnostic.data.individualModifier === true) {
184689
+ const declText = document2.textDocument.getText(diagnostic.range);
184690
+ const match = /\bindividual\b[ \t]*/u.exec(declText);
184691
+ if (match) {
184692
+ const start2 = document2.textDocument.offsetAt(diagnostic.range.start) + match.index;
184693
+ actions.push({
184694
+ title: "Remove 'individual'",
184695
+ kind: import_vscode_languageserver18.CodeActionKind.QuickFix,
184696
+ diagnostics: [diagnostic],
184697
+ edit: {
184698
+ changes: {
184699
+ [uri]: [import_vscode_languageserver18.TextEdit.replace({
184700
+ start: document2.textDocument.positionAt(start2),
184701
+ end: document2.textDocument.positionAt(start2 + match[0].length)
184702
+ }, "")]
184703
+ }
184704
+ }
184705
+ });
184706
+ }
184707
+ }
184317
184708
  if (code === "STYL006") {
184318
184709
  const suffix = document2.textDocument.getText(diagnostic.range).replace(/\s+/gu, "");
184319
184710
  if (suffix === "::**") {
@@ -210237,7 +210628,7 @@ async function runExport(command) {
210237
210628
  }
210238
210629
 
210239
210630
  // src/main.ts
210240
- var VERSION2 = true ? "0.32.0" : "dev";
210631
+ var VERSION2 = true ? "0.33.0" : "dev";
210241
210632
  function display(file) {
210242
210633
  const rel2 = path9.relative(process.cwd(), file);
210243
210634
  return rel2 && !rel2.startsWith("..") ? rel2.split(path9.sep).join("/") : file;