@jesscss/core 2.0.0-alpha.2 → 2.0.0-alpha.5
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/README.md +3 -1
- package/lib/tree/ampersand.d.ts +4 -0
- package/lib/tree/ampersand.d.ts.map +1 -1
- package/lib/tree/ampersand.js +51 -1
- package/lib/tree/ampersand.js.map +1 -1
- package/lib/tree/any.d.ts +1 -1
- package/lib/tree/any.d.ts.map +1 -1
- package/lib/tree/any.js +5 -2
- package/lib/tree/any.js.map +1 -1
- package/lib/tree/bool.d.ts +1 -0
- package/lib/tree/bool.d.ts.map +1 -1
- package/lib/tree/bool.js +5 -1
- package/lib/tree/bool.js.map +1 -1
- package/lib/tree/color.d.ts.map +1 -1
- package/lib/tree/color.js +2 -2
- package/lib/tree/color.js.map +1 -1
- package/lib/tree/combinator.d.ts +1 -0
- package/lib/tree/combinator.d.ts.map +1 -1
- package/lib/tree/combinator.js +5 -1
- package/lib/tree/combinator.js.map +1 -1
- package/lib/tree/comment.d.ts.map +1 -1
- package/lib/tree/comment.js +2 -1
- package/lib/tree/comment.js.map +1 -1
- package/lib/tree/declaration-var.d.ts +0 -1
- package/lib/tree/declaration-var.d.ts.map +1 -1
- package/lib/tree/declaration-var.js +1 -1
- package/lib/tree/declaration-var.js.map +1 -1
- package/lib/tree/declaration.d.ts.map +1 -1
- package/lib/tree/declaration.js +5 -8
- package/lib/tree/declaration.js.map +1 -1
- package/lib/tree/dimension.d.ts +1 -0
- package/lib/tree/dimension.d.ts.map +1 -1
- package/lib/tree/dimension.js +5 -2
- package/lib/tree/dimension.js.map +1 -1
- package/lib/tree/expression.d.ts +1 -0
- package/lib/tree/expression.d.ts.map +1 -1
- package/lib/tree/expression.js +5 -1
- package/lib/tree/expression.js.map +1 -1
- package/lib/tree/extend-list.d.ts +2 -2
- package/lib/tree/extend-list.d.ts.map +1 -1
- package/lib/tree/extend-list.js +5 -2
- package/lib/tree/extend-list.js.map +1 -1
- package/lib/tree/extend.d.ts +2 -2
- package/lib/tree/extend.d.ts.map +1 -1
- package/lib/tree/extend.js +6 -2
- package/lib/tree/extend.js.map +1 -1
- package/lib/tree/import-style.d.ts.map +1 -1
- package/lib/tree/import-style.js +11 -1
- package/lib/tree/import-style.js.map +1 -1
- package/lib/tree/nil.d.ts +0 -1
- package/lib/tree/nil.d.ts.map +1 -1
- package/lib/tree/nil.js +2 -3
- package/lib/tree/nil.js.map +1 -1
- package/lib/tree/node-base.d.ts +2 -0
- package/lib/tree/node-base.d.ts.map +1 -1
- package/lib/tree/node-base.js +46 -0
- package/lib/tree/node-base.js.map +1 -1
- package/lib/tree/paren.d.ts +2 -1
- package/lib/tree/paren.d.ts.map +1 -1
- package/lib/tree/paren.js +7 -1
- package/lib/tree/paren.js.map +1 -1
- package/lib/tree/quoted.d.ts +2 -1
- package/lib/tree/quoted.d.ts.map +1 -1
- package/lib/tree/quoted.js +10 -1
- package/lib/tree/quoted.js.map +1 -1
- package/lib/tree/reference.d.ts.map +1 -1
- package/lib/tree/reference.js.map +1 -1
- package/lib/tree/rules.d.ts +7 -0
- package/lib/tree/rules.d.ts.map +1 -1
- package/lib/tree/rules.js +147 -81
- package/lib/tree/rules.js.map +1 -1
- package/lib/tree/ruleset.d.ts +1 -0
- package/lib/tree/ruleset.d.ts.map +1 -1
- package/lib/tree/ruleset.js +27 -5
- package/lib/tree/ruleset.js.map +1 -1
- package/lib/tree/selector-basic.d.ts +1 -0
- package/lib/tree/selector-basic.d.ts.map +1 -1
- package/lib/tree/selector-basic.js +5 -1
- package/lib/tree/selector-basic.js.map +1 -1
- package/lib/tree/selector-list.d.ts.map +1 -1
- package/lib/tree/selector-list.js +3 -13
- package/lib/tree/selector-list.js.map +1 -1
- package/lib/tree/selector-pseudo.d.ts.map +1 -1
- package/lib/tree/selector-pseudo.js +13 -0
- package/lib/tree/selector-pseudo.js.map +1 -1
- package/lib/tree/sequence.d.ts.map +1 -1
- package/lib/tree/sequence.js +4 -1
- package/lib/tree/sequence.js.map +1 -1
- package/lib/tree/util/extend-roots.d.ts.map +1 -1
- package/lib/tree/util/extend-roots.js +25 -7
- package/lib/tree/util/extend-roots.js.map +1 -1
- package/lib/tree/util/extend-walk.d.ts +53 -0
- package/lib/tree/util/extend-walk.d.ts.map +1 -0
- package/lib/tree/util/extend-walk.js +881 -0
- package/lib/tree/util/extend-walk.js.map +1 -0
- package/lib/tree/util/extend.d.ts.map +1 -1
- package/lib/tree/util/extend.js +160 -11
- package/lib/tree/util/extend.js.map +1 -1
- package/lib/tree/util/registry-utils.d.ts.map +1 -1
- package/lib/tree/util/registry-utils.js +13 -41
- package/lib/tree/util/registry-utils.js.map +1 -1
- package/lib/tree/util/selector-match-core.d.ts +13 -0
- package/lib/tree/util/selector-match-core.d.ts.map +1 -1
- package/lib/tree/util/selector-match-core.js +55 -30
- package/lib/tree/util/selector-match-core.js.map +1 -1
- package/package.json +4 -2
package/lib/tree/rules.js
CHANGED
|
@@ -637,6 +637,12 @@ export class Rules extends Node {
|
|
|
637
637
|
rules.value[index] = node.preEval(context);
|
|
638
638
|
return;
|
|
639
639
|
}
|
|
640
|
+
// Nodes that don't register by name (Call, Expression, etc.) skip
|
|
641
|
+
// both preEval and dynamic resolution — they're handled by the eval queue.
|
|
642
|
+
if (!this._isRegisterableType(node)) {
|
|
643
|
+
node.index = index;
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
640
646
|
if (this._hasStaticName(node)) {
|
|
641
647
|
// Pre-evaluate nodes with static names before registration
|
|
642
648
|
// This ensures selectors are evaluated and keySets are available for rulesets
|
|
@@ -696,6 +702,15 @@ export class Rules extends Node {
|
|
|
696
702
|
// Primitive values (strings, numbers, etc.) are considered static
|
|
697
703
|
return true;
|
|
698
704
|
}
|
|
705
|
+
/**
|
|
706
|
+
* Check if a node type participates in name-based registration.
|
|
707
|
+
* Only these node types have names/selectors that _resolveDynamicNodes
|
|
708
|
+
* needs to resolve. Everything else (Call, Expression, Comment, etc.)
|
|
709
|
+
* goes straight to the eval queue without preEval.
|
|
710
|
+
*/
|
|
711
|
+
_isRegisterableType(node) {
|
|
712
|
+
return isNode(node, ['VarDeclaration', 'Declaration', 'Mixin', 'Ruleset', 'StyleImport']);
|
|
713
|
+
}
|
|
699
714
|
/**
|
|
700
715
|
* Check if a node has a static name that can be registered immediately
|
|
701
716
|
*/
|
|
@@ -708,6 +723,10 @@ export class Rules extends Node {
|
|
|
708
723
|
const name = node.value.name;
|
|
709
724
|
return this._isStatic(name);
|
|
710
725
|
}
|
|
726
|
+
if (isNode(node, 'Declaration')) {
|
|
727
|
+
const name = node.value.name;
|
|
728
|
+
return this._isStatic(name);
|
|
729
|
+
}
|
|
711
730
|
if (isNode(node, 'StyleImport')) {
|
|
712
731
|
const path = node.value.path;
|
|
713
732
|
return this._isStatic(path);
|
|
@@ -729,7 +748,7 @@ export class Rules extends Node {
|
|
|
729
748
|
}
|
|
730
749
|
return false;
|
|
731
750
|
}
|
|
732
|
-
// For other node types,
|
|
751
|
+
// For other registerable node types, check the F_STATIC flag
|
|
733
752
|
return node.hasFlag(F_STATIC);
|
|
734
753
|
}
|
|
735
754
|
/**
|
|
@@ -751,105 +770,132 @@ export class Rules extends Node {
|
|
|
751
770
|
* Multi-pass resolution of dynamic nodes with interpolated names
|
|
752
771
|
*/
|
|
753
772
|
_resolveDynamicNodes(rules, context, saved, dynamicNodes) {
|
|
754
|
-
const unresolvedNodes = [...dynamicNodes];
|
|
755
773
|
const resolvedNodes = [];
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
774
|
+
const handleResolvedNode = (resolvedNode, node, stillUnresolved) => {
|
|
775
|
+
if (resolvedNode.index === undefined) {
|
|
776
|
+
resolvedNode.index = node.index;
|
|
777
|
+
}
|
|
778
|
+
if (!resolvedNode.sourceNode) {
|
|
779
|
+
resolvedNode.sourceNode = node.sourceNode ?? node;
|
|
780
|
+
}
|
|
781
|
+
if (resolvedNode.type === 'Ruleset') {
|
|
782
|
+
rules.registerNode(resolvedNode);
|
|
783
|
+
}
|
|
784
|
+
if (isNode(resolvedNode, 'Nil') || this._hasStaticName(resolvedNode)) {
|
|
785
|
+
resolvedNodes.push(resolvedNode);
|
|
786
|
+
this._registerNodeIfEligible(rules, resolvedNode, context);
|
|
787
|
+
return true; // made progress
|
|
788
|
+
}
|
|
789
|
+
else {
|
|
790
|
+
stillUnresolved.push(resolvedNode);
|
|
791
|
+
return false;
|
|
792
|
+
}
|
|
793
|
+
};
|
|
794
|
+
const applyResolvedNodes = () => {
|
|
795
|
+
for (let i = 0; i < rules.value.length; i++) {
|
|
796
|
+
const node = rules.value[i];
|
|
797
|
+
const resolvedNode = resolvedNodes.find(n => n.index === node.index);
|
|
798
|
+
if (resolvedNode && resolvedNode !== node) {
|
|
799
|
+
rules.value[i] = resolvedNode.inherit(node);
|
|
800
|
+
rules.adopt(resolvedNode);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
};
|
|
804
|
+
const finishResolution = () => {
|
|
805
|
+
applyResolvedNodes();
|
|
806
|
+
context.rulesContext = saved.rulesContext;
|
|
807
|
+
context.treeRoot = saved.treeRoot;
|
|
808
|
+
if (saved.root !== undefined) {
|
|
809
|
+
context.root = saved.root;
|
|
810
|
+
}
|
|
811
|
+
return rules;
|
|
812
|
+
};
|
|
813
|
+
// Separate declarations (whose dynamic names might depend on each other)
|
|
814
|
+
// from non-declarations (which depend on declaration VALUES, not names,
|
|
815
|
+
// so retrying during preEval won't help).
|
|
816
|
+
const isDeclarationType = (n) => isNode(n, 'VarDeclaration') || isNode(n, 'Declaration');
|
|
817
|
+
const dynamicDeclarations = [];
|
|
818
|
+
const otherDynamic = [];
|
|
819
|
+
for (const node of dynamicNodes) {
|
|
820
|
+
if (isDeclarationType(node)) {
|
|
821
|
+
dynamicDeclarations.push(node);
|
|
822
|
+
}
|
|
823
|
+
else {
|
|
824
|
+
otherDynamic.push(node);
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
// Phase 1: Resolve declarations with dynamic names.
|
|
828
|
+
// Retry because one declaration's name might depend on another's being registered.
|
|
829
|
+
const MAX_DECL_RETRIES = 5;
|
|
830
|
+
let declRetries = 0;
|
|
831
|
+
const unresolvedDecls = [...dynamicDeclarations];
|
|
832
|
+
const resolveDeclarations = () => {
|
|
833
|
+
declRetries++;
|
|
834
|
+
if (declRetries > MAX_DECL_RETRIES || unresolvedDecls.length === 0) {
|
|
835
|
+
return;
|
|
763
836
|
}
|
|
764
837
|
const stillUnresolved = [];
|
|
765
838
|
let madeProgress = false;
|
|
766
|
-
for (
|
|
839
|
+
for (let i = 0; i < unresolvedDecls.length; i++) {
|
|
840
|
+
const node = unresolvedDecls[i];
|
|
767
841
|
try {
|
|
768
|
-
// Try to preEval the node
|
|
769
842
|
const result = node.preEval(context);
|
|
770
843
|
if (isThenable(result)) {
|
|
771
|
-
|
|
844
|
+
const remaining = unresolvedDecls.slice(i + 1);
|
|
772
845
|
return result.then((resolvedNode) => {
|
|
773
|
-
if (resolvedNode
|
|
774
|
-
resolvedNode.index = node.index;
|
|
775
|
-
}
|
|
776
|
-
if (!resolvedNode.sourceNode) {
|
|
777
|
-
resolvedNode.sourceNode = node.sourceNode ?? node;
|
|
778
|
-
}
|
|
779
|
-
// Register rulesets after preEval regardless of static name
|
|
780
|
-
if (resolvedNode.type === 'Ruleset') {
|
|
781
|
-
// registerNode handles both 'mixin' and 'ruleset' registries
|
|
782
|
-
rules.registerNode(resolvedNode);
|
|
783
|
-
}
|
|
784
|
-
if (isNode(resolvedNode, 'Nil') || this._hasStaticName(resolvedNode)) {
|
|
785
|
-
resolvedNodes.push(resolvedNode);
|
|
786
|
-
this._registerNodeIfEligible(rules, resolvedNode, context);
|
|
846
|
+
if (handleResolvedNode(resolvedNode, node, stillUnresolved)) {
|
|
787
847
|
madeProgress = true;
|
|
788
848
|
}
|
|
789
|
-
|
|
790
|
-
|
|
849
|
+
unresolvedDecls.length = 0;
|
|
850
|
+
unresolvedDecls.push(...stillUnresolved, ...remaining);
|
|
851
|
+
if (madeProgress && unresolvedDecls.length > 0) {
|
|
852
|
+
return resolveDeclarations();
|
|
791
853
|
}
|
|
792
|
-
return attemptResolution();
|
|
793
854
|
});
|
|
794
855
|
}
|
|
795
|
-
|
|
796
|
-
if (result.index === undefined) {
|
|
797
|
-
result.index = node.index;
|
|
798
|
-
}
|
|
799
|
-
if (!result.sourceNode) {
|
|
800
|
-
result.sourceNode = node.sourceNode ?? node;
|
|
801
|
-
}
|
|
802
|
-
if (result.type === 'Ruleset') {
|
|
803
|
-
// registerNode handles both 'mixin' and 'ruleset' registries
|
|
804
|
-
rules.registerNode(result);
|
|
805
|
-
}
|
|
806
|
-
// Check if the node now has a static name
|
|
807
|
-
if (isNode(result, 'Nil') || this._hasStaticName(result)) {
|
|
808
|
-
resolvedNodes.push(result);
|
|
809
|
-
this._registerNodeIfEligible(rules, result, context);
|
|
856
|
+
if (handleResolvedNode(result, node, stillUnresolved)) {
|
|
810
857
|
madeProgress = true;
|
|
811
858
|
}
|
|
812
|
-
else {
|
|
813
|
-
stillUnresolved.push(result);
|
|
814
|
-
}
|
|
815
859
|
}
|
|
816
|
-
catch
|
|
817
|
-
if (!firstError) {
|
|
818
|
-
firstError = error;
|
|
819
|
-
}
|
|
860
|
+
catch {
|
|
820
861
|
stillUnresolved.push(node);
|
|
821
862
|
}
|
|
822
863
|
}
|
|
823
|
-
// Update the rules with resolved nodes
|
|
824
|
-
for (let i = 0; i < rules.value.length; i++) {
|
|
825
|
-
const node = rules.value[i];
|
|
826
|
-
const resolvedNode = resolvedNodes.find(n => n.index === node.index);
|
|
827
|
-
if (resolvedNode && resolvedNode !== node) {
|
|
828
|
-
rules.value[i] = resolvedNode.inherit(node);
|
|
829
|
-
rules.adopt(resolvedNode);
|
|
830
|
-
}
|
|
831
|
-
}
|
|
832
|
-
// If we made progress, try again
|
|
833
864
|
if (madeProgress && stillUnresolved.length > 0) {
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
return
|
|
865
|
+
unresolvedDecls.length = 0;
|
|
866
|
+
unresolvedDecls.push(...stillUnresolved);
|
|
867
|
+
return resolveDeclarations();
|
|
837
868
|
}
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
869
|
+
};
|
|
870
|
+
// Phase 2: Try non-declarations once. Their interpolated names typically
|
|
871
|
+
// depend on declaration VALUES (e.g. @infix from breakpoint-infix()),
|
|
872
|
+
// which aren't evaluated until the eval phase. Retrying won't help.
|
|
873
|
+
const resolveOtherOnce = () => {
|
|
874
|
+
for (let i = 0; i < otherDynamic.length; i++) {
|
|
875
|
+
const node = otherDynamic[i];
|
|
876
|
+
try {
|
|
877
|
+
const result = node.preEval(context);
|
|
878
|
+
if (isThenable(result)) {
|
|
879
|
+
const remaining = otherDynamic.slice(i + 1);
|
|
880
|
+
return result.then((resolvedNode) => {
|
|
881
|
+
handleResolvedNode(resolvedNode, node, []);
|
|
882
|
+
// Continue with remaining nodes
|
|
883
|
+
otherDynamic.length = 0;
|
|
884
|
+
otherDynamic.push(...remaining);
|
|
885
|
+
return resolveOtherOnce();
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
handleResolvedNode(result, node, []);
|
|
889
|
+
}
|
|
890
|
+
catch {
|
|
891
|
+
// Can't resolve during preEval — leave in place for eval phase
|
|
892
|
+
}
|
|
849
893
|
}
|
|
850
|
-
return rules;
|
|
851
894
|
};
|
|
852
|
-
return
|
|
895
|
+
return pipe(() => resolveDeclarations(), () => {
|
|
896
|
+
applyResolvedNodes();
|
|
897
|
+
return resolveOtherOnce();
|
|
898
|
+
}, () => finishResolution());
|
|
853
899
|
}
|
|
854
900
|
/**
|
|
855
901
|
* Helper method to continue preEval'ing remaining children after an async preEval.
|
|
@@ -1025,6 +1071,15 @@ export class Rules extends Node {
|
|
|
1025
1071
|
if (p === 0 /* Priority.None */) {
|
|
1026
1072
|
throw error;
|
|
1027
1073
|
}
|
|
1074
|
+
// Only retry when the import path itself couldn't be resolved
|
|
1075
|
+
// (e.g. @import "@{theme}/file" where @theme isn't available yet).
|
|
1076
|
+
// Path resolution is cheap (no cloning). Content evaluation errors
|
|
1077
|
+
// (after cloning the import tree) are never retried — each retry
|
|
1078
|
+
// would re-clone the entire tree, causing memory blowup.
|
|
1079
|
+
const isPathError = error instanceof Error && error._isPathResolutionError;
|
|
1080
|
+
if (!isPathError) {
|
|
1081
|
+
throw error;
|
|
1082
|
+
}
|
|
1028
1083
|
// Retry policy:
|
|
1029
1084
|
// 1) first failure at a priority -> retry once at same priority
|
|
1030
1085
|
// 2) second+ failure at that priority -> step down one level
|
|
@@ -2038,7 +2093,7 @@ export function getFunctionFromMixins(mixins) {
|
|
|
2038
2093
|
Mixin: 'public'
|
|
2039
2094
|
}
|
|
2040
2095
|
});
|
|
2041
|
-
candidate.parent.adopt(outerRules);
|
|
2096
|
+
(thisContext.rulesContext ?? candidate.parent).adopt(outerRules);
|
|
2042
2097
|
outerRules.index = candidate.index;
|
|
2043
2098
|
for (let i = 0; i < params.value.length; i++) {
|
|
2044
2099
|
let param = params.value[i];
|
|
@@ -2108,9 +2163,20 @@ export function getFunctionFromMixins(mixins) {
|
|
|
2108
2163
|
.map(p => p.value.value);
|
|
2109
2164
|
const argumentNodes = (paramValues && paramValues.length > 0) ? paramValues : nodeArgs;
|
|
2110
2165
|
for (const argNode of argumentNodes) {
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2166
|
+
// If a Rest param collected args into a Sequence, spread its items
|
|
2167
|
+
// so @arguments reflects the actual argument count
|
|
2168
|
+
if (isNode(argNode, 'Sequence')) {
|
|
2169
|
+
for (const item of argNode.value) {
|
|
2170
|
+
const cloned = item.copy(true, freezeChildren);
|
|
2171
|
+
cloned.frozen = true;
|
|
2172
|
+
argumentsArgs.push(cloned);
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2175
|
+
else {
|
|
2176
|
+
const cloned = argNode.copy(true, freezeChildren);
|
|
2177
|
+
cloned.frozen = true;
|
|
2178
|
+
argumentsArgs.push(cloned);
|
|
2179
|
+
}
|
|
2114
2180
|
}
|
|
2115
2181
|
}
|
|
2116
2182
|
}
|