@grexx/grexxlinter 0.2.1295 → 0.2.1372

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 CHANGED
@@ -14547,8 +14547,7 @@ function buildCoverageIndex(doc) {
14547
14547
  return {
14548
14548
  clauseCovered(casetype, field, modality, when) {
14549
14549
  if (!casetype || !field) return null;
14550
- const v = map.get(key(casetype, field, modality, when));
14551
- return v === void 0 ? null : v;
14550
+ return map.get(key(casetype, field, modality, when)) ?? null;
14552
14551
  },
14553
14552
  uncoveredCount: (casetype) => uncovered.get(casetype) ?? 0
14554
14553
  };
@@ -15039,7 +15038,8 @@ function lintDocument(ctx, input) {
15039
15038
  if (!emittedReqAny.has(key2)) {
15040
15039
  emittedReqAny.add(key2);
15041
15040
  const state = describeState(schema, g.err, input.value, ctx.registry.resolveRef);
15042
- push("required-field", g.instancePath, null, `missing at least one of: ${g.fields.join(", ")}${state ? ` ${state}` : ""}`);
15041
+ const stateSuffix = state ? ` ${state}` : "";
15042
+ push("required-field", g.instancePath, null, `missing at least one of: ${g.fields.join(", ")}${stateSuffix}`);
15043
15043
  }
15044
15044
  continue;
15045
15045
  }
@@ -15063,11 +15063,14 @@ function lintDocument(ctx, input) {
15063
15063
  }
15064
15064
  if (e.keyword === "type") {
15065
15065
  const actual = valueAtPointer(input.value, e.instancePath);
15066
- const recv = actual === null ? "null" : Array.isArray(actual) ? "array" : typeof actual;
15066
+ let recv = typeof actual;
15067
+ if (actual === null) recv = "null";
15068
+ else if (Array.isArray(actual)) recv = "array";
15067
15069
  let val = JSON.stringify(actual) ?? "";
15068
15070
  if (val.length > 60) val = `${val.slice(0, 57)}\u2026"`;
15069
15071
  const expected = String(e.params.type);
15070
- push("invalid-type", path, field, `expected ${expected} but received ${recv}${actual === void 0 ? "" : ` with value ${val}`}`);
15072
+ const withValue = actual === void 0 ? "" : ` with value ${val}`;
15073
+ push("invalid-type", path, field, `expected ${expected} but received ${recv}${withValue}`);
15071
15074
  continue;
15072
15075
  }
15073
15076
  const rule = ruleForKeyword(e.keyword);
@@ -15124,7 +15127,7 @@ function toJSOrError(doc) {
15124
15127
  // src/cli.ts
15125
15128
  var PARALLEL_THRESHOLD = 200;
15126
15129
  var MAX_WORKERS = 8;
15127
- var VERSION = true ? "0.2.1295" : "0.0.0-dev";
15130
+ var VERSION = true ? "0.2.1372" : "0.0.0-dev";
15128
15131
  function isNewer(latest, current) {
15129
15132
  const a = latest.split(".").map(Number);
15130
15133
  const b = current.split(".").map(Number);
@@ -15195,6 +15198,7 @@ function discover(paths, exclude) {
15195
15198
  for (const p of paths) walk(p);
15196
15199
  return files;
15197
15200
  }
15201
+ var KEY_SEP = String.fromCodePoint(0);
15198
15202
  var COLORS = { error: "\x1B[31m", warning: "\x1B[33m", info: "\x1B[36m" };
15199
15203
  var RESET = "\x1B[0m";
15200
15204
  var useColor = process.stdout.isTTY;
@@ -15205,7 +15209,8 @@ function printText(results, settings, quiet, errorsOnly) {
15205
15209
  const msgs = errorsOnly ? r.messages.filter((m) => m.severity === "error") : r.messages;
15206
15210
  if (quiet && msgs.length === 0) continue;
15207
15211
  const rel = r.file ? relative(process.cwd(), r.file) : "<input>";
15208
- const head = `${rel}${r.casetype ? ` (${r.casetype})` : ""}`;
15212
+ const casetypeTag = r.casetype ? ` (${r.casetype})` : "";
15213
+ const head = `${rel}${casetypeTag}`;
15209
15214
  if (msgs.length === 0) {
15210
15215
  if (!quiet) console.log(`${paint("ok", COLORS.info)} ${head}`);
15211
15216
  continue;
@@ -15218,9 +15223,12 @@ function printText(results, settings, quiet, errorsOnly) {
15218
15223
  }
15219
15224
  const s = summarize(results.filter((r) => !r.skipped));
15220
15225
  const skipped = results.filter((r) => r.skipped).length;
15226
+ const skippedNote = skipped ? `, ${skipped} skipped` : "";
15227
+ const errorsText = paint(`${s.errors} error(s)`, COLORS.error);
15228
+ const warningsText = paint(`${s.warnings} warning(s)`, COLORS.warning);
15221
15229
  console.log(
15222
15230
  `
15223
- ${s.files} file(s)${skipped ? `, ${skipped} skipped` : ""} \u2014 ${paint(`${s.errors} error(s)`, COLORS.error)}, ${paint(`${s.warnings} warning(s)`, COLORS.warning)}, ${s.infos} info(s) [fail-on: ${settings.failOn}]`
15231
+ ${s.files} file(s)${skippedNote} \u2014 ${errorsText}, ${warningsText}, ${s.infos} info(s) [fail-on: ${settings.failOn}]`
15224
15232
  );
15225
15233
  }
15226
15234
  function printReport(results, kind, errorsOnly) {
@@ -15243,7 +15251,7 @@ function printReport(results, kind, errorsOnly) {
15243
15251
  }
15244
15252
  const by = /* @__PURE__ */ new Map();
15245
15253
  for (const m of msgs) {
15246
- const key2 = `${m.casetype ?? "?"}\0${m.rule}\0${m.severity}\0${m.message}`;
15254
+ const key2 = [m.casetype ?? "?", m.rule, m.severity, m.message].join(KEY_SEP);
15247
15255
  const e = by.get(key2) ?? { count: 0, casetype: m.casetype ?? "?", severity: m.severity, message: m.message };
15248
15256
  e.count++;
15249
15257
  by.set(key2, e);
@@ -15363,5 +15371,5 @@ async function main() {
15363
15371
  }
15364
15372
  process.exit(summarize(results.filter((r) => !r.skipped)).exitCode);
15365
15373
  }
15366
- if (isMainThread) void main();
15374
+ if (isMainThread) await main();
15367
15375
  else runWorker();
package/lsp.js CHANGED
@@ -23616,8 +23616,7 @@ function buildCoverageIndex(doc) {
23616
23616
  return {
23617
23617
  clauseCovered(casetype, field, modality, when) {
23618
23618
  if (!casetype || !field) return null;
23619
- const v = map.get(key(casetype, field, modality, when));
23620
- return v === void 0 ? null : v;
23619
+ return map.get(key(casetype, field, modality, when)) ?? null;
23621
23620
  },
23622
23621
  uncoveredCount: (casetype) => uncovered.get(casetype) ?? 0
23623
23622
  };
@@ -23997,7 +23996,8 @@ function lintDocument(ctx2, input) {
23997
23996
  if (!emittedReqAny.has(key2)) {
23998
23997
  emittedReqAny.add(key2);
23999
23998
  const state = describeState(schema, g.err, input.value, ctx2.registry.resolveRef);
24000
- push("required-field", g.instancePath, null, `missing at least one of: ${g.fields.join(", ")}${state ? ` ${state}` : ""}`);
23999
+ const stateSuffix = state ? ` ${state}` : "";
24000
+ push("required-field", g.instancePath, null, `missing at least one of: ${g.fields.join(", ")}${stateSuffix}`);
24001
24001
  }
24002
24002
  continue;
24003
24003
  }
@@ -24021,11 +24021,14 @@ function lintDocument(ctx2, input) {
24021
24021
  }
24022
24022
  if (e.keyword === "type") {
24023
24023
  const actual = valueAtPointer(input.value, e.instancePath);
24024
- const recv = actual === null ? "null" : Array.isArray(actual) ? "array" : typeof actual;
24024
+ let recv = typeof actual;
24025
+ if (actual === null) recv = "null";
24026
+ else if (Array.isArray(actual)) recv = "array";
24025
24027
  let val = JSON.stringify(actual) ?? "";
24026
24028
  if (val.length > 60) val = `${val.slice(0, 57)}\u2026"`;
24027
24029
  const expected = String(e.params.type);
24028
- push("invalid-type", path, field, `expected ${expected} but received ${recv}${actual === void 0 ? "" : ` with value ${val}`}`);
24030
+ const withValue = actual === void 0 ? "" : ` with value ${val}`;
24031
+ push("invalid-type", path, field, `expected ${expected} but received ${recv}${withValue}`);
24029
24032
  continue;
24030
24033
  }
24031
24034
  const rule = ruleForKeyword(e.keyword);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grexx/grexxlinter",
3
- "version": "0.2.1295",
3
+ "version": "0.2.1372",
4
4
  "description": "Lint Grexx Studio casetype YAML against the studio JSON Schemas.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -250,6 +250,280 @@
250
250
  "title": "widget",
251
251
  "type": "object",
252
252
  "allOf": [
253
+ {
254
+ "$comment": "Shape of the legacy options blob for grids — the only structure it has, since widget.options is declared `additionalProperties: true`. Closed at every level: an unknown key is an additional-field finding. The key set and the types are the union observed over 1275 grid widgets (def-yamls-142 plus three real projects); where the stored spelling and the studio's mapper disagree, both are declared, because both are live.",
255
+ "if": {
256
+ "properties": {
257
+ "widgetType": {
258
+ "enum": [
259
+ "grid",
260
+ "grid-v2"
261
+ ]
262
+ }
263
+ },
264
+ "required": [
265
+ "widgetType"
266
+ ]
267
+ },
268
+ "then": {
269
+ "properties": {
270
+ "options": {
271
+ "type": "object",
272
+ "additionalProperties": false,
273
+ "properties": {
274
+ "type": {
275
+ "type": "string"
276
+ },
277
+ "usesCases": {
278
+ "type": "boolean"
279
+ },
280
+ "dataset": {
281
+ "type": "string"
282
+ },
283
+ "extraclasses": {
284
+ "$comment": "Extra CSS classes on the widget wrapper. No editor writes it; it rides through from the legacy designer.",
285
+ "type": "string"
286
+ },
287
+ "grid": {
288
+ "type": "object",
289
+ "additionalProperties": false,
290
+ "properties": {
291
+ "showHeader": {
292
+ "type": "boolean"
293
+ },
294
+ "title": {
295
+ "type": "string"
296
+ },
297
+ "showToolbar": {
298
+ "type": "boolean"
299
+ },
300
+ "showSimpleSearch": {
301
+ "type": "boolean"
302
+ },
303
+ "showAdvancedSearch": {
304
+ "type": "boolean"
305
+ },
306
+ "showLinenumbers": {
307
+ "type": "boolean"
308
+ },
309
+ "showColumnHeaders": {
310
+ "type": "boolean"
311
+ },
312
+ "showColumnSelector": {
313
+ "type": "boolean"
314
+ },
315
+ "showFooter": {
316
+ "type": "boolean"
317
+ },
318
+ "noFullCount": {
319
+ "type": "boolean"
320
+ },
321
+ "selectColumn": {
322
+ "type": "boolean"
323
+ },
324
+ "autoHeight": {
325
+ "type": "boolean"
326
+ },
327
+ "saveSearch": {
328
+ "type": "string"
329
+ },
330
+ "orderColumn": {
331
+ "type": "string"
332
+ },
333
+ "height": {
334
+ "$comment": "Every stored value is a string (\"640\"); the studio's mapper writes a number on edit.",
335
+ "type": [
336
+ "string",
337
+ "number"
338
+ ]
339
+ },
340
+ "pagination": {
341
+ "type": "object",
342
+ "additionalProperties": false,
343
+ "properties": {
344
+ "rowsPerPage": {
345
+ "type": [
346
+ "number",
347
+ "string"
348
+ ]
349
+ },
350
+ "inifiteScroll": {
351
+ "$comment": "Misspelled in the atalanta runtime that reads it — this is the wire format.",
352
+ "type": "boolean"
353
+ }
354
+ }
355
+ },
356
+ "gridAggregationRowType": {
357
+ "$comment": "Mirror of the first-class gridAggregationRowType; stored as an empty array on all but one of 475 occurrences, so both spellings are allowed.",
358
+ "type": [
359
+ "string",
360
+ "array"
361
+ ]
362
+ },
363
+ "gridAggregationRowPosition": {
364
+ "$comment": "Mirror of the first-class gridAggregationRowPosition; stored as an empty array, as above.",
365
+ "type": [
366
+ "string",
367
+ "array"
368
+ ]
369
+ }
370
+ }
371
+ },
372
+ "row": {
373
+ "type": "object",
374
+ "additionalProperties": false,
375
+ "properties": {
376
+ "clickHandler": {
377
+ "type": "string"
378
+ },
379
+ "clickHandlerColumnCase": {
380
+ "type": "string"
381
+ },
382
+ "rowHeight": {
383
+ "type": [
384
+ "string",
385
+ "number"
386
+ ]
387
+ },
388
+ "viewToOpen": {
389
+ "$comment": "Only read when clickHandler is viewHandler; the studio drops both keys when it is not.",
390
+ "type": "string"
391
+ },
392
+ "customViewModalClasses": {
393
+ "type": "string"
394
+ }
395
+ }
396
+ },
397
+ "subgrid": {
398
+ "type": "object",
399
+ "additionalProperties": false,
400
+ "properties": {
401
+ "enabled": {
402
+ "type": "boolean"
403
+ },
404
+ "height": {
405
+ "type": [
406
+ "string",
407
+ "number"
408
+ ]
409
+ }
410
+ }
411
+ },
412
+ "columns": {
413
+ "$comment": "Keyed by the dataset column's atalanta case id. On a case-converted grid the entry degrades to a caseId pointer at the gridColumn; on a grid that was never converted it keeps the full inline column settings instead, and those 2798 legacy entries are what the types below are read off. `size` stays untyped: it is a nested map whose own key set has no second source to check against.",
414
+ "type": "object",
415
+ "additionalProperties": {
416
+ "type": "object",
417
+ "additionalProperties": false,
418
+ "properties": {
419
+ "caseId": {
420
+ "type": "string"
421
+ },
422
+ "name": {
423
+ "type": "string"
424
+ },
425
+ "column": {
426
+ "type": "string"
427
+ },
428
+ "title": {
429
+ "type": "string"
430
+ },
431
+ "hidden": {
432
+ "type": "boolean"
433
+ },
434
+ "hideable": {
435
+ "type": "boolean"
436
+ },
437
+ "searchable": {
438
+ "type": "boolean"
439
+ },
440
+ "sortable": {
441
+ "type": "boolean"
442
+ },
443
+ "resizable": {
444
+ "type": "boolean"
445
+ },
446
+ "wordwrap": {
447
+ "type": "boolean"
448
+ },
449
+ "valueAsRowClass": {
450
+ "type": "boolean"
451
+ },
452
+ "render": {
453
+ "type": "string"
454
+ },
455
+ "order": {
456
+ "type": [
457
+ "integer",
458
+ "string"
459
+ ]
460
+ },
461
+ "clickHandler": {
462
+ "type": "string"
463
+ },
464
+ "clickHandlerColumnCase": {
465
+ "type": "string"
466
+ },
467
+ "aggregationOperation": {
468
+ "$comment": "Written here by the studio's mapper, but absent from every stored legacy entry — no observed value to type it from, so the key is accepted untyped."
469
+ },
470
+ "size": {
471
+ "type": "object"
472
+ }
473
+ }
474
+ }
475
+ },
476
+ "activities": {
477
+ "$comment": "Keyed by slot — addActivityId / editActivity / finishActivity / multiNN. Unlike columns these keep their full legacy field set alongside the caseId pointer, so every key here is observed and typed.",
478
+ "type": "object",
479
+ "additionalProperties": {
480
+ "type": "object",
481
+ "additionalProperties": false,
482
+ "properties": {
483
+ "caseId": {
484
+ "type": "string"
485
+ },
486
+ "activity": {
487
+ "type": "string"
488
+ },
489
+ "enabled": {
490
+ "type": "boolean"
491
+ },
492
+ "title": {
493
+ "type": "string"
494
+ },
495
+ "useActivityTitle": {
496
+ "type": "boolean"
497
+ },
498
+ "icon": {
499
+ "type": "string"
500
+ },
501
+ "type": {
502
+ "type": "string"
503
+ },
504
+ "checkRights": {
505
+ "type": "string"
506
+ },
507
+ "whenDoneRefreshType": {
508
+ "type": "string"
509
+ },
510
+ "breaker": {
511
+ "type": "boolean"
512
+ },
513
+ "order": {
514
+ "type": [
515
+ "integer",
516
+ "string"
517
+ ]
518
+ }
519
+ }
520
+ }
521
+ }
522
+ }
523
+ }
524
+ }
525
+ }
526
+ },
253
527
  {
254
528
  "if": {
255
529
  "properties": {