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 +1 -1
- package/dist/cli/index.js +32 -14
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.js +32 -12
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.js +30 -11
- package/dist/mcp/server.js.map +1 -1
- package/docs/CUSTOMIZATION.md +1 -1
- package/package.json +1 -1
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:
|
|
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:
|
|
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:
|
|
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 (
|
|
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
|
|
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 (
|
|
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.
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
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",
|
|
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",
|
|
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 {
|