sysml-validate 0.15.0 → 0.15.1
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 +82 -4
- package/out/main.js.map +3 -3
- package/package.json +1 -1
- package/resources/sysml.dimension-table.json +1 -1
package/out/main.js
CHANGED
|
@@ -30760,6 +30760,9 @@ function isExhibitStateDecl(item) {
|
|
|
30760
30760
|
var ExitAction = "ExitAction";
|
|
30761
30761
|
var ExposeMember = "ExposeMember";
|
|
30762
30762
|
var ExposePath = "ExposePath";
|
|
30763
|
+
function isExposePath(item) {
|
|
30764
|
+
return reflection2.isInstance(item, ExposePath);
|
|
30765
|
+
}
|
|
30763
30766
|
var ExpressionDecl = "ExpressionDecl";
|
|
30764
30767
|
var FeatureDecl = "FeatureDecl";
|
|
30765
30768
|
function isFeatureDecl(item) {
|
|
@@ -58052,14 +58055,14 @@ function evaluateFilterCondition(node, metadataTypes, resolveRefs) {
|
|
|
58052
58055
|
return node.items.length === 1 ? evaluateFilterCondition(node.items[0], metadataTypes, resolveRefs) : void 0;
|
|
58053
58056
|
}
|
|
58054
58057
|
if (isBinExpr(node)) {
|
|
58055
|
-
if (
|
|
58058
|
+
if (CONJUNCTION_OPERATORS.has(node.op)) {
|
|
58056
58059
|
const left = evaluateFilterCondition(node.left, metadataTypes, resolveRefs);
|
|
58057
58060
|
const right = evaluateFilterCondition(node.right, metadataTypes, resolveRefs);
|
|
58058
58061
|
if (left === false || right === false)
|
|
58059
58062
|
return false;
|
|
58060
58063
|
return left === void 0 || right === void 0 ? void 0 : true;
|
|
58061
58064
|
}
|
|
58062
|
-
if (
|
|
58065
|
+
if (DISJUNCTION_OPERATORS.has(node.op)) {
|
|
58063
58066
|
const left = evaluateFilterCondition(node.left, metadataTypes, resolveRefs);
|
|
58064
58067
|
const right = evaluateFilterCondition(node.right, metadataTypes, resolveRefs);
|
|
58065
58068
|
if (left === true || right === true)
|
|
@@ -58070,6 +58073,42 @@ function evaluateFilterCondition(node, metadataTypes, resolveRefs) {
|
|
|
58070
58073
|
}
|
|
58071
58074
|
return void 0;
|
|
58072
58075
|
}
|
|
58076
|
+
var CONJUNCTION_OPERATORS = /* @__PURE__ */ new Set(["and", "&"]);
|
|
58077
|
+
var DISJUNCTION_OPERATORS = /* @__PURE__ */ new Set(["or", "|"]);
|
|
58078
|
+
function undecidableFilterCondition(condition) {
|
|
58079
|
+
if (!condition)
|
|
58080
|
+
return void 0;
|
|
58081
|
+
if (isSelfClassifyExpr(condition)) {
|
|
58082
|
+
return condition.op === "@" || condition.op === "@@" ? void 0 : { node: condition, construct: `the '${condition.op}' classification operator` };
|
|
58083
|
+
}
|
|
58084
|
+
if (isNotExpr(condition) && condition.operand) {
|
|
58085
|
+
return undecidableFilterCondition(condition.operand);
|
|
58086
|
+
}
|
|
58087
|
+
if (condition.$type === "NotExpr")
|
|
58088
|
+
return void 0;
|
|
58089
|
+
if (isParenExpr(condition)) {
|
|
58090
|
+
return condition.items.length === 1 ? undecidableFilterCondition(condition.items[0]) : { node: condition, construct: "a parenthesized expression list" };
|
|
58091
|
+
}
|
|
58092
|
+
if (isBinExpr(condition)) {
|
|
58093
|
+
if (CONJUNCTION_OPERATORS.has(condition.op) || DISJUNCTION_OPERATORS.has(condition.op)) {
|
|
58094
|
+
return undecidableFilterCondition(condition.left) ?? undecidableFilterCondition(condition.right);
|
|
58095
|
+
}
|
|
58096
|
+
return { node: condition, construct: `the '${condition.op}' operator` };
|
|
58097
|
+
}
|
|
58098
|
+
return { node: condition, construct: describeFilterExpr(condition) };
|
|
58099
|
+
}
|
|
58100
|
+
function describeFilterExpr(node) {
|
|
58101
|
+
if (isPostfixOp(node)) {
|
|
58102
|
+
if ((node.dot || node.select) && node.field)
|
|
58103
|
+
return `the '.${node.field}' feature access`;
|
|
58104
|
+
if (node.arrow && node.invoke)
|
|
58105
|
+
return `the '->${node.invoke}' invocation`;
|
|
58106
|
+
return "this postfix expression";
|
|
58107
|
+
}
|
|
58108
|
+
if (isPathExpr(node))
|
|
58109
|
+
return "a plain feature reference";
|
|
58110
|
+
return "this expression form";
|
|
58111
|
+
}
|
|
58073
58112
|
function attachedMetadataTypes(node, resolveRefs) {
|
|
58074
58113
|
const siblings = node.$container?.members;
|
|
58075
58114
|
if (!Array.isArray(siblings))
|
|
@@ -58713,6 +58752,13 @@ var DIAGNOSTIC_MESSAGES = {
|
|
|
58713
58752
|
// implicit-redefinition resolution this validator does not yet model.
|
|
58714
58753
|
RES017_DUPLICATE_MEMBER: (name) => `'${name}' is already declared in this namespace. Members must be distinguishable by name \u2014 rename or remove the duplicate.`,
|
|
58715
58754
|
RES017_DUPLICATE_SHORT_NAME: (name) => `Short name '<${name}>' is already used in this namespace. Members must be distinguishable \u2014 rename the short name.`,
|
|
58755
|
+
// issue #102 — REQ-387. The filter evaluator (`import-visibility.ts`,
|
|
58756
|
+
// `evaluateFilterCondition`) decides metadata-presence tests and the Boolean
|
|
58757
|
+
// operators over them; every other form fails OPEN, keeping the member. Failing
|
|
58758
|
+
// open is the right default — under-importing would manufacture spurious
|
|
58759
|
+
// RES001s — but an unevaluated filter produces a scope or view that looks
|
|
58760
|
+
// authoritative and is not, so the fail-open is stated rather than assumed.
|
|
58761
|
+
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.`,
|
|
58716
58762
|
// REQ-007 — SysML v1 → v2 migration guardrail.
|
|
58717
58763
|
MIG001_V1_KEYWORD: (keyword, v2, note) => `'${keyword}' is a SysML v1 construct, not a SysML v2 keyword. ${note} Use '${v2}'.`,
|
|
58718
58764
|
MIG002_V1_STEREOTYPE_KNOWN: (stereotype, v2, note) => `SysML v2 has no stereotypes. ${note} Replace \xAB${stereotype}\xBB with '${v2}'.`,
|
|
@@ -60567,6 +60613,7 @@ ${baseIndent}}`;
|
|
|
60567
60613
|
checkCrossReferences(node, accept) {
|
|
60568
60614
|
const index = this.buildIndex();
|
|
60569
60615
|
const imports = [];
|
|
60616
|
+
const exposePaths = [];
|
|
60570
60617
|
const decls = [];
|
|
60571
60618
|
const verifyStmts = [];
|
|
60572
60619
|
const satisfyStmts = [];
|
|
@@ -60578,7 +60625,9 @@ ${baseIndent}}`;
|
|
|
60578
60625
|
const path10 = importedPath(child);
|
|
60579
60626
|
if (alias && path10 && importWildcard(child) === "none")
|
|
60580
60627
|
aliasMap.set(alias, path10);
|
|
60581
|
-
} else if (
|
|
60628
|
+
} else if (isExposePath(child))
|
|
60629
|
+
exposePaths.push(child);
|
|
60630
|
+
else if (isVerifyStmt(child))
|
|
60582
60631
|
verifyStmts.push(child);
|
|
60583
60632
|
else if (isSatisfyStmt(child))
|
|
60584
60633
|
satisfyStmts.push(child);
|
|
@@ -60594,6 +60643,7 @@ ${baseIndent}}`;
|
|
|
60594
60643
|
this.checkPrivateImports(imports, index, accept);
|
|
60595
60644
|
this.checkPrivateWildcardReferences(node, imports, index, accept);
|
|
60596
60645
|
this.checkImportCycles(imports, index, accept);
|
|
60646
|
+
this.checkUnevaluatedFilters(imports, exposePaths, accept);
|
|
60597
60647
|
if (sysmlDiagnosticSettings.unusedImports !== "off") {
|
|
60598
60648
|
this.checkUnusedImports(node, imports, index, sysmlDiagnosticSettings.unusedImports, accept);
|
|
60599
60649
|
}
|
|
@@ -61212,6 +61262,34 @@ ${baseIndent}}`;
|
|
|
61212
61262
|
}
|
|
61213
61263
|
return false;
|
|
61214
61264
|
}
|
|
61265
|
+
/**
|
|
61266
|
+
* REQ-387 — RES018: an `import` or `expose` filter the metadata-filter
|
|
61267
|
+
* evaluator cannot decide (issue #102).
|
|
61268
|
+
*
|
|
61269
|
+
* The evaluator keeps a member it cannot decide, so an unevaluated filter
|
|
61270
|
+
* silently contributes the members it was written to exclude — a scope or a
|
|
61271
|
+
* view that reads as authoritative and is not. Failing open stays (narrowing
|
|
61272
|
+
* on a guess would manufacture unresolved-name errors); what changes is that
|
|
61273
|
+
* the model now says so at the filter that is not applied.
|
|
61274
|
+
*
|
|
61275
|
+
* Default severity is `info` rather than a warning: the model is legal and the
|
|
61276
|
+
* limitation is this evaluator's, not the author's. Teams that want an
|
|
61277
|
+
* unevaluated filter to break a build raise it per code through
|
|
61278
|
+
* `sysml.validation.severities` (REQ-240).
|
|
61279
|
+
*/
|
|
61280
|
+
checkUnevaluatedFilters(imports, exposePaths, accept) {
|
|
61281
|
+
const report = (condition, subject) => {
|
|
61282
|
+
const undecidable = undecidableFilterCondition(condition);
|
|
61283
|
+
if (!undecidable)
|
|
61284
|
+
return;
|
|
61285
|
+
accept(severity("RES018", "info"), DIAGNOSTIC_MESSAGES.RES018_UNEVALUATED_FILTER(subject, undecidable.construct), { node: undecidable.node, code: "RES018" });
|
|
61286
|
+
};
|
|
61287
|
+
for (const imp of imports)
|
|
61288
|
+
for (const filter3 of imp.filters)
|
|
61289
|
+
report(filter3.condition, "Import");
|
|
61290
|
+
for (const path10 of exposePaths)
|
|
61291
|
+
report(path10.condition, "Expose");
|
|
61292
|
+
}
|
|
61215
61293
|
// REQ-324 — RES009 unused import (configurable, OFF by default)
|
|
61216
61294
|
checkUnusedImports(root3, imports, index, level, accept) {
|
|
61217
61295
|
if (imports.length === 0)
|
|
@@ -69031,7 +69109,7 @@ async function runValidation(command) {
|
|
|
69031
69109
|
}
|
|
69032
69110
|
|
|
69033
69111
|
// src/main.ts
|
|
69034
|
-
var VERSION2 = true ? "0.15.
|
|
69112
|
+
var VERSION2 = true ? "0.15.1" : "dev";
|
|
69035
69113
|
async function main(argv) {
|
|
69036
69114
|
const command = parseArgs(argv);
|
|
69037
69115
|
if (command.kind === "help") {
|