analyzthis_design 2.0.0 → 2.0.1

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 (32) hide show
  1. package/HOW-TO-USE.md +436 -0
  2. package/README.md +20 -9
  3. package/dist/HOW-TO-USE.md +15 -3
  4. package/dist/README.md +20 -9
  5. package/dist/lib/chunk-executor.js +1 -1
  6. package/dist/lib/chunk-planner.js +1 -1
  7. package/dist/lib/chunk-run.js +1 -1
  8. package/dist/lib/evolve.js +1 -1
  9. package/dist/lib/orchestrator/run.js +1 -1
  10. package/dist/lib/reference-pack.js +1 -0
  11. package/dist/skills/design-reference/google-fonts.csv +1924 -1924
  12. package/dist/skills/design-reference/products.csv +162 -162
  13. package/dist/skills/design-reference/schema.json +159 -0
  14. package/dist/skills/design-reference/stacks/angular.csv +1 -1
  15. package/dist/skills/design-reference/stacks/astro.csv +1 -1
  16. package/dist/skills/design-reference/stacks/laravel.csv +2 -2
  17. package/dist/skills/design-reference/stacks/threejs.csv +54 -54
  18. package/dist/skills/design-reference/styles.csv +85 -85
  19. package/dist/skills/design-reference/typography.csv +75 -74
  20. package/dist/skills/design-reference/ui-reasoning.csv +1 -1
  21. package/package.json +6 -3
  22. package/scripts/validate-csvs.js +197 -0
  23. package/skills/design-reference/google-fonts.csv +1924 -1924
  24. package/skills/design-reference/products.csv +162 -162
  25. package/skills/design-reference/schema.json +159 -0
  26. package/skills/design-reference/stacks/angular.csv +1 -1
  27. package/skills/design-reference/stacks/astro.csv +1 -1
  28. package/skills/design-reference/stacks/laravel.csv +2 -2
  29. package/skills/design-reference/stacks/threejs.csv +54 -54
  30. package/skills/design-reference/styles.csv +85 -85
  31. package/skills/design-reference/typography.csv +75 -74
  32. package/skills/design-reference/ui-reasoning.csv +1 -1
@@ -0,0 +1,197 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * CSV validation script.
6
+ *
7
+ * Checks every CSV file in skills/design-reference/ against schema.json:
8
+ * 1. Row cell count matches header column count
9
+ * 2. No column has a No column missing
10
+ * 3. Cross-file joins resolve (e.g. products.csv Mapped Pattern → landing.csv Pattern Name)
11
+ * 4. Filter columns are populated (not empty for majority of rows)
12
+ *
13
+ * Usage: node scripts/validate-csvs.js
14
+ * Exit code: 0 = all pass, 1 = errors found
15
+ */
16
+
17
+ var fs = require('fs');
18
+ var path = require('path');
19
+ var retrieve = require('../lib/retrieve');
20
+
21
+ var REF_DIR = path.join(__dirname, '..', 'skills', 'design-reference');
22
+ var SCHEMA_PATH = path.join(REF_DIR, 'schema.json');
23
+
24
+ function parseCsvLine(line) {
25
+ var cells = [];
26
+ var cur = '';
27
+ var inQuotes = false;
28
+ for (var i = 0; i < line.length; i++) {
29
+ var ch = line[i];
30
+ if (inQuotes) {
31
+ if (ch === '"' && line[i + 1] === '"') { cur += '"'; i++; }
32
+ else if (ch === '"') { inQuotes = false; }
33
+ else { cur += ch; }
34
+ } else if (ch === '"') { inQuotes = true; }
35
+ else if (ch === ',') { cells.push(cur); cur = ''; }
36
+ else { cur += ch; }
37
+ }
38
+ cells.push(cur);
39
+ return cells;
40
+ }
41
+
42
+ function splitCsvRows(text) {
43
+ var rows = [];
44
+ var cur = '';
45
+ var inQuotes = false;
46
+ for (var i = 0; i < text.length; i++) {
47
+ var ch = text[i];
48
+ if (ch === '"') inQuotes = !inQuotes;
49
+ if (ch === '\n' && !inQuotes) { rows.push(cur); cur = ''; }
50
+ else if (ch !== '\r') cur += ch;
51
+ }
52
+ if (cur.trim().length) rows.push(cur);
53
+ return rows;
54
+ }
55
+
56
+ var schema = JSON.parse(fs.readFileSync(SCHEMA_PATH, 'utf8'));
57
+ var errors = [];
58
+ var warnings = [];
59
+
60
+ for (var fileKey in schema.files) {
61
+ var spec = schema.files[fileKey];
62
+ var filePath = path.join(REF_DIR, fileKey);
63
+ if (!fs.existsSync(filePath)) {
64
+ errors.push(fileKey + ': FILE MISSING');
65
+ continue;
66
+ }
67
+
68
+ var content = fs.readFileSync(filePath, 'utf8');
69
+ var rows = splitCsvRows(content);
70
+ var header = parseCsvLine(rows[0]);
71
+ var expectedHeader = spec.header;
72
+
73
+ // Check header matches schema
74
+ if (header.length !== expectedHeader.length) {
75
+ errors.push(fileKey + ': header has ' + header.length + ' columns, schema expects ' + expectedHeader.length);
76
+ } else {
77
+ for (var h = 0; h < header.length; h++) {
78
+ if (header[h].trim() !== expectedHeader[h].trim()) {
79
+ errors.push(fileKey + ': header column ' + h + ' is "' + header[h].trim() + '", schema expects "' + expectedHeader[h].trim() + '"');
80
+ }
81
+ }
82
+ }
83
+
84
+ // Check each data row has the right cell count
85
+ var badRows = 0;
86
+ for (var r = 1; r < rows.length; r++) {
87
+ if (!rows[r].trim()) continue;
88
+ var cells = parseCsvLine(rows[r]);
89
+ if (cells.length !== header.length) {
90
+ badRows++;
91
+ if (badRows <= 3) {
92
+ errors.push(fileKey + ' row ' + (r + 1) + ': ' + cells.length + ' cells (expected ' + header.length + ')');
93
+ }
94
+ }
95
+ }
96
+ if (badRows > 3) {
97
+ errors.push(fileKey + ': ... and ' + (badRows - 3) + ' more row-length mismatches');
98
+ }
99
+
100
+ // Check No column exists
101
+ if (spec.no_column && header.indexOf(spec.no_column) === -1) {
102
+ errors.push(fileKey + ': missing No column "' + spec.no_column + '"');
103
+ }
104
+
105
+ // Check filter column is populated
106
+ if (spec.filter_column) {
107
+ var filterIdx = header.indexOf(spec.filter_column);
108
+ if (filterIdx === -1) {
109
+ errors.push(fileKey + ': filter column "' + spec.filter_column + '" not found in header');
110
+ } else {
111
+ var emptyCount = 0;
112
+ var totalRows = 0;
113
+ for (var r2 = 1; r2 < rows.length; r2++) {
114
+ if (!rows[r2].trim()) continue;
115
+ totalRows++;
116
+ var cells2 = parseCsvLine(rows[r2]);
117
+ if (!cells2[filterIdx] || !cells2[filterIdx].trim()) emptyCount++;
118
+ }
119
+ if (totalRows > 0 && emptyCount / totalRows > 0.3) {
120
+ warnings.push(fileKey + ': filter column "' + spec.filter_column + '" is empty in ' + emptyCount + '/' + totalRows + ' rows (' + Math.round(emptyCount / totalRows * 100) + '%)');
121
+ }
122
+ }
123
+ }
124
+
125
+ // Check cross-file joins
126
+ if (spec.joins) {
127
+ for (var joinCol in spec.joins) {
128
+ var joinSpec = spec.joins[joinCol];
129
+ var joinIdx = header.indexOf(joinCol);
130
+ if (joinIdx === -1) continue;
131
+
132
+ var targetPath = path.join(REF_DIR, joinSpec.target_file);
133
+ if (!fs.existsSync(targetPath)) continue;
134
+ var targetContent = fs.readFileSync(targetPath, 'utf8');
135
+ var targetRows = splitCsvRows(targetContent);
136
+ var targetHeader = parseCsvLine(targetRows[0]);
137
+ var targetColIdx = targetHeader.indexOf(joinSpec.target_column);
138
+ if (targetColIdx === -1) continue;
139
+
140
+ var targetValues = {};
141
+ for (var tr = 1; tr < targetRows.length; tr++) {
142
+ if (!targetRows[tr].trim()) continue;
143
+ var targetCells = parseCsvLine(targetRows[tr]);
144
+ var val = targetCells[targetColIdx];
145
+ if (val) targetValues[val] = true;
146
+ }
147
+
148
+ var joinMisses = 0;
149
+ var joinTotal = 0;
150
+ for (var jr = 1; jr < rows.length; jr++) {
151
+ if (!rows[jr].trim()) continue;
152
+ var joinCells = parseCsvLine(rows[jr]);
153
+ var joinVal = joinCells[joinIdx];
154
+ if (!joinVal || !joinVal.trim()) continue;
155
+ joinTotal++;
156
+ if (!targetValues[joinVal]) joinMisses++;
157
+ }
158
+ if (joinTotal > 0 && joinMisses / joinTotal > 0.2) {
159
+ warnings.push(fileKey + ': join "' + joinCol + '" → ' + joinSpec.target_file + '.' + joinSpec.target_column + ': ' + joinMisses + '/' + joinTotal + ' misses (' + Math.round(joinMisses / joinTotal * 100) + '%)');
160
+ }
161
+ }
162
+ }
163
+
164
+ // Check Docs URL sparseness in stack files
165
+ if (fileKey.indexOf('stacks/') === 0) {
166
+ var docsIdx = header.indexOf('Docs URL');
167
+ if (docsIdx !== -1) {
168
+ var emptyDocs = 0;
169
+ var totalStack = 0;
170
+ for (var dr = 1; dr < rows.length; dr++) {
171
+ if (!rows[dr].trim()) continue;
172
+ totalStack++;
173
+ var docsCells = parseCsvLine(rows[dr]);
174
+ if (!docsCells[docsIdx] || !docsCells[docsIdx].trim()) emptyDocs++;
175
+ }
176
+ if (totalStack > 0 && emptyDocs / totalStack > 0.5) {
177
+ warnings.push(fileKey + ': Docs URL empty in ' + emptyDocs + '/' + totalStack + ' rows');
178
+ }
179
+ }
180
+ }
181
+ }
182
+
183
+ // Report
184
+ if (warnings.length) {
185
+ console.log('\n── Warnings ──');
186
+ warnings.forEach(function(w) { console.log(' ⚠ ' + w); });
187
+ }
188
+
189
+ if (errors.length) {
190
+ console.log('\n── Errors ──');
191
+ errors.forEach(function(e) { console.log(' ✗ ' + e); });
192
+ console.log('\n❌ ' + errors.length + ' error(s), ' + warnings.length + ' warning(s)\n');
193
+ process.exit(1);
194
+ } else {
195
+ console.log('\n✅ All ' + Object.keys(schema.files).length + ' CSV files pass validation (' + warnings.length + ' warning(s))\n');
196
+ process.exit(0);
197
+ }