@topogram/cli 0.3.47 → 0.3.49
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/package.json +1 -1
- package/src/cli.js +187 -14
- package/src/generator/context/slice.js +131 -0
- package/src/generator/registry.js +5 -2
- package/src/generator/surfaces/shared.js +2 -1
- package/src/generator/surfaces/web/react-components.js +3 -7
- package/src/generator/surfaces/web/sveltekit-components.js +3 -7
- package/src/import/core/runner.js +63 -20
- package/src/realization/ui/build-ui-shared-realization.js +48 -16
- package/src/realization/ui/build-web-realization.js +5 -38
- package/src/resolver/index.js +13 -0
- package/src/ui/taxonomy.js +201 -0
- package/src/validator/index.js +124 -4
- package/src/validator/kinds.js +21 -52
package/src/validator/index.js
CHANGED
|
@@ -37,6 +37,16 @@ import {
|
|
|
37
37
|
UI_NAVIGATION_PATTERNS,
|
|
38
38
|
UI_REGION_KINDS,
|
|
39
39
|
UI_PATTERN_KINDS,
|
|
40
|
+
UI_APP_SHELL_KINDS,
|
|
41
|
+
UI_WINDOWING_MODES,
|
|
42
|
+
UI_STATE_KINDS,
|
|
43
|
+
UI_DESIGN_DENSITIES,
|
|
44
|
+
UI_DESIGN_TONES,
|
|
45
|
+
UI_DESIGN_RADIUS_SCALES,
|
|
46
|
+
UI_DESIGN_COLOR_ROLES,
|
|
47
|
+
UI_DESIGN_TYPOGRAPHY_ROLES,
|
|
48
|
+
UI_DESIGN_ACTION_ROLES,
|
|
49
|
+
UI_DESIGN_ACCESSIBILITY_VALUES,
|
|
40
50
|
FIELD_SPECS
|
|
41
51
|
} from "./kinds.js";
|
|
42
52
|
import { validateComponent } from "./per-kind/component.js";
|
|
@@ -78,6 +88,16 @@ export {
|
|
|
78
88
|
UI_NAVIGATION_PATTERNS,
|
|
79
89
|
UI_REGION_KINDS,
|
|
80
90
|
UI_PATTERN_KINDS,
|
|
91
|
+
UI_APP_SHELL_KINDS,
|
|
92
|
+
UI_WINDOWING_MODES,
|
|
93
|
+
UI_STATE_KINDS,
|
|
94
|
+
UI_DESIGN_DENSITIES,
|
|
95
|
+
UI_DESIGN_TONES,
|
|
96
|
+
UI_DESIGN_RADIUS_SCALES,
|
|
97
|
+
UI_DESIGN_COLOR_ROLES,
|
|
98
|
+
UI_DESIGN_TYPOGRAPHY_ROLES,
|
|
99
|
+
UI_DESIGN_ACTION_ROLES,
|
|
100
|
+
UI_DESIGN_ACCESSIBILITY_VALUES,
|
|
81
101
|
FIELD_SPECS
|
|
82
102
|
} from "./kinds.js";
|
|
83
103
|
|
|
@@ -279,7 +299,7 @@ function validateFieldShapes(errors, statement, fieldMap) {
|
|
|
279
299
|
ensureSingleValueField(errors, statement, fieldMap, key, ["list"]);
|
|
280
300
|
}
|
|
281
301
|
|
|
282
|
-
for (const key of ["fields", "props", "events", "slots", "behaviors", "keys", "relations", "invariants", "rename", "overrides", "http", "http_errors", "http_fields", "http_responses", "http_preconditions", "http_idempotency", "http_cache", "http_delete", "http_async", "http_status", "http_download", "http_authz", "http_callbacks", "ui_screens", "ui_collections", "ui_actions", "ui_visibility", "ui_lookups", "ui_routes", "ui_web", "ui_ios", "ui_app_shell", "ui_navigation", "ui_screen_regions", "ui_components", "db_tables", "db_columns", "db_keys", "db_indexes", "db_relations", "db_lifecycle", "generator_defaults"]) {
|
|
302
|
+
for (const key of ["fields", "props", "events", "slots", "behaviors", "keys", "relations", "invariants", "rename", "overrides", "http", "http_errors", "http_fields", "http_responses", "http_preconditions", "http_idempotency", "http_cache", "http_delete", "http_async", "http_status", "http_download", "http_authz", "http_callbacks", "ui_screens", "ui_collections", "ui_actions", "ui_visibility", "ui_lookups", "ui_routes", "ui_web", "ui_ios", "ui_app_shell", "ui_navigation", "ui_screen_regions", "ui_components", "ui_design", "db_tables", "db_columns", "db_keys", "db_indexes", "db_relations", "db_lifecycle", "generator_defaults"]) {
|
|
283
303
|
ensureSingleValueField(errors, statement, fieldMap, key, ["block"]);
|
|
284
304
|
}
|
|
285
305
|
|
|
@@ -2320,18 +2340,113 @@ function validateProjectionUiAppShell(errors, statement, fieldMap) {
|
|
|
2320
2340
|
}
|
|
2321
2341
|
seenKeys.add(key);
|
|
2322
2342
|
|
|
2323
|
-
if (key === "shell" && !
|
|
2343
|
+
if (key === "shell" && !UI_APP_SHELL_KINDS.has(value)) {
|
|
2324
2344
|
pushError(errors, `Projection ${statement.id} ui_app_shell has invalid shell '${value}'`, entry.loc);
|
|
2325
2345
|
}
|
|
2326
2346
|
if (["global_search", "notifications", "account_menu", "workspace_switcher"].includes(key) && !["true", "false"].includes(value)) {
|
|
2327
2347
|
pushError(errors, `Projection ${statement.id} ui_app_shell '${key}' must be true or false`, entry.loc);
|
|
2328
2348
|
}
|
|
2329
|
-
if (key === "windowing" && !
|
|
2349
|
+
if (key === "windowing" && !UI_WINDOWING_MODES.has(value)) {
|
|
2330
2350
|
pushError(errors, `Projection ${statement.id} ui_app_shell has invalid windowing '${value}'`, entry.loc);
|
|
2331
2351
|
}
|
|
2332
2352
|
}
|
|
2333
2353
|
}
|
|
2334
2354
|
|
|
2355
|
+
function validateProjectionUiDesign(errors, statement, fieldMap) {
|
|
2356
|
+
if (statement.kind !== "projection") {
|
|
2357
|
+
return;
|
|
2358
|
+
}
|
|
2359
|
+
|
|
2360
|
+
const designField = fieldMap.get("ui_design")?.[0];
|
|
2361
|
+
if (!designField || designField.value.type !== "block") {
|
|
2362
|
+
return;
|
|
2363
|
+
}
|
|
2364
|
+
|
|
2365
|
+
if (symbolValue(getFieldValue(statement, "platform")) !== "ui_shared") {
|
|
2366
|
+
pushError(errors, `Projection ${statement.id} ui_design belongs on shared UI projections; concrete UI projections inherit semantic design intent through 'realizes'`, designField.loc);
|
|
2367
|
+
}
|
|
2368
|
+
|
|
2369
|
+
for (const entry of designField.value.entries) {
|
|
2370
|
+
const tokens = blockSymbolItems(entry).map((item) => item.value);
|
|
2371
|
+
const [key, value, extra] = tokens;
|
|
2372
|
+
|
|
2373
|
+
if (key === "density") {
|
|
2374
|
+
if (!UI_DESIGN_DENSITIES.has(value || "")) {
|
|
2375
|
+
pushError(errors, `Projection ${statement.id} ui_design density has invalid value '${value}'`, entry.loc);
|
|
2376
|
+
}
|
|
2377
|
+
if (tokens.length !== 2) {
|
|
2378
|
+
pushError(errors, `Projection ${statement.id} ui_design density accepts exactly one value`, entry.loc);
|
|
2379
|
+
}
|
|
2380
|
+
continue;
|
|
2381
|
+
}
|
|
2382
|
+
|
|
2383
|
+
if (key === "tone") {
|
|
2384
|
+
if (!UI_DESIGN_TONES.has(value || "")) {
|
|
2385
|
+
pushError(errors, `Projection ${statement.id} ui_design tone has invalid value '${value}'`, entry.loc);
|
|
2386
|
+
}
|
|
2387
|
+
if (tokens.length !== 2) {
|
|
2388
|
+
pushError(errors, `Projection ${statement.id} ui_design tone accepts exactly one value`, entry.loc);
|
|
2389
|
+
}
|
|
2390
|
+
continue;
|
|
2391
|
+
}
|
|
2392
|
+
|
|
2393
|
+
if (key === "radius_scale") {
|
|
2394
|
+
if (!UI_DESIGN_RADIUS_SCALES.has(value || "")) {
|
|
2395
|
+
pushError(errors, `Projection ${statement.id} ui_design radius_scale has invalid value '${value}'`, entry.loc);
|
|
2396
|
+
}
|
|
2397
|
+
if (tokens.length !== 2) {
|
|
2398
|
+
pushError(errors, `Projection ${statement.id} ui_design radius_scale accepts exactly one value`, entry.loc);
|
|
2399
|
+
}
|
|
2400
|
+
continue;
|
|
2401
|
+
}
|
|
2402
|
+
|
|
2403
|
+
if (key === "color_role") {
|
|
2404
|
+
if (!UI_DESIGN_COLOR_ROLES.has(value || "")) {
|
|
2405
|
+
pushError(errors, `Projection ${statement.id} ui_design color_role has invalid role '${value}'`, entry.loc);
|
|
2406
|
+
}
|
|
2407
|
+
if (tokens.length !== 3) {
|
|
2408
|
+
pushError(errors, `Projection ${statement.id} ui_design color_role must use 'color_role <role> <semantic-token>'`, entry.loc);
|
|
2409
|
+
}
|
|
2410
|
+
continue;
|
|
2411
|
+
}
|
|
2412
|
+
|
|
2413
|
+
if (key === "typography_role") {
|
|
2414
|
+
if (!UI_DESIGN_TYPOGRAPHY_ROLES.has(value || "")) {
|
|
2415
|
+
pushError(errors, `Projection ${statement.id} ui_design typography_role has invalid role '${value}'`, entry.loc);
|
|
2416
|
+
}
|
|
2417
|
+
if (tokens.length !== 3) {
|
|
2418
|
+
pushError(errors, `Projection ${statement.id} ui_design typography_role must use 'typography_role <role> <semantic-token>'`, entry.loc);
|
|
2419
|
+
}
|
|
2420
|
+
continue;
|
|
2421
|
+
}
|
|
2422
|
+
|
|
2423
|
+
if (key === "action_role") {
|
|
2424
|
+
if (!UI_DESIGN_ACTION_ROLES.has(value || "")) {
|
|
2425
|
+
pushError(errors, `Projection ${statement.id} ui_design action_role has invalid role '${value}'`, entry.loc);
|
|
2426
|
+
}
|
|
2427
|
+
if (tokens.length !== 3) {
|
|
2428
|
+
pushError(errors, `Projection ${statement.id} ui_design action_role must use 'action_role <role> <semantic-token>'`, entry.loc);
|
|
2429
|
+
}
|
|
2430
|
+
continue;
|
|
2431
|
+
}
|
|
2432
|
+
|
|
2433
|
+
if (key === "accessibility") {
|
|
2434
|
+
const values = UI_DESIGN_ACCESSIBILITY_VALUES[value];
|
|
2435
|
+
if (tokens.length !== 3) {
|
|
2436
|
+
pushError(errors, `Projection ${statement.id} ui_design accessibility must use 'accessibility <setting> <value>'`, entry.loc);
|
|
2437
|
+
}
|
|
2438
|
+
if (!values) {
|
|
2439
|
+
pushError(errors, `Projection ${statement.id} ui_design accessibility has invalid setting '${value}'`, entry.loc);
|
|
2440
|
+
} else if (!values.has(extra || "")) {
|
|
2441
|
+
pushError(errors, `Projection ${statement.id} ui_design accessibility '${value}' has invalid value '${extra}'`, entry.loc);
|
|
2442
|
+
}
|
|
2443
|
+
continue;
|
|
2444
|
+
}
|
|
2445
|
+
|
|
2446
|
+
pushError(errors, `Projection ${statement.id} ui_design has unknown key '${key}'`, entry.loc);
|
|
2447
|
+
}
|
|
2448
|
+
}
|
|
2449
|
+
|
|
2335
2450
|
function validateProjectionUiNavigation(errors, statement, fieldMap, registry) {
|
|
2336
2451
|
if (statement.kind !== "projection") {
|
|
2337
2452
|
return;
|
|
@@ -2458,7 +2573,7 @@ function validateProjectionUiScreenRegions(errors, statement, fieldMap, registry
|
|
|
2458
2573
|
if (directives.has("placement") && !["primary", "secondary", "supporting"].includes(directives.get("placement"))) {
|
|
2459
2574
|
pushError(errors, `Projection ${statement.id} ui_screen_regions for '${screenId}' has invalid placement '${directives.get("placement")}'`, entry.loc);
|
|
2460
2575
|
}
|
|
2461
|
-
if (directives.has("state") && !
|
|
2576
|
+
if (directives.has("state") && !UI_STATE_KINDS.has(directives.get("state"))) {
|
|
2462
2577
|
pushError(errors, `Projection ${statement.id} ui_screen_regions for '${screenId}' has invalid state '${directives.get("state")}'`, entry.loc);
|
|
2463
2578
|
}
|
|
2464
2579
|
}
|
|
@@ -2474,6 +2589,10 @@ function validateProjectionUiComponents(errors, statement, fieldMap, registry) {
|
|
|
2474
2589
|
return;
|
|
2475
2590
|
}
|
|
2476
2591
|
|
|
2592
|
+
if (symbolValue(getFieldValue(statement, "platform")) !== "ui_shared") {
|
|
2593
|
+
pushError(errors, `Projection ${statement.id} ui_components belongs on shared UI projections; concrete UI projections inherit component placement through 'realizes'`, componentsField.loc);
|
|
2594
|
+
}
|
|
2595
|
+
|
|
2477
2596
|
const availableScreens = collectAvailableUiScreenIds(statement, fieldMap, registry);
|
|
2478
2597
|
const availableRegions = collectAvailableUiRegionKeys(statement, registry);
|
|
2479
2598
|
const availableRegionPatterns = collectAvailableUiRegionPatterns(statement, registry);
|
|
@@ -3387,6 +3506,7 @@ export function validateWorkspace(workspaceAst) {
|
|
|
3387
3506
|
validateProjectionUiLookups(errors, statement, fieldMap, registry);
|
|
3388
3507
|
validateProjectionUiRoutes(errors, statement, fieldMap, registry);
|
|
3389
3508
|
validateProjectionUiAppShell(errors, statement, fieldMap);
|
|
3509
|
+
validateProjectionUiDesign(errors, statement, fieldMap);
|
|
3390
3510
|
validateProjectionUiNavigation(errors, statement, fieldMap, registry);
|
|
3391
3511
|
validateProjectionUiScreenRegions(errors, statement, fieldMap, registry);
|
|
3392
3512
|
validateProjectionUiComponents(errors, statement, fieldMap, registry);
|
package/src/validator/kinds.js
CHANGED
|
@@ -74,58 +74,26 @@ export const STATUS_SETS_BY_KIND = {
|
|
|
74
74
|
bug: BUG_STATUSES
|
|
75
75
|
};
|
|
76
76
|
export const VERIFICATION_METHODS = new Set(["smoke", "runtime", "contract", "journey", "manual"]);
|
|
77
|
-
|
|
78
|
-
export
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
"aside",
|
|
98
|
-
"related",
|
|
99
|
-
"activity",
|
|
100
|
-
"comments",
|
|
101
|
-
"timeline",
|
|
102
|
-
"tabs",
|
|
103
|
-
"bulk_actions",
|
|
104
|
-
"footer_actions"
|
|
105
|
-
]);
|
|
106
|
-
export const UI_PATTERN_KINDS = new Set([
|
|
107
|
-
"resource_table",
|
|
108
|
-
"data_grid_view",
|
|
109
|
-
"resource_cards",
|
|
110
|
-
"detail_panel",
|
|
111
|
-
"edit_form",
|
|
112
|
-
"lookup_select",
|
|
113
|
-
"action_bar",
|
|
114
|
-
"status_badge",
|
|
115
|
-
"summary_stats",
|
|
116
|
-
"activity_feed",
|
|
117
|
-
"comment_thread",
|
|
118
|
-
"timeline_view",
|
|
119
|
-
"board_view",
|
|
120
|
-
"calendar_view",
|
|
121
|
-
"settings_section",
|
|
122
|
-
"wizard_stepper",
|
|
123
|
-
"audit_log",
|
|
124
|
-
"search_results",
|
|
125
|
-
"empty_state_panel",
|
|
126
|
-
"inspector_pane",
|
|
127
|
-
"master_detail"
|
|
128
|
-
]);
|
|
77
|
+
|
|
78
|
+
export {
|
|
79
|
+
UI_APP_SHELL_KINDS,
|
|
80
|
+
UI_WINDOWING_MODES,
|
|
81
|
+
UI_SCREEN_KINDS,
|
|
82
|
+
UI_COLLECTION_PRESENTATIONS,
|
|
83
|
+
UI_NAVIGATION_PATTERNS,
|
|
84
|
+
UI_REGION_KINDS,
|
|
85
|
+
UI_PATTERN_KINDS,
|
|
86
|
+
UI_ACTION_PRESENTATIONS,
|
|
87
|
+
UI_STATE_KINDS,
|
|
88
|
+
UI_PLATFORM_PATTERNS,
|
|
89
|
+
UI_DESIGN_DENSITIES,
|
|
90
|
+
UI_DESIGN_TONES,
|
|
91
|
+
UI_DESIGN_RADIUS_SCALES,
|
|
92
|
+
UI_DESIGN_COLOR_ROLES,
|
|
93
|
+
UI_DESIGN_TYPOGRAPHY_ROLES,
|
|
94
|
+
UI_DESIGN_ACTION_ROLES,
|
|
95
|
+
UI_DESIGN_ACCESSIBILITY_VALUES
|
|
96
|
+
} from "../ui/taxonomy.js";
|
|
129
97
|
|
|
130
98
|
// Kinds that may carry an optional singular `domain dom_x` field. Keep this
|
|
131
99
|
// set in sync with the `allowed[]` arrays in FIELD_SPECS below; the cross-kind
|
|
@@ -221,6 +189,7 @@ export const FIELD_SPECS = {
|
|
|
221
189
|
"ui_navigation",
|
|
222
190
|
"ui_screen_regions",
|
|
223
191
|
"ui_components",
|
|
192
|
+
"ui_design",
|
|
224
193
|
"db_tables",
|
|
225
194
|
"db_columns",
|
|
226
195
|
"db_keys",
|