@nebutra/next-unicorn-skill 1.0.0

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.
Files changed (119) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/LICENSE +21 -0
  3. package/README.md +316 -0
  4. package/SKILL.md +318 -0
  5. package/dist/analyzer/pattern-catalog.d.ts +35 -0
  6. package/dist/analyzer/pattern-catalog.d.ts.map +1 -0
  7. package/dist/analyzer/pattern-catalog.js +342 -0
  8. package/dist/analyzer/pattern-catalog.js.map +1 -0
  9. package/dist/analyzer/scanner.d.ts +33 -0
  10. package/dist/analyzer/scanner.d.ts.map +1 -0
  11. package/dist/analyzer/scanner.js +302 -0
  12. package/dist/analyzer/scanner.js.map +1 -0
  13. package/dist/auditor/ux-auditor.d.ts +26 -0
  14. package/dist/auditor/ux-auditor.d.ts.map +1 -0
  15. package/dist/auditor/ux-auditor.js +272 -0
  16. package/dist/auditor/ux-auditor.js.map +1 -0
  17. package/dist/checker/peer-dependency-checker.d.ts +62 -0
  18. package/dist/checker/peer-dependency-checker.d.ts.map +1 -0
  19. package/dist/checker/peer-dependency-checker.js +94 -0
  20. package/dist/checker/peer-dependency-checker.js.map +1 -0
  21. package/dist/index.d.ts +78 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +325 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/planner/migration-planner.d.ts +47 -0
  26. package/dist/planner/migration-planner.d.ts.map +1 -0
  27. package/dist/planner/migration-planner.js +144 -0
  28. package/dist/planner/migration-planner.js.map +1 -0
  29. package/dist/pr-creator/git-operations.d.ts +29 -0
  30. package/dist/pr-creator/git-operations.d.ts.map +1 -0
  31. package/dist/pr-creator/git-operations.js +10 -0
  32. package/dist/pr-creator/git-operations.js.map +1 -0
  33. package/dist/pr-creator/platform-client.d.ts +47 -0
  34. package/dist/pr-creator/platform-client.d.ts.map +1 -0
  35. package/dist/pr-creator/platform-client.js +9 -0
  36. package/dist/pr-creator/platform-client.js.map +1 -0
  37. package/dist/pr-creator/pr-description-builder.d.ts +23 -0
  38. package/dist/pr-creator/pr-description-builder.d.ts.map +1 -0
  39. package/dist/pr-creator/pr-description-builder.js +187 -0
  40. package/dist/pr-creator/pr-description-builder.js.map +1 -0
  41. package/dist/pr-creator/pr-executor.d.ts +30 -0
  42. package/dist/pr-creator/pr-executor.d.ts.map +1 -0
  43. package/dist/pr-creator/pr-executor.js +109 -0
  44. package/dist/pr-creator/pr-executor.js.map +1 -0
  45. package/dist/pr-creator/pr-strategy.d.ts +56 -0
  46. package/dist/pr-creator/pr-strategy.d.ts.map +1 -0
  47. package/dist/pr-creator/pr-strategy.js +125 -0
  48. package/dist/pr-creator/pr-strategy.js.map +1 -0
  49. package/dist/schemas/input.schema.d.ts +231 -0
  50. package/dist/schemas/input.schema.d.ts.map +1 -0
  51. package/dist/schemas/input.schema.js +159 -0
  52. package/dist/schemas/input.schema.js.map +1 -0
  53. package/dist/schemas/output.schema.d.ts +2543 -0
  54. package/dist/schemas/output.schema.d.ts.map +1 -0
  55. package/dist/schemas/output.schema.js +199 -0
  56. package/dist/schemas/output.schema.js.map +1 -0
  57. package/dist/scorer/impact-scorer.d.ts +45 -0
  58. package/dist/scorer/impact-scorer.d.ts.map +1 -0
  59. package/dist/scorer/impact-scorer.js +243 -0
  60. package/dist/scorer/impact-scorer.js.map +1 -0
  61. package/dist/security/osv-client.d.ts +72 -0
  62. package/dist/security/osv-client.d.ts.map +1 -0
  63. package/dist/security/osv-client.js +36 -0
  64. package/dist/security/osv-client.js.map +1 -0
  65. package/dist/security/vuln-report-builder.d.ts +18 -0
  66. package/dist/security/vuln-report-builder.d.ts.map +1 -0
  67. package/dist/security/vuln-report-builder.js +141 -0
  68. package/dist/security/vuln-report-builder.js.map +1 -0
  69. package/dist/security/vulnerability-scanner.d.ts +65 -0
  70. package/dist/security/vulnerability-scanner.d.ts.map +1 -0
  71. package/dist/security/vulnerability-scanner.js +140 -0
  72. package/dist/security/vulnerability-scanner.js.map +1 -0
  73. package/dist/updater/changelog-verifier.d.ts +29 -0
  74. package/dist/updater/changelog-verifier.d.ts.map +1 -0
  75. package/dist/updater/changelog-verifier.js +80 -0
  76. package/dist/updater/changelog-verifier.js.map +1 -0
  77. package/dist/updater/registry-client.d.ts +49 -0
  78. package/dist/updater/registry-client.d.ts.map +1 -0
  79. package/dist/updater/registry-client.js +10 -0
  80. package/dist/updater/registry-client.js.map +1 -0
  81. package/dist/updater/update-plan-builder.d.ts +23 -0
  82. package/dist/updater/update-plan-builder.d.ts.map +1 -0
  83. package/dist/updater/update-plan-builder.js +93 -0
  84. package/dist/updater/update-plan-builder.js.map +1 -0
  85. package/dist/updater/update-policy.d.ts +50 -0
  86. package/dist/updater/update-policy.d.ts.map +1 -0
  87. package/dist/updater/update-policy.js +118 -0
  88. package/dist/updater/update-policy.js.map +1 -0
  89. package/dist/updater/update-scorer.d.ts +51 -0
  90. package/dist/updater/update-scorer.d.ts.map +1 -0
  91. package/dist/updater/update-scorer.js +166 -0
  92. package/dist/updater/update-scorer.js.map +1 -0
  93. package/dist/utils/constraint-filter.d.ts +44 -0
  94. package/dist/utils/constraint-filter.d.ts.map +1 -0
  95. package/dist/utils/constraint-filter.js +69 -0
  96. package/dist/utils/constraint-filter.js.map +1 -0
  97. package/dist/utils/serializer.d.ts +17 -0
  98. package/dist/utils/serializer.d.ts.map +1 -0
  99. package/dist/utils/serializer.js +24 -0
  100. package/dist/utils/serializer.js.map +1 -0
  101. package/dist/utils/skill-parser.d.ts +29 -0
  102. package/dist/utils/skill-parser.d.ts.map +1 -0
  103. package/dist/utils/skill-parser.js +175 -0
  104. package/dist/utils/skill-parser.js.map +1 -0
  105. package/dist/verifier/context7.d.ts +48 -0
  106. package/dist/verifier/context7.d.ts.map +1 -0
  107. package/dist/verifier/context7.js +97 -0
  108. package/dist/verifier/context7.js.map +1 -0
  109. package/examples/backend-node/input.json +28 -0
  110. package/examples/backend-node/output.json +343 -0
  111. package/examples/frontend-nextjs/input.json +37 -0
  112. package/examples/frontend-nextjs/output.json +302 -0
  113. package/package.json +79 -0
  114. package/templates/deletion-checklist.md +42 -0
  115. package/templates/migration-plan.md +61 -0
  116. package/templates/prd-template.md +123 -0
  117. package/templates/summary-table.md +28 -0
  118. package/templates/update-plan.md +61 -0
  119. package/templates/vuln-report.md +50 -0
@@ -0,0 +1,302 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { getPatternCatalog } from './pattern-catalog.js';
4
+ const MANIFEST_TYPES = [
5
+ {
6
+ file: 'package.json',
7
+ packageManager: 'npm',
8
+ language: 'typescript',
9
+ parseDeps: (content) => {
10
+ try {
11
+ const pkg = JSON.parse(content);
12
+ return { ...pkg.dependencies, ...pkg.devDependencies };
13
+ }
14
+ catch {
15
+ return {};
16
+ }
17
+ },
18
+ },
19
+ {
20
+ file: 'pyproject.toml',
21
+ packageManager: 'pip',
22
+ language: 'python',
23
+ parseDeps: (content) => {
24
+ const deps = {};
25
+ // Simple regex to extract dependencies from pyproject.toml
26
+ const depSection = /\[(?:project\.)?dependencies\]\s*\n([\s\S]*?)(?:\n\[|$)/;
27
+ const match = depSection.exec(content);
28
+ if (match?.[1]) {
29
+ const lines = match[1].split('\n');
30
+ for (const line of lines) {
31
+ const depMatch = /^\s*["']?([a-zA-Z0-9_-]+)["']?\s*(?:[><=!~]+\s*["']?([^"',\s]+))?/.exec(line.trim());
32
+ if (depMatch?.[1]) {
33
+ deps[depMatch[1]] = depMatch[2] ?? '*';
34
+ }
35
+ }
36
+ }
37
+ return deps;
38
+ },
39
+ },
40
+ {
41
+ file: 'Cargo.toml',
42
+ packageManager: 'cargo',
43
+ language: 'rust',
44
+ parseDeps: (content) => {
45
+ const deps = {};
46
+ const depSection = /\[dependencies\]\s*\n([\s\S]*?)(?:\n\[|$)/;
47
+ const match = depSection.exec(content);
48
+ if (match?.[1]) {
49
+ const lines = match[1].split('\n');
50
+ for (const line of lines) {
51
+ const depMatch = /^\s*([a-zA-Z0-9_-]+)\s*=\s*"([^"]+)"/.exec(line.trim());
52
+ if (depMatch?.[1] && depMatch[2]) {
53
+ deps[depMatch[1]] = depMatch[2];
54
+ }
55
+ }
56
+ }
57
+ return deps;
58
+ },
59
+ },
60
+ {
61
+ file: 'go.mod',
62
+ packageManager: 'go',
63
+ language: 'go',
64
+ parseDeps: (content) => {
65
+ const deps = {};
66
+ const requireBlock = /require\s*\(([\s\S]*?)\)/;
67
+ const match = requireBlock.exec(content);
68
+ if (match?.[1]) {
69
+ const lines = match[1].split('\n');
70
+ for (const line of lines) {
71
+ const depMatch = /^\s*(\S+)\s+(\S+)/.exec(line.trim());
72
+ if (depMatch?.[1] && depMatch[2]) {
73
+ deps[depMatch[1]] = depMatch[2];
74
+ }
75
+ }
76
+ }
77
+ return deps;
78
+ },
79
+ },
80
+ ];
81
+ // ---------------------------------------------------------------------------
82
+ // File-tree walking utilities
83
+ // ---------------------------------------------------------------------------
84
+ /** Directories to always skip when walking the file tree */
85
+ const SKIP_DIRS = new Set([
86
+ 'node_modules',
87
+ '.git',
88
+ 'dist',
89
+ 'build',
90
+ '.next',
91
+ '__pycache__',
92
+ '.venv',
93
+ 'venv',
94
+ 'target',
95
+ 'vendor',
96
+ '.turbo',
97
+ 'coverage',
98
+ ]);
99
+ /**
100
+ * Recursively walk a directory and yield file paths.
101
+ * Skips common non-source directories.
102
+ */
103
+ function* walkDir(dir) {
104
+ let entries;
105
+ try {
106
+ entries = fs.readdirSync(dir, { withFileTypes: true });
107
+ }
108
+ catch {
109
+ // Unreadable directory — skip silently (Req 9.1 edge case)
110
+ return;
111
+ }
112
+ for (const entry of entries) {
113
+ const fullPath = path.join(dir, entry.name);
114
+ if (entry.isDirectory()) {
115
+ if (!SKIP_DIRS.has(entry.name)) {
116
+ yield* walkDir(fullPath);
117
+ }
118
+ }
119
+ else if (entry.isFile()) {
120
+ yield fullPath;
121
+ }
122
+ }
123
+ }
124
+ /**
125
+ * Check whether a file path matches any of the glob-like patterns.
126
+ * Supports simple patterns: `**\/*.ext` and `*.ext`.
127
+ */
128
+ function matchesFilePattern(filePath, patterns) {
129
+ const ext = path.extname(filePath);
130
+ const basename = path.basename(filePath);
131
+ for (const pattern of patterns) {
132
+ // Handle **/*.ext patterns
133
+ if (pattern.startsWith('**/')) {
134
+ const suffix = pattern.slice(3); // e.g. "*.ts"
135
+ if (suffix.startsWith('*.')) {
136
+ const requiredExt = suffix.slice(1); // e.g. ".ts"
137
+ if (ext === requiredExt)
138
+ return true;
139
+ }
140
+ else if (basename === suffix) {
141
+ return true;
142
+ }
143
+ }
144
+ // Handle *.ext patterns
145
+ else if (pattern.startsWith('*.')) {
146
+ const requiredExt = pattern.slice(1);
147
+ if (ext === requiredExt)
148
+ return true;
149
+ }
150
+ // Exact filename match
151
+ else if (basename === pattern) {
152
+ return true;
153
+ }
154
+ }
155
+ return false;
156
+ }
157
+ // ---------------------------------------------------------------------------
158
+ // Workspace detection
159
+ // ---------------------------------------------------------------------------
160
+ /**
161
+ * Detect workspace roots by scanning for manifest files.
162
+ * For monorepos, each directory containing a manifest is a workspace root.
163
+ */
164
+ function detectWorkspaces(repoPath) {
165
+ const workspaces = [];
166
+ const visited = new Set();
167
+ for (const filePath of walkDir(repoPath)) {
168
+ const dir = path.dirname(filePath);
169
+ const basename = path.basename(filePath);
170
+ for (const manifest of MANIFEST_TYPES) {
171
+ if (basename === manifest.file && !visited.has(`${dir}:${manifest.file}`)) {
172
+ visited.add(`${dir}:${manifest.file}`);
173
+ let content;
174
+ try {
175
+ content = fs.readFileSync(filePath, 'utf-8');
176
+ }
177
+ catch {
178
+ continue;
179
+ }
180
+ // Detect actual package manager from lockfiles
181
+ let packageManager = manifest.packageManager;
182
+ if (manifest.file === 'package.json') {
183
+ packageManager = detectNodePackageManager(dir);
184
+ }
185
+ workspaces.push({
186
+ root: path.relative(repoPath, dir) || '.',
187
+ packageManager,
188
+ language: manifest.language,
189
+ dependencies: manifest.parseDeps(content),
190
+ });
191
+ }
192
+ }
193
+ }
194
+ // If no workspaces found, create a root workspace from input metadata
195
+ if (workspaces.length === 0) {
196
+ workspaces.push({
197
+ root: '.',
198
+ packageManager: 'unknown',
199
+ language: 'unknown',
200
+ dependencies: {},
201
+ });
202
+ }
203
+ return workspaces;
204
+ }
205
+ /**
206
+ * Detect the Node.js package manager by checking for lockfiles.
207
+ */
208
+ function detectNodePackageManager(dir) {
209
+ if (fileExists(path.join(dir, 'pnpm-lock.yaml')))
210
+ return 'pnpm';
211
+ if (fileExists(path.join(dir, 'yarn.lock')))
212
+ return 'yarn';
213
+ if (fileExists(path.join(dir, 'bun.lockb')))
214
+ return 'bun';
215
+ return 'npm';
216
+ }
217
+ function fileExists(filePath) {
218
+ try {
219
+ return fs.statSync(filePath).isFile();
220
+ }
221
+ catch {
222
+ return false;
223
+ }
224
+ }
225
+ // ---------------------------------------------------------------------------
226
+ // Pattern matching
227
+ // ---------------------------------------------------------------------------
228
+ /**
229
+ * Scan a single file's content against the pattern catalog.
230
+ * Returns detections for each pattern match found.
231
+ */
232
+ function scanFile(filePath, relativeFilePath, catalog) {
233
+ let content;
234
+ try {
235
+ content = fs.readFileSync(filePath, 'utf-8');
236
+ }
237
+ catch {
238
+ // Unreadable file (binary, permissions) — skip
239
+ return [];
240
+ }
241
+ // Skip very large files (likely generated/minified)
242
+ if (content.length > 500_000)
243
+ return [];
244
+ const lines = content.split('\n');
245
+ const detections = [];
246
+ // Filter catalog to patterns whose filePatterns match this file
247
+ const applicablePatterns = catalog.filter((p) => matchesFilePattern(filePath, p.filePatterns));
248
+ for (const pattern of applicablePatterns) {
249
+ for (const regex of pattern.codePatterns) {
250
+ for (let i = 0; i < lines.length; i++) {
251
+ const line = lines[i];
252
+ if (line !== undefined && regex.test(line)) {
253
+ // Determine the line range — include surrounding context
254
+ const start = i + 1; // 1-indexed
255
+ const end = Math.min(i + 1, lines.length); // at least the matched line
256
+ detections.push({
257
+ filePath: relativeFilePath,
258
+ lineRange: { start, end },
259
+ patternCategory: pattern.id,
260
+ confidenceScore: pattern.confidenceBase,
261
+ suggestedLibrary: pattern.suggestedLibrary,
262
+ domain: pattern.domain,
263
+ });
264
+ // Only report the first match per pattern per file to avoid noise
265
+ break;
266
+ }
267
+ }
268
+ }
269
+ }
270
+ return detections;
271
+ }
272
+ // ---------------------------------------------------------------------------
273
+ // Main scanner entry point
274
+ // ---------------------------------------------------------------------------
275
+ /**
276
+ * Scan a codebase for hand-rolled implementations that could be replaced
277
+ * by third-party libraries.
278
+ *
279
+ * - Walks the file tree under `input.projectMetadata.repoPath`
280
+ * - Detects workspace roots for monorepos (package.json, pyproject.toml, etc.)
281
+ * - Matches source files against the pattern catalog
282
+ * - Returns structured `ScanResult` with detections and workspace info
283
+ */
284
+ export async function scanCodebase(input) {
285
+ const repoPath = path.resolve(input.projectMetadata.repoPath);
286
+ // Verify the repo path exists
287
+ if (!fs.existsSync(repoPath)) {
288
+ return { detections: [], workspaces: [] };
289
+ }
290
+ const catalog = getPatternCatalog();
291
+ // Detect workspaces (monorepo support)
292
+ const workspaces = detectWorkspaces(repoPath);
293
+ // Walk the file tree and scan each source file
294
+ const detections = [];
295
+ for (const filePath of walkDir(repoPath)) {
296
+ const relativeFilePath = path.relative(repoPath, filePath);
297
+ const fileDetections = scanFile(filePath, relativeFilePath, catalog);
298
+ detections.push(...fileDetections);
299
+ }
300
+ return { detections, workspaces };
301
+ }
302
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../src/analyzer/scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { ScanResult } from '../analyzer/scanner.js';
2
+ import type { InputSchema } from '../schemas/input.schema.js';
3
+ export interface UxAuditResult {
4
+ items: UxAuditItem[];
5
+ }
6
+ export interface UxAuditItem {
7
+ category: UxCategory;
8
+ status: 'present' | 'partial' | 'missing';
9
+ filePaths: string[];
10
+ recommendedLibrary?: string;
11
+ rationale: string;
12
+ }
13
+ export type UxCategory = 'accessibility' | 'error-states' | 'empty-states' | 'loading-states' | 'form-validation' | 'performance-feel' | 'copy-consistency' | 'design-system-alignment';
14
+ /**
15
+ * Audit UX completeness across 8 categories by examining scanner detections
16
+ * and the project's current library dependencies.
17
+ *
18
+ * Always returns exactly 8 items — one for each UX category.
19
+ * Items with status "partial" or "missing" include a recommendedLibrary and rationale.
20
+ *
21
+ * @param scanResult - The result from the codebase scanner
22
+ * @param projectMetadata - Project metadata including current libraries
23
+ * @returns UxAuditResult with exactly 8 audit items
24
+ */
25
+ export declare function auditUxCompleteness(scanResult: ScanResult, projectMetadata: InputSchema['projectMetadata']): UxAuditResult;
26
+ //# sourceMappingURL=ux-auditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ux-auditor.d.ts","sourceRoot":"","sources":["../../src/auditor/ux-auditor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,wBAAwB,CAAC;AACpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAM9D,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,UAAU,CAAC;IACrB,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;IAC1C,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD,MAAM,MAAM,UAAU,GAClB,eAAe,GACf,cAAc,GACd,cAAc,GACd,gBAAgB,GAChB,iBAAiB,GACjB,kBAAkB,GAClB,kBAAkB,GAClB,yBAAyB,CAAC;AAyS9B;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,UAAU,EACtB,eAAe,EAAE,WAAW,CAAC,iBAAiB,CAAC,GAC9C,aAAa,CA0Cf"}
@@ -0,0 +1,272 @@
1
+ const ALL_UX_CATEGORIES = [
2
+ 'accessibility',
3
+ 'error-states',
4
+ 'empty-states',
5
+ 'loading-states',
6
+ 'form-validation',
7
+ 'performance-feel',
8
+ 'copy-consistency',
9
+ 'design-system-alignment',
10
+ ];
11
+ const CATEGORY_CONFIGS = [
12
+ {
13
+ category: 'accessibility',
14
+ detectionPatternIds: [],
15
+ detectionDomains: ['ux-completeness'],
16
+ patternKeywords: [/a11y/i, /accessibility/i, /aria/i, /screen.?reader/i, /wcag/i],
17
+ libraryIndicators: [
18
+ 'react-aria',
19
+ '@radix-ui/react-accessible-icon',
20
+ 'axe-core',
21
+ '@axe-core/react',
22
+ 'eslint-plugin-jsx-a11y',
23
+ 'react-focus-lock',
24
+ '@reach/visually-hidden',
25
+ ],
26
+ recommendedLibrary: 'react-aria',
27
+ missingRationale: 'No accessibility patterns detected. Add react-aria for accessible primitives with ARIA attributes, focus management, and keyboard navigation built-in.',
28
+ partialRationale: 'Some accessibility patterns found but coverage is incomplete. react-aria provides comprehensive accessible component primitives.',
29
+ presentRationale: 'Accessibility patterns detected across frontend files with proper ARIA attributes and focus management.',
30
+ },
31
+ {
32
+ category: 'error-states',
33
+ detectionPatternIds: ['observability-manual-error-tracking'],
34
+ detectionDomains: ['observability'],
35
+ patternKeywords: [/error.?boundar/i, /error.?state/i, /error.?handling/i, /catch/i, /fallback/i],
36
+ libraryIndicators: [
37
+ 'react-error-boundary',
38
+ '@sentry/react',
39
+ 'sentry',
40
+ 'react-query',
41
+ '@tanstack/react-query',
42
+ ],
43
+ recommendedLibrary: 'react-error-boundary',
44
+ missingRationale: 'No error boundary or error state patterns detected. react-error-boundary provides declarative error boundaries with fallback UI, retry, and reset capabilities.',
45
+ partialRationale: 'Some error handling found but missing structured error boundaries. react-error-boundary adds declarative fallback UI and recovery patterns.',
46
+ presentRationale: 'Error state handling detected with error boundaries and fallback UI patterns.',
47
+ },
48
+ {
49
+ category: 'empty-states',
50
+ detectionPatternIds: [],
51
+ detectionDomains: ['ux-completeness'],
52
+ patternKeywords: [/empty.?state/i, /no.?data/i, /no.?results/i, /placeholder/i, /zero.?state/i],
53
+ libraryIndicators: ['react-empty-state', '@illustrations/undraw'],
54
+ recommendedLibrary: 'react-empty-state',
55
+ missingRationale: 'No empty state patterns detected. Add dedicated empty state components with illustrations and call-to-action buttons for better user guidance.',
56
+ partialRationale: 'Some empty state handling found but not consistently applied. Consider a dedicated empty state component library for consistent UX.',
57
+ presentRationale: 'Empty state patterns detected with appropriate placeholder content and user guidance.',
58
+ },
59
+ {
60
+ category: 'loading-states',
61
+ detectionPatternIds: ['ux-manual-loading-states'],
62
+ detectionDomains: ['ux-completeness'],
63
+ patternKeywords: [/loading/i, /spinner/i, /skeleton/i, /suspense/i, /pending/i],
64
+ libraryIndicators: [
65
+ 'react-loading-skeleton',
66
+ 'react-spinners',
67
+ 'react-content-loader',
68
+ '@tanstack/react-query',
69
+ 'swr',
70
+ ],
71
+ recommendedLibrary: 'react-loading-skeleton',
72
+ missingRationale: 'No loading state patterns detected. react-loading-skeleton provides animated placeholder UI that reduces perceived load time and prevents layout shift.',
73
+ partialRationale: 'Hand-rolled loading states found. react-loading-skeleton provides consistent, animated skeleton screens with automatic sizing.',
74
+ presentRationale: 'Loading state patterns detected with skeleton screens or spinner components.',
75
+ },
76
+ {
77
+ category: 'form-validation',
78
+ detectionPatternIds: ['ux-manual-form-validation'],
79
+ detectionDomains: ['ux-completeness'],
80
+ patternKeywords: [/form.?valid/i, /validation/i, /form.?error/i, /setError/i, /useForm/i],
81
+ libraryIndicators: [
82
+ 'react-hook-form',
83
+ 'formik',
84
+ 'yup',
85
+ 'zod',
86
+ '@hookform/resolvers',
87
+ 'vest',
88
+ ],
89
+ recommendedLibrary: 'react-hook-form',
90
+ missingRationale: 'No form validation patterns detected. react-hook-form provides performant form validation with minimal re-renders, schema integration, and accessible error messages.',
91
+ partialRationale: 'Hand-rolled form validation found. react-hook-form reduces boilerplate and provides consistent validation UX with schema-based validation support.',
92
+ presentRationale: 'Form validation patterns detected with structured validation library integration.',
93
+ },
94
+ {
95
+ category: 'performance-feel',
96
+ detectionPatternIds: [],
97
+ detectionDomains: ['ux-completeness'],
98
+ patternKeywords: [
99
+ /virtuali[sz]/i,
100
+ /lazy/i,
101
+ /code.?split/i,
102
+ /optimistic/i,
103
+ /debounce/i,
104
+ /throttle/i,
105
+ /intersection.?observer/i,
106
+ /prefetch/i,
107
+ ],
108
+ libraryIndicators: [
109
+ 'react-virtual',
110
+ '@tanstack/react-virtual',
111
+ 'react-window',
112
+ 'react-virtualized',
113
+ 'react-intersection-observer',
114
+ 'framer-motion',
115
+ ],
116
+ recommendedLibrary: '@tanstack/react-virtual',
117
+ missingRationale: 'No performance optimization patterns detected. @tanstack/react-virtual provides efficient list virtualization, reducing DOM nodes and improving scroll performance for large datasets.',
118
+ partialRationale: 'Some performance patterns found but missing virtualization or optimistic updates. @tanstack/react-virtual improves rendering performance for large lists.',
119
+ presentRationale: 'Performance optimization patterns detected including virtualization and lazy loading.',
120
+ },
121
+ {
122
+ category: 'copy-consistency',
123
+ detectionPatternIds: ['i18n-manual-pluralization', 'i18n-manual-locale-detection'],
124
+ detectionDomains: ['i18n'],
125
+ patternKeywords: [/i18n/i, /l10n/i, /locale/i, /translat/i, /intl/i, /plurali[sz]/i],
126
+ libraryIndicators: [
127
+ 'i18next',
128
+ 'react-i18next',
129
+ 'react-intl',
130
+ 'next-intl',
131
+ 'formatjs',
132
+ '@formatjs/intl',
133
+ ],
134
+ recommendedLibrary: 'react-i18next',
135
+ missingRationale: 'No internationalization or copy management patterns detected. react-i18next provides structured copy management with pluralization, interpolation, and locale-aware formatting for consistent UI text.',
136
+ partialRationale: 'Hand-rolled i18n patterns found. react-i18next provides centralized copy management ensuring consistency across the application.',
137
+ presentRationale: 'Copy consistency patterns detected with internationalization library integration.',
138
+ },
139
+ {
140
+ category: 'design-system-alignment',
141
+ detectionPatternIds: [],
142
+ detectionDomains: ['ux-completeness'],
143
+ patternKeywords: [
144
+ /design.?system/i,
145
+ /component.?library/i,
146
+ /theme/i,
147
+ /styled/i,
148
+ /tailwind/i,
149
+ /chakra/i,
150
+ /radix/i,
151
+ /shadcn/i,
152
+ ],
153
+ libraryIndicators: [
154
+ '@radix-ui/react-dialog',
155
+ '@radix-ui/react-dropdown-menu',
156
+ '@radix-ui/react-popover',
157
+ '@radix-ui/react-select',
158
+ '@radix-ui/react-tooltip',
159
+ '@chakra-ui/react',
160
+ '@mui/material',
161
+ 'antd',
162
+ 'tailwindcss',
163
+ 'styled-components',
164
+ '@emotion/react',
165
+ 'class-variance-authority',
166
+ ],
167
+ recommendedLibrary: '@radix-ui/themes',
168
+ missingRationale: 'No design system or component library patterns detected. @radix-ui/themes provides accessible, composable UI primitives that enforce design consistency across the application.',
169
+ partialRationale: 'Some design system patterns found but coverage is incomplete. @radix-ui/themes provides a comprehensive set of accessible, themed components.',
170
+ presentRationale: 'Design system alignment detected with component library and theming patterns.',
171
+ },
172
+ ];
173
+ // ---------------------------------------------------------------------------
174
+ // Core audit logic
175
+ // ---------------------------------------------------------------------------
176
+ /**
177
+ * Determine the status of a UX category based on scanner detections and
178
+ * the project's current libraries.
179
+ */
180
+ function evaluateCategory(config, detections, currentLibraries) {
181
+ const filePaths = [];
182
+ let hasDetections = false;
183
+ let hasLibrary = false;
184
+ // Check if any scanner detections match this category
185
+ for (const detection of detections) {
186
+ const matchesPatternId = config.detectionPatternIds.includes(detection.patternCategory);
187
+ const matchesDomain = config.detectionDomains.includes(detection.domain);
188
+ const matchesKeyword = config.patternKeywords.some((kw) => kw.test(detection.patternCategory) || kw.test(detection.domain));
189
+ if (matchesPatternId || matchesDomain || matchesKeyword) {
190
+ hasDetections = true;
191
+ if (!filePaths.includes(detection.filePath)) {
192
+ filePaths.push(detection.filePath);
193
+ }
194
+ }
195
+ }
196
+ // Check if any current libraries indicate coverage for this category
197
+ const libraryNames = Object.keys(currentLibraries);
198
+ for (const indicator of config.libraryIndicators) {
199
+ if (libraryNames.some((lib) => lib === indicator || lib.includes(indicator))) {
200
+ hasLibrary = true;
201
+ break;
202
+ }
203
+ }
204
+ // Determine status:
205
+ // - present: library installed AND no hand-rolled detections, OR library installed
206
+ // - partial: hand-rolled detections found (library may or may not be installed)
207
+ // - missing: no library and no detections
208
+ if (hasLibrary && !hasDetections) {
209
+ return { status: 'present', filePaths };
210
+ }
211
+ else if (hasDetections) {
212
+ // Hand-rolled patterns detected — partial coverage (library may help replace them)
213
+ return { status: 'partial', filePaths };
214
+ }
215
+ else if (hasLibrary) {
216
+ return { status: 'present', filePaths };
217
+ }
218
+ else {
219
+ return { status: 'missing', filePaths };
220
+ }
221
+ }
222
+ // ---------------------------------------------------------------------------
223
+ // Public API
224
+ // ---------------------------------------------------------------------------
225
+ /**
226
+ * Audit UX completeness across 8 categories by examining scanner detections
227
+ * and the project's current library dependencies.
228
+ *
229
+ * Always returns exactly 8 items — one for each UX category.
230
+ * Items with status "partial" or "missing" include a recommendedLibrary and rationale.
231
+ *
232
+ * @param scanResult - The result from the codebase scanner
233
+ * @param projectMetadata - Project metadata including current libraries
234
+ * @returns UxAuditResult with exactly 8 audit items
235
+ */
236
+ export function auditUxCompleteness(scanResult, projectMetadata) {
237
+ const currentLibraries = projectMetadata.currentLibraries;
238
+ const items = [];
239
+ for (const config of CATEGORY_CONFIGS) {
240
+ const { status, filePaths } = evaluateCategory(config, scanResult.detections, currentLibraries);
241
+ const item = {
242
+ category: config.category,
243
+ status,
244
+ filePaths,
245
+ rationale: status === 'missing'
246
+ ? config.missingRationale
247
+ : status === 'partial'
248
+ ? config.partialRationale
249
+ : config.presentRationale,
250
+ };
251
+ // Add recommendedLibrary for partial or missing statuses (required by spec)
252
+ if (status === 'partial' || status === 'missing') {
253
+ item.recommendedLibrary = config.recommendedLibrary;
254
+ }
255
+ items.push(item);
256
+ }
257
+ // Ensure all 8 categories are present (defensive — should always be true)
258
+ const coveredCategories = new Set(items.map((i) => i.category));
259
+ for (const category of ALL_UX_CATEGORIES) {
260
+ if (!coveredCategories.has(category)) {
261
+ items.push({
262
+ category,
263
+ status: 'missing',
264
+ filePaths: [],
265
+ recommendedLibrary: 'unknown',
266
+ rationale: `No patterns detected for ${category}. Manual review recommended.`,
267
+ });
268
+ }
269
+ }
270
+ return { items };
271
+ }
272
+ //# sourceMappingURL=ux-auditor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ux-auditor.js","sourceRoot":"","sources":["../../src/auditor/ux-auditor.ts"],"names":[],"mappings":"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"}