inkbridge 0.1.0-beta.20 → 0.1.0-beta.21

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.
Files changed (36) hide show
  1. package/README.md +2 -1
  2. package/bin/inkbridge.mjs +64 -9
  3. package/code.js +11 -11
  4. package/package.json +8 -2
  5. package/scanner/adapter-utils-regression.ts +159 -0
  6. package/scanner/component-scanner.ts +276 -19
  7. package/scanner/font-family-extract-regression.ts +113 -0
  8. package/scanner/framework-adapter-shadcn-regression.ts +96 -1
  9. package/scanner/grid-cols-extraction-regression.ts +110 -0
  10. package/scanner/input-range-regression.ts +217 -0
  11. package/scanner/jsx-prop-unresolved-regression.ts +178 -0
  12. package/scanner/local-const-className-regression.ts +331 -0
  13. package/scanner/ring-utility-regression.ts +25 -4
  14. package/scanner/state-classification-regression.ts +38 -0
  15. package/scanner/stretch-to-parent-width-regression.ts +35 -1
  16. package/scanner/tailwind-parser.ts +38 -2
  17. package/src/components/component-gen.ts +11 -151
  18. package/src/design-system/cva-master.ts +7 -3
  19. package/src/design-system/design-system.ts +8 -0
  20. package/src/design-system/node-helpers.ts +15 -1
  21. package/src/design-system/preview-builder.ts +14 -45
  22. package/src/design-system/state-master.ts +23 -1
  23. package/src/design-system/story-builder.ts +55 -5
  24. package/src/design-system/ui-builder.ts +116 -6
  25. package/src/framework-adapters/index.ts +15 -2
  26. package/src/framework-adapters/shadcn.ts +83 -67
  27. package/src/layout/deferred-layout.ts +187 -1
  28. package/src/layout/layout-utils.ts +2 -1
  29. package/src/layout/ring-utils.ts +31 -82
  30. package/src/render-engine-version.ts +1 -1
  31. package/src/tailwind/adapter-utils.ts +137 -0
  32. package/src/tailwind/jsx-utils.ts +9 -0
  33. package/src/tailwind/node-ir.ts +172 -0
  34. package/src/tailwind/tailwind.ts +23 -16
  35. package/src/tokens/tokens.ts +11 -3
  36. package/templates/scan-components-route.ts +11 -1
package/README.md CHANGED
@@ -36,13 +36,14 @@ pnpm add -D inkbridge
36
36
  pnpm exec inkbridge setup
37
37
  ```
38
38
 
39
- `pnpm exec inkbridge setup` is the only required step after install. It prints exactly what it will change before writing anything (run with `--dry-run` to preview without applying):
39
+ `pnpm exec inkbridge setup` is the only required step after install. It prints exactly what it will change before writing anything (run with `--dry-run` to preview without applying, or `--force` to refresh route templates and `inkbridge.config.json` after a plugin update):
40
40
 
41
41
  - Creates `inkbridge.config.json` in your project root (auto-detects component paths from `.storybook/main.*`)
42
42
  - Creates the scanner API route at `src/app/api/inkbridge/scan-components/route.ts`
43
43
  - Creates the token patch API route at `src/app/api/inkbridge/patch-tokens/route.ts`
44
44
  - Adds `inkbridge:dev` and `inkbridge:scan` scripts to your `package.json`
45
45
  - Adds `headers()` to your `next.config.*` exposing CORS on `/api/inkbridge/:path*` so the Figma plugin iframe can reach those routes (scoped — your other routes are untouched)
46
+ - Appends `.inkbridge/` to your `.gitignore` so the scanner-output JSON doesn't show up in every diff
46
47
 
47
48
  Inkbridge does not modify your ESLint config or any other tooling. The recommended `react/forbid-dom-props` rule for inline styles is suggested in "Recommended lint rules" below, but never written by setup.
48
49
 
package/bin/inkbridge.mjs CHANGED
@@ -157,6 +157,14 @@ function printEnvironment(env) {
157
157
 
158
158
  async function setup() {
159
159
  const dryRun = process.argv.includes("--dry-run");
160
+ // `--force` re-creates the inkbridge-managed files (route templates,
161
+ // inkbridge.config.json) even when they already exist. Useful when a
162
+ // newer plugin version ships an updated template (e.g. the
163
+ // INKBRIDGE_LOCAL check in the scanner route) and the consumer wants
164
+ // to refresh without hand-editing. Never touches package.json or
165
+ // next.config — those are partial-edit territory and force-rewriting
166
+ // them would clobber consumer state.
167
+ const force = process.argv.includes("--force");
160
168
  const scanRouteDest = join(PROJECT_ROOT, "src/app/api/inkbridge/scan-components/route.ts");
161
169
  const scanRouteSrc = join(PACKAGE_DIR, "templates/scan-components-route.ts");
162
170
  const patchRouteDest = join(PROJECT_ROOT, "src/app/api/inkbridge/patch-tokens/route.ts");
@@ -165,7 +173,7 @@ async function setup() {
165
173
  const inkbridgeCfgPath = join(PROJECT_ROOT, "inkbridge.config.json");
166
174
 
167
175
  console.log("");
168
- console.log(` inkbridge setup${dryRun ? " — dry run (no files will be written)" : ""}`);
176
+ console.log(` inkbridge setup${dryRun ? " — dry run (no files will be written)" : ""}${force ? " — force (overwrite existing inkbridge files)" : ""}`);
169
177
  console.log("");
170
178
 
171
179
  const env = detectEnvironment(PROJECT_ROOT);
@@ -176,14 +184,24 @@ async function setup() {
176
184
  // ------------------------------------------------------------------
177
185
  const plan = [];
178
186
 
179
- if (!existsSync(inkbridgeCfgPath)) {
180
- plan.push({ kind: "create", path: "inkbridge.config.json", detail: `componentPaths: [${env.componentPaths.join(", ")}]` });
187
+ if (!existsSync(inkbridgeCfgPath) || force) {
188
+ plan.push({
189
+ kind: existsSync(inkbridgeCfgPath) ? "overwrite" : "create",
190
+ path: "inkbridge.config.json",
191
+ detail: `componentPaths: [${env.componentPaths.join(", ")}]`,
192
+ });
181
193
  }
182
- if (!existsSync(scanRouteDest)) {
183
- plan.push({ kind: "create", path: "src/app/api/inkbridge/scan-components/route.ts" });
194
+ if (!existsSync(scanRouteDest) || force) {
195
+ plan.push({
196
+ kind: existsSync(scanRouteDest) ? "overwrite" : "create",
197
+ path: "src/app/api/inkbridge/scan-components/route.ts",
198
+ });
184
199
  }
185
- if (!existsSync(patchRouteDest)) {
186
- plan.push({ kind: "create", path: "src/app/api/inkbridge/patch-tokens/route.ts" });
200
+ if (!existsSync(patchRouteDest) || force) {
201
+ plan.push({
202
+ kind: existsSync(patchRouteDest) ? "overwrite" : "create",
203
+ path: "src/app/api/inkbridge/patch-tokens/route.ts",
204
+ });
187
205
  }
188
206
 
189
207
  let pkg = null;
@@ -215,6 +233,27 @@ async function setup() {
215
233
  });
216
234
  }
217
235
 
236
+ // Make sure the scanner-output directory is gitignored. The API
237
+ // route writes `.inkbridge/component-definitions.json` on every
238
+ // plugin run; without this entry consumers see the file in their
239
+ // diff after every `pnpm inkbridge:scan`.
240
+ const gitignorePath = join(PROJECT_ROOT, ".gitignore");
241
+ const gitignoreSource = existsSync(gitignorePath)
242
+ ? readFileSync(gitignorePath, "utf8")
243
+ : "";
244
+ const gitignoreNeedsPatch = existsSync(join(PROJECT_ROOT, ".git"))
245
+ && !gitignoreSource.split("\n").some(line => {
246
+ const trimmed = line.trim();
247
+ return trimmed === ".inkbridge" || trimmed === ".inkbridge/";
248
+ });
249
+ if (gitignoreNeedsPatch) {
250
+ plan.push({
251
+ kind: "modify",
252
+ path: ".gitignore",
253
+ detail: "+ .inkbridge/ (scanner output)",
254
+ });
255
+ }
256
+
218
257
  if (plan.length === 0) {
219
258
  console.log(" Nothing to do — setup is already complete.");
220
259
  console.log("");
@@ -224,7 +263,11 @@ async function setup() {
224
263
 
225
264
  console.log(" Setup will make these changes:");
226
265
  for (const item of plan) {
227
- const prefix = item.kind === "create" ? "+ create" : "~ modify";
266
+ const prefix = item.kind === "create"
267
+ ? "+ create"
268
+ : item.kind === "overwrite"
269
+ ? "↻ overwrite"
270
+ : "~ modify";
228
271
  console.log(` ${prefix} ${item.path}${item.detail ? ` (${item.detail})` : ""}`);
229
272
  }
230
273
  console.log("");
@@ -259,8 +302,20 @@ async function setup() {
259
302
  } else if (env.nextConfig && item.path === env.nextConfig) {
260
303
  await patchNextConfig(PROJECT_ROOT);
261
304
  continue; // patchNextConfig already prints
305
+ } else if (item.path === ".gitignore") {
306
+ const existing = existsSync(gitignorePath)
307
+ ? readFileSync(gitignorePath, "utf8")
308
+ : "";
309
+ const needsLeadingNewline = existing.length > 0 && !existing.endsWith("\n");
310
+ const block = (needsLeadingNewline ? "\n" : "")
311
+ + "\n# Inkbridge scanner output (regenerated on every plugin run)\n.inkbridge/\n";
312
+ await writeFile(gitignorePath, existing + block, "utf8");
262
313
  }
263
- const prefix = item.kind === "create" ? "✓ created" : "✓ modified";
314
+ const prefix = item.kind === "create"
315
+ ? "✓ created"
316
+ : item.kind === "overwrite"
317
+ ? "✓ overwrote"
318
+ : "✓ modified";
264
319
  console.log(` ${prefix} ${item.path}`);
265
320
  }
266
321