canicode 0.8.4 → 0.8.5

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.
@@ -178,7 +178,7 @@ var RULE_CONFIGS = {
178
178
  }
179
179
  },
180
180
  // ============================================
181
- // Component (6 rules)
181
+ // Component (7 rules)
182
182
  // ============================================
183
183
  "missing-component": {
184
184
  severity: "risk",
@@ -213,6 +213,11 @@ var RULE_CONFIGS = {
213
213
  score: -1,
214
214
  enabled: true
215
215
  },
216
+ "missing-component-description": {
217
+ severity: "missing-info",
218
+ score: -2,
219
+ enabled: true
220
+ },
216
221
  // ============================================
217
222
  // Naming (5 rules)
218
223
  // ============================================
@@ -795,6 +800,20 @@ function transformNode(node) {
795
800
  }
796
801
  return base;
797
802
  }
803
+ function transformFileNodesResponse(fileKey, response) {
804
+ const entries = Object.values(response.nodes);
805
+ const first = entries[0];
806
+ if (!first) throw new Error("No nodes returned from Figma API");
807
+ return {
808
+ fileKey,
809
+ name: response.name,
810
+ lastModified: response.lastModified,
811
+ version: response.version,
812
+ document: transformNode(first.document),
813
+ components: transformComponents(first.components),
814
+ styles: transformStyles(first.styles)
815
+ };
816
+ }
798
817
  function transformComponents(components) {
799
818
  const result = {};
800
819
  for (const [id, component] of Object.entries(components)) {
@@ -952,6 +971,13 @@ async function loadFromApi(fileKey, nodeId, token) {
952
971
  );
953
972
  }
954
973
  const client = new FigmaClient({ token: figmaToken });
974
+ if (nodeId) {
975
+ const response2 = await client.getFileNodes(fileKey, [nodeId.replace(/-/g, ":")]);
976
+ return {
977
+ file: transformFileNodesResponse(fileKey, response2),
978
+ nodeId
979
+ };
980
+ }
955
981
  const response = await client.getFile(fileKey);
956
982
  return {
957
983
  file: transformFigmaResponse(fileKey, response),
@@ -1362,7 +1388,7 @@ function parseDesignData(data, fileKey, fileName) {
1362
1388
  }
1363
1389
 
1364
1390
  // package.json
1365
- var version = "0.8.4";
1391
+ var version = "0.8.5";
1366
1392
  var AnalysisNodeTypeSchema = z.enum([
1367
1393
  "DOCUMENT",
1368
1394
  "CANVAS",
@@ -2175,6 +2201,35 @@ defineRule({
2175
2201
  definition: singleUseComponentDef,
2176
2202
  check: singleUseComponentCheck
2177
2203
  });
2204
+ var seenMissingDescriptionComponentIds = /* @__PURE__ */ new Set();
2205
+ var missingComponentDescriptionDef = {
2206
+ id: "missing-component-description",
2207
+ name: "Missing Component Description",
2208
+ category: "component",
2209
+ why: "Component descriptions in Figma are the primary channel for communicating intent, usage guidelines, and prop expectations to developers. Without them, developers must reverse-engineer purpose from visual appearance alone.",
2210
+ impact: "Increases implementation ambiguity, especially for icon-only components, compound components with multiple variants, and components whose names are variant key strings that give no prose context.",
2211
+ fix: "Open the component in Figma, select it, and add a description in the right-hand panel under the component's properties. Include: what the component is, when to use it, any accessibility or interaction notes, and the owning team or design token set if applicable."
2212
+ };
2213
+ var missingComponentDescriptionCheck = (node, context) => {
2214
+ if (node.type !== "INSTANCE") return null;
2215
+ const componentId = node.componentId;
2216
+ if (!componentId) return null;
2217
+ const componentMeta = context.file.components[componentId];
2218
+ if (!componentMeta) return null;
2219
+ if (componentMeta.description.trim() !== "") return null;
2220
+ if (seenMissingDescriptionComponentIds.has(componentId)) return null;
2221
+ seenMissingDescriptionComponentIds.add(componentId);
2222
+ return {
2223
+ ruleId: missingComponentDescriptionDef.id,
2224
+ nodeId: node.id,
2225
+ nodePath: context.path.join(" > "),
2226
+ message: `Component "${componentMeta.name}" has no description. Descriptions help developers understand purpose and usage.`
2227
+ };
2228
+ };
2229
+ defineRule({
2230
+ definition: missingComponentDescriptionDef,
2231
+ check: missingComponentDescriptionCheck
2232
+ });
2178
2233
 
2179
2234
  // src/core/rules/naming/index.ts
2180
2235
  var DEFAULT_NAME_PATTERNS = [