canicode 0.4.1 → 0.5.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.
@@ -1870,15 +1870,50 @@ function mergeConfigs(base, overrides) {
1870
1870
  }
1871
1871
  return merged;
1872
1872
  }
1873
+ var MatchConditionSchema = z.object({
1874
+ // Node type conditions
1875
+ type: z.array(z.string()).optional(),
1876
+ notType: z.array(z.string()).optional(),
1877
+ // Name conditions (case-insensitive, substring match)
1878
+ nameContains: z.string().optional(),
1879
+ nameNotContains: z.string().optional(),
1880
+ namePattern: z.string().optional(),
1881
+ // Size conditions
1882
+ minWidth: z.number().optional(),
1883
+ maxWidth: z.number().optional(),
1884
+ minHeight: z.number().optional(),
1885
+ maxHeight: z.number().optional(),
1886
+ // Layout conditions
1887
+ hasAutoLayout: z.boolean().optional(),
1888
+ hasChildren: z.boolean().optional(),
1889
+ minChildren: z.number().optional(),
1890
+ maxChildren: z.number().optional(),
1891
+ // Component conditions
1892
+ isComponent: z.boolean().optional(),
1893
+ isInstance: z.boolean().optional(),
1894
+ hasComponentId: z.boolean().optional(),
1895
+ // Visibility
1896
+ isVisible: z.boolean().optional(),
1897
+ // Fill/style conditions
1898
+ hasFills: z.boolean().optional(),
1899
+ hasStrokes: z.boolean().optional(),
1900
+ hasEffects: z.boolean().optional(),
1901
+ // Depth condition
1902
+ minDepth: z.number().optional(),
1903
+ maxDepth: z.number().optional()
1904
+ });
1873
1905
  var CustomRuleSchema = z.object({
1874
1906
  id: z.string(),
1875
1907
  category: CategorySchema,
1876
1908
  severity: SeveritySchema,
1877
1909
  score: z.number().int().max(0),
1878
- prompt: z.string(),
1910
+ match: MatchConditionSchema,
1911
+ message: z.string().optional(),
1879
1912
  why: z.string(),
1880
1913
  impact: z.string(),
1881
- fix: z.string()
1914
+ fix: z.string(),
1915
+ // Backward compat: silently ignore the old prompt field
1916
+ prompt: z.string().optional()
1882
1917
  });
1883
1918
  var CustomRulesFileSchema = z.array(CustomRuleSchema);
1884
1919
 
@@ -1891,6 +1926,7 @@ async function loadCustomRules(filePath) {
1891
1926
  const rules = [];
1892
1927
  const configs = {};
1893
1928
  for (const cr of customRules) {
1929
+ if (!cr.match) continue;
1894
1930
  rules.push(toRule(cr));
1895
1931
  configs[cr.id] = {
1896
1932
  severity: cr.severity,
@@ -1910,13 +1946,52 @@ function toRule(cr) {
1910
1946
  impact: cr.impact,
1911
1947
  fix: cr.fix
1912
1948
  },
1913
- check: createPromptBasedCheck()
1949
+ check: createPatternCheck(cr)
1914
1950
  };
1915
1951
  }
1916
- function createPromptBasedCheck(_cr) {
1917
- return (node, _context) => {
1952
+ function createPatternCheck(cr) {
1953
+ return (node, context) => {
1918
1954
  if (node.type === "DOCUMENT" || node.type === "CANVAS") return null;
1919
- return null;
1955
+ const match = cr.match;
1956
+ if (match.type && !match.type.includes(node.type)) return null;
1957
+ if (match.notType && match.notType.includes(node.type)) return null;
1958
+ if (match.nameContains !== void 0 && !node.name.toLowerCase().includes(match.nameContains.toLowerCase())) return null;
1959
+ if (match.nameNotContains !== void 0 && node.name.toLowerCase().includes(match.nameNotContains.toLowerCase())) return null;
1960
+ if (match.namePattern !== void 0 && !new RegExp(match.namePattern, "i").test(node.name)) return null;
1961
+ const bbox = node.absoluteBoundingBox;
1962
+ if (match.minWidth !== void 0 && (!bbox || bbox.width < match.minWidth)) return null;
1963
+ if (match.maxWidth !== void 0 && (!bbox || bbox.width > match.maxWidth)) return null;
1964
+ if (match.minHeight !== void 0 && (!bbox || bbox.height < match.minHeight)) return null;
1965
+ if (match.maxHeight !== void 0 && (!bbox || bbox.height > match.maxHeight)) return null;
1966
+ if (match.hasAutoLayout === true && !node.layoutMode) return null;
1967
+ if (match.hasAutoLayout === false && node.layoutMode) return null;
1968
+ if (match.hasChildren === true && (!node.children || node.children.length === 0)) return null;
1969
+ if (match.hasChildren === false && node.children && node.children.length > 0) return null;
1970
+ if (match.minChildren !== void 0 && (!node.children || node.children.length < match.minChildren)) return null;
1971
+ if (match.maxChildren !== void 0 && node.children && node.children.length > match.maxChildren) return null;
1972
+ if (match.isComponent === true && node.type !== "COMPONENT" && node.type !== "COMPONENT_SET") return null;
1973
+ if (match.isComponent === false && (node.type === "COMPONENT" || node.type === "COMPONENT_SET")) return null;
1974
+ if (match.isInstance === true && node.type !== "INSTANCE") return null;
1975
+ if (match.isInstance === false && node.type === "INSTANCE") return null;
1976
+ if (match.hasComponentId === true && !node.componentId) return null;
1977
+ if (match.hasComponentId === false && node.componentId) return null;
1978
+ if (match.isVisible === true && !node.visible) return null;
1979
+ if (match.isVisible === false && node.visible) return null;
1980
+ if (match.hasFills === true && (!node.fills || node.fills.length === 0)) return null;
1981
+ if (match.hasFills === false && node.fills && node.fills.length > 0) return null;
1982
+ if (match.hasStrokes === true && (!node.strokes || node.strokes.length === 0)) return null;
1983
+ if (match.hasStrokes === false && node.strokes && node.strokes.length > 0) return null;
1984
+ if (match.hasEffects === true && (!node.effects || node.effects.length === 0)) return null;
1985
+ if (match.hasEffects === false && node.effects && node.effects.length > 0) return null;
1986
+ if (match.minDepth !== void 0 && context.depth < match.minDepth) return null;
1987
+ if (match.maxDepth !== void 0 && context.depth > match.maxDepth) return null;
1988
+ const msg = (cr.message ?? `"${node.name}" matched custom rule "${cr.id}"`).replace(/\{name\}/g, node.name).replace(/\{type\}/g, node.type);
1989
+ return {
1990
+ ruleId: cr.id,
1991
+ nodeId: node.id,
1992
+ nodePath: context.path.join(" > "),
1993
+ message: msg
1994
+ };
1920
1995
  };
1921
1996
  }
1922
1997