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/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: 8
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: 8
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 (INTENTIONAL_ABSOLUTE_PATTERNS.test(node.name)) return null;
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.layoutAlign === "STRETCH") return null;
998
- const bbox = node.absoluteBoundingBox;
999
- if (!bbox) return null;
1000
- if (node.layoutAlign !== "INHERIT") return null;
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", 8);
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", 8);
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 (EXCLUDED_NAME_PATTERN.test(node.name)) return false;
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;