Add a "Resolving Extends" section.

This commit is contained in:
Natalie Weizenbaum 2016-01-15 19:19:04 -08:00
parent a4e6690afa
commit d20ae8030b

View File

@ -336,3 +336,59 @@ The downside to hyphens are that they look like normal identifiers, which makes
it less locally clear what's a namespace and what's a normal member name. It it less locally clear what's a namespace and what's a normal member name. It
also allows module prefixes to shadow other members, and introduces the also allows module prefixes to shadow other members, and introduces the
possibility of conflicting prefixes between modules. possibility of conflicting prefixes between modules.
### Resolving Extends
The module system also scopes the resolution of the `@extend` directive. This
helps satisfy locality, making selector extension more predictable than it is
using `@import`s.
Extension is scoped to CSS in [module](#module)s *transitively used* by the
module in which the `@extend` appears. This transitivity is necessary because
CSS is not considered a [member](#member) of a module, and can't be controlled
as explicitly as members can. Extending all transitively-used modules means that
the `@extend` affects exactly that CSS that is guaranteed to exist by the `@use`
directives.
Specifically, once all modules have been loaded, do a global pass to resolve the
extends.
* For each module that contains CSS (call it the *extended module*):
* Set this module's *virtual selectors* to the set of selectors in all of its
CSS rules. These virtual selectors remember the original selector they were
generated from.
* Take the subgraph of the module graph that can transitively reach the
extended module.
* For every module in this subgraph (call it the *extending module*) in
reverse [topological][] order:
* For each of the extended module's selectors:
* Take the corresponding virtual selector from each module used by the
extending module, if it has such a selector set.
* Create a new selector that matches the union of all elements matched by
these virtual selectors, and set it as a virtual selector of this
subgraph.
* Replace the selectors in the extended module's rules with the corresponding
virtual selectors of the [entrypoint module](#entrypoint-module).
[topological]: https://en.wikipedia.org/wiki/Topological_sorting
> **Implementation note:**
>
> This process as written is O(n²) for the number of modules in the compilation,
> and in a pathological case this is accurate. However, it's intended to be
> tightly constrained by the number and scope of the extensions the user chooses
> to write. Even a relatively naïve implementation should be able to keep it to
> O(n×m) for extending modules and extended modules. It's possible there's even
> an O(n) implementation that integrates extension with compilation, but that's
> beyond the scope of this document.
There is intentionally no way for a module to affect the extensions of another
module that doesn't transitively use it. This promotes locality, and matches the
behavior of mixins and functions in that monkey-patching is disallowed.