diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..01411cde00 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2022, Google Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/accepted/bogus-combinators.changes.md b/accepted/bogus-combinators.changes.md new file mode 100644 index 0000000000..dbb42e64d1 --- /dev/null +++ b/accepted/bogus-combinators.changes.md @@ -0,0 +1,34 @@ +## Draft 3 + +* In Phase 1: + + * Clarify the definition of bogus selectors. + + * 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 + matching nothing to include bogus pseudo selectors, since these can never be + transformed into anything useful. + +* In Phase 2: + + * Don't throw an error for style rules that contain no children, since this + would break nesting. + + * Throw an error for an `@extend` rule with a bogus extender. + + * Support single leading combinators. + + * Support complex selectors composed of only a single combinator. + + * Allow bogus selectors in `selector.append()`. + +## Draft 2 + +* Allow leading combinators in `:has()`. + +* Replace our custom `Combinator` production with the CSS spec's ``. + +## Draft 1 + +* Initial draft. diff --git a/accepted/bogus-combinators.md b/accepted/bogus-combinators.md new file mode 100644 index 0000000000..4d93badce5 --- /dev/null +++ b/accepted/bogus-combinators.md @@ -0,0 +1,257 @@ +# Bogus Combinators: Draft 3 + +*([Issue](https://github.com/sass/sass/issues/3340), [Changelog](bogus-combinators.changes.md))* + +This proposal increases the strictness with which Sass parses and resolves +non-standard ("bogus") uses of selector combinators. In particular, it forbids +the use of multiple combinators in a row (such as `div + ~ a`) and limits the +use of leading combinators (such as `> a`) and trailing combinators (such as `a +>`) to selector nesting. + +## Table of Contents + +* [Background](#background) +* [Summary](#summary) + * [Phase 1: Deprecation](#phase-1-deprecation) + * [Phase 2: Removal](#phase-2-removal) +* [Definitions](#definitions) + * [Visible Combinator](#visible-combinator) + * [Complex Selector](#complex-selector) + * [Complex Selector Component](#complex-selector-component) + * [Trailing Combinator](#trailing-combinator) + * [Bogus Selector](#bogus-selector) +* [Syntax](#syntax) + * [`ComplexSelector`](#complexselector) +* [Semantics](#semantics) + * [Evaluating a Style Rule](#evaluating-a-style-rule) + * [Executing an Extend Rule](#executing-an-extend-rule) +* [Functions](#functions) +* [Deprecation Process](#deprecation-process) + * [Phase 1](#phase-1) + * [Phase 2](#phase-2) + +## Background + +> This section is non-normative. + +Currently, Sass is very liberal when it comes to where explicit selector +combinators can be written—much more so than CSS itself. It allows: + +* Multiple combinators between compound selectors (`a > + b`). +* Combinators at the beginning of selectors (`> a`). +* Combinators at the end of selectors (`a >`). + +The latter two are useful when nesting style rules, but the former has no known +use at all. Historically, we've said that we support these because they enable +some browser hacks, but this seems to be purely hypothetical: [browserhacks.com] +is the most comprehensive source of hacks I've found, and it doesn't list any +hacks that are enabled by this support, even among its "legacy hacks". + +[browserhacks.com]: http://browserhacks.com + +In addition, supporting these selectors imposes substantial complexity on Sass +implementations. They [cause bugs] and make the data model more complex than it +needs to be. This in turn makes bugs like [sass/sass#1807] that don't involve +non-standard combinators more difficult to resolve. + +[cause bugs]: https://github.com/sass/dart-sass/issues/1053 +[sass/sass#1807]: https://github.com/sass/sass/issues/1807 + +## Summary + +> This section is non-normative. + +We'll move towards forbidding these combinators in two phases. + +### Phase 1: Deprecation + +In the first phase, we'll issue deprecation messages for all forbidden cases, +but only change behavior in cases where Sass was already producing invalid CSS +anyway. In particular: + +* Once nesting and extensions have been resolved, if any of a style rule's + selectors contains a leading, trailing, or multiple combinator after nesting + and extensions are resolved, omit that style rule from the generated CSS and + emit a deprecation warning. + +* If a selector with a leading or trailing combinator is used with any + extend-related infrastructure, emit a deprecation warning but *don't* change + the behavior unless the resolved selector still has a bogus combinator, as + above. + +* If a selector with a doubled combinator is used with any extend-related + infrastructure, emit a deprecation warning and treat that selector as though + it matches no elements. + +This will be sufficient to substantially simplify the implementation without +affecting the in-browser behavior of any stylesheets. + +### Phase 2: Removal + +In the second phase, which for existing implementations will accompany a major +version release, we will emit errors everywhere Phase 1 produced deprecation +warnings. In particular: + +* If a style rule's selectors contain leading, trailing, or multiple combinators + after nesting is resolved, emit an error. + +* If a selector with a leading, trailing, or multiple combinator is used with + `@extend` (which, given the previous restriction, will only be possible using + extension functions from `sass:selector`), emit an error. + +## Definitions + +> Most existing definitions being modified here haven't been defined explicitly +> before this document. The old definitions are listed in strikethrough mode to +> clarify the change. + +### Visible Combinator + +A *visible combinator* is any selector [combinator] other than the [descendant +combinator]. + +[combinator]: https://drafts.csswg.org/selectors-4/#combinators +[descendant combinator]: https://drafts.csswg.org/selectors-4/#descendant-combinators + +### Complex Selector + +~~A *complex selector* is a sequence of [visible combinators] (its *leading +combinators*) as well as a sequence of [complex selector components]. Either, +but not both, of these sequences may be empty~~ + +[visible combinators]: #visible-combinator +[complex selector components]: #complex-selector-components + +A *complex selector* is an optional [visible combinator] (its *leading +combinator*) as well as a sequence of [complex selector components]. The +component sequence may be empty only for complex selectors with leading +combinators. + +[visible combinator]: #visible-combinator + +### Complex Selector Component + +~~A *complex selector component* is a compound selector as well as a sequence of +zero or more [visible combinators].~~ + +A *complex selector component* is a compound selector as well as a single +[combinator]. + +### Trailing Combinator + +A [complex selector]'s *trailing combinator* is its final [complex selector +component]'s combinator if it's not a [descendant combinator]. If it *is* a +descendant combinator, the complex selector doesn't have a trailing combinator. + +[complex selector]: #complex-selector +[complex selector component]: #complex-selector-component + +### Bogus Selector + +A [complex selector] is *bogus* if it has a leading or [trailing combinator], or +if any of the simple selectors it transitively contains is a selector pseudo +with a bogus selector, except that `:has()` may contain complex selectors with +leading combinators. + +A selector list is *bogus* if any of its complex selectors are bogus. + +[trailing combinator]: #trailing-combinator + +## Syntax + +### `ComplexSelector` + +> Note that the existing productions being modified have not been defined +> explicitly before this document. The old productions are listed in +> strikethrough mode to clarify the change. + +This proposal modifies the existing `ComplexSelector` and +`ComplexSelectorComponent` productions to drop support for multiple combinators: + +
+~~**ComplexSelector**          ::= [\]* ComplexSelectorComponent+~~
+~~                           | [\]+~~
+~~**ComplexSelectorComponent** ::= CompoundSelector [\]*~~
+**ComplexSelector**          ::= [\]? ComplexSelectorComponent+
+                           | [\]
+**ComplexSelectorComponent** ::= CompoundSelector [\]?
+
+ +[\]: https://drafts.csswg.org/selectors-4/#typedef-combinator + +## Semantics + +### Evaluating a Style Rule + +This proposal adds the following to [Evaluating a Style Rule], after executing +each child of `rule`: + +[Evaluating a Style Rule]: ../spec/style-rules.md#semantics + +* If `css` contains any children and `selector` is [bogus], throw an error. + +[bogus]: #bogus-selector + +### Executing an Extend Rule + +This proposal adds the following to [Executing an Extend Rule], after checking +for a current style rule: + +[Executing an Extend Rule]: ../spec/at-rules/extend.md#executing-an-extend-rule + +* If the current style rule is [bogus], throw an error. + +## Functions + +For the `selector.extend()`, `selector.is-superselector()`, +`selector.replace()`, and `selector.unify()` functions, after parsing their +selector arguments, throw an error if any of the parsed selectors are [bogus]. + +> `selector.append()`, `selector.nest()`, and `selector.parse()` are still +> allowed to take bogus selectors because these functions are syntactic rather +> than semantic. This means on one hand that there aren't ambiguities about how +> to handle bogus selector inputs, and on the other that it may be useful to +> emit bogus selectors for later use in nesting contexts. +> +> Note that `selector.append()` already forbids selectors with leading or +> trailing combinators from being passed in between selectors. + +## Deprecation Process + +The deprecation will be divided into two phases: + +### Phase 1 + +This phase will only change behavior that doesn't affect in-browser rendering. +In particular: + +* The parsing of `ComplexSelector` and `ComplexSelectorComponent` is unchanged. + +* 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. + +* The newly-added errors produce deprecation warnings instead. + +* In [Evaluating a Style Rule], remove any complex selectors from `css`'s + selectors that are [bogus], except those that have a single leading combinator + but are otherwise not bogus. + + > Leading combinators are allowed in Phase 1 (but still emit deprecation + > warnings) because they may be used for nesting along with `meta.load-css()`. + +* Define a "useless" selector as: + + * A complex selector that has multiple combinators. + + * A bogus pseudo selector. + + * Any selector that contains a useless selector. + + In [Extending a Selector], treat useless selectors as selectors that can match + no elements. + + [Extending a Selector]: ../spec/at-rules/extend.md#extending-a-selector + +### Phase 2 + +This phase will emit errors as described in the body of the proposal. diff --git a/accepted/color-4-hwb.md b/accepted/color-4-hwb.md index f2a563a59a..1a34e0060d 100644 --- a/accepted/color-4-hwb.md +++ b/accepted/color-4-hwb.md @@ -78,7 +78,7 @@ are left to a future proposal. ## Procedures -### Scaling a Number +### Scaling a Number This algorithm takes a number `number`, a value `factor`, and a number `max`. It's written "scale `` by `` with a `max` of ``". It @@ -112,7 +112,7 @@ All new functions are part of the `sass:color` built-in module. * If either of `$whiteness` or `$blackness` don't have unit `%` or aren't between `0%` and `100%` (inclusive), throw an error. - * Let `hue` be `($hue % 360) / 60` without units. + * Let `hue` be `$hue` without units. * Let `whiteness` be `$whiteness / 100%`. @@ -131,7 +131,7 @@ All new functions are part of the `sass:color` built-in module. and rounded to the nearest integers. * Let `alpha` be the result of [percent-converting][] `$alpha` with a `max` of 1. - + * Return a color with the given `red`, `green`, `blue`, and `alpha` channels. [percent-converting]: ../spec/built-in-modules/color.md#percent-converting-a-number @@ -260,7 +260,7 @@ This function's new definition is as follows: * Let `hue`, `saturation`, and `lightness` be the result of calling `hue($color)`, `saturation($color)`, and `lightness($color)` respectively. - + * If `$hue` isn't null, set `hue` to `hue + $hue`. * If `$saturation` isn't null, set `saturation` to `saturation + $saturation` @@ -279,7 +279,7 @@ This function's new definition is as follows: * Let `hue`, `whiteness`, and `blackness` be the result of calling `hue($color)`, `whiteness($color)`, and `blackness($color)` respectively. - + * If `$hue` isn't null, set `hue` to `hue + $hue`. * If `$whiteness` isn't null, set `whiteness` to `whiteness + $whiteness` @@ -334,7 +334,7 @@ This function's new definition is as follows: * Let `green` be `$color`'s green channel if `$green` is null or `$green` without units otherwise. - + * Let `blue` be `$color`'s blue channel if `$blue` is null or `$blue` without units otherwise. @@ -401,7 +401,7 @@ This function's new definition is as follows: * If `$alpha` isn't null, set `alpha` to the result of [scaling][] `alpha` by `$alpha` with `max` 1. - + [scaling]: #scaling-a-number * If any of `$red`, `$green`, or `$blue` aren't null: diff --git a/accepted/deep-merge-order.md b/accepted/deep-merge-order.md new file mode 100644 index 0000000000..406fd07c23 --- /dev/null +++ b/accepted/deep-merge-order.md @@ -0,0 +1,123 @@ +# Deep Merge Order: Draft 1 + +*([Issue](https://github.com/sass/sass/issues/3092))* + +This proposal changes the ordering of maps returned by `map.deep-merge()` to +match that returned by `map.merge()`. + +## Table of Contents + +* [Background](#background) +* [Summary](#summary) + * [Design Decisions](#design-decisions) + * [Whether to Specify Order](#whether-to-specify-order) +* [Functions](#functions) + * [`map.deep-merge()`](#mapdeep-merge) +* [Deprecation Process](#deprecation-process) + +## Background + +> This section is non-normative. + +When `map.deep-merge()` was first discussed in [issue 1739] and later [added to +the spec], their ordering wasn't explicitly discussed. In practice, the ordering +implied by the original specification put any keys that appeared in both maps at +the end of the result, in the order they appeared in `$map2`. This was different +than the ordering produced by the `map.merge()` function in a way that confused +users. + +[issue 1739]: https://github.com/sass/sass/issues/1739 +[added to the spec]: ../accepted/nested-map-functions.md + +## Summary + +> This section is non-normative. + +This proposal changes the `map.deep-merge()` function to match the ordering of +`map.merge()`, in which all keys in `$map1` appear in the result the same order +they did in `$map1` (whether or not they're in `$map2`), followed by all keys +that are only in `$map2` in the same relative order as in `$map2`. For example: + +* `map.deep-merge((a: 1, b: 1), (b: 2, c: 2))` produces `(a: 1, b: 2, c: 2)` in + both the current spec and this proposal. + +* `map.deep-merge((a: 1, b: 1), (a: 2, c: 2))` produces `(b: 1, a: 2, c: 2)` in + the current spec but `(a: 2, b: 1, c: 2)` in this proposal. + +### Design Decisions + +#### Whether to Specify Order + +Rather than change the specified order of map entries, we considered updating +the specification to explicitly make the order an implementation detail. This +would have the advantage of allowing implementations to choose a more performant +ordering in the future if, for example, they used an immutable representation of +maps that could re-use internal data structures. + +However, because in practice there's currently only one recommended +implementation of Sass, its behavior would still end up being the *de facto* +standard. In addition, users clearly desire an intuitive map ordering and +there's not clear evidence that any performance gains would be substantial +enough to warrant breaking that intuition. + +## Functions + +Replace the definition of the `deep-merge()` function in the `sass:map` built-in +module with the following definition: + +### `map.deep-merge()` + +``` +deep-merge($map1, $map2) +``` + +* If `$map1` and `$map2` are not maps, throw an error. + +* Let `merged` be an empty map. + +* For each `old-key`/`old-value` pair in `$map1`: + + * If `$map2` has a key `new-key` that's `==` to `old-key`: + + * Let `new-value` be the value associated with `new-key` in `$map2`. + + * If both `old-value` and `new-value` are maps, set `new-value` to the + result of calling `deep-merge()` with `old-value` and `new-value`. + + * Associate `old-key` with `new-value` in `merged`. + + * Otherwise, associate `old-key` with `old-value` in `merged`. + +* For each `new-key`/`new-value` pair in `$map2`: + + * If `merged` doesn't have key that's `==` to `new-key`, associate `new-key` + with `new-value` in `merged`. + +* Return `merged`. + +> Note that the order of keys in each merged map is the same as the keys in +> `$map1`, with any new keys from `$map2` added at the end in the same order +> they appear in `$map2`. This matches the ordering of the `merge()` function. + +## Deprecation Process + +This is technically a breaking change, since stylesheets could be relying on the +current ordering of `map.deep-merge()`. However, there are several reasons why a +standard deprecation process isn't a good fit here: + +* There isn't a good way to deprecate the old behavior non-disruptively. If we + support the old behavior as written, the new behavior would need to be awkward + to use. + +* The breaking change is small. Output ordering is not a core part of + `map.deep-merge()`'s behavior and is unlikely to be something anyone is + relying on in practice. + +* `map.deep-merge()` is relatively young, which means that there are not as many + Sass stylesheets using it (and thus relying on every aspect of its behavior) + as there are using older behaviors. + +* The change is a clear improvement in terms of consistency with `map.merge()` + and with merge behavior in other languages. It could even be argued as a bug + fix. Any pain caused by this change is likely to be mitigated by the pain due + to confusing ordering it will prevent. diff --git a/accepted/media-logic.changes.md b/accepted/media-logic.changes.md new file mode 100644 index 0000000000..2e4550de0c --- /dev/null +++ b/accepted/media-logic.changes.md @@ -0,0 +1,13 @@ +## Draft 1.1 + +* In the `MediaQuery` production, don't allow an `Interpolation` to be followed + by `(MediaAnd* | MediaOr*)` since `Interpolation` is ambiguous with + `MediaType`. + +* Forbid whitespace in the `MediaNot`, `MediaAnd`, and `MediaOr` productions. + +* Fix the link for `CssMediaQuery`. + +## Draft 1 + +* Initial draft. diff --git a/accepted/media-logic.md b/accepted/media-logic.md new file mode 100644 index 0000000000..5ea53d344c --- /dev/null +++ b/accepted/media-logic.md @@ -0,0 +1,132 @@ +# Media Logic: Draft 1.1 + +*([Issue](https://github.com/sass/sass/issues/2538), [Changelog](media-logic.changes.md))* + +This proposal adds support for the full [Media Queries Level 4] syntax for media +conditions, including arbitrary boolean logic using `and`, `or`, and `not`. + +[Media Queries Level 4]: https://www.w3.org/TR/mediaqueries-4/#media-conditions + +## Table of Contents + +* [Background](#background) +* [Summary](#summary) +* [Syntax](#syntax) + * [`MediaQuery`](#mediaquery) + * [`CssMediaQuery`](#cssmediaquery) +* [Deprecation Process](#deprecation-process) + +## Background + +> This section is non-normative. + +For historical reasons, Sass fully parses media queries and allows SassScript to +be embedded directly in them, as in `@media ($query: $value)`, in contrast to +most other at-rules in which SassScript can only be injected using +interpolation. This means that as CSS adds new media query syntax, Sass is +obligated to update its specification to accommodate it. + +[Media Queries Level 4] adds support for arbitrary boolean logic in media +queries, such as `@media ((width >= 100px) and (width <= 800px)) or (grid)`. +Sass must therefore update its syntax accordingly. + +## Summary + +> This section is non-normative. + +The proposal is relatively straightforward: it adds the new syntax to Sass's +grammar. It is worth noting, though, that this will require a few breaking +changes. These are unlikely to affect many real-world stylesheets, but they're +worth highlighting nevertheless. + +The new syntax allows any [``] to appear inside a +[``]. This means that queries beginning with `(not ` or `((` +must be parsed as nested media queries, rather than SassScript expressions as +they have historically been parsed. We'll issue a short deprecation period for +the SassScript expressions in question, recommending users migrate them to +interpolation instead, then drop support and begin parsing them as media queries +for CSS compatibility. + +[``]: https://drafts.csswg.org/mediaqueries-4/#typedef-media-condition +[``]: https://drafts.csswg.org/mediaqueries-4/#typedef-media-in-parens + +## Syntax + +### `MediaQuery` + +Replace the definition of the [`MediaQuery`] production with the following (with +all identifiers matched case-insensitively): + +[`MediaQuery`]: ../spec/at-rules/media.md#sass + +
+**MediaQuery**     ::= MediaNot
+                 | MediaInParens (MediaAnd* | MediaOr*)
+                 | MediaType ('and' MediaNot | MediaAnd*)
+**MediaType**      ::= [InterpolatedIdentifier] [InterpolatedIdentifier]¹?
+**MediaNot**²      ::= 'not' MediaOrInterp
+**MediaAnd**²      ::= 'and' MediaOrInterp
+**MediaOr**²       ::= 'or' MediaOrInterp
+**MediaOrInterp**  ::= Interpolation | MediaInParens
+**MediaInParens**  ::= '(' Expression³ ')'
+                 | '(' Expression³ [\] Expression³ ')'
+                 | '(' Expression³ [\] Expression³ [\] Expression³ ')'
+                 | '(' Expression³ [\] Expression³ [\] Expression³ ')'
+                 | '(' MediaNot ')'
+                 | '(' MediaInParens (MediaAnd* | MediaOr*) ')'
+
+ +[InterpolatedIdentifier]: ../syntax.md#interpolatedidentifier +[\]: https://drafts.csswg.org/mediaqueries-4/#typedef-mf-comparison +[\]: https://drafts.csswg.org/mediaqueries-4/#typedef-mf-lt +[\]: https://drafts.csswg.org/mediaqueries-4/#typedef-mf-gt + +1. This `InterpolatedIdentifier` may not be the identifier `"and"`. + +2. No whitespace is allowed between the identifier and the `MediaOrInterp` in + these productions. + +3. These `Expression`s may not: + + * Contain binary operator expressions with the operators `=`, `>`, `>=`, `<`, + or `<=`, except within parentheses (including function calls and map + literals) and square brackets. + + * Begin with the case-insensitive identifier `"not"`. + + * Begin with the character `"("`. + +### `CssMediaQuery` + +Replace the definition of the [`CssMediaQuery`] production with the following (with +all identifiers matched case-insensitively): + +[`CssMediaQuery`]: ../spec/at-rules/media.md#css + +
+**CssMediaQuery**     ::= CssMediaCondition
+                    | CssMediaType ('and' CssMediaNot | CssMediaAnd*)
+**CssMediaType**      ::= [\] [\]¹?
+**CssMediaCondition** ::= CssMediaNot | CssMediaInParens (CssMediaAnd* | CssMediaOr*)
+**CssMediaNot**       ::= 'not' CssMediaInParens
+**CssMediaAnd**       ::= 'and' CssMediaInParens
+**CssMediaOr**        ::= 'or' CssMediaInParens
+**CssMediaInParens**  ::= '(' [\] ')'
+
+ +[\]: https://drafts.csswg.org/css-syntax-3/#ident-token-diagram +[\]: https://drafts.csswg.org/css-syntax-3/#typedef-declaration-value + +1. This `` may not be the identifier `"and"`. + +## Deprecation Process + +Before this specification is applied in full force, it will be applied with the +following modifications: + +* [`MediaInParens`](#mediaquery) will not allow the productions `'(' MediaNot + ')'` or `'(' MediaInParens (MediaAnd* | MediaOr*) ')'`. + +* If the first `Expression` in a `MediaInParens` production begins with the + case-insensitive identifier `"not"` or the character `"("`, emit a deprecation + warning. diff --git a/accepted/module-system.changes.md b/accepted/module-system.changes.md index 36123493d3..987ee15cba 100644 --- a/accepted/module-system.changes.md +++ b/accepted/module-system.changes.md @@ -1,3 +1,7 @@ +## Draft 10 + +* Update the timeline for the deprecation and removal of `@import`. + ## Draft 9 * Don't add imported module members to the global scope for a nested import. diff --git a/accepted/module-system.md b/accepted/module-system.md index cd611e82e6..84c876c653 100644 --- a/accepted/module-system.md +++ b/accepted/module-system.md @@ -1,4 +1,4 @@ -# The Next-Generation Sass Module System: Draft 6 +# The Next-Generation Sass Module System: Draft 10 *([Issues](https://github.com/sass/sass/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3A%22%40use%22), [Changelog](module-system.changes.md))* @@ -1776,14 +1776,22 @@ However, doing away with `@import` entirely is the ultimate goal for simplicity, performance, and CSS compatibility. As such, we plan to gradually turn down support for `@import` on the following timeline: -* One year after both implementations launch support for the module system *or* - two years after Dart Sass launches support for the module system, whichever - comes sooner (**1 October 2021** at latest): Deprecate `@import` as well as global - core library function calls that could be made through modules. +* ~~One year after both implementations launch support for the module system + *or* two years after Dart Sass launches support for the module system, + whichever comes sooner (**1 October 2021** at latest): Deprecate `@import` as + well as global core library function calls that could be made through + modules.~~ -* One year after this deprecation goes into effect (**1 October 2022** at +* ~~One year after this deprecation goes into effect (**1 October 2022** at latest): Drop support for `@import` and most global functions entirely. This - will involve a major version release for all implementations. + will involve a major version release for all implementations.~~ -This means that there will be at least two full years when `@import` and `@use` -are both usable at once, and likely closer to three years in practice. +~~This means that there will be at least two full years when `@import` and `@use` +are both usable at once, and likely closer to three years in practice.~~ + +**July 2022**: In light of the fact that LibSass was deprecated before ever +adding support for the new module system, the timeline for deprecating and +removing `@import` has been pushed back. We now intend to wait until 80% of +users are using Dart Sass (measured by npm downloads) before deprecating +`@import`, and wait at least a year after that and likely more before removing +it entirely. diff --git a/accepted/random-with-units.changes.md b/accepted/random-with-units.changes.md new file mode 100644 index 0000000000..4b6f37713a --- /dev/null +++ b/accepted/random-with-units.changes.md @@ -0,0 +1,9 @@ +## Draft 1.1 + +* Replace floating-point wording for simply "number". + +* Update integer return value range from `[1, $limit)` to `[1, $limit]`. + +## Draft 1 + +* Initial draft. diff --git a/accepted/random-with-units.md b/accepted/random-with-units.md new file mode 100644 index 0000000000..e28c7a863a --- /dev/null +++ b/accepted/random-with-units.md @@ -0,0 +1,101 @@ +# Random With Units: Draft 1.1 + +*([Issue](https://github.com/sass/sass/issues/1890), [Changelog](random-with-units.changes.md))* + +This proposal modifies the behavior of the built-in [`math.random()`][random] +function to return a number with matching units to the numeric argument it +received. + +[random]: ../spec/built-in-modules/math.md#random + +## Table of Contents + +* [Background](#background) +* [Summary](#summary) + * [Design Decisions](#design-decisions) + * [New Behavior vs New Syntax](#new-behavior-vs-new-syntax) + * [No Stripping Units Fallback](#no-stripping-units-fallback) +* [Semantics](#semantics) +* [Deprecation Process](#deprecation-process) + +## Background + +> This section is non-normative. + +Sass provides a built-in [`math.random()` function][random] which takes an +optional numeric parameter `$limit` (defaults to `null`). + +When `null` is passed it returns a decimal in the range `[0, 1)`. When an +integer greater than zero is passed it returns a number in the range +`[1, $limit)`. Otherwise it throws an error. + +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. +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 + +## Summary + +> This section is non-normative. + +The built-in `math.random($limit: null)` function will keep the same behavior +for numbers without units, but when given an integer with units it will return a +random integer with matching units. + +### Design Decisions + +#### New Behavior vs New Syntax + +This proposal keeps the existing syntax but changes the semantics, therefore it +is a breaking change. + +A backwards compatible alternative was a second optional parameter for units, +e.g. `math.random(42, 'px')`, but it didn't solve the problem when the first +parameter has units, e.g. `math.random(42em, 'px')`. + +We decided to update the behavior and follow the [deprecation process]. + +[deprecation process]: #deprecation-process + +#### No Stripping Units Fallback + +Sass considers [stripping units an anti-pattern], so we won't provide a fallback +option for the previous unit-stripping behavior. Users are expected to rely on +unit-based arithmetic. + +[stripping units an anti-pattern]: https://github.com/sass/sass/issues/533#issuecomment-52531596 + +## Semantics + +The `math.random()` function can take an optional parameter `$limit` which +defaults to `null`. + +* If `$limit` is `null` then return a pseudo-random unitless number whose value + is in the range `[0, 1)`. + + > Example: `math.random() => 0.1337001337` + +* If `$limit` is an **integer** [number] greater than zero: + + * Return a pseudo-random integer in the range `[1, $limit]` with the same + [units] as `$limit`. + + > Examples: + > - `math.random(123) => 87` + > - `math.random(123px) => 43px` + > - `math.random(500%) => 238%` + +* Otherwise throw an error. + +[number]: https://sass-lang.com/documentation/values/numbers +[units]: https://sass-lang.com/documentation/values/numbers#units + +## Deprecation Process + +Given some users may be relying on the existing Dart Sass implementation which +strips off the units, this will be a breaking change for Dart Sass v1. + +We will emit deprecation warnings for any use of `math.random($limit)` where the +`$limit` argument evaluates to a number with units. diff --git a/js-api-doc/README.md b/js-api-doc/README.md index 9a1b1e989e..8407913400 100644 --- a/js-api-doc/README.md +++ b/js-api-doc/README.md @@ -18,29 +18,39 @@ much slower,** but they allow custom importers and functions to run asynchronously. * [[compile]] and [[compileAsync]] take a path to a Sass file and return the - result of compiling that file to CSS. + result of compiling that file to CSS. These functions accept an additional + [[Options]] argument. ```js const sass = require('sass'); const result = sass.compile("style.scss"); console.log(result.css); + + const compressed = sass.compile("style.scss", {style: "compressed"}); + console.log(compressed.css); ``` * [[compileString]] and [[compileStringAsync]] take a string that represents the contents of a Sass file and return the result of compiling that file to CSS. + These functions accept an additional [[StringOptions]] argument. ```js const sass = require('sass'); - const result = sass.compileString(` + const input = ` h1 { font-size: 40px; code { font-face: Roboto Mono; } - }`); + }`; + + const result = sass.compileString(input); console.log(result.css); + + const compressed = sass.compileString(input, {style: "compressed"}); + console.log(compressed.css); ``` ## Integrations @@ -76,7 +86,7 @@ Sass code by passing in a [[LegacyStringOptions]]. * [[renderSync]] runs synchronously. It's **by far the fastest option** when using Dart Sass, but at the cost of only supporting synchronous {@link LegacyImporter | importer} and {@link LegacyFunction | function} plugins. - + ```js const sass = require('sass'); // or require('node-sass'); diff --git a/js-api-doc/importer.d.ts b/js-api-doc/importer.d.ts index 68a834023f..124425a0e7 100644 --- a/js-api-doc/importer.d.ts +++ b/js-api-doc/importer.d.ts @@ -23,7 +23,7 @@ import {PromiseOr} from './util/promise_or'; * @example * * ```js - * const {fileURLToPath} = require('url'); + * const {pathToFileURL} = require('url'); * * sass.compile('style.scss', { * importers: [{ diff --git a/js-api-doc/options.d.ts b/js-api-doc/options.d.ts index 1f3ba66358..4c9445d7f5 100644 --- a/js-api-doc/options.d.ts +++ b/js-api-doc/options.d.ts @@ -38,7 +38,8 @@ export type OutputStyle = 'expanded' | 'compressed'; * const result = sass.compile('style.scss', { * functions: { * "sum($arg1, $arg2)": (args) => { - * const value1 = args[0].assertNumber('arg1').value; + * const arg1 = args[0].assertNumber('arg1'); + * const value1 = arg1.value; * const value2 = args[1].assertNumber('arg2') * .convertValueToMatch(arg1, 'arg2', 'arg1'); * return new sass.SassNumber(value1 + value2).coerceToMatch(arg1); @@ -107,6 +108,20 @@ export interface Options { */ alertColor?: boolean; + /** + * If `true`, the compiler may prepend `@charset "UTF-8";` or U+FEFF + * (byte-order marker) if it outputs non-ASCII CSS. + * + * If `false`, the compiler never emits these byte sequences. This is ideal + * when concatenating or embedding in HTML `