canicode 0.11.0 → 0.11.2

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.
@@ -671,9 +671,27 @@ function defineRule(rule) {
671
671
  ruleRegistry.register(rule);
672
672
  return rule;
673
673
  }
674
+ var AcknowledgmentIntentSchema = z.object({
675
+ field: z.string(),
676
+ value: z.unknown(),
677
+ scope: z.enum(["instance", "definition"])
678
+ });
679
+ var AcknowledgmentSceneWriteOutcomeSchema = z.object({
680
+ result: z.enum([
681
+ "succeeded",
682
+ "silent-ignored",
683
+ "api-rejected",
684
+ "user-declined-propagation",
685
+ "unknown"
686
+ ]),
687
+ reason: z.string().optional()
688
+ });
674
689
  var AcknowledgmentSchema = z.object({
675
690
  nodeId: z.string(),
676
- ruleId: z.string()
691
+ ruleId: z.string(),
692
+ intent: AcknowledgmentIntentSchema.optional(),
693
+ sceneWriteOutcome: AcknowledgmentSceneWriteOutcomeSchema.optional(),
694
+ codegenDirective: z.string().optional()
677
695
  });
678
696
  z.array(AcknowledgmentSchema);
679
697
  function normalizeNodeId(id) {
@@ -1845,7 +1863,7 @@ function computeApplyContext(violation, instanceContext) {
1845
1863
  }
1846
1864
 
1847
1865
  // package.json
1848
- var version = "0.11.0";
1866
+ var version = "0.11.2";
1849
1867
 
1850
1868
  // src/core/engine/scoring.ts
1851
1869
  function computeTotalScorePerCategory(configs) {
@@ -2215,7 +2233,13 @@ var BATCHABLE_RULE_IDS = [
2215
2233
  "no-auto-layout",
2216
2234
  "fixed-size-in-auto-layout"
2217
2235
  ];
2236
+ var OPT_IN_BATCHABLE_RULE_IDS = [
2237
+ "missing-prototype"
2238
+ ];
2218
2239
  var BATCHABLE_SET = new Set(BATCHABLE_RULE_IDS);
2240
+ var OPT_IN_BATCHABLE_SET = new Set(
2241
+ OPT_IN_BATCHABLE_RULE_IDS
2242
+ );
2219
2243
  var NO_SOURCE_SENTINEL = "_no-source";
2220
2244
  function groupAndBatchSurveyQuestions(questions) {
2221
2245
  if (questions.length === 0) {
@@ -2256,20 +2280,25 @@ function sourceComponentKey(question) {
2256
2280
  }
2257
2281
  function pushIntoBatch(group, question) {
2258
2282
  const sceneWeight = Math.max(question.replicas ?? 1, 1);
2259
- const isBatchable = BATCHABLE_SET.has(question.ruleId);
2283
+ const batchMode = resolveBatchMode(question.ruleId);
2260
2284
  const last = group.batches.at(-1);
2261
- if (last !== void 0 && last.ruleId === question.ruleId && isBatchable && last.batchable) {
2285
+ if (last !== void 0 && last.ruleId === question.ruleId && batchMode !== "none" && last.batchMode === batchMode) {
2262
2286
  last.questions.push(question);
2263
2287
  last.totalScenes += sceneWeight;
2264
2288
  return;
2265
2289
  }
2266
2290
  group.batches.push({
2267
2291
  ruleId: question.ruleId,
2268
- batchable: isBatchable,
2292
+ batchMode,
2269
2293
  questions: [question],
2270
2294
  totalScenes: sceneWeight
2271
2295
  });
2272
2296
  }
2297
+ function resolveBatchMode(ruleId) {
2298
+ if (BATCHABLE_SET.has(ruleId)) return "safe";
2299
+ if (OPT_IN_BATCHABLE_SET.has(ruleId)) return "opt-in";
2300
+ return "none";
2301
+ }
2273
2302
 
2274
2303
  // src/core/gotcha/survey-generator.ts
2275
2304
  var NODE_PATH_SEPARATOR = " > ";
@@ -2288,12 +2317,18 @@ function generateGotchaSurvey(result, scores, options = {}) {
2288
2317
  const mapped = sorted.map((issue) => mapToQuestion(issue, result.file)).filter((q) => q !== null);
2289
2318
  const questions = deduplicateBySourceComponent(mapped);
2290
2319
  const groupedQuestions = groupAndBatchSurveyQuestions(questions);
2320
+ const PROPAGATION_CANDIDATE_THRESHOLD = 3;
2321
+ const propagationCandidates = questions.filter(
2322
+ (q) => q.isInstanceChild
2323
+ ).length;
2324
+ const suggestedDefaultApply = propagationCandidates >= PROPAGATION_CANDIDATE_THRESHOLD;
2291
2325
  return {
2292
2326
  designGrade: grade,
2293
2327
  isReadyForCodeGen: isReadyForCodeGen(grade),
2294
2328
  questions,
2295
2329
  groupedQuestions,
2296
- designKey: options.designKey ?? ""
2330
+ designKey: options.designKey ?? "",
2331
+ suggestedDefaultApply
2297
2332
  };
2298
2333
  }
2299
2334
  function deduplicateSiblingIssues(issues) {
@@ -3611,7 +3646,9 @@ var EVENTS = {
3611
3646
  // cannot import `core/monitoring` directly, so the event fires through a
3612
3647
  // caller-supplied callback. Define the typed name here so a future consumer
3613
3648
  // has a single place to wire it up.
3614
- ROUNDTRIP_DEFINITION_WRITE_SKIPPED: `${EVENT_PREFIX}roundtrip_definition_write_skipped`
3649
+ ROUNDTRIP_DEFINITION_WRITE_SKIPPED: `${EVENT_PREFIX}roundtrip_definition_write_skipped`,
3650
+ /** CLI `canicode roundtrip-tally` completed successfully. */
3651
+ ROUNDTRIP_TALLY: `${EVENT_PREFIX}roundtrip_tally`
3615
3652
  };
3616
3653
 
3617
3654
  // src/core/monitoring/capture.ts
@@ -5157,7 +5194,7 @@ Provide a Figma URL or fixture path via the input parameter. Requires FIGMA_TOKE
5157
5194
  targetNodeId: z.string().optional().describe("Scope analysis to a specific node ID"),
5158
5195
  configPath: z.string().optional().describe("Path to config JSON file for rule overrides"),
5159
5196
  openReport: z.boolean().optional().describe("Open the generated HTML report in the user's browser. Defaults to false \u2014 opt in only when a visible report is the explicit user request (#365). The HTML file is always written to disk regardless."),
5160
- acknowledgments: z.array(AcknowledgmentSchema).optional().describe("(#371) Pre-resolved [{ nodeId, ruleId }] pairs harvested from canicode-authored Figma annotations (e.g. via the `readCanicodeAcknowledgments` Plugin helper inside a use_figma batch). Matching issues are flagged `acknowledged: true` and contribute half weight to the density score so re-analyze surfaces movement after a roundtrip even under ADR-012's annotate-by-default policy."),
5197
+ acknowledgments: z.array(AcknowledgmentSchema).optional().describe("(#371 / ADR-019) Pre-resolved acknowledgments from canicode-authored Figma annotations (e.g. via readCanicodeAcknowledgments in a use_figma batch). Each entry includes nodeId and ruleId; newer annotations may also carry intent, sceneWriteOutcome, and codegenDirective from a canicode-json fenced block (#444). Matching issues are flagged acknowledged and contribute half weight to the density score."),
5161
5198
  scope: z.enum(["page", "component"]).optional().describe("(#404) Override analysis scope \u2014 `page` (screen/section where container bounds are required) or `component` (standalone reusable unit where root FILL is the design contract). Defaults to auto-detection from the root node type: `COMPONENT` / `COMPONENT_SET` / `INSTANCE` roots resolve to `component`, everything else to `page`.")
5162
5199
  },
5163
5200
  {