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.
- package/README.md +49 -1
- package/dist/cli/index.js +120 -23
- package/dist/cli/index.js.map +1 -1
- package/dist/mcp/server.js +81 -6
- package/dist/mcp/server.js.map +1 -1
- package/docs/CUSTOMIZATION.md +248 -0
- package/package.json +1 -1
package/dist/mcp/server.js
CHANGED
|
@@ -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
|
-
|
|
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:
|
|
1949
|
+
check: createPatternCheck(cr)
|
|
1914
1950
|
};
|
|
1915
1951
|
}
|
|
1916
|
-
function
|
|
1917
|
-
return (node,
|
|
1952
|
+
function createPatternCheck(cr) {
|
|
1953
|
+
return (node, context) => {
|
|
1918
1954
|
if (node.type === "DOCUMENT" || node.type === "CANVAS") return null;
|
|
1919
|
-
|
|
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
|
|