@usefidel/contracts 0.5.0 → 0.6.0

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.
@@ -76,3 +76,26 @@ export declare function buildDsConfigJson(existingRaw: Record<string, unknown> |
76
76
  * The trailing newline is intentional and asserted; the file ends with one.
77
77
  */
78
78
  export declare const WORKFLOW_YAML = "name: Design Validation\non:\n pull_request:\n types: [opened, synchronize]\n\npermissions:\n contents: read\n pull-requests: write\n id-token: write\n\njobs:\n fidel:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: usefidel/fidel-action@v1\n";
79
+ /** One frame chosen in `fidel init`'s Figma picker. */
80
+ export interface Selection {
81
+ nodeId: string;
82
+ name: string;
83
+ page: string;
84
+ width: number;
85
+ height: number;
86
+ url: string;
87
+ }
88
+ /**
89
+ * Figma branch: write `checks[]`.
90
+ *
91
+ * `viewport` is emitted ONLY when the frame is not 1440x900, and only when the
92
+ * dimensions are real positive integers — a Selection missing width/height makes
93
+ * Math.round() return NaN, which serializes to null, and
94
+ * `viewport: {width: null, height: null}` is rejected outright by the
95
+ * marketplace Action's own validator. The CLI must never write a config our own
96
+ * Action refuses to load.
97
+ *
98
+ * Already-serialized checks from an existing fidel.config.json arrive on a
99
+ * re-run carrying `figma`/`url` and no `nodeId`; they pass straight through.
100
+ */
101
+ export declare function buildConfigJson(selections: Selection[], fileKey: string): string;
@@ -111,3 +111,52 @@ jobs:
111
111
  - uses: actions/checkout@v4
112
112
  - uses: usefidel/fidel-action@v1
113
113
  `;
114
+ /** `https://www.figma.com/design/<key>/?node-id=<a-b>` — Figma wants dashes, not colons. */
115
+ function buildFigmaFrameUrl(fileKey, nodeId) {
116
+ const dashNodeId = nodeId.replace(/:/g, '-');
117
+ return `https://www.figma.com/design/${fileKey}/?node-id=${dashNodeId}`;
118
+ }
119
+ /**
120
+ * Figma branch: write `checks[]`.
121
+ *
122
+ * `viewport` is emitted ONLY when the frame is not 1440x900, and only when the
123
+ * dimensions are real positive integers — a Selection missing width/height makes
124
+ * Math.round() return NaN, which serializes to null, and
125
+ * `viewport: {width: null, height: null}` is rejected outright by the
126
+ * marketplace Action's own validator. The CLI must never write a config our own
127
+ * Action refuses to load.
128
+ *
129
+ * Already-serialized checks from an existing fidel.config.json arrive on a
130
+ * re-run carrying `figma`/`url` and no `nodeId`; they pass straight through.
131
+ */
132
+ export function buildConfigJson(selections, fileKey) {
133
+ const checks = selections.map((s) => {
134
+ // Already-serialized checks from an existing fidel.config.json come through
135
+ // here on a re-run: they carry `figma`/`url` and have NO `nodeId`. Passing
136
+ // them to buildFigmaFrameUrl() would throw on `nodeId.replace`. Pass them
137
+ // straight through — they're already in output shape.
138
+ if (s.nodeId === undefined && s.figma !== undefined) {
139
+ return s;
140
+ }
141
+ const check = {
142
+ name: s.name,
143
+ figma: buildFigmaFrameUrl(fileKey, s.nodeId),
144
+ url: s.url,
145
+ };
146
+ // A Selection missing width/height makes Math.round() return NaN, which
147
+ // serializes to `null` — and `viewport: { width: null, height: null }` is
148
+ // rejected outright by the marketplace Action's own validator
149
+ // (config.ts requirePositiveInteger → "must be a positive integer").
150
+ // Our CLI must never write a config our Action refuses to load. When the
151
+ // dimensions aren't real positive integers, omit `viewport` entirely: an
152
+ // absent viewport means the 1440x900 default, which is the right fallback.
153
+ const w = Math.round(s.width);
154
+ const h = Math.round(s.height);
155
+ const hasRealDimensions = Number.isInteger(w) && w > 0 && Number.isInteger(h) && h > 0;
156
+ if (hasRealDimensions && (w !== 1440 || h !== 900)) {
157
+ check.viewport = { width: w, height: h };
158
+ }
159
+ return check;
160
+ });
161
+ return JSON.stringify({ checks }, null, 2) + '\n';
162
+ }
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "The source of truth still lives in the monorepo at packages/contracts/."
8
8
  ],
9
9
  "name": "@usefidel/contracts",
10
- "version": "0.5.0",
10
+ "version": "0.6.0",
11
11
  "description": "Shared, code-free contracts between Fidel surfaces. Run-error taxonomy, theme-intake wire types, and the canonical fidel.config.json builders.",
12
12
  "license": "UNLICENSED",
13
13
  "private": false,