@grexx/grexxlinter 0.2.2716 → 0.2.2770
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/cli.js +19 -2
- package/lsp.js +18 -1
- package/package.json +1 -1
- package/schemas/.caserefs.json +5 -2
- package/schemas/mapping.schema.json +15 -0
- package/schemas/trigger.schema.json +17 -2
package/cli.js
CHANGED
|
@@ -15659,6 +15659,23 @@ function pushUncovered(push, coverage, casetype) {
|
|
|
15659
15659
|
const n = coverage.uncoveredCount(casetype);
|
|
15660
15660
|
if (n > 0) push("unknown-casetype", "", casetype, `${n} rule clause(s) for "${casetype}" are behaviour-only and not checked by the schema`);
|
|
15661
15661
|
}
|
|
15662
|
+
function isInactive(node) {
|
|
15663
|
+
return !!node && typeof node === "object" && node.inactive === true;
|
|
15664
|
+
}
|
|
15665
|
+
function underInactive(root, pointer) {
|
|
15666
|
+
if (isInactive(root)) return true;
|
|
15667
|
+
let cur = root;
|
|
15668
|
+
for (const raw of pointer.split("/").slice(1)) {
|
|
15669
|
+
if (cur == null || typeof cur !== "object") return false;
|
|
15670
|
+
cur = cur[raw.replaceAll("~1", "/").replaceAll("~0", "~")];
|
|
15671
|
+
if (isInactive(cur)) return true;
|
|
15672
|
+
}
|
|
15673
|
+
return false;
|
|
15674
|
+
}
|
|
15675
|
+
function dropInactive(messages, root) {
|
|
15676
|
+
if (isInactive(root)) return [];
|
|
15677
|
+
return messages.filter((m) => !underInactive(root, m.path));
|
|
15678
|
+
}
|
|
15662
15679
|
function dedupeMessages(messages) {
|
|
15663
15680
|
const seen = /* @__PURE__ */ new Set();
|
|
15664
15681
|
return messages.filter((m) => {
|
|
@@ -15690,7 +15707,7 @@ function lintDocument(ctx, input) {
|
|
|
15690
15707
|
});
|
|
15691
15708
|
}
|
|
15692
15709
|
if (settings.reportUncovered) pushUncovered(push, ctx.coverage, casetype);
|
|
15693
|
-
const deduped = dedupeMessages(messages);
|
|
15710
|
+
const deduped = dropInactive(dedupeMessages(messages), input.value);
|
|
15694
15711
|
const ok = !deduped.some((m) => meetsThreshold(m.severity, settings.failOn));
|
|
15695
15712
|
return { file: input.file, casetype, messages: deduped, skipped: false, ok };
|
|
15696
15713
|
}
|
|
@@ -15769,7 +15786,7 @@ function lintFiles(files, ctx, settings) {
|
|
|
15769
15786
|
// src/cli.ts
|
|
15770
15787
|
var PARALLEL_THRESHOLD = 200;
|
|
15771
15788
|
var MAX_WORKERS = 8;
|
|
15772
|
-
var VERSION = "0.2.
|
|
15789
|
+
var VERSION = "0.2.2770";
|
|
15773
15790
|
function isNewer(latest, current) {
|
|
15774
15791
|
const a = latest.split(".").map(Number);
|
|
15775
15792
|
const b = current.split(".").map(Number);
|
package/lsp.js
CHANGED
|
@@ -25608,6 +25608,23 @@ function pushUncovered(push, coverage, casetype) {
|
|
|
25608
25608
|
const n = coverage.uncoveredCount(casetype);
|
|
25609
25609
|
if (n > 0) push("unknown-casetype", "", casetype, `${n} rule clause(s) for "${casetype}" are behaviour-only and not checked by the schema`);
|
|
25610
25610
|
}
|
|
25611
|
+
function isInactive(node) {
|
|
25612
|
+
return !!node && typeof node === "object" && node.inactive === true;
|
|
25613
|
+
}
|
|
25614
|
+
function underInactive(root, pointer) {
|
|
25615
|
+
if (isInactive(root)) return true;
|
|
25616
|
+
let cur = root;
|
|
25617
|
+
for (const raw of pointer.split("/").slice(1)) {
|
|
25618
|
+
if (cur == null || typeof cur !== "object") return false;
|
|
25619
|
+
cur = cur[raw.replaceAll("~1", "/").replaceAll("~0", "~")];
|
|
25620
|
+
if (isInactive(cur)) return true;
|
|
25621
|
+
}
|
|
25622
|
+
return false;
|
|
25623
|
+
}
|
|
25624
|
+
function dropInactive(messages, root) {
|
|
25625
|
+
if (isInactive(root)) return [];
|
|
25626
|
+
return messages.filter((m) => !underInactive(root, m.path));
|
|
25627
|
+
}
|
|
25611
25628
|
function dedupeMessages(messages) {
|
|
25612
25629
|
const seen = /* @__PURE__ */ new Set();
|
|
25613
25630
|
return messages.filter((m) => {
|
|
@@ -25639,7 +25656,7 @@ function lintDocument(ctx2, input) {
|
|
|
25639
25656
|
});
|
|
25640
25657
|
}
|
|
25641
25658
|
if (settings2.reportUncovered) pushUncovered(push, ctx2.coverage, casetype);
|
|
25642
|
-
const deduped = dedupeMessages(messages);
|
|
25659
|
+
const deduped = dropInactive(dedupeMessages(messages), input.value);
|
|
25643
25660
|
const ok = !deduped.some((m) => meetsThreshold(m.severity, settings2.failOn));
|
|
25644
25661
|
return { file: input.file, casetype, messages: deduped, skipped: false, ok };
|
|
25645
25662
|
}
|
package/package.json
CHANGED
package/schemas/.caserefs.json
CHANGED
|
@@ -248,14 +248,17 @@
|
|
|
248
248
|
},
|
|
249
249
|
"simpleCondition": {
|
|
250
250
|
"leftField": [
|
|
251
|
-
"
|
|
251
|
+
"attribute",
|
|
252
|
+
"formfield",
|
|
253
|
+
"platformAttribute"
|
|
252
254
|
],
|
|
253
255
|
"leftActivityAttribute": [
|
|
254
256
|
"activityAttribute"
|
|
255
257
|
],
|
|
256
258
|
"rightField": [
|
|
257
259
|
"attribute",
|
|
258
|
-
"formfield"
|
|
260
|
+
"formfield",
|
|
261
|
+
"platformAttribute"
|
|
259
262
|
],
|
|
260
263
|
"rightActivityAttribute": [
|
|
261
264
|
"activityAttribute"
|
|
@@ -240,6 +240,21 @@
|
|
|
240
240
|
}
|
|
241
241
|
}
|
|
242
242
|
},
|
|
243
|
+
{
|
|
244
|
+
"$comment": "A mapping always names a destination. Which field carries it depends on toAttributeType (usersession -> toKey, everything else -> toAttribute), and the generated branches already require toKey for usersession and activityAttribute for taskAttribute -- but nothing requires the ordinary toAttribute, so a mapping with no destination at all linted clean. Zero findings across packages/schemas/def-yamls-142 and apps/backend/test/fixtures/compile-6685 (1837 active mappings).",
|
|
245
|
+
"anyOf": [
|
|
246
|
+
{
|
|
247
|
+
"required": [
|
|
248
|
+
"toAttribute"
|
|
249
|
+
]
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
"required": [
|
|
253
|
+
"toKey"
|
|
254
|
+
]
|
|
255
|
+
}
|
|
256
|
+
]
|
|
257
|
+
},
|
|
243
258
|
{
|
|
244
259
|
"if": {
|
|
245
260
|
"properties": {
|
|
@@ -120,7 +120,23 @@
|
|
|
120
120
|
],
|
|
121
121
|
"title": "trigger",
|
|
122
122
|
"type": "object",
|
|
123
|
+
"$comment": "Hand-maintained overlay (deep-merged by scripts/extend.mjs into extended/trigger.schema.json). A trigger always names an activity to run, whatever its `toTriggerType` -- see the allOf below. The manager exports this per toTriggerType value, but the `page` group's `when` is \"[To page] is not «empty» AND [To type] is \\\"page\\\"\", and condToSchema cannot express the not-empty conjunct (`!==` is outside EQ_OPS and `''` is in BAD_VALUES), so that one group is deferred and never reaches the schema. Stating it unconditionally covers `page`, and additionally covers a trigger with no `toTriggerType` at all -- which the per-value groups all miss, since each `if` requires the field to be present. Conditionals generated by packages/schemas/scripts/extend.mjs from rules/trigger.json.",
|
|
123
124
|
"allOf": [
|
|
125
|
+
{
|
|
126
|
+
"$comment": "Zero findings across packages/schemas/def-yamls-142 and apps/backend/test/fixtures/compile-6685 (659 active triggers).",
|
|
127
|
+
"anyOf": [
|
|
128
|
+
{
|
|
129
|
+
"required": [
|
|
130
|
+
"activityTo"
|
|
131
|
+
]
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"required": [
|
|
135
|
+
"activityTag"
|
|
136
|
+
]
|
|
137
|
+
}
|
|
138
|
+
]
|
|
139
|
+
},
|
|
124
140
|
{
|
|
125
141
|
"if": {
|
|
126
142
|
"properties": {
|
|
@@ -453,6 +469,5 @@
|
|
|
453
469
|
]
|
|
454
470
|
}
|
|
455
471
|
}
|
|
456
|
-
]
|
|
457
|
-
"$comment": "Conditionals generated by packages/schemas/scripts/extend.mjs from rules/trigger.json."
|
|
472
|
+
]
|
|
458
473
|
}
|