Skip to content

Latest commit

 

History

History
435 lines (281 loc) · 14.9 KB

File metadata and controls

435 lines (281 loc) · 14.9 KB

Modules

Table of Contents

Definitions

Member

A member is a Sass construct that's defined either by the user or the implementation and is identified by a Sass identifier. This currently includes variables, mixins, and functions (but not placeholder selectors). All members have definitions associated with them, whose specific structure depends on the type of the given member.

Two members are considered identical if they have the same name, type, source location, and were defined in or forwarded from the same original module.

Each member type has its own namespace in Sass, so for example the mixin name doesn't conflict with the function name or the variable $name.

CSS Tree

A CSS tree is an abstract CSS syntax tree. It has multiple top-level CSS statements like at-rules or style rules. The ordering of these statements is significant. A CSS tree cannot contain any Sass-specific constructs, with the notable exception of placeholder selectors.

An empty CSS tree contains no statements.

Configuration

A configuration is a map from variable names to SassScript values. An empty configuration contains no entries.

Module

A module is a collection of various properties:

  • A set of members that contains at most one member of any given type and name.

    For example, a module may not have two variables named $name, although it may contain a function and a mixin with the same name or two functions with different names.

    The names (and mixin and function signatures) of a module's members are static, and can be determined without executing its associated source file. This means that any possible module for a given source file has the same member names and signatures regardless of the context in which those modules are loaded.

  • A set of extensions.

  • A CSS tree.

    This tree is empty for built-in modules and user-defined modules that only define variables, functions, and mixins without including any plain CSS rules.

  • A list of references to other modules, known as the module's dependencies, in the same order as their @use rules and/or @forward rules appear in the module's source file. If a dependency is referred to from multiple rules, its order is determined by the first such rule.

    Modules without a source file never have dependencies. Each dependency is guaranteed to correspond to at least one @use rule or @forward rule.

  • An optional source file.

    Note that built-in modules do not have source files associated with them.

  • An absolute URL, known as the module's canonical URL. If the module has a source file, this must be the same as the source file's canonical URL.

Once a user-defined module has been returned by Executing a File, it is immutable except for its variable values. Built-in modules are always immutable.

Module Graph

The set of modules loaded in the course of processing a stylesheet can be construed as a directed acyclic graph where the vertices are modules and the edges are @use rules and/or @forward rules. We call this the module graph.

The module graph is not allowed to contain cycles because they make it impossible to guarantee that all dependencies of a module are available before that module is loaded. Although the names and APIs of a dependency's members can be determined without executing it, Sass allows code to be executed during load, so those members may not behave correctly when invoked before the dependency is executed.

Import Context

An import context is a set of members that contains at most one member of any given type and name. It's always mutable.

Import contexts serve as glue between the old @import rule and the module system. It serves as a shared global namespace for stylesheets loaded using @import rules, while also preventing global names from leaking into or out of stylesheets loaded using @use rules and/or @forward rules.

Built-In Module

A built-in module is a module defined either by the Sass specification or by the host environment of the Sass compilation in some implementation-specific way. Modules defined by the Sass specification all have the scheme sass: and are all described in the built_in_modules directory. Modules defined outside the Sass compilation may not use the scheme sass:.

Built-in modules may contain mixins, variables, or functions, but they may never contain CSS or extensions.

Basename

The basename of a URL is the final component of that URL's path.

Dirname

The dirname of a URL is the prefix of that URL up to, but not including, the beginning of its basename.

Syntax

The module system defines the following syntax for referring to names from other modules:

PublicIdentifier     ::= <ident-token> that doesn't begin with '-' or '_'
NamespacedIdentifier ::= Identifier | Identifier '.' PublicIdentifier

No whitespace is allowed before or after the '.' in NamespacedIdentifier.

Procedures

Loading a Module

This algorithm takes a string argument and configuration config and returns a module:

  • If argument is a valid URL with scheme sass:

    • If config is not empty, throw an error.

    • If a built-in module exists with the exact given URL, return it.

    • Otherwise, throw an error.

  • Let file be the result of loading the file at argument.

  • If file is null, throw an error.

  • If file has already been executed:

    • If config is not empty, throw an error.

    • Otherwise, return the module that execution produced.

  • If file is currently being executed, throw an error.

    This disallows circular @uses, which ensures that modules can't be used until they're fully initialized.

  • Otherwise, return the result of executing file with config and a new import context.

    For simplicity, the spec creates an import context for every module. Implementations are encouraged to avoid eagerly allocating resources for imports, though, to make use-cases only involving @use more efficient.

Loading a Source File

This algorithm takes a string, argument, and returns either a source file or null.

  • If the scheme of the current source file's canonical URL is file:

    • Let root be the current source file's canonical URL.
  • Otherwise, let root be null.

  • Let bases be a list beginning with root if it's non-null, followed by the absolute file: URLs of all import paths.

  • For each base in bases:

    • Let url be the result of parsing argument as a URL with base as the base URL.

      If this returns a failure, throw that failure.

    • If url's scheme is not file, return null.

    • Let resolved be the result of resolving url.

    • If resolved is null:

    • If resolved is still null, continue to the next loop.

    • Let text be the contents of the file at resolved.

    • Let ast be:

      • The result of parsing text as SCSS if resolved ends in .scss.
      • The result of parsing text as the indented syntax if resolved ends in .sass.
      • The result of parsing text as CSS if resolved ends in .css.

      The algorithm for resolving a file: URL guarantees that resolved will have one of these extensions.

    • Return a source file with ast as its abstract syntax tree and resolved as its canonical URL.

  • Return null.

Resolving a file: URL

This algorithm takes a URL, url, whose scheme must be file and returns either another URL that's guaranteed to point to a file on disk or null.

Resolving a file: URL for Partials

This algorithm takes a URL, url, whose scheme must be file and returns either another URL that's guaranteed to point to a file on disk or null.

  • If url's basename begins with "_":

    • If a file exists on disk at url, return url.

      Otherwise return null.

  • Let partial be dirname(url) + "_" + basename(url).

  • If a file exists on disk at both url and partial, throw an error.

  • If a file exists on disk at url, return url.

  • If a file exists on disk at partial, return partial.

  • Return null.

Resolving a Member

This algorithm takes a member name name and a member type type, and returns a member of type type or null.

  • If name is a plain Identifier or a Variable that's not a NamespacedVariable:

    • Let scope be the scope of the innermost block containing the current statement such that scope has a member of type type named name, or null if no such scope exists.

    • If scope is not null, return scope's value of type type named name.

  • If name is a NamespacedIdentifier of the form namespace.raw-name or a Variable of the form namespace.$raw-name:

    • Let use be the @use rule in the current source file whose namespace is namespace. If there isn't exactly one such rule, throw an error.

      Unlike other identifiers in Sass, module namespaces do not treat - and _ as equivalent.

    • If use hasn't been executed yet, throw an error.

    • Otherwise, let module be use's module.

    • Return the member of module with type type and name raw-name. If there is no such member, throw an error.

  • If type is not "variable" and the current source file contains a top-level definition of a member of type type named name:

    Local function and mixin definitions shadow those from global @use rules, so that an upstream package adding a member is less likely to break its downstream dependencies. We exclude variables from this because a top-level variable definition will set the module's variable value rather than defining a new variable local to this module.

    • If the current import context contains a member member of type type named name, return it.

      This includes member definitions within the current module.

    • Otherwise, return null.

      It's an error to refer to a local member before it's defined, even if a member with the same name is defined in a loaded module. The referent to a member is guaranteed not to change due to definitions later in the file.

  • Let members be the set of unique members of type type named name in modules of the global @use rules.

  • If the current import context contains a member member of type type named name:

    • If members is not empty, throw an error.

    • Otherwise, return member.

  • Otherwise, if members contains more than one member, throw an error.

    This ensures that, if a new version of a library produces a conflicting name, it causes an immediate error.

  • Otherwise, if modules contains a single module, return the member of type type named name in that module.

  • Otherwise, if the implementation defines a global member member of type type named name, return that member.

    This includes the global functions and mixins defined as part of the Sass spec, and may also include other members defined through the implementation's host language API.

  • Otherwise, return null.