@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.
@@ -171,7 +171,8 @@ var ServerSettingsSchema = import_v4.z.object({
171
171
  useESLintConfig: import_v4.z.boolean().default(true),
172
172
  eslintConfigPath: import_v4.z.string().optional(),
173
173
  accessibilityPolicy: AccessibilityPolicySchema.default("wcag-aa"),
174
- exclude: import_v4.z.array(import_v4.z.string()).default([])
174
+ exclude: import_v4.z.array(import_v4.z.string()).default([]),
175
+ enableTypeScriptDiagnostics: import_v4.z.boolean().default(false)
175
176
  });
176
177
  var isBun = typeof globalThis.Bun !== "undefined";
177
178
  var CHAR_FOLD_BIT = 32;
@@ -8303,10 +8304,17 @@ function wireJSXHierarchy(graph) {
8303
8304
  }
8304
8305
  function findParentJSXNode(node) {
8305
8306
  let current = node.parent;
8307
+ let crossedFunctionBoundary = false;
8306
8308
  while (current) {
8307
8309
  if (import_typescript29.default.isJsxElement(current) || import_typescript29.default.isJsxFragment(current)) {
8308
8310
  return current;
8309
8311
  }
8312
+ if (import_typescript29.default.isArrowFunction(current) || import_typescript29.default.isFunctionExpression(current)) {
8313
+ crossedFunctionBoundary = true;
8314
+ }
8315
+ if (crossedFunctionBoundary && import_typescript29.default.isJsxAttribute(current)) {
8316
+ return null;
8317
+ }
8310
8318
  current = current.parent;
8311
8319
  }
8312
8320
  return null;
@@ -30181,7 +30189,8 @@ var layoutSignalNames = [
30181
30189
  "inset-block-start",
30182
30190
  "inset-block-end",
30183
30191
  "writing-mode",
30184
- "direction"
30192
+ "direction",
30193
+ "contain"
30185
30194
  ];
30186
30195
 
30187
30196
  // src/cross-file/layout/offset-baseline.ts
@@ -31814,6 +31823,7 @@ function findNodeModulesPackage(importerFile, packageName) {
31814
31823
  }
31815
31824
 
31816
31825
  // src/cross-file/layout/scope.ts
31826
+ var CSS_COLOCATED_EXTENSIONS = [".css"];
31817
31827
  function collectCSSScopeBySolidFile(solids, css, moduleResolver) {
31818
31828
  const resolver = moduleResolver ?? createLayoutModuleResolver(solids, css);
31819
31829
  const cssFilesByNormalizedPath = buildCSSFileIndex(css);
@@ -31824,6 +31834,20 @@ function collectCSSScopeBySolidFile(solids, css, moduleResolver) {
31824
31834
  const solid = solids[i];
31825
31835
  if (!solid) continue;
31826
31836
  const scope = /* @__PURE__ */ new Set();
31837
+ const colocatedCssPath = resolveColocatedCss(solid.file, cssFilesByNormalizedPath);
31838
+ if (colocatedCssPath !== null) {
31839
+ const colocatedScope = getOrCollectTransitiveScope(
31840
+ colocatedCssPath,
31841
+ resolver,
31842
+ cssFilesByNormalizedPath,
31843
+ transitiveScopeByEntryPath
31844
+ );
31845
+ for (let k = 0; k < colocatedScope.length; k++) {
31846
+ const cs = colocatedScope[k];
31847
+ if (!cs) continue;
31848
+ scope.add(cs);
31849
+ }
31850
+ }
31827
31851
  for (let j = 0; j < solid.imports.length; j++) {
31828
31852
  const imp = solid.imports[j];
31829
31853
  if (!imp) continue;
@@ -31866,6 +31890,18 @@ function collectCSSScopeBySolidFile(solids, css, moduleResolver) {
31866
31890
  }
31867
31891
  return out;
31868
31892
  }
31893
+ function resolveColocatedCss(solidFilePath, cssFilesByNormalizedPath) {
31894
+ const dotIndex = solidFilePath.lastIndexOf(".");
31895
+ if (dotIndex === -1) return null;
31896
+ const stem = solidFilePath.slice(0, dotIndex);
31897
+ for (let i = 0; i < CSS_COLOCATED_EXTENSIONS.length; i++) {
31898
+ const ext = CSS_COLOCATED_EXTENSIONS[i];
31899
+ if (!ext) continue;
31900
+ const candidate = canonicalPath(stem + ext);
31901
+ if (cssFilesByNormalizedPath.has(candidate)) return candidate;
31902
+ }
31903
+ return null;
31904
+ }
31869
31905
  function buildCSSFileIndex(css) {
31870
31906
  const out = /* @__PURE__ */ new Map();
31871
31907
  for (let i = 0; i < css.files.length; i++) {
@@ -33207,73 +33243,108 @@ function compoundGroupNeedsAttributes(groups) {
33207
33243
  }
33208
33244
  function selectorMatchesLayoutElement(matcher, node, perf, fileRootElements = null, logger = noopLogger) {
33209
33245
  const firstCompound = matcher.compoundsRightToLeft[0];
33210
- if (firstCompound === void 0) return false;
33211
- if (!matchesCompound(node, firstCompound)) return false;
33212
- if (matcher.compoundsRightToLeft.length === 1) return true;
33213
- return matchesChain(matcher, node, 0, perf, fileRootElements, logger);
33246
+ if (firstCompound === void 0) return "no-match";
33247
+ const subjectResult = matchesCompound(node, firstCompound);
33248
+ if (subjectResult === "no-match") return "no-match";
33249
+ if (matcher.compoundsRightToLeft.length === 1) return subjectResult;
33250
+ const chainResult = matchesChain(matcher, node, 0, perf, fileRootElements, logger);
33251
+ if (chainResult === "no-match") return "no-match";
33252
+ if (subjectResult === "conditional" || chainResult === "conditional") return "conditional";
33253
+ return "match";
33214
33254
  }
33215
33255
  function matchesChain(matcher, node, index, perf, fileRootElements, logger) {
33216
33256
  const combinator = matcher.combinatorsRightToLeft[index];
33217
- if (combinator === void 0) return false;
33257
+ if (combinator === void 0) return "no-match";
33218
33258
  const nextIndex = index + 1;
33219
33259
  const targetCompound = matcher.compoundsRightToLeft[nextIndex];
33220
- if (targetCompound === void 0) return false;
33260
+ if (targetCompound === void 0) return "no-match";
33221
33261
  const isFinal = nextIndex === matcher.compoundsRightToLeft.length - 1;
33222
33262
  if (combinator === "child") {
33223
33263
  const parent = node.parentElementNode;
33224
- if (parent === null) return false;
33264
+ if (parent === null) return "no-match";
33225
33265
  perf.ancestryChecks++;
33226
- if (!matchesCompound(parent, targetCompound)) return false;
33227
- if (isFinal) return true;
33228
- return matchesChain(matcher, parent, nextIndex, perf, fileRootElements, logger);
33266
+ const compoundResult = matchesCompound(parent, targetCompound);
33267
+ if (compoundResult === "no-match") return "no-match";
33268
+ if (isFinal) return compoundResult;
33269
+ const chainResult = matchesChain(matcher, parent, nextIndex, perf, fileRootElements, logger);
33270
+ return mergeMatchResults(compoundResult, chainResult);
33229
33271
  }
33230
33272
  if (combinator === "adjacent") {
33231
33273
  const sibling = node.previousSiblingNode;
33232
- if (sibling === null) return false;
33274
+ if (sibling === null) return "no-match";
33233
33275
  perf.ancestryChecks++;
33234
- if (!matchesCompound(sibling, targetCompound)) return false;
33235
- if (isFinal) return true;
33236
- return matchesChain(matcher, sibling, nextIndex, perf, fileRootElements, logger);
33276
+ const compoundResult = matchesCompound(sibling, targetCompound);
33277
+ if (compoundResult === "no-match") return "no-match";
33278
+ if (isFinal) return compoundResult;
33279
+ const chainResult = matchesChain(matcher, sibling, nextIndex, perf, fileRootElements, logger);
33280
+ return mergeMatchResults(compoundResult, chainResult);
33237
33281
  }
33238
33282
  if (combinator === "sibling") {
33239
33283
  let sibling = node.previousSiblingNode;
33240
33284
  while (sibling !== null) {
33241
33285
  perf.ancestryChecks++;
33242
- if (matchesCompound(sibling, targetCompound)) {
33243
- if (isFinal) return true;
33244
- if (matchesChain(matcher, sibling, nextIndex, perf, fileRootElements, logger)) return true;
33286
+ const compoundResult = matchesCompound(sibling, targetCompound);
33287
+ if (compoundResult !== "no-match") {
33288
+ if (isFinal) return compoundResult;
33289
+ const chainResult = matchesChain(matcher, sibling, nextIndex, perf, fileRootElements, logger);
33290
+ if (chainResult !== "no-match") return mergeMatchResults(compoundResult, chainResult);
33245
33291
  }
33246
33292
  sibling = sibling.previousSiblingNode;
33247
33293
  }
33248
- return false;
33294
+ return "no-match";
33249
33295
  }
33296
+ let bestResult = "no-match";
33250
33297
  let ancestor = node.parentElementNode;
33251
33298
  while (ancestor !== null) {
33252
33299
  perf.ancestryChecks++;
33253
- if (matchesCompound(ancestor, targetCompound)) {
33254
- if (isFinal) return true;
33255
- if (matchesChain(matcher, ancestor, nextIndex, perf, fileRootElements, logger)) return true;
33300
+ const compoundResult = matchesCompound(ancestor, targetCompound);
33301
+ if (compoundResult !== "no-match") {
33302
+ if (isFinal) return compoundResult;
33303
+ const chainResult = matchesChain(matcher, ancestor, nextIndex, perf, fileRootElements, logger);
33304
+ if (chainResult !== "no-match") {
33305
+ const merged = mergeMatchResults(compoundResult, chainResult);
33306
+ if (merged === "match") return "match";
33307
+ bestResult = merged;
33308
+ }
33256
33309
  }
33257
33310
  ancestor = ancestor.parentElementNode;
33258
33311
  }
33259
33312
  if (fileRootElements !== null) {
33313
+ if (logger.enabled) {
33314
+ const compoundDesc = describeCompound(targetCompound);
33315
+ logger.trace(`[selector-match] fallback: node=${node.key} tag=${node.tagName} checking ${fileRootElements.length} roots for compound=${compoundDesc}`);
33316
+ }
33260
33317
  for (let r = 0; r < fileRootElements.length; r++) {
33261
33318
  const root = fileRootElements[r];
33262
33319
  if (root === void 0) continue;
33263
33320
  if (root === node) continue;
33264
33321
  if (root.solidFile !== node.solidFile) continue;
33265
33322
  perf.ancestryChecks++;
33266
- if (matchesCompound(root, targetCompound)) {
33323
+ const compoundResult = matchesCompound(root, targetCompound);
33324
+ if (logger.enabled && compoundResult === "no-match") {
33325
+ logger.trace(`[selector-match] fallback MISS: root=${root.key} tag=${root.tagName} attrs=[${[...root.attributes.entries()].map(([k, v]) => `${k}=${v}`).join(",")}]`);
33326
+ }
33327
+ if (compoundResult !== "no-match") {
33267
33328
  if (logger.enabled) {
33268
33329
  const compoundDesc = describeCompound(targetCompound);
33269
33330
  logger.debug(`[selector-match] fallback HIT: node=${node.key} tag=${node.tagName} matched root=${root.key} tag=${root.tagName} compound=${compoundDesc} isFinal=${isFinal}`);
33270
33331
  }
33271
- if (isFinal) return true;
33272
- if (matchesChain(matcher, root, nextIndex, perf, fileRootElements, logger)) return true;
33332
+ if (isFinal) return compoundResult;
33333
+ const chainResult = matchesChain(matcher, root, nextIndex, perf, fileRootElements, logger);
33334
+ if (chainResult !== "no-match") {
33335
+ const merged = mergeMatchResults(compoundResult, chainResult);
33336
+ if (merged === "match") return "match";
33337
+ bestResult = merged;
33338
+ }
33273
33339
  }
33274
33340
  }
33275
33341
  }
33276
- return false;
33342
+ return bestResult;
33343
+ }
33344
+ function mergeMatchResults(a, b) {
33345
+ if (a === "no-match" || b === "no-match") return "no-match";
33346
+ if (a === "conditional" || b === "conditional") return "conditional";
33347
+ return "match";
33277
33348
  }
33278
33349
  function describeCompound(compound) {
33279
33350
  const parts = [];
@@ -33293,15 +33364,16 @@ function describeCompound(compound) {
33293
33364
  return parts.join("") || "*";
33294
33365
  }
33295
33366
  function matchesCompound(node, compound) {
33296
- if (compound.tagName !== null && node.tagName !== compound.tagName) return false;
33367
+ if (compound.tagName !== null && node.tagName !== compound.tagName) return "no-match";
33297
33368
  if (compound.idValue !== null) {
33298
33369
  const id = node.attributes.get("id");
33299
- if (id !== compound.idValue) return false;
33370
+ if (id !== compound.idValue) return "no-match";
33300
33371
  }
33301
- if (!matchesRequiredClasses(compound.classes, node.classTokenSet)) return false;
33302
- if (!matchesRequiredAttributes(compound.attributes, node.attributes)) return false;
33303
- if (!matchesPseudoConstraints(node, compound.pseudo)) return false;
33304
- return true;
33372
+ if (!matchesRequiredClasses(compound.classes, node.classTokenSet)) return "no-match";
33373
+ const attrResult = matchesRequiredAttributes(compound.attributes, node.attributes);
33374
+ if (attrResult === "no-match") return "no-match";
33375
+ if (!matchesPseudoConstraints(node, compound.pseudo)) return "no-match";
33376
+ return attrResult;
33305
33377
  }
33306
33378
  function matchesPseudoConstraints(node, pseudo) {
33307
33379
  if (pseudo.firstChild && node.siblingIndex !== 1) return false;
@@ -33326,7 +33398,7 @@ function matchesPseudoConstraints(node, pseudo) {
33326
33398
  for (let j = 0; j < group.length; j++) {
33327
33399
  const compound = group[j];
33328
33400
  if (compound === void 0) continue;
33329
- if (!matchesCompound(node, compound)) continue;
33401
+ if (matchesCompound(node, compound) === "no-match") continue;
33330
33402
  matched = true;
33331
33403
  break;
33332
33404
  }
@@ -33338,7 +33410,7 @@ function matchesPseudoConstraints(node, pseudo) {
33338
33410
  for (let j = 0; j < group.length; j++) {
33339
33411
  const compound = group[j];
33340
33412
  if (compound === void 0) continue;
33341
- if (!matchesCompound(node, compound)) continue;
33413
+ if (matchesCompound(node, compound) === "no-match") continue;
33342
33414
  return false;
33343
33415
  }
33344
33416
  }
@@ -33983,19 +34055,24 @@ function matchesRequiredClasses(required, actual) {
33983
34055
  return true;
33984
34056
  }
33985
34057
  function matchesRequiredAttributes(required, actual) {
33986
- if (required.length === 0) return true;
34058
+ if (required.length === 0) return "match";
34059
+ let hasConditional = false;
33987
34060
  for (let i = 0; i < required.length; i++) {
33988
34061
  const constraint = required[i];
33989
34062
  if (constraint === void 0) continue;
33990
- if (!actual.has(constraint.name)) return false;
34063
+ if (!actual.has(constraint.name)) return "no-match";
33991
34064
  if (constraint.operator === "exists") continue;
33992
34065
  const actualValue = actual.get(constraint.name);
33993
- if (actualValue === null || actualValue === void 0) return false;
33994
- if (constraint.value === null) return false;
34066
+ if (actualValue === void 0) return "no-match";
34067
+ if (actualValue === null) {
34068
+ hasConditional = true;
34069
+ continue;
34070
+ }
34071
+ if (constraint.value === null) return "no-match";
33995
34072
  if (matchesAttributeValue(actualValue, constraint)) continue;
33996
- return false;
34073
+ return "no-match";
33997
34074
  }
33998
- return true;
34075
+ return hasConditional ? "conditional" : "match";
33999
34076
  }
34000
34077
  function matchesAttributeValue(actualValue, constraint) {
34001
34078
  const expectedValue = constraint.value;
@@ -36361,6 +36438,11 @@ function compareCascadePositions(posA, posB) {
36361
36438
  }
36362
36439
 
36363
36440
  // src/cross-file/layout/cascade-builder.ts
36441
+ var DYNAMIC_ATTRIBUTE_GUARD = {
36442
+ kind: 1 /* Conditional */,
36443
+ conditions: [{ kind: "dynamic-attribute", query: null, key: "dynamic-attribute:*" }],
36444
+ key: "dynamic-attribute:*"
36445
+ };
36364
36446
  var SCROLLABLE_VALUES = /* @__PURE__ */ new Set(["auto", "scroll"]);
36365
36447
  var EMPTY_EXPANSION_RESULT = [];
36366
36448
  function collectMonitoredDeclarations(selector, layerOrder, guard) {
@@ -36435,14 +36517,21 @@ function appendMatchingEdgesFromSelectorIds(ctx, selectorIds, node, applies, app
36435
36517
  if (!selector) {
36436
36518
  throw new Error(`missing selector ${selectorId}`);
36437
36519
  }
36438
- if (!selectorMatchesLayoutElement(metadata.matcher, node, ctx.perf, fileRoots, ctx.logger)) continue;
36520
+ const matchResult = selectorMatchesLayoutElement(metadata.matcher, node, ctx.perf, fileRoots, ctx.logger);
36521
+ if (matchResult === "no-match") continue;
36439
36522
  const edge = {
36440
36523
  selectorId: selector.id,
36441
36524
  specificityScore: selector.specificityScore,
36442
- sourceOrder: selector.rule.sourceOrder
36525
+ sourceOrder: selector.rule.sourceOrder,
36526
+ conditionalMatch: matchResult === "conditional"
36443
36527
  };
36444
36528
  applies.push(edge);
36445
36529
  ctx.perf.matchEdgesCreated++;
36530
+ if (ctx.logger.enabled) {
36531
+ ctx.logger.trace(
36532
+ `[cascade] edge node=${node.key} selector=${selector.id} match=${matchResult} conditional=${edge.conditionalMatch} selector-raw=${selector.raw.slice(0, 80)}`
36533
+ );
36534
+ }
36446
36535
  const existing = appliesByElementNodeMutable.get(node);
36447
36536
  if (existing) {
36448
36537
  existing.push(edge);
@@ -36503,10 +36592,11 @@ function buildCascadeMapForElement(node, edges, monitoredDeclarationsBySelectorI
36503
36592
  const declaration = declarations[j];
36504
36593
  if (!declaration) continue;
36505
36594
  const property = declaration.property;
36595
+ const guardProvenance = edge.conditionalMatch && declaration.guardProvenance.kind === 0 /* Unconditional */ ? DYNAMIC_ATTRIBUTE_GUARD : declaration.guardProvenance;
36506
36596
  const newDeclaration = {
36507
36597
  value: declaration.value,
36508
36598
  source: 0 /* Selector */,
36509
- guardProvenance: declaration.guardProvenance
36599
+ guardProvenance
36510
36600
  };
36511
36601
  const existingPosition = positions.get(property);
36512
36602
  if (existingPosition === void 0) {
@@ -36588,7 +36678,7 @@ function resolveRuleLayerOrder(rule, css) {
36588
36678
  if (!name) return 0;
36589
36679
  return css.layerOrder.get(name) ?? 0;
36590
36680
  }
36591
- function buildConditionalDeltaIndex(elements, appliesByNode, monitoredDeclarationsBySelectorId) {
36681
+ function buildConditionalDeltaIndex(elements, appliesByNode, monitoredDeclarationsBySelectorId, selectorsById) {
36592
36682
  const conditionalSignalDeltaFactsByNode = /* @__PURE__ */ new Map();
36593
36683
  const elementsWithConditionalDeltaBySignal = /* @__PURE__ */ new Map();
36594
36684
  const baselineOffsetFactsByNode = /* @__PURE__ */ new Map();
@@ -36599,11 +36689,16 @@ function buildConditionalDeltaIndex(elements, appliesByNode, monitoredDeclaratio
36599
36689
  let factByProperty = null;
36600
36690
  if (edges !== void 0 && edges.length > 0) {
36601
36691
  const byProperty = /* @__PURE__ */ new Map();
36692
+ let conditionalAttributeDispatch = null;
36602
36693
  for (let j = 0; j < edges.length; j++) {
36603
36694
  const currentEdge = edges[j];
36604
36695
  if (!currentEdge) continue;
36605
36696
  const declarations = monitoredDeclarationsBySelectorId.get(currentEdge.selectorId);
36606
36697
  if (!declarations) continue;
36698
+ let conditionalAttributeName = null;
36699
+ if (currentEdge.conditionalMatch) {
36700
+ conditionalAttributeName = identifyConditionalAttribute(currentEdge.selectorId, node, selectorsById);
36701
+ }
36607
36702
  for (let k = 0; k < declarations.length; k++) {
36608
36703
  const declaration = declarations[k];
36609
36704
  if (!declaration) continue;
@@ -36620,8 +36715,17 @@ function buildConditionalDeltaIndex(elements, appliesByNode, monitoredDeclaratio
36620
36715
  };
36621
36716
  byProperty.set(property, bucket);
36622
36717
  }
36623
- if (declaration.guardProvenance.kind === 1 /* Conditional */) {
36718
+ if (declaration.guardProvenance.kind === 1 /* Conditional */ || currentEdge.conditionalMatch) {
36624
36719
  bucket.conditional.add(expandedEntry.value);
36720
+ if (conditionalAttributeName !== null && declaration.guardProvenance.kind !== 1 /* Conditional */) {
36721
+ if (conditionalAttributeDispatch === null) conditionalAttributeDispatch = /* @__PURE__ */ new Map();
36722
+ let dispatchMap = conditionalAttributeDispatch.get(property);
36723
+ if (!dispatchMap) {
36724
+ dispatchMap = /* @__PURE__ */ new Map();
36725
+ conditionalAttributeDispatch.set(property, dispatchMap);
36726
+ }
36727
+ dispatchMap.set(expandedEntry.value, conditionalAttributeName);
36728
+ }
36625
36729
  continue;
36626
36730
  }
36627
36731
  bucket.unconditional.add(expandedEntry.value);
@@ -36646,6 +36750,24 @@ function buildConditionalDeltaIndex(elements, appliesByNode, monitoredDeclaratio
36646
36750
  }
36647
36751
  }
36648
36752
  }
36753
+ if (hasDelta && conditionalAttributeDispatch !== null) {
36754
+ const dispatchMap = conditionalAttributeDispatch.get(property);
36755
+ if (dispatchMap !== void 0 && dispatchMap.size === conditionalValues.length) {
36756
+ let singleAttribute = null;
36757
+ let allSameAttribute = true;
36758
+ for (const attrName of dispatchMap.values()) {
36759
+ if (singleAttribute === null) {
36760
+ singleAttribute = attrName;
36761
+ } else if (singleAttribute !== attrName) {
36762
+ allSameAttribute = false;
36763
+ break;
36764
+ }
36765
+ }
36766
+ if (allSameAttribute && singleAttribute !== null) {
36767
+ hasDelta = false;
36768
+ }
36769
+ }
36770
+ }
36649
36771
  const scrollProfile = buildScrollValueProfile(property, conditionalValues, unconditionalValues);
36650
36772
  facts.set(property, {
36651
36773
  hasConditional,
@@ -36731,6 +36853,25 @@ function buildConditionalDeltaSignalGroupElements(elementsWithConditionalDeltaBy
36731
36853
  }
36732
36854
  return out;
36733
36855
  }
36856
+ function identifyConditionalAttribute(selectorId, node, selectorsById) {
36857
+ const selector = selectorsById.get(selectorId);
36858
+ if (!selector) return null;
36859
+ const constraints = selector.anchor.attributes;
36860
+ let dynamicAttributeName = null;
36861
+ for (let i = 0; i < constraints.length; i++) {
36862
+ const constraint = constraints[i];
36863
+ if (!constraint) continue;
36864
+ if (constraint.operator !== "equals") continue;
36865
+ if (constraint.value === null) continue;
36866
+ const elementValue = node.attributes.get(constraint.name);
36867
+ if (elementValue !== null) continue;
36868
+ if (dynamicAttributeName !== null && dynamicAttributeName !== constraint.name) {
36869
+ return null;
36870
+ }
36871
+ dynamicAttributeName = constraint.name;
36872
+ }
36873
+ return dynamicAttributeName;
36874
+ }
36734
36875
  function buildScrollValueProfile(property, conditionalValues, unconditionalValues) {
36735
36876
  if (property !== "overflow" && property !== "overflow-y") {
36736
36877
  return {
@@ -37112,6 +37253,23 @@ function buildLayoutGraph(solids, css, logger = noopLogger) {
37112
37253
  const moduleResolver = createLayoutModuleResolver(solids, css);
37113
37254
  const componentHostResolver = createLayoutComponentHostResolver(solids, moduleResolver, logger);
37114
37255
  const cssScopeBySolidFile = collectCSSScopeBySolidFile(solids, css, moduleResolver);
37256
+ if (logger.enabled) {
37257
+ for (const [solidFile, scopePaths] of cssScopeBySolidFile) {
37258
+ if (scopePaths.length > 0) {
37259
+ let names = "";
37260
+ for (let k = 0; k < scopePaths.length; k++) {
37261
+ const p = scopePaths[k];
37262
+ if (!p) continue;
37263
+ if (names.length > 0) names += ", ";
37264
+ const slash = p.lastIndexOf("/");
37265
+ names += slash === -1 ? p : p.slice(slash + 1);
37266
+ }
37267
+ logger.trace(`[scope] ${solidFile} \u2192 ${scopePaths.length} CSS files: ${names}`);
37268
+ } else {
37269
+ logger.trace(`[scope] ${solidFile} \u2192 EMPTY (no CSS in scope)`);
37270
+ }
37271
+ }
37272
+ }
37115
37273
  const selectorIndexStartedAt = performance.now();
37116
37274
  const scopedSelectorsBySolidFile = buildScopedSelectorIndexBySolidFile(
37117
37275
  cssScopeBySolidFile,
@@ -37254,13 +37412,30 @@ function buildLayoutGraph(solids, css, logger = noopLogger) {
37254
37412
  appliesByNode.set(node, edges);
37255
37413
  }
37256
37414
  perf.cascadeBuildMs = performance.now() - cascadeStartedAt;
37415
+ if (logger.enabled) {
37416
+ for (let i = 0; i < elements.length; i++) {
37417
+ const node = elements[i];
37418
+ if (!node) continue;
37419
+ const cascade = cascadeByElementNode.get(node);
37420
+ if (!cascade || cascade.size === 0) continue;
37421
+ const displayDecl = cascade.get("display");
37422
+ const flexDirDecl = cascade.get("flex-direction");
37423
+ if (!displayDecl && !flexDirDecl) continue;
37424
+ const displayGuard = displayDecl?.guardProvenance.kind === 1 /* Conditional */ ? "conditional" : "unconditional";
37425
+ const flexDirGuard = flexDirDecl?.guardProvenance.kind === 1 /* Conditional */ ? "conditional" : "unconditional";
37426
+ logger.trace(
37427
+ `[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(",")}]`
37428
+ );
37429
+ }
37430
+ }
37257
37431
  const snapshotByElementNode = buildSignalSnapshotIndex(elements, cascadeByElementNode, perf);
37258
37432
  const measurementNodeByRootKey = buildMeasurementNodeIndex(elements, childrenByParentNodeMutable, snapshotByElementNode);
37259
37433
  const factIndex = buildElementFactIndex(elements, snapshotByElementNode);
37260
37434
  const conditionalDeltaIndex = buildConditionalDeltaIndex(
37261
37435
  elements,
37262
37436
  appliesByNode,
37263
- monitoredDeclarationsBySelectorId
37437
+ monitoredDeclarationsBySelectorId,
37438
+ selectorsById
37264
37439
  );
37265
37440
  const elementsWithConditionalOverflowDelta = buildConditionalDeltaSignalGroupElements(
37266
37441
  conditionalDeltaIndex.elementsWithConditionalDeltaBySignal,
@@ -37271,7 +37446,7 @@ function buildLayoutGraph(solids, css, logger = noopLogger) {
37271
37446
  layoutOffsetSignals
37272
37447
  );
37273
37448
  const statefulRuleIndexes = buildStatefulRuleIndexes(css.rules);
37274
- const contextByParentNode = buildContextIndex(childrenByParentNodeMutable, snapshotByElementNode, perf);
37449
+ const contextByParentNode = buildContextIndex(childrenByParentNodeMutable, snapshotByElementNode, perf, logger);
37275
37450
  const cohortIndex = buildCohortIndex({
37276
37451
  childrenByParentNode: childrenByParentNodeMutable,
37277
37452
  contextByParentNode,
@@ -37691,16 +37866,27 @@ function computeFlowParticipationFact(snapshot) {
37691
37866
  hasUnconditionalOutOfFlow: signal.guard.kind === 0 /* Unconditional */ && outOfFlow
37692
37867
  };
37693
37868
  }
37694
- function buildContextIndex(childrenByParentNode, snapshotByElementNode, perf) {
37869
+ function buildContextIndex(childrenByParentNode, snapshotByElementNode, perf, logger) {
37695
37870
  const out = /* @__PURE__ */ new Map();
37871
+ const trace = logger.enabled;
37696
37872
  for (const [parent, children] of childrenByParentNode) {
37697
37873
  if (children.length < 2) continue;
37698
37874
  const snapshot = snapshotByElementNode.get(parent);
37699
37875
  if (!snapshot) {
37700
37876
  throw new Error(`missing parent snapshot for context classification ${parent.key}`);
37701
37877
  }
37702
- out.set(parent, createAlignmentContextForParent(parent, snapshot));
37878
+ const ctx = createAlignmentContextForParent(parent, snapshot);
37879
+ out.set(parent, ctx);
37703
37880
  perf.contextsClassified++;
37881
+ if (trace) {
37882
+ const displaySignal = snapshot.signals.get("display");
37883
+ const flexDirSignal = snapshot.signals.get("flex-direction");
37884
+ const displayDesc = displaySignal ? `${displaySignal.kind}:${displaySignal.kind === "known" ? displaySignal.normalized : "?"}(guard=${displaySignal.guard.kind === 1 /* Conditional */ ? "conditional" : "unconditional"})` : "absent";
37885
+ const flexDirDesc = flexDirSignal ? `${flexDirSignal.kind}:${flexDirSignal.kind === "known" ? flexDirSignal.normalized : "?"}(guard=${flexDirSignal.guard.kind === 1 /* Conditional */ ? "conditional" : "unconditional"})` : "absent";
37886
+ logger.trace(
37887
+ `[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}`
37888
+ );
37889
+ }
37704
37890
  }
37705
37891
  return out;
37706
37892
  }
@@ -39283,7 +39469,13 @@ var MIN_OFFSET_PX_THRESHOLD = 2;
39283
39469
  var siblingAlignmentDetector = {
39284
39470
  id: "sibling-alignment-outlier",
39285
39471
  collect: collectAlignmentCases,
39286
- evaluate(input) {
39472
+ evaluate(input, context) {
39473
+ if (context.logger.enabled) {
39474
+ const ctx = input.context;
39475
+ context.logger.trace(
39476
+ `[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}`
39477
+ );
39478
+ }
39287
39479
  const decision = evaluateAlignmentCase(input);
39288
39480
  if (decision.kind === "reject") {
39289
39481
  return {
@@ -40401,8 +40593,16 @@ function isExemptFromCLS(layout, solidFile, element, property) {
40401
40593
  if (POSITIONED_OFFSET_PROPERTIES.has(property) && flowFact.position !== null && flowFact.position !== "static") {
40402
40594
  return true;
40403
40595
  }
40596
+ if (hasLayoutContainment(node) || node.parentElementNode !== null && hasLayoutContainment(node.parentElementNode)) {
40597
+ return true;
40598
+ }
40404
40599
  return false;
40405
40600
  }
40601
+ function hasLayoutContainment(node) {
40602
+ const contain = node.inlineStyleValues.get("contain");
40603
+ if (contain === void 0) return false;
40604
+ return contain === "layout" || contain === "strict" || contain === "content" || contain.includes("layout");
40605
+ }
40406
40606
  function hasUnstableLayoutDelta(property, node) {
40407
40607
  const unwrapped = unwrapTypeWrapper(node);
40408
40608
  if (isStaticComparable(property, unwrapped)) return false;