@objectstack/lint 17.1.0 → 17.2.0
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/CHANGELOG.md +229 -0
- package/dist/index.cjs +236 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +218 -14
- package/dist/index.d.ts +218 -14
- package/dist/index.js +229 -31
- package/dist/index.js.map +1 -1
- package/dist/{runtime-s3X9D9hm.d.cts → runtime-cV-l_vtC.d.cts} +20 -1
- package/dist/{runtime-s3X9D9hm.d.ts → runtime-cV-l_vtC.d.ts} +20 -1
- package/dist/runtime.cjs +206 -28
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.d.cts +1 -1
- package/dist/runtime.d.ts +1 -1
- package/dist/runtime.js +206 -28
- package/dist/runtime.js.map +1 -1
- package/package.json +6 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,234 @@
|
|
|
1
1
|
# @objectstack/lint
|
|
2
2
|
|
|
3
|
+
## 17.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 78818ec: Report an unparseable source instead of scoring it CLEAN (#10653).
|
|
8
|
+
|
|
9
|
+
Four validators parsed authored source with `ts.createSourceFile` and never read
|
|
10
|
+
`parseDiagnostics`. That call **cannot throw**, so a source with syntax errors
|
|
11
|
+
came back as a tree built by error recovery, got walked like any other, and
|
|
12
|
+
produced no findings — a source the validator could not read, reported as a
|
|
13
|
+
source with nothing to report. Two of the sites carried a `try/catch` around the
|
|
14
|
+
parse that never once ran.
|
|
15
|
+
|
|
16
|
+
Each now reports what it could not read, as a finding the author receives rather
|
|
17
|
+
than as an exit — a publish-time validator is handed metadata by someone else,
|
|
18
|
+
so ending the process on their input is not its call. Four new advisory
|
|
19
|
+
(`warning`) rule ids, all additive: every finding these rules produce today they
|
|
20
|
+
still produce, including from a partially recovered tree.
|
|
21
|
+
|
|
22
|
+
- `react-page-source-unparseable` — `kind:'react'` page source
|
|
23
|
+
(`validateReactPageProps`)
|
|
24
|
+
- `startup-source-unparseable` — plugin source (`findStartupRegistryVerdicts`)
|
|
25
|
+
- `hook-body-source-unparseable` — L2 hook body (`validateHookBodyWrites`)
|
|
26
|
+
- `action-body-source-unparseable` — L2 action body (`validateActionBodyWrites`)
|
|
27
|
+
|
|
28
|
+
New exports: the four rule-id constants, plus `describeParseFailure`,
|
|
29
|
+
`PARSE_FAILURE_HINT` and the `SourceParseFailure` / `CheckedParse` /
|
|
30
|
+
`CheckedParseOptions` types. `ExtractedHookBodyWriteSet` gains an optional
|
|
31
|
+
`parseFailure`, so a consumer of the extractor can tell "wrote nothing" from
|
|
32
|
+
"could not be read" — the distinction that was missing.
|
|
33
|
+
|
|
34
|
+
Nothing is removed or renamed, and no source that parses gains a finding. A
|
|
35
|
+
stack whose authored sources all parse lints exactly as before; one carrying a
|
|
36
|
+
source with a syntax error gains a warning that names the file, line and column
|
|
37
|
+
instead of silently skipping the checks.
|
|
38
|
+
- def0d3e: Runtime publish-gate findings for collection-resident write types (`object` /
|
|
39
|
+
`permission` / `book`) now key the top-level collection entry in
|
|
40
|
+
`issues[].path` / `advisories[].path` by NAME —
|
|
41
|
+
`objects.acme_invoice.sharingModel` — instead of by the gate's private
|
|
42
|
+
per-write snapshot index (`objects[417].sharingModel`), which no caller could
|
|
43
|
+
resolve: that index numbered an in-memory array a Studio / MCP / REST receiver
|
|
44
|
+
has never seen. Single-member write types keep their trivially-stable
|
|
45
|
+
positional form (`flows[0].nodes[1]…`), and nested positions inside one named
|
|
46
|
+
item (`objects.acme_invoice.indexes[1]`) stay positional — they index the
|
|
47
|
+
author's own document. An entry with no splice-safe name falls back to the
|
|
48
|
+
positional spelling. The accepted metadata set is unchanged; only the spelling
|
|
49
|
+
of the emitted finding `path` changes, and `RuntimeAuthoringIssueSchema.path`'s
|
|
50
|
+
description now states the convention. CLI (`os validate` / `os lint`) output
|
|
51
|
+
is unchanged — there the index resolves against the author's own config file.
|
|
52
|
+
- e2bb237: The SORT axis now asks the #8116 provenance question about a name the blanket
|
|
53
|
+
`SYSTEM_FIELDS` union told it not to flag — new rule `sort-field-unprovisioned`
|
|
54
|
+
(#10474), the twin of `searchable-field-unprovisioned` on the identical index
|
|
55
|
+
(#8404).
|
|
56
|
+
|
|
57
|
+
`validate-sortable-fields` consulted the union and stopped there, so a list view
|
|
58
|
+
ordering by a registry-injected anchor on an ADR-0015 `external` object was
|
|
59
|
+
skipped in silence. The #8999 consumer census recorded that gap with the reason
|
|
60
|
+
that such an object never reaches the union branch at all — skip (2) was believed
|
|
61
|
+
to catch it. **That reason was measured wrong.** `declaredFieldTarget` returns
|
|
62
|
+
`null` on exactly one condition (`fields` missing, unreadable, or naming
|
|
63
|
+
nothing) and nothing in it tests `external`, so the shipped shape — a federated
|
|
64
|
+
object that declares a mapped field map, as `examples/app-showcase`'s
|
|
65
|
+
`showcase_ext_customer` does — is indexed like any other object and lands
|
|
66
|
+
squarely in the skip. The census ledger entry now carries the correction rather
|
|
67
|
+
than the inherited reason.
|
|
68
|
+
|
|
69
|
+
Why the authoring gate is the only door available for it: both runtime doors on
|
|
70
|
+
this axis judge `formula` alone (`UNMATERIALIZED_SORT_TYPES`) — the REST ingress
|
|
71
|
+
`assertSortFieldsExist` (#6994) and the engine's `assertOrderByIsMaterializable`
|
|
72
|
+
(#7095). An injected anchor is a `datetime` or `lookup`, it *is* in `gate.known`
|
|
73
|
+
because the registry injected it into the served schema, and it is undotted, so
|
|
74
|
+
it clears every verdict and reaches the driver. Measured with a real `SqlDriver`
|
|
75
|
+
over better-sqlite3, the object declared exactly as the showcase declares it,
|
|
76
|
+
against a remote `customers` table carrying `[id, name, email, region,
|
|
77
|
+
lifetime_value]` and none of the seven injected anchors:
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
orderBy name asc -> [c1,c2,c3] desc -> [c3,c2,c1] (a real column: reverses)
|
|
81
|
+
orderBy created_at asc -> [c1,c2,c3] desc -> [c1,c2,c3] asc === desc, 3 rows, no error
|
|
82
|
+
orderBy owner_id asc -> [c1,c2,c3] desc -> [c1,c2,c3] asc === desc, 3 rows, no error
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`asc` and `desc` byte-identical while the baseline reverses is what makes it a
|
|
86
|
+
dropped sort rather than a coincidence — the same signature this rule already
|
|
87
|
+
records for `formula`, reached by a second route, except that a formula sort is
|
|
88
|
+
refused at both doors and this one is not. A list view ordered by an anchor with
|
|
89
|
+
no storage answers `200` with the rows in the driver's arbitrary order, on the
|
|
90
|
+
view's first fetch and every fetch after it, which `limit`/`offset` then slice
|
|
91
|
+
into an arbitrary page.
|
|
92
|
+
|
|
93
|
+
`warning`, never `error` and never gating (#4330's cost asymmetry, the call every
|
|
94
|
+
sibling makes): the remote schema is invisible to this pass, so the remote table
|
|
95
|
+
may genuinely carry a `created_at` of its own. Declaring that column — the first
|
|
96
|
+
remedy the shared hint prescribes — silences the finding, because
|
|
97
|
+
`unprovisionedInjectedColumnsFor` excludes an author-declared column of the same
|
|
98
|
+
name (#7859's security direction). The runtime publish gate sorts on severity, so
|
|
99
|
+
this lands as an advisory and refuses no write.
|
|
100
|
+
|
|
101
|
+
Two deliberate narrowings, both pinned:
|
|
102
|
+
|
|
103
|
+
- **Undotted names only** — the one place this axis departs from the SEARCH twin.
|
|
104
|
+
`resolveSearchFields` matches by exact string and drops a dotted entry like a
|
|
105
|
+
typo, but a dotted SORT name is refused by the ingress gate as its own verdict
|
|
106
|
+
(`400 INVALID_SORT`, loudly, on every fetch), so the silent degradation this
|
|
107
|
+
finding reports cannot happen there. Answering would give the SORT axis its own
|
|
108
|
+
dotted verdict, which is exactly the posture the rule shares with the FILTER
|
|
109
|
+
and PROJECTION axes (#4256 / #7532 / #7589) and declines to break.
|
|
110
|
+
- **`checkSortDeclaration`'s new anchor-index parameter is optional**, with the
|
|
111
|
+
same meaning `checkSearchableFieldList`'s carries: an out-of-repo caller that
|
|
112
|
+
never built the index keeps its pre-#10474 answers. Every in-repo caller passes
|
|
113
|
+
it.
|
|
114
|
+
|
|
115
|
+
Also re-ruled, with fresh eyes and on evidence rather than inheritance:
|
|
116
|
+
`validate-translation-references` still correctly asks nothing. It reads the
|
|
117
|
+
union at exactly one site (the `fields.<name>` orphan test), and the key it
|
|
118
|
+
decides about is derived from the *registered* metadata, into which the registry
|
|
119
|
+
injects the anchor on a federated object just as on a local one — so the key
|
|
120
|
+
resolves and the label renders. Warning there would flag a translation that
|
|
121
|
+
works. The blank-column consequence belongs to the surface that renders the
|
|
122
|
+
anchor (`validate-page-field-bindings`, #8340), not to the bundle that names it.
|
|
123
|
+
- adbcbfd: feat(lint): the two list-view field rules reach a standalone list view at the runtime publish gate — `view` writes are now judged by `validateSearchableFields` and `validateSortableFields` (#9313)
|
|
124
|
+
|
|
125
|
+
An `active`-state `view` save through `saveMetaItem` (Studio, REST `/meta` item
|
|
126
|
+
CRUD, an MCP/AI author) is now refused with the existing 422 `invalid_metadata`
|
|
127
|
+
envelope when its list view declares a `sort` or `searchableFields` entry the
|
|
128
|
+
bound object cannot honor — an unknown field name, a virtual (`formula`) sort
|
|
129
|
+
target with no stored column to ORDER BY, or a search narrowing the #4254
|
|
130
|
+
ingress gate would refuse on every toolbar search. Both rules already gated
|
|
131
|
+
`os validate` / `os build` / `os lint`; the runtime door — the only door a
|
|
132
|
+
Studio tenant or an MCP/AI author has — ran neither, and an author writing the
|
|
133
|
+
exact declaration these rules exist to refuse got it accepted.
|
|
134
|
+
|
|
135
|
+
Two halves, because either alone is a silent no-op: the reference-integrity
|
|
136
|
+
suite's registry entry gains `runtimeTypes: ['view']`, and both rules' metadata
|
|
137
|
+
walks gain the SELF rung — a `views[]` entry that IS a flattened standalone
|
|
138
|
+
list overlay (`ViewMetadataSchema`'s list-overlay member: `viewKind: 'list'`,
|
|
139
|
+
no nested `config`), the shape a standalone list view takes on the wire and the
|
|
140
|
+
shape the gate snapshots as `views: [item]`.
|
|
141
|
+
|
|
142
|
+
The suite dispatches per member on this door: a `view` snapshot reaches exactly
|
|
143
|
+
the two list-view field rules (`ReferenceIntegrityRule.runtimeTypes`, default
|
|
144
|
+
`['flow']`), never the members whose resolution universe the per-write snapshot
|
|
145
|
+
does not carry — `validateActionNameRefs` resolving against `stack.actions`
|
|
146
|
+
would otherwise refuse legitimate view writes. CLI behaviour is unchanged (the
|
|
147
|
+
commands run the full suite as before); `flow` snapshots keep every member.
|
|
148
|
+
Measured before crossing: 0 refusals and 0 advisories over 50 shipped
|
|
149
|
+
view-door bodies (11 containers + 39 console-shaped personalization overlays,
|
|
150
|
+
`sort[].id` decorations included) across four authoring lineages — a lower
|
|
151
|
+
bound, as every authored corpus is. Draft saves are untouched (D1), stored rows
|
|
152
|
+
keep being served (ADR-0087 asymmetry), and
|
|
153
|
+
`OS_ALLOW_UNLINTED_METADATA_WRITES=1` still degrades the refusal to a loud log.
|
|
154
|
+
- f1b5ad3: feat(lint): a standalone ViewItem record's nested `config.sort` / `config.searchableFields` reach the runtime publish gate (#10001)
|
|
155
|
+
|
|
156
|
+
An `active`-state `view` save through `saveMetaItem` (Studio, REST `/meta`
|
|
157
|
+
item CRUD, an MCP/AI author) whose body is a standalone ViewItem RECORD —
|
|
158
|
+
`ViewMetadataSchema`'s member 1, `{ name, object, viewKind: 'list', config }`,
|
|
159
|
+
the shape a Studio-saved view takes and the shape objectui's `updateView`
|
|
160
|
+
round-trips on every pin/reorder toggle — is now refused with the existing
|
|
161
|
+
422 `invalid_metadata` envelope when its `config.sort` / `config.searchableFields`
|
|
162
|
+
declares a field the bound object cannot honor: an unknown name, a virtual
|
|
163
|
+
(`formula`) sort target with no stored column to ORDER BY, or a search
|
|
164
|
+
narrowing the #4254 ingress gate would refuse on every toolbar search. #9313
|
|
165
|
+
closed the same gap for the flattened list overlay, one union member over;
|
|
166
|
+
the record's declarations live one level down, inside `config`, and were
|
|
167
|
+
judged by neither list-view field rule — so a record write carrying
|
|
168
|
+
`config.sort: [{ field: '' }]` published in silence and answered
|
|
169
|
+
`400 INVALID_SORT` (#6994/#7095) on the view's first fetch, every load.
|
|
170
|
+
|
|
171
|
+
Walk-only, by design: #9313 already widened the reference-integrity suite
|
|
172
|
+
entry and exactly these two members onto `view` writes, so this change adds
|
|
173
|
+
the RECORD rung to both twin walks — recognised by the wire union's own
|
|
174
|
+
member discrimination (`viewKind: 'list'` AND a record-shaped `config`; the
|
|
175
|
+
flattened-overlay rung keeps its `no nested config` guard, a strict container
|
|
176
|
+
carries neither key, and a `form` record has no list-field surface), judged
|
|
177
|
+
against `listViewObject(config) ?? record.object` at path
|
|
178
|
+
`views[i].config.sort[…]` / `views[i].config.searchableFields[…]`. The
|
|
179
|
+
per-member granularity split is unchanged: no further suite member crosses
|
|
180
|
+
onto `view`. Measured before shipping: 0 refusals and 0 advisories over 39
|
|
181
|
+
record-shaped console round-trip bodies (one per shipped list surface,
|
|
182
|
+
`config.sort[].id` decorations and `isPinned`/`sortOrder` riding along, the
|
|
183
|
+
shape `saveMetaItem` really stores) across the four shipped stacks — a lower
|
|
184
|
+
bound, as every authored corpus is. Draft saves are untouched (D1), stored
|
|
185
|
+
rows keep being served (ADR-0087 asymmetry), and
|
|
186
|
+
`OS_ALLOW_UNLINTED_METADATA_WRITES=1` still degrades the refusal to a loud log.
|
|
187
|
+
|
|
188
|
+
### Patch Changes
|
|
189
|
+
|
|
190
|
+
- Updated dependencies [6936d07]
|
|
191
|
+
- Updated dependencies [59eb04d]
|
|
192
|
+
- Updated dependencies [9f05b7d]
|
|
193
|
+
- Updated dependencies [7d2d112]
|
|
194
|
+
- Updated dependencies [5fa0d72]
|
|
195
|
+
- Updated dependencies [02b3b07]
|
|
196
|
+
- Updated dependencies [914c413]
|
|
197
|
+
- Updated dependencies [55809a0]
|
|
198
|
+
- Updated dependencies [52db1d1]
|
|
199
|
+
- Updated dependencies [5649efb]
|
|
200
|
+
- Updated dependencies [2306a76]
|
|
201
|
+
- Updated dependencies [e5ea701]
|
|
202
|
+
- Updated dependencies [a40dcc1]
|
|
203
|
+
- Updated dependencies [def0d3e]
|
|
204
|
+
- Updated dependencies [8d0bb79]
|
|
205
|
+
- Updated dependencies [5acb58d]
|
|
206
|
+
- Updated dependencies [2e3cf95]
|
|
207
|
+
- Updated dependencies [4c93387]
|
|
208
|
+
- Updated dependencies [a037f7c]
|
|
209
|
+
- Updated dependencies [3ee8ddf]
|
|
210
|
+
- Updated dependencies [16cef97]
|
|
211
|
+
- Updated dependencies [a79bd35]
|
|
212
|
+
- Updated dependencies [6ceaa4b]
|
|
213
|
+
- Updated dependencies [15ea214]
|
|
214
|
+
- Updated dependencies [de19489]
|
|
215
|
+
- Updated dependencies [c684d00]
|
|
216
|
+
- Updated dependencies [923c424]
|
|
217
|
+
- Updated dependencies [1ec36b7]
|
|
218
|
+
- Updated dependencies [5f2e54c]
|
|
219
|
+
- Updated dependencies [189373b]
|
|
220
|
+
- Updated dependencies [35ad101]
|
|
221
|
+
- Updated dependencies [ceb33a9]
|
|
222
|
+
- Updated dependencies [73d9795]
|
|
223
|
+
- Updated dependencies [8012960]
|
|
224
|
+
- Updated dependencies [f34f56b]
|
|
225
|
+
- Updated dependencies [f399618]
|
|
226
|
+
- Updated dependencies [75e9301]
|
|
227
|
+
- Updated dependencies [2810695]
|
|
228
|
+
- @objectstack/spec@17.2.0
|
|
229
|
+
- @objectstack/formula@17.2.0
|
|
230
|
+
- @objectstack/sdui-parser@17.2.0
|
|
231
|
+
|
|
3
232
|
## 17.1.0
|
|
4
233
|
|
|
5
234
|
### Minor Changes
|