Skip to content

Commit ee82f06

Browse files
dmealingclaude
andcommitted
feat(metadata): register @formExclude on field.* wildcard (cross-port)
The form template already reads @formExclude to omit a field from a generated form, but core never registered it, so strict verify would reject it (ERR_UNKNOWN_ATTR). Register it on the field.* wildcard in spec/metamodel/ui.json mirroring @filterable/@Sortable; sync the committed C#/Python copies; regenerate the embedded metamodel + expected-registry (adds formExclude per concrete field subtype). Data-driven — no non-TS provider code. Add FIELD_ATTR_FORM_EXCLUDE. Cross-port conformance green: TS, Java metadata, Kotlin, Python, C#. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NGQ7oSuNcjhsMHWwZzhBwr
1 parent c99ddf1 commit ee82f06

7 files changed

Lines changed: 160 additions & 3 deletions

File tree

fixtures/registry-conformance/coverage-report.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"column",
3333
"dbColumnType",
3434
"example",
35+
"formExclude",
3536
"instruction",
3637
"readOnly",
3738
"sortable",
@@ -46,6 +47,7 @@
4647
"dbColumnType",
4748
"default",
4849
"example",
50+
"formExclude",
4951
"instruction",
5052
"readOnly",
5153
"sortable",
@@ -62,6 +64,7 @@
6264
"dbColumnType",
6365
"default",
6466
"example",
67+
"formExclude",
6568
"instruction",
6669
"readOnly",
6770
"sortable",
@@ -77,6 +80,7 @@
7780
"dbColumnType",
7881
"default",
7982
"example",
83+
"formExclude",
8084
"instruction",
8185
"readOnly",
8286
"sortable",
@@ -92,6 +96,7 @@
9296
"dbColumnType",
9397
"default",
9498
"example",
99+
"formExclude",
95100
"instruction",
96101
"readOnly",
97102
"sortable",
@@ -106,6 +111,7 @@
106111
"column",
107112
"dbColumnType",
108113
"example",
114+
"formExclude",
109115
"instruction",
110116
"readOnly",
111117
"sortable",
@@ -122,6 +128,7 @@
122128
"dbColumnType",
123129
"default",
124130
"example",
131+
"formExclude",
125132
"instruction",
126133
"readOnly",
127134
"sortable",
@@ -139,6 +146,7 @@
139146
"default",
140147
"example",
141148
"filterable",
149+
"formExclude",
142150
"instruction",
143151
"readOnly",
144152
"sortable",
@@ -153,6 +161,7 @@
153161
"column",
154162
"dbColumnType",
155163
"example",
164+
"formExclude",
156165
"instruction",
157166
"sortableDefaultOrder",
158167
"unique",
@@ -166,6 +175,7 @@
166175
"db.indexed",
167176
"dbColumnType",
168177
"example",
178+
"formExclude",
169179
"instruction",
170180
"sortableDefaultOrder",
171181
"unique",
@@ -181,6 +191,7 @@
181191
"default",
182192
"example",
183193
"filterable",
194+
"formExclude",
184195
"instruction",
185196
"readOnly",
186197
"required",
@@ -198,6 +209,7 @@
198209
"dbColumnType",
199210
"default",
200211
"example",
212+
"formExclude",
201213
"instruction",
202214
"readOnly",
203215
"sortable",
@@ -209,6 +221,7 @@
209221
{
210222
"key": "field.string",
211223
"untestedAttrs": [
224+
"formExclude",
212225
"sortableDefaultOrder",
213226
"xmlText"
214227
]
@@ -222,6 +235,7 @@
222235
"dbColumnType",
223236
"default",
224237
"example",
238+
"formExclude",
225239
"instruction",
226240
"readOnly",
227241
"sortable",
@@ -238,6 +252,7 @@
238252
"dbColumnType",
239253
"default",
240254
"example",
255+
"formExclude",
241256
"instruction",
242257
"sortableDefaultOrder",
243258
"unique",
@@ -253,6 +268,7 @@
253268
"default",
254269
"example",
255270
"filterable",
271+
"formExclude",
256272
"instruction",
257273
"readOnly",
258274
"sortable",
@@ -268,6 +284,7 @@
268284
"dbColumnType",
269285
"default",
270286
"example",
287+
"formExclude",
271288
"instruction",
272289
"readOnly",
273290
"sortable",

fixtures/registry-conformance/expected-registry.json

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@
122122
"required": false,
123123
"description": "When true, the field is exposed in generated CRUD filter allowlists (Project D filter layer)."
124124
},
125+
{
126+
"name": "formExclude",
127+
"valueType": "boolean",
128+
"isArray": false,
129+
"required": false,
130+
"description": "When true, the field is omitted from generated forms. Inert on fields for which no form is generated (e.g. projection/derived fields)."
131+
},
125132
{
126133
"name": "instruction",
127134
"valueType": "string",
@@ -252,6 +259,13 @@
252259
"required": false,
253260
"description": "When true, the field is exposed in generated CRUD filter allowlists (Project D filter layer)."
254261
},
262+
{
263+
"name": "formExclude",
264+
"valueType": "boolean",
265+
"isArray": false,
266+
"required": false,
267+
"description": "When true, the field is omitted from generated forms. Inert on fields for which no form is generated (e.g. projection/derived fields)."
268+
},
255269
{
256270
"name": "instruction",
257271
"valueType": "string",
@@ -390,6 +404,13 @@
390404
"required": false,
391405
"description": "When true, the field is exposed in generated CRUD filter allowlists (Project D filter layer)."
392406
},
407+
{
408+
"name": "formExclude",
409+
"valueType": "boolean",
410+
"isArray": false,
411+
"required": false,
412+
"description": "When true, the field is omitted from generated forms. Inert on fields for which no form is generated (e.g. projection/derived fields)."
413+
},
393414
{
394415
"name": "instruction",
395416
"valueType": "string",
@@ -531,6 +552,13 @@
531552
"required": false,
532553
"description": "When true, the field is exposed in generated CRUD filter allowlists (Project D filter layer)."
533554
},
555+
{
556+
"name": "formExclude",
557+
"valueType": "boolean",
558+
"isArray": false,
559+
"required": false,
560+
"description": "When true, the field is omitted from generated forms. Inert on fields for which no form is generated (e.g. projection/derived fields)."
561+
},
534562
{
535563
"name": "instruction",
536564
"valueType": "string",
@@ -662,6 +690,13 @@
662690
"required": false,
663691
"description": "When true, the field is exposed in generated CRUD filter allowlists (Project D filter layer)."
664692
},
693+
{
694+
"name": "formExclude",
695+
"valueType": "boolean",
696+
"isArray": false,
697+
"required": false,
698+
"description": "When true, the field is omitted from generated forms. Inert on fields for which no form is generated (e.g. projection/derived fields)."
699+
},
665700
{
666701
"name": "instruction",
667702
"valueType": "string",
@@ -806,6 +841,13 @@
806841
"required": false,
807842
"description": "When true, the field is exposed in generated CRUD filter allowlists (Project D filter layer)."
808843
},
844+
{
845+
"name": "formExclude",
846+
"valueType": "boolean",
847+
"isArray": false,
848+
"required": false,
849+
"description": "When true, the field is omitted from generated forms. Inert on fields for which no form is generated (e.g. projection/derived fields)."
850+
},
809851
{
810852
"name": "instruction",
811853
"valueType": "string",
@@ -958,6 +1000,13 @@
9581000
"required": false,
9591001
"description": "When true, the field is exposed in generated CRUD filter allowlists (Project D filter layer)."
9601002
},
1003+
{
1004+
"name": "formExclude",
1005+
"valueType": "boolean",
1006+
"isArray": false,
1007+
"required": false,
1008+
"description": "When true, the field is omitted from generated forms. Inert on fields for which no form is generated (e.g. projection/derived fields)."
1009+
},
9611010
{
9621011
"name": "instruction",
9631012
"valueType": "string",
@@ -1113,6 +1162,13 @@
11131162
"required": false,
11141163
"description": "When true, the field is exposed in generated CRUD filter allowlists (Project D filter layer)."
11151164
},
1165+
{
1166+
"name": "formExclude",
1167+
"valueType": "boolean",
1168+
"isArray": false,
1169+
"required": false,
1170+
"description": "When true, the field is omitted from generated forms. Inert on fields for which no form is generated (e.g. projection/derived fields)."
1171+
},
11161172
{
11171173
"name": "instruction",
11181174
"valueType": "string",
@@ -1243,6 +1299,13 @@
12431299
"required": false,
12441300
"description": "When true, the field is exposed in generated CRUD filter allowlists (Project D filter layer)."
12451301
},
1302+
{
1303+
"name": "formExclude",
1304+
"valueType": "boolean",
1305+
"isArray": false,
1306+
"required": false,
1307+
"description": "When true, the field is omitted from generated forms. Inert on fields for which no form is generated (e.g. projection/derived fields)."
1308+
},
12461309
{
12471310
"name": "instruction",
12481311
"valueType": "string",
@@ -1373,6 +1436,13 @@
13731436
"required": false,
13741437
"description": "When true, the field is exposed in generated CRUD filter allowlists (Project D filter layer)."
13751438
},
1439+
{
1440+
"name": "formExclude",
1441+
"valueType": "boolean",
1442+
"isArray": false,
1443+
"required": false,
1444+
"description": "When true, the field is omitted from generated forms. Inert on fields for which no form is generated (e.g. projection/derived fields)."
1445+
},
13761446
{
13771447
"name": "instruction",
13781448
"valueType": "string",
@@ -1503,6 +1573,13 @@
15031573
"required": false,
15041574
"description": "When true, the field is exposed in generated CRUD filter allowlists (Project D filter layer)."
15051575
},
1576+
{
1577+
"name": "formExclude",
1578+
"valueType": "boolean",
1579+
"isArray": false,
1580+
"required": false,
1581+
"description": "When true, the field is omitted from generated forms. Inert on fields for which no form is generated (e.g. projection/derived fields)."
1582+
},
15061583
{
15071584
"name": "instruction",
15081585
"valueType": "string",
@@ -1634,6 +1711,13 @@
16341711
"required": false,
16351712
"description": "When true, the field is exposed in generated CRUD filter allowlists (Project D filter layer)."
16361713
},
1714+
{
1715+
"name": "formExclude",
1716+
"valueType": "boolean",
1717+
"isArray": false,
1718+
"required": false,
1719+
"description": "When true, the field is omitted from generated forms. Inert on fields for which no form is generated (e.g. projection/derived fields)."
1720+
},
16371721
{
16381722
"name": "instruction",
16391723
"valueType": "string",
@@ -1779,6 +1863,13 @@
17791863
"required": false,
17801864
"description": "When true, the field is exposed in generated CRUD filter allowlists (Project D filter layer)."
17811865
},
1866+
{
1867+
"name": "formExclude",
1868+
"valueType": "boolean",
1869+
"isArray": false,
1870+
"required": false,
1871+
"description": "When true, the field is omitted from generated forms. Inert on fields for which no form is generated (e.g. projection/derived fields)."
1872+
},
17821873
{
17831874
"name": "instruction",
17841875
"valueType": "string",
@@ -1928,6 +2019,13 @@
19282019
"required": false,
19292020
"description": "When true, the field is exposed in generated CRUD filter allowlists (Project D filter layer)."
19302021
},
2022+
{
2023+
"name": "formExclude",
2024+
"valueType": "boolean",
2025+
"isArray": false,
2026+
"required": false,
2027+
"description": "When true, the field is omitted from generated forms. Inert on fields for which no form is generated (e.g. projection/derived fields)."
2028+
},
19312029
{
19322030
"name": "instruction",
19332031
"valueType": "string",
@@ -2086,6 +2184,13 @@
20862184
"required": false,
20872185
"description": "When true, the field is exposed in generated CRUD filter allowlists (Project D filter layer)."
20882186
},
2187+
{
2188+
"name": "formExclude",
2189+
"valueType": "boolean",
2190+
"isArray": false,
2191+
"required": false,
2192+
"description": "When true, the field is omitted from generated forms. Inert on fields for which no form is generated (e.g. projection/derived fields)."
2193+
},
20892194
{
20902195
"name": "instruction",
20912196
"valueType": "string",
@@ -2227,6 +2332,13 @@
22272332
"required": false,
22282333
"description": "When true, the field is exposed in generated CRUD filter allowlists (Project D filter layer)."
22292334
},
2335+
{
2336+
"name": "formExclude",
2337+
"valueType": "boolean",
2338+
"isArray": false,
2339+
"required": false,
2340+
"description": "When true, the field is omitted from generated forms. Inert on fields for which no form is generated (e.g. projection/derived fields)."
2341+
},
22302342
{
22312343
"name": "instruction",
22322344
"valueType": "string",
@@ -2364,6 +2476,13 @@
23642476
"required": false,
23652477
"description": "When true, the field is exposed in generated CRUD filter allowlists (Project D filter layer)."
23662478
},
2479+
{
2480+
"name": "formExclude",
2481+
"valueType": "boolean",
2482+
"isArray": false,
2483+
"required": false,
2484+
"description": "When true, the field is omitted from generated forms. Inert on fields for which no form is generated (e.g. projection/derived fields)."
2485+
},
23672486
{
23682487
"name": "instruction",
23692488
"valueType": "string",
@@ -2494,6 +2613,13 @@
24942613
"required": false,
24952614
"description": "When true, the field is exposed in generated CRUD filter allowlists (Project D filter layer)."
24962615
},
2616+
{
2617+
"name": "formExclude",
2618+
"valueType": "boolean",
2619+
"isArray": false,
2620+
"required": false,
2621+
"description": "When true, the field is omitted from generated forms. Inert on fields for which no form is generated (e.g. projection/derived fields)."
2622+
},
24972623
{
24982624
"name": "instruction",
24992625
"valueType": "string",

server/csharp/MetaObjects/SpecMetamodel/ui.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"children": [
88
{ "type": "attr", "subType": "boolean", "name": "filterable", "min": 0, "max": 1, "description": "When true, the field is exposed in generated CRUD filter allowlists (Project D filter layer)." },
99
{ "type": "attr", "subType": "boolean", "name": "sortable", "min": 0, "max": 1, "description": "When true, the field is exposed in generated CRUD sort allowlists. Inherits from @filterable by default; set false to opt out." },
10-
{ "type": "attr", "subType": "string", "name": "sortableDefaultOrder", "min": 0, "max": 1, "allowedValues": ["asc", "desc"], "description": "Default sort direction applied when this field is the default sort field." }
10+
{ "type": "attr", "subType": "string", "name": "sortableDefaultOrder", "min": 0, "max": 1, "allowedValues": ["asc", "desc"], "description": "Default sort direction applied when this field is the default sort field." },
11+
{ "type": "attr", "subType": "boolean", "name": "formExclude", "min": 0, "max": 1, "description": "When true, the field is omitted from generated forms. Inert on fields for which no form is generated (e.g. projection/derived fields)." }
1112
]
1213
},
1314
{

0 commit comments

Comments
 (0)