inkbridge 0.1.0-beta.21 → 0.1.0-beta.23

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 (69) hide show
  1. package/README.md +29 -0
  2. package/code.js +15 -15
  3. package/manifest.json +1 -2
  4. package/package.json +40 -22
  5. package/scanner/border-dash-pattern-regression.ts +163 -0
  6. package/scanner/child-sizing-matrix-regression.ts +9 -0
  7. package/scanner/cli.ts +21 -5
  8. package/scanner/component-scanner.ts +1333 -77
  9. package/scanner/conditional-map-branch-regression.ts +180 -0
  10. package/scanner/css-token-reader.ts +66 -5
  11. package/scanner/dialog-content-gate-regression.ts +195 -0
  12. package/scanner/expression-evaluator-regression.ts +432 -0
  13. package/scanner/framework-adapter-shadcn-regression.ts +157 -1
  14. package/scanner/hidden-check-drift-regression.ts +125 -0
  15. package/scanner/horizontal-text-shrink-regression.ts +230 -0
  16. package/scanner/imported-array-map-regression.ts +195 -0
  17. package/scanner/inline-flex-regression.ts +5 -0
  18. package/scanner/intrinsic-sizing-regression.ts +333 -0
  19. package/scanner/portal-class-strip-regression.ts +109 -0
  20. package/scanner/responsive-hidden-inline-regression.ts +226 -0
  21. package/scanner/responsive-opt-in-regression.ts +212 -0
  22. package/scanner/select-root-flatten-regression.ts +314 -0
  23. package/scanner/space-between-single-child-regression.ts +163 -0
  24. package/scanner/story-args-resolution-regression.ts +311 -0
  25. package/scanner/story-dimensioning-regression.ts +76 -1
  26. package/scanner/style-map.ts +57 -0
  27. package/scanner/table-column-alignment-regression.ts +355 -0
  28. package/scanner/ternary-fragment-branch-regression.ts +196 -0
  29. package/scanner/text-truncate-regression.ts +481 -0
  30. package/scanner/types.ts +13 -0
  31. package/src/components/component-gen.ts +21 -38
  32. package/src/design-system/cva-master.ts +11 -18
  33. package/src/design-system/design-system.ts +36 -7
  34. package/src/design-system/frame-stabilizers.ts +109 -12
  35. package/src/design-system/preview-builder.ts +38 -0
  36. package/src/design-system/selectable-state.ts +8 -1
  37. package/src/design-system/story-builder.ts +62 -32
  38. package/src/design-system/story-dimensioning.ts +14 -3
  39. package/src/design-system/tag-predicates.ts +8 -0
  40. package/src/design-system/typography.ts +26 -0
  41. package/src/design-system/ui-builder.ts +188 -60
  42. package/src/effects/icon-builder.ts +8 -0
  43. package/src/framework-adapters/shadcn.ts +113 -0
  44. package/src/github/github.ts +22 -4
  45. package/src/layout/index.ts +4 -0
  46. package/src/layout/intrinsic-applier.ts +105 -0
  47. package/src/layout/intrinsic-sizing.ts +183 -0
  48. package/src/layout/layout-parser.ts +36 -0
  49. package/src/layout/parser/layout-mode.ts +14 -4
  50. package/src/layout/table-layout.ts +271 -0
  51. package/src/layout/text-truncate-pass.ts +151 -0
  52. package/src/layout/width-solver.ts +63 -17
  53. package/src/main.ts +37 -124
  54. package/src/plugin/config.ts +21 -0
  55. package/src/plugin/packs/pack-provider.ts +20 -4
  56. package/src/plugin/packs/packs.ts +14 -0
  57. package/src/render-engine-version.ts +1 -1
  58. package/src/tailwind/jsx-utils.ts +39 -0
  59. package/src/tailwind/node-ir.ts +8 -1
  60. package/src/tailwind/responsive-analyzer.ts +57 -3
  61. package/src/tailwind/tailwind.ts +344 -51
  62. package/src/text/index.ts +1 -0
  63. package/src/text/inline-text.ts +112 -12
  64. package/src/text/text-builder.ts +2 -2
  65. package/src/text/text-truncate.ts +101 -0
  66. package/src/tokens/tokens.ts +107 -16
  67. package/src/tokens/variables.ts +203 -46
  68. package/templates/scan-components-route.ts +8 -0
  69. package/ui.html +144 -43
package/manifest.json CHANGED
@@ -25,7 +25,6 @@
25
25
  { "name": "Settings", "command": "settings" },
26
26
  { "separator": true },
27
27
  { "name": "Generate Design System Page", "command": "generate" },
28
- { "name": "Clean Generated Artifacts", "command": "clean-generated" },
29
- { "name": "Debug Selection (Console)", "command": "debug-selection" }
28
+ { "name": "Clean Generated Artifacts", "command": "clean-generated" }
30
29
  ]
31
30
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inkbridge",
3
- "version": "0.1.0-beta.21",
3
+ "version": "0.1.0-beta.23",
4
4
  "description": "Generate a Figma design system from your Storybook stories — Tailwind React components rendered as native frames, design tokens, component states, and round-trip code sync.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -19,25 +19,6 @@
19
19
  "publishConfig": {
20
20
  "access": "public"
21
21
  },
22
- "keywords": [
23
- "figma",
24
- "plugin",
25
- "tailwind",
26
- "design-tokens",
27
- "storybook"
28
- ],
29
- "license": "MIT",
30
- "homepage": "https://inkbridge.ink",
31
- "peerDependencies": {
32
- "react": ">=18",
33
- "react-dom": ">=18",
34
- "tailwindcss": ">=4",
35
- "postcss": ">=8"
36
- },
37
- "dependencies": {
38
- "tailwind-merge": "^3.4.0",
39
- "ts-morph": "^27.0.0"
40
- },
41
22
  "scripts": {
42
23
  "build": "node build.mjs",
43
24
  "watch": "node build.mjs --watch",
@@ -95,8 +76,45 @@
95
76
  "test:input-range": "cd ../.. && ./node_modules/.bin/tsx tools/figma-plugin/scanner/input-range-regression.ts",
96
77
  "test:font-family-extract": "cd ../.. && ./node_modules/.bin/tsx tools/figma-plugin/scanner/font-family-extract-regression.ts",
97
78
  "test:local-const-className": "cd ../.. && ./node_modules/.bin/tsx tools/figma-plugin/scanner/local-const-className-regression.ts",
79
+ "test:imported-array-map": "cd ../.. && ./node_modules/.bin/tsx tools/figma-plugin/scanner/imported-array-map-regression.ts",
80
+ "test:story-args-resolution": "cd ../.. && ./node_modules/.bin/tsx tools/figma-plugin/scanner/story-args-resolution-regression.ts",
81
+ "test:intrinsic-sizing": "cd ../.. && ./node_modules/.bin/tsx tools/figma-plugin/scanner/intrinsic-sizing-regression.ts",
82
+ "test:responsive-opt-in": "cd ../.. && ./node_modules/.bin/tsx tools/figma-plugin/scanner/responsive-opt-in-regression.ts",
83
+ "test:conditional-map-branch": "cd ../.. && ./node_modules/.bin/tsx tools/figma-plugin/scanner/conditional-map-branch-regression.ts",
84
+ "test:table-column-alignment": "cd ../.. && ./node_modules/.bin/tsx tools/figma-plugin/scanner/table-column-alignment-regression.ts",
85
+ "test:responsive-hidden-inline": "cd ../.. && ./node_modules/.bin/tsx tools/figma-plugin/scanner/responsive-hidden-inline-regression.ts",
86
+ "test:text-truncate": "cd ../.. && ./node_modules/.bin/tsx tools/figma-plugin/scanner/text-truncate-regression.ts",
87
+ "test:space-between-single-child": "cd ../.. && ./node_modules/.bin/tsx tools/figma-plugin/scanner/space-between-single-child-regression.ts",
88
+ "test:hidden-check-drift": "cd ../.. && ./node_modules/.bin/tsx tools/figma-plugin/scanner/hidden-check-drift-regression.ts",
89
+ "test:expression-evaluator": "cd ../.. && ./node_modules/.bin/tsx tools/figma-plugin/scanner/expression-evaluator-regression.ts",
90
+ "test:portal-class-strip": "cd ../.. && ./node_modules/.bin/tsx tools/figma-plugin/scanner/portal-class-strip-regression.ts",
91
+ "test:select-root-flatten": "cd ../.. && ./node_modules/.bin/tsx tools/figma-plugin/scanner/select-root-flatten-regression.ts",
92
+ "test:horizontal-text-shrink": "cd ../.. && ./node_modules/.bin/tsx tools/figma-plugin/scanner/horizontal-text-shrink-regression.ts",
93
+ "test:dialog-content-gate": "cd ../.. && ./node_modules/.bin/tsx tools/figma-plugin/scanner/dialog-content-gate-regression.ts",
94
+ "test:ternary-fragment-branch": "cd ../.. && ./node_modules/.bin/tsx tools/figma-plugin/scanner/ternary-fragment-branch-regression.ts",
95
+ "test:border-dash-pattern": "cd ../.. && ./node_modules/.bin/tsx tools/figma-plugin/scanner/border-dash-pattern-regression.ts",
98
96
  "docs:audit": "node ./scripts/docs-audit.mjs",
99
- "verify": "pnpm run scan && pnpm run test:blob && pnpm run test:tokens && pnpm run test:font && pnpm run test:radial && pnpm run test:transform && pnpm run test:csspatch && pnpm run test:state-classification && pnpm run test:component-sections && pnpm run test:block-cache && pnpm run test:story-dimensioning && pnpm run test:story-render-strategy && pnpm run test:render-prop-parser && pnpm run test:story-diagnostics && pnpm run test:instance-rendering && pnpm run test:layout-spacing && pnpm run test:layout-sizing && pnpm run test:layout-alignment && pnpm run test:layout-flex && pnpm run test:layout-mode && pnpm run test:svg-marker && pnpm run test:aspect-ratio && pnpm run test:percent-position && pnpm run test:svg-fill-parent && pnpm run test:inline-flex && pnpm run test:child-sizing-matrix && pnpm run test:full-width-matrix && pnpm run test:text-resize-matrix && pnpm run test:provider-flatten && pnpm run test:provider-cascade && pnpm run test:selection-pressed && pnpm run test:cva-jsx-child-fallback && pnpm run test:cva-master-icon && pnpm run test:data-attr-prop-alias && pnpm run test:jsx-prop-unresolved && pnpm run test:grid-cols-extraction && pnpm run test:explicit-size-root && pnpm run test:image-src-collector && pnpm run test:size-full-normalization && pnpm run test:stretch-to-parent-width && pnpm run test:framework-adapter-shadcn && pnpm run test:compound-classes-lookup && pnpm run test:sandbox-spread && pnpm run test:jsx-text && pnpm run test:aspect-percent && pnpm run test:svg-group-inherit && pnpm run test:svg-marker-inline && pnpm run test:ring-utility && pnpm run test:adapter-utils && pnpm run test:input-range && pnpm run test:font-family-extract && pnpm run test:local-const-className && pnpm run docs:audit && pnpm run build && pnpm run test:bundle-size",
97
+ "verify": "pnpm run scan && pnpm run test:blob && pnpm run test:tokens && pnpm run test:font && pnpm run test:radial && pnpm run test:transform && pnpm run test:csspatch && pnpm run test:state-classification && pnpm run test:component-sections && pnpm run test:block-cache && pnpm run test:story-dimensioning && pnpm run test:story-render-strategy && pnpm run test:render-prop-parser && pnpm run test:story-diagnostics && pnpm run test:instance-rendering && pnpm run test:layout-spacing && pnpm run test:layout-sizing && pnpm run test:layout-alignment && pnpm run test:layout-flex && pnpm run test:layout-mode && pnpm run test:svg-marker && pnpm run test:aspect-ratio && pnpm run test:percent-position && pnpm run test:svg-fill-parent && pnpm run test:inline-flex && pnpm run test:child-sizing-matrix && pnpm run test:full-width-matrix && pnpm run test:text-resize-matrix && pnpm run test:provider-flatten && pnpm run test:provider-cascade && pnpm run test:selection-pressed && pnpm run test:cva-jsx-child-fallback && pnpm run test:cva-master-icon && pnpm run test:data-attr-prop-alias && pnpm run test:jsx-prop-unresolved && pnpm run test:grid-cols-extraction && pnpm run test:explicit-size-root && pnpm run test:image-src-collector && pnpm run test:size-full-normalization && pnpm run test:stretch-to-parent-width && pnpm run test:framework-adapter-shadcn && pnpm run test:compound-classes-lookup && pnpm run test:sandbox-spread && pnpm run test:jsx-text && pnpm run test:aspect-percent && pnpm run test:svg-group-inherit && pnpm run test:svg-marker-inline && pnpm run test:ring-utility && pnpm run test:adapter-utils && pnpm run test:input-range && pnpm run test:font-family-extract && pnpm run test:local-const-className && pnpm run test:imported-array-map && pnpm run test:story-args-resolution && pnpm run test:intrinsic-sizing && pnpm run test:responsive-opt-in && pnpm run test:conditional-map-branch && pnpm run test:table-column-alignment && pnpm run test:responsive-hidden-inline && pnpm run test:text-truncate && pnpm run test:space-between-single-child && pnpm run test:hidden-check-drift && pnpm run test:expression-evaluator && pnpm run test:portal-class-strip && pnpm run test:select-root-flatten && pnpm run test:horizontal-text-shrink && pnpm run test:dialog-content-gate && pnpm run test:ternary-fragment-branch && pnpm run test:border-dash-pattern && pnpm run docs:audit && pnpm run build && pnpm run test:bundle-size",
98
+ "prepublishOnly": "node build.mjs",
100
99
  "release:beta": "pnpm publish --tag beta && npm dist-tag add inkbridge@$npm_package_version latest && npm view inkbridge dist-tags"
100
+ },
101
+ "keywords": [
102
+ "figma",
103
+ "plugin",
104
+ "tailwind",
105
+ "design-tokens",
106
+ "storybook"
107
+ ],
108
+ "license": "MIT",
109
+ "homepage": "https://inkbridge.ink",
110
+ "peerDependencies": {
111
+ "react": ">=18",
112
+ "react-dom": ">=18",
113
+ "tailwindcss": ">=4",
114
+ "postcss": ">=8"
115
+ },
116
+ "dependencies": {
117
+ "tailwind-merge": "^3.4.0",
118
+ "ts-morph": "^27.0.0"
101
119
  }
102
- }
120
+ }
@@ -0,0 +1,163 @@
1
+ import assert from 'node:assert/strict';
2
+
3
+ (globalThis as unknown as { figma: unknown }).figma = {
4
+ notify: () => undefined,
5
+ showUI: () => undefined,
6
+ variables: {
7
+ getLocalVariableCollections: () => [],
8
+ getLocalVariables: () => [],
9
+ },
10
+ };
11
+
12
+ /**
13
+ * Regression: Tailwind's `border-dashed` / `border-dotted` / `border-solid`
14
+ * must map to Figma's `dashPattern` array. The plugin previously had no
15
+ * handling for these style modifiers — every border rendered solid even
16
+ * when the consumer asked for dashed.
17
+ *
18
+ * Real-world trigger: greenhouse-app `IncreasePositionModal`'s Position
19
+ * impact card uses
20
+ * `<div className="my-1 h-px border-t border-dashed
21
+ * border-muted-foreground/30" />`
22
+ * as the visual separator between the side badge and the metrics grid.
23
+ * Without dashPattern the line rendered solid, breaking the visual
24
+ * hierarchy users see in the browser.
25
+ *
26
+ * Dash patterns picked to match typical browser-default dashed / dotted
27
+ * (Chrome / Safari): dashed = [4, 4], dotted = [1, 2]. solid /
28
+ * border-none = [] (default; reset to solid).
29
+ */
30
+
31
+ import { applyTailwindStylesToFrame } from '../src/tailwind';
32
+
33
+ interface StubFrame {
34
+ type: 'FRAME';
35
+ width: number;
36
+ height: number;
37
+ fills: unknown[];
38
+ strokes: unknown[];
39
+ strokeWeight: number;
40
+ strokeTopWeight?: number;
41
+ strokeRightWeight?: number;
42
+ strokeBottomWeight?: number;
43
+ strokeLeftWeight?: number;
44
+ dashPattern?: number[];
45
+ layoutMode?: string;
46
+ primaryAxisSizingMode?: string;
47
+ counterAxisSizingMode?: string;
48
+ paddingLeft?: number;
49
+ paddingRight?: number;
50
+ paddingTop?: number;
51
+ paddingBottom?: number;
52
+ cornerRadius?: number;
53
+ topLeftRadius?: number;
54
+ topRightRadius?: number;
55
+ bottomLeftRadius?: number;
56
+ bottomRightRadius?: number;
57
+ itemSpacing?: number;
58
+ resize?: (w: number, h: number) => void;
59
+ children?: unknown[];
60
+ }
61
+
62
+ function frame(): StubFrame {
63
+ return {
64
+ type: 'FRAME',
65
+ width: 100,
66
+ height: 1,
67
+ fills: [],
68
+ strokes: [],
69
+ strokeWeight: 0,
70
+ dashPattern: [],
71
+ children: [],
72
+ resize() {},
73
+ };
74
+ }
75
+
76
+ const colorGroup: Record<string, string> = {
77
+ 'muted-foreground': '#888888',
78
+ 'primary': '#16a34a',
79
+ };
80
+
81
+ const apply = (cls: string[], f: StubFrame): void => {
82
+ applyTailwindStylesToFrame(
83
+ f as unknown as FrameNode,
84
+ cls,
85
+ colorGroup,
86
+ null,
87
+ 'primary',
88
+ );
89
+ };
90
+
91
+ // ---------------------------------------------------------------------------
92
+ // Case 1: border-dashed + border-t + border color → dashPattern [4, 4]
93
+ // ---------------------------------------------------------------------------
94
+
95
+ {
96
+ const f = frame();
97
+ apply(['h-px', 'border-t', 'border-dashed', 'border-muted-foreground/30'], f);
98
+ assert.deepEqual(
99
+ f.dashPattern,
100
+ [4, 4],
101
+ 'border-dashed sets dashPattern to [4, 4] — the Position impact separator',
102
+ );
103
+ }
104
+
105
+ // ---------------------------------------------------------------------------
106
+ // Case 2: border-dotted → dashPattern [1, 2]
107
+ // ---------------------------------------------------------------------------
108
+
109
+ {
110
+ const f = frame();
111
+ apply(['border', 'border-dotted', 'border-primary'], f);
112
+ assert.deepEqual(
113
+ f.dashPattern,
114
+ [1, 2],
115
+ 'border-dotted sets a tighter dash pattern that reads as dots',
116
+ );
117
+ }
118
+
119
+ // ---------------------------------------------------------------------------
120
+ // Case 3: border-solid resets to []
121
+ // ---------------------------------------------------------------------------
122
+
123
+ {
124
+ const f = frame();
125
+ f.dashPattern = [4, 4];
126
+ apply(['border', 'border-solid', 'border-primary'], f);
127
+ assert.deepEqual(
128
+ f.dashPattern,
129
+ [],
130
+ 'border-solid resets dashPattern to [] — covers consumers that explicitly opt out',
131
+ );
132
+ }
133
+
134
+ // ---------------------------------------------------------------------------
135
+ // Case 4: no border-style class → dashPattern untouched
136
+ // ---------------------------------------------------------------------------
137
+
138
+ {
139
+ const f = frame();
140
+ f.dashPattern = [4, 4]; // pretend a previous pass set it
141
+ apply(['border', 'border-primary'], f);
142
+ assert.deepEqual(
143
+ f.dashPattern,
144
+ [4, 4],
145
+ 'absent border-style class leaves dashPattern alone — don\'t clobber prior intent',
146
+ );
147
+ }
148
+
149
+ // ---------------------------------------------------------------------------
150
+ // Case 5: last-wins between conflicting style classes
151
+ // ---------------------------------------------------------------------------
152
+
153
+ {
154
+ const f = frame();
155
+ apply(['border', 'border-dashed', 'border-solid', 'border-primary'], f);
156
+ assert.deepEqual(
157
+ f.dashPattern,
158
+ [],
159
+ 'when both dashed and solid appear, the last in the class list wins (CSS cascade semantics)',
160
+ );
161
+ }
162
+
163
+ console.log('border-dash-pattern-regression: PASS');
@@ -110,16 +110,25 @@ type ParentKind =
110
110
 
111
111
  function makeParent(kind: ParentKind): FrameNode {
112
112
  const parent = makeStubFrame();
113
+ // FIXED-width parents represent the production "Card / section with a
114
+ // known story width" case. Implicit stretch in applyChildProperties
115
+ // now requires `parent.counterAxisSizingMode === 'FIXED'` so the
116
+ // child's "fill the parent's width" intent is only honoured when the
117
+ // parent's width is actually definite — without this guard a HUG
118
+ // parent collapses to its first non-stretch child's width, and any
119
+ // STRETCH siblings get visually clipped.
113
120
  if (kind === 'horizontal-row') {
114
121
  parent.layoutMode = 'HORIZONTAL';
115
122
  parent.width = 600;
116
123
  parent.primaryAxisSizingMode = 'FIXED';
124
+ parent.counterAxisSizingMode = 'FIXED';
117
125
  setFrameCrossAlign(parent as unknown as FrameNode, 'MIN');
118
126
  setFrameFromBlockFlow(parent as unknown as FrameNode, false);
119
127
  } else {
120
128
  parent.layoutMode = 'VERTICAL';
121
129
  parent.width = 600;
122
130
  parent.primaryAxisSizingMode = 'FIXED';
131
+ parent.counterAxisSizingMode = 'FIXED';
123
132
  if (kind === 'flex-col-stretch') {
124
133
  setFrameCrossAlign(parent as unknown as FrameNode, 'STRETCH');
125
134
  setFrameFromBlockFlow(parent as unknown as FrameNode, false);
package/scanner/cli.ts CHANGED
@@ -21,7 +21,7 @@ import { ComponentScanner } from './component-scanner';
21
21
  import { extractColorTokens, extractPaletteTokens, TAILWIND_SPACING, inferLayout, groupClassesByBreakpoint, groupClassesByColorScheme } from './tailwind-parser';
22
22
  import { collectAllClasses } from './class-collector';
23
23
  import { buildStyleMap } from './style-map';
24
- import { readTokenSourceMap } from './css-token-reader';
24
+ import { readTokenSourceMap, readConsumerOwnedTokenMap } from './css-token-reader';
25
25
  import type { ComponentDefinitions, ScannerConfig, ResponsiveInfo, IconImportSpec, IconRegistryEntry, ComponentAnalysis, JsxNode, AtomicKind } from './types';
26
26
  import type { TokenSourceMode } from '../src/tokens/token-source';
27
27
  import { inferSafeTextOverridePropKeys } from '../src/components/symbol-instance-policy';
@@ -129,15 +129,31 @@ async function main() {
129
129
  styleMap,
130
130
  };
131
131
 
132
- // Optionally include token map when called with --include-tokens
133
- const finalOutput: typeof output & { tokens?: ReturnType<typeof readTokenSourceMap> } = output;
132
+ // Optionally include token map when called with --include-tokens.
133
+ //
134
+ // `tokens` = full scan, including Tailwind / tw-animate-css defaults
135
+ // pulled in via `@import "tailwindcss"` etc. Used by the runtime
136
+ // token resolver so utilities like `text-sm` keep resolving even
137
+ // when the consumer didn't override them.
138
+ //
139
+ // `consumerTokens` = consumer-only scan (bare `@import`s skipped).
140
+ // Used by the Design Tokens panel to show ONLY what the consumer
141
+ // wrote in their own files — no leaked Tailwind defaults like
142
+ // `serif: ui-serif, Georgia, Cambria, …` or the lone Tailwind
143
+ // `spacing: 0.25rem` baseline value.
144
+ const finalOutput: typeof output & {
145
+ tokens?: ReturnType<typeof readTokenSourceMap>;
146
+ consumerTokens?: ReturnType<typeof readConsumerOwnedTokenMap>;
147
+ } = output;
134
148
  if (CLI_INCLUDE_TOKENS) {
135
- finalOutput.tokens = readTokenSourceMap({
149
+ const baseOpts = {
136
150
  projectRoot: process.cwd(),
137
151
  tokenSourceMode: CLI_TOKEN_MODE,
138
152
  cssTokenPath: CLI_CSS_TOKEN_PATH,
139
153
  dtcgTokenPath: CLI_DTCG_TOKEN_PATH,
140
- });
154
+ };
155
+ finalOutput.tokens = readTokenSourceMap(baseOpts);
156
+ finalOutput.consumerTokens = readConsumerOwnedTokenMap(baseOpts);
141
157
  }
142
158
 
143
159
  // Write to JSON file. Default matches the consumer-side path used by