sysml-validate 0.15.2 → 0.15.3
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
|
@@ -45489,8 +45489,17 @@ var SysMLGrammar = () => loadedSysMLGrammar ?? (loadedSysMLGrammar = loadGrammar
|
|
|
45489
45489
|
"$type": "Group",
|
|
45490
45490
|
"elements": [
|
|
45491
45491
|
{
|
|
45492
|
-
"$type": "
|
|
45493
|
-
"
|
|
45492
|
+
"$type": "Alternatives",
|
|
45493
|
+
"elements": [
|
|
45494
|
+
{
|
|
45495
|
+
"$type": "Keyword",
|
|
45496
|
+
"value": "."
|
|
45497
|
+
},
|
|
45498
|
+
{
|
|
45499
|
+
"$type": "Keyword",
|
|
45500
|
+
"value": "::"
|
|
45501
|
+
}
|
|
45502
|
+
]
|
|
45494
45503
|
},
|
|
45495
45504
|
{
|
|
45496
45505
|
"$type": "Assignment",
|
|
@@ -58759,6 +58768,15 @@ var DIAGNOSTIC_MESSAGES = {
|
|
|
58759
58768
|
// RES001s — but an unevaluated filter produces a scope or view that looks
|
|
58760
58769
|
// authoritative and is not, so the fail-open is stated rather than assumed.
|
|
58761
58770
|
RES018_UNEVALUATED_FILTER: (subject, construct) => `${subject} filter is not evaluated: ${construct} is outside the metadata-filter evaluator, which decides '@'/'@@' metadata tests combined with 'not', 'and'/'&', and 'or'/'|'. The filter fails open \u2014 it is treated as pass-through and removes nothing.`,
|
|
58771
|
+
// REQ-389 — Namespace qualification versus feature chaining in every written path
|
|
58772
|
+
// issue #213 — the KerML textual BNF binds `::` tighter than `.`: each
|
|
58773
|
+
// dot-separated link of a FeatureChain is a complete QualifiedName, and only
|
|
58774
|
+
// a Feature can be an `OwnedFeatureChaining::chainingFeature`. A Definition
|
|
58775
|
+
// specializes Classifier, not Feature, so it can never sit on the LEFT of a
|
|
58776
|
+
// dot. Our permissive scoping resolves the dotted form anyway (a definition
|
|
58777
|
+
// is a Type, hence a Namespace), which is exactly why it needs saying: the
|
|
58778
|
+
// Pilot implementation refuses the same text at linking time.
|
|
58779
|
+
RES019_DEFINITION_IN_FEATURE_CHAIN: (segment, member) => `'${segment}' is a definition, not a usage, so '${member}' is reached through it with '::' rather than '.'. Only a feature can be chained with '.' (KerML FeatureChain).`,
|
|
58762
58780
|
// REQ-007 — SysML v1 → v2 migration guardrail.
|
|
58763
58781
|
MIG001_V1_KEYWORD: (keyword, v2, note) => `'${keyword}' is a SysML v1 construct, not a SysML v2 keyword. ${note} Use '${v2}'.`,
|
|
58764
58782
|
MIG002_V1_STEREOTYPE_KNOWN: (stereotype, v2, note) => `SysML v2 has no stereotypes. ${note} Replace \xAB${stereotype}\xBB with '${v2}'.`,
|
|
@@ -59169,7 +59187,31 @@ var FeaturePathResolver = class {
|
|
|
59169
59187
|
}
|
|
59170
59188
|
// REQ-220/317 — resolve every independently clickable/diagnosable segment.
|
|
59171
59189
|
resolve(node) {
|
|
59172
|
-
|
|
59190
|
+
return this.resolveSegments(node, this.segmentsOf(node));
|
|
59191
|
+
}
|
|
59192
|
+
// REQ-389 — Namespace qualification versus feature chaining in every written path
|
|
59193
|
+
// issue #213 — a `perform` / `exhibit` target is stored as `name` plus an
|
|
59194
|
+
// untyped `chainSegs` array, so `A::b`, `A.b` and `A.b::c` all collapse to the
|
|
59195
|
+
// same AST and the separator rule is unenforceable from it. The CST still
|
|
59196
|
+
// carries the separators verbatim; read the path back off it and resolve it
|
|
59197
|
+
// exactly as an expression path is resolved.
|
|
59198
|
+
resolveDeclarationPath(node) {
|
|
59199
|
+
return this.resolveSegments(node, this.declarationSegmentsOf(node));
|
|
59200
|
+
}
|
|
59201
|
+
// REQ-389 — Namespace qualification versus feature chaining in every written path
|
|
59202
|
+
// issue #213 — a connector end keeps its whole path in ONE datatype-string
|
|
59203
|
+
// property (`ConnectorEnd.path`, a `RelationPath`), so there is no `chainSegs`
|
|
59204
|
+
// list to read at all. Resolve it off that property's CST span instead; the
|
|
59205
|
+
// separator rule is the same one, because a connector end reaches the world
|
|
59206
|
+
// through the same OwnedReferenceSubsetting as `perform` and `exhibit`.
|
|
59207
|
+
resolvePropertyPath(node, property3) {
|
|
59208
|
+
const cst = node.$cstNode;
|
|
59209
|
+
const propertyNode = cst ? grammar_utils_exports.findNodeForProperty(cst, property3) : void 0;
|
|
59210
|
+
if (!cst || !propertyNode)
|
|
59211
|
+
return { segments: [] };
|
|
59212
|
+
return this.resolveSegments(node, this.segmentsInSpan(cst, propertyNode.offset, propertyNode.end));
|
|
59213
|
+
}
|
|
59214
|
+
resolveSegments(node, segments) {
|
|
59173
59215
|
if (segments.length === 0)
|
|
59174
59216
|
return { segments };
|
|
59175
59217
|
const root3 = ast_utils_exports.getDocument(node).parseResult.value;
|
|
@@ -59218,6 +59260,61 @@ var FeaturePathResolver = class {
|
|
|
59218
59260
|
}
|
|
59219
59261
|
return segments;
|
|
59220
59262
|
}
|
|
59263
|
+
// REQ-389 — Namespace qualification versus feature chaining in every written path
|
|
59264
|
+
// issue #213 — the path of a reference-form declaration (`perform A::b.c;`,
|
|
59265
|
+
// `exhibit VehicleStates::operating;`) spans the `name` property through the
|
|
59266
|
+
// last `chainSegs` element. Everything after it (a `redefines` tail, a typing,
|
|
59267
|
+
// a body) belongs to other properties and must not be read as path segments,
|
|
59268
|
+
// so the CST leaves are taken only from that span.
|
|
59269
|
+
declarationSegmentsOf(node) {
|
|
59270
|
+
const cst = node.$cstNode;
|
|
59271
|
+
if (!cst)
|
|
59272
|
+
return [];
|
|
59273
|
+
const nameNode = grammar_utils_exports.findNodeForProperty(cst, "name");
|
|
59274
|
+
if (!nameNode)
|
|
59275
|
+
return [];
|
|
59276
|
+
const chainNodes = grammar_utils_exports.findNodesForProperty(cst, "chainSegs");
|
|
59277
|
+
const end = chainNodes.length > 0 ? chainNodes[chainNodes.length - 1].end : nameNode.end;
|
|
59278
|
+
return this.segmentsInSpan(cst, nameNode.offset, end);
|
|
59279
|
+
}
|
|
59280
|
+
/** The path segments spelled between two offsets of `cst`, separators retained.
|
|
59281
|
+
* `$` is the root-namespace GlobalQualification prefix and carries no segment;
|
|
59282
|
+
* a `RelationSegment`'s own `[n]` multiplicity addresses the segment it follows
|
|
59283
|
+
* (`engine[2]`) and is likewise not one, so bracketed text is skipped whole. */
|
|
59284
|
+
segmentsInSpan(cst, from, to) {
|
|
59285
|
+
const segments = [];
|
|
59286
|
+
let separator;
|
|
59287
|
+
let bracketDepth = 0;
|
|
59288
|
+
for (const leaf of cst_utils_exports.flattenCst(cst)) {
|
|
59289
|
+
if (leaf.offset < from)
|
|
59290
|
+
continue;
|
|
59291
|
+
if (leaf.end > to)
|
|
59292
|
+
break;
|
|
59293
|
+
if (leaf.text === "[") {
|
|
59294
|
+
bracketDepth += 1;
|
|
59295
|
+
continue;
|
|
59296
|
+
}
|
|
59297
|
+
if (leaf.text === "]") {
|
|
59298
|
+
bracketDepth = Math.max(0, bracketDepth - 1);
|
|
59299
|
+
continue;
|
|
59300
|
+
}
|
|
59301
|
+
if (bracketDepth > 0)
|
|
59302
|
+
continue;
|
|
59303
|
+
if (leaf.text === "$")
|
|
59304
|
+
continue;
|
|
59305
|
+
if (leaf.text === "." || leaf.text === "::") {
|
|
59306
|
+
separator = leaf.text;
|
|
59307
|
+
continue;
|
|
59308
|
+
}
|
|
59309
|
+
segments.push({
|
|
59310
|
+
text: canonicalEscapedName(leaf.text),
|
|
59311
|
+
separator: segments.length === 0 ? void 0 : separator,
|
|
59312
|
+
cst: leaf
|
|
59313
|
+
});
|
|
59314
|
+
separator = void 0;
|
|
59315
|
+
}
|
|
59316
|
+
return segments;
|
|
59317
|
+
}
|
|
59221
59318
|
resolveRoot(node, name, snapshot) {
|
|
59222
59319
|
if (name === "self" || name === "this" || name === "that") {
|
|
59223
59320
|
for (let owner = node.$container; owner; owner = owner.$container) {
|
|
@@ -59408,6 +59505,28 @@ var FeaturePathResolver = class {
|
|
|
59408
59505
|
}
|
|
59409
59506
|
};
|
|
59410
59507
|
|
|
59508
|
+
// ../language-server/out/src/services/namespace-kind.js
|
|
59509
|
+
var KERML_CLASSIFIER_DECL_TYPES = /* @__PURE__ */ new Set([
|
|
59510
|
+
"AssociationDecl",
|
|
59511
|
+
"BehaviorDecl",
|
|
59512
|
+
"ClassDecl",
|
|
59513
|
+
"ClassifierDecl",
|
|
59514
|
+
"DatatypeDecl",
|
|
59515
|
+
"FunctionDecl",
|
|
59516
|
+
"InteractionDecl",
|
|
59517
|
+
"MetaclassDecl",
|
|
59518
|
+
"PredicateDecl",
|
|
59519
|
+
"StructDecl",
|
|
59520
|
+
"TypeDecl"
|
|
59521
|
+
]);
|
|
59522
|
+
function isNamespaceOnlyDecl(node) {
|
|
59523
|
+
if (isPackage(node) || node.$type === "NamespaceDecl" || node.$type === "BareDefDecl")
|
|
59524
|
+
return true;
|
|
59525
|
+
if (KERML_CLASSIFIER_DECL_TYPES.has(node.$type))
|
|
59526
|
+
return true;
|
|
59527
|
+
return node.isDef === true;
|
|
59528
|
+
}
|
|
59529
|
+
|
|
59411
59530
|
// ../language-server/out/src/services/validator.js
|
|
59412
59531
|
var severityOverrides = {};
|
|
59413
59532
|
function setSeverityOverrides(overrides) {
|
|
@@ -59419,6 +59538,9 @@ function severity(code, defaultSeverity) {
|
|
|
59419
59538
|
function isLibraryDocument2(node) {
|
|
59420
59539
|
return isLibraryDocument(ast_utils_exports.getDocument(node));
|
|
59421
59540
|
}
|
|
59541
|
+
function isDefinitionOnlyNode(node) {
|
|
59542
|
+
return !isPackage(node) && isNamespaceOnlyDecl(node);
|
|
59543
|
+
}
|
|
59422
59544
|
var TABLE_4_ESCAPES = /* @__PURE__ */ new Set(['"', "'", "\\", "b", "f", "t", "n"]);
|
|
59423
59545
|
var IDENT_START = /[\p{L}_]/u;
|
|
59424
59546
|
var IDENT_PART = /[\p{L}\p{N}_]/u;
|
|
@@ -59601,6 +59723,53 @@ var SysmlValidator = class _SysmlValidator {
|
|
|
59601
59723
|
data: { featurePathSegment: true }
|
|
59602
59724
|
});
|
|
59603
59725
|
}
|
|
59726
|
+
// REQ-389 — Namespace qualification versus feature chaining in every written path
|
|
59727
|
+
// issue #213 — RES019: `::` binds tighter than `.`. Each dot-separated link of
|
|
59728
|
+
// a KerML FeatureChain is a complete QualifiedName, and an
|
|
59729
|
+
// `OwnedFeatureChaining::chainingFeature` is scoped to `[SysML::Feature|…]`,
|
|
59730
|
+
// so only a USAGE may sit on the left of a dot; a Definition specializes
|
|
59731
|
+
// Classifier and a package is a plain Namespace. `perform`, `exhibit` and
|
|
59732
|
+
// every connector end reach the world through the same
|
|
59733
|
+
// OwnedReferenceSubsetting, so one rule governs them all. This extension's
|
|
59734
|
+
// permissive scoping resolves the dotted form regardless (a definition IS a
|
|
59735
|
+
// Namespace), which is precisely why it is worth a warning rather than
|
|
59736
|
+
// silence: the Pilot implementation refuses the same text at LINKING time, so
|
|
59737
|
+
// the model is not portable. A warning, never an error — the text is
|
|
59738
|
+
// well-formed here and the fix is mechanical.
|
|
59739
|
+
checkChainSeparators(node, accept) {
|
|
59740
|
+
const chainSegs = node.chainSegs;
|
|
59741
|
+
if (!Array.isArray(chainSegs) || chainSegs.length === 0)
|
|
59742
|
+
return;
|
|
59743
|
+
this.reportChainSeparators(node, this.featurePaths.resolveDeclarationPath(node).segments, accept);
|
|
59744
|
+
}
|
|
59745
|
+
// REQ-389 — issue #213. A connector end (`connect`, `flow`, `bind`,
|
|
59746
|
+
// `succession`, `interface`, `allocate`, the transition ends) keeps its whole
|
|
59747
|
+
// path in one `RelationPath` datatype string, so there is no `chainSegs` list —
|
|
59748
|
+
// but it reaches its target through the same OwnedReferenceSubsetting as
|
|
59749
|
+
// `perform` and `exhibit`, and the rule does not change with the statement that
|
|
59750
|
+
// carries it. `reference` is the `references` / `::>` tail, which is a second
|
|
59751
|
+
// OwnedReferenceSubsetting on the same end and is judged the same way.
|
|
59752
|
+
checkConnectorEndSeparators(node, accept) {
|
|
59753
|
+
for (const property3 of ["path", "reference"]) {
|
|
59754
|
+
const text = node[property3];
|
|
59755
|
+
if (typeof text !== "string" || !text.includes("."))
|
|
59756
|
+
continue;
|
|
59757
|
+
this.reportChainSeparators(node, this.featurePaths.resolvePropertyPath(node, property3).segments, accept);
|
|
59758
|
+
}
|
|
59759
|
+
}
|
|
59760
|
+
/** RES019 for one resolved path: the first non-final link that is chained with
|
|
59761
|
+
* `.` from something that can never be a Feature. */
|
|
59762
|
+
reportChainSeparators(node, segments, accept) {
|
|
59763
|
+
for (let index = 0; index + 1 < segments.length; index += 1) {
|
|
59764
|
+
if (segments[index + 1].separator !== ".")
|
|
59765
|
+
continue;
|
|
59766
|
+
const owner = segments[index].target;
|
|
59767
|
+
if (!owner || !isDefinitionOnlyNode(owner))
|
|
59768
|
+
continue;
|
|
59769
|
+
accept(severity("RES019", "warning"), DIAGNOSTIC_MESSAGES.RES019_DEFINITION_IN_FEATURE_CHAIN(segments[index].text, segments[index + 1].text), { node, range: segments[index].cst.range, code: "RES019" });
|
|
59770
|
+
return;
|
|
59771
|
+
}
|
|
59772
|
+
}
|
|
59604
59773
|
// REQ-169, REQ-329 — SSM001 def/usage mismatch for parts
|
|
59605
59774
|
checkPartDecl(node, accept) {
|
|
59606
59775
|
if (!node.isDef && node.name && /^[A-Z]/.test(node.name)) {
|
|
@@ -61465,6 +61634,11 @@ ${baseIndent}}`;
|
|
|
61465
61634
|
Document: this.checkDocument.bind(this),
|
|
61466
61635
|
PartDecl: this.checkPartDecl.bind(this),
|
|
61467
61636
|
PathExpr: this.checkPathExpr.bind(this),
|
|
61637
|
+
// issue #213 — RES019: the `::` vs `.` rule on the reference-form
|
|
61638
|
+
// declarations that reach their target through OwnedReferenceSubsetting.
|
|
61639
|
+
PerformStmt: this.checkChainSeparators.bind(this),
|
|
61640
|
+
ExhibitStateDecl: this.checkChainSeparators.bind(this),
|
|
61641
|
+
ConnectorEnd: this.checkConnectorEndSeparators.bind(this),
|
|
61468
61642
|
RequirementDecl: this.checkRequirementDecl.bind(this),
|
|
61469
61643
|
AttributeDecl: this.checkAttributeDecl.bind(this),
|
|
61470
61644
|
ConstraintDecl: this.checkConstraintDecl.bind(this),
|
|
@@ -69105,7 +69279,7 @@ async function runValidation(command) {
|
|
|
69105
69279
|
}
|
|
69106
69280
|
|
|
69107
69281
|
// src/main.ts
|
|
69108
|
-
var VERSION2 = true ? "0.15.
|
|
69282
|
+
var VERSION2 = true ? "0.15.3" : "dev";
|
|
69109
69283
|
async function main(argv) {
|
|
69110
69284
|
const command = parseArgs(argv);
|
|
69111
69285
|
if (command.kind === "help") {
|