@drskillissue/ganko 0.2.1 → 0.2.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.
@@ -96,7 +96,8 @@ var ServerSettingsSchema = z.object({
96
96
  useESLintConfig: z.boolean().default(true),
97
97
  eslintConfigPath: z.string().optional(),
98
98
  accessibilityPolicy: AccessibilityPolicySchema.default("wcag-aa"),
99
- exclude: z.array(z.string()).default([])
99
+ exclude: z.array(z.string()).default([]),
100
+ enableTypeScriptDiagnostics: z.boolean().default(false)
100
101
  });
101
102
  var isBun = typeof globalThis.Bun !== "undefined";
102
103
  var CHAR_FOLD_BIT = 32;
@@ -21868,10 +21869,17 @@ function wireJSXHierarchy(graph) {
21868
21869
  }
21869
21870
  function findParentJSXNode(node) {
21870
21871
  let current = node.parent;
21872
+ let crossedFunctionBoundary = false;
21871
21873
  while (current) {
21872
21874
  if (ts119.isJsxElement(current) || ts119.isJsxFragment(current)) {
21873
21875
  return current;
21874
21876
  }
21877
+ if (ts119.isArrowFunction(current) || ts119.isFunctionExpression(current)) {
21878
+ crossedFunctionBoundary = true;
21879
+ }
21880
+ if (crossedFunctionBoundary && ts119.isJsxAttribute(current)) {
21881
+ return null;
21882
+ }
21875
21883
  current = current.parent;
21876
21884
  }
21877
21885
  return null;
@@ -30787,6 +30795,7 @@ function findNodeModulesPackage(importerFile, packageName) {
30787
30795
  }
30788
30796
 
30789
30797
  // src/cross-file/layout/scope.ts
30798
+ var CSS_COLOCATED_EXTENSIONS = [".css"];
30790
30799
  function collectCSSScopeBySolidFile(solids, css, moduleResolver) {
30791
30800
  const resolver = moduleResolver ?? createLayoutModuleResolver(solids, css);
30792
30801
  const cssFilesByNormalizedPath = buildCSSFileIndex(css);
@@ -30797,6 +30806,20 @@ function collectCSSScopeBySolidFile(solids, css, moduleResolver) {
30797
30806
  const solid = solids[i];
30798
30807
  if (!solid) continue;
30799
30808
  const scope = /* @__PURE__ */ new Set();
30809
+ const colocatedCssPath = resolveColocatedCss(solid.file, cssFilesByNormalizedPath);
30810
+ if (colocatedCssPath !== null) {
30811
+ const colocatedScope = getOrCollectTransitiveScope(
30812
+ colocatedCssPath,
30813
+ resolver,
30814
+ cssFilesByNormalizedPath,
30815
+ transitiveScopeByEntryPath
30816
+ );
30817
+ for (let k = 0; k < colocatedScope.length; k++) {
30818
+ const cs = colocatedScope[k];
30819
+ if (!cs) continue;
30820
+ scope.add(cs);
30821
+ }
30822
+ }
30800
30823
  for (let j = 0; j < solid.imports.length; j++) {
30801
30824
  const imp = solid.imports[j];
30802
30825
  if (!imp) continue;
@@ -30839,6 +30862,18 @@ function collectCSSScopeBySolidFile(solids, css, moduleResolver) {
30839
30862
  }
30840
30863
  return out;
30841
30864
  }
30865
+ function resolveColocatedCss(solidFilePath, cssFilesByNormalizedPath) {
30866
+ const dotIndex = solidFilePath.lastIndexOf(".");
30867
+ if (dotIndex === -1) return null;
30868
+ const stem = solidFilePath.slice(0, dotIndex);
30869
+ for (let i = 0; i < CSS_COLOCATED_EXTENSIONS.length; i++) {
30870
+ const ext = CSS_COLOCATED_EXTENSIONS[i];
30871
+ if (!ext) continue;
30872
+ const candidate = canonicalPath(stem + ext);
30873
+ if (cssFilesByNormalizedPath.has(candidate)) return candidate;
30874
+ }
30875
+ return null;
30876
+ }
30842
30877
  function buildCSSFileIndex(css) {
30843
30878
  const out = /* @__PURE__ */ new Map();
30844
30879
  for (let i = 0; i < css.files.length; i++) {
@@ -30929,7 +30964,8 @@ var layoutSignalNames = [
30929
30964
  "inset-block-start",
30930
30965
  "inset-block-end",
30931
30966
  "writing-mode",
30932
- "direction"
30967
+ "direction",
30968
+ "contain"
30933
30969
  ];
30934
30970
 
30935
30971
  // src/cross-file/layout/util.ts
@@ -32769,73 +32805,108 @@ function compoundGroupNeedsAttributes(groups) {
32769
32805
  }
32770
32806
  function selectorMatchesLayoutElement(matcher, node, perf, fileRootElements = null, logger = noopLogger) {
32771
32807
  const firstCompound = matcher.compoundsRightToLeft[0];
32772
- if (firstCompound === void 0) return false;
32773
- if (!matchesCompound(node, firstCompound)) return false;
32774
- if (matcher.compoundsRightToLeft.length === 1) return true;
32775
- return matchesChain(matcher, node, 0, perf, fileRootElements, logger);
32808
+ if (firstCompound === void 0) return "no-match";
32809
+ const subjectResult = matchesCompound(node, firstCompound);
32810
+ if (subjectResult === "no-match") return "no-match";
32811
+ if (matcher.compoundsRightToLeft.length === 1) return subjectResult;
32812
+ const chainResult = matchesChain(matcher, node, 0, perf, fileRootElements, logger);
32813
+ if (chainResult === "no-match") return "no-match";
32814
+ if (subjectResult === "conditional" || chainResult === "conditional") return "conditional";
32815
+ return "match";
32776
32816
  }
32777
32817
  function matchesChain(matcher, node, index, perf, fileRootElements, logger) {
32778
32818
  const combinator = matcher.combinatorsRightToLeft[index];
32779
- if (combinator === void 0) return false;
32819
+ if (combinator === void 0) return "no-match";
32780
32820
  const nextIndex = index + 1;
32781
32821
  const targetCompound = matcher.compoundsRightToLeft[nextIndex];
32782
- if (targetCompound === void 0) return false;
32822
+ if (targetCompound === void 0) return "no-match";
32783
32823
  const isFinal = nextIndex === matcher.compoundsRightToLeft.length - 1;
32784
32824
  if (combinator === "child") {
32785
32825
  const parent = node.parentElementNode;
32786
- if (parent === null) return false;
32826
+ if (parent === null) return "no-match";
32787
32827
  perf.ancestryChecks++;
32788
- if (!matchesCompound(parent, targetCompound)) return false;
32789
- if (isFinal) return true;
32790
- return matchesChain(matcher, parent, nextIndex, perf, fileRootElements, logger);
32828
+ const compoundResult = matchesCompound(parent, targetCompound);
32829
+ if (compoundResult === "no-match") return "no-match";
32830
+ if (isFinal) return compoundResult;
32831
+ const chainResult = matchesChain(matcher, parent, nextIndex, perf, fileRootElements, logger);
32832
+ return mergeMatchResults(compoundResult, chainResult);
32791
32833
  }
32792
32834
  if (combinator === "adjacent") {
32793
32835
  const sibling = node.previousSiblingNode;
32794
- if (sibling === null) return false;
32836
+ if (sibling === null) return "no-match";
32795
32837
  perf.ancestryChecks++;
32796
- if (!matchesCompound(sibling, targetCompound)) return false;
32797
- if (isFinal) return true;
32798
- return matchesChain(matcher, sibling, nextIndex, perf, fileRootElements, logger);
32838
+ const compoundResult = matchesCompound(sibling, targetCompound);
32839
+ if (compoundResult === "no-match") return "no-match";
32840
+ if (isFinal) return compoundResult;
32841
+ const chainResult = matchesChain(matcher, sibling, nextIndex, perf, fileRootElements, logger);
32842
+ return mergeMatchResults(compoundResult, chainResult);
32799
32843
  }
32800
32844
  if (combinator === "sibling") {
32801
32845
  let sibling = node.previousSiblingNode;
32802
32846
  while (sibling !== null) {
32803
32847
  perf.ancestryChecks++;
32804
- if (matchesCompound(sibling, targetCompound)) {
32805
- if (isFinal) return true;
32806
- if (matchesChain(matcher, sibling, nextIndex, perf, fileRootElements, logger)) return true;
32848
+ const compoundResult = matchesCompound(sibling, targetCompound);
32849
+ if (compoundResult !== "no-match") {
32850
+ if (isFinal) return compoundResult;
32851
+ const chainResult = matchesChain(matcher, sibling, nextIndex, perf, fileRootElements, logger);
32852
+ if (chainResult !== "no-match") return mergeMatchResults(compoundResult, chainResult);
32807
32853
  }
32808
32854
  sibling = sibling.previousSiblingNode;
32809
32855
  }
32810
- return false;
32856
+ return "no-match";
32811
32857
  }
32858
+ let bestResult = "no-match";
32812
32859
  let ancestor = node.parentElementNode;
32813
32860
  while (ancestor !== null) {
32814
32861
  perf.ancestryChecks++;
32815
- if (matchesCompound(ancestor, targetCompound)) {
32816
- if (isFinal) return true;
32817
- if (matchesChain(matcher, ancestor, nextIndex, perf, fileRootElements, logger)) return true;
32862
+ const compoundResult = matchesCompound(ancestor, targetCompound);
32863
+ if (compoundResult !== "no-match") {
32864
+ if (isFinal) return compoundResult;
32865
+ const chainResult = matchesChain(matcher, ancestor, nextIndex, perf, fileRootElements, logger);
32866
+ if (chainResult !== "no-match") {
32867
+ const merged = mergeMatchResults(compoundResult, chainResult);
32868
+ if (merged === "match") return "match";
32869
+ bestResult = merged;
32870
+ }
32818
32871
  }
32819
32872
  ancestor = ancestor.parentElementNode;
32820
32873
  }
32821
32874
  if (fileRootElements !== null) {
32875
+ if (logger.enabled) {
32876
+ const compoundDesc = describeCompound(targetCompound);
32877
+ logger.trace(`[selector-match] fallback: node=${node.key} tag=${node.tagName} checking ${fileRootElements.length} roots for compound=${compoundDesc}`);
32878
+ }
32822
32879
  for (let r = 0; r < fileRootElements.length; r++) {
32823
32880
  const root = fileRootElements[r];
32824
32881
  if (root === void 0) continue;
32825
32882
  if (root === node) continue;
32826
32883
  if (root.solidFile !== node.solidFile) continue;
32827
32884
  perf.ancestryChecks++;
32828
- if (matchesCompound(root, targetCompound)) {
32885
+ const compoundResult = matchesCompound(root, targetCompound);
32886
+ if (logger.enabled && compoundResult === "no-match") {
32887
+ logger.trace(`[selector-match] fallback MISS: root=${root.key} tag=${root.tagName} attrs=[${[...root.attributes.entries()].map(([k, v]) => `${k}=${v}`).join(",")}]`);
32888
+ }
32889
+ if (compoundResult !== "no-match") {
32829
32890
  if (logger.enabled) {
32830
32891
  const compoundDesc = describeCompound(targetCompound);
32831
32892
  logger.debug(`[selector-match] fallback HIT: node=${node.key} tag=${node.tagName} matched root=${root.key} tag=${root.tagName} compound=${compoundDesc} isFinal=${isFinal}`);
32832
32893
  }
32833
- if (isFinal) return true;
32834
- if (matchesChain(matcher, root, nextIndex, perf, fileRootElements, logger)) return true;
32894
+ if (isFinal) return compoundResult;
32895
+ const chainResult = matchesChain(matcher, root, nextIndex, perf, fileRootElements, logger);
32896
+ if (chainResult !== "no-match") {
32897
+ const merged = mergeMatchResults(compoundResult, chainResult);
32898
+ if (merged === "match") return "match";
32899
+ bestResult = merged;
32900
+ }
32835
32901
  }
32836
32902
  }
32837
32903
  }
32838
- return false;
32904
+ return bestResult;
32905
+ }
32906
+ function mergeMatchResults(a, b) {
32907
+ if (a === "no-match" || b === "no-match") return "no-match";
32908
+ if (a === "conditional" || b === "conditional") return "conditional";
32909
+ return "match";
32839
32910
  }
32840
32911
  function describeCompound(compound) {
32841
32912
  const parts = [];
@@ -32855,15 +32926,16 @@ function describeCompound(compound) {
32855
32926
  return parts.join("") || "*";
32856
32927
  }
32857
32928
  function matchesCompound(node, compound) {
32858
- if (compound.tagName !== null && node.tagName !== compound.tagName) return false;
32929
+ if (compound.tagName !== null && node.tagName !== compound.tagName) return "no-match";
32859
32930
  if (compound.idValue !== null) {
32860
32931
  const id = node.attributes.get("id");
32861
- if (id !== compound.idValue) return false;
32932
+ if (id !== compound.idValue) return "no-match";
32862
32933
  }
32863
- if (!matchesRequiredClasses(compound.classes, node.classTokenSet)) return false;
32864
- if (!matchesRequiredAttributes(compound.attributes, node.attributes)) return false;
32865
- if (!matchesPseudoConstraints(node, compound.pseudo)) return false;
32866
- return true;
32934
+ if (!matchesRequiredClasses(compound.classes, node.classTokenSet)) return "no-match";
32935
+ const attrResult = matchesRequiredAttributes(compound.attributes, node.attributes);
32936
+ if (attrResult === "no-match") return "no-match";
32937
+ if (!matchesPseudoConstraints(node, compound.pseudo)) return "no-match";
32938
+ return attrResult;
32867
32939
  }
32868
32940
  function matchesPseudoConstraints(node, pseudo) {
32869
32941
  if (pseudo.firstChild && node.siblingIndex !== 1) return false;
@@ -32888,7 +32960,7 @@ function matchesPseudoConstraints(node, pseudo) {
32888
32960
  for (let j = 0; j < group.length; j++) {
32889
32961
  const compound = group[j];
32890
32962
  if (compound === void 0) continue;
32891
- if (!matchesCompound(node, compound)) continue;
32963
+ if (matchesCompound(node, compound) === "no-match") continue;
32892
32964
  matched = true;
32893
32965
  break;
32894
32966
  }
@@ -32900,7 +32972,7 @@ function matchesPseudoConstraints(node, pseudo) {
32900
32972
  for (let j = 0; j < group.length; j++) {
32901
32973
  const compound = group[j];
32902
32974
  if (compound === void 0) continue;
32903
- if (!matchesCompound(node, compound)) continue;
32975
+ if (matchesCompound(node, compound) === "no-match") continue;
32904
32976
  return false;
32905
32977
  }
32906
32978
  }
@@ -33545,19 +33617,24 @@ function matchesRequiredClasses(required, actual) {
33545
33617
  return true;
33546
33618
  }
33547
33619
  function matchesRequiredAttributes(required, actual) {
33548
- if (required.length === 0) return true;
33620
+ if (required.length === 0) return "match";
33621
+ let hasConditional = false;
33549
33622
  for (let i = 0; i < required.length; i++) {
33550
33623
  const constraint = required[i];
33551
33624
  if (constraint === void 0) continue;
33552
- if (!actual.has(constraint.name)) return false;
33625
+ if (!actual.has(constraint.name)) return "no-match";
33553
33626
  if (constraint.operator === "exists") continue;
33554
33627
  const actualValue = actual.get(constraint.name);
33555
- if (actualValue === null || actualValue === void 0) return false;
33556
- if (constraint.value === null) return false;
33628
+ if (actualValue === void 0) return "no-match";
33629
+ if (actualValue === null) {
33630
+ hasConditional = true;
33631
+ continue;
33632
+ }
33633
+ if (constraint.value === null) return "no-match";
33557
33634
  if (matchesAttributeValue(actualValue, constraint)) continue;
33558
- return false;
33635
+ return "no-match";
33559
33636
  }
33560
- return true;
33637
+ return hasConditional ? "conditional" : "match";
33561
33638
  }
33562
33639
  function matchesAttributeValue(actualValue, constraint) {
33563
33640
  const expectedValue = constraint.value;
@@ -36542,6 +36619,11 @@ function compareCascadePositions(posA, posB) {
36542
36619
  }
36543
36620
 
36544
36621
  // src/cross-file/layout/cascade-builder.ts
36622
+ var DYNAMIC_ATTRIBUTE_GUARD = {
36623
+ kind: 1 /* Conditional */,
36624
+ conditions: [{ kind: "dynamic-attribute", query: null, key: "dynamic-attribute:*" }],
36625
+ key: "dynamic-attribute:*"
36626
+ };
36545
36627
  var SCROLLABLE_VALUES = /* @__PURE__ */ new Set(["auto", "scroll"]);
36546
36628
  var EMPTY_EXPANSION_RESULT = [];
36547
36629
  function collectMonitoredDeclarations(selector, layerOrder, guard) {
@@ -36616,14 +36698,21 @@ function appendMatchingEdgesFromSelectorIds(ctx, selectorIds, node, applies, app
36616
36698
  if (!selector) {
36617
36699
  throw new Error(`missing selector ${selectorId}`);
36618
36700
  }
36619
- if (!selectorMatchesLayoutElement(metadata.matcher, node, ctx.perf, fileRoots, ctx.logger)) continue;
36701
+ const matchResult = selectorMatchesLayoutElement(metadata.matcher, node, ctx.perf, fileRoots, ctx.logger);
36702
+ if (matchResult === "no-match") continue;
36620
36703
  const edge = {
36621
36704
  selectorId: selector.id,
36622
36705
  specificityScore: selector.specificityScore,
36623
- sourceOrder: selector.rule.sourceOrder
36706
+ sourceOrder: selector.rule.sourceOrder,
36707
+ conditionalMatch: matchResult === "conditional"
36624
36708
  };
36625
36709
  applies.push(edge);
36626
36710
  ctx.perf.matchEdgesCreated++;
36711
+ if (ctx.logger.enabled) {
36712
+ ctx.logger.trace(
36713
+ `[cascade] edge node=${node.key} selector=${selector.id} match=${matchResult} conditional=${edge.conditionalMatch} selector-raw=${selector.raw.slice(0, 80)}`
36714
+ );
36715
+ }
36627
36716
  const existing = appliesByElementNodeMutable.get(node);
36628
36717
  if (existing) {
36629
36718
  existing.push(edge);
@@ -36684,10 +36773,11 @@ function buildCascadeMapForElement(node, edges, monitoredDeclarationsBySelectorI
36684
36773
  const declaration = declarations[j];
36685
36774
  if (!declaration) continue;
36686
36775
  const property = declaration.property;
36776
+ const guardProvenance = edge.conditionalMatch && declaration.guardProvenance.kind === 0 /* Unconditional */ ? DYNAMIC_ATTRIBUTE_GUARD : declaration.guardProvenance;
36687
36777
  const newDeclaration = {
36688
36778
  value: declaration.value,
36689
36779
  source: 0 /* Selector */,
36690
- guardProvenance: declaration.guardProvenance
36780
+ guardProvenance
36691
36781
  };
36692
36782
  const existingPosition = positions.get(property);
36693
36783
  if (existingPosition === void 0) {
@@ -36801,7 +36891,7 @@ function buildConditionalDeltaIndex(elements, appliesByNode, monitoredDeclaratio
36801
36891
  };
36802
36892
  byProperty.set(property, bucket);
36803
36893
  }
36804
- if (declaration.guardProvenance.kind === 1 /* Conditional */) {
36894
+ if (declaration.guardProvenance.kind === 1 /* Conditional */ || currentEdge.conditionalMatch) {
36805
36895
  bucket.conditional.add(expandedEntry.value);
36806
36896
  continue;
36807
36897
  }
@@ -37293,6 +37383,23 @@ function buildLayoutGraph(solids, css, logger = noopLogger) {
37293
37383
  const moduleResolver = createLayoutModuleResolver(solids, css);
37294
37384
  const componentHostResolver = createLayoutComponentHostResolver(solids, moduleResolver, logger);
37295
37385
  const cssScopeBySolidFile = collectCSSScopeBySolidFile(solids, css, moduleResolver);
37386
+ if (logger.enabled) {
37387
+ for (const [solidFile, scopePaths] of cssScopeBySolidFile) {
37388
+ if (scopePaths.length > 0) {
37389
+ let names = "";
37390
+ for (let k = 0; k < scopePaths.length; k++) {
37391
+ const p = scopePaths[k];
37392
+ if (!p) continue;
37393
+ if (names.length > 0) names += ", ";
37394
+ const slash = p.lastIndexOf("/");
37395
+ names += slash === -1 ? p : p.slice(slash + 1);
37396
+ }
37397
+ logger.trace(`[scope] ${solidFile} \u2192 ${scopePaths.length} CSS files: ${names}`);
37398
+ } else {
37399
+ logger.trace(`[scope] ${solidFile} \u2192 EMPTY (no CSS in scope)`);
37400
+ }
37401
+ }
37402
+ }
37296
37403
  const selectorIndexStartedAt = performance.now();
37297
37404
  const scopedSelectorsBySolidFile = buildScopedSelectorIndexBySolidFile(
37298
37405
  cssScopeBySolidFile,
@@ -37435,6 +37542,22 @@ function buildLayoutGraph(solids, css, logger = noopLogger) {
37435
37542
  appliesByNode.set(node, edges);
37436
37543
  }
37437
37544
  perf.cascadeBuildMs = performance.now() - cascadeStartedAt;
37545
+ if (logger.enabled) {
37546
+ for (let i = 0; i < elements.length; i++) {
37547
+ const node = elements[i];
37548
+ if (!node) continue;
37549
+ const cascade = cascadeByElementNode.get(node);
37550
+ if (!cascade || cascade.size === 0) continue;
37551
+ const displayDecl = cascade.get("display");
37552
+ const flexDirDecl = cascade.get("flex-direction");
37553
+ if (!displayDecl && !flexDirDecl) continue;
37554
+ const displayGuard = displayDecl?.guardProvenance.kind === 1 /* Conditional */ ? "conditional" : "unconditional";
37555
+ const flexDirGuard = flexDirDecl?.guardProvenance.kind === 1 /* Conditional */ ? "conditional" : "unconditional";
37556
+ logger.trace(
37557
+ `[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(",")}]`
37558
+ );
37559
+ }
37560
+ }
37438
37561
  const snapshotByElementNode = buildSignalSnapshotIndex(elements, cascadeByElementNode, perf);
37439
37562
  const measurementNodeByRootKey = buildMeasurementNodeIndex(elements, childrenByParentNodeMutable, snapshotByElementNode);
37440
37563
  const factIndex = buildElementFactIndex(elements, snapshotByElementNode);
@@ -37452,7 +37575,7 @@ function buildLayoutGraph(solids, css, logger = noopLogger) {
37452
37575
  layoutOffsetSignals
37453
37576
  );
37454
37577
  const statefulRuleIndexes = buildStatefulRuleIndexes(css.rules);
37455
- const contextByParentNode = buildContextIndex(childrenByParentNodeMutable, snapshotByElementNode, perf);
37578
+ const contextByParentNode = buildContextIndex(childrenByParentNodeMutable, snapshotByElementNode, perf, logger);
37456
37579
  const cohortIndex = buildCohortIndex({
37457
37580
  childrenByParentNode: childrenByParentNodeMutable,
37458
37581
  contextByParentNode,
@@ -37872,16 +37995,27 @@ function computeFlowParticipationFact(snapshot) {
37872
37995
  hasUnconditionalOutOfFlow: signal.guard.kind === 0 /* Unconditional */ && outOfFlow
37873
37996
  };
37874
37997
  }
37875
- function buildContextIndex(childrenByParentNode, snapshotByElementNode, perf) {
37998
+ function buildContextIndex(childrenByParentNode, snapshotByElementNode, perf, logger) {
37876
37999
  const out = /* @__PURE__ */ new Map();
38000
+ const trace = logger.enabled;
37877
38001
  for (const [parent, children] of childrenByParentNode) {
37878
38002
  if (children.length < 2) continue;
37879
38003
  const snapshot = snapshotByElementNode.get(parent);
37880
38004
  if (!snapshot) {
37881
38005
  throw new Error(`missing parent snapshot for context classification ${parent.key}`);
37882
38006
  }
37883
- out.set(parent, createAlignmentContextForParent(parent, snapshot));
38007
+ const ctx = createAlignmentContextForParent(parent, snapshot);
38008
+ out.set(parent, ctx);
37884
38009
  perf.contextsClassified++;
38010
+ if (trace) {
38011
+ const displaySignal = snapshot.signals.get("display");
38012
+ const flexDirSignal = snapshot.signals.get("flex-direction");
38013
+ const displayDesc = displaySignal ? `${displaySignal.kind}:${displaySignal.kind === "known" ? displaySignal.normalized : "?"}(guard=${displaySignal.guard.kind === 1 /* Conditional */ ? "conditional" : "unconditional"})` : "absent";
38014
+ const flexDirDesc = flexDirSignal ? `${flexDirSignal.kind}:${flexDirSignal.kind === "known" ? flexDirSignal.normalized : "?"}(guard=${flexDirSignal.guard.kind === 1 /* Conditional */ ? "conditional" : "unconditional"})` : "absent";
38015
+ logger.trace(
38016
+ `[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}`
38017
+ );
38018
+ }
37885
38019
  }
37886
38020
  return out;
37887
38021
  }
@@ -39508,7 +39642,13 @@ var MIN_OFFSET_PX_THRESHOLD = 2;
39508
39642
  var siblingAlignmentDetector = {
39509
39643
  id: "sibling-alignment-outlier",
39510
39644
  collect: collectAlignmentCases,
39511
- evaluate(input) {
39645
+ evaluate(input, context) {
39646
+ if (context.logger.enabled) {
39647
+ const ctx = input.context;
39648
+ context.logger.trace(
39649
+ `[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}`
39650
+ );
39651
+ }
39512
39652
  const decision = evaluateAlignmentCase(input);
39513
39653
  if (decision.kind === "reject") {
39514
39654
  return {
@@ -40626,8 +40766,16 @@ function isExemptFromCLS(layout, solidFile, element, property) {
40626
40766
  if (POSITIONED_OFFSET_PROPERTIES.has(property) && flowFact.position !== null && flowFact.position !== "static") {
40627
40767
  return true;
40628
40768
  }
40769
+ if (hasLayoutContainment(node) || node.parentElementNode !== null && hasLayoutContainment(node.parentElementNode)) {
40770
+ return true;
40771
+ }
40629
40772
  return false;
40630
40773
  }
40774
+ function hasLayoutContainment(node) {
40775
+ const contain = node.inlineStyleValues.get("contain");
40776
+ if (contain === void 0) return false;
40777
+ return contain === "layout" || contain === "strict" || contain === "content" || contain.includes("layout");
40778
+ }
40631
40779
  function hasUnstableLayoutDelta(property, node) {
40632
40780
  const unwrapped = unwrapTypeWrapper(node);
40633
40781
  if (isStaticComparable(property, unwrapped)) return false;
@@ -41074,4 +41222,4 @@ export {
41074
41222
  rules3,
41075
41223
  runCrossFileRules
41076
41224
  };
41077
- //# sourceMappingURL=chunk-CAKVXEYV.js.map
41225
+ //# sourceMappingURL=chunk-HIADOXXV.js.map