@buoy-design/core 0.1.1 → 0.1.3

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 (110) hide show
  1. package/dist/analysis/audit.d.ts +47 -0
  2. package/dist/analysis/audit.d.ts.map +1 -0
  3. package/dist/analysis/audit.js +168 -0
  4. package/dist/analysis/audit.js.map +1 -0
  5. package/dist/analysis/index.d.ts +1 -0
  6. package/dist/analysis/index.d.ts.map +1 -1
  7. package/dist/analysis/index.js +2 -0
  8. package/dist/analysis/index.js.map +1 -1
  9. package/dist/analysis/semantic-diff.d.ts +15 -0
  10. package/dist/analysis/semantic-diff.d.ts.map +1 -1
  11. package/dist/analysis/semantic-diff.js +204 -1
  12. package/dist/analysis/semantic-diff.js.map +1 -1
  13. package/dist/analysis/token-suggestions.d.ts +8 -1
  14. package/dist/analysis/token-suggestions.d.ts.map +1 -1
  15. package/dist/analysis/token-suggestions.js +116 -10
  16. package/dist/analysis/token-suggestions.js.map +1 -1
  17. package/dist/extraction/css-parser.d.ts +51 -0
  18. package/dist/extraction/css-parser.d.ts.map +1 -0
  19. package/dist/extraction/css-parser.js +303 -0
  20. package/dist/extraction/css-parser.js.map +1 -0
  21. package/dist/extraction/index.d.ts +2 -0
  22. package/dist/extraction/index.d.ts.map +1 -0
  23. package/dist/extraction/index.js +2 -0
  24. package/dist/extraction/index.js.map +1 -0
  25. package/dist/graph/builder.d.ts +118 -0
  26. package/dist/graph/builder.d.ts.map +1 -0
  27. package/dist/graph/builder.js +328 -0
  28. package/dist/graph/builder.js.map +1 -0
  29. package/dist/graph/collectors/git.d.ts +90 -0
  30. package/dist/graph/collectors/git.d.ts.map +1 -0
  31. package/dist/graph/collectors/git.js +253 -0
  32. package/dist/graph/collectors/git.js.map +1 -0
  33. package/dist/graph/collectors/imports.d.ts +55 -0
  34. package/dist/graph/collectors/imports.d.ts.map +1 -0
  35. package/dist/graph/collectors/imports.js +230 -0
  36. package/dist/graph/collectors/imports.js.map +1 -0
  37. package/dist/graph/collectors/index.d.ts +9 -0
  38. package/dist/graph/collectors/index.d.ts.map +1 -0
  39. package/dist/graph/collectors/index.js +12 -0
  40. package/dist/graph/collectors/index.js.map +1 -0
  41. package/dist/graph/collectors/usages.d.ts +68 -0
  42. package/dist/graph/collectors/usages.d.ts.map +1 -0
  43. package/dist/graph/collectors/usages.js +244 -0
  44. package/dist/graph/collectors/usages.js.map +1 -0
  45. package/dist/graph/index.d.ts +11 -0
  46. package/dist/graph/index.d.ts.map +1 -0
  47. package/dist/graph/index.js +29 -0
  48. package/dist/graph/index.js.map +1 -0
  49. package/dist/graph/queries.d.ts +81 -0
  50. package/dist/graph/queries.d.ts.map +1 -0
  51. package/dist/graph/queries.js +379 -0
  52. package/dist/graph/queries.js.map +1 -0
  53. package/dist/graph/types.d.ts +184 -0
  54. package/dist/graph/types.d.ts.map +1 -0
  55. package/dist/graph/types.js +8 -0
  56. package/dist/graph/types.js.map +1 -0
  57. package/dist/index.d.ts +4 -0
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +8 -0
  60. package/dist/index.js.map +1 -1
  61. package/dist/models/drift.d.ts +20 -4
  62. package/dist/models/drift.d.ts.map +1 -1
  63. package/dist/models/drift.js +55 -1
  64. package/dist/models/drift.js.map +1 -1
  65. package/dist/models/index.d.ts +3 -3
  66. package/dist/models/index.d.ts.map +1 -1
  67. package/dist/models/index.js +2 -2
  68. package/dist/models/index.js.map +1 -1
  69. package/dist/models/token.d.ts +57 -0
  70. package/dist/models/token.d.ts.map +1 -1
  71. package/dist/models/token.js +9 -0
  72. package/dist/models/token.js.map +1 -1
  73. package/dist/tokenization/generator.d.ts +49 -0
  74. package/dist/tokenization/generator.d.ts.map +1 -0
  75. package/dist/tokenization/generator.js +886 -0
  76. package/dist/tokenization/generator.js.map +1 -0
  77. package/dist/tokenization/index.d.ts +2 -0
  78. package/dist/tokenization/index.d.ts.map +1 -0
  79. package/dist/tokenization/index.js +2 -0
  80. package/dist/tokenization/index.js.map +1 -0
  81. package/dist/tokens/comparison.d.ts +30 -0
  82. package/dist/tokens/comparison.d.ts.map +1 -0
  83. package/dist/tokens/comparison.js +142 -0
  84. package/dist/tokens/comparison.js.map +1 -0
  85. package/dist/tokens/index.d.ts +3 -0
  86. package/dist/tokens/index.d.ts.map +1 -0
  87. package/dist/tokens/index.js +5 -0
  88. package/dist/tokens/index.js.map +1 -0
  89. package/dist/tokens/parser.d.ts +11 -0
  90. package/dist/tokens/parser.d.ts.map +1 -0
  91. package/dist/tokens/parser.js +268 -0
  92. package/dist/tokens/parser.js.map +1 -0
  93. package/package.json +14 -10
  94. package/LICENSE +0 -21
  95. package/dist/analysis/semantic-diff.test.d.ts +0 -2
  96. package/dist/analysis/semantic-diff.test.d.ts.map +0 -1
  97. package/dist/analysis/semantic-diff.test.js +0 -188
  98. package/dist/analysis/semantic-diff.test.js.map +0 -1
  99. package/dist/models/component.test.d.ts +0 -2
  100. package/dist/models/component.test.d.ts.map +0 -1
  101. package/dist/models/component.test.js +0 -55
  102. package/dist/models/component.test.js.map +0 -1
  103. package/dist/models/drift.test.d.ts +0 -2
  104. package/dist/models/drift.test.d.ts.map +0 -1
  105. package/dist/models/drift.test.js +0 -38
  106. package/dist/models/drift.test.js.map +0 -1
  107. package/dist/models/token.test.d.ts +0 -2
  108. package/dist/models/token.test.d.ts.map +0 -1
  109. package/dist/models/token.test.js +0 -168
  110. package/dist/models/token.test.js.map +0 -1
@@ -0,0 +1,47 @@
1
+ export interface AuditValue {
2
+ category: 'color' | 'spacing' | 'typography' | 'radius';
3
+ value: string;
4
+ file: string;
5
+ line: number;
6
+ }
7
+ export interface CategoryStats {
8
+ uniqueCount: number;
9
+ totalUsages: number;
10
+ mostCommon: Array<{
11
+ value: string;
12
+ count: number;
13
+ }>;
14
+ }
15
+ export interface FileIssue {
16
+ file: string;
17
+ issueCount: number;
18
+ }
19
+ export interface CloseMatch {
20
+ value: string;
21
+ closeTo: string;
22
+ distance: number;
23
+ }
24
+ export interface AuditReport {
25
+ categories: Record<string, CategoryStats>;
26
+ worstFiles: FileIssue[];
27
+ totals: {
28
+ uniqueValues: number;
29
+ totalUsages: number;
30
+ filesAffected: number;
31
+ };
32
+ closeMatches: CloseMatch[];
33
+ score: number;
34
+ }
35
+ /**
36
+ * Generate an audit report from extracted values
37
+ */
38
+ export declare function generateAuditReport(values: AuditValue[]): AuditReport;
39
+ /**
40
+ * Find values that are close to design tokens (likely typos)
41
+ */
42
+ export declare function findCloseMatches(foundValues: string[], designTokens: string[], category: 'color' | 'spacing' | 'typography' | 'radius'): CloseMatch[];
43
+ /**
44
+ * Calculate health score (0-100) from audit report
45
+ */
46
+ export declare function calculateHealthScore(report: AuditReport): number;
47
+ //# sourceMappingURL=audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/analysis/audit.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,YAAY,GAAG,QAAQ,CAAC;IACxD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrD;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC1C,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,MAAM,EAAE;QACN,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,YAAY,EAAE,UAAU,EAAE,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,WAAW,CAoErE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EAAE,EACrB,YAAY,EAAE,MAAM,EAAE,EACtB,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,YAAY,GAAG,QAAQ,GACtD,UAAU,EAAE,CAoCd;AA0DD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CA6BhE"}
@@ -0,0 +1,168 @@
1
+ // Audit report generation - analyzes codebase for design system health
2
+ /**
3
+ * Generate an audit report from extracted values
4
+ */
5
+ export function generateAuditReport(values) {
6
+ if (values.length === 0) {
7
+ return {
8
+ categories: {},
9
+ worstFiles: [],
10
+ totals: { uniqueValues: 0, totalUsages: 0, filesAffected: 0 },
11
+ closeMatches: [],
12
+ score: 100,
13
+ };
14
+ }
15
+ // Group by category
16
+ const byCategory = new Map();
17
+ const byFile = new Map();
18
+ const allFiles = new Set();
19
+ for (const v of values) {
20
+ // Category stats
21
+ if (!byCategory.has(v.category)) {
22
+ byCategory.set(v.category, new Map());
23
+ }
24
+ const catMap = byCategory.get(v.category);
25
+ catMap.set(v.value, (catMap.get(v.value) || 0) + 1);
26
+ // File stats
27
+ byFile.set(v.file, (byFile.get(v.file) || 0) + 1);
28
+ allFiles.add(v.file);
29
+ }
30
+ // Build category stats
31
+ const categories = {};
32
+ let totalUnique = 0;
33
+ for (const [category, valueMap] of byCategory) {
34
+ const entries = [...valueMap.entries()];
35
+ const uniqueCount = entries.length;
36
+ const totalUsages = entries.reduce((sum, [, count]) => sum + count, 0);
37
+ // Sort by count descending for mostCommon
38
+ const mostCommon = entries
39
+ .map(([value, count]) => ({ value, count }))
40
+ .sort((a, b) => b.count - a.count)
41
+ .slice(0, 10);
42
+ categories[category] = { uniqueCount, totalUsages, mostCommon };
43
+ totalUnique += uniqueCount;
44
+ }
45
+ // Build worst files list
46
+ const worstFiles = [...byFile.entries()]
47
+ .map(([file, issueCount]) => ({ file, issueCount }))
48
+ .sort((a, b) => b.issueCount - a.issueCount)
49
+ .slice(0, 10);
50
+ const report = {
51
+ categories,
52
+ worstFiles,
53
+ totals: {
54
+ uniqueValues: totalUnique,
55
+ totalUsages: values.length,
56
+ filesAffected: allFiles.size,
57
+ },
58
+ closeMatches: [],
59
+ score: 0,
60
+ };
61
+ report.score = calculateHealthScore(report);
62
+ return report;
63
+ }
64
+ /**
65
+ * Find values that are close to design tokens (likely typos)
66
+ */
67
+ export function findCloseMatches(foundValues, designTokens, category) {
68
+ const matches = [];
69
+ const tokenSet = new Set(designTokens.map((t) => t.toLowerCase()));
70
+ for (const value of foundValues) {
71
+ const valueLower = value.toLowerCase();
72
+ // Skip exact matches
73
+ if (tokenSet.has(valueLower)) {
74
+ continue;
75
+ }
76
+ // Find closest token
77
+ let closestToken = null;
78
+ let closestDistance = Infinity;
79
+ for (const token of designTokens) {
80
+ const distance = getDistance(value, token, category);
81
+ if (distance < closestDistance && distance > 0) {
82
+ closestDistance = distance;
83
+ closestToken = token;
84
+ }
85
+ }
86
+ // Only include if close enough (threshold depends on category)
87
+ const threshold = category === 'color' ? 5 : 2;
88
+ if (closestToken && closestDistance <= threshold) {
89
+ matches.push({
90
+ value,
91
+ closeTo: closestToken,
92
+ distance: closestDistance,
93
+ });
94
+ }
95
+ }
96
+ return matches;
97
+ }
98
+ /**
99
+ * Calculate distance between two values
100
+ */
101
+ function getDistance(a, b, category) {
102
+ if (category === 'color') {
103
+ return colorDistance(a, b);
104
+ }
105
+ if (category === 'spacing' || category === 'radius') {
106
+ return numericDistance(a, b);
107
+ }
108
+ // For typography, use simple string comparison
109
+ return a.toLowerCase() === b.toLowerCase() ? 0 : Infinity;
110
+ }
111
+ /**
112
+ * Calculate color distance (simple hex comparison)
113
+ */
114
+ function colorDistance(a, b) {
115
+ const hexA = a.replace('#', '').toLowerCase();
116
+ const hexB = b.replace('#', '').toLowerCase();
117
+ if (hexA.length !== 6 || hexB.length !== 6) {
118
+ return Infinity;
119
+ }
120
+ // Count differing characters
121
+ let diff = 0;
122
+ for (let i = 0; i < 6; i++) {
123
+ if (hexA[i] !== hexB[i]) {
124
+ diff++;
125
+ }
126
+ }
127
+ return diff;
128
+ }
129
+ /**
130
+ * Calculate numeric distance for spacing/radius
131
+ */
132
+ function numericDistance(a, b) {
133
+ const numA = parseFloat(a);
134
+ const numB = parseFloat(b);
135
+ if (isNaN(numA) || isNaN(numB)) {
136
+ return Infinity;
137
+ }
138
+ return Math.abs(numA - numB);
139
+ }
140
+ /**
141
+ * Calculate health score (0-100) from audit report
142
+ */
143
+ export function calculateHealthScore(report) {
144
+ // Perfect score if no issues
145
+ if (report.totals.uniqueValues === 0) {
146
+ return 100;
147
+ }
148
+ let score = 100;
149
+ // Penalize for too many unique values
150
+ // Expect roughly: colors ~12, spacing ~8, typography ~6, radius ~4 = ~30 total
151
+ const expectedMaxUnique = 30;
152
+ const uniqueRatio = report.totals.uniqueValues / expectedMaxUnique;
153
+ if (uniqueRatio > 1) {
154
+ // Heavy penalty for exceeding expected unique values
155
+ // 50 unique = ratio 1.67, penalty = 0.67 * 80 = 53
156
+ score -= Math.min(80, (uniqueRatio - 1) * 80);
157
+ }
158
+ // Penalize for close matches (typos) - 6 points each
159
+ score -= report.closeMatches.length * 6;
160
+ // Penalize for concentration in worst files
161
+ const worstFile = report.worstFiles[0];
162
+ if (worstFile && worstFile.issueCount > 20) {
163
+ score -= Math.min(20, (worstFile.issueCount - 20) * 0.5);
164
+ }
165
+ // Clamp to 0-100
166
+ return Math.max(0, Math.min(100, Math.round(score)));
167
+ }
168
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/analysis/audit.ts"],"names":[],"mappings":"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"}
@@ -2,4 +2,5 @@ export { SemanticDiffEngine, type ComponentMatch, type ComponentDifference, type
2
2
  export { TokenSuggestionService, type TokenSuggestion, } from "./token-suggestions.js";
3
3
  export { stringSimilarity, levenshteinDistance, normalizeForComparison, } from "./string-utils.js";
4
4
  export { MATCHING_CONFIG, NAMING_CONFIG, TOKEN_SUGGESTION_CONFIG, SCANNER_CONFIG, getOutlierThreshold, } from "./config.js";
5
+ export { generateAuditReport, findCloseMatches, calculateHealthScore, type AuditValue, type AuditReport, type CategoryStats, type FileIssue, type CloseMatch, } from "./audit.js";
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analysis/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,eAAe,GACrB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,sBAAsB,EACtB,KAAK,eAAe,GACrB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,eAAe,EACf,aAAa,EACb,uBAAuB,EACvB,cAAc,EACd,mBAAmB,GACpB,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analysis/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,eAAe,GACrB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,sBAAsB,EACtB,KAAK,eAAe,GACrB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,eAAe,EACf,aAAa,EACb,uBAAuB,EACvB,cAAc,EACd,mBAAmB,GACpB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,EACpB,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,KAAK,UAAU,GAChB,MAAM,YAAY,CAAC"}
@@ -5,4 +5,6 @@ export { TokenSuggestionService, } from "./token-suggestions.js";
5
5
  export { stringSimilarity, levenshteinDistance, normalizeForComparison, } from "./string-utils.js";
6
6
  // Analysis configuration
7
7
  export { MATCHING_CONFIG, NAMING_CONFIG, TOKEN_SUGGESTION_CONFIG, SCANNER_CONFIG, getOutlierThreshold, } from "./config.js";
8
+ // Audit report
9
+ export { generateAuditReport, findCloseMatches, calculateHealthScore, } from "./audit.js";
8
10
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/analysis/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,GAOnB,MAAM,oBAAoB,CAAC;AAE5B,6BAA6B;AAC7B,OAAO,EACL,sBAAsB,GAEvB,MAAM,wBAAwB,CAAC;AAEhC,mBAAmB;AACnB,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAE3B,yBAAyB;AACzB,OAAO,EACL,eAAe,EACf,aAAa,EACb,uBAAuB,EACvB,cAAc,EACd,mBAAmB,GACpB,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/analysis/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,GAOnB,MAAM,oBAAoB,CAAC;AAE5B,6BAA6B;AAC7B,OAAO,EACL,sBAAsB,GAEvB,MAAM,wBAAwB,CAAC;AAEhC,mBAAmB;AACnB,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAE3B,yBAAyB;AACzB,OAAO,EACL,eAAe,EACf,aAAa,EACb,uBAAuB,EACvB,cAAc,EACd,mBAAmB,GACpB,MAAM,aAAa,CAAC;AAErB,eAAe;AACf,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,oBAAoB,GAMrB,MAAM,YAAY,CAAC"}
@@ -122,6 +122,21 @@ export declare class SemanticDiffEngine {
122
122
  private tokenToDriftSource;
123
123
  private getHighestSeverity;
124
124
  private checkAccessibility;
125
+ /**
126
+ * Check for color contrast issues in component
127
+ * Detects foreground/background color pairs that fail WCAG contrast ratios
128
+ */
129
+ private checkColorContrast;
130
+ /**
131
+ * Check for unused components
132
+ * Components that are defined but never imported/used elsewhere
133
+ */
134
+ checkUnusedComponents(components: Component[], usageMap: Map<string, number>): DriftSignal[];
135
+ /**
136
+ * Check for unused tokens
137
+ * Design tokens that are defined but never referenced
138
+ */
139
+ checkUnusedTokens(tokens: DesignToken[], usageMap: Map<string, number>): DriftSignal[];
125
140
  /**
126
141
  * Find token suggestions for a hardcoded color value
127
142
  * Delegates to TokenSuggestionService
@@ -1 +1 @@
1
- {"version":3,"file":"semantic-diff.d.ts","sourceRoot":"","sources":["../../src/analysis/semantic-diff.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"semantic-diff.d.ts","sourceRoot":"","sources":["../../src/analysis/semantic-diff.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,84 @@ import { createDriftId, normalizeComponentName, normalizeTokenName, tokensMatch,
2
2
  import { TokenSuggestionService, } from "./token-suggestions.js";
3
3
  import { stringSimilarity as calcStringSimilarity } from "./string-utils.js";
4
4
  import { MATCHING_CONFIG, NAMING_CONFIG, getOutlierThreshold, } from "./config.js";
5
+ /**
6
+ * Calculate relative luminance for WCAG contrast ratio
7
+ * https://www.w3.org/TR/WCAG20/#relativeluminancedef
8
+ */
9
+ function getRelativeLuminance(r, g, b) {
10
+ const normalize = (c) => {
11
+ const sRGB = c / 255;
12
+ return sRGB <= 0.03928 ? sRGB / 12.92 : Math.pow((sRGB + 0.055) / 1.055, 2.4);
13
+ };
14
+ const rs = normalize(r);
15
+ const gs = normalize(g);
16
+ const bs = normalize(b);
17
+ return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
18
+ }
19
+ /**
20
+ * Calculate WCAG contrast ratio between two colors
21
+ * https://www.w3.org/TR/WCAG20/#contrast-ratiodef
22
+ */
23
+ function getContrastRatio(color1, color2) {
24
+ const l1 = getRelativeLuminance(color1.r, color1.g, color1.b);
25
+ const l2 = getRelativeLuminance(color2.r, color2.g, color2.b);
26
+ const lighter = Math.max(l1, l2);
27
+ const darker = Math.min(l1, l2);
28
+ return (lighter + 0.05) / (darker + 0.05);
29
+ }
30
+ /**
31
+ * Parse hex color to RGB
32
+ */
33
+ function hexToRgb(hex) {
34
+ const normalized = hex.replace(/^#/, '');
35
+ // Handle 3-digit hex
36
+ if (normalized.length === 3) {
37
+ const [r, g, b] = normalized.split('').map(c => parseInt(c + c, 16));
38
+ return { r: r, g: g, b: b };
39
+ }
40
+ // Handle 6-digit hex
41
+ if (normalized.length === 6) {
42
+ const r = parseInt(normalized.substring(0, 2), 16);
43
+ const g = parseInt(normalized.substring(2, 4), 16);
44
+ const b = parseInt(normalized.substring(4, 6), 16);
45
+ return { r, g, b };
46
+ }
47
+ return null;
48
+ }
49
+ /**
50
+ * Parse rgb/rgba string to RGB
51
+ */
52
+ function parseRgbString(rgbString) {
53
+ const match = rgbString.match(/rgba?\((\d+),?\s*(\d+),?\s*(\d+)/);
54
+ if (!match)
55
+ return null;
56
+ return {
57
+ r: parseInt(match[1]),
58
+ g: parseInt(match[2]),
59
+ b: parseInt(match[3]),
60
+ };
61
+ }
62
+ /**
63
+ * Convert color value to RGB
64
+ */
65
+ function colorToRgb(color) {
66
+ if (color.startsWith('#')) {
67
+ return hexToRgb(color);
68
+ }
69
+ if (color.startsWith('rgb')) {
70
+ return parseRgbString(color);
71
+ }
72
+ // Named colors (common ones)
73
+ const namedColors = {
74
+ 'white': { r: 255, g: 255, b: 255 },
75
+ 'black': { r: 0, g: 0, b: 0 },
76
+ 'red': { r: 255, g: 0, b: 0 },
77
+ 'green': { r: 0, g: 128, b: 0 },
78
+ 'blue': { r: 0, g: 0, b: 255 },
79
+ 'transparent': { r: 255, g: 255, b: 255 }, // Treat as white for contrast purposes
80
+ };
81
+ return namedColors[color.toLowerCase()] || null;
82
+ }
5
83
  /**
6
84
  * Semantic suffixes that represent legitimate separate components.
7
85
  * Components with these suffixes are NOT duplicates of their base component.
@@ -473,6 +551,11 @@ export class SemanticDiffEngine {
473
551
  });
474
552
  }
475
553
  }
554
+ // Check for color contrast issues
555
+ if (options.checkAccessibility) {
556
+ const contrastIssues = this.checkColorContrast(component);
557
+ drifts.push(...contrastIssues);
558
+ }
476
559
  }
477
560
  // Cross-component checks
478
561
  // Check for potential duplicate components
@@ -705,7 +788,8 @@ export class SemanticDiffEngine {
705
788
  if (lowerName.endsWith(suffix) &&
706
789
  lowerName.length > suffix.length &&
707
790
  // Ensure the suffix is at a word boundary (e.g., "ButtonGroup" not "Buttong")
708
- lowerName[lowerName.length - suffix.length - 1]?.match(/[a-z]/)) {
791
+ // Use [a-z0-9] to handle names like "Button2Group" where digit precedes suffix
792
+ lowerName[lowerName.length - suffix.length - 1]?.match(/[a-z0-9]/)) {
709
793
  // This is a compound component, not a duplicate candidate
710
794
  // Return the full name as the base (it's distinct)
711
795
  return { baseName: lowerName, hasVersionSuffix: false };
@@ -932,6 +1016,125 @@ export class SemanticDiffEngine {
932
1016
  }
933
1017
  return issues;
934
1018
  }
1019
+ /**
1020
+ * Check for color contrast issues in component
1021
+ * Detects foreground/background color pairs that fail WCAG contrast ratios
1022
+ */
1023
+ checkColorContrast(component) {
1024
+ const drifts = [];
1025
+ if (!component.metadata.hardcodedValues) {
1026
+ return drifts;
1027
+ }
1028
+ const colorValues = component.metadata.hardcodedValues.filter((h) => h.type === "color");
1029
+ // Look for color/background-color pairs
1030
+ const colorsByProperty = new Map();
1031
+ for (const cv of colorValues) {
1032
+ const prop = cv.property.toLowerCase();
1033
+ if (!colorsByProperty.has(prop)) {
1034
+ colorsByProperty.set(prop, []);
1035
+ }
1036
+ colorsByProperty.get(prop).push(cv);
1037
+ }
1038
+ const foregroundColors = colorsByProperty.get("color") || [];
1039
+ const backgroundColors = colorsByProperty.get("background-color") ||
1040
+ colorsByProperty.get("background") ||
1041
+ [];
1042
+ // Check contrast ratio for each foreground/background pair
1043
+ for (const fg of foregroundColors) {
1044
+ for (const bg of backgroundColors) {
1045
+ const fgRgb = colorToRgb(fg.value);
1046
+ const bgRgb = colorToRgb(bg.value);
1047
+ if (!fgRgb || !bgRgb)
1048
+ continue;
1049
+ const ratio = getContrastRatio(fgRgb, bgRgb);
1050
+ // WCAG AA requires 4.5:1 for normal text, 3:1 for large text
1051
+ // WCAG AAA requires 7:1 for normal text, 4.5:1 for large text
1052
+ const minRatioAA = 4.5;
1053
+ const minRatioAAA = 7;
1054
+ if (ratio < minRatioAA) {
1055
+ const level = ratio < 3 ? "WCAG AA and AAA" : "WCAG AAA";
1056
+ drifts.push({
1057
+ id: createDriftId("color-contrast", component.id, `${fg.value}-${bg.value}`),
1058
+ type: "color-contrast",
1059
+ severity: "critical",
1060
+ source: this.componentToDriftSource(component),
1061
+ message: `Component "${component.name}" has insufficient color contrast: ${fg.value} on ${bg.value} (ratio: ${ratio.toFixed(2)}:1)`,
1062
+ details: {
1063
+ expected: `Minimum ${minRatioAA}:1 for WCAG AA, ${minRatioAAA}:1 for AAA`,
1064
+ actual: `${ratio.toFixed(2)}:1`,
1065
+ suggestions: [
1066
+ `Fails ${level} - adjust colors to meet minimum ${minRatioAA}:1 ratio`,
1067
+ "Use a contrast checker tool to find accessible color combinations",
1068
+ "Consider using design system color tokens with built-in contrast ratios",
1069
+ ],
1070
+ affectedFiles: [
1071
+ `${fg.location}: ${fg.property}: ${fg.value}`,
1072
+ `${bg.location}: ${bg.property}: ${bg.value}`,
1073
+ ],
1074
+ },
1075
+ detectedAt: new Date(),
1076
+ });
1077
+ }
1078
+ }
1079
+ }
1080
+ return drifts;
1081
+ }
1082
+ /**
1083
+ * Check for unused components
1084
+ * Components that are defined but never imported/used elsewhere
1085
+ */
1086
+ checkUnusedComponents(components, usageMap) {
1087
+ const drifts = [];
1088
+ for (const component of components) {
1089
+ const usageCount = usageMap.get(component.id) || usageMap.get(component.name) || 0;
1090
+ if (usageCount === 0) {
1091
+ drifts.push({
1092
+ id: createDriftId("unused-component", component.id),
1093
+ type: "unused-component",
1094
+ severity: "warning",
1095
+ source: this.componentToDriftSource(component),
1096
+ message: `Component "${component.name}" is defined but never used`,
1097
+ details: {
1098
+ suggestions: [
1099
+ "Remove component if no longer needed",
1100
+ "Export component if it's part of the public API",
1101
+ "Add usage in tests or documentation",
1102
+ ],
1103
+ },
1104
+ detectedAt: new Date(),
1105
+ });
1106
+ }
1107
+ }
1108
+ return drifts;
1109
+ }
1110
+ /**
1111
+ * Check for unused tokens
1112
+ * Design tokens that are defined but never referenced
1113
+ */
1114
+ checkUnusedTokens(tokens, usageMap) {
1115
+ const drifts = [];
1116
+ for (const token of tokens) {
1117
+ const usageCount = usageMap.get(token.id) || usageMap.get(token.name) || 0;
1118
+ if (usageCount === 0) {
1119
+ drifts.push({
1120
+ id: createDriftId("unused-token", token.id),
1121
+ type: "unused-token",
1122
+ severity: "info",
1123
+ source: this.tokenToDriftSource(token),
1124
+ message: `Token "${token.name}" is defined but never used`,
1125
+ details: {
1126
+ suggestions: [
1127
+ "Remove token if no longer needed",
1128
+ "Document token for future use",
1129
+ "Check if token is referenced by name in CSS/JS",
1130
+ ],
1131
+ },
1132
+ detectedAt: new Date(),
1133
+ });
1134
+ }
1135
+ }
1136
+ return drifts;
1137
+ }
935
1138
  /**
936
1139
  * Find token suggestions for a hardcoded color value
937
1140
  * Delegates to TokenSuggestionService