canicode 0.12.0 → 0.12.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.
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import { GetFileResponse, Node } from '@figma/rest-api-spec';
3
3
 
4
- var version = "0.12.0";
4
+ var version = "0.12.2";
5
5
 
6
6
  declare const SeveritySchema: z.ZodEnum<{
7
7
  blocking: "blocking";
@@ -377,6 +377,35 @@ type Category = z.infer<typeof CategorySchema>;
377
377
  declare const CATEGORIES: ("pixel-critical" | "responsive-critical" | "code-quality" | "token-management" | "semantic" | "interaction")[];
378
378
  declare const CATEGORY_LABELS: Record<Category, string>;
379
379
 
380
+ declare const AcknowledgmentSchema: z.ZodObject<{
381
+ nodeId: z.ZodString;
382
+ ruleId: z.ZodString;
383
+ intent: z.ZodOptional<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodDiscriminatedUnion<[z.ZodObject<{
384
+ kind: z.ZodDefault<z.ZodLiteral<"property">>;
385
+ field: z.ZodString;
386
+ value: z.ZodUnknown;
387
+ scope: z.ZodEnum<{
388
+ instance: "instance";
389
+ definition: "definition";
390
+ }>;
391
+ }, z.core.$strip>, z.ZodObject<{
392
+ kind: z.ZodLiteral<"rule-opt-out">;
393
+ ruleId: z.ZodString;
394
+ }, z.core.$strict>], "kind">>>;
395
+ sceneWriteOutcome: z.ZodOptional<z.ZodObject<{
396
+ result: z.ZodEnum<{
397
+ unknown: "unknown";
398
+ succeeded: "succeeded";
399
+ "silent-ignored": "silent-ignored";
400
+ "api-rejected": "api-rejected";
401
+ "user-declined-propagation": "user-declined-propagation";
402
+ }>;
403
+ reason: z.ZodOptional<z.ZodString>;
404
+ }, z.core.$strip>>;
405
+ codegenDirective: z.ZodOptional<z.ZodString>;
406
+ }, z.core.$strip>;
407
+ type Acknowledgment = z.infer<typeof AcknowledgmentSchema>;
408
+
380
409
  /**
381
410
  * Rule definition - static metadata (does not change)
382
411
  */
@@ -451,6 +480,20 @@ interface RuleContext {
451
480
  * sync with `AnalysisNode.type` without a translation layer.
452
481
  */
453
482
  rootNodeType: string;
483
+ /**
484
+ * ADR-022: lookup canicode-authored acknowledgments by `(nodeId, ruleId)`.
485
+ * The rule engine builds this from `RuleEngineOptions.acknowledgments` and
486
+ * exposes it to every rule so individual rules can short-circuit (suppress
487
+ * emission) when an acknowledgment carries a rule-opt-out intent. The
488
+ * existing density-half-weight semantic (#371) is unchanged — that path
489
+ * still flags `acknowledged: true` post-emit and is independent of this
490
+ * helper.
491
+ *
492
+ * Returns the matching acknowledgment, or `undefined` when there is no
493
+ * acknowledgment for the pair. Node ids are normalised by the engine, so
494
+ * callers can pass URL-style or Plugin-API-style ids interchangeably.
495
+ */
496
+ findAcknowledgment: (nodeId: string, ruleId: string) => Acknowledgment | undefined;
454
497
  }
455
498
  /**
456
499
  * Get or initialize per-analysis state for a rule.
@@ -701,6 +744,10 @@ declare const McpAnalyzeResponseSchema: z.ZodObject<{
701
744
  }, z.core.$strip>>;
702
745
  summary: z.ZodString;
703
746
  failedRules: z.ZodOptional<z.ZodArray<z.ZodString>>;
747
+ codeConnectCoverage: z.ZodOptional<z.ZodObject<{
748
+ mapped: z.ZodNumber;
749
+ total: z.ZodNumber;
750
+ }, z.core.$strip>>;
704
751
  }, z.core.$strip>;
705
752
  type McpAnalyzeResponse = z.infer<typeof McpAnalyzeResponseSchema>;
706
753
 
@@ -1123,31 +1170,6 @@ declare const GotchaSurveySchema: z.ZodObject<{
1123
1170
  }, z.core.$strip>;
1124
1171
  type GotchaSurvey = z.infer<typeof GotchaSurveySchema>;
1125
1172
 
1126
- declare const AcknowledgmentSchema: z.ZodObject<{
1127
- nodeId: z.ZodString;
1128
- ruleId: z.ZodString;
1129
- intent: z.ZodOptional<z.ZodObject<{
1130
- field: z.ZodString;
1131
- value: z.ZodUnknown;
1132
- scope: z.ZodEnum<{
1133
- instance: "instance";
1134
- definition: "definition";
1135
- }>;
1136
- }, z.core.$strip>>;
1137
- sceneWriteOutcome: z.ZodOptional<z.ZodObject<{
1138
- result: z.ZodEnum<{
1139
- unknown: "unknown";
1140
- succeeded: "succeeded";
1141
- "silent-ignored": "silent-ignored";
1142
- "api-rejected": "api-rejected";
1143
- "user-declined-propagation": "user-declined-propagation";
1144
- }>;
1145
- reason: z.ZodOptional<z.ZodString>;
1146
- }, z.core.$strip>>;
1147
- codegenDirective: z.ZodOptional<z.ZodString>;
1148
- }, z.core.$strip>;
1149
- type Acknowledgment = z.infer<typeof AcknowledgmentSchema>;
1150
-
1151
1173
  /**
1152
1174
  * Analysis issue with calculated score and metadata.
1153
1175
  *
@@ -1234,6 +1256,7 @@ declare class RuleEngine {
1234
1256
  private excludeNamePattern;
1235
1257
  private excludeNodeTypes;
1236
1258
  private acknowledgments;
1259
+ private acknowledgmentsByKey;
1237
1260
  private scopeOverride;
1238
1261
  constructor(options?: RuleEngineOptions);
1239
1262
  /**
@@ -1355,6 +1378,50 @@ declare function getCategoryLabel(category: Category): string;
1355
1378
  * Get severity label for display
1356
1379
  */
1357
1380
  declare function getSeverityLabel(severity: Severity): string;
1381
+ /**
1382
+ * Code Connect mapping coverage metric (#526 sub-task 3). Surfaces how many of
1383
+ * the file's components are already wired to a code path via a `figma.connect`
1384
+ * declaration. Optional — only computed when the consuming repo has Code
1385
+ * Connect set up (figma.config.json present).
1386
+ */
1387
+ interface CodeConnectCoverage {
1388
+ /** Number of components in this file that have a Code Connect mapping. */
1389
+ mapped: number;
1390
+ /** Total components in this file (numerator + unmapped). */
1391
+ total: number;
1392
+ }
1393
+ /**
1394
+ * Format the coverage line that ships in the analyze summary. Kept exported
1395
+ * so consumers (HTML report, MCP wrapper) render the same wording.
1396
+ */
1397
+ declare function formatCodeConnectCoverageLine(coverage: CodeConnectCoverage): string;
1398
+ /**
1399
+ * ADR-022 / #526 sub-task 2: standalone analyze hint.
1400
+ *
1401
+ * `canicode analyze` and the MCP `analyze` tool cannot read Figma annotations
1402
+ * directly — the REST `annotations` field is private beta. When the
1403
+ * `unmapped-component` rule fires AND the caller did not supply an
1404
+ * acknowledgments list, surface a one-line hint telling the user that any
1405
+ * roundtrip-recorded opt-outs are invisible to standalone analyze and that
1406
+ * `/canicode-roundtrip` will apply them.
1407
+ *
1408
+ * Returns `null` when:
1409
+ * - no `unmapped-component` issue fired (nothing to explain), or
1410
+ * - acknowledgments were supplied (roundtrip mode — opt-outs already applied
1411
+ * and any remaining issues are real). `acknowledgmentsProvided` MUST track
1412
+ * whether the caller passed an ack channel at all, NOT whether the array
1413
+ * was non-empty: a roundtrip on a clean file legitimately passes `[]` and
1414
+ * the hint would be misleading there.
1415
+ *
1416
+ * The hint is informational; it never moves the score, never bumps severity,
1417
+ * and is independent of the count of `unmapped-component` issues.
1418
+ */
1419
+ declare const ROUNDTRIP_OPT_OUT_HINT = "Some components may carry roundtrip-recorded opt-outs that this standalone analyze cannot see (Figma REST annotations field is in private beta). Run /canicode-roundtrip to apply opt-outs.";
1420
+ declare function formatRoundtripOptOutHintLine(issues: ReadonlyArray<{
1421
+ violation: {
1422
+ ruleId: string;
1423
+ };
1424
+ }>, acknowledgmentsProvided: boolean): string | null;
1358
1425
  /**
1359
1426
  * Build a JSON-serializable analysis result summary.
1360
1427
  * Shared by CLI (--json) and MCP server (analyze tool response).
@@ -1363,6 +1430,16 @@ declare function buildResultJson(fileName: string, result: AnalysisResult, score
1363
1430
  fileKey?: string;
1364
1431
  designKey?: string;
1365
1432
  codegenReadyMinGrade?: Grade;
1433
+ codeConnectCoverage?: CodeConnectCoverage;
1434
+ /**
1435
+ * ADR-022 / #526 sub-task 2: when true, the engine was called WITHOUT
1436
+ * an `acknowledgments` channel (standalone CLI / MCP `analyze`) and
1437
+ * `unmapped-component` opt-outs recorded via roundtrip cannot be seen.
1438
+ * Surfaces a `roundtripOptOutHint` field on the JSON response and
1439
+ * appends a hint line to `summary` when at least one
1440
+ * `unmapped-component` issue fired.
1441
+ */
1442
+ roundtripOptOutHintEligible?: boolean;
1366
1443
  }): Record<string, unknown>;
1367
1444
 
1368
1445
  /**
@@ -1904,6 +1981,21 @@ declare class FigmaClient {
1904
1981
  * Download an image URL and return as base64
1905
1982
  */
1906
1983
  fetchImageAsBase64(imageUrl: string): Promise<string>;
1984
+ /**
1985
+ * Get the components a file has published to a team library.
1986
+ *
1987
+ * `GET /v1/files/:file_key/components` returns only components that have
1988
+ * been pushed via the Publish Library action — local-but-unpublished
1989
+ * components are absent. This is the authoritative way to detect whether
1990
+ * a Figma component is mappable via Code Connect (#532): `add_code_connect_map`
1991
+ * requires a published component and otherwise fails with "Published
1992
+ * component not found."
1993
+ */
1994
+ getPublishedComponents(fileKey: string): Promise<Array<{
1995
+ key: string;
1996
+ node_id: string;
1997
+ name: string;
1998
+ }>>;
1907
1999
  getFileNodes(fileKey: string, nodeIds: string[]): Promise<GetFileNodesResponse>;
1908
2000
  }
1909
2001
  declare class FigmaClientError extends Error {
@@ -2394,4 +2486,4 @@ declare class ActivityLogger {
2394
2486
  getLogPath(): string;
2395
2487
  }
2396
2488
 
2397
- export { ALL_STRIP_TYPES, ActivityLogger, type AnalysisAgentInput, type AnalysisAgentOutput, type AnalysisFile, AnalysisFileSchema, type AnalysisIssue, type AnalysisNode, AnalysisNodeSchema, type AnalysisNodeType, AnalysisNodeTypeSchema, type AnalysisResult, type AnalysisScope, AnalysisScopeSchema, AnnotationPropertySchema, CATEGORIES, CATEGORY_LABELS, type CalibrationConfig, type CalibrationConfigInput, CalibrationConfigSchema, type CalibrationRun, type CalibrationStatus, CalibrationStatusSchema, type Category, CategorySchema, type CategoryScore, type CategoryScoreResult, CategoryScoreSchema, type Confidence, ConfidenceSchema, type ConversionRecord, ConversionRecordSchema, DEFAULT_CODEGEN_READY_MIN_GRADE, DEPTH_WEIGHT_CATEGORIES, DESIGN_TREE_INFO_TYPES, type DesignTreeInfoType, type DesignTreeOptions, type DesignTreeResult, type DesignTreeStripType, type Detection, DetectionSchema, type Difficulty, DifficultySchema, type EvaluationAgentInput, type EvaluationAgentOutput, FigmaClient, FigmaClientError, type FigmaClientOptions, FigmaFileLoadError, type FigmaUrlInfo, FigmaUrlInfoSchema, FigmaUrlParseError, GRADE_ORDER, type GapAnalyzerOutput, GapAnalyzerOutputSchema, type GapEntry, GapEntrySchema, type GetFileNodesResponse, type GotchaApplyResolution, type GotchaApplyStrategy, GotchaDetectionSchema, GotchaOutputChannelSchema, GotchaPersistenceIntentSchema, type GotchaSurvey, type GotchaSurveyQuestion, GotchaSurveyQuestionSchema, GotchaSurveySchema, type Grade, type GridChildAlign, GridChildAlignSchema, type GroupedSurvey, GroupedSurveySchema, type InstanceChildIdParts, type InstanceContext, InstanceContextSchema, type Issue, IssueSchema, type LayoutAlign, LayoutAlignSchema, type LayoutConstraint, LayoutConstraintSchema, type LayoutMode, LayoutModeSchema, type LayoutPositioning, LayoutPositioningSchema, type LayoutWrap, LayoutWrapSchema, type McpAnalyzeResponse, McpAnalyzeResponseSchema, type MismatchCase, MismatchCaseSchema, type MismatchType, MismatchTypeSchema, type NewRuleProposal, NewRuleProposalSchema, type NodeIssueDetail, type NodeIssueSummary, NodeIssueSummarySchema, type OutputChannel, OutputChannelSchema, type OverflowDirection, OverflowDirectionSchema, type PersistenceIntent, PersistenceIntentSchema, type Preset, RULE_ANNOTATION_PROPERTIES, RULE_CONFIGS, RULE_ID_CATEGORY, RULE_PURPOSE, type Report, type ReportMetadata, ReportMetadataSchema, ReportSchema, type Rule, type RuleApplyStrategy, RuleApplyStrategySchema, type RuleCheckFn, type RuleConfig, RuleConfigSchema, type RuleContext, type RuleDefinition, RuleDefinitionSchema, RuleEngine, type RuleEngineOptions, type RuleFailure, type RuleId, RuleImpactAssessmentSchema, type RulePurpose, RulePurposeSchema, type RuleRelatedStruggle, RuleRelatedStruggleSchema, type RuleViolation, SEVERITY_LABELS, SEVERITY_WEIGHT, type SamplingStrategy, SamplingStrategySchema, type ScoreAdjustment, ScoreAdjustmentSchema, type ScoreReport, type Severity, SeveritySchema, type StripDeltaForEval, type StripDeltaResult, StripDeltaResultSchema, StripDeltasArraySchema, StripTypeEnum, type SurveyQuestionBatch, SurveyQuestionBatchSchema, type SurveyQuestionGroup, SurveyQuestionGroupSchema, type TuningAgentInput, type TuningAgentOutput, type UncoveredStruggle, UncoveredStruggleSchema, UncoveredStrugglesInputSchema, version as VERSION, type VisualCompareCliOptions, VisualCompareCliOptionsSchema, absolutePositionInAutoLayout, analyzeFile, buildFigmaDeepLink, buildResultJson, calculateScores, collectComponentIds, collectInteractionDestinationIds, createRuleEngine, deepNesting, defineRule, detachedInstance, detectAnalysisScope, extractRuleScores, fixedSizeInAutoLayout, formatScoreSummary, generateCalibrationReport, generateDesignTree, generateDesignTreeWithStats, getAnalysisState, getAnnotationProperties, getCategoryLabel, getConfigsWithPreset, getRuleOption, getRulePurpose, getSeverityLabel, gradeToClassName, inconsistentNamingConvention, irregularSpacing, isInstanceChildNodeId, isReadyForCodeGen, loadFigmaFileFromJson, missingComponent, missingInteractionState, missingPrototype, missingSizeConstraint, noAutoLayout, nonLayoutContainer, nonSemanticName, nonStandardNaming, parseFigmaJson, parseFigmaUrl, parseInstanceChildNodeId, rawValue, resolveComponentDefinitions, resolveGotchaApplyTarget, resolveInteractionDestinations, ruleRegistry, runAnalysisAgent, runCalibrationAnalyze, runCalibrationEvaluate, runEvaluationAgent, runTuningAgent, stripDeltaToDifficulty, stripDesignTree, supportsDepthWeight, toCommentableNodeId, tokenDeltaToDifficulty, transformComponentMasterNodes, transformFigmaResponse, transformFileNodesResponse, unmappedComponent, variantStructureMismatch };
2489
+ export { ALL_STRIP_TYPES, ActivityLogger, type AnalysisAgentInput, type AnalysisAgentOutput, type AnalysisFile, AnalysisFileSchema, type AnalysisIssue, type AnalysisNode, AnalysisNodeSchema, type AnalysisNodeType, AnalysisNodeTypeSchema, type AnalysisResult, type AnalysisScope, AnalysisScopeSchema, AnnotationPropertySchema, CATEGORIES, CATEGORY_LABELS, type CalibrationConfig, type CalibrationConfigInput, CalibrationConfigSchema, type CalibrationRun, type CalibrationStatus, CalibrationStatusSchema, type Category, CategorySchema, type CategoryScore, type CategoryScoreResult, CategoryScoreSchema, type CodeConnectCoverage, type Confidence, ConfidenceSchema, type ConversionRecord, ConversionRecordSchema, DEFAULT_CODEGEN_READY_MIN_GRADE, DEPTH_WEIGHT_CATEGORIES, DESIGN_TREE_INFO_TYPES, type DesignTreeInfoType, type DesignTreeOptions, type DesignTreeResult, type DesignTreeStripType, type Detection, DetectionSchema, type Difficulty, DifficultySchema, type EvaluationAgentInput, type EvaluationAgentOutput, FigmaClient, FigmaClientError, type FigmaClientOptions, FigmaFileLoadError, type FigmaUrlInfo, FigmaUrlInfoSchema, FigmaUrlParseError, GRADE_ORDER, type GapAnalyzerOutput, GapAnalyzerOutputSchema, type GapEntry, GapEntrySchema, type GetFileNodesResponse, type GotchaApplyResolution, type GotchaApplyStrategy, GotchaDetectionSchema, GotchaOutputChannelSchema, GotchaPersistenceIntentSchema, type GotchaSurvey, type GotchaSurveyQuestion, GotchaSurveyQuestionSchema, GotchaSurveySchema, type Grade, type GridChildAlign, GridChildAlignSchema, type GroupedSurvey, GroupedSurveySchema, type InstanceChildIdParts, type InstanceContext, InstanceContextSchema, type Issue, IssueSchema, type LayoutAlign, LayoutAlignSchema, type LayoutConstraint, LayoutConstraintSchema, type LayoutMode, LayoutModeSchema, type LayoutPositioning, LayoutPositioningSchema, type LayoutWrap, LayoutWrapSchema, type McpAnalyzeResponse, McpAnalyzeResponseSchema, type MismatchCase, MismatchCaseSchema, type MismatchType, MismatchTypeSchema, type NewRuleProposal, NewRuleProposalSchema, type NodeIssueDetail, type NodeIssueSummary, NodeIssueSummarySchema, type OutputChannel, OutputChannelSchema, type OverflowDirection, OverflowDirectionSchema, type PersistenceIntent, PersistenceIntentSchema, type Preset, ROUNDTRIP_OPT_OUT_HINT, RULE_ANNOTATION_PROPERTIES, RULE_CONFIGS, RULE_ID_CATEGORY, RULE_PURPOSE, type Report, type ReportMetadata, ReportMetadataSchema, ReportSchema, type Rule, type RuleApplyStrategy, RuleApplyStrategySchema, type RuleCheckFn, type RuleConfig, RuleConfigSchema, type RuleContext, type RuleDefinition, RuleDefinitionSchema, RuleEngine, type RuleEngineOptions, type RuleFailure, type RuleId, RuleImpactAssessmentSchema, type RulePurpose, RulePurposeSchema, type RuleRelatedStruggle, RuleRelatedStruggleSchema, type RuleViolation, SEVERITY_LABELS, SEVERITY_WEIGHT, type SamplingStrategy, SamplingStrategySchema, type ScoreAdjustment, ScoreAdjustmentSchema, type ScoreReport, type Severity, SeveritySchema, type StripDeltaForEval, type StripDeltaResult, StripDeltaResultSchema, StripDeltasArraySchema, StripTypeEnum, type SurveyQuestionBatch, SurveyQuestionBatchSchema, type SurveyQuestionGroup, SurveyQuestionGroupSchema, type TuningAgentInput, type TuningAgentOutput, type UncoveredStruggle, UncoveredStruggleSchema, UncoveredStrugglesInputSchema, version as VERSION, type VisualCompareCliOptions, VisualCompareCliOptionsSchema, absolutePositionInAutoLayout, analyzeFile, buildFigmaDeepLink, buildResultJson, calculateScores, collectComponentIds, collectInteractionDestinationIds, createRuleEngine, deepNesting, defineRule, detachedInstance, detectAnalysisScope, extractRuleScores, fixedSizeInAutoLayout, formatCodeConnectCoverageLine, formatRoundtripOptOutHintLine, formatScoreSummary, generateCalibrationReport, generateDesignTree, generateDesignTreeWithStats, getAnalysisState, getAnnotationProperties, getCategoryLabel, getConfigsWithPreset, getRuleOption, getRulePurpose, getSeverityLabel, gradeToClassName, inconsistentNamingConvention, irregularSpacing, isInstanceChildNodeId, isReadyForCodeGen, loadFigmaFileFromJson, missingComponent, missingInteractionState, missingPrototype, missingSizeConstraint, noAutoLayout, nonLayoutContainer, nonSemanticName, nonStandardNaming, parseFigmaJson, parseFigmaUrl, parseInstanceChildNodeId, rawValue, resolveComponentDefinitions, resolveGotchaApplyTarget, resolveInteractionDestinations, ruleRegistry, runAnalysisAgent, runCalibrationAnalyze, runCalibrationEvaluate, runEvaluationAgent, runTuningAgent, stripDeltaToDifficulty, stripDesignTree, supportsDepthWeight, toCommentableNodeId, tokenDeltaToDifficulty, transformComponentMasterNodes, transformFigmaResponse, transformFileNodesResponse, unmappedComponent, variantStructureMismatch };
package/dist/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import { z } from 'zod';
2
- import { existsSync, readFileSync, mkdirSync, writeFileSync, statSync } from 'fs';
3
- import { resolve, join, basename, dirname } from 'path';
2
+ import { existsSync, readFileSync, mkdirSync, writeFileSync, statSync, readdirSync } from 'fs';
3
+ import { resolve, join, basename, dirname, isAbsolute, sep } from 'path';
4
4
  import { readFile, writeFile, appendFile } from 'fs/promises';
5
5
  import 'crypto';
6
6
  import { homedir } from 'os';
7
7
 
8
8
  // package.json
9
- var version = "0.12.0";
9
+ var version = "0.12.2";
10
10
  var SeveritySchema = z.enum([
11
11
  "blocking",
12
12
  "risk",
@@ -359,7 +359,14 @@ var McpAnalyzeResponseSchema = z.object({
359
359
  issuesByRule: z.record(z.string(), z.number().int().min(0)),
360
360
  issues: z.array(McpIssueSchema),
361
361
  summary: z.string(),
362
- failedRules: z.array(z.string()).optional()
362
+ failedRules: z.array(z.string()).optional(),
363
+ /**
364
+ * #526 sub-task 3 — Code Connect mapping coverage. Optional: only emitted
365
+ * when the consuming repo has `figma.config.json`. Numerator = components in
366
+ * this file with a discovered `figma.connect` declaration; denominator =
367
+ * total components in the file.
368
+ */
369
+ codeConnectCoverage: z.object({ mapped: z.number().int().min(0), total: z.number().int().min(0) }).optional()
363
370
  });
364
371
  var GradeSchema2 = z.enum(["S", "A+", "A", "B+", "B", "C+", "C", "D", "F"]);
365
372
  var InstanceContextSchema = z.object({
@@ -836,11 +843,31 @@ function defineRule(rule) {
836
843
  ruleRegistry.register(rule);
837
844
  return rule;
838
845
  }
839
- var AcknowledgmentIntentSchema = z.object({
846
+ var PropertyAcknowledgmentIntentSchema = z.object({
847
+ kind: z.literal("property").default("property"),
840
848
  field: z.string(),
841
849
  value: z.unknown(),
842
850
  scope: z.enum(["instance", "definition"])
843
851
  });
852
+ var RuleOptOutAcknowledgmentIntentSchema = z.object({
853
+ kind: z.literal("rule-opt-out"),
854
+ ruleId: z.string()
855
+ }).strict();
856
+ var AcknowledgmentIntentSchema = z.preprocess((raw) => {
857
+ if (raw && typeof raw === "object" && !Array.isArray(raw)) {
858
+ const obj = raw;
859
+ if (obj["kind"] === void 0) {
860
+ return { ...obj, kind: "property" };
861
+ }
862
+ }
863
+ return raw;
864
+ }, z.discriminatedUnion("kind", [
865
+ PropertyAcknowledgmentIntentSchema,
866
+ RuleOptOutAcknowledgmentIntentSchema
867
+ ]));
868
+ function isRuleOptOutIntent(intent) {
869
+ return intent !== void 0 && intent.kind === "rule-opt-out";
870
+ }
844
871
  var AcknowledgmentSceneWriteOutcomeSchema = z.object({
845
872
  result: z.enum([
846
873
  "succeeded",
@@ -913,6 +940,7 @@ var RuleEngine = class {
913
940
  excludeNamePattern;
914
941
  excludeNodeTypes;
915
942
  acknowledgments;
943
+ acknowledgmentsByKey;
916
944
  scopeOverride;
917
945
  constructor(options = {}) {
918
946
  this.configs = options.configs ?? RULE_CONFIGS;
@@ -921,10 +949,15 @@ var RuleEngine = class {
921
949
  this.targetNodeId = options.targetNodeId;
922
950
  this.excludeNamePattern = options.excludeNodeNames && options.excludeNodeNames.length > 0 ? new RegExp(`\\b(${options.excludeNodeNames.join("|")})\\b`, "i") : null;
923
951
  this.excludeNodeTypes = options.excludeNodeTypes && options.excludeNodeTypes.length > 0 ? new Set(options.excludeNodeTypes) : null;
952
+ const ackList = options.acknowledgments ?? [];
924
953
  this.acknowledgments = new Set(
925
- (options.acknowledgments ?? []).map(
926
- (a) => `${normalizeNodeId(a.nodeId)}::${a.ruleId}`
927
- )
954
+ ackList.map((a) => `${normalizeNodeId(a.nodeId)}::${a.ruleId}`)
955
+ );
956
+ this.acknowledgmentsByKey = new Map(
957
+ ackList.map((a) => [
958
+ `${normalizeNodeId(a.nodeId)}::${a.ruleId}`,
959
+ a
960
+ ])
928
961
  );
929
962
  this.scopeOverride = options.scope;
930
963
  }
@@ -1008,6 +1041,7 @@ var RuleEngine = class {
1008
1041
  if (this.excludeNamePattern && this.excludeNamePattern.test(node.name)) {
1009
1042
  return;
1010
1043
  }
1044
+ const acknowledgmentsByKey = this.acknowledgmentsByKey;
1011
1045
  const context = {
1012
1046
  file,
1013
1047
  parent,
@@ -1019,7 +1053,8 @@ var RuleEngine = class {
1019
1053
  siblings,
1020
1054
  analysisState,
1021
1055
  scope,
1022
- rootNodeType
1056
+ rootNodeType,
1057
+ findAcknowledgment: (nodeId, ruleId) => acknowledgmentsByKey.get(`${normalizeNodeId(nodeId)}::${ruleId}`)
1023
1058
  };
1024
1059
  for (const rule of rules) {
1025
1060
  const ruleId = rule.definition.id;
@@ -1378,6 +1413,20 @@ function getSeverityLabel(severity) {
1378
1413
  };
1379
1414
  return labels[severity];
1380
1415
  }
1416
+ function formatCodeConnectCoverageLine(coverage) {
1417
+ const { mapped, total } = coverage;
1418
+ const pct = total === 0 ? 0 : Math.round(mapped / total * 100);
1419
+ return `Code Connect coverage: ${mapped}/${total} components (${pct}%) mapped`;
1420
+ }
1421
+ var ROUNDTRIP_OPT_OUT_HINT = "Some components may carry roundtrip-recorded opt-outs that this standalone analyze cannot see (Figma REST annotations field is in private beta). Run /canicode-roundtrip to apply opt-outs.";
1422
+ function formatRoundtripOptOutHintLine(issues, acknowledgmentsProvided) {
1423
+ if (acknowledgmentsProvided) return null;
1424
+ const hasUnmapped = issues.some(
1425
+ (issue) => issue.violation.ruleId === "unmapped-component"
1426
+ );
1427
+ if (!hasUnmapped) return null;
1428
+ return ROUNDTRIP_OPT_OUT_HINT;
1429
+ }
1381
1430
  function buildResultJson(fileName, result, scores, options) {
1382
1431
  const issuesByRule = {};
1383
1432
  for (const issue of result.issues) {
@@ -1407,6 +1456,14 @@ function buildResultJson(fileName, result, scores, options) {
1407
1456
  ...issue.acknowledged === true ? { acknowledged: true } : {}
1408
1457
  };
1409
1458
  });
1459
+ const optOutHint = options?.roundtripOptOutHintEligible ? formatRoundtripOptOutHintLine(result.issues, false) : null;
1460
+ const summaryParts = [formatScoreSummary(scores)];
1461
+ if (options?.codeConnectCoverage) {
1462
+ summaryParts.push(formatCodeConnectCoverageLine(options.codeConnectCoverage));
1463
+ }
1464
+ if (optOutHint) {
1465
+ summaryParts.push(optOutHint);
1466
+ }
1410
1467
  const json = {
1411
1468
  version,
1412
1469
  analyzedAt: result.analyzedAt,
@@ -1426,8 +1483,14 @@ function buildResultJson(fileName, result, scores, options) {
1426
1483
  },
1427
1484
  issuesByRule,
1428
1485
  issues,
1429
- summary: formatScoreSummary(scores)
1486
+ summary: summaryParts.join("\n\n")
1430
1487
  };
1488
+ if (options?.codeConnectCoverage) {
1489
+ json["codeConnectCoverage"] = options.codeConnectCoverage;
1490
+ }
1491
+ if (optOutHint) {
1492
+ json["roundtripOptOutHint"] = optOutHint;
1493
+ }
1431
1494
  if (result.failedRules.length > 0) {
1432
1495
  json["failedRules"] = result.failedRules;
1433
1496
  }
@@ -3046,6 +3109,130 @@ var irregularSpacing = defineRule({
3046
3109
  definition: irregularSpacingDef,
3047
3110
  check: irregularSpacingCheck
3048
3111
  });
3112
+ var FIGMA_CONFIG_FILENAME = "figma.config.json";
3113
+ var FIGMA_CONNECT_FILE_GLOB = /\.figma\.(tsx?|jsx?)$/;
3114
+ var NODE_ID_QUERY_RE = /[?&]node-id=([0-9A-Za-z%:\-_]+)/;
3115
+ function parseCodeConnectMappings(cwd) {
3116
+ const configPath = join(cwd, FIGMA_CONFIG_FILENAME);
3117
+ if (!existsSync(configPath)) {
3118
+ return {
3119
+ mappedNodeIds: /* @__PURE__ */ new Set(),
3120
+ scannedFiles: [],
3121
+ skipReason: "no-config",
3122
+ skippedReason: `${FIGMA_CONFIG_FILENAME} not found at ${cwd}`
3123
+ };
3124
+ }
3125
+ let config;
3126
+ try {
3127
+ config = JSON.parse(readFileSync(configPath, "utf-8"));
3128
+ } catch (err) {
3129
+ return {
3130
+ mappedNodeIds: /* @__PURE__ */ new Set(),
3131
+ scannedFiles: [],
3132
+ skipReason: "malformed-config",
3133
+ skippedReason: `malformed ${FIGMA_CONFIG_FILENAME}: ${err.message}`
3134
+ };
3135
+ }
3136
+ const includes = config.codeConnect?.include ?? config.include ?? [];
3137
+ if (includes.length === 0) {
3138
+ return {
3139
+ mappedNodeIds: /* @__PURE__ */ new Set(),
3140
+ scannedFiles: [],
3141
+ skipReason: "no-includes",
3142
+ skippedReason: `${FIGMA_CONFIG_FILENAME} has no codeConnect.include paths`
3143
+ };
3144
+ }
3145
+ const candidateFiles = /* @__PURE__ */ new Set();
3146
+ for (const includePattern of includes) {
3147
+ for (const file of resolveInclude(cwd, includePattern)) {
3148
+ candidateFiles.add(file);
3149
+ }
3150
+ }
3151
+ const mappedNodeIds = /* @__PURE__ */ new Set();
3152
+ const scannedFiles = [];
3153
+ for (const file of candidateFiles) {
3154
+ scannedFiles.push(file);
3155
+ let contents;
3156
+ try {
3157
+ contents = readFileSync(file, "utf-8");
3158
+ } catch {
3159
+ continue;
3160
+ }
3161
+ for (const nodeId of extractNodeIdsFromSource(contents)) {
3162
+ mappedNodeIds.add(nodeId);
3163
+ }
3164
+ }
3165
+ return { mappedNodeIds, scannedFiles };
3166
+ }
3167
+ function resolveInclude(cwd, includePattern) {
3168
+ const results = [];
3169
+ const absolute = isAbsolute(includePattern) ? includePattern : resolve(cwd, includePattern);
3170
+ const segments = absolute.split(sep);
3171
+ let firstGlobIdx = segments.findIndex((s) => /[*?{[]/.test(s));
3172
+ if (firstGlobIdx === -1) {
3173
+ if (existsSync(absolute)) {
3174
+ const stat = statSync(absolute);
3175
+ if (stat.isFile() && FIGMA_CONNECT_FILE_GLOB.test(absolute)) {
3176
+ results.push(absolute);
3177
+ } else if (stat.isDirectory()) {
3178
+ walkDir(absolute, results);
3179
+ }
3180
+ }
3181
+ return results;
3182
+ }
3183
+ const rootSegments = segments.slice(0, firstGlobIdx);
3184
+ const root = rootSegments.length === 0 ? sep : rootSegments.join(sep);
3185
+ if (!existsSync(root)) return results;
3186
+ const rootStat = statSync(root);
3187
+ if (!rootStat.isDirectory()) return results;
3188
+ walkDir(root, results);
3189
+ const prefix = rootSegments.join(sep) + sep;
3190
+ return results.filter((f) => f.startsWith(prefix) || rootSegments.length === 0);
3191
+ }
3192
+ function walkDir(dir, out) {
3193
+ let entries;
3194
+ try {
3195
+ entries = readdirSync(dir);
3196
+ } catch {
3197
+ return;
3198
+ }
3199
+ for (const entry of entries) {
3200
+ if (entry === "node_modules" || entry.startsWith(".")) continue;
3201
+ const full = join(dir, entry);
3202
+ let stat;
3203
+ try {
3204
+ stat = statSync(full);
3205
+ } catch {
3206
+ continue;
3207
+ }
3208
+ if (stat.isDirectory()) {
3209
+ walkDir(full, out);
3210
+ } else if (stat.isFile() && FIGMA_CONNECT_FILE_GLOB.test(full)) {
3211
+ out.push(full);
3212
+ }
3213
+ }
3214
+ }
3215
+ function extractNodeIdsFromSource(source) {
3216
+ const nodeIds = /* @__PURE__ */ new Set();
3217
+ const re = new RegExp(NODE_ID_QUERY_RE, "g");
3218
+ let match;
3219
+ while ((match = re.exec(source)) !== null) {
3220
+ const raw = match[1];
3221
+ if (!raw) continue;
3222
+ const decoded = safeDecode(raw);
3223
+ nodeIds.add(decoded.replace(/-/g, ":"));
3224
+ }
3225
+ return nodeIds;
3226
+ }
3227
+ function safeDecode(raw) {
3228
+ try {
3229
+ return decodeURIComponent(raw);
3230
+ } catch {
3231
+ return raw;
3232
+ }
3233
+ }
3234
+
3235
+ // src/core/rules/component/index.ts
3049
3236
  var STYLE_COMPARE_KEYS = ["fills", "strokes", "effects", "cornerRadius", "strokeWeight", "individualStrokeWeights"];
3050
3237
  function detectStyleOverrides(master, instance) {
3051
3238
  const overrides = [];
@@ -3254,11 +3441,23 @@ var variantStructureMismatch = defineRule({
3254
3441
  check: variantStructureMismatchCheck
3255
3442
  });
3256
3443
  var CODE_CONNECT_SETUP_KEY = "unmapped-component:setup-detected";
3444
+ var CODE_CONNECT_MAPPINGS_KEY = "unmapped-component:mappings";
3445
+ var SEEN_MAIN_IDS_KEY = "unmapped-component:seen-main-ids";
3257
3446
  function codeConnectIsSetUp(context) {
3258
3447
  return getAnalysisState(context, CODE_CONNECT_SETUP_KEY, () => {
3259
3448
  return existsSync(join(process.cwd(), "figma.config.json"));
3260
3449
  });
3261
3450
  }
3451
+ function codeConnectMappings(context) {
3452
+ return getAnalysisState(
3453
+ context,
3454
+ CODE_CONNECT_MAPPINGS_KEY,
3455
+ () => parseCodeConnectMappings(process.cwd())
3456
+ );
3457
+ }
3458
+ function seenMainIds(context) {
3459
+ return getAnalysisState(context, SEEN_MAIN_IDS_KEY, () => /* @__PURE__ */ new Set());
3460
+ }
3262
3461
  var unmappedComponentDef = {
3263
3462
  id: "unmapped-component",
3264
3463
  name: "Unmapped Component",
@@ -3268,14 +3467,33 @@ var unmappedComponentDef = {
3268
3467
  fix: "Run /canicode-roundtrip on this component to register a mapping. Figma's get_code_connect_map will skip if a mapping already exists."
3269
3468
  };
3270
3469
  var unmappedComponentCheck = (node, context) => {
3271
- if (node.type !== "COMPONENT" && node.type !== "COMPONENT_SET") return null;
3272
- if (isInsideInstance(context)) return null;
3273
3470
  if (!codeConnectIsSetUp(context)) return null;
3471
+ let mainId = null;
3472
+ let mainName = node.name;
3473
+ if (node.type === "COMPONENT" || node.type === "COMPONENT_SET") {
3474
+ if (isInsideInstance(context)) return null;
3475
+ mainId = node.id;
3476
+ } else if (node.type === "INSTANCE" && node.componentId) {
3477
+ mainId = node.componentId;
3478
+ const meta = context.file.components[node.componentId];
3479
+ if (meta?.name) mainName = meta.name;
3480
+ } else {
3481
+ return null;
3482
+ }
3483
+ const seen = seenMainIds(context);
3484
+ if (seen.has(mainId)) return null;
3485
+ seen.add(mainId);
3486
+ const mappings = codeConnectMappings(context);
3487
+ if (mappings.mappedNodeIds.has(mainId)) return null;
3488
+ const ack = context.findAcknowledgment(mainId, unmappedComponentDef.id);
3489
+ if (ack && isRuleOptOutIntent(ack.intent) && ack.intent.ruleId === unmappedComponentDef.id) {
3490
+ return null;
3491
+ }
3274
3492
  return {
3275
3493
  ruleId: unmappedComponentDef.id,
3276
- nodeId: node.id,
3494
+ nodeId: mainId,
3277
3495
  nodePath: context.path.join(" > "),
3278
- ...unmappedComponentMsg(node.name)
3496
+ ...unmappedComponentMsg(mainName)
3279
3497
  };
3280
3498
  };
3281
3499
  var unmappedComponent = defineRule({
@@ -3785,6 +4003,32 @@ var FigmaClient = class _FigmaClient {
3785
4003
  const buffer = await response.arrayBuffer();
3786
4004
  return Buffer.from(buffer).toString("base64");
3787
4005
  }
4006
+ /**
4007
+ * Get the components a file has published to a team library.
4008
+ *
4009
+ * `GET /v1/files/:file_key/components` returns only components that have
4010
+ * been pushed via the Publish Library action — local-but-unpublished
4011
+ * components are absent. This is the authoritative way to detect whether
4012
+ * a Figma component is mappable via Code Connect (#532): `add_code_connect_map`
4013
+ * requires a published component and otherwise fails with "Published
4014
+ * component not found."
4015
+ */
4016
+ async getPublishedComponents(fileKey) {
4017
+ const url = `${FIGMA_API_BASE}/files/${fileKey}/components`;
4018
+ const response = await fetch(url, {
4019
+ headers: { "X-Figma-Token": this.token }
4020
+ });
4021
+ if (!response.ok) {
4022
+ const error = await response.json().catch(() => ({}));
4023
+ throw new FigmaClientError(
4024
+ `Failed to fetch published components: ${response.status} ${response.statusText}`,
4025
+ response.status,
4026
+ error
4027
+ );
4028
+ }
4029
+ const data = await response.json();
4030
+ return data.meta?.components ?? [];
4031
+ }
3788
4032
  async getFileNodes(fileKey, nodeIds) {
3789
4033
  const ids = nodeIds.join(",");
3790
4034
  const url = `${FIGMA_API_BASE}/files/${fileKey}/nodes?ids=${encodeURIComponent(ids)}`;
@@ -5427,6 +5671,6 @@ var ActivityLogger = class {
5427
5671
  }
5428
5672
  };
5429
5673
 
5430
- export { ALL_STRIP_TYPES, ActivityLogger, AnalysisFileSchema, AnalysisNodeSchema, AnalysisNodeTypeSchema, AnalysisScopeSchema, AnnotationPropertySchema, CATEGORIES, CATEGORY_LABELS, CalibrationConfigSchema, CalibrationStatusSchema, CategorySchema, CategoryScoreSchema, ConfidenceSchema, ConversionRecordSchema, DEFAULT_CODEGEN_READY_MIN_GRADE, DEPTH_WEIGHT_CATEGORIES, DESIGN_TREE_INFO_TYPES, DetectionSchema, DifficultySchema, FigmaClient, FigmaClientError, FigmaFileLoadError, FigmaUrlInfoSchema, FigmaUrlParseError, GRADE_ORDER, GapAnalyzerOutputSchema, GapEntrySchema, GotchaDetectionSchema, GotchaOutputChannelSchema, GotchaPersistenceIntentSchema, GotchaSurveyQuestionSchema, GotchaSurveySchema, GridChildAlignSchema, GroupedSurveySchema, InstanceContextSchema, IssueSchema, LayoutAlignSchema, LayoutConstraintSchema, LayoutModeSchema, LayoutPositioningSchema, LayoutWrapSchema, McpAnalyzeResponseSchema, MismatchCaseSchema, MismatchTypeSchema, NewRuleProposalSchema, NodeIssueSummarySchema, OutputChannelSchema, OverflowDirectionSchema, PersistenceIntentSchema, RULE_ANNOTATION_PROPERTIES, RULE_CONFIGS, RULE_ID_CATEGORY, RULE_PURPOSE, ReportMetadataSchema, ReportSchema, RuleApplyStrategySchema, RuleConfigSchema, RuleDefinitionSchema, RuleEngine, RuleImpactAssessmentSchema, RulePurposeSchema, RuleRelatedStruggleSchema, SEVERITY_LABELS, SEVERITY_WEIGHT, SamplingStrategySchema, ScoreAdjustmentSchema, SeveritySchema, StripDeltaResultSchema, StripDeltasArraySchema, StripTypeEnum, SurveyQuestionBatchSchema, SurveyQuestionGroupSchema, UncoveredStruggleSchema, UncoveredStrugglesInputSchema, version as VERSION, VisualCompareCliOptionsSchema, absolutePositionInAutoLayout, analyzeFile, buildFigmaDeepLink, buildResultJson, calculateScores, collectComponentIds, collectInteractionDestinationIds, createRuleEngine, deepNesting, defineRule, detachedInstance, detectAnalysisScope, extractRuleScores, fixedSizeInAutoLayout, formatScoreSummary, generateCalibrationReport, generateDesignTree, generateDesignTreeWithStats, getAnalysisState, getAnnotationProperties, getCategoryLabel, getConfigsWithPreset, getRuleOption, getRulePurpose, getSeverityLabel, gradeToClassName, inconsistentNamingConvention, irregularSpacing, isInstanceChildNodeId, isReadyForCodeGen, loadFigmaFileFromJson, missingComponent, missingInteractionState, missingPrototype, missingSizeConstraint, noAutoLayout, nonLayoutContainer, nonSemanticName, nonStandardNaming, parseFigmaJson, parseFigmaUrl, parseInstanceChildNodeId, rawValue, resolveComponentDefinitions, resolveGotchaApplyTarget, resolveInteractionDestinations, ruleRegistry, runAnalysisAgent, runCalibrationAnalyze, runCalibrationEvaluate, runEvaluationAgent, runTuningAgent, stripDeltaToDifficulty, stripDesignTree, supportsDepthWeight, toCommentableNodeId, tokenDeltaToDifficulty, transformComponentMasterNodes, transformFigmaResponse, transformFileNodesResponse, unmappedComponent, variantStructureMismatch };
5674
+ export { ALL_STRIP_TYPES, ActivityLogger, AnalysisFileSchema, AnalysisNodeSchema, AnalysisNodeTypeSchema, AnalysisScopeSchema, AnnotationPropertySchema, CATEGORIES, CATEGORY_LABELS, CalibrationConfigSchema, CalibrationStatusSchema, CategorySchema, CategoryScoreSchema, ConfidenceSchema, ConversionRecordSchema, DEFAULT_CODEGEN_READY_MIN_GRADE, DEPTH_WEIGHT_CATEGORIES, DESIGN_TREE_INFO_TYPES, DetectionSchema, DifficultySchema, FigmaClient, FigmaClientError, FigmaFileLoadError, FigmaUrlInfoSchema, FigmaUrlParseError, GRADE_ORDER, GapAnalyzerOutputSchema, GapEntrySchema, GotchaDetectionSchema, GotchaOutputChannelSchema, GotchaPersistenceIntentSchema, GotchaSurveyQuestionSchema, GotchaSurveySchema, GridChildAlignSchema, GroupedSurveySchema, InstanceContextSchema, IssueSchema, LayoutAlignSchema, LayoutConstraintSchema, LayoutModeSchema, LayoutPositioningSchema, LayoutWrapSchema, McpAnalyzeResponseSchema, MismatchCaseSchema, MismatchTypeSchema, NewRuleProposalSchema, NodeIssueSummarySchema, OutputChannelSchema, OverflowDirectionSchema, PersistenceIntentSchema, ROUNDTRIP_OPT_OUT_HINT, RULE_ANNOTATION_PROPERTIES, RULE_CONFIGS, RULE_ID_CATEGORY, RULE_PURPOSE, ReportMetadataSchema, ReportSchema, RuleApplyStrategySchema, RuleConfigSchema, RuleDefinitionSchema, RuleEngine, RuleImpactAssessmentSchema, RulePurposeSchema, RuleRelatedStruggleSchema, SEVERITY_LABELS, SEVERITY_WEIGHT, SamplingStrategySchema, ScoreAdjustmentSchema, SeveritySchema, StripDeltaResultSchema, StripDeltasArraySchema, StripTypeEnum, SurveyQuestionBatchSchema, SurveyQuestionGroupSchema, UncoveredStruggleSchema, UncoveredStrugglesInputSchema, version as VERSION, VisualCompareCliOptionsSchema, absolutePositionInAutoLayout, analyzeFile, buildFigmaDeepLink, buildResultJson, calculateScores, collectComponentIds, collectInteractionDestinationIds, createRuleEngine, deepNesting, defineRule, detachedInstance, detectAnalysisScope, extractRuleScores, fixedSizeInAutoLayout, formatCodeConnectCoverageLine, formatRoundtripOptOutHintLine, formatScoreSummary, generateCalibrationReport, generateDesignTree, generateDesignTreeWithStats, getAnalysisState, getAnnotationProperties, getCategoryLabel, getConfigsWithPreset, getRuleOption, getRulePurpose, getSeverityLabel, gradeToClassName, inconsistentNamingConvention, irregularSpacing, isInstanceChildNodeId, isReadyForCodeGen, loadFigmaFileFromJson, missingComponent, missingInteractionState, missingPrototype, missingSizeConstraint, noAutoLayout, nonLayoutContainer, nonSemanticName, nonStandardNaming, parseFigmaJson, parseFigmaUrl, parseInstanceChildNodeId, rawValue, resolveComponentDefinitions, resolveGotchaApplyTarget, resolveInteractionDestinations, ruleRegistry, runAnalysisAgent, runCalibrationAnalyze, runCalibrationEvaluate, runEvaluationAgent, runTuningAgent, stripDeltaToDifficulty, stripDesignTree, supportsDepthWeight, toCommentableNodeId, tokenDeltaToDifficulty, transformComponentMasterNodes, transformFigmaResponse, transformFileNodesResponse, unmappedComponent, variantStructureMismatch };
5431
5675
  //# sourceMappingURL=index.js.map
5432
5676
  //# sourceMappingURL=index.js.map