@jskit-ai/kernel 0.1.65 → 0.1.67

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.
@@ -0,0 +1,542 @@
1
+ import { normalizeText } from "./normalize.js";
2
+
3
+ const GENERATED_UI_NAVIGATION_ROLE_VALUES = Object.freeze([
4
+ "primary",
5
+ "secondary",
6
+ "utility",
7
+ "detail",
8
+ "workflow",
9
+ "none"
10
+ ]);
11
+ const GENERATED_UI_NAVIGATION_ROLE_DEFAULT = "primary";
12
+ const GENERATED_UI_NAVIGATION_ROLE_LINK_PLACEMENTS = Object.freeze({
13
+ secondary: "shell.secondary-nav",
14
+ utility: "shell.global-actions"
15
+ });
16
+ const GENERATED_UI_NO_LINK_NAVIGATION_ROLES = Object.freeze(["detail", "workflow", "none"]);
17
+ const GENERATED_UI_NO_LINK_NAVIGATION_ROLE_SET = new Set(GENERATED_UI_NO_LINK_NAVIGATION_ROLES);
18
+ const GENERATED_UI_SURFACE_PROFILES = Object.freeze({
19
+ task: Object.freeze({
20
+ id: "task",
21
+ className: "generated-ui-screen--app",
22
+ density: "comfortable",
23
+ titleLabel: "Screen",
24
+ emptyStateBody: "Activity and actions for this screen will appear here."
25
+ }),
26
+ operator: Object.freeze({
27
+ id: "operator",
28
+ className: "generated-ui-screen--operator",
29
+ density: "compact",
30
+ titleLabel: "Workspace tool",
31
+ emptyStateBody: "Operational activity and actions for this screen will appear here."
32
+ }),
33
+ settings: Object.freeze({
34
+ id: "settings",
35
+ className: "generated-ui-screen--settings",
36
+ density: "comfortable",
37
+ titleLabel: "Settings",
38
+ emptyStateBody: "Saved settings, controls, and activity for this section will appear here."
39
+ })
40
+ });
41
+ const GENERATED_UI_NAVIGATION_ROLE_OPTION = Object.freeze({
42
+ required: false,
43
+ inputType: "text",
44
+ validationType: "enum",
45
+ allowedValues: GENERATED_UI_NAVIGATION_ROLE_VALUES,
46
+ defaultValue: "",
47
+ promptLabel: "Navigation role",
48
+ promptHint: "Product navigation role for generated links. When omitted, dynamic detail and workflow routes create no nav link; primary uses normal inference, secondary maps to shell.secondary-nav, utility maps to shell.global-actions, and detail/workflow/none force no nav link."
49
+ });
50
+ const GENERATED_UI_FORBIDDEN_LIVE_COPY_PATTERNS = Object.freeze([
51
+ Object.freeze({
52
+ id: "replace-this-copy",
53
+ pattern: /replace\s+this/i,
54
+ message: "Generated live UI must not tell users to replace scaffold content."
55
+ }),
56
+ Object.freeze({
57
+ id: "use-this-area-copy",
58
+ pattern: /use\s+this\s+area/i,
59
+ message: "Generated live UI must be a usable screen, not an implementation instruction."
60
+ }),
61
+ Object.freeze({
62
+ id: "this-is-your-page-copy",
63
+ pattern: /this\s+is\s+your\s+page/i,
64
+ message: "Generated live UI must not describe itself as a scaffold page."
65
+ }),
66
+ Object.freeze({
67
+ id: "ready-for-implementation-copy",
68
+ pattern: /ready\s+for\s+your\s+implementation/i,
69
+ message: "Generated live UI must not ask the app author to implement the screen."
70
+ }),
71
+ Object.freeze({
72
+ id: "main-public-surface-copy",
73
+ pattern: /main\s+public\s+surface/i,
74
+ message: "Generated live UI must not expose framework/surface scaffolding language."
75
+ }),
76
+ Object.freeze({
77
+ id: "generate-route-copy",
78
+ pattern: /generate\s+(?:a|your\s+first)\s+(?:page|route)/i,
79
+ message: "Starter UI should present a product-shaped empty state, not CLI instructions."
80
+ }),
81
+ Object.freeze({
82
+ id: "install-package-copy",
83
+ pattern: /install\s+(?:a\s+)?package/i,
84
+ message: "Starter UI should avoid package-installation instructions in live screens."
85
+ }),
86
+ Object.freeze({
87
+ id: "add-product-packages-copy",
88
+ pattern: /add\s+product\s+packages/i,
89
+ message: "Starter UI should avoid package-installation instructions in live screens."
90
+ })
91
+ ]);
92
+ const GENERATED_UI_FORBIDDEN_CARD_SHELL_PATTERNS = Object.freeze([
93
+ Object.freeze({
94
+ id: "vuetify-card-shell",
95
+ pattern: /<v-card\b/i,
96
+ message: "Generated page architecture should not use a generic v-card shell."
97
+ }),
98
+ Object.freeze({
99
+ id: "vuetify-card-title-shell",
100
+ pattern: /<v-card-title\b/i,
101
+ message: "Generated pages should not repeat page titles inside card title chrome."
102
+ })
103
+ ]);
104
+ const GENERATED_UI_SOURCE_CONTRACT_PROFILES = Object.freeze({
105
+ page: Object.freeze({
106
+ forbidCardShell: true,
107
+ requiredPatterns: Object.freeze([
108
+ Object.freeze({
109
+ id: "shared-screen-class",
110
+ pattern: /generated-ui-screen\s+generated-ui-screen--/,
111
+ message: "Generated pages must opt into the shared screen density contract."
112
+ }),
113
+ Object.freeze({
114
+ id: "page-screen-title",
115
+ pattern: /generated-page-screen__title/,
116
+ message: "Generated pages need an explicit responsive page title class."
117
+ }),
118
+ Object.freeze({
119
+ id: "page-empty-state-sheet",
120
+ pattern: /<v-sheet\b[\s\S]*generated-page-screen__empty-state/,
121
+ message: "Generated pages need a direct sheet-based empty/work region."
122
+ }),
123
+ Object.freeze({
124
+ id: "page-responsive-title-type",
125
+ pattern: /--generated-ui-screen-title-size/,
126
+ message: "Generated pages need shared responsive title typography."
127
+ }),
128
+ Object.freeze({
129
+ id: "page-compact-rules",
130
+ pattern: /@media\s*\(max-width:\s*640px\)/,
131
+ message: "Generated pages need explicit compact-width layout rules."
132
+ })
133
+ ])
134
+ }),
135
+ "placed-element": Object.freeze({
136
+ requiredPatterns: Object.freeze([
137
+ Object.freeze({
138
+ id: "placed-element-min-target",
139
+ pattern: /min-height:\s*48px/,
140
+ message: "Placed generated elements need a 48px minimum interactive target."
141
+ })
142
+ ])
143
+ }),
144
+ "crud-list": Object.freeze({
145
+ forbidCardShell: true,
146
+ forbiddenPatterns: Object.freeze([
147
+ Object.freeze({
148
+ id: "desktop-only-data-table",
149
+ pattern: /<v-data-table\b/i,
150
+ message: "Generated CRUD lists must not rely on a desktop-only data table."
151
+ })
152
+ ]),
153
+ requiredPatterns: Object.freeze([
154
+ Object.freeze({
155
+ id: "crud-list-package-screen",
156
+ pattern: /CrudListScreen/,
157
+ message: "Generated CRUD lists must delegate package-owned layout to CrudListScreen."
158
+ }),
159
+ Object.freeze({
160
+ id: "crud-list-screen-runtime",
161
+ pattern: /useCrudListScreen/,
162
+ message: "Generated CRUD lists must use the package-owned list screen runtime."
163
+ }),
164
+ Object.freeze({
165
+ id: "crud-list-card-slot",
166
+ pattern: /#card-fields/,
167
+ message: "Generated CRUD lists must keep resource card fields in a thin slot."
168
+ }),
169
+ Object.freeze({
170
+ id: "crud-list-table-header-slot",
171
+ pattern: /#table-header/,
172
+ message: "Generated CRUD lists must keep resource table headers in a thin slot."
173
+ }),
174
+ Object.freeze({
175
+ id: "crud-list-table-row-slot",
176
+ pattern: /#table-row/,
177
+ message: "Generated CRUD lists must keep resource table rows in a thin slot."
178
+ }),
179
+ Object.freeze({
180
+ id: "crud-list-bulk-config",
181
+ pattern: /listBulkActions/,
182
+ message: "Generated CRUD lists must expose bulk actions through resource-local config."
183
+ }),
184
+ Object.freeze({
185
+ id: "crud-list-filter-config",
186
+ pattern: /listFilters/,
187
+ message: "Generated CRUD lists must expose filters through resource-local config."
188
+ }),
189
+ Object.freeze({
190
+ id: "crud-list-empty-state",
191
+ pattern: /__JSKIT_UI_LIST_EMPTY_TITLE__/,
192
+ message: "Generated CRUD lists need resource-shaped empty state copy."
193
+ }),
194
+ Object.freeze({
195
+ id: "crud-list-error-state",
196
+ pattern: /__JSKIT_UI_LIST_LOAD_ERROR_TITLE__/,
197
+ message: "Generated CRUD lists need resource-shaped load error copy."
198
+ })
199
+ ])
200
+ }),
201
+ "crud-detail": Object.freeze({
202
+ forbidCardShell: true,
203
+ requiredPatterns: Object.freeze([
204
+ Object.freeze({
205
+ id: "crud-detail-package-screen",
206
+ pattern: /Crud(?:View|AddEdit)Screen/,
207
+ message: "Generated CRUD detail screens must delegate package-owned layout to a CRUD screen component."
208
+ }),
209
+ Object.freeze({
210
+ id: "crud-detail-screen-runtime",
211
+ pattern: /useCrud(?:View|AddEdit)Screen/,
212
+ message: "Generated CRUD detail screens must use the package-owned detail screen runtime."
213
+ }),
214
+ Object.freeze({
215
+ id: "crud-detail-fields-slot",
216
+ pattern: /#fields/,
217
+ message: "Generated CRUD detail screens must keep resource fields in a thin slot."
218
+ }),
219
+ Object.freeze({
220
+ id: "crud-detail-resource",
221
+ pattern: /resource:\s*uiResource/,
222
+ message: "Generated CRUD detail screens must pass the shared resource contract into the screen runtime."
223
+ }),
224
+ Object.freeze({
225
+ id: "crud-detail-title",
226
+ pattern: /(?:title\s*:|resource-singular-title=)/,
227
+ message: "Generated CRUD detail screens must provide resource-shaped screen title metadata."
228
+ })
229
+ ])
230
+ }),
231
+ "responsive-smoke": Object.freeze({
232
+ forbidLiveCopy: false,
233
+ requiredPatterns: Object.freeze([
234
+ Object.freeze({
235
+ id: "compact-viewport",
236
+ pattern: /\b390\b/,
237
+ message: "Generated UI smoke tests must include compact phone width."
238
+ }),
239
+ Object.freeze({
240
+ id: "medium-viewport",
241
+ pattern: /\b768\b/,
242
+ message: "Generated UI smoke tests must include tablet-ish medium width."
243
+ }),
244
+ Object.freeze({
245
+ id: "expanded-viewport",
246
+ pattern: /\b1280\b/,
247
+ message: "Generated UI smoke tests must include expanded desktop width."
248
+ }),
249
+ Object.freeze({
250
+ id: "overflow-check",
251
+ pattern: /scrollWidth/,
252
+ message: "Generated UI smoke tests must check horizontal overflow."
253
+ }),
254
+ Object.freeze({
255
+ id: "tap-target-check",
256
+ pattern: /toBeGreaterThanOrEqual\(48\)/,
257
+ message: "Generated UI smoke tests must check compact tap targets."
258
+ }),
259
+ Object.freeze({
260
+ id: "screen-contract-check",
261
+ pattern: /generated-ui-screen/,
262
+ message: "Generated UI smoke tests must verify the generated screen contract."
263
+ })
264
+ ])
265
+ }),
266
+ "starter-home": Object.freeze({
267
+ requiredPatterns: Object.freeze([
268
+ Object.freeze({
269
+ id: "app-surface-profile",
270
+ pattern: /generated-ui-screen--app/,
271
+ message: "Base generated apps must use the app surface density profile."
272
+ }),
273
+ Object.freeze({
274
+ id: "starter-home-screen",
275
+ pattern: /home-start-screen/,
276
+ message: "Base generated apps need a stable starter home screen."
277
+ }),
278
+ Object.freeze({
279
+ id: "starter-home-panel",
280
+ pattern: /<v-sheet\b[\s\S]*home-start-screen__panel/,
281
+ message: "Base generated apps need a real sheet-based starter panel."
282
+ }),
283
+ Object.freeze({
284
+ id: "starter-home-responsive-title",
285
+ pattern: /--generated-ui-screen-title-size/,
286
+ message: "Base generated apps need shared responsive starter typography."
287
+ })
288
+ ])
289
+ }),
290
+ "shell-home": Object.freeze({
291
+ requiredPatterns: Object.freeze([
292
+ Object.freeze({
293
+ id: "app-surface-profile",
294
+ pattern: /generated-ui-screen--app/,
295
+ message: "Shell starter home must use the app surface density profile."
296
+ }),
297
+ Object.freeze({
298
+ id: "shell-home-health",
299
+ pattern: /Service health/,
300
+ message: "Shell starter home should expose real runtime health state."
301
+ }),
302
+ Object.freeze({
303
+ id: "shell-home-responsive-action",
304
+ pattern: /min-height:\s*48px/,
305
+ message: "Shell starter home actions need compact tap targets."
306
+ })
307
+ ])
308
+ })
309
+ });
310
+ const GENERATED_UI_WORKFLOW_ROUTE_SEGMENTS = new Set(["create", "edit", "new", "setup"]);
311
+
312
+ function matchesGeneratedUiContractPattern(source = "", pattern) {
313
+ const sourceText = String(source || "");
314
+ if (pattern instanceof RegExp) {
315
+ pattern.lastIndex = 0;
316
+ return pattern.test(sourceText);
317
+ }
318
+ const literalPattern = String(pattern || "");
319
+ return literalPattern ? sourceText.includes(literalPattern) : false;
320
+ }
321
+
322
+ function normalizeGeneratedUiContractPattern(patternEntry = {}, fallbackMessage = "") {
323
+ if (patternEntry instanceof RegExp || typeof patternEntry === "string") {
324
+ return Object.freeze({
325
+ id: String(patternEntry),
326
+ pattern: patternEntry,
327
+ message: fallbackMessage
328
+ });
329
+ }
330
+ return Object.freeze({
331
+ id: normalizeText(patternEntry?.id) || String(patternEntry?.pattern || ""),
332
+ pattern: patternEntry?.pattern || "",
333
+ message: normalizeText(patternEntry?.message) || fallbackMessage
334
+ });
335
+ }
336
+
337
+ function normalizeGeneratedUiContractPatternList(patternEntries = [], fallbackMessage = "") {
338
+ return (Array.isArray(patternEntries) ? patternEntries : [])
339
+ .map((entry) => normalizeGeneratedUiContractPattern(entry, fallbackMessage))
340
+ .filter((entry) => entry.id && entry.pattern);
341
+ }
342
+
343
+ function resolveGeneratedUiSourceContractProfile(profile = "") {
344
+ const normalizedProfile = normalizeText(profile).toLowerCase();
345
+ return GENERATED_UI_SOURCE_CONTRACT_PROFILES[normalizedProfile] || Object.freeze({});
346
+ }
347
+
348
+ function collectGeneratedUiSourceContractIssues(source = "", {
349
+ profile = "",
350
+ forbidLiveCopy = undefined,
351
+ forbidCardShell = undefined,
352
+ forbiddenPatterns = [],
353
+ requiredPatterns = []
354
+ } = {}) {
355
+ const profileContract = resolveGeneratedUiSourceContractProfile(profile);
356
+ const shouldForbidLiveCopy = forbidLiveCopy ?? profileContract.forbidLiveCopy ?? true;
357
+ const shouldForbidCardShell = forbidCardShell ?? profileContract.forbidCardShell ?? false;
358
+ const resolvedForbiddenPatterns = [
359
+ ...(shouldForbidLiveCopy ? GENERATED_UI_FORBIDDEN_LIVE_COPY_PATTERNS : []),
360
+ ...(shouldForbidCardShell ? GENERATED_UI_FORBIDDEN_CARD_SHELL_PATTERNS : []),
361
+ ...normalizeGeneratedUiContractPatternList(profileContract.forbiddenPatterns, "Generated UI contains forbidden source."),
362
+ ...normalizeGeneratedUiContractPatternList(forbiddenPatterns, "Generated UI contains forbidden source.")
363
+ ];
364
+ const resolvedRequiredPatterns = [
365
+ ...normalizeGeneratedUiContractPatternList(profileContract.requiredPatterns, "Generated UI is missing required source."),
366
+ ...normalizeGeneratedUiContractPatternList(requiredPatterns, "Generated UI is missing required source.")
367
+ ];
368
+ const issues = [];
369
+
370
+ for (const patternEntry of resolvedForbiddenPatterns) {
371
+ if (!matchesGeneratedUiContractPattern(source, patternEntry.pattern)) {
372
+ continue;
373
+ }
374
+ issues.push(Object.freeze({
375
+ kind: "forbidden",
376
+ id: patternEntry.id,
377
+ message: patternEntry.message
378
+ }));
379
+ }
380
+
381
+ for (const patternEntry of resolvedRequiredPatterns) {
382
+ if (matchesGeneratedUiContractPattern(source, patternEntry.pattern)) {
383
+ continue;
384
+ }
385
+ issues.push(Object.freeze({
386
+ kind: "missing",
387
+ id: patternEntry.id,
388
+ message: patternEntry.message
389
+ }));
390
+ }
391
+
392
+ return Object.freeze(issues);
393
+ }
394
+
395
+ function assertGeneratedUiSourceContract(source = "", options = {}) {
396
+ const issues = collectGeneratedUiSourceContractIssues(source, options);
397
+ if (issues.length < 1) {
398
+ return;
399
+ }
400
+ const sourceName = normalizeText(options?.sourceName);
401
+ const sourceLabel = sourceName ? ` for ${sourceName}` : "";
402
+ throw new Error(
403
+ `Generated UI source contract failed${sourceLabel}: ` +
404
+ issues.map((issue) => `${issue.kind}:${issue.id} - ${issue.message}`).join("; ")
405
+ );
406
+ }
407
+
408
+ function normalizeGeneratedUiNavigationRole(value = "") {
409
+ const normalizedRole = normalizeText(value).toLowerCase();
410
+ if (!normalizedRole) {
411
+ return GENERATED_UI_NAVIGATION_ROLE_DEFAULT;
412
+ }
413
+ if (!GENERATED_UI_NAVIGATION_ROLE_VALUES.includes(normalizedRole)) {
414
+ throw new Error(`navigation-role must be one of: ${GENERATED_UI_NAVIGATION_ROLE_VALUES.join(", ")}.`);
415
+ }
416
+ return normalizedRole;
417
+ }
418
+
419
+ function hasExplicitGeneratedUiNavigationRole(options = {}) {
420
+ if (!options || typeof options !== "object") {
421
+ return false;
422
+ }
423
+ return Object.prototype.hasOwnProperty.call(options, "navigation-role") &&
424
+ Boolean(normalizeText(options?.["navigation-role"]));
425
+ }
426
+
427
+ function normalizeGeneratedUiRouteSegments(routePath = "") {
428
+ return normalizeText(routePath)
429
+ .replaceAll("\\", "/")
430
+ .split("/")
431
+ .map((entry) => normalizeText(entry))
432
+ .filter(Boolean);
433
+ }
434
+
435
+ function isGeneratedUiDynamicRouteSegment(routeSegment = "") {
436
+ const normalizedSegment = normalizeText(routeSegment);
437
+ return normalizedSegment.startsWith("[") && normalizedSegment.endsWith("]");
438
+ }
439
+
440
+ function resolveGeneratedUiSurfaceProfile(surfaceProfile = "") {
441
+ const surfaceProfileId = normalizeText(surfaceProfile).toLowerCase();
442
+ return GENERATED_UI_SURFACE_PROFILES[surfaceProfileId] || GENERATED_UI_SURFACE_PROFILES.task;
443
+ }
444
+
445
+ function buildGeneratedUiScreenClassName(baseClassName = "", {
446
+ surfaceProfile = ""
447
+ } = {}) {
448
+ const profile = resolveGeneratedUiSurfaceProfile(surfaceProfile);
449
+ return [
450
+ "generated-ui-screen",
451
+ profile.className,
452
+ normalizeText(baseClassName)
453
+ ]
454
+ .filter(Boolean)
455
+ .join(" ");
456
+ }
457
+
458
+ function inferGeneratedUiNavigationRole(options = {}, {
459
+ dynamicRoutePolicy = "leaf",
460
+ routePath = ""
461
+ } = {}) {
462
+ if (hasExplicitGeneratedUiNavigationRole(options)) {
463
+ return normalizeGeneratedUiNavigationRole(options?.["navigation-role"]);
464
+ }
465
+
466
+ const routeSegments = normalizeGeneratedUiRouteSegments(routePath);
467
+ const dynamicRouteSegments = routeSegments.filter((routeSegment) => isGeneratedUiDynamicRouteSegment(routeSegment));
468
+ const lastRouteSegment = routeSegments.at(-1) || "";
469
+ if (
470
+ dynamicRouteSegments.length > 0 &&
471
+ (
472
+ normalizeText(dynamicRoutePolicy).toLowerCase() === "any" ||
473
+ isGeneratedUiDynamicRouteSegment(lastRouteSegment)
474
+ )
475
+ ) {
476
+ return "detail";
477
+ }
478
+ if (GENERATED_UI_WORKFLOW_ROUTE_SEGMENTS.has(lastRouteSegment)) {
479
+ return "workflow";
480
+ }
481
+ return GENERATED_UI_NAVIGATION_ROLE_DEFAULT;
482
+ }
483
+
484
+ function isGeneratedUiNoLinkNavigationRole(value = "") {
485
+ return GENERATED_UI_NO_LINK_NAVIGATION_ROLE_SET.has(normalizeGeneratedUiNavigationRole(value));
486
+ }
487
+
488
+ function resolveGeneratedUiNavigationRoleLinkPlacement(options = {}, inferenceContext = {}) {
489
+ const explicitPlacement = normalizeText(options?.["link-placement"]);
490
+ if (explicitPlacement) {
491
+ return explicitPlacement;
492
+ }
493
+ const role = inferGeneratedUiNavigationRole(options, inferenceContext);
494
+ return GENERATED_UI_NAVIGATION_ROLE_LINK_PLACEMENTS[role] || "";
495
+ }
496
+
497
+ function shouldCreateGeneratedUiNavigationLink(options = {}, {
498
+ allowLinkTo = false,
499
+ dynamicRoutePolicy = "leaf",
500
+ routePath = ""
501
+ } = {}) {
502
+ const hasExplicitNoLinkRole = hasExplicitGeneratedUiNavigationRole(options) &&
503
+ GENERATED_UI_NO_LINK_NAVIGATION_ROLE_SET.has(normalizeGeneratedUiNavigationRole(options?.["navigation-role"]));
504
+ const role = inferGeneratedUiNavigationRole(options, {
505
+ dynamicRoutePolicy,
506
+ routePath
507
+ });
508
+ const linkPlacement = normalizeText(options?.["link-placement"]);
509
+ const linkTo = allowLinkTo ? normalizeText(options?.["link-to"]) : "";
510
+ if (!GENERATED_UI_NO_LINK_NAVIGATION_ROLE_SET.has(role)) {
511
+ return true;
512
+ }
513
+ if (linkPlacement || linkTo) {
514
+ if (!hasExplicitNoLinkRole) {
515
+ return true;
516
+ }
517
+ const disallowedOptions = allowLinkTo ? "--link-placement or --link-to" : "--link-placement";
518
+ throw new Error(`navigation-role "${role}" cannot be combined with ${disallowedOptions}.`);
519
+ }
520
+ return false;
521
+ }
522
+
523
+ export {
524
+ GENERATED_UI_FORBIDDEN_CARD_SHELL_PATTERNS,
525
+ GENERATED_UI_FORBIDDEN_LIVE_COPY_PATTERNS,
526
+ GENERATED_UI_NAVIGATION_ROLE_DEFAULT,
527
+ GENERATED_UI_NAVIGATION_ROLE_LINK_PLACEMENTS,
528
+ GENERATED_UI_NAVIGATION_ROLE_OPTION,
529
+ GENERATED_UI_NAVIGATION_ROLE_VALUES,
530
+ GENERATED_UI_NO_LINK_NAVIGATION_ROLES,
531
+ GENERATED_UI_SOURCE_CONTRACT_PROFILES,
532
+ GENERATED_UI_SURFACE_PROFILES,
533
+ assertGeneratedUiSourceContract,
534
+ buildGeneratedUiScreenClassName,
535
+ collectGeneratedUiSourceContractIssues,
536
+ inferGeneratedUiNavigationRole,
537
+ isGeneratedUiNoLinkNavigationRole,
538
+ normalizeGeneratedUiNavigationRole,
539
+ resolveGeneratedUiSurfaceProfile,
540
+ resolveGeneratedUiNavigationRoleLinkPlacement,
541
+ shouldCreateGeneratedUiNavigationLink
542
+ };