synthesisui 0.16.82 → 0.16.84

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,129 @@
1
+ /**
2
+ * WHAT THIS VERSION CAN AND CANNOT READ, MEASURED ON THEIR OWN REPO.
3
+ *
4
+ * The most commercially important thing in the pipeline, and it took a person saying
5
+ * "nothing works" to see it (dono, 01/08).
6
+ *
7
+ * Before this, importing a CSS-Modules app produced 283 components with zero
8
+ * declarations and said nothing about why. A person seeing that concludes the product is
9
+ * broken, and they are reasoning correctly from what they were shown. The defect was
10
+ * never the gap - every reader has a boundary. The defect was the SILENCE about it.
11
+ *
12
+ * So the census measures its own coverage and says the number before anything is sent:
13
+ * how each component expresses style, how many of those this version reads, and which
14
+ * ones it does not - by name, with the count from their repo rather than a disclaimer.
15
+ *
16
+ * A governance product that cannot state what it does not govern is not trustworthy.
17
+ */
18
+ /**
19
+ * Every shape, in the order the enumeration found them. Each entry survived being
20
+ * counted on a real repo: a shape with no evidence is a shape I assumed.
21
+ */
22
+ export const STYLE_SHAPES = [
23
+ {
24
+ key: "static",
25
+ label: "a class list written out",
26
+ reads: "full",
27
+ test: /className=["'][^"']+["']/,
28
+ },
29
+ {
30
+ key: "module",
31
+ label: "CSS Modules",
32
+ reads: "full",
33
+ test: /from\s+["'][^"']*\.module\.(?:css|scss|sass|less)["']/,
34
+ },
35
+ {
36
+ key: "cva",
37
+ label: "cva / tailwind-variants",
38
+ reads: "full",
39
+ test: /\b(?:cva|tv)\s*\(/,
40
+ },
41
+ {
42
+ key: "record",
43
+ label: "a lookup record of option to classes",
44
+ reads: "full",
45
+ test: /(?:const|let)\s+\w*(?:[Ss]tyles?|[Cc]lasses|[Vv]ariants?|[Mm]ap|[Cc]olors?|[Ss]izes?|[Tt]ones?)\w*\s*(?::\s*[^=]+)?=\s*\{/,
46
+ },
47
+ {
48
+ key: "ternary",
49
+ label: "a ternary between class literals",
50
+ reads: "full",
51
+ test: /\?\s*["'][^"']*(?:bg-|text-|border-|p-|px-|rounded-)/,
52
+ },
53
+ {
54
+ key: "inline",
55
+ label: "style={{ }}",
56
+ reads: "partial",
57
+ because: "a literal travels as a literal, so it re-themes nowhere until you promote it - and a value computed at render time is not in the source at all",
58
+ test: /style=\{\{/,
59
+ },
60
+ {
61
+ key: "interpolated",
62
+ label: "a template with a runtime value in it",
63
+ reads: "partial",
64
+ because: "the literal halves are read and a `${cond ? a : b}` between two known classes is read as a variant; a class assembled from a variable does not exist in the source, so there is nothing to read",
65
+ test: /className=\{`[^`]*\$\{/,
66
+ },
67
+ {
68
+ key: "styled",
69
+ label: "styled-components / emotion",
70
+ reads: "none",
71
+ because: "not read by this version. It was left out deliberately rather than guessed at: zero files in the repo this was measured against, and building for a shape with no evidence is the same mistake as building for one file",
72
+ test: /styled[.(]|@emotion/,
73
+ },
74
+ {
75
+ key: "sx",
76
+ label: "a style-prop system (Chakra, Panda, MUI sx)",
77
+ reads: "none",
78
+ because: "the styling lives in props this version does not read; a component that only forwards to that library is reported as an adapter instead",
79
+ test: /\bsx=\{|@chakra-ui|@pandacss/,
80
+ },
81
+ ];
82
+ export function countShape(source, name, into) {
83
+ for (const shape of STYLE_SHAPES) {
84
+ if (!shape.test.test(source))
85
+ continue;
86
+ const at = into.get(shape.key) ?? { shape, files: 0, examples: [] };
87
+ at.files += 1;
88
+ if (at.examples.length < 4)
89
+ at.examples.push(name);
90
+ into.set(shape.key, at);
91
+ }
92
+ }
93
+ export function summarizeCoverage(counts, components, read, declarations) {
94
+ return {
95
+ components,
96
+ read,
97
+ declarations,
98
+ counts: [...counts.values()].sort((a, b) => b.files - a.files),
99
+ };
100
+ }
101
+ /**
102
+ * The report, in the words a person needs before they decide whether to import.
103
+ *
104
+ * Leads with the number that matters - how many components came out with a look - and
105
+ * then names every shape that is not fully read, with the reason. No percentages without
106
+ * the count behind them: "75%" of an unknown total is a marketing number.
107
+ */
108
+ export function describeCoverage(c) {
109
+ if (c.components === 0)
110
+ return [];
111
+ const lines = [];
112
+ const pct = Math.round((c.read / c.components) * 100);
113
+ lines.push(`${c.read} of ${c.components} components came out with a look - ${pct}%, ${c.declarations} declarations in total. This is measured on your files, not an estimate.`);
114
+ for (const { shape, files, examples } of c.counts) {
115
+ const share = Math.round((files / c.components) * 100);
116
+ const head = ` ${files} (${share}%) ${shape.label}`;
117
+ if (shape.reads === "full") {
118
+ lines.push(`${head} - read`);
119
+ continue;
120
+ }
121
+ lines.push(`${head} - ${shape.reads === "none" ? "NOT read" : "partly read"}. ${shape.because ?? ""}`);
122
+ lines.push(` ${examples.join(", ")}`);
123
+ }
124
+ const missing = c.components - c.read;
125
+ if (missing > 0) {
126
+ lines.push(`${missing} came out with no look at all. They still arrive as contracts - the axes their types declare, their name, their place in your tree - and the look stays yours to write. That is the design, but you should know the number before you decide.`);
127
+ }
128
+ return lines;
129
+ }
@@ -155,11 +155,41 @@ const AXIS_SYNONYM = {
155
155
  placement: "side",
156
156
  position: "side",
157
157
  };
158
+ /**
159
+ * THE LIVE TABLE, when a run fetched one.
160
+ *
161
+ * Module-level and set once per run, so every call site gets the same answer without
162
+ * threading the table through nine functions that do not care about it. Absent means the
163
+ * written `SYNONYM` floor answers - which is a smaller answer, and the run says so.
164
+ *
165
+ * The written table had 26 names against a catalogue of 41: twenty of our own components
166
+ * could not be matched at all (dono, 01/08). It stays as the offline floor, not as truth.
167
+ */
168
+ let live = null;
169
+ export function useLiveCatalogue(table) {
170
+ live = table;
171
+ }
172
+ /** How many names the written floor knows - the number a fallback message needs. */
173
+ export function floorSize() {
174
+ return new Set(Object.values(SYNONYM)).size;
175
+ }
158
176
  export function canonicalName(name) {
159
177
  const head = name
160
178
  .split(".")[0]
161
179
  .toLowerCase()
162
180
  .replace(/[^a-z]/g, "");
181
+ /**
182
+ * The live catalogue first, and its own name counts as a synonym for itself: their
183
+ * `Textarea` matching our `textarea` needed nothing clever, only a table that knew
184
+ * `textarea` exists.
185
+ */
186
+ if (live) {
187
+ for (const [canonical, also] of Object.entries(live.synonyms)) {
188
+ const words = [canonical, ...also].map((w) => w.replace(/[^a-z]/g, ""));
189
+ if (words.includes(head))
190
+ return canonical;
191
+ }
192
+ }
163
193
  if (SYNONYM[head])
164
194
  return SYNONYM[head];
165
195
  // A compound like `WidgetCard` or `ArrowDownIcon` is only canonical when the
@@ -379,7 +409,10 @@ opts) {
379
409
  sharedCount(component.props, mine.find((m) => m.name === t.name)?.props ?? {}) >= TWIN_MIN_SHARED &&
380
410
  sharedMeaning(component.props, mine.find((m) => m.name === t.name)?.props ?? {}) >= 1)
381
411
  .sort((a, b) => b.overlap - a.overlap);
382
- if (canonical && CATALOGUE[canonical]) {
412
+ // The LIVE catalogue counts as knowing the name: gating on the written table
413
+ // meant a component matched by the live one fell through to `nearly` (the same
414
+ // staleness, one branch down).
415
+ if (canonical && (CATALOGUE[canonical] || live?.axes[canonical])) {
383
416
  const alsoClaiming = (claims.get(canonical) ?? []).filter((n) => n !== component.name);
384
417
  /**
385
418
  * LIBRARY MODE: the match is a NOTE, not a verdict.