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 functionname
or the variable$name
.
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.
A configuration is a map from variable names to SassScript values and an opaque ID. An empty configuration contains no entries.
A new configuration ID is unique unless otherwise specified.
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.
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.
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.
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.
An importer is a function that takes a string that may be either a relative or absolute URL and returns three values: a string (the text of a stylesheet), a syntax ("indented", "scss", or "css"), and an absolute URL (that stylesheet's canonical URL). It may also return null to indicate that the importer doesn't recognize the URL in question or cannot find a corresponding stylesheet. If the URL is recognized but invalid, it should throw an error rather than returning null. What constitutes "recognized" or "invalid" is left up to the importer.
The details of an importer's behavior is typically defined by the end user in an implementation-specific way. However, all importers must adhere to the following contract:
-
When the URL returned by an importer is passed back to that importer, it must return the same result.
-
The importer must return the same result for all URLs that refer to the same file, although what specifically constitutes "the same file" is left up to the importer.
Importers are represented as a single function in the spec to simplify the writing of algorithms, but implementations are encouraged to have users instead define two separate functions: a
canonicalize()
function that converts an input string into a canonical URL, and aload()
function that loads the contents of a canonical URL. This allows implementations to avoid the overhead of reloading the same file over and over.
A filesystem importer is an importer with an associated absolute
file:
URL named base
. When a filesystem importer is invoked with a string
named string
:
-
Let
url
be the result of parsingstring
as a URL withbase
as the base URL. If this returns a failure, throw that failure. -
If
url
's scheme is notfile
, return null. -
Let
resolved
be the result of resolvingurl
. -
If
resolved
is null, return null. -
Let
text
be the contents of the file atresolved
. -
Let
syntax
be:- "scss" if
url
ends in.scss
. - "indented" if
url
ends in.sass
. - "css" if
url
ends in.css
.
The algorithm for resolving a
file:
URL guarantees thaturl
will have one of these extensions. - "scss" if
-
Return
text
,syntax
, andresolved
.
The global importer list is a list of importers that's set for the entire duration of a Sass compilation.
The basename of a URL is the final component of that URL's path.
The dirname of a URL is the prefix of that URL up to, but not including, the beginning of its basename.
The module system defines the following syntax for referring to names from other modules:
PublicIdentifier ::= <ident-token> that doesn't begin with '-' or '_' NamespacedIdentifier ::= <ident-token> | <ident-token> '.' PublicIdentifier
No whitespace is allowed before or after the '.'
in NamespacedIdentifier
.
This algorithm takes a string argument
and configuration
config
and returns a module:
-
If
argument
is a valid URL with schemesass
:-
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 atargument
. -
If
file
is null, throw an error. -
If
file
has already been executed by the Loading a Module procedure:-
If
config
is not empty and has a different ID than the configuration that was passed the first timefile
was executed by the Loading a Module procedure, throw an error.An ID may be reused in a new configuration via
@forward ... with
. -
Otherwise, return the module that execution produced.
-
-
If
file
is currently being executed, throw an error.This disallows circular
@use
s, which ensures that modules can't be used until they're fully initialized. -
Otherwise, return the result of executing
file
withconfig
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.
This algorithm takes a string, argument
, and returns either a source file or
null.
-
If
argument
is a relative URL:-
Let
resolved
be the result of parsingargument
as a URL with the current source file's canonical URL as the base URL. -
Let
result
be the result of passingresolved
to the current source file's importer. -
If
result
is not null:-
Let
ast
be the result of parsingresult
's text asresult
's syntax. -
Return a source file with
ast
as its abstract syntax tree,result
's URL as its canonical URL, and the current source file's importer as its importer.
-
-
-
For each
importer
in the global importer list:-
Let
result
be the result of passingargument
toimporter
. -
If
result
is not null:-
Let
ast
be the result of parsingresult
's text asresult
's syntax. -
Return a source file with
ast
as its abstract syntax tree,result
's URL as its canonical URL, andimporter
as its importer.
-
-
-
Return null.
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.
-
Let
resolved
be the result of resolvingurl
for extensions. -
If
resolved
is not null, return it. Otherwise: -
Let
index
beurl
+"/index"
-
Return the result of resolving
index
for extensions.
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
ends in.scss
,.sass
, or.css
:-
If this algorithm is being run for an
@import
:-
Let
suffix
be the trailing.scss
,.sass
,.css
inurl
, andprefix
the portion ofurl
beforesuffix
. -
If the result of resolving
prefix
+".import"
+suffix
for partials is not null, return it.
-
-
Otherwise, return the result of resolving
url
for partials.
@import
s whose URLs explicitly end in.css
will have been treated as plain CSS@import
s before this algorithm even runs, sourl
will only end in.css
for@use
rules. -
-
If this algorithm is being run for an
@import
:-
Let
sass
be the result of resolvingurl
+".import.sass"
for partials. -
Let
scss
be the result of resolvingurl
+".import.scss"
for partials. -
If neither
sass
norscss
are null, throw an error. -
Otherwise, if exactly one of
sass
andscss
is null, return the other one. -
Otherwise, if the result of resolving
url
+".import.css"
for partials is not null, return it.
-
-
Let
sass
be the result of resolvingurl
+".sass"
for partials. -
Let
scss
be the result of resolvingurl
+".scss"
for partials. -
If neither
sass
norscss
are null, throw an error. -
Otherwise, if exactly one of
sass
andscss
is null, return the other one. -
Otherwise, return the result of resolving
url
+".css"
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
, returnurl
.Otherwise return null.
-
-
Let
partial
bedirname(url)
+"_"
+basename(url)
. -
If a file exists on disk at both
url
andpartial
, throw an error. -
If a file exists on disk at
url
, returnurl
. -
If a file exists on disk at
partial
, returnpartial
. -
Return null.
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 plainIdentifier
or aVariable
that's not aNamespacedVariable
:-
Let
scope
be the scope of the innermost block containing the current statement such thatscope
has a member of typetype
namedname
, or null if no such scope exists. -
If
scope
is not null, returnscope
's value of typetype
namedname
.
-
-
If
name
is aNamespacedIdentifier
of the formnamespace.raw-name
or aVariable
of the formnamespace.$raw-name
:-
Let
use
be the@use
rule in the current source file whose namespace isnamespace
. 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
beuse
's module. -
Return the member of
module
with typetype
and nameraw-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 typetype
namedname
: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 typetype
namedname
, 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 typetype
namedname
in modules of the global@use
rules. -
If the current import context contains a member
member
of typetype
namedname
:-
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 typetype
namedname
in that module. -
Otherwise, if the implementation defines a global member
member
of typetype
namedname
, 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.