canicode 0.3.2 → 0.4.0
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 +379 -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 +338 -11
- package/dist/mcp/server.js.map +1 -1
- package/docs/CUSTOMIZATION.md +32 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -125,6 +125,16 @@ declare const BaseAnalysisNodeSchema: z.ZodObject<{
|
|
|
125
125
|
AUTO: "AUTO";
|
|
126
126
|
ABSOLUTE: "ABSOLUTE";
|
|
127
127
|
}>>;
|
|
128
|
+
layoutSizingHorizontal: z.ZodOptional<z.ZodEnum<{
|
|
129
|
+
FIXED: "FIXED";
|
|
130
|
+
HUG: "HUG";
|
|
131
|
+
FILL: "FILL";
|
|
132
|
+
}>>;
|
|
133
|
+
layoutSizingVertical: z.ZodOptional<z.ZodEnum<{
|
|
134
|
+
FIXED: "FIXED";
|
|
135
|
+
HUG: "HUG";
|
|
136
|
+
FILL: "FILL";
|
|
137
|
+
}>>;
|
|
128
138
|
primaryAxisAlignItems: z.ZodOptional<z.ZodString>;
|
|
129
139
|
counterAxisAlignItems: z.ZodOptional<z.ZodString>;
|
|
130
140
|
itemSpacing: z.ZodOptional<z.ZodNumber>;
|
package/dist/index.js
CHANGED
|
@@ -79,6 +79,8 @@ var BaseAnalysisNodeSchema = z.object({
|
|
|
79
79
|
layoutMode: LayoutModeSchema.optional(),
|
|
80
80
|
layoutAlign: LayoutAlignSchema.optional(),
|
|
81
81
|
layoutPositioning: LayoutPositioningSchema.optional(),
|
|
82
|
+
layoutSizingHorizontal: z.enum(["FIXED", "HUG", "FILL"]).optional(),
|
|
83
|
+
layoutSizingVertical: z.enum(["FIXED", "HUG", "FILL"]).optional(),
|
|
82
84
|
primaryAxisAlignItems: z.string().optional(),
|
|
83
85
|
counterAxisAlignItems: z.string().optional(),
|
|
84
86
|
itemSpacing: z.number().optional(),
|
|
@@ -284,7 +286,7 @@ var RULE_CONFIGS = {
|
|
|
284
286
|
score: -2,
|
|
285
287
|
enabled: true,
|
|
286
288
|
options: {
|
|
287
|
-
gridBase:
|
|
289
|
+
gridBase: 4
|
|
288
290
|
}
|
|
289
291
|
},
|
|
290
292
|
"magic-number-spacing": {
|
|
@@ -292,7 +294,7 @@ var RULE_CONFIGS = {
|
|
|
292
294
|
score: -4,
|
|
293
295
|
enabled: true,
|
|
294
296
|
options: {
|
|
295
|
-
gridBase:
|
|
297
|
+
gridBase: 4
|
|
296
298
|
}
|
|
297
299
|
},
|
|
298
300
|
"raw-shadow": {
|
|
@@ -913,6 +915,12 @@ function getSeverityLabel(severity) {
|
|
|
913
915
|
return labels[severity];
|
|
914
916
|
}
|
|
915
917
|
|
|
918
|
+
// src/rules/excluded-names.ts
|
|
919
|
+
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;
|
|
920
|
+
function isExcludedName(name) {
|
|
921
|
+
return EXCLUDED_NAME_PATTERN.test(name);
|
|
922
|
+
}
|
|
923
|
+
|
|
916
924
|
// src/rules/layout/index.ts
|
|
917
925
|
function isContainerNode(node) {
|
|
918
926
|
return node.type === "FRAME" || node.type === "GROUP" || node.type === "COMPONENT";
|
|
@@ -954,7 +962,6 @@ var absolutePositionInAutoLayoutDef = {
|
|
|
954
962
|
impact: "Element will not respond to sibling changes, may overlap unexpectedly",
|
|
955
963
|
fix: "Remove absolute positioning or use proper Auto Layout alignment"
|
|
956
964
|
};
|
|
957
|
-
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;
|
|
958
965
|
function isSmallRelativeToParent(node, parent) {
|
|
959
966
|
const nodeBB = node.absoluteBoundingBox;
|
|
960
967
|
const parentBB = parent.absoluteBoundingBox;
|
|
@@ -968,7 +975,8 @@ var absolutePositionInAutoLayoutCheck = (node, context) => {
|
|
|
968
975
|
if (!context.parent) return null;
|
|
969
976
|
if (!hasAutoLayout(context.parent)) return null;
|
|
970
977
|
if (node.layoutPositioning !== "ABSOLUTE") return null;
|
|
971
|
-
if (
|
|
978
|
+
if (node.type === "VECTOR" || node.type === "BOOLEAN_OPERATION" || node.type === "LINE" || node.type === "ELLIPSE" || node.type === "STAR" || node.type === "REGULAR_POLYGON") return null;
|
|
979
|
+
if (isExcludedName(node.name)) return null;
|
|
972
980
|
if (isSmallRelativeToParent(node, context.parent)) return null;
|
|
973
981
|
if (context.parent.type === "COMPONENT") return null;
|
|
974
982
|
return {
|
|
@@ -994,10 +1002,14 @@ var fixedWidthInResponsiveContextCheck = (node, context) => {
|
|
|
994
1002
|
if (!context.parent) return null;
|
|
995
1003
|
if (!hasAutoLayout(context.parent)) return null;
|
|
996
1004
|
if (!isContainerNode(node)) return null;
|
|
997
|
-
if (node.
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1005
|
+
if (node.layoutSizingHorizontal) {
|
|
1006
|
+
if (node.layoutSizingHorizontal !== "FIXED") return null;
|
|
1007
|
+
} else {
|
|
1008
|
+
if (node.layoutAlign === "STRETCH") return null;
|
|
1009
|
+
if (!node.absoluteBoundingBox) return null;
|
|
1010
|
+
if (node.layoutAlign !== "INHERIT") return null;
|
|
1011
|
+
}
|
|
1012
|
+
if (isExcludedName(node.name)) return null;
|
|
1001
1013
|
return {
|
|
1002
1014
|
ruleId: fixedWidthInResponsiveContextDef.id,
|
|
1003
1015
|
nodeId: node.id,
|
|
@@ -1270,7 +1282,7 @@ var inconsistentSpacingDef = {
|
|
|
1270
1282
|
fix: "Use spacing values from the design system grid (e.g., 8pt increments)"
|
|
1271
1283
|
};
|
|
1272
1284
|
var inconsistentSpacingCheck = (node, context, options) => {
|
|
1273
|
-
const gridBase = options?.["gridBase"] ?? getRuleOption("inconsistent-spacing", "gridBase",
|
|
1285
|
+
const gridBase = options?.["gridBase"] ?? getRuleOption("inconsistent-spacing", "gridBase", 4);
|
|
1274
1286
|
const paddings = [
|
|
1275
1287
|
node.paddingLeft,
|
|
1276
1288
|
node.paddingRight,
|
|
@@ -1312,7 +1324,7 @@ var magicNumberSpacingDef = {
|
|
|
1312
1324
|
fix: "Round spacing to the nearest grid value or use spacing tokens"
|
|
1313
1325
|
};
|
|
1314
1326
|
var magicNumberSpacingCheck = (node, context, options) => {
|
|
1315
|
-
const gridBase = options?.["gridBase"] ?? getRuleOption("magic-number-spacing", "gridBase",
|
|
1327
|
+
const gridBase = options?.["gridBase"] ?? getRuleOption("magic-number-spacing", "gridBase", 4);
|
|
1316
1328
|
const allSpacings = [
|
|
1317
1329
|
node.paddingLeft,
|
|
1318
1330
|
node.paddingRight,
|
|
@@ -1629,6 +1641,7 @@ var defaultNameDef = {
|
|
|
1629
1641
|
};
|
|
1630
1642
|
var defaultNameCheck = (node, context) => {
|
|
1631
1643
|
if (!node.name) return null;
|
|
1644
|
+
if (isExcludedName(node.name)) return null;
|
|
1632
1645
|
if (!isDefaultName(node.name)) return null;
|
|
1633
1646
|
return {
|
|
1634
1647
|
ruleId: defaultNameDef.id,
|
|
@@ -1651,6 +1664,7 @@ var nonSemanticNameDef = {
|
|
|
1651
1664
|
};
|
|
1652
1665
|
var nonSemanticNameCheck = (node, context) => {
|
|
1653
1666
|
if (!node.name) return null;
|
|
1667
|
+
if (isExcludedName(node.name)) return null;
|
|
1654
1668
|
if (!isNonSemanticName(node.name)) return null;
|
|
1655
1669
|
if (!node.children || node.children.length === 0) {
|
|
1656
1670
|
const shapeTypes = ["RECTANGLE", "ELLIPSE", "VECTOR", "LINE", "STAR", "REGULAR_POLYGON"];
|
|
@@ -1719,6 +1733,7 @@ var numericSuffixNameDef = {
|
|
|
1719
1733
|
};
|
|
1720
1734
|
var numericSuffixNameCheck = (node, context) => {
|
|
1721
1735
|
if (!node.name) return null;
|
|
1736
|
+
if (isExcludedName(node.name)) return null;
|
|
1722
1737
|
if (isDefaultName(node.name)) return null;
|
|
1723
1738
|
if (!hasNumericSuffix(node.name)) return null;
|
|
1724
1739
|
return {
|
|
@@ -2249,6 +2264,12 @@ function transformNode(node) {
|
|
|
2249
2264
|
if ("layoutPositioning" in node && node.layoutPositioning) {
|
|
2250
2265
|
base.layoutPositioning = node.layoutPositioning;
|
|
2251
2266
|
}
|
|
2267
|
+
if ("layoutSizingHorizontal" in node && node.layoutSizingHorizontal) {
|
|
2268
|
+
base.layoutSizingHorizontal = node.layoutSizingHorizontal;
|
|
2269
|
+
}
|
|
2270
|
+
if ("layoutSizingVertical" in node && node.layoutSizingVertical) {
|
|
2271
|
+
base.layoutSizingVertical = node.layoutSizingVertical;
|
|
2272
|
+
}
|
|
2252
2273
|
if ("primaryAxisAlignItems" in node) {
|
|
2253
2274
|
base.primaryAxisAlignItems = node.primaryAxisAlignItems;
|
|
2254
2275
|
}
|
|
@@ -3277,14 +3298,13 @@ var ELIGIBLE_NODE_TYPES = /* @__PURE__ */ new Set([
|
|
|
3277
3298
|
"COMPONENT",
|
|
3278
3299
|
"INSTANCE"
|
|
3279
3300
|
]);
|
|
3280
|
-
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;
|
|
3281
3301
|
function filterConversionCandidates(summaries, documentRoot) {
|
|
3282
3302
|
return summaries.filter((summary) => {
|
|
3283
3303
|
const node = findNode(documentRoot, summary.nodeId);
|
|
3284
3304
|
if (!node) return false;
|
|
3285
3305
|
if (EXCLUDED_NODE_TYPES.has(node.type)) return false;
|
|
3286
3306
|
if (!ELIGIBLE_NODE_TYPES.has(node.type)) return false;
|
|
3287
|
-
if (
|
|
3307
|
+
if (isExcludedName(node.name)) return false;
|
|
3288
3308
|
const bbox = node.absoluteBoundingBox;
|
|
3289
3309
|
if (bbox && (bbox.width < MIN_WIDTH || bbox.height < MIN_HEIGHT)) return false;
|
|
3290
3310
|
if (!node.children || node.children.length < 3) return false;
|