|
| 1 | +--- |
| 2 | +"@objectstack/lint": minor |
| 3 | +--- |
| 4 | + |
| 5 | +feat(lint): the react-page publish gate PARSES `ChartAggregateSchema` instead of re-deriving it (#5020) |
| 6 | + |
| 7 | +`<ObjectChart aggregate={{…}}>` is judged at publish time by |
| 8 | +`validate-react-page-props`. That gate used to RE-DERIVE the aggregate's |
| 9 | +declaration: a local `CHART_FUNCTIONS` copy of the function vocabulary and a |
| 10 | +hand-written twin of the schema's count/field refinement. Two implementations of |
| 11 | +one contract, each free to drift — and, because unknown-key handling is a |
| 12 | +property of a **parse** rather than of a list of `if`s, a gate with no |
| 13 | +unknown-key check at all. The rule now calls `ChartAggregateSchema.safeParse()` |
| 14 | +on a statically resolvable literal, exactly as #5022 did for |
| 15 | +`ChartDrillDownSchema` beside it, and both hand-derived copies are deleted: |
| 16 | +`@objectstack/spec` is the single source of the vocabulary and the refinement |
| 17 | +again. |
| 18 | + |
| 19 | +**Newly reported (all `error`, all previously silent).** These are shapes the |
| 20 | +schema, the published react-blocks type and objectui's renderer already agreed |
| 21 | +were wrong; the old gate simply could not see them: |
| 22 | + |
| 23 | +| authored | before | after | |
| 24 | +|---|---|---| |
| 25 | +| `aggregate={{ field: 'total', groupBy: 'status' }}` (no `function`) | accepted | `aggregate.function: Invalid option: expected one of "count"\|"sum"\|"avg"\|"min"\|"max" (nothing is set there)` | |
| 26 | +| `aggregate={{ field: 42, function: 'sum', groupBy: 'status' }}` | accepted | `aggregate.field: Invalid input: expected string, received number` | |
| 27 | +| `aggregate={{ function: 'count', groupBy: 42 }}` | accepted | `aggregate.groupBy: Invalid input (received 42) — no accepted form matched: (1) … (2) …` | |
| 28 | +| `aggregate="count"` / `aggregate={[]}` | accepted | `aggregate must be a configuration object, not string.` | |
| 29 | + |
| 30 | +**Re-worded, same verdict.** Two messages now arrive from the schema rather than |
| 31 | +from this rule's own copy. If you match on lint output, update the text: |
| 32 | + |
| 33 | +- FROM `aggregate.function "median" is not an aggregation this chart can run.` |
| 34 | + (hint: `Use one of: count, sum, avg, min, max.`) |
| 35 | + TO `aggregate.function: Invalid option: expected one of "count"|"sum"|"avg"|"min"|"max" (received "median")` |
| 36 | + — the vocabulary is the enum's own, and the author's value is echoed back from |
| 37 | + the input (the one part zod does not put in the message). |
| 38 | +- FROM `aggregate.function "sum" has no "field" to aggregate.` |
| 39 | + TO `aggregate.field: aggregate.function "sum" needs a "field" to aggregate (only "count" may omit it).` |
| 40 | + — verbatim from the schema's refinement. |
| 41 | + |
| 42 | +The rule id (`react-chart-aggregate-invalid`) and the severity are unchanged for |
| 43 | +both. |
| 44 | + |
| 45 | +**`aggregate.groupBy` missing is a NEW `warning`, deliberately not an error.** |
| 46 | +It is the one violation the platform does not agree with itself about: |
| 47 | +`ChartAggregateSchema` and the published react-blocks type both declare `groupBy` |
| 48 | +**required**, while objectui's `ObjectChart` honours its absence |
| 49 | +(`schema.aggregate?.groupBy || schema.xAxisKey`) and this protocol's own |
| 50 | +`chartAggregateCategoryKey` documents the ungrouped single-row result. Gating it |
| 51 | +would break a working authoring shape to enforce a declaration the platform does |
| 52 | +not keep, so the finding explains the situation and does not fail |
| 53 | +`os lint`/`validate`/`compile`. Whether the schema loosens or the renderer |
| 54 | +tightens is decided on #5583. |
| 55 | + |
| 56 | +**What this does NOT fix yet.** `ChartAggregateSchema` and `ChartGroupBySchema`'s |
| 57 | +object arm are still STRIP-posture, so the parse this gate now runs **drops** an |
| 58 | +unknown key rather than reporting it: `groupby` for `groupBy` and |
| 59 | +`dateGranularty` for `dateGranularity` still degrade a chart to one ungrouped |
| 60 | +point with the build green. Wiring the parse is the precondition for closing |
| 61 | +that, not the closing — `.strict()` is a property of a parse, and until now there |
| 62 | +was no parse to make strict. The spec-side tightening is **#5583**; the tolerance |
| 63 | +is pinned by name in this rule's tests so a wired gate cannot be mistaken for a |
| 64 | +closed one (#4583). |
0 commit comments