nestWithin method

SelectorList nestWithin(
  1. SelectorList? parent, {
  2. bool implicitParent = true,
  3. bool preserveParentSelectors = false,
})

Returns a new selector list that represents this nested within parent.

By default, this replaces ParentSelectors in this with parent. If preserveParentSelectors is true, this instead preserves those selectors as parent selectors.

If implicitParent is true, this prepends parent to any ComplexSelectors in this that don't contain explicit ParentSelectors, or to all ComplexSelectors if preserveParentSelectors is true.

The given parent may be null, indicating that this has no parents. If so, this list is returned as-is if it doesn't contain any explicit ParentSelectors or if preserveParentSelectors is true. Otherwise, this throws a SassScriptException.

Implementation

SelectorList nestWithin(SelectorList? parent,
    {bool implicitParent = true, bool preserveParentSelectors = false}) {
  if (parent == null) {
    if (preserveParentSelectors) return this;
    var parentSelector = accept(const _ParentSelectorVisitor());
    if (parentSelector == null) return this;
    throw SassException(
        'Top-level selectors may not contain the parent selector "&".',
        parentSelector.span);
  }

  return SelectorList(flattenVertically(components.map((complex) {
    if (preserveParentSelectors || !_containsParentSelector(complex)) {
      if (!implicitParent) return [complex];
      return parent.components.map((parentComplex) =>
          parentComplex.concatenate(complex, complex.span));
    }

    var newComplexes = <ComplexSelector>[];
    for (var component in complex.components) {
      var resolved = _nestWithinCompound(component, parent);
      if (resolved == null) {
        if (newComplexes.isEmpty) {
          newComplexes.add(ComplexSelector(
              complex.leadingCombinators, [component], complex.span,
              lineBreak: false));
        } else {
          for (var i = 0; i < newComplexes.length; i++) {
            newComplexes[i] = newComplexes[i]
                .withAdditionalComponent(component, complex.span);
          }
        }
      } else if (newComplexes.isEmpty) {
        newComplexes.addAll(complex.leadingCombinators.isEmpty
            ? resolved
            : resolved.map((resolvedComplex) => ComplexSelector(
                resolvedComplex.leadingCombinators.isEmpty
                    ? complex.leadingCombinators
                    : [
                        ...complex.leadingCombinators,
                        ...resolvedComplex.leadingCombinators
                      ],
                resolvedComplex.components,
                complex.span,
                lineBreak: resolvedComplex.lineBreak)));
      } else {
        var previousComplexes = newComplexes;
        newComplexes = [
          for (var newComplex in previousComplexes)
            for (var resolvedComplex in resolved)
              newComplex.concatenate(resolvedComplex, newComplex.span)
        ];
      }
    }

    return newComplexes;
  })), span);
}