Finish the struct and list leftovers: inline lists, list fields, item kinds
An unconnected list input is a button into the List tab instead of a number field; a struct field can hold a list, so ListSlot carries an optional field name and the three owner cases only say what sits at a key; and a list variable picks its item kind in the inspector (marker doubles as the chooser), so a list of structs no longer has to be born from a project file. The declaration keeps the storable shapes finite: a struct field may be a list, but that list holds primitives only, so list->struct->primitive and struct->list->primitive are the two deepest forms. check 674, e2e 483, jump-run 24, Tetris 19. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
fe3c63c48c
commit
10d030376a
18 files changed
+984
-184
No files matched your search
@@ -194,13 +194,21 @@ function normalizeStructFields(raw: unknown): StructFieldDef[] {
|
||||
const f = asRecord(item);
|
||||
const key = typeof f.key === 'string' ? f.key : '';
|
||||
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key) || seen.has(key)) continue;
|
||||
if (!(FIELD_KINDS as readonly string[]).includes(String(f.kind))) continue;
|
||||
const field = readField(key, f);
|
||||
if (!field) continue;
|
||||
seen.add(key);
|
||||
fields.push({ key, kind: f.kind as FieldKind });
|
||||
fields.push(field);
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
function readField(key: string, f: Record<string, unknown>): StructFieldDef | null {
|
||||
const isFieldKind = (value: unknown) => (FIELD_KINDS as readonly string[]).includes(String(value));
|
||||
if (f.kind === 'list')
|
||||
return { key, kind: 'list', items: isFieldKind(f.items) ? (f.items as FieldKind) : 'number' };
|
||||
return isFieldKind(f.kind) ? { key, kind: f.kind as FieldKind } : null;
|
||||
}
|
||||
|
||||
function normalizePorts(raw: unknown): DeclaredPort[] {
|
||||
const ports: DeclaredPort[] = [];
|
||||
const seen = new Set<string>();
|
||||
|
||||
Reference in new issue
Block a user