@drskillissue/ganko 0.2.1 → 0.2.6

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.
@@ -14,7 +14,7 @@ import {
14
14
  rules3,
15
15
  runCrossFileRules,
16
16
  runPhases
17
- } from "./chunk-CAKVXEYV.js";
17
+ } from "./chunk-FTIRRRQY.js";
18
18
  import "./chunk-EGRHWZRV.js";
19
19
 
20
20
  // src/eslint-adapter.ts
package/dist/index.cjs CHANGED
@@ -180,7 +180,8 @@ var ServerSettingsSchema = import_v4.z.object({
180
180
  useESLintConfig: import_v4.z.boolean().default(true),
181
181
  eslintConfigPath: import_v4.z.string().optional(),
182
182
  accessibilityPolicy: AccessibilityPolicySchema.default("wcag-aa"),
183
- exclude: import_v4.z.array(import_v4.z.string()).default([])
183
+ exclude: import_v4.z.array(import_v4.z.string()).default([]),
184
+ enableTypeScriptDiagnostics: import_v4.z.boolean().default(false)
184
185
  });
185
186
  var isBun = typeof globalThis.Bun !== "undefined";
186
187
  var CHAR_FOLD_BIT = 32;
@@ -8748,10 +8749,17 @@ function wireJSXHierarchy(graph) {
8748
8749
  }
8749
8750
  function findParentJSXNode(node) {
8750
8751
  let current = node.parent;
8752
+ let crossedFunctionBoundary = false;
8751
8753
  while (current) {
8752
8754
  if (import_typescript29.default.isJsxElement(current) || import_typescript29.default.isJsxFragment(current)) {
8753
8755
  return current;
8754
8756
  }
8757
+ if (import_typescript29.default.isArrowFunction(current) || import_typescript29.default.isFunctionExpression(current)) {
8758
+ crossedFunctionBoundary = true;
8759
+ }
8760
+ if (crossedFunctionBoundary && import_typescript29.default.isJsxAttribute(current)) {
8761
+ return null;
8762
+ }
8755
8763
  current = current.parent;
8756
8764
  }
8757
8765
  return null;
@@ -30905,7 +30913,8 @@ var layoutSignalNames = [
30905
30913
  "inset-block-start",
30906
30914
  "inset-block-end",
30907
30915
  "writing-mode",
30908
- "direction"
30916
+ "direction",
30917
+ "contain"
30909
30918
  ];
30910
30919
 
30911
30920
  // src/cross-file/layout/offset-baseline.ts
@@ -32538,6 +32547,7 @@ function findNodeModulesPackage(importerFile, packageName) {
32538
32547
  }
32539
32548
 
32540
32549
  // src/cross-file/layout/scope.ts
32550
+ var CSS_COLOCATED_EXTENSIONS = [".css"];
32541
32551
  function collectCSSScopeBySolidFile(solids, css, moduleResolver) {
32542
32552
  const resolver = moduleResolver ?? createLayoutModuleResolver(solids, css);
32543
32553
  const cssFilesByNormalizedPath = buildCSSFileIndex(css);
@@ -32548,6 +32558,20 @@ function collectCSSScopeBySolidFile(solids, css, moduleResolver) {
32548
32558
  const solid = solids[i];
32549
32559
  if (!solid) continue;
32550
32560
  const scope = /* @__PURE__ */ new Set();
32561
+ const colocatedCssPath = resolveColocatedCss(solid.file, cssFilesByNormalizedPath);
32562
+ if (colocatedCssPath !== null) {
32563
+ const colocatedScope = getOrCollectTransitiveScope(
32564
+ colocatedCssPath,
32565
+ resolver,
32566
+ cssFilesByNormalizedPath,
32567
+ transitiveScopeByEntryPath
32568
+ );
32569
+ for (let k = 0; k < colocatedScope.length; k++) {
32570
+ const cs = colocatedScope[k];
32571
+ if (!cs) continue;
32572
+ scope.add(cs);
32573
+ }
32574
+ }
32551
32575
  for (let j = 0; j < solid.imports.length; j++) {
32552
32576
  const imp = solid.imports[j];
32553
32577
  if (!imp) continue;
@@ -32590,6 +32614,18 @@ function collectCSSScopeBySolidFile(solids, css, moduleResolver) {
32590
32614
  }
32591
32615
  return out;
32592
32616
  }
32617
+ function resolveColocatedCss(solidFilePath, cssFilesByNormalizedPath) {
32618
+ const dotIndex = solidFilePath.lastIndexOf(".");
32619
+ if (dotIndex === -1) return null;
32620
+ const stem = solidFilePath.slice(0, dotIndex);
32621
+ for (let i = 0; i < CSS_COLOCATED_EXTENSIONS.length; i++) {
32622
+ const ext = CSS_COLOCATED_EXTENSIONS[i];
32623
+ if (!ext) continue;
32624
+ const candidate = canonicalPath(stem + ext);
32625
+ if (cssFilesByNormalizedPath.has(candidate)) return candidate;
32626
+ }
32627
+ return null;
32628
+ }
32593
32629
  function buildCSSFileIndex(css) {
32594
32630
  const out = /* @__PURE__ */ new Map();
32595
32631
  for (let i = 0; i < css.files.length; i++) {
@@ -33914,73 +33950,108 @@ function compoundGroupNeedsAttributes(groups) {
33914
33950
  }
33915
33951
  function selectorMatchesLayoutElement(matcher, node, perf, fileRootElements = null, logger = noopLogger) {
33916
33952
  const firstCompound = matcher.compoundsRightToLeft[0];
33917
- if (firstCompound === void 0) return false;
33918
- if (!matchesCompound(node, firstCompound)) return false;
33919
- if (matcher.compoundsRightToLeft.length === 1) return true;
33920
- return matchesChain(matcher, node, 0, perf, fileRootElements, logger);
33953
+ if (firstCompound === void 0) return "no-match";
33954
+ const subjectResult = matchesCompound(node, firstCompound);
33955
+ if (subjectResult === "no-match") return "no-match";
33956
+ if (matcher.compoundsRightToLeft.length === 1) return subjectResult;
33957
+ const chainResult = matchesChain(matcher, node, 0, perf, fileRootElements, logger);
33958
+ if (chainResult === "no-match") return "no-match";
33959
+ if (subjectResult === "conditional" || chainResult === "conditional") return "conditional";
33960
+ return "match";
33921
33961
  }
33922
33962
  function matchesChain(matcher, node, index, perf, fileRootElements, logger) {
33923
33963
  const combinator = matcher.combinatorsRightToLeft[index];
33924
- if (combinator === void 0) return false;
33964
+ if (combinator === void 0) return "no-match";
33925
33965
  const nextIndex = index + 1;
33926
33966
  const targetCompound = matcher.compoundsRightToLeft[nextIndex];
33927
- if (targetCompound === void 0) return false;
33967
+ if (targetCompound === void 0) return "no-match";
33928
33968
  const isFinal = nextIndex === matcher.compoundsRightToLeft.length - 1;
33929
33969
  if (combinator === "child") {
33930
33970
  const parent = node.parentElementNode;
33931
- if (parent === null) return false;
33971
+ if (parent === null) return "no-match";
33932
33972
  perf.ancestryChecks++;
33933
- if (!matchesCompound(parent, targetCompound)) return false;
33934
- if (isFinal) return true;
33935
- return matchesChain(matcher, parent, nextIndex, perf, fileRootElements, logger);
33973
+ const compoundResult = matchesCompound(parent, targetCompound);
33974
+ if (compoundResult === "no-match") return "no-match";
33975
+ if (isFinal) return compoundResult;
33976
+ const chainResult = matchesChain(matcher, parent, nextIndex, perf, fileRootElements, logger);
33977
+ return mergeMatchResults(compoundResult, chainResult);
33936
33978
  }
33937
33979
  if (combinator === "adjacent") {
33938
33980
  const sibling = node.previousSiblingNode;
33939
- if (sibling === null) return false;
33981
+ if (sibling === null) return "no-match";
33940
33982
  perf.ancestryChecks++;
33941
- if (!matchesCompound(sibling, targetCompound)) return false;
33942
- if (isFinal) return true;
33943
- return matchesChain(matcher, sibling, nextIndex, perf, fileRootElements, logger);
33983
+ const compoundResult = matchesCompound(sibling, targetCompound);
33984
+ if (compoundResult === "no-match") return "no-match";
33985
+ if (isFinal) return compoundResult;
33986
+ const chainResult = matchesChain(matcher, sibling, nextIndex, perf, fileRootElements, logger);
33987
+ return mergeMatchResults(compoundResult, chainResult);
33944
33988
  }
33945
33989
  if (combinator === "sibling") {
33946
33990
  let sibling = node.previousSiblingNode;
33947
33991
  while (sibling !== null) {
33948
33992
  perf.ancestryChecks++;
33949
- if (matchesCompound(sibling, targetCompound)) {
33950
- if (isFinal) return true;
33951
- if (matchesChain(matcher, sibling, nextIndex, perf, fileRootElements, logger)) return true;
33993
+ const compoundResult = matchesCompound(sibling, targetCompound);
33994
+ if (compoundResult !== "no-match") {
33995
+ if (isFinal) return compoundResult;
33996
+ const chainResult = matchesChain(matcher, sibling, nextIndex, perf, fileRootElements, logger);
33997
+ if (chainResult !== "no-match") return mergeMatchResults(compoundResult, chainResult);
33952
33998
  }
33953
33999
  sibling = sibling.previousSiblingNode;
33954
34000
  }
33955
- return false;
34001
+ return "no-match";
33956
34002
  }
34003
+ let bestResult = "no-match";
33957
34004
  let ancestor = node.parentElementNode;
33958
34005
  while (ancestor !== null) {
33959
34006
  perf.ancestryChecks++;
33960
- if (matchesCompound(ancestor, targetCompound)) {
33961
- if (isFinal) return true;
33962
- if (matchesChain(matcher, ancestor, nextIndex, perf, fileRootElements, logger)) return true;
34007
+ const compoundResult = matchesCompound(ancestor, targetCompound);
34008
+ if (compoundResult !== "no-match") {
34009
+ if (isFinal) return compoundResult;
34010
+ const chainResult = matchesChain(matcher, ancestor, nextIndex, perf, fileRootElements, logger);
34011
+ if (chainResult !== "no-match") {
34012
+ const merged = mergeMatchResults(compoundResult, chainResult);
34013
+ if (merged === "match") return "match";
34014
+ bestResult = merged;
34015
+ }
33963
34016
  }
33964
34017
  ancestor = ancestor.parentElementNode;
33965
34018
  }
33966
34019
  if (fileRootElements !== null) {
34020
+ if (logger.enabled) {
34021
+ const compoundDesc = describeCompound(targetCompound);
34022
+ logger.trace(`[selector-match] fallback: node=${node.key} tag=${node.tagName} checking ${fileRootElements.length} roots for compound=${compoundDesc}`);
34023
+ }
33967
34024
  for (let r = 0; r < fileRootElements.length; r++) {
33968
34025
  const root = fileRootElements[r];
33969
34026
  if (root === void 0) continue;
33970
34027
  if (root === node) continue;
33971
34028
  if (root.solidFile !== node.solidFile) continue;
33972
34029
  perf.ancestryChecks++;
33973
- if (matchesCompound(root, targetCompound)) {
34030
+ const compoundResult = matchesCompound(root, targetCompound);
34031
+ if (logger.enabled && compoundResult === "no-match") {
34032
+ logger.trace(`[selector-match] fallback MISS: root=${root.key} tag=${root.tagName} attrs=[${[...root.attributes.entries()].map(([k, v]) => `${k}=${v}`).join(",")}]`);
34033
+ }
34034
+ if (compoundResult !== "no-match") {
33974
34035
  if (logger.enabled) {
33975
34036
  const compoundDesc = describeCompound(targetCompound);
33976
34037
  logger.debug(`[selector-match] fallback HIT: node=${node.key} tag=${node.tagName} matched root=${root.key} tag=${root.tagName} compound=${compoundDesc} isFinal=${isFinal}`);
33977
34038
  }
33978
- if (isFinal) return true;
33979
- if (matchesChain(matcher, root, nextIndex, perf, fileRootElements, logger)) return true;
34039
+ if (isFinal) return compoundResult;
34040
+ const chainResult = matchesChain(matcher, root, nextIndex, perf, fileRootElements, logger);
34041
+ if (chainResult !== "no-match") {
34042
+ const merged = mergeMatchResults(compoundResult, chainResult);
34043
+ if (merged === "match") return "match";
34044
+ bestResult = merged;
34045
+ }
33980
34046
  }
33981
34047
  }
33982
34048
  }
33983
- return false;
34049
+ return bestResult;
34050
+ }
34051
+ function mergeMatchResults(a, b) {
34052
+ if (a === "no-match" || b === "no-match") return "no-match";
34053
+ if (a === "conditional" || b === "conditional") return "conditional";
34054
+ return "match";
33984
34055
  }
33985
34056
  function describeCompound(compound) {
33986
34057
  const parts = [];
@@ -34000,15 +34071,16 @@ function describeCompound(compound) {
34000
34071
  return parts.join("") || "*";
34001
34072
  }
34002
34073
  function matchesCompound(node, compound) {
34003
- if (compound.tagName !== null && node.tagName !== compound.tagName) return false;
34074
+ if (compound.tagName !== null && node.tagName !== compound.tagName) return "no-match";
34004
34075
  if (compound.idValue !== null) {
34005
34076
  const id = node.attributes.get("id");
34006
- if (id !== compound.idValue) return false;
34077
+ if (id !== compound.idValue) return "no-match";
34007
34078
  }
34008
- if (!matchesRequiredClasses(compound.classes, node.classTokenSet)) return false;
34009
- if (!matchesRequiredAttributes(compound.attributes, node.attributes)) return false;
34010
- if (!matchesPseudoConstraints(node, compound.pseudo)) return false;
34011
- return true;
34079
+ if (!matchesRequiredClasses(compound.classes, node.classTokenSet)) return "no-match";
34080
+ const attrResult = matchesRequiredAttributes(compound.attributes, node.attributes);
34081
+ if (attrResult === "no-match") return "no-match";
34082
+ if (!matchesPseudoConstraints(node, compound.pseudo)) return "no-match";
34083
+ return attrResult;
34012
34084
  }
34013
34085
  function matchesPseudoConstraints(node, pseudo) {
34014
34086
  if (pseudo.firstChild && node.siblingIndex !== 1) return false;
@@ -34033,7 +34105,7 @@ function matchesPseudoConstraints(node, pseudo) {
34033
34105
  for (let j = 0; j < group.length; j++) {
34034
34106
  const compound = group[j];
34035
34107
  if (compound === void 0) continue;
34036
- if (!matchesCompound(node, compound)) continue;
34108
+ if (matchesCompound(node, compound) === "no-match") continue;
34037
34109
  matched = true;
34038
34110
  break;
34039
34111
  }
@@ -34045,7 +34117,7 @@ function matchesPseudoConstraints(node, pseudo) {
34045
34117
  for (let j = 0; j < group.length; j++) {
34046
34118
  const compound = group[j];
34047
34119
  if (compound === void 0) continue;
34048
- if (!matchesCompound(node, compound)) continue;
34120
+ if (matchesCompound(node, compound) === "no-match") continue;
34049
34121
  return false;
34050
34122
  }
34051
34123
  }
@@ -34690,19 +34762,24 @@ function matchesRequiredClasses(required, actual) {
34690
34762
  return true;
34691
34763
  }
34692
34764
  function matchesRequiredAttributes(required, actual) {
34693
- if (required.length === 0) return true;
34765
+ if (required.length === 0) return "match";
34766
+ let hasConditional = false;
34694
34767
  for (let i = 0; i < required.length; i++) {
34695
34768
  const constraint = required[i];
34696
34769
  if (constraint === void 0) continue;
34697
- if (!actual.has(constraint.name)) return false;
34770
+ if (!actual.has(constraint.name)) return "no-match";
34698
34771
  if (constraint.operator === "exists") continue;
34699
34772
  const actualValue = actual.get(constraint.name);
34700
- if (actualValue === null || actualValue === void 0) return false;
34701
- if (constraint.value === null) return false;
34773
+ if (actualValue === void 0) return "no-match";
34774
+ if (actualValue === null) {
34775
+ hasConditional = true;
34776
+ continue;
34777
+ }
34778
+ if (constraint.value === null) return "no-match";
34702
34779
  if (matchesAttributeValue(actualValue, constraint)) continue;
34703
- return false;
34780
+ return "no-match";
34704
34781
  }
34705
- return true;
34782
+ return hasConditional ? "conditional" : "match";
34706
34783
  }
34707
34784
  function matchesAttributeValue(actualValue, constraint) {
34708
34785
  const expectedValue = constraint.value;
@@ -37068,6 +37145,11 @@ function compareCascadePositions(posA, posB) {
37068
37145
  }
37069
37146
 
37070
37147
  // src/cross-file/layout/cascade-builder.ts
37148
+ var DYNAMIC_ATTRIBUTE_GUARD = {
37149
+ kind: 1 /* Conditional */,
37150
+ conditions: [{ kind: "dynamic-attribute", query: null, key: "dynamic-attribute:*" }],
37151
+ key: "dynamic-attribute:*"
37152
+ };
37071
37153
  var SCROLLABLE_VALUES = /* @__PURE__ */ new Set(["auto", "scroll"]);
37072
37154
  var EMPTY_EXPANSION_RESULT = [];
37073
37155
  function collectMonitoredDeclarations(selector, layerOrder, guard) {
@@ -37142,14 +37224,21 @@ function appendMatchingEdgesFromSelectorIds(ctx, selectorIds, node, applies, app
37142
37224
  if (!selector) {
37143
37225
  throw new Error(`missing selector ${selectorId}`);
37144
37226
  }
37145
- if (!selectorMatchesLayoutElement(metadata.matcher, node, ctx.perf, fileRoots, ctx.logger)) continue;
37227
+ const matchResult = selectorMatchesLayoutElement(metadata.matcher, node, ctx.perf, fileRoots, ctx.logger);
37228
+ if (matchResult === "no-match") continue;
37146
37229
  const edge = {
37147
37230
  selectorId: selector.id,
37148
37231
  specificityScore: selector.specificityScore,
37149
- sourceOrder: selector.rule.sourceOrder
37232
+ sourceOrder: selector.rule.sourceOrder,
37233
+ conditionalMatch: matchResult === "conditional"
37150
37234
  };
37151
37235
  applies.push(edge);
37152
37236
  ctx.perf.matchEdgesCreated++;
37237
+ if (ctx.logger.enabled) {
37238
+ ctx.logger.trace(
37239
+ `[cascade] edge node=${node.key} selector=${selector.id} match=${matchResult} conditional=${edge.conditionalMatch} selector-raw=${selector.raw.slice(0, 80)}`
37240
+ );
37241
+ }
37153
37242
  const existing = appliesByElementNodeMutable.get(node);
37154
37243
  if (existing) {
37155
37244
  existing.push(edge);
@@ -37210,10 +37299,11 @@ function buildCascadeMapForElement(node, edges, monitoredDeclarationsBySelectorI
37210
37299
  const declaration = declarations[j];
37211
37300
  if (!declaration) continue;
37212
37301
  const property = declaration.property;
37302
+ const guardProvenance = edge.conditionalMatch && declaration.guardProvenance.kind === 0 /* Unconditional */ ? DYNAMIC_ATTRIBUTE_GUARD : declaration.guardProvenance;
37213
37303
  const newDeclaration = {
37214
37304
  value: declaration.value,
37215
37305
  source: 0 /* Selector */,
37216
- guardProvenance: declaration.guardProvenance
37306
+ guardProvenance
37217
37307
  };
37218
37308
  const existingPosition = positions.get(property);
37219
37309
  if (existingPosition === void 0) {
@@ -37295,7 +37385,7 @@ function resolveRuleLayerOrder(rule, css) {
37295
37385
  if (!name) return 0;
37296
37386
  return css.layerOrder.get(name) ?? 0;
37297
37387
  }
37298
- function buildConditionalDeltaIndex(elements, appliesByNode, monitoredDeclarationsBySelectorId) {
37388
+ function buildConditionalDeltaIndex(elements, appliesByNode, monitoredDeclarationsBySelectorId, selectorsById) {
37299
37389
  const conditionalSignalDeltaFactsByNode = /* @__PURE__ */ new Map();
37300
37390
  const elementsWithConditionalDeltaBySignal = /* @__PURE__ */ new Map();
37301
37391
  const baselineOffsetFactsByNode = /* @__PURE__ */ new Map();
@@ -37306,11 +37396,16 @@ function buildConditionalDeltaIndex(elements, appliesByNode, monitoredDeclaratio
37306
37396
  let factByProperty = null;
37307
37397
  if (edges !== void 0 && edges.length > 0) {
37308
37398
  const byProperty = /* @__PURE__ */ new Map();
37399
+ let conditionalAttributeDispatch = null;
37309
37400
  for (let j = 0; j < edges.length; j++) {
37310
37401
  const currentEdge = edges[j];
37311
37402
  if (!currentEdge) continue;
37312
37403
  const declarations = monitoredDeclarationsBySelectorId.get(currentEdge.selectorId);
37313
37404
  if (!declarations) continue;
37405
+ let conditionalAttributeName = null;
37406
+ if (currentEdge.conditionalMatch) {
37407
+ conditionalAttributeName = identifyConditionalAttribute(currentEdge.selectorId, node, selectorsById);
37408
+ }
37314
37409
  for (let k = 0; k < declarations.length; k++) {
37315
37410
  const declaration = declarations[k];
37316
37411
  if (!declaration) continue;
@@ -37327,8 +37422,17 @@ function buildConditionalDeltaIndex(elements, appliesByNode, monitoredDeclaratio
37327
37422
  };
37328
37423
  byProperty.set(property, bucket);
37329
37424
  }
37330
- if (declaration.guardProvenance.kind === 1 /* Conditional */) {
37425
+ if (declaration.guardProvenance.kind === 1 /* Conditional */ || currentEdge.conditionalMatch) {
37331
37426
  bucket.conditional.add(expandedEntry.value);
37427
+ if (conditionalAttributeName !== null && declaration.guardProvenance.kind !== 1 /* Conditional */) {
37428
+ if (conditionalAttributeDispatch === null) conditionalAttributeDispatch = /* @__PURE__ */ new Map();
37429
+ let dispatchMap = conditionalAttributeDispatch.get(property);
37430
+ if (!dispatchMap) {
37431
+ dispatchMap = /* @__PURE__ */ new Map();
37432
+ conditionalAttributeDispatch.set(property, dispatchMap);
37433
+ }
37434
+ dispatchMap.set(expandedEntry.value, conditionalAttributeName);
37435
+ }
37332
37436
  continue;
37333
37437
  }
37334
37438
  bucket.unconditional.add(expandedEntry.value);
@@ -37353,6 +37457,24 @@ function buildConditionalDeltaIndex(elements, appliesByNode, monitoredDeclaratio
37353
37457
  }
37354
37458
  }
37355
37459
  }
37460
+ if (hasDelta && conditionalAttributeDispatch !== null) {
37461
+ const dispatchMap = conditionalAttributeDispatch.get(property);
37462
+ if (dispatchMap !== void 0 && dispatchMap.size === conditionalValues.length) {
37463
+ let singleAttribute = null;
37464
+ let allSameAttribute = true;
37465
+ for (const attrName of dispatchMap.values()) {
37466
+ if (singleAttribute === null) {
37467
+ singleAttribute = attrName;
37468
+ } else if (singleAttribute !== attrName) {
37469
+ allSameAttribute = false;
37470
+ break;
37471
+ }
37472
+ }
37473
+ if (allSameAttribute && singleAttribute !== null) {
37474
+ hasDelta = false;
37475
+ }
37476
+ }
37477
+ }
37356
37478
  const scrollProfile = buildScrollValueProfile(property, conditionalValues, unconditionalValues);
37357
37479
  facts.set(property, {
37358
37480
  hasConditional,
@@ -37438,6 +37560,25 @@ function buildConditionalDeltaSignalGroupElements(elementsWithConditionalDeltaBy
37438
37560
  }
37439
37561
  return out;
37440
37562
  }
37563
+ function identifyConditionalAttribute(selectorId, node, selectorsById) {
37564
+ const selector = selectorsById.get(selectorId);
37565
+ if (!selector) return null;
37566
+ const constraints = selector.anchor.attributes;
37567
+ let dynamicAttributeName = null;
37568
+ for (let i = 0; i < constraints.length; i++) {
37569
+ const constraint = constraints[i];
37570
+ if (!constraint) continue;
37571
+ if (constraint.operator !== "equals") continue;
37572
+ if (constraint.value === null) continue;
37573
+ const elementValue = node.attributes.get(constraint.name);
37574
+ if (elementValue !== null) continue;
37575
+ if (dynamicAttributeName !== null && dynamicAttributeName !== constraint.name) {
37576
+ return null;
37577
+ }
37578
+ dynamicAttributeName = constraint.name;
37579
+ }
37580
+ return dynamicAttributeName;
37581
+ }
37441
37582
  function buildScrollValueProfile(property, conditionalValues, unconditionalValues) {
37442
37583
  if (property !== "overflow" && property !== "overflow-y") {
37443
37584
  return {
@@ -37819,6 +37960,23 @@ function buildLayoutGraph(solids, css, logger = noopLogger) {
37819
37960
  const moduleResolver = createLayoutModuleResolver(solids, css);
37820
37961
  const componentHostResolver = createLayoutComponentHostResolver(solids, moduleResolver, logger);
37821
37962
  const cssScopeBySolidFile = collectCSSScopeBySolidFile(solids, css, moduleResolver);
37963
+ if (logger.enabled) {
37964
+ for (const [solidFile, scopePaths] of cssScopeBySolidFile) {
37965
+ if (scopePaths.length > 0) {
37966
+ let names = "";
37967
+ for (let k = 0; k < scopePaths.length; k++) {
37968
+ const p = scopePaths[k];
37969
+ if (!p) continue;
37970
+ if (names.length > 0) names += ", ";
37971
+ const slash = p.lastIndexOf("/");
37972
+ names += slash === -1 ? p : p.slice(slash + 1);
37973
+ }
37974
+ logger.trace(`[scope] ${solidFile} \u2192 ${scopePaths.length} CSS files: ${names}`);
37975
+ } else {
37976
+ logger.trace(`[scope] ${solidFile} \u2192 EMPTY (no CSS in scope)`);
37977
+ }
37978
+ }
37979
+ }
37822
37980
  const selectorIndexStartedAt = performance.now();
37823
37981
  const scopedSelectorsBySolidFile = buildScopedSelectorIndexBySolidFile(
37824
37982
  cssScopeBySolidFile,
@@ -37961,13 +38119,30 @@ function buildLayoutGraph(solids, css, logger = noopLogger) {
37961
38119
  appliesByNode.set(node, edges);
37962
38120
  }
37963
38121
  perf.cascadeBuildMs = performance.now() - cascadeStartedAt;
38122
+ if (logger.enabled) {
38123
+ for (let i = 0; i < elements.length; i++) {
38124
+ const node = elements[i];
38125
+ if (!node) continue;
38126
+ const cascade = cascadeByElementNode.get(node);
38127
+ if (!cascade || cascade.size === 0) continue;
38128
+ const displayDecl = cascade.get("display");
38129
+ const flexDirDecl = cascade.get("flex-direction");
38130
+ if (!displayDecl && !flexDirDecl) continue;
38131
+ const displayGuard = displayDecl?.guardProvenance.kind === 1 /* Conditional */ ? "conditional" : "unconditional";
38132
+ const flexDirGuard = flexDirDecl?.guardProvenance.kind === 1 /* Conditional */ ? "conditional" : "unconditional";
38133
+ logger.trace(
38134
+ `[cascade] node=${node.key} tag=${node.tagName ?? "null"} display=${displayDecl ? `${displayDecl.value}(${displayGuard})` : "absent"} flex-direction=${flexDirDecl ? `${flexDirDecl.value}(${flexDirGuard})` : "absent"} edges=${(appliesByNode.get(node) ?? []).length} attrs=[${[...node.attributes.keys()].join(",")}]`
38135
+ );
38136
+ }
38137
+ }
37964
38138
  const snapshotByElementNode = buildSignalSnapshotIndex(elements, cascadeByElementNode, perf);
37965
38139
  const measurementNodeByRootKey = buildMeasurementNodeIndex(elements, childrenByParentNodeMutable, snapshotByElementNode);
37966
38140
  const factIndex = buildElementFactIndex(elements, snapshotByElementNode);
37967
38141
  const conditionalDeltaIndex = buildConditionalDeltaIndex(
37968
38142
  elements,
37969
38143
  appliesByNode,
37970
- monitoredDeclarationsBySelectorId
38144
+ monitoredDeclarationsBySelectorId,
38145
+ selectorsById
37971
38146
  );
37972
38147
  const elementsWithConditionalOverflowDelta = buildConditionalDeltaSignalGroupElements(
37973
38148
  conditionalDeltaIndex.elementsWithConditionalDeltaBySignal,
@@ -37978,7 +38153,7 @@ function buildLayoutGraph(solids, css, logger = noopLogger) {
37978
38153
  layoutOffsetSignals
37979
38154
  );
37980
38155
  const statefulRuleIndexes = buildStatefulRuleIndexes(css.rules);
37981
- const contextByParentNode = buildContextIndex(childrenByParentNodeMutable, snapshotByElementNode, perf);
38156
+ const contextByParentNode = buildContextIndex(childrenByParentNodeMutable, snapshotByElementNode, perf, logger);
37982
38157
  const cohortIndex = buildCohortIndex({
37983
38158
  childrenByParentNode: childrenByParentNodeMutable,
37984
38159
  contextByParentNode,
@@ -38398,16 +38573,27 @@ function computeFlowParticipationFact(snapshot) {
38398
38573
  hasUnconditionalOutOfFlow: signal.guard.kind === 0 /* Unconditional */ && outOfFlow
38399
38574
  };
38400
38575
  }
38401
- function buildContextIndex(childrenByParentNode, snapshotByElementNode, perf) {
38576
+ function buildContextIndex(childrenByParentNode, snapshotByElementNode, perf, logger) {
38402
38577
  const out = /* @__PURE__ */ new Map();
38578
+ const trace = logger.enabled;
38403
38579
  for (const [parent, children] of childrenByParentNode) {
38404
38580
  if (children.length < 2) continue;
38405
38581
  const snapshot = snapshotByElementNode.get(parent);
38406
38582
  if (!snapshot) {
38407
38583
  throw new Error(`missing parent snapshot for context classification ${parent.key}`);
38408
38584
  }
38409
- out.set(parent, createAlignmentContextForParent(parent, snapshot));
38585
+ const ctx = createAlignmentContextForParent(parent, snapshot);
38586
+ out.set(parent, ctx);
38410
38587
  perf.contextsClassified++;
38588
+ if (trace) {
38589
+ const displaySignal = snapshot.signals.get("display");
38590
+ const flexDirSignal = snapshot.signals.get("flex-direction");
38591
+ const displayDesc = displaySignal ? `${displaySignal.kind}:${displaySignal.kind === "known" ? displaySignal.normalized : "?"}(guard=${displaySignal.guard.kind === 1 /* Conditional */ ? "conditional" : "unconditional"})` : "absent";
38592
+ const flexDirDesc = flexDirSignal ? `${flexDirSignal.kind}:${flexDirSignal.kind === "known" ? flexDirSignal.normalized : "?"}(guard=${flexDirSignal.guard.kind === 1 /* Conditional */ ? "conditional" : "unconditional"})` : "absent";
38593
+ logger.trace(
38594
+ `[context] parent=${parent.key} tag=${parent.tagName ?? "null"} children=${children.length} display=${displayDesc} flex-direction=${flexDirDesc} \u2192 kind=${ctx.kind} certainty=${ctx.certainty} crossAxisIsBlockAxis=${ctx.crossAxisIsBlockAxis} baseline=${ctx.baselineRelevance}`
38595
+ );
38596
+ }
38411
38597
  }
38412
38598
  return out;
38413
38599
  }
@@ -39895,7 +40081,13 @@ var MIN_OFFSET_PX_THRESHOLD = 2;
39895
40081
  var siblingAlignmentDetector = {
39896
40082
  id: "sibling-alignment-outlier",
39897
40083
  collect: collectAlignmentCases,
39898
- evaluate(input) {
40084
+ evaluate(input, context) {
40085
+ if (context.logger.enabled) {
40086
+ const ctx = input.context;
40087
+ context.logger.trace(
40088
+ `[sibling-alignment] evaluate subject=${input.subject.elementKey} tag=${input.subject.tag} parent=${ctx.parentElementKey} parentTag=${ctx.parentTag} context.kind=${ctx.kind} certainty=${ctx.certainty} display=${ctx.parentDisplay} alignItems=${ctx.parentAlignItems} crossAxisIsBlockAxis=${ctx.crossAxisIsBlockAxis} crossAxisCertainty=${ctx.crossAxisIsBlockAxisCertainty} baseline=${ctx.baselineRelevance}`
40089
+ );
40090
+ }
39899
40091
  const decision = evaluateAlignmentCase(input);
39900
40092
  if (decision.kind === "reject") {
39901
40093
  return {
@@ -41013,8 +41205,16 @@ function isExemptFromCLS(layout, solidFile, element, property) {
41013
41205
  if (POSITIONED_OFFSET_PROPERTIES.has(property) && flowFact.position !== null && flowFact.position !== "static") {
41014
41206
  return true;
41015
41207
  }
41208
+ if (hasLayoutContainment(node) || node.parentElementNode !== null && hasLayoutContainment(node.parentElementNode)) {
41209
+ return true;
41210
+ }
41016
41211
  return false;
41017
41212
  }
41213
+ function hasLayoutContainment(node) {
41214
+ const contain = node.inlineStyleValues.get("contain");
41215
+ if (contain === void 0) return false;
41216
+ return contain === "layout" || contain === "strict" || contain === "content" || contain.includes("layout");
41217
+ }
41018
41218
  function hasUnstableLayoutDelta(property, node) {
41019
41219
  const unwrapped = unwrapTypeWrapper(node);
41020
41220
  if (isStaticComparable(property, unwrapped)) return false;