canicode 0.6.4 → 0.7.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.
@@ -41,7 +41,7 @@ var SEVERITY_LABELS = {
41
41
  suggestion: "Suggestion"
42
42
  };
43
43
 
44
- // src/contracts/rule.ts
44
+ // src/core/contracts/rule.ts
45
45
  z.object({
46
46
  id: z.string(),
47
47
  name: z.string(),
@@ -62,7 +62,7 @@ function supportsDepthWeight(category) {
62
62
  return DEPTH_WEIGHT_CATEGORIES.includes(category);
63
63
  }
64
64
 
65
- // src/rules/rule-config.ts
65
+ // src/core/rules/rule-config.ts
66
66
  var RULE_CONFIGS = {
67
67
  // ============================================
68
68
  // Layout (11 rules)
@@ -357,7 +357,7 @@ function getRuleOption(ruleId, optionKey, defaultValue) {
357
357
  return value ?? defaultValue;
358
358
  }
359
359
 
360
- // src/rules/rule-registry.ts
360
+ // src/core/rules/rule-registry.ts
361
361
  var RuleRegistry = class {
362
362
  rules = /* @__PURE__ */ new Map();
363
363
  /**
@@ -418,7 +418,7 @@ function defineRule(rule) {
418
418
  return rule;
419
419
  }
420
420
 
421
- // src/core/rule-engine.ts
421
+ // src/core/engine/rule-engine.ts
422
422
  function calculateMaxDepth(node, currentDepth = 0) {
423
423
  if (!node.children || node.children.length === 0) {
424
424
  return currentDepth;
@@ -591,7 +591,7 @@ function analyzeFile(file, options) {
591
591
  return engine.analyze(file);
592
592
  }
593
593
 
594
- // src/adapters/figma-client.ts
594
+ // src/core/adapters/figma-client.ts
595
595
  var FIGMA_API_BASE = "https://api.figma.com/v1";
596
596
  var FigmaClient = class _FigmaClient {
597
597
  token;
@@ -699,7 +699,7 @@ var FigmaClientError = class extends Error {
699
699
  }
700
700
  };
701
701
 
702
- // src/adapters/figma-transformer.ts
702
+ // src/core/adapters/figma-transformer.ts
703
703
  function transformFigmaResponse(fileKey, response) {
704
704
  return {
705
705
  fileKey,
@@ -818,7 +818,7 @@ function transformStyles(styles) {
818
818
  return result;
819
819
  }
820
820
 
821
- // src/adapters/figma-file-loader.ts
821
+ // src/core/adapters/figma-file-loader.ts
822
822
  async function loadFigmaFileFromJson(filePath) {
823
823
  const content = await readFile(filePath, "utf-8");
824
824
  const data = JSON.parse(content);
@@ -916,7 +916,7 @@ function getDeviceId() {
916
916
  return id;
917
917
  }
918
918
 
919
- // src/core/loader.ts
919
+ // src/core/engine/loader.ts
920
920
  function isFigmaUrl(input) {
921
921
  return input.includes("figma.com/");
922
922
  }
@@ -959,7 +959,7 @@ async function loadFromApi(fileKey, nodeId, token) {
959
959
  };
960
960
  }
961
961
 
962
- // src/adapters/figma-mcp-adapter.ts
962
+ // src/core/adapters/figma-mcp-adapter.ts
963
963
  var TAG_TYPE_MAP = {
964
964
  canvas: "CANVAS",
965
965
  frame: "FRAME",
@@ -1090,7 +1090,7 @@ function parseMcpMetadataXml(xml, fileKey, fileName) {
1090
1090
  };
1091
1091
  }
1092
1092
 
1093
- // src/core/design-data-parser.ts
1093
+ // src/core/engine/design-data-parser.ts
1094
1094
  function parseDesignData(data, fileKey, fileName) {
1095
1095
  const trimmed = data.trim();
1096
1096
  if (trimmed.startsWith("<")) {
@@ -1108,7 +1108,7 @@ function parseDesignData(data, fileKey, fileName) {
1108
1108
  );
1109
1109
  }
1110
1110
 
1111
- // src/core/scoring.ts
1111
+ // src/core/engine/scoring.ts
1112
1112
  var SEVERITY_DENSITY_WEIGHT = {
1113
1113
  blocking: 3,
1114
1114
  risk: 2,
@@ -1271,7 +1271,7 @@ function formatScoreSummary(report) {
1271
1271
  return lines.join("\n");
1272
1272
  }
1273
1273
 
1274
- // src/report-html/index.ts
1274
+ // src/core/ui-constants.ts
1275
1275
  var GAUGE_R = 54;
1276
1276
  var GAUGE_C = Math.round(2 * Math.PI * GAUGE_R);
1277
1277
  var CATEGORY_DESCRIPTIONS = {
@@ -1282,12 +1282,31 @@ var CATEGORY_DESCRIPTIONS = {
1282
1282
  "ai-readability": "Structure clarity for AI code generation, z-index, empty frames",
1283
1283
  "handoff-risk": "Hardcoded values, text truncation, image placeholders, dev status"
1284
1284
  };
1285
- var SEVERITY_ORDER = ["blocking", "risk", "missing-info", "suggestion"];
1285
+ var SEVERITY_ORDER = [
1286
+ "blocking",
1287
+ "risk",
1288
+ "missing-info",
1289
+ "suggestion"
1290
+ ];
1291
+
1292
+ // src/core/ui-helpers.ts
1286
1293
  function gaugeColor(pct) {
1287
1294
  if (pct >= 75) return "#22c55e";
1288
1295
  if (pct >= 50) return "#f59e0b";
1289
1296
  return "#ef4444";
1290
1297
  }
1298
+ function escapeHtml(text) {
1299
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
1300
+ }
1301
+ function severityDot(sev) {
1302
+ const map = {
1303
+ blocking: "bg-red-500",
1304
+ risk: "bg-amber-500",
1305
+ "missing-info": "bg-zinc-400",
1306
+ suggestion: "bg-green-500"
1307
+ };
1308
+ return map[sev];
1309
+ }
1291
1310
  function severityBadge(sev) {
1292
1311
  const map = {
1293
1312
  blocking: "bg-red-500/10 text-red-600 border-red-500/20",
@@ -1302,15 +1321,24 @@ function scoreBadgeStyle(pct) {
1302
1321
  if (pct >= 50) return "bg-amber-500/10 text-amber-700 border-amber-500/20";
1303
1322
  return "bg-red-500/10 text-red-700 border-red-500/20";
1304
1323
  }
1305
- function severityDot(sev) {
1306
- const map = {
1307
- blocking: "bg-red-500",
1308
- risk: "bg-amber-500",
1309
- "missing-info": "bg-zinc-400",
1310
- suggestion: "bg-green-500"
1311
- };
1312
- return map[sev];
1324
+ function renderGaugeSvg(pct, size, strokeW, grade) {
1325
+ const offset = GAUGE_C * (1 - pct / 100);
1326
+ const color = gaugeColor(pct);
1327
+ if (grade) {
1328
+ return `<svg width="${size}" height="${size}" viewBox="0 0 120 120" class="gauge-svg block">
1329
+ <circle cx="60" cy="60" r="${GAUGE_R}" fill="none" stroke-width="${strokeW}" stroke="#e4e4e7" class="stroke-border" />
1330
+ <circle cx="60" cy="60" r="${GAUGE_R}" fill="none" stroke="${color}" stroke-width="${strokeW}" stroke-linecap="round" stroke-dasharray="${GAUGE_C}" stroke-dashoffset="${offset}" transform="rotate(-90 60 60)" class="gauge-fill" />
1331
+ <text x="60" y="60" text-anchor="middle" dominant-baseline="central" fill="currentColor" font-size="48" font-weight="700" font-family="Inter,-apple-system,sans-serif" class="font-sans">${escapeHtml(grade)}</text>
1332
+ </svg>`;
1333
+ }
1334
+ return `<svg width="${size}" height="${size}" viewBox="0 0 120 120" class="gauge-svg block">
1335
+ <circle cx="60" cy="60" r="${GAUGE_R}" fill="none" stroke-width="${strokeW}" stroke="#e4e4e7" class="stroke-border" />
1336
+ <circle cx="60" cy="60" r="${GAUGE_R}" fill="none" stroke="${color}" stroke-width="${strokeW}" stroke-linecap="round" stroke-dasharray="${GAUGE_C}" stroke-dashoffset="${offset}" transform="rotate(-90 60 60)" class="gauge-fill" />
1337
+ <text x="60" y="62" text-anchor="middle" dominant-baseline="central" fill="currentColor" font-size="28" font-weight="700" font-family="Inter,-apple-system,sans-serif" class="font-sans">${pct}</text>
1338
+ </svg>`;
1313
1339
  }
1340
+
1341
+ // src/core/report-html/index.ts
1314
1342
  function generateHtmlReport(file, result, scores, options) {
1315
1343
  const screenshotMap = new Map(
1316
1344
  (options?.nodeScreenshots ?? []).map((ns) => [ns.nodeId, ns])
@@ -1467,23 +1495,6 @@ ${figmaToken ? ` <script>
1467
1495
  </body>
1468
1496
  </html>`;
1469
1497
  }
1470
- function renderGaugeSvg(pct, size, strokeW, grade) {
1471
- const offset = GAUGE_C * (1 - pct / 100);
1472
- const color = gaugeColor(pct);
1473
- if (grade) {
1474
- return `<svg width="${size}" height="${size}" viewBox="0 0 120 120" class="block">
1475
- <circle cx="60" cy="60" r="${GAUGE_R}" fill="none" stroke-width="${strokeW}" class="stroke-border" />
1476
- <circle cx="60" cy="60" r="${GAUGE_R}" fill="none" stroke="${color}" stroke-width="${strokeW}" stroke-linecap="round" stroke-dasharray="${GAUGE_C}" stroke-dashoffset="${offset}" transform="rotate(-90 60 60)" class="gauge-fill" />
1477
- <text x="60" y="60" text-anchor="middle" dominant-baseline="central" fill="currentColor" font-size="52" font-weight="700" class="font-sans">${esc(grade)}</text>
1478
- </svg>`;
1479
- }
1480
- const fontSize = 32;
1481
- return `<svg width="${size}" height="${size}" viewBox="0 0 120 120" class="block">
1482
- <circle cx="60" cy="60" r="${GAUGE_R}" fill="none" stroke-width="${strokeW}" class="stroke-border" />
1483
- <circle cx="60" cy="60" r="${GAUGE_R}" fill="none" stroke="${color}" stroke-width="${strokeW}" stroke-linecap="round" stroke-dasharray="${GAUGE_C}" stroke-dashoffset="${offset}" transform="rotate(-90 60 60)" class="gauge-fill" />
1484
- <text x="60" y="62" text-anchor="middle" dominant-baseline="central" fill="currentColor" font-size="${fontSize}" font-weight="700" class="font-sans">${pct}</text>
1485
- </svg>`;
1486
- }
1487
1498
  function renderSummaryDot(dotClass, count, label) {
1488
1499
  return `<div class="flex items-center gap-2">
1489
1500
  <span class="w-2.5 h-2.5 rounded-full ${dotClass}"></span>
@@ -1595,9 +1606,7 @@ function groupIssuesByCategory(issues) {
1595
1606
  for (const issue of issues) grouped.get(issue.rule.definition.category).push(issue);
1596
1607
  return grouped;
1597
1608
  }
1598
- function esc(text) {
1599
- return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
1600
- }
1609
+ var esc = escapeHtml;
1601
1610
  var RuleOverrideSchema = z.object({
1602
1611
  score: z.number().int().max(0).optional(),
1603
1612
  severity: SeveritySchema.optional(),
@@ -1700,7 +1709,7 @@ var CustomRuleSchema = z.object({
1700
1709
  });
1701
1710
  var CustomRulesFileSchema = z.array(CustomRuleSchema);
1702
1711
 
1703
- // src/rules/custom/custom-rule-loader.ts
1712
+ // src/core/rules/custom/custom-rule-loader.ts
1704
1713
  async function loadCustomRules(filePath) {
1705
1714
  const absPath = resolve(filePath);
1706
1715
  const raw = await readFile(absPath, "utf-8");
@@ -1778,7 +1787,7 @@ function createPatternCheck(cr) {
1778
1787
  };
1779
1788
  }
1780
1789
 
1781
- // src/monitoring/events.ts
1790
+ // src/core/monitoring/events.ts
1782
1791
  var EVENT_PREFIX = "cic_";
1783
1792
  var EVENTS = {
1784
1793
  // Analysis
@@ -1796,7 +1805,7 @@ var EVENTS = {
1796
1805
  CLI_INIT: `${EVENT_PREFIX}cli_init`
1797
1806
  };
1798
1807
 
1799
- // src/monitoring/capture.ts
1808
+ // src/core/monitoring/capture.ts
1800
1809
  var monitoringEnabled = false;
1801
1810
  var posthogApiKey;
1802
1811
  var sentryDsn;
@@ -1901,7 +1910,7 @@ function shutdownCapture() {
1901
1910
  commonProps = {};
1902
1911
  }
1903
1912
 
1904
- // src/monitoring/index.ts
1913
+ // src/core/monitoring/index.ts
1905
1914
  function initMonitoring(config2) {
1906
1915
  initCapture(config2);
1907
1916
  }
@@ -1924,17 +1933,17 @@ function shutdownMonitoring() {
1924
1933
  }
1925
1934
  }
1926
1935
 
1927
- // src/monitoring/keys.ts
1936
+ // src/core/monitoring/keys.ts
1928
1937
  var POSTHOG_API_KEY = "phc_rBFeG140KqJLpUnlpYDEFgdMM6JozZeqQsf9twXf5Dq" ;
1929
1938
  var SENTRY_DSN = "https://80a836a8300b25f17ef5bbf23afb5b3a@o4511080656207872.ingest.us.sentry.io/4511080661319680" ;
1930
1939
 
1931
- // src/rules/excluded-names.ts
1940
+ // src/core/rules/excluded-names.ts
1932
1941
  var EXCLUDED_NAME_PATTERN = /(badge|close|dismiss|overlay|float|fab|dot|indicator|corner|decoration|tag|status|notification|icon|ico|image|asset|filter|dim|dimmed|bg|background|logo|avatar|divider|separator|nav|navigation|gnb|header|footer|sidebar|toolbar|modal|dialog|popup|toast|tooltip|dropdown|menu|sticky|spinner|loader|cursor|cta|chatbot|thumb|thumbnail|tabbar|tab-bar|statusbar|status-bar)/i;
1933
1942
  function isExcludedName(name) {
1934
1943
  return EXCLUDED_NAME_PATTERN.test(name);
1935
1944
  }
1936
1945
 
1937
- // src/rules/layout/index.ts
1946
+ // src/core/rules/layout/index.ts
1938
1947
  function isContainerNode(node) {
1939
1948
  return node.type === "FRAME" || node.type === "GROUP" || node.type === "COMPONENT";
1940
1949
  }
@@ -2221,7 +2230,7 @@ defineRule({
2221
2230
  check: inconsistentSiblingLayoutDirectionCheck
2222
2231
  });
2223
2232
 
2224
- // src/rules/token/index.ts
2233
+ // src/core/rules/token/index.ts
2225
2234
  function hasStyleReference(node, styleType) {
2226
2235
  return node.styles !== void 0 && styleType in node.styles;
2227
2236
  }
@@ -2425,7 +2434,7 @@ defineRule({
2425
2434
  check: multipleFillColorsCheck
2426
2435
  });
2427
2436
 
2428
- // src/rules/component/index.ts
2437
+ // src/core/rules/component/index.ts
2429
2438
  function isComponentInstance(node) {
2430
2439
  return node.type === "INSTANCE";
2431
2440
  }
@@ -2599,7 +2608,7 @@ defineRule({
2599
2608
  check: singleUseComponentCheck
2600
2609
  });
2601
2610
 
2602
- // src/rules/naming/index.ts
2611
+ // src/core/rules/naming/index.ts
2603
2612
  var DEFAULT_NAME_PATTERNS = [
2604
2613
  /^Frame\s*\d*$/i,
2605
2614
  /^Group\s*\d*$/i,
@@ -2784,7 +2793,7 @@ defineRule({
2784
2793
  check: tooLongNameCheck
2785
2794
  });
2786
2795
 
2787
- // src/rules/ai-readability/index.ts
2796
+ // src/core/rules/ai-readability/index.ts
2788
2797
  function hasAutoLayout2(node) {
2789
2798
  return node.layoutMode !== void 0 && node.layoutMode !== "NONE";
2790
2799
  }
@@ -2961,7 +2970,7 @@ defineRule({
2961
2970
  check: emptyFrameCheck
2962
2971
  });
2963
2972
 
2964
- // src/rules/handoff-risk/index.ts
2973
+ // src/core/rules/handoff-risk/index.ts
2965
2974
  function hasAutoLayout3(node) {
2966
2975
  return node.layoutMode !== void 0 && node.layoutMode !== "NONE";
2967
2976
  }