clava 0.4.0 → 0.4.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/CHANGELOG.md +20 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +57 -16
- package/dist/index.js.map +1 -1
- package/package.json +5 -1
- package/src/index.ts +252 -75
- package/src/types.ts +2 -2
- package/src/utils.ts +31 -10
- package/tests/_utils.ts +6 -2
- package/tests/build.test.ts +81 -7
- package/tests/extend.test.ts +7 -2
- package/tests/refine.test.ts +149 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# clava
|
|
2
2
|
|
|
3
|
+
## 0.4.1
|
|
4
|
+
|
|
5
|
+
### Improved refine iteration warning with debugging context
|
|
6
|
+
|
|
7
|
+
When the [`refine`](https://clava.style/docs/reference/refine) iteration cap is hit, the development warning now lists the variant keys that did not stabilize and includes the stack trace of the [`cv`](https://clava.style/docs/reference/cv) call that defined the component. This makes it easier to find the offending component without searching through the codebase.
|
|
8
|
+
|
|
9
|
+
```txt
|
|
10
|
+
Clava: Maximum refine iterations exceeded. This can happen when a refine callback calls setVariants or setDefaultVariants, but one of the variants changes on every run.
|
|
11
|
+
Variant(s) that did not stabilize: size.
|
|
12
|
+
Component created at:
|
|
13
|
+
at toolbarButton (src/components/toolbar.ts:42:18)
|
|
14
|
+
...
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The frame is captured at component creation but formatted lazily, so component creation stays cheap unless the warning actually fires, and the capture is skipped entirely for components that cannot enter the refine loop. The whole warning is wrapped in a `process.env.NODE_ENV !== "production"` guard, so bundlers that inline that constant strip the warning machinery from production builds.
|
|
18
|
+
|
|
19
|
+
### Other updates
|
|
20
|
+
|
|
21
|
+
- Removed refine warning-only code from production bundles when bundlers statically replace `process.env.NODE_ENV`.
|
|
22
|
+
|
|
3
23
|
## 0.4.0
|
|
4
24
|
|
|
5
25
|
### Removed `computedVariants` in favor of function values in `variants`
|
package/dist/index.d.ts
CHANGED
|
@@ -30,11 +30,11 @@ type ComponentProps<V = {}> = VariantValues<V> & NullableComponentResult;
|
|
|
30
30
|
type GetVariants<V> = (variants?: VariantValues<V>) => VariantValues<V>;
|
|
31
31
|
type ComponentPropKey<R extends ComponentResult> = keyof R | (R extends StyleClassProps ? "className" : never);
|
|
32
32
|
type KeySourceArray = readonly string[];
|
|
33
|
-
|
|
33
|
+
interface KeySourceComponent {
|
|
34
34
|
propKeys: readonly string[];
|
|
35
35
|
variantKeys: readonly string[];
|
|
36
36
|
getVariants: () => Record<string, unknown>;
|
|
37
|
-
}
|
|
37
|
+
}
|
|
38
38
|
type KeySource = KeySourceArray | KeySourceComponent;
|
|
39
39
|
type IsComponent<S> = S extends {
|
|
40
40
|
getVariants: () => unknown;
|
package/dist/index.js
CHANGED
|
@@ -224,6 +224,7 @@ function isHTMLObjStyle(style) {
|
|
|
224
224
|
const META_KEY = "__meta";
|
|
225
225
|
const EMPTY_DEFAULTS = Object.freeze({});
|
|
226
226
|
const MAX_REFINE_RUNS = 50;
|
|
227
|
+
const REFINE_UNSTABLE_TRACKING_WINDOW = 10;
|
|
227
228
|
function areVariantsEqual(a, b) {
|
|
228
229
|
for (const key in a) {
|
|
229
230
|
if (!Object.hasOwn(a, key)) continue;
|
|
@@ -235,10 +236,47 @@ function areVariantsEqual(a, b) {
|
|
|
235
236
|
}
|
|
236
237
|
return true;
|
|
237
238
|
}
|
|
238
|
-
function
|
|
239
|
+
function captureCreationFrame(skipFn) {
|
|
240
|
+
if (process.env.NODE_ENV === "production") return void 0;
|
|
241
|
+
if (typeof Error.captureStackTrace === "function") {
|
|
242
|
+
const holder = {};
|
|
243
|
+
Error.captureStackTrace(holder, skipFn);
|
|
244
|
+
return holder;
|
|
245
|
+
}
|
|
246
|
+
return /* @__PURE__ */ new Error();
|
|
247
|
+
}
|
|
248
|
+
function formatCreationStack(frame) {
|
|
249
|
+
let stack = frame.stack;
|
|
250
|
+
if (!stack) return void 0;
|
|
251
|
+
const newlineIdx = stack.indexOf("\n");
|
|
252
|
+
if (newlineIdx > 0) {
|
|
253
|
+
const firstLine = stack.slice(0, newlineIdx);
|
|
254
|
+
if (firstLine === "Error" || firstLine.startsWith("Error:")) stack = stack.slice(newlineIdx + 1);
|
|
255
|
+
}
|
|
256
|
+
return stack;
|
|
257
|
+
}
|
|
258
|
+
function accumulateUnstableVariantKeys(into, prev, next) {
|
|
259
|
+
for (const key in next) {
|
|
260
|
+
if (!Object.hasOwn(next, key)) continue;
|
|
261
|
+
if (!Object.is(prev[key], next[key])) into.add(key);
|
|
262
|
+
}
|
|
263
|
+
for (const key in prev) {
|
|
264
|
+
if (!Object.hasOwn(prev, key)) continue;
|
|
265
|
+
if (Object.hasOwn(next, key)) continue;
|
|
266
|
+
into.add(key);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
function warnRefineLimit(runState, creationFrame, unstableKeys) {
|
|
270
|
+
if (process.env.NODE_ENV === "production") return;
|
|
239
271
|
if (runState.warned) return;
|
|
240
272
|
runState.warned = true;
|
|
241
|
-
|
|
273
|
+
let message = "Clava: Maximum refine iterations exceeded. This can happen when a refine callback calls setVariants or setDefaultVariants, but one of the variants changes on every run.";
|
|
274
|
+
if (unstableKeys && unstableKeys.size > 0) message += `\nVariant(s) that did not stabilize: ${Array.from(unstableKeys).join(", ")}.`;
|
|
275
|
+
if (creationFrame) {
|
|
276
|
+
const creationStack = formatCreationStack(creationFrame);
|
|
277
|
+
if (creationStack) message += `\nComponent created at:\n${creationStack}`;
|
|
278
|
+
}
|
|
279
|
+
console.warn(message);
|
|
242
280
|
}
|
|
243
281
|
function getExtUserVariantProps(userVariantProps, protectedVariants, changedVariants) {
|
|
244
282
|
const extUserVariantProps = {};
|
|
@@ -578,6 +616,7 @@ function create({ transformClass = (className) => className } = {}) {
|
|
|
578
616
|
}
|
|
579
617
|
const extMetasWithRefineCount = extMetasWithRefine.length;
|
|
580
618
|
const shouldCollectChangedVariants = extMetasWithRefineCount > 0;
|
|
619
|
+
const creationFrame = !!refine || extMetasWithRefineCount > 0 ? captureCreationFrame(cv) : void 0;
|
|
581
620
|
const functionVariantKeys = /* @__PURE__ */ new Set();
|
|
582
621
|
for (let i = 0; i < extCount; i++) {
|
|
583
622
|
const fnKeys = extMetas[i].functionVariantKeys;
|
|
@@ -898,16 +937,12 @@ function create({ transformClass = (className) => className } = {}) {
|
|
|
898
937
|
if (cStyle) Object.assign(styleOut, cStyle);
|
|
899
938
|
return workingResolved;
|
|
900
939
|
};
|
|
901
|
-
const compute = !refine && extMetasWithRefineCount === 0 ? (resolved, userVariantProps, skipKeys, skipValues, classesOut, styleOut, runState, protectedVariants, pendingProtectedVariants, protectedVariantKeys) => {
|
|
902
|
-
|
|
903
|
-
} : (resolved, userVariantProps, skipKeys, skipValues, classesOut, styleOut, runState, protectedVariants, pendingProtectedVariants, protectedVariantKeys) => {
|
|
904
|
-
runState ??= {
|
|
905
|
-
remaining: MAX_REFINE_RUNS,
|
|
906
|
-
warned: false
|
|
907
|
-
};
|
|
940
|
+
const compute = !refine && extMetasWithRefineCount === 0 ? computeOnce : (resolved, userVariantProps, skipKeys, skipValues, classesOut, styleOut, runState, protectedVariants, pendingProtectedVariants, protectedVariantKeys) => {
|
|
941
|
+
runState ??= { remaining: MAX_REFINE_RUNS };
|
|
908
942
|
protectedVariants ??= {};
|
|
909
943
|
protectedVariantKeys ??= /* @__PURE__ */ new Set();
|
|
910
944
|
let workingResolved = resolved;
|
|
945
|
+
let unstableKeys = null;
|
|
911
946
|
let lastClasses = [];
|
|
912
947
|
let lastStyle = {};
|
|
913
948
|
let isFirstRun = true;
|
|
@@ -935,8 +970,12 @@ function create({ transformClass = (className) => className } = {}) {
|
|
|
935
970
|
}
|
|
936
971
|
return nextResolved;
|
|
937
972
|
}
|
|
973
|
+
if (process.env.NODE_ENV !== "production" && runState.remaining < REFINE_UNSTABLE_TRACKING_WINDOW) {
|
|
974
|
+
if (!unstableKeys) unstableKeys = /* @__PURE__ */ new Set();
|
|
975
|
+
accumulateUnstableVariantKeys(unstableKeys, workingResolved, nextResolved);
|
|
976
|
+
}
|
|
938
977
|
if (useDirectOutput && runState.remaining === 0) {
|
|
939
|
-
warnRefineLimit(runState);
|
|
978
|
+
warnRefineLimit(runState, creationFrame, unstableKeys);
|
|
940
979
|
return nextResolved;
|
|
941
980
|
}
|
|
942
981
|
if (useDirectOutput) {
|
|
@@ -949,7 +988,7 @@ function create({ transformClass = (className) => className } = {}) {
|
|
|
949
988
|
workingResolved = nextResolved;
|
|
950
989
|
isFirstRun = false;
|
|
951
990
|
}
|
|
952
|
-
warnRefineLimit(runState);
|
|
991
|
+
warnRefineLimit(runState, creationFrame, unstableKeys);
|
|
953
992
|
for (let i = 0; i < lastClasses.length; i++) classesOut.push(lastClasses[i]);
|
|
954
993
|
Object.assign(styleOut, lastStyle);
|
|
955
994
|
return workingResolved;
|
|
@@ -974,13 +1013,11 @@ function create({ transformClass = (className) => className } = {}) {
|
|
|
974
1013
|
return workingResolved;
|
|
975
1014
|
};
|
|
976
1015
|
const resolveRefine = refine || extMetasWithRefineCount > 0 ? (resolved, userVariantProps, filterOwnVariants = true, runState, protectedVariants, pendingProtectedVariants, protectedVariantKeys) => {
|
|
977
|
-
runState ??= {
|
|
978
|
-
remaining: MAX_REFINE_RUNS,
|
|
979
|
-
warned: false
|
|
980
|
-
};
|
|
1016
|
+
runState ??= { remaining: MAX_REFINE_RUNS };
|
|
981
1017
|
protectedVariants ??= {};
|
|
982
1018
|
protectedVariantKeys ??= /* @__PURE__ */ new Set();
|
|
983
1019
|
let workingResolved = resolved;
|
|
1020
|
+
let unstableKeys = null;
|
|
984
1021
|
let reachedLimit = true;
|
|
985
1022
|
while (runState.remaining > 0) {
|
|
986
1023
|
runState.remaining -= 1;
|
|
@@ -994,9 +1031,13 @@ function create({ transformClass = (className) => className } = {}) {
|
|
|
994
1031
|
reachedLimit = false;
|
|
995
1032
|
break;
|
|
996
1033
|
}
|
|
1034
|
+
if (process.env.NODE_ENV !== "production" && runState.remaining < REFINE_UNSTABLE_TRACKING_WINDOW) {
|
|
1035
|
+
if (!unstableKeys) unstableKeys = /* @__PURE__ */ new Set();
|
|
1036
|
+
accumulateUnstableVariantKeys(unstableKeys, workingResolved, nextResolved);
|
|
1037
|
+
}
|
|
997
1038
|
workingResolved = nextResolved;
|
|
998
1039
|
}
|
|
999
|
-
if (reachedLimit) warnRefineLimit(runState);
|
|
1040
|
+
if (reachedLimit) warnRefineLimit(runState, creationFrame, unstableKeys);
|
|
1000
1041
|
return workingResolved;
|
|
1001
1042
|
} : null;
|
|
1002
1043
|
const computeResult = (props = EMPTY_DEFAULTS) => {
|