Add a Markdown linter (#3667)

This commit is contained in:
Natalie Weizenbaum 2023-08-22 14:10:27 -07:00 committed by GitHub
parent d874ddbaf3
commit 1523bffb36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
58 changed files with 1166 additions and 1012 deletions

View File

@ -16,7 +16,11 @@ jobs:
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: {node-version: '${{ env.NODE_VERSION }}'} with: {node-version: '${{ env.NODE_VERSION }}'}
- run: npm ci - run: npm ci
- run: npm run tangle && npx gts lint && npx tsc --noEmit - run: >
npm run tangle &&
npx gts lint &&
npx tsc --noEmit &&
npx markdownlint-cli2
toc: toc:
name: Tables of contents name: Tables of contents

27
.markdownlint-cli2.yaml Normal file
View File

@ -0,0 +1,27 @@
globs: ["**.md"]
ignores: ["node_modules/**"]
config:
# BNF syntax examples can go over length, and there's no way to exempt them
# specifically.
line-length: false
# We use inline HTML to format BNF syntax definitions.
no-inline-html: false
# We use untagged code blocks for function definitions.
fenced-code-language: false
emphasis-style:
style: asterisk
# We often have to have duplicate subheadings for different parents.
no-duplicate-heading: false
# We use multiple sequential blockquotes to indicate unrelated non-normative
# notes.
no-blanks-blockquote: false
# We use spaces in code formatting because spaces are relevant in Sass.
no-space-in-code: false
first-line-heading: false

View File

@ -172,7 +172,7 @@ accepted.
<x><pre> <x><pre>
**MinMaxExpression** ::= CssMinMax | FunctionExpression **MinMaxExpression** ::= CssMinMax | FunctionExpression
**CssMinMax** ::= ('min(' | 'max(') CalcValue (',' CalcValue)* ')' **CssMinMax** ::= ('min(' | 'max(') CalcValue (',' CalcValue)\* ')'
**CalcValue** ::= CalcValue (('+' | '-' | '*' | '/') CalcValue)+ **CalcValue** ::= CalcValue (('+' | '-' | '*' | '/') CalcValue)+
&#32; | '(' CalcValue ')' &#32; | '(' CalcValue ')'
&#32; | ('calc(' | 'env(' | 'var(') InterpolatedDeclarationValue ')' &#32; | ('calc(' | 'env(' | 'var(') InterpolatedDeclarationValue ')'

View File

@ -4,7 +4,7 @@
* Clarify the definition of bogus selectors. * Clarify the definition of bogus selectors.
* Only omit style rules if _all_ of their complex selectors are bogus. * Only omit style rules if *all* of their complex selectors are bogus.
* Expand the set of selectors that are treated by the extend algorithm as * Expand the set of selectors that are treated by the extend algorithm as
matching nothing to include bogus pseudo selectors, since these can never be matching nothing to include bogus pseudo selectors, since these can never be

View File

@ -119,7 +119,7 @@ combinator].
combinators*) as well as a sequence of [complex selector components]. Either, combinators*) as well as a sequence of [complex selector components]. Either,
but not both, of these sequences may be empty~~ but not both, of these sequences may be empty~~
[visible combinators]: #visible-combinator [visible combinators]: #visible-combinator
[complex selector components]: #complex-selector-component [complex selector components]: #complex-selector-component
A *complex selector* is an optional [visible combinator] (its *leading A *complex selector* is an optional [visible combinator] (its *leading
@ -127,7 +127,7 @@ combinator*) as well as a sequence of [complex selector components]. The
component sequence may be empty only for complex selectors with leading component sequence may be empty only for complex selectors with leading
combinators. combinators.
[visible combinator]: #visible-combinator [visible combinator]: #visible-combinator
### Complex Selector Component ### Complex Selector Component
@ -169,9 +169,9 @@ This proposal modifies the existing `ComplexSelector` and
`ComplexSelectorComponent` productions to drop support for multiple combinators: `ComplexSelectorComponent` productions to drop support for multiple combinators:
<x><pre> <x><pre>
~~**ComplexSelector** ::= [\<combinator>]* ComplexSelectorComponent+~~ ~~**ComplexSelector** ::= [\<combinator>]\* ComplexSelectorComponent+~~
~~&#32; | [\<combinator>]+~~ ~~&#32; | [\<combinator>]+~~
~~**ComplexSelectorComponent** ::= CompoundSelector [\<combinator>]*~~ ~~**ComplexSelectorComponent** ::= CompoundSelector [\<combinator>]\*~~
**ComplexSelector** ::= [\<combinator>]? ComplexSelectorComponent+ **ComplexSelector** ::= [\<combinator>]? ComplexSelectorComponent+
&#32; | [\<combinator>] &#32; | [\<combinator>]
**ComplexSelectorComponent** ::= CompoundSelector [\<combinator>]? **ComplexSelectorComponent** ::= CompoundSelector [\<combinator>]?
@ -228,7 +228,7 @@ In particular:
* The parsing of `ComplexSelector` and `ComplexSelectorComponent` is unchanged. * The parsing of `ComplexSelector` and `ComplexSelectorComponent` is unchanged.
* A complex selector is instead considered [bogus] if it would be bogus in Phase * A complex selector is instead considered [bogus] if it would be bogus in Phase
2 _or_ if it can be parsed in Phase 1 but not in Phase 2. 2 *or* if it can be parsed in Phase 1 but not in Phase 2.
* The newly-added errors produce deprecation warnings instead. * The newly-added errors produce deprecation warnings instead.

View File

@ -3,7 +3,7 @@
* Throw an error when serializing a degenerate number with complex units in a * Throw an error when serializing a degenerate number with complex units in a
calculation. calculation.
* Clarify that we're checking for degenerate _values_ in "Converting a Number to * Clarify that we're checking for degenerate *values* in "Converting a Number to
a Calculation". a Calculation".
* Use `UnquotedString`s to represent unknown calculation constants rather than * Use `UnquotedString`s to represent unknown calculation constants rather than

View File

@ -68,16 +68,16 @@ silence real errors without providing any actual value.
[Converting a Number to a Calculation]: #converting-a-number-to-a-calculation [Converting a Number to a Calculation]: #converting-a-number-to-a-calculation
Whether and how we want to support this once browsers _can_ parse it is a Whether and how we want to support this once browsers *can* parse it is a
question for another time. question for another time.
## Definitions ## Definitions
### Degenerate Number ### Degenerate Number
The doubles `Infinity`, `-Infinity`, and `NaN` are _degenerate_. The doubles `Infinity`, `-Infinity`, and `NaN` are *degenerate*.
A number is _degenerate_ if its value is degenerate. A number is *degenerate* if its value is degenerate.
## Syntax ## Syntax

View File

@ -18,7 +18,7 @@
## Draft 1.4 ## Draft 1.4
* Don't exempt percentages from most functions' simplification logic, since * Don't exempt percentages from most functions' simplification logic, since
those functions don't allow _any_ units in CSS, including percents. Now only those functions don't allow *any* units in CSS, including percents. Now only
`abs()`, `sign()`, `atan2()`, and `hypot()` check for known units because CSS `abs()`, `sign()`, `atan2()`, and `hypot()` check for known units because CSS
allows percentages for them but they aren't linear so they can't be resolved allows percentages for them but they aren't linear so they can't be resolved
in terms of percentages in Sass. in terms of percentages in Sass.

View File

@ -73,7 +73,7 @@ calculations.
#### Changing Mod Infinity Behavior #### Changing Mod Infinity Behavior
This proposal changes the behavior of the `%` operation when the right-hand side This proposal changes the behavior of the `%` operation when the right-hand side
is infinite _and_ has a different sign than the left-hand side. Sass used to is infinite *and* has a different sign than the left-hand side. Sass used to
return the right-hand side in accordance with the floating point specification, return the right-hand side in accordance with the floating point specification,
but it now returns NaN to match CSS's `mod()` function. but it now returns NaN to match CSS's `mod()` function.
@ -334,7 +334,7 @@ This algorithm takes a calculation `calc` and returns a number or a calculation.
> In this case, `number` is either `+0`, `-0`, or NaN. > In this case, `number` is either `+0`, `-0`, or NaN.
> To match CSS's behavior, these computations _don't_ use fuzzy comparisons. > To match CSS's behavior, these computations *don't* use fuzzy comparisons.
* If `calc`'s name is `"log"`: * If `calc`'s name is `"log"`:
@ -533,7 +533,7 @@ To evaluate a `UnaryCalcExpression`, `BinaryCalcExpression`, `HypotExpression`,
Add `"round"`, `"mod"`, `"rem"`, `"sin"`, `"cos"`, `"tan"`, `"asin"`, `"acos"`, Add `"round"`, `"mod"`, `"rem"`, `"sin"`, `"cos"`, `"tan"`, `"asin"`, `"acos"`,
`"atan"`, `atan2""`, `"pow"`, `"sqrt"`, `"hypot"`, `"log"`, `"exp"`, `"abs"`, `"atan"`, `atan2""`, `"pow"`, `"sqrt"`, `"hypot"`, `"log"`, `"exp"`, `"abs"`,
and `"sign"` to the set of prohibited function names. Do _not_ prohibit and `"sign"` to the set of prohibited function names. Do *not* prohibit
vendor-prefixed versions of these names. vendor-prefixed versions of these names.
> No browser has ever supported a vendor-prefixed version of these names, and > No browser has ever supported a vendor-prefixed version of these names, and
@ -583,7 +583,7 @@ Phase 2 implements all the changes described above, with the following
exceptions: exceptions:
1. When simplifying a calculation named `"abs"` whose sole argument is a number 1. When simplifying a calculation named `"abs"` whose sole argument is a number
_without_ [known units], return the result of calling `math.abs()` with that *without* [known units], return the result of calling `math.abs()` with that
number and emit a deprecation warning named `abs-percent`. number and emit a deprecation warning named `abs-percent`.
2. No new `@function` names are forbidden. 2. No new `@function` names are forbidden.

View File

@ -290,8 +290,6 @@ export type CalculationOperator = '+' | '-' | '*' | '/';
The JS API representation of a Sass [`CalculationOperation`]. The JS API representation of a Sass [`CalculationOperation`].
[CalculationOperation]: ../spec/types/calculation.md#types
```ts ```ts
export class CalculationOperation implements ValueObject { export class CalculationOperation implements ValueObject {
``` ```

View File

@ -3,7 +3,7 @@
*([Issue](https://github.com/sass/sass/issues/2834))* *([Issue](https://github.com/sass/sass/issues/2834))*
This proposal adds a new `hwb()` color format to the `sass:color` module, along This proposal adds a new `hwb()` color format to the `sass:color` module, along
with inspection and adjustment options for _whiteness_ and _blackness_. with inspection and adjustment options for *whiteness* and *blackness*.
## Table of Contents ## Table of Contents
@ -42,12 +42,12 @@ module to avoid conflicts with the CSS syntax, and will be converted to more
common color-name, hex, or `rgba()` syntax for output -- following the same common color-name, hex, or `rgba()` syntax for output -- following the same
logic as our current color functions. logic as our current color functions.
- New `color.hwb()` function describes colors in the sRGB colorspace using * New `color.hwb()` function describes colors in the sRGB colorspace using
`$hue` (defined identically to the `hsl()` "hue" value), along with `$hue` (defined identically to the `hsl()` "hue" value), along with
`$whiteness`, `$blackness`, and optional `$alpha` transparency. `$whiteness`, `$blackness`, and optional `$alpha` transparency.
- New `color.whiteness()` and `color.blackness()` functions return the respective * New `color.whiteness()` and `color.blackness()` functions return the respective
values of `w` or `b` for a given color. values of `w` or `b` for a given color.
- Existing `color.adjust()`, `color.scale()`, and `color.change()` functions will * Existing `color.adjust()`, `color.scale()`, and `color.change()` functions will
accept additional `$whiteness` and `$blackness` parameters before the final accept additional `$whiteness` and `$blackness` parameters before the final
`$alpha` parameter. `$alpha` parameter.
@ -137,7 +137,6 @@ All new functions are part of the `sass:color` built-in module.
[percent-converting]: ../spec/built-in-modules/color.md#percent-converting-a-number [percent-converting]: ../spec/built-in-modules/color.md#percent-converting-a-number
[to RGB]: https://www.w3.org/TR/css-color-4/#hwb-to-rgb [to RGB]: https://www.w3.org/TR/css-color-4/#hwb-to-rgb
* ``` * ```
hwb($channels) hwb($channels)
``` ```

View File

@ -4,6 +4,7 @@
[Changelog](deprecations-api.changes.md))* [Changelog](deprecations-api.changes.md))*
## Table of Contents ## Table of Contents
* [Background](#background) * [Background](#background)
* [Summary](#summary) * [Summary](#summary)
* [Design Decisions](#design-decisions) * [Design Decisions](#design-decisions)
@ -110,7 +111,7 @@ that applies only to itself, it may still do so.
Additionally, while a deprecation's status is part of the specification, we Additionally, while a deprecation's status is part of the specification, we
chose to leave the `deprecatedIn` and `obsoleteIn` versions of each chose to leave the `deprecatedIn` and `obsoleteIn` versions of each
deprecation out of the specification. As the two current implementers of this deprecation out of the specification. As the two current implementers of this
API are both based on Dart Sass, these versions are _currently_ consistent API are both based on Dart Sass, these versions are *currently* consistent
across implementations in practice, potential future implementers should not across implementations in practice, potential future implementers should not
need to be tied to Dart Sass's versioning. need to be tied to Dart Sass's versioning.
@ -579,6 +580,7 @@ the compiler must respond with a `CompileFailure` instead of a `CompileSuccess`.
The compiler must emit an event of type `LogEventType.WARNING` if any of the The compiler must emit an event of type `LogEventType.WARNING` if any of the
following is true: following is true:
* an invalid deprecation ID is passed * an invalid deprecation ID is passed
* an obsolete deprecation ID is passed * an obsolete deprecation ID is passed
* a future deprecation ID is passed that is not also passed to * a future deprecation ID is passed that is not also passed to

View File

@ -62,7 +62,7 @@ This proposal makes three breaking changes to the embedded Sass protocol:
#### Length Before Compilation ID #### Length Before Compilation ID
This proposal places the compilation ID for each request _after_ the length. The This proposal places the compilation ID for each request *after* the length. The
length is defined as the length of the protocol buffer plus the length of the length is defined as the length of the protocol buffer plus the length of the
compilation ID. compilation ID.
@ -101,7 +101,7 @@ length of the compilation ID, which is given by the following table:
#### Cross-Compilation State #### Cross-Compilation State
We have a [future goal] to (optionally) share state _across_ compilations, to We have a [future goal] to (optionally) share state *across* compilations, to
more efficiently compile projects with many small entrypoints where the bulk of more efficiently compile projects with many small entrypoints where the bulk of
the complexity is in static shared libraries. If/when we support this, there the complexity is in static shared libraries. If/when we support this, there
could be two broad implementation strategies for a compiler with worker-based could be two broad implementation strategies for a compiler with worker-based
@ -139,8 +139,8 @@ compilation ID will only have one request at a time, so we could just declare
that any response with a given compilation ID is for the single outstanding that any response with a given compilation ID is for the single outstanding
request. request.
However, the _expectation_ that each compilation be single-threaded isn't a However, the *expectation* that each compilation be single-threaded isn't a
_requirement_. One could imagine a multithreaded Sass compiler that actually is *requirement*. One could imagine a multithreaded Sass compiler that actually is
capable of fielding multiple concurrent requests as it compiles independent capable of fielding multiple concurrent requests as it compiles independent
chunks of a given stylesheet or resolves loads eagerly. We don't want to cut off chunks of a given stylesheet or resolves loads eagerly. We don't want to cut off
this possibility, so we retain the outbound request IDs. this possibility, so we retain the outbound request IDs.
@ -153,12 +153,12 @@ Replace the last paragraph of the [embedded protocol overview] with:
[embedded protocol overview]: ../spec/embedded-protocol.md#overview [embedded protocol overview]: ../spec/embedded-protocol.md#overview
Each message in the embedded protocol is sent as a _packet_ which contains two Each message in the embedded protocol is sent as a *packet* which contains two
values: an unsigned [varint] up to 32 bits long known as the "compilation ID", values: an unsigned [varint] up to 32 bits long known as the "compilation ID",
and a protocol buffer that contains the protobuf message. For streams (like and a protocol buffer that contains the protobuf message. For streams (like
standard input and output) that don't have built-in message boundaries, every standard input and output) that don't have built-in message boundaries, every
packet must begin with another unsigned varint indicating the length in bytes of packet must begin with another unsigned varint indicating the length in bytes of
the remaining message (_including the compilation ID_). This matches the best the remaining message (*including the compilation ID*). This matches the best
practice described in [the protocol buffer documentation]. practice described in [the protocol buffer documentation].
Because JavaScript can't easily represent integers larger than 2^53 - 1, the Because JavaScript can't easily represent integers larger than 2^53 - 1, the

View File

@ -18,7 +18,7 @@ extend(a.foo, a, b) = a.foo, b.foo
extend(c, a, b) = c extend(c, a, b) = c
``` ```
### Specificity of the Base Selector ## Specificity of the Base Selector
Note that so far, it's always the case that `extend(S, A, B)[0] = S`. However, Note that so far, it's always the case that `extend(S, A, B)[0] = S`. However,
consider `extend(a.foo, .foo, a)`. One interpretation of this would give the consider `extend(a.foo, .foo, a)`. One interpretation of this would give the
@ -62,12 +62,12 @@ This new selector has higher specificity than the original. As such, we must
allow the generated selector to have higher specificity than the original in allow the generated selector to have higher specificity than the original in
some cases. some cases.
#### First Law of Extend: `spec(extend(S, A, B)[0]) >= spec(S)` ### First Law of Extend: `spec(extend(S, A, B)[0]) >= spec(S)`
This is not always the behavior in Sass, either in master or in stable; this is This is not always the behavior in Sass, either in master or in stable; this is
clearly a bug that should be fixed. clearly a bug that should be fixed.
### Specificity of Generated Selectors ## Specificity of Generated Selectors
Now that we've established what `spec(extend(S, A, B)[0])` should look like, Now that we've established what `spec(extend(S, A, B)[0])` should look like,
it's time to think about what `spec(extend(S, A, B)[1])` should look like as it's time to think about what `spec(extend(S, A, B)[1])` should look like as
@ -97,9 +97,9 @@ There is one guarantee we can make, though:
`spec(extend(S, A, B)[1]) >= spec(B)`, since everything in `S` is either merged `spec(extend(S, A, B)[1]) >= spec(B)`, since everything in `S` is either merged
with or added to `B`. with or added to `B`.
#### Second Law of Extend: `spec(extend(S, A, B)[1]) >= spec(B)` ### Second Law of Extend: `spec(extend(S, A, B)[1]) >= spec(B)`
### Implications for Optimization ## Implications for Optimization
The ultimate goal of this discussion is, of course, that we want to be able to The ultimate goal of this discussion is, of course, that we want to be able to
perform certain optimizations on the generated selectors in order to reduce perform certain optimizations on the generated selectors in order to reduce
@ -120,7 +120,7 @@ However, many of the optimizations added in [8f4869e][] do still work. For
example, `extend(.bar a, a, a.foo) = .bar a` works because example, `extend(.bar a, a, a.foo) = .bar a` works because
`spec(.bar a) = spec(a.foo)`. `spec(.bar a) = spec(a.foo)`.
### Conclusion ## Conclusion
As long as we make the `@extend` optimizer specificity-aware, we can retain a As long as we make the `@extend` optimizer specificity-aware, we can retain a
number of useful optimizations while still providing the same guarantees that number of useful optimizations while still providing the same guarantees that

View File

@ -380,8 +380,6 @@ case-insensitively.
†: These productions are invalid in plain CSS syntax. †: These productions are invalid in plain CSS syntax.
[`<function-token>`]: https://drafts.csswg.org/css-syntax-3/#ref-for-typedef-function-token%E2%91%A0
> The `CalcArgument` production provides backwards-compatibility with the > The `CalcArgument` production provides backwards-compatibility with the
> historical use of interpolation to inject SassScript values into `calc()` > historical use of interpolation to inject SassScript values into `calc()`
> expressions. Because interpolation could inject any part of a `calc()` > expressions. Because interpolation could inject any part of a `calc()`
@ -544,12 +542,12 @@ This algorithm takes a `CalculationValue` `value` and returns a
* If `value` is a calculation: * If `value` is a calculation:
* Let `result` be the result of [simplifying] `value`. * Let `result` be the result of [simplifying] `value`.
* If `result` is a calculation whose name is `"calc"`, return `result`'s * If `result` is a calculation whose name is `"calc"`, return `result`'s
single argument. single argument.
* Otherwise, return `result`. * Otherwise, return `result`.
[simplifying]: #simplifying-a-calculation [simplifying]: #simplifying-a-calculation

View File

@ -660,8 +660,6 @@ Replace this function's procedure with:
* Let `double` be the value of [converting `$number` to `rad`] allowing * Let `double` be the value of [converting `$number` to `rad`] allowing
unitless. unitless.
[converting `$number` to `rad`]: #converting-a-number-to-units
* Return a unitless number whose value is the result of `sin(double)` as defined * Return a unitless number whose value is the result of `sin(double)` as defined
by [IEEE 754 2019], §9.2. by [IEEE 754 2019], §9.2.
@ -672,8 +670,6 @@ Replace this function's procedure with:
* Let `double` be the value of [converting `$number` to `rad`] allowing * Let `double` be the value of [converting `$number` to `rad`] allowing
unitless. unitless.
[converting `$number` to `rad`]: #converting-a-number-to-units
* Return a unitless number whose value is the result of `tan(double)` as defined * Return a unitless number whose value is the result of `tan(double)` as defined
by [IEEE 754 2019], §9.2. by [IEEE 754 2019], §9.2.

View File

@ -46,23 +46,23 @@ I propose that, as today, `#{}` be allowed either within strings (quoted or
unquoted) or on its own. However, its effect will be limited to the strings that unquoted) or on its own. However, its effect will be limited to the strings that
contain it or to its own value. Specifically: contain it or to its own value. Specifically:
- When parsing or evaluating a quoted string, treat interpolation the same way * When parsing or evaluating a quoted string, treat interpolation the same way
it's treated today. it's treated today.
- When parsing an identifier, treat interpolation as though it's an alphabetic * When parsing an identifier, treat interpolation as though it's an alphabetic
character. When evaluating an interpolated unquoted string, concatenate the character. When evaluating an interpolated unquoted string, concatenate the
literal identifier characters with the values of the interpolated segments. literal identifier characters with the values of the interpolated segments.
- Otherwise, parse an interpolation as an individual expression. When evaluating * Otherwise, parse an interpolation as an individual expression. When evaluating
it, return its value as an unquoted string. it, return its value as an unquoted string.
Here are some examples (I'm including quotes for unquoted strings in the output Here are some examples (I'm including quotes for unquoted strings in the output
to clarify their extents): to clarify their extents):
- `"a #{b} c"` would continue to produce `"a b c"`. * `"a #{b} c"` would continue to produce `"a b c"`.
- `a#{b}c` would continue to produce `"abc"`. * `a#{b}c` would continue to produce `"abc"`.
- `a #{b}c` currently produces `"a bc"` but would produce `"a" "bc"`. * `a #{b}c` currently produces `"a bc"` but would produce `"a" "bc"`.
- `a#{b} c` currently produces `"ab c"` but would produce `"ab" "c"`. * `a#{b} c` currently produces `"ab c"` but would produce `"ab" "c"`.
- `a b#{c}d e` currently produces `"a bcd e"` but would produce `"a" "bcd" "e"`. * `a b#{c}d e` currently produces `"a bcd e"` but would produce `"a" "bcd" "e"`.
- `a #{b} c` currently produces `"a b c"` but would produce `"a" "b" "c"`. * `a #{b} c` currently produces `"a b c"` but would produce `"a" "b" "c"`.
## Design decisions ## Design decisions
@ -77,24 +77,24 @@ various situations.
### Interpolation in unquoted strings ### Interpolation in unquoted strings
It was tempting to restrict interpolation for use _only_ in quoted strings. It was tempting to restrict interpolation for use *only* in quoted strings.
Interpolation in unquoted strings can be mimicked using `+`, and allowing it in Interpolation in unquoted strings can be mimicked using `+`, and allowing it in
unquoted strings could produce the incorrect impression that interpolation is unquoted strings could produce the incorrect impression that interpolation is
performed before any other SassScript resolution. However, we decided to allow performed before any other SassScript resolution. However, we decided to allow
this for several reasons: this for several reasons:
- Backwards compatibility, as described above. * Backwards compatibility, as described above.
- Similarity with quoted strings. It's not always obvious that unquoted strings * Similarity with quoted strings. It's not always obvious that unquoted strings
and quoted strings are the same sorts of value under the hood, but sharing and quoted strings are the same sorts of value under the hood, but sharing
capabilities helps reinforce that idea. capabilities helps reinforce that idea.
- Similarity with other identifiers. Interpolation can be used in almost all * Similarity with other identifiers. Interpolation can be used in almost all
most non-SassScript contexts where identifiers appear, most notably property most non-SassScript contexts where identifiers appear, most notably property
names, so it's natural that users would think that all Sass identifiers can be names, so it's natural that users would think that all Sass identifiers can be
interpolated. interpolated.
- Vendor prefixes. It would be very difficult to dynamically choose vendor * Vendor prefixes. It would be very difficult to dynamically choose vendor
prefixes for function names or other values, since `-` on its own is not an prefixes for function names or other values, since `-` on its own is not an
identifier. identifier.
- Aesthetics. Although `font-stretch: $amount + -condensed` is legal, it's less * Aesthetics. Although `font-stretch: $amount + -condensed` is legal, it's less
clear and less pleasant than `font-stretch: #{$amount}-condensed`. clear and less pleasant than `font-stretch: #{$amount}-condensed`.
### Interpolation outside of strings ### Interpolation outside of strings
@ -128,13 +128,13 @@ rules, and E the value of the same expression under the new rules. Let S2 be the
conversion of E to CSS. For example, suppose the expression in question is conversion of E to CSS. For example, suppose the expression in question is
`a #{b} + c`. S1 is `"a b + c"`, E is `"a" "bc"`, and S2 is `"a bc"`. `a #{b} + c`. S1 is `"a b + c"`, E is `"a" "bc"`, and S2 is `"a bc"`.
- If S1 and S2 aren't semantically identical when interpreted as CSS, issue a * If S1 and S2 aren't semantically identical when interpreted as CSS, issue a
warning. This means that `#{a} + b` would emit a warning since S1 is `"a + b"` warning. This means that `#{a} + b` would emit a warning since S1 is `"a + b"`
but S2 is `"ab"`. However, `#{a} b c` would not emit a warning, since S1 and but S2 is `"ab"`. However, `#{a} b c` would not emit a warning, since S1 and
S2 are both `"a b c"`. Note that an expressions like `#{a} / b` _should not_ S2 are both `"a b c"`. Note that an expressions like `#{a} / b` *should not*
emit a warning here, since we know that it will produce `a/b` under the new emit a warning here, since we know that it will produce `a/b` under the new
semantics. semantics.
- Otherwise, if E is not a string, set an "interpolated" flag on S1. If any * Otherwise, if E is not a string, set an "interpolated" flag on S1. If any
operation is performed on S1 that wouldn't first convert it to a string, emit operation is performed on S1 that wouldn't first convert it to a string, emit
a warning. a warning.
@ -146,14 +146,14 @@ problem in the second case, which we'll get to below.
In service of determining how to go about deprecating the current semantics of In service of determining how to go about deprecating the current semantics of
SassScript interpolation, I want to precisely define them. For our purposes, we SassScript interpolation, I want to precisely define them. For our purposes, we
only care about _free interpolation_—that is, interpolation outside the context only care about *free interpolation*—that is, interpolation outside the context
of a string or a special function (e.g. `calc()`) that's parsed like a string. of a string or a special function (e.g. `calc()`) that's parsed like a string.
The grammar for interpolation is straightforward. Note that the representation The grammar for interpolation is straightforward. Note that the representation
below elides much of the unrelated complexity of the SassScript grammar. The below elides much of the unrelated complexity of the SassScript grammar. The
`Operation` and `UnaryOperation` productions should be understood to encompass `Operation` and `UnaryOperation` productions should be understood to encompass
all binary and unary operations supported by SassScript, except for `,` which is all binary and unary operations supported by SassScript, except for `,` which is
handled by the `CommaList` production. Note that this _includes_ the implicit handled by the `CommaList` production. Note that this *includes* the implicit
adjacency operator that normally creates space-separated lists. `Value` should adjacency operator that normally creates space-separated lists. `Value` should
be understood to encompass literals, parenthesized expressions, maps, and be understood to encompass literals, parenthesized expressions, maps, and
function calls. function calls.
@ -192,8 +192,8 @@ If there was any whitespace in the source text between the operator and the
| `-#{1}` | ``` `-#{1}` ``` | `-1` | | `-#{1}` | ``` `-#{1}` ``` | `-1` |
| `- #{1}` | ``` `- #{1}` ``` | `- 1` | | `- #{1}` | ``` `- #{1}` ``` | `- 1` |
For an `Operation` production, all _adjacent_ `UnaryOperation` sub-expressions For an `Operation` production, all *adjacent* `UnaryOperation` sub-expressions
that are _not_ `Interpolation`s are parsed as normal, and interpolated into the that are *not* `Interpolation`s are parsed as normal, and interpolated into the
ESI alongside the `Interpolation` subexpressions, separated by the operation in ESI alongside the `Interpolation` subexpressions, separated by the operation in
question. As with a `UnaryOperation`, a space will be included before or after question. As with a `UnaryOperation`, a space will be included before or after
the `Interpolation`s depending on whether whitespace appeared in the the `Interpolation`s depending on whether whitespace appeared in the
@ -212,7 +212,7 @@ have a space operator.
| `a#{b}c` | ``` `#{a}#{b}#{c}` ``` | `abc` | | `a#{b}c` | ``` `#{a}#{b}#{c}` ``` | `abc` |
Finally, `CommaList` productions behave almost the same as `Operation`s. The Finally, `CommaList` productions behave almost the same as `Operation`s. The
only difference is that if _only_ the first `Operation` sub-expression is an only difference is that if *only* the first `Operation` sub-expression is an
`Interpolation`, the rest of the list isn't included in the interpolation. `Interpolation`, the rest of the list isn't included in the interpolation.
| SassScript | ESI | CSS | | SassScript | ESI | CSS |
@ -228,8 +228,8 @@ Now that we (hopefully) have a clear idea of how free interpolation works right
now, we can start figuring out the surface area that needs deprecation warnings now, we can start figuring out the surface area that needs deprecation warnings
when moving to the new semantics. when moving to the new semantics.
Ideally, we want to warn only when the new semantics will produce _semantically Ideally, we want to warn only when the new semantics will produce *semantically
different_ CSS output. In practice determining this exactly isn't always different* CSS output. In practice determining this exactly isn't always
feasible, since free interpolation produces values that can be used in many feasible, since free interpolation produces values that can be used in many
heterogeneous ways, so instead we'll warn if the values they produce are ever heterogeneous ways, so instead we'll warn if the values they produce are ever
used in a way that will change behavior under the new semantics. used in a way that will change behavior under the new semantics.
@ -268,7 +268,7 @@ different meanings. This includes any operators that don't insert their own
textual representation when operating on a string. textual representation when operating on a string.
The following operators and their inverses should produce warnings immediately. The following operators and their inverses should produce warnings immediately.
Note that _any expression_ containing free interpolation whose new ESI contains Note that *any expression* containing free interpolation whose new ESI contains
these operators should have an immediate warning, even if they also include these operators should have an immediate warning, even if they also include
other operators. other operators.
@ -328,7 +328,7 @@ the first and fourth should not, as their stringifications remain the same.
There is one case where the new behavior differs from the old. It comes up when There is one case where the new behavior differs from the old. It comes up when
a dynamic value is included in an interpolated string without an explicit a dynamic value is included in an interpolated string without an explicit
`#{}`—that is, for every location that doesn't have a `#{}` in the SassScript `#{}`—that is, for every location that doesn't have a `#{}` in the SassScript
but does in the ESI. _If that value is a quoted string_, it will retain its but does in the ESI. *If that value is a quoted string*, it will retain its
quotes, where if it were explicitly interpolated it would lose them. For quotes, where if it were explicitly interpolated it would lose them. For
example: example:
@ -375,30 +375,30 @@ as a list. When passing an interpolation value produced via a list operator to
such a function, the implementation should emit a deprecation warning. Of the such a function, the implementation should emit a deprecation warning. Of the
canonical Sass functions, this includes: canonical Sass functions, this includes:
- `unquote()` * `unquote()`
- `quote()` * `quote()`
- `str-length()` * `str-length()`
- The first or second argument of `str-insert()` * The first or second argument of `str-insert()`
- `str-index()` * `str-index()`
- The first argument of `str-slice()` * The first argument of `str-slice()`
- `to-upper-case()` * `to-upper-case()`
- `to-lower-case()` * `to-lower-case()`
- `length()` * `length()`
- The first argument of `nth()` * The first argument of `nth()`
- The first argument of `set-nth()` * The first argument of `set-nth()`
- `join()` * `join()`
- The first or last argument of `append()` * The first or last argument of `append()`
- `zip()` * `zip()`
- The first argument of `index()` * The first argument of `index()`
- `list-separator()` * `list-separator()`
- `feature-exists()` * `feature-exists()`
- `variable-exists()` * `variable-exists()`
- `global-variable-exists()` * `global-variable-exists()`
- `function-exists()` * `function-exists()`
- `mixin-exists()` * `mixin-exists()`
- `inspect()` * `inspect()`
- `type-of()` * `type-of()`
- The first argument of `call()` * The first argument of `call()`
It's up to each implementation to determine whether to emit warnings for which It's up to each implementation to determine whether to emit warnings for which
user-defined functions. user-defined functions.

View File

@ -131,15 +131,12 @@ This production has the same grammar as [`<ident-token>`][].
This algorithm consumes input from a stream of [code points][] and returns a This algorithm consumes input from a stream of [code points][] and returns a
sequence of strings and/or expressions. sequence of strings and/or expressions.
[code points]: https://infra.spec.whatwg.org/#code-point
The grammar for this production is: The grammar for this production is:
<x><pre> <x><pre>
**InterpolatedIdentifier** ::= ([\<ident-token>][`<ident-token>`] | '-'? Interpolation) ([Name](#consuming-a-name) | Interpolation)* **InterpolatedIdentifier** ::= ([\<ident-token>][`<ident-token>`] | '-'? Interpolation) ([Name](#consuming-a-name) | Interpolation)*
</pre></x> </pre></x>
[name-start code point]: https://drafts.csswg.org/css-syntax-3/#name-start-code-point
[escape]: https://drafts.csswg.org/css-syntax-3/#escape-diagram [escape]: https://drafts.csswg.org/css-syntax-3/#escape-diagram
No whitespace is allowed between components of an `InterpolatedIdentifier`. No whitespace is allowed between components of an `InterpolatedIdentifier`.
@ -219,10 +216,9 @@ This production has the same grammar as [`escape`][escape] in CSS Syntax Level 3
[non-printable code point]: https://drafts.csswg.org/css-syntax-3/#non-printable-code-point [non-printable code point]: https://drafts.csswg.org/css-syntax-3/#non-printable-code-point
[digit]: https://drafts.csswg.org/css-syntax-3/#digit [digit]: https://drafts.csswg.org/css-syntax-3/#digit
* Let `code` be the lowercase hexadecimal representation of `codepoint`, * Let `code` be the lowercase hexadecimal representation of `codepoint`,
with no leading `0`s. with no leading `0`s.
* Return `"\"` + `code` + `" "`. * Return `"\"` + `code` + `" "`.
* Otherwise, return `"\"` + `character`. * Otherwise, return `"\"` + `character`.

View File

@ -139,7 +139,6 @@ created, if the type is not specified, it is considered *explicit*.
This proposal modifies the fourth bullet of the [Loading Modules][] procedure This proposal modifies the fourth bullet of the [Loading Modules][] procedure
within the [module system spec][] to read as follows: within the [module system spec][] to read as follows:
* If `file` has already been [executed][]: * If `file` has already been [executed][]:
* If `config` is **explicit and** not empty, throw an error. * If `config` is **explicit and** not empty, throw an error.

View File

@ -61,8 +61,8 @@ all identifiers matched case-insensitively):
<x><pre> <x><pre>
**MediaQuery** ::= MediaNot **MediaQuery** ::= MediaNot
&#32; | MediaInParens (MediaAnd* | MediaOr*) &#32; | MediaInParens (MediaAnd\* | MediaOr\*)
&#32; | MediaType ('and' MediaNot | MediaAnd*) &#32; | MediaType ('and' MediaNot | MediaAnd\*)
**MediaType** ::= [InterpolatedIdentifier] [InterpolatedIdentifier]¹? **MediaType** ::= [InterpolatedIdentifier] [InterpolatedIdentifier]¹?
**MediaNot**² ::= 'not' MediaOrInterp **MediaNot**² ::= 'not' MediaOrInterp
**MediaAnd**² ::= 'and' MediaOrInterp **MediaAnd**² ::= 'and' MediaOrInterp
@ -73,7 +73,7 @@ all identifiers matched case-insensitively):
&#32; | '(' Expression³ [\<mf-lt>] Expression³ [\<mf-lt>] Expression³ ')' &#32; | '(' Expression³ [\<mf-lt>] Expression³ [\<mf-lt>] Expression³ ')'
&#32; | '(' Expression³ [\<mf-gt>] Expression³ [\<mf-gt>] Expression³ ')' &#32; | '(' Expression³ [\<mf-gt>] Expression³ [\<mf-gt>] Expression³ ')'
&#32; | '(' MediaNot ')' &#32; | '(' MediaNot ')'
&#32; | '(' MediaInParens (MediaAnd* | MediaOr*) ')' &#32; | '(' MediaInParens (MediaAnd\* | MediaOr\*) ')'
</pre></x> </pre></x>
[InterpolatedIdentifier]: ../spec/syntax.md#interpolatedidentifier [InterpolatedIdentifier]: ../spec/syntax.md#interpolatedidentifier

View File

@ -69,7 +69,6 @@ intended to replace the existing syntax.
&#32; | '(' Expression² <mf-gt> Expression² <mf-gt> Expression² ')' &#32; | '(' Expression² <mf-gt> Expression² <mf-gt> Expression² ')'
</pre></x> </pre></x>
1: This `InterpolatedIdentifier` may not be the identifier `"and"`. 1: This `InterpolatedIdentifier` may not be the identifier `"and"`.
2: These `Expression`s may not contain binary operator expressions with the 2: These `Expression`s may not contain binary operator expressions with the

View File

@ -81,7 +81,7 @@ The grammar for this production is:
<x><pre> <x><pre>
**MinMaxExpression** ::= CssMinMax | FunctionExpression **MinMaxExpression** ::= CssMinMax | FunctionExpression
**CssMinMax** ::= ('min(' | 'max(') CalcValue (',' CalcValue)* ')' **CssMinMax** ::= ('min(' | 'max(') CalcValue (',' CalcValue)\* ')'
**CalcValue** ::= CalcValue (('+' | '-' | '*' | '/') CalcValue)+ **CalcValue** ::= CalcValue (('+' | '-' | '*' | '/') CalcValue)+
&#32; | '(' CalcValue ')' &#32; | '(' CalcValue ')'
&#32; | ('calc(' | 'env(' | 'var(') InterpolatedDeclarationValue ')' &#32; | ('calc(' | 'env(' | 'var(') InterpolatedDeclarationValue ')'

View File

@ -777,7 +777,7 @@ controlled as explicitly as members can.
> ``` > ```
> >
> isn't identical (from a downstream user's perspective) to > isn't identical (from a downstream user's perspective) to
> >
> ```scss > ```scss
> .foo, .bar { /* ... */ } > .foo, .bar { /* ... */ }
> ``` > ```
@ -853,7 +853,6 @@ CSS for *all* modules transitively used or forwarded by `starting-module`.
* Add a copy of `extension` with its extender replaced by `complex` to * Add a copy of `extension` with its extender replaced by `complex` to
`new-extensions[domestic]`. `new-extensions[domestic]`.
[the first law of extend]: ../spec/at-rules/extend.md#specificity
[the specificity laws of extend]: ../spec/at-rules/extend.md#specificity [the specificity laws of extend]: ../spec/at-rules/extend.md#specificity
* Let `css` be an empty CSS tree. * Let `css` be an empty CSS tree.
@ -867,7 +866,7 @@ CSS for *all* modules transitively used or forwarded by `starting-module`.
> Because this traverses modules depth-first, it emits CSS in reverse > Because this traverses modules depth-first, it emits CSS in reverse
> topological order. > topological order.
* Let `initial-imports` be the longest initial subsequence of top-level * Let `initial-imports` be the longest initial subsequence of top-level
statements in `domestic`'s CSS that contains only comments and `@import` statements in `domestic`'s CSS that contains only comments and `@import`
rules *and* that ends with an `@import` rule. rules *and* that ends with an `@import` rule.
@ -888,7 +887,6 @@ CSS for *all* modules transitively used or forwarded by `starting-module`.
* Return `css`. * Return `css`.
[queue]: https://en.wikipedia.org/wiki/Queue_(abstract_data_type)
[topological]: https://en.wikipedia.org/wiki/Topological_sorting [topological]: https://en.wikipedia.org/wiki/Topological_sorting
### Resolving a `file:` URL ### Resolving a `file:` URL
@ -1096,7 +1094,7 @@ Given a source file `file`, a [configuration](#configuration) `config`, and an
* Remove any [complex selectors][] containing a placeholder selector that * Remove any [complex selectors][] containing a placeholder selector that
begins with `-` or `_` from `css`. begins with `-` or `_` from `css`.
* Remove any style rules that now have no selector from `css`. * Remove any style rules that now have no selector from `css`.
* Append `css` to `module`'s CSS. * Append `css` to `module`'s CSS.

View File

@ -5,6 +5,7 @@
This proposal adds the following members to the built-in `sass:math` module. This proposal adds the following members to the built-in `sass:math` module.
## Table of Contents ## Table of Contents
* [Background](#background) * [Background](#background)
* [Summary](#summary) * [Summary](#summary)
* [Semantics](#semantics) * [Semantics](#semantics)

View File

@ -23,13 +23,13 @@ setting, and getting elements from nested maps.
Variables have always been a key feature of the Sass language. But these days, Variables have always been a key feature of the Sass language. But these days,
design systems and component libraries form the basis of most CSS projects -- design systems and component libraries form the basis of most CSS projects --
with well organized _design tokens_ as the foundation. While Individual token with well organized *design tokens* as the foundation. While Individual token
variables can be quite useful, the ability to group tokens into structured and variables can be quite useful, the ability to group tokens into structured and
meaningful relationships is essential for creating resilient systems. meaningful relationships is essential for creating resilient systems.
There are many ways to group tokens. The popular [Style Dictionary] recommends a There are many ways to group tokens. The popular [Style Dictionary] recommends a
deep nesting of _category_, _type_, _item_, _sub-item_, and _state_. Other deep nesting of *category*, *type*, *item*, *sub-item*, and *state*. Other
taxonomies also include concepts like _theme_, or even _operating system_. Most taxonomies also include concepts like *theme*, or even *operating system*. Most
of the existing tools rely on YAML or JSON objects to achieve that nested of the existing tools rely on YAML or JSON objects to achieve that nested
structure, at the expense of other important information. YAML and JSON are not structure, at the expense of other important information. YAML and JSON are not
design languages, and do not understand fundamental CSS concepts like color or design languages, and do not understand fundamental CSS concepts like color or

View File

@ -97,9 +97,9 @@ a {
``` ```
Linked order makes sense when using comments to annotate information about Linked order makes sense when using comments to annotate information about
dependencies, but it's counterproductive when a user wants to annotate the _end_ dependencies, but it's counterproductive when a user wants to annotate the *end*
of a module, since that comment would be considered linked to the next module of a module, since that comment would be considered linked to the next module
load. Traversal order handles that case better _and_ matches the old `@import` load. Traversal order handles that case better *and* matches the old `@import`
behavior, so we chose to use it instead. behavior, so we chose to use it instead.
## Procedures ## Procedures

View File

@ -41,8 +41,6 @@ to access the URL of the stylesheet that contained the load, known in the legacy
API as the "previous URL". This was an intentional design choice which enforced API as the "previous URL". This was an intentional design choice which enforced
the invariant that the same canonical URL always refers to the same file. the invariant that the same canonical URL always refers to the same file.
[new import API]: ../accepted/new-js-importer.d.ts
However, this restriction makes it difficult for importers to work as expected However, this restriction makes it difficult for importers to work as expected
in certain contexts. For example, in the Node.js ecosystem JS loads depend on in certain contexts. For example, in the Node.js ecosystem JS loads depend on
the structure of the `node_modules` directory closest to the containing file. the structure of the `node_modules` directory closest to the containing file.
@ -63,10 +61,10 @@ that provides the canonical URL of the containing file (the "containing URL").
However, in order to preserve the desired invariants, this option is only However, in order to preserve the desired invariants, this option is only
provided when either: provided when either:
- `Importer.canonicalize()` is being passed a relative URL (which means the URL * `Importer.canonicalize()` is being passed a relative URL (which means the URL
has already been tried as a load relative to the current canonical URL), or has already been tried as a load relative to the current canonical URL), or
- `Importer.canonicalize()` is passed an absolute URL whose scheme the importer * `Importer.canonicalize()` is passed an absolute URL whose scheme the importer
has declared as non-canonical. has declared as non-canonical.
A "non-canonical" scheme is a new concept introduced by this proposal. A "non-canonical" scheme is a new concept introduced by this proposal.
@ -110,7 +108,7 @@ Providing access to the containing URL puts these invariants at risk in two ways
#### Alternatives Considered #### Alternatives Considered
To mitigate these risks, we need to have _some_ restriction on when the To mitigate these risks, we need to have *some* restriction on when the
containing URL is available to importers. We considered the following containing URL is available to importers. We considered the following
alternative restrictions before settling on the current one: alternative restrictions before settling on the current one:
@ -155,7 +153,7 @@ URLs, this is a blocking limitation.
[package imports]: https://github.com/sass/sass/issues/2739 [package imports]: https://github.com/sass/sass/issues/2739
Thus we arrive at the actual behavior, which makes the containing URL Thus we arrive at the actual behavior, which makes the containing URL
unavailable for absolute loads _unless_ they have a URL scheme declared unavailable for absolute loads *unless* they have a URL scheme declared
explicitly non-canonical. This supports the `pkg:` use-case while still explicitly non-canonical. This supports the `pkg:` use-case while still
protecting against risk (1), since the containing URL is never available for protecting against risk (1), since the containing URL is never available for
canonical resolutions. canonical resolutions.

View File

@ -33,7 +33,6 @@ However, a numeric integer can include units (e.g. `5px` or `8em`) and the
current behavior [drops the units][issue], which is unexpected for most users. current behavior [drops the units][issue], which is unexpected for most users.
For example: `math.random(42px) => 28` (there is no `px`). For example: `math.random(42px) => 28` (there is no `px`).
[random]: https://sass-lang.com/documentation/modules/math#random
[issue]: https://github.com/sass/sass/issues/1890 [issue]: https://github.com/sass/sass/issues/1890
## Summary ## Summary
@ -83,9 +82,10 @@ defaults to `null`.
[units] as `$limit`. [units] as `$limit`.
> Examples: > Examples:
> - `math.random(123) => 87` >
> - `math.random(123px) => 43px` > * `math.random(123) => 87`
> - `math.random(500%) => 238%` > * `math.random(123px) => 43px`
> * `math.random(500%) => 238%`
* Otherwise throw an error. * Otherwise throw an error.

View File

@ -5,7 +5,7 @@
## Draft 1.1 ## Draft 1.1
* Returns a bracketed list instead of an unbracketed one to be more clear * Returns a bracketed list instead of an unbracketed one to be more clear
about what type of value is being returned. about what type of value is being returned.
## Draft 1 ## Draft 1

View File

@ -15,22 +15,22 @@ This proposal adds `string.split()` to the `sass:string` module.
> This section is non-normative. > This section is non-normative.
The `sass:string` module contains several functions for manipulating and finding The `sass:string` module contains several functions for manipulating and finding
out information about strings. Currently, though, there is no built-in function out information about strings. Currently, though, there is no built-in function
that splits one string into a list of substrings, and authors have been creating that splits one string into a list of substrings, and authors have been creating
their own versions of functions that achieve this functionality. their own versions of functions that achieve this functionality.
## Summary ## Summary
> This section is non-normative. > This section is non-normative.
This proposal adds the `string.split()` function to the `sass:string` module. This proposal adds the `string.split()` function to the `sass:string` module.
The function takes a string, splits it based on a provided separator, and The function takes a string, splits it based on a provided separator, and
returns a bracketed, comma-separated list of substrings. returns a bracketed, comma-separated list of substrings.
This could be used to take a string and repurpose parts of it for some other This could be used to take a string and repurpose parts of it for some other
use. For example, fonts contained in a font stack list could be split into use. For example, fonts contained in a font stack list could be split into
segments and then used as keys in a new map. segments and then used as keys in a new map.
Examples: Examples:
@ -39,14 +39,13 @@ $fonts: "Helvetica Neue, Helvetica, Arial";
string.split($fonts, ', '); // ["Helvetica Neue", "Helvetica", "Arial"] string.split($fonts, ', '); // ["Helvetica Neue", "Helvetica", "Arial"]
``` ```
A third argument can set a limit to the the number of splits performed on the A third argument can set a limit to the the number of splits performed on the
string: string:
```scss ```scss
string.split($fonts, ', ', 1); // ["Helvetica Neue", "Helvetica, Arial"] string.split($fonts, ', ', 1); // ["Helvetica Neue", "Helvetica, Arial"]
``` ```
An empty `$separator` returns all Unicode code points in the original string: An empty `$separator` returns all Unicode code points in the original string:
```scss ```scss
@ -54,7 +53,6 @@ $font: "Helvetica"
string.split($font, ''); // ["H", "e", "l", "v", "e", "t", "i", "c", "a"] string.split($font, ''); // ["H", "e", "l", "v", "e", "t", "i", "c", "a"]
``` ```
## Semantics ## Semantics
### `split()` ### `split()`
@ -71,12 +69,12 @@ split($string, $separator, $limit: null)
* If `$limit` is less than 1, throw an error. * If `$limit` is less than 1, throw an error.
* If `$string` is an empty string, return a list with `$string` as the only * If `$string` is an empty string, return a list with `$string` as the only
item. item.
* Let `split-list` be an empty list. * Let `split-list` be an empty list.
* If `$limit` is `null`, set `$limit` to the value of calling * If `$limit` is `null`, set `$limit` to the value of calling
`string.length($string)`. `string.length($string)`.
* Let `split-counter` equal 0. * Let `split-counter` equal 0.
@ -87,7 +85,7 @@ split($string, $separator, $limit: null)
* Append `$string` to `split-list`. * Append `$string` to `split-list`.
* Set `$string` to an empty string. * Set `$string` to an empty string.
* Otherwise: * Otherwise:
@ -103,10 +101,10 @@ split($string, $separator, $limit: null)
* Otherwise: * Otherwise:
* Let `index` be the result of calling * Let `index` be the result of calling
`string.index($string, $separator)`. `string.index($string, $separator)`.
* If `index` is `null`, append `$string` to `split-list` and set `$string` * If `index` is `null`, append `$string` to `split-list` and set `$string`
to an empty string. to an empty string.
* Otherwise: * Otherwise:
@ -115,10 +113,10 @@ split($string, $separator, $limit: null)
`string.slice($string, 1, index - 1)`. `string.slice($string, 1, index - 1)`.
* Append `current-substring` to `split-list`. * Append `current-substring` to `split-list`.
* Set `$string` to * Set `$string` to
`string.slice($string, index + string.length($separator))`. `string.slice($string, index + string.length($separator))`.
* Increase `split-counter` by 1. * Increase `split-counter` by 1.
* Return `split-list` as a bracketed, comma-separated list. * Return `split-list` as a bracketed, comma-separated list.

1581
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -16,31 +16,31 @@
"typedoc": "npm run tangle && npx typedoc --treatWarningsAsErrors js-api-doc/index.d.ts", "typedoc": "npm run tangle && npx typedoc --treatWarningsAsErrors js-api-doc/index.d.ts",
"tangle": "npx ts-node tool/tangle.ts", "tangle": "npx ts-node tool/tangle.ts",
"untangle": "npx ts-node tool/untangle.ts", "untangle": "npx ts-node tool/untangle.ts",
"fix": "npm run update-toc && npm run tangle && gts fix && npm run untangle", "markdownlint": "npx markdownlint-cli '**/*.md' '*.md' --ignore 'node_modules/**'",
"fix": "npm run update-toc && npm run markdownlint -- --fix && npm run tangle && gts fix && npm run untangle",
"test": "npm run tangle && gts lint && tsc --noEmit && npm run toc-check && npm run link-check && npm run js-api-doc-check && npm run typedoc" "test": "npm run tangle && gts lint && tsc --noEmit && npm run toc-check && npm run link-check && npm run js-api-doc-check && npm run typedoc"
}, },
"dependencies": { "dependencies": {
"@types/diff": "^5.0.1", "@types/diff": "^5.0.1",
"@types/glob": "^7.1.4", "@types/glob": "^7.1.4",
"@types/marked": "^4.0.8", "@types/marked": "^4.0.8",
"@types/node": "^14.11.2",
"@types/prettier": "^2.4.1", "@types/prettier": "^2.4.1",
"colors": "^1.3.3", "colors": "^1.3.3",
"diff": "^5.0.0", "diff": "^5.0.0",
"glob": "^10.0.0", "glob": "^10.0.0",
"gts": "^3.1.0",
"immutable": "^4.0.0", "immutable": "^4.0.0",
"indent-string": "^4.0.0", "indent-string": "^4.0.0",
"markdown-link-check": "3.11.1", "markdown-link-check": "3.11.1",
"markdown-toc": "^1.2.0", "markdown-toc": "^1.2.0",
"markdownlint-cli2": "^0.8.1",
"marked": "^4.3.0", "marked": "^4.3.0",
"prettier": "^2.4.1", "prettier": "^2.4.1",
"source-map-js": "^0.6.2", "source-map-js": "^0.6.2",
"ts-dedent": "^2.2.0", "ts-dedent": "^2.2.0",
"ts-node": "^10.2.1", "ts-node": "^10.2.1",
"typedoc": "^0.24.7" "typedoc": "^0.24.7",
},
"devDependencies": {
"@types/node": "^14.11.2",
"gts": "^3.1.0",
"typescript": "^5.0.4" "typescript": "^5.0.4"
} }
} }

View File

@ -1,6 +1,6 @@
## Draft 1.7 ## Draft 1.7
* Resolve missing `alpha` channels _after_ premultiplying colors. * Resolve missing `alpha` channels *after* premultiplying colors.
## Draft 1.6 ## Draft 1.6
@ -88,7 +88,7 @@
function syntax is already explicit about which parameter is where. function syntax is already explicit about which parameter is where.
* `color.invert()` throws an error when `$weight` would require mixing in an * `color.invert()` throws an error when `$weight` would require mixing in an
invalid `color.mix()` _interpolation color space_. invalid `color.mix()` *interpolation color space*.
* Allow scaling channels with a non-0 minimum value, such as the `a` and `b` * Allow scaling channels with a non-0 minimum value, such as the `a` and `b`
channels in `lab()`/`oklab()`. channels in `lab()`/`oklab()`.

View File

@ -530,7 +530,7 @@ Legacy colors that have [missing] components are
### Color Equality ### Color Equality
For determining _equality_ between two colors: For determining *equality* between two colors:
* If both colors are [legacy colors](#legacy-color): * If both colors are [legacy colors](#legacy-color):
@ -552,13 +552,13 @@ Each channel has a name, and an associated unit where allowed. Space and
channel names match unquoted strings, ignoring case. They are always emitted as channel names match unquoted strings, ignoring case. They are always emitted as
unquoted lowercase strings by inspection functions. unquoted lowercase strings by inspection functions.
Values outside a _bounded gamut_ range (including infinity or negative infinity) Values outside a *bounded gamut* range (including infinity or negative infinity)
are valid but are considered _out of gamut_ for the given color space. They are valid but are considered *out of gamut* for the given color space. They
remain un-clamped unless the gamut is specifically marked as "clamped". If the remain un-clamped unless the gamut is specifically marked as "clamped". If the
channel is bounded, or has a percentage mapping, then the channel is considered channel is bounded, or has a percentage mapping, then the channel is considered
_scalable_. *scalable*.
Some color spaces use a _polar angle_ value for the `hue` channel. Polar-angle Some color spaces use a *polar angle* value for the `hue` channel. Polar-angle
hues represent an angle position around a given hue wheel, using a CSS `<angle>` hues represent an angle position around a given hue wheel, using a CSS `<angle>`
dimension or number (interpreted as a `deg` value), and are serialized with dimension or number (interpreted as a `deg` value), and are serialized with
`deg` units. `deg` units.
@ -669,7 +669,7 @@ The known color spaces and their channels are:
> 'Predefined color spaces' can be described using the `color()` function. > 'Predefined color spaces' can be described using the `color()` function.
The _predefined RGB spaces_ are: The *predefined RGB spaces* are:
* `srgb` * `srgb`
* `srgb-linear` * `srgb-linear`
@ -678,7 +678,7 @@ The _predefined RGB spaces_ are:
* `prophoto-rgb` * `prophoto-rgb`
* `rec2020` * `rec2020`
The _predefined XYZ spaces_ are: The *predefined XYZ spaces* are:
* `xyz` * `xyz`
* `xyz-d50` * `xyz-d50`
@ -693,7 +693,7 @@ value of that same component in the other color. In all other cases, the
missing value is treated as `0`. missing value is treated as `0`.
For the sake of [interpolating] between colors with missing components, the For the sake of [interpolating] between colors with missing components, the
following _analogous components_ are defined by [CSS Color Level 4][color-4]: following *analogous components* are defined by [CSS Color Level 4][color-4]:
| Category | Components | | Category | Components |
| ------------- | ------------------- | | ------------- | ------------------- |
@ -737,7 +737,7 @@ in certain circumstances.
### Color Interpolation Method ### Color Interpolation Method
A _color interpolation method_ is a space-separated list of unquoted strings, A *color interpolation method* is a space-separated list of unquoted strings,
parsed according to the following syntax definition: parsed according to the following syntax definition:
<x><pre> <x><pre>
@ -751,9 +751,9 @@ parsed according to the following syntax definition:
&#32; ) 'hue' &#32; ) 'hue'
</pre></x> </pre></x>
A valid _PolarColorSpace_ is the name of a [known color space] with a polar A valid *PolarColorSpace* is the name of a [known color space] with a polar
angle hue channel. A _RectangularColorSpace_ is the name of any other angle hue channel. A *RectangularColorSpace* is the name of any other
[known color space], without a polar-angle hue. The _interpolation color space_ [known color space], without a polar-angle hue. The *interpolation color space*
is the result of [looking up a known color space] named by either the is the result of [looking up a known color space] named by either the
`PolarColorSpace` or `RectangularColorSpace` productions. `PolarColorSpace` or `RectangularColorSpace` productions.
@ -950,131 +950,131 @@ three values: a color space, a list of channel values, and an alpha value.
The procedure is: The procedure is:
* If `input` is a [special variable string], return an unquoted string with * If `input` is a [special variable string], return an unquoted string with
the value of `input`. the value of `input`.
* If `input` is a bracketed list, or a list with a separator other than * If `input` is a bracketed list, or a list with a separator other than
'slash' or 'space', throw an error. 'slash' or 'space', throw an error.
* If `input` is a slash-separated list: * If `input` is a slash-separated list:
* If `input` doesn't have exactly two elements, throw an error. * If `input` doesn't have exactly two elements, throw an error.
* Otherwise, let `components` be the first element and `alpha` the second * Otherwise, let `components` be the first element and `alpha` the second
element of `input`. element of `input`.
* Otherwise: * Otherwise:
* Let `components` be an unbracketed space separated list of all except the * Let `components` be an unbracketed space separated list of all except the
last element of `input`. last element of `input`.
* If the last element of `input` is an unquoted string that contains `/`: * If the last element of `input` is an unquoted string that contains `/`:
* Let `split-last` be the result calling `string.split()` with the last * Let `split-last` be the result calling `string.split()` with the last
element of `input` as the string to split, and `/` as the separator. element of `input` as the string to split, and `/` as the separator.
* If `split-last` has two items, and one or both items are an unquoted * If `split-last` has two items, and one or both items are an unquoted
string that's case-insensitively equal to 'none': string that's case-insensitively equal to 'none':
> Special handling for `none/none`, `none/<number>`, and `<number>/none`. > Special handling for `none/none`, `none/<number>`, and `<number>/none`.
* If either item in `split-last` can be coerced to a number, replace * If either item in `split-last` can be coerced to a number, replace
the current value of the item with the resulting number value. the current value of the item with the resulting number value.
* If any item in `split-last` is not a number or an unquoted string * If any item in `split-last` is not a number or an unquoted string
that's case-insensitively equal to 'none', return an unquoted string that's case-insensitively equal to 'none', return an unquoted string
with the value of `input`. with the value of `input`.
* Otherwise, let `alpha` be the second element in `split-last`, and * Otherwise, let `alpha` be the second element in `split-last`, and
append the first element of `split-last` to `components`. append the first element of `split-last` to `components`.
* Otherwise, return an unquoted string with the value of `input`. * Otherwise, return an unquoted string with the value of `input`.
> This solves for a legacy handling of `/` in Sass that would produce an > This solves for a legacy handling of `/` in Sass that would produce an
> unquoted string when the alpha value is a CSS function such as `var()` > unquoted string when the alpha value is a CSS function such as `var()`
> or when either value is `none`. > or when either value is `none`.
* Otherwise, if the last element of `input` has preserved its status as two * Otherwise, if the last element of `input` has preserved its status as two
slash-separated numbers: slash-separated numbers:
* Let `alpha` be the number after the slash, and append the number before * Let `alpha` be the number after the slash, and append the number before
the slash to `components`. the slash to `components`.
* Otherwise, append the last element of `input` to `components`. * Otherwise, append the last element of `input` to `components`.
* If `components` is an empty list, throw an error. * If `components` is an empty list, throw an error.
* If `components` is a [special variable string]: * If `components` is a [special variable string]:
* Let `channels` be the value of `components`. * Let `channels` be the value of `components`.
* Otherwise: * Otherwise:
* If `components` is not an unbracketed space-separated list, throw an error. * If `components` is not an unbracketed space-separated list, throw an error.
* If `space` is null: * If `space` is null:
* Let `input-space` be the first element in `components`. * Let `input-space` be the first element in `components`.
* If `input-space` is a [special variable string], return an unquoted * If `input-space` is a [special variable string], return an unquoted
string with the value of `input`. string with the value of `input`.
* Set `space` be the result of [looking up a known color space] with the * Set `space` be the result of [looking up a known color space] with the
name `input-space`. name `input-space`.
* If `space` is not a [predefined color space], throw an error. * If `space` is not a [predefined color space], throw an error.
> Only predefined spaces can be passed in as color syntax components. > Only predefined spaces can be passed in as color syntax components.
> All other known color spaces use explicit functions. > All other known color spaces use explicit functions.
* Let `channels` be an unbracketed space-separated list with the * Let `channels` be an unbracketed space-separated list with the
remaining elements from `components`. remaining elements from `components`.
* Otherwise, let `channels` be the value of `components`. * Otherwise, let `channels` be the value of `components`.
* Let `expected` be the number of channels in `space`. * Let `expected` be the number of channels in `space`.
* If any element of `channels` is not either a number, a special variable * If any element of `channels` is not either a number, a special variable
string, a [special number], or an unquoted string that's string, a [special number], or an unquoted string that's
case-insensitively equal to 'none', throw an error. case-insensitively equal to 'none', throw an error.
* If `alpha` is null, let `alpha` be `1`. * If `alpha` is null, let `alpha` be `1`.
* Otherwise, If `alpha` is not a [special number]: * Otherwise, If `alpha` is not a [special number]:
* If `alpha` is a number, set `alpha` to the result of * If `alpha` is a number, set `alpha` to the result of
[percent-converting] `alpha` with a max of 1, and then clamping the value [percent-converting] `alpha` with a max of 1, and then clamping the value
between 0 and 1, inclusive. between 0 and 1, inclusive.
* Otherwise, throw an error. * Otherwise, throw an error.
* If `channels` is a [special variable string], or if `alpha` is a [special * If `channels` is a [special variable string], or if `alpha` is a [special
number], return an unquoted string with the value of `input`. number], return an unquoted string with the value of `input`.
* If any element of `channels` is a [special number]: * If any element of `channels` is a [special number]:
* If `space` is a [legacy color] space: * If `space` is a [legacy color] space:
* Let `comma-list` be the result of calling * Let `comma-list` be the result of calling
`list.append(channels, alpha, 'comma')`. `list.append(channels, alpha, 'comma')`.
* Return an unquoted string with the value of `comma-list`. * Return an unquoted string with the value of `comma-list`.
* Otherwise, return an unquoted string with the value of `input`. * Otherwise, return an unquoted string with the value of `input`.
> Doing this late in the process allows us to throw any obvious syntax > Doing this late in the process allows us to throw any obvious syntax
> errors, even for colors that can't be fully resolved during compilation. > errors, even for colors that can't be fully resolved during compilation.
* If the length of `channels` is not equal to `expected`, throw an error. * If the length of `channels` is not equal to `expected`, throw an error.
> Once special values have been handled, any colors remaining should have > Once special values have been handled, any colors remaining should have
> exactly the expected number of channels. > exactly the expected number of channels.
* Set `channels` to the result of [normalizing] `channels` in `space`. * Set `channels` to the result of [normalizing] `channels` in `space`.
* Let `space-name` be a lowercase unquoted string of the `space` name. * Let `space-name` be a lowercase unquoted string of the `space` name.
* Return `space-name`, `channels` channels, and `alpha` alpha value. * Return `space-name`, `channels` channels, and `alpha` alpha value.
[special variable string]: ../spec/functions.md#special-variable-string [special variable string]: ../spec/functions.md#special-variable-string
[special number]: ../spec/functions.md#special-number [special number]: ../spec/functions.md#special-number
@ -1265,14 +1265,14 @@ input colors.
* If `weight == 1`, return `color1`. * If `weight == 1`, return `color1`.
* Let `space` be the _interpolation color space_ specified by the `method` * Let `space` be the *interpolation color space* specified by the `method`
[color interpolation method]. [color interpolation method].
> Only known color spaces are allowed as part of a color interpolation method. > Only known color spaces are allowed as part of a color interpolation method.
* If `space` is a [PolarColorSpace][color-method]: * If `space` is a [PolarColorSpace][color-method]:
* Let `hue-arc` be the `HueInterpolationMethod` specified in `method`, or * Let `hue-arc` be the `HueInterpolationMethod` specified in `method`, or
`shorter` if no hue interpolation is specified. `shorter` if no hue interpolation is specified.
* Set `color1` and `color2` respectively to the results of [converting] `color1` * Set `color1` and `color2` respectively to the results of [converting] `color1`
@ -1683,10 +1683,10 @@ This function is also available as a global function named `change-color()`.
* If the keyword argument `$space` is specified in `$args`: * If the keyword argument `$space` is specified in `$args`:
* Let `known-space` be the result [looking up a known color space] named * Let `known-space` be the result [looking up a known color space] named
`$space`. `$space`.
* If `space != origin-space`, set `color` to the result of calling * If `space != origin-space`, set `color` to the result of calling
`color.to-space(color, space)`. `color.to-space(color, space)`.
* Otherwise, let `known-space` be `origin-space`. * Otherwise, let `known-space` be `origin-space`.
@ -1695,7 +1695,7 @@ This function is also available as a global function named `change-color()`.
* If the keyword argument `$alpha` is specified in `$args`: * If the keyword argument `$alpha` is specified in `$args`:
* Set `alpha` to the result of [percent-converting] `$alpha`, and clamping * Set `alpha` to the result of [percent-converting] `$alpha`, and clamping
it between 0 and 1 (inclusive). it between 0 and 1 (inclusive).
* Let `channel-args` be the remaining keyword arguments in `$args`, not * Let `channel-args` be the remaining keyword arguments in `$args`, not
@ -1760,10 +1760,10 @@ This function is also available as a global function named `adjust-color()`.
* If the keyword argument `$space` is specified in `$args`: * If the keyword argument `$space` is specified in `$args`:
* Let `known-space` be the result [looking up a known color space] named * Let `known-space` be the result [looking up a known color space] named
`$space`. `$space`.
* If `space != origin-space`, set `color` to the result of calling * If `space != origin-space`, set `color` to the result of calling
`color.to-space(color, space)`. `color.to-space(color, space)`.
* Otherwise, let `known-space` be `origin-space`. * Otherwise, let `known-space` be `origin-space`.
@ -1772,7 +1772,7 @@ This function is also available as a global function named `adjust-color()`.
* If the keyword argument `$alpha` is specified in `$args`: * If the keyword argument `$alpha` is specified in `$args`:
* If `alpha == none`, throw an error. * If `alpha == none`, throw an error.
> This is not the ideal solution for handling `none`, but we want to > This is not the ideal solution for handling `none`, but we want to
> match CSS relative color syntax if possible. Throwing an error for now > match CSS relative color syntax if possible. Throwing an error for now
@ -1861,10 +1861,10 @@ This function is also available as a global function named `scale-color()`.
* If the keyword argument `$space` is specified in `$args`: * If the keyword argument `$space` is specified in `$args`:
* Let `space` be the result of [looking up a known color space] named * Let `space` be the result of [looking up a known color space] named
`$space`. `$space`.
* Let `color` be the result of [converting] `$color` to `space`. * Let `color` be the result of [converting] `$color` to `space`.
* Otherwise: * Otherwise:
@ -1876,13 +1876,13 @@ This function is also available as a global function named `scale-color()`.
* If the keyword argument `$alpha` is specified in `$args`: * If the keyword argument `$alpha` is specified in `$args`:
* If `alpha == none`, throw an error. * If `alpha == none`, throw an error.
> This is not the ideal solution for handling `none`, but we want to > This is not the ideal solution for handling `none`, but we want to
> match CSS relative color syntax if possible. Throwing an error for now > match CSS relative color syntax if possible. Throwing an error for now
> means we can adjust to match the CSS behavior once it is defined. > means we can adjust to match the CSS behavior once it is defined.
* Set `alpha` to the result of [scaling] `alpha` by `$alpha` with `max` 1. * Set `alpha` to the result of [scaling] `alpha` by `$alpha` with `max` 1.
* Let `channel-args` be the remaining keyword arguments in `$args`, not * Let `channel-args` be the remaining keyword arguments in `$args`, not
including `$space` or `$alpha` arguments. including `$space` or `$alpha` arguments.
@ -2003,8 +2003,8 @@ This function is also available as a global function named `invert()`.
* If `$weight == 0%`, return the value of `$color`. * If `$weight == 0%`, return the value of `$color`.
* If `space` is not a valid [color interpolation method] _interpolation color * If `space` is not a valid [color interpolation method] *interpolation color
space_, and `$weight != 100%`, throw an error. space*, and `$weight != 100%`, throw an error.
* Let `color` be the result of [converting] `$color` into `space`. * Let `color` be the result of [converting] `$color` into `space`.
@ -2099,7 +2099,6 @@ ie-hex-str($color)
* Return the result of concatenating `hex-list` into a string. * Return the result of concatenating `hex-list` into a string.
## New Global Functions ## New Global Functions
These new CSS functions are provided globally. These new CSS functions are provided globally.

View File

@ -61,7 +61,6 @@ one would with function values:
* `meta.call()` => `meta.apply()` * `meta.call()` => `meta.apply()`
### JavaScript API Design Decisions ### JavaScript API Design Decisions
Mixins differ from functions in that the result of their execution is a Sass AST Mixins differ from functions in that the result of their execution is a Sass AST
@ -73,7 +72,6 @@ For this reason, it is not meaningful -- or even possible -- to construct or
execute a mixin through the JavaScript API. A mixin object shall be opaque, and execute a mixin through the JavaScript API. A mixin object shall be opaque, and
the only operation available shall be to return the object as-is. the only operation available shall be to return the object as-is.
## Types ## Types
This proposal promotes the [mixin value] to a Sass value type. This proposal promotes the [mixin value] to a Sass value type.
@ -290,4 +288,4 @@ message CompilerMixin {
The protocol allows first-class mixins defined in the compiler to be passed The protocol allows first-class mixins defined in the compiler to be passed
to the host and vice-versa as `Value.CompilerMixin`s. to the host and vice-versa as `Value.CompilerMixin`s.
Two first-class mixins are equal if they have the same ID. Two first-class mixins are equal if they have the same ID.

View File

@ -65,7 +65,7 @@ Adjust the list of productions that should produce errors as follows:
* Add "A style rule whose selector contains a trailing combinator." * Add "A style rule whose selector contains a trailing combinator."
> While the [bogus combinators] deprecation is in place, style rules with > While the [bogus combinators] deprecation is in place, style rules with
> trailing combinators that _don't_ have nested rules will produce warnings. > trailing combinators that *don't* have nested rules will produce warnings.
> Those with nested rules will produce errors since Sass never parsed them > Those with nested rules will produce errors since Sass never parsed them
> successfully in the first place. > successfully in the first place.

View File

@ -14,13 +14,13 @@ still supported for backwards-compatibility.
## Syntax ## Syntax
<x><pre> <x><pre>
**ImportRule** ::= '@import' (ImportArgumentNoMedia ',')* ImportArgument **ImportRule** ::= '@import' (ImportArgumentNoMedia ',')\* ImportArgument
**ImportArgumentNoMedia** ::= ImportUrl ImportModifierNoMedia* **ImportArgumentNoMedia** ::= ImportUrl ImportModifierNoMedia*
**ImportArgument** ::= ImportUrl ImportModifier **ImportArgument** ::= ImportUrl ImportModifier
**ImportModifierNoMedia** ::= InterpolatedIdentifier* (ImportFunction | ImportSupports) **ImportModifierNoMedia** ::= InterpolatedIdentifier\* (ImportFunction | ImportSupports)
**ImportModifier** ::= ImportModifierNoMedia* InterpolatedIdentifier* ImportMedia? **ImportModifier** ::= ImportModifierNoMedia\* InterpolatedIdentifier\* ImportMedia?
**ImportMedia** ::= [MediaFeatureInParens] (',' [MediaQueryList])* **ImportMedia** ::= [MediaFeatureInParens] (',' [MediaQueryList])\*
&#32; | InterpolatedIdentifier (',' [MediaQueryList])* &#32; | InterpolatedIdentifier (',' [MediaQueryList])\*
**ImportSupports** ::= 'supports(' SupportsDeclaration ')' **ImportSupports** ::= 'supports(' SupportsDeclaration ')'
**ImportFunction** ::= [InterpolatedIdentifier]¹ '(' InterpolatedDeclarationValue? ')' **ImportFunction** ::= [InterpolatedIdentifier]¹ '(' InterpolatedDeclarationValue? ')'
**ImportUrl** ::= QuotedString | [InterpolatedUrl][] **ImportUrl** ::= QuotedString | [InterpolatedUrl][]
@ -137,10 +137,10 @@ To execute an `@import` rule `rule`:
* Add `imported`'s [extensions][] to the current module. * Add `imported`'s [extensions][] to the current module.
* If the `@import` rule is nested within at-rules and/or style rules, add each * If the `@import` rule is nested within at-rules and/or style rules, add each
member in `imported` to the local [scope][]. member in `imported` to the local [scope][].
* Otherwise, add each member in `imported` to the current import context and * Otherwise, add each member in `imported` to the current import context and
the current module. the current module.
> Members defined directly in `imported` will have already been added to > Members defined directly in `imported` will have already been added to

View File

@ -37,7 +37,7 @@ identifiers are matched case-insensitively:
&#32; | '(' Expression³ [\<mf-lt>] Expression³ [\<mf-lt>] Expression³ ')' &#32; | '(' Expression³ [\<mf-lt>] Expression³ [\<mf-lt>] Expression³ ')'
&#32; | '(' Expression³ [\<mf-gt>] Expression³ [\<mf-gt>] Expression³ ')' &#32; | '(' Expression³ [\<mf-gt>] Expression³ [\<mf-gt>] Expression³ ')'
&#32; | '(' MediaNot ')' &#32; | '(' MediaNot ')'
&#32; | '(' MediaInParens (MediaAnd* | MediaOr*) ')' &#32; | '(' MediaInParens (MediaAnd\*| MediaOr\*) ')'
</pre></x> </pre></x>
[InterpolatedIdentifier]: ../syntax.md#interpolatedidentifier [InterpolatedIdentifier]: ../syntax.md#interpolatedidentifier

View File

@ -21,8 +21,6 @@ the current stylesheet, and includes its CSS in the compilation output.
A `@use` rule's *module* is a [module][] associated with a `@use` rule. This A `@use` rule's *module* is a [module][] associated with a `@use` rule. This
module is only associated once the rule has been [executed](#semantics). module is only associated once the rule has been [executed](#semantics).
[module]: ../modules.md#module
## Syntax ## Syntax
The grammar for the `@use` rule is as follows: The grammar for the `@use` rule is as follows:
@ -138,4 +136,3 @@ To execute a `@use` rule `rule`:
* If `variable` wasn't declared with a `!default` flag, throw an error. * If `variable` wasn't declared with a `!default` flag, throw an error.
* Set [`rule`'s module](#a-use-rules-module) to `module`. * Set [`rule`'s module](#a-use-rules-module) to `module`.

View File

@ -443,7 +443,6 @@ This function is also available as a global function named `hue()`.
[percent-converting]: #percent-converting-a-number [percent-converting]: #percent-converting-a-number
[to RGB]: https://www.w3.org/TR/css-color-4/#hwb-to-rgb [to RGB]: https://www.w3.org/TR/css-color-4/#hwb-to-rgb
* ``` * ```
hwb($channels) hwb($channels)
``` ```

View File

@ -221,7 +221,6 @@ hypot($numbers...)
log($number, $base: null) log($number, $base: null)
``` ```
* If `$number` has units, throw an error. * If `$number` has units, throw an error.
* Return a unitless number whose value is the result of `log($number.value)` as * Return a unitless number whose value is the result of `log($number.value)` as
@ -444,9 +443,10 @@ This function is also available as a global function named `random()`.
units as `$limit`. units as `$limit`.
> Examples: > Examples:
> - `math.random(123) => 87` >
> - `math.random(123px) => 43px` > * `math.random(123) => 87`
> - `math.random(500%) => 238%` > * `math.random(123px) => 43px`
> * `math.random(500%) => 238%`
* Otherwise throw an error. * Otherwise throw an error.

View File

@ -55,7 +55,7 @@ representation of a CSS selector.
* Append a comma to `text` unless `complex` is the last element of * Append a comma to `text` unless `complex` is the last element of
`selector`. `selector`.
* Otherwise, if `selector` is not a string, throw an error. * Otherwise, if `selector` is not a string, throw an error.
* Otherwise, set `text` to the contents of `selector`. * Otherwise, set `text` to the contents of `selector`.
@ -135,8 +135,6 @@ This function is also available as a global function named `selector-replace()`.
* If any of `selector`, `original`, or `replacement` is [bogus], throw an error. * If any of `selector`, `original`, or `replacement` is [bogus], throw an error.
[bogus]: ../selectors.md#bogus-selector
* > Additional semantics have not yet been explicitly written. * > Additional semantics have not yet been explicitly written.
### `simple-selectors()` ### `simple-selectors()`

View File

@ -18,7 +18,6 @@ This built-in module is available from the URL `sass:string`.
## Functions ## Functions
### `index()` ### `index()`
``` ```
@ -73,12 +72,12 @@ split($string, $separator, $limit: null)
* If `$limit` is less than 1, throw an error. * If `$limit` is less than 1, throw an error.
* If `$string` is an empty string, return a list with `$string` as the only * If `$string` is an empty string, return a list with `$string` as the only
item. item.
* Let `split-list` be an empty list. * Let `split-list` be an empty list.
* If `$limit` is `null`, set `$limit` to the value of calling * If `$limit` is `null`, set `$limit` to the value of calling
`string.length($string)`. `string.length($string)`.
* Let `split-counter` equal 0. * Let `split-counter` equal 0.
@ -89,7 +88,7 @@ split($string, $separator, $limit: null)
* Append `$string` to `split-list`. * Append `$string` to `split-list`.
* Set `$string` to an empty string. * Set `$string` to an empty string.
* Otherwise: * Otherwise:
@ -105,10 +104,10 @@ split($string, $separator, $limit: null)
* Otherwise: * Otherwise:
* Let `index` be the result of calling * Let `index` be the result of calling
`string.index($string, $separator)`. `string.index($string, $separator)`.
* If `index` is `null`, append `$string` to `split-list` and set `$string` * If `index` is `null`, append `$string` to `split-list` and set `$string`
to an empty string. to an empty string.
* Otherwise: * Otherwise:
@ -117,12 +116,12 @@ split($string, $separator, $limit: null)
`string.slice($string, 1, index - 1)`. `string.slice($string, 1, index - 1)`.
* Append `current-substring` to `split-list`. * Append `current-substring` to `split-list`.
* Set `$string` to * Set `$string` to
`string.slice($string, index + string.length($separator))`. `string.slice($string, index + string.length($separator))`.
* Increase `split-counter` by 1. * Increase `split-counter` by 1.
* Return `split-list` as a bracketed, comma-separated list. * Return `split-list` as a bracketed, comma-separated list.
### `to-lower-case()` ### `to-lower-case()`
@ -156,4 +155,3 @@ unquote($string)
``` ```
This function is also available as a global function named `unquote()`. This function is also available as a global function named `unquote()`.

View File

@ -5,7 +5,7 @@ a Sass implementation and a host environment. It allows the host environment to
invoke the Sass compiler on source files, and to define custom functions and invoke the Sass compiler on source files, and to define custom functions and
importers in the host language. importers in the host language.
Sass implementations are _not_ required to support the embedded protocol. Sass implementations are *not* required to support the embedded protocol.
However, if they do, they must adhere to the specification given in this file However, if they do, they must adhere to the specification given in this file
and [`embedded_sass.proto`] for the compiler endpoint. and [`embedded_sass.proto`] for the compiler endpoint.
@ -60,12 +60,12 @@ its standard input and output streams.
### Packet Structure ### Packet Structure
Each message in the embedded protocol is sent as a _packet_ which contains two Each message in the embedded protocol is sent as a *packet* which contains two
values: an unsigned [varint] up to 32 bits long known as the "compilation ID", values: an unsigned [varint] up to 32 bits long known as the "compilation ID",
and a protocol buffer that contains the protobuf message. For streams (like and a protocol buffer that contains the protobuf message. For streams (like
standard input and output) that don't have built-in message boundaries, every standard input and output) that don't have built-in message boundaries, every
packet must begin with another unsigned varint indicating the length in bytes of packet must begin with another unsigned varint indicating the length in bytes of
the remaining message (_including the compilation ID_). This matches the best the remaining message (*including the compilation ID*). This matches the best
practice described in [the protocol buffer documentation]. practice described in [the protocol buffer documentation].
Because JavaScript can't easily represent integers larger than 2^53 - 1, the Because JavaScript can't easily represent integers larger than 2^53 - 1, the
@ -319,7 +319,7 @@ tell if a value is "truthy" (one of those values) or "falsey" (`false` or
`null`). It should encourage users to check this rather than directly testing `null`). It should encourage users to check this rather than directly testing
for `true` or `false`. for `true` or `false`.
Two booleans are equal if they're both `true` or both` false`. Two booleans are equal if they're both `true` or both `false`.
### Null ### Null

View File

@ -7,7 +7,7 @@
* [Special Variable String](#special-variable-string) * [Special Variable String](#special-variable-string)
* [Syntax](#syntax) * [Syntax](#syntax)
* [Semantics](#semantics) * [Semantics](#semantics)
* [`EmptyFallbackVar`:](#emptyfallbackvar) * [`EmptyFallbackVar`](#emptyfallbackvar)
* [`FunctionCall`](#functioncall) * [`FunctionCall`](#functioncall)
* [Global Functions](#global-functions) * [Global Functions](#global-functions)
* [`adjust-hue()`](#adjust-hue) * [`adjust-hue()`](#adjust-hue)
@ -76,14 +76,12 @@ matching is case-insensitive.
**FunctionCall** ::= [NamespacedIdentifier][] ArgumentInvocation **FunctionCall** ::= [NamespacedIdentifier][] ArgumentInvocation
</pre></x> </pre></x>
[NamespacedIdentifier]: modules.md#syntax
No whitespace is allowed between the `NamespacedIdentifier` and the No whitespace is allowed between the `NamespacedIdentifier` and the
`ArgumentInvocation` in `FunctionCall`. `ArgumentInvocation` in `FunctionCall`.
## Semantics ## Semantics
### `EmptyFallbackVar`: ### `EmptyFallbackVar`
To evaluate an `EmptyFallbackVar` `call`: To evaluate an `EmptyFallbackVar` `call`:
@ -436,8 +434,6 @@ plain CSS function named `"hsl"` that function is named `"hsla"` instead.
* Call `hsl()` with `hue`, `saturation`, `lightness`, and `alpha` (if it's * Call `hsl()` with `hue`, `saturation`, `lightness`, and `alpha` (if it's
defined) as arguments and return the result. defined) as arguments and return the result.
[special variable string]: #special-variable-string
### `if()` ### `if()`
``` ```

View File

@ -125,8 +125,6 @@ Compiles the Sass `source`:
> The structure of the sourceMap can vary from implementation to > The structure of the sourceMap can vary from implementation to
> implementation. > implementation.
[loaded]: ../modules.md#loading-a-source-file
* If the compilation fails, throw an `Exception`. * If the compilation fails, throw an `Exception`.
```ts ```ts

View File

@ -135,7 +135,6 @@ charset?: boolean;
#### `quietDeps` #### `quietDeps`
If true, the compiler must not print deprecation warnings for stylesheets that If true, the compiler must not print deprecation warnings for stylesheets that
are transitively loaded through an import path. are transitively loaded through an import path.
@ -162,7 +161,6 @@ verbose?: boolean;
#### `logger` #### `logger`
A [custom logger] that provides callbacks for the compiler to use in lieu of its A [custom logger] that provides callbacks for the compiler to use in lieu of its
default messaging behavior. default messaging behavior.

View File

@ -17,7 +17,6 @@ export {SourceSpan} from './source_span';
* [`Logger`](#logger-1) * [`Logger`](#logger-1)
* [`silent`](#silent) * [`silent`](#silent)
## Types ## Types
### `Logger` ### `Logger`

View File

@ -312,7 +312,7 @@ url?: URL;
### `StringOptionsWithImporter` ### `StringOptionsWithImporter`
> This interface is used for calls to [`compileString()`] and > This interface is used for calls to [`compileString()`] and
> [`compileStringAsync()`] that _do_ pass the `importer` parameter, and so _do_ > [`compileStringAsync()`] that *do* pass the `importer` parameter, and so *do*
> support relative imports. > support relative imports.
```ts ```ts
@ -334,7 +334,7 @@ importer: Importer<sync> | FileImporter<sync>;
The canonical URL of the entrypoint. The canonical URL of the entrypoint.
> This _must_ be passed when `importer` is passed, since otherwise there's > This *must* be passed when `importer` is passed, since otherwise there's
> nothing to resolve relative URLs relative to. > nothing to resolve relative URLs relative to.
```ts ```ts

View File

@ -161,8 +161,6 @@ export type CalculationOperator = '+' | '-' | '*' | '/';
The JS API representation of a Sass [`CalculationOperation`]. The JS API representation of a Sass [`CalculationOperation`].
[CalculationOperation]: ../../types/calculation.md#types
```ts ```ts
export class CalculationOperation implements ValueObject { export class CalculationOperation implements ValueObject {
``` ```

View File

@ -141,16 +141,16 @@ get separator(): ListSeparator;
Converts the Sass index `sassIndex` to a JS index into the array returned by Converts the Sass index `sassIndex` to a JS index into the array returned by
`asList`: `asList`:
- If `sassIndex` is not a unitless Sass number, throw an error. * If `sassIndex` is not a unitless Sass number, throw an error.
- Let `value` be the value of `sassIndex`. Let `index` be the result of * Let `value` be the value of `sassIndex`. Let `index` be the result of
`fuzzyAsInt(value)`. If `index === null`, throw an error. `fuzzyAsInt(value)`. If `index === null`, throw an error.
- If `index === 0`, or the absolute value of `index` is greater than * If `index === 0`, or the absolute value of `index` is greater than
`asList.length`, throw an error. `asList.length`, throw an error.
- If `index > 0`, return `index - 1`. * If `index > 0`, return `index - 1`.
- Otherwise, if `index < 0`, return `asList.length + index`. * Otherwise, if `index < 0`, return `asList.length + index`.
> Sass indices start counting at 1, and may be negative in order to index from > Sass indices start counting at 1, and may be negative in order to index from
> the end of the list. > the end of the list.
@ -285,7 +285,7 @@ Returns the same number for any two `Value`s that are equal according to
[`equals`]: #equals [`equals`]: #equals
> This is _not_ required to be different for different values, although having > This is *not* required to be different for different values, although having
> overlap between common values is likely to cause performance issues. > overlap between common values is likely to cause performance issues.
```ts ```ts

View File

@ -33,7 +33,6 @@ The [private `internal` field] refers to a Sass map.
[private `internal` field]: index.d.ts.md#internal [private `internal` field]: index.d.ts.md#internal
#### Constructor #### Constructor
Creates a Sass map: Creates a Sass map:

View File

@ -291,7 +291,7 @@ by `newNumerators` and `newDenominators`:
* If `newNumerators` and `newDenominators` are both empty, return the result of * If `newNumerators` and `newDenominators` are both empty, return the result of
`new SassNumber(this.value)`. `new SassNumber(this.value)`.
* If `internal` is unitless, return the result of: * If `internal` is [unitless], return the result of:
[unitless]: ../../types/number.md# [unitless]: ../../types/number.md#

View File

@ -28,7 +28,7 @@ combinator*) as well as a sequence of [complex selector components]. The
component sequence may be empty only for complex selectors with leading component sequence may be empty only for complex selectors with leading
combinators. combinators.
[visible combinator]: #visible-combinator [visible combinator]: #visible-combinator
[complex selector components]: #complex-selector-component [complex selector components]: #complex-selector-component
### Complex Selector Component ### Complex Selector Component

View File

@ -102,6 +102,7 @@ a string.
> exposes this to the user. > exposes this to the user.
This algorithm takes: This algorithm takes:
* a string `string`, * a string `string`,
* a syntax `syntax` ("indented", "scss", or "css"), * a syntax `syntax` ("indented", "scss", or "css"),
* an optional URL `url`, * an optional URL `url`,
@ -147,8 +148,6 @@ It runs as follows:
* Let `file` be the [source file][] with `ast`, canonical URL `url`, and * Let `file` be the [source file][] with `ast`, canonical URL `url`, and
importer `importer`. importer `importer`.
[source file]: syntax.md#source-file
* Let `module` be the result of [executing](#executing-a-file) `file`. * Let `module` be the result of [executing](#executing-a-file) `file`.
* Let `css` be the result of [resolving `module`'s extensions][]. * Let `css` be the result of [resolving `module`'s extensions][].
@ -166,10 +165,6 @@ It runs as follows:
This algorithm takes a [source file][] `file`, a [configuration][] `config`, an This algorithm takes a [source file][] `file`, a [configuration][] `config`, an
[import context][] `import`, and returns a [module][]. [import context][] `import`, and returns a [module][].
[module]: modules.md#module
[configuration]: modules.md#configuration
[import context]: modules.md#import-context
* Let `module` be an empty module with source file `file`. * Let `module` be an empty module with source file `file`.
* Let `uses` be an empty map from `@use` rules to modules. * Let `uses` be an empty map from `@use` rules to modules.

View File

@ -106,7 +106,6 @@ No whitespace is allowed between components of an `InterpolatedUnquotedUrlConten
[\<declaration-value>]: https://www.w3.org/TR/css-syntax-3/#typedef-declaration-value [\<declaration-value>]: https://www.w3.org/TR/css-syntax-3/#typedef-declaration-value
[\<an+b>]: https://www.w3.org/TR/css-syntax-3/#the-anb-type [\<an+b>]: https://www.w3.org/TR/css-syntax-3/#the-anb-type
[\<ident-token>]: https://drafts.csswg.org/css-syntax-3/#ident-token-diagram
1: The string `of` is matched case-insensitively. In addition, it must be parsed 1: The string `of` is matched case-insensitively. In addition, it must be parsed
as an identifier. as an identifier.
@ -295,7 +294,6 @@ This algorithm consumes input from a stream of [code points][] and returns a
sequence of strings and/or expressions. It follows the grammar for an sequence of strings and/or expressions. It follows the grammar for an
[`InterpolatedIdentifier`][]. [`InterpolatedIdentifier`][].
[code points]: https://infra.spec.whatwg.org/#code-point
[`InterpolatedIdentifier`]: #interpolatedidentifier [`InterpolatedIdentifier`]: #interpolatedidentifier
* Let `components` be an empty list of strings and/or expressions. * Let `components` be an empty list of strings and/or expressions.

View File

@ -265,12 +265,12 @@ This algorithm takes a `CalculationValue` `value` and returns a
* If `value` is a calculation: * If `value` is a calculation:
* Let `result` be the result of [simplifying] `value`. * Let `result` be the result of [simplifying] `value`.
* If `result` is a calculation whose name is `"calc"`, return `result`'s * If `result` is a calculation whose name is `"calc"`, return `result`'s
single argument. single argument.
* Otherwise, return `result`. * Otherwise, return `result`.
[simplifying]: #simplifying-a-calculation [simplifying]: #simplifying-a-calculation

View File

@ -51,9 +51,9 @@ as defined by [IEEE 754 2019], §3.2-3.3.
### Degenerate Number ### Degenerate Number
The doubles `Infinity`, `-Infinity`, and `NaN` are _degenerate_. The doubles `Infinity`, `-Infinity`, and `NaN` are *degenerate*.
A number is _degenerate_ if its value is degenerate. A number is *degenerate* if its value is degenerate.
### Conversion Factors ### Conversion Factors
@ -132,8 +132,6 @@ possible-compatibility.
> units; this preserves forwards-compatibility with new units that are > units; this preserves forwards-compatibility with new units that are
> introduced in browsers over time. > introduced in browsers over time.
[CSS Values and Units]: https://www.w3.org/TR/css-values-3/
| Type | Units | | Type | Units |
| -------------- | -------------------------------------------------------------------------------------------- | | -------------- | -------------------------------------------------------------------------------------------- |
| `<length>` | `em`, `ex`, `ch`, `rem`, `vw`, `vh`, `vmin`, `vmax`, `cm`, `mm`, `Q`, `in`, `pt`, `pc`, `px` | | `<length>` | `em`, `ex`, `ch`, `rem`, `vw`, `vh`, `vmin`, `vmax`, `cm`, `mm`, `Q`, `in`, `pt`, `pc`, `px` |
@ -247,8 +245,6 @@ The value type known as a *number* has three components:
* A list of strings called *numerator units*. * A list of strings called *numerator units*.
* A list of strings called *denominator units*. * A list of strings called *denominator units*.
[double]: #doubles
Several shorthands exist when referring to numbers: Several shorthands exist when referring to numbers:
* A number's *units* refers to the [set of units] containing its numerator units * A number's *units* refers to the [set of units] containing its numerator units