synthesisui 0.8.0 → 0.8.1
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.
- package/dist/commands/doctor.js +5 -0
- package/dist/doctor/overrides.js +106 -18
- package/package.json +1 -1
package/dist/commands/doctor.js
CHANGED
|
@@ -308,8 +308,13 @@ export async function doctor(opts) {
|
|
|
308
308
|
console.log(body(file));
|
|
309
309
|
for (const o of opts.all ? list : list.slice(0, 3)) {
|
|
310
310
|
console.log(` ${String(o.line).padStart(4)} ds-${o.component} · ${o.prop}: ${o.wrote}`);
|
|
311
|
+
// Always say what is being overruled. A finding that cannot name it is
|
|
312
|
+
// indistinguishable from a bug in the reader's eyes, and one of these
|
|
313
|
+
// (`.ds-card:hover { transform: none }`) was a real, deliberate call.
|
|
311
314
|
if (o.recipe)
|
|
312
315
|
console.log(` the recipe binds ${o.recipe}`);
|
|
316
|
+
else if (o.where)
|
|
317
|
+
console.log(` the recipe binds it ${o.where}`);
|
|
313
318
|
}
|
|
314
319
|
if (!opts.all && list.length > 3) {
|
|
315
320
|
console.log(` +${list.length - 3} more`);
|
package/dist/doctor/overrides.js
CHANGED
|
@@ -46,10 +46,37 @@ export function bindingsOf(recipe) {
|
|
|
46
46
|
collect(r.variants, false);
|
|
47
47
|
collect(r.states, false);
|
|
48
48
|
collect(r.parts, false);
|
|
49
|
+
// Where a non-base property lives, so the report can name it. Base wins: if
|
|
50
|
+
// base binds it too, that value is the one worth showing.
|
|
51
|
+
const boundIn = new Map();
|
|
52
|
+
const note = (block, label) => {
|
|
53
|
+
if (!block || typeof block !== "object")
|
|
54
|
+
return;
|
|
55
|
+
for (const [k, v] of Object.entries(block)) {
|
|
56
|
+
if (typeof v === "string" || typeof v === "number") {
|
|
57
|
+
const p = kebab(k);
|
|
58
|
+
if (!baseValues.has(p) && !boundIn.has(p))
|
|
59
|
+
boundIn.set(p, `${label}: ${v}`);
|
|
60
|
+
}
|
|
61
|
+
else if (v && typeof v === "object") {
|
|
62
|
+
note(v, label);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
for (const [state, block] of Object.entries((r.states ?? {}))) {
|
|
67
|
+
note(block, `on ${state}`);
|
|
68
|
+
}
|
|
69
|
+
for (const [axis, opts] of Object.entries((r.variants ?? {}))) {
|
|
70
|
+
if (!opts || typeof opts !== "object")
|
|
71
|
+
continue;
|
|
72
|
+
for (const [opt, block] of Object.entries(opts)) {
|
|
73
|
+
note(block, `on ${axis}="${opt}"`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
49
76
|
const usage = Array.isArray(r.usage)
|
|
50
77
|
? r.usage.filter((x) => typeof x === "string")
|
|
51
78
|
: [];
|
|
52
|
-
return { props, baseValues, usage };
|
|
79
|
+
return { props, baseValues, boundIn, usage };
|
|
53
80
|
}
|
|
54
81
|
/**
|
|
55
82
|
* How many places each known component is used. An inventory nobody has today:
|
|
@@ -117,6 +144,55 @@ function enclosingTag(src, at) {
|
|
|
117
144
|
return null;
|
|
118
145
|
}
|
|
119
146
|
const lineAt = (src, index) => src.slice(0, index).split("\n").length;
|
|
147
|
+
/**
|
|
148
|
+
* Whatever the `style` prop was given, with where it starts. The expression
|
|
149
|
+
* container, not `{{` specifically: a real component writes
|
|
150
|
+
* `style={showImg ? undefined : { color: "#fff" }}`, and requiring the double
|
|
151
|
+
* brace dropped that finding on the floor. Brace matching rather than a regex,
|
|
152
|
+
* because the value nests.
|
|
153
|
+
*/
|
|
154
|
+
function styleRegions(tag) {
|
|
155
|
+
const out = [];
|
|
156
|
+
const open = /style\s*=\s*\{/g;
|
|
157
|
+
let m = open.exec(tag);
|
|
158
|
+
while (m !== null) {
|
|
159
|
+
const start = m.index + m[0].length;
|
|
160
|
+
let depth = 1; // the container brace just consumed
|
|
161
|
+
let end = start;
|
|
162
|
+
for (; end < tag.length; end++) {
|
|
163
|
+
if (tag[end] === "{")
|
|
164
|
+
depth++;
|
|
165
|
+
else if (tag[end] === "}" && --depth === 0)
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
// Only the OBJECT LITERALS inside the container. Scanning the container
|
|
169
|
+
// whole let a one-line ternary eat the declaration: in
|
|
170
|
+
// `style={on ? undefined : { padding: "7px" }}` the colon after `undefined`
|
|
171
|
+
// reads as a property separator and swallows the padding behind it.
|
|
172
|
+
const container = tag.slice(start, end);
|
|
173
|
+
let d = 0;
|
|
174
|
+
let objStart = -1;
|
|
175
|
+
for (let i = 0; i < container.length; i++) {
|
|
176
|
+
if (container[i] === "{") {
|
|
177
|
+
if (d === 0)
|
|
178
|
+
objStart = i + 1;
|
|
179
|
+
d++;
|
|
180
|
+
}
|
|
181
|
+
else if (container[i] === "}" && d > 0 && --d === 0) {
|
|
182
|
+
out.push({
|
|
183
|
+
text: container.slice(objStart, i),
|
|
184
|
+
offset: start + objStart,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// `style={{ … }}` - the container IS the object
|
|
189
|
+
if (objStart === -1)
|
|
190
|
+
out.push({ text: container, offset: start });
|
|
191
|
+
open.lastIndex = end;
|
|
192
|
+
m = open.exec(tag);
|
|
193
|
+
}
|
|
194
|
+
return out;
|
|
195
|
+
}
|
|
120
196
|
/**
|
|
121
197
|
* The literal a style property was given, or null when it was given an
|
|
122
198
|
* expression instead.
|
|
@@ -159,22 +235,29 @@ export function findOverrides(source, recipes) {
|
|
|
159
235
|
const tag = enclosingTag(source, m.index ?? 0);
|
|
160
236
|
if (!tag)
|
|
161
237
|
continue;
|
|
162
|
-
// inline style={{ borderRadius: 4 }}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
238
|
+
// inline style={{ borderRadius: 4 }} - and ONLY that. Reading the whole tag
|
|
239
|
+
// meant reading every object prop on it, so Framer Motion's
|
|
240
|
+
// `animate={{ opacity: 1 }}` came back as "ds-card overrules opacity"
|
|
241
|
+
// (investidorez, 25/07). An animation is not a design decision.
|
|
242
|
+
for (const region of styleRegions(tag.text)) {
|
|
243
|
+
for (const s of region.text.matchAll(/([a-zA-Z-]+)\s*:\s*("[^"]*"|'[^']*'|[^,}\n]+)/g)) {
|
|
244
|
+
const prop = kebab(s[1]);
|
|
245
|
+
if (!bind.props.has(prop))
|
|
246
|
+
continue;
|
|
247
|
+
const wrote = literalValue(s[2]);
|
|
248
|
+
if (wrote === null)
|
|
249
|
+
continue;
|
|
250
|
+
const at = tag.start + region.offset + (s.index ?? 0);
|
|
251
|
+
record({
|
|
252
|
+
component: name,
|
|
253
|
+
prop,
|
|
254
|
+
wrote,
|
|
255
|
+
recipe: bind.baseValues.get(prop) ?? null,
|
|
256
|
+
where: bind.boundIn.get(prop) ?? null,
|
|
257
|
+
line: lineAt(source, at),
|
|
258
|
+
excerpt: clip(lines[lineAt(source, at) - 1]?.trim() ?? ""),
|
|
259
|
+
});
|
|
260
|
+
}
|
|
178
261
|
}
|
|
179
262
|
// utility classes sitting beside the ds-* class
|
|
180
263
|
for (const cls of tag.text.matchAll(/[\w:[\]#().%/-]+/g)) {
|
|
@@ -186,6 +269,7 @@ export function findOverrides(source, recipes) {
|
|
|
186
269
|
prop,
|
|
187
270
|
wrote: cls[0],
|
|
188
271
|
recipe: bind.baseValues.get(prop) ?? null,
|
|
272
|
+
where: bind.boundIn.get(prop) ?? null,
|
|
189
273
|
line: lineAt(source, tag.start + (cls.index ?? 0)),
|
|
190
274
|
excerpt: clip(lines[lineAt(source, tag.start + (cls.index ?? 0)) - 1]?.trim() ?? ""),
|
|
191
275
|
});
|
|
@@ -193,7 +277,10 @@ export function findOverrides(source, recipes) {
|
|
|
193
277
|
}
|
|
194
278
|
// ── CSS: a rule whose selector reaches a ds-* component ───────────────────
|
|
195
279
|
for (const rule of source.matchAll(/([^{}]+)\{([^{}]*)\}/g)) {
|
|
196
|
-
|
|
280
|
+
// A CSS comment is not a selector. `/* botões (.ds-button) … */` above an
|
|
281
|
+
// unrelated rule made the doctor attribute that rule to ds-button - it was
|
|
282
|
+
// reading prose as structure (investidorez, 25/07).
|
|
283
|
+
const selector = rule[1].replace(/\/\*[\s\S]*?\*\//g, "");
|
|
197
284
|
const hit = /\.ds-([a-z][a-z0-9-]*)\b/.exec(selector);
|
|
198
285
|
const bind = hit ? recipes.get(hit[1]) : undefined;
|
|
199
286
|
if (!hit || !bind)
|
|
@@ -211,6 +298,7 @@ export function findOverrides(source, recipes) {
|
|
|
211
298
|
prop,
|
|
212
299
|
wrote: decl[2].trim(),
|
|
213
300
|
recipe: bind.baseValues.get(prop) ?? null,
|
|
301
|
+
where: bind.boundIn.get(prop) ?? null,
|
|
214
302
|
line: lineAt(source, at),
|
|
215
303
|
excerpt: clip(lines[lineAt(source, at) - 1]?.trim() ?? ""),
|
|
216
304
|
});
|
package/package.json
CHANGED