@bsuite/page-builder 1.0.7 → 2.0.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.
@@ -0,0 +1,278 @@
1
+ /**
2
+ * Which headings are CARD headings, and do they carry the gradient?
3
+ *
4
+ * WHY THIS EXISTS. The estate's heading gradient was implemented as a
5
+ * PAGE-TITLE convention and shipped: 183 of 232 crm7 `<h1>` page titles carry
6
+ * `.text-gradient-accent`. Card headings were never in scope, and the numbers
7
+ * say so plainly — 0 of 304 crm7 `<h2>`/`<h3>`, 15 of 734 estate-wide. The work
8
+ * was done, declared complete, and covered a DIFFERENT ELEMENT than the one the
9
+ * operator keeps pointing at. On the very dashboard he screenshotted,
10
+ * "Dashboard" (h1) has the gradient and "Quick Actions", "Communication Center"
11
+ * and "Pipeline Overview" (h2/h3) do not.
12
+ *
13
+ * SO WHY NOT JUST GREP `<h2`? Because `<h2>` is not the same thing as "card
14
+ * heading", and a sweep that treats them as equal gradients dialog titles,
15
+ * empty-state titles, section labels and table captions along with the cards.
16
+ * The operator asked for card headings. A detector that cannot tell a card
17
+ * heading from any other heading would deliver 734 changes to satisfy a request
18
+ * about roughly 600 of them, and the excess is what gets noticed.
19
+ *
20
+ * A heading is a CARD heading here when an enclosing element paints card chrome
21
+ * — a card component, or a border+radius+background surface — which is the same
22
+ * definition `cardSurfaceScanner` already uses for nested chrome. One definition
23
+ * of "card", two scanners.
24
+ *
25
+ * FAIL CLOSED. A file whose JSX tags do not balance is UNKNOWN, not clean: a
26
+ * tag stack that has lost its place cannot say what encloses what, and
27
+ * "checked nothing" must not share an exit code with "found nothing" (D-92).
28
+ *
29
+ * Node-only: filesystem access, exported from `@bsuite/page-builder/scanner`.
30
+ */
31
+ import { readFileSync, readdirSync, statSync, existsSync } from 'node:fs';
32
+ import { join, relative } from 'node:path';
33
+ import { stripComments, elementDeclaresCardChrome } from './cardSurfaceScanner.js';
34
+ const DEFAULT_HEADINGS = ['h2', 'h3'];
35
+ const DEFAULT_GRADIENT_CLASSES = ['text-gradient-accent', 'gradient-text'];
36
+ /**
37
+ * Classes whose effect DEPENDS on the heading filling its box.
38
+ *
39
+ * `.text-gradient-accent` sets `width: fit-content`, and that is load-bearing —
40
+ * `background-clip: text` paints across the ELEMENT BOX, so a block-level
41
+ * heading spanning its container samples only the first slice of the gradient
42
+ * and renders flat, indistinguishable from having no gradient at all. Shrinking
43
+ * the box is therefore not optional; it is the effect.
44
+ *
45
+ * But shrinking the box is VISIBLE wherever the box itself is visible or
46
+ * positioned. Three families, and the first was the only one measured on the
47
+ * first pass:
48
+ *
49
+ * 1. SIZE — `truncate`, `flex-1`, `w-full`, `line-clamp-*`. Fit-content never
50
+ * truncates and never fills.
51
+ * 2. POSITION — `text-center`, `mx-auto`. A centred heading stops centring the
52
+ * moment its box hugs the glyphs, because there is nothing left to centre
53
+ * the text inside.
54
+ * 3. PAINT — the heading's OWN `border-*` or `bg-*`. A rule or a tinted strip
55
+ * that used to span the card suddenly ends at the last letter. This is the
56
+ * most visible of the three and the easiest to miss in a diff.
57
+ *
58
+ * A first, loose measurement over a three-line window put family 1 at 2 and
59
+ * implied the sweep was nearly free. Reading the heading's OWN attributes puts
60
+ * the full hazard set an order of magnitude higher. The loose number was the
61
+ * kind that makes a codemod look safe.
62
+ */
63
+ const WIDTH_DEPENDENT = [
64
+ 'truncate',
65
+ 'flex-1',
66
+ 'w-full',
67
+ 'grow',
68
+ 'flex-grow',
69
+ 'text-center',
70
+ 'mx-auto',
71
+ ];
72
+ const WIDTH_DEPENDENT_PREFIXES = ['line-clamp-', 'basis-', 'w-', 'min-w-', 'max-w-'];
73
+ /** The heading paints its own box — a border or a background of its own. */
74
+ const OWN_PAINT = /(?:^|\s)(?:border(?:-[a-z0-9[\]().\-/]+)?|bg-[a-z0-9[\]().\-/]+)(?=$|\s)/;
75
+ /** Void HTML elements never carry a closing tag. */
76
+ const VOID_TAGS = new Set([
77
+ 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',
78
+ 'link', 'meta', 'param', 'source', 'track', 'wbr',
79
+ ]);
80
+ /**
81
+ * Tokenise JSX tags with their kind and offset.
82
+ *
83
+ * `openingTags` in the sibling module is deliberately kind-blind — it only has
84
+ * to find chrome inside a known block. Ancestry needs a stack, and a stack
85
+ * needs to know which tags close.
86
+ */
87
+ export function jsxTags(source) {
88
+ const out = [];
89
+ for (let i = 0; i < source.length; i++) {
90
+ if (source[i] !== '<')
91
+ continue;
92
+ const close = /^<\/([A-Za-z][A-Za-z0-9._-]*)\s*>/.exec(source.slice(i, i + 80));
93
+ if (close) {
94
+ out.push({ kind: 'close', tag: close[1], attrs: '', index: i });
95
+ i += close[0].length - 1;
96
+ continue;
97
+ }
98
+ const open = /^<([A-Za-z][A-Za-z0-9._-]*)/.exec(source.slice(i, i + 64));
99
+ if (!open)
100
+ continue;
101
+ // KNOWN LIMITATION, measured rather than papered over. A TypeScript type
102
+ // argument presents as a tag to any matcher this cheap:
103
+ // `row.getValue<string>('code')` pushes `<string>`, and every ancestry
104
+ // answer after it in that file is fiction. The file is therefore reported
105
+ // UNKNOWN by the stack check below — 23 files across six apps, 0.8% of the
106
+ // tree, named individually rather than absorbed.
107
+ //
108
+ // A GUARD WAS TRIED AND REVERTED, and the measurement is why. Skipping a
109
+ // tag whose `<` is preceded by an identifier character catches the generics
110
+ // — and also catches JSX that follows TEXT (`Total<span>`), which is
111
+ // ordinary markup. Skipping an OPENING tag while its CLOSING tag is still
112
+ // counted unbalances the stack outright, so UNKNOWN went from 23 to 106.
113
+ // An over-eager filter feeding a stack is strictly worse than no filter,
114
+ // and a real parser is the fix if 23 ever stops being acceptable.
115
+ let j = i + open[0].length;
116
+ let depth = 0;
117
+ let quote = null;
118
+ let closed = false;
119
+ for (; j < source.length; j++) {
120
+ const c = source[j];
121
+ if (quote) {
122
+ if (c === quote && source[j - 1] !== '\\')
123
+ quote = null;
124
+ continue;
125
+ }
126
+ if (c === '"' || c === "'" || c === '`') {
127
+ quote = c;
128
+ continue;
129
+ }
130
+ if (c === '{')
131
+ depth++;
132
+ else if (c === '}')
133
+ depth--;
134
+ else if (c === '>' && depth === 0) {
135
+ closed = true;
136
+ break;
137
+ }
138
+ }
139
+ if (!closed)
140
+ continue;
141
+ const attrs = source.slice(i + open[0].length, j);
142
+ const selfClosing = /\/\s*$/.test(attrs) || VOID_TAGS.has(open[1]);
143
+ out.push({
144
+ kind: selfClosing ? 'self' : 'open',
145
+ tag: open[1],
146
+ attrs: attrs.replace(/\/\s*$/, ''),
147
+ index: i,
148
+ });
149
+ i = j;
150
+ }
151
+ return out;
152
+ }
153
+ function classText(attrs) {
154
+ const m = /class(?:Name)?\s*=\s*(?:"([^"]*)"|'([^']*)'|\{([\s\S]*)\})/.exec(attrs);
155
+ if (!m)
156
+ return '';
157
+ if (m[1] !== undefined)
158
+ return m[1];
159
+ if (m[2] !== undefined)
160
+ return m[2];
161
+ const lit = /(?:"([^"]*)"|'([^']*)'|`([^`]*)`)/g;
162
+ const parts = [];
163
+ let l;
164
+ while ((l = lit.exec(m[3] ?? '')) !== null)
165
+ parts.push(l[1] ?? l[2] ?? l[3] ?? '');
166
+ return parts.join(' ');
167
+ }
168
+ function widthDependent(classes) {
169
+ const tokens = classes.split(/\s+/).filter(Boolean);
170
+ const hits = tokens.filter((t) => WIDTH_DEPENDENT.includes(t) ||
171
+ WIDTH_DEPENDENT_PREFIXES.some((p) => t.startsWith(p)));
172
+ // A heading that paints its own box: shrinking the box moves the paint.
173
+ for (const t of tokens)
174
+ if (OWN_PAINT.test(` ${t} `) && !hits.includes(t))
175
+ hits.push(t);
176
+ return hits;
177
+ }
178
+ function walk(dir, extensions, acc) {
179
+ for (const entry of readdirSync(dir)) {
180
+ if (entry === 'node_modules' || entry === 'dist' || entry === '.git')
181
+ continue;
182
+ const full = join(dir, entry);
183
+ const st = statSync(full);
184
+ if (st.isDirectory())
185
+ walk(full, extensions, acc);
186
+ else if (extensions.some((e) => entry.endsWith(e)) && !/\.(test|spec)\./.test(entry))
187
+ acc.push(full);
188
+ }
189
+ }
190
+ export function scanCardHeadings(config) {
191
+ const extensions = config.extensions ?? ['.tsx'];
192
+ const headings = new Set(config.headingTags ?? DEFAULT_HEADINGS);
193
+ const gradientClasses = config.gradientClasses ?? DEFAULT_GRADIENT_CLASSES;
194
+ const chromeTags = new Set([...config.cardTags, ...(config.nestedChromeTags ?? [])]);
195
+ const findings = [];
196
+ const unknownFiles = [];
197
+ const files = [];
198
+ const scanRootsResolved = [];
199
+ // D-92: assert the inputs before reporting a verdict.
200
+ for (const root of config.scanRoots) {
201
+ const abs = join(config.projectRoot, root);
202
+ if (!existsSync(abs))
203
+ throw new Error(`[cardHeadingScanner] scan root "${root}" does not exist at ${abs}. ` +
204
+ `A scanner that silently skips a missing root reports a false pass.`);
205
+ const before = files.length;
206
+ walk(abs, extensions, files);
207
+ if (files.length === before)
208
+ throw new Error(`[cardHeadingScanner] scan root "${root}" matched ZERO files. ` +
209
+ `Refusing to report a verdict from an empty scan.`);
210
+ scanRootsResolved.push(root);
211
+ }
212
+ for (const file of files) {
213
+ const rel = relative(config.projectRoot, file);
214
+ let src;
215
+ try {
216
+ src = stripComments(readFileSync(file, 'utf8'));
217
+ }
218
+ catch {
219
+ unknownFiles.push(rel);
220
+ continue;
221
+ }
222
+ if (!/<h[1-6][\s/>]/.test(src))
223
+ continue;
224
+ const tags = jsxTags(src);
225
+ const stack = [];
226
+ let lostPlace = false;
227
+ for (const t of tags) {
228
+ if (t.kind === 'self')
229
+ continue;
230
+ if (t.kind === 'close') {
231
+ // A close with nothing to close, or closing something else, means the
232
+ // stack no longer describes the tree. Ancestry answers become fiction
233
+ // from here, so stop and report UNKNOWN rather than guess.
234
+ const top = stack[stack.length - 1];
235
+ if (!top || top.tag !== t.tag) {
236
+ lostPlace = true;
237
+ break;
238
+ }
239
+ stack.pop();
240
+ continue;
241
+ }
242
+ if (headings.has(t.tag)) {
243
+ const surface = stack
244
+ .slice()
245
+ .reverse()
246
+ .map((a) => elementDeclaresCardChrome(a, chromeTags))
247
+ .find((hit) => Boolean(hit));
248
+ if (surface) {
249
+ const classes = classText(t.attrs);
250
+ findings.push({
251
+ file: rel,
252
+ tag: t.tag,
253
+ line: src.slice(0, t.index).split('\n').length,
254
+ enclosingSurface: surface,
255
+ hasGradient: gradientClasses.some((g) => new RegExp(`(?:^|\\s)${g}(?:$|\\s)`).test(classes)),
256
+ widthDependentClasses: widthDependent(classes),
257
+ });
258
+ }
259
+ }
260
+ stack.push({ tag: t.tag, attrs: t.attrs });
261
+ }
262
+ if (lostPlace) {
263
+ unknownFiles.push(rel);
264
+ // Drop this file's findings — an ancestry answer from a broken stack is
265
+ // worse than no answer, because it looks like a measurement.
266
+ for (let i = findings.length - 1; i >= 0; i--)
267
+ if (findings[i].file === rel)
268
+ findings.splice(i, 1);
269
+ }
270
+ }
271
+ const missing = findings.filter((f) => !f.hasGradient);
272
+ const risky = missing.filter((f) => f.widthDependentClasses.length > 0);
273
+ const summary = `scanned ${files.length} files across ${scanRootsResolved.length} root(s) [${scanRootsResolved.join(', ')}]; ` +
274
+ `${findings.length} card heading(s), ${findings.length - missing.length} already gradient, ` +
275
+ `${missing.length} without — of which ${risky.length} carry a width-dependent class and need a ` +
276
+ `decision rather than a codemod; ${unknownFiles.length} UNKNOWN file(s) — an UNKNOWN is not a clean file.`;
277
+ return { findings, filesScanned: files.length, scanRootsResolved, unknownFiles, summary };
278
+ }
@@ -46,7 +46,20 @@ export type CardSurfaceIdiom =
46
46
  /** autoHeight opt-out on a card that is not a virtualized list. */
47
47
  | 'autoheight-optout'
48
48
  /** autoHeight={false} with a seed height so small the card must clip. */
49
- | 'clipped-card';
49
+ | 'clipped-card'
50
+ /**
51
+ * V-C5. A grid item whose child re-declares card chrome — border + radius +
52
+ * background — inside the chrome the grid item already paints. 28px inside
53
+ * 24px, two 1px borders. This is the idiom V-C4 (`glued-widget`) cannot see:
54
+ * ONE card in ONE slot is not glue, and it is still a double frame.
55
+ */
56
+ | 'nested-chrome'
57
+ /**
58
+ * The file could not be parsed with confidence. NOT a clean verdict. A gate
59
+ * that cannot tell "checked nothing" from "found nothing" is not a gate
60
+ * (D-92), so an unparseable file gets its own idiom and its own exit path.
61
+ */
62
+ | 'unparseable';
50
63
  export interface CardSurfaceFinding {
51
64
  file: string;
52
65
  idiom: CardSurfaceIdiom;
@@ -95,6 +108,36 @@ export interface CardSurfaceScannerConfig {
95
108
  autoHeightEscapeHatch?: RegExp;
96
109
  /** File extensions to scan. Defaults to .tsx. */
97
110
  extensions?: string[];
111
+ /**
112
+ * Extra component names that count as CARD CHROME when they appear inside a
113
+ * grid slot — a component that paints its own border + radius + background.
114
+ * `cardTags` is always included; this is for app-local chrome components the
115
+ * glue check does not need (BSU `MagicCard`, conduit `CounterCard`, …).
116
+ */
117
+ nestedChromeTags?: string[];
118
+ /** file -> reason. A nested-chrome file listed here is allowed. */
119
+ nestedChromeExclusions?: Record<string, string>;
120
+ /**
121
+ * Does the GRID ITEM paint card chrome in the version this app resolves?
122
+ *
123
+ * TRUE for `@bsuite/page-builder` <= 1.0.7, where every grid item painted
124
+ * `rounded-3xl bg-card border border-border` unconditionally and there was
125
+ * no way to turn it off. On those versions a nested card is ALWAYS a double
126
+ * frame, so every nesting slot is a finding.
127
+ *
128
+ * FALSE from 2.0.0, where chrome is opt-in. A nested card then becomes the
129
+ * CORRECT shape — it is the only surface — and the defect narrows to a slot
130
+ * that opts back INTO chrome (`itemChrome`, or `chrome` on the item or the
131
+ * CanvasCard) AND still nests a card.
132
+ *
133
+ * DEFAULTS TO TRUE, i.e. it assumes the pre-inversion package until an app
134
+ * says otherwise. A shared-package fix that four consumers receive and one
135
+ * does not is this estate's recorded failure mode (conduit sat on a
136
+ * minor-locked `^0.6.3` while the fix shipped in 0.8.0, and nothing
137
+ * reported it), so each app must DECLARE which side of the inversion it is
138
+ * on rather than inherit an optimistic default.
139
+ */
140
+ gridItemPaintsChrome?: boolean;
98
141
  }
99
142
  export interface CardSurfaceScanResult {
100
143
  findings: CardSurfaceFinding[];
@@ -103,6 +146,14 @@ export interface CardSurfaceScanResult {
103
146
  scanRootsResolved: string[];
104
147
  /** Exclusion-ledger keys that no longer match any finding — stale entries. */
105
148
  staleExclusions: string[];
149
+ /**
150
+ * Files the scanner could NOT parse with confidence. These are UNKNOWN, not
151
+ * clean. A caller that treats an empty `findings` array as a pass while this
152
+ * array is non-empty has reproduced the exact defect D-92 names.
153
+ */
154
+ unknownFiles: string[];
155
+ /** Distinct files carrying at least one `nested-chrome` finding. */
156
+ nestedChromeFiles: string[];
106
157
  /** Human-readable account of how the verdict was reached. */
107
158
  summary: string;
108
159
  }
@@ -116,5 +167,54 @@ export interface CardSurfaceScanResult {
116
167
  * skipped entirely. Stripping first fixes both.
117
168
  */
118
169
  export declare function stripComments(source: string): string;
170
+ /**
171
+ * Every opening tag in a JSX body, with its raw attribute text.
172
+ *
173
+ * Hand-rolled rather than regex-only because an attribute value can contain
174
+ * `>` inside a string, a template literal or a `{…}` expression — three of the
175
+ * five hand-rolled copies this module replaced were defeated by exactly that.
176
+ */
177
+ export declare function openingTags(body: string): {
178
+ tag: string;
179
+ attrs: string;
180
+ }[];
181
+ /**
182
+ * Does this element paint its OWN card chrome?
183
+ *
184
+ * Chrome means all three of border, radius and background, because that is
185
+ * exactly what `PageGridLayout` already paints on the slot. Two of the three is
186
+ * a tinted panel or a divider, not a second card — requiring all three is what
187
+ * separates BSU's `glass-card rounded-2xl border-primary/30` (a real double
188
+ * frame) from a `rounded-lg bg-muted` inline chip (not one).
189
+ *
190
+ * Chrome declared through `style={{ background, border, borderRadius }}` counts
191
+ * the same as chrome declared through classes. BSU's `Settings.tsx` is chrome
192
+ * entirely in inline style; a class-only detector calls that file clean, which
193
+ * is how a nested card hides from a gate that only reads Tailwind.
194
+ */
195
+ export declare function elementDeclaresCardChrome(el: {
196
+ tag: string;
197
+ attrs: string;
198
+ }, chromeTags: Set<string>): string | null;
199
+ /**
200
+ * Does this grid slot paint chrome of its OWN, post-inversion?
201
+ *
202
+ * Three ways to opt in, and all three have to be visible to the scanner or a
203
+ * re-chromed slot goes unnoticed: `itemChrome` on the grid component (whole
204
+ * app/page), `chrome: true` on the layout item, and `chrome` on the CanvasCard.
205
+ */
206
+ export declare function slotOptsIntoChrome(fileSource: string, slotBody: string): boolean;
207
+ /** The first nested-chrome element inside one grid slot, or null. */
208
+ export declare function findNestedChrome(slotBody: string, config: Pick<CardSurfaceScannerConfig, 'cardTags' | 'nestedChromeTags'>): string | null;
209
+ /**
210
+ * Can this file be parsed with confidence?
211
+ *
212
+ * Returns a reason when it CANNOT. Every `<CanvasCard` must pair with a
213
+ * `</CanvasCard>` the block regex can reach, and every `widgets={{` must close
214
+ * before EOF. A file that fails either is UNKNOWN — it is not reported clean,
215
+ * and it is not silently skipped. "Checked nothing" and "found nothing" do not
216
+ * share an exit code here.
217
+ */
218
+ export declare function parseConfidence(src: string): string | null;
119
219
  export declare function scanCardSurfaces(config: CardSurfaceScannerConfig): CardSurfaceScanResult;
120
220
  //# sourceMappingURL=cardSurfaceScanner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cardSurfaceScanner.d.ts","sourceRoot":"","sources":["../../src/scanner/cardSurfaceScanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAKH,MAAM,MAAM,gBAAgB;AAC1B,2DAA2D;AACzD,cAAc;AAChB,6EAA6E;GAC3E,sBAAsB;AACxB,yEAAyE;GACvE,mBAAmB;AACrB,mEAAmE;GACjE,mBAAmB;AACrB,yEAAyE;GACvE,cAAc,CAAC;AAEnB,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,gBAAgB,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,wBAAwB;IACvC,sCAAsC;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB;;;;OAIG;IACH,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,sDAAsD;IACtD,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,mFAAmF;IACnF,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,6DAA6D;IAC7D,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,2EAA2E;IAC3E,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC;;;OAGG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,iDAAiD;IACjD,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,kBAAkB,EAAE,CAAC;IAC/B,iEAAiE;IACjE,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,8EAA8E;IAC9E,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAC;CACjB;AASD;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKpD;AAwHD,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,wBAAwB,GAC/B,qBAAqB,CAwIvB"}
1
+ {"version":3,"file":"cardSurfaceScanner.d.ts","sourceRoot":"","sources":["../../src/scanner/cardSurfaceScanner.ts"],"names":[],"mappings":"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"}