@empline/preflight 1.1.25 → 1.1.26
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,97 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* UI Uniformity & Visual Polish Preflight (NON-BLOCKING)
|
|
4
|
+
*
|
|
5
|
+
* Validates visual polish patterns to ensure a premium, cohesive UX similar
|
|
6
|
+
* to platforms like X (Twitter) or Facebook. This check goes beyond structural
|
|
7
|
+
* consistency to enforce micro-interactions, transitions, and animation uniformity.
|
|
8
|
+
*
|
|
9
|
+
* Checks:
|
|
10
|
+
* 1. Transition Token Consistency - All transitions must use design tokens
|
|
11
|
+
* 2. Hover State Completeness - Interactive elements need hover/focus feedback
|
|
12
|
+
* 3. Animation Library Uniformity - No mixing of animation approaches
|
|
13
|
+
* 4. Loading State Elegance - Prefer skeleton/shimmer for content loading
|
|
14
|
+
* 5. Micro-Interaction Feedback - Buttons/actions should provide visual feedback
|
|
15
|
+
* 6. Focus Ring Consistency - Keyboard focus must be visible and consistent
|
|
16
|
+
* 7. Disabled State Polish - Disabled elements should use consistent styling
|
|
17
|
+
* 8. Interactive Cursor Indication - Clickable elements need proper cursors
|
|
18
|
+
*
|
|
19
|
+
* Usage:
|
|
20
|
+
* pnpm preflight:ui-uniformity
|
|
21
|
+
* pnpm preflight:ui-uniformity --verbose
|
|
22
|
+
*/
|
|
23
|
+
export declare const id = "ui/ui-uniformity-polish";
|
|
24
|
+
export declare const name = "UI Uniformity & Visual Polish";
|
|
25
|
+
export declare const description = "Validates visual polish patterns for premium, cohesive UX";
|
|
26
|
+
export declare const category = "ui";
|
|
27
|
+
export declare const blocking = false;
|
|
28
|
+
export declare const tags: string[];
|
|
29
|
+
interface CheckResult {
|
|
30
|
+
name: string;
|
|
31
|
+
passed: boolean;
|
|
32
|
+
duration: number;
|
|
33
|
+
errors: string[];
|
|
34
|
+
warnings: string[];
|
|
35
|
+
info: string[];
|
|
36
|
+
}
|
|
37
|
+
declare class UIUniformityPreflight {
|
|
38
|
+
private verbose;
|
|
39
|
+
private projectRoot;
|
|
40
|
+
constructor(options?: {
|
|
41
|
+
verbose?: boolean;
|
|
42
|
+
projectRoot?: string;
|
|
43
|
+
});
|
|
44
|
+
private readFile;
|
|
45
|
+
private shouldExclude;
|
|
46
|
+
private getFiles;
|
|
47
|
+
/**
|
|
48
|
+
* Check 1: Transition Token Consistency
|
|
49
|
+
* Ensures all transitions use design system tokens
|
|
50
|
+
*/
|
|
51
|
+
private validateTransitionConsistency;
|
|
52
|
+
/**
|
|
53
|
+
* Check 2: Hover State Completeness
|
|
54
|
+
* Ensures interactive elements have hover/focus feedback
|
|
55
|
+
*/
|
|
56
|
+
private validateHoverStates;
|
|
57
|
+
/**
|
|
58
|
+
* Check 3: Animation Library Uniformity
|
|
59
|
+
* Detects mixing of different animation libraries
|
|
60
|
+
*/
|
|
61
|
+
private validateAnimationLibraryUniformity;
|
|
62
|
+
/**
|
|
63
|
+
* Check 4: Loading State Elegance
|
|
64
|
+
* Ensures content loading uses elegant patterns (skeleton/shimmer)
|
|
65
|
+
*/
|
|
66
|
+
private validateLoadingStateElegance;
|
|
67
|
+
/**
|
|
68
|
+
* Check 5: Focus Ring Consistency
|
|
69
|
+
* Ensures keyboard focus indicators are visible and consistent
|
|
70
|
+
*/
|
|
71
|
+
private validateFocusRingConsistency;
|
|
72
|
+
/**
|
|
73
|
+
* Check 6: Disabled State Polish
|
|
74
|
+
* Ensures disabled elements have consistent, accessible styling
|
|
75
|
+
*/
|
|
76
|
+
private validateDisabledStatePolish;
|
|
77
|
+
/**
|
|
78
|
+
* Check 7: Cursor Indication
|
|
79
|
+
* Ensures clickable elements use proper cursor styles
|
|
80
|
+
*/
|
|
81
|
+
private validateCursorIndication;
|
|
82
|
+
/**
|
|
83
|
+
* Check 8: Micro-Interaction Feedback
|
|
84
|
+
* Validates that buttons and actions provide visual feedback
|
|
85
|
+
*/
|
|
86
|
+
private validateMicroInteractions;
|
|
87
|
+
/**
|
|
88
|
+
* Run all checks
|
|
89
|
+
*/
|
|
90
|
+
runAll(): Promise<{
|
|
91
|
+
passed: boolean;
|
|
92
|
+
results: CheckResult[];
|
|
93
|
+
}>;
|
|
94
|
+
private printResults;
|
|
95
|
+
}
|
|
96
|
+
export { UIUniformityPreflight };
|
|
97
|
+
//# sourceMappingURL=ui-uniformity-polish.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-uniformity-polish.d.ts","sourceRoot":"","sources":["../../../src/checks/ui/ui-uniformity-polish.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;GAoBG;AASH,eAAO,MAAM,EAAE,4BAA4B,CAAC;AAC5C,eAAO,MAAM,IAAI,kCAAkC,CAAC;AACpD,eAAO,MAAM,WAAW,8DAA8D,CAAC;AACvF,eAAO,MAAM,QAAQ,OAAO,CAAC;AAC7B,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAC9B,eAAO,MAAM,IAAI,UAShB,CAAC;AAEF,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAiLD,cAAM,qBAAqB;IACzB,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,WAAW,CAAS;gBAEhB,OAAO,GAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAO;IAKrE,OAAO,CAAC,QAAQ;IAMhB,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,QAAQ;IAYhB;;;OAGG;IACH,OAAO,CAAC,6BAA6B;IA6DrC;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IA6D3B;;;OAGG;IACH,OAAO,CAAC,kCAAkC;IA0D1C;;;OAGG;IACH,OAAO,CAAC,4BAA4B;IAyDpC;;;OAGG;IACH,OAAO,CAAC,4BAA4B;IAgEpC;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IA0DnC;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IAmDhC;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IAqEjC;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,WAAW,EAAE,CAAA;KAAE,CAAC;IAuBpE,OAAO,CAAC,YAAY;CAuDrB;AAkBD,OAAO,EAAE,qBAAqB,EAAE,CAAC"}
|
|
@@ -0,0 +1,759 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* UI Uniformity & Visual Polish Preflight (NON-BLOCKING)
|
|
5
|
+
*
|
|
6
|
+
* Validates visual polish patterns to ensure a premium, cohesive UX similar
|
|
7
|
+
* to platforms like X (Twitter) or Facebook. This check goes beyond structural
|
|
8
|
+
* consistency to enforce micro-interactions, transitions, and animation uniformity.
|
|
9
|
+
*
|
|
10
|
+
* Checks:
|
|
11
|
+
* 1. Transition Token Consistency - All transitions must use design tokens
|
|
12
|
+
* 2. Hover State Completeness - Interactive elements need hover/focus feedback
|
|
13
|
+
* 3. Animation Library Uniformity - No mixing of animation approaches
|
|
14
|
+
* 4. Loading State Elegance - Prefer skeleton/shimmer for content loading
|
|
15
|
+
* 5. Micro-Interaction Feedback - Buttons/actions should provide visual feedback
|
|
16
|
+
* 6. Focus Ring Consistency - Keyboard focus must be visible and consistent
|
|
17
|
+
* 7. Disabled State Polish - Disabled elements should use consistent styling
|
|
18
|
+
* 8. Interactive Cursor Indication - Clickable elements need proper cursors
|
|
19
|
+
*
|
|
20
|
+
* Usage:
|
|
21
|
+
* pnpm preflight:ui-uniformity
|
|
22
|
+
* pnpm preflight:ui-uniformity --verbose
|
|
23
|
+
*/
|
|
24
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
25
|
+
if (k2 === undefined) k2 = k;
|
|
26
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
27
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
28
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
29
|
+
}
|
|
30
|
+
Object.defineProperty(o, k2, desc);
|
|
31
|
+
}) : (function(o, m, k, k2) {
|
|
32
|
+
if (k2 === undefined) k2 = k;
|
|
33
|
+
o[k2] = m[k];
|
|
34
|
+
}));
|
|
35
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
36
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
37
|
+
}) : function(o, v) {
|
|
38
|
+
o["default"] = v;
|
|
39
|
+
});
|
|
40
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
41
|
+
var ownKeys = function(o) {
|
|
42
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
43
|
+
var ar = [];
|
|
44
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
45
|
+
return ar;
|
|
46
|
+
};
|
|
47
|
+
return ownKeys(o);
|
|
48
|
+
};
|
|
49
|
+
return function (mod) {
|
|
50
|
+
if (mod && mod.__esModule) return mod;
|
|
51
|
+
var result = {};
|
|
52
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
53
|
+
__setModuleDefault(result, mod);
|
|
54
|
+
return result;
|
|
55
|
+
};
|
|
56
|
+
})();
|
|
57
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
58
|
+
exports.UIUniformityPreflight = exports.tags = exports.blocking = exports.category = exports.description = exports.name = exports.id = void 0;
|
|
59
|
+
const fs = __importStar(require("fs"));
|
|
60
|
+
const glob_1 = require("glob");
|
|
61
|
+
const path = __importStar(require("path"));
|
|
62
|
+
const glob_patterns_1 = require("../../shared/glob-patterns");
|
|
63
|
+
const console_chars_1 = require("../../utils/console-chars");
|
|
64
|
+
// METADATA - Required for plugin loader discovery
|
|
65
|
+
exports.id = "ui/ui-uniformity-polish";
|
|
66
|
+
exports.name = "UI Uniformity & Visual Polish";
|
|
67
|
+
exports.description = "Validates visual polish patterns for premium, cohesive UX";
|
|
68
|
+
exports.category = "ui";
|
|
69
|
+
exports.blocking = false;
|
|
70
|
+
exports.tags = [
|
|
71
|
+
"ui",
|
|
72
|
+
"ux",
|
|
73
|
+
"polish",
|
|
74
|
+
"transitions",
|
|
75
|
+
"animations",
|
|
76
|
+
"micro-interactions",
|
|
77
|
+
"hover",
|
|
78
|
+
"focus",
|
|
79
|
+
];
|
|
80
|
+
// Files/patterns to exclude from checks
|
|
81
|
+
const EXCLUDED_FILES = [
|
|
82
|
+
".stories.tsx",
|
|
83
|
+
".test.tsx",
|
|
84
|
+
".spec.tsx",
|
|
85
|
+
"Button.examples.tsx",
|
|
86
|
+
"DevErrorBoundary.tsx",
|
|
87
|
+
];
|
|
88
|
+
// Directories to exclude
|
|
89
|
+
const EXCLUDED_DIRS = [
|
|
90
|
+
...glob_patterns_1.STANDARD_EXCLUDES,
|
|
91
|
+
...glob_patterns_1.TEST_FILE_EXCLUDES,
|
|
92
|
+
"**/api/**",
|
|
93
|
+
"**/dev/**",
|
|
94
|
+
"**/node_modules/**",
|
|
95
|
+
"**/.next/**",
|
|
96
|
+
];
|
|
97
|
+
// =============================================================================
|
|
98
|
+
// PATTERN DEFINITIONS
|
|
99
|
+
// =============================================================================
|
|
100
|
+
/**
|
|
101
|
+
* Allowed transition token patterns
|
|
102
|
+
* These ensure all animations use the design system
|
|
103
|
+
*/
|
|
104
|
+
const TRANSITION_TOKEN_PATTERNS = [
|
|
105
|
+
// CSS variable transitions
|
|
106
|
+
/var\(--transition/,
|
|
107
|
+
/var\(--duration/,
|
|
108
|
+
/var\(--ease/,
|
|
109
|
+
// Tailwind transition utilities
|
|
110
|
+
/transition-all/,
|
|
111
|
+
/transition-colors/,
|
|
112
|
+
/transition-opacity/,
|
|
113
|
+
/transition-shadow/,
|
|
114
|
+
/transition-transform/,
|
|
115
|
+
/transition-none/,
|
|
116
|
+
// Duration classes
|
|
117
|
+
/duration-\d+/,
|
|
118
|
+
// Ease classes
|
|
119
|
+
/ease-in-out/,
|
|
120
|
+
/ease-in/,
|
|
121
|
+
/ease-out/,
|
|
122
|
+
/ease-linear/,
|
|
123
|
+
];
|
|
124
|
+
/**
|
|
125
|
+
* Hardcoded transition patterns (anti-pattern)
|
|
126
|
+
* These should be replaced with design tokens
|
|
127
|
+
*/
|
|
128
|
+
const HARDCODED_TRANSITION_PATTERNS = [
|
|
129
|
+
// Inline transition with hardcoded duration
|
|
130
|
+
/transition:\s*[\w-]+\s+\d+(\.\d+)?s/,
|
|
131
|
+
// Inline transition-duration without var()
|
|
132
|
+
/transition-duration:\s*\d+(\.\d+)?s(?!.*var\()/,
|
|
133
|
+
// Arbitrary Tailwind values that aren't in the design system
|
|
134
|
+
/\[transition:.*?\d+ms.*?\]/,
|
|
135
|
+
];
|
|
136
|
+
/**
|
|
137
|
+
* Animation library patterns to detect mixing
|
|
138
|
+
*/
|
|
139
|
+
const ANIMATION_LIBRARIES = {
|
|
140
|
+
framerMotion: {
|
|
141
|
+
pattern: /from\s+["']framer-motion["']|import.*motion\s+from/,
|
|
142
|
+
name: "Framer Motion",
|
|
143
|
+
},
|
|
144
|
+
reactSpring: {
|
|
145
|
+
pattern: /from\s+["']@react-spring\/|from\s+["']react-spring["']/,
|
|
146
|
+
name: "React Spring",
|
|
147
|
+
},
|
|
148
|
+
animateCss: {
|
|
149
|
+
pattern: /animate__animated|animate__/,
|
|
150
|
+
name: "Animate.css",
|
|
151
|
+
},
|
|
152
|
+
gsap: {
|
|
153
|
+
pattern: /from\s+["']gsap["']/,
|
|
154
|
+
name: "GSAP",
|
|
155
|
+
},
|
|
156
|
+
cssAnimations: {
|
|
157
|
+
pattern: /@keyframes\s+\w+/,
|
|
158
|
+
name: "CSS @keyframes",
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
/**
|
|
162
|
+
* Loading state patterns
|
|
163
|
+
*/
|
|
164
|
+
const LOADING_PATTERNS = {
|
|
165
|
+
// Preferred patterns (elegant)
|
|
166
|
+
elegant: [
|
|
167
|
+
/UnifiedSkeleton/,
|
|
168
|
+
/SkeletonLoader/,
|
|
169
|
+
/animate-shimmer/,
|
|
170
|
+
/animate-pulse/,
|
|
171
|
+
/Skeleton\s/,
|
|
172
|
+
/\bskeleton\b/i,
|
|
173
|
+
],
|
|
174
|
+
// Acceptable patterns (spinners for actions)
|
|
175
|
+
acceptable: [
|
|
176
|
+
/LoadingSpinner/,
|
|
177
|
+
/CircularProgress/,
|
|
178
|
+
/Loader2/,
|
|
179
|
+
/Spinner/,
|
|
180
|
+
],
|
|
181
|
+
};
|
|
182
|
+
/**
|
|
183
|
+
* Interactive element patterns that need hover states
|
|
184
|
+
*/
|
|
185
|
+
const INTERACTIVE_ELEMENTS = [
|
|
186
|
+
/<Button[^/]*>/,
|
|
187
|
+
/<IconButton[^/]*>/,
|
|
188
|
+
/<a\s[^>]*href/,
|
|
189
|
+
/<Link[^/]*>/,
|
|
190
|
+
/onClick=\{/,
|
|
191
|
+
/role=["']button["']/,
|
|
192
|
+
];
|
|
193
|
+
/**
|
|
194
|
+
* Hover/focus feedback patterns
|
|
195
|
+
*/
|
|
196
|
+
const HOVER_FOCUS_PATTERNS = [
|
|
197
|
+
/hover:/,
|
|
198
|
+
/focus:/,
|
|
199
|
+
/focus-visible:/,
|
|
200
|
+
/active:/,
|
|
201
|
+
/group-hover:/,
|
|
202
|
+
/peer-hover:/,
|
|
203
|
+
/:hover\s*\{/,
|
|
204
|
+
/:focus\s*\{/,
|
|
205
|
+
];
|
|
206
|
+
/**
|
|
207
|
+
* Focus ring patterns for accessibility
|
|
208
|
+
*/
|
|
209
|
+
const FOCUS_RING_PATTERNS = [
|
|
210
|
+
/focus-visible:ring/,
|
|
211
|
+
/focus:ring/,
|
|
212
|
+
/focus:outline/,
|
|
213
|
+
/focus-visible:outline/,
|
|
214
|
+
/:focus-visible\s*\{[^}]*ring/,
|
|
215
|
+
/:focus-visible\s*\{[^}]*outline/,
|
|
216
|
+
];
|
|
217
|
+
/**
|
|
218
|
+
* Disabled state patterns
|
|
219
|
+
*/
|
|
220
|
+
const DISABLED_STATE_PATTERNS = {
|
|
221
|
+
// Good patterns
|
|
222
|
+
good: [
|
|
223
|
+
/disabled:opacity-/,
|
|
224
|
+
/disabled:cursor-not-allowed/,
|
|
225
|
+
/disabled:bg-/,
|
|
226
|
+
/disabled:text-/,
|
|
227
|
+
/\[&:disabled\]/,
|
|
228
|
+
],
|
|
229
|
+
// Anti-patterns (inconsistent or missing)
|
|
230
|
+
bad: [
|
|
231
|
+
/disabled.*opacity-25/, // Too light, not accessible
|
|
232
|
+
/disabled.*opacity-30/, // Too light
|
|
233
|
+
],
|
|
234
|
+
};
|
|
235
|
+
/**
|
|
236
|
+
* Cursor patterns for interactive elements
|
|
237
|
+
*/
|
|
238
|
+
const CURSOR_PATTERNS = {
|
|
239
|
+
interactive: /cursor-pointer/,
|
|
240
|
+
disabled: /cursor-not-allowed/,
|
|
241
|
+
loading: /cursor-wait/,
|
|
242
|
+
};
|
|
243
|
+
class UIUniformityPreflight {
|
|
244
|
+
verbose;
|
|
245
|
+
projectRoot;
|
|
246
|
+
constructor(options = {}) {
|
|
247
|
+
this.verbose = options.verbose || false;
|
|
248
|
+
this.projectRoot = options.projectRoot || process.cwd();
|
|
249
|
+
}
|
|
250
|
+
readFile(filePath) {
|
|
251
|
+
const fullPath = path.join(this.projectRoot, filePath);
|
|
252
|
+
if (!fs.existsSync(fullPath))
|
|
253
|
+
return null;
|
|
254
|
+
return fs.readFileSync(fullPath, "utf-8");
|
|
255
|
+
}
|
|
256
|
+
shouldExclude(fileName) {
|
|
257
|
+
return EXCLUDED_FILES.some((excl) => fileName.includes(excl));
|
|
258
|
+
}
|
|
259
|
+
getFiles(patterns) {
|
|
260
|
+
const files = [];
|
|
261
|
+
for (const pattern of patterns) {
|
|
262
|
+
const matches = glob_1.glob.sync(pattern, {
|
|
263
|
+
cwd: this.projectRoot,
|
|
264
|
+
ignore: EXCLUDED_DIRS,
|
|
265
|
+
});
|
|
266
|
+
files.push(...matches);
|
|
267
|
+
}
|
|
268
|
+
return [...new Set(files)];
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Check 1: Transition Token Consistency
|
|
272
|
+
* Ensures all transitions use design system tokens
|
|
273
|
+
*/
|
|
274
|
+
validateTransitionConsistency() {
|
|
275
|
+
const startTime = Date.now();
|
|
276
|
+
const errors = [];
|
|
277
|
+
const warnings = [];
|
|
278
|
+
const info = [];
|
|
279
|
+
const files = this.getFiles(["components/**/*.tsx", "app/**/*.tsx"]);
|
|
280
|
+
let filesWithTransitions = 0;
|
|
281
|
+
let tokenizedTransitions = 0;
|
|
282
|
+
let hardcodedTransitions = 0;
|
|
283
|
+
for (const filePath of files) {
|
|
284
|
+
const content = this.readFile(filePath);
|
|
285
|
+
if (!content)
|
|
286
|
+
continue;
|
|
287
|
+
const fileName = path.basename(filePath);
|
|
288
|
+
if (this.shouldExclude(fileName))
|
|
289
|
+
continue;
|
|
290
|
+
// Check for any transition usage
|
|
291
|
+
const hasTransition = content.includes("transition") || content.includes("duration-");
|
|
292
|
+
if (!hasTransition)
|
|
293
|
+
continue;
|
|
294
|
+
filesWithTransitions++;
|
|
295
|
+
// Check for tokenized transitions
|
|
296
|
+
const hasTokenized = TRANSITION_TOKEN_PATTERNS.some((p) => p.test(content));
|
|
297
|
+
if (hasTokenized)
|
|
298
|
+
tokenizedTransitions++;
|
|
299
|
+
// Check for hardcoded transitions (anti-pattern)
|
|
300
|
+
for (const pattern of HARDCODED_TRANSITION_PATTERNS) {
|
|
301
|
+
const matches = content.match(pattern);
|
|
302
|
+
if (matches) {
|
|
303
|
+
hardcodedTransitions++;
|
|
304
|
+
warnings.push(`${fileName}: Hardcoded transition found. Use design tokens (duration-*, ease-*) instead.`);
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
const coverage = filesWithTransitions > 0
|
|
310
|
+
? Math.round((tokenizedTransitions / filesWithTransitions) * 100)
|
|
311
|
+
: 100;
|
|
312
|
+
info.push(`Files with transitions: ${filesWithTransitions}, Using tokens: ${tokenizedTransitions} (${coverage}%)`);
|
|
313
|
+
return {
|
|
314
|
+
name: "Transition Token Consistency",
|
|
315
|
+
passed: hardcodedTransitions === 0,
|
|
316
|
+
duration: Date.now() - startTime,
|
|
317
|
+
errors,
|
|
318
|
+
warnings,
|
|
319
|
+
info,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Check 2: Hover State Completeness
|
|
324
|
+
* Ensures interactive elements have hover/focus feedback
|
|
325
|
+
*/
|
|
326
|
+
validateHoverStates() {
|
|
327
|
+
const startTime = Date.now();
|
|
328
|
+
const errors = [];
|
|
329
|
+
const warnings = [];
|
|
330
|
+
const info = [];
|
|
331
|
+
const files = this.getFiles(["components/**/*.tsx", "app/**/*.tsx"]);
|
|
332
|
+
let interactiveElements = 0;
|
|
333
|
+
let elementsWithFeedback = 0;
|
|
334
|
+
const missingFeedbackFiles = [];
|
|
335
|
+
for (const filePath of files) {
|
|
336
|
+
const content = this.readFile(filePath);
|
|
337
|
+
if (!content)
|
|
338
|
+
continue;
|
|
339
|
+
const fileName = path.basename(filePath);
|
|
340
|
+
if (this.shouldExclude(fileName))
|
|
341
|
+
continue;
|
|
342
|
+
// Check if file has interactive elements
|
|
343
|
+
const hasInteractive = INTERACTIVE_ELEMENTS.some((p) => p.test(content));
|
|
344
|
+
if (!hasInteractive)
|
|
345
|
+
continue;
|
|
346
|
+
interactiveElements++;
|
|
347
|
+
// Check for hover/focus feedback
|
|
348
|
+
const hasFeedback = HOVER_FOCUS_PATTERNS.some((p) => p.test(content));
|
|
349
|
+
if (hasFeedback) {
|
|
350
|
+
elementsWithFeedback++;
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
missingFeedbackFiles.push(fileName);
|
|
354
|
+
warnings.push(`${fileName}: Interactive elements found without hover/focus feedback. Add hover: or focus: states.`);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
// Limit warnings to avoid noise
|
|
358
|
+
if (missingFeedbackFiles.length > 5) {
|
|
359
|
+
warnings.length = 5;
|
|
360
|
+
warnings.push(`...and ${missingFeedbackFiles.length - 5} more files`);
|
|
361
|
+
}
|
|
362
|
+
const coverage = interactiveElements > 0
|
|
363
|
+
? Math.round((elementsWithFeedback / interactiveElements) * 100)
|
|
364
|
+
: 100;
|
|
365
|
+
info.push(`Interactive files: ${interactiveElements}, With feedback: ${elementsWithFeedback} (${coverage}%)`);
|
|
366
|
+
return {
|
|
367
|
+
name: "Hover State Completeness",
|
|
368
|
+
passed: coverage >= 80, // 80% threshold
|
|
369
|
+
duration: Date.now() - startTime,
|
|
370
|
+
errors,
|
|
371
|
+
warnings,
|
|
372
|
+
info,
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Check 3: Animation Library Uniformity
|
|
377
|
+
* Detects mixing of different animation libraries
|
|
378
|
+
*/
|
|
379
|
+
validateAnimationLibraryUniformity() {
|
|
380
|
+
const startTime = Date.now();
|
|
381
|
+
const errors = [];
|
|
382
|
+
const warnings = [];
|
|
383
|
+
const info = [];
|
|
384
|
+
const files = this.getFiles([
|
|
385
|
+
"components/**/*.tsx",
|
|
386
|
+
"app/**/*.tsx",
|
|
387
|
+
"lib/**/*.ts",
|
|
388
|
+
]);
|
|
389
|
+
const librariesUsed = new Map();
|
|
390
|
+
for (const filePath of files) {
|
|
391
|
+
const content = this.readFile(filePath);
|
|
392
|
+
if (!content)
|
|
393
|
+
continue;
|
|
394
|
+
const fileName = path.basename(filePath);
|
|
395
|
+
if (this.shouldExclude(fileName))
|
|
396
|
+
continue;
|
|
397
|
+
for (const [key, lib] of Object.entries(ANIMATION_LIBRARIES)) {
|
|
398
|
+
if (lib.pattern.test(content)) {
|
|
399
|
+
const existing = librariesUsed.get(lib.name) || [];
|
|
400
|
+
existing.push(fileName);
|
|
401
|
+
librariesUsed.set(lib.name, existing);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
const libCount = librariesUsed.size;
|
|
406
|
+
info.push(`Animation libraries detected: ${libCount}`);
|
|
407
|
+
if (libCount > 1) {
|
|
408
|
+
const libNames = [...librariesUsed.keys()].join(", ");
|
|
409
|
+
warnings.push(`Multiple animation libraries detected (${libNames}). Consider standardizing on one approach.`);
|
|
410
|
+
for (const [libName, files] of librariesUsed) {
|
|
411
|
+
info.push(` ${libName}: ${files.length} files`);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
else if (libCount === 1) {
|
|
415
|
+
const [libName] = librariesUsed.keys();
|
|
416
|
+
info.push(`Standardized on: ${libName}`);
|
|
417
|
+
}
|
|
418
|
+
else {
|
|
419
|
+
info.push("Using CSS/Tailwind animations only (good!)");
|
|
420
|
+
}
|
|
421
|
+
return {
|
|
422
|
+
name: "Animation Library Uniformity",
|
|
423
|
+
passed: libCount <= 1, // At most one library is ideal
|
|
424
|
+
duration: Date.now() - startTime,
|
|
425
|
+
errors,
|
|
426
|
+
warnings,
|
|
427
|
+
info,
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Check 4: Loading State Elegance
|
|
432
|
+
* Ensures content loading uses elegant patterns (skeleton/shimmer)
|
|
433
|
+
*/
|
|
434
|
+
validateLoadingStateElegance() {
|
|
435
|
+
const startTime = Date.now();
|
|
436
|
+
const errors = [];
|
|
437
|
+
const warnings = [];
|
|
438
|
+
const info = [];
|
|
439
|
+
const files = this.getFiles(["components/**/*.tsx", "app/**/*.tsx"]);
|
|
440
|
+
let elegantCount = 0;
|
|
441
|
+
let acceptableCount = 0;
|
|
442
|
+
let filesWithLoading = 0;
|
|
443
|
+
for (const filePath of files) {
|
|
444
|
+
const content = this.readFile(filePath);
|
|
445
|
+
if (!content)
|
|
446
|
+
continue;
|
|
447
|
+
const fileName = path.basename(filePath);
|
|
448
|
+
if (this.shouldExclude(fileName))
|
|
449
|
+
continue;
|
|
450
|
+
// Check for loading patterns
|
|
451
|
+
const hasElegant = LOADING_PATTERNS.elegant.some((p) => p.test(content));
|
|
452
|
+
const hasAcceptable = LOADING_PATTERNS.acceptable.some((p) => p.test(content));
|
|
453
|
+
if (hasElegant || hasAcceptable) {
|
|
454
|
+
filesWithLoading++;
|
|
455
|
+
if (hasElegant)
|
|
456
|
+
elegantCount++;
|
|
457
|
+
if (hasAcceptable && !hasElegant)
|
|
458
|
+
acceptableCount++;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
const elegantPercent = filesWithLoading > 0
|
|
462
|
+
? Math.round((elegantCount / filesWithLoading) * 100)
|
|
463
|
+
: 100;
|
|
464
|
+
info.push(`Files with loading: ${filesWithLoading}, Elegant (skeleton): ${elegantCount} (${elegantPercent}%), Spinner-only: ${acceptableCount}`);
|
|
465
|
+
if (acceptableCount > elegantCount && filesWithLoading > 10) {
|
|
466
|
+
warnings.push(`More spinner-based loading (${acceptableCount}) than skeleton-based (${elegantCount}). ` +
|
|
467
|
+
`Consider using UnifiedSkeleton or animate-pulse for content loading.`);
|
|
468
|
+
}
|
|
469
|
+
return {
|
|
470
|
+
name: "Loading State Elegance",
|
|
471
|
+
passed: elegantPercent >= 50 || filesWithLoading < 10,
|
|
472
|
+
duration: Date.now() - startTime,
|
|
473
|
+
errors,
|
|
474
|
+
warnings,
|
|
475
|
+
info,
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Check 5: Focus Ring Consistency
|
|
480
|
+
* Ensures keyboard focus indicators are visible and consistent
|
|
481
|
+
*/
|
|
482
|
+
validateFocusRingConsistency() {
|
|
483
|
+
const startTime = Date.now();
|
|
484
|
+
const errors = [];
|
|
485
|
+
const warnings = [];
|
|
486
|
+
const info = [];
|
|
487
|
+
const files = this.getFiles(["components/**/*.tsx", "app/**/*.tsx"]);
|
|
488
|
+
let interactiveFiles = 0;
|
|
489
|
+
let filesWithFocusRing = 0;
|
|
490
|
+
for (const filePath of files) {
|
|
491
|
+
const content = this.readFile(filePath);
|
|
492
|
+
if (!content)
|
|
493
|
+
continue;
|
|
494
|
+
const fileName = path.basename(filePath);
|
|
495
|
+
if (this.shouldExclude(fileName))
|
|
496
|
+
continue;
|
|
497
|
+
// Check if file has interactive elements
|
|
498
|
+
const hasInteractive = INTERACTIVE_ELEMENTS.some((p) => p.test(content));
|
|
499
|
+
if (!hasInteractive)
|
|
500
|
+
continue;
|
|
501
|
+
interactiveFiles++;
|
|
502
|
+
// Check for focus ring patterns
|
|
503
|
+
const hasFocusRing = FOCUS_RING_PATTERNS.some((p) => p.test(content));
|
|
504
|
+
if (hasFocusRing) {
|
|
505
|
+
filesWithFocusRing++;
|
|
506
|
+
}
|
|
507
|
+
// Check for dangerous outline:none without replacement
|
|
508
|
+
if (content.includes("outline-none") ||
|
|
509
|
+
content.includes("outline: none")) {
|
|
510
|
+
const hasRingReplacement = content.includes("focus:ring") ||
|
|
511
|
+
content.includes("focus-visible:ring");
|
|
512
|
+
if (!hasRingReplacement) {
|
|
513
|
+
warnings.push(`${fileName}: Uses outline-none without focus ring replacement. Add focus-visible:ring-* for accessibility.`);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
const coverage = interactiveFiles > 0
|
|
518
|
+
? Math.round((filesWithFocusRing / interactiveFiles) * 100)
|
|
519
|
+
: 100;
|
|
520
|
+
info.push(`Interactive files: ${interactiveFiles}, With focus rings: ${filesWithFocusRing} (${coverage}%)`);
|
|
521
|
+
return {
|
|
522
|
+
name: "Focus Ring Consistency",
|
|
523
|
+
passed: warnings.length === 0,
|
|
524
|
+
duration: Date.now() - startTime,
|
|
525
|
+
errors,
|
|
526
|
+
warnings: warnings.slice(0, 5), // Limit to 5 warnings
|
|
527
|
+
info,
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* Check 6: Disabled State Polish
|
|
532
|
+
* Ensures disabled elements have consistent, accessible styling
|
|
533
|
+
*/
|
|
534
|
+
validateDisabledStatePolish() {
|
|
535
|
+
const startTime = Date.now();
|
|
536
|
+
const errors = [];
|
|
537
|
+
const warnings = [];
|
|
538
|
+
const info = [];
|
|
539
|
+
const files = this.getFiles(["components/**/*.tsx"]);
|
|
540
|
+
let filesWithDisabled = 0;
|
|
541
|
+
let properlyStyled = 0;
|
|
542
|
+
for (const filePath of files) {
|
|
543
|
+
const content = this.readFile(filePath);
|
|
544
|
+
if (!content)
|
|
545
|
+
continue;
|
|
546
|
+
const fileName = path.basename(filePath);
|
|
547
|
+
if (this.shouldExclude(fileName))
|
|
548
|
+
continue;
|
|
549
|
+
// Check if file uses disabled state
|
|
550
|
+
if (!content.includes("disabled"))
|
|
551
|
+
continue;
|
|
552
|
+
filesWithDisabled++;
|
|
553
|
+
// Check for proper disabled styling
|
|
554
|
+
const hasGoodPatterns = DISABLED_STATE_PATTERNS.good.some((p) => p.test(content));
|
|
555
|
+
if (hasGoodPatterns)
|
|
556
|
+
properlyStyled++;
|
|
557
|
+
// Check for bad patterns (too low opacity)
|
|
558
|
+
for (const pattern of DISABLED_STATE_PATTERNS.bad) {
|
|
559
|
+
if (pattern.test(content)) {
|
|
560
|
+
warnings.push(`${fileName}: Disabled state uses low opacity (<50%). Use disabled:opacity-50 or higher for accessibility.`);
|
|
561
|
+
break;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
const coverage = filesWithDisabled > 0
|
|
566
|
+
? Math.round((properlyStyled / filesWithDisabled) * 100)
|
|
567
|
+
: 100;
|
|
568
|
+
info.push(`Files with disabled: ${filesWithDisabled}, Properly styled: ${properlyStyled} (${coverage}%)`);
|
|
569
|
+
return {
|
|
570
|
+
name: "Disabled State Polish",
|
|
571
|
+
passed: warnings.length === 0,
|
|
572
|
+
duration: Date.now() - startTime,
|
|
573
|
+
errors,
|
|
574
|
+
warnings: warnings.slice(0, 5),
|
|
575
|
+
info,
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* Check 7: Cursor Indication
|
|
580
|
+
* Ensures clickable elements use proper cursor styles
|
|
581
|
+
*/
|
|
582
|
+
validateCursorIndication() {
|
|
583
|
+
const startTime = Date.now();
|
|
584
|
+
const errors = [];
|
|
585
|
+
const warnings = [];
|
|
586
|
+
const info = [];
|
|
587
|
+
const files = this.getFiles(["components/**/*.tsx", "app/**/*.tsx"]);
|
|
588
|
+
let clickableElements = 0;
|
|
589
|
+
let withProperCursor = 0;
|
|
590
|
+
for (const filePath of files) {
|
|
591
|
+
const content = this.readFile(filePath);
|
|
592
|
+
if (!content)
|
|
593
|
+
continue;
|
|
594
|
+
const fileName = path.basename(filePath);
|
|
595
|
+
if (this.shouldExclude(fileName))
|
|
596
|
+
continue;
|
|
597
|
+
// Check for clickable divs/spans (non-semantic interactive elements)
|
|
598
|
+
const clickableDivPattern = /<(?:div|span)[^>]*onClick[^>]*>/g;
|
|
599
|
+
const clickableDivs = content.match(clickableDivPattern) || [];
|
|
600
|
+
if (clickableDivs.length > 0) {
|
|
601
|
+
clickableElements += clickableDivs.length;
|
|
602
|
+
// Check if they have cursor-pointer
|
|
603
|
+
const hasCursor = content.includes("cursor-pointer");
|
|
604
|
+
if (hasCursor) {
|
|
605
|
+
withProperCursor += clickableDivs.length;
|
|
606
|
+
}
|
|
607
|
+
else {
|
|
608
|
+
warnings.push(`${fileName}: Clickable div/span found without cursor-pointer. Add cursor-pointer for UX.`);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
info.push(`Clickable non-button elements: ${clickableElements}, With cursor: ${withProperCursor}`);
|
|
613
|
+
return {
|
|
614
|
+
name: "Cursor Indication",
|
|
615
|
+
passed: true, // Non-blocking
|
|
616
|
+
duration: Date.now() - startTime,
|
|
617
|
+
errors,
|
|
618
|
+
warnings: warnings.slice(0, 5),
|
|
619
|
+
info,
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* Check 8: Micro-Interaction Feedback
|
|
624
|
+
* Validates that buttons and actions provide visual feedback
|
|
625
|
+
*/
|
|
626
|
+
validateMicroInteractions() {
|
|
627
|
+
const startTime = Date.now();
|
|
628
|
+
const errors = [];
|
|
629
|
+
const warnings = [];
|
|
630
|
+
const info = [];
|
|
631
|
+
const files = this.getFiles(["components/**/*.tsx", "app/**/*.tsx"]);
|
|
632
|
+
let buttonsFound = 0;
|
|
633
|
+
let buttonsWithFeedback = 0;
|
|
634
|
+
// Patterns that indicate interaction feedback
|
|
635
|
+
const feedbackPatterns = [
|
|
636
|
+
/active:/,
|
|
637
|
+
/active:scale/,
|
|
638
|
+
/active:bg/,
|
|
639
|
+
/active:shadow/,
|
|
640
|
+
/active:opacity/,
|
|
641
|
+
/:active\s*\{/,
|
|
642
|
+
/scale-95/,
|
|
643
|
+
/pressed/i,
|
|
644
|
+
];
|
|
645
|
+
for (const filePath of files) {
|
|
646
|
+
const content = this.readFile(filePath);
|
|
647
|
+
if (!content)
|
|
648
|
+
continue;
|
|
649
|
+
const fileName = path.basename(filePath);
|
|
650
|
+
if (this.shouldExclude(fileName))
|
|
651
|
+
continue;
|
|
652
|
+
// Check for Button components
|
|
653
|
+
const buttonPattern = /<Button[^>]*>/g;
|
|
654
|
+
const buttons = content.match(buttonPattern) || [];
|
|
655
|
+
if (buttons.length > 0) {
|
|
656
|
+
buttonsFound += buttons.length;
|
|
657
|
+
// Check for active/pressed state feedback
|
|
658
|
+
const hasFeedback = feedbackPatterns.some((p) => p.test(content));
|
|
659
|
+
if (hasFeedback) {
|
|
660
|
+
buttonsWithFeedback += buttons.length;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
const feedbackPercent = buttonsFound > 0
|
|
665
|
+
? Math.round((buttonsWithFeedback / buttonsFound) * 100)
|
|
666
|
+
: 100;
|
|
667
|
+
info.push(`Buttons found: ${buttonsFound}, With active feedback: ${buttonsWithFeedback} (${feedbackPercent}%)`);
|
|
668
|
+
if (feedbackPercent < 20 && buttonsFound > 10) {
|
|
669
|
+
warnings.push(`Consider adding active: states to buttons for tactile feedback (e.g., active:scale-95).`);
|
|
670
|
+
}
|
|
671
|
+
return {
|
|
672
|
+
name: "Micro-Interaction Feedback",
|
|
673
|
+
passed: true, // Non-blocking, advisory
|
|
674
|
+
duration: Date.now() - startTime,
|
|
675
|
+
errors,
|
|
676
|
+
warnings,
|
|
677
|
+
info,
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
/**
|
|
681
|
+
* Run all checks
|
|
682
|
+
*/
|
|
683
|
+
async runAll() {
|
|
684
|
+
console.log("\n" + console_chars_1.emoji.palette + " UI UNIFORMITY & VISUAL POLISH");
|
|
685
|
+
console.log((0, console_chars_1.createDivider)(60, "heavy"));
|
|
686
|
+
console.log(`${console_chars_1.emoji.info} Checking for premium UX patterns...\n`);
|
|
687
|
+
const results = [];
|
|
688
|
+
// Run all validation checks
|
|
689
|
+
results.push(this.validateTransitionConsistency());
|
|
690
|
+
results.push(this.validateHoverStates());
|
|
691
|
+
results.push(this.validateAnimationLibraryUniformity());
|
|
692
|
+
results.push(this.validateLoadingStateElegance());
|
|
693
|
+
results.push(this.validateFocusRingConsistency());
|
|
694
|
+
results.push(this.validateDisabledStatePolish());
|
|
695
|
+
results.push(this.validateCursorIndication());
|
|
696
|
+
results.push(this.validateMicroInteractions());
|
|
697
|
+
this.printResults(results);
|
|
698
|
+
const allPassed = results.every((r) => r.passed);
|
|
699
|
+
return { passed: allPassed, results };
|
|
700
|
+
}
|
|
701
|
+
printResults(results) {
|
|
702
|
+
console.log("\n" + (0, console_chars_1.createDivider)(60, "light"));
|
|
703
|
+
for (const result of results) {
|
|
704
|
+
const icon = result.passed ? console_chars_1.emoji.success : console_chars_1.emoji.warning;
|
|
705
|
+
const time = result.duration < 1000
|
|
706
|
+
? `${result.duration}ms`
|
|
707
|
+
: `${(result.duration / 1000).toFixed(1)}s`;
|
|
708
|
+
console.log(`${icon} ${result.name.padEnd(35)} ${time.padStart(8)}`);
|
|
709
|
+
// Show info in verbose mode
|
|
710
|
+
if (this.verbose) {
|
|
711
|
+
for (const infoLine of result.info) {
|
|
712
|
+
console.log(` ${console_chars_1.emoji.info} ${infoLine}`);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
// Show warnings
|
|
716
|
+
if (result.warnings.length > 0 && (this.verbose || !result.passed)) {
|
|
717
|
+
for (const warning of result.warnings) {
|
|
718
|
+
console.log(` ${console_chars_1.emoji.warning} ${warning}`);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
// Show errors
|
|
722
|
+
for (const error of result.errors) {
|
|
723
|
+
console.log(` ${console_chars_1.emoji.error} ${error}`);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
console.log("\n" + (0, console_chars_1.createDivider)(60, "heavy"));
|
|
727
|
+
const passed = results.filter((r) => r.passed).length;
|
|
728
|
+
const failed = results.filter((r) => !r.passed).length;
|
|
729
|
+
const totalWarnings = results.reduce((sum, r) => sum + r.warnings.length, 0);
|
|
730
|
+
const totalTime = results.reduce((sum, r) => sum + r.duration, 0);
|
|
731
|
+
console.log(`${console_chars_1.emoji.chart} Results: ${passed} passed, ${failed} need attention`);
|
|
732
|
+
if (totalWarnings > 0) {
|
|
733
|
+
console.log(`${console_chars_1.emoji.warning} Warnings: ${totalWarnings}`);
|
|
734
|
+
}
|
|
735
|
+
console.log(`${console_chars_1.emoji.clock} Total time: ${(totalTime / 1000).toFixed(1)}s`);
|
|
736
|
+
if (failed === 0) {
|
|
737
|
+
console.log(`\n${console_chars_1.emoji.party} UI UNIFORMITY VALIDATION PASSED`);
|
|
738
|
+
console.log(`${console_chars_1.emoji.thumbsUp} Your UI has a polished, premium feel!`);
|
|
739
|
+
}
|
|
740
|
+
else {
|
|
741
|
+
console.log(`\n${console_chars_1.emoji.warning} UI UNIFORMITY VALIDATION COMPLETED WITH SUGGESTIONS`);
|
|
742
|
+
console.log(`${console_chars_1.emoji.info} Address the warnings above for a more cohesive UX.`);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
exports.UIUniformityPreflight = UIUniformityPreflight;
|
|
747
|
+
// CLI
|
|
748
|
+
async function main() {
|
|
749
|
+
const args = process.argv.slice(2);
|
|
750
|
+
const verbose = args.includes("--verbose") || args.includes("-v");
|
|
751
|
+
const preflight = new UIUniformityPreflight({ verbose });
|
|
752
|
+
const { passed } = await preflight.runAll();
|
|
753
|
+
// Non-blocking check - always exit 0
|
|
754
|
+
process.exit(0);
|
|
755
|
+
}
|
|
756
|
+
if (require.main === module) {
|
|
757
|
+
main();
|
|
758
|
+
}
|
|
759
|
+
//# sourceMappingURL=ui-uniformity-polish.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-uniformity-polish.js","sourceRoot":"","sources":["../../../src/checks/ui/ui-uniformity-polish.ts"],"names":[],"mappings":";;AACA;;;;;;;;;;;;;;;;;;;;GAoBG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,uCAAyB;AACzB,+BAA4B;AAC5B,2CAA6B;AAC7B,8DAAmF;AACnF,6DAAiE;AAEjE,kDAAkD;AACrC,QAAA,EAAE,GAAG,yBAAyB,CAAC;AAC/B,QAAA,IAAI,GAAG,+BAA+B,CAAC;AACvC,QAAA,WAAW,GAAG,2DAA2D,CAAC;AAC1E,QAAA,QAAQ,GAAG,IAAI,CAAC;AAChB,QAAA,QAAQ,GAAG,KAAK,CAAC;AACjB,QAAA,IAAI,GAAG;IAClB,IAAI;IACJ,IAAI;IACJ,QAAQ;IACR,aAAa;IACb,YAAY;IACZ,oBAAoB;IACpB,OAAO;IACP,OAAO;CACR,CAAC;AAWF,wCAAwC;AACxC,MAAM,cAAc,GAAG;IACrB,cAAc;IACd,WAAW;IACX,WAAW;IACX,qBAAqB;IACrB,sBAAsB;CACvB,CAAC;AAEF,yBAAyB;AACzB,MAAM,aAAa,GAAG;IACpB,GAAG,iCAAiB;IACpB,GAAG,kCAAkB;IACrB,WAAW;IACX,WAAW;IACX,oBAAoB;IACpB,aAAa;CACd,CAAC;AAEF,gFAAgF;AAChF,sBAAsB;AACtB,gFAAgF;AAEhF;;;GAGG;AACH,MAAM,yBAAyB,GAAG;IAChC,2BAA2B;IAC3B,mBAAmB;IACnB,iBAAiB;IACjB,aAAa;IACb,gCAAgC;IAChC,gBAAgB;IAChB,mBAAmB;IACnB,oBAAoB;IACpB,mBAAmB;IACnB,sBAAsB;IACtB,iBAAiB;IACjB,mBAAmB;IACnB,cAAc;IACd,eAAe;IACf,aAAa;IACb,SAAS;IACT,UAAU;IACV,aAAa;CACd,CAAC;AAEF;;;GAGG;AACH,MAAM,6BAA6B,GAAG;IACpC,4CAA4C;IAC5C,qCAAqC;IACrC,2CAA2C;IAC3C,gDAAgD;IAChD,6DAA6D;IAC7D,4BAA4B;CAC7B,CAAC;AAEF;;GAEG;AACH,MAAM,mBAAmB,GAAG;IAC1B,YAAY,EAAE;QACZ,OAAO,EAAE,oDAAoD;QAC7D,IAAI,EAAE,eAAe;KACtB;IACD,WAAW,EAAE;QACX,OAAO,EAAE,wDAAwD;QACjE,IAAI,EAAE,cAAc;KACrB;IACD,UAAU,EAAE;QACV,OAAO,EAAE,6BAA6B;QACtC,IAAI,EAAE,aAAa;KACpB;IACD,IAAI,EAAE;QACJ,OAAO,EAAE,qBAAqB;QAC9B,IAAI,EAAE,MAAM;KACb;IACD,aAAa,EAAE;QACb,OAAO,EAAE,kBAAkB;QAC3B,IAAI,EAAE,gBAAgB;KACvB;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,gBAAgB,GAAG;IACvB,+BAA+B;IAC/B,OAAO,EAAE;QACP,iBAAiB;QACjB,gBAAgB;QAChB,iBAAiB;QACjB,eAAe;QACf,YAAY;QACZ,eAAe;KAChB;IACD,6CAA6C;IAC7C,UAAU,EAAE;QACV,gBAAgB;QAChB,kBAAkB;QAClB,SAAS;QACT,SAAS;KACV;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,oBAAoB,GAAG;IAC3B,eAAe;IACf,mBAAmB;IACnB,eAAe;IACf,aAAa;IACb,YAAY;IACZ,qBAAqB;CACtB,CAAC;AAEF;;GAEG;AACH,MAAM,oBAAoB,GAAG;IAC3B,QAAQ;IACR,QAAQ;IACR,gBAAgB;IAChB,SAAS;IACT,cAAc;IACd,aAAa;IACb,aAAa;IACb,aAAa;CACd,CAAC;AAEF;;GAEG;AACH,MAAM,mBAAmB,GAAG;IAC1B,oBAAoB;IACpB,YAAY;IACZ,eAAe;IACf,uBAAuB;IACvB,8BAA8B;IAC9B,iCAAiC;CAClC,CAAC;AAEF;;GAEG;AACH,MAAM,uBAAuB,GAAG;IAC9B,gBAAgB;IAChB,IAAI,EAAE;QACJ,mBAAmB;QACnB,6BAA6B;QAC7B,cAAc;QACd,gBAAgB;QAChB,gBAAgB;KACjB;IACD,0CAA0C;IAC1C,GAAG,EAAE;QACH,sBAAsB,EAAE,4BAA4B;QACpD,sBAAsB,EAAE,YAAY;KACrC;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,eAAe,GAAG;IACtB,WAAW,EAAE,gBAAgB;IAC7B,QAAQ,EAAE,oBAAoB;IAC9B,OAAO,EAAE,aAAa;CACvB,CAAC;AAEF,MAAM,qBAAqB;IACjB,OAAO,CAAU;IACjB,WAAW,CAAS;IAE5B,YAAY,UAAuD,EAAE;QACnE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,KAAK,CAAC;QACxC,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1D,CAAC;IAEO,QAAQ,CAAC,QAAgB;QAC/B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QACvD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAC;QAC1C,OAAO,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC5C,CAAC;IAEO,aAAa,CAAC,QAAgB;QACpC,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IAChE,CAAC;IAEO,QAAQ,CAAC,QAAkB;QACjC,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,OAAO,GAAG,WAAI,CAAC,IAAI,CAAC,OAAO,EAAE;gBACjC,GAAG,EAAE,IAAI,CAAC,WAAW;gBACrB,MAAM,EAAE,aAAa;aACtB,CAAC,CAAC;YACH,KAAK,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC;QACzB,CAAC;QACD,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7B,CAAC;IAED;;;OAGG;IACK,6BAA6B;QACnC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAa,EAAE,CAAC;QAE1B,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,qBAAqB,EAAE,cAAc,CAAC,CAAC,CAAC;QACrE,IAAI,oBAAoB,GAAG,CAAC,CAAC;QAC7B,IAAI,oBAAoB,GAAG,CAAC,CAAC;QAC7B,IAAI,oBAAoB,GAAG,CAAC,CAAC;QAE7B,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;YAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACxC,IAAI,CAAC,OAAO;gBAAE,SAAS;YAEvB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACzC,IAAI,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC;gBAAE,SAAS;YAE3C,iCAAiC;YACjC,MAAM,aAAa,GACjB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;YAClE,IAAI,CAAC,aAAa;gBAAE,SAAS;YAE7B,oBAAoB,EAAE,CAAC;YAEvB,kCAAkC;YAClC,MAAM,YAAY,GAAG,yBAAyB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;YAC5E,IAAI,YAAY;gBAAE,oBAAoB,EAAE,CAAC;YAEzC,iDAAiD;YACjD,KAAK,MAAM,OAAO,IAAI,6BAA6B,EAAE,CAAC;gBACpD,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBACvC,IAAI,OAAO,EAAE,CAAC;oBACZ,oBAAoB,EAAE,CAAC;oBACvB,QAAQ,CAAC,IAAI,CACX,GAAG,QAAQ,+EAA+E,CAC3F,CAAC;oBACF,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GACZ,oBAAoB,GAAG,CAAC;YACtB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,oBAAoB,GAAG,oBAAoB,CAAC,GAAG,GAAG,CAAC;YACjE,CAAC,CAAC,GAAG,CAAC;QAEV,IAAI,CAAC,IAAI,CACP,2BAA2B,oBAAoB,mBAAmB,oBAAoB,KAAK,QAAQ,IAAI,CACxG,CAAC;QAEF,OAAO;YACL,IAAI,EAAE,8BAA8B;YACpC,MAAM,EAAE,oBAAoB,KAAK,CAAC;YAClC,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;YAChC,MAAM;YACN,QAAQ;YACR,IAAI;SACL,CAAC;IACJ,CAAC;IAED;;;OAGG;IACK,mBAAmB;QACzB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAa,EAAE,CAAC;QAE1B,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,qBAAqB,EAAE,cAAc,CAAC,CAAC,CAAC;QACrE,IAAI,mBAAmB,GAAG,CAAC,CAAC;QAC5B,IAAI,oBAAoB,GAAG,CAAC,CAAC;QAC7B,MAAM,oBAAoB,GAAa,EAAE,CAAC;QAE1C,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;YAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACxC,IAAI,CAAC,OAAO;gBAAE,SAAS;YAEvB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACzC,IAAI,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC;gBAAE,SAAS;YAE3C,yCAAyC;YACzC,MAAM,cAAc,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;YACzE,IAAI,CAAC,cAAc;gBAAE,SAAS;YAE9B,mBAAmB,EAAE,CAAC;YAEtB,iCAAiC;YACjC,MAAM,WAAW,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;YACtE,IAAI,WAAW,EAAE,CAAC;gBAChB,oBAAoB,EAAE,CAAC;YACzB,CAAC;iBAAM,CAAC;gBACN,oBAAoB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBACpC,QAAQ,CAAC,IAAI,CACX,GAAG,QAAQ,yFAAyF,CACrG,CAAC;YACJ,CAAC;QACH,CAAC;QAED,gCAAgC;QAChC,IAAI,oBAAoB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;YACpB,QAAQ,CAAC,IAAI,CAAC,UAAU,oBAAoB,CAAC,MAAM,GAAG,CAAC,aAAa,CAAC,CAAC;QACxE,CAAC;QAED,MAAM,QAAQ,GACZ,mBAAmB,GAAG,CAAC;YACrB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,oBAAoB,GAAG,mBAAmB,CAAC,GAAG,GAAG,CAAC;YAChE,CAAC,CAAC,GAAG,CAAC;QAEV,IAAI,CAAC,IAAI,CACP,sBAAsB,mBAAmB,oBAAoB,oBAAoB,KAAK,QAAQ,IAAI,CACnG,CAAC;QAEF,OAAO;YACL,IAAI,EAAE,0BAA0B;YAChC,MAAM,EAAE,QAAQ,IAAI,EAAE,EAAE,gBAAgB;YACxC,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;YAChC,MAAM;YACN,QAAQ;YACR,IAAI;SACL,CAAC;IACJ,CAAC;IAED;;;OAGG;IACK,kCAAkC;QACxC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAa,EAAE,CAAC;QAE1B,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC;YAC1B,qBAAqB;YACrB,cAAc;YACd,aAAa;SACd,CAAC,CAAC;QACH,MAAM,aAAa,GAAG,IAAI,GAAG,EAAoB,CAAC;QAElD,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;YAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACxC,IAAI,CAAC,OAAO;gBAAE,SAAS;YAEvB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACzC,IAAI,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC;gBAAE,SAAS;YAE3C,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,mBAAmB,CAAC,EAAE,CAAC;gBAC7D,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;oBAC9B,MAAM,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;oBACnD,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;oBACxB,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;gBACxC,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC;QACpC,IAAI,CAAC,IAAI,CAAC,iCAAiC,QAAQ,EAAE,CAAC,CAAC;QAEvD,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YACjB,MAAM,QAAQ,GAAG,CAAC,GAAG,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACtD,QAAQ,CAAC,IAAI,CACX,0CAA0C,QAAQ,4CAA4C,CAC/F,CAAC;YAEF,KAAK,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,aAAa,EAAE,CAAC;gBAC7C,IAAI,CAAC,IAAI,CAAC,KAAK,OAAO,KAAK,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC;YACnD,CAAC;QACH,CAAC;aAAM,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM,CAAC,OAAO,CAAC,GAAG,aAAa,CAAC,IAAI,EAAE,CAAC;YACvC,IAAI,CAAC,IAAI,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAC;QAC3C,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;QAC1D,CAAC;QAED,OAAO;YACL,IAAI,EAAE,8BAA8B;YACpC,MAAM,EAAE,QAAQ,IAAI,CAAC,EAAE,+BAA+B;YACtD,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;YAChC,MAAM;YACN,QAAQ;YACR,IAAI;SACL,CAAC;IACJ,CAAC;IAED;;;OAGG;IACK,4BAA4B;QAClC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAa,EAAE,CAAC;QAE1B,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,qBAAqB,EAAE,cAAc,CAAC,CAAC,CAAC;QACrE,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,IAAI,eAAe,GAAG,CAAC,CAAC;QACxB,IAAI,gBAAgB,GAAG,CAAC,CAAC;QAEzB,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;YAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACxC,IAAI,CAAC,OAAO;gBAAE,SAAS;YAEvB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACzC,IAAI,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC;gBAAE,SAAS;YAE3C,6BAA6B;YAC7B,MAAM,UAAU,GAAG,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;YACzE,MAAM,aAAa,GAAG,gBAAgB,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAC3D,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAChB,CAAC;YAEF,IAAI,UAAU,IAAI,aAAa,EAAE,CAAC;gBAChC,gBAAgB,EAAE,CAAC;gBACnB,IAAI,UAAU;oBAAE,YAAY,EAAE,CAAC;gBAC/B,IAAI,aAAa,IAAI,CAAC,UAAU;oBAAE,eAAe,EAAE,CAAC;YACtD,CAAC;QACH,CAAC;QAED,MAAM,cAAc,GAClB,gBAAgB,GAAG,CAAC;YAClB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,YAAY,GAAG,gBAAgB,CAAC,GAAG,GAAG,CAAC;YACrD,CAAC,CAAC,GAAG,CAAC;QAEV,IAAI,CAAC,IAAI,CACP,uBAAuB,gBAAgB,yBAAyB,YAAY,KAAK,cAAc,qBAAqB,eAAe,EAAE,CACtI,CAAC;QAEF,IAAI,eAAe,GAAG,YAAY,IAAI,gBAAgB,GAAG,EAAE,EAAE,CAAC;YAC5D,QAAQ,CAAC,IAAI,CACX,+BAA+B,eAAe,0BAA0B,YAAY,KAAK;gBACvF,sEAAsE,CACzE,CAAC;QACJ,CAAC;QAED,OAAO;YACL,IAAI,EAAE,wBAAwB;YAC9B,MAAM,EAAE,cAAc,IAAI,EAAE,IAAI,gBAAgB,GAAG,EAAE;YACrD,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;YAChC,MAAM;YACN,QAAQ;YACR,IAAI;SACL,CAAC;IACJ,CAAC;IAED;;;OAGG;IACK,4BAA4B;QAClC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAa,EAAE,CAAC;QAE1B,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,qBAAqB,EAAE,cAAc,CAAC,CAAC,CAAC;QACrE,IAAI,gBAAgB,GAAG,CAAC,CAAC;QACzB,IAAI,kBAAkB,GAAG,CAAC,CAAC;QAE3B,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;YAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACxC,IAAI,CAAC,OAAO;gBAAE,SAAS;YAEvB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACzC,IAAI,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC;gBAAE,SAAS;YAE3C,yCAAyC;YACzC,MAAM,cAAc,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;YACzE,IAAI,CAAC,cAAc;gBAAE,SAAS;YAE9B,gBAAgB,EAAE,CAAC;YAEnB,gCAAgC;YAChC,MAAM,YAAY,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;YACtE,IAAI,YAAY,EAAE,CAAC;gBACjB,kBAAkB,EAAE,CAAC;YACvB,CAAC;YAED,uDAAuD;YACvD,IACE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;gBAChC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,EACjC,CAAC;gBACD,MAAM,kBAAkB,GACtB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;oBAC9B,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;gBACzC,IAAI,CAAC,kBAAkB,EAAE,CAAC;oBACxB,QAAQ,CAAC,IAAI,CACX,GAAG,QAAQ,iGAAiG,CAC7G,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GACZ,gBAAgB,GAAG,CAAC;YAClB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,kBAAkB,GAAG,gBAAgB,CAAC,GAAG,GAAG,CAAC;YAC3D,CAAC,CAAC,GAAG,CAAC;QAEV,IAAI,CAAC,IAAI,CACP,sBAAsB,gBAAgB,uBAAuB,kBAAkB,KAAK,QAAQ,IAAI,CACjG,CAAC;QAEF,OAAO;YACL,IAAI,EAAE,wBAAwB;YAC9B,MAAM,EAAE,QAAQ,CAAC,MAAM,KAAK,CAAC;YAC7B,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;YAChC,MAAM;YACN,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,sBAAsB;YACtD,IAAI;SACL,CAAC;IACJ,CAAC;IAED;;;OAGG;IACK,2BAA2B;QACjC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAa,EAAE,CAAC;QAE1B,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC;QACrD,IAAI,iBAAiB,GAAG,CAAC,CAAC;QAC1B,IAAI,cAAc,GAAG,CAAC,CAAC;QAEvB,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;YAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACxC,IAAI,CAAC,OAAO;gBAAE,SAAS;YAEvB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACzC,IAAI,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC;gBAAE,SAAS;YAE3C,oCAAoC;YACpC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;gBAAE,SAAS;YAE5C,iBAAiB,EAAE,CAAC;YAEpB,oCAAoC;YACpC,MAAM,eAAe,GAAG,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAC9D,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAChB,CAAC;YACF,IAAI,eAAe;gBAAE,cAAc,EAAE,CAAC;YAEtC,2CAA2C;YAC3C,KAAK,MAAM,OAAO,IAAI,uBAAuB,CAAC,GAAG,EAAE,CAAC;gBAClD,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;oBAC1B,QAAQ,CAAC,IAAI,CACX,GAAG,QAAQ,gGAAgG,CAC5G,CAAC;oBACF,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GACZ,iBAAiB,GAAG,CAAC;YACnB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,cAAc,GAAG,iBAAiB,CAAC,GAAG,GAAG,CAAC;YACxD,CAAC,CAAC,GAAG,CAAC;QAEV,IAAI,CAAC,IAAI,CACP,wBAAwB,iBAAiB,sBAAsB,cAAc,KAAK,QAAQ,IAAI,CAC/F,CAAC;QAEF,OAAO;YACL,IAAI,EAAE,uBAAuB;YAC7B,MAAM,EAAE,QAAQ,CAAC,MAAM,KAAK,CAAC;YAC7B,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;YAChC,MAAM;YACN,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;YAC9B,IAAI;SACL,CAAC;IACJ,CAAC;IAED;;;OAGG;IACK,wBAAwB;QAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAa,EAAE,CAAC;QAE1B,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,qBAAqB,EAAE,cAAc,CAAC,CAAC,CAAC;QACrE,IAAI,iBAAiB,GAAG,CAAC,CAAC;QAC1B,IAAI,gBAAgB,GAAG,CAAC,CAAC;QAEzB,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;YAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACxC,IAAI,CAAC,OAAO;gBAAE,SAAS;YAEvB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACzC,IAAI,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC;gBAAE,SAAS;YAE3C,qEAAqE;YACrE,MAAM,mBAAmB,GACvB,kCAAkC,CAAC;YACrC,MAAM,aAAa,GAAG,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,IAAI,EAAE,CAAC;YAE/D,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC7B,iBAAiB,IAAI,aAAa,CAAC,MAAM,CAAC;gBAE1C,oCAAoC;gBACpC,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;gBACrD,IAAI,SAAS,EAAE,CAAC;oBACd,gBAAgB,IAAI,aAAa,CAAC,MAAM,CAAC;gBAC3C,CAAC;qBAAM,CAAC;oBACN,QAAQ,CAAC,IAAI,CACX,GAAG,QAAQ,+EAA+E,CAC3F,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,CAAC,IAAI,CACP,kCAAkC,iBAAiB,kBAAkB,gBAAgB,EAAE,CACxF,CAAC;QAEF,OAAO;YACL,IAAI,EAAE,mBAAmB;YACzB,MAAM,EAAE,IAAI,EAAE,eAAe;YAC7B,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;YAChC,MAAM;YACN,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;YAC9B,IAAI;SACL,CAAC;IACJ,CAAC;IAED;;;OAGG;IACK,yBAAyB;QAC/B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAa,EAAE,CAAC;QAE1B,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,qBAAqB,EAAE,cAAc,CAAC,CAAC,CAAC;QACrE,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,IAAI,mBAAmB,GAAG,CAAC,CAAC;QAE5B,8CAA8C;QAC9C,MAAM,gBAAgB,GAAG;YACvB,SAAS;YACT,cAAc;YACd,WAAW;YACX,eAAe;YACf,gBAAgB;YAChB,cAAc;YACd,UAAU;YACV,UAAU;SACX,CAAC;QAEF,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;YAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACxC,IAAI,CAAC,OAAO;gBAAE,SAAS;YAEvB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACzC,IAAI,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC;gBAAE,SAAS;YAE3C,8BAA8B;YAC9B,MAAM,aAAa,GAAG,gBAAgB,CAAC;YACvC,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;YAEnD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;gBAE/B,0CAA0C;gBAC1C,MAAM,WAAW,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;gBAClE,IAAI,WAAW,EAAE,CAAC;oBAChB,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC;gBACxC,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,eAAe,GACnB,YAAY,GAAG,CAAC;YACd,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,mBAAmB,GAAG,YAAY,CAAC,GAAG,GAAG,CAAC;YACxD,CAAC,CAAC,GAAG,CAAC;QAEV,IAAI,CAAC,IAAI,CACP,kBAAkB,YAAY,2BAA2B,mBAAmB,KAAK,eAAe,IAAI,CACrG,CAAC;QAEF,IAAI,eAAe,GAAG,EAAE,IAAI,YAAY,GAAG,EAAE,EAAE,CAAC;YAC9C,QAAQ,CAAC,IAAI,CACX,yFAAyF,CAC1F,CAAC;QACJ,CAAC;QAED,OAAO;YACL,IAAI,EAAE,4BAA4B;YAClC,MAAM,EAAE,IAAI,EAAE,yBAAyB;YACvC,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;YAChC,MAAM;YACN,QAAQ;YACR,IAAI;SACL,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,MAAM;QACV,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,qBAAK,CAAC,OAAO,GAAG,gCAAgC,CAAC,CAAC;QACrE,OAAO,CAAC,GAAG,CAAC,IAAA,6BAAa,EAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,GAAG,qBAAK,CAAC,IAAI,wCAAwC,CAAC,CAAC;QAEnE,MAAM,OAAO,GAAkB,EAAE,CAAC;QAElC,4BAA4B;QAC5B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,6BAA6B,EAAE,CAAC,CAAC;QACnD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC,CAAC;QACzC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,kCAAkC,EAAE,CAAC,CAAC;QACxD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,4BAA4B,EAAE,CAAC,CAAC;QAClD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,4BAA4B,EAAE,CAAC,CAAC;QAClD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,2BAA2B,EAAE,CAAC,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,wBAAwB,EAAE,CAAC,CAAC;QAC9C,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,yBAAyB,EAAE,CAAC,CAAC;QAE/C,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAE3B,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACjD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;IACxC,CAAC;IAEO,YAAY,CAAC,OAAsB;QACzC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,IAAA,6BAAa,EAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;QAE/C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,qBAAK,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAK,CAAC,OAAO,CAAC;YAC3D,MAAM,IAAI,GACR,MAAM,CAAC,QAAQ,GAAG,IAAI;gBACpB,CAAC,CAAC,GAAG,MAAM,CAAC,QAAQ,IAAI;gBACxB,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;YAChD,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAErE,4BAA4B;YAC5B,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACjB,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;oBACnC,OAAO,CAAC,GAAG,CAAC,MAAM,qBAAK,CAAC,IAAI,IAAI,QAAQ,EAAE,CAAC,CAAC;gBAC9C,CAAC;YACH,CAAC;YAED,gBAAgB;YAChB,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;gBACnE,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;oBACtC,OAAO,CAAC,GAAG,CAAC,MAAM,qBAAK,CAAC,OAAO,IAAI,OAAO,EAAE,CAAC,CAAC;gBAChD,CAAC;YACH,CAAC;YAED,cAAc;YACd,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;gBAClC,OAAO,CAAC,GAAG,CAAC,MAAM,qBAAK,CAAC,KAAK,IAAI,KAAK,EAAE,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,IAAA,6BAAa,EAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;QAE/C,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC;QACtD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC;QACvD,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAClC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,EACnC,CAAC,CACF,CAAC;QACF,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QAElE,OAAO,CAAC,GAAG,CAAC,GAAG,qBAAK,CAAC,KAAK,aAAa,MAAM,YAAY,MAAM,iBAAiB,CAAC,CAAC;QAClF,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,GAAG,qBAAK,CAAC,OAAO,cAAc,aAAa,EAAE,CAAC,CAAC;QAC7D,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,GAAG,qBAAK,CAAC,KAAK,gBAAgB,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAE5E,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,KAAK,qBAAK,CAAC,KAAK,kCAAkC,CAAC,CAAC;YAChE,OAAO,CAAC,GAAG,CAAC,GAAG,qBAAK,CAAC,QAAQ,wCAAwC,CAAC,CAAC;QACzE,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,KAAK,qBAAK,CAAC,OAAO,sDAAsD,CAAC,CAAC;YACtF,OAAO,CAAC,GAAG,CAAC,GAAG,qBAAK,CAAC,IAAI,qDAAqD,CAAC,CAAC;QAClF,CAAC;IACH,CAAC;CACF;AAkBQ,sDAAqB;AAhB9B,MAAM;AACN,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAElE,MAAM,SAAS,GAAG,IAAI,qBAAqB,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;IACzD,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE,CAAC;IAE5C,qCAAqC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;IAC5B,IAAI,EAAE,CAAC;AACT,CAAC"}
|