canicode 0.3.2 → 0.3.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.
package/README.md CHANGED
@@ -194,7 +194,7 @@ canicode analyze <url> --config ./my-config.json
194
194
 
195
195
  | Option | Description |
196
196
  |--------|-------------|
197
- | `gridBase` | Spacing grid unit (default: 8) |
197
+ | `gridBase` | Spacing grid unit (default: 4) |
198
198
  | `colorTolerance` | Color difference tolerance (default: 10) |
199
199
  | `excludeNodeTypes` | Node types to skip |
200
200
  | `excludeNodeNames` | Node name patterns to skip |
package/dist/cli/index.js CHANGED
@@ -185,7 +185,7 @@ var RULE_CONFIGS = {
185
185
  score: -2,
186
186
  enabled: true,
187
187
  options: {
188
- gridBase: 8
188
+ gridBase: 4
189
189
  }
190
190
  },
191
191
  "magic-number-spacing": {
@@ -193,7 +193,7 @@ var RULE_CONFIGS = {
193
193
  score: -4,
194
194
  enabled: true,
195
195
  options: {
196
- gridBase: 8
196
+ gridBase: 4
197
197
  }
198
198
  },
199
199
  "raw-shadow": {
@@ -764,6 +764,12 @@ function transformNode(node) {
764
764
  if ("layoutPositioning" in node && node.layoutPositioning) {
765
765
  base.layoutPositioning = node.layoutPositioning;
766
766
  }
767
+ if ("layoutSizingHorizontal" in node && node.layoutSizingHorizontal) {
768
+ base.layoutSizingHorizontal = node.layoutSizingHorizontal;
769
+ }
770
+ if ("layoutSizingVertical" in node && node.layoutSizingVertical) {
771
+ base.layoutSizingVertical = node.layoutSizingVertical;
772
+ }
767
773
  if ("primaryAxisAlignItems" in node) {
768
774
  base.primaryAxisAlignItems = node.primaryAxisAlignItems;
769
775
  }
@@ -1552,7 +1558,7 @@ ${figmaToken ? ` <script>
1552
1558
  const res = await fetch('https://api.figma.com/v1/files/' + fileKey + '/comments', {
1553
1559
  method: 'POST',
1554
1560
  headers: { 'X-FIGMA-TOKEN': FIGMA_TOKEN, 'Content-Type': 'application/json' },
1555
- body: JSON.stringify({ message: commentBody, client_meta: { node_id: nodeId } }),
1561
+ body: JSON.stringify({ message: commentBody, client_meta: { node_id: nodeId, node_offset: { x: 0, y: 0 } } }),
1556
1562
  });
1557
1563
  if (!res.ok) throw new Error(await res.text());
1558
1564
  btn.textContent = 'Sent \\u2713';
@@ -2315,6 +2321,12 @@ var ActivityLogger = class {
2315
2321
  }
2316
2322
  };
2317
2323
 
2324
+ // src/rules/excluded-names.ts
2325
+ 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;
2326
+ function isExcludedName(name) {
2327
+ return EXCLUDED_NAME_PATTERN.test(name);
2328
+ }
2329
+
2318
2330
  // src/agents/orchestrator.ts
2319
2331
  function selectNodes(summaries, strategy, maxNodes) {
2320
2332
  if (summaries.length === 0) return [];
@@ -2370,14 +2382,13 @@ var ELIGIBLE_NODE_TYPES = /* @__PURE__ */ new Set([
2370
2382
  "COMPONENT",
2371
2383
  "INSTANCE"
2372
2384
  ]);
2373
- var EXCLUDED_NAME_PATTERN = /\b(icon|ico|badge|indicator|image|asset|chatbot|cta|gnb|navigation|nav|fab|modal|dialog|popup|overlay|toast|snackbar|tooltip|dropdown|menu|sticky|bg|background|divider|separator|logo|avatar|thumbnail|thumb|header|footer|sidebar|toolbar|tabbar|tab-bar|statusbar|status-bar|spinner|loader|cursor|dot|dim|dimmed|filter)\b/i;
2374
2385
  function filterConversionCandidates(summaries, documentRoot) {
2375
2386
  return summaries.filter((summary) => {
2376
2387
  const node = findNode(documentRoot, summary.nodeId);
2377
2388
  if (!node) return false;
2378
2389
  if (EXCLUDED_NODE_TYPES.has(node.type)) return false;
2379
2390
  if (!ELIGIBLE_NODE_TYPES.has(node.type)) return false;
2380
- if (EXCLUDED_NAME_PATTERN.test(node.name)) return false;
2391
+ if (isExcludedName(node.name)) return false;
2381
2392
  const bbox = node.absoluteBoundingBox;
2382
2393
  if (bbox && (bbox.width < MIN_WIDTH || bbox.height < MIN_HEIGHT)) return false;
2383
2394
  if (!node.children || node.children.length < 3) return false;
@@ -2762,7 +2773,7 @@ Override canicode's default rule scores, severity, and filters.
2762
2773
  STRUCTURE
2763
2774
  - excludeNodeTypes: node types to skip (e.g. VECTOR, BOOLEAN_OPERATION)
2764
2775
  - excludeNodeNames: name patterns to skip (e.g. icon, ico)
2765
- - gridBase: spacing grid unit, default 8
2776
+ - gridBase: spacing grid unit, default 4
2766
2777
  - colorTolerance: color diff tolerance, default 10
2767
2778
  - rules: per-rule overrides (score, severity, enabled)
2768
2779
 
@@ -2848,7 +2859,6 @@ var absolutePositionInAutoLayoutDef = {
2848
2859
  impact: "Element will not respond to sibling changes, may overlap unexpectedly",
2849
2860
  fix: "Remove absolute positioning or use proper Auto Layout alignment"
2850
2861
  };
2851
- var INTENTIONAL_ABSOLUTE_PATTERNS = /^(badge|close|dismiss|overlay|float|fab|dot|indicator|corner|decoration|tag|status|notification|x|icon[-_ ]?(close|dismiss|x)|btn[-_ ]?(close|dismiss))/i;
2852
2862
  function isSmallRelativeToParent(node, parent) {
2853
2863
  const nodeBB = node.absoluteBoundingBox;
2854
2864
  const parentBB = parent.absoluteBoundingBox;
@@ -2862,7 +2872,8 @@ var absolutePositionInAutoLayoutCheck = (node, context) => {
2862
2872
  if (!context.parent) return null;
2863
2873
  if (!hasAutoLayout(context.parent)) return null;
2864
2874
  if (node.layoutPositioning !== "ABSOLUTE") return null;
2865
- if (INTENTIONAL_ABSOLUTE_PATTERNS.test(node.name)) return null;
2875
+ if (node.type === "VECTOR" || node.type === "BOOLEAN_OPERATION" || node.type === "LINE" || node.type === "ELLIPSE" || node.type === "STAR" || node.type === "REGULAR_POLYGON") return null;
2876
+ if (isExcludedName(node.name)) return null;
2866
2877
  if (isSmallRelativeToParent(node, context.parent)) return null;
2867
2878
  if (context.parent.type === "COMPONENT") return null;
2868
2879
  return {
@@ -2888,10 +2899,14 @@ var fixedWidthInResponsiveContextCheck = (node, context) => {
2888
2899
  if (!context.parent) return null;
2889
2900
  if (!hasAutoLayout(context.parent)) return null;
2890
2901
  if (!isContainerNode(node)) return null;
2891
- if (node.layoutAlign === "STRETCH") return null;
2892
- const bbox = node.absoluteBoundingBox;
2893
- if (!bbox) return null;
2894
- if (node.layoutAlign !== "INHERIT") return null;
2902
+ if (node.layoutSizingHorizontal) {
2903
+ if (node.layoutSizingHorizontal !== "FIXED") return null;
2904
+ } else {
2905
+ if (node.layoutAlign === "STRETCH") return null;
2906
+ if (!node.absoluteBoundingBox) return null;
2907
+ if (node.layoutAlign !== "INHERIT") return null;
2908
+ }
2909
+ if (isExcludedName(node.name)) return null;
2895
2910
  return {
2896
2911
  ruleId: fixedWidthInResponsiveContextDef.id,
2897
2912
  nodeId: node.id,
@@ -3164,7 +3179,7 @@ var inconsistentSpacingDef = {
3164
3179
  fix: "Use spacing values from the design system grid (e.g., 8pt increments)"
3165
3180
  };
3166
3181
  var inconsistentSpacingCheck = (node, context, options) => {
3167
- const gridBase = options?.["gridBase"] ?? getRuleOption("inconsistent-spacing", "gridBase", 8);
3182
+ const gridBase = options?.["gridBase"] ?? getRuleOption("inconsistent-spacing", "gridBase", 4);
3168
3183
  const paddings = [
3169
3184
  node.paddingLeft,
3170
3185
  node.paddingRight,
@@ -3206,7 +3221,7 @@ var magicNumberSpacingDef = {
3206
3221
  fix: "Round spacing to the nearest grid value or use spacing tokens"
3207
3222
  };
3208
3223
  var magicNumberSpacingCheck = (node, context, options) => {
3209
- const gridBase = options?.["gridBase"] ?? getRuleOption("magic-number-spacing", "gridBase", 8);
3224
+ const gridBase = options?.["gridBase"] ?? getRuleOption("magic-number-spacing", "gridBase", 4);
3210
3225
  const allSpacings = [
3211
3226
  node.paddingLeft,
3212
3227
  node.paddingRight,
@@ -3523,6 +3538,7 @@ var defaultNameDef = {
3523
3538
  };
3524
3539
  var defaultNameCheck = (node, context) => {
3525
3540
  if (!node.name) return null;
3541
+ if (isExcludedName(node.name)) return null;
3526
3542
  if (!isDefaultName(node.name)) return null;
3527
3543
  return {
3528
3544
  ruleId: defaultNameDef.id,
@@ -3545,6 +3561,7 @@ var nonSemanticNameDef = {
3545
3561
  };
3546
3562
  var nonSemanticNameCheck = (node, context) => {
3547
3563
  if (!node.name) return null;
3564
+ if (isExcludedName(node.name)) return null;
3548
3565
  if (!isNonSemanticName(node.name)) return null;
3549
3566
  if (!node.children || node.children.length === 0) {
3550
3567
  const shapeTypes = ["RECTANGLE", "ELLIPSE", "VECTOR", "LINE", "STAR", "REGULAR_POLYGON"];
@@ -3613,6 +3630,7 @@ var numericSuffixNameDef = {
3613
3630
  };
3614
3631
  var numericSuffixNameCheck = (node, context) => {
3615
3632
  if (!node.name) return null;
3633
+ if (isExcludedName(node.name)) return null;
3616
3634
  if (isDefaultName(node.name)) return null;
3617
3635
  if (!hasNumericSuffix(node.name)) return null;
3618
3636
  return {