feat(icon): icon.show handler + variadic positional schema (T-313)

icon.show resolves Phosphor glyphs by name (injected resolver) or a 0xNNNN
codepoint, reads a --file JSON array of {icon,label,description,color}
entries, validates colors via parseSvgColor (hex or CSS name), and
publishes on the `icon` bus channel. Honest userError on an unknown glyph,
a bad color, or a malformed payload. A trailing stringList positional is
now variadic so `icon show gear folder gauge` collects every token.
Flutter-free, dart-tested. Card widget + wiring next.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-29 13:04:44 +02:00
co-authored by Claude Opus 4.8
parent f0fb5a5134
commit 9a2b4e9eca
6 changed files with 446 additions and 2 deletions
+23
View File
@@ -124,6 +124,29 @@ void main() {
expect(out['to'], '300');
});
test('a trailing stringList positional absorbs all remaining tokens (T-313)', () {
const variadic = CommandSchema(
positional: ['head', 'rest'],
args: {
'head': ArgSpec(),
'rest': ArgSpec(type: ArgType.stringList),
},
);
final out = variadic.normalize(const {
'positional': ['a', 'b', 'c', 'd'],
});
expect(out['head'], 'a');
expect(out['rest'], ['b', 'c', 'd']);
});
test('a variadic positional with no tokens normalizes to an empty list', () {
const variadic = CommandSchema(
positional: ['rest'],
args: {'rest': ArgSpec(type: ArgType.stringList)},
);
expect(variadic.normalize(const {'positional': []})['rest'], const <Object?>[]);
});
test('passthrough is carried over', () {
final out = schema.normalize(const {
'positional': ['x'],