From d25f305c4c2e0da68a04f4bb07343f7219253e91 Mon Sep 17 00:00:00 2001 From: Sana Javed Date: Fri, 17 Feb 2023 17:10:42 +0100 Subject: [PATCH 01/42] Learn sass page and first pass at code example helper --- eleventy.config.cjs | 38 ++ package.json | 2 +- source/_includes/code_example.liquid | 45 ++ source/_layouts/base.liquid | 2 +- source/assets/js/vendor/index.ts | 4 +- source/code-snippets/_homepage-sass-watch.md | 3 + source/guide.md | 447 +++++++++++++++++++ yarn.lock | 10 +- 8 files changed, 543 insertions(+), 8 deletions(-) create mode 100644 source/_includes/code_example.liquid create mode 100644 source/code-snippets/_homepage-sass-watch.md create mode 100644 source/guide.md diff --git a/eleventy.config.cjs b/eleventy.config.cjs index 91a45a8dd..590730557 100644 --- a/eleventy.config.cjs +++ b/eleventy.config.cjs @@ -6,6 +6,7 @@ const yaml = require('js-yaml'); const markdown = require('markdown-it'); const markdownDefList = require('markdown-it-deflist'); const typogrify = require('typogr'); +const sass = require('sass'); /** @param {import('@11ty/eleventy').UserConfig} eleventyConfig */ module.exports = (eleventyConfig) => { @@ -63,6 +64,43 @@ module.exports = (eleventyConfig) => { page.url.startsWith('/documentation/js-api/'), ); + eleventyConfig.addLiquidFilter( + 'codeExample', + (contents, autogenCSS=true, syntax=null) => { + //TODO when are values for syntax passed in? + //TODO add tests + const splitContents = contents.split('==='); + + const scssContents = splitContents[0]; + const sassContents = splitContents[1]; + const cssContents = splitContents[2]; + + const scssExamples = scssContents.split('---') + const sassExamples = sassContents.split('---') + + let cssExample; + if(cssContents){ + cssExample = cssContents + } + else if(!cssContents && autogenCSS) { + // TODO check first if you even have scss or sass to generate css from + // TODO what if no scss but sass? + cssExample = ''; + scssExamples.forEach((scssSnippet) => { + const generatedCSS = sass.compileString(scssSnippet); + cssExample += generatedCSS.css; + }); + } + + return { + scss: scssExamples, + css: cssExample, + sass: sassExamples, + splitLocation: '50.0%' //TODO dynamically determine + }; + }, + ); + eleventyConfig.addPlugin(EleventyRenderPlugin); // settings diff --git a/package.json b/package.json index 0bc590fe3..06a0c4749 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "npm-run-all": "^4.1.5", "prettier": "^2.8.3", "rollup": "^3.12.0", - "sass": "^1.57.1", + "sass": "^1.58.0", "semver-parser": "^4.0.1", "stylelint": "^14.16.1", "stylelint-config-prettier": "^9.0.4", diff --git a/source/_includes/code_example.liquid b/source/_includes/code_example.liquid new file mode 100644 index 000000000..aeebb6395 --- /dev/null +++ b/source/_includes/code_example.liquid @@ -0,0 +1,45 @@ +{% assign first_tab_id = ui_id %} +{% assign second_tab_id = first_tab_id | plus: 1 %} +{% assign third_tab_id = second_tab_id | plus: 1 %} + +
+ +
+ {% for scss in code.scss %} +
+            
+                {{ scss | strip }}
+            
+        
+ {% endfor %} +
+ + +
\ No newline at end of file diff --git a/source/_layouts/base.liquid b/source/_layouts/base.liquid index 6c8a976f9..70788af95 100644 --- a/source/_layouts/base.liquid +++ b/source/_layouts/base.liquid @@ -43,6 +43,7 @@ gtag('config', 'UA-535380-14'); + @@ -130,7 +131,6 @@ } }(document, 'script', 'twitter-wjs'); - diff --git a/source/assets/js/vendor/index.ts b/source/assets/js/vendor/index.ts index 9171c4ac0..1e7648224 100644 --- a/source/assets/js/vendor/index.ts +++ b/source/assets/js/vendor/index.ts @@ -1,5 +1,7 @@ +import 'jquery'; import 'jquery-ui'; - +import 'jquery-ui/ui/unique-id'; +import 'jquery-ui/ui/widgets/tabs'; import './jquery-smooth-scroll.min'; import './modernizr.custom.min'; import './html5-boilerplate/plugins'; diff --git a/source/code-snippets/_homepage-sass-watch.md b/source/code-snippets/_homepage-sass-watch.md new file mode 100644 index 000000000..9f8f8adc7 --- /dev/null +++ b/source/code-snippets/_homepage-sass-watch.md @@ -0,0 +1,3 @@ +``` +sass --watch app/sass:public/stylesheets +``` diff --git a/source/guide.md b/source/guide.md new file mode 100644 index 000000000..bd52b21c2 --- /dev/null +++ b/source/guide.md @@ -0,0 +1,447 @@ +--- +layout: has_no_sidebars +title: Sass Basics +introduction: > + Before you can use Sass, you need to set it up on your project. If you want to + just browse here, go ahead, but we recommend you go install Sass first. [Go + here](/install) if you want to learn how to get everything set up. +--- + + + +## Preprocessing + +CSS on its own can be fun, but stylesheets are getting larger, more +complex, and harder to maintain. This is where a preprocessor can help. +Sass has features that don't exist in CSS yet like nesting, mixins, +inheritance, and other nifty goodies that help you write robust, +maintainable CSS. + +Once you start tinkering with Sass, it will take your preprocessed Sass +file and save it as a normal CSS file that you can use in your website. + +The most direct way to make this happen is in your terminal. Once Sass is +installed, you can compile your Sass to CSS using the `sass` command. +You'll need to tell Sass which file to build from, and where to output CSS +to. For example, running `sass input.scss output.css` from your terminal +would take a single Sass file, `input.scss`, and compile that file to +`output.css`. + +You can also watch individual files or directories with the `--watch` +flag. The watch flag tells Sass to watch your source files for changes, +and re-compile CSS each time you save your Sass. If you wanted to watch +(instead of manually build) your `input.scss` file, you'd just add the +watch flag to your command, like so: + +``` +sass --watch input.scss output.css +``` + +You can watch and output to directories by using folder paths as your +input and output, and separating them with a colon. In this example: + +{% renderFile 'source/code-snippets/_homepage-sass-watch.md' %} + +Sass would watch all files in the `app/sass` folder for changes, and +compile CSS to the `public/stylesheets` folder. + +
+ +### 💡 Fun fact: + +Sass has two syntaxes! The SCSS syntax (`.scss`) is used most commonly. It's +a superset of CSS, which means all valid CSS is also valid SCSS. The +indented syntax (`.sass`) is more unusual: it uses indentation rather than +curly braces to nest statements, and newlines instead of semicolons to +separate them. All our examples are available in both syntaxes. + +
+ +--- + +## Variables + +Think of variables as a way to store information that you want to reuse +throughout your stylesheet. You can store things like colors, font stacks, +or any CSS value you think you'll want to reuse. Sass uses the `$` symbol +to make something a variable. Here's an example: + +{% assign code = "$font-stack: Helvetica, sans-serif; +$primary-color: #333; + +body { +font: 100% $font-stack; +color: $primary-color; +} + +=== + +$font-stack: Helvetica, sans-serif +$primary-color: #333 + +body +font: 100% $font-stack +color: $primary-color" | codeExample: true, 'scss' -%} + +{% assign example_id = 1 %} +{% assign ui_id = 1 %} +{% render 'code_example', +code: code, +example_id: example_id, +ui_id: ui_id %} + +When the Sass is processed, it takes the variables we define for the +`$font-stack` and `$primary-color` and outputs normal CSS with our +variable values placed in the CSS. This can be extremely powerful when +working with brand colors and keeping them consistent throughout the site. + +--- + +## Nesting + +When writing HTML you've probably noticed that it has a clear nested and visual hierarchy. CSS, on the other hand, doesn't. + +Sass will let you nest your CSS selectors in a way that follows the same +visual hierarchy of your HTML. Be aware that overly nested rules will +result in over-qualified CSS that could prove hard to maintain and is +generally considered bad practice. + +With that in mind, here's an example of some typical styles for a site's +navigation: + +{% capture example_id %} + {{ example_id | plus: 1 }} +{% endcapture %} +{% capture ui_id %} + {{ ui_id | plus: 3 }} +{% endcapture %} + +{% assign code = +"nav { +ul { + margin: 0; + padding: 0; + list-style: none; +} + +li { display: inline-block; } + +a { + display: block; + padding: 6px 12px; + text-decoration: none; +} +} +=== +nav + ul + margin: 0 + padding: 0 + list-style: none + + li + display: inline-block + + a + display: block + padding: 6px 12px + text-decoration: none" | codeExample: true, 'scss' %} + + +{% render 'code_example', +code: code, +example_id: example_id, +ui_id: ui_id %} + +--- + +## Partials + +You can create partial Sass files that contain little snippets of CSS that you can include in other Sass files. +This is a great way to modularize your CSS and help keep things easier to maintain. A partial is a +Sass file named with a leading underscore. You might name it something +like `_partial.scss`. The underscore lets Sass know that the file is only +a partial file and that it should not be generated into a CSS file. Sass +partials are used with the `@use` rule. + +--- + +## Modules + + +You don't have to write all your Sass in a single file. You can split it up however you want with the `@use` rule. This rule loads another Sass file as +a *module*, which means you can refer to its variables, [mixins][], and [functions][] in your Sass file with a namespace based on the filename. Using a file will also include the CSS it generates in your compiled output! + +[mixins]: #topic-6 +[functions]: documentation/at-rules/function + +{% capture example_id %} + {{ example_id | plus: 1 }} +{% endcapture %} +{% capture ui_id %} + {{ ui_id | plus: 3 }} +{% endcapture %} + +{% assign code = +"// _base.scss + $font-stack: Helvetica, sans-serif; + $primary-color: #333; + + body { + font: 100% $font-stack; + color: $primary-color; + } + --- + // styles.scss + @use 'base'; + + .inverse { + background-color: base.$primary-color; + color: white; + } + === + // _base.sass + $font-stack: Helvetica, sans-serif + $primary-color: #333 + + body + font: 100% $font-stack + color: $primary-color + --- + // styles.sass + @use 'base' + + .inverse + background-color: base.$primary-color + color: white + === + body { + font: 100% Helvetica, sans-serif; + color: #333; + } + + .inverse { + background-color: #333; + color: white; + }" +| codeExample: true, 'scss' %} + + +{% render 'code_example', +code: code, +example_id: example_id, +ui_id: ui_id %} + +--- + +## Mixins + +Some things in CSS are a bit tedious to write, especially with CSS3 and the many vendor prefixes that exist. A mixin lets you make groups of CSS declarations that you want to reuse throughout your site. It helps keep your +Sass very DRY. You can even pass in values to make your mixin more flexible. Here's an example for `theme`. + +{% capture example_id %} + {{ example_id | plus: 1 }} +{% endcapture %} +{% capture ui_id %} + {{ ui_id | plus: 3 }} +{% endcapture %} + +{% assign code = +"@mixin theme($theme: DarkGray) { +background: $theme; +box-shadow: 0 0 1px rgba($theme, .25); +color: #fff; +} + +.info { +@include theme; +} +.alert { +@include theme($theme: DarkRed); +} +.success { +@include theme($theme: DarkGreen); +} +=== +@mixin theme($theme: DarkGray) +background: $theme +box-shadow: 0 0 1px rgba($theme, .25) +color: #fff + + +.info +@include theme + +.alert +@include theme($theme: DarkRed) + +.success +@include theme($theme: DarkGreen)" +| codeExample: true, 'scss' %} + +{% render 'code_example', +code: code, +example_id: example_id, +ui_id: ui_id %} + +To create a mixin you use the `@mixin` directive and give it a name. We've named our mixin `theme`. We're also using the variable `$theme` inside the parentheses so we can pass in a `theme` of whatever we want. +After you create your mixin, you can then use it as a CSS declaration starting with `@include` followed by the name of the mixin. + +--- + +## Extend/Inheritance + +Using `@extend` lets you share a set of CSS properties from one selector to another. In our example we're going to create a simple series of messaging for errors, warnings and successes using another feature which goes hand in hand with extend, placeholder classes. A placeholder class is a special type of class that only prints when it is extended, and can help keep your compiled CSS neat and clean. + +{% capture example_id %} + {{ example_id | plus: 1 }} +{% endcapture %} +{% capture ui_id %} + {{ ui_id | plus: 3 }} +{% endcapture %} + +{% assign code = +"// This CSS will print because %message-shared is extended. +%message-shared { + border: 1px solid #ccc; + padding: 10px; + color: #333; +} + +// This CSS won't print because %equal-heights is never extended. +%equal-heights { + display: flex; + flex-wrap: wrap; +} + +.message { + @extend %message-shared; +} + +.success { + @extend %message-shared; + border-color: green; +} + +.error { + @extend %message-shared; + border-color: red; +} + +.warning { + @extend %message-shared; + border-color: yellow; +} +=== +// This CSS will print because %message-shared is extended. +%message-shared + border: 1px solid #ccc + padding: 10px + color: #333 + + +// This CSS won't print because %equal-heights is never extended. +%equal-heights + display: flex + flex-wrap: wrap + + +.message + @extend %message-shared + + +.success + @extend %message-shared + border-color: green + + +.error + @extend %message-shared + border-color: red + + +.warning + @extend %message-shared + border-color: yellow"| codeExample: true, 'scss' %} + +{% render 'code_example', +code: code, +example_id: example_id, +ui_id: ui_id %} + +What the above code does is tells `.message`, `.success`, `.error`, and `.warning` to behave just like `%message-shared`. That means anywhere that `%message-shared` shows up, `.message`, `.success`, `.error`, & `.warning` will too. The magic happens in the generated CSS, where each of these classes will get the same CSS properties as `%message-shared`. This helps you avoid having to write multiple class names on HTML elements. + +You can extend most simple CSS selectors in addition to placeholder classes in Sass, but using placeholders is the easiest way to make sure you aren't extending a class that's nested elsewhere in your styles, which can result in unintended selectors in your CSS. + +Note that the CSS in `%equal-heights` isn't generated, because `%equal-heights` is never extended. + +--- + +## Operators + +Doing math in your CSS is very helpful. Sass has a handful of standard math operators like `+`, `-`, `*`, `math.div()`, and `%`. In our example we're going to do some simple math to calculate widths for an `article` and `aside`. + +{% capture example_id %} + {{ example_id | plus: 1 }} +{% endcapture %} +{% capture ui_id %} + {{ ui_id | plus: 3 }} +{% endcapture %} + +{% assign code = +'@use "sass:math"; + +.container { + display: flex; +} + +article[role="main"] { + width: math.div(600px, 960px) * 100%; +} + +aside[role="complementary"] { + width: math.div(300px, 960px) * 100%; + margin-left: auto; +} +=== +@use "sass:math" + +.container + display: flex + +article[role="main"] + width: math.div(600px, 960px) * 100% + +aside[role="complementary"] + width: math.div(300px, 960px) * 100% + margin-left: auto +=== +.container { + display: flex; +} + +article[role="main"] { + width: 62.5%; +} + +aside[role="complementary"] { + width: 31.25%; + margin-left: auto; +}'| codeExample: true, 'scss' %} + +{% render 'code_example', +code: code, +example_id: example_id, +ui_id: ui_id %} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 337db0d85..fdfa2d1ca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6277,7 +6277,7 @@ __metadata: npm-run-all: ^4.1.5 prettier: ^2.8.3 rollup: ^3.12.0 - sass: ^1.57.1 + sass: ^1.58.0 semver-parser: ^4.0.1 stylelint: ^14.16.1 stylelint-config-prettier: ^9.0.4 @@ -6288,16 +6288,16 @@ __metadata: languageName: unknown linkType: soft -"sass@npm:^1.57.1": - version: 1.57.1 - resolution: "sass@npm:1.57.1" +"sass@npm:^1.58.0": + version: 1.58.0 + resolution: "sass@npm:1.58.0" dependencies: chokidar: ">=3.0.0 <4.0.0" immutable: ^4.0.0 source-map-js: ">=0.6.2 <2.0.0" bin: sass: sass.js - checksum: 734a08781bcbe0e8defb2d54864e7012014ed3e68ba5fcb766189b002929019fc37b2f83a18d4be0b5f69ad77317c92396ce6112447ab47a194ed600ae1afb27 + checksum: a7219634881d2de6441fb619787fb1a02e3fa0333fb715be26aa335ba49d6bdb4f1105d9df70a80a67200893022b08346745783dc49046095d94fc6e044492d6 languageName: node linkType: hard From 5913b66ca84c207118df5ec4653e3761ccdf0fb4 Mon Sep 17 00:00:00 2001 From: Sana Javed Date: Fri, 17 Feb 2023 17:48:22 +0100 Subject: [PATCH 02/42] Lint --- eleventy.config.cjs | 23 +++--- source/guide.md | 186 +++++++++++++++++++++----------------------- 2 files changed, 101 insertions(+), 108 deletions(-) diff --git a/eleventy.config.cjs b/eleventy.config.cjs index 590730557..54904abf8 100644 --- a/eleventy.config.cjs +++ b/eleventy.config.cjs @@ -66,23 +66,22 @@ module.exports = (eleventyConfig) => { eleventyConfig.addLiquidFilter( 'codeExample', - (contents, autogenCSS=true, syntax=null) => { + (contents, autogenCSS = true, syntax = null) => { //TODO when are values for syntax passed in? - //TODO add tests - const splitContents = contents.split('==='); - + //TODO add tests + const splitContents = contents.split('==='); + const scssContents = splitContents[0]; const sassContents = splitContents[1]; const cssContents = splitContents[2]; - const scssExamples = scssContents.split('---') - const sassExamples = sassContents.split('---') + const scssExamples = scssContents.split('---'); + const sassExamples = sassContents.split('---'); let cssExample; - if(cssContents){ - cssExample = cssContents - } - else if(!cssContents && autogenCSS) { + if (cssContents) { + cssExample = cssContents; + } else if (!cssContents && autogenCSS) { // TODO check first if you even have scss or sass to generate css from // TODO what if no scss but sass? cssExample = ''; @@ -93,10 +92,10 @@ module.exports = (eleventyConfig) => { } return { - scss: scssExamples, + scss: scssExamples, css: cssExample, sass: sassExamples, - splitLocation: '50.0%' //TODO dynamically determine + splitLocation: '50.0%', //TODO dynamically determine }; }, ); diff --git a/source/guide.md b/source/guide.md index bd52b21c2..c0652c98b 100644 --- a/source/guide.md +++ b/source/guide.md @@ -97,8 +97,8 @@ color: $primary-color" | codeExample: true, 'scss' -%} {% assign example_id = 1 %} {% assign ui_id = 1 %} -{% render 'code_example', -code: code, +{% render 'code_example', +code: code, example_id: example_id, ui_id: ui_id %} @@ -122,46 +122,45 @@ With that in mind, here's an example of some typical styles for a site's navigation: {% capture example_id %} - {{ example_id | plus: 1 }} +{{ example_id | plus: 1 }} {% endcapture %} {% capture ui_id %} - {{ ui_id | plus: 3 }} +{{ ui_id | plus: 3 }} {% endcapture %} -{% assign code = +{% assign code = "nav { ul { - margin: 0; - padding: 0; - list-style: none; +margin: 0; +padding: 0; +list-style: none; } li { display: inline-block; } a { - display: block; - padding: 6px 12px; - text-decoration: none; +display: block; +padding: 6px 12px; +text-decoration: none; } } === nav - ul - margin: 0 - padding: 0 - list-style: none +ul +margin: 0 +padding: 0 +list-style: none - li - display: inline-block +li +display: inline-block - a - display: block - padding: 6px 12px - text-decoration: none" | codeExample: true, 'scss' %} +a +display: block +padding: 6px 12px +text-decoration: none" | codeExample: true, 'scss' %} - -{% render 'code_example', -code: code, +{% render 'code_example', +code: code, example_id: example_id, ui_id: ui_id %} @@ -169,7 +168,7 @@ ui_id: ui_id %} ## Partials -You can create partial Sass files that contain little snippets of CSS that you can include in other Sass files. +You can create partial Sass files that contain little snippets of CSS that you can include in other Sass files. This is a great way to modularize your CSS and help keep things easier to maintain. A partial is a Sass file named with a leading underscore. You might name it something like `_partial.scss`. The underscore lets Sass know that the file is only @@ -181,23 +180,24 @@ partials are used with the `@use` rule. ## Modules + You don't have to write all your Sass in a single file. You can split it up however you want with the `@use` rule. This rule loads another Sass file as -a *module*, which means you can refer to its variables, [mixins][], and [functions][] in your Sass file with a namespace based on the filename. Using a file will also include the CSS it generates in your compiled output! +a _module_, which means you can refer to its variables, [mixins][], and [functions][] in your Sass file with a namespace based on the filename. Using a file will also include the CSS it generates in your compiled output! [mixins]: #topic-6 [functions]: documentation/at-rules/function {% capture example_id %} - {{ example_id | plus: 1 }} +{{ example_id | plus: 1 }} {% endcapture %} {% capture ui_id %} - {{ ui_id | plus: 3 }} +{{ ui_id | plus: 3 }} {% endcapture %} -{% assign code = -"// _base.scss - $font-stack: Helvetica, sans-serif; - $primary-color: #333; +{% assign code = +"// \_base.scss +$font-stack: Helvetica, sans-serif; +$primary-color: #333; body { font: 100% $font-stack; @@ -235,12 +235,12 @@ a *module*, which means you can refer to its variables, [mixins][], and [functio .inverse { background-color: #333; color: white; - }" -| codeExample: true, 'scss' %} + }" +| codeExample: true, 'scss' %} -{% render 'code_example', -code: code, +{% render 'code_example', +code: code, example_id: example_id, ui_id: ui_id %} @@ -252,13 +252,13 @@ Some things in CSS are a bit tedious to write, especially with CSS3 and the many Sass very DRY. You can even pass in values to make your mixin more flexible. Here's an example for `theme`. {% capture example_id %} - {{ example_id | plus: 1 }} +{{ example_id | plus: 1 }} {% endcapture %} {% capture ui_id %} - {{ ui_id | plus: 3 }} +{{ ui_id | plus: 3 }} {% endcapture %} -{% assign code = +{% assign code = "@mixin theme($theme: DarkGray) { background: $theme; box-shadow: 0 0 1px rgba($theme, .25); @@ -280,7 +280,6 @@ background: $theme box-shadow: 0 0 1px rgba($theme, .25) color: #fff - .info @include theme @@ -291,8 +290,8 @@ color: #fff @include theme($theme: DarkGreen)" | codeExample: true, 'scss' %} -{% render 'code_example', -code: code, +{% render 'code_example', +code: code, example_id: example_id, ui_id: ui_id %} @@ -306,78 +305,73 @@ After you create your mixin, you can then use it as a CSS declaration starting w Using `@extend` lets you share a set of CSS properties from one selector to another. In our example we're going to create a simple series of messaging for errors, warnings and successes using another feature which goes hand in hand with extend, placeholder classes. A placeholder class is a special type of class that only prints when it is extended, and can help keep your compiled CSS neat and clean. {% capture example_id %} - {{ example_id | plus: 1 }} +{{ example_id | plus: 1 }} {% endcapture %} {% capture ui_id %} - {{ ui_id | plus: 3 }} +{{ ui_id | plus: 3 }} {% endcapture %} -{% assign code = -"// This CSS will print because %message-shared is extended. +{% assign code = +"// This CSS will print because %message-shared is extended. %message-shared { - border: 1px solid #ccc; - padding: 10px; - color: #333; +border: 1px solid #ccc; +padding: 10px; +color: #333; } // This CSS won't print because %equal-heights is never extended. %equal-heights { - display: flex; - flex-wrap: wrap; +display: flex; +flex-wrap: wrap; } .message { - @extend %message-shared; +@extend %message-shared; } .success { - @extend %message-shared; - border-color: green; +@extend %message-shared; +border-color: green; } .error { - @extend %message-shared; - border-color: red; +@extend %message-shared; +border-color: red; } .warning { - @extend %message-shared; - border-color: yellow; +@extend %message-shared; +border-color: yellow; } === -// This CSS will print because %message-shared is extended. +// This CSS will print because %message-shared is extended. %message-shared - border: 1px solid #ccc - padding: 10px - color: #333 - +border: 1px solid #ccc +padding: 10px +color: #333 // This CSS won't print because %equal-heights is never extended. %equal-heights - display: flex - flex-wrap: wrap - +display: flex +flex-wrap: wrap .message - @extend %message-shared - +@extend %message-shared .success - @extend %message-shared - border-color: green - +@extend %message-shared +border-color: green .error - @extend %message-shared - border-color: red - +@extend %message-shared +border-color: red .warning - @extend %message-shared - border-color: yellow"| codeExample: true, 'scss' %} +@extend %message-shared +border-color: yellow"| codeExample: true, 'scss' %} -{% render 'code_example', -code: code, +{% render 'code_example', +code: code, example_id: example_id, ui_id: ui_id %} @@ -394,54 +388,54 @@ Note that the CSS in `%equal-heights` isn't generated, because `%equal-heights` Doing math in your CSS is very helpful. Sass has a handful of standard math operators like `+`, `-`, `*`, `math.div()`, and `%`. In our example we're going to do some simple math to calculate widths for an `article` and `aside`. {% capture example_id %} - {{ example_id | plus: 1 }} +{{ example_id | plus: 1 }} {% endcapture %} {% capture ui_id %} - {{ ui_id | plus: 3 }} +{{ ui_id | plus: 3 }} {% endcapture %} -{% assign code = +{% assign code = '@use "sass:math"; .container { - display: flex; +display: flex; } article[role="main"] { - width: math.div(600px, 960px) * 100%; +width: math.div(600px, 960px) \* 100%; } aside[role="complementary"] { - width: math.div(300px, 960px) * 100%; - margin-left: auto; +width: math.div(300px, 960px) \* 100%; +margin-left: auto; } === @use "sass:math" .container - display: flex +display: flex article[role="main"] - width: math.div(600px, 960px) * 100% +width: math.div(600px, 960px) \* 100% aside[role="complementary"] - width: math.div(300px, 960px) * 100% - margin-left: auto +width: math.div(300px, 960px) \* 100% +margin-left: auto === .container { - display: flex; +display: flex; } article[role="main"] { - width: 62.5%; +width: 62.5%; } aside[role="complementary"] { - width: 31.25%; - margin-left: auto; +width: 31.25%; +margin-left: auto; }'| codeExample: true, 'scss' %} -{% render 'code_example', -code: code, +{% render 'code_example', +code: code, example_id: example_id, -ui_id: ui_id %} \ No newline at end of file +ui_id: ui_id %} From d216a68d6c9b8c6443616bd21d29d2f22b74cfff Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Fri, 17 Feb 2023 14:58:17 -0500 Subject: [PATCH 03/42] Add more jQuery UI deps --- source/assets/js/vendor/index.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/source/assets/js/vendor/index.ts b/source/assets/js/vendor/index.ts index 1e7648224..b7e94ea73 100644 --- a/source/assets/js/vendor/index.ts +++ b/source/assets/js/vendor/index.ts @@ -1,7 +1,12 @@ -import 'jquery'; -import 'jquery-ui'; +// import jQuery UI "Tabs" widget and dependencies +// https://jqueryui.com/tabs/ +import 'jquery-ui/ui/version'; +import 'jquery-ui/ui/widget'; +import 'jquery-ui/ui/keycode'; import 'jquery-ui/ui/unique-id'; +import 'jquery-ui/ui/safe-active-element'; import 'jquery-ui/ui/widgets/tabs'; + import './jquery-smooth-scroll.min'; import './modernizr.custom.min'; import './html5-boilerplate/plugins'; From 2f1a8ae1d0d01616b0ecd5ab9d33779af98d7ccb Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Fri, 17 Feb 2023 15:08:32 -0500 Subject: [PATCH 04/42] prettier --- source/_includes/code_example.liquid | 104 +++++++++++++++++------ source/_includes/header.liquid | 5 +- source/_layouts/has_complimentary.liquid | 2 +- 3 files changed, 81 insertions(+), 30 deletions(-) diff --git a/source/_includes/code_example.liquid b/source/_includes/code_example.liquid index aeebb6395..2e3256b7c 100644 --- a/source/_includes/code_example.liquid +++ b/source/_includes/code_example.liquid @@ -3,43 +3,91 @@ {% assign third_tab_id = second_tab_id | plus: 1 %}
- -
- {% for scss in code.scss %} -
+  
+  
+ {% for scss in code.scss %} +
             
                 {{ scss | strip }}
             
         
- {% endfor %} -
- + - + -
\ No newline at end of file +
+ diff --git a/source/_includes/header.liquid b/source/_includes/header.liquid index ade3f98bb..827fa3091 100644 --- a/source/_includes/header.liquid +++ b/source/_includes/header.liquid @@ -16,7 +16,10 @@

- Sass + Sass

{% renderFile 'source/_includes/header_nav.md' %} diff --git a/source/_layouts/has_complimentary.liquid b/source/_layouts/has_complimentary.liquid index 60677bd8a..f080b23aa 100644 --- a/source/_layouts/has_complimentary.liquid +++ b/source/_layouts/has_complimentary.liquid @@ -5,7 +5,7 @@ layout: base
- +
{% if before_introduction %} {{ before_introduction | markdown }} {% endif %} From 2a08b9b088aef522818d3b752d8360e4c1d98d48 Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Fri, 17 Feb 2023 16:39:25 -0500 Subject: [PATCH 05/42] indentation --- source/_includes/code_example.liquid | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/source/_includes/code_example.liquid b/source/_includes/code_example.liquid index 2e3256b7c..9ee072660 100644 --- a/source/_includes/code_example.liquid +++ b/source/_includes/code_example.liquid @@ -54,13 +54,9 @@ role="tabpanel" aria-hidden="false" style=""> - {% for scss in code.scss %} -
-            
-                {{ scss | strip }}
-            
-        
- {% endfor %} + {%- for scss in code.scss -%} +
{{ scss | strip }}
+ {%- endfor -%}
From 16e774921229b25857c187cc63254a9aa53c968a Mon Sep 17 00:00:00 2001 From: Sana Javed Date: Tue, 21 Feb 2023 17:20:52 +0100 Subject: [PATCH 06/42] Switching from markdown file to liquid template --- source/_layouts/base.liquid | 2 +- source/_layouts/guide.liquid | 481 +++++++++++++++++++++++++++++++++++ source/guide.md | 437 +------------------------------ 3 files changed, 484 insertions(+), 436 deletions(-) create mode 100644 source/_layouts/guide.liquid diff --git a/source/_layouts/base.liquid b/source/_layouts/base.liquid index 783929e15..ddac0286c 100644 --- a/source/_layouts/base.liquid +++ b/source/_layouts/base.liquid @@ -43,7 +43,6 @@ gtag('config', 'UA-535380-14'); - {%- assign classes = page.filePathStem | replace: "/", " " | strip -%} @@ -133,6 +132,7 @@ } }(document, 'script', 'twitter-wjs'); + diff --git a/source/_layouts/guide.liquid b/source/_layouts/guide.liquid new file mode 100644 index 000000000..dc89fdb96 --- /dev/null +++ b/source/_layouts/guide.liquid @@ -0,0 +1,481 @@ +--- +layout: has_no_sidebars +title: Sass Basics +introduction: > + Before you can use Sass, you need to set it up on your project. If you want to + just browse here, go ahead, but we recommend you go install Sass first. [Go + here](/install) if you want to learn how to get everything set up. +--- + +
+ {% markdown %}## Preprocessing + + CSS on its own can be fun, but stylesheets are getting larger, more + complex, and harder to maintain. This is where a preprocessor can help. + + Sass has features that don't exist in CSS yet like nesting, mixins, + inheritance, and other nifty goodies that help you write robust, + maintainable CSS. + + Once you start tinkering with Sass, it will take your preprocessed Sass + file and save it as a normal CSS file that you can use in your website. + + The most direct way to make this happen is in your terminal. Once Sass is + installed, you can compile your Sass to CSS using the `sass` command. + You'll need to tell Sass which file to build from, and where to output CSS + to. For example, running `sass input.scss output.css` from your terminal + would take a single Sass file, `input.scss`, and compile that file to + `output.css`. + + You can also watch individual files or directories with the `--watch` + flag. The watch flag tells Sass to watch your source files for changes, + and re-compile CSS each time you save your Sass. If you wanted to watch + (instead of manually build) your `input.scss` file, you'd just add the + watch flag to your command, like so: + + ``` + sass --watch input.scss output.css + ``` + + You can watch and output to directories by using folder paths as your + input and output, and separating them with a colon. In this example: + + + {% renderFile 'source/code-snippets/_homepage-sass-watch.md' %} + + Sass would watch all files in the `app/sass` folder for changes, and + compile CSS to the `public/stylesheets` folder. + {% endmarkdown %} +
+ {% markdown %}### 💡 Fun fact: + Sass has two syntaxes! The SCSS syntax (`.scss`) is used most commonly. It's + a superset of CSS, which means all valid CSS is also valid SCSS. The + indented syntax (`.sass`) is more unusual: it uses indentation rather than + curly braces to nest statements, and newlines instead of semicolons to + separate them. All our examples are available in both syntaxes. + {% endmarkdown %} +
+ +
+ +
+ +
+ {% markdown %}## Variables + Think of variables as a way to store information that you want to reuse + throughout your stylesheet. You can store things like colors, font stacks, + or any CSS value you think you'll want to reuse. Sass uses the `$` symbol + to make something a variable. Here's an example: + {% endmarkdown %} + +{%- capture captureCode -%} +$font-stack: Helvetica, sans-serif; +$primary-color: #333; + +body { + font: 100% $font-stack; + color: $primary-color; +} +=== +$font-stack: Helvetica, sans-serif +$primary-color: #333 + +body + font: 100% $font-stack + color: $primary-color +{%- endcapture -%} + + {%- assign parsedExample = captureCode | codeExample: true, 'scss' -%} + + {% assign example_id = 1 %} + {% assign ui_id = 1 %} + {% render 'code_example', code: parsedExample,example_id: example_id, ui_id: ui_id %} + + {% markdown %} + When the Sass is processed, it takes the variables we define for the + `$font-stack` and `$primary-color` and outputs normal CSS with our + variable values placed in the CSS. This can be extremely powerful when + working with brand colors and keeping them consistent throughout the site. + {% endmarkdown %} +
+ +
+ +
+ {% markdown %}## Nesting + When writing HTML you've probably noticed that it has a clear nested and visual hierarchy. CSS, on the other hand, doesn't. + + Sass will let you nest your CSS selectors in a way that follows the same + visual hierarchy of your HTML. Be aware that overly nested rules will + result in over-qualified CSS that could prove hard to maintain and is + generally considered bad practice. + + With that in mind, here's an example of some typical styles for a site's + navigation: + {% endmarkdown %} + +{%- capture captureCode -%} +nav { + ul { + margin: 0; + padding: 0; + list-style: none; + } + + li { display: inline-block; } + + a { + display: block; + padding: 6px 12px; + text-decoration: none; + } +} +=== +nav + ul + margin: 0 + padding: 0 + list-style: none + + li + display: inline-block + + a + display: block + padding: 6px 12px + text-decoration: none +{%- endcapture -%} + + {% capture example_id %} + {{ example_id | plus: 1 }} + {% endcapture %} + + {% capture ui_id %} + {{ ui_id | plus: 3 }} + {% endcapture %} + + {%- assign parsedExample = captureCode | codeExample: true, 'scss' -%} + {% render 'code_example', code: parsedExample, example_id: example_id, ui_id: ui_id %} + +
+ +
+ +
+ {% markdown %}## Partials + You can create partial Sass files that contain little snippets of CSS that you can include in other Sass files. + This is a great way to modularize your CSS and help keep things easier to maintain. A partial is a + Sass file named with a leading underscore. You might name it something + like `_partial.scss`. The underscore lets Sass know that the file is only + a partial file and that it should not be generated into a CSS file. Sass + partials are used with the `@use` rule. + {% endmarkdown %} +
+ +
+ +
+ {% markdown %}## Modules + + You don't have to write all your Sass in a single file. You can split it up however you want with the `@use` rule. This rule loads another Sass file as + a _module_, which means you can refer to its variables, [mixins][], and [functions][] in your Sass file with a namespace based on the filename. + Using a file will also include the CSS it generates in your compiled output! + + [mixins]: #topic-6 + [functions]: documentation/at-rules/function + {% endmarkdown %} + +{%- capture captureCode -%} +// _base.scss +$font-stack: Helvetica, sans-serif; +$primary-color: #333; + +body { + font: 100% $font-stack; + color: $primary-color; +} +--- + +// styles.scss +@use 'base'; + +.inverse { + background-color: base.$primary-color; + color: white; +} + +=== +// _base.sass +$font-stack: Helvetica, sans-serif +$primary-color: #333 + +body + font: 100% $font-stack + color: $primary-color +--- + +// styles.sass +@use 'base' + +.inverse + background-color: base.$primary-color + color: white +=== + +body { + font: 100% Helvetica, sans-serif; + color: #333; +} + +.inverse { + background-color: #333; + color: white; +} +{% endcapture %} + + {% capture example_id %} + {{ example_id | plus: 1 }} + {% endcapture %} + + {% capture ui_id %} + {{ ui_id | plus: 3 }} + {% endcapture %} + + {%- assign parsedExample = captureCode | codeExample: true, 'scss' -%} + {% render 'code_example', code: parsedExample, example_id: example_id, ui_id: ui_id %} + +
+ +
+ +
+ {% markdown %}## Mixins + Some things in CSS are a bit tedious to write, especially with CSS3 and the many vendor prefixes that exist. A mixin lets you make groups of CSS declarations that you want to reuse throughout your site. It helps keep your + Sass very DRY. You can even pass in values to make your mixin more flexible. Here's an example for `theme`. + {% endmarkdown %} + + {% capture example_id %} + {{ example_id | plus: 1 }} + {% endcapture %} + + {% capture ui_id %} + {{ ui_id | plus: 3 }} + {% endcapture %} + +{% capture captureCode %} +@mixin theme($theme: DarkGray) { + background: $theme; + box-shadow: 0 0 1px rgba($theme, .25); + color: #fff; +} + +.info { + @include theme; +} +.alert { + @include theme($theme: DarkRed); +} +.success { + @include theme($theme: DarkGreen); +} + +=== + +@mixin theme($theme: DarkGray) + background: $theme + box-shadow: 0 0 1px rgba($theme, .25) + color: #fff + +.info + @include theme +.alert + @include theme($theme: DarkRed) + +.success + @include theme($theme: DarkGreen) + +{% endcapture %} + + {% capture example_id %} + {{ example_id | plus: 1 }} + {% endcapture %} + + {% capture ui_id %} + {{ ui_id | plus: 3 }} + {% endcapture %} + + {%- assign parsedExample = captureCode | codeExample: true, 'scss' -%} + {% render 'code_example', code: parsedExample, example_id: example_id, ui_id: ui_id %} + + {% markdown %} + To create a mixin you use the `@mixin` directive and give it a name. We've named our mixin `theme`. We're also using the variable `$theme` inside the parentheses so we can pass in a `theme` of whatever we want. + After you create your mixin, you can then use it as a CSS declaration starting with `@include` followed by the name of the mixin. +{% endmarkdown %} + +
+ +
+ +
+ + {% markdown %}## Extend/Inheritance + Using `@extend` lets you share a set of CSS properties from one selector to another. In our example we're going to create a simple series of messaging for errors, warnings and successes using another feature which goes hand in hand with extend, placeholder classes. A placeholder class is a special type of class that only prints when it is extended, and can help keep your compiled CSS neat and clean. + {% endmarkdown %} + +{%- capture captureCode -%} +// This CSS will print because %message-shared is extended. +%message-shared { + border: 1px solid #ccc; + padding: 10px; + color: #333; +} + +// This CSS won't print because %equal-heights is never extended. +%equal-heights { + display: flex; + flex-wrap: wrap; +} + +.message { + @extend %message-shared; +} + +.success { + @extend %message-shared; + border-color: green; +} + +.error { + @extend %message-shared; + border-color: red; +} + +.warning { + @extend %message-shared; + border-color: yellow; +} +=== + +// This CSS will print because %message-shared is extended. +%message-shared + border: 1px solid #ccc + padding: 10px + color: #333 + +// This CSS won't print because %equal-heights is never extended. +%equal-heights + display: flex + flex-wrap: wrap + +.message + @extend %message-shared + +.success + @extend %message-shared + border-color: green + +.error + @extend %message-shared + border-color: red + +.warning + @extend %message-shared + border-color: yellow" | codeExample: true, 'scss' %} +{% endcapture %} + + {% capture example_id %} + {{ example_id | plus: 1 }} + {% endcapture %} + {% capture ui_id %} + {{ ui_id | plus: 3 }} + {% endcapture %} + + {%- assign parsedExample = captureCode | codeExample: true, 'scss' -%} + {% render 'code_example', code: parsedExample, example_id: example_id, ui_id: ui_id %} + + {% markdown %} + What the above code does is tells `.message`, `.success`, `.error`, and `.warning` to behave just like `%message-shared`. That means anywhere that `%message-shared` shows up, `.message`, `.success`, `.error`, & `.warning` will too. The magic happens in the generated CSS, where each of these classes will get the same CSS properties as `%message-shared`. This helps you avoid having to write multiple class names on HTML elements. + + You can extend most simple CSS selectors in addition to placeholder classes in Sass, but using placeholders is the easiest way to make sure you aren't extending a class that's nested elsewhere in your styles, which can result in unintended selectors in your CSS. + + Note that the CSS in `%equal-heights` isn't generated, because `%equal-heights` is never extended. + {% endmarkdown %} +
+ +
+ +
+ {% markdown%}## Operators + Doing math in your CSS is very helpful. Sass has a handful of standard math operators like `+`, `-`, `*`, `math.div()`, and `%`. In our example we're going to do some simple math to calculate widths for an `article` and `aside`. + {% endmarkdown %} + + {% capture example_id %} + {{ example_id | plus: 1 }} + {% endcapture %} + {% capture ui_id %} + {{ ui_id | plus: 3 }} + {% endcapture %} + +{%- capture captureCode -%} +@use "sass:math"; + +.container { + display: flex; +} + +article[role="main"] { + width: math.div(600px, 960px) * 100%; +} + +aside[role="complementary"] { + width: math.div(300px, 960px) * 100%; + margin-left: auto; +} + +=== +@use "sass:math" + +.container + display: flex + +article[role="main"] + width: math.div(600px, 960px) * 100% + +aside[role="complementary"] + width: math.div(300px, 960px) * 100% + margin-left: auto + +=== + +.container { + display: flex; +} + +article[role="main"] { + width: 62.5%; +} + +aside[role="complementary"] { + width: 31.25%; + margin-left: auto; +} +{% endcapture %} + + {% capture example_id %} + {{ example_id | plus: 1 }} + {% endcapture %} + + {% capture ui_id %} + {{ ui_id | plus: 3 }} + {% endcapture %} + + {%- assign parsedExample = captureCode | codeExample: true, 'scss' -%} + {% render 'code_example', code: parsedExample, example_id: example_id, ui_id: ui_id %} + + {% markdown %} + We've created a very simple fluid grid, based on 960px. Operations in Sass + let us do something like take pixel values and convert them to percentages + without much hassle. + {% endmarkdown %} +
+
\ No newline at end of file diff --git a/source/guide.md b/source/guide.md index c0652c98b..3a71672c6 100644 --- a/source/guide.md +++ b/source/guide.md @@ -1,441 +1,8 @@ --- -layout: has_no_sidebars +layout: guide title: Sass Basics introduction: > Before you can use Sass, you need to set it up on your project. If you want to just browse here, go ahead, but we recommend you go install Sass first. [Go here](/install) if you want to learn how to get everything set up. ---- - - - -## Preprocessing - -CSS on its own can be fun, but stylesheets are getting larger, more -complex, and harder to maintain. This is where a preprocessor can help. -Sass has features that don't exist in CSS yet like nesting, mixins, -inheritance, and other nifty goodies that help you write robust, -maintainable CSS. - -Once you start tinkering with Sass, it will take your preprocessed Sass -file and save it as a normal CSS file that you can use in your website. - -The most direct way to make this happen is in your terminal. Once Sass is -installed, you can compile your Sass to CSS using the `sass` command. -You'll need to tell Sass which file to build from, and where to output CSS -to. For example, running `sass input.scss output.css` from your terminal -would take a single Sass file, `input.scss`, and compile that file to -`output.css`. - -You can also watch individual files or directories with the `--watch` -flag. The watch flag tells Sass to watch your source files for changes, -and re-compile CSS each time you save your Sass. If you wanted to watch -(instead of manually build) your `input.scss` file, you'd just add the -watch flag to your command, like so: - -``` -sass --watch input.scss output.css -``` - -You can watch and output to directories by using folder paths as your -input and output, and separating them with a colon. In this example: - -{% renderFile 'source/code-snippets/_homepage-sass-watch.md' %} - -Sass would watch all files in the `app/sass` folder for changes, and -compile CSS to the `public/stylesheets` folder. - -
- -### 💡 Fun fact: - -Sass has two syntaxes! The SCSS syntax (`.scss`) is used most commonly. It's -a superset of CSS, which means all valid CSS is also valid SCSS. The -indented syntax (`.sass`) is more unusual: it uses indentation rather than -curly braces to nest statements, and newlines instead of semicolons to -separate them. All our examples are available in both syntaxes. - -
- ---- - -## Variables - -Think of variables as a way to store information that you want to reuse -throughout your stylesheet. You can store things like colors, font stacks, -or any CSS value you think you'll want to reuse. Sass uses the `$` symbol -to make something a variable. Here's an example: - -{% assign code = "$font-stack: Helvetica, sans-serif; -$primary-color: #333; - -body { -font: 100% $font-stack; -color: $primary-color; -} - -=== - -$font-stack: Helvetica, sans-serif -$primary-color: #333 - -body -font: 100% $font-stack -color: $primary-color" | codeExample: true, 'scss' -%} - -{% assign example_id = 1 %} -{% assign ui_id = 1 %} -{% render 'code_example', -code: code, -example_id: example_id, -ui_id: ui_id %} - -When the Sass is processed, it takes the variables we define for the -`$font-stack` and `$primary-color` and outputs normal CSS with our -variable values placed in the CSS. This can be extremely powerful when -working with brand colors and keeping them consistent throughout the site. - ---- - -## Nesting - -When writing HTML you've probably noticed that it has a clear nested and visual hierarchy. CSS, on the other hand, doesn't. - -Sass will let you nest your CSS selectors in a way that follows the same -visual hierarchy of your HTML. Be aware that overly nested rules will -result in over-qualified CSS that could prove hard to maintain and is -generally considered bad practice. - -With that in mind, here's an example of some typical styles for a site's -navigation: - -{% capture example_id %} -{{ example_id | plus: 1 }} -{% endcapture %} -{% capture ui_id %} -{{ ui_id | plus: 3 }} -{% endcapture %} - -{% assign code = -"nav { -ul { -margin: 0; -padding: 0; -list-style: none; -} - -li { display: inline-block; } - -a { -display: block; -padding: 6px 12px; -text-decoration: none; -} -} -=== -nav -ul -margin: 0 -padding: 0 -list-style: none - -li -display: inline-block - -a -display: block -padding: 6px 12px -text-decoration: none" | codeExample: true, 'scss' %} - -{% render 'code_example', -code: code, -example_id: example_id, -ui_id: ui_id %} - ---- - -## Partials - -You can create partial Sass files that contain little snippets of CSS that you can include in other Sass files. -This is a great way to modularize your CSS and help keep things easier to maintain. A partial is a -Sass file named with a leading underscore. You might name it something -like `_partial.scss`. The underscore lets Sass know that the file is only -a partial file and that it should not be generated into a CSS file. Sass -partials are used with the `@use` rule. - ---- - -## Modules - - - -You don't have to write all your Sass in a single file. You can split it up however you want with the `@use` rule. This rule loads another Sass file as -a _module_, which means you can refer to its variables, [mixins][], and [functions][] in your Sass file with a namespace based on the filename. Using a file will also include the CSS it generates in your compiled output! - -[mixins]: #topic-6 -[functions]: documentation/at-rules/function - -{% capture example_id %} -{{ example_id | plus: 1 }} -{% endcapture %} -{% capture ui_id %} -{{ ui_id | plus: 3 }} -{% endcapture %} - -{% assign code = -"// \_base.scss -$font-stack: Helvetica, sans-serif; -$primary-color: #333; - - body { - font: 100% $font-stack; - color: $primary-color; - } - --- - // styles.scss - @use 'base'; - - .inverse { - background-color: base.$primary-color; - color: white; - } - === - // _base.sass - $font-stack: Helvetica, sans-serif - $primary-color: #333 - - body - font: 100% $font-stack - color: $primary-color - --- - // styles.sass - @use 'base' - - .inverse - background-color: base.$primary-color - color: white - === - body { - font: 100% Helvetica, sans-serif; - color: #333; - } - - .inverse { - background-color: #333; - color: white; - }" - -| codeExample: true, 'scss' %} - -{% render 'code_example', -code: code, -example_id: example_id, -ui_id: ui_id %} - ---- - -## Mixins - -Some things in CSS are a bit tedious to write, especially with CSS3 and the many vendor prefixes that exist. A mixin lets you make groups of CSS declarations that you want to reuse throughout your site. It helps keep your -Sass very DRY. You can even pass in values to make your mixin more flexible. Here's an example for `theme`. - -{% capture example_id %} -{{ example_id | plus: 1 }} -{% endcapture %} -{% capture ui_id %} -{{ ui_id | plus: 3 }} -{% endcapture %} - -{% assign code = -"@mixin theme($theme: DarkGray) { -background: $theme; -box-shadow: 0 0 1px rgba($theme, .25); -color: #fff; -} - -.info { -@include theme; -} -.alert { -@include theme($theme: DarkRed); -} -.success { -@include theme($theme: DarkGreen); -} -=== -@mixin theme($theme: DarkGray) -background: $theme -box-shadow: 0 0 1px rgba($theme, .25) -color: #fff - -.info -@include theme - -.alert -@include theme($theme: DarkRed) - -.success -@include theme($theme: DarkGreen)" -| codeExample: true, 'scss' %} - -{% render 'code_example', -code: code, -example_id: example_id, -ui_id: ui_id %} - -To create a mixin you use the `@mixin` directive and give it a name. We've named our mixin `theme`. We're also using the variable `$theme` inside the parentheses so we can pass in a `theme` of whatever we want. -After you create your mixin, you can then use it as a CSS declaration starting with `@include` followed by the name of the mixin. - ---- - -## Extend/Inheritance - -Using `@extend` lets you share a set of CSS properties from one selector to another. In our example we're going to create a simple series of messaging for errors, warnings and successes using another feature which goes hand in hand with extend, placeholder classes. A placeholder class is a special type of class that only prints when it is extended, and can help keep your compiled CSS neat and clean. - -{% capture example_id %} -{{ example_id | plus: 1 }} -{% endcapture %} -{% capture ui_id %} -{{ ui_id | plus: 3 }} -{% endcapture %} - -{% assign code = -"// This CSS will print because %message-shared is extended. -%message-shared { -border: 1px solid #ccc; -padding: 10px; -color: #333; -} - -// This CSS won't print because %equal-heights is never extended. -%equal-heights { -display: flex; -flex-wrap: wrap; -} - -.message { -@extend %message-shared; -} - -.success { -@extend %message-shared; -border-color: green; -} - -.error { -@extend %message-shared; -border-color: red; -} - -.warning { -@extend %message-shared; -border-color: yellow; -} -=== -// This CSS will print because %message-shared is extended. -%message-shared -border: 1px solid #ccc -padding: 10px -color: #333 - -// This CSS won't print because %equal-heights is never extended. -%equal-heights -display: flex -flex-wrap: wrap - -.message -@extend %message-shared - -.success -@extend %message-shared -border-color: green - -.error -@extend %message-shared -border-color: red - -.warning -@extend %message-shared -border-color: yellow"| codeExample: true, 'scss' %} - -{% render 'code_example', -code: code, -example_id: example_id, -ui_id: ui_id %} - -What the above code does is tells `.message`, `.success`, `.error`, and `.warning` to behave just like `%message-shared`. That means anywhere that `%message-shared` shows up, `.message`, `.success`, `.error`, & `.warning` will too. The magic happens in the generated CSS, where each of these classes will get the same CSS properties as `%message-shared`. This helps you avoid having to write multiple class names on HTML elements. - -You can extend most simple CSS selectors in addition to placeholder classes in Sass, but using placeholders is the easiest way to make sure you aren't extending a class that's nested elsewhere in your styles, which can result in unintended selectors in your CSS. - -Note that the CSS in `%equal-heights` isn't generated, because `%equal-heights` is never extended. - ---- - -## Operators - -Doing math in your CSS is very helpful. Sass has a handful of standard math operators like `+`, `-`, `*`, `math.div()`, and `%`. In our example we're going to do some simple math to calculate widths for an `article` and `aside`. - -{% capture example_id %} -{{ example_id | plus: 1 }} -{% endcapture %} -{% capture ui_id %} -{{ ui_id | plus: 3 }} -{% endcapture %} - -{% assign code = -'@use "sass:math"; - -.container { -display: flex; -} - -article[role="main"] { -width: math.div(600px, 960px) \* 100%; -} - -aside[role="complementary"] { -width: math.div(300px, 960px) \* 100%; -margin-left: auto; -} -=== -@use "sass:math" - -.container -display: flex - -article[role="main"] -width: math.div(600px, 960px) \* 100% - -aside[role="complementary"] -width: math.div(300px, 960px) \* 100% -margin-left: auto -=== -.container { -display: flex; -} - -article[role="main"] { -width: 62.5%; -} - -aside[role="complementary"] { -width: 31.25%; -margin-left: auto; -}'| codeExample: true, 'scss' %} - -{% render 'code_example', -code: code, -example_id: example_id, -ui_id: ui_id %} +--- \ No newline at end of file From 3309a0b472e13a9947732a1ec265a7ad95da519f Mon Sep 17 00:00:00 2001 From: Sana Javed Date: Tue, 21 Feb 2023 17:21:35 +0100 Subject: [PATCH 07/42] lint --- source/guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/guide.md b/source/guide.md index 3a71672c6..de0be57ab 100644 --- a/source/guide.md +++ b/source/guide.md @@ -5,4 +5,4 @@ introduction: > Before you can use Sass, you need to set it up on your project. If you want to just browse here, go ahead, but we recommend you go install Sass first. [Go here](/install) if you want to learn how to get everything set up. ---- \ No newline at end of file +--- From 23ecbb94ac3e4a62115b21d5afc52af6e0488daa Mon Sep 17 00:00:00 2001 From: Sana Javed Date: Tue, 21 Feb 2023 20:36:16 +0100 Subject: [PATCH 08/42] Updating indentation --- source/_layouts/guide.liquid | 481 ---------------------------------- source/guide.liquid | 494 +++++++++++++++++++++++++++++++++++ source/guide.md | 8 - 3 files changed, 494 insertions(+), 489 deletions(-) delete mode 100644 source/_layouts/guide.liquid create mode 100644 source/guide.liquid delete mode 100644 source/guide.md diff --git a/source/_layouts/guide.liquid b/source/_layouts/guide.liquid deleted file mode 100644 index dc89fdb96..000000000 --- a/source/_layouts/guide.liquid +++ /dev/null @@ -1,481 +0,0 @@ ---- -layout: has_no_sidebars -title: Sass Basics -introduction: > - Before you can use Sass, you need to set it up on your project. If you want to - just browse here, go ahead, but we recommend you go install Sass first. [Go - here](/install) if you want to learn how to get everything set up. ---- - -
- {% markdown %}## Preprocessing - - CSS on its own can be fun, but stylesheets are getting larger, more - complex, and harder to maintain. This is where a preprocessor can help. - - Sass has features that don't exist in CSS yet like nesting, mixins, - inheritance, and other nifty goodies that help you write robust, - maintainable CSS. - - Once you start tinkering with Sass, it will take your preprocessed Sass - file and save it as a normal CSS file that you can use in your website. - - The most direct way to make this happen is in your terminal. Once Sass is - installed, you can compile your Sass to CSS using the `sass` command. - You'll need to tell Sass which file to build from, and where to output CSS - to. For example, running `sass input.scss output.css` from your terminal - would take a single Sass file, `input.scss`, and compile that file to - `output.css`. - - You can also watch individual files or directories with the `--watch` - flag. The watch flag tells Sass to watch your source files for changes, - and re-compile CSS each time you save your Sass. If you wanted to watch - (instead of manually build) your `input.scss` file, you'd just add the - watch flag to your command, like so: - - ``` - sass --watch input.scss output.css - ``` - - You can watch and output to directories by using folder paths as your - input and output, and separating them with a colon. In this example: - - - {% renderFile 'source/code-snippets/_homepage-sass-watch.md' %} - - Sass would watch all files in the `app/sass` folder for changes, and - compile CSS to the `public/stylesheets` folder. - {% endmarkdown %} -
- {% markdown %}### 💡 Fun fact: - Sass has two syntaxes! The SCSS syntax (`.scss`) is used most commonly. It's - a superset of CSS, which means all valid CSS is also valid SCSS. The - indented syntax (`.sass`) is more unusual: it uses indentation rather than - curly braces to nest statements, and newlines instead of semicolons to - separate them. All our examples are available in both syntaxes. - {% endmarkdown %} -
- -
- -
- -
- {% markdown %}## Variables - Think of variables as a way to store information that you want to reuse - throughout your stylesheet. You can store things like colors, font stacks, - or any CSS value you think you'll want to reuse. Sass uses the `$` symbol - to make something a variable. Here's an example: - {% endmarkdown %} - -{%- capture captureCode -%} -$font-stack: Helvetica, sans-serif; -$primary-color: #333; - -body { - font: 100% $font-stack; - color: $primary-color; -} -=== -$font-stack: Helvetica, sans-serif -$primary-color: #333 - -body - font: 100% $font-stack - color: $primary-color -{%- endcapture -%} - - {%- assign parsedExample = captureCode | codeExample: true, 'scss' -%} - - {% assign example_id = 1 %} - {% assign ui_id = 1 %} - {% render 'code_example', code: parsedExample,example_id: example_id, ui_id: ui_id %} - - {% markdown %} - When the Sass is processed, it takes the variables we define for the - `$font-stack` and `$primary-color` and outputs normal CSS with our - variable values placed in the CSS. This can be extremely powerful when - working with brand colors and keeping them consistent throughout the site. - {% endmarkdown %} -
- -
- -
- {% markdown %}## Nesting - When writing HTML you've probably noticed that it has a clear nested and visual hierarchy. CSS, on the other hand, doesn't. - - Sass will let you nest your CSS selectors in a way that follows the same - visual hierarchy of your HTML. Be aware that overly nested rules will - result in over-qualified CSS that could prove hard to maintain and is - generally considered bad practice. - - With that in mind, here's an example of some typical styles for a site's - navigation: - {% endmarkdown %} - -{%- capture captureCode -%} -nav { - ul { - margin: 0; - padding: 0; - list-style: none; - } - - li { display: inline-block; } - - a { - display: block; - padding: 6px 12px; - text-decoration: none; - } -} -=== -nav - ul - margin: 0 - padding: 0 - list-style: none - - li - display: inline-block - - a - display: block - padding: 6px 12px - text-decoration: none -{%- endcapture -%} - - {% capture example_id %} - {{ example_id | plus: 1 }} - {% endcapture %} - - {% capture ui_id %} - {{ ui_id | plus: 3 }} - {% endcapture %} - - {%- assign parsedExample = captureCode | codeExample: true, 'scss' -%} - {% render 'code_example', code: parsedExample, example_id: example_id, ui_id: ui_id %} - -
- -
- -
- {% markdown %}## Partials - You can create partial Sass files that contain little snippets of CSS that you can include in other Sass files. - This is a great way to modularize your CSS and help keep things easier to maintain. A partial is a - Sass file named with a leading underscore. You might name it something - like `_partial.scss`. The underscore lets Sass know that the file is only - a partial file and that it should not be generated into a CSS file. Sass - partials are used with the `@use` rule. - {% endmarkdown %} -
- -
- -
- {% markdown %}## Modules - - You don't have to write all your Sass in a single file. You can split it up however you want with the `@use` rule. This rule loads another Sass file as - a _module_, which means you can refer to its variables, [mixins][], and [functions][] in your Sass file with a namespace based on the filename. - Using a file will also include the CSS it generates in your compiled output! - - [mixins]: #topic-6 - [functions]: documentation/at-rules/function - {% endmarkdown %} - -{%- capture captureCode -%} -// _base.scss -$font-stack: Helvetica, sans-serif; -$primary-color: #333; - -body { - font: 100% $font-stack; - color: $primary-color; -} ---- - -// styles.scss -@use 'base'; - -.inverse { - background-color: base.$primary-color; - color: white; -} - -=== -// _base.sass -$font-stack: Helvetica, sans-serif -$primary-color: #333 - -body - font: 100% $font-stack - color: $primary-color ---- - -// styles.sass -@use 'base' - -.inverse - background-color: base.$primary-color - color: white -=== - -body { - font: 100% Helvetica, sans-serif; - color: #333; -} - -.inverse { - background-color: #333; - color: white; -} -{% endcapture %} - - {% capture example_id %} - {{ example_id | plus: 1 }} - {% endcapture %} - - {% capture ui_id %} - {{ ui_id | plus: 3 }} - {% endcapture %} - - {%- assign parsedExample = captureCode | codeExample: true, 'scss' -%} - {% render 'code_example', code: parsedExample, example_id: example_id, ui_id: ui_id %} - -
- -
- -
- {% markdown %}## Mixins - Some things in CSS are a bit tedious to write, especially with CSS3 and the many vendor prefixes that exist. A mixin lets you make groups of CSS declarations that you want to reuse throughout your site. It helps keep your - Sass very DRY. You can even pass in values to make your mixin more flexible. Here's an example for `theme`. - {% endmarkdown %} - - {% capture example_id %} - {{ example_id | plus: 1 }} - {% endcapture %} - - {% capture ui_id %} - {{ ui_id | plus: 3 }} - {% endcapture %} - -{% capture captureCode %} -@mixin theme($theme: DarkGray) { - background: $theme; - box-shadow: 0 0 1px rgba($theme, .25); - color: #fff; -} - -.info { - @include theme; -} -.alert { - @include theme($theme: DarkRed); -} -.success { - @include theme($theme: DarkGreen); -} - -=== - -@mixin theme($theme: DarkGray) - background: $theme - box-shadow: 0 0 1px rgba($theme, .25) - color: #fff - -.info - @include theme -.alert - @include theme($theme: DarkRed) - -.success - @include theme($theme: DarkGreen) - -{% endcapture %} - - {% capture example_id %} - {{ example_id | plus: 1 }} - {% endcapture %} - - {% capture ui_id %} - {{ ui_id | plus: 3 }} - {% endcapture %} - - {%- assign parsedExample = captureCode | codeExample: true, 'scss' -%} - {% render 'code_example', code: parsedExample, example_id: example_id, ui_id: ui_id %} - - {% markdown %} - To create a mixin you use the `@mixin` directive and give it a name. We've named our mixin `theme`. We're also using the variable `$theme` inside the parentheses so we can pass in a `theme` of whatever we want. - After you create your mixin, you can then use it as a CSS declaration starting with `@include` followed by the name of the mixin. -{% endmarkdown %} - -
- -
- -
- - {% markdown %}## Extend/Inheritance - Using `@extend` lets you share a set of CSS properties from one selector to another. In our example we're going to create a simple series of messaging for errors, warnings and successes using another feature which goes hand in hand with extend, placeholder classes. A placeholder class is a special type of class that only prints when it is extended, and can help keep your compiled CSS neat and clean. - {% endmarkdown %} - -{%- capture captureCode -%} -// This CSS will print because %message-shared is extended. -%message-shared { - border: 1px solid #ccc; - padding: 10px; - color: #333; -} - -// This CSS won't print because %equal-heights is never extended. -%equal-heights { - display: flex; - flex-wrap: wrap; -} - -.message { - @extend %message-shared; -} - -.success { - @extend %message-shared; - border-color: green; -} - -.error { - @extend %message-shared; - border-color: red; -} - -.warning { - @extend %message-shared; - border-color: yellow; -} -=== - -// This CSS will print because %message-shared is extended. -%message-shared - border: 1px solid #ccc - padding: 10px - color: #333 - -// This CSS won't print because %equal-heights is never extended. -%equal-heights - display: flex - flex-wrap: wrap - -.message - @extend %message-shared - -.success - @extend %message-shared - border-color: green - -.error - @extend %message-shared - border-color: red - -.warning - @extend %message-shared - border-color: yellow" | codeExample: true, 'scss' %} -{% endcapture %} - - {% capture example_id %} - {{ example_id | plus: 1 }} - {% endcapture %} - {% capture ui_id %} - {{ ui_id | plus: 3 }} - {% endcapture %} - - {%- assign parsedExample = captureCode | codeExample: true, 'scss' -%} - {% render 'code_example', code: parsedExample, example_id: example_id, ui_id: ui_id %} - - {% markdown %} - What the above code does is tells `.message`, `.success`, `.error`, and `.warning` to behave just like `%message-shared`. That means anywhere that `%message-shared` shows up, `.message`, `.success`, `.error`, & `.warning` will too. The magic happens in the generated CSS, where each of these classes will get the same CSS properties as `%message-shared`. This helps you avoid having to write multiple class names on HTML elements. - - You can extend most simple CSS selectors in addition to placeholder classes in Sass, but using placeholders is the easiest way to make sure you aren't extending a class that's nested elsewhere in your styles, which can result in unintended selectors in your CSS. - - Note that the CSS in `%equal-heights` isn't generated, because `%equal-heights` is never extended. - {% endmarkdown %} -
- -
- -
- {% markdown%}## Operators - Doing math in your CSS is very helpful. Sass has a handful of standard math operators like `+`, `-`, `*`, `math.div()`, and `%`. In our example we're going to do some simple math to calculate widths for an `article` and `aside`. - {% endmarkdown %} - - {% capture example_id %} - {{ example_id | plus: 1 }} - {% endcapture %} - {% capture ui_id %} - {{ ui_id | plus: 3 }} - {% endcapture %} - -{%- capture captureCode -%} -@use "sass:math"; - -.container { - display: flex; -} - -article[role="main"] { - width: math.div(600px, 960px) * 100%; -} - -aside[role="complementary"] { - width: math.div(300px, 960px) * 100%; - margin-left: auto; -} - -=== -@use "sass:math" - -.container - display: flex - -article[role="main"] - width: math.div(600px, 960px) * 100% - -aside[role="complementary"] - width: math.div(300px, 960px) * 100% - margin-left: auto - -=== - -.container { - display: flex; -} - -article[role="main"] { - width: 62.5%; -} - -aside[role="complementary"] { - width: 31.25%; - margin-left: auto; -} -{% endcapture %} - - {% capture example_id %} - {{ example_id | plus: 1 }} - {% endcapture %} - - {% capture ui_id %} - {{ ui_id | plus: 3 }} - {% endcapture %} - - {%- assign parsedExample = captureCode | codeExample: true, 'scss' -%} - {% render 'code_example', code: parsedExample, example_id: example_id, ui_id: ui_id %} - - {% markdown %} - We've created a very simple fluid grid, based on 960px. Operations in Sass - let us do something like take pixel values and convert them to percentages - without much hassle. - {% endmarkdown %} -
-
\ No newline at end of file diff --git a/source/guide.liquid b/source/guide.liquid new file mode 100644 index 000000000..40c4290be --- /dev/null +++ b/source/guide.liquid @@ -0,0 +1,494 @@ +--- +layout: has_no_sidebars +title: Sass Basics +introduction: > + Before you can use Sass, you need to set it up on your project. If you want to + just browse here, go ahead, but we recommend you go install Sass first. [Go + here](/install) if you want to learn how to get everything set up. +--- + +
+{% markdown %} + +## Preprocessing + +CSS on its own can be fun, but stylesheets are getting larger, more +complex, and harder to maintain. This is where a preprocessor can help. + +Sass has features that don't exist in CSS yet like nesting, mixins, +inheritance, and other nifty goodies that help you write robust, +maintainable CSS. + +Once you start tinkering with Sass, it will take your preprocessed Sass +file and save it as a normal CSS file that you can use in your website. + +The most direct way to make this happen is in your terminal. Once Sass is +installed, you can compile your Sass to CSS using the `sass` command. +You'll need to tell Sass which file to build from, and where to output CSS +to. For example, running `sass input.scss output.css` from your terminal +would take a single Sass file, `input.scss`, and compile that file to +`output.css`. + +You can also watch individual files or directories with the `--watch` +flag. The watch flag tells Sass to watch your source files for changes, +and re-compile CSS each time you save your Sass. If you wanted to watch +(instead of manually build) your `input.scss` file, you'd just add the +watch flag to your command, like so: + +``` +sass --watch input.scss output.css +``` + +You can watch and output to directories by using folder paths as your +input and output, and separating them with a colon. In this example: + + +{% renderFile 'source/code-snippets/_homepage-sass-watch.md' %} + +Sass would watch all files in the `app/sass` folder for changes, and +compile CSS to the `public/stylesheets` folder. +{% endmarkdown %} + +
+{% markdown %} +### 💡 Fun fact: + +Sass has two syntaxes! The SCSS syntax (`.scss`) is used most commonly. It's +a superset of CSS, which means all valid CSS is also valid SCSS. The +indented syntax (`.sass`) is more unusual: it uses indentation rather than +curly braces to nest statements, and newlines instead of semicolons to +separate them. All our examples are available in both syntaxes. + +{% endmarkdown %} +
+ +
+ +
+ +
+{% markdown %} + + ## Variables + + Think of variables as a way to store information that you want to reuse + throughout your stylesheet. You can store things like colors, font stacks, + or any CSS value you think you'll want to reuse. Sass uses the `$` symbol + to make something a variable. Here's an example: + +{% endmarkdown %} + +{%- capture captureCode -%} +$font-stack: Helvetica, sans-serif; +$primary-color: #333; + +body { + font: 100% $font-stack; + color: $primary-color; +} +=== +$font-stack: Helvetica, sans-serif +$primary-color: #333 + +body + font: 100% $font-stack + color: $primary-color +{%- endcapture -%} + +{%- assign parsedExample = captureCode | codeExample: true, 'scss' -%} + +{% assign example_id = 1 %} +{% assign ui_id = 1 %} +{% render 'code_example', code: parsedExample,example_id: example_id, ui_id: ui_id %} + +{% markdown %} + When the Sass is processed, it takes the variables we define for the + `$font-stack` and `$primary-color` and outputs normal CSS with our + variable values placed in the CSS. This can be extremely powerful when + working with brand colors and keeping them consistent throughout the site. +{% endmarkdown %} +
+ +
+ +
+{% markdown %} + +## Nesting +When writing HTML you've probably noticed that it has a clear nested and visual hierarchy. CSS, on the other hand, doesn't. + +Sass will let you nest your CSS selectors in a way that follows the same +visual hierarchy of your HTML. Be aware that overly nested rules will +result in over-qualified CSS that could prove hard to maintain and is +generally considered bad practice. + +With that in mind, here's an example of some typical styles for a site's +navigation: + +{% endmarkdown %} + +{%- capture captureCode -%} +nav { + ul { + margin: 0; + padding: 0; + list-style: none; + } + + li { display: inline-block; } + + a { + display: block; + padding: 6px 12px; + text-decoration: none; + } +} +=== +nav + ul + margin: 0 + padding: 0 + list-style: none + + li + display: inline-block + + a + display: block + padding: 6px 12px + text-decoration: none +{%- endcapture -%} + +{% capture example_id %} + {{ example_id | plus: 1 }} +{% endcapture %} + +{% capture ui_id %} + {{ ui_id | plus: 3 }} +{% endcapture %} + +{%- assign parsedExample = captureCode | codeExample: true, 'scss' -%} +{% render 'code_example', code: parsedExample, example_id: example_id, ui_id: ui_id %} + +
+ +
+ +
+ {% markdown %}## Partials + You can create partial Sass files that contain little snippets of CSS that you can include in other Sass files. + This is a great way to modularize your CSS and help keep things easier to maintain. A partial is a + Sass file named with a leading underscore. You might name it something + like `_partial.scss`. The underscore lets Sass know that the file is only + a partial file and that it should not be generated into a CSS file. Sass + partials are used with the `@use` rule. + {% endmarkdown %} +
+ +
+ +
+{% markdown %} + +## Modules + + +You don't have to write all your Sass in a single file. You can split it up however you want with the `@use` rule. This rule loads another Sass file as a _module_, which means you can refer to its variables, [mixins][], and [functions][] in your Sass file with a namespace based on the filename. Using a file will also include the CSS it generates in your compiled output! + +[mixins]: #topic-6 +[functions]: documentation/at-rules/function +{% endmarkdown %} + +{%- capture captureCode -%} +// _base.scss +$font-stack: Helvetica, sans-serif; +$primary-color: #333; + +body { + font: 100% $font-stack; + color: $primary-color; +} +--- + +// styles.scss +@use 'base'; + +.inverse { + background-color: base.$primary-color; + color: white; +} + +=== +// _base.sass +$font-stack: Helvetica, sans-serif +$primary-color: #333 + +body + font: 100% $font-stack + color: $primary-color +--- + +// styles.sass +@use 'base' + +.inverse + background-color: base.$primary-color + color: white +=== + +body { + font: 100% Helvetica, sans-serif; + color: #333; +} + +.inverse { + background-color: #333; + color: white; +} +{% endcapture %} + +{% capture example_id %} + {{ example_id | plus: 1 }} +{% endcapture %} + +{% capture ui_id %} + {{ ui_id | plus: 3 }} +{% endcapture %} + +{%- assign parsedExample = captureCode | codeExample: true, 'scss' -%} +{% render 'code_example', code: parsedExample, example_id: example_id, ui_id: ui_id %} + +
+ +
+ +
+{% markdown %} + +## Mixins + +Some things in CSS are a bit tedious to write, especially with CSS3 and the many vendor prefixes that exist. A mixin lets you make groups of CSS declarations that you want to reuse throughout your site. It helps keep your +Sass very DRY. You can even pass in values to make your mixin more flexible. Here's an example for `theme`. + +{% endmarkdown %} + +{% capture captureCode %} +@mixin theme($theme: DarkGray) { + background: $theme; + box-shadow: 0 0 1px rgba($theme, .25); + color: #fff; +} + +.info { + @include theme; +} +.alert { + @include theme($theme: DarkRed); +} +.success { + @include theme($theme: DarkGreen); +} + +=== + +@mixin theme($theme: DarkGray) + background: $theme + box-shadow: 0 0 1px rgba($theme, .25) + color: #fff + +.info + @include theme +.alert + @include theme($theme: DarkRed) + +.success + @include theme($theme: DarkGreen) + +{% endcapture %} + +{% capture example_id %} + {{ example_id | plus: 1 }} +{% endcapture %} + +{% capture ui_id %} + {{ ui_id | plus: 3 }} +{% endcapture %} + +{%- assign parsedExample = captureCode | codeExample: true, 'scss' -%} +{% render 'code_example', code: parsedExample, example_id: example_id, ui_id: ui_id %} + +{% markdown %} +To create a mixin you use the `@mixin` directive and give it a name. We've named our mixin `theme`. We're also using the variable `$theme` inside the parentheses so we can pass in a `theme` of whatever we want. After you create your mixin, you can then use it as a CSS declaration starting with `@include` followed by the name of the mixin. +{% endmarkdown %} + +
+ +
+ +
+ +{% markdown %} + +## Extend/Inheritance + +Using `@extend` lets you share a set of CSS properties from one selector to another. In our example we're going to create a simple series of messaging for errors, warnings and successes using another feature which goes hand in hand with extend, placeholder classes. A placeholder class is a special type of class that only prints when it is extended, and can help keep your compiled CSS neat and clean. + +{% endmarkdown %} + +{%- capture captureCode -%} +// This CSS will print because %message-shared is extended. +%message-shared { + border: 1px solid #ccc; + padding: 10px; + color: #333; +} + +// This CSS won't print because %equal-heights is never extended. +%equal-heights { + display: flex; + flex-wrap: wrap; +} + +.message { + @extend %message-shared; +} + +.success { + @extend %message-shared; + border-color: green; +} + +.error { + @extend %message-shared; + border-color: red; +} + +.warning { + @extend %message-shared; + border-color: yellow; +} +=== + +// This CSS will print because %message-shared is extended. +%message-shared + border: 1px solid #ccc + padding: 10px + color: #333 + +// This CSS won't print because %equal-heights is never extended. +%equal-heights + display: flex + flex-wrap: wrap + +.message + @extend %message-shared + +.success + @extend %message-shared + border-color: green + +.error + @extend %message-shared + border-color: red + +.warning + @extend %message-shared + border-color: yellow" | codeExample: true, 'scss' %} +{% endcapture %} + +{% capture example_id %} + {{ example_id | plus: 1 }} +{% endcapture %} + +{% capture ui_id %} + {{ ui_id | plus: 3 }} +{% endcapture %} + +{%- assign parsedExample = captureCode | codeExample: true, 'scss' -%} +{% render 'code_example', code: parsedExample, example_id: example_id, ui_id: ui_id %} + +{% markdown %} +What the above code does is tells `.message`, `.success`, `.error`, and `.warning` to behave just like `%message-shared`. That means anywhere that `%message-shared` shows up, `.message`, `.success`, `.error`, & `.warning` will too. The magic happens in the generated CSS, where each of these classes will get the same CSS properties as `%message-shared`. This helps you avoid having to write multiple class names on HTML elements. + +You can extend most simple CSS selectors in addition to placeholder classes in Sass, but using placeholders is the easiest way to make sure you aren't extending a class that's nested elsewhere in your styles, which can result in unintended selectors in your CSS. + +Note that the CSS in `%equal-heights` isn't generated, because `%equal-heights` is never extended. +{% endmarkdown %} +
+ +
+ +
+ +{% markdown%} + +## Operators + +Doing math in your CSS is very helpful. Sass has a handful of standard math operators like `+`, `-`, `*`, `math.div()`, and `%`. In our example we're going to do some simple math to calculate widths for an `article` and `aside`. + +{% endmarkdown %} + +{%- capture captureCode -%} +@use "sass:math"; + +.container { + display: flex; +} + +article[role="main"] { + width: math.div(600px, 960px) * 100%; +} + +aside[role="complementary"] { + width: math.div(300px, 960px) * 100%; + margin-left: auto; +} + +=== +@use "sass:math" + +.container + display: flex + +article[role="main"] + width: math.div(600px, 960px) * 100% + +aside[role="complementary"] + width: math.div(300px, 960px) * 100% + margin-left: auto + +=== + +.container { + display: flex; +} + +article[role="main"] { + width: 62.5%; +} + +aside[role="complementary"] { + width: 31.25%; + margin-left: auto; +} +{% endcapture %} + +{% capture example_id %} + {{ example_id | plus: 1 }} +{% endcapture %} + +{% capture ui_id %} + {{ ui_id | plus: 3 }} +{% endcapture %} + +{%- assign parsedExample = captureCode | codeExample: true, 'scss' -%} +{% render 'code_example', code: parsedExample, example_id: example_id, ui_id: ui_id %} + +{% markdown %} +We've created a very simple fluid grid, based on 960px. Operations in Sass +let us do something like take pixel values and convert them to percentages +without much hassle. +{% endmarkdown %} + +
+
\ No newline at end of file diff --git a/source/guide.md b/source/guide.md deleted file mode 100644 index de0be57ab..000000000 --- a/source/guide.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -layout: guide -title: Sass Basics -introduction: > - Before you can use Sass, you need to set it up on your project. If you want to - just browse here, go ahead, but we recommend you go install Sass first. [Go - here](/install) if you want to learn how to get everything set up. ---- From d2ef6e00aa365afc63ab4e795a5b71c2835a40d4 Mon Sep 17 00:00:00 2001 From: Sana Javed Date: Tue, 21 Feb 2023 20:52:19 +0100 Subject: [PATCH 09/42] Updating example --- source/guide.liquid | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/guide.liquid b/source/guide.liquid index 40c4290be..366701d09 100644 --- a/source/guide.liquid +++ b/source/guide.liquid @@ -393,7 +393,7 @@ Using `@extend` lets you share a set of CSS properties from one selector to anot .warning @extend %message-shared - border-color: yellow" | codeExample: true, 'scss' %} + border-color: yellow" {% endcapture %} {% capture example_id %} From 655099c8dd57f61e637ee934659d563c70f770e6 Mon Sep 17 00:00:00 2001 From: Sana Javed Date: Tue, 21 Feb 2023 20:53:27 +0100 Subject: [PATCH 10/42] typo --- source/guide.liquid | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/guide.liquid b/source/guide.liquid index 366701d09..7c99a9a35 100644 --- a/source/guide.liquid +++ b/source/guide.liquid @@ -393,7 +393,7 @@ Using `@extend` lets you share a set of CSS properties from one selector to anot .warning @extend %message-shared - border-color: yellow" + border-color: yellow {% endcapture %} {% capture example_id %} From 0a81665d85485370dcff57efb48be6d165b90baa Mon Sep 17 00:00:00 2001 From: Sana Javed Date: Sat, 25 Feb 2023 13:44:14 +0100 Subject: [PATCH 11/42] Adding compatibility helper --- eleventy.config.cjs | 23 ++++++++++++++++++++ source/_includes/impl_status.liquid | 33 +++++++++++++++++++++++++++++ source/guide.liquid | 5 ++++- source/helpers/sass_helpers.ts | 16 ++++++++++++++ 4 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 source/_includes/impl_status.liquid create mode 100644 source/helpers/sass_helpers.ts diff --git a/eleventy.config.cjs b/eleventy.config.cjs index 83b474988..5eefcba81 100644 --- a/eleventy.config.cjs +++ b/eleventy.config.cjs @@ -8,6 +8,7 @@ const markdown = require('markdown-it'); const markdownDefList = require('markdown-it-deflist'); const typogrify = require('typogr'); const sass = require('sass'); +const { getImplStatus } = require('./source/helpers/sass_helpers.ts'); /** @param {import('@11ty/eleventy').UserConfig} eleventyConfig */ module.exports = (eleventyConfig) => { @@ -65,6 +66,28 @@ module.exports = (eleventyConfig) => { page.url.startsWith('/documentation/js-api/'), ); + eleventyConfig.addLiquidFilter( + 'implStatus', + ( + dart = null, + libsass = null, + ruby = null, + node = null, + feature = null, + markdown = null, + ) => { + const data = { + dart: getImplStatus(dart), + libsass: getImplStatus(libsass), + ruby: getImplStatus(ruby), + node: getImplStatus(node), + feature: feature, + markdown: markdown, + }; + return data; + }, + ); + eleventyConfig.addLiquidFilter( 'codeExample', (contents, autogenCSS = true, syntax = null) => { diff --git a/source/_includes/impl_status.liquid b/source/_includes/impl_status.liquid new file mode 100644 index 000000000..732958065 --- /dev/null +++ b/source/_includes/impl_status.liquid @@ -0,0 +1,33 @@ +
+
Compatibility{% if implStatusData.feature %} ({{ implStatusData.feature }}){% endif %}:
+{% if implStatusData.dart %} +
+
Dart Sass
+
{{ implStatusData.dart }}
+
+{% endif %} +{% if implStatusData.libsass %} +
+
LibSass
+
{{ implStatusData.libsass }}
+
+{% endif %} +{% if implStatusData.ruby %} +
+
Ruby Sass
+
{{ implStatusData.ruby }}
+
+{% endif %} +{% if implStatusData.markdown %} + +{% endif %} +
+ +{% if implStatusData.markdown %} + +{% endif %} + diff --git a/source/guide.liquid b/source/guide.liquid index 7c99a9a35..50bd6444d 100644 --- a/source/guide.liquid +++ b/source/guide.liquid @@ -191,7 +191,10 @@ nav {% markdown %} ## Modules - +{% assign implStatusData = "1.23.0" | implStatus: false, false, false, false, "Only Dart Sass currently supports `@use`. Users of other implementations must use the [`@import` rule][] instead. + +[`@import` rule]: /documentation/at-rules/import" %} +{% render 'impl_status', implStatusData: implStatusData %} You don't have to write all your Sass in a single file. You can split it up however you want with the `@use` rule. This rule loads another Sass file as a _module_, which means you can refer to its variables, [mixins][], and [functions][] in your Sass file with a namespace based on the filename. Using a file will also include the CSS it generates in your compiled output! diff --git a/source/helpers/sass_helpers.ts b/source/helpers/sass_helpers.ts new file mode 100644 index 000000000..01cb30f56 --- /dev/null +++ b/source/helpers/sass_helpers.ts @@ -0,0 +1,16 @@ +function getImplStatus(status) { + switch (status) { + case null: + return status; + case true: + return '✓'; + case false: + return '✗'; + case 'partial': + return 'partial'; + default: + return `since ${status}`; + } +} + +module.exports = { getImplStatus }; From d2a837dc12679874e2ab68f35e2258b845825d6d Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Sat, 25 Feb 2023 18:07:51 -0700 Subject: [PATCH 12/42] Enable Typescript for 11ty filters --- .eslintrc.cjs => .eslintrc.js | 30 ++-- babel.config.js | 2 +- eleventy.config.cjs => eleventy.config.js | 0 package.json | 6 +- rollup.config.js | 14 +- source/_data/{releases.cjs => releases.js} | 2 +- source/helpers/sass_helpers.ts | 4 +- tool/{typedoc-theme.cjs => typedoc-theme.js} | 1 - yarn.lock | 139 ++++++++++++++++++- 9 files changed, 161 insertions(+), 37 deletions(-) rename .eslintrc.cjs => .eslintrc.js (67%) rename eleventy.config.cjs => eleventy.config.js (100%) rename source/_data/{releases.cjs => releases.js} (100%) rename tool/{typedoc-theme.cjs => typedoc-theme.js} (99%) diff --git a/.eslintrc.cjs b/.eslintrc.js similarity index 67% rename from .eslintrc.cjs rename to .eslintrc.js index aeaacb393..f29c5b60f 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.js @@ -2,7 +2,7 @@ module.exports = { root: true, parser: '@typescript-eslint/parser', parserOptions: { - sourceType: 'module', + sourceType: 'script', ecmaVersion: 2021, tsconfigRootDir: __dirname, warnOnUnsupportedTypeScriptVersion: false, @@ -12,7 +12,7 @@ module.exports = { es2021: true, node: true, }, - plugins: ['simple-import-sort', 'import', '@typescript-eslint'], + plugins: ['import', 'simple-import-sort', '@typescript-eslint'], extends: [ 'eslint:recommended', 'plugin:import/recommended', @@ -25,37 +25,29 @@ module.exports = { typescript: { project: ['tsconfig.json'], }, - node: { - extensions: ['.cjs'], - }, }, }, overrides: [ - { - files: ['*.cjs'], - parserOptions: { - sourceType: 'script', - }, - rules: { - 'import/order': 1, - 'simple-import-sort/imports': 0, - '@typescript-eslint/no-var-requires': 0, - }, - }, { files: ['*.ts'], parserOptions: { + sourceType: 'module', project: ['tsconfig.json'], }, extends: [ 'plugin:@typescript-eslint/recommended-requiring-type-checking', ], + rules: { + 'import/order': 0, + 'sort-imports': 0, + 'simple-import-sort/imports': 1, + }, }, ], rules: { - 'import/order': 0, - 'sort-imports': 0, - 'simple-import-sort/imports': 1, + 'import/order': 1, + 'simple-import-sort/imports': 0, + '@typescript-eslint/no-var-requires': 0, 'no-console': 1, 'no-warning-comments': [1, { terms: ['todo', 'fixme', '@@@'] }], }, diff --git a/babel.config.js b/babel.config.js index 1c43c0940..40fab8500 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,3 +1,3 @@ -export default { +module.exports = { presets: ['@babel/preset-typescript'], }; diff --git a/eleventy.config.cjs b/eleventy.config.js similarity index 100% rename from eleventy.config.cjs rename to eleventy.config.js diff --git a/package.json b/package.json index 53609890f..6af8d80fe 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,6 @@ "node": "^16", "yarn": "^3" }, - "type": "module", "packageManager": "yarn@3.3.1", "scripts": { "serve": "run-p 'watch:**'", @@ -25,8 +24,8 @@ "build-dev:scripts": "rollup -c", "build-prod:scripts": "BABEL_ENV=production rollup -c", "watch:scripts": "npm run build-dev:scripts -- -w", - "build:11ty": "eleventy", - "watch:11ty": "eleventy --serve --incremental", + "build:11ty": "NODE_OPTIONS='-r ts-node/register' eleventy", + "watch:11ty": "yarn build:11ty --serve --incremental", "tsc": "tsc", "prettier": "prettier --write .", "prettier:ci": "prettier --check .", @@ -77,6 +76,7 @@ "semver-parser": "^4.1.2", "stylelint": "^15.2.0", "stylelint-config-standard-scss": "^7.0.1", + "ts-node": "^10.9.1", "typedoc": "^0.23.25", "typescript": "^4.9.5", "typogr": "^0.6.8" diff --git a/rollup.config.js b/rollup.config.js index ddecee343..7482282f2 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,9 +1,9 @@ -import { babel } from '@rollup/plugin-babel'; -import commonjs from '@rollup/plugin-commonjs'; -import inject from '@rollup/plugin-inject'; -import { nodeResolve } from '@rollup/plugin-node-resolve'; -import terser from '@rollup/plugin-terser'; -import { defineConfig } from 'rollup'; +const { babel } = require('@rollup/plugin-babel'); +const commonjs = require('@rollup/plugin-commonjs'); +const inject = require('@rollup/plugin-inject'); +const { nodeResolve } = require('@rollup/plugin-node-resolve'); +const terser = require('@rollup/plugin-terser'); +const { defineConfig } = require('rollup'); const prod = process.env.BABEL_ENV === 'production'; @@ -24,7 +24,7 @@ if (prod) { plugins.push(terser()); } -export default defineConfig({ +module.exports = defineConfig({ input: 'source/assets/js/sass.ts', output: { file: 'source/assets/dist/js/sass.js', diff --git a/source/_data/releases.cjs b/source/_data/releases.js similarity index 100% rename from source/_data/releases.cjs rename to source/_data/releases.js index 943803b10..b6f957f81 100644 --- a/source/_data/releases.cjs +++ b/source/_data/releases.js @@ -1,7 +1,7 @@ const { spawn: nodeSpawn } = require('node:child_process'); const fs = require('node:fs/promises'); -const deepEqual = require('deep-equal'); +const deepEqual = require('deep-equal'); const chalk = require('kleur'); const VERSION_CACHE_PATH = './source/_data/versionCache.json'; diff --git a/source/helpers/sass_helpers.ts b/source/helpers/sass_helpers.ts index 01cb30f56..b2d1b0ec3 100644 --- a/source/helpers/sass_helpers.ts +++ b/source/helpers/sass_helpers.ts @@ -1,4 +1,4 @@ -function getImplStatus(status) { +export function getImplStatus(status: string | boolean | null) { switch (status) { case null: return status; @@ -12,5 +12,3 @@ function getImplStatus(status) { return `since ${status}`; } } - -module.exports = { getImplStatus }; diff --git a/tool/typedoc-theme.cjs b/tool/typedoc-theme.js similarity index 99% rename from tool/typedoc-theme.cjs rename to tool/typedoc-theme.js index 85ea24116..fe8f4c435 100644 --- a/tool/typedoc-theme.cjs +++ b/tool/typedoc-theme.js @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-var-requires */ const { DefaultTheme, DefaultThemeRenderContext, diff --git a/yarn.lock b/yarn.lock index f0f24d8b9..a7451840c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1396,6 +1396,15 @@ __metadata: languageName: node linkType: hard +"@cspotcode/source-map-support@npm:^0.8.0": + version: 0.8.1 + resolution: "@cspotcode/source-map-support@npm:0.8.1" + dependencies: + "@jridgewell/trace-mapping": 0.3.9 + checksum: 5718f267085ed8edb3e7ef210137241775e607ee18b77d95aa5bd7514f47f5019aa2d82d96b3bf342ef7aa890a346fa1044532ff7cc3009e7d24fce3ce6200fa + languageName: node + linkType: hard + "@csstools/css-parser-algorithms@npm:^2.0.1": version: 2.0.1 resolution: "@csstools/css-parser-algorithms@npm:2.0.1" @@ -1509,7 +1518,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/resolve-uri@npm:3.1.0": +"@jridgewell/resolve-uri@npm:3.1.0, @jridgewell/resolve-uri@npm:^3.0.3": version: 3.1.0 resolution: "@jridgewell/resolve-uri@npm:3.1.0" checksum: b5ceaaf9a110fcb2780d1d8f8d4a0bfd216702f31c988d8042e5f8fbe353c55d9b0f55a1733afdc64806f8e79c485d2464680ac48a0d9fcadb9548ee6b81d267 @@ -1540,6 +1549,16 @@ __metadata: languageName: node linkType: hard +"@jridgewell/trace-mapping@npm:0.3.9": + version: 0.3.9 + resolution: "@jridgewell/trace-mapping@npm:0.3.9" + dependencies: + "@jridgewell/resolve-uri": ^3.0.3 + "@jridgewell/sourcemap-codec": ^1.4.10 + checksum: d89597752fd88d3f3480845691a05a44bd21faac18e2185b6f436c3b0fd0c5a859fbbd9aaa92050c4052caf325ad3e10e2e1d1b64327517471b7d51babc0ddef + languageName: node + linkType: hard + "@jridgewell/trace-mapping@npm:^0.3.9": version: 0.3.17 resolution: "@jridgewell/trace-mapping@npm:0.3.17" @@ -1743,6 +1762,34 @@ __metadata: languageName: node linkType: hard +"@tsconfig/node10@npm:^1.0.7": + version: 1.0.9 + resolution: "@tsconfig/node10@npm:1.0.9" + checksum: a33ae4dc2a621c0678ac8ac4bceb8e512ae75dac65417a2ad9b022d9b5411e863c4c198b6ba9ef659e14b9fb609bbec680841a2e84c1172df7a5ffcf076539df + languageName: node + linkType: hard + +"@tsconfig/node12@npm:^1.0.7": + version: 1.0.11 + resolution: "@tsconfig/node12@npm:1.0.11" + checksum: 5ce29a41b13e7897a58b8e2df11269c5395999e588b9a467386f99d1d26f6c77d1af2719e407621412520ea30517d718d5192a32403b8dfcc163bf33e40a338a + languageName: node + linkType: hard + +"@tsconfig/node14@npm:^1.0.0": + version: 1.0.3 + resolution: "@tsconfig/node14@npm:1.0.3" + checksum: 19275fe80c4c8d0ad0abed6a96dbf00642e88b220b090418609c4376e1cef81bf16237bf170ad1b341452feddb8115d8dd2e5acdfdea1b27422071163dc9ba9d + languageName: node + linkType: hard + +"@tsconfig/node16@npm:^1.0.2": + version: 1.0.3 + resolution: "@tsconfig/node16@npm:1.0.3" + checksum: 3a8b657dd047495b7ad23437d6afd20297ce90380ff0bdee93fc7d39a900dbd8d9e26e53ff6b465e7967ce2adf0b218782590ce9013285121e6a5928fbd6819f + languageName: node + linkType: hard + "@types/estree@npm:*, @types/estree@npm:^1.0.0": version: 1.0.0 resolution: "@types/estree@npm:1.0.0" @@ -1975,6 +2022,13 @@ __metadata: languageName: node linkType: hard +"acorn-walk@npm:^8.1.1": + version: 8.2.0 + resolution: "acorn-walk@npm:8.2.0" + checksum: 1715e76c01dd7b2d4ca472f9c58968516a4899378a63ad5b6c2d668bba8da21a71976c14ec5f5b75f887b6317c4ae0b897ab141c831d741dc76024d8745f1ad1 + languageName: node + linkType: hard + "acorn@npm:^7.1.1": version: 7.4.1 resolution: "acorn@npm:7.4.1" @@ -1984,7 +2038,7 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.5.0, acorn@npm:^8.8.0": +"acorn@npm:^8.4.1, acorn@npm:^8.5.0, acorn@npm:^8.8.0": version: 8.8.2 resolution: "acorn@npm:8.8.2" bin: @@ -2113,6 +2167,13 @@ __metadata: languageName: node linkType: hard +"arg@npm:^4.1.0": + version: 4.1.3 + resolution: "arg@npm:4.1.3" + checksum: 544af8dd3f60546d3e4aff084d451b96961d2267d668670199692f8d054f0415d86fc5497d0e641e91546f0aa920e7c29e5250e99fc89f5552a34b5d93b77f43 + languageName: node + linkType: hard + "argparse@npm:^1.0.7": version: 1.0.10 resolution: "argparse@npm:1.0.10" @@ -2691,6 +2752,13 @@ __metadata: languageName: node linkType: hard +"create-require@npm:^1.1.0": + version: 1.1.1 + resolution: "create-require@npm:1.1.1" + checksum: a9a1503d4390d8b59ad86f4607de7870b39cad43d929813599a23714831e81c520bddf61bcdd1f8e30f05fd3a2b71ae8538e946eb2786dc65c2bbc520f692eff + languageName: node + linkType: hard + "cross-spawn@npm:^6.0.5": version: 6.0.5 resolution: "cross-spawn@npm:6.0.5" @@ -2908,6 +2976,13 @@ __metadata: languageName: node linkType: hard +"diff@npm:^4.0.1": + version: 4.0.2 + resolution: "diff@npm:4.0.2" + checksum: f2c09b0ce4e6b301c221addd83bf3f454c0bc00caa3dd837cf6c127d6edf7223aa2bbe3b688feea110b7f262adbfc845b757c44c8a9f8c0c5b15d8fa9ce9d20d + languageName: node + linkType: hard + "dir-glob@npm:^3.0.1": version: 3.0.1 resolution: "dir-glob@npm:3.0.1" @@ -4995,6 +5070,13 @@ __metadata: languageName: node linkType: hard +"make-error@npm:^1.1.1": + version: 1.3.6 + resolution: "make-error@npm:1.3.6" + checksum: b86e5e0e25f7f777b77fabd8e2cbf15737972869d852a22b7e73c17623928fccb826d8e46b9951501d3f20e51ad74ba8c59ed584f610526a48f8ccf88aaec402 + languageName: node + linkType: hard + "make-fetch-happen@npm:^10.0.3": version: 10.2.1 resolution: "make-fetch-happen@npm:10.2.1" @@ -6501,6 +6583,7 @@ __metadata: semver-parser: ^4.1.2 stylelint: ^15.2.0 stylelint-config-standard-scss: ^7.0.1 + ts-node: ^10.9.1 typedoc: ^0.23.25 typescript: ^4.9.5 typogr: ^0.6.8 @@ -7197,6 +7280,44 @@ __metadata: languageName: node linkType: hard +"ts-node@npm:^10.9.1": + version: 10.9.1 + resolution: "ts-node@npm:10.9.1" + dependencies: + "@cspotcode/source-map-support": ^0.8.0 + "@tsconfig/node10": ^1.0.7 + "@tsconfig/node12": ^1.0.7 + "@tsconfig/node14": ^1.0.0 + "@tsconfig/node16": ^1.0.2 + acorn: ^8.4.1 + acorn-walk: ^8.1.1 + arg: ^4.1.0 + create-require: ^1.1.0 + diff: ^4.0.1 + make-error: ^1.1.1 + v8-compile-cache-lib: ^3.0.1 + yn: 3.1.1 + peerDependencies: + "@swc/core": ">=1.2.50" + "@swc/wasm": ">=1.2.50" + "@types/node": "*" + typescript: ">=2.7" + peerDependenciesMeta: + "@swc/core": + optional: true + "@swc/wasm": + optional: true + bin: + ts-node: dist/bin.js + ts-node-cwd: dist/bin-cwd.js + ts-node-esm: dist/bin-esm.js + ts-node-script: dist/bin-script.js + ts-node-transpile-only: dist/bin-transpile.js + ts-script: dist/bin-script-deprecated.js + checksum: 090adff1302ab20bd3486e6b4799e90f97726ed39e02b39e566f8ab674fd5bd5f727f43615debbfc580d33c6d9d1c6b1b3ce7d8e3cca3e20530a145ffa232c35 + languageName: node + linkType: hard + "tsconfig-paths@npm:^3.14.1": version: 3.14.1 resolution: "tsconfig-paths@npm:3.14.1" @@ -7446,6 +7567,13 @@ __metadata: languageName: node linkType: hard +"v8-compile-cache-lib@npm:^3.0.1": + version: 3.0.1 + resolution: "v8-compile-cache-lib@npm:3.0.1" + checksum: 78089ad549e21bcdbfca10c08850022b22024cdcc2da9b168bcf5a73a6ed7bf01a9cebb9eac28e03cd23a684d81e0502797e88f3ccd27a32aeab1cfc44c39da0 + languageName: node + linkType: hard + "v8-compile-cache@npm:^2.3.0": version: 2.3.0 resolution: "v8-compile-cache@npm:2.3.0" @@ -7633,6 +7761,13 @@ __metadata: languageName: node linkType: hard +"yn@npm:3.1.1": + version: 3.1.1 + resolution: "yn@npm:3.1.1" + checksum: 2c487b0e149e746ef48cda9f8bad10fc83693cd69d7f9dcd8be4214e985de33a29c9e24f3c0d6bcf2288427040a8947406ab27f7af67ee9456e6b84854f02dd6 + languageName: node + linkType: hard + "yocto-queue@npm:^0.1.0": version: 0.1.0 resolution: "yocto-queue@npm:0.1.0" From 2193a69e496fabeebd27db469d661886169487de Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 27 Feb 2023 08:06:30 +0000 Subject: [PATCH 13/42] chore(deps): Automated dependency upgrades --- package.json | 14 +- yarn.lock | 481 ++++++++++++++++++++++++++------------------------- 2 files changed, 252 insertions(+), 243 deletions(-) diff --git a/package.json b/package.json index 53609890f..d0922df4e 100644 --- a/package.json +++ b/package.json @@ -41,9 +41,9 @@ "devDependencies": { "@11ty/eleventy": "^2.0.0", "@11ty/eleventy-plugin-syntaxhighlight": "^4.2.0", - "@babel/core": "^7.20.12", + "@babel/core": "^7.21.0", "@babel/preset-env": "^7.20.2", - "@babel/preset-typescript": "^7.18.6", + "@babel/preset-typescript": "^7.21.0", "@rollup/plugin-babel": "^6.0.3", "@rollup/plugin-commonjs": "^24.0.1", "@rollup/plugin-inject": "^5.0.3", @@ -52,11 +52,11 @@ "@types/jquery": "^3.5.16", "@types/jqueryui": "^1.12.16", "@types/node": "^16", - "@typescript-eslint/eslint-plugin": "^5.52.0", - "@typescript-eslint/parser": "^5.52.0", + "@typescript-eslint/eslint-plugin": "^5.53.0", + "@typescript-eslint/parser": "^5.53.0", "date-fns": "^2.29.3", "deep-equal": "^2.2.0", - "eslint": "^8.34.0", + "eslint": "^8.35.0", "eslint-config-prettier": "^8.6.0", "eslint-import-resolver-typescript": "^3.5.3", "eslint-plugin-import": "^2.27.5", @@ -72,12 +72,12 @@ "netlify-plugin-11ty": "^1.3.0", "npm-run-all": "^4.1.5", "prettier": "^2.8.4", - "rollup": "^3.17.2", + "rollup": "^3.17.3", "sass": "^1.58.3", "semver-parser": "^4.1.2", "stylelint": "^15.2.0", "stylelint-config-standard-scss": "^7.0.1", - "typedoc": "^0.23.25", + "typedoc": "^0.23.26", "typescript": "^4.9.5", "typogr": "^0.6.8" }, diff --git a/yarn.lock b/yarn.lock index f0f24d8b9..bd480a07f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -102,7 +102,7 @@ __metadata: languageName: node linkType: hard -"@ampproject/remapping@npm:^2.1.0": +"@ampproject/remapping@npm:^2.2.0": version: 2.2.0 resolution: "@ampproject/remapping@npm:2.2.0" dependencies: @@ -122,43 +122,44 @@ __metadata: linkType: hard "@babel/compat-data@npm:^7.17.7, @babel/compat-data@npm:^7.20.1, @babel/compat-data@npm:^7.20.5": - version: 7.20.14 - resolution: "@babel/compat-data@npm:7.20.14" - checksum: 6c9efe36232094e4ad0b70d165587f21ca718e5d011f7a52a77a18502a7524e90e2855aa5a2e086395bcfd21bd2c7c99128dcd8d9fdffe94316b72acf5c66f2c + version: 7.21.0 + resolution: "@babel/compat-data@npm:7.21.0" + checksum: dbf632c532f9c75ba0be7d1dc9f6cd3582501af52f10a6b90415d634ec5878735bd46064c91673b10317af94d4cc99c4da5bd9d955978cdccb7905fc33291e4d languageName: node linkType: hard -"@babel/core@npm:^7.20.12": - version: 7.20.12 - resolution: "@babel/core@npm:7.20.12" +"@babel/core@npm:^7.21.0": + version: 7.21.0 + resolution: "@babel/core@npm:7.21.0" dependencies: - "@ampproject/remapping": ^2.1.0 + "@ampproject/remapping": ^2.2.0 "@babel/code-frame": ^7.18.6 - "@babel/generator": ^7.20.7 + "@babel/generator": ^7.21.0 "@babel/helper-compilation-targets": ^7.20.7 - "@babel/helper-module-transforms": ^7.20.11 - "@babel/helpers": ^7.20.7 - "@babel/parser": ^7.20.7 + "@babel/helper-module-transforms": ^7.21.0 + "@babel/helpers": ^7.21.0 + "@babel/parser": ^7.21.0 "@babel/template": ^7.20.7 - "@babel/traverse": ^7.20.12 - "@babel/types": ^7.20.7 + "@babel/traverse": ^7.21.0 + "@babel/types": ^7.21.0 convert-source-map: ^1.7.0 debug: ^4.1.0 gensync: ^1.0.0-beta.2 json5: ^2.2.2 semver: ^6.3.0 - checksum: 62e6c3e2149a70b5c9729ef5f0d3e2e97e9dcde89fc039c8d8e3463d5d7ba9b29ee84d10faf79b61532ac1645aa62f2bd42338320617e6e3a8a4d8e2a27076e7 + checksum: 357f4dd3638861ceebf6d95ff49ad8b902065ee8b7b352621deed5666c2a6d702a48ca7254dba23ecae2a0afb67d20f90db7dd645c3b75e35e72ad9776c671aa languageName: node linkType: hard -"@babel/generator@npm:^7.20.7": - version: 7.20.14 - resolution: "@babel/generator@npm:7.20.14" +"@babel/generator@npm:^7.21.0, @babel/generator@npm:^7.21.1": + version: 7.21.1 + resolution: "@babel/generator@npm:7.21.1" dependencies: - "@babel/types": ^7.20.7 + "@babel/types": ^7.21.0 "@jridgewell/gen-mapping": ^0.3.2 + "@jridgewell/trace-mapping": ^0.3.17 jsesc: ^2.5.1 - checksum: 5f6aa2d86af26e76d276923a5c34191124a119b16ee9ccc34aef654a7dec84fbd7d2daed2e6458a6a06bf87f3661deb77c9fea59b8f67faff5c90793c96d76d6 + checksum: 69085a211ff91a7a608ee3f86e6fcb9cf5e724b756d792a713b0c328a671cd3e423e1ef1b12533f366baba0616caffe0a7ba9d328727eab484de5961badbef00 languageName: node linkType: hard @@ -196,33 +197,33 @@ __metadata: languageName: node linkType: hard -"@babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.20.12, @babel/helper-create-class-features-plugin@npm:^7.20.5, @babel/helper-create-class-features-plugin@npm:^7.20.7": - version: 7.20.12 - resolution: "@babel/helper-create-class-features-plugin@npm:7.20.12" +"@babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.21.0": + version: 7.21.0 + resolution: "@babel/helper-create-class-features-plugin@npm:7.21.0" dependencies: "@babel/helper-annotate-as-pure": ^7.18.6 "@babel/helper-environment-visitor": ^7.18.9 - "@babel/helper-function-name": ^7.19.0 - "@babel/helper-member-expression-to-functions": ^7.20.7 + "@babel/helper-function-name": ^7.21.0 + "@babel/helper-member-expression-to-functions": ^7.21.0 "@babel/helper-optimise-call-expression": ^7.18.6 "@babel/helper-replace-supers": ^7.20.7 "@babel/helper-skip-transparent-expression-wrappers": ^7.20.0 "@babel/helper-split-export-declaration": ^7.18.6 peerDependencies: "@babel/core": ^7.0.0 - checksum: 1e9ed4243b75278fa24deb40dc62bf537b79307987223a2d2d2ae5abf7ba6dc8435d6e3bb55d52ceb30d3e1eba88e7eb6a1885a8bb519e5cfc3e9dedb97d43e6 + checksum: 3e781d91d1056ea9b3a0395f3017492594a8b86899119b4a1645227c31727b8bec9bc8f6b72e86b1c5cf2dd6690893d2e8c5baff4974c429e616ead089552a21 languageName: node linkType: hard "@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.20.5": - version: 7.20.5 - resolution: "@babel/helper-create-regexp-features-plugin@npm:7.20.5" + version: 7.21.0 + resolution: "@babel/helper-create-regexp-features-plugin@npm:7.21.0" dependencies: "@babel/helper-annotate-as-pure": ^7.18.6 - regexpu-core: ^5.2.1 + regexpu-core: ^5.3.1 peerDependencies: "@babel/core": ^7.0.0 - checksum: 7f29c3cb7447cca047b0d394f8ab98e4923d00e86a7afa56e5df9770c48ec107891505d2d1f06b720ecc94ed24bf58d90986cc35fe4a43b549eb7b7a5077b693 + checksum: 63a6396a4e9444edc7e97617845583ea5cf059573d0b4cc566869f38576d543e37fde0edfcc21d6dfb7962ed241e909561714dc41c5213198bac04e0983b04f2 languageName: node linkType: hard @@ -258,13 +259,13 @@ __metadata: languageName: node linkType: hard -"@babel/helper-function-name@npm:^7.18.9, @babel/helper-function-name@npm:^7.19.0": - version: 7.19.0 - resolution: "@babel/helper-function-name@npm:7.19.0" +"@babel/helper-function-name@npm:^7.18.9, @babel/helper-function-name@npm:^7.19.0, @babel/helper-function-name@npm:^7.21.0": + version: 7.21.0 + resolution: "@babel/helper-function-name@npm:7.21.0" dependencies: - "@babel/template": ^7.18.10 - "@babel/types": ^7.19.0 - checksum: eac1f5db428ba546270c2b8d750c24eb528b8fcfe50c81de2e0bdebf0e20f24bec688d4331533b782e4a907fad435244621ca2193cfcf80a86731299840e0f6e + "@babel/template": ^7.20.7 + "@babel/types": ^7.21.0 + checksum: d63e63c3e0e3e8b3138fa47b0cd321148a300ef12b8ee951196994dcd2a492cc708aeda94c2c53759a5c9177fffaac0fd8778791286746f72a000976968daf4e languageName: node linkType: hard @@ -277,12 +278,12 @@ __metadata: languageName: node linkType: hard -"@babel/helper-member-expression-to-functions@npm:^7.20.7": - version: 7.20.7 - resolution: "@babel/helper-member-expression-to-functions@npm:7.20.7" +"@babel/helper-member-expression-to-functions@npm:^7.20.7, @babel/helper-member-expression-to-functions@npm:^7.21.0": + version: 7.21.0 + resolution: "@babel/helper-member-expression-to-functions@npm:7.21.0" dependencies: - "@babel/types": ^7.20.7 - checksum: cec17aab7e964830b0146e575bd141127032319f26ed864a65b35abd75ad618d264d3e11449b9b4e29cfd95bb1a7e774afddd4884fdcc29c36ac9cbd2b66359f + "@babel/types": ^7.21.0 + checksum: 49cbb865098195fe82ba22da3a8fe630cde30dcd8ebf8ad5f9a24a2b685150c6711419879cf9d99b94dad24cff9244d8c2a890d3d7ec75502cd01fe58cff5b5d languageName: node linkType: hard @@ -295,9 +296,9 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-transforms@npm:^7.18.6, @babel/helper-module-transforms@npm:^7.20.11": - version: 7.20.11 - resolution: "@babel/helper-module-transforms@npm:7.20.11" +"@babel/helper-module-transforms@npm:^7.18.6, @babel/helper-module-transforms@npm:^7.20.11, @babel/helper-module-transforms@npm:^7.21.0, @babel/helper-module-transforms@npm:^7.21.2": + version: 7.21.2 + resolution: "@babel/helper-module-transforms@npm:7.21.2" dependencies: "@babel/helper-environment-visitor": ^7.18.9 "@babel/helper-module-imports": ^7.18.6 @@ -305,9 +306,9 @@ __metadata: "@babel/helper-split-export-declaration": ^7.18.6 "@babel/helper-validator-identifier": ^7.19.1 "@babel/template": ^7.20.7 - "@babel/traverse": ^7.20.10 - "@babel/types": ^7.20.7 - checksum: 29319ebafa693d48756c6ba0d871677bb0037e0da084fbe221a17c38d57093fc8aa38543c07d76e788266a937976e37ab4901971ca7f237c5ab45f524b9ecca0 + "@babel/traverse": ^7.21.2 + "@babel/types": ^7.21.2 + checksum: 8a1c129a4f90bdf97d8b6e7861732c9580f48f877aaaafbc376ce2482febebcb8daaa1de8bc91676d12886487603f8c62a44f9e90ee76d6cac7f9225b26a49e1 languageName: node linkType: hard @@ -396,10 +397,10 @@ __metadata: languageName: node linkType: hard -"@babel/helper-validator-option@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/helper-validator-option@npm:7.18.6" - checksum: f9cc6eb7cc5d759c5abf006402180f8d5e4251e9198197428a97e05d65eb2f8ae5a0ce73b1dfd2d35af41d0eb780627a64edf98a4e71f064eeeacef8de58f2cf +"@babel/helper-validator-option@npm:^7.18.6, @babel/helper-validator-option@npm:^7.21.0": + version: 7.21.0 + resolution: "@babel/helper-validator-option@npm:7.21.0" + checksum: 8ece4c78ffa5461fd8ab6b6e57cc51afad59df08192ed5d84b475af4a7193fc1cb794b59e3e7be64f3cdc4df7ac78bf3dbb20c129d7757ae078e6279ff8c2f07 languageName: node linkType: hard @@ -415,14 +416,14 @@ __metadata: languageName: node linkType: hard -"@babel/helpers@npm:^7.20.7": - version: 7.20.13 - resolution: "@babel/helpers@npm:7.20.13" +"@babel/helpers@npm:^7.21.0": + version: 7.21.0 + resolution: "@babel/helpers@npm:7.21.0" dependencies: "@babel/template": ^7.20.7 - "@babel/traverse": ^7.20.13 - "@babel/types": ^7.20.7 - checksum: d62076fa834f342798f8c3fd7aec0870cc1725d273d99e540cbaa8d6c3ed10258228dd14601c8e66bfeabbb9424c3b31090ecc467fe855f7bd72c4734df7fb09 + "@babel/traverse": ^7.21.0 + "@babel/types": ^7.21.0 + checksum: 9370dad2bb665c551869a08ac87c8bdafad53dbcdce1f5c5d498f51811456a3c005d9857562715151a0f00b2e912ac8d89f56574f837b5689f5f5072221cdf54 languageName: node linkType: hard @@ -437,12 +438,12 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.20.13, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.6.0, @babel/parser@npm:^7.9.6": - version: 7.20.15 - resolution: "@babel/parser@npm:7.20.15" +"@babel/parser@npm:^7.20.7, @babel/parser@npm:^7.21.0, @babel/parser@npm:^7.21.2, @babel/parser@npm:^7.6.0, @babel/parser@npm:^7.9.6": + version: 7.21.2 + resolution: "@babel/parser@npm:7.21.2" bin: parser: ./bin/babel-parser.js - checksum: 1d0f47ca67ff2652f1c0ff1570bed8deccbc4b53509e7cd73476af9cc7ed23480c99f1179bd6d0be01612368b92b39e206d330ad6054009d699934848a89298b + checksum: e2b89de2c63d4cdd2cafeaea34f389bba729727eec7a8728f736bc472a59396059e3e9fe322c9bed8fd126d201fb609712949dc8783f4cae4806acd9a73da6ff languageName: node linkType: hard @@ -497,15 +498,15 @@ __metadata: linkType: hard "@babel/plugin-proposal-class-static-block@npm:^7.18.6": - version: 7.20.7 - resolution: "@babel/plugin-proposal-class-static-block@npm:7.20.7" + version: 7.21.0 + resolution: "@babel/plugin-proposal-class-static-block@npm:7.21.0" dependencies: - "@babel/helper-create-class-features-plugin": ^7.20.7 + "@babel/helper-create-class-features-plugin": ^7.21.0 "@babel/helper-plugin-utils": ^7.20.2 "@babel/plugin-syntax-class-static-block": ^7.14.5 peerDependencies: "@babel/core": ^7.12.0 - checksum: ce1f3e8fd96437d820aa36323b7b3a0cb65b5f2600612665129880d5a4eb7194ce6a298ed2a5a4d3a9ea49bd33089ab95503c4c5b3ba9cea251a07d1706453d9 + checksum: 236c0ad089e7a7acab776cc1d355330193314bfcd62e94e78f2df35817c6144d7e0e0368976778afd6b7c13e70b5068fa84d7abbf967d4f182e60d03f9ef802b languageName: node linkType: hard @@ -609,15 +610,15 @@ __metadata: linkType: hard "@babel/plugin-proposal-optional-chaining@npm:^7.18.9, @babel/plugin-proposal-optional-chaining@npm:^7.20.7": - version: 7.20.7 - resolution: "@babel/plugin-proposal-optional-chaining@npm:7.20.7" + version: 7.21.0 + resolution: "@babel/plugin-proposal-optional-chaining@npm:7.21.0" dependencies: "@babel/helper-plugin-utils": ^7.20.2 "@babel/helper-skip-transparent-expression-wrappers": ^7.20.0 "@babel/plugin-syntax-optional-chaining": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 274b8932335bd064ca24cf1a4da2b2c20c92726d4bfa8b0cb5023857479b8481feef33505c16650c7b9239334e5c6959babc924816324c4cf223dd91c7ca79bc + checksum: 11c5449e01b18bb8881e8e005a577fa7be2fe5688e2382c8822d51f8f7005342a301a46af7b273b1f5645f9a7b894c428eee8526342038a275ef6ba4c8d8d746 languageName: node linkType: hard @@ -634,16 +635,16 @@ __metadata: linkType: hard "@babel/plugin-proposal-private-property-in-object@npm:^7.18.6": - version: 7.20.5 - resolution: "@babel/plugin-proposal-private-property-in-object@npm:7.20.5" + version: 7.21.0 + resolution: "@babel/plugin-proposal-private-property-in-object@npm:7.21.0" dependencies: "@babel/helper-annotate-as-pure": ^7.18.6 - "@babel/helper-create-class-features-plugin": ^7.20.5 + "@babel/helper-create-class-features-plugin": ^7.21.0 "@babel/helper-plugin-utils": ^7.20.2 "@babel/plugin-syntax-private-property-in-object": ^7.14.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 513b5e0e2c1b2846be5336cf680e932ae17924ef885aa1429e1a4f7924724bdd99b15f28d67187d0a006d5f18a0c4b61d96c3ecb4902fed3c8fe2f0abfc9753a + checksum: add881a6a836635c41d2710551fdf777e2c07c0b691bf2baacc5d658dd64107479df1038680d6e67c468bfc6f36fb8920025d6bac2a1df0a81b867537d40ae78 languageName: node linkType: hard @@ -871,24 +872,24 @@ __metadata: linkType: hard "@babel/plugin-transform-block-scoping@npm:^7.20.2": - version: 7.20.15 - resolution: "@babel/plugin-transform-block-scoping@npm:7.20.15" + version: 7.21.0 + resolution: "@babel/plugin-transform-block-scoping@npm:7.21.0" dependencies: "@babel/helper-plugin-utils": ^7.20.2 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 1dddf7be578306837074cb5059f8408af0b1c0bfcf922ed920d4aa65d08fb7c6e6129ca254e9879c4c6d2a6be4937111551f51922e8b0e071ed16eb6564a4dbb + checksum: 15aacaadbecf96b53a750db1be4990b0d89c7f5bc3e1794b63b49fb219638c1fd25d452d15566d7e5ddf5b5f4e1a0a0055c35c1c7aee323c7b114bf49f66f4b0 languageName: node linkType: hard "@babel/plugin-transform-classes@npm:^7.20.2": - version: 7.20.7 - resolution: "@babel/plugin-transform-classes@npm:7.20.7" + version: 7.21.0 + resolution: "@babel/plugin-transform-classes@npm:7.21.0" dependencies: "@babel/helper-annotate-as-pure": ^7.18.6 "@babel/helper-compilation-targets": ^7.20.7 "@babel/helper-environment-visitor": ^7.18.9 - "@babel/helper-function-name": ^7.19.0 + "@babel/helper-function-name": ^7.21.0 "@babel/helper-optimise-call-expression": ^7.18.6 "@babel/helper-plugin-utils": ^7.20.2 "@babel/helper-replace-supers": ^7.20.7 @@ -896,7 +897,7 @@ __metadata: globals: ^11.1.0 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 4cf55ad88e52c7c66a991add4c8e1c3324384bd52df7085962d396879561456a44352e5ab1725cc80f4e83737a2931e847c4a96c7aa4a549357f23631ff31799 + checksum: 088ae152074bd0e90f64659169255bfe50393e637ec8765cb2a518848b11b0299e66b91003728fd0a41563a6fdc6b8d548ece698a314fd5447f5489c22e466b7 languageName: node linkType: hard @@ -959,13 +960,13 @@ __metadata: linkType: hard "@babel/plugin-transform-for-of@npm:^7.18.8": - version: 7.18.8 - resolution: "@babel/plugin-transform-for-of@npm:7.18.8" + version: 7.21.0 + resolution: "@babel/plugin-transform-for-of@npm:7.21.0" dependencies: - "@babel/helper-plugin-utils": ^7.18.6 + "@babel/helper-plugin-utils": ^7.20.2 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: ca64c623cf0c7a80ab6f07ebd3e6e4ade95e2ae806696f70b43eafe6394fa8ce21f2b1ffdd15df2067f7363d2ecfe26472a97c6c774403d2163fa05f50c98f17 + checksum: 2f3f86ca1fab2929fcda6a87e4303d5c635b5f96dc9a45fd4ca083308a3020c79ac33b9543eb4640ef2b79f3586a00ab2d002a7081adb9e9d7440dce30781034 languageName: node linkType: hard @@ -1017,15 +1018,15 @@ __metadata: linkType: hard "@babel/plugin-transform-modules-commonjs@npm:^7.19.6": - version: 7.20.11 - resolution: "@babel/plugin-transform-modules-commonjs@npm:7.20.11" + version: 7.21.2 + resolution: "@babel/plugin-transform-modules-commonjs@npm:7.21.2" dependencies: - "@babel/helper-module-transforms": ^7.20.11 + "@babel/helper-module-transforms": ^7.21.2 "@babel/helper-plugin-utils": ^7.20.2 "@babel/helper-simple-access": ^7.20.2 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: ddd0623e2ad4b5c0faaa0ae30d3407a3fa484d911c968ed33cfb1b339ac3691321c959db60b66dc136dbd67770fff586f7e48a7ce0d7d357f92d6ef6fb7ed1a7 + checksum: 65aa06e3e3792f39b99eb5f807034693ff0ecf80438580f7ae504f4c4448ef04147b1889ea5e6f60f3ad4a12ebbb57c6f1f979a249dadbd8d11fe22f4441918b languageName: node linkType: hard @@ -1191,16 +1192,16 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-typescript@npm:^7.18.6": - version: 7.20.13 - resolution: "@babel/plugin-transform-typescript@npm:7.20.13" +"@babel/plugin-transform-typescript@npm:^7.21.0": + version: 7.21.0 + resolution: "@babel/plugin-transform-typescript@npm:7.21.0" dependencies: - "@babel/helper-create-class-features-plugin": ^7.20.12 + "@babel/helper-create-class-features-plugin": ^7.21.0 "@babel/helper-plugin-utils": ^7.20.2 "@babel/plugin-syntax-typescript": ^7.20.0 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 0b0c3a3e53268d4feb35eb17d57873f2488392e404a0b32735d51c49b08462dc738ebd860f0ff3a3dc5cd1b1fa70340bb6c072239c86afca635831b930593b3b + checksum: 091931118eb515738a4bc8245875f985fc9759d3f85cdf08ee641779b41520241b369404e2bb86fc81907ad827678fdb704e8e5a995352def5dd3051ea2cd870 languageName: node linkType: hard @@ -1327,16 +1328,16 @@ __metadata: languageName: node linkType: hard -"@babel/preset-typescript@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/preset-typescript@npm:7.18.6" +"@babel/preset-typescript@npm:^7.21.0": + version: 7.21.0 + resolution: "@babel/preset-typescript@npm:7.21.0" dependencies: - "@babel/helper-plugin-utils": ^7.18.6 - "@babel/helper-validator-option": ^7.18.6 - "@babel/plugin-transform-typescript": ^7.18.6 + "@babel/helper-plugin-utils": ^7.20.2 + "@babel/helper-validator-option": ^7.21.0 + "@babel/plugin-transform-typescript": ^7.21.0 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 7fe0da5103eb72d3cf39cf3e138a794c8cdd19c0b38e3e101507eef519c46a87a0d6d0e8bc9e28a13ea2364001ebe7430b9d75758aab4c3c3a8db9a487b9dc7c + checksum: 6e1f4d7294de2678fbaf36035e98847b2be432f40fe7a1204e5e45b8b05bcbe22902fe0d726e16af14de5bc08987fae28a7899871503fd661050d85f58755af6 languageName: node linkType: hard @@ -1348,11 +1349,11 @@ __metadata: linkType: hard "@babel/runtime@npm:^7.8.4": - version: 7.20.13 - resolution: "@babel/runtime@npm:7.20.13" + version: 7.21.0 + resolution: "@babel/runtime@npm:7.21.0" dependencies: regenerator-runtime: ^0.13.11 - checksum: 09b7a97a05c80540db6c9e4ddf8c5d2ebb06cae5caf3a87e33c33f27f8c4d49d9c67a2d72f1570e796045288fad569f98a26ceba0c4f5fad2af84b6ad855c4fb + checksum: 7b33e25bfa9e0e1b9e8828bb61b2d32bdd46b41b07ba7cb43319ad08efc6fda8eb89445193e67d6541814627df0ca59122c0ea795e412b99c5183a0540d338ab languageName: node linkType: hard @@ -1367,32 +1368,32 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:^7.20.10, @babel/traverse@npm:^7.20.12, @babel/traverse@npm:^7.20.13, @babel/traverse@npm:^7.20.5, @babel/traverse@npm:^7.20.7": - version: 7.20.13 - resolution: "@babel/traverse@npm:7.20.13" +"@babel/traverse@npm:^7.20.5, @babel/traverse@npm:^7.20.7, @babel/traverse@npm:^7.21.0, @babel/traverse@npm:^7.21.2": + version: 7.21.2 + resolution: "@babel/traverse@npm:7.21.2" dependencies: "@babel/code-frame": ^7.18.6 - "@babel/generator": ^7.20.7 + "@babel/generator": ^7.21.1 "@babel/helper-environment-visitor": ^7.18.9 - "@babel/helper-function-name": ^7.19.0 + "@babel/helper-function-name": ^7.21.0 "@babel/helper-hoist-variables": ^7.18.6 "@babel/helper-split-export-declaration": ^7.18.6 - "@babel/parser": ^7.20.13 - "@babel/types": ^7.20.7 + "@babel/parser": ^7.21.2 + "@babel/types": ^7.21.2 debug: ^4.1.0 globals: ^11.1.0 - checksum: 30ca6e0bd18233fda48fa09315efd14dfc61dcf5b8fa3712b343bfc61b32bc63b5e85ea1773cc9576c9b293b96f46b4589aaeb0a52e1f3eeac4edc076d049fc7 + checksum: d851e3f5cfbdc2fac037a014eae7b0707709de50f7d2fbb82ffbf932d3eeba90a77431529371d6e544f8faaf8c6540eeb18fdd8d1c6fa2b61acea0fb47e18d4b languageName: node linkType: hard -"@babel/types@npm:^7.18.6, @babel/types@npm:^7.18.9, @babel/types@npm:^7.19.0, @babel/types@npm:^7.20.0, @babel/types@npm:^7.20.2, @babel/types@npm:^7.20.5, @babel/types@npm:^7.20.7, @babel/types@npm:^7.4.4, @babel/types@npm:^7.6.1, @babel/types@npm:^7.8.3, @babel/types@npm:^7.9.6": - version: 7.20.7 - resolution: "@babel/types@npm:7.20.7" +"@babel/types@npm:^7.18.6, @babel/types@npm:^7.18.9, @babel/types@npm:^7.20.0, @babel/types@npm:^7.20.2, @babel/types@npm:^7.20.5, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.0, @babel/types@npm:^7.21.2, @babel/types@npm:^7.4.4, @babel/types@npm:^7.6.1, @babel/types@npm:^7.8.3, @babel/types@npm:^7.9.6": + version: 7.21.2 + resolution: "@babel/types@npm:7.21.2" dependencies: "@babel/helper-string-parser": ^7.19.4 "@babel/helper-validator-identifier": ^7.19.1 to-fast-properties: ^2.0.0 - checksum: b39af241f0b72bba67fd6d0d23914f6faec8c0eba8015c181cbd5ea92e59fc91a52a1ab490d3520c7dbd19ddb9ebb76c476308f6388764f16d8201e37fae6811 + checksum: a45a52acde139e575502c6de42c994bdbe262bafcb92ae9381fb54cdf1a3672149086843fda655c7683ce9806e998fd002bbe878fa44984498d0fdc7935ce7ff languageName: node linkType: hard @@ -1406,9 +1407,9 @@ __metadata: linkType: hard "@csstools/css-tokenizer@npm:^2.0.1": - version: 2.0.2 - resolution: "@csstools/css-tokenizer@npm:2.0.2" - checksum: 49bd0a191954b56e9fa50d4a3e2d04059196f04efe398c0cb3c2cbcc18549313d984cd0b8c3faa161d81768256014461d1b4d0f40a67764c9c7a6c0e14a97fea + version: 2.1.0 + resolution: "@csstools/css-tokenizer@npm:2.1.0" + checksum: af3619557e18cd348810cfb41b3b7177b36d216df8dd4cac3979f241c15416baf8cdd55fb764ecc78fab5985b085363cfc8e8b8a18aaa361d00c9b9300b7c0f3 languageName: node linkType: hard @@ -1432,9 +1433,9 @@ __metadata: languageName: node linkType: hard -"@eslint/eslintrc@npm:^1.4.1": - version: 1.4.1 - resolution: "@eslint/eslintrc@npm:1.4.1" +"@eslint/eslintrc@npm:^2.0.0": + version: 2.0.0 + resolution: "@eslint/eslintrc@npm:2.0.0" dependencies: ajv: ^6.12.4 debug: ^4.3.2 @@ -1445,7 +1446,14 @@ __metadata: js-yaml: ^4.1.0 minimatch: ^3.1.2 strip-json-comments: ^3.1.1 - checksum: cd3e5a8683db604739938b1c1c8b77927dc04fce3e28e0c88e7f2cd4900b89466baf83dfbad76b2b9e4d2746abdd00dd3f9da544d3e311633d8693f327d04cd7 + checksum: 31119c8ca06723d80384f18f5c78e0530d8e6306ad36379868650131a8b10dd7cffd7aff79a5deb3a2e9933660823052623d268532bae9538ded53d5b19a69a6 + languageName: node + linkType: hard + +"@eslint/js@npm:8.35.0": + version: 8.35.0 + resolution: "@eslint/js@npm:8.35.0" + checksum: 6687ceff659a6d617e37823f809dc9c4b096535961a81acead27d26b1a51a4cf608a5e59d831ddd57f24f6f8bb99340a4a0e19f9c99b390fbb4b275f51ed5f5e languageName: node linkType: hard @@ -1540,7 +1548,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.9": +"@jridgewell/trace-mapping@npm:^0.3.17, @jridgewell/trace-mapping@npm:^0.3.9": version: 0.3.17 resolution: "@jridgewell/trace-mapping@npm:0.3.17" dependencies: @@ -1797,9 +1805,9 @@ __metadata: linkType: hard "@types/node@npm:^16": - version: 16.18.12 - resolution: "@types/node@npm:16.18.12" - checksum: fc3271182414f8593018ef8f00b4718116a92f463f619081bd399d9460e7861e1dd7eebc7cf94c23567e418ff397babed077011711aae8d47171b5a81c5bd71d + version: 16.18.13 + resolution: "@types/node@npm:16.18.13" + checksum: c284f97a0630d65887be0e0d7ef8e5e5022eb4916ffae142db07f22dad565a80f17b6a84f21b4521c707f642540430710a8aa5930a2cf2bcbecde0a476ff9c02 languageName: node linkType: hard @@ -1831,13 +1839,13 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:^5.52.0": - version: 5.52.0 - resolution: "@typescript-eslint/eslint-plugin@npm:5.52.0" +"@typescript-eslint/eslint-plugin@npm:^5.53.0": + version: 5.53.0 + resolution: "@typescript-eslint/eslint-plugin@npm:5.53.0" dependencies: - "@typescript-eslint/scope-manager": 5.52.0 - "@typescript-eslint/type-utils": 5.52.0 - "@typescript-eslint/utils": 5.52.0 + "@typescript-eslint/scope-manager": 5.53.0 + "@typescript-eslint/type-utils": 5.53.0 + "@typescript-eslint/utils": 5.53.0 debug: ^4.3.4 grapheme-splitter: ^1.0.4 ignore: ^5.2.0 @@ -1851,43 +1859,43 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: cff07ee94d8ab2a1b6c33b5c5bf641eff2bf2bebc0f35a9d8b3f128fd610e27a4aaf620bc2ad23608ad161b1810b7e32e5a2e0f746cc5094c3f506f7a14daa34 + checksum: 12dffe65969d8e5248c86a700fe46a737e55ecafb276933e747b4731eab6266fe55e2d43a34b8b340179fe248e127d861cd016a7614b1b9804cd0687c99616d1 languageName: node linkType: hard -"@typescript-eslint/parser@npm:^5.52.0": - version: 5.52.0 - resolution: "@typescript-eslint/parser@npm:5.52.0" +"@typescript-eslint/parser@npm:^5.53.0": + version: 5.53.0 + resolution: "@typescript-eslint/parser@npm:5.53.0" dependencies: - "@typescript-eslint/scope-manager": 5.52.0 - "@typescript-eslint/types": 5.52.0 - "@typescript-eslint/typescript-estree": 5.52.0 + "@typescript-eslint/scope-manager": 5.53.0 + "@typescript-eslint/types": 5.53.0 + "@typescript-eslint/typescript-estree": 5.53.0 debug: ^4.3.4 peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 1d8ff6e932f9c9db8d24b16ce89fd963f0982c38559e500aa1f8dc5cd66abd02f1659dd1a1361ce550def05331803caa69a69a039b54c94fc0f22919a2305c12 + checksum: 979e5d63793a9e64998b1f956ba0f00f8a2674db3a664fafce7b2433323f5248bd776af8305e2419d73a9d94c55176fee099abc5c153b4cc52e5765c725c1edd languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:5.52.0": - version: 5.52.0 - resolution: "@typescript-eslint/scope-manager@npm:5.52.0" +"@typescript-eslint/scope-manager@npm:5.53.0": + version: 5.53.0 + resolution: "@typescript-eslint/scope-manager@npm:5.53.0" dependencies: - "@typescript-eslint/types": 5.52.0 - "@typescript-eslint/visitor-keys": 5.52.0 - checksum: 9a03fe30f8e90a5106c482478f213eefdd09f2f74e24d9dc59b453885466a758fe6d1cd24d706aed6188fb03c84b16ca6491cf20da6b16b8fc53cad8b8c327f2 + "@typescript-eslint/types": 5.53.0 + "@typescript-eslint/visitor-keys": 5.53.0 + checksum: 51f31dc01e95908611f402441f58404da80a338c0237b2b82f4a7b0b2e8868c4bfe8f7cf44b2567dd56533de609156a5d4ac54bb1f9f09c7014b99428aef2543 languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:5.52.0": - version: 5.52.0 - resolution: "@typescript-eslint/type-utils@npm:5.52.0" +"@typescript-eslint/type-utils@npm:5.53.0": + version: 5.53.0 + resolution: "@typescript-eslint/type-utils@npm:5.53.0" dependencies: - "@typescript-eslint/typescript-estree": 5.52.0 - "@typescript-eslint/utils": 5.52.0 + "@typescript-eslint/typescript-estree": 5.53.0 + "@typescript-eslint/utils": 5.53.0 debug: ^4.3.4 tsutils: ^3.21.0 peerDependencies: @@ -1895,23 +1903,23 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: ac5422040461febab8a2eeec76d969024ccff76203dec357f7220c9b5e0dde96e3e3a76fd4118d42b50bd5bfb3a194aaceeb63417a2ac4e1ebf5e687558a9a10 + checksum: 52c40967c5fabd58c2ae8bf519ef89e4feb511e4df630aeaeac8335661a79b6b3a32d30a61a5f1d8acc703f21c4d90751a5d41cda1b35d08867524da11bc2e1d languageName: node linkType: hard -"@typescript-eslint/types@npm:5.52.0": - version: 5.52.0 - resolution: "@typescript-eslint/types@npm:5.52.0" - checksum: 018940d61aebf7cf3f7de1b9957446e2ea01f08fe950bef4788c716a3a88f7c42765fe7d80152b0d0428fcd4bd3ace2dfa8c459ba1c59d9a84e951642180f869 +"@typescript-eslint/types@npm:5.53.0": + version: 5.53.0 + resolution: "@typescript-eslint/types@npm:5.53.0" + checksum: b0eaf23de4ab13697d4d2095838c959a3f410c30f0d19091e5ca08e62320c3cc3c72bcb631823fb6a4fbb31db0a059e386a0801244930d0a88a6a698e5f46548 languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:5.52.0": - version: 5.52.0 - resolution: "@typescript-eslint/typescript-estree@npm:5.52.0" +"@typescript-eslint/typescript-estree@npm:5.53.0": + version: 5.53.0 + resolution: "@typescript-eslint/typescript-estree@npm:5.53.0" dependencies: - "@typescript-eslint/types": 5.52.0 - "@typescript-eslint/visitor-keys": 5.52.0 + "@typescript-eslint/types": 5.53.0 + "@typescript-eslint/visitor-keys": 5.53.0 debug: ^4.3.4 globby: ^11.1.0 is-glob: ^4.0.3 @@ -1920,35 +1928,35 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 67d396907fee3d6894e26411a5098a37f07e5d50343189e6361ff7db91c74a7ffe2abd630d11f14c2bda1f4af13edf52b80b11cbccb55b44079c7cec14c9e108 + checksum: 6e119c8e4167c8495d728c5556a834545a9c064918dd5e7b79b0d836726f4f8e2a0297b0ac82bf2b71f1e5427552217d0b59d8fb1406fd79bd3bf91b75dca873 languageName: node linkType: hard -"@typescript-eslint/utils@npm:5.52.0": - version: 5.52.0 - resolution: "@typescript-eslint/utils@npm:5.52.0" +"@typescript-eslint/utils@npm:5.53.0": + version: 5.53.0 + resolution: "@typescript-eslint/utils@npm:5.53.0" dependencies: "@types/json-schema": ^7.0.9 "@types/semver": ^7.3.12 - "@typescript-eslint/scope-manager": 5.52.0 - "@typescript-eslint/types": 5.52.0 - "@typescript-eslint/typescript-estree": 5.52.0 + "@typescript-eslint/scope-manager": 5.53.0 + "@typescript-eslint/types": 5.53.0 + "@typescript-eslint/typescript-estree": 5.53.0 eslint-scope: ^5.1.1 eslint-utils: ^3.0.0 semver: ^7.3.7 peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: 01906be5262ece36537e9d586e4d2d4791e05752a9354bcb42b1f5bf965f53daa13309c61c3dff5e201ea28c298e4e01cf0c93738afa0099fea0da3b1d8cb3a5 + checksum: 18e6bac14ae853385a74123759850bca367904723e170c37416fc014673eb714afb6bb090367bff61494a8387e941b6af65ee5f4f845f7177fabb4df85e01643 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:5.52.0": - version: 5.52.0 - resolution: "@typescript-eslint/visitor-keys@npm:5.52.0" +"@typescript-eslint/visitor-keys@npm:5.53.0": + version: 5.53.0 + resolution: "@typescript-eslint/visitor-keys@npm:5.53.0" dependencies: - "@typescript-eslint/types": 5.52.0 + "@typescript-eslint/types": 5.53.0 eslint-visitor-keys: ^3.3.0 - checksum: 33b44f0cd35b7b47f34e89d52e47b8d8200f55af306b22db4de104d79f65907458ea022e548f50d966e32fea150432ac9c1ae65b3001b0ad2ac8a17c0211f370 + checksum: 090695883c15364c6f401e97f56b13db0f31c1114f3bd22562bd41734864d27f6a3c80de33957e9dedab2d5f94b0f4480ba3fde1d4574e74dca4593917b7b54a languageName: node linkType: hard @@ -2478,9 +2486,9 @@ __metadata: linkType: hard "caniuse-lite@npm:^1.0.30001449": - version: 1.0.30001457 - resolution: "caniuse-lite@npm:1.0.30001457" - checksum: f311a7c5098681962402a86a0a367014ee91c3135395ee68bbfaf45caf0e36d581e42d7c5b1526ce99484a228e6cf5cf0e400678292c65f5a21512a3fc7a5fb6 + version: 1.0.30001458 + resolution: "caniuse-lite@npm:1.0.30001458" + checksum: 258cc5a25babbbfe483bf788c6f321a19400ff80b2bf156b360bac09a6f9f4da44516350d187a30395667cb142c682d9ea96577ea0df236d35f76234b07ccb41 languageName: node linkType: hard @@ -2671,23 +2679,23 @@ __metadata: linkType: hard "core-js-compat@npm:^3.25.1": - version: 3.28.0 - resolution: "core-js-compat@npm:3.28.0" + version: 3.29.0 + resolution: "core-js-compat@npm:3.29.0" dependencies: browserslist: ^4.21.5 - checksum: 41d1d58c99ce7ee7abd8cf070f4c07a8f2655dbed1777d90a26246dddd7fac68315d53d2192584c8621a5328e6fe1a10da39b6bf2666e90fd5c2ff3b8f24e874 + checksum: ca5d370296c15ebd5f961dae6b6a24a153a84937bff58543099b7f1c407e8d5bbafafa7ca27e65baad522ece762d6356e1d6ea9efa99815f6fefd150fac7e8a5 languageName: node linkType: hard "cosmiconfig@npm:^8.0.0": - version: 8.0.0 - resolution: "cosmiconfig@npm:8.0.0" + version: 8.1.0 + resolution: "cosmiconfig@npm:8.1.0" dependencies: import-fresh: ^3.2.1 js-yaml: ^4.1.0 parse-json: ^5.0.0 path-type: ^4.0.0 - checksum: ff4cdf89ac1ae52e7520816622c21a9e04380d04b82d653f5139ec581aa4f7f29e096d46770bc76c4a63c225367e88a1dfa233ea791669a35101f5f9b972c7d1 + checksum: 78a1846acc4935ab4d928e3f768ee2ad2fddbec96377935462749206568423ff4757140ac7f2ccd1f547f86309b8448c04b26588848b5a1520f2e9741cdeecf0 languageName: node linkType: hard @@ -3030,9 +3038,9 @@ __metadata: linkType: hard "electron-to-chromium@npm:^1.4.284": - version: 1.4.302 - resolution: "electron-to-chromium@npm:1.4.302" - checksum: aa764494f9a5b6916ba9f311c0204b2c73449addba18cc55d43e84e8c4465732af9cd6560a8efeb32f3c5a928299030e41352e5b3a081e9e56b086d5be618f45 + version: 1.4.311 + resolution: "electron-to-chromium@npm:1.4.311" + checksum: 663fde5d90293d19c05b0dc65996e1ba6f3ee89d6365de3503de6a96c21439e18ea579fdd7d718e260708aa871ef333de934a4024d54fd109959ac0bca9d1400 languageName: node linkType: hard @@ -3379,11 +3387,12 @@ __metadata: languageName: node linkType: hard -"eslint@npm:^8.34.0": - version: 8.34.0 - resolution: "eslint@npm:8.34.0" +"eslint@npm:^8.35.0": + version: 8.35.0 + resolution: "eslint@npm:8.35.0" dependencies: - "@eslint/eslintrc": ^1.4.1 + "@eslint/eslintrc": ^2.0.0 + "@eslint/js": 8.35.0 "@humanwhocodes/config-array": ^0.11.8 "@humanwhocodes/module-importer": ^1.0.1 "@nodelib/fs.walk": ^1.2.8 @@ -3397,7 +3406,7 @@ __metadata: eslint-utils: ^3.0.0 eslint-visitor-keys: ^3.3.0 espree: ^9.4.0 - esquery: ^1.4.0 + esquery: ^1.4.2 esutils: ^2.0.2 fast-deep-equal: ^3.1.3 file-entry-cache: ^6.0.1 @@ -3424,7 +3433,7 @@ __metadata: text-table: ^0.2.0 bin: eslint: bin/eslint.js - checksum: 4e13e9eb05ac2248efbb6acae0b2325091235d5c47ba91a4775c7d6760778cbcd358a773ebd42f4629d2ad89e27c02f5d66eb1f737d75d9f5fc411454f83b2e5 + checksum: 6212173691d90b1bc94dd3d640e1f210374b30c3905fc0a15e501cf71c6ca52aa3d80ea7a9a245adaaed26d6019169e01fb6881b3f2885b188d37069c749308c languageName: node linkType: hard @@ -3449,7 +3458,7 @@ __metadata: languageName: node linkType: hard -"esquery@npm:^1.4.0": +"esquery@npm:^1.4.2": version: 1.4.2 resolution: "esquery@npm:1.4.2" dependencies: @@ -4720,7 +4729,7 @@ __metadata: languageName: node linkType: hard -"json5@npm:^1.0.1": +"json5@npm:^1.0.2": version: 1.0.2 resolution: "json5@npm:1.0.2" dependencies: @@ -4832,14 +4841,14 @@ __metadata: linkType: hard "liquidjs@npm:^10.4.0": - version: 10.5.0 - resolution: "liquidjs@npm:10.5.0" + version: 10.6.0 + resolution: "liquidjs@npm:10.6.0" dependencies: commander: ^10.0.0 bin: liquid: bin/liquid.js liquidjs: bin/liquid.js - checksum: c450f81e111f2a7bac94867e8fdee9504d781329573fb36f98acc2c48bc969b544a5655647243b1d0f0bdfb244bd5ca9f5d8caaa0fa6ce6452fd4fb6e2788d5c + checksum: ee0858847d9e32b00de5ed840a6b13b0eea83af6032cca7fd853e2f2ff250199856f62167adb1e9ec7484ad40df8c4b9f9f795183723e75af371c28550ad1b49 languageName: node linkType: hard @@ -4966,9 +4975,9 @@ __metadata: linkType: hard "lru-cache@npm:^7.7.1": - version: 7.16.1 - resolution: "lru-cache@npm:7.16.1" - checksum: 64618e3ed4fd1203afedd9bbf5247921b1419f8e3100f20e58e5f04e741f8287bd7d04fefaad332411bb53b3a73445714b235de750cf5d310cba1fa23bd82795 + version: 7.17.0 + resolution: "lru-cache@npm:7.17.0" + checksum: 28c2a98ad313b8d61beac1f08257b6f0ca990e39d24a9bc831030b6e209447cfb11c6d9d1a774282189bfc9609d1dfd17ebe485228dd68f7b96b6b9b7740894e languageName: node linkType: hard @@ -5184,12 +5193,12 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^6.1.6": - version: 6.2.0 - resolution: "minimatch@npm:6.2.0" +"minimatch@npm:^7.1.3": + version: 7.2.0 + resolution: "minimatch@npm:7.2.0" dependencies: brace-expansion: ^2.0.1 - checksum: 0ffb77d05bd483fcc344ba3e64a501d569e658fa6c592d94e9716ffc7925de7a8c2ac294cafa822b160bd8b2cbf7e01012917e06ffb9a85cfa9604629b3f2c04 + checksum: f3c66f60e097fb9e1550a1b6ce5d8588d3cdfdb22c1bde9a293bd99e7a01833be2b975795299b50b9456542b239b2f0ba5edba71728ec644e5ca14d09d0cf620 languageName: node linkType: hard @@ -5272,9 +5281,9 @@ __metadata: linkType: hard "minipass@npm:^4.0.0": - version: 4.0.3 - resolution: "minipass@npm:4.0.3" - checksum: a09f405e2f380ae7f6ee0cbb53b45c1fcc1b6c70fc3896f4d20649d92a10e61892c57bd9960a64cedf6c90b50022cb6c195905b515039c335b423202f99e6f18 + version: 4.2.4 + resolution: "minipass@npm:4.2.4" + checksum: c664f2ae4401408d1e7a6e4f50aca45f87b1b0634bc9261136df5c378e313e77355765f73f59c4a5abcadcdf43d83fcd3eb14e4a7cdcce8e36508e2290345753 languageName: node linkType: hard @@ -5625,13 +5634,13 @@ __metadata: linkType: hard "open@npm:^8.4.0": - version: 8.4.1 - resolution: "open@npm:8.4.1" + version: 8.4.2 + resolution: "open@npm:8.4.2" dependencies: define-lazy-prop: ^2.0.0 is-docker: ^2.1.1 is-wsl: ^2.2.0 - checksum: dbe8e1d98889df60b5179eab8b94b9591744d1f0033bce1a9a10738ba140bd9d625d6bcde7ff9f043e379aafb918975c2daa03b87cef13eb046ac18ed807f06d + checksum: 6388bfff21b40cb9bd8f913f9130d107f2ed4724ea81a8fd29798ee322b361ca31fa2cdfb491a5c31e43a3996cfe9566741238c7a741ada8d7af1cb78d85cf26 languageName: node linkType: hard @@ -6207,13 +6216,13 @@ __metadata: linkType: hard "readable-stream@npm:^3.6.0": - version: 3.6.0 - resolution: "readable-stream@npm:3.6.0" + version: 3.6.1 + resolution: "readable-stream@npm:3.6.1" dependencies: inherits: ^2.0.3 string_decoder: ^1.1.1 util-deprecate: ^1.0.1 - checksum: d4ea81502d3799439bb955a3a5d1d808592cf3133350ed352aeaa499647858b27b1c4013984900238b0873ec8d0d8defce72469fb7a83e61d53f5ad61cb80dc8 + checksum: b7ab0508dba3c37277b9e43c0a970ea27635375698859a687f558c3c9393154b6c4f39c3aa5689641de183fffa26771bc1a45878ddde0236ad18fc8fdfde50ea languageName: node linkType: hard @@ -6303,7 +6312,7 @@ __metadata: languageName: node linkType: hard -"regexpu-core@npm:^5.2.1": +"regexpu-core@npm:^5.3.1": version: 5.3.1 resolution: "regexpu-core@npm:5.3.1" dependencies: @@ -6411,9 +6420,9 @@ __metadata: languageName: node linkType: hard -"rollup@npm:^3.17.2": - version: 3.17.2 - resolution: "rollup@npm:3.17.2" +"rollup@npm:^3.17.3": + version: 3.17.3 + resolution: "rollup@npm:3.17.3" dependencies: fsevents: ~2.3.2 dependenciesMeta: @@ -6421,7 +6430,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: 9473eb7e7ffdb74c8e01e813eccb2e81e86cd429aea4705c424a5369845bedd871e715347a53be04a157f8febb99a8e502c124b896141e06d94fb86d6e121721 + checksum: afce20a6ef4a613e5803eff7fb17a3efe740e326257b43f48bdbe10783f3eae79587d7e455234bc68f3c3154a50f2c29c85d4d2a42cdebcc17a5abeaeb04e0ed languageName: node linkType: hard @@ -6465,9 +6474,9 @@ __metadata: dependencies: "@11ty/eleventy": ^2.0.0 "@11ty/eleventy-plugin-syntaxhighlight": ^4.2.0 - "@babel/core": ^7.20.12 + "@babel/core": ^7.21.0 "@babel/preset-env": ^7.20.2 - "@babel/preset-typescript": ^7.18.6 + "@babel/preset-typescript": ^7.21.0 "@rollup/plugin-babel": ^6.0.3 "@rollup/plugin-commonjs": ^24.0.1 "@rollup/plugin-inject": ^5.0.3 @@ -6476,11 +6485,11 @@ __metadata: "@types/jquery": ^3.5.16 "@types/jqueryui": ^1.12.16 "@types/node": ^16 - "@typescript-eslint/eslint-plugin": ^5.52.0 - "@typescript-eslint/parser": ^5.52.0 + "@typescript-eslint/eslint-plugin": ^5.53.0 + "@typescript-eslint/parser": ^5.53.0 date-fns: ^2.29.3 deep-equal: ^2.2.0 - eslint: ^8.34.0 + eslint: ^8.35.0 eslint-config-prettier: ^8.6.0 eslint-import-resolver-typescript: ^3.5.3 eslint-plugin-import: ^2.27.5 @@ -6496,12 +6505,12 @@ __metadata: netlify-plugin-11ty: ^1.3.0 npm-run-all: ^4.1.5 prettier: ^2.8.4 - rollup: ^3.17.2 + rollup: ^3.17.3 sass: ^1.58.3 semver-parser: ^4.1.2 stylelint: ^15.2.0 stylelint-config-standard-scss: ^7.0.1 - typedoc: ^0.23.25 + typedoc: ^0.23.26 typescript: ^4.9.5 typogr: ^0.6.8 languageName: unknown @@ -7137,8 +7146,8 @@ __metadata: linkType: hard "terser@npm:^5.15.1": - version: 5.16.4 - resolution: "terser@npm:5.16.4" + version: 5.16.5 + resolution: "terser@npm:5.16.5" dependencies: "@jridgewell/source-map": ^0.3.2 acorn: ^8.5.0 @@ -7146,7 +7155,7 @@ __metadata: source-map-support: ~0.5.20 bin: terser: bin/terser - checksum: 92c7b38b7322340993d6a3578d74818c3556f362b3014f18a9b3d079ac7fa5da57954fda9a0d40d53013bc3ba82f50758296881abc40761e1bafdbde9a2ab967 + checksum: f2c1a087fac7f4ff04b1b4e79bffc52e2fc0b068b98912bfcc0b341184c284c30c19ed73f76ac92b225b71668f7f8fc586d99a7e50a29cdc1c916cb1265522ec languageName: node linkType: hard @@ -7198,14 +7207,14 @@ __metadata: linkType: hard "tsconfig-paths@npm:^3.14.1": - version: 3.14.1 - resolution: "tsconfig-paths@npm:3.14.1" + version: 3.14.2 + resolution: "tsconfig-paths@npm:3.14.2" dependencies: "@types/json5": ^0.0.29 - json5: ^1.0.1 + json5: ^1.0.2 minimist: ^1.2.6 strip-bom: ^3.0.0 - checksum: 8afa01c673ebb4782ba53d3a12df97fa837ce524f8ad38ee4e2b2fd57f5ac79abc21c574e9e9eb014d93efe7fe8214001b96233b5c6ea75bd1ea82afe17a4c6d + checksum: a6162eaa1aed680537f93621b82399c7856afd10ec299867b13a0675e981acac4e0ec00896860480efc59fc10fd0b16fdc928c0b885865b52be62cadac692447 languageName: node linkType: hard @@ -7275,19 +7284,19 @@ __metadata: languageName: node linkType: hard -"typedoc@npm:^0.23.25": - version: 0.23.25 - resolution: "typedoc@npm:0.23.25" +"typedoc@npm:^0.23.26": + version: 0.23.26 + resolution: "typedoc@npm:0.23.26" dependencies: lunr: ^2.3.9 marked: ^4.2.12 - minimatch: ^6.1.6 + minimatch: ^7.1.3 shiki: ^0.14.1 peerDependencies: typescript: 4.6.x || 4.7.x || 4.8.x || 4.9.x bin: typedoc: bin/typedoc - checksum: 2089d6da0293e63f6d3fac9460e9427fb6bfd56ddf669f2f13bef9435aa69ca7e72a8754e8951788db69432356e419c48b811105c8a74a47cab1f92a0bdad75b + checksum: 09dbd221b5bd27a7f6c593a6aa7e4efc3c46f20761e109a76bf0ed7239011cca1261357094710c01472582060d75a7558aab5bf5b78db3aff7c52188d146ee65 languageName: node linkType: hard From 512e5e210950018e5f2b31eaa391cedbd9e67933 Mon Sep 17 00:00:00 2001 From: oluniyiawo Date: Wed, 1 Mar 2023 19:46:05 +0000 Subject: [PATCH 14/42] components all working, need author and date subtitle --- old_source/blog/001-how-extend-works.html.md | 2 +- .../002-a-change-in-plans-for-sass-33.html.md | 2 +- .../blog/003-sass-33-is-released.html.md | 2 +- .../blog/004-sass-34-is-released.html.md | 2 +- .../005-cleaning-up-interpolation.html.md | 2 +- ...ping-support-for-old-ruby-versions.html.md | 2 +- old_source/blog/007-thank-you-marcel.html.md | 2 +- .../008-sass-35-release-candidate.html.md | 2 +- .../blog/009-announcing-dart-sass.html.md | 2 +- .../010-dart-sass-is-on-chocolatey.html.md | 2 +- ...011-sass-and-browser-compatibility.html.md | 2 +- .../blog/012-dart-sass-is-in-beta.html.md | 2 +- .../blog/013-sass-35-is-released.html.md | 2 +- .../014-dart-sass-100-is-released.html.md | 2 +- .../blog/015-ruby-sass-is-deprecated.html.md | 2 +- ...st-for-commentsimporting-css-files.html.md | 2 +- ...hcss-imports-and-css-compatibility.html.md | 2 +- ...tent-arguments-and-color-functions.html.md | 2 +- ...or-comments-module-system-proposal.html.md | 2 +- .../blog/020-ruby-sass-is-unsupported.html.md | 2 +- .../blog/021-brand-new-sass-docs.html.md | 2 +- ...commentsforward-slash-as-separator.html.md | 2 +- .../blog/023-module-system-preview.html.md | 2 +- .../024-the-module-system-is-launched.html.md | 2 +- ...quest-for-comments-nested-map-functions.md | 2 +- .../026-request-for-comments-hwb-functions.md | 2 +- old_source/blog/027-libsass-is-deprecated.md | 2 +- ...8-request-for-comments-first-class-calc.md | 2 +- .../blog/029-node-fibers-discontinued.md | 2 +- ...30-request-for-comments-new-js-api.html.md | 2 +- .../031-new-js-api-release-candidate.html.md | 2 +- old_source/blog/032-embedded-sass-is-live.md | 2 +- ...est-for-comments-strict-unary-operators.md | 2 +- .../034-request-for-comments-color-spaces.md | 2 +- .../035-security-alert-tar-permissions.md | 2 +- source/_layouts/blog.liquid | 5 + source/blog.liquid | 33 + source/blog/001-how-extend-works.html.md | 206 +++++ .../002-a-change-in-plans-for-sass-33.html.md | 126 +++ source/blog/003-sass-33-is-released.html.md | 164 ++++ source/blog/004-sass-34-is-released.html.md | 91 ++ .../005-cleaning-up-interpolation.html.md | 154 ++++ ...ping-support-for-old-ruby-versions.html.md | 60 ++ source/blog/007-thank-you-marcel.html.md | 32 + .../008-sass-35-release-candidate.html.md | 155 ++++ source/blog/009-announcing-dart-sass.html.md | 178 ++++ .../010-dart-sass-is-on-chocolatey.html.md | 47 + ...011-sass-and-browser-compatibility.html.md | 53 ++ source/blog/012-dart-sass-is-in-beta.html.md | 73 ++ source/blog/013-sass-35-is-released.html.md | 99 +++ .../014-dart-sass-100-is-released.html.md | 96 +++ .../blog/015-ruby-sass-is-deprecated.html.md | 100 +++ ...st-for-commentsimporting-css-files.html.md | 103 +++ ...hcss-imports-and-css-compatibility.html.md | 116 +++ ...tent-arguments-and-color-functions.html.md | 136 +++ ...or-comments-module-system-proposal.html.md | 402 +++++++++ .../blog/020-ruby-sass-is-unsupported.html.md | 58 ++ source/blog/021-brand-new-sass-docs.html.md | 34 + ...commentsforward-slash-as-separator.html.md | 84 ++ source/blog/023-module-system-preview.html.md | 52 ++ .../024-the-module-system-is-launched.html.md | 362 ++++++++ ...quest-for-comments-nested-map-functions.md | 141 +++ .../026-request-for-comments-hwb-functions.md | 67 ++ source/blog/027-libsass-is-deprecated.md | 136 +++ ...8-request-for-comments-first-class-calc.md | 78 ++ source/blog/029-node-fibers-discontinued.md | 161 ++++ ...30-request-for-comments-new-js-api.html.md | 801 ++++++++++++++++++ .../031-new-js-api-release-candidate.html.md | 56 ++ source/blog/032-embedded-sass-is-live.md | 77 ++ ...est-for-comments-strict-unary-operators.md | 88 ++ .../034-request-for-comments-color-spaces.md | 264 ++++++ .../035-security-alert-tar-permissions.md | 118 +++ 72 files changed, 5041 insertions(+), 35 deletions(-) create mode 100644 source/_layouts/blog.liquid create mode 100644 source/blog.liquid create mode 100644 source/blog/001-how-extend-works.html.md create mode 100644 source/blog/002-a-change-in-plans-for-sass-33.html.md create mode 100644 source/blog/003-sass-33-is-released.html.md create mode 100644 source/blog/004-sass-34-is-released.html.md create mode 100644 source/blog/005-cleaning-up-interpolation.html.md create mode 100644 source/blog/006-dropping-support-for-old-ruby-versions.html.md create mode 100644 source/blog/007-thank-you-marcel.html.md create mode 100644 source/blog/008-sass-35-release-candidate.html.md create mode 100644 source/blog/009-announcing-dart-sass.html.md create mode 100644 source/blog/010-dart-sass-is-on-chocolatey.html.md create mode 100644 source/blog/011-sass-and-browser-compatibility.html.md create mode 100644 source/blog/012-dart-sass-is-in-beta.html.md create mode 100644 source/blog/013-sass-35-is-released.html.md create mode 100644 source/blog/014-dart-sass-100-is-released.html.md create mode 100644 source/blog/015-ruby-sass-is-deprecated.html.md create mode 100644 source/blog/016-request-for-commentsimporting-css-files.html.md create mode 100644 source/blog/017-feature-watchcss-imports-and-css-compatibility.html.md create mode 100644 source/blog/018-feature-watchcontent-arguments-and-color-functions.html.md create mode 100644 source/blog/019-request-for-comments-module-system-proposal.html.md create mode 100644 source/blog/020-ruby-sass-is-unsupported.html.md create mode 100644 source/blog/021-brand-new-sass-docs.html.md create mode 100644 source/blog/022-request-for-commentsforward-slash-as-separator.html.md create mode 100644 source/blog/023-module-system-preview.html.md create mode 100644 source/blog/024-the-module-system-is-launched.html.md create mode 100644 source/blog/025-request-for-comments-nested-map-functions.md create mode 100644 source/blog/026-request-for-comments-hwb-functions.md create mode 100644 source/blog/027-libsass-is-deprecated.md create mode 100644 source/blog/028-request-for-comments-first-class-calc.md create mode 100644 source/blog/029-node-fibers-discontinued.md create mode 100644 source/blog/030-request-for-comments-new-js-api.html.md create mode 100644 source/blog/031-new-js-api-release-candidate.html.md create mode 100644 source/blog/032-embedded-sass-is-live.md create mode 100644 source/blog/033-request-for-comments-strict-unary-operators.md create mode 100644 source/blog/034-request-for-comments-color-spaces.md create mode 100644 source/blog/035-security-alert-tar-permissions.md diff --git a/old_source/blog/001-how-extend-works.html.md b/old_source/blog/001-how-extend-works.html.md index 4e8b5692e..e3159d6bb 100644 --- a/old_source/blog/001-how-extend-works.html.md +++ b/old_source/blog/001-how-extend-works.html.md @@ -1,7 +1,7 @@ --- title: How @extend Works author: Natalie Weizenbaum -date: 2013-11-22 16:57 PST +# date: 2013-11-22 16:57 PST --- _This was originally published as [a gist](https://gist.github.com/nex3/7609394)_. diff --git a/old_source/blog/002-a-change-in-plans-for-sass-33.html.md b/old_source/blog/002-a-change-in-plans-for-sass-33.html.md index 12ff26e3d..78b6f1d98 100644 --- a/old_source/blog/002-a-change-in-plans-for-sass-33.html.md +++ b/old_source/blog/002-a-change-in-plans-for-sass-33.html.md @@ -1,7 +1,7 @@ --- title: A Change in Plans for Sass 3.3 author: Natalie Weizenbaum -date: 2013-12-19 20:05 PST +# date: 2013-12-19 20:05 PST --- _This was originally published as [a gist](https://gist.github.com/nex3/8050187)._ diff --git a/old_source/blog/003-sass-33-is-released.html.md b/old_source/blog/003-sass-33-is-released.html.md index 83e609a08..c21189944 100644 --- a/old_source/blog/003-sass-33-is-released.html.md +++ b/old_source/blog/003-sass-33-is-released.html.md @@ -1,7 +1,7 @@ --- title: Sass 3.3 is Released author: Natalie Weizenbaum -date: 2014-03-07 16:40 PST +# date: 2014-03-07 16:40 PST --- After ironing out a bunch of bugs in numerous release candidates, we're finally diff --git a/old_source/blog/004-sass-34-is-released.html.md b/old_source/blog/004-sass-34-is-released.html.md index c30a49a8c..a2253542d 100644 --- a/old_source/blog/004-sass-34-is-released.html.md +++ b/old_source/blog/004-sass-34-is-released.html.md @@ -1,7 +1,7 @@ --- title: Sass 3.4 is Released author: Natalie Weizenbaum -date: 2014-08-18 16:38 PST +# date: 2014-08-18 16:38 PST --- We've been trying to increase the pace of Sass releases, and it looks like we've diff --git a/old_source/blog/005-cleaning-up-interpolation.html.md b/old_source/blog/005-cleaning-up-interpolation.html.md index 69a55bf29..bee84726b 100644 --- a/old_source/blog/005-cleaning-up-interpolation.html.md +++ b/old_source/blog/005-cleaning-up-interpolation.html.md @@ -1,7 +1,7 @@ --- title: Cleaning Up Interpolation author: Natalie Weizenbaum -date: 2015-12-09 15:20 PST +# date: 2015-12-09 15:20 PST --- Interpolation—the ability to add variables and other snippets using `#{...}`—is diff --git a/old_source/blog/006-dropping-support-for-old-ruby-versions.html.md b/old_source/blog/006-dropping-support-for-old-ruby-versions.html.md index 114b6bbfb..16d469f84 100644 --- a/old_source/blog/006-dropping-support-for-old-ruby-versions.html.md +++ b/old_source/blog/006-dropping-support-for-old-ruby-versions.html.md @@ -1,7 +1,7 @@ --- title: Dropping Support For Old Ruby Versions author: Natalie Weizenbaum -date: 2016-02-29 14:25 PST +# date: 2016-02-29 14:25 PST --- As of version 3.5, Ruby Sass will drop support for Ruby 1.8.7 and Ruby 1.9.3. We diff --git a/old_source/blog/007-thank-you-marcel.html.md b/old_source/blog/007-thank-you-marcel.html.md index 40fdf4c3c..d336cf144 100644 --- a/old_source/blog/007-thank-you-marcel.html.md +++ b/old_source/blog/007-thank-you-marcel.html.md @@ -1,7 +1,7 @@ --- title: Dropping Support For Old Ruby Versions author: Natalie Weizenbaum -date: 2016-05-24 14:41 PST +# date: 2016-05-24 14:41 PST --- You may not know [Marcel Greter](https://github.com/mgreter), but you almost diff --git a/old_source/blog/008-sass-35-release-candidate.html.md b/old_source/blog/008-sass-35-release-candidate.html.md index ccee5c2ec..851585d65 100644 --- a/old_source/blog/008-sass-35-release-candidate.html.md +++ b/old_source/blog/008-sass-35-release-candidate.html.md @@ -1,7 +1,7 @@ --- title: Sass 3.5 Release Candidate author: Natalie Weizenbaum -date: 2016-08-30 15:00 PST +# date: 2016-08-30 15:00 PST --- I've just pushed the button to release Sass 3.5.0-rc.1. If it seems like it's diff --git a/old_source/blog/009-announcing-dart-sass.html.md b/old_source/blog/009-announcing-dart-sass.html.md index 7a9b541b5..2725a9b8e 100644 --- a/old_source/blog/009-announcing-dart-sass.html.md +++ b/old_source/blog/009-announcing-dart-sass.html.md @@ -1,7 +1,7 @@ --- title: Announcing Dart Sass author: Natalie Weizenbaum -date: 2016-10-31 13:28 PST +# date: 2016-10-31 13:28 PST --- Over the past few months, I've been quietly working on a new project. Today I'm diff --git a/old_source/blog/010-dart-sass-is-on-chocolatey.html.md b/old_source/blog/010-dart-sass-is-on-chocolatey.html.md index 6bf1852b9..9a419e8d0 100644 --- a/old_source/blog/010-dart-sass-is-on-chocolatey.html.md +++ b/old_source/blog/010-dart-sass-is-on-chocolatey.html.md @@ -1,7 +1,7 @@ --- title: Dart Sass is On Chocolatey author: Natalie Weizenbaum -date: 2017-01-13 14:43 PST +# date: 2017-01-13 14:43 PST --- One of the quieter benefits of [moving to Dart](/blog/announcing-dart-sass) is diff --git a/old_source/blog/011-sass-and-browser-compatibility.html.md b/old_source/blog/011-sass-and-browser-compatibility.html.md index 2114116d4..5d5e4fd4d 100644 --- a/old_source/blog/011-sass-and-browser-compatibility.html.md +++ b/old_source/blog/011-sass-and-browser-compatibility.html.md @@ -1,7 +1,7 @@ --- title: Sass and Browser Compatibility author: Natalie Weizenbaum -date: 2017-02-10 17:46 PST +# date: 2017-02-10 17:46 PST --- One of the core design principles of Sass has always been to **understand CSS as diff --git a/old_source/blog/012-dart-sass-is-in-beta.html.md b/old_source/blog/012-dart-sass-is-in-beta.html.md index c264e47f7..4ff952e9f 100644 --- a/old_source/blog/012-dart-sass-is-in-beta.html.md +++ b/old_source/blog/012-dart-sass-is-in-beta.html.md @@ -1,7 +1,7 @@ --- title: Dart Sass is in Beta author: Natalie Weizenbaum -date: 2017-06-05 13:00 PST +# date: 2017-06-05 13:00 PST --- Last weekend was [three days long](https://en.wikipedia.org/wiki/Memorial_Day) diff --git a/old_source/blog/013-sass-35-is-released.html.md b/old_source/blog/013-sass-35-is-released.html.md index 3b8d82878..76653032c 100644 --- a/old_source/blog/013-sass-35-is-released.html.md +++ b/old_source/blog/013-sass-35-is-released.html.md @@ -1,7 +1,7 @@ --- title: Sass 3.5 is Released author: Natalie Weizenbaum -date: 2017-07-07 15:33 PST +# date: 2017-07-07 15:33 PST --- I'm excited to announce that I've just released the stable version of Sass 3.5. diff --git a/old_source/blog/014-dart-sass-100-is-released.html.md b/old_source/blog/014-dart-sass-100-is-released.html.md index 5f6be3320..0a7501021 100644 --- a/old_source/blog/014-dart-sass-100-is-released.html.md +++ b/old_source/blog/014-dart-sass-100-is-released.html.md @@ -1,7 +1,7 @@ --- title: Dart Sass 1.0.0 is Released author: Natalie Weizenbaum -date: 2018-03-26 13:15 PST +# date: 2018-03-26 13:15 PST --- I've just uploaded Dart Sass 1.0.0, the very first stable release, to diff --git a/old_source/blog/015-ruby-sass-is-deprecated.html.md b/old_source/blog/015-ruby-sass-is-deprecated.html.md index 02449bcac..77c14d39a 100644 --- a/old_source/blog/015-ruby-sass-is-deprecated.html.md +++ b/old_source/blog/015-ruby-sass-is-deprecated.html.md @@ -1,7 +1,7 @@ --- title: Ruby Sass is Deprecated author: Natalie Weizenbaum -date: 2018-04-02 11:35 PST +# date: 2018-04-02 11:35 PST --- With the release of [Dart Sass 1.0.0 stable](/blog/dart-sass-100-is-released) diff --git a/old_source/blog/016-request-for-commentsimporting-css-files.html.md b/old_source/blog/016-request-for-commentsimporting-css-files.html.md index 4a32ce2d6..8bda0e04b 100644 --- a/old_source/blog/016-request-for-commentsimporting-css-files.html.md +++ b/old_source/blog/016-request-for-commentsimporting-css-files.html.md @@ -1,7 +1,7 @@ --- title: "Request For Comments: Importing CSS Files" author: Natalie Weizenbaum -date: 2018-07-09 11:19 PST +# date: 2018-07-09 11:19 PST --- As Dart Sass catches up with Ruby Sass in terms of usability, we're starting diff --git a/old_source/blog/017-feature-watchcss-imports-and-css-compatibility.html.md b/old_source/blog/017-feature-watchcss-imports-and-css-compatibility.html.md index c534bebf5..59c41660b 100644 --- a/old_source/blog/017-feature-watchcss-imports-and-css-compatibility.html.md +++ b/old_source/blog/017-feature-watchcss-imports-and-css-compatibility.html.md @@ -1,7 +1,7 @@ --- title: "Feature Watch: CSS Imports and CSS Compatibility" author: Natalie Weizenbaum -date: 2018-08-13 14:17 PST +# date: 2018-08-13 14:17 PST --- Dart Sass 1.11 has just been released, and with it a handful of new features. diff --git a/old_source/blog/018-feature-watchcontent-arguments-and-color-functions.html.md b/old_source/blog/018-feature-watchcontent-arguments-and-color-functions.html.md index f8339f008..6ce1a472f 100644 --- a/old_source/blog/018-feature-watchcontent-arguments-and-color-functions.html.md +++ b/old_source/blog/018-feature-watchcontent-arguments-and-color-functions.html.md @@ -1,7 +1,7 @@ --- title: "Feature Watch: Content Arguments and Color Functions" author: Natalie Weizenbaum -date: 2018-11-14 14:14 PST +# date: 2018-11-14 14:14 PST --- Dart Sass 1.15, released today and available [on diff --git a/old_source/blog/019-request-for-comments-module-system-proposal.html.md b/old_source/blog/019-request-for-comments-module-system-proposal.html.md index 82a1b4933..2fb19895c 100644 --- a/old_source/blog/019-request-for-comments-module-system-proposal.html.md +++ b/old_source/blog/019-request-for-comments-module-system-proposal.html.md @@ -1,7 +1,7 @@ --- title: "Request For Comments: Module System" author: Natalie Weizenbaum -date: 2018-11-27 13:10 PST +# date: 2018-11-27 13:10 PST --- Many of the most frequently-requested features for Sass have to do with its diff --git a/old_source/blog/020-ruby-sass-is-unsupported.html.md b/old_source/blog/020-ruby-sass-is-unsupported.html.md index fb72351bb..d23058d5a 100644 --- a/old_source/blog/020-ruby-sass-is-unsupported.html.md +++ b/old_source/blog/020-ruby-sass-is-unsupported.html.md @@ -1,7 +1,7 @@ --- title: Ruby Sass Has Reached End-Of-Life author: Natalie Weizenbaum -date: 2019-04-03 16:15 PST +# date: 2019-04-03 16:15 PST --- One year has passed since we announced [the deprecation of Ruby diff --git a/old_source/blog/021-brand-new-sass-docs.html.md b/old_source/blog/021-brand-new-sass-docs.html.md index b709c9682..7981e15d3 100644 --- a/old_source/blog/021-brand-new-sass-docs.html.md +++ b/old_source/blog/021-brand-new-sass-docs.html.md @@ -1,7 +1,7 @@ --- title: Brand New Sass Docs author: Natalie Weizenbaum -date: 2019-04-23 10:04 PST +# date: 2019-04-23 10:04 PST --- I'm excited to announce the launch of [a full rewrite and redesign of the Sass diff --git a/old_source/blog/022-request-for-commentsforward-slash-as-separator.html.md b/old_source/blog/022-request-for-commentsforward-slash-as-separator.html.md index 85f53ea48..e8273767d 100644 --- a/old_source/blog/022-request-for-commentsforward-slash-as-separator.html.md +++ b/old_source/blog/022-request-for-commentsforward-slash-as-separator.html.md @@ -1,7 +1,7 @@ --- title: "Request For Comments: Forward Slash as Separator" author: Natalie Weizenbaum -date: 2019-05-06 16:15 PST +# date: 2019-05-06 16:15 PST --- Early on in Sass's history, the decision was made to use `/` as a division diff --git a/old_source/blog/023-module-system-preview.html.md b/old_source/blog/023-module-system-preview.html.md index 4742666ca..88ce444f0 100644 --- a/old_source/blog/023-module-system-preview.html.md +++ b/old_source/blog/023-module-system-preview.html.md @@ -1,7 +1,7 @@ --- title: Module System Preview author: Natalie Weizenbaum -date: 2019-09-04 15:14 PST +# date: 2019-09-04 15:14 PST --- Exciting news, Sass fans! After a year of development and some iteration on the diff --git a/old_source/blog/024-the-module-system-is-launched.html.md b/old_source/blog/024-the-module-system-is-launched.html.md index ce7272324..40bfdda26 100644 --- a/old_source/blog/024-the-module-system-is-launched.html.md +++ b/old_source/blog/024-the-module-system-is-launched.html.md @@ -1,7 +1,7 @@ --- title: The Module System is Launched author: Natalie Weizenbaum -date: 2019-10-01 18:58 PST +# date: 2019-10-01 18:58 PST --- The Sass team has known for years that the `@import` rule, one of the earliest diff --git a/old_source/blog/025-request-for-comments-nested-map-functions.md b/old_source/blog/025-request-for-comments-nested-map-functions.md index 340064acf..d947a61ab 100644 --- a/old_source/blog/025-request-for-comments-nested-map-functions.md +++ b/old_source/blog/025-request-for-comments-nested-map-functions.md @@ -1,7 +1,7 @@ --- title: "Request for Comments: Nested Map Functions" author: Natalie Weizenbaum -date: 2020-9-16 14:40 PST +# date: 2020-9-16 14:40 PST --- As Sass libraries and design systems get more complex and have more users with diff --git a/old_source/blog/026-request-for-comments-hwb-functions.md b/old_source/blog/026-request-for-comments-hwb-functions.md index 47f1a2f43..d57c3fad7 100644 --- a/old_source/blog/026-request-for-comments-hwb-functions.md +++ b/old_source/blog/026-request-for-comments-hwb-functions.md @@ -1,7 +1,7 @@ --- title: "Request for Comments: HWB Functions" author: Natalie Weizenbaum -date: 2020-10-06 16:00 PST +# date: 2020-10-06 16:00 PST --- The CSS working group has been up to all sorts of exciting stuff recently in the diff --git a/old_source/blog/027-libsass-is-deprecated.md b/old_source/blog/027-libsass-is-deprecated.md index a85eafc3b..c35160c9e 100644 --- a/old_source/blog/027-libsass-is-deprecated.md +++ b/old_source/blog/027-libsass-is-deprecated.md @@ -1,7 +1,7 @@ --- title: LibSass is Deprecated author: Natalie Weizenbaum -date: 2020-10-26 12:00 PST +# date: 2020-10-26 12:00 PST --- After much discussion among the Sass core team, we've come to the conclusion diff --git a/old_source/blog/028-request-for-comments-first-class-calc.md b/old_source/blog/028-request-for-comments-first-class-calc.md index c6e44309d..dd2330475 100644 --- a/old_source/blog/028-request-for-comments-first-class-calc.md +++ b/old_source/blog/028-request-for-comments-first-class-calc.md @@ -1,7 +1,7 @@ --- title: "Request for Comments: First-Class Calc" author: Natalie Weizenbaum -date: 2021-3-15 1:35 PST +# date: 2021-3-15 1:35 PST --- One of the absolutely most-requested features in Sass is the ability to more diff --git a/old_source/blog/029-node-fibers-discontinued.md b/old_source/blog/029-node-fibers-discontinued.md index 84c81362a..82586d8ce 100644 --- a/old_source/blog/029-node-fibers-discontinued.md +++ b/old_source/blog/029-node-fibers-discontinued.md @@ -1,7 +1,7 @@ --- title: "The Discontinuation of node-fibers" author: Natalie Weizenbaum -date: 2021-3-26 15:00 PST +# date: 2021-3-26 15:00 PST --- We have recently received the unfortunate but not entirely surprising news that diff --git a/old_source/blog/030-request-for-comments-new-js-api.html.md b/old_source/blog/030-request-for-comments-new-js-api.html.md index dcc730909..00267df09 100644 --- a/old_source/blog/030-request-for-comments-new-js-api.html.md +++ b/old_source/blog/030-request-for-comments-new-js-api.html.md @@ -1,7 +1,7 @@ --- title: "Request for Comments: New JS API" author: Natalie Weizenbaum -date: 2021-08-05 15:30 PST +# date: 2021-08-05 15:30 PST --- I'm excited to officially unveil something that's been in the works for quite a diff --git a/old_source/blog/031-new-js-api-release-candidate.html.md b/old_source/blog/031-new-js-api-release-candidate.html.md index 6394a2e3d..886ec0bff 100644 --- a/old_source/blog/031-new-js-api-release-candidate.html.md +++ b/old_source/blog/031-new-js-api-release-candidate.html.md @@ -1,7 +1,7 @@ --- title: "New JS API Release Candidate is Live" author: Natalie Weizenbaum -date: 2021-11-20 16:15 PST +# date: 2021-11-20 16:15 PST --- The new JavaScript API that we [announced a few months ago] is now fully diff --git a/old_source/blog/032-embedded-sass-is-live.md b/old_source/blog/032-embedded-sass-is-live.md index 8cfcec8a7..925424248 100644 --- a/old_source/blog/032-embedded-sass-is-live.md +++ b/old_source/blog/032-embedded-sass-is-live.md @@ -1,7 +1,7 @@ --- title: "Embedded Sass is Live" author: Natalie Weizenbaum -date: 2022-02-01 2:00 PST +# date: 2022-02-01 2:00 PST --- After several years of planning and development, I'm excited to finally announce diff --git a/old_source/blog/033-request-for-comments-strict-unary-operators.md b/old_source/blog/033-request-for-comments-strict-unary-operators.md index 9c696e217..85ce40cac 100644 --- a/old_source/blog/033-request-for-comments-strict-unary-operators.md +++ b/old_source/blog/033-request-for-comments-strict-unary-operators.md @@ -1,7 +1,7 @@ --- title: "Request for Comments: Strict Unary Operators" author: Natalie Weizenbaum -date: 2022-06-15 15:30 PST +# date: 2022-06-15 15:30 PST --- Do you know what `margin: $a -$b` does in Sass? If you said "the same thing as diff --git a/old_source/blog/034-request-for-comments-color-spaces.md b/old_source/blog/034-request-for-comments-color-spaces.md index 87fe1c738..c39e21088 100644 --- a/old_source/blog/034-request-for-comments-color-spaces.md +++ b/old_source/blog/034-request-for-comments-color-spaces.md @@ -1,7 +1,7 @@ --- title: "Request for Comments: Color Spaces" author: Miriam Suzanne and Natalie Weizenbaum -date: 2022-09-21 13:00 PST +# date: 2022-09-21 13:00 PST --- There's been a lot of exciting work in the CSS color specifications lately, and diff --git a/old_source/blog/035-security-alert-tar-permissions.md b/old_source/blog/035-security-alert-tar-permissions.md index 42d0d2748..582463b3d 100644 --- a/old_source/blog/035-security-alert-tar-permissions.md +++ b/old_source/blog/035-security-alert-tar-permissions.md @@ -1,7 +1,7 @@ --- title: "Security Alert: Tar Permissions" author: Natalie Weizenbaum -date: 2022-12-09 16:00 PST +# date: 2022-12-09 16:00 PST --- The Sass team was recently alerted by prolific external contributor [@ntkme] to diff --git a/source/_layouts/blog.liquid b/source/_layouts/blog.liquid new file mode 100644 index 000000000..4df63fbfd --- /dev/null +++ b/source/_layouts/blog.liquid @@ -0,0 +1,5 @@ +--- +layout: base +--- + +{{ content }} \ No newline at end of file diff --git a/source/blog.liquid b/source/blog.liquid new file mode 100644 index 000000000..a4f202f00 --- /dev/null +++ b/source/blog.liquid @@ -0,0 +1,33 @@ +--- +pagination: + data: collections.blog + size: 5 + alias: posts +layout: blog +title: Sass Blog +--- + +Page {{ pagination.pageNumber | plus: 1 }} of {{ pagination.size }} + + +
    +
  • + {% if pagination.href.previous %} + Previous + {% else %}Previous{% endif %} +
  • +
  • + {% if pagination.href.next %} + Next + {% else %}Next{% endif %} +
  • +
\ No newline at end of file diff --git a/source/blog/001-how-extend-works.html.md b/source/blog/001-how-extend-works.html.md new file mode 100644 index 000000000..801cd0717 --- /dev/null +++ b/source/blog/001-how-extend-works.html.md @@ -0,0 +1,206 @@ +--- +title: How @extend Works +author: Natalie Weizenbaum +tags: blog +layout: base +# date: 2013-11-22 16:57 -8 +--- + +_This was originally published as [a gist](https://gist.github.com/nex3/7609394)_. + +[Aaron Leung](https://github.com/akhleung) is working on +[hcatlin/libsass](http://github.com/hcatlin/libsass) and was wondering how +`@extend` is implemented in the Ruby implementation of Sass. Rather than just +tell him, I thought I'd write up a public document about it so anyone who's +porting Sass or is just curious about how it works can see. + +Note that this explanation is simplified in numerous ways. It's intended to +explain the most complex parts of a basic correct `@extend` transformation, but +it leaves out numerous details that will be important if full Sass compatibility +is desired. This should be considered an explication of the groundwork for +`@extend`, upon which full support can be built. For a complete understanding of +`@extend`, there's no substitute for consulting the [Ruby Sass +code](http://github.com/sass/ruby-sass/tree/master/lib/sass) and [its +tests](https://github.com/sass/ruby-sass/blob/master/test/sass/extend_test.rb). + +This document assumes familiarity with the selector terminology defined in the +[Selectors Level 4](http://dev.w3.org/csswg/selectors4/#syntax) spec. Throughout +the document, selectors will be treated interchangeably with lists or sets of +their components. For example, a complex selector may be treated as a list of +compound selectors or a list of lists of simple selectors. + +## Primitives + +Following are a set of primitive objects, definitions, and operations that are +necessary for implementing `@extend`. Implementing these is left as an exercise +for the reader. + +- A selector object is obviously necessary, since `@extend` is all about + selectors. Selectors will need to be parsed thoroughly and semantically. It's + necessary for the implementation to know a fair amount of the meaning behind + the various different forms of selectors. + +- A custom data structure I call a "subset map" is also necessary. A subset map + has two operations: `Map.set(Set, Object)` and `Map.get(Set) => [Object]`. The + former associates a value with a set of keys in the map. The latter looks up + all values that are associated with _subsets_ of a set of keys. For example: + + map.set([1, 2], 'value1') + map.set([2, 3], 'value2) + map.set([3, 4], 'value3') + map.get([1, 2, 3]) => ['value1', 'value2'] + +- A selector `S1` is a "superselector" of a selector `S2` if every element + matched by `S2` is also matched by `S1`. For example, `.foo` is a + superselector of `.foo.bar`, `a` is a superselector of `div a`, and `*` is a + superselector of everything. The inverse of a superselector is a + "subselector". + +- An operation `unify(Compound Selector, Compound Selector) => Compound +Selector` that returns a selector that matches exactly those elements matched + by both input selectors. For example, `unify(.foo, .bar)` returns `.foo.bar`. + This only needs to work for compound or simpler selectors. This operation can + fail (e.g. `unify(a, h1)`), in which case it should return `null`. + +- An operation `trim([Selector List]) => Selector List` that removes complex + selectors that are subselectors of other complex selectors in the input. It + takes the input as multiple selector lists and only checks for subselectors + across these lists since the prior `@extend` process won't produce intra-list + subselectors. For example, if it's passed `[[a], [.foo a]]` it would return + `[a]` since `.foo a` is a subselector of `a`. + +- An operation `paths([[Object]]) => [[Object]]` that returns a list of all + possible paths through a list of choices for each step. For example, + `paths([[1, 2], [3], [4, 5, 6]])` returns `[[1, 3, 4], [1, 3, 5], [1, 3, 6], +[2, 3, 4], [2, 3, 5], [2, 3, 6]]`. + +## The Algorithm + +The `@extend` algorithm requires two passes: one to record the `@extend`s that +are declared in the stylesheet, and another to transform selectors using those +`@extend`s. This is necessary, since `@extend`s can affect selectors earlier in +the stylesheet as well. + +### Recording Pass + +In pseudocode, this pass can be described as follows: + +``` +let MAP be an empty subset map from simple selectors to (complex selector, compound selector) pairs +for each @extend in the document: + let EXTENDER be the complex selector of the CSS rule containing the @extend + let TARGET be the compound selector being @extended + MAP.set(TARGET, (EXTENDER, TARGET)) +``` + +### Transformation Pass + +The transformation pass is more complicated than the recording pass. It's +described in pseudocode below: + +``` +let MAP be the subset map from the recording pass + +define extend_complex(COMPLEX, SEEN) to be: + let CHOICES be an empty list of lists of complex selectors + for each compound selector COMPOUND in COMPLEX: + let EXTENDED be extend_compound(COMPOUND, SEEN) + if no complex selector in EXTENDED is a superselector of COMPOUND: + add a complex selector composed only of COMPOUND to EXTENDED + add EXTENDED to CHOICES + + let WEAVES be an empty list of selector lists + for each list of complex selectors PATH in paths(CHOICES): + add weave(PATH) to WEAVES + return trim(WEAVES) + +define extend_compound(COMPOUND, SEEN) to be: + let RESULTS be an empty list of complex selectors + for each (EXTENDER, TARGET) in MAP.get(COMPOUND): + if SEEN contains TARGET, move to the next iteration + + let COMPOUND_WITHOUT_TARGET be COMPOUND without any of the simple selectors in TARGET + let EXTENDER_COMPOUND be the last compound selector in EXTENDER + let UNIFIED be unify(EXTENDER_COMPOUND, COMPOUND_WITHOUT_TARGET) + if UNIFIED is null, move to the next iteration + + let UNIFIED_COMPLEX be EXTENDER with the last compound selector replaced with UNIFIED + with TARGET in SEEN: + add each complex selector in extend_complex(UNIFIED_COMPLEX, SEEN) to RESULTS + return RESULTS + +for each selector COMPLEX in the document: + let SEEN be an empty set of compound selectors + let LIST be a selector list comprised of the complex selectors in extend_complex(COMPLEX, SEEN) + replace COMPLEX with LIST +``` + +A keen reader will have noticed an undefined function used in this pseudocode: +`weave`. `weave` is much more complicated than the other primitive operations, +so I wanted to explain it in detail. + +### Weave + +At a high level, the "weave" operation is pretty easy to understand. It's best +to think of it as expanding a "parenthesized selector". Imagine you could write +`.foo (.bar a)` and it would match every `a` element that has both a `.foo` +parent element _and_ a `.bar` parent element. `weave` makes this happen. + +In order to match this `a` element, you need to expand `.foo (.bar a)` into the +following selector list: `.foo .bar a, .foo.bar a, .bar .foo a`. This matches +all possible ways that `a` could have both a `.foo` parent and a `.bar` parent. +However, `weave` does not in fact emit `.foo.bar a`; including merged selectors +like it would cause exponential output size and provide very little utility. + +This parenthesized selector is passed in to `weave` as a list of complex +selectors. For example, `.foo (.bar a)` would be passed in as `[.foo, .bar a]`. +Similarly, `(.foo div) (.bar a) (.baz h1 span)` would be passed in as `[.foo +div, .bar a, .baz h1 span]`. + +`weave` works by moving left-to-right through the parenthesized selector, +building up a list of all possible prefixes and adding to this list as each +parenthesized component is encountered. Here's the pseudocode: + +``` +let PAREN_SELECTOR be the argument to weave(), a list of complex selectors +let PREFIXES be an empty list of complex selectors + +for each complex selector COMPLEX in PAREN_SELECTOR: + if PREFIXES is empty: + add COMPLEX to PREFIXES + move to the next iteration + + let COMPLEX_SUFFIX be the final compound selector in COMPLEX + let COMPLEX_PREFIX be COMPLEX without COMPLEX_SUFFIX + let NEW_PREFIXES be an empty list of complex selectors + for each complex selector PREFIX in PREFIXES: + let WOVEN be subweave(PREFIX, COMPLEX_PREFIX) + if WOVEN is null, move to the next iteration + for each complex selector WOVEN_COMPLEX in WOVEN: + append COMPLEX_SUFFIX to WOVEN_COMPLEX + add WOVEN_COMPLEX to NEW_PREFIXES + let PREFIXES be NEW_PREFIXES + +return PREFIXES +``` + +This includes yet another undefined function, `subweave`, which contains most of +the logic of weaving together selectors. It's one of the most complicated pieces +of logic in the entire `@extend` algorithm -- it handles selector combinators, +superselectors, subject selectors, and more. However, the semantics are +extremely simple, and writing a baseline version of it is very easy. + +Where `weave` weaves together many complex selectors, `subweave` just weaves +two. The complex selectors it weaves together are considered to have an implicit +identical trailing compound selector; for example, if it's passed `.foo .bar` +and `.x .y .z`, it weaves them together as though they were `.foo .bar E` and +`.x .y .z E`. In addition, it doesn't merge the two selectors in most cases, so +it would just return `.foo .bar .x .y .z, .x .y .z .foo .bar` in this case. An +extremely naive implementation could just return the two orderings of the two +arguments and be correct a majority of the time. + +Delving into the full complexity of `subweave` is out of scope here, since it +falls almost entirely into the category of advanced functionality that this +document is intentionally avoiding. The code for it is located in +[`lib/sass/selector/sequence.rb`](https://github.com/sass/ruby-sass/blob/master/lib/sass/selector/sequence.rb) +and should be consulted when attempting a serious implementation. diff --git a/source/blog/002-a-change-in-plans-for-sass-33.html.md b/source/blog/002-a-change-in-plans-for-sass-33.html.md new file mode 100644 index 000000000..036c19948 --- /dev/null +++ b/source/blog/002-a-change-in-plans-for-sass-33.html.md @@ -0,0 +1,126 @@ +--- +title: A Change in Plans for Sass 3.3 +author: Natalie Weizenbaum +tags: blog +#date: 2013-12-19 20:05 PST +--- + +_This was originally published as [a gist](https://gist.github.com/nex3/8050187)._ + +Sass 3.3 is coming soon, and along with it several major new features. It +supports source maps, SassScript maps, and the use of `&` in SassScript. In +preparation for its release, we've put out a couple of release candidates to be +sure that everything was set and ready to go. Unfortunately, it wasn't. + +Release candidates often turn up small bugs and inconsistencies in new features, +but it's rare that they find anything truly damning. In this case, though, +several users noticed an issue with using `&` in SassScript that rendered a +sizable chunk of our plan for that section of 3.3 unworkable. It's not a fatal +issue, and we think we have a good plan for dealing with it (I'll get to that in +a bit), but it is a problem. + +## The Background + +To understand what's wrong, first you need to understand the reason we decided +to make `&` accessible to SassScript in the first place. One thing users want to +do pretty often is to add suffixes to classes. Sometimes this takes the place of +nesting selectors, sometimes it's just to make a new class based on the old ones +-- the reason doesn't matter much to this discussion. When people tried to do +this, they'd write something like `.foo { &-suffix { ... } }`, and it wouldn't +work. The reason is that `&` has the same syntactic function as a type selector +(e.g. `h1`) or a universal selector (`*`), since it could be replaced by any of +those. It doesn't make sense to write `*-suffix` in a selector, so `&-suffix` +wasn't allowed either. + +This didn't stop people from wanting to do it, though. So we decided, "all +right, we already use interpolation (`#{}`) to support injecting text into +selectors -- let's just use that". We decided to add `&` as a sort of special +variable in SassScript that contained a parsed representation of the current +selector. You could then mimic `&-suffix` by doing `@at-root #{&}-suffix` +instead[^1]. Life was peachy, until our intrepid users discovered the problem. + +## The Problem + +Here's a small snippet of SCSS that demonstrates the issue. See if you can +figure it out: + +```scss +.foo, +.bar { + @at-root #{&}-suffix { + color: blue; + } +} +``` + +Did you get it? That's right: `&` in this example is `.foo, .bar`, which means +the selector compiles to `.foo, .bar-suffix`. Since `#{}` injects plain old +text, there's no chance for Sass to figure out how it should split up the +selector. + +[Chris](https://github.com/chriseppstein) and I talked and talked about how to +fix this. We considered adding a function to add the suffix, but that was too +verbose. We considered making `&` split the compilation of the CSS rule into +several parallel rules which each had a single selector for `&`, but that was +too complicated and fell down in too many edge cases. We eventually concluded +that there was no way for SassScript `&` to cleanly support the use case we +designed it for. + +## The Solution + +We knew we wanted to support the `&-suffix` use case, and our clever plan for +doing so had failed. We put our heads together and discussed, and decided that +the best way to support it was the most straightforward: we'd just allow +`&-suffix`. This was, after all, what most people tried first when they wanted +this behavior, and with the `&` embedded directly in the selector, we can handle +selector lists easily. + +This means that **`&-suffix` will be supported in Sass 3.3**, without needing +`#{}` or `@at-root`. I've created [issue +1055](https://github.com/nex3/sass/issues/1055) to track it. When compiling +these selectors, if the parent selector is one that would result in an invalid +selector (e.g. `*-suffix` or `:nth-child(1)-suffix`), we'll throw an error there +describing why that selector was generated. + +We are still worried about cases where people write mixins using `&-suffix` that +will then fail to work with certain parent selectors, but in this case we +determined that this would be the least of all available evils. + +## The Future of `&` in SassScript + +In addition to supporting `&-suffix`, **we've decided to pull SassScript `&` +from the 3.3 release**. Rest assured that it will return -- we recognize that it +has other good use cases, and we intend to bring it back for the next big +release (likely 3.4). In addition, it will come with a suite of functions for +manipulating the selectors it makes available, so it will be more powerful than +ever. + +There are two reasons that we want to hold off on using `&` in SassScript for +now. The first is that we want some time to create the functions that will go +along with it and put them through their paces. This may require changing the +way it works in various ways, and we don't want to have to make +backwards-incompatible changes to do so. + +The second reason is that we've spent a fair amount of energy talking up `#{&}` +as a solution to the `&-suffix` problem. This is our own fault, clearly, but +it's true and it's something we need to deal with. Making `&-suffix` work is +great, but if everyone is using `#{&}` anyway because that's what we told them +about a few months ago, then it's not doing everything it can. Having a release +where `&-suffix` works but `#{&}` doesn't will help guide users towards the best +way to solve their problem, before we make the more advanced functionality +available. + +`@at-root` will still be included in Sass 3.3. + +## Releasing 3.3 + +Unfortunately, this change will delay the release of 3.3, but hopefully not by +too much. I anticipate this being relatively straightforward to implement; the +major hurdle was figuring out what to do about it, and that part's done. I plan +to devote a large chunk of time to getting 3.3 out the door after I come back +from winter vacation, so hopefully (no promises) it'll be released some time in +January. + +[^1]: + The `@at-root` is necessary since Sass can't reliably figure out whether + `&` was used in the selector like it can when `&` is used without `#{}`. diff --git a/source/blog/003-sass-33-is-released.html.md b/source/blog/003-sass-33-is-released.html.md new file mode 100644 index 000000000..f72cfa5f5 --- /dev/null +++ b/source/blog/003-sass-33-is-released.html.md @@ -0,0 +1,164 @@ +--- +title: Sass 3.3 is Released +author: Natalie Weizenbaum +tags: blog +#date: 2014-03-07 16:40 PST +--- + +After ironing out a bunch of bugs in numerous release candidates, we're finally +ready to release Sass 3.3.0, codename Maptastic Maple, for public consumption. +This release has a lot of exciting new features that you can read about in full +in [the changelog](/documentation/file.SASS_CHANGELOG.html), but there are three +that I want to draw your attention to in particular. + +# Maps in SassScript + +As language designers, most of our job is to listen to feedback from users and +act upon it. This is tricker than it sounds: users are very good at knowing the +precise thing that they want to accomplish, but they tend not to have a sense of +how that fits into the big picture. So we take a large volume of user requests, +try to distill the core needs that aren't being met, and see if we can come up +with features that hit as many of those as possible as simply as possible. + +SassScript maps are a great example of this. We had a lot of users requesting +things like variable interpolation, so they could write things like +`$#{$theme-name}-background-color`. Other users wanted built-in functions that +worked with lists of pairs, or a way to get the name of a variable that was +passed to a function. We eventually realized the underlying feature that people +actually wanted: a way to associate values with names. + +Most programming languages have a notion of maps[^1], which are associations +from "key" objects to "value" objects. Sass 3.3 adds support for these as a +first-class data structure. The syntax is designed to be very similar to that +used for `@media` queries. They look like this: + +```scss +$map: ( + key1: value1, + key2: value2, + key3: value3, +); +``` + +Unlike lists, maps must always be surrounded by parentheses. `()`, which +previously referred to an empty list, now _also_ refers to an empty map; both +list and map operations will work on it. + +Maps can't be used as CSS values, since they aren't valid CSS syntax. However, +there are a number of [new built-in +functions](/documentation/Sass/Script/Functions.html#map_functions) that allow +user-defined mixins and functions to use them. Here are a few particularly +useful ones: + +- `map-get($map, $key)` looks up a value in a map using its key. For example, + using the example above, `map-get($map, key2)` would return `value2`. + +- `map-merge($map1, $map2)` merges two maps together. The keys in `$map2` + overwrite those in `$map1`, so this is also a good way to add values to a map. + For example, `map-merge($map, (key1: new-value))` would return `(key1: +new-value, key2: value2, key3: value3)`. + +- `map-remove($map, $key)` removes a value in a map. For example, + `map-remove($map, $key)` would return `(key: value2, key3: value3)`. + +In addition to the new map functions, all the existing list functions also work +on maps. The list functions will see each map as a list of pairs. For example, +`nth($map, 1)` will return `(key1 value1)`. Not only that, but `@each` has new +syntax for working with both maps and lists of pairs. For example: + +```scss +@each $header, $size in (h1: 2em, h2: 1.5em, h3: 1.2em) { + #{$header} { + font-size: $size; + } +} +``` + +produces: + +```css +h1 { + font-size: 2em; +} + +h2 { + font-size: 1.5em; +} + +h3 { + font-size: 1.2em; +} +``` + +# Source Maps + +Continuing the map theme, Sass 3.3 comes with support for generating source maps +when compiling to CSS. Source maps are a standard format for telling browsers +how files they consume got generated. For Sass, this means that browsers' +development tools can now tell you exactly which line of your Sass source file +each style rule came from. Currently this is only well-supported in Chrome, but +hopefully other browsers will add support soon. + +When compiling Sass from the command line, all you need to do to generate source +maps is pass the `--sourcemap` flag. Sass will automatically generate a +`.css.map` file next to the generated `.css` file. All you have to do then is +make sure your `.scss` or `.sass` file is visible to the browser, and you'll be +good to go. + +# More Flexible `&` + +When we released Sass 3.0, we added support for SCSS, which meant we had to +actually parse all the selectors in the document. This meant that you couldn't +just plop the parent selector, `&`, anywhere in a selector. Overall this was an +improvement: it caught more errors and encouraged users to write more flexible +mixins. + +Unfortunately, it also made one important use-case harder. With the rise in +popularity of [BEM](http://gembem.com/), [OOCSS](http://oocss.org/), and +[SMACSS](http://smacss.com/), people became more and more interested in adding +suffixes to classes. When using Sass, they wanted to write mixins to do this, +and the restrictions on `&` made that very hard to do. + +In Sass 3.3, we're loosening these restrictions. You can now write `&-suffix` +(or `&_suffix`, or even `&suffix` if you really want) and Sass will make it +work. If this fails to apply—for example, if `&` is `*`—Sass will +print a helpful error message. + +# Deprecation: Variable Scope and `!global` + +We don't always get everything right the first time, and in order to make Sass +the best language it can be we occasionally have to change old behavior. +Sometimes this happens in ways that might make existing stylesheets stop +functioning, so we have a policy of printing warnings for stylesheets that are +going to change in the future. + +Sass 3.3 adds a number of deprecations, but the biggest one by far has to do +with the way variable scope works. Up until now, when you wrote `$var: value` in +a function, mixin, or CSS rule in Sass, it could do one of two things. If there +was a global variable named `$var`, it would overwrite that variable. Otherwise, +it would create a local variable that was only visible within the current set of +curly braces. + +This was a pretty big problem, since any given variable assignment could +potentially be modifying a variable that it had no way of knowing existed. We +want to migrate to a better system where assigning to a variable in a local +scope won't overwrite a global variable unless the assignment explicitly says to +do so, as in `$var: value !global`. + +In order to avoid breaking existing stylesheets, we haven't made this change +yet. Instead, if a global variable is overwritten by a local declaration, we now +print a deprecation warning suggesting that the user add `!global`. Right now, +`!global` doesn't do much other than make the warning go away, but in a future +release it will work as I described above. + +# That's All + +Actually, there's a lot more, but that's all I have room for in this post. If +you want to see the full assortment of new features, check out [the +changelog](/documentation/file.SASS_CHANGELOG.html#330_7_March_2014). You can +also play with the new features on [SassMeister](http://sassmeister.com/) or on +your own computer by running `gem update sass`. Enjoy! + +[^1]: + Some languages call them "hashes", "dictionaries", or "associative + arrays". JavaScript calls them "objects" for weird historical reasons. diff --git a/source/blog/004-sass-34-is-released.html.md b/source/blog/004-sass-34-is-released.html.md new file mode 100644 index 000000000..136793412 --- /dev/null +++ b/source/blog/004-sass-34-is-released.html.md @@ -0,0 +1,91 @@ +--- +title: Sass 3.4 is Released +author: Natalie Weizenbaum +tags: blog +#date: 2014-08-18 16:38 PST +--- + +We've been trying to increase the pace of Sass releases, and it looks like we've +succeeded. A mere five months after the release of [Sass +3.3](/blog/sass-33-is-released), we're announcing the release of Sass 3.4.0, +codename Selective Steve. Faster releases mean fewer major features per release, +so there are only two big new things to talk about (although there are plenty of +little improvements you can read about in [the +changelog](/documentation/file.SASS_CHANGELOG.html)). As the version name +suggests, both of these features have to do with selectors. + +# Using `&` in SassScript + +"SassScript" is what we call the mini-language Sass uses for variables, property +values, and so forth. It's mostly just CSS values, but it also supports custom +functions, arithmetic, and so forth. In Sass 3.4, we added support for something +new: the parent selector, `&`. + +Most Sass users will probably recognize `&` from its previous appearances in +selectors around the world, where it's used to explicitly refer to the parent +selector. For example, in `.parent { .child & { ... } }`, `&` refers to +`.parent`, and this compiles to `.child .parent { ... }`. + +Now `&` works much the same way in SassScript. It refers to the same parent +selector, but instead of just being dropped in it's exposed as a list of lists +to make it easy for functions to inspect and manipulate it. For example, if you +write `.foo .bar, .baz { $selector: & }`, `$selector` will be `((".foo" ".bar"), +(".baz",))`. + +We had originally slated this feature for version 3.3, but we took it out when +we realized [it was really hard to use these selectors in a way that didn't +break when they contained commas](/blog/a-change-in-plans-for-sass-33). +Because of that, we decided to delay it for a version to give us time to come up +with its compantion feature: selector functions. + +# Selector Functions + +The problem with just exposing `&` was that the only way to use it with other +selectors was by glomming them together as strings. This works okay in simple +cases, but when you write `#{$selector} .child` and `$selector` is `.foo, .bar`, +you want `.foo .child, .bar .child` but you get `.foo, .bar .child`. This is no +good at all. + +To solve this, we added a slew of functions that use Sass's powerful built-in +selector logic to do the right thing. For example, you can now write +**`selector-nest(".foo, .bar", ".child")`** and get exactly what you want. These +functions all return the same sort of nested-list representation that `&` +uses,but they're very liberal in what they accept: anything from nested lists to +plain old strings. + +If you want to see every selector function we thought up, check out [the +changelog](/documentation/file.SASS_CHANGELOG.html). I do want to highlight a +few that I'm particularly fond of, though. You've already seen +`selector-nest()`, and **`selector-append()`** is a close relative. The +difference between them is whitespace: `selector-nest()` adds a space between +its selectors, where `selector-append()` doesn't. This means that +`selector-append(".foo, .bar", "-suffix")` returns `.foo-suffix, .bar-suffix`. + +Another function I like a lot is **`selector-replace()`**. This does a +search-and-replace of one selector within another, but it's a lot more clever +than your basic string replace. It uses Sass's `@extend` logic to replace +selectors _semantically_, as though every element matched by the replacement +selector was also matched by the replaced selector. For example, +`selector-replace(".foo.bar.baz", ".foo.baz", ".qux")` returns `.bar.qux`. + +The last really powerful function I want to draw your attention to is +**`selector-unify()`**. This takes two selectors and returns a new selector that +matches only elements that are matched by _both_ input selectors. This is an +operation Sass uses a lot internally, and now users can access it as well. For +example, `selector-unify(".foo.bar", ".bar.baz")` will return `.foo.bar.baz`. + +# What's Next? + +I won't rule out the possibility of Sass 3.5 existing, but +[Chris](https://twitter.com/chriseppstein) and I plan to focus pretty hard on +Sass 4.0. The big feature for 4.0 is going to be `@import`, or rather the lack +thereof. Our current import system is beginning to show its age in a major way, +and we intend to replace it wholesale, up to and including the name. As of 4.0, +the recommended way of pulling in other Sass files will be `@use`. + +Among the features we're planning for `@use` are two that have been widely +requested. You'll be able to import CSS stylesheets directly into your Sass +ones, and each stylesheet will only be run once, no matter how many times it's +imported. + +Until then, though, run `gem update sass` and enjoy Selective Steve! diff --git a/source/blog/005-cleaning-up-interpolation.html.md b/source/blog/005-cleaning-up-interpolation.html.md new file mode 100644 index 000000000..edaadf5f5 --- /dev/null +++ b/source/blog/005-cleaning-up-interpolation.html.md @@ -0,0 +1,154 @@ +--- +title: Cleaning Up Interpolation +author: Natalie Weizenbaum +tags: blog +#date: 2015-12-09 15:20 PST +--- + +Interpolation—the ability to add variables and other snippets using `#{...}`—is +one of the handiest all-purpose features of Sass. You can use it just about +everywhere you might need to inject a variable, a function call, or some other +expression. In most of those places it just plops the value into the surrounding +text. It's straightforward, easy to understand, and useful, which is exactly +what we want from a feature. + +Unfortunately, that's only true in _most places_. For complicated historical +reasons, there's one place where interpolation goes a little bit bananas: inside +an expression but outside quotes. Most of the time, it makes sense; if you write +`display: -#{$prefix}-box`, you'll get what you expect. But if any operators +like `+` are used next to the interpolation, you start to get weird output. For +example, `$name + #{$counter + 1}` might return an unquoted string containing +the text `name + 3`. + +This is really weird behavior. Why does `+` behave differently here than it does +everywhere else? Why is it treated as plain text when `$name` gets evaluated +normally? This behavior is confusing, inconsistent, and not particularly useful, +which are very much _not_ things we want in a feature. So why do they exist in +the first place? + +## Complicated Historical Reasons + +_If you don't care for a history lesson, skip on down to [A Brave New +World](#a-brave-new-world)._ + +Way back in the dawn of time, when the indented syntax was the only syntax, Sass +had a distinction between "static" and "dynamic" properties. A static property +was basically plain CSS; it was declared using `property: value`, and the value +was used as-is without any further processing. If you wanted to use a variable +or a function, you had to use a dynamic property, which was declared using +`property= value`. A You'd see a lot of stylesheets like this: + +```sass +.border + border-width: 4px + border-style: solid + border-color= !background_color +``` + +Also, in the dawn of time, variables used `!` instead of `$` and couldn't +include hyphens. The dawn of time kind of sucked. But it was in this context +that we first added interpolation. We wanted to allow properties like `border` +with multiple values to be partially dynamic, so we decided to follow in Ruby's +footsteps and allow `#{}` to be used to drop in values. Soon stylesheets started +looking like this: + +```sass +.border + border: 4px solid #{!background_color} +``` + +That's so much better! And for a while, all was calm. + +### Then Came SCSS + +It eventually became clear that users really strongly wanted their stylesheets +to look like CSS, so we sat down and started work on the syntax that would +become SCSS in the release that would become Sass 3. As part of this work, we +decided to get rid of the distinction between static and dynamic properties +altogether. Having all properties work the same way was obviously great for +users, but it meant we had to figure out how to merge the two syntaxes with a +minimum of pain. + +This was mostly straightforward, since the old expression syntax was pretty much +universally invalid CSS or something that emitted its CSS value anyway. But +interpolation proved tricky. Backwards compatibility is really important to us, +so we wanted to be sure that all the places interpolation was used—or _could +theoretically be used_—in Sass 2 would continue to work in Sass 3, even though +everything around them was now fully parsed. + +Our solution was to make basically anything around `#{}` that wasn't obviously +part of a plain-CSS expression turn into a string. That way, hopefully any weird +corner cases that people had would keep working when they upgraded. This led to +the weird behavior I described above, but at the time our top priority was +making it as easy as possible for users to migrate to Sass 3. We decided the +weirdness was worth it, and shipped it. + +## A Brave New World + +Flash forward to today. We're now starting work on the next major release, Sass +4, and (I dearly hope) no one's written any Sass 2 stylesheets in years. A major +release is a great opportunity to clean up this bit of historical cruft, and +after [discussing it extensively on the issue +tracker](https://github.com/sass/sass/issues/1778) we decided to make the +change. + +There are three major steps in a backwards-incompatible change like this. The +first is to design the new syntax, which was pretty easy here, since it's +basically just "do what everyone thought it did already." We just had to take +that general notion and suss out the specifics. + +We ended up framing it as `#{}` being, syntactically, part of an identifier. +When you write `-#{$prefix}-box`, Sass parses it as a single identifier +containing `"-"` followed by the value of `$prefix` followed by `"-box"`. Even +if you write `#{$font}` all on its own, it's parsed as an identifier that only +contains the value of `$font`. This way, interpolation doesn't have weird +behavior around operators any more than identifiers ever did. + +Once we had a design, the second step was to deprecate the old behavior. The +meat of deprecation is figuring out when to print a warning, and that was pretty +tough here. We didn't want to warn for situations that would continue to work, +even when they involved operators—for example, `12px/#{$line-height}` will print +the right thing in the old and new worlds (although for slightly different +reasons), but `12px+#{$line-height}` won't. + +I won't go into the gory details of how we got deprecation working here; that's +what the [GitHub issue](https://github.com/sass/sass/issues/1778) is for. +Suffice it to say that it involved a lot of special cases, including some where +a deprecation warning can be printed based on how a value is _used_ rather than +how it's _written_. I'm pretty happy with where it ended up, though; I suspect +it'll catch 99% of cases that will actually break in practice. + +Another exciting bonus was the ability to automatically update code. This +doesn't always work when introducing backwards-incompatibilities, but in this +case we were able to make `sass-convert` convert deprecated uses of +interpolation into Sass 4-compatible code. It has some false negatives—it only +converts cases it can prove will be incompatible—but it's enough to get users a +long way there. + +The final step once the deprecation was in place was to move to [the `main` +branch](https://github.com/sass/sass/commits/main) (which will eventually +become Sass 4), rip out all the old behavior, and implement the new. And it was +_wonderful_. Deleting gross code and replacing it with something clean feels +like taking a shower after spending a day hiking through dust under a hot sun. +And after working on this feature for weeks, I was happy to see the other end of +it. + +## Checking it Out + +Sass 3.4.20, released today, was the first release to include the deprecation +warnings for the old syntax. If you want to check whether you've got any +deprecated interpolations lurking in your stylesheets, just `gem install sass` +and recompile your stylesheet. And if you do find some, try running +`sass-convert --recursive --in-place .` to fix a bunch automatically. + +If you want to try out the new syntax, 4.0.0.alpha.1 was also released today. +You can get it with `gem install sass --prerelease`. But beware: it is alpha +software, so it may change in the future. We generally try to keep even our +prereleases pretty stable, but there's also a chance you'll run into a bug. + +If you do find a bug, please file it on [the issue +tracker](https://github.com/sass/sass/issues). Even if it's something as simple +as a typo, we want to know. If we've deprecated something that should be valid, +we _especially_ want to know. And if you just have a question, feel free to +tweet at [@SassCSS](https://twitter.com/SassCSS) or post it on the [mailing +list](https://groups.google.com/forum/#!forum/sass-lang). diff --git a/source/blog/006-dropping-support-for-old-ruby-versions.html.md b/source/blog/006-dropping-support-for-old-ruby-versions.html.md new file mode 100644 index 000000000..ccac52421 --- /dev/null +++ b/source/blog/006-dropping-support-for-old-ruby-versions.html.md @@ -0,0 +1,60 @@ +--- +title: Dropping Support For Old Ruby Versions +author: Natalie Weizenbaum +tags: blog +#date: 2016-02-29 14:25 PST +--- + +As of version 3.5, Ruby Sass will drop support for Ruby 1.8.7 and Ruby 1.9.3. We +will continue to support Ruby 2.0.0 and higher. + +Ruby 1.8.7 was retired by the Ruby maintainers in [June +2013](https://www.ruby-lang.org/en/news/2013/06/30/we-retire-1-8-7/), and Ruby +1.9.3 was retired in [February +2015](https://www.ruby-lang.org/en/news/2015/02/23/support-for-ruby-1-9-3-has-ended/). +Despite that, we continued to maintain support for older versions because Ruby +1.8.7 was installed by default on Mac OS X through Mountain Lion (which was +released in July 2012). + +There are many users of Sass who aren't independently users of Ruby. We wanted +to minimize the amount of work these users need to do to use Sass, which means +letting it run on their machine without also requiring them to install a new +language. + +That decision wasn't without costs, though. Most seriously, recent versions of +the [listen package](https://github.com/guard/listen) didn't support older Ruby +versions, and older versions of RubyGems weren't clever enough to avoid +downloading them on incompatible Ruby versions. To work around this, we bundled +an older version of `listen` with Sass and used it for users who didn't have a +compatible version installed elsewhere, but this produced constant compatibility +headaches. + +These headaches led us to reevaluate our policy for supporting older Ruby +versions. We still cared a lot about users' built-in Ruby versions, but we +couldn't support them forever. We needed a way to determine when the benefit of +dropping support outweighed the costs. + +We decided to use the analytics data for sass-lang.com to approximate the +proportion of our user base that was still using operating systems that shipped +with old Ruby versions. Before we looked at the data, we decided that we would +drop support for a Ruby version if it had been retired by the Ruby maintainers, +_and_ less than 2% of our visitors across the previous month were using an OS +that shipped it by default. + +Once we did that, we looked at the data. 34.3% of our visitors were using OS X, +and 1.4% of OS X users were using Mountain Lion or earlier. We were clearly able +to drop support for 1.8.7. In addition, 1.9.3 was never shipped with OS X so we +were able to drop it as well. Ruby 2.0.0, despite retired [last +week](https://www.ruby-lang.org/en/news/2016/02/24/support-plan-of-ruby-2-0-0-and-2-1/), +was shipped with the most recent OS X version—we won't be dropping support for +it any time soon. + +sass-lang.com visitors by operating system + +For Sass 3.4, we're just planning on printing deprecation messages for users of +deprecated Ruby versions. But once 3.5 releases, support will be fully dropped +and we'll switch to using `listen` as a proper gem dependency. If you're on an +older version of OS X and you haven't upgraded your Ruby version, there are some +simple instructions [on the Ruby +site](https://www.ruby-lang.org/en/documentation/installation/#homebrew) for how +to do so easily using Homebrew. diff --git a/source/blog/007-thank-you-marcel.html.md b/source/blog/007-thank-you-marcel.html.md new file mode 100644 index 000000000..1e282f135 --- /dev/null +++ b/source/blog/007-thank-you-marcel.html.md @@ -0,0 +1,32 @@ +--- +title: Dropping Support For Old Ruby Versions +author: Natalie Weizenbaum +tags: blog +#date: 2016-05-24 14:41 PST +--- + +You may not know [Marcel Greter](https://github.com/mgreter), but you almost +certainly know his work. For more than two years, he has been the #1 contributor +on LibSass and is the #2 contributor for the history of the project. His +monumental efforts, together with [Michael Mifsud](https://github.com/xzyfer), +are what has kept LibSass thriving recently and why it has reached feature +parity with Ruby Sass and is now used by more users than Ruby Sass every day. + +Presently, as we are pivoting to a new development model and release cadence, +Marcel has decided it is the best time for him to exit the LibSass core team. We +are truly sad to see him go, but we wish him well in all his new endeavors. +Please join us in thanking him for all his hard work. You can follow and tweet +him [@mgreter](https://twitter.com/mgreter). + +--- + +Unfortunately, this leaves the LibSass project with some big shoes to fill. +LibSass is a popular project that has more than 1.5 Million downloads a month +and as of right now, it is in desparate need of new contributors. + +We have a bunch of new features planned for Sass 3.5 that need to be implemented +in LibSass and we want to do a coordinated release of both Ruby Sass and LibSass +as soon as we can. If you can write production quality C++ and want to build +parsers and compilers, we would love to help you become a contributor. If you +don't have free time, but still want to contribute, consider asking your +workplace to support the project by donating a percentage of your time. diff --git a/source/blog/008-sass-35-release-candidate.html.md b/source/blog/008-sass-35-release-candidate.html.md new file mode 100644 index 000000000..40b5d80fc --- /dev/null +++ b/source/blog/008-sass-35-release-candidate.html.md @@ -0,0 +1,155 @@ +--- +title: Sass 3.5 Release Candidate +author: Natalie Weizenbaum +tags: blog +#date: 2016-08-30 15:00 PST +--- + +I've just pushed the button to release Sass 3.5.0-rc.1. If it seems like it's +been a while since the last release, that's true! But there's a good reason. We +decided to enter feature freeze after the 3.5 release to give +[libsass](/libsass), the super-speedy C++ implementation of Sass, time to reach +feature parity with Sass 3.4. Libsass is much younger than Sass, and C++ is +generally a slower language to work in than Ruby, so this took some time. But it +paid off: libsass is now almost 100% compatible with Ruby Sass, differing only +in a few small bugs. + +After the feature freeze lifted, we were primarily focused on designing the new +module system that will be the central feature of Sass 4.0. But we also found +some time to add some new features, which are the focus of this release. + +## CSS Custom Property Support + +Sass 3.5 now fully supports [CSS custom +properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables). +These posed a particular challenge for us, since the custom property syntax is +_extremely_ broad. You can put just about anything on the right-hand side. For +example, this is totally valid, meaningful CSS: + +```css +.wacky-property { + --property: .%(#@$~`^[^_+]<;:"}"|?)*+; +} +``` + +In particular, this means that SassScript expressions are _also_ valid CSS, +which poses a problem for our goal of CSS compatibility. Wherever possible, we +want valid CSS to mean the same thing in Sass as it does in CSS. So treating +custom properties just like normal properties—which we did in 3.4—wasn't a good +solution. Not only was some valid CSS interpreted differently, some of it wasn't +even possible. The following CSS, taken straight from the Polymer docs, was next +to impossible to represent in Sass: + +```css +:host { + --my-toolbar-theme: { + background-color: green; + border-radius: 4px; + border: 1px solid gray; + } +} +``` + +On the other hand, we needed _some_ way of including dynamic SassScript values +in custom properties. So we decided on a compromise: we'd treat custom +properties like we do selectors and at-rule values, and only allow `#{}` as a +means of including Sass values. While technically this is plain CSS, it's a very +small surface area and it's very easy to escape, so we're not too worried. This +means that in 3.5 you can write: + +```scss +:host { + --my-toolbar-theme: { + background-color: #{$toolbar-background}; + border-radius: 4px; + border: 1px solid gray; + } +} +``` + +## New Data Type: First-Class Functions + +In preparation for the module system that's coming in Sass 4.0, 3.5 adds a new +data type: first-class functions. This is just a way of referring to a function +that's more specific than just its name. You can get a first-class function by +passing its name to `get-function($name)`, and you can pass it to `call()` where +you used to pass the function name. + +You might be wondering, "Why is this useful? I could already just pass the +function name." Well, right now, Sass has global scope. All functions (as well +as variables, mixins, and selectors) are visible to any code that's executing +later on. This makes some things, like `call()`, simple, but it also causes a +lot of problems. It's way too easy to accidentally overwrite a variable or +function that was defined elsewhere, and it's way too hard to figure out where +any given name was originally defined. + +We aren't quite ready to talk widely about our plans for the 4.0 module system, +but one of the things we're sure of is that it won't use global scope. Each Sass +file will only be able to see a limited number of the names that have been +defined, and Sass libraries in particular won't be able to see anything defined +by the end-user stylesheets that import them. First-class functions allow users +to pass functions they define to libraries. + +Any stylesheets that are currently passing around function names as strings +should switch to passing first-class functions instead. To this end, calling +`call()` with a string has been deprecated. It won't actually break until 4.0, +when it won't be much use anyway, but we strongly encourage users to switch to +`get-function()` immediately. + +## New Syntax: Bracketed Lists + +The new [CSS Grid +Layout](https://css-tricks.com/snippets/css/complete-guide-grid/) module added a +new type of syntax: identifiers surrounded by square brackets. We're always +striving to be totally compatible with CSS, which meant we needed to support +these brackets as well. Here's what they look like in CSS: + +```css +.container { + grid-template-columns: [first] 40px [line2] 50px [line3] auto [col4-start] 50px [five] 40px [end]; + grid-template-rows: [row1-start] 25% [row1-end] 100px [third-line] auto [last-line]; +} +``` + +The solution was clear: Sass already has a [list data +type](/documentation/file.SASS_REFERENCE.html#lists), so we'd just allow lists +to have square brackets. So `[first]` is just a list containing the unquoted +string `first`. Like all Sass lists, bracketed lists can either be +space-separated or comma-separated: `[foo bar baz]` and `[foo, bar, baz]` are +both lists containing three elements. + +We've also added function support for bracketed lists. The `is-bracketed($list)` +function returns whether a list is bracketed or not, and `join()` has a new +`$bracketed` parameter that allows the caller to choose whether or not the +resulting list will have brackets (by default, the result is bracketed if the +first list is). + +## Smaller Features + +We've added a `content-exists()` function that returns whether or not a content +block was passed to the current mixin. This allows mixins to optionally take a +content block, rather than having to define one mixin that takes content and one +that does not. + +We've added the ability to add a trailing comma to argument lists. This matches +the behavior of lists and maps. + +We've added a `$weight` parameter to the `invert()` function. This is a +percentage between 0% and 100% that indicates how inverted the resulting color +should be. It defaults to 100%. + +## The Road to Release + +This is just a release candidate, but it's in a place that we'd be happy +shipping it as the final release. We're not doing so because, now that we've +reached feature compatibility with libsass, we're committed to staying there. + +Unfortunately, since [Marcel Greter moved on from the +project](/blog/thank-you-marcel), libsass has been moving pretty slowly lately. +If you or anyone you know would be interested in working on a project that would +benefit thousands of people, we're still looking for new contributors! + +Until we have libsass compatibility, 3.5 will stay at a release candidate level. +But don't let that stop you from trying it out and letting us know what you +think! We're always interested in hearing feedback on [the mailing +list](https://groups.google.com/forum/#!forum/sass-lang)! diff --git a/source/blog/009-announcing-dart-sass.html.md b/source/blog/009-announcing-dart-sass.html.md new file mode 100644 index 000000000..13862297f --- /dev/null +++ b/source/blog/009-announcing-dart-sass.html.md @@ -0,0 +1,178 @@ +--- +title: Announcing Dart Sass +author: Natalie Weizenbaum +tags: blog +#date: 2016-10-31 13:28 PST +--- + +Over the past few months, I've been quietly working on a new project. Today I'm +ready to announce [Dart Sass](https://github.com/sass/dart-sass) to the world. +It's a totally new implementation of Sass, designed to be fast, easy to install, +and easy to hack on. It's not yet complete—I'm steadily working my way through +[sass-spec](https://github.com/sass/sass-spec)—so today I'm just releasing +version 1.0.0-alpha.1. But it's solid enough for you to download, play with, and +[start filing issues](https://github.com/sass/dart-sass/issues). + +You can download a standalone archive [from the release +page](https://github.com/sass/dart-sass/releases/tag/1.0.0-alpha.1)—just extract +it, add the folder to your path, and run `dart-sass`. Dart also compiles to +JavaScript, so if you have [npm](https://www.npmjs.com/) installed you can +install the JS version by running `npm install -g dart-sass`. And, if you happen +to be a Dart user yourself, you can install it using `pub global install sass`. + +## Why Rewrite Sass? + +Over the past few years, there have been two primary implementations of Sass. +[Ruby Sass](https://github.com/sass/sass) was the original, written mostly by me +with substantial help from [Chris](https://twitter.com/chriseppstein). It's +high-level and easy to hack on, so it's where we iterate on new features and +where they first get released. Then there's +[LibSass](https://github.com/sass/libsass), the C++ implementation, originally +created by [Aaron](https://github.com/akhleung) and +[Hampton](https://github.com/hcatlin) and now maintained by +[Marcel](https://github.com/mgreter) and [Michael](https://github.com/xzyfer). +It's low-level, which makes it very fast and easy to install and embed in other +languages. In particular, its [Node.js +bindings](https://github.com/sass/node-sass) are a very popular way to use Sass +in the JavaScript world. + +Each implementation's strengths complement the other's weaknesses. Where LibSass +is fast and portable, Ruby Sass is slow and difficult for non-Ruby-users to +install. Where Ruby Sass is easy to iterate on, LibSass's low-level language +makes it substantially harder to add new features. A complementary relationship +can be healthy, but it can also mean that neither solution is as good as it +needs to be. That's what we found when, in May, [Marcel officially left the +LibSass team](http://blog.sass-lang.com/posts/734390-thank-you-marcel)[^1]. + +[^1]: + I say "officially" because he's still contributing to the project when he + can, just not in an official maintainer capacity. + +Without two people's worth of effort, we were no longer sure that LibSass could +keep pace with the speed Chris and I wanted to introduce changes into the +language. And it had been clear for a long time that Ruby Sass was far too slow +for use cases involving large stylesheets. We needed a new implementation, one +that could generate CSS quickly _and_ add new features quickly. + +## Why Dart? + +We considered a number of possible languages, and ended up deciding on Dart for +a number of reasons. First, it's _really fast_—the Dart VM is generally much +faster than JavaScript VMs, and [early +benchmarks](https://github.com/sass/dart-sass/blob/main/perf.md)[^2] indicate +that, for large stylesheets, Dart Sass is 5-10x faster than Ruby Sass and only +about 1.5x slower than LibSass. I'll hazard a guess that it would be about +1.5-2x faster than an idiomatic JS implementation, but I can't say for sure. And +Dart's performance continues to get better all the time. + +[^2]: + Caveats apply: I'm not a benchmarking expert, and these tests were _ad + hoc_ and run against non-representative source stylesheets. If anyone is + interested in working on more scientific benchmarks, please let me know! + +At the same time, Dart is easy to work with—much more so than C++, and to some +extent even more than Ruby for such a large project. Granted, not as many people +are familiar with it as with JavaScript, but language implementations don't tend +to get many external contributions anyway. I'll be doing most of the work on the +new implementation, and Dart is the language that I'm personally most +comfortable with at the moment (when I'm not working on Sass, I'm on the Dart +team). Using Dart gives me a lot of extra velocity. + +Unlike Ruby or JavaScript, Dart is _statically typed_, so every value's type can +be figured out without running the code. Unlike C++, it's _garbage collected_, +so we don't have to worry as much about cleaning up after ourselves. This makes +it easy to write, easy to modify, and easy to maintain. Maybe even more +importantly, it makes it easy to translate to other programming languages, which +will help LibSass get new features faster. + +The last reason we chose Dart is something that only a few other languages can +boast: JavaScript compatibility. Dart can be compiled to JavaScript, which can +be used directly in Node.js or even potentially run in a browser. A huge chunk +of the Sass ecosystem built on node-sass, and we intend to make the JS version +of Dart Sass as close to API-compatible with node-sass as possible, so that it +can easily drop into existing tools and build systems. + +The only downside is that there's a speed hit: Dart Sass is about twice as slow +running on V8 as it is running on the Dart VM. However, this still puts it +solidly 3-4x faster than Ruby Sass. Ultimately we also hope to provide an easy +path for users of the JS-compiled version to move to the Dart VM version as +little friction as possible. + +## What Will Happen to The Other Implementations? + +Nothing's changing about LibSass's development. Michael's hard at work adding +features from [Sass +3.5](http://blog.sass-lang.com/posts/809572-sass-35-release-candidate), and we +expect that process to continue as new language features are added. The only +difference is that LibSass will no longer be required to be strictly compatible +with the latest version of the language in order for that version to launch, +since it will no longer be the only implementation with reasonable performance. + +More flexibility translates into faster LibSass releases that prioritize the +features users want most. Strict compatibility meant that important features +like [CSS custom property support](https://github.com/sass/libsass/issues/2076) +can't be released until all the tiny tricky edge cases that were in the +corresponding Ruby Sass release, like [`:root` +unification](https://github.com/sass/libsass/issues/2071), are implemented as +well. We'll still strive for as much compatibility as possible, but we won't let +that stand in the way of velocity. + +Ruby Sass, on the other hand, will eventually go away unless a new maintainer +appears. We don't want to make the transition sudden and risk fracturing the +ecosystem: Chris and I are committed to maintaining it for one year, which +includes keeping the language in sync with any new additions in Dart Sass. If +anyone is interested in volunteering as a maintainer after that period, we'd be +thrilled to mentor them and teach them the codebase over the coming year. But if +no one steps up, Ruby Sass will be officially considered deprecated and +unmaintained. + +I want to emphasize that we aren't making the decision to stop developing Ruby +Sass lightly. This is a big change, and it's not an easy one for me—I've worked +on Ruby Sass continuously for almost ten years now, and it's difficult to let +that history go. But Chris and I have discussed this thoroughly, and we're +convinced this is the right move. We only have so much time to devote to Sass, +and it no longer makes sense to put that time into an implementation that's so +slow as to be infeasible for many of our largest users. + +## What Next? + +Before we release the first stable version of Dart Sass, there are a few big +things on our to-do list: + +- Full sass-spec compatibility. There are still a bunch of corners of the + language where Dart Sass does the wrong thing, especially with respect to + `@extend`. I don't expect any individual incompatibility to be especially + difficult to address, and sass-spec is pretty comprehensive, so it's just a + matter of steadily reducing the number of failing specs until it hits zero. + +- Close-enough node-sass `render()` compatibility in the npm package. The + node-sass `render()` API is the main entrypoint to LibSass in the JavaScript + world. It's how build systems run Sass, how users define custom Sass + functions, and how [Eyeglass](https://github.com/sass-eyeglass/eyeglass) + passes modules to Sass. We want to support this API with enough fidelity that + the existing ecosystem works with JS-compiled Dart Sass. + +- Dart Sass compatibility in Ruby Sass. There are some cases where Dart Sass + intentionally differs from Ruby Sass, particularly when Ruby Sass's behavior + is considered a bug. We should add deprecation messages in Ruby Sass and, if + we can do so with minimal disruption, add support for the new behavior. + +There's plenty more we'd like to do eventually, like supporting Sass in the +browser and providing a node-sass-compatible wrapper for Sass on the Dart VM, +but those aren't blocking the initial release. + +## Onward Into the Future + +The next couple months will see a lot of work go into getting Dart Sass stable +and compatible, and getting [Sass 3.5 +features](http://blog.sass-lang.com/posts/809572-sass-35-release-candidate) into +LibSass. I think it's likely that early 2017 will see a stable release of Dart +Sass and a 3.5 release of LibSass. At that point we'll set our sight on the big +features and start working towards Sass 4.0 and its brand new module system. + +Dart Sass is a big change, but it's an exciting one as well. It'll allow us to +get new features into users' hands faster, and to make those features _run_ +faster. It'll make it possible for users to trivially install and run the +reference implementation. And it'll give us a performant way to run Sass in pure +JavaScript Sass for the first time ever. The benefits are large and tangible, +and I'm confident they're worth the costs. diff --git a/source/blog/010-dart-sass-is-on-chocolatey.html.md b/source/blog/010-dart-sass-is-on-chocolatey.html.md new file mode 100644 index 000000000..c1e9b54b4 --- /dev/null +++ b/source/blog/010-dart-sass-is-on-chocolatey.html.md @@ -0,0 +1,47 @@ +--- +title: Dart Sass is On Chocolatey +author: Natalie Weizenbaum +tags: blog +#date: 2017-01-13 14:43 PST +--- + +One of the quieter benefits of [moving to Dart](/blog/announcing-dart-sass) is +how easy it is to distribute Dart applications. The Dart VM is able to bundle +all the sources for an application into one easy-to-load binary snapshot, which +means running a Dart application requires only three files: the `dart` +executable, the snapshot file, and a tiny shell script to invoke the app[^1]. +This is a huge relief coming from Ruby, which required a whole installation of +executables and libraries in order to run a single app. + +Those three files are what we distribute today [on our GitHub release +page](https://github.com/sass/dart-sass/releases). But finding, downloading, and +opening an archive and adding it to the command-line path is still a barrier to +entry that we'd like to avoid where possible. Today we're taking a step in that +direction by releasing [a Dart Sass +package](https://chocolatey.org/packages/sass) on +[Chocolatey](https://chocolatey.org/), the Windows package manager. You can +install it now using: + +``` +$ choco install sass -prerelease +``` + +This will give you a `sass` executable that runs Dart Sass on the (really fast) +Dart VM. + +A large percentage of Sass users are on Windows, and it hasn't always been easy +for them to get the latest and greatest Sass versions without a bunch of +installation headaches. I'm excited that we can start taking advantage of our +new infrastructure to fix that. + +In addition to Chocolatey, we'd love to get Dart Sass on +[Homebrew](http://brew.sh/) for our OS X users. If you're interested in helping +out with that, let us know—[this +issue](https://github.com/sass/dart-sass/issues/97) would be a great place to +start! + +[^1]: + There's also [an open + issue](https://github.com/dart-lang/sdk/issues/27596) for bundling the VM + and the snapshot into a single executable file, which would allow us to pare + down our distribution to a single file. diff --git a/source/blog/011-sass-and-browser-compatibility.html.md b/source/blog/011-sass-and-browser-compatibility.html.md new file mode 100644 index 000000000..7a1480f09 --- /dev/null +++ b/source/blog/011-sass-and-browser-compatibility.html.md @@ -0,0 +1,53 @@ +--- +title: Sass and Browser Compatibility +author: Natalie Weizenbaum +tags: blog +#date: 2017-02-10 17:46 PST +--- + +One of the core design principles of Sass has always been to **understand CSS as +little as possible**. As a CSS preprocessor of course we have to understand the +syntax of CSS, but as much as we can we try to avoid caring about the +_semantics_—the meaning behind the styles. This means that Sass has no idea +which properties are valid, which HTML elements actually exist, or even to a +large extent what the syntax of most @-rules is. + +We get a lot of benefit from this. The less built-in knowledge Sass has about +CSS, the less likely it is to work poorly with new CSS features. Imagine having +to file a feature request every time you want to use a new CSS property—that +would suck! Instead, older versions of Sass will happily keep working unless the +actual _syntax_ changes, which is much rarer. + +Because of this decoupling, we've never needed to worry much about browser +compatibility. Sass just passes whatever CSS its given on through. It's up to +the user to determine what works where, which gives them a lot of flexibility +and gives us designers one fewer tough decision to make. + +But despite this general policy, there are always a few cases where CSS +knowledge turns out to be necessary. A big one is `@extend`, which needs to know +a lot about the meaning of selectors to properly unify them and weed out +duplicates. Property values sometimes require semantic knowledge as well—we have +to know how to interpret colors, for example. + +One of those cases has leapt up to bite us. Long ago, we made the decision to +always emit transparent colors as the keyword `transparent`, because it was +supported on IE6 through 8 and the alternative `rgba()` syntax was not. But it +turns out that the opposite is true for more recent versions: in IE10, `:hover` +styles aren't triggered for elements with `background-color: transparent` but +they are with `background-color: rgba(0, 0, 0, 0)`. Thanks, IE! + +So we were faced with a dilemma. Keep the existing behavior which was compatible +with old outdated browsers that no one uses, or choose a new behavior that works +better with modern browsers? The choice was pretty clear: we decided to always +emit `rgba(0, 0, 0, 0)`. + +In addition, we wanted to come up with a general rule to guide us in determining +which browsers we were willing to consider outdated, and which we would continue +to support (whatever that meant for the behavior in question). We decided that +if a change would negatively affect less than 2% of the global market share of +browsers according to [StatCounter GlobalStats](http://gs.statcounter.com/), we +were willing to make it. + +This limit isn't set in stone. We reserve the right to change it in the future, +and to make individual decisions that may affect more browsers. But this is the +general guideline we're paying attention to, and we wanted you all to know. diff --git a/source/blog/012-dart-sass-is-in-beta.html.md b/source/blog/012-dart-sass-is-in-beta.html.md new file mode 100644 index 000000000..ac5767025 --- /dev/null +++ b/source/blog/012-dart-sass-is-in-beta.html.md @@ -0,0 +1,73 @@ +--- +title: Dart Sass is in Beta +author: Natalie Weizenbaum +tags: blog +#date: 2017-06-05 13:00 PST +--- + +Last weekend was [three days long](https://en.wikipedia.org/wiki/Memorial_Day) +and the weather in Seattle was gorgeous. Contrary to stereotype, spring here is +often characterized by bright sunny days that aren't too hot, and on days like +that I love to curl up on the armchair in my living room and write some code. +This weekend, that meant finishing up the last few outstanding `@extend` bugs, +finally **making Dart Sass fully sass-spec compatible**[^1]. + +[^1]: + Technically there are still two specs marked as "TODO". These test UTF-16 + support, which is currently [blocked on Dart + support](https://github.com/dart-lang/sdk/issues/11744). + +This is the milestone we've decided would mark the transition from alpha to beta +releases of Dart Sass. Dart Sass 1.0.0-beta.1 is up now on npm, pub, and +Chocolatey, and I encourage people to start trying it out in their own +applications. We've fixed all the bugs we know about, so now we need our +diligent users to find the rest of them and [tell +us](https://github.com/sass/dart-sass/issues/new)! + +## Next Steps: Ruby Sass + +There are a number of [intentional behavior +differences](https://github.com/sass/dart-sass#behavioral-differences-from-ruby-sass) between +Dart Sass and the existing implementations. All of these differences are things +we think improve the language, and many of them have also made Dart Sass much +easier to implement, but we recognize that they can make migration more +difficult. That's why our next priority is updating Ruby Sass by deprecating old +behavior or adding new behavior, as necessary. + +Our long-term compatibility goal is to ensure, as much as possible, that **if a +stylesheet compiles without warnings on Ruby Sass, it will also work with Dart +Sass**. So a substantial portion of our effort in the near future be spent on +ensuring [all the compatibility +issues](https://github.com/sass/sass/labels/Dart%20Sass%20Compatibility) are +fixed. Once that's done, we'll release those changes as part of Ruby Sass 3.5. + +## Next Steps: Dart Sass + +On the Dart front, we have [a number of +issues](https://github.com/sass/dart-sass/milestone/1) outstanding that we want +to resolve before we release a stable version of 1.0.0. The majority of these +issues are focused on one thing: compatibility with the node-sass `render()` +API. This will make it easy to integrate Dart Sass into existing JS ecosystem +tools and workflows, since anything that works with node-sass will automatically +work with Dart Sass as well. + +## Try It Out + +As with all Dart Sass releases, 1.0.0-beta.1 is available on many platforms. +Give it a try on whichever is easiest for you: + +- Standalone tarballs are [available on + GitHub](https://github.com/sass/dart-sass/releases/tag/1.0.0-beta.1), which + you can just download and run from the command line. + +- [Chocolatey](https://chocolatey.org) users on Windows can just run `choco +install sass --pre` (or `choco upgrade sass --pre` if you already have it). + +- You can get the pure-JavaScript version from npm by running `npm install -g +dart-sass`. + +- Or if you're a Dart user, you can run `pub global activate sass`. + +I'm very pleased to have 1.0.0-beta.1 tagged and out in the world, but the work +of a language maintainer is never done. I'm back to work, and if I hustle, +hopefully I'll be writing about 1.0.0-rc.1 soon! diff --git a/source/blog/013-sass-35-is-released.html.md b/source/blog/013-sass-35-is-released.html.md new file mode 100644 index 000000000..afd061053 --- /dev/null +++ b/source/blog/013-sass-35-is-released.html.md @@ -0,0 +1,99 @@ +--- +title: Sass 3.5 is Released +author: Natalie Weizenbaum +tags: blog +#date: 2017-07-07 15:33 PST +--- + +I'm excited to announce that I've just released the stable version of Sass 3.5. +This release focuses on compatibility with new CSS syntax, and helps lay the +groundwork for the upcoming module system and compatibility with [Dart +Sass](/blog/announcing-dart-sass). + +Most of the major features in 3.5 were already in the release candidate, which +[you can read about here](/blog/sass-35-release-candidate). But there are a +handful of other changes that have been added since then: + +- Sass now supports the [the `::slotted()` + pseudo-element](https://drafts.csswg.org/css-scoping-1/#slotted-pseudo), + including extending its selector arguments. + +- [The `var()` function](https://www.w3.org/TR/css-variables-1/#using-variables) + may be safely passed to the CSS color functions `rgb()`, `rgba()`, `hsl()`, + and `hsla()`. + +- Transparent colors created by Sass's color functions will now be written as + `rgba(0, 0, 0, 0)` rather than `transparent` to work around a bug in Internet + Explorer. Colors written as `transparent` in the document will still be + emitted as written. + +### Dart Sass Compatibility + +[I wrote last month](http://sass.logdown.com/posts/1909151) about our plans for +keeping Ruby Sass compatible with Dart Sass in the short term. Sass 3.5 begins +to implement those plans by adding support for a number of small behavioral +extensions added by Dart Sass: + +- It's no longer an error to `@extend` a selector that appears in the + stylesheet, but for which unification fails. The purpose of extension errors + was to prevent typos, which weren't occurring in this case. + +- Pseudo selectors that take arguments can now take any argument that matches + CSS's [`` + syntax](https://drafts.csswg.org/css-syntax-3/#typedef-declaration-value). + This will provide better forwards-compatibility with new selectors. + +- Pseudo selectors that contain placeholder selectors as well as + non-placeholders—for example, `:matches(.foo, %bar)`—will no longer be + eliminated. This matches the definition of a placeholder as a selector that + matches nothing. + +- You can now vary the indentation within an indented-syntax file, as long as it + still defines a consistent tree structure. + +There are also some deprecations for functionality that's not supported in Ruby +Sass: + +- Extending compound selectors, such as `@extend .foo.bar`, is deprecated. This + never followed the stated semantics of extend: elements that match the + extending selector are styled as though they matches the extended selector. + + When you write `h1 {@extend .a.b}`, this _should_ mean that all `h1` elements + are styled as though they match `.a.b`—that is, as though they have `class="a +b"`, which means they'd match both `.a` and `.b` separately. But instead we + extend only selectors that contain _both_ `.a` and `.b`, which is incorrect. + +- Color arithmetic is deprecated. Channel-by-channel arithmetic doesn't + correspond closely to intuitive understandings of color. Sass's suite of + [color + functions](/documentation/Sass/Script/Functions.html#other_color_functions) + are a much cleaner and more comprehensible way of manipulating colors + dynamically. + +- The reference combinator, `/foo/`, is deprecated since it hasn't been in the + CSS specification for some time and is being removed from Chrome soon. + +- The old-style `:name value` property syntax is deprecated. This syntax is not + widely used, and is unnecessarily different from CSS. + +### LibSass Compatibility + +[LibSass](/libsass), the C++ implementation of Sass, is well on its way to +compatibility with all these features. It's not quite there yet, but we decided +we didn't want to block the 3.5 release on 100% compatibility. LibSass will +release these features as it implements them. + +### What's Next? + +In the most immediate future, I'm going on leave for a few months, so there's +not likely to be a huge amount of work. Once that's over, I'll be focusing on +getting Dart Sass to a full 1.0.0 release, which means spending a bunch of time +making its JavaScript API compatible with +[node-sass](http://npmjs.com/package/node-sass). + +As far as Ruby Sass goes, I'll continue to fix bugs and add support for the CSS +features as browsers start to support them. Once Dart Sass 1.0.0 is out, I'll +add new features concurrently across both Ruby and Dart until the one-year +support period is up. + +But for now, run `gem update sass` and enjoy 3.5! diff --git a/source/blog/014-dart-sass-100-is-released.html.md b/source/blog/014-dart-sass-100-is-released.html.md new file mode 100644 index 000000000..9d17add7a --- /dev/null +++ b/source/blog/014-dart-sass-100-is-released.html.md @@ -0,0 +1,96 @@ +--- +title: Dart Sass 1.0.0 is Released +author: Natalie Weizenbaum +tags: blog +#date: 2018-03-26 13:15 PST +--- + +I've just uploaded Dart Sass 1.0.0, the very first stable release, to +[GitHub](https://github.com/sass/dart-sass/releases/tag/1.0.0-rc.1), +[npm](https://www.npmjs.com/package/sass), +[Chocolatey](https://chocolatey.org/packages/sass), +[Homebrew](https://github.com/sass/homebrew-sass), and +[pub](http://pub.dartlang.org/packages/sass). After working on it for almost two +years, I'm thrilled to have a stable release out there and officially ready to +use in real-world applications. [All the reasons we chose +Dart](/blog/announcing-dart-sass) as the implementation language are bearing +fruit: Dart Sass is much faster than Ruby Sass, much easier to make available +across operating systems and language environments, and much more maintainable. + +The 1.0.0 stable release indicates that Dart Sass is fully compatible with the +Sass language as defined by [the sass-spec test +suite](http://github.com/sass/sass-spec), and that its npm package is compatible +with the [Node Sass +API](https://github.com/sass/node-sass/blob/master/README.md#usage), with the +exception of source map support which is [coming +soon](https://github.com/sass/dart-sass/issues/2). + +I've also updated sass-lang.com to cover Dart Sass. The release bar now shows +the latest version of all three major implementations, as well as links to their +release notes and documentation about each one. The [install page](/install) +covers Dart Sass instead of Ruby Sass, and the [Dart Sass page](/dart-sass) +talks all about what Dart Sass is and the various ways it can be used. + +### What's Next? + +At first, the focus of Dart Sass was on compatibility with the Sass language. +Once we reached that and [graduated to a beta +release](/blog/dart-sass-is-in-beta), we shifted our focus to compatibility with +the Node Sass API. Now that we've reached that, our primary aim for the next +several months will be bringing the usability of Dart Sass up to (at least) the +standard of Ruby Sass and Node Sass. + +This means focusing on a number of features outside the language that make +working with Sass pleasant. This includes [generating source +maps](https://github.com/sass/dart-sass/issues/2) from both the command-line +interface and the JavaScript API, [adding a live watch +mode](https://github.com/sass/dart-sass/issues/264), and [integrating Dart Sass +into the Node ecosystem](https://github.com/sass/dart-sass/issues/267). We've +also got our eye on the possibility of creating [a Ruby +gem](https://github.com/sass/dart-sass/issues/249) that embeds Dart Sass with a +Ruby Sass-like API. + +Of course, I'll also continue to keep on top of bug fixes and new CSS features. +I probably won't personally have a lot of bandwidth for adding new language +features, but if anyone else is interested there are a number that [wouldn't be +too hard to +add](https://github.com/sass/sass/issues?utf8=%E2%9C%93&q=is%3Aopen+is%3Aissue+label%3A%22Help+Wanted%22+label%3APlanned). +Dart is a very easy language to learn, and I've written up a [helpful guide on +contributing](https://github.com/sass/dart-sass/blob/main/CONTRIBUTING.md#readme). + +### What About Ruby Sass? + +I'll be posting a more detailed post about the future of Ruby Sass soon, but the +abbreviated version is that it's now officially deprecated. I'll continue +maintaining it for one more year from the date this blog post goes live, +including fixing bugs and updating it to support new CSS features, but it won't +be getting any new language features. Once the one-year deprecation period is +up, the repository will be archived and no new versions will be released. + +Of course, all that could change if someone is willing to step up as a new +maintainer! It's not an easy task, but it's a chance to work on something that's +used by tons of people every day. If you're interested, please email +[me](mailto:nex342@gmail.com) and [Chris](mailto:chris@eppsteins.net) and we'll +talk to you about next steps. + +### Give It a Whirl + +One of the big benefits of switching to Dart is increased portability, which +means it's easier than ever to install Sass. Give it a try on whichever is +easiest for you: + +- Standalone tarballs are [available on + GitHub](https://github.com/sass/dart-sass/releases/tag/1.0.0), which you can + just download and run from the command line. + +- You can get the pure-JavaScript version from npm by running `npm install -g +sass`. + +- [Chocolatey](https://chocolatey.org/) users on Windows can run `choco install +sass` (or `choco upgrade sass` if you already have it). + +- [Homebrew](https://brew.sh/) users on Mac OS X can run `brew install +sass/sass/sass` (or `brew upgrade sass` if you already have it). +- Or if you're a Dart user, you can run `pub global activate sass`. + +Now, get styling! diff --git a/source/blog/015-ruby-sass-is-deprecated.html.md b/source/blog/015-ruby-sass-is-deprecated.html.md new file mode 100644 index 000000000..a142c1499 --- /dev/null +++ b/source/blog/015-ruby-sass-is-deprecated.html.md @@ -0,0 +1,100 @@ +--- +title: Ruby Sass is Deprecated +author: Natalie Weizenbaum +tags: blog +#date: 2018-04-02 11:35 PST +--- + +With the release of [Dart Sass 1.0.0 stable](/blog/dart-sass-100-is-released) +last week, Ruby Sass was officially deprecated. I'll continue to maintain it +over the next year, but when 26 March 2019 rolls around it will reach its +official end-of-life. I encourage all users to start migrating away sooner +rather than later. + +### The Deprecation Period + +Over the next year, I'll continue to work on Ruby Sass in a limited capacity. +I'll triage and fix any bugs that are reported, unless they're minor or obscure +enough to be unlikely to pose a practical problem over the next year. I'll also +add support for any new CSS features that require changes to the Sass parser or +other parts of the language. + +I won't be working on language features that aren't necessary for CSS support, +though. The latest and greatest features will be appearing exclusively in [Dart +Sass](/dart-sass) and [LibSass](/libsass) from here on out. + +I also won't be accepting pull requests for new Ruby Sass features. While pull +requests are a great way to contribute to projects, they still take work on my +part to merge in, and it just doesn't make sense to spend time on that work when +the project is being turned down. If you're interested in contributing to Sass, +I highly recommend [contributing to Dart +Sass](https://github.com/sass/dart-sass/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22)—Dart +is an extremely easy language to learn! + +We're also be migrating the Ruby Sass repository to +https://github.com/sass/ruby-sass, so be sure to update your Git URLs. The old +repository URL will continue to work during the deprecation period, but it will +be frozen; all ongoing maintenance will happen at the new URL. Once the +deprecation period is over, the Git history for the old URL will be wiped and +replaced with feature specifications. See [this +issue](https://github.com/sass/sass/issues/2480) for the full plan. + +### Migrating Away + +We want to make it as easy as possible to migrate from Ruby Sass onto an +actively-maintained implementation. The best way to do that depends on how you +use Ruby Sass today. + +If you use Ruby Sass as a command-line tool, the easiest way to migrate is to +[install Dart Sass](/install) as a command-line tool. It supports a similar +interface to Ruby Sass, although it currently doesn't support the `--watch` or +`--update` flags—[adding them](https://github.com/sass/dart-sass/issues/264) is +high priority, though! + +If you use Ruby Sass as a plugin for a Ruby web app, particularly if you define +your own Sass functions in Ruby, the +[`sassc`](https://github.com/sass/sassc-ruby) gem provides access to +[LibSass](/libsass) from Ruby with a very similar API to Ruby Sass. In most +cases, you can just replace the `Sass` module with the `SassC` module and your +code will continue to work. + +If you're using Rails, I particularly recommend using the +[`sassc-rails`](https://github.com/sass/sassc-rails) gem, which wraps up the +`sassc` gem and integrates it smoothly into the asset pipeline. Most of the time +you won't even need to change any of your code. + +We're also planning to add support to Dart Sass for [embedding it in +Ruby](https://github.com/sass/dart-sass/issues/248) (and other programming +languages). This will allow Ruby users to get the latest and greatest features +as soon as they're implemented. + +### End of Life + +On 26 March 2019, the deprecation period for Ruby Sass will end and it will no +longer be maintained. The new `sass/ruby-sass` repository will be +[archived](https://help.github.com/articles/about-archiving-repositories/), +which means no changes will be made and no new issues or pull requests will be +accepted. The old `sass/sass` repository will have its Git history replaced with +feature specifications that have historically just been scattered around issue +comments. + +Leading up to the end of life, we'll be migrating the user-focused [reference +documentation](/documentation/file.SASS_REFERENCE.html) from the Ruby Sass +repository to the Sass website. We could use some help doing the migration and +touching up the documentation, so if you're interested please [chime in on the +tracking issue](https://github.com/sass/sass-site/issues/205)! + +#### Unless... + +We're turning down support for Ruby Sass because the Sass team just doesn't have +the bandwidth to maintain it along with the other major implementations. But +there could be another solution. If someone from the community is willing to +step up and take on the mantle of maintainer, we'd be more than happy to show +them the ropes and help them keep Ruby Sass going. + +Maintaining a language implementation isn't necessarily easy. It requires +keeping up with features as they're added to Dart Sass, as well as fixing bugs +and fielding pull requests. But it's also a great opportunity to work on a big +project with a lot of impact, and I'm happy to help get a new maintainer up to +speed. If you're interested, please email [me](mailto:nex342@gmail.com) and +[Chris](mailto:chris@eppsteins.net) and we'll talk about how to get started. diff --git a/source/blog/016-request-for-commentsimporting-css-files.html.md b/source/blog/016-request-for-commentsimporting-css-files.html.md new file mode 100644 index 000000000..450272df8 --- /dev/null +++ b/source/blog/016-request-for-commentsimporting-css-files.html.md @@ -0,0 +1,103 @@ +--- +title: 'Request For Comments: Importing CSS Files' +author: Natalie Weizenbau +tags: blog +#date: 2018-07-09 11:19 PST +--- + +As Dart Sass catches up with Ruby Sass in terms of usability, we're starting +work on adding new features to the language. The first feature we're looking at +is one that's long been requested by users: adding support for importing plain +CSS files without having to rename them to `.scss`. Not only do we expect this +to be very useful, it's already partially implemented in LibSass, so this will +help bring the implementations more in line with one another. + +We're also trying out a new process with this feature. In order to help keep the +behavior of different implementations in sync, we're starting with a prose +specification of the feature before moving on to writing code. We're also taking +this as an opportunity to solicit feedback from you, the Sass community! We want +to hear your thoughts on the new feature while we have a chance to revise it +based on that feedback. + +## Background + +Historically, the reference implementations of Sass—first Ruby Sass, then Dart +Sass—only supported importing other Sass files. However, LibSass supported +importing CSS files as well, interpreting them as though they were SCSS. +Although this technically violated the [implementation guide][]'s prohibition on +unilaterally extending the language, these CSS imports were useful and were +widely adopted in the Node.js community. + +[implementation guide]: /implementation + +This became particularly clear when, at the language team's urging, LibSass +added [deprecation warnings][libsass#2611] for CSS imports and users were left +without a suitable replacement. The language team came together to discuss the +problem, and decided to move towards allowing CSS imports but forbidding the use +of non-CSS features in the imported files. The proposal describes the specifics +of that idea. + +[libsass#2611]: https://github.com/sass/libsass/issues/2611 + +LibSass's behavior at time of writing is to import files with the extension +`.css` at the same precedence level as those with the `.scss` and `.sass` +extensions, and to throw an error if an import is ambiguous between a `.css` +file and a `.scss` or `.sass` file. + +## Summary + +The proposal seeks to strike a balance between preserving compatibility with +LibSass's existing behavior and moving towards a more principled scheme for +loading CSS. This is particularly important as we intend to allow `@use` to load +CSS files without Sass features, so we want the existing CSS loading support to +be as similar as possible. + +Locating CSS files for import works similarly under the proposal as it does in +LibSass currently: a relative `.css` file takes precedence over files with any +extension on the load path, a `.css` file earlier on the load path takes +precedence over a file with any extension later on the load path, and `foo.css` +takes precedence over `index/foo.scss`. + +The only difference in loading scheme occurs when an import is ambiguous between +a `.css` file and a `.scss` or `.sass` file at the same path. LibSass currently +produces an error here, but in order to maximize compatibility with existing +Dart Sass (and Ruby Sass) behavior, the proposal has the `.scss` or `.sass` file +taking precedence. This is not a breaking change to LibSass's behavior, since it +only applies in situations that would previously have produced an error. + +The proposal diverges significantly from LibSass in parsing the imported CSS +files, though: it forbids all use of SCSS features in the parsed files. Most +SCSS features produce errors (rather than compiling to plain, likely-invalid +CSS) in order to help users who accidentally wrote SCSS in their CSS realize +what's going wrong. However, features like `@import` that overlap with plain CSS +continue to be rendered as CSS. + +In order to avoid a sudden backwards-incompatible change in LibSass, this also +includes a proposal for a set of deprecation warnings that can be added to +LibSass's existing behavior to steer users away from using Sass features in +their imported CSS without entirely breaking their build process. + +## Giving Feedback + +If you want more details on exactly how the proposed behavior will work, [head +over to the `sass/language` repo and read the full +proposal](https://github.com/sass/language/blob/main/accepted/css-imports.md). +You can skip the Background and Summary sections, since they're included above. +Be aware, though, that it's written to be a specification; it's a great for +figuring out how exactly an edge case should work, but it's not as +conversational as the sections quoted above. + +If you have any issues with the proposal as written, or if it doesn't cover a +use-case that's important to you, [please bring that up in the `sass/language` +issue +tracker](https://github.com/sass/language/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3A%22proposal%3A+CSS+imports%22). +We'll be leaving it open for discussion for at least two weeks before we mark +the proposal as "accepted" and move on to the implementation phase. + +Please be aware, though, that while we welcome community feedback, the design of +Sass is ultimately in the hands of the language team. We'll absolutely consider +the perspectives and use-cases of users who speak up, but it's also our job to +consider all the users who are new to Sass or even to CSS and who don't yet know +to read blogs or comment on issue trackers. Remember that our careful +decision-making made Sass what it is today, and have patience with us if we +don't make the decisions you would have! diff --git a/source/blog/017-feature-watchcss-imports-and-css-compatibility.html.md b/source/blog/017-feature-watchcss-imports-and-css-compatibility.html.md new file mode 100644 index 000000000..6045edcc1 --- /dev/null +++ b/source/blog/017-feature-watchcss-imports-and-css-compatibility.html.md @@ -0,0 +1,116 @@ +--- +title: 'Feature Watch: CSS Imports and CSS Compatibility' +author: Natalie Weizenbaum +tags: blog +#date: 2018-08-13 14:17 PST +--- + +Dart Sass 1.11 has just been released, and with it a handful of new features. +This is an exciting moment, because it marks the first major new feature that's +been added to the language since Dart Sass was launched. It's also the first +release with features that have gone through the new process, from +[proposal](https://github.com/sass/language/blob/main/accepted/css-imports.md) +to [tests](https://github.com/sass/sass-spec/pull/1277) to +[implementation](https://github.com/sass/dart-sass/pull/436). + +### CSS Imports + +The biggest feature in Dart Sass 1.11 is support for importing plain CSS files. +This is a long-awaited feature, and while we'd initially planned on waiting on +it until we launched the upcoming module system, we ended up deciding to +[implement it earlier](/blog/request-for-commentsimporting-css-files). + +You can now import a CSS file, say `styles.css`, just by writing `@import +"styles"`. That file will be parsed as plain CSS, which means that any Sass +features like variables or mixins or interpolation will be disallowed. The CSS +it defines will become part of your stylesheet, and can be `@extend`ed just like +any other styles. + +There are a couple caveats: because SCSS is a superset of plain CSS, it will +still compile `@import "styles.css"` (with an explicit extension) to a CSS +`@import` rule. If you want to import a CSS file into your Sass compilation, you +must omit the extension. + +Also, this feature isn't fully [implemented in +LibSass](https://github.com/sass/libsass/issues/2699) yet. It still has its old +behavior, where it imports CSS files but parses them as SCSS, with all the extra +Sass features allowed. This behavior will be deprecated soon, and eventually it +will produce errors for anything other than plain CSS, just like Dart Sass does +today. + +### CSS `min()` and `max()` + +Dart Sass 1.11 also adds support for CSS's `min()` and `max()` mathematical +functions. For those unfamiliar, these functions work a lot like `calc()`, +except they return the minimum or maximum of a series of values. For example, +you can write `width: max(50%, 100px)` to make your element either 50% of the +parent's width or 100px wide, whichever is greater. + +Because Sass has its own functions named `min()` and `max()`, it was difficult +to use these CSS functions... until now. Dart Sass 1.11 will intelligently +decide whether to use the plain CSS functions or the built-in Sass functions +based on whether or not you're passing in dynamic Sass values. For example: + +- The Sass function will be called if you pass a variable, like `max($width, +100px)`. +- The Sass function will be called if you call another Sass function, like + `max(compute-width(), 100px)`. +- It will compile to a plain CSS function if you just use plain CSS numbers, + like `max(50% + 10px, 100px)`. +- It will still compile to a plain CSS function even if you use interpolation, + like `max(50% + #{$width / 2}, #{$width})`. + +This preserves backwards-compatibility with existing uses of the Sass functions, +while also users to use the CSS functions the same way they would in plain CSS. + +This feature isn't yet implemented in +[LibSass](https://github.com/sass/libsass/issues/2701) or [Ruby +Sass](https://github.com/sass/ruby-sass/issues/77). + +### Range-Format Media Queries + +CSS Media Queries Level 4 defines a [range +syntax](https://www.w3.org/TR/mediaqueries-4/#mq-range-context) for defining +certain media queries: + +```css +@media (width > 500px) { + /* ... */ +} +``` + +Dart Sass 1.11 adds support for this syntax. It works just like existing media +query support: you can either use interpolation or plain Sass expressions to +inject Sass logic into the query, and they can still be nested. + +```scss +@media (width > $width) { + @media (height < #{$height}) { + /* ... */ + } +} +``` + +This feature isn't yet implemented in +[LibSass](https://github.com/sass/libsass/issues/2698) or [Ruby +Sass](https://github.com/sass/ruby-sass/issues/75). + +### Normalized Identifier Escapes + +The last compatibility improvement is a bit of an edge case, but it's still +worth mentioning: the way Sass parses escapes in identifiers has been improved +to better match the CSS spec. + +Escapes are now normalized to a standard format, which means that (for example) +`éclair` and `\E9clair` are parsed to the same value (in this case, `éclair`). +Prior to this change, if an escape was written, it would always be preserved +as-is, so `str-length(\E9clair)` would return `8` even though that identifier +means exactly the same thing to CSS as `éclair`. + +We don't anticipate this affecting many users, but we always strive to bring +Sass as close to the semantics of CSS as possible. This is a small but important +step on that path. + +This feature isn't yet implemented in +[LibSass](https://github.com/sass/libsass/issues/2700) or [Ruby +Sass](https://github.com/sass/ruby-sass/issues/76). diff --git a/source/blog/018-feature-watchcontent-arguments-and-color-functions.html.md b/source/blog/018-feature-watchcontent-arguments-and-color-functions.html.md new file mode 100644 index 000000000..6690fc233 --- /dev/null +++ b/source/blog/018-feature-watchcontent-arguments-and-color-functions.html.md @@ -0,0 +1,136 @@ +--- +title: 'Feature Watch: Content Arguments and Color Functions' +author: Natalie Weizenbaum +tags: blog +#date: 2018-11-14 14:14 PST +--- + +Dart Sass 1.15, released today and available [on +npm](https://npmjs.com/package/sass) and [all other distribution +channels](/install), brings with it a number of highly-anticipated new Sass +features. This is also the first release of Dart Sass with major new language +features that _aren't_ just for CSS compatibility. That's a big accomplishment, +and we intend to continue that pattern moving forward! + +### `@content` Arguments + +Mixins that take [`@content` +blocks](/documentation/file.SASS_REFERENCE.html#mixin-content) can now pass +arguments to those blocks. This is written `@content()`. If a +mixin passes arguments to its content block, users of that mixin must accept +those arguments by writing `@include using ()`. The +argument list for a content block works just like a mixin's argument list, and +the arguments passed to it by `@content` work just like passing arguments to a +mixin. + +```scss +// style.scss +@mixin media($types...) { + @each $type in $types { + @media #{$type} { + @content ($type); + } + } +} + +@include media(screen, print) using ($type) { + h1 { + font-size: 40px; + @if $type == print { + font-family: Calluna; + } + } +} +``` + +```css +/* style.css */ +@media screen { + h1 { + font-size: 40px; + } +} +@media print { + h1 { + font-size: 40px; + font-family: Calluna; + } +} +``` + +For more details, see [the feature +proposal](https://github.com/sass/language/blob/main/accepted/content-args.md). +This feature is implemented in LibSass, and will be released in version 3.6.0. +Since [Ruby Sass is deprecated](/blog/ruby-sass-is-deprecated) and this isn't a +CSS compatibility feature, it won't be implemented in Ruby Sass. + +### Color Level 4 Syntax for `rgb()` and `hsl()` + +The [CSS Color Module Level 4](https://drafts.csswg.org/css-color/) has +introduced new syntax for the `rgb()` and `hsl()` functions, which has begun to +be supported in browsers. This syntax makes these functions more compact, allows +the alpha value to be specified without needing additional `rgba()` and `hsla()` +functions, and it looks like `rgb(0 255 0 / 0.5)` and `hsla(0 100% 50%)`. + +To support this function, Sass's `rgb()` and `hsl()` functions now accept a +space-separated list of components as a single argument. If this last argument +is a slash-separated pair of numbers, the first number will be treated as the +blue channel or lightness (respectively) and the second as the alpha channel. + +**Be aware though** that the normal rules for [disambiguating between division +and `/` as a +separator](/documentation/file.SASS_REFERENCE.html#division-and-slash) still +apply! So if you want to pass a variable for the alpha value, you'll need to use +the old `rgba()` syntax. We're [considering possible long-term +solutions](https://github.com/sass/sass/issues/2565) for this problem as `/` is +used more prominently as a separator in CSS. + +In addition, the new color spec defines the `rgba()` and `hsla()` functions as +pure aliases for `rgb()` and `hsl()`, and adds support for the four-argument +`rgba()` and `hsla()` syntax to `rgb()` and `hsl()` as well. To match this +behavior, Sass is also defining `rgba()` and `hsla()` as aliases and adding +support for all their definitions to `rgb()` and `hsl()`. + +All in all, this means that the function calls like all of the following are +newly supported in Sass: + +- `rgb(0 255 0)`, `rgb(0% 100% 0%)`, `rgb(0 255 0 / 0.5)`, and `rgb(0, 255, 0, +0.5)`; +- `hsl(0 100% 50%)`, `hsl(0 100% 50% / 0.5)`, and `hsl(0, 100%, 50%, 0.5)`; +- `rgba(0, 255, 0)` and `hsla(0, 100%, 50%)`; +- and `rgb($color, 0.5)`. + +This change is fully backwards-compatible, so all the arguments to `rgb()`, +`hsl()`, `rgba()`, and `hsla()` that previously worked will continue to do so. + +For more details, see [the feature +proposal](https://github.com/sass/language/blob/main/accepted/color-4-rgb-hsl.md). +This feature isn't yet implemented in +[LibSass](https://github.com/sass/libsass/issues/2722) or [Ruby +Sass](https://github.com/sass/ruby-sass/issues/84). + +### Interpolated At-Rule Names + +This feature is a little smaller than the last two, but it's been on the to-do +list for even longer: adding support for interpolation in the names of at-rules! +This works just how you'd expect: + +```scss +@mixin viewport($prefixes) { + @each $prefix in $prefixes { + @- #{$prefix}-viewport { + @content; + } + } + @viewport { + @content; + } +} +``` + +For more details, see [the feature +proposal](https://github.com/sass/language/blob/main/accepted/at-rule-interpolation.md). +This feature isn't yet implemented in +[LibSass](https://github.com/sass/libsass/issues/2721). Since [Ruby Sass is +deprecated](http://sass.logdown.com/posts/7081811) and this isn't a CSS +compatibility feature, it won't be implemented in Ruby Sass. diff --git a/source/blog/019-request-for-comments-module-system-proposal.html.md b/source/blog/019-request-for-comments-module-system-proposal.html.md new file mode 100644 index 000000000..d1f2563ae --- /dev/null +++ b/source/blog/019-request-for-comments-module-system-proposal.html.md @@ -0,0 +1,402 @@ +--- +title: 'Request For Comments: Module System' +author: Natalie Weizenbaum +tags: blog +#date: 2018-11-27 13:10 PST +--- + +Many of the most frequently-requested features for Sass have to do with its +imports. The import system that we've had since the very early releases of Sass +is, to put it simply, not great. It does little more than textually include one +Sass file in another, which makes it hard to keep track of where mixins, +functions, and variables were defined and hard to be sure that any new additions +won't happen to conflict with something elsewhere in the project. To make +matters worse, it overlaps with CSS's built-in `@import` rule, which forces us +to have [a bunch of heuristics](/documentation/file.SASS_REFERENCE.html#import) +to decide which is which. + +Because of these problems and others, we've wanted to do a full overhaul of the +way Sass files relate to one another for a long time. Over the last few years, +I've been working with the Sass core team and Sass framework maintainers to +create a proposal for a module system that's fit to replace `@import`. That +proposal is now in a place that the core team is pretty happy with, at least as +a starting point, so we want to open it up for community feedback. + +If you want to read the full proposal, [it's available on +GitHub](https://github.com/sass/language/blob/main/accepted/module-system.md). +Feel free to [file issues](https://github.com/sass/language/issues/new) for any +feedback you have. The main body of the proposal is written as a spec, so it's +very detailed, but the Goals, Summary, and FAQ sections (reproduced below) +should be accessible to anyone familiar with Sass. + +## Goals + +### High-Level + +These are the philosophical design goals for the module system as a whole. While +they don't uniquely specify a system, they do represent the underlying +motivations behind many of the lower-level design decisions. + +- **Locality**. The module system should make it possible to understand a Sass + file by looking only at that file. An important aspect of this is that names + in the file should be resolved based on the contents of the file rather than + the global state of the compilation. This also applies to authoring: an author + should be able to be confident that a name is safe to use as long as it + doesn't conflict with any name visible in the file. + +- **Encapsulation**. The module system should allow authors, particularly + library authors, to choose what API they expose. They should be able to define + entities for internal use without making those entities available for external + users to access or modify. The organization of a library's implementation into + files should be flexible enough to change without changing the user-visible + API. + +- **Configuration**. Sass is unusual among languages in that its design leads to + the use of files whose entire purpose is to produce side effects—specifically, + to emit CSS. There's also a broader class of libraries that may not emit CSS + directly, but do define configuration variables that are used in computations, + including computation of other top-level variables' values. The module system + should allow the user to flexibly use and configure modules with side-effects. + +### Low-Level + +These are goals that are based less on philosophy than on practicality. For the +most part, they're derived from user feedback that we've collected about +`@import` over the years. + +- **Import once**. Because `@import` is a literal textual inclusion, multiple + `@import`s of the same Sass file within the scope of a compilation will + compile and run that file multiple times. At best this hurts compilation time + for little benefit, and it can also contribute to bloated CSS output when the + styles themselves are duplicated. The new module system should only compile a + file once. + +- **Backwards compatibility**. We want to make it as easy as possible for people + to migrate to the new module system, and that means making it work in + conjunction with existing stylesheets that use `@import`. Existing stylesheets + that only use `@import` should have identical importing behavior to earlier + versions of Sass, and stylesheets should be able to change parts to `@use` + without changing the whole thing at once. + +### Non-Goals + +These are potential goals that we have explicitly decided to avoid pursuing as +part of this proposal for various reasons. Some of them may be on the table for +future work, but we don't consider them to be blocking the module system. + +- **Dynamic imports**. Allowing the path to a module to be defined dynamically, + whether by including variables or including it in a conditional block, moves + away from being declarative. In addition to making stylesheets harder to read, + this makes any sort of static analysis more difficult (and actually impossible + in the general case). It also limits the possibility of future implementation + optimizations. + +- **Importing multiple files at once**. In addition to the long-standing reason + that this hasn't been supported—that it opens authors up to sneaky and + difficult-to-debug ordering bugs—this violates the principle of locality by + obfuscating which files are imported and thus where names come from. + +- **Extend-only imports**. The idea of importing a file so that the CSS it + generates isn't emitted unless it's `@extend`ed is cool, but it's also a lot + of extra work. This is the most likely feature to end up in a future release, + but it's not central enough to include in the initial module system. + +- **Context-independent modules**. It's tempting to try to make the loaded form + of a module, including the CSS it generates and the resolved values of all its + variables, totally independent of the entrypoint that cause it to be loaded. + This would make it possible to share loaded modules across multiple + compilations and potentially even serialize them to the filesystem for + incremental compilation. + + However, it's not feasible in practice. Modules that generate CSS almost + always do so based on some configuration, which may be changed by different + entrypoints rendering caching useless. What's more, multiple modules may + depend on the same shared module, and one may modify its configuration before + the other uses it. Forbidding this case in general would effectively amount to + forbidding modules from generating CSS based on variables. + + Fortunately, implementations have a lot of leeway to cache information that + the can statically determine to be context-independent, including source trees + and potentially even constant-folded variable values and CSS trees. Full + context independence isn't likely to provide much value in addition to that. + +- **Increased strictness**. Large teams with many people often want stricter + rules around how Sass stylesheets are written, to enforce best practices and + quickly catch mistakes. It's tempting to use a new module system as a lever to + push strictness further; for example, we could make it harder to have partials + directly generate CSS, or we could decline to move functions we'd prefer + people avoid to the new built-in modules. + + As tempting as it is, though, we want to make all existing use-cases as easy + as possible in the new system, _even if we think they should be avoided_. This + module system is already a major departure from the existing behavior, and + will require a substantial amount of work from Sass users to support. We want + to make this transition as easy as possible, and part of that is avoiding + adding any unnecessary hoops users have to jump through to get their existing + stylesheets working in the new module system. + + Once `@use` is thoroughly adopted in the ecosystem, we can start thinking + about increased strictness in the form of lints or TypeScript-style + `--strict-*` flags. + +- **Code splitting**. The ability to split monolithic CSS into separate chunks + that can be served lazily is important for maintaining quick load times for + very large applications. However, it's orthogonal to the problems that this + module system is trying to solve. This system is primarily concerned with + scoping Sass APIs (mixins, functions, and placeholders) rather than declaring + dependencies between chunks of generated CSS. + + We believe that this module system can work in concert with external + code-splitting systems. For example, the module system can be used to load + libraries that are used to style individual components, each of which is + compiled to its own CSS file. These CSS files could then declare dependencies + on one another using special comments or custom at-rules and be stitched + together by a code-splitting post-processor. + +## Summary + +This proposal adds two at-rules, `@use` and `@forward`, which may only appear at +the top level of stylesheets before any rules (other than `@charset`). Together, +they're intended to completely replace `@import`, which will eventually be +deprecated and even more eventually removed from the language. + +### `@use` + +`@use` makes CSS, variables, mixins, and functions from another stylesheet +accessible in the current stylesheet. By default, variables, mixins, and +functions are available in a namespace based on the basename of the URL. + +```scss +@use 'bootstrap'; + +.element { + @include bootstrap.float-left; +} +``` + +In addition to namespacing, there are a few important differences between `@use` +and `@import`: + +- `@use` only executes a stylesheet and includes its CSS once, no matter how + many times that stylesheet is used. +- `@use` only makes names available in the current stylesheet, as opposed to + globally. +- Members whose names begin with `-` or `_` are private to the current + stylesheet with `@use`. +- If a stylesheet includes `@extend`, that extension is only applied to + stylesheets it imports, not stylesheets that import it. + +Note that placeholder selectors are _not_ namespaced, but they _do_ respect +privacy. + +#### Controlling Namespaces + +Although a `@use` rule's default namespace is determined by the basename of its +URL, it can also be set explicitly using `as`. + +```scss +@use 'bootstrap' as b; + +.element { + @include b.float-left; +} +``` + +The special construct `as *` can also be used to include everything in the +top-level namespace. Note that if multiple modules expose members with the same +name and are used with `as *`, Sass will produce an error. + +```scss +@use 'bootstrap' as *; + +.element { + @include float-left; +} +``` + +#### Configuring Libraries + +With `@import`, libraries are often configured by setting global variables that +override `!default` variables defined by those libraries. Because variables are +no longer global with `@use`, it supports a more explicit way of configuring +libraries: the `with` clause. + +```scss +// bootstrap.scss +$paragraph-margin-bottom: 1rem !default; + +p { + margin-top: 0; + margin-bottom: $paragraph-margin-bottom; +} +``` + +```scss +@use 'bootstrap' with ( + $paragraph-margin-bottom: 1.2rem +); +``` + +This sets bootstrap's `$paragraph-margin-bottom` variable to `1.2rem` before +evaluating it. The `with` clause only allows variables defined in (or forwarded +by) the module being imported, and only if they're defined with `!default`, so +users are protected against typos. + +### `@forward` + +The `@forward` rule includes another module's variables, mixins, and functions +as part of the API exposed by the current module, without making them visible to +code within the current module. It allows library authors to be able to split up +their library among many different source files without sacrificing locality +within those files. Unlike `@use`, forward doesn't add any namespaces to names. + +```scss +// bootstrap.scss +@forward 'functions'; +@forward 'variables'; +@forward 'mixins'; +``` + +#### Visibility Controls + +A `@forward` rule can choose to show only specific names: + +```scss +@forward 'functions' show color-yiq; +``` + +It can also hide names that are intended to be library-private: + +```scss +@forward 'functions' hide assert-ascending; +``` + +#### Extra Prefixing + +If you forward a child module through an all-in-one module, you may want to add +some manual namespacing to that module. You can do what with the `as` clause, +which adds a prefix to every member name that's forwarded: + +```scss +// material/_index.scss +@forward 'theme' as theme-*; +``` + +This way users can use the all-in-one module with well-scoped names for theme +variables: + +```scss +@use 'material' with ( + $theme-primary: blue +); +``` + +or they can use the child module with simpler names: + +```scss +@use 'material/theme' with ( + $primary: blue +); +``` + +### `@import` Compatibility + +The Sass ecosystem won't switch to `@use` overnight, so in the meantime it needs +to interoperate well with `@import`. This is supported in both directions: + +- When a file that contains `@import`s is `@use`d, everything in its global + namespace is treated as a single module. This module's members are then + referred to using its namespace as normal. + +- When a file that contains `@use`s is `@import`ed, everything in its public API + is added to the importing stylesheet's global scope. This allows a library to + control what specific names it exports, even for users who `@import` it rather + than `@use` it. + +In order to allow libraries to maintain their existing `@import`-oriented API, +with explicit namespacing where necessary, this proposal also adds support for +files that are only visible to `@import`, not to `@use`. They're written +`"file.import.scss"`, and imported when the user writes `@import "file"`. + +### Built-In Modules + +The new module system will also add seven built-in modules: `math`, `color`, +`string`, `list`, `map`, `selector`, and `meta`. These will hold all the +existing built-in Sass functions. Because these modules will (typically) be +imported with a namespace, it will be much easier to use Sass functions without +running into conflicts with plain CSS functions. + +This in turn will make it much safer for Sass to add new functions. We expect to +add a number of convenience functions to these modules in the future. + +#### `meta.load-css()` + +This proposal also adds a new built-in mixin, `meta.load-css($url, $with: ())`. +This mixin dynamically loads the module with the given URL and includes its CSS +(although its functions, variables, and mixins are not made available). This is +a replacement for nested imports, and it helps address some use-cases of dynamic +imports without many of the problems that would arise if new members could be +loaded dynamically. + +## Frequently Asked Questions + +- **Why this privacy model?** We considered a number of models for declaring + members to be private, including a JS-like model where only members that were + explicitly exported from a module were visible and a C#-like model with an + explicit `@private` keyword. These models involve a lot more boilerplate, + though, and they work particularly poorly for placeholder selectors where + privacy may be mixed within a single style rule. Name-based privacy also + provides a degree of compatibility with conventions libraries are already + using. + +- **Can I make a member library-private?** There's no language-level notion of a + "library", so library-privacy isn't built in either. However, members used by + one module aren't automatically visible to downstream modules. If a module + isn't [`@forward`ed](#forward) through a library's main stylesheet, it won't + be visible to downstream consumers and thus is effectively library-private. +

As a convention, we recommend that libraries write library-private + stylesheets that aren't intended to be used directly by their users in a + directory named `src`. + +- **How do I make my library configurable?** If you have a large library made up + of many source files that all share some core `!default`-based configuration, + we recommend that you define that configuration in a file that gets forwarded + from your library's entrypoint and used by your library's files. For example: + +```scss +// bootstrap.scss +@forward 'variables'; +@use 'reboot'; +``` + +```scss +// _variables.scss +$paragraph-margin-bottom: 1rem !default; +``` + +```scss +// _reboot.scss +@use 'variables' as *; + +p { + margin-top: 0; + margin-bottom: $paragraph-margin-bottom; +} +``` + +```scss +// User's stylesheet +@use 'bootstrap' with ( + $paragraph-margin-bottom: 1.2rem +); +``` + +## Sending Feedback + +This is still just a proposal. We're pretty happy with the overall shape of the +module system, but it's not at all set in stone, and anything can change with +enough feedback provided by users like you. If you have opinions, please [file +an issue on GitHub](https://github.com/sass/language/issues/new) or just [tweet +at @SassCSS](https://twitter.com/SassCSS). We'll take anything from "it looks +awesome" to "it looks awful", although the more specific you can be the more +information we have to work with! diff --git a/source/blog/020-ruby-sass-is-unsupported.html.md b/source/blog/020-ruby-sass-is-unsupported.html.md new file mode 100644 index 000000000..d5315c4a2 --- /dev/null +++ b/source/blog/020-ruby-sass-is-unsupported.html.md @@ -0,0 +1,58 @@ +--- +title: Ruby Sass Has Reached End-Of-Life +author: Natalie Weizenbaum +tags: blog +#date: 2019-04-03 16:15 PST +--- + +One year has passed since we announced [the deprecation of Ruby +Sass](/blog/ruby-sass-is-deprecated), and it has now officially reached its +end-of-life. We will release one final version of the Ruby Sass gem that will +print a warning indicating that it's no longer receiving updates, and then +archive [the GitHub repository](https://github.com/sass/ruby-sass). + +![A woman saying "Goodbye, my friend"](/assets/img/blog/020-goodbye.gif) + +We will then merge the [sass/language](https://github.com/sass/language) repo +into the [sass/sass](https://github.com/sass/sass) repo. This means that +**anyone still depending on Ruby Sass from `github.com/sass/sass` will break.** +Going forward, the sass/sass repo will be the location for working on the +language specs, and will not contain any code. The sass/language repo will just +include links pointing to sass/sass. + +### Migrating Away + +If you haven't migrated away from Ruby Sass yet, now is the time. The best way +to do that depends on how you use Ruby Sass today. + +If you use Ruby Sass as a command-line tool, the easiest way to migrate is to +[install Dart Sass](/install) as a command-line tool. It supports a similar +interface to Ruby Sass, and you can run `sass --help` for a full explanation of +its capabilities. + +If you use Ruby Sass as a plugin for a Ruby web app, particularly if you define +your own Sass functions in Ruby, the +[`sassc`](https://github.com/sass/sassc-ruby) gem provides access to +[LibSass](/libsass) from Ruby with a very similar API to Ruby Sass. In most +cases, you can just replace the `Sass` module with the `SassC` module and your +code will continue to work. + +If you're using Rails, we particularly recommend using the +[`sassc-rails`](https://github.com/sass/sassc-rails) gem, which wraps up the +`sassc` gem and integrates it smoothly into the asset pipeline. Most of the time +you won't even need to change any of your code. + +### Farewell, Ruby Sass! + +On a personal note, I started writing Ruby Sass in 2006 when I was just a +college kid coding in between homework assignments. I've worked on it (with +varying degrees of focus) continuously for the last 13 years, and I expect it'll +take me a long time to match that record with any other codebase. I'm glad to +see the language [moving forward](/blog/announcing-dart-sass), but at the same +time I'll miss Ruby Sass terribly. + +I also want to take this opportunity to thank our users, especially those in the +Ruby community in which Sass was born, for appreciating the language we created +and evangelizing it so widely. Sass has an incredible userbase, and I've been so +proud to see how large and diverse it's grown over the years. Let's keep it up +as we move into a new era of Sass! diff --git a/source/blog/021-brand-new-sass-docs.html.md b/source/blog/021-brand-new-sass-docs.html.md new file mode 100644 index 000000000..1fa28e228 --- /dev/null +++ b/source/blog/021-brand-new-sass-docs.html.md @@ -0,0 +1,34 @@ +--- +title: Brand New Sass Docs +author: Natalie Weizenbaum +tags: blog +#date: 2019-04-23 10:04 PST +--- + +I'm excited to announce the launch of [a full rewrite and redesign of the Sass +documentation](/documentation), going live today after eight months of work by +[Jina Anne](https://github.com/jina) and myself! Jina, the lead of Team Sass +Design, is responsible for the layout and visual design of the new +documentation. She made everything gorgeous and readable. +[I](https://github.com/nex3) wrote all the text, so if you see a typo I'm the +one to blame. + +A preview of the function documentation page. + +In addition to reorganizing and rewriting all the documentation, we've added a special example widget that makes it easy to see how Sass stylesheets translate into CSS. It has tabs for both SCSS and the indented syntax, so you can use whichever you prefer, or switch between them to see the difference. + +The example widget. + +The Sass function documentation is included in the rewrite. Functions are now organized into easy-to-understand sections, and Jina designed a super readable layout for them. + +The round() function. + +Best of all, the new documentation has full-text search courtesy of our friends +at [Algolia](https://www.algolia.com/). You can search for features, function +names, or anything else you want to learn more about and find it in an instant. + +![An Algolia search.](/assets/img/blog/021-search.png) + +Please take a look and enjoy! And if you find any issues, don't hesitate to +[file them](https://github.com/sass/sass-site/issues/new) so we can keep making +the website better and better. diff --git a/source/blog/022-request-for-commentsforward-slash-as-separator.html.md b/source/blog/022-request-for-commentsforward-slash-as-separator.html.md new file mode 100644 index 000000000..eb0aa9ec7 --- /dev/null +++ b/source/blog/022-request-for-commentsforward-slash-as-separator.html.md @@ -0,0 +1,84 @@ +--- +title: 'Request For Comments: Forward Slash as Separator' +author: Natalie Weizenbaum +tags: blog +#date: 2019-05-06 16:15 PST +--- + +Early on in Sass's history, the decision was made to use `/` as a division +operator, since that was (and is) by far the most common representation across +programming languages. The `/` character was used in very few plain CSS +properties, and for those it was an optional shorthand. So Sass defined [a set +of heuristics][] that defined when `/` would be rendered as a literal slash +versus treated as an operator. + +[a set of heuristics]: /documentation/operators/numeric#slash-separated-values + +For a long time, these heuristics worked pretty well. In recent years, however, +new additions to CSS such as [CSS Grid][] and [CSS Color Level 4][] have been +using `/` as a separator increasingly often. Using the same character for both +division and slash-separation is becoming more and more annoying to users, and +will likely eventually become untenable. + +[CSS Grid]: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row +[CSS Color Level 4]: https://drafts.csswg.org/css-color/#rgb-functions + +As such, we're planning to redefine `/` to be _only_ a separator. Rather than +creating an unquoted string (as it currently does when at least one operand +isn't a number), it will create a list with a new slash separator. For example, +`1 / 2 / 3` will be a three-element slash-separated list. Division will instead +be written as a function, `divide()` (or `math.div()` in [the new module +system][]). + +[the new module system]: /blog/request-for-comments-module-system-proposal + +## Rollout + +This is a major breaking change to existing Sass semantics, so we'll roll it out +in a three-stage process: + +1. The first stage won't introduce any breaking changes. It will: + + - Add a `divide()` function which will work exactly like the `/` operator + does today, except that it will produce deprecation warnings for any + non-number arguments. + - Add slash-separated lists to Sass's object models, _without_ a literal + syntax for creating them. That will come later, since it would otherwise be + a breaking change. + - Add a `slash-list()` function that will create slash-separated lists. + - Produce deprecation warnings for all `/` operations that are interpreted as + division. + +2. The second stage _will_ be a breaking change. It will: + + - Make `/` exclusively a list separator. + - Make `divide()` throw errors for non-number arguments. + - Deprecate the `slash-list()` function, since it will now be redundant. + +3. The third stage will just remove the `slash-list()` function. This is not a + priority, and will be delayed until the next major version release. + +## Giving Feedback + +If you want more details on exactly how the proposed behavior will work, [head +over to the Sass language repo and read the full +proposal](https://github.com/sass/sass/blob/main/accepted/slash-separator.md). +You can skip the Background and Summary sections, since they're included above. +Be aware, though, that it's written to be a specification; it's a great for +figuring out how exactly an edge case should work, but it's not as +conversational as the sections quoted above. + +If you have any issues with the proposal as written, or if it doesn't cover a +use-case that's important to you, [please bring that up in the Sass language +issue +tracker](https://github.com/sass/sass/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3A%22proposal%3A+slash+separator%22). +We'll be leaving it open for discussion for at least two weeks before we mark +the proposal as "accepted" and move on to the implementation phase. + +Please be aware, though, that while we welcome community feedback, the design of +Sass is ultimately in the hands of the language team. We'll absolutely consider +the perspectives and use-cases of users who speak up, but it's also our job to +consider all the users who are new to Sass or even to CSS and who don't yet know +to read blogs or comment on issue trackers. Remember that our careful +decision-making made Sass what it is today, and have patience with us if we +don't make the decisions you would have! diff --git a/source/blog/023-module-system-preview.html.md b/source/blog/023-module-system-preview.html.md new file mode 100644 index 000000000..84b560ef3 --- /dev/null +++ b/source/blog/023-module-system-preview.html.md @@ -0,0 +1,52 @@ +--- +title: Module System Preview +author: Natalie Weizenbaum +tags: blog +#date: 2019-09-04 15:14 PST +--- + +Exciting news, Sass fans! After a year of development and some iteration on the +spec, we're ready to launch a beta preview of the new Sass module system! We may +still make a few last-minute tweaks based on user feedback, so don't go using +itin production just yet, but please do take this opportunity to play around +with it and let us know what you think. + +## Installing the Preview + +The preview release is available on all the normal distribution channels as +version `1.23.0-module.beta.1`. You can download it from the [GitHub release +page](https://github.com/sass/dart-sass/releases/tag/1.23.0-module.beta.1), or +install it using one of the following commands (depending on your preferred +installation channel): + +```shellsession +$ npm install --save-dev sass@1.23.0-module.beta.1 + +$ npm install -g sass@1.23.0-module.beta.1 + +$ brew install sass/sass/sass@1.23.0-module.beta.1 + +$ choco install sass --version 1.23.0.modulebeta-1 + +$ pub global activate sass 1.23.0-module.beta.1 +``` + +Note that 1.23.0 may not _actually_ be the final version number for the stable +module system release, it's just the next minor version number in Dart Sass's +release series. + +## How to Use the Module System + +The original [summary of the module +system](/blog/request-for-comments-module-system-proposal) is still a great way +to learn how it works. You can also check out the [official +proposal](https://github.com/sass/sass/blob/main/accepted/module-system.md) +for a much more detailed dive into its behavior. + +## Sending Feedback + +If you have opinions on the module system, please [file an issue on +GitHub](https://github.com/sass/language/issues/new) or just [tweet at +@SassCSS](https://twitter.com/SassCSS). We'll take anything from "it looks +awesome" to "it looks awful", although the more specific you can be the more +information we have to work with! diff --git a/source/blog/024-the-module-system-is-launched.html.md b/source/blog/024-the-module-system-is-launched.html.md new file mode 100644 index 000000000..4e023b821 --- /dev/null +++ b/source/blog/024-the-module-system-is-launched.html.md @@ -0,0 +1,362 @@ +--- +title: The Module System is Launched +author: Natalie Weizenbaum +tags: blog +#date: 2019-10-01 18:58 PST +--- + +The Sass team has known for years that the `@import` rule, one of the earliest +additions to Sass, wasn't as good as we wanted it. It caused a litany of +problems for our users: + +- It was next to impossible to figure out where a given variable, mixin, or + function (collectively called "members") was originally defined, since + anything defined in one stylesheet was available to all stylesheets that were + imported after it. + +- Even if you chose to explicitly import every stylesheet that defined members + you used, you'd end up with duplicate CSS and strange side-effects, because + stylesheets were reloaded from scratch every time they were imported. + +- It wasn't safe to use terse and simple names because there was always a + possibility that some other stylesheet elsewhere in your application would use + the same name and mess up your logic. To be safe users had to manually add + long, awkward namespaces to everything they defined. + +- Library authors had no way to ensure that their private helpers wouldn't be + accessed by downstream users, causing confusion and backwards-compatibility + headaches. + +- The [`@extend` rule][] could affect any selector anywhere in the stylesheet, + not just those that its author explicitly chose to extend. + + [`@extend` rule]: /documentation/at-rules/extend + +We also knew that any replacement we wanted to introduce would have to be +designed and developed with the utmost care to ensure it would provide a +rock-solid foundation for the future of Sass development. Over the past few +years, we've discussed, designed, and developed a brand-new module system that +solves these problems and more, and today we're excited to announce that it's +available in Dart Sass 1.23.0. + +Please note that the module system is _fully backwards-compatible_. No existing +features have been removed or deprecated, and your current Sass stylesheets will +keep working just as they always have. We designed the module system to be +[fully interoperable with `@import`](#import-compatibility) to make it easy for +stylesheet authors to migrate to it incrementally. We do plan to [eventually get +rid of `@import`](#future-plans), but not until long after everyone's had a +chance to migrate. + +## `@use`, the Heart of the Module System + +The [`@use` rule][] is the primary replacement for `@import`: it makes CSS, +variables, mixins, and functions from another stylesheet accessible in the +current stylesheet. By default, variables, mixins, and functions are available +in a namespace based on the basename of the URL. + +[`@use` rule]: /documentation/at-rules/use + +```scss +@use 'bootstrap'; + +.element { + background-color: bootstrap.$body-bg; + @include bootstrap.float-left; +} +``` + +In addition to namespacing, there are a few important differences between `@use` +and `@import`: + +- `@use` only executes a stylesheet and includes its CSS once, no matter how + many times that stylesheet is used. +- `@use` only makes names available in the current stylesheet, as opposed to globally. +- Members whose names begin with `-` or `_` are private to the current + stylesheet with `@use`. +- If a stylesheet includes `@extend`, that extension is only applied to + stylesheets it imports, not stylesheets that import it. + +Note that placeholder selectors are _not_ namespaced, but they _do_ respect +privacy. + +### Controlling Namespaces + +Although a `@use` rule's default namespace is determined by the basename of its +URL, it can also be set explicitly using `as`. + +```scss +@use 'bootstrap' as b; + +.element { + @include b.float-left; +} +``` + +The special construct `as *` can also be used to include everything in the +top-level namespace. Note that if multiple modules expose members with the same +name and are used with `as *`, Sass will produce an error. + +```scss +@use 'bootstrap' as *; + +.element { + @include float-left; +} +``` + +#### Configuring Libraries + +With `@import`, libraries are often configured by setting global variables that +override `!default` variables defined by those libraries. Because variables are +no longer global with `@use`, it supports a more explicit way of configuring +libraries: the `with` clause. + +```scss +// bootstrap.scss +$paragraph-margin-bottom: 1rem !default; + +p { + margin-top: 0; + margin-bottom: $paragraph-margin-bottom; +} +``` + +```scss +@use 'bootstrap' with ( + $paragraph-margin-bottom: 1.2rem +); +``` + +This sets bootstrap's `$paragraph-margin-bottom` variable to `1.2rem` before +evaluating it. The `with` clause only allows variables defined in (or forwarded +by) the module being imported, and only if they're defined with `!default`, so +users are protected against typos. + +## `@forward`, for Library Authors + +The [`@forward` rule][] includes another module's variables, mixins, and +functions as part of the API exposed by the current module, without making them +visible to code within the current module. It allows library authors to be able +to split up their library among many different source files without sacrificing +locality within those files. Unlike `@use`, forward doesn't add any namespaces +to names. + +[`@forward` rule]: /documentation/at-rules/forward + +```scss +// bootstrap.scss +@forward 'functions'; +@forward 'variables'; +@forward 'mixins'; +``` + +### Visibility Controls + +A `@forward` rule can choose to show only specific names: + +```scss +@forward 'functions' show color-yiq; +``` + +It can also hide names that are intended to be library-private: + +```scss +@forward 'functions' hide assert-ascending; +``` + +### Extra Prefixing + +If you forward a child module through an all-in-one module, you may want to add +some manual namespacing to that module. You can do what with the `as` clause, +which adds a prefix to every member name that's forwarded: + +```scss +// material/_index.scss +@forward 'theme' as theme-*; +``` + +This way users can use the all-in-one module with well-scoped names for theme +variables: + +```scss +@use 'material' with ( + $theme-primary: blue +); +``` + +or they can use the child module with simpler names: + +```scss +@use 'material/theme' with ( + $primary: blue +); +``` + +## Built-In Modules + +The new module system also adds [built-in modules](/documentation/modules) +(`sass:math`, `sass:color`, `sass:string`, `sass:list`, `sass:map`, +`sass:selector`, and `sass:meta`) to hold all the existing built-in Sass +functions. Because these modules will (typically) be imported with a namespace, +it's now much easier to use Sass functions without running into conflicts with +plain CSS functions. + +This in turn makes it much safer for Sass to add new functions. We expect to add a number of convenience functions to these modules in the future. + +### Renamed Functions + +Some functions have different names in the built-in modules than they did as +global functions. Built-in functions that already had manual namespaces, like +[`map-get()`](/documentation/modules/map#get), have those namespaces removed in +the built-in modules so you can just write `map.get()`. Similarly, +[`adjust-color()`](/documentation/modules/color#adjust), +[`scale-color()`](/documentation/modules/color#scale), and +[`change-color()`](/documentation/modules/color#change) are now +`color.adjust()`, `color.scale()`, and `color.change()`. + +We've also taken this opportunity to change a couple confusing old function +names. [`unitless()`](/documentation/modules/math#unitless) is now +`math.is-unitless()`, and +[`comparable()`](/documentation/modules/math#compatible) is now +`math.compatible()`. + +### Removed Functions + +Sass's shorthand color functions `lighten()`, `darken()`, `saturate()`, +`desaturate()`, `opacify()`, `fade-in()`, `transparentize()`, and `fade-out()` +all had very unintuitive behavior. Rather than scaling their associated +attributes fluidly, they just incremented them by a static amount, so that +`lighten($color, 20%)` would return `white` for a color with `85%` lightness +rather than returning a color with `88%` lightness (`20%` closer to full white). + +To help set us on the path towards fixing this, these functions (along with +`adjust-hue()`) aren't included in the new built-in modules. You can still get +the same effect by calling +[`color.adjust()`](/documentation/modules/color#adjust)—for example, +`lighten($color, $amount)` is equivalent to `color.adjust($color, $lightness: +$amount)`—but we recommend trying to use +[`color.scale()`](/documentation/modules/color#scale) instead if possible +because of how much more intuitive it is. + +At some point in the future, we plan to add `color.lighten()` and similar +functions as shorthands for `color.scale()`. + +### `meta.load-css()` + +The new module system comes with a new built-in mixin, [`meta.load-css($url, +$with: ())`](/documentation/modules/meta#load-css). This mixin dynamically loads +the module with the given URL and includes its CSS (although its functions, +variables, and mixins are not made available). This is a replacement for nested +imports, and it helps address some use-cases of dynamic imports without many of +the problems that would arise if new members could be loaded dynamically. + +## `@import` Compatibility + +The Sass ecosystem won't switch to `@use` overnight, so in the meantime it needs +to [interoperate well with +`@import`](/documentation/at-rules/import#import-and-modules). +This is supported in both directions: + +- When a file that contains `@import`s is `@use`d, everything in its global + namespace is treated as a single module. This module's members are then + referred to using its namespace as normal. + +- When a file that contains `@use`s is `@import`ed, everything in its public API + is added to the importing stylesheet's global scope. This allows a library to + control what specific names it exports, even for users who `@import` it rather + than `@use` it. + +In order to allow libraries to maintain their existing `@import`-oriented API, +with explicit namespacing where necessary, this proposal also adds support for +files that are only visible to `@import`, not to `@use`. They're written +`"file.import.scss"`, and imported when the user writes `@import "file"`. + +## Automatic Migration + +Concurrent with the launch of the new module system, we're launching a new +[automated Sass migrator](/documentation/cli/migrator). This tool makes it easy +to migrate most stylesheets to use the new module system automatically. Follow +the instructions on [the Sass website](/documentation/cli/migrator#installation) +to install it, then run it on your application: + +```shellsession +$ sass-migrator module --migrate-deps +``` + +The [`--migrate-deps` flag](/documentation/cli/migrator#migrate-deps) tells the +migrator to migrate not only the file you pass, but anything it imports as well. +The migrator will automatically pick up files imported through [Webpack's +`node_modules` +syntax](https://github.com/webpack-contrib/sass-loader#resolving-import-at-rules), +but you can also pass explicit load paths with the [`--load-path` +flag](/documentation/cli/migrator#load-path). + +If you want the migrator to tell you what changes it would make without actually +making them, pass both the [`--dry-run` +flag](/documentation/cli/migrator#dry-run) and the [`--verbose` +flag](/documentation/cli/migrator#verbose) to tell it to just print out the +changes it would make without saving them to disk. + +### Migrating a Library + +If you want to migrate a Sass library that's meant for downstream users to load +and use, run: + +```shellsession +$ sass-migrator module --migrate-deps --forward=all +``` + +The [`--forward` flag](/documentation/cli/migrator#forward) tells the migrator +to add [`@forward` rules](/documentation/at-rules/forward) so that users can +still load all the mixins, variables, and functions your library defines with a +single `@use`. + +If you added a manual namespace to your library to avoid name conflicts, the +migrator will remove it for you if you pass the [`--remove-prefix` +flag](/documentation/cli/migrator#remove-prefix). You can even choose to only +forward members that originally had that prefix by passing `--forward=prefixed`. + +### Filing Issues + +The migration tool is brand new, so it may still have some rough edges. If you +run into any problems, please don't hesitate to [file an issue on +GitHub](https://github.com/sass/migrator/issues/new)! + +## Try It Now! + +The module system is available as part of Dart Sass 1.23.0. You can install it +right now using: + +```shellsession +$ npm install -g sass +``` + +Alternately, check out [the installation page](/install) for all the different +ways it can be installed! + +## Future Plans + +The Sass team wants to allow for a large amount of time when `@use` and +`@import` can coexist, to help the ecosystem smoothly migrate to the new system. +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 Dart Sass and LibSass have launched 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), we will + 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 + latest), we will drop support for `@import` and most global functions + entirely. This 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.~~ + +**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/source/blog/025-request-for-comments-nested-map-functions.md b/source/blog/025-request-for-comments-nested-map-functions.md new file mode 100644 index 000000000..be9c88a91 --- /dev/null +++ b/source/blog/025-request-for-comments-nested-map-functions.md @@ -0,0 +1,141 @@ +--- +title: 'Request for Comments: Nested Map Functions' +author: Natalie Weizenbaum +tags: blog +#date: 2020-9-16 14:40 PST +--- + +As Sass libraries and design systems get more complex and have more users with +different needs, they tend to develop the need to share and override +configuration and design tokens. This configuration is often hierarchical, and +ends up being represented as maps that contain maps that contain still more +maps. Up until now, Sass's map functions haven't really made it easy to work +with this sort of nested map structure. But that's changing with the latest +language proposal, written by Sass core team member [Miriam Suzanne]. + +[Miriam Suzanne]: https://www.miriamsuzanne.com/ + +This proposal expands the existing map functions and adds a few new ones to make +working with nested maps much easier than it was before. It's based on helper +functions that pop up in all sorts of Sass projects around the web, +incorporating best practices back into the language itself. + +## The Functions + +Here are the new and improved functions this proposal adds: + +### `map.get()` and `map.has-key()` + +The [`map.get()`] and [`map.has-key()`] functions both now take any number of +keys as arguments. Each key drills deeper into a nested map, allowing you to +easily inspect nested values without needing to chain a bunch of function calls +together. + +[`map.get()`]: https://sass-lang.com/documentation/modules/map#get +[`map.has-key()`]: https://sass-lang.com/documentation/modules/map#has-key + +For example, let's take the following simplified configuration map: + +```scss +$config: ( + 'colors': ( + 'primary': red, + 'secondary': blue, + ), +); +``` + +For this map, `map.get($config, "colors", "primary")` gets the value of the +`"colors"` key (`("primary": red)`) then the value of the `"primary"` key and +returns `red`. + +Similarly, `map.has-key($config, "colors", "primary")` returns `true` while +`map.has-key($config, "colors", "tertiary")` returns `false`. + +### `map.merge()` + +The [`map.merge()`] function can now be called as `map.merge($map1, $keys..., +$map2)`. This will merge `$map2` with a child of `$map1` at the location given +by the keys, updating the parent maps as it goes. + +[`map.merge()`]: https://sass-lang.com/documentation/modules/map#merge + +For example, using the configuration map [defined above] `map.merge($config, +"colors", ("primary": green))` will return + +[defined above]: #map-get-and-map-has-key + +``` +( + "colors": ( + "primary": green, + "secondary": blue + ) +) +``` + +### `map.set()` + +The `map.set($map, $keys..., $value)` function is all-new. Although updating +individual values in maps was always possible with `map.merge()`, we've found +that users get confused by the absence of a dedicated `set()` function. This +function not only fills that role, but makes it possible to set values within +nested maps as well. + +You can use `map.set()` for normal single-layer maps by just passing one key. +For example, `map.set(("wide": 200px, "narrow": 70px), "wide", 180px)` will +return `("wide": 180px, "narrow": 70px)`. + +But you can also use it for nested maps. For example, `map.set($config, +"colors", "tertiary", yellow)` will return + +``` +( + "colors": ( + "primary": red, + "secondary": blue, + "tertiary": yellow + ) +) +``` + +### `map.deep-remove()` + +Because the existing [`map.remove()`] function already takes any number of +arguments, we couldn't just update it to work with nested maps. Instead, we +chose to add a new function just for nested maps, called `map.deep-remove($map, +$keys...)`. This function removes the value at the final key in the list, and +updates all the parent maps accordingly. + +[`map.remove()`]: https://sass-lang.com/documentation/modules/map#remove + +For example, `map.deep-remove($config, "colors", "secondary")` will return +`("colors": ("primary": red))`. + +### `map.deep-merge()` + +The final new function may be the most exciting. `map.deep-merge($map1, $map2)` +works just like `map.merge()`, except that any nested maps are _also_ merged, +including maps within those maps and so on. This makes it easy to combine two +configuration maps that have the same structure without having to manually merge +each level by hand. + +For example, `map.deep-merge($config, ("colors": ("secondary": teal)))` returns + +``` +( + "colors": ( + "primary": red, + "secondary": teal + ) +) +``` + +## Let us know what you think! + +If you're interested in learning more about this proposal, [read it in full] on +GitHub. It's open for comments and revisions for the next month, so if you'd +like to see something change please [file an issue] and we can discuss it! + +[read it in full]: https://github.com/sass/sass/tree/main/accepted/nested-map-functions.md +[file an issue]: https://github.com/sass/sass/issues/new diff --git a/source/blog/026-request-for-comments-hwb-functions.md b/source/blog/026-request-for-comments-hwb-functions.md new file mode 100644 index 000000000..c881f7f77 --- /dev/null +++ b/source/blog/026-request-for-comments-hwb-functions.md @@ -0,0 +1,67 @@ +--- +title: 'Request for Comments: HWB Functions' +author: Natalie Weizenbaum +tags: blog +#date: 2020-10-06 16:00 PST +--- + +The CSS working group has been up to all sorts of exciting stuff recently in the +[Color Level 4] spec, and the Sass team is starting to think about how to +integrate those cool new features into Sass's color model. We need more time to +hammer out exactly the right designs for complex features like the Lab color +space, but that doesn't mean we can't add a few new color goodies. + +[Color Level 4]: https://www.w3.org/TR/css-color-4/ + +Today we're announcing a proposal for one such feature: built-in Sass functions +for [HWB] colors! Once this proposal (drafted by Sass core team member [Miriam +Suzanne]) is accepted and implemented, you'll be able to write colors in HWB +syntax and adjust their whiteness and blackness the same way you can adjust a +color's saturation and lightness today. + +[HWB]: https://www.w3.org/TR/css-color-4/#the-hwb-notation +[Miriam Suzanne]: https://www.miriamsuzanne.com/ + +## The Functions + +Here are the new and improved functions this proposal adds: + +### `color.hwb()` + +The `color.hwb()` function defines a color using its hue, whiteness, and +blackness. Like the existing `rgb()` and `hsl()` functions, It can either use +the space-separated syntax defined in [the spec][HWB] (`hwb(270 20% 40%)`) or +the more Sass-y comma-separated syntax (`hwb(270, 20%, 40%)`). Because HWB +colors use the same sRGB colorspace as all other Sass color values, colors +created this way are fully compatible with all existing Sass color functions and +will be emitted as their RGB equivalents for maximum browser compatibility. + +Note that _unlike_ `rgb()` and `hsl()`, the proposal doesn't add this function +to the global scope yet. This is because Sass has a policy of never adding +support for new CSS syntax before at least one browser implements it. Specs have +a tendency to change until they're locked in by browsers, and if Sass ends up +supporting something different than the browsers themselves that's bad news! + +### `color.whiteness()` and `color.blackness()` + +These functions work like the `color.saturation()` and `color.lightness()` +functions do for HSL colors. They even work for colors that weren't created with +`color.hwb()`, so you can use them to check how pale or dark any color is. + +Because HWB colors have the same notion of "hue" as HSL colors, the existing +`color.hue()` function already works perfectly! + +### `color.scale()`, `color.adjust()`, and `color.change()` + +All three color modification functions now support `$whiteness` and `$blackness` +arguments. If you want a color (again no matter how it was created) to be 20% +whiter, just pass it to `color.scale($color, $whiteness: 20%)` and there you go! + +## Let us know what you think! + +If you’re interested in learning more about this proposal, [read it in full] on +GitHub. It’s open for comments and revisions for the next month, so if you’d +like to see something change please [file an issue] and we can discuss it! + +[read it in full]: https://github.com/sass/sass/tree/main/proposal/color-4-hwb.md +[file an issue]: https://github.com/sass/sass/issues/new diff --git a/source/blog/027-libsass-is-deprecated.md b/source/blog/027-libsass-is-deprecated.md new file mode 100644 index 000000000..d5acf66b1 --- /dev/null +++ b/source/blog/027-libsass-is-deprecated.md @@ -0,0 +1,136 @@ +--- +title: LibSass is Deprecated +author: Natalie Weizenbaum +tags: blog +#date: 2020-10-26 12:00 PST +--- + +After much discussion among the Sass core team, we've come to the conclusion +that it's time to officially declare that LibSass and the packages built on top +of it, including Node Sass, are deprecated. For several years now, it's been +clear that there's simply not enough engineering bandwidth behind LibSass to +keep it up-to-date with the latest developments in the Sass language (for +example, the most recent new language feature was added in [November 2018]). As +much as we've hoped to see this pattern turn around, even the excellent work of +long-time LibSass contributors Michael Mifsud and Marcel Greter couldn't keep up +with the fast pace of language development in both CSS and Sass. + +[November 2018]: https://github.com/sass/libsass/releases/tag/3.5.5 + +I'll go into detail about what this means below, but here are the major points: + +- We no longer recommend LibSass for new Sass projects. Use [Dart Sass] instead. + + [Dart Sass]: https://sass-lang.com/dart-sass + +- We recommend all existing LibSass users make plans to eventually move onto + Dart Sass, and that all Sass libraries make plans to eventually drop support + for LibSass. + +- We're no longer planning to add any new features to LibSass, including + compatibility with new CSS features. + +- LibSass and Node Sass will continue to be maintained indefinitely on a + best-effort basis, including fixing major bugs and security issues and + maintaining compatibility with the latest Node versions. + +## Why deprecate? + +For several years now, Sass has managed to exist in an ambiguous kind of state +where LibSass was an officially-supported implementation in theory, but its +feature surface was static in practice. As time has gone on, it's becoming +increasingly clear that this state causes substantial concrete problems for Sass +users. For example, we regularly see users confused as to why [plain-CSS `min()` +and `max()` don't work] and assuming Sass as a whole is at fault, when in fact +it's only LibSass that doesn't support that feature. + +[plain-CSS `min()` and `max()` don't work]: https://github.com/sass/sass/issues/2849 + +Official support for LibSass doesn't just cause pain for individual users. +Because LibSass doesn't support the [Sass module system] that launched last +year, major shared Sass libraries have been unable to use it for fear that their +downstream users would be incompatible. By clearly indicating that all Sass +users should eventually move off of LibSass, we hope to make it more feasible +for these library authors to use more modern features. + +[Sass module system]: https://sass-lang.com/blog/the-module-system-is-launched + +LibSass has even inhibited the development of the Sass language itself. We've +been unable to move forward with the proposal for [treating `/` as a separator] +because any code they'd write would either produce deprecation warnings in Dart +Sass or fail to compile in LibSass. By marking LibSass as deprecated, this +becomes much more feasible, and Sass becomes much better at supporting the +latest versions of CSS. + +[treating `/` as a separator]: https://github.com/sass/sass/blob/main/accepted/slash-separator.md + +## What does "deprecated" mean? + +We're choosing to use the term "deprecated" because it carries a lot of weight +in the programming community, and provides a strong signal that users should +start planning to move away from LibSass. However, it doesn't mean that the +project is entirely dead. Michael Mifsud, the lead maintainer of LibSass and +Node Sass, has affirmed that he plans to continue maintenance on the same level +as the past few years. This means that although there will be no more features +added (and as such LibSass will slowly drift further and further out of +compatibility with the latest CSS and Sass syntax), there will continue to be +maintenance releases indefinitely. + +## What about portability and performance? + +LibSass today has two major benefits over Dart Sass: + +- **Portability**: since it's written in C++, it's easy to embed LibSass within + other programming languages and provide a native-feeling API. + +- **Performance**: calling out to LibSass via the C++ API is very fast relative + to the speeds of code written directly in scripting languages. In particular, + this means LibSass is substantially faster in JavaScript than Dart + Sass-compiled-to-JS (although it's comparable to Dart Sass's command-line + executable). + +We're working on addressing both of those with the [Sass embedded protocol], +which runs a Sass compiler as a subprocess that can communicate with any host +language via message-passing. The embedded protocol supports all the features of +a native Sass API, including the ability to define custom importers and Sass +functions, while also providing the high performance of the CLI app. Dart Sass +has already implemented the compiler side of the embedded protocol, and a +JavaScript host for it is in active development. + +[Sass embedded protocol]: https://github.com/sass/embedded-protocol + +## How do I migrate? + +If you're a user of Node Sass, migrating to Dart Sass is straightforward: just +replace `node-sass` in your `package.json` file with `sass`. Both packages +expose the same JavaScript API. + +If you're using the SassC command-line interface, you can switch to [Dart Sass's +CLI]. Note that this doesn't have exactly the same interface as SassC, so you +may need to change a few flags. + +[Dart Sass's CLI]: https://sass-lang.com/documentation/cli/dart-sass + +If you're using LibSass through a wrapper library in another language, you can +either switch to the Dart Sass CLI or ask the maintainer of the LibSass wrapper +to convert it to a host for the [Sass embedded protocol]. The embedded protocol +allows any language to provide a native API that calls out to Dart Sass. + +Please note that because activity on LibSass has been low for several years, it +has a number of outstanding bugs and behavioral variations from the Sass spec. +You may need to make minor updates to stylesheets to make them compatible with +Dart Sass. See [this list of major compatibility issues] for reference. + +[this list of major compatibility issues]: https://github.com/sass/libsass/issues?q=is%3Aopen+is%3Aissue+label%3A%22Compatibility+-+P1+%E2%9A%A0%EF%B8%8F%22 + +## Thank you + +Finally, I want to thank everyone who's put so much time and energy into LibSass +and Node Sass over the years. It will always be a towering achievement, and +Sass's popularity outside of the Ruby community is undoubtedly due in large part +to its existence. Many people have tried to implement Sass only to find that the +language is much deeper and more complex than they expected, and LibSass alone +among all of those implementations managed to become fully-featured enough to +provide real value for thousands if not millions of users. These maintainers +deserve to be proud of that work, and I hope they'll always consider themselves +part of the Sass community going forward. diff --git a/source/blog/028-request-for-comments-first-class-calc.md b/source/blog/028-request-for-comments-first-class-calc.md new file mode 100644 index 000000000..97cb2a2e0 --- /dev/null +++ b/source/blog/028-request-for-comments-first-class-calc.md @@ -0,0 +1,78 @@ +--- +title: 'Request for Comments: First-Class Calc' +author: Natalie Weizenbaum +tags: blog +# date: 2021-3-15 1:35 PST +--- + +One of the absolutely most-requested features in Sass is the ability to more +easily work with `calc()` expressions. These expressions have historically been +parsed opaquely: between the parentheses, you can put any text at all, and +Sass will just treat it as an unquoted string. This has simplified Sass's +parser, since we don't have to support the specific `calc()` microsyntax, and +it's meant that we automatically support new features like the use of [CSS +variables] within `calc()`. + +[CSS variables]: https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties + +However, it comes at a substantial usability cost as well. Because each `calc()` +is totally opaque to Sass's parser, users can't simply use Sass variables in +place of values; they have to [interpolate] variables explicitly. And once a +`calc()` expression has been created, there's no way to manipulate it with Sass +the way you can manipulate a plain number. + +[interpolate]: https://sass-lang.com/documentation/interpolation + +We're looking to change that with a new proposal we call "First-Class Calc". +This proposal changes `calc()` (and other supported mathematical functions) from +being parsed as unquoted strings to being parsed in-depth, and sometimes +(although not always) producing a new data type known as a "calculation". This +data type represents mathematical expressions that can't be resolved at +compile-time, such as `calc(10% + 5px)`, and allows those expressions to be +combined gracefully within further mathematical functions. + +To be more specific: a `calc()` expression will be parsed according to the [CSS +syntax], with additional support for Sass variables, functions, and (for +backwards compatibility) interpolation. Sass will perform as much math as +possible at compile-time, and if the result is a single number it will return it +as a normal Sass number type. Otherwise, it will return a calculation that +represents the (simplified) expression that can be resolved in the browser. + +[CSS syntax]: https://drafts.csswg.org/css-values-3/#calc-syntax + +For example: + +- `calc(1px + 10px)` will return the number `11px`. + +- Similarly, if `$length` is `10px`, `calc(1px + $length)` will return `11px`. + +- However, `calc(1px + 10%)` will return the calc `calc(1px + 10%)`. + +- If `$length` is `calc(1px + 10%)`, `calc(1px + $length)` will return + `calc(2px + 10%)`. + +- Sass functions can be used directly in `calc()`, so `calc(1% + +math.round(15.3px))` returns `calc(1% + 15px)`. + +Note that calculations cannot generally be used in place of numbers. For +example, `1px + calc(1px + 10%)` will produce an error, as will +`math.round(calc(1px + 10%))`. This is because calculations can't be used +interchangeably with numbers (you can't pass a calculation to `math.sqrt()`), so +we want to make sure mathematical functions are explicit about whether or not +they support calculations by either wrapping all of their math in `calc()` or +using normal Sass arithmetic. + +For backwards compatibility, `calc()` expressions that contain interpolation +will continue to be parsed using the old highly-permissive syntax, although this +behavior will eventually be deprecated and removed. These expressions will still +return calculation values, but they'll never be simplified or resolve to plain +numbers. + +## Let us know what you think! + +If you're interested in learning more about this proposal, [read it in full] on +GitHub. It's open for comments and revisions for the next month, so if you'd +like to see something change please [file an issue] and we can discuss it! + +[read it in full]: https://github.com/sass/sass/tree/main/proposal/first-class-calc.md +[file an issue]: https://github.com/sass/sass/issues/new diff --git a/source/blog/029-node-fibers-discontinued.md b/source/blog/029-node-fibers-discontinued.md new file mode 100644 index 000000000..1d296f817 --- /dev/null +++ b/source/blog/029-node-fibers-discontinued.md @@ -0,0 +1,161 @@ +--- +title: 'The Discontinuation of node-fibers' +author: Natalie Weizenbaum +tags: blog +# date: 2021-3-26 15:00 PST +--- + +We have recently received the unfortunate but not entirely surprising news that +[the `node-fibers` package has reached its end-of-life] and will not be updated +for compatibility with Node 16. Dart Sass has historically allowed JavaScript +users to pass in `node-fibers` to improve the performance of the asynchronous +`render()` method, but going forward this will unfortunately no longer be an +option in Node 16 and on. + +[the `node-fibers` package has reached its end-of-life]: https://github.com/laverdet/node-fibers/commit/8f2809869cc92c28c92880c4a38317ae3dbe654d + +There are a number of [alternative options] for reclaiming this lost +performance, some of them which are available today, some which are in +development, and some which are theoretical but could be made real with pull +requests from users like you. Sadly, none of the options that are ready today +are drop-in solutions with the same level of ease-of-use as `node-fibers`, so if +that performance is crucial to you we recommend staying on Node 14 for the time +being. + +[alternative options]: #reclaiming-performance + +## What Happened? + +In order to understand how we got here, it's important to know two pieces of +history. First, why does Dart Sass use `node-fibers` in the first place? And +second, why is `node-fibers` dying? + +_This section is fairly technical, so feel free to [skip ahead] if you don't care +about the gory details._ + +[skip ahead]: #reclaiming-performance + +### Fibers in Sass + +Dart Sass inherited its [JavaScript API] from the now-deprecated [Node Sass]. +This API has two main functions for compiling Sass files: `renderSync()` which +synchronously returned the compiled CSS, and `render()` which instead takes a +callback to which it passes the compiled CSS asynchronously. Only `render()` +allowed asynchronous plugins, including widely-used importers such as webpack's +[`sass-loader`], so `render()` became very widely used in practice. + +[JavaScript API]: /documentation/js-api +[Node Sass]: https://www.npmjs.com/package/node-sass +[`sass-loader`]: https://www.npmjs.com/package/sass-loader + +For Node Sass, the performance difference between `render()` and `renderSync()` +was negligible, because it was built on C++ code which had few restrictions on +how it handled asynchrony. However, Dart Sass runs as pure JavaScript, which +makes it subject to JavaScript's strict async rules. Asynchrony in JavaScript is +_contagious_, which means that if any function (such as an importer plugin) is +asynchronous, then everything that calls it must be asynchronous, and so on +until the entire program is asynchronous. + +And asynchrony in JavaScript isn't free. Every asynchronous function call has to +allocate callbacks, store them somewhere, and take a trip back to the event loop +before invoking those callbacks, and that all takes time. In fact, it takes +enough time that the asynchronous `render()` in Dart Sass tends to be 2-3x +slower than `renderSync()`. + +Enter fibers. Fibers are a very cool concept, available in languages like Ruby +and C++, that give the programmer more control over asynchronous functions. They +can even allow a chunk of synchronous code (such as the Sass compiler) to call +asynchronous callbacks (such as the webpack plugin). The `node-fibers` package +did some arcane magick with the V8 virtual machine to implement Fibers in +JavaScript, which allowed Dart Sass to use the fast synchronous code to +implement the asynchronous `render()` API. And for a time, it was great. + +### The Death of Fibers + +Unfortunately, the arcane magick that `node-fibers` used involved accessing some +parts of V8 that were not officially part of its public API. There was no +guarantee that the interfaces they were using would stay the same from release +to release, and indeed they tended to change fairly regularly. For a long time, +those changes were small enough that it was possible to release a new version of +`node-fibers` that supported them, but with Node.js 16 the luck ran out. + +The latest version of V8 involves some major overhauls to its internals. These +will eventually allow it to implement some cool improvements, so its hard to +begrudge, but a side effect is that the APIs `node-fibers` was using are +completely gone without an obvious replacement. This is no one's fault: since +those interfaces weren't part of V8's public API, they were under no obligation +to keep them stable. Sometimes in software that's just the way things go. + +## Reclaiming Performance + +There are a few options for getting back the performance that's lost by no +longer being able to pass `node-fibers` to `sass.render()`. In order from +nearest to longest term: + +### Avoid Asynchronous Plugins + +This is something you can do today. If it's at all possible to make the plugins +you pass in to Sass synchronous, you can use the `renderSync()` method which +doesn't need fibers to go fast. This may require rewriting some existing +plugins, but it will pay dividends immediately. + +### Embedded Dart Sass + +While it's not ready for prime-time yet, the Sass team is working on a project +called "embedded Dart Sass". This involves running Dart Sass as a _subprocess_, +rather than a library, and communicating with it using a special protocol. This +provides several important improvements over the existing alternatives: + +- Unlike running `sass` from the command line, this will still work with plugins + like the webpack importer. In fact, we plan to match the existing JavaScript + API as closely as possible. This will probably run asynchronous plugins _even + faster_ than synchronous ones. + +- Unlike the existing JS-compiled version, this will use the Dart VM. Due to the + more static nature of the Dart language, the Dart VM runs Sass substantially + faster than Node.js, which will provide about a 2x speed improvement for large + stylesheets. + +The Node.js host for Embedded Sass is still in active development, but there's +[a beta release] available (with minimal features) if you want to kick the +tires. + +[a beta release]: https://www.npmjs.com/package/sass-embedded + +### Worker Threads + +We've explored the possibility of running the pure-JS Dart Sass in a Node.js +worker thread. Worker threads work a bit like fibers in that they make it +possible for synchronous code to wait for asynchronous callbacks to run. +Unfortunately, they're also _extremely_ restrictive about what sorts of +information can be passed across the thread boundary, which makes it much harder +to use them to wrap a complex API like Sass's. + +At the moment, the Sass team is focused on Embedded Sass, so we don't have the +spare bandwidth to dive into worker threads as an alternative. That said, we'd +be happy to help a motivated user implement this. If you're interested, follow +up on [the GitHub issue]! + +[the GitHub issue]: https://github.com/sass/dart-sass/issues/868 + +### Reanimating `node-fibers` + +There's one other potential solution, although it would take true dedication to +turn into reality. It would in principle be possible to add a new API to V8 that +would _officially_ support the hooks `node-fibers` needs to do its good work. +This would allow the package to return gloriously to life and Sass to make +`render()` fast on into the future. + +The Sass team has contacted both the V8 team and the owner of `node-fibers`, and +both of them are amenable to this idea in principle. While neither one has the +time to see it through to completion themselves, they've expressed willingness +to help an engineer who's willing to give it a shot. + +This isn't a contribution for the faint of heart, though: it requires knowledge +of C++, a willingness to learn at least the basics of the `node-fibers` codebase +and V8's isolate APIs, and skills in both API design and human interaction to +negotiate a stable API that will meet the needs of `node-fibers` _and_ that the +V8 team feels comfortable committing to maintain. But if you're interested, +please don't hesitate to [reach out]! + +[reach out]: mailto:nweiz@google.com diff --git a/source/blog/030-request-for-comments-new-js-api.html.md b/source/blog/030-request-for-comments-new-js-api.html.md new file mode 100644 index 000000000..575f17a93 --- /dev/null +++ b/source/blog/030-request-for-comments-new-js-api.html.md @@ -0,0 +1,801 @@ +--- +title: 'Request for Comments: New JS API' +author: Natalie Weizenbaum +tags: blog +# date: 2021-08-05 15:30 PST +--- + +I'm excited to officially unveil something that's been in the works for quite a +while now: a (proposal for a) brand new JavaScript API for Sass. This API has +been redesigned from the ground up based on lessons learned from both the Node +Sass API and various other historical Sass APIs in other languages through the +years, and it addresses many of the shortcomings of the existing API. + +The API has four main components, all of which I'll cover in this post: + +- [The core compilation API](#compilation) +- [The logger API](#loggers) +- [The importer API](#importers) +- [The function API](#functions) + +As you read on, remember that this API is still just a proposal. We want to hear +from you, our users, whether it meets your needs and how we can improve it +before we lock it in to a full release. So go ahead and make your voices known +[on the issue tracker]! + +[on the issue tracker]: https://github.com/sass/sass/issues/new + +## Why a New API? + +The existing JavaScript API is showing its age. It predates Dart Sass, having +been originally designed for the `node-sass` package, which wrapped the +now-[deprecated] [LibSass] implementation. (That's why we call it the "Node Sass +API"!) It grew organically and often messily along with LibSass, and ended up +with more than a few awkward legacy behaviors. Many of these behaviors are more +of a pain for implementation than anything else, but a few of them made life +quite difficult: + +[deprecated]: /blog/libsass-is-deprecated +[LibSass]: /libsass + +- The importer API was built around file paths rather than URLs, and was tightly + coupled to the physical filesystem. This made it impossible to override _all_ + file-based loads and present a fully virtual filesystem, and caused custom + Node importers to interact poorly with the new [module system]. + +- The function API was built around mutable value objects, which runs counter to + Sass's immutable nature. It also provided no utility methods (such as looking + up a key in a map) to make it easier to implement idiomatic custom functions, + and didn't provide access to crucial information about values such as whether + strings were quoted. + +- All of the asynchronous functions were callback-based rather than + promise-based. + +[module system]: https://sass-lang.com/blog/the-module-system-is-launched + +The new API addresses these issues and more with a modern, idiomatic API that +will make working with Sass from JS a breeze. + +## Compilation + +At the heart of the API are four functions that do the actual Sass compilation, +two synchronous and two asynchronous. They're presented here in TypeScript +syntax to clarify exactly what they take and return, but you can always call +them from plain JS: + +```ts +function compile(path: string, options?: Options<'sync'>): CompileResult; + +function compileString( + source: string, + options?: StringOptions<'sync'>, +): CompileResult; + +function compileAsync( + path: string, + options?: Options<'async'>, +): Promise; + +function compileStringAsync( + source: string, + options?: StringOptions<'async'>, +): Promise; +``` + +The `compile()` and `compileAsync()` functions load a Sass file from a path on +disk, whereas `compileString()` and `compileStringAsync()` compile Sass source +code passed in as a string. All these take the following options: + +- `alertAscii`: Whether errors and warnings should use only ASCII characters (as + opposed to, for example, Unicode box-drawing characters). +- `alertColor`: Whether errors and warnings should use terminal colors. +- `loadPaths`: A list of file paths to use to look up files to load, just like + `includePaths` in the old API. +- `importers`: A list of [custom importers](#importers) to use to load Sass + source files. +- `functions`: An object whose keys are Sass function signatures and whose + values are [custom functions](#functions). +- `quietDeps`: Whether to silence deprecation warnings in dependencies. +- `logger`: The [custom logger](#loggers) to use to emit warnings and debug + messages. +- `sourceMap`: Whether to generate a source map during compilation. +- `style`: The output style, `'compressed'` or `'expanded'`. +- `verbose`: Whether to emit every deprecation warning encountered. + +The `compileString()` and `compileStringAsync()` functions take a few additional +options: + +- `syntax`: The syntax of the file, `'scss'` (the default), `'indented'`, or + `'css'`. +- `url`: The [canonical URL](#canonicalizing) of the file. +- `importer`: The [custom importer](#importers) to treat as the file's source. + If this is passed, this importer will be used to resolve relative loads from + this stylesheet. + +All these functions return an object with the following fields: + +- `css`: The compiled CSS, as a string. +- `loadedUrls`: All the URLs loaded during the compilation, in no particular + order. +- `sourceMap`: The source map for the file if `sourceMap: true` was passed, as + a decoded object. + +As with the Node Sass API, the synchronous functions will be substantially +faster than their asynchronous counterparts. Unfortunately the new API will not +support the `fibers` option for speeding up asynchronous compilation, since [the +`fibers` package has been discontinued]. + +[the `fibers` package has been discontinued]: /blog/node-fibers-discontinued + +## Loggers + +The logger API gives you more fine-grained control over how and when warnings +and debug messages are emitted. Unlike other aspects of this proposal, a +`logger` option will also be added to the _old_ API to allow you to control your +messages there without needing to upgrade to the new API immediately. + +A logger implements the following interface: + +```ts +interface Logger { + warn?( + message: string, + options: { + deprecation: boolean; + span?: SourceSpan; + stack?: string; + }, + ): void; + + debug?(message: string, options: { span: SourceSpan }): void; +} +``` + +The `warn` function handles warnings, including both warnings from the compiler +itself and from `@warn` rules. It's passed: + +- The warning message +- A flag indicating whether it's specifically a deprecation warning +- A span indicating where the warning was located, if it comes from a specific + location +- The Sass stack trace at the point at which the warning was encountered, if it + was encountered during execution + +The `debug` function handles only `@debug` rules, and is just passed the message +and the rule's span. For more information on the `SourceSpan` type, see [the +Logger proposal]. + +[the Logger proposal]: https://github.com/sass/sass/tree/main/proposal/js-logger.d.ts + +Sass will also provide a built-in logger, `Logger.silent`, that never emits any +messages. This will allow you to easily run Sass in "quiet mode" where no +warnings are ever surfaced. + +## Importers + +Rather than modeling importers as single-function callbacks, the new API models +them as objects that expose two methods: one that _canonicalizes_ a URL, and one +that _loads_ a canonical URL. + +```ts +// Importers for compileAsync() and compileStringAsync() are the same, except +// they may return Promises as well. +interface Importer { + canonicalize(url: string, options: { fromImport: boolean }): URL | null; + + load(canonicalUrl: URL): ImporterResult | null; +} +``` + +Note that even stylesheets that are loaded directly from the filesystem through +`compile()` or `loadPaths` are treated as though they're loaded by an importer. +This built-in filesystem importer canonicalizes all paths to `file:` URLs, and +loads those URLs from the physical filesystem. + +### Canonicalizing + +The first step determines the canonical URL for a stylesheet. Each stylesheet +has exactly one canonical URL that in turn refers to exactly one stylesheet. The +canonical URL must be absolute, including a scheme, but the specific structure +is up to the importer. In most cases, the stylesheet in question will exist on +disk and the importer will just return a `file:` URL for it. + +The `canonicalize()` method takes a URL string that may be either relative or +absolute. If the importer recognizes that URL, it returns a corresponding +absolute URL (including a scheme). This is the _canonical URL_ for the +stylesheet in question. Although the input URL may omit a file extension or +an initial underscore, the canonical URL must be fully resolved. + +For a stylesheet that's loaded from the filesystem, the canonical URL will be +the absolute `file:` URL of the physical file on disk. If it's generated +in-memory, the importer should choose a custom URL scheme to guarantee that +its canonical URLs don't conflict with any other importer's. + +For example, if you're loading Sass files from a database, you might use the +scheme `db:`. The canonical URL for a stylesheet associated with key `styles` +in the database might be `db:styles`. + +This function also takes a `fromImport` option that indicates whether the +importer is being invoked from an `@import` rule (as opposed to `@use`, +`@forward`, or `meta.load-css()`). + +Having a canonical URL for each stylesheet allows Sass to ensure that the +same stylesheet isn't loaded multiple times in the new module system. + +#### Canonicalizing Relative Loads + +When a stylesheet tries to load a relative URL, such as `@use "variables"`, it's +not clear from the document itself whether that refers to a file that exists +relative to the stylesheet or to another importer or load path. Here's how the +importer API resolves that ambiguity: + +- First, the relative URL is resolved relative to the canonical URL of the + stylesheet that contained the `@use` (or `@forward` or `@import`). For + example, if the canonical URL is `file:///path/to/my/_styles.scss`, then the + resolved URL will be `file:///path/to/my/variables`. + +- This URL is then passed to the `canonicalize()` method of the importer that + loaded the old stylesheet. (That means it's important for your importers to + support absolute URLs!) If the importer recognizes it, it returns the + canonical value which is then passed to that importer's `load()`; otherwise, + it returns `null`. + +- If the old stylesheet's importer didn't recognize the URL, it's passed to all + the `importers`' canonicalize functions in the order they appear in `options`, + then checked for in all the `loadPaths`. If none of those recognizes it, the + load fails. + +It's important that local relative paths take precedence over other importers or +load paths, because otherwise your local stylesheets could get unexpectedly +broken by a dependency adding a file with a conflicting name. + +### Loading + +The second step actually loads the text of the stylesheet. The `load()` +method takes a canonical URL that was returned by `canonicalize()` and +returns the contents of the stylesheet at that URL. This is only called once +per compilation for each canonical URL; future loads of the same URL will +re-use either the existing module (for `@use` and `@forward`) or the parse +tree (for `@import`). + +The `load()` method returns an object with the following fields: + +- `css`: The text of the loaded stylesheet. +- `syntax`: The syntax of the file: `'scss'`, `'indented'`, or `'css'`. +- `sourceMapUrl`: An optional browser-accessible `URL` to include in source maps + when referring to this file. + +### `FileImporter` + +This proposal also adds a special type of importer known as a `FileImporter`. +This importer makes the common case of redirecting loads to somewhere on the +physical filesystem easier. It doesn't require the caller to implement +`load()`, since that's always going to be the same for files on disk. + +```ts +interface FileImporter { + findFileUrl( + url: string, + options: { fromImport: boolean }, + ): FileImporterResult | null; +} +``` + +The `findFileUrl()` method takes a relative URL and returns an object with the +following fields: + +- `url`: The absolute `file:` URL of the file to load. This URL doesn't need to + be fully canonicalized: the Sass compiler will take care of resolving + partials, file extensions, index files, and so on. +- `sourceMapUrl`: An optional browser-accessible `URL` to include in source maps + when referring to this file. + +## Functions + +The new function API's function type is very similar to the old API's: + +```ts +type CustomFunctionCallback = (args: Value[]) => Value; +``` + +The only differences are: + +- Async functions return a `Promise` rather than calling a callback. +- The value types themselves are different. + +The second point is pretty substantial, though! The new value types are much +more fleshed out than the old versions. Let's start with the parent class: + +```ts +abstract class Value { + /** + * Returns the values of `this` when interpreted as a list. + * + * - For a list, this returns its elements. + * - For a map, this returns each of its key/value pairs as a `SassList`. + * - For any other value, this returns a list that contains only that value. + */ + get asList(): List; + + /** Whether `this` is a bracketed Sass list. */ + get hasBrackets(): boolean; + + /** Whether `this` is truthy (any value other than `null` or `false`). */ + get isTruthy(): boolean; + + /** Returns JS's null if this is `sassNull`, or `this` otherwise. */ + get realNull(): null | Value; + + /** If `this` is a list, return its separator. Otherwise, return `null`. */ + get separator(): ListSeparator; + + /** + * Converts the Sass index `sassIndex` to a JS index into the array returned + * by `asList`. + * + * Sass indices start counting at 1, and may be negative in order to index + * from the end of the list. + */ + sassIndexToListIndex(sassIndex: Value): number; + + /** + * Returns `this` if it's a `SassBoolean`, and throws an error otherwise. + * + * The `name` parameter is used for error reporting. It should match the name + * of a parameter passed to the custom function (without the `$`). + */ + assertBoolean(name?: string): SassBoolean; + + /** + * Returns `this` if it's a `SassColor`, and throws an error otherwise. + * + * The `name` parameter is used for error reporting. It should match the name + * of a parameter passed to the custom function (without the `$`). + */ + assertColor(name?: string): SassColor; + + /** + * Returns `this` if it's a `SassFunction`, and throws an error otherwise. + * + * The `name` parameter is used for error reporting. It should match the name + * of the parameter passed to the custom function (without the `$`). + */ + assertFunction(name?: string): SassFunction; + + /** + * Returns `this` if it's a `SassMap` (or converts it to a `SassMap` if it's + * an empty list), and throws an error otherwise. + * + * The `name` parameter is used for error reporting. It should match the name + * of the parameter passed to the custom function (without the `$`). + */ + assertMap(name?: string): SassMap; + + /** + * Returns `this` if it's a `SassNumber`, and throws an error otherwise. + * + * The `name` parameter is used for error reporting. It should match the name + * of a parameter passed to the custom function (without the `$`). + */ + assertNumber(name?: string): SassNumber; + + /** + * Returns `this` if it's a `SassString`, and throws an error otherwise. + * + * The `name` parameter is used for error reporting. It should match the name + * of a parameter passed to the custom function (without the `$`). + */ + assertString(name?: string): SassString; + + /** + * Returns the value of `this` if it can be interpreted as a map. + * + * - If this is a map, returns its contents. + * - If this is an empty list, returns an empty map. + * - Otherwise, returns `null`. + */ + tryMap(): OrderedMap | null; + + /** Returns whether `this == other` in SassScript. */ + equals(other: Value): boolean; +} +``` + +There are a couple important things to note here: + +- Because CSS doesn't have a strong syntactic differentiation between a single + element and a list containing one element, any Sass value may be treated as + though it's a list. The `Value` makes it easy to follow this convention by + making the `asList()`, `hasBrackets()`, and `separator()` getters available + for every `Value`. + +- The list returned this was and the map returned by `asMap()` are immutable + types from the [`immutable` package]. This reflects Sass's built-in + immutability of all its types. Although these values can't be modified + directly, their APIs make it easy and efficient to create new values with + changes applied. + +- Sass's list-indexing conventions are different than JavaScript's. The + `sassIndexToListIndex()` function makes it easy to convert from Sass index to + JS index. + +- In Sass, any value may be used in a boolean context, with `false` + and `null` counting as "falsey" values. The `isTruthy` getter makes this + convention easy to follow. + +- The `assert*()` functions make it easy to ensure that you're being passed the + arguments you expect, and to throw an idiomatic error if you're not. They're + particularly useful for TypeScript users since they'll automatically narrow + the type of the `Value`. + +[`immutable` package]: https://immutable-js.com/ + +Most Sass values have their own subclasses, but there are three singleton values +that are just available as constants: `sassTrue`, `sassFalse`, and `sassNull` +represent Sass's `true`, `false`, and `null` values respectively. + +### Colors + +The new API's `SassColor` class provides access to colors in RGB, HSL, and HWB +format. As with built-in Sass color functions, any attribute can be accessed on +any color regardless of how it was initially created. + +```ts +class SassColor extends Value { + /** Creates an RGB color. */ + static rgb( + red: number, + green: number, + blue: number, + alpha?: number, + ): SassColor; + + /** Creates an HSL color. */ + static hsl( + hue: number, + saturation: number, + lightness: number, + alpha?: number, + ): SassColor; + + /** Creates an HWB color. */ + static hwb( + hue: number, + whiteness: number, + blackness: number, + alpha?: number, + ): SassColor; + + /** The color's red channel. */ + get red(): number; + + /** The color's green channel. */ + get green(): number; + + /** The color's blue channel. */ + get blue(): number; + + /** The color's hue. */ + get hue(): number; + + /** The color's saturation. */ + get saturation(): number; + + /** The color's lightness. */ + get lightness(): number; + + /** The color's whiteness. */ + get whiteness(): number; + + /** The color's blackeness. */ + get blackness(): number; + + /** The color's alpha channel. */ + get alpha(): number; + + /** + * Returns a copy of `this` with the RGB channels updated to match `options`. + */ + changeRgb(options: { + red?: number; + green?: number; + blue?: number; + alpha?: number; + }): SassColor; + + /** + * Returns a copy of `this` with the HSL values updated to match `options`. + */ + changeHsl(options: { + hue?: number; + saturation?: number; + lightness?: number; + alpha?: number; + }): SassColor; + + /** + * Returns a copy of `this` with the HWB values updated to match `options`. + */ + changeHwb(options: { + hue?: number; + whiteness?: number; + blackness?: number; + alpha?: number; + }): SassColor; + + /** Returns a copy of `this` with `alpha` as its alpha channel. */ + changeAlpha(alpha: number): SassColor; +} +``` + +### Numbers + +The `SassNumber` class stores its numerator and denominator units as arrays +rather than strings. In addition, it provides methods for asserting that it has +specific units (`assertNoUnits()`, `assertUnit()`) and for converting it to +specific units (`convert()`, `convertToMatch()`, `convertValue()`, +`convertValueToMatch()`, `coerce()`, `coerceValue()`, `coerceValueToMatch()`). + +Sass's numeric logic is also subtly different from JS, since Sass considers +numbers that differ by less than the 10th decimal digit to be identical. This +API provides a number of methods that help convert between this and JavaScript's +numeric logic. + +```ts +class SassNumber extends Value { + /** Creates a Sass number with no units or a single numerator unit. */ + constructor(value: number, unit?: string); + + /** Creates a Sass number with multiple numerator and/or denominator units. */ + static withUnits( + value: number, + options?: { + numeratorUnits?: string[] | List; + denominatorUnits?: string[] | List; + } + ): SassNumber; + + /** This number's value. */ + get value(): number; + + /** + * Whether `value` is an integer according to Sass's numeric logic. + * + * The integer value can be accessed using `asInt`. + */ + get isInt(): boolean; + + /** + * If `value` is an integer according to Sass's numeric logic, returns the + * corresponding JS integer, or `null` if `value` isn't an integer. + */ + get asInt(): number | null; + + /** This number's numerator units. */ + get numeratorUnits(): List; + + /** This number's denominator units. */ + get denominatorUnits(): List; + + /** Whether `this` has numerator or denominator units. */ + get hasUnits(): boolean; + + /** + * If `value` is an integer according to Sass's numeric logic, returns the + * corresponding JS integer, or throws an error if `value` isn't an integer. + * + * The `name` parameter is used for error reporting. It should match the name + * of the parameter passed to the custom function (without the `$`). + */ + assertInt(name?: string): number; + + /** + * If `value` is between `min` and `max` according to Sass's numeric logic, + * returns it clamped to that range. Otherwise, throws an error. + * + * The `name` parameter is used for error reporting. It should match the name + * of the parameter passed to the custom function (without the `$`). + */ + assertInRange(min: number, max: number, name?: string): number; + + /** + * Returns `this` if it has no units. Otherwise, throws an error. + * + * The `name` parameter is used for error reporting. It should match the name + * of a parameter passed to the custom function (without the `$`). + */ + assertNoUnits(name?: string): SassNumber; + + /** + * Returns `this` if it has `unit` as its single (numerator) unit. Otherwise, + * throws an error. + * + * The `name` parameter is used for error reporting. It should match the name + * of a parameter passed to the custom function (without the `$`). + */ + assertUnit(name?: stringunit: string): SassNumber; + + /** Returns whether `this` has the single numerator unit `unit`. */ + hasUnit(unit: string): boolean; + + /** Returns whether this number's units are compatible with `unit`. */ + compatibleWithUnit(unit: string): boolean; + + /** + * If this number's units are compatible with `newNumerators` and + * `newDenominators`, returns a new number with those units that's equal to + * `this`. Otherwise, throws an error. + * + * Note that unitless numbers are only compatible with other unitless numbers. + */ + convert( + newNumerators: string[] | List, + newDenominators: string[] | List + ): SassNumber; + + /** + * If this number's units are compatible with `other`'s, returns a new number + * with `other`'s units that's equal to `this`. Otherwise, throws an error. + * + * Note that unitless numbers are only compatible with other unitless numbers. + */ + convertToMatch(other: SassNumber): SassNumber; + + /** Equivalent to `convert(newNumerators, newDenominators).value`. */ + convertValue( + newNumerators: string[] | List, + newDenominators: string[] | List + ): number; + + /** Equivalent to `convertToMatch(other).value`. */ + convertValueToMatch(other: SassNumber): number; + + /** + * Like `convert()`, but if `this` is unitless returns a copy of it with the + * same value and the given units. + */ + coerce( + newNumerators: string[] | List, + newDenominators: string[] | List + ): SassNumber; + + /** + * Like `convertToMatch()`, but if `this` is unitless returns a copy of it + * with the same value and `other`'s units. + */ + coerceToMatch(other: SassNumber): SassNumber; + + /** Equivalent to `coerce(newNumerators, newDenominators).value`. */ + coerceValue( + newNumerators: string[] | List, + newDenominators: string[] | List + ): number; + + /** Equivalent to `coerceToMatch(other).value`. */ + coerceValueToMatch(other: SassNumber): number; +} +``` + +### Strings + +The `SassString` class provides access to information about whether or not the +string is quoted. As with lists, JS's notion of indexes differs from Sass's, so +it also provides the `sassIndexToStringIndex()` method to convert a JS index +into a Sass index. + +```ts +class SassString extends Value { + /** Creates a string with the given `text`. */ + constructor( + text: string, + options?: { + /** @default true */ + quotes: boolean; + }, + ); + + /** Creates an empty string`. */ + static empty(options?: { + /** @default true */ + quotes: boolean; + }): SassString; + + /** The contents of `this`. */ + get text(): string; + + /** Whether `this` has quotes. */ + get hasQuotes(): boolean; + + /** The number of Unicode code points in `text`. */ + get sassLength(): number; + + /** + * Converts the Sass index `sassIndex` to a JS index into `text`. + * + * Sass indices start counting at 1, and may be negative in order to index + * from the end of the list. In addition, Sass indexes strings by Unicode code + * point, while JS indexes them by UTF-16 code unit. + */ + sassIndexToStringIndex(sassIndex: Value): number; +} +``` + +### Lists + +As mentioned above, most list functions are on the `Value` superclass to make it +easy to follow the Sass convention of treating all values as lists. However, the +`SassList` class can still be constructed to make new lists: + +```ts +class SassList extends Value { + /** Creates a Sass list with the given `contents`. */ + constructor( + contents: Value[] | List, + options?: { + /** @default ',' */ + separator?: ListSeparator; + /** @default false */ + brackets?: boolean; + }, + ); + + /** Creates an empty Sass list. */ + static empty(options?: { + /** @default null */ + separator?: ListSeparator; + /** @default false */ + brackets?: boolean; + }): SassList; +} +``` + +### Maps + +The `SassMap` class simply exposes its contents as an `OrderedMap` from the +[`immutable` package]. + +```ts +class SassMap extends Value { + /** Creates a Sass map with the given `contents`. */ + constructor(contents: OrderedMap); + + /** Creates an empty Sass map. */ + static empty(): SassMap; + + /** Returns this map's contents. */ + get contents(): OrderedMap; +} +``` + +### Functions + +The `SassFunction` class is fairly restrictive: it just allows a new first-class +function to be created with a synchronous callback. These functions can't be +invoked by custom functions—but they still provide more power than the old API! + +```ts +class SassFunction extends Value { + /** + * Creates a Sass function value with the given `signature` that calls + * `callback` when it's invoked. + */ + constructor(signature: string, callback: CustomFunctionCallback); +} +``` + +## More Information + +If you want to know more about these proposals and see their most up-to-date +forms, they're available on GitHub to view in full: + +- [Compile API proposal](https://github.com/sass/sass/tree/main/proposal/new-js-api.d.ts) +- [Logger proposal](https://github.com/sass/sass/blob/main/proposal/js-logger.d.ts) +- [Importer proposal](https://github.com/sass/sass/blob/main/proposal/new-js-importer.d.ts) +- [Functions and values proposal](https://github.com/sass/sass/blob/main/proposal/new-function-and-values-api.d.ts) + +We're eager for feedback, so please [let us know what you think]! The proposals +in question will be open for at least a month after this blog post goes live, +and possibly more depending on how lively the discussion around them is. + +[let us know what you think]: https://github.com/sass/sass/issues/new diff --git a/source/blog/031-new-js-api-release-candidate.html.md b/source/blog/031-new-js-api-release-candidate.html.md new file mode 100644 index 000000000..79eaaea54 --- /dev/null +++ b/source/blog/031-new-js-api-release-candidate.html.md @@ -0,0 +1,56 @@ +--- +title: 'New JS API Release Candidate is Live' +author: Natalie Weizenbaum +tags: blog +# date: 2021-11-20 16:15 PST +--- + +The new JavaScript API that we [announced a few months ago] is now fully +implemented in Dart Sass and ready for you to try! The new API is designed to be +more idiomatic, performant, and usable than the old one, and we hope it'll be +adopted swiftly by tooling packages. + +Because this is such a substantial addition, we want to give users a chance to +kick the tires a bit before we set it in stone, so we've released it as a release +candidate in Dart Sass 1.45.0-rc.1. Download it, try it out, and let us know +what you think by [filing issues] or [sending us a tweet]. Unless major changes +are necessary, we plan to make a stable release some time next week. + +[announced a few months ago]: https://sass-lang.com/blog/request-for-comments-new-js-api +[filing issues]: https://github.com/sass/sass/issues/new +[sending us a tweet]: https://twitter.com/SassCSS + +## How to use it + +The new API comes with four new entrypoint functions: `compile()` and +`compileAsync()` take Sass file paths and return the result of compiling them to +CSS, while `compileString()` and `compileStringAsync()` take a +string of Sass source and compile it to CSS. Unlike the old API, the async +functions all return `Promise`s. As with the old API, the synchronous functions +are substantially faster than their async counterparts, so we recommend using +them if at all possible. + +```js +const sass = require('sass'); + +const result = sass.compileString(` +h1 { + font-size: 40px; + code { + font-face: Roboto Mono; + } +}`); +console.log(result.css); +``` + +Check out [the API docs] for more details on the API, including the brand-new +importer and custom function APIs. + +[the API docs]: /documentation/js-api + +## What about the old API? + +Once the new API has a stable release, we'll officially consider the old API to +be deprecated. Since it's still widely-used, we'll continue to maintain it for a +good long while going forward. Expect it to start printing a deprecation warning +in a year or so, and to be disabled for good once we release Dart Sass 2.0.0. diff --git a/source/blog/032-embedded-sass-is-live.md b/source/blog/032-embedded-sass-is-live.md new file mode 100644 index 000000000..bc201313b --- /dev/null +++ b/source/blog/032-embedded-sass-is-live.md @@ -0,0 +1,77 @@ +--- +title: 'Embedded Sass is Live' +author: Natalie Weizenbaum +tags: blog +# date: 2022-02-01 2:00 PST +--- + +After several years of planning and development, I'm excited to finally announce +the stable release of Embedded Dart Sass along with its first official wrapper, +the [`sass-embedded`] package available now on npm! + +[`sass-embedded`]: https://www.npmjs.com/package/sass-embedded + +Embedded Sass is an ongoing effort to make a highly-performant Sass library +available to as many different languages as possible, starting with Node.js. +Although Node.js already has access to the pure-JS `sass` package, the nature of +JavaScript inherently limits how quickly this package can process large Sass +files especially in asynchronous mode. We expect `sass-embedded` to be a major +boon to developers for whom compilation speed is a concern, particularly the +remaining users of `node-sass` for whom performance has been a major reason to +avoid Dart Sass. + +The `sass-embedded` package fully supports the [new JS API] as well as the +[legacy API] other than a few cosmetic options. You can use it as a drop-in +replacement for the `sass` package, and it should work with all the same build +plugins and libraries. Note that `sass-embedded` is a bit faster in +_asynchronous_ mode than it is in synchronous mode (whereas the `sass` package +was faster in synchronous mode). For substantial Sass files, running +`sass-embedded` in either mode will generally be much faster than `sass`. + +[new JS API]: https://sass-lang.com/documentation/js-api#usage +[legacy API]: https://sass-lang.com/documentation/js-api#legacy-api + +In order to limit the confusion about which version of which package supports +which feature, the `sass-embedded` package will always have the same version as +the `sass` package. When new features are added to the JS API, they'll be +supported at the same time in both packages, and when new language features are +added to Sass they'll always be included in a new `sass-embedded` release +straight away. + +## How it Works + +Embedded Sass is composed of three parts: + +1. [The compiler], a Dart executable that wraps Dart Sass and does the actual + heavy lifting of parsing and compiling the files. Dart native executables are + generally much faster than JavaScript, so using them for the + computationally-intensive work of stylesheet evaluation is where Embedded + Sass gets its speed. + +2. [The host], a library in any language (in this case JavaScript) that provides a + usable end-user API for invoking the compiler. The host provides callers with + configuration options, including the ability to define custom importers and + Sass functions that are used by the compilation. + +3. [The protocol], a [protocol-buffer]-based specification of how the host and + the compiler communicate with one another. This communication happens over + the standard input and output streams of the compiler executable, which is + invoked by the host to perform each compilation. + +[The compiler]: https://github.com/sass/dart-sass-embedded +[The host]: https://github.com/sass/embedded-host-node +[The protocol]: https://github.com/sass/embedded-protocol +[protocol-buffer]: https://en.wikipedia.org/wiki/Protocol_Buffers + +## Other Languages + +Embedded Sass was designed in part as a way for languages other than JavaScript +to have access to the full power of Sass compilation with custom importers and +functions, similarly to how C++ wrappers for [LibSass] worked in the past. We +hope that community members will use this protocol to implement embedded hosts +for many other popular frontend languages. If you end up doing so, message us +[on Twitter] or [Gitter] and we'll link it on this site! + +[LibSass]: https://sass-lang.com/libsass +[on Twitter]: https://twitter.com/SassCSS +[Gitter]: https://gitter.im/sass/sass diff --git a/source/blog/033-request-for-comments-strict-unary-operators.md b/source/blog/033-request-for-comments-strict-unary-operators.md new file mode 100644 index 000000000..01a85f268 --- /dev/null +++ b/source/blog/033-request-for-comments-strict-unary-operators.md @@ -0,0 +1,88 @@ +--- +title: 'Request for Comments: Strict Unary Operators' +author: Natalie Weizenbaum +tags: blog +# date: 2022-06-15 15:30 PST +--- + +Do you know what `margin: $a -$b` does in Sass? If you said "the same thing as +`margin: $a (-$b)`, I'm sorry, but you're wrong. It's _actually_ the same thing +as `margin: $a - $b`. Don't worry, you're not the first person to get tripped up +by this weird corner of Sass's parser! But our new language proposal aims to fix +that. + +In the [Strict Unary Operators] proposal, which is currently open for community +feedback, we propose to first deprecate and then eventually disallow expressions +of the form `$a -$b`. We know deprecations are never pleasant, but this should +be fairly painless as they go: you can simply write `$a - $b` or `$a (-$b)`, +depending which you intend. We'll also provide a [Sass migrator] migration to +automatically update your stylesheets. + +[strict unary operators]: https://github.com/sass/sass/blob/main/proposal/strict-unary.md +[Sass migrator]: https://sass-lang.com/documentation/cli/migrator + +**Deprecated:** + +- `$a -$b` will no longer be allowed, because it's unclear what the author + intended and the current behavior is likely to be incorrect. + +**Still allowed:** + +- `$a - $b` will continue to work, since it's clearly supposed to indicate + subtraction. + +- `$a (-$b)` will continue to work, since the parentheses make the unary minus + unambiguous. + +The `$a - $b` or `$a (-$b)` options are supported by all widely-used Sass +versions, so there shouldn't be any trouble for libraries to avoid this +deprecation warning and continue to support older Sass versions. In addition, +you can always use the [`--quiet-deps` command-line flag] or the [`quietDeps` JS +API option] to silence warnings from dependencies you don't control. + +[`--quiet-deps` command-line flag]: https://sass-lang.com/documentation/cli/dart-sass#quiet-deps +[`quietDeps` JS API option]: https://sass-lang.com/documentation/js-api/interfaces/Options#quietDeps + +## Why does it work this way? + +Why, you might wonder, does `$a -$b` parse this way in the first place? The +short answer is, "because other programming languages do it that way". In most +programming languages, operators are parsed the same way regardless of the +whitespace that may or may not surround them. If you parse `$a - $b` as +subtraction, you should parse `$a -$b` as subtraction as well. + +The problem for Sass is that we also inherit CSS's use of space-separated lists +of values, so in some contexts users expect to be able to write two expressions +next to one another and have them parse the same way they would if they were +each used on their own. These two principles come into conflict and produce the +confusion this proposal seeks to address. + +## Why not just change the way it works? + +In theory, we could change Sass so that `$a -$b` parses the same as `$a (-$b)`: +a space-separated list of two values, the latter with a unary minus. We chose +not to do that for two reasons: + +1. Pragmatically, it's more painful to make a breaking change that changes the + behavior of existing syntax than it is to make one that just forbids the + syntax entirely. It requires more releases and more different versions of + Sass with different behaviors. It also opens the door for a stylesheet that + upgrades many versions at once to switch to the new behavior _without + producing an error_, which could lead to the worst-case scenario: shipping + incorrect styles. + +2. It's not obvious that `$a -$b` _should_ parse as `$a (-$b)` in every case. + Users coming from other programming languages may expect it to parse the same + way it does in those languages. Even in Sass, `$a -$b` will continue to be a + valid binary operation within `calc()`. It may not be elegant style, but + sometimes formatting isn't at the top of an author's mind! + +## Let us know what you think! + +If you've got thoughts or opinions about this change, please read over [the full +proposal] and then [file an issue] with your feedback. We'll be leaving this +open to comments for a month, after which we'll finalize the proposal and start +implementing it. + +[the full proposal]: https://github.com/sass/sass/blob/main/proposal/strict-unary.md +[file an issue]: https://github.com/sass/sass/issues/new diff --git a/source/blog/034-request-for-comments-color-spaces.md b/source/blog/034-request-for-comments-color-spaces.md new file mode 100644 index 000000000..a5332929d --- /dev/null +++ b/source/blog/034-request-for-comments-color-spaces.md @@ -0,0 +1,264 @@ +--- +title: 'Request for Comments: Color Spaces' +author: Miriam Suzanne and Natalie Weizenbaum +tags: blog +# date: 2022-09-21 13:00 PST +--- + +There's been a lot of exciting work in the CSS color specifications lately, and +as it begins to land in browsers we've been preparing to add support for it in +Sass as well. The first and largest part of that is adding support for _color +spaces_ to Sass, which represents a huge (but largely backwards-compatible) +rethinking of the way colors work. + +Historically, all colors in CSS have existed in the same color space, known as +"sRGB". Whether you represent them as a hex code, an `hsl()` function, or a +color name, they represented the same set of visible colors you could tell a +screen to display. While this is conceptually simple, there are some major +downsides: + +- As monitors have improved over time, they've become capable of displaying more + colors than can be represented in the sRGB color space. + +- sRGB, even when you're using it via `hsl()`, doesn't correspond very well with + how humans perceive colors. Cyan looks noticeably lighter than purple with the + same saturation and lightness values. + +- There's no way to represent domain- or device-specific color spaces, such as + the [CMYK] color space that's used by printers. + + [CMYK]: https://en.wikipedia.org/wiki/CMYK_color_model + +Color spaces solve all of these problems. Now not every color has a red, green, +and blue channel (which can be interpreted as hue, saturation, and lightness). +Instead, every color has a specific _color space_ which specifies which +channels it has. For example, the color `oklch(80% 50% 90deg)` has `oklch` as +its color space, `80%` lightness, `50%` chroma, and `90deg` hue. + +## Color Spaces in Sass + +Today we're announcing [a proposal for how to handle color spaces in Sass]. In +addition to expanding Sass's color values to support color spaces, this proposal +defines Sassified versions of all the color functions in [CSS Color Level +4][color-4]. + +[a proposal for how to handle color spaces in Sass]: https://github.com/sass/sass/blob/main/proposal/color-4-new-spaces.md +[color-4]: https://www.w3.org/TR/css-color-4/ + +### Rules of Thumb + +There are several rules of thumb for working with color spaces in Sass: + +- The `rgb`, `hsl`, and `hwb` spaces are considered "legacy spaces", and will + often get special handling for the sake of backwards compatibility. Colors + defined using hex notation or CSS color names are considered part of the `rgb` + color space. Legacy colors are emitted in the most compatible format. This + matches CSS's own backwards-compatibility behavior. + +- Otherwise, any color defined in a given space will remain in that space, and + be emitted in that space. + +- Authors can explicitly convert a color's space by using `color.to-space()`. + This can be useful to enforce non-legacy behavior, by converting into a + non-legacy space, or to ensure the color output is compatible with older + browsers by converting colors into a legacy space before emitting. + +- The `srgb` color space is equivalent to `rgb`, except that one is a legacy + space, and the other is not. They also use different coordinate systems, with + `rgb()` accepting a range from 0-255, and `srgb` using a range of 0-1. + +- Color functions that allow specifying a color space for manipulation will + always use the source color space by default. When an explicit space is + provided for manipulation, the resulting color will still be returned in the + same space as the origin color. For `color.mix()`, the first color parameter + is considered the origin color. + +- All legacy and RGB-style spaces represent bounded gamuts of color. Since + mapping colors into gamut is a lossy process, it should generally be left to + browsers, which can map colors as-needed, based on the capabilities of a + display. For that reason, out-of-gamut channel values are maintained by Sass + whenever possible, even when converting into gamut-bounded color spaces. The + only exception is that `hsl` and `hwb` color spaces are not able to express + out-of-gamut color, so converting colors into those spaces will gamut-map the + colors as well. Authors can also perform explicit gamut mapping with the + `color.to-gamut()` function. + +- Legacy browsers require colors in the `srgb` gamut. However, most modern + displays support the wider `display-p3` gamut. + +### Standard CSS Color Functions + +#### `oklab()` and `oklch()` + +The `oklab()` (cubic) and `oklch()` (cylindrical) functions provide access to an +unbounded gamut of colors in a perceptually uniform space. Authors can use these +functions to define reliably uniform colors. For example, the following colors +are perceptually similar in lightness and saturation: + +```scss +$pink: oklch(64% 0.196 353); // hsl(329.8 70.29% 58.75%) +$blue: oklch(64% 0.196 253); // hsl(207.4 99.22% 50.69%) +``` + +The `oklch()` format uses consistent "lightness" and "chroma" values, while the +`hsl()` format shows dramatic changes in both "lightness" and "saturation". As +such, `oklch` is often the best space for consistent transforms. + +#### `lab()` and `lch()` + +The `lab()` and `lch()` functions provide access to an unbounded gamut of colors +in a space that's less perpetually-uniform but more widely-adopted than OKLab +and OKLCH. + +#### `hwb()` + +Sass now supports a top-level `hwb()` function that uses the same syntax as +CSS's built-in `hwb()` syntax. + +#### `color()` + +The new `color()` function provides access to a number of specialty spaces. Most +notably, `display-p3` is a common space for wide-gamut monitors, making it +likely one of the more popular options for authors who simply want access to a +wider range of colors. For example, P3 greens are significantly 'brighter' and +more saturated than the greens available in sRGB: + +```scss +$fallback-green: rgb(0% 100% 0%); +$brighter-green: color(display-p3 0 1 0); +``` + +Sass will natively support all predefined color spaces declared in the Colors +Level 4 specification. It will also support unknown color spaces, although these +can't be converted to and from any other color space. + +### New Sass Color Functions + +#### `color.channel()` + +This function returns the value of a single channel in a color. By default, it +only supports channels that are available in the color's own space, but you can +pass the `$space` parameter to return the value of the channel after converting +to the given space. + +```scss +$brand: hsl(0 100% 25.1%); + +// result: 25.1% +$hsl-lightness: color.channel($brand, 'lightness'); + +// result: 37.67% +$oklch-lightness: color.channel($brand, 'lightness', $space: oklch); +``` + +#### `color.space()` + +This function returns the name of the color's space. + +```scss +// result: hsl +$hsl-space: color.space(hsl(0 100% 25.1%)); + +// result: oklch +$oklch-space: color.space(oklch(37.7% 38.75% 29.23deg)); +``` + +#### `color.is-in-gamut()`, `color.is-legacy()` + +These functions return various facts about the color. `color.is-in-gamut()` +returns whether the color is in-gamut for its color space (as opposed to having +one or more of its channels out of bounds, like `rgb(300 0 0)`). +`color.is-legacy()` returns whether the color is a legacy color in the `rgb`, +`hsl`, or `hwb` color space. + +#### `color.is-powerless()` + +This function returns whether a given channel is "powerless" in the given color. +This is a special state that's defined for individual color spaces, which +indicates that a channel's value won't affect how a color is displayed. + +```scss +$grey: hsl(0 0% 60%); + +// result: true, because saturation is 0 +$hue-powerless: color.is-powerless($grey, 'hue'); + +// result: false +$hue-powerless: color.is-powerless($grey, 'lightness'); +``` + +#### `color.same()` + +This function returns whether two colors will be displayed the same way, even if +this requires converting between spaces. This is unlike the `==` operator, which +always considers colors in different non-legacy spaces to be inequal. + +```scss +$orange-rgb: #ff5f00; +$orange-oklch: oklch(68.72% 20.966858279% 41.4189852913deg); + +// result: false +$equal: $orange-rgb == $orange-oklch; + +// result: true +$same: color.same($orange-rgb, $orange-oklch); +``` + +### Existing Sass Color Functions + +#### `color.scale()`, `color.adjust()`, and `color.change()` + +By default, all Sass color transformations are handled and returned in the color +space of the original color parameter. However, all relevant functions now allow +specifying an explicit color space for transformations. For example, lightness & +darkness adjustments are most reliable in `oklch`: + +```scss +$brand: hsl(0 100% 25.1%); + +// result: hsl(0 100% 43.8%) +$hsl-lightness: color.scale($brand, $lightness: 25%); + +// result: hsl(5.76 56% 45.4%) +$oklch-lightness: color.scale($brand, $lightness: 25%, $space: oklch); +``` + +Note that the returned color is still emitted in the original color space, even +when the adjustment is performed in a different space. + +#### `color.mix()` + +The `color.mix()` function will retain its existing behavior for legacy color +spaces, but for new color spaces it will match CSS's "color interpolation" +specification. This is how CSS computes which color to use in between two colors +in a gradient or an animation. + +#### Deprecations + +A number of existing functions only make sense for legacy colors, and so are +being deprecated in favor of color-space-friendly functions like +`color.channel()` and `color.adjust()`: + +- `color.red()` +- `color.green()` +- `color.blue()` +- `color.hue()` +- `color.saturation()` +- `color.lightness()` +- `color.whiteness()` +- `color.blackness()` +- `adjust-hue()` +- `saturate()` +- `desaturate()` +- `transparentize()`/`fade-out()` +- `opacify()`/`fade-in()` +- `lighten()`/`darken()` + +## Let Us Know What You Think! + +There's lots more detail to this proposal, and it's not set in stone yet. We +want your feedback on it! Read it over [on GitHub], and [file an issue] with any +thoughts or concerns you may have. + +[on GitHub]: https://github.com/sass/sass/blob/main/proposal/color-4-new-spaces.md#deprecated-functions +[file an issue]: https://github.com/sass/sass/issues/new diff --git a/source/blog/035-security-alert-tar-permissions.md b/source/blog/035-security-alert-tar-permissions.md new file mode 100644 index 000000000..96b40c053 --- /dev/null +++ b/source/blog/035-security-alert-tar-permissions.md @@ -0,0 +1,118 @@ +--- +title: 'Security Alert: Tar Permissions' +author: Natalie Weizenbaum +tags: blog +layout: base +# date: 2022-12-09 16:00 PST +--- + +The Sass team was recently alerted by prolific external contributor [@ntkme] to +a security issue in our release process. + +[@ntkme]: https://github.com/ntkme + +## TL;DR + +If you're using Linux or Mac OS, run `ls -ax path/to/sass`. If the last group of +letters in the first column contains `w`, you're vulnerable: + +``` +Vulnerable: +-rwxr-xrwx 1 nweiz primarygroup 407 Dec 13 12:33 sass-1.56.2/sass + +Not vulnerable: +-rwxr-xr-x 1 nweiz primarygroup 407 Dec 13 12:33 sass-1.56.2/sass +``` + +If you're using the `sass-embedded` package, do the same thing for +`node_modules/sass-embedded/dist/lib/src/vendor/dart-sass-embedded/dart-sass-embedded`. + +## Who's Affected? + +While we don't expect this issue to be a problem for the vast majority of users, +it does affect the following groups: + +- Users who downloaded the stand-alone Dart Sass, Dart Sass Embedded, or Sass + Migrator `.tar.gz` archives from the Dart Sass website and extracted them as + the Unix root user. + +- Users who installed the `sass-embedded` npm package as the Unix root user + prior to version 1.54.5. + +- Users who installed the "non-native" version of the community-maintained + `sass-embedded` RubyGems package as the Unix root user prior to version + 1.56.2. + +- Users on multi-user systems who downloaded the stand-alone Dart Sass, Dart + Sass Embedded, or Sass Migrator `.tar.gz` archives from the Dart Sass website + and explicitly passed the `-p`/`--preserve-permissions` flag when extracting + them. + +Users who installed Dart Sass via the `sass` npm package, Homebrew, or +Chocolatey are categorically not at risk, nor are users on Windows. + +We strongly recommend that users in these vulnerable groups delete and +re-install Sass. All the `.tar.gz` files on GitHub have been scrubbed to remove +the vulnerability, so you can reinstall the same version you were previously +using without needing to upgrade to the latest version. + +This is a privilege-escalation issue, which means it could allow a hypothetical +attacker with access to a low-privilege account on your computer to escalate +their access to your account's privileges. However, this also means that it's +not a risk _unless_ an attacker already has access to an account on your +machine. + +## What went wrong? + +We were inadvertently uploading `.tar.gz` archives with permissions metadata +indicating that executable files could be overwritten by all users, not just the +owner. + +In most cases, this metadata is ignored when extracting the archives and the +permissions are set to only be writable by the user doing the extraction. +However, when extracting archives as the Unix root user or explicitly passing +the `-p`/`--preserve-permissions` flag, the permissions for the extracted files +are set according to the archive's metadata. Because the metadata was incorrect, +an attacker with access to a low-privilege account would be able to overwrite +the executable file and escalate their privileges once it's executed. + +## How did this happen? + +Dart Sass is automatically deployed to various different release platforms using +a Dart package called [`cli_pkg`], which is also written maintained by the Sass +team. This package uses the Dart [`archive`] package to generate `.tar.gz` files +for stand-alone release packages which are then uploaded to GitHub, and when +initially writing the code to use this package I wrote the following function: + +[`cli_pkg`]: https://pub.dev/packages/cli_pkg +[`archive`]: https://pub.dev/packages/archive + +```dart +ArchiveFile fileFromBytes(String path, List data, + {bool executable = false}) => + ArchiveFile(path, data.length, data) + ..mode = executable ? 495 : 428 + ..lastModTime = DateTime.now().millisecondsSinceEpoch ~/ 1000; +``` + +My intention was to set the executable mode to `755` (read/write/execute for the +owner, read/execute only for the other users) and the non-executable mode to +`644` (read/write for the owner, read-only for other users). However, Dart +doesn't support literal octal numbers and I must have done the decimal-to-octal +conversion wrong. The actual permissions that got set were `757` +(read/write/execute for the owner **and other users**, read/execute for the +group) and `654` (read/write for the owner, read/execute for the group, and +read-only for other users). + +This went unnoticed for several years, until @ntkme notified us of the issue +last week and provided a fix to `cli_pkg`. + +## What's been done? + +We've released `cli_pkg` 2.1.7 which sets the archive permissions correctly. In +addition, we've updated all `.tar.gz` files in the Dart Sass, Dart Sass +Embedded, and Sass Migrator repositories to correctly limit write permissions to +only the owner of the files. We're announcing the vulnerability here and on the +[@SassCSS Twitter account]. + +[@SassCSS Twitter account]: https://twitter.com/SassCSS From b5dcf566a7533dc8d79d6bacded856b494419271 Mon Sep 17 00:00:00 2001 From: oluniyiawo Date: Fri, 3 Mar 2023 15:39:31 +0000 Subject: [PATCH 15/42] more blog edits --- source/blog.liquid | 25 +++++++++---------- ...-works.html.md => 001-how-extend-works.md} | 2 +- ...d => 002-a-change-in-plans-for-sass-33.md} | 2 +- ...sed.html.md => 003-sass-33-is-released.md} | 2 +- ...sed.html.md => 004-sass-34-is-released.md} | 2 +- ...ml.md => 005-cleaning-up-interpolation.md} | 2 +- ...dropping-support-for-old-ruby-versions.md} | 2 +- ...marcel.html.md => 007-thank-you-marcel.md} | 2 +- ...ml.md => 008-sass-35-release-candidate.md} | 2 +- ...ss.html.md => 009-announcing-dart-sass.md} | 2 +- ...l.md => 010-dart-sass-is-on-chocolatey.md} | 2 +- ... => 011-sass-and-browser-compatibility.md} | 2 +- ...ta.html.md => 012-dart-sass-is-in-beta.md} | 2 +- ...sed.html.md => 013-sass-35-is-released.md} | 2 +- ...ml.md => 014-dart-sass-100-is-released.md} | 2 +- ...html.md => 015-ruby-sass-is-deprecated.md} | 2 +- ...equest-for-commentsimporting-css-files.md} | 4 +-- ...watchcss-imports-and-css-compatibility.md} | 2 +- ...hcontent-arguments-and-color-functions.md} | 2 +- ...st-for-comments-module-system-proposal.md} | 2 +- ...tml.md => 020-ruby-sass-is-unsupported.md} | 2 +- ...ocs.html.md => 021-brand-new-sass-docs.md} | 2 +- ...for-commentsforward-slash-as-separator.md} | 2 +- ...w.html.md => 023-module-system-preview.md} | 2 +- ...d => 024-the-module-system-is-launched.md} | 2 +- ...quest-for-comments-nested-map-functions.md | 2 +- .../026-request-for-comments-hwb-functions.md | 2 +- source/blog/027-libsass-is-deprecated.md | 2 +- ...8-request-for-comments-first-class-calc.md | 2 +- source/blog/029-node-fibers-discontinued.md | 2 +- ...30-request-for-comments-new-js-api.html.md | 2 +- .../031-new-js-api-release-candidate.html.md | 2 +- source/blog/032-embedded-sass-is-live.md | 2 +- ...est-for-comments-strict-unary-operators.md | 2 +- .../034-request-for-comments-color-spaces.md | 2 +- .../035-security-alert-tar-permissions.md | 2 +- 36 files changed, 48 insertions(+), 49 deletions(-) rename source/blog/{001-how-extend-works.html.md => 001-how-extend-works.md} (99%) rename source/blog/{002-a-change-in-plans-for-sass-33.html.md => 002-a-change-in-plans-for-sass-33.md} (99%) rename source/blog/{003-sass-33-is-released.html.md => 003-sass-33-is-released.md} (99%) rename source/blog/{004-sass-34-is-released.html.md => 004-sass-34-is-released.md} (99%) rename source/blog/{005-cleaning-up-interpolation.html.md => 005-cleaning-up-interpolation.md} (99%) rename source/blog/{006-dropping-support-for-old-ruby-versions.html.md => 006-dropping-support-for-old-ruby-versions.md} (99%) rename source/blog/{007-thank-you-marcel.html.md => 007-thank-you-marcel.md} (98%) rename source/blog/{008-sass-35-release-candidate.html.md => 008-sass-35-release-candidate.md} (99%) rename source/blog/{009-announcing-dart-sass.html.md => 009-announcing-dart-sass.md} (99%) rename source/blog/{010-dart-sass-is-on-chocolatey.html.md => 010-dart-sass-is-on-chocolatey.md} (98%) rename source/blog/{011-sass-and-browser-compatibility.html.md => 011-sass-and-browser-compatibility.md} (99%) rename source/blog/{012-dart-sass-is-in-beta.html.md => 012-dart-sass-is-in-beta.md} (99%) rename source/blog/{013-sass-35-is-released.html.md => 013-sass-35-is-released.md} (99%) rename source/blog/{014-dart-sass-100-is-released.html.md => 014-dart-sass-100-is-released.md} (99%) rename source/blog/{015-ruby-sass-is-deprecated.html.md => 015-ruby-sass-is-deprecated.md} (99%) rename source/blog/{016-request-for-commentsimporting-css-files.html.md => 016-request-for-commentsimporting-css-files.md} (98%) rename source/blog/{017-feature-watchcss-imports-and-css-compatibility.html.md => 017-feature-watchcss-imports-and-css-compatibility.md} (99%) rename source/blog/{018-feature-watchcontent-arguments-and-color-functions.html.md => 018-feature-watchcontent-arguments-and-color-functions.md} (99%) rename source/blog/{019-request-for-comments-module-system-proposal.html.md => 019-request-for-comments-module-system-proposal.md} (99%) rename source/blog/{020-ruby-sass-is-unsupported.html.md => 020-ruby-sass-is-unsupported.md} (98%) rename source/blog/{021-brand-new-sass-docs.html.md => 021-brand-new-sass-docs.md} (98%) rename source/blog/{022-request-for-commentsforward-slash-as-separator.html.md => 022-request-for-commentsforward-slash-as-separator.md} (99%) rename source/blog/{023-module-system-preview.html.md => 023-module-system-preview.md} (98%) rename source/blog/{024-the-module-system-is-launched.html.md => 024-the-module-system-is-launched.md} (99%) diff --git a/source/blog.liquid b/source/blog.liquid index a4f202f00..60d753d31 100644 --- a/source/blog.liquid +++ b/source/blog.liquid @@ -3,31 +3,30 @@ pagination: data: collections.blog size: 5 alias: posts + reverse: true layout: blog title: Sass Blog --- Page {{ pagination.pageNumber | plus: 1 }} of {{ pagination.size }} -
    + {% if pagination.href.previous %} +
  • + Previous +
  • + {% endif %} {%- for post in posts -%}
  • {{ post.data.title }}

    -

    {{ post.content }}

    +

    Posted at {{ post.data.date }} by {{ post.data.author }}

    +

    {{ post.content | truncatewords: 250 }}

  • {%- endfor -%} -
-
    -
  • - {% if pagination.href.previous %} - Previous - {% else %}Previous{% endif %} -
  • -
  • - {% if pagination.href.next %} + {% if pagination.href.next %} +
  • Next - {% else %}Next{% endif %} -
  • + + {% endif %}
\ No newline at end of file diff --git a/source/blog/001-how-extend-works.html.md b/source/blog/001-how-extend-works.md similarity index 99% rename from source/blog/001-how-extend-works.html.md rename to source/blog/001-how-extend-works.md index 801cd0717..6dca45b8d 100644 --- a/source/blog/001-how-extend-works.html.md +++ b/source/blog/001-how-extend-works.md @@ -3,7 +3,7 @@ title: How @extend Works author: Natalie Weizenbaum tags: blog layout: base -# date: 2013-11-22 16:57 -8 +date: 2013-11-22 16:57:00 -8 --- _This was originally published as [a gist](https://gist.github.com/nex3/7609394)_. diff --git a/source/blog/002-a-change-in-plans-for-sass-33.html.md b/source/blog/002-a-change-in-plans-for-sass-33.md similarity index 99% rename from source/blog/002-a-change-in-plans-for-sass-33.html.md rename to source/blog/002-a-change-in-plans-for-sass-33.md index 036c19948..fff4cbc27 100644 --- a/source/blog/002-a-change-in-plans-for-sass-33.html.md +++ b/source/blog/002-a-change-in-plans-for-sass-33.md @@ -2,7 +2,7 @@ title: A Change in Plans for Sass 3.3 author: Natalie Weizenbaum tags: blog -#date: 2013-12-19 20:05 PST +date: 2013-12-19 20:05:00 -8 --- _This was originally published as [a gist](https://gist.github.com/nex3/8050187)._ diff --git a/source/blog/003-sass-33-is-released.html.md b/source/blog/003-sass-33-is-released.md similarity index 99% rename from source/blog/003-sass-33-is-released.html.md rename to source/blog/003-sass-33-is-released.md index f72cfa5f5..09d443f6f 100644 --- a/source/blog/003-sass-33-is-released.html.md +++ b/source/blog/003-sass-33-is-released.md @@ -2,7 +2,7 @@ title: Sass 3.3 is Released author: Natalie Weizenbaum tags: blog -#date: 2014-03-07 16:40 PST +date: 2014-03-07 16:40:00 -8 --- After ironing out a bunch of bugs in numerous release candidates, we're finally diff --git a/source/blog/004-sass-34-is-released.html.md b/source/blog/004-sass-34-is-released.md similarity index 99% rename from source/blog/004-sass-34-is-released.html.md rename to source/blog/004-sass-34-is-released.md index 136793412..05ee61a9d 100644 --- a/source/blog/004-sass-34-is-released.html.md +++ b/source/blog/004-sass-34-is-released.md @@ -2,7 +2,7 @@ title: Sass 3.4 is Released author: Natalie Weizenbaum tags: blog -#date: 2014-08-18 16:38 PST +date: 2014-08-18 16:38:00 -8 --- We've been trying to increase the pace of Sass releases, and it looks like we've diff --git a/source/blog/005-cleaning-up-interpolation.html.md b/source/blog/005-cleaning-up-interpolation.md similarity index 99% rename from source/blog/005-cleaning-up-interpolation.html.md rename to source/blog/005-cleaning-up-interpolation.md index edaadf5f5..8cb63cc9d 100644 --- a/source/blog/005-cleaning-up-interpolation.html.md +++ b/source/blog/005-cleaning-up-interpolation.md @@ -2,7 +2,7 @@ title: Cleaning Up Interpolation author: Natalie Weizenbaum tags: blog -#date: 2015-12-09 15:20 PST +date: 2015-12-09 15:20:00 -8 --- Interpolation—the ability to add variables and other snippets using `#{...}`—is diff --git a/source/blog/006-dropping-support-for-old-ruby-versions.html.md b/source/blog/006-dropping-support-for-old-ruby-versions.md similarity index 99% rename from source/blog/006-dropping-support-for-old-ruby-versions.html.md rename to source/blog/006-dropping-support-for-old-ruby-versions.md index ccac52421..87df4227c 100644 --- a/source/blog/006-dropping-support-for-old-ruby-versions.html.md +++ b/source/blog/006-dropping-support-for-old-ruby-versions.md @@ -2,7 +2,7 @@ title: Dropping Support For Old Ruby Versions author: Natalie Weizenbaum tags: blog -#date: 2016-02-29 14:25 PST +date: 2016-02-29 14:25:00 -8 --- As of version 3.5, Ruby Sass will drop support for Ruby 1.8.7 and Ruby 1.9.3. We diff --git a/source/blog/007-thank-you-marcel.html.md b/source/blog/007-thank-you-marcel.md similarity index 98% rename from source/blog/007-thank-you-marcel.html.md rename to source/blog/007-thank-you-marcel.md index 1e282f135..dbcbc95f0 100644 --- a/source/blog/007-thank-you-marcel.html.md +++ b/source/blog/007-thank-you-marcel.md @@ -2,7 +2,7 @@ title: Dropping Support For Old Ruby Versions author: Natalie Weizenbaum tags: blog -#date: 2016-05-24 14:41 PST +date: 2016-05-24 14:41:00 -8 --- You may not know [Marcel Greter](https://github.com/mgreter), but you almost diff --git a/source/blog/008-sass-35-release-candidate.html.md b/source/blog/008-sass-35-release-candidate.md similarity index 99% rename from source/blog/008-sass-35-release-candidate.html.md rename to source/blog/008-sass-35-release-candidate.md index 40b5d80fc..0b57d5dbe 100644 --- a/source/blog/008-sass-35-release-candidate.html.md +++ b/source/blog/008-sass-35-release-candidate.md @@ -2,7 +2,7 @@ title: Sass 3.5 Release Candidate author: Natalie Weizenbaum tags: blog -#date: 2016-08-30 15:00 PST +date: 2016-08-30 15:00:00 -8 --- I've just pushed the button to release Sass 3.5.0-rc.1. If it seems like it's diff --git a/source/blog/009-announcing-dart-sass.html.md b/source/blog/009-announcing-dart-sass.md similarity index 99% rename from source/blog/009-announcing-dart-sass.html.md rename to source/blog/009-announcing-dart-sass.md index 13862297f..26acb3f9e 100644 --- a/source/blog/009-announcing-dart-sass.html.md +++ b/source/blog/009-announcing-dart-sass.md @@ -2,7 +2,7 @@ title: Announcing Dart Sass author: Natalie Weizenbaum tags: blog -#date: 2016-10-31 13:28 PST +date: 2016-10-31 13:28:00 -8 --- Over the past few months, I've been quietly working on a new project. Today I'm diff --git a/source/blog/010-dart-sass-is-on-chocolatey.html.md b/source/blog/010-dart-sass-is-on-chocolatey.md similarity index 98% rename from source/blog/010-dart-sass-is-on-chocolatey.html.md rename to source/blog/010-dart-sass-is-on-chocolatey.md index c1e9b54b4..dde51c4bc 100644 --- a/source/blog/010-dart-sass-is-on-chocolatey.html.md +++ b/source/blog/010-dart-sass-is-on-chocolatey.md @@ -2,7 +2,7 @@ title: Dart Sass is On Chocolatey author: Natalie Weizenbaum tags: blog -#date: 2017-01-13 14:43 PST +date: 2017-01-13 14:43:00 -8 --- One of the quieter benefits of [moving to Dart](/blog/announcing-dart-sass) is diff --git a/source/blog/011-sass-and-browser-compatibility.html.md b/source/blog/011-sass-and-browser-compatibility.md similarity index 99% rename from source/blog/011-sass-and-browser-compatibility.html.md rename to source/blog/011-sass-and-browser-compatibility.md index 7a1480f09..73846ba31 100644 --- a/source/blog/011-sass-and-browser-compatibility.html.md +++ b/source/blog/011-sass-and-browser-compatibility.md @@ -2,7 +2,7 @@ title: Sass and Browser Compatibility author: Natalie Weizenbaum tags: blog -#date: 2017-02-10 17:46 PST +date: 2017-02-10 17:46:00 -8 --- One of the core design principles of Sass has always been to **understand CSS as diff --git a/source/blog/012-dart-sass-is-in-beta.html.md b/source/blog/012-dart-sass-is-in-beta.md similarity index 99% rename from source/blog/012-dart-sass-is-in-beta.html.md rename to source/blog/012-dart-sass-is-in-beta.md index ac5767025..c15cb9bbe 100644 --- a/source/blog/012-dart-sass-is-in-beta.html.md +++ b/source/blog/012-dart-sass-is-in-beta.md @@ -2,7 +2,7 @@ title: Dart Sass is in Beta author: Natalie Weizenbaum tags: blog -#date: 2017-06-05 13:00 PST +date: 2017-06-05 13:00:00 -8 --- Last weekend was [three days long](https://en.wikipedia.org/wiki/Memorial_Day) diff --git a/source/blog/013-sass-35-is-released.html.md b/source/blog/013-sass-35-is-released.md similarity index 99% rename from source/blog/013-sass-35-is-released.html.md rename to source/blog/013-sass-35-is-released.md index afd061053..adfaffa1d 100644 --- a/source/blog/013-sass-35-is-released.html.md +++ b/source/blog/013-sass-35-is-released.md @@ -2,7 +2,7 @@ title: Sass 3.5 is Released author: Natalie Weizenbaum tags: blog -#date: 2017-07-07 15:33 PST +date: 2017-07-07 15:33:00 -8 --- I'm excited to announce that I've just released the stable version of Sass 3.5. diff --git a/source/blog/014-dart-sass-100-is-released.html.md b/source/blog/014-dart-sass-100-is-released.md similarity index 99% rename from source/blog/014-dart-sass-100-is-released.html.md rename to source/blog/014-dart-sass-100-is-released.md index 9d17add7a..e226c8354 100644 --- a/source/blog/014-dart-sass-100-is-released.html.md +++ b/source/blog/014-dart-sass-100-is-released.md @@ -2,7 +2,7 @@ title: Dart Sass 1.0.0 is Released author: Natalie Weizenbaum tags: blog -#date: 2018-03-26 13:15 PST +date: 2018-03-26 13:15:00 -8 --- I've just uploaded Dart Sass 1.0.0, the very first stable release, to diff --git a/source/blog/015-ruby-sass-is-deprecated.html.md b/source/blog/015-ruby-sass-is-deprecated.md similarity index 99% rename from source/blog/015-ruby-sass-is-deprecated.html.md rename to source/blog/015-ruby-sass-is-deprecated.md index a142c1499..1803aee9d 100644 --- a/source/blog/015-ruby-sass-is-deprecated.html.md +++ b/source/blog/015-ruby-sass-is-deprecated.md @@ -2,7 +2,7 @@ title: Ruby Sass is Deprecated author: Natalie Weizenbaum tags: blog -#date: 2018-04-02 11:35 PST +date: 2018-04-02 11:35:00 -8 --- With the release of [Dart Sass 1.0.0 stable](/blog/dart-sass-100-is-released) diff --git a/source/blog/016-request-for-commentsimporting-css-files.html.md b/source/blog/016-request-for-commentsimporting-css-files.md similarity index 98% rename from source/blog/016-request-for-commentsimporting-css-files.html.md rename to source/blog/016-request-for-commentsimporting-css-files.md index 450272df8..97ea78d8a 100644 --- a/source/blog/016-request-for-commentsimporting-css-files.html.md +++ b/source/blog/016-request-for-commentsimporting-css-files.md @@ -1,8 +1,8 @@ --- title: 'Request For Comments: Importing CSS Files' -author: Natalie Weizenbau +author: Natalie Weizenbaum tags: blog -#date: 2018-07-09 11:19 PST +date: 2018-07-09 11:19:00 -8 --- As Dart Sass catches up with Ruby Sass in terms of usability, we're starting diff --git a/source/blog/017-feature-watchcss-imports-and-css-compatibility.html.md b/source/blog/017-feature-watchcss-imports-and-css-compatibility.md similarity index 99% rename from source/blog/017-feature-watchcss-imports-and-css-compatibility.html.md rename to source/blog/017-feature-watchcss-imports-and-css-compatibility.md index 6045edcc1..7c3be9188 100644 --- a/source/blog/017-feature-watchcss-imports-and-css-compatibility.html.md +++ b/source/blog/017-feature-watchcss-imports-and-css-compatibility.md @@ -2,7 +2,7 @@ title: 'Feature Watch: CSS Imports and CSS Compatibility' author: Natalie Weizenbaum tags: blog -#date: 2018-08-13 14:17 PST +date: 2018-08-13 14:17:00 -8 --- Dart Sass 1.11 has just been released, and with it a handful of new features. diff --git a/source/blog/018-feature-watchcontent-arguments-and-color-functions.html.md b/source/blog/018-feature-watchcontent-arguments-and-color-functions.md similarity index 99% rename from source/blog/018-feature-watchcontent-arguments-and-color-functions.html.md rename to source/blog/018-feature-watchcontent-arguments-and-color-functions.md index 6690fc233..5795f8e69 100644 --- a/source/blog/018-feature-watchcontent-arguments-and-color-functions.html.md +++ b/source/blog/018-feature-watchcontent-arguments-and-color-functions.md @@ -2,7 +2,7 @@ title: 'Feature Watch: Content Arguments and Color Functions' author: Natalie Weizenbaum tags: blog -#date: 2018-11-14 14:14 PST +date: 2018-11-14 14:14:00 -8 --- Dart Sass 1.15, released today and available [on diff --git a/source/blog/019-request-for-comments-module-system-proposal.html.md b/source/blog/019-request-for-comments-module-system-proposal.md similarity index 99% rename from source/blog/019-request-for-comments-module-system-proposal.html.md rename to source/blog/019-request-for-comments-module-system-proposal.md index d1f2563ae..c261b07c9 100644 --- a/source/blog/019-request-for-comments-module-system-proposal.html.md +++ b/source/blog/019-request-for-comments-module-system-proposal.md @@ -2,7 +2,7 @@ title: 'Request For Comments: Module System' author: Natalie Weizenbaum tags: blog -#date: 2018-11-27 13:10 PST +date: 2018-11-27 13:10:00 -8 --- Many of the most frequently-requested features for Sass have to do with its diff --git a/source/blog/020-ruby-sass-is-unsupported.html.md b/source/blog/020-ruby-sass-is-unsupported.md similarity index 98% rename from source/blog/020-ruby-sass-is-unsupported.html.md rename to source/blog/020-ruby-sass-is-unsupported.md index d5315c4a2..ea106ea6d 100644 --- a/source/blog/020-ruby-sass-is-unsupported.html.md +++ b/source/blog/020-ruby-sass-is-unsupported.md @@ -2,7 +2,7 @@ title: Ruby Sass Has Reached End-Of-Life author: Natalie Weizenbaum tags: blog -#date: 2019-04-03 16:15 PST +date: 2019-04-03 16:15:00 -8 --- One year has passed since we announced [the deprecation of Ruby diff --git a/source/blog/021-brand-new-sass-docs.html.md b/source/blog/021-brand-new-sass-docs.md similarity index 98% rename from source/blog/021-brand-new-sass-docs.html.md rename to source/blog/021-brand-new-sass-docs.md index 1fa28e228..5e7bfb4a2 100644 --- a/source/blog/021-brand-new-sass-docs.html.md +++ b/source/blog/021-brand-new-sass-docs.md @@ -2,7 +2,7 @@ title: Brand New Sass Docs author: Natalie Weizenbaum tags: blog -#date: 2019-04-23 10:04 PST +date: 2019-04-23 10:04:00 -8 --- I'm excited to announce the launch of [a full rewrite and redesign of the Sass diff --git a/source/blog/022-request-for-commentsforward-slash-as-separator.html.md b/source/blog/022-request-for-commentsforward-slash-as-separator.md similarity index 99% rename from source/blog/022-request-for-commentsforward-slash-as-separator.html.md rename to source/blog/022-request-for-commentsforward-slash-as-separator.md index eb0aa9ec7..b2c17be43 100644 --- a/source/blog/022-request-for-commentsforward-slash-as-separator.html.md +++ b/source/blog/022-request-for-commentsforward-slash-as-separator.md @@ -2,7 +2,7 @@ title: 'Request For Comments: Forward Slash as Separator' author: Natalie Weizenbaum tags: blog -#date: 2019-05-06 16:15 PST +date: 2019-05-06 16:15:00 -8 --- Early on in Sass's history, the decision was made to use `/` as a division diff --git a/source/blog/023-module-system-preview.html.md b/source/blog/023-module-system-preview.md similarity index 98% rename from source/blog/023-module-system-preview.html.md rename to source/blog/023-module-system-preview.md index 84b560ef3..a2922318d 100644 --- a/source/blog/023-module-system-preview.html.md +++ b/source/blog/023-module-system-preview.md @@ -2,7 +2,7 @@ title: Module System Preview author: Natalie Weizenbaum tags: blog -#date: 2019-09-04 15:14 PST +date: 2019-09-04 15:14:00 -8 --- Exciting news, Sass fans! After a year of development and some iteration on the diff --git a/source/blog/024-the-module-system-is-launched.html.md b/source/blog/024-the-module-system-is-launched.md similarity index 99% rename from source/blog/024-the-module-system-is-launched.html.md rename to source/blog/024-the-module-system-is-launched.md index 4e023b821..a73fffeec 100644 --- a/source/blog/024-the-module-system-is-launched.html.md +++ b/source/blog/024-the-module-system-is-launched.md @@ -2,7 +2,7 @@ title: The Module System is Launched author: Natalie Weizenbaum tags: blog -#date: 2019-10-01 18:58 PST +date: 2019-10-01 18:58:00 -8 --- The Sass team has known for years that the `@import` rule, one of the earliest diff --git a/source/blog/025-request-for-comments-nested-map-functions.md b/source/blog/025-request-for-comments-nested-map-functions.md index be9c88a91..8a3708e58 100644 --- a/source/blog/025-request-for-comments-nested-map-functions.md +++ b/source/blog/025-request-for-comments-nested-map-functions.md @@ -2,7 +2,7 @@ title: 'Request for Comments: Nested Map Functions' author: Natalie Weizenbaum tags: blog -#date: 2020-9-16 14:40 PST +date: 2020-9-16 14:40:00 -8 --- As Sass libraries and design systems get more complex and have more users with diff --git a/source/blog/026-request-for-comments-hwb-functions.md b/source/blog/026-request-for-comments-hwb-functions.md index c881f7f77..80a5bc7ea 100644 --- a/source/blog/026-request-for-comments-hwb-functions.md +++ b/source/blog/026-request-for-comments-hwb-functions.md @@ -2,7 +2,7 @@ title: 'Request for Comments: HWB Functions' author: Natalie Weizenbaum tags: blog -#date: 2020-10-06 16:00 PST +date: 2020-10-06 16:00:00 -8 --- The CSS working group has been up to all sorts of exciting stuff recently in the diff --git a/source/blog/027-libsass-is-deprecated.md b/source/blog/027-libsass-is-deprecated.md index d5acf66b1..bcbeae418 100644 --- a/source/blog/027-libsass-is-deprecated.md +++ b/source/blog/027-libsass-is-deprecated.md @@ -2,7 +2,7 @@ title: LibSass is Deprecated author: Natalie Weizenbaum tags: blog -#date: 2020-10-26 12:00 PST +date: 2020-10-26 12:00:00 -8 --- After much discussion among the Sass core team, we've come to the conclusion diff --git a/source/blog/028-request-for-comments-first-class-calc.md b/source/blog/028-request-for-comments-first-class-calc.md index 97cb2a2e0..490e84a4e 100644 --- a/source/blog/028-request-for-comments-first-class-calc.md +++ b/source/blog/028-request-for-comments-first-class-calc.md @@ -2,7 +2,7 @@ title: 'Request for Comments: First-Class Calc' author: Natalie Weizenbaum tags: blog -# date: 2021-3-15 1:35 PST +date: 2021-3-15 1:35:00 -8 --- One of the absolutely most-requested features in Sass is the ability to more diff --git a/source/blog/029-node-fibers-discontinued.md b/source/blog/029-node-fibers-discontinued.md index 1d296f817..a8a7e4afe 100644 --- a/source/blog/029-node-fibers-discontinued.md +++ b/source/blog/029-node-fibers-discontinued.md @@ -2,7 +2,7 @@ title: 'The Discontinuation of node-fibers' author: Natalie Weizenbaum tags: blog -# date: 2021-3-26 15:00 PST +date: 2021-3-26 15:00:00 -8 --- We have recently received the unfortunate but not entirely surprising news that diff --git a/source/blog/030-request-for-comments-new-js-api.html.md b/source/blog/030-request-for-comments-new-js-api.html.md index 575f17a93..5ecbfb5a3 100644 --- a/source/blog/030-request-for-comments-new-js-api.html.md +++ b/source/blog/030-request-for-comments-new-js-api.html.md @@ -2,7 +2,7 @@ title: 'Request for Comments: New JS API' author: Natalie Weizenbaum tags: blog -# date: 2021-08-05 15:30 PST +date: 2021-08-05 15:30:00 -8 --- I'm excited to officially unveil something that's been in the works for quite a diff --git a/source/blog/031-new-js-api-release-candidate.html.md b/source/blog/031-new-js-api-release-candidate.html.md index 79eaaea54..2f3f61f46 100644 --- a/source/blog/031-new-js-api-release-candidate.html.md +++ b/source/blog/031-new-js-api-release-candidate.html.md @@ -2,7 +2,7 @@ title: 'New JS API Release Candidate is Live' author: Natalie Weizenbaum tags: blog -# date: 2021-11-20 16:15 PST +date: 2021-11-20 16:15:00 -8 --- The new JavaScript API that we [announced a few months ago] is now fully diff --git a/source/blog/032-embedded-sass-is-live.md b/source/blog/032-embedded-sass-is-live.md index bc201313b..d0f87020e 100644 --- a/source/blog/032-embedded-sass-is-live.md +++ b/source/blog/032-embedded-sass-is-live.md @@ -2,7 +2,7 @@ title: 'Embedded Sass is Live' author: Natalie Weizenbaum tags: blog -# date: 2022-02-01 2:00 PST +date: 2022-02-01 2:00:00 -8 --- After several years of planning and development, I'm excited to finally announce diff --git a/source/blog/033-request-for-comments-strict-unary-operators.md b/source/blog/033-request-for-comments-strict-unary-operators.md index 01a85f268..0a03bbe38 100644 --- a/source/blog/033-request-for-comments-strict-unary-operators.md +++ b/source/blog/033-request-for-comments-strict-unary-operators.md @@ -2,7 +2,7 @@ title: 'Request for Comments: Strict Unary Operators' author: Natalie Weizenbaum tags: blog -# date: 2022-06-15 15:30 PST +date: 2022-06-15 15:30:00 -8 --- Do you know what `margin: $a -$b` does in Sass? If you said "the same thing as diff --git a/source/blog/034-request-for-comments-color-spaces.md b/source/blog/034-request-for-comments-color-spaces.md index a5332929d..bb6db9736 100644 --- a/source/blog/034-request-for-comments-color-spaces.md +++ b/source/blog/034-request-for-comments-color-spaces.md @@ -2,7 +2,7 @@ title: 'Request for Comments: Color Spaces' author: Miriam Suzanne and Natalie Weizenbaum tags: blog -# date: 2022-09-21 13:00 PST +date: 2022-09-21 13:00:00 -8 --- There's been a lot of exciting work in the CSS color specifications lately, and diff --git a/source/blog/035-security-alert-tar-permissions.md b/source/blog/035-security-alert-tar-permissions.md index 96b40c053..5c1db6017 100644 --- a/source/blog/035-security-alert-tar-permissions.md +++ b/source/blog/035-security-alert-tar-permissions.md @@ -3,7 +3,7 @@ title: 'Security Alert: Tar Permissions' author: Natalie Weizenbaum tags: blog layout: base -# date: 2022-12-09 16:00 PST +date: 2022-12-09 16:00:00 -8 --- The Sass team was recently alerted by prolific external contributor [@ntkme] to From cf0bd2c4bedbbd8eb4e6a2f8551ec1e873ce016e Mon Sep 17 00:00:00 2001 From: Sana Javed Date: Sat, 4 Mar 2023 13:24:19 +0100 Subject: [PATCH 16/42] Fixing yarn lock --- yarn.lock | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/yarn.lock b/yarn.lock index 7ffd9e33d..c35dfbe41 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1557,6 +1557,15 @@ __metadata: languageName: node linkType: hard +"@jridgewell/trace-mapping@npm:0.3.9": + version: 0.3.9 + resolution: "@jridgewell/trace-mapping@npm:0.3.9" + dependencies: + "@jridgewell/resolve-uri": ^3.0.3 + "@jridgewell/sourcemap-codec": ^1.4.10 + checksum: d89597752fd88d3f3480845691a05a44bd21faac18e2185b6f436c3b0fd0c5a859fbbd9aaa92050c4052caf325ad3e10e2e1d1b64327517471b7d51babc0ddef + languageName: node + linkType: hard "@jridgewell/trace-mapping@npm:^0.3.17, @jridgewell/trace-mapping@npm:^0.3.9": version: 0.3.17 From 9fdd40c14b612d67b6ea90f5eeb794199927d9b2 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 6 Mar 2023 08:06:10 +0000 Subject: [PATCH 17/42] chore(deps): Automated dependency upgrades --- package.json | 10 +-- yarn.lock | 202 +++++++++++++++++++++++++-------------------------- 2 files changed, 106 insertions(+), 106 deletions(-) diff --git a/package.json b/package.json index d0922df4e..f63d02c3e 100644 --- a/package.json +++ b/package.json @@ -52,8 +52,8 @@ "@types/jquery": "^3.5.16", "@types/jqueryui": "^1.12.16", "@types/node": "^16", - "@typescript-eslint/eslint-plugin": "^5.53.0", - "@typescript-eslint/parser": "^5.53.0", + "@typescript-eslint/eslint-plugin": "^5.54.0", + "@typescript-eslint/parser": "^5.54.0", "date-fns": "^2.29.3", "deep-equal": "^2.2.0", "eslint": "^8.35.0", @@ -72,12 +72,12 @@ "netlify-plugin-11ty": "^1.3.0", "npm-run-all": "^4.1.5", "prettier": "^2.8.4", - "rollup": "^3.17.3", + "rollup": "^3.18.0", "sass": "^1.58.3", - "semver-parser": "^4.1.2", + "semver-parser": "^4.1.3", "stylelint": "^15.2.0", "stylelint-config-standard-scss": "^7.0.1", - "typedoc": "^0.23.26", + "typedoc": "^0.24.0-beta.2", "typescript": "^4.9.5", "typogr": "^0.6.8" }, diff --git a/yarn.lock b/yarn.lock index bd480a07f..88d8ae44e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1805,9 +1805,9 @@ __metadata: linkType: hard "@types/node@npm:^16": - version: 16.18.13 - resolution: "@types/node@npm:16.18.13" - checksum: c284f97a0630d65887be0e0d7ef8e5e5022eb4916ffae142db07f22dad565a80f17b6a84f21b4521c707f642540430710a8aa5930a2cf2bcbecde0a476ff9c02 + version: 16.18.14 + resolution: "@types/node@npm:16.18.14" + checksum: 7865c1c3e7c7d2fef6103c6dfa181755dc48365024253d6acc460e884508b5937a222aa8bd04835988ff0bdc47867e2ada78859c0a7f9c65b44884316f3b469c languageName: node linkType: hard @@ -1839,13 +1839,13 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:^5.53.0": - version: 5.53.0 - resolution: "@typescript-eslint/eslint-plugin@npm:5.53.0" +"@typescript-eslint/eslint-plugin@npm:^5.54.0": + version: 5.54.0 + resolution: "@typescript-eslint/eslint-plugin@npm:5.54.0" dependencies: - "@typescript-eslint/scope-manager": 5.53.0 - "@typescript-eslint/type-utils": 5.53.0 - "@typescript-eslint/utils": 5.53.0 + "@typescript-eslint/scope-manager": 5.54.0 + "@typescript-eslint/type-utils": 5.54.0 + "@typescript-eslint/utils": 5.54.0 debug: ^4.3.4 grapheme-splitter: ^1.0.4 ignore: ^5.2.0 @@ -1859,43 +1859,43 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 12dffe65969d8e5248c86a700fe46a737e55ecafb276933e747b4731eab6266fe55e2d43a34b8b340179fe248e127d861cd016a7614b1b9804cd0687c99616d1 + checksum: 4fdb520b8e0f6b9eb878206ddfa4212522f170d1507d7aba8a975159a198efa37af6d2d17982dd560317452d0748f2e2da5dd7347b172bc4446d1c5562ce2e94 languageName: node linkType: hard -"@typescript-eslint/parser@npm:^5.53.0": - version: 5.53.0 - resolution: "@typescript-eslint/parser@npm:5.53.0" +"@typescript-eslint/parser@npm:^5.54.0": + version: 5.54.0 + resolution: "@typescript-eslint/parser@npm:5.54.0" dependencies: - "@typescript-eslint/scope-manager": 5.53.0 - "@typescript-eslint/types": 5.53.0 - "@typescript-eslint/typescript-estree": 5.53.0 + "@typescript-eslint/scope-manager": 5.54.0 + "@typescript-eslint/types": 5.54.0 + "@typescript-eslint/typescript-estree": 5.54.0 debug: ^4.3.4 peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 979e5d63793a9e64998b1f956ba0f00f8a2674db3a664fafce7b2433323f5248bd776af8305e2419d73a9d94c55176fee099abc5c153b4cc52e5765c725c1edd + checksum: 368d6dd85be42c3f518f0ddeed23ecd1d3c9484a77ae291ee4e08e2703ed379bed613bde014cd8ab2a3e06e85dd8aef201112ae5e3d2a07deba29ae80bb1fe06 languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:5.53.0": - version: 5.53.0 - resolution: "@typescript-eslint/scope-manager@npm:5.53.0" +"@typescript-eslint/scope-manager@npm:5.54.0": + version: 5.54.0 + resolution: "@typescript-eslint/scope-manager@npm:5.54.0" dependencies: - "@typescript-eslint/types": 5.53.0 - "@typescript-eslint/visitor-keys": 5.53.0 - checksum: 51f31dc01e95908611f402441f58404da80a338c0237b2b82f4a7b0b2e8868c4bfe8f7cf44b2567dd56533de609156a5d4ac54bb1f9f09c7014b99428aef2543 + "@typescript-eslint/types": 5.54.0 + "@typescript-eslint/visitor-keys": 5.54.0 + checksum: e50f12396de0ddb94aab119bdd5f4769b80dd2c273e137fd25e5811e25114d7a3d3668cdb3c454aca9537e940744881d62a1fed2ec86f07f60533dc7382ae15c languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:5.53.0": - version: 5.53.0 - resolution: "@typescript-eslint/type-utils@npm:5.53.0" +"@typescript-eslint/type-utils@npm:5.54.0": + version: 5.54.0 + resolution: "@typescript-eslint/type-utils@npm:5.54.0" dependencies: - "@typescript-eslint/typescript-estree": 5.53.0 - "@typescript-eslint/utils": 5.53.0 + "@typescript-eslint/typescript-estree": 5.54.0 + "@typescript-eslint/utils": 5.54.0 debug: ^4.3.4 tsutils: ^3.21.0 peerDependencies: @@ -1903,23 +1903,23 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 52c40967c5fabd58c2ae8bf519ef89e4feb511e4df630aeaeac8335661a79b6b3a32d30a61a5f1d8acc703f21c4d90751a5d41cda1b35d08867524da11bc2e1d + checksum: 9cb5b52c7277bdf74b9ea3282fc40f41fda90ea4b1d33039044476e43cf05a766b1294e7d45f429594f2776828f7d17729cfa4ea027315f3df883e748ba57514 languageName: node linkType: hard -"@typescript-eslint/types@npm:5.53.0": - version: 5.53.0 - resolution: "@typescript-eslint/types@npm:5.53.0" - checksum: b0eaf23de4ab13697d4d2095838c959a3f410c30f0d19091e5ca08e62320c3cc3c72bcb631823fb6a4fbb31db0a059e386a0801244930d0a88a6a698e5f46548 +"@typescript-eslint/types@npm:5.54.0": + version: 5.54.0 + resolution: "@typescript-eslint/types@npm:5.54.0" + checksum: 0f66b1b93078f3afea6dfcd3d4e2f0abea4f60cd0c613c2cf13f85098e5bf786185484c9846ed80b6c4272de2c31a70c5a8aacb91314cf1b6da7dcb8855cb7ac languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:5.53.0": - version: 5.53.0 - resolution: "@typescript-eslint/typescript-estree@npm:5.53.0" +"@typescript-eslint/typescript-estree@npm:5.54.0": + version: 5.54.0 + resolution: "@typescript-eslint/typescript-estree@npm:5.54.0" dependencies: - "@typescript-eslint/types": 5.53.0 - "@typescript-eslint/visitor-keys": 5.53.0 + "@typescript-eslint/types": 5.54.0 + "@typescript-eslint/visitor-keys": 5.54.0 debug: ^4.3.4 globby: ^11.1.0 is-glob: ^4.0.3 @@ -1928,35 +1928,35 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 6e119c8e4167c8495d728c5556a834545a9c064918dd5e7b79b0d836726f4f8e2a0297b0ac82bf2b71f1e5427552217d0b59d8fb1406fd79bd3bf91b75dca873 + checksum: 377c75c34c4f95b7ab6218c1d96a6db3ea6ed6727711b6a09354582fe0157861dc1b6fb9e3f7113cd09741f713735d59d5ab5845457f5733a4ebad7470bf600a languageName: node linkType: hard -"@typescript-eslint/utils@npm:5.53.0": - version: 5.53.0 - resolution: "@typescript-eslint/utils@npm:5.53.0" +"@typescript-eslint/utils@npm:5.54.0": + version: 5.54.0 + resolution: "@typescript-eslint/utils@npm:5.54.0" dependencies: "@types/json-schema": ^7.0.9 "@types/semver": ^7.3.12 - "@typescript-eslint/scope-manager": 5.53.0 - "@typescript-eslint/types": 5.53.0 - "@typescript-eslint/typescript-estree": 5.53.0 + "@typescript-eslint/scope-manager": 5.54.0 + "@typescript-eslint/types": 5.54.0 + "@typescript-eslint/typescript-estree": 5.54.0 eslint-scope: ^5.1.1 eslint-utils: ^3.0.0 semver: ^7.3.7 peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: 18e6bac14ae853385a74123759850bca367904723e170c37416fc014673eb714afb6bb090367bff61494a8387e941b6af65ee5f4f845f7177fabb4df85e01643 + checksum: b8f344fc2961c7af530b93e53d5a17b5084cdf550b381082e3fb7f349ef16e718d9eebde1b9fc2d8fc4ecf8d60d334b004359977247554265c1afc87323bed37 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:5.53.0": - version: 5.53.0 - resolution: "@typescript-eslint/visitor-keys@npm:5.53.0" +"@typescript-eslint/visitor-keys@npm:5.54.0": + version: 5.54.0 + resolution: "@typescript-eslint/visitor-keys@npm:5.54.0" dependencies: - "@typescript-eslint/types": 5.53.0 + "@typescript-eslint/types": 5.54.0 eslint-visitor-keys: ^3.3.0 - checksum: 090695883c15364c6f401e97f56b13db0f31c1114f3bd22562bd41734864d27f6a3c80de33957e9dedab2d5f94b0f4480ba3fde1d4574e74dca4593917b7b54a + checksum: 17fc323c09e6272b603cdaec30a99916600fbbb737e1fbc8c1727a487753b4363cea112277fa43e0562bff34bdd1de9ad73ff9433118b1fd469b112fad0313ca languageName: node linkType: hard @@ -2011,13 +2011,13 @@ __metadata: linkType: hard "agentkeepalive@npm:^4.2.1": - version: 4.2.1 - resolution: "agentkeepalive@npm:4.2.1" + version: 4.3.0 + resolution: "agentkeepalive@npm:4.3.0" dependencies: debug: ^4.1.0 - depd: ^1.1.2 + depd: ^2.0.0 humanize-ms: ^1.2.1 - checksum: 39cb49ed8cf217fd6da058a92828a0a84e0b74c35550f82ee0a10e1ee403c4b78ade7948be2279b188b7a7303f5d396ea2738b134731e464bf28de00a4f72a18 + checksum: 982453aa44c11a06826c836025e5162c846e1200adb56f2d075400da7d32d87021b3b0a58768d949d824811f5654223d5a8a3dad120921a2439625eb847c6260 languageName: node linkType: hard @@ -2486,9 +2486,9 @@ __metadata: linkType: hard "caniuse-lite@npm:^1.0.30001449": - version: 1.0.30001458 - resolution: "caniuse-lite@npm:1.0.30001458" - checksum: 258cc5a25babbbfe483bf788c6f321a19400ff80b2bf156b360bac09a6f9f4da44516350d187a30395667cb142c682d9ea96577ea0df236d35f76234b07ccb41 + version: 1.0.30001460 + resolution: "caniuse-lite@npm:1.0.30001460" + checksum: dad91eb82aa65aecf33ad6a04ad620b9df6f0152020dc6c1874224e8c6f4aa50695f585201b3dfcd2760b3c43326a86c9505cc03af856698fbef67b267ef786f languageName: node linkType: hard @@ -2893,10 +2893,10 @@ __metadata: languageName: node linkType: hard -"depd@npm:^1.1.2": - version: 1.1.2 - resolution: "depd@npm:1.1.2" - checksum: 6b406620d269619852885ce15965272b829df6f409724415e0002c8632ab6a8c0a08ec1f0bd2add05dc7bd7507606f7e2cc034fa24224ab829580040b835ecd9 +"depd@npm:^2.0.0": + version: 2.0.0 + resolution: "depd@npm:2.0.0" + checksum: abbe19c768c97ee2eed6282d8ce3031126662252c58d711f646921c9623f9052e3e1906443066beec1095832f534e57c523b7333f8e7e0d93051ab6baef5ab3a languageName: node linkType: hard @@ -3038,9 +3038,9 @@ __metadata: linkType: hard "electron-to-chromium@npm:^1.4.284": - version: 1.4.311 - resolution: "electron-to-chromium@npm:1.4.311" - checksum: 663fde5d90293d19c05b0dc65996e1ba6f3ee89d6365de3503de6a96c21439e18ea579fdd7d718e260708aa871ef333de934a4024d54fd109959ac0bca9d1400 + version: 1.4.320 + resolution: "electron-to-chromium@npm:1.4.320" + checksum: ea2c02bc286c0471ed7ad9b61225f6561921cf5f24a060cd1c46c2ea9932283ab924f66c370fbe5a229225dc1f747b395c943a0f5a9d058b72f561b1d8225787 languageName: node linkType: hard @@ -3459,11 +3459,11 @@ __metadata: linkType: hard "esquery@npm:^1.4.2": - version: 1.4.2 - resolution: "esquery@npm:1.4.2" + version: 1.5.0 + resolution: "esquery@npm:1.5.0" dependencies: estraverse: ^5.1.0 - checksum: 2f4ad89c5aafaca61cc2c15e256190f0d6deb4791cae6552d3cb4b1eb8867958cdf27a56aaa3272ff17435e3eaa19ee0d4129fac336ca6373d7354d7b5da7966 + checksum: aefb0d2596c230118656cd4ec7532d447333a410a48834d80ea648b1e7b5c9bc9ed8b5e33a89cb04e487b60d622f44cf5713bf4abed7c97343edefdc84a35900 languageName: node linkType: hard @@ -4266,13 +4266,13 @@ __metadata: linkType: hard "is-array-buffer@npm:^3.0.1": - version: 3.0.1 - resolution: "is-array-buffer@npm:3.0.1" + version: 3.0.2 + resolution: "is-array-buffer@npm:3.0.2" dependencies: call-bind: ^1.0.2 - get-intrinsic: ^1.1.3 + get-intrinsic: ^1.2.0 is-typed-array: ^1.1.10 - checksum: f26ab87448e698285daf707e52a533920449f7abf63714140ffab9d5571aa5a71ac2fa2677e8b793ad0d5d3e40078d4d2c8a0ab39c957e3cfc6513bb6c9dfdc9 + checksum: dcac9dda66ff17df9cabdc58214172bf41082f956eab30bb0d86bc0fab1e44b690fc8e1f855cf2481245caf4e8a5a006a982a71ddccec84032ed41f9d8da8c14 languageName: node linkType: hard @@ -4841,14 +4841,14 @@ __metadata: linkType: hard "liquidjs@npm:^10.4.0": - version: 10.6.0 - resolution: "liquidjs@npm:10.6.0" + version: 10.6.1 + resolution: "liquidjs@npm:10.6.1" dependencies: commander: ^10.0.0 bin: liquid: bin/liquid.js liquidjs: bin/liquid.js - checksum: ee0858847d9e32b00de5ed840a6b13b0eea83af6032cca7fd853e2f2ff250199856f62167adb1e9ec7484ad40df8c4b9f9f795183723e75af371c28550ad1b49 + checksum: fabb179a61c409dbda49e9f1da8dce643bcc562f0ef82a67fc35762b505c8d26d955a76211404e52835941f4fd2face8960b99b6d5766244fce232b65f836b29 languageName: node linkType: hard @@ -4975,9 +4975,9 @@ __metadata: linkType: hard "lru-cache@npm:^7.7.1": - version: 7.17.0 - resolution: "lru-cache@npm:7.17.0" - checksum: 28c2a98ad313b8d61beac1f08257b6f0ca990e39d24a9bc831030b6e209447cfb11c6d9d1a774282189bfc9609d1dfd17ebe485228dd68f7b96b6b9b7740894e + version: 7.18.3 + resolution: "lru-cache@npm:7.18.3" + checksum: e550d772384709deea3f141af34b6d4fa392e2e418c1498c078de0ee63670f1f46f5eee746e8ef7e69e1c895af0d4224e62ee33e66a543a14763b0f2e74c1356 languageName: node linkType: hard @@ -4989,9 +4989,9 @@ __metadata: linkType: hard "luxon@npm:^3.2.1": - version: 3.2.1 - resolution: "luxon@npm:3.2.1" - checksum: 3fa3def2c5f5d3032b4c46220c4da8aeb467ac979888fc9d2557adcd22195f93516b4ad5909a75862bec8dc6ddc0953b0f38e6d2f4a8ab8450ddc531a83cf20d + version: 3.3.0 + resolution: "luxon@npm:3.3.0" + checksum: 50cf17a0dc155c3dcacbeae8c0b7e80db425e0ba97b9cbdf12a7fc142d841ff1ab1560919f033af46240ed44e2f70c49f76e3422524c7fc8bb8d81ca47c66187 languageName: node linkType: hard @@ -5194,11 +5194,11 @@ __metadata: linkType: hard "minimatch@npm:^7.1.3": - version: 7.2.0 - resolution: "minimatch@npm:7.2.0" + version: 7.4.2 + resolution: "minimatch@npm:7.4.2" dependencies: brace-expansion: ^2.0.1 - checksum: f3c66f60e097fb9e1550a1b6ce5d8588d3cdfdb22c1bde9a293bd99e7a01833be2b975795299b50b9456542b239b2f0ba5edba71728ec644e5ca14d09d0cf620 + checksum: 9e341b04e69d5ab03e4206dcb61c8a158e3b8709628bf5e1a4eaa9f3b72c0ba925e24ad959b1f6ce6835caa5a927131d5087fae6836b69e7d99d7d5e63ef0bd8 languageName: node linkType: hard @@ -6420,9 +6420,9 @@ __metadata: languageName: node linkType: hard -"rollup@npm:^3.17.3": - version: 3.17.3 - resolution: "rollup@npm:3.17.3" +"rollup@npm:^3.18.0": + version: 3.18.0 + resolution: "rollup@npm:3.18.0" dependencies: fsevents: ~2.3.2 dependenciesMeta: @@ -6430,7 +6430,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: afce20a6ef4a613e5803eff7fb17a3efe740e326257b43f48bdbe10783f3eae79587d7e455234bc68f3c3154a50f2c29c85d4d2a42cdebcc17a5abeaeb04e0ed + checksum: 0bcd1abb1cc383abdd09b5594de862ecb2f946e950954bb472a370289bdc4499aea8d04477be55ce205450d973d38ad255f0dc6926162500a251d73bf0e60e6f languageName: node linkType: hard @@ -6485,8 +6485,8 @@ __metadata: "@types/jquery": ^3.5.16 "@types/jqueryui": ^1.12.16 "@types/node": ^16 - "@typescript-eslint/eslint-plugin": ^5.53.0 - "@typescript-eslint/parser": ^5.53.0 + "@typescript-eslint/eslint-plugin": ^5.54.0 + "@typescript-eslint/parser": ^5.54.0 date-fns: ^2.29.3 deep-equal: ^2.2.0 eslint: ^8.35.0 @@ -6505,12 +6505,12 @@ __metadata: netlify-plugin-11ty: ^1.3.0 npm-run-all: ^4.1.5 prettier: ^2.8.4 - rollup: ^3.17.3 + rollup: ^3.18.0 sass: ^1.58.3 - semver-parser: ^4.1.2 + semver-parser: ^4.1.3 stylelint: ^15.2.0 stylelint-config-standard-scss: ^7.0.1 - typedoc: ^0.23.26 + typedoc: ^0.24.0-beta.2 typescript: ^4.9.5 typogr: ^0.6.8 languageName: unknown @@ -6546,10 +6546,10 @@ __metadata: languageName: node linkType: hard -"semver-parser@npm:^4.1.2": - version: 4.1.2 - resolution: "semver-parser@npm:4.1.2" - checksum: acc04e6d90639d261599c2097cbfe7bdf530cb0e3e7a2c4935dfd762bbd823ea53fc0fe930cd751a298719543a711e2dcb2592926654201f4ff144eaaf4e5cdd +"semver-parser@npm:^4.1.3": + version: 4.1.3 + resolution: "semver-parser@npm:4.1.3" + checksum: d675bf0021c9ba6ee0b6dee658d2626cfca38e25da885c10a9678a26adbdba433e916a514eb7df78a48fa6736c6503cffac4b08139a4c9644987aa088447fe1f languageName: node linkType: hard @@ -7284,9 +7284,9 @@ __metadata: languageName: node linkType: hard -"typedoc@npm:^0.23.26": - version: 0.23.26 - resolution: "typedoc@npm:0.23.26" +"typedoc@npm:^0.24.0-beta.2": + version: 0.24.0-beta.2 + resolution: "typedoc@npm:0.24.0-beta.2" dependencies: lunr: ^2.3.9 marked: ^4.2.12 @@ -7296,7 +7296,7 @@ __metadata: typescript: 4.6.x || 4.7.x || 4.8.x || 4.9.x bin: typedoc: bin/typedoc - checksum: 09dbd221b5bd27a7f6c593a6aa7e4efc3c46f20761e109a76bf0ed7239011cca1261357094710c01472582060d75a7558aab5bf5b78db3aff7c52188d146ee65 + checksum: b3dbc02608775a8fcf19ae892221fcda06b3d766550e9ad889d698fb69a4c3fa6fc26439fd795586317ec59062c02faa2e44b09e5b30b8a0ca3ee819be3902c7 languageName: node linkType: hard From 2f4eec238abcbacf3efedb6f5c2e3a213b3ad9b4 Mon Sep 17 00:00:00 2001 From: Sana Javed Date: Mon, 6 Mar 2023 12:59:38 +0100 Subject: [PATCH 18/42] canSplit calculation and new codeExample short code --- eleventy.config.js | 50 ++++------------- source/_includes/code_example.liquid | 38 ++++++------- source/guide.liquid | 84 ++++------------------------ source/helpers/sass_helpers.ts | 57 +++++++++++++++++++ 4 files changed, 98 insertions(+), 131 deletions(-) diff --git a/eleventy.config.js b/eleventy.config.js index 0657f3d0b..1308dd1da 100644 --- a/eleventy.config.js +++ b/eleventy.config.js @@ -1,5 +1,6 @@ 'use strict'; +const path = require('path'); const { EleventyRenderPlugin } = require('@11ty/eleventy'); const syntaxHighlight = require('@11ty/eleventy-plugin-syntaxhighlight'); const formatDistanceToNow = require('date-fns/formatDistanceToNow'); @@ -9,8 +10,8 @@ const markdown = require('markdown-it'); const markdownItAttrs = require('markdown-it-attrs'); const markdownDefList = require('markdown-it-deflist'); const typogrify = require('typogr'); -const sass = require('sass'); -const { getImplStatus } = require('./source/helpers/sass_helpers.ts'); +const { Liquid } = require('liquidjs'); +const { getImplStatus, canSplit, generateCodeExample } = require('./source/helpers/sass_helpers.ts'); /** @param {import('@11ty/eleventy').UserConfig} eleventyConfig */ module.exports = (eleventyConfig) => { @@ -53,6 +54,15 @@ module.exports = (eleventyConfig) => { return ''; }); + const engine = new Liquid({ + root: path.resolve(__dirname, 'source/_includes/'), + extname: '.liquid', + }); + eleventyConfig.addLiquidShortcode('codeExample', (contents, exampleName, autogenCSS = true, syntax = null) => { + const codeExample = generateCodeExample(contents, autogenCSS) + return engine.renderFile('code_example.liquid', {code: codeExample, exampleName: exampleName}) + }) + // Paired shortcodes... eleventyConfig.addPairedLiquidShortcode('markdown', (content) => mdown.render(content), @@ -109,42 +119,6 @@ module.exports = (eleventyConfig) => { }, ); - eleventyConfig.addLiquidFilter( - 'codeExample', - (contents, autogenCSS = true, syntax = null) => { - //TODO when are values for syntax passed in? - //TODO add tests - const splitContents = contents.split('==='); - - const scssContents = splitContents[0]; - const sassContents = splitContents[1]; - const cssContents = splitContents[2]; - - const scssExamples = scssContents.split('---'); - const sassExamples = sassContents.split('---'); - - let cssExample; - if (cssContents) { - cssExample = cssContents; - } else if (!cssContents && autogenCSS) { - // TODO check first if you even have scss or sass to generate css from - // TODO what if no scss but sass? - cssExample = ''; - scssExamples.forEach((scssSnippet) => { - const generatedCSS = sass.compileString(scssSnippet); - cssExample += generatedCSS.css; - }); - } - - return { - scss: scssExamples, - css: cssExample, - sass: sassExamples, - splitLocation: '50.0%', //TODO dynamically determine - }; - }, - ); - eleventyConfig.addPlugin(EleventyRenderPlugin); eleventyConfig.addPlugin(syntaxHighlight); diff --git a/source/_includes/code_example.liquid b/source/_includes/code_example.liquid index 9ee072660..5bd567712 100644 --- a/source/_includes/code_example.liquid +++ b/source/_includes/code_example.liquid @@ -1,56 +1,52 @@ -{% assign first_tab_id = ui_id %} -{% assign second_tab_id = first_tab_id | plus: 1 %} -{% assign third_tab_id = second_tab_id | plus: 1 %} - -
+
@@ -59,9 +55,9 @@ {%- endfor -%}
diff --git a/yarn.lock b/yarn.lock index 3e8c98d4e..316386a3d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6587,6 +6587,7 @@ __metadata: netlify-plugin-11ty: ^1.3.0 npm-run-all: ^4.1.5 prettier: ^2.8.4 + prismjs: ^1.29.0 rollup: ^3.18.0 sass: ^1.58.3 semver-parser: ^4.1.3 From d5980ec95004b43144702b29a88c7352262d0120 Mon Sep 17 00:00:00 2001 From: oluniyiawo Date: Tue, 7 Mar 2023 22:08:12 +0000 Subject: [PATCH 26/42] add author and date to individual blogs --- source/_layouts/blog.liquid | 5 ++++- source/blog/blog.11tydata.yml | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/source/_layouts/blog.liquid b/source/_layouts/blog.liquid index d4574dad0..b5519f437 100644 --- a/source/_layouts/blog.liquid +++ b/source/_layouts/blog.liquid @@ -1,5 +1,8 @@ --- layout: has_no_sidebars --- - +Posted {{ page.date | formatBlogDate }} by {{ author }} + {{ content }} \ No newline at end of file diff --git a/source/blog/blog.11tydata.yml b/source/blog/blog.11tydata.yml index 4d89d81aa..5fc21f80e 100644 --- a/source/blog/blog.11tydata.yml +++ b/source/blog/blog.11tydata.yml @@ -1,2 +1,2 @@ -layout: has_no_sidebars +layout: blog tags: blog From 67ab605ec0fa943a06215e94365ca2840fabb581 Mon Sep 17 00:00:00 2001 From: oluniyiawo Date: Tue, 7 Mar 2023 22:08:49 +0000 Subject: [PATCH 27/42] Remove extra console log --- source/_layouts/blog.liquid | 3 --- 1 file changed, 3 deletions(-) diff --git a/source/_layouts/blog.liquid b/source/_layouts/blog.liquid index b5519f437..3e65931a7 100644 --- a/source/_layouts/blog.liquid +++ b/source/_layouts/blog.liquid @@ -2,7 +2,4 @@ layout: has_no_sidebars --- Posted {{ page.date | formatBlogDate }} by {{ author }} - {{ content }} \ No newline at end of file From 1ee58ae14da74cc4c70d1240ce23caaa63b7505f Mon Sep 17 00:00:00 2001 From: oluniyiawo Date: Tue, 7 Mar 2023 22:13:28 +0000 Subject: [PATCH 28/42] sort out permalinks --- source/blog/007-thank-you-marcel.md | 1 + source/blog/blog.11tydata.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/source/blog/007-thank-you-marcel.md b/source/blog/007-thank-you-marcel.md index 10d0ee72b..205071103 100644 --- a/source/blog/007-thank-you-marcel.md +++ b/source/blog/007-thank-you-marcel.md @@ -2,6 +2,7 @@ title: Dropping Support For Old Ruby Versions author: Natalie Weizenbaum date: 2016-05-24 14:41:00 -8 +permalink: /thank-you-marcel --- You may not know [Marcel Greter](https://github.com/mgreter), but you almost diff --git a/source/blog/blog.11tydata.yml b/source/blog/blog.11tydata.yml index 5fc21f80e..6bae59ef8 100644 --- a/source/blog/blog.11tydata.yml +++ b/source/blog/blog.11tydata.yml @@ -1,2 +1,3 @@ layout: blog tags: blog +permalink: /{{ title | slugify }} From edc5c5f901eef34b21ba2c8d7f587b6c3a27a68b Mon Sep 17 00:00:00 2001 From: oluniyiawo Date: Tue, 7 Mar 2023 22:14:08 +0000 Subject: [PATCH 29/42] sort out permalinks --- source/blog/blog.11tydata.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blog/blog.11tydata.yml b/source/blog/blog.11tydata.yml index 6bae59ef8..5c7e49bdf 100644 --- a/source/blog/blog.11tydata.yml +++ b/source/blog/blog.11tydata.yml @@ -1,3 +1,3 @@ layout: blog tags: blog -permalink: /{{ title | slugify }} +permalink: /blog/{{ title | slugify }} From f755d09364ed5403eb0d4c06da8df78e0862bae3 Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Wed, 8 Mar 2023 11:18:32 -0500 Subject: [PATCH 30/42] Clean up code example logic and templates --- eleventy.config.js | 13 ++- source/_includes/code_example.liquid | 77 ------------- .../code_examples/code_example.liquid | 27 +++++ source/_includes/code_examples/panel.liquid | 9 ++ source/_includes/code_examples/tab.liquid | 3 + source/guide.liquid | 51 +++++---- source/helpers/sass_helpers.ts | 102 ++++++++++++------ 7 files changed, 150 insertions(+), 132 deletions(-) delete mode 100644 source/_includes/code_example.liquid create mode 100644 source/_includes/code_examples/code_example.liquid create mode 100644 source/_includes/code_examples/panel.liquid create mode 100644 source/_includes/code_examples/tab.liquid diff --git a/eleventy.config.js b/eleventy.config.js index 211916e40..94b94216d 100644 --- a/eleventy.config.js +++ b/eleventy.config.js @@ -16,9 +16,8 @@ const PrismLoader = require('prismjs/components/index.js'); const typogrify = require('typogr'); const { - getImplStatus, - canSplit, generateCodeExample, + getImplStatus, } = require('./source/helpers/sass_helpers.ts'); /** @param {import('@11ty/eleventy').UserConfig} eleventyConfig */ @@ -71,6 +70,11 @@ module.exports = (eleventyConfig) => { }); // Paired shortcodes... + + // Ideally this could be used with named args, but that's not supported yet in + // 11ty's implementation of LiquidJS: + // https://github.com/11ty/eleventy/issues/2679 + // In the meantime, the args are: `dart`, `libsass`, `ruby`, `feature` eleventyConfig.addPairedLiquidShortcode( 'compatibility', async (details, dart = null, libsass = null, ruby = null, feature = null) => @@ -86,8 +90,8 @@ module.exports = (eleventyConfig) => { eleventyConfig.addPairedLiquidShortcode( 'codeExample', async (contents, exampleName, autogenCSS = true, syntax = null) => { - const code = generateCodeExample(contents, autogenCSS); - return await liquidEngine.renderFile('code_example', { + const code = generateCodeExample(contents, autogenCSS, syntax); + return liquidEngine.renderFile('code_examples/code_example', { code, exampleName, }); @@ -146,6 +150,7 @@ module.exports = (eleventyConfig) => { getImplStatus(status), ); + // plugins eleventyConfig.addPlugin(EleventyRenderPlugin); eleventyConfig.addPlugin(syntaxHighlight); diff --git a/source/_includes/code_example.liquid b/source/_includes/code_example.liquid deleted file mode 100644 index a156f4aca..000000000 --- a/source/_includes/code_example.liquid +++ /dev/null @@ -1,77 +0,0 @@ -
- -
- {%- for scss in code.scss -%} - {% code 'scss' %}{{ scss | strip }}{% endcode %} - {%- endfor -%} -
- - -
diff --git a/source/_includes/code_examples/code_example.liquid b/source/_includes/code_examples/code_example.liquid new file mode 100644 index 000000000..1c27fe02f --- /dev/null +++ b/source/_includes/code_examples/code_example.liquid @@ -0,0 +1,27 @@ +
+
    + {% if code.scss.size %} + {% render 'code_examples/tab', name: 'SCSS', syntax: 'scss', id: exampleName, enabled: true %} + {% endif %} + {% if code.sass.size %} + {% assign enabled = code.scss.size == 0 %} + {% render 'code_examples/tab', name: 'Sass', syntax: 'sass', id: exampleName, enabled: enabled %} + {% endif %} + {% if code.css.size %} + {% render 'code_examples/tab', name: 'CSS', syntax: 'css', id: exampleName, enabled: false %} + {% endif %} +
+ {% if code.scss.size %} + {% render 'code_examples/panel', name: 'SCSS Syntax', syntax: 'scss', id: exampleName, examples: code.scss, enabled: true %} + {% endif %} + {% if code.sass.size %} + {% assign enabled = code.scss.size == 0 %} + {% render 'code_examples/panel', name: 'Sass Syntax', syntax: 'sass', id: exampleName, examples: code.sass, enabled: enabled %} + {% endif %} + {% if code.css.size %} + {% render 'code_examples/panel', name: 'CSS Output', syntax: 'css', id: exampleName, examples: code.css, enabled: false %} + {% endif %} +
diff --git a/source/_includes/code_examples/panel.liquid b/source/_includes/code_examples/panel.liquid new file mode 100644 index 000000000..d0647fa75 --- /dev/null +++ b/source/_includes/code_examples/panel.liquid @@ -0,0 +1,9 @@ +
+

{{ name }}

+ {% for example in examples %} + {% code syntax %}{{ example | strip }}{% endcode %} + {% endfor %} +
diff --git a/source/_includes/code_examples/tab.liquid b/source/_includes/code_examples/tab.liquid new file mode 100644 index 000000000..2e9584d44 --- /dev/null +++ b/source/_includes/code_examples/tab.liquid @@ -0,0 +1,3 @@ +
  • + {{ name }} +
  • diff --git a/source/guide.liquid b/source/guide.liquid index 1e3566567..b3b417c75 100644 --- a/source/guide.liquid +++ b/source/guide.liquid @@ -10,19 +10,21 @@ navigation: | --- -
    +
    +{% # retain older link %} + {% markdown %} ## Preprocessing @@ -76,7 +78,9 @@ separate them. All our examples are available in both syntaxes.
    -
    +
    +{% # retain older link %} + {% markdown %} ## Variables @@ -115,7 +119,9 @@ working with brand colors and keeping them consistent throughout the site.
    -
    +
    +{% # retain older link %} + {% markdown %} ## Nesting @@ -174,7 +180,9 @@ readable.
    -
    +
    +{% # retain older link %} + {% markdown %} ## Partials @@ -192,7 +200,9 @@ partials are used with the `@use` rule.
    -
    +
    +{% # retain older link %} +

    Modules

    @@ -205,7 +215,7 @@ a *module*, which means you can refer to its variables, [mixins][], and [functions][] in your Sass file with a namespace based on the filename. Using a file will also include the CSS it generates in your compiled output! -[mixins]: #topic-6 +[mixins]: #mixins [functions]: documentation/at-rules/function {% endmarkdown %} @@ -263,7 +273,9 @@ figure it out for you.
    -
    +
    +{% # retain older link %} + {% markdown %} ## Mixins @@ -319,7 +331,9 @@ starting with `@include` followed by the name of the mixin.
    -
    +
    +{% # retain older link %} + {% markdown %} ## Extend/Inheritance @@ -413,7 +427,9 @@ Note that the CSS in `%equal-heights` isn't generated, because
    -
    +
    +{% # retain older link %} + {% markdown %} ## Operators @@ -473,4 +489,3 @@ without much hassle. {% endmarkdown %}
    -
    diff --git a/source/helpers/sass_helpers.ts b/source/helpers/sass_helpers.ts index b4c966e78..c2da81619 100644 --- a/source/helpers/sass_helpers.ts +++ b/source/helpers/sass_helpers.ts @@ -3,36 +3,69 @@ import sass from 'sass'; export function generateCodeExample( contents: string, autogenCSS: boolean, - syntax: string, + syntax: 'sass' | 'scss' | null, ) { - const splitContents = contents.split('==='); + const splitContents = contents.split('\n===\n'); - const scssContents = splitContents[0]; - const sassContents = splitContents[1]; - const cssContents = splitContents[2]; + let scssContents, sassContents, cssContents; + switch (syntax) { + case 'scss': + scssContents = splitContents[0]; + cssContents = splitContents[1]; + break; + case 'sass': + sassContents = splitContents[0]; + cssContents = splitContents[1]; + break; + default: + scssContents = splitContents[0]; + sassContents = splitContents[1]; + cssContents = splitContents[2]; + if (!sassContents) { + throw new Error(`Couldn't find === in:\n${contents}`); + } + break; + } + + const scssExamples = + scssContents?.split('\n---\n').map((str) => str.trim()) ?? []; + const sassExamples = + sassContents?.split('\n---\n').map((str) => str.trim()) ?? []; + + if (!cssContents && autogenCSS) { + const sections = scssContents ? scssExamples : sassExamples; + if (sections.length !== 1) { + throw new Error("Can't auto-generate CSS from more than one SCSS block."); + } + cssContents = sass.compileString(sections[0], { + syntax: syntax === 'sass' ? 'indented' : 'scss', + }).css; + } - const scssExamples = scssContents.split('---'); - const sassExamples = sassContents.split('---'); + const cssExamples = + cssContents?.split('\n---\n').map((str) => str.trim()) ?? []; - let cssExample: string; - if (cssContents) { - cssExample = cssContents; - } else { - // TODO check first if you even have scss or sass to generate css from - // TODO what if no scss but sass? - cssExample = ''; - scssExamples.forEach((scssSnippet) => { - const generatedCSS = sass.compileString(scssSnippet); - cssExample += generatedCSS.css; - }); + const { canSplit, maxSourceWidth, maxCSSWidth } = getCanSplit( + scssExamples, + sassExamples, + cssExamples, + ); + let splitLocation: number | null = null; + if (canSplit) { + if (maxSourceWidth < 55 && maxCSSWidth < 55) { + splitLocation = 0.5 * 100; + } else { + // Put the split exactly in between the two longest lines. + splitLocation = 0.5 + ((maxSourceWidth - maxCSSWidth) / 110.0 / 2) * 100; + } } return { scss: scssExamples, - css: cssExample, sass: sassExamples, - canSplit: canSplit(scssExamples, sassExamples, cssExample), - splitLocation: '50.0%', // TODO remove when css grid implementation done + css: cssExamples, + canSplit, + splitLocation, }; } @@ -50,23 +83,26 @@ export function getImplStatus(status: string | boolean | null) { } } -export function canSplit( +function getCanSplit( scssExamples: string[], sassExamples: string[], - cssExample: string, + cssExamples: string[], ) { - const exampleSources: [string[], string[]] = [scssExamples, sassExamples]; - const exampleSourceLengths = exampleSources - .map((sourceList) => - sourceList.map((source) => source.split('\n').map((line) => line.length)), - ) - .flat() - .flat(); - const cssSourceLengths = cssExample.split('\n').map((line) => line.length); + const exampleSourceLengths = [...scssExamples, ...sassExamples].flatMap( + (source) => source.split('\n').map((line) => line.length), + ); + const cssSourceLengths = cssExamples.flatMap((source) => + source.split('\n').map((line) => line.length), + ); const maxSourceWidth = Math.max(...exampleSourceLengths); const maxCSSWidth = Math.max(...cssSourceLengths); - //TODO css example doesn't include comments so extend inheritance example can split is wrong - return Boolean(maxSourceWidth + maxCSSWidth < 110); + const canSplit = Boolean(maxCSSWidth && maxSourceWidth + maxCSSWidth < 110); + + return { + canSplit, + maxSourceWidth, + maxCSSWidth, + }; } From 047fdf318df7dcc8879a4686a790a44a60152a08 Mon Sep 17 00:00:00 2001 From: oluniyiawo Date: Wed, 8 Mar 2023 19:03:38 +0000 Subject: [PATCH 31/42] addressed style review comments --- source/_layouts/blog.liquid | 2 +- source/blog.liquid | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/_layouts/blog.liquid b/source/_layouts/blog.liquid index 3e65931a7..360cfc52a 100644 --- a/source/_layouts/blog.liquid +++ b/source/_layouts/blog.liquid @@ -1,5 +1,5 @@ --- layout: has_no_sidebars --- -Posted {{ page.date | formatBlogDate }} by {{ author }} +

    Posted {{ page.date | formatBlogDate }} by {{ author }}

    {{ content }} \ No newline at end of file diff --git a/source/blog.liquid b/source/blog.liquid index 96df7f8d3..28b1ed705 100644 --- a/source/blog.liquid +++ b/source/blog.liquid @@ -20,8 +20,8 @@ Page {{ pagination.pageNumber | plus: 1 }} of {{ pagination.pages.length }}

    {{ post.data.title }}

    -

    Posted {{ post.date | formatBlogDate }} by {{ post.data.author }}

    -

    {{ post.content | truncatePost }}

    +

    Posted {{ post.date | formatBlogDate }} by {{ post.data.author }}

    + {{ post.content | truncatePost }} {%- endfor -%} {% if pagination.href.next %} From 7b7047a4bd5881f3da5fd7c5ee49ae26d767f1a5 Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Wed, 8 Mar 2023 15:59:19 -0500 Subject: [PATCH 32/42] Organize and document 11ty filters. --- eleventy.config.js | 150 ++++-------------- package.json | 3 + source/@types/markdown-it-deflist.d.ts | 5 + source/@types/typogr.d.ts | 3 + source/_data/releases.js | 20 ++- .../{sass_helpers.ts => codeExample.ts} | 75 +++++++-- source/helpers/compatibility.ts | 54 +++++++ source/helpers/components.ts | 29 ++++ source/helpers/dates.ts | 9 ++ source/helpers/engines.ts | 34 ++++ source/helpers/page.ts | 15 ++ source/helpers/type.ts | 45 ++++++ tsconfig.json | 3 + yarn.lock | 43 +++++ 14 files changed, 351 insertions(+), 137 deletions(-) create mode 100644 source/@types/markdown-it-deflist.d.ts create mode 100644 source/@types/typogr.d.ts rename source/helpers/{sass_helpers.ts => codeExample.ts} (59%) create mode 100644 source/helpers/compatibility.ts create mode 100644 source/helpers/components.ts create mode 100644 source/helpers/dates.ts create mode 100644 source/helpers/engines.ts create mode 100644 source/helpers/page.ts create mode 100644 source/helpers/type.ts diff --git a/eleventy.config.js b/eleventy.config.js index 94b94216d..ce4791078 100644 --- a/eleventy.config.js +++ b/eleventy.config.js @@ -1,24 +1,16 @@ 'use strict'; -const path = require('path'); - const { EleventyRenderPlugin } = require('@11ty/eleventy'); const syntaxHighlight = require('@11ty/eleventy-plugin-syntaxhighlight'); -const formatDistanceToNow = require('date-fns/formatDistanceToNow'); const yaml = require('js-yaml'); -const { Liquid } = require('liquidjs'); -const { LoremIpsum } = require('lorem-ipsum'); -const markdown = require('markdown-it'); -const markdownItAttrs = require('markdown-it-attrs'); -const markdownDefList = require('markdown-it-deflist'); -const Prism = require('prismjs'); -const PrismLoader = require('prismjs/components/index.js'); -const typogrify = require('typogr'); -const { - generateCodeExample, - getImplStatus, -} = require('./source/helpers/sass_helpers.ts'); +const codeExample = require('./source/helpers/codeExample.ts').default; +const compatibility = require('./source/helpers/compatibility.ts'); +const components = require('./source/helpers/components.ts'); +const dates = require('./source/helpers/dates.ts'); +const { liquidEngine, markdownEngine } = require('./source/helpers/engines.ts'); +const page = require('./source/helpers/page.ts'); +const type = require('./source/helpers/type.ts'); /** @param {import('@11ty/eleventy').UserConfig} eleventyConfig */ module.exports = (eleventyConfig) => { @@ -26,129 +18,49 @@ module.exports = (eleventyConfig) => { eleventyConfig.addPassthroughCopy('source/assets/img'); eleventyConfig.addPassthroughCopy('source/favicon.ico'); - const liquidEngine = new Liquid({ - root: [ - path.resolve(__dirname, 'source/_includes/'), - path.resolve(__dirname, 'source/'), - ], - extname: '.liquid', - strictFilters: true, - jsTruthy: true, - }); - - eleventyConfig.setLibrary('liquid', liquidEngine); eleventyConfig.setUseGitIgnore(false); eleventyConfig.watchIgnores.add('source/_data/versionCache.json'); - const mdown = markdown({ - html: true, - typographer: true, - }) - .use(markdownDefList) - .use(markdownItAttrs); - - eleventyConfig.setLibrary('md', mdown); + eleventyConfig.setLibrary('liquid', liquidEngine); + eleventyConfig.setLibrary('md', markdownEngine); eleventyConfig.addDataExtension('yml, yaml', (contents) => yaml.load(contents), ); - // Shortcodes... - const lorem = new LoremIpsum(); - eleventyConfig.addLiquidShortcode('lorem', (type, number = 1) => { - switch (type) { - case 'sentence': - case 'sentences': - return lorem.generateSentences(number); - case 'paragraph': - case 'paragraphs': - return lorem.generateParagraphs(number); - case 'word': - case 'words': - return lorem.generateWords(number); - } - return ''; - }); - - // Paired shortcodes... - + // Components + eleventyConfig.addPairedLiquidShortcode('code', components.codeBlock); + eleventyConfig.addPairedLiquidShortcode('codeExample', codeExample); // Ideally this could be used with named args, but that's not supported yet in // 11ty's implementation of LiquidJS: // https://github.com/11ty/eleventy/issues/2679 // In the meantime, the args are: `dart`, `libsass`, `ruby`, `feature` eleventyConfig.addPairedLiquidShortcode( 'compatibility', - async (details, dart = null, libsass = null, ruby = null, feature = null) => - liquidEngine.renderFile('compatibility', { - details, - dart, - libsass, - ruby, - feature, - }), + compatibility.compatibility, ); + eleventyConfig.addPairedLiquidShortcode('funFact', components.funFact); + eleventyConfig.addLiquidFilter('implStatus', compatibility.implStatus); + // Type + eleventyConfig.addLiquidShortcode('lorem', type.getLorem); + eleventyConfig.addPairedLiquidShortcode('markdown', type.markdown); + eleventyConfig.addLiquidFilter('markdown', type.markdown); eleventyConfig.addPairedLiquidShortcode( - 'codeExample', - async (contents, exampleName, autogenCSS = true, syntax = null) => { - const code = generateCodeExample(contents, autogenCSS, syntax); - return liquidEngine.renderFile('code_examples/code_example', { - code, - exampleName, - }); - }, - ); - - eleventyConfig.addPairedLiquidShortcode('funFact', async (contents) => - liquidEngine.renderFile('fun_fact', { - contents, - }), - ); - - eleventyConfig.addPairedLiquidShortcode('markdown', (content) => - mdown.render(content), - ); - - eleventyConfig.addPairedLiquidShortcode('markdownInline', (content) => - mdown.renderInline(content), + 'markdownInline', + type.markdownInline, ); - - eleventyConfig.addPairedLiquidShortcode('typogr', (content) => - typogrify.typogrify(content), + eleventyConfig.addLiquidFilter('markdownInline', type.markdownInline); + eleventyConfig.addPairedLiquidShortcode('typogr', type.typogr); + eleventyConfig.addLiquidFilter('typogr', type.typogr); + + // Dates + eleventyConfig.addLiquidFilter( + 'formatDistanceToNow', + dates.formatDistanceToNow, ); - eleventyConfig.addPairedLiquidShortcode('code', (content, language) => { - if (!Prism.languages[language]) { - PrismLoader(language); - } - const html = Prism.highlight(content, Prism.languages[language], language); - const attr = `language-${language}`; - return `
    ${html}
    `; - }); - - // Filters... - eleventyConfig.addLiquidFilter('formatDistanceToNow', (date) => { - return formatDistanceToNow(new Date(date)); - }); - - eleventyConfig.addLiquidFilter('markdown', (content) => - mdown.render(content), - ); - - eleventyConfig.addLiquidFilter('markdownInline', (content) => - mdown.renderInline(content), - ); - - eleventyConfig.addLiquidFilter('typogr', (content) => - typogrify.typogrify(content), - ); - - eleventyConfig.addLiquidFilter('isTypedoc', (page) => - page.url.startsWith('/documentation/js-api/'), - ); - - eleventyConfig.addLiquidFilter('implStatus', (status) => - getImplStatus(status), - ); + // Page + eleventyConfig.addLiquidFilter('isTypedoc', page.isTypedoc); // plugins eleventyConfig.addPlugin(EleventyRenderPlugin); diff --git a/package.json b/package.json index fb6e571ee..65ab9d14d 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,10 @@ "@rollup/plugin-terser": "^0.4.0", "@types/jquery": "^3.5.16", "@types/jqueryui": "^1.12.16", + "@types/markdown-it": "^12.2.3", + "@types/markdown-it-attrs": "^4.1.0", "@types/node": "^16", + "@types/prismjs": "^1.26.0", "@typescript-eslint/eslint-plugin": "^5.54.0", "@typescript-eslint/parser": "^5.54.0", "date-fns": "^2.29.3", diff --git a/source/@types/markdown-it-deflist.d.ts b/source/@types/markdown-it-deflist.d.ts new file mode 100644 index 000000000..a444f5df0 --- /dev/null +++ b/source/@types/markdown-it-deflist.d.ts @@ -0,0 +1,5 @@ +declare module 'markdown-it-deflist' { + import MarkdownIt from 'markdown-it'; + + export default function deflist(md: MarkdownIt): void; +} diff --git a/source/@types/typogr.d.ts b/source/@types/typogr.d.ts new file mode 100644 index 000000000..dcb187478 --- /dev/null +++ b/source/@types/typogr.d.ts @@ -0,0 +1,3 @@ +declare module 'typogr' { + export function typogrify(src: string): string; +} diff --git a/source/_data/releases.js b/source/_data/releases.js index b6f957f81..eac3d0531 100644 --- a/source/_data/releases.js +++ b/source/_data/releases.js @@ -6,8 +6,10 @@ const chalk = require('kleur'); const VERSION_CACHE_PATH = './source/_data/versionCache.json'; -// Promise version of `spawn` to avoid blocking the main thread while waiting -// for the child processes +/** + * Promise version of `spawn` to avoid blocking the main thread while waiting + * for the child processes. + */ function spawn(cmd, args, options) { return new Promise((resolve, reject) => { const child = nodeSpawn(cmd, args, options); @@ -26,6 +28,9 @@ function spawn(cmd, args, options) { }); } +/** + * Retrieves cached version object from cache file. + */ async function getCacheFile() { if (process.env.NETLIFY || process.env.REBUILD_VERSION_CACHE) return {}; let versionCache; @@ -41,13 +46,18 @@ async function getCacheFile() { return versionCache; } +/** + * Writes version object to cache file. + */ async function writeCacheFile(cache) { // eslint-disable-next-line no-console console.info(chalk.green(`[11ty] Writing version cache file...`)); await fs.writeFile(VERSION_CACHE_PATH, JSON.stringify(cache)); } -// Retrieve the highest stable version of `repo`, based on its git tags +/** + * Retrieves the highest stable version of `repo`, based on its git tags. + */ async function getLatestVersion(repo) { // eslint-disable-next-line no-console console.info(chalk.cyan(`[11ty] Fetching version information for ${repo}`)); @@ -78,6 +88,10 @@ async function getLatestVersion(repo) { return version; } +/** + * Returns the version and URL for the latest release of the given + * implementation. + */ module.exports = async () => { const repos = ['sass/libsass', 'sass/dart-sass', 'sass/migrator']; const cache = await getCacheFile(); diff --git a/source/helpers/sass_helpers.ts b/source/helpers/codeExample.ts similarity index 59% rename from source/helpers/sass_helpers.ts rename to source/helpers/codeExample.ts index c2da81619..6a23d8747 100644 --- a/source/helpers/sass_helpers.ts +++ b/source/helpers/codeExample.ts @@ -1,6 +1,65 @@ import sass from 'sass'; -export function generateCodeExample( +import { liquidEngine } from './engines'; + +/** + * Renders a code example. + * + * This takes a block of SCSS and/or indented syntax code, and emits HTML that + * (combined with JS) will allow users to choose which to display. + * + * The SCSS should be separated from the Sass with `===`. For example, in + * LiquidJS: + * + * {% codeExample 'unique-id-string' %} + * .foo { + * color: blue; + * } + * === + * .foo + * color: blue + * {% endcodeExample %} + * + * Different sections can be separated within one syntax (for example, to + * indicate different files) with `---`. For example, in LiquidJS: + * + * {% codeExample 'unique-id-string' %} + * // _reset.scss + * * {margin: 0} + * --- + * // base.scss + * @import 'reset'; + * === + * // _reset.sass + * * + * margin: 0; + * --- + * // base.sass + * @import reset + * {% endcodeExample %} + * + * A third section may optionally be provided to represent compiled CSS. If it's + * not passed and `autogenCSS` is `true`, it's generated from the SCSS source. + * If the autogenerated CSS is empty, it's omitted entirely. + * + * If `syntax` is either `sass` or `scss`, the first section will be + * interpreted as that syntax and the second will be interpreted (or + * auto-generated) as the CSS output. + */ +export default async function codeExample( + contents: string, + exampleName: string, + autogenCSS = true, + syntax: 'sass' | 'scss' | null = null, +) { + const code = generateCodeExample(contents, autogenCSS, syntax); + return liquidEngine.renderFile('code_examples/code_example', { + code, + exampleName, + }); +} + +function generateCodeExample( contents: string, autogenCSS: boolean, syntax: 'sass' | 'scss' | null, @@ -69,20 +128,6 @@ export function generateCodeExample( }; } -export function getImplStatus(status: string | boolean | null) { - switch (status) { - case true: - return '✓'; - case false: - return '✗'; - case 'partial': - case null: - return status; - default: - return `since ${status}`; - } -} - function getCanSplit( scssExamples: string[], sassExamples: string[], diff --git a/source/helpers/compatibility.ts b/source/helpers/compatibility.ts new file mode 100644 index 000000000..5db58edc6 --- /dev/null +++ b/source/helpers/compatibility.ts @@ -0,0 +1,54 @@ +import { liquidEngine } from './engines'; + +/** + * Renders a status dashboard for each implementation's support for a feature. + * + * Each implementation's value can be: + * + * - `true`, indicating that that implementation fully supports the feature; + * - `false`, indicating that it does not yet support the feature at all; + * - `'partial'`, indicating that it has limited or incorrect support for the + * feature; + * - or a string, indicating the version it started supporting the feature. + * + * When possible, prefer using the start version rather than `true`. + * + * If `feature` is passed, it should be a terse (one- to three-word) description + * of the particular feature whose compatibility is described. This should be + * used whenever the status isn't referring to the entire feature being + * described by the surrounding prose. + * + * This takes an optional Markdown block (`details`) that should provide more + * information about the implementation differences or the old behavior. + */ +export const compatibility = async ( + details: string, + dart: string | boolean | null = null, + libsass: string | boolean | null = null, + ruby: string | boolean | null = null, + feature: string | null = null, +) => + liquidEngine.renderFile('compatibility', { + details, + dart, + libsass, + ruby, + feature, + }); + +/** + * Renders a single row for `compatibility`. + */ +export const implStatus = (status: string | boolean | null) => { + switch (status) { + case true: + return '✓'; + case false: + return '✗'; + case 'partial': + case null: + return status; + default: + return `since ${status}`; + } +}; diff --git a/source/helpers/components.ts b/source/helpers/components.ts new file mode 100644 index 000000000..2977116f2 --- /dev/null +++ b/source/helpers/components.ts @@ -0,0 +1,29 @@ +import { highlight, languages } from 'prismjs'; +import PrismLoader from 'prismjs/components/index'; + +import { liquidEngine } from './engines'; + +/** + * Returns HTML for a fun fact that's not directly relevant to the main + * documentation. + */ +export const funFact = async (contents: string) => + liquidEngine.renderFile('fun_fact', { + contents, + }); + +/** + * Returns HTML for a code block with syntax highlighting via [Prism][]. + * + * [Prism]: https://prismjs.com/ + * + * @see https://prismjs.com/ + */ +export const codeBlock = (contents: string, language: string) => { + if (!languages[language]) { + PrismLoader(language); + } + const html = highlight(contents, languages[language], language); + const attr = `language-${language}`; + return `
    ${html}
    `; +}; diff --git a/source/helpers/dates.ts b/source/helpers/dates.ts new file mode 100644 index 000000000..25cb36143 --- /dev/null +++ b/source/helpers/dates.ts @@ -0,0 +1,9 @@ +import formatDistanceToNowBase from 'date-fns/formatDistanceToNow'; + +/** + * Returns the distance between the given date and now in words. + * + * @see https://date-fns.org/docs/formatDistanceToNow + */ +export const formatDistanceToNow = (date: string) => + formatDistanceToNowBase(new Date(date)); diff --git a/source/helpers/engines.ts b/source/helpers/engines.ts new file mode 100644 index 000000000..b6fc6a884 --- /dev/null +++ b/source/helpers/engines.ts @@ -0,0 +1,34 @@ +import { Liquid } from 'liquidjs'; +import markdown from 'markdown-it'; +import markdownItAttrs from 'markdown-it-attrs'; +import markdownDefList from 'markdown-it-deflist'; +import path from 'path'; + +/** + * Returns Markdown engine with custom configuration and plugins. + * + * @see https://github.com/markdown-it/markdown-it + * @see https://github.com/markdown-it/markdown-it-deflist + * @see https://github.com/arve0/markdown-it-attrs + */ +export const markdownEngine = markdown({ + html: true, + typographer: true, +}) + .use(markdownDefList) + .use(markdownItAttrs); + +/** + * Returns LiquidJS engine with custom configuration. + * + * @see https://liquidjs.com/ + */ +export const liquidEngine = new Liquid({ + root: [ + path.resolve(__dirname, '../_includes/'), + path.resolve(__dirname, '../'), + ], + extname: '.liquid', + strictFilters: true, + jsTruthy: true, +}); diff --git a/source/helpers/page.ts b/source/helpers/page.ts new file mode 100644 index 000000000..ccd60163f --- /dev/null +++ b/source/helpers/page.ts @@ -0,0 +1,15 @@ +interface Page { + url: string | false; + fileSlug: string; + filePathStem: string; + date: Date; + inputPath: string; + outputPath: string | false; + outputFileExtension: string; +} + +/** + * Indicates whether the given page is part of the JS API documentation. + */ +export const isTypedoc = (page: Page) => + page.url ? page.url.startsWith('/documentation/js-api/') : false; diff --git a/source/helpers/type.ts b/source/helpers/type.ts new file mode 100644 index 000000000..a154ea43d --- /dev/null +++ b/source/helpers/type.ts @@ -0,0 +1,45 @@ +import { LoremIpsum } from 'lorem-ipsum'; +import { typogrify } from 'typogr'; + +import { markdownEngine } from './engines'; + +const lorem = new LoremIpsum(); + +/** + * Returns block of generated `lorem ipsum` text. + * + * @see https://github.com/knicklabs/lorem-ipsum.js + */ +export const getLorem = (type: string, number = 1) => { + switch (type) { + case 'sentence': + case 'sentences': + return lorem.generateSentences(number); + case 'paragraph': + case 'paragraphs': + return lorem.generateParagraphs(number); + case 'word': + case 'words': + return lorem.generateWords(number); + } + return ''; +}; + +/** + * Renders block of Markdown into HTML. + */ +export const markdown = (content: string) => markdownEngine.render(content); + +/** + * Renders single line of Markdown into HTML, without wrapping `

    `. + */ +export const markdownInline = (content: string) => + markdownEngine.renderInline(content); + +/** + * Applies various transformations to plain text in order to yield + * typographically-improved HTML. + * + * @see https://github.com/ekalinin/typogr.js + */ +export const typogr = (content: string) => typogrify(content); diff --git a/tsconfig.json b/tsconfig.json index 5941de198..fccc0ee28 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,4 +1,7 @@ { + "ts-node": { + "transpileOnly": true + }, "compilerOptions": { "module": "node16", "target": "es2022", diff --git a/yarn.lock b/yarn.lock index 316386a3d..1661734b2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1837,6 +1837,39 @@ __metadata: languageName: node linkType: hard +"@types/linkify-it@npm:*": + version: 3.0.2 + resolution: "@types/linkify-it@npm:3.0.2" + checksum: dff8f10fafb885422474e456596f12d518ec4cdd6c33cca7a08e7c86b912d301ed91cf5a7613e148c45a12600dc9ab3d85ad16d5b48dc1aaeda151a68f16b536 + languageName: node + linkType: hard + +"@types/markdown-it-attrs@npm:^4.1.0": + version: 4.1.0 + resolution: "@types/markdown-it-attrs@npm:4.1.0" + dependencies: + "@types/markdown-it": "*" + checksum: a8bc1f8176ddeea8ac3f66958683a02bd84ba46ccb47fc941d10b83ac52e83595a03ff39efdf594c6614ae3f71f63b88fc62f706681c48630ec5ac9fc411b387 + languageName: node + linkType: hard + +"@types/markdown-it@npm:*, @types/markdown-it@npm:^12.2.3": + version: 12.2.3 + resolution: "@types/markdown-it@npm:12.2.3" + dependencies: + "@types/linkify-it": "*" + "@types/mdurl": "*" + checksum: 868824a3e4d00718ba9cd4762cf16694762a670860f4b402e6e9f952b6841a2027488bdc55d05c2b960bf5078df21a9d041270af7e8949514645fe88fdb722ac + languageName: node + linkType: hard + +"@types/mdurl@npm:*": + version: 1.0.2 + resolution: "@types/mdurl@npm:1.0.2" + checksum: 79c7e523b377f53cf1f5a240fe23d0c6cae856667692bd21bf1d064eafe5ccc40ae39a2aa0a9a51e8c94d1307228c8f6b121e847124591a9a828c3baf65e86e2 + languageName: node + linkType: hard + "@types/minimatch@npm:^3.0.3": version: 3.0.5 resolution: "@types/minimatch@npm:3.0.5" @@ -1865,6 +1898,13 @@ __metadata: languageName: node linkType: hard +"@types/prismjs@npm:^1.26.0": + version: 1.26.0 + resolution: "@types/prismjs@npm:1.26.0" + checksum: cd5e7a6214c1f4213ec512a5fcf6d8fe37a56b813fc57ac95b5ff5ee074742bfdbd2f2730d9fd985205bf4586728e09baa97023f739e5aa1c9735a7c1ecbd11a + languageName: node + linkType: hard + "@types/resolve@npm:1.20.2": version: 1.20.2 resolution: "@types/resolve@npm:1.20.2" @@ -6566,7 +6606,10 @@ __metadata: "@rollup/plugin-terser": ^0.4.0 "@types/jquery": ^3.5.16 "@types/jqueryui": ^1.12.16 + "@types/markdown-it": ^12.2.3 + "@types/markdown-it-attrs": ^4.1.0 "@types/node": ^16 + "@types/prismjs": ^1.26.0 "@typescript-eslint/eslint-plugin": ^5.54.0 "@typescript-eslint/parser": ^5.54.0 date-fns: ^2.29.3 From 1b09b6caa6b5b7c43ea5910590a42b1e5fea2cc5 Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Wed, 8 Mar 2023 16:14:25 -0500 Subject: [PATCH 33/42] lint --- source/_data/releases.js | 31 ++++++++++++------- source/assets/js/components/impl-status.ts | 8 +++-- source/assets/js/components/navigation.ts | 4 +-- source/assets/js/components/redirect.ts | 28 ++++++++++++----- .../js/vendor/html5-boilerplate/plugins.ts | 10 +++--- .../snippets/module-system-status.liquid | 8 +---- source/helpers/codeExample.ts | 12 +++---- 7 files changed, 60 insertions(+), 41 deletions(-) diff --git a/source/_data/releases.js b/source/_data/releases.js index eac3d0531..cc3ffb004 100644 --- a/source/_data/releases.js +++ b/source/_data/releases.js @@ -10,7 +10,7 @@ const VERSION_CACHE_PATH = './source/_data/versionCache.json'; * Promise version of `spawn` to avoid blocking the main thread while waiting * for the child processes. */ -function spawn(cmd, args, options) { +const spawn = (cmd, args, options) => { return new Promise((resolve, reject) => { const child = nodeSpawn(cmd, args, options); const stderr = []; @@ -22,17 +22,22 @@ function spawn(cmd, args, options) { stderr.push(e.toString()); }); child.on('close', () => { - if (stderr.length) reject(stderr.join('')); - else resolve(stdout.join('')); + if (stderr.length) { + reject(stderr.join('')); + } else { + resolve(stdout.join('')); + } }); }); -} +}; /** * Retrieves cached version object from cache file. */ -async function getCacheFile() { - if (process.env.NETLIFY || process.env.REBUILD_VERSION_CACHE) return {}; +const getCacheFile = async () => { + if (process.env.NETLIFY || process.env.REBUILD_VERSION_CACHE) { + return {}; + } let versionCache; try { versionCache = JSON.parse(await fs.readFile(VERSION_CACHE_PATH)); @@ -44,21 +49,21 @@ async function getCacheFile() { } } return versionCache; -} +}; /** * Writes version object to cache file. */ -async function writeCacheFile(cache) { +const writeCacheFile = async (cache) => { // eslint-disable-next-line no-console console.info(chalk.green(`[11ty] Writing version cache file...`)); await fs.writeFile(VERSION_CACHE_PATH, JSON.stringify(cache)); -} +}; /** * Retrieves the highest stable version of `repo`, based on its git tags. */ -async function getLatestVersion(repo) { +const getLatestVersion = async (repo) => { // eslint-disable-next-line no-console console.info(chalk.cyan(`[11ty] Fetching version information for ${repo}`)); const { parseSemVer, compareSemVer } = await import('semver-parser'); @@ -86,7 +91,7 @@ async function getLatestVersion(repo) { .at(-1); return version; -} +}; /** * Returns the version and URL for the latest release of the given @@ -110,7 +115,9 @@ module.exports = async () => { ); const nextCache = Object.fromEntries(versions); - if (!deepEqual(cache, nextCache)) await writeCacheFile(nextCache); + if (!deepEqual(cache, nextCache)) { + await writeCacheFile(nextCache); + } return data; }; diff --git a/source/assets/js/components/impl-status.ts b/source/assets/js/components/impl-status.ts index cc191c21b..64a123d2f 100644 --- a/source/assets/js/components/impl-status.ts +++ b/source/assets/js/components/impl-status.ts @@ -2,10 +2,14 @@ $(function () { $('.impl-status').each(function () { const statusBar = $(this); const expandLink = statusBar.find('a'); - if (expandLink == null) return; + if (expandLink == null) { + return; + } const details = statusBar.next(); - if (!details.hasClass('sl-c-callout')) return; + if (!details.hasClass('sl-c-callout')) { + return; + } details.hide(); expandLink.on('click', function () { diff --git a/source/assets/js/components/navigation.ts b/source/assets/js/components/navigation.ts index 693d10e85..8b681c4d4 100644 --- a/source/assets/js/components/navigation.ts +++ b/source/assets/js/components/navigation.ts @@ -5,7 +5,7 @@ $(function () { const sticky = nav.offset(); // Added sticky class when window top is great than nav top - function stickyNav() { + const stickyNav = () => { if ( nav.length > 0 && sticky && @@ -15,7 +15,7 @@ $(function () { } else { $('.sl-l-medium-holy-grail__body').removeClass('sl-js-nav--is-sticky'); } - } + }; // When scrolling the page, execute stickyNav $(window).on('scroll', function () { diff --git a/source/assets/js/components/redirect.ts b/source/assets/js/components/redirect.ts index 3220216a7..4784dd65e 100644 --- a/source/assets/js/components/redirect.ts +++ b/source/assets/js/components/redirect.ts @@ -110,7 +110,9 @@ if (window.location.hash) { redirect = '/ruby-sass'; } - if (redirect) window.location.href = redirect; + if (redirect) { + window.location.href = redirect; + } } else if (window.location.pathname == '/documentation/modules') { const redirects: Record = { '#declare-class_method': '/ruby-sass', @@ -219,7 +221,9 @@ if (window.location.hash) { }; const redirect: string | undefined = redirects[window.location.hash]; - if (redirect) window.location.href = redirect; + if (redirect) { + window.location.href = redirect; + } } else if (window.location.pathname == '/documentation/modules/color') { const redirects: Record = { '#rgb': '/documentation/modules#rgb', @@ -229,21 +233,27 @@ if (window.location.hash) { }; const redirect: string | undefined = redirects[window.location.hash]; - if (redirect) window.location.href = redirect; + if (redirect) { + window.location.href = redirect; + } } else if (window.location.pathname == '/documentation/modules/map') { const redirects: Record = { '#keywords': '/documentation/modules/meta#keywords', }; const redirect: string | undefined = redirects[window.location.hash]; - if (redirect) window.location.href = redirect; + if (redirect) { + window.location.href = redirect; + } } else if (window.location.pathname == '/documentation/at-rules/use') { const redirects: Record = { '#configuring-modules': '/documentation/at-rules/use#configuration', }; const redirect: string | undefined = redirects[window.location.hash]; - if (redirect) window.location.href = redirect; + if (redirect) { + window.location.href = redirect; + } } else if ( window.location.pathname == '/documentation/syntax/special-functions' ) { @@ -254,7 +264,9 @@ if (window.location.hash) { }; const redirect: string | undefined = redirects[window.location.hash]; - if (redirect) window.location.href = redirect; + if (redirect) { + window.location.href = redirect; + } } else if (window.location.pathname == '/documentation/js-api') { const redirects: Record = { '#rendersync': '/documentation/js-api/modules#renderSync', @@ -391,6 +403,8 @@ if (window.location.hash) { }; const redirect: string | undefined = redirects[window.location.hash]; - if (redirect) window.location.href = redirect; + if (redirect) { + window.location.href = redirect; + } } } diff --git a/source/assets/js/vendor/html5-boilerplate/plugins.ts b/source/assets/js/vendor/html5-boilerplate/plugins.ts index ad9f39301..3c221bc60 100644 --- a/source/assets/js/vendor/html5-boilerplate/plugins.ts +++ b/source/assets/js/vendor/html5-boilerplate/plugins.ts @@ -1,15 +1,15 @@ // Avoid `console` errors in browsers that lack a console. (function() { - var method; - var noop = function () {}; - var methods = [ + let method; + const noop = function () {}; + const methods = [ 'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd', 'timeline', 'timelineEnd', 'timeStamp', 'trace', 'warn' ]; - var length = methods.length; - var console = (window.console = window.console || {}); + let length = methods.length; + const console = (window.console = window.console || {}); while (length--) { method = methods[length]; diff --git a/source/documentation/snippets/module-system-status.liquid b/source/documentation/snippets/module-system-status.liquid index e87505f24..42cf26c6a 100644 --- a/source/documentation/snippets/module-system-status.liquid +++ b/source/documentation/snippets/module-system-status.liquid @@ -1,10 +1,4 @@ -{% comment %} - Ideally this would use named args, but that's not supported yet: - https://github.com/11ty/eleventy/issues/2679 - - In the meantime, the args are (in order): `dart`, `libsass`, `ruby`, `feature` -{% endcomment %} - +{% # Arguments are (in order): `dart`, `libsass`, `ruby` %} {% compatibility '1.23.0', false, false %} Only Dart Sass currently supports `@use`. Users of other implementations must use the [`@import` rule][] instead. diff --git a/source/helpers/codeExample.ts b/source/helpers/codeExample.ts index 6a23d8747..1097ab14f 100644 --- a/source/helpers/codeExample.ts +++ b/source/helpers/codeExample.ts @@ -59,11 +59,11 @@ export default async function codeExample( }); } -function generateCodeExample( +const generateCodeExample = ( contents: string, autogenCSS: boolean, syntax: 'sass' | 'scss' | null, -) { +) => { const splitContents = contents.split('\n===\n'); let scssContents, sassContents, cssContents; @@ -126,13 +126,13 @@ function generateCodeExample( canSplit, splitLocation, }; -} +}; -function getCanSplit( +const getCanSplit = ( scssExamples: string[], sassExamples: string[], cssExamples: string[], -) { +) => { const exampleSourceLengths = [...scssExamples, ...sassExamples].flatMap( (source) => source.split('\n').map((line) => line.length), ); @@ -150,4 +150,4 @@ function getCanSplit( maxSourceWidth, maxCSSWidth, }; -} +}; From b288910d5b3f8ead93efe548d85815cd1cda95ee Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Wed, 8 Mar 2023 16:22:40 -0500 Subject: [PATCH 34/42] comment --- source/helpers/components.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/helpers/components.ts b/source/helpers/components.ts index 2977116f2..6f26b490f 100644 --- a/source/helpers/components.ts +++ b/source/helpers/components.ts @@ -15,7 +15,12 @@ export const funFact = async (contents: string) => /** * Returns HTML for a code block with syntax highlighting via [Prism][]. * + * This should be equivalent to the [11ty `{% highlight %}` tag][hl-tag], except + * this tag can wrap dynamic content (partials, variables, etc), while the 11ty + * tag only wraps plain text. + * * [Prism]: https://prismjs.com/ + * [hl-tag]: https://www.11ty.dev/docs/plugins/syntaxhighlight/#usage * * @see https://prismjs.com/ */ From 0cc138ad94ea1c265297481d8d5c6d55cf67295f Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Wed, 8 Mar 2023 17:48:53 -0500 Subject: [PATCH 35/42] First round of blog review. --- eleventy.config.cjs | 14 +++--- old_source/blog/001-how-extend-works.html.md | 2 +- .../002-a-change-in-plans-for-sass-33.html.md | 2 +- .../blog/003-sass-33-is-released.html.md | 2 +- .../blog/004-sass-34-is-released.html.md | 2 +- .../005-cleaning-up-interpolation.html.md | 2 +- ...ping-support-for-old-ruby-versions.html.md | 2 +- old_source/blog/007-thank-you-marcel.html.md | 2 +- .../008-sass-35-release-candidate.html.md | 2 +- .../blog/009-announcing-dart-sass.html.md | 2 +- .../010-dart-sass-is-on-chocolatey.html.md | 2 +- ...011-sass-and-browser-compatibility.html.md | 2 +- .../blog/012-dart-sass-is-in-beta.html.md | 2 +- .../blog/013-sass-35-is-released.html.md | 2 +- .../014-dart-sass-100-is-released.html.md | 2 +- .../blog/015-ruby-sass-is-deprecated.html.md | 2 +- ...st-for-commentsimporting-css-files.html.md | 2 +- ...hcss-imports-and-css-compatibility.html.md | 2 +- ...tent-arguments-and-color-functions.html.md | 2 +- ...or-comments-module-system-proposal.html.md | 2 +- .../blog/020-ruby-sass-is-unsupported.html.md | 2 +- .../blog/021-brand-new-sass-docs.html.md | 2 +- ...commentsforward-slash-as-separator.html.md | 2 +- .../blog/023-module-system-preview.html.md | 2 +- .../024-the-module-system-is-launched.html.md | 2 +- ...quest-for-comments-nested-map-functions.md | 2 +- .../026-request-for-comments-hwb-functions.md | 2 +- old_source/blog/027-libsass-is-deprecated.md | 2 +- ...8-request-for-comments-first-class-calc.md | 2 +- .../blog/029-node-fibers-discontinued.md | 2 +- ...30-request-for-comments-new-js-api.html.md | 2 +- .../031-new-js-api-release-candidate.html.md | 2 +- old_source/blog/032-embedded-sass-is-live.md | 2 +- ...est-for-comments-strict-unary-operators.md | 2 +- .../034-request-for-comments-color-spaces.md | 2 +- .../035-security-alert-tar-permissions.md | 2 +- source/_includes/attribution.liquid | 1 + source/_layouts/blog.liquid | 7 +-- source/blog.liquid | 45 ++++++++++--------- source/blog/007-thank-you-marcel.md | 1 - source/blog/014-dart-sass-100-is-released.md | 1 + .../blog/024-the-module-system-is-launched.md | 1 + source/blog/blog.11tydata.yml | 6 ++- 43 files changed, 78 insertions(+), 68 deletions(-) create mode 100644 source/_includes/attribution.liquid diff --git a/eleventy.config.cjs b/eleventy.config.cjs index 033029177..f97c5a3f7 100644 --- a/eleventy.config.cjs +++ b/eleventy.config.cjs @@ -66,13 +66,13 @@ module.exports = (eleventyConfig) => { ); // Filters... -eleventyConfig.addLiquidFilter('truncatePost', (post) => { - return truncate(post, 250, { byWords: true }); -}) + eleventyConfig.addLiquidFilter('truncateHTML', (post, words = 250) => { + return truncate(post, words, { byWords: true }); + }); - eleventyConfig.addLiquidFilter('formatBlogDate', (date) => { - return format(new Date(date),'d MMMM yyyy'); - }) + eleventyConfig.addLiquidFilter('format', (date, pattern = 'd MMMM yyyy') => { + return format(new Date(date), pattern); + }); eleventyConfig.addLiquidFilter('formatDistanceToNow', (date) => { return formatDistanceToNow(new Date(date)); @@ -97,6 +97,8 @@ eleventyConfig.addLiquidFilter('truncatePost', (post) => { eleventyConfig.addPlugin(EleventyRenderPlugin); eleventyConfig.addPlugin(syntaxHighlight); + eleventyConfig.setQuietMode(true); + // settings return { dir: { diff --git a/old_source/blog/001-how-extend-works.html.md b/old_source/blog/001-how-extend-works.html.md index e3159d6bb..4e8b5692e 100644 --- a/old_source/blog/001-how-extend-works.html.md +++ b/old_source/blog/001-how-extend-works.html.md @@ -1,7 +1,7 @@ --- title: How @extend Works author: Natalie Weizenbaum -# date: 2013-11-22 16:57 PST +date: 2013-11-22 16:57 PST --- _This was originally published as [a gist](https://gist.github.com/nex3/7609394)_. diff --git a/old_source/blog/002-a-change-in-plans-for-sass-33.html.md b/old_source/blog/002-a-change-in-plans-for-sass-33.html.md index 78b6f1d98..12ff26e3d 100644 --- a/old_source/blog/002-a-change-in-plans-for-sass-33.html.md +++ b/old_source/blog/002-a-change-in-plans-for-sass-33.html.md @@ -1,7 +1,7 @@ --- title: A Change in Plans for Sass 3.3 author: Natalie Weizenbaum -# date: 2013-12-19 20:05 PST +date: 2013-12-19 20:05 PST --- _This was originally published as [a gist](https://gist.github.com/nex3/8050187)._ diff --git a/old_source/blog/003-sass-33-is-released.html.md b/old_source/blog/003-sass-33-is-released.html.md index c21189944..83e609a08 100644 --- a/old_source/blog/003-sass-33-is-released.html.md +++ b/old_source/blog/003-sass-33-is-released.html.md @@ -1,7 +1,7 @@ --- title: Sass 3.3 is Released author: Natalie Weizenbaum -# date: 2014-03-07 16:40 PST +date: 2014-03-07 16:40 PST --- After ironing out a bunch of bugs in numerous release candidates, we're finally diff --git a/old_source/blog/004-sass-34-is-released.html.md b/old_source/blog/004-sass-34-is-released.html.md index a2253542d..c30a49a8c 100644 --- a/old_source/blog/004-sass-34-is-released.html.md +++ b/old_source/blog/004-sass-34-is-released.html.md @@ -1,7 +1,7 @@ --- title: Sass 3.4 is Released author: Natalie Weizenbaum -# date: 2014-08-18 16:38 PST +date: 2014-08-18 16:38 PST --- We've been trying to increase the pace of Sass releases, and it looks like we've diff --git a/old_source/blog/005-cleaning-up-interpolation.html.md b/old_source/blog/005-cleaning-up-interpolation.html.md index bee84726b..69a55bf29 100644 --- a/old_source/blog/005-cleaning-up-interpolation.html.md +++ b/old_source/blog/005-cleaning-up-interpolation.html.md @@ -1,7 +1,7 @@ --- title: Cleaning Up Interpolation author: Natalie Weizenbaum -# date: 2015-12-09 15:20 PST +date: 2015-12-09 15:20 PST --- Interpolation—the ability to add variables and other snippets using `#{...}`—is diff --git a/old_source/blog/006-dropping-support-for-old-ruby-versions.html.md b/old_source/blog/006-dropping-support-for-old-ruby-versions.html.md index 16d469f84..114b6bbfb 100644 --- a/old_source/blog/006-dropping-support-for-old-ruby-versions.html.md +++ b/old_source/blog/006-dropping-support-for-old-ruby-versions.html.md @@ -1,7 +1,7 @@ --- title: Dropping Support For Old Ruby Versions author: Natalie Weizenbaum -# date: 2016-02-29 14:25 PST +date: 2016-02-29 14:25 PST --- As of version 3.5, Ruby Sass will drop support for Ruby 1.8.7 and Ruby 1.9.3. We diff --git a/old_source/blog/007-thank-you-marcel.html.md b/old_source/blog/007-thank-you-marcel.html.md index d336cf144..40fdf4c3c 100644 --- a/old_source/blog/007-thank-you-marcel.html.md +++ b/old_source/blog/007-thank-you-marcel.html.md @@ -1,7 +1,7 @@ --- title: Dropping Support For Old Ruby Versions author: Natalie Weizenbaum -# date: 2016-05-24 14:41 PST +date: 2016-05-24 14:41 PST --- You may not know [Marcel Greter](https://github.com/mgreter), but you almost diff --git a/old_source/blog/008-sass-35-release-candidate.html.md b/old_source/blog/008-sass-35-release-candidate.html.md index 851585d65..ccee5c2ec 100644 --- a/old_source/blog/008-sass-35-release-candidate.html.md +++ b/old_source/blog/008-sass-35-release-candidate.html.md @@ -1,7 +1,7 @@ --- title: Sass 3.5 Release Candidate author: Natalie Weizenbaum -# date: 2016-08-30 15:00 PST +date: 2016-08-30 15:00 PST --- I've just pushed the button to release Sass 3.5.0-rc.1. If it seems like it's diff --git a/old_source/blog/009-announcing-dart-sass.html.md b/old_source/blog/009-announcing-dart-sass.html.md index 2725a9b8e..7a9b541b5 100644 --- a/old_source/blog/009-announcing-dart-sass.html.md +++ b/old_source/blog/009-announcing-dart-sass.html.md @@ -1,7 +1,7 @@ --- title: Announcing Dart Sass author: Natalie Weizenbaum -# date: 2016-10-31 13:28 PST +date: 2016-10-31 13:28 PST --- Over the past few months, I've been quietly working on a new project. Today I'm diff --git a/old_source/blog/010-dart-sass-is-on-chocolatey.html.md b/old_source/blog/010-dart-sass-is-on-chocolatey.html.md index 9a419e8d0..6bf1852b9 100644 --- a/old_source/blog/010-dart-sass-is-on-chocolatey.html.md +++ b/old_source/blog/010-dart-sass-is-on-chocolatey.html.md @@ -1,7 +1,7 @@ --- title: Dart Sass is On Chocolatey author: Natalie Weizenbaum -# date: 2017-01-13 14:43 PST +date: 2017-01-13 14:43 PST --- One of the quieter benefits of [moving to Dart](/blog/announcing-dart-sass) is diff --git a/old_source/blog/011-sass-and-browser-compatibility.html.md b/old_source/blog/011-sass-and-browser-compatibility.html.md index 5d5e4fd4d..2114116d4 100644 --- a/old_source/blog/011-sass-and-browser-compatibility.html.md +++ b/old_source/blog/011-sass-and-browser-compatibility.html.md @@ -1,7 +1,7 @@ --- title: Sass and Browser Compatibility author: Natalie Weizenbaum -# date: 2017-02-10 17:46 PST +date: 2017-02-10 17:46 PST --- One of the core design principles of Sass has always been to **understand CSS as diff --git a/old_source/blog/012-dart-sass-is-in-beta.html.md b/old_source/blog/012-dart-sass-is-in-beta.html.md index 4ff952e9f..c264e47f7 100644 --- a/old_source/blog/012-dart-sass-is-in-beta.html.md +++ b/old_source/blog/012-dart-sass-is-in-beta.html.md @@ -1,7 +1,7 @@ --- title: Dart Sass is in Beta author: Natalie Weizenbaum -# date: 2017-06-05 13:00 PST +date: 2017-06-05 13:00 PST --- Last weekend was [three days long](https://en.wikipedia.org/wiki/Memorial_Day) diff --git a/old_source/blog/013-sass-35-is-released.html.md b/old_source/blog/013-sass-35-is-released.html.md index 76653032c..3b8d82878 100644 --- a/old_source/blog/013-sass-35-is-released.html.md +++ b/old_source/blog/013-sass-35-is-released.html.md @@ -1,7 +1,7 @@ --- title: Sass 3.5 is Released author: Natalie Weizenbaum -# date: 2017-07-07 15:33 PST +date: 2017-07-07 15:33 PST --- I'm excited to announce that I've just released the stable version of Sass 3.5. diff --git a/old_source/blog/014-dart-sass-100-is-released.html.md b/old_source/blog/014-dart-sass-100-is-released.html.md index 0a7501021..5f6be3320 100644 --- a/old_source/blog/014-dart-sass-100-is-released.html.md +++ b/old_source/blog/014-dart-sass-100-is-released.html.md @@ -1,7 +1,7 @@ --- title: Dart Sass 1.0.0 is Released author: Natalie Weizenbaum -# date: 2018-03-26 13:15 PST +date: 2018-03-26 13:15 PST --- I've just uploaded Dart Sass 1.0.0, the very first stable release, to diff --git a/old_source/blog/015-ruby-sass-is-deprecated.html.md b/old_source/blog/015-ruby-sass-is-deprecated.html.md index 77c14d39a..02449bcac 100644 --- a/old_source/blog/015-ruby-sass-is-deprecated.html.md +++ b/old_source/blog/015-ruby-sass-is-deprecated.html.md @@ -1,7 +1,7 @@ --- title: Ruby Sass is Deprecated author: Natalie Weizenbaum -# date: 2018-04-02 11:35 PST +date: 2018-04-02 11:35 PST --- With the release of [Dart Sass 1.0.0 stable](/blog/dart-sass-100-is-released) diff --git a/old_source/blog/016-request-for-commentsimporting-css-files.html.md b/old_source/blog/016-request-for-commentsimporting-css-files.html.md index 8bda0e04b..4a32ce2d6 100644 --- a/old_source/blog/016-request-for-commentsimporting-css-files.html.md +++ b/old_source/blog/016-request-for-commentsimporting-css-files.html.md @@ -1,7 +1,7 @@ --- title: "Request For Comments: Importing CSS Files" author: Natalie Weizenbaum -# date: 2018-07-09 11:19 PST +date: 2018-07-09 11:19 PST --- As Dart Sass catches up with Ruby Sass in terms of usability, we're starting diff --git a/old_source/blog/017-feature-watchcss-imports-and-css-compatibility.html.md b/old_source/blog/017-feature-watchcss-imports-and-css-compatibility.html.md index 59c41660b..c534bebf5 100644 --- a/old_source/blog/017-feature-watchcss-imports-and-css-compatibility.html.md +++ b/old_source/blog/017-feature-watchcss-imports-and-css-compatibility.html.md @@ -1,7 +1,7 @@ --- title: "Feature Watch: CSS Imports and CSS Compatibility" author: Natalie Weizenbaum -# date: 2018-08-13 14:17 PST +date: 2018-08-13 14:17 PST --- Dart Sass 1.11 has just been released, and with it a handful of new features. diff --git a/old_source/blog/018-feature-watchcontent-arguments-and-color-functions.html.md b/old_source/blog/018-feature-watchcontent-arguments-and-color-functions.html.md index 6ce1a472f..f8339f008 100644 --- a/old_source/blog/018-feature-watchcontent-arguments-and-color-functions.html.md +++ b/old_source/blog/018-feature-watchcontent-arguments-and-color-functions.html.md @@ -1,7 +1,7 @@ --- title: "Feature Watch: Content Arguments and Color Functions" author: Natalie Weizenbaum -# date: 2018-11-14 14:14 PST +date: 2018-11-14 14:14 PST --- Dart Sass 1.15, released today and available [on diff --git a/old_source/blog/019-request-for-comments-module-system-proposal.html.md b/old_source/blog/019-request-for-comments-module-system-proposal.html.md index 2fb19895c..82a1b4933 100644 --- a/old_source/blog/019-request-for-comments-module-system-proposal.html.md +++ b/old_source/blog/019-request-for-comments-module-system-proposal.html.md @@ -1,7 +1,7 @@ --- title: "Request For Comments: Module System" author: Natalie Weizenbaum -# date: 2018-11-27 13:10 PST +date: 2018-11-27 13:10 PST --- Many of the most frequently-requested features for Sass have to do with its diff --git a/old_source/blog/020-ruby-sass-is-unsupported.html.md b/old_source/blog/020-ruby-sass-is-unsupported.html.md index d23058d5a..fb72351bb 100644 --- a/old_source/blog/020-ruby-sass-is-unsupported.html.md +++ b/old_source/blog/020-ruby-sass-is-unsupported.html.md @@ -1,7 +1,7 @@ --- title: Ruby Sass Has Reached End-Of-Life author: Natalie Weizenbaum -# date: 2019-04-03 16:15 PST +date: 2019-04-03 16:15 PST --- One year has passed since we announced [the deprecation of Ruby diff --git a/old_source/blog/021-brand-new-sass-docs.html.md b/old_source/blog/021-brand-new-sass-docs.html.md index 7981e15d3..b709c9682 100644 --- a/old_source/blog/021-brand-new-sass-docs.html.md +++ b/old_source/blog/021-brand-new-sass-docs.html.md @@ -1,7 +1,7 @@ --- title: Brand New Sass Docs author: Natalie Weizenbaum -# date: 2019-04-23 10:04 PST +date: 2019-04-23 10:04 PST --- I'm excited to announce the launch of [a full rewrite and redesign of the Sass diff --git a/old_source/blog/022-request-for-commentsforward-slash-as-separator.html.md b/old_source/blog/022-request-for-commentsforward-slash-as-separator.html.md index e8273767d..85f53ea48 100644 --- a/old_source/blog/022-request-for-commentsforward-slash-as-separator.html.md +++ b/old_source/blog/022-request-for-commentsforward-slash-as-separator.html.md @@ -1,7 +1,7 @@ --- title: "Request For Comments: Forward Slash as Separator" author: Natalie Weizenbaum -# date: 2019-05-06 16:15 PST +date: 2019-05-06 16:15 PST --- Early on in Sass's history, the decision was made to use `/` as a division diff --git a/old_source/blog/023-module-system-preview.html.md b/old_source/blog/023-module-system-preview.html.md index 88ce444f0..4742666ca 100644 --- a/old_source/blog/023-module-system-preview.html.md +++ b/old_source/blog/023-module-system-preview.html.md @@ -1,7 +1,7 @@ --- title: Module System Preview author: Natalie Weizenbaum -# date: 2019-09-04 15:14 PST +date: 2019-09-04 15:14 PST --- Exciting news, Sass fans! After a year of development and some iteration on the diff --git a/old_source/blog/024-the-module-system-is-launched.html.md b/old_source/blog/024-the-module-system-is-launched.html.md index 40bfdda26..ce7272324 100644 --- a/old_source/blog/024-the-module-system-is-launched.html.md +++ b/old_source/blog/024-the-module-system-is-launched.html.md @@ -1,7 +1,7 @@ --- title: The Module System is Launched author: Natalie Weizenbaum -# date: 2019-10-01 18:58 PST +date: 2019-10-01 18:58 PST --- The Sass team has known for years that the `@import` rule, one of the earliest diff --git a/old_source/blog/025-request-for-comments-nested-map-functions.md b/old_source/blog/025-request-for-comments-nested-map-functions.md index d947a61ab..340064acf 100644 --- a/old_source/blog/025-request-for-comments-nested-map-functions.md +++ b/old_source/blog/025-request-for-comments-nested-map-functions.md @@ -1,7 +1,7 @@ --- title: "Request for Comments: Nested Map Functions" author: Natalie Weizenbaum -# date: 2020-9-16 14:40 PST +date: 2020-9-16 14:40 PST --- As Sass libraries and design systems get more complex and have more users with diff --git a/old_source/blog/026-request-for-comments-hwb-functions.md b/old_source/blog/026-request-for-comments-hwb-functions.md index d57c3fad7..47f1a2f43 100644 --- a/old_source/blog/026-request-for-comments-hwb-functions.md +++ b/old_source/blog/026-request-for-comments-hwb-functions.md @@ -1,7 +1,7 @@ --- title: "Request for Comments: HWB Functions" author: Natalie Weizenbaum -# date: 2020-10-06 16:00 PST +date: 2020-10-06 16:00 PST --- The CSS working group has been up to all sorts of exciting stuff recently in the diff --git a/old_source/blog/027-libsass-is-deprecated.md b/old_source/blog/027-libsass-is-deprecated.md index c35160c9e..a85eafc3b 100644 --- a/old_source/blog/027-libsass-is-deprecated.md +++ b/old_source/blog/027-libsass-is-deprecated.md @@ -1,7 +1,7 @@ --- title: LibSass is Deprecated author: Natalie Weizenbaum -# date: 2020-10-26 12:00 PST +date: 2020-10-26 12:00 PST --- After much discussion among the Sass core team, we've come to the conclusion diff --git a/old_source/blog/028-request-for-comments-first-class-calc.md b/old_source/blog/028-request-for-comments-first-class-calc.md index dd2330475..c6e44309d 100644 --- a/old_source/blog/028-request-for-comments-first-class-calc.md +++ b/old_source/blog/028-request-for-comments-first-class-calc.md @@ -1,7 +1,7 @@ --- title: "Request for Comments: First-Class Calc" author: Natalie Weizenbaum -# date: 2021-3-15 1:35 PST +date: 2021-3-15 1:35 PST --- One of the absolutely most-requested features in Sass is the ability to more diff --git a/old_source/blog/029-node-fibers-discontinued.md b/old_source/blog/029-node-fibers-discontinued.md index 82586d8ce..84c81362a 100644 --- a/old_source/blog/029-node-fibers-discontinued.md +++ b/old_source/blog/029-node-fibers-discontinued.md @@ -1,7 +1,7 @@ --- title: "The Discontinuation of node-fibers" author: Natalie Weizenbaum -# date: 2021-3-26 15:00 PST +date: 2021-3-26 15:00 PST --- We have recently received the unfortunate but not entirely surprising news that diff --git a/old_source/blog/030-request-for-comments-new-js-api.html.md b/old_source/blog/030-request-for-comments-new-js-api.html.md index 00267df09..dcc730909 100644 --- a/old_source/blog/030-request-for-comments-new-js-api.html.md +++ b/old_source/blog/030-request-for-comments-new-js-api.html.md @@ -1,7 +1,7 @@ --- title: "Request for Comments: New JS API" author: Natalie Weizenbaum -# date: 2021-08-05 15:30 PST +date: 2021-08-05 15:30 PST --- I'm excited to officially unveil something that's been in the works for quite a diff --git a/old_source/blog/031-new-js-api-release-candidate.html.md b/old_source/blog/031-new-js-api-release-candidate.html.md index 886ec0bff..6394a2e3d 100644 --- a/old_source/blog/031-new-js-api-release-candidate.html.md +++ b/old_source/blog/031-new-js-api-release-candidate.html.md @@ -1,7 +1,7 @@ --- title: "New JS API Release Candidate is Live" author: Natalie Weizenbaum -# date: 2021-11-20 16:15 PST +date: 2021-11-20 16:15 PST --- The new JavaScript API that we [announced a few months ago] is now fully diff --git a/old_source/blog/032-embedded-sass-is-live.md b/old_source/blog/032-embedded-sass-is-live.md index 925424248..8cfcec8a7 100644 --- a/old_source/blog/032-embedded-sass-is-live.md +++ b/old_source/blog/032-embedded-sass-is-live.md @@ -1,7 +1,7 @@ --- title: "Embedded Sass is Live" author: Natalie Weizenbaum -# date: 2022-02-01 2:00 PST +date: 2022-02-01 2:00 PST --- After several years of planning and development, I'm excited to finally announce diff --git a/old_source/blog/033-request-for-comments-strict-unary-operators.md b/old_source/blog/033-request-for-comments-strict-unary-operators.md index 85ce40cac..9c696e217 100644 --- a/old_source/blog/033-request-for-comments-strict-unary-operators.md +++ b/old_source/blog/033-request-for-comments-strict-unary-operators.md @@ -1,7 +1,7 @@ --- title: "Request for Comments: Strict Unary Operators" author: Natalie Weizenbaum -# date: 2022-06-15 15:30 PST +date: 2022-06-15 15:30 PST --- Do you know what `margin: $a -$b` does in Sass? If you said "the same thing as diff --git a/old_source/blog/034-request-for-comments-color-spaces.md b/old_source/blog/034-request-for-comments-color-spaces.md index c39e21088..87fe1c738 100644 --- a/old_source/blog/034-request-for-comments-color-spaces.md +++ b/old_source/blog/034-request-for-comments-color-spaces.md @@ -1,7 +1,7 @@ --- title: "Request for Comments: Color Spaces" author: Miriam Suzanne and Natalie Weizenbaum -# date: 2022-09-21 13:00 PST +date: 2022-09-21 13:00 PST --- There's been a lot of exciting work in the CSS color specifications lately, and diff --git a/old_source/blog/035-security-alert-tar-permissions.md b/old_source/blog/035-security-alert-tar-permissions.md index 582463b3d..42d0d2748 100644 --- a/old_source/blog/035-security-alert-tar-permissions.md +++ b/old_source/blog/035-security-alert-tar-permissions.md @@ -1,7 +1,7 @@ --- title: "Security Alert: Tar Permissions" author: Natalie Weizenbaum -# date: 2022-12-09 16:00 PST +date: 2022-12-09 16:00 PST --- The Sass team was recently alerted by prolific external contributor [@ntkme] to diff --git a/source/_includes/attribution.liquid b/source/_includes/attribution.liquid new file mode 100644 index 000000000..71ee28cf1 --- /dev/null +++ b/source/_includes/attribution.liquid @@ -0,0 +1 @@ +

    Posted {{ date | format }} by {{ author }}

    diff --git a/source/_layouts/blog.liquid b/source/_layouts/blog.liquid index 360cfc52a..e68075a77 100644 --- a/source/_layouts/blog.liquid +++ b/source/_layouts/blog.liquid @@ -1,5 +1,6 @@ --- -layout: has_no_sidebars +layout: base --- -

    Posted {{ page.date | formatBlogDate }} by {{ author }}

    -{{ content }} \ No newline at end of file +{% render 'attribution', date: page.date, author: author %} + +{{ content }} diff --git a/source/blog.liquid b/source/blog.liquid index 28b1ed705..6dc30227b 100644 --- a/source/blog.liquid +++ b/source/blog.liquid @@ -1,32 +1,35 @@ --- +layout: has_no_sidebars +title: Sass Blog pagination: data: collections.blog size: 5 alias: posts reverse: true -layout: has_no_sidebars -title: Sass Blog +permalink: '/blog/{% if pagination.pageNumber > 0 %}page/{{ pagination.pageNumber | plus: 1 }}/{% endif %}index.html' --- -Page {{ pagination.pageNumber | plus: 1 }} of {{ pagination.pages.length }} -
      - {% if pagination.href.previous %} -
    • - Previous -
    • +{% assign pageNumber = pagination.pageNumber | plus: 1 %} +{% assign pages = pagination.pages.size %} + +{% if pages > 1 %} +

      Page {{ pageNumber }} of {{ pagination.pages.size }}

      + {% if pagination.page.previous %} +

      Previous page

      {% endif %} - {%- for post in posts -%} -
    • -

      - {{ post.data.title }} -

      -

      Posted {{ post.date | formatBlogDate }} by {{ post.data.author }}

      - {{ post.content | truncatePost }} -
    • - {%- endfor -%} - {% if pagination.href.next %} +{% endif %} + +
        + {% for post in posts %}
      • - Next +

        {{ post.data.title }}

        + {% render 'attribution', date: post.date, author: post.data.author %} + {% # @@@ This shouls also replace internal links with links to the page %} + {{ post.content | truncateHTML }}
      • - {% endif %} -
      \ No newline at end of file + {% endfor %} +
    + +{% if pagination.page.next %} +

    Next page

    +{% endif %} diff --git a/source/blog/007-thank-you-marcel.md b/source/blog/007-thank-you-marcel.md index 205071103..10d0ee72b 100644 --- a/source/blog/007-thank-you-marcel.md +++ b/source/blog/007-thank-you-marcel.md @@ -2,7 +2,6 @@ title: Dropping Support For Old Ruby Versions author: Natalie Weizenbaum date: 2016-05-24 14:41:00 -8 -permalink: /thank-you-marcel --- You may not know [Marcel Greter](https://github.com/mgreter), but you almost diff --git a/source/blog/014-dart-sass-100-is-released.md b/source/blog/014-dart-sass-100-is-released.md index 47a3936aa..4aa00af62 100644 --- a/source/blog/014-dart-sass-100-is-released.md +++ b/source/blog/014-dart-sass-100-is-released.md @@ -90,6 +90,7 @@ sass` (or `choco upgrade sass` if you already have it). - [Homebrew](https://brew.sh/) users on Mac OS X can run `brew install sass/sass/sass` (or `brew upgrade sass` if you already have it). + - Or if you're a Dart user, you can run `pub global activate sass`. Now, get styling! diff --git a/source/blog/024-the-module-system-is-launched.md b/source/blog/024-the-module-system-is-launched.md index 2ed399e21..85c37f056 100644 --- a/source/blog/024-the-module-system-is-launched.md +++ b/source/blog/024-the-module-system-is-launched.md @@ -346,6 +346,7 @@ support for `@import` on the following timeline: system, whichever comes sooner (**1 October 2021** at latest), we will 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 latest), we will drop support for `@import` and most global functions entirely. This will involve a major version release for all implementations.~~ diff --git a/source/blog/blog.11tydata.yml b/source/blog/blog.11tydata.yml index 5c7e49bdf..91e3bcf8d 100644 --- a/source/blog/blog.11tydata.yml +++ b/source/blog/blog.11tydata.yml @@ -1,3 +1,5 @@ layout: blog -tags: blog -permalink: /blog/{{ title | slugify }} +tags: + - blog +# @@@ This should strip the `id` from the slug first +permalink: '/blog/{{ page.fileSlug }}/index.html' From 022f1accf2db148b6319ec404fa43aaa20c309a6 Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Thu, 9 Mar 2023 11:19:39 -0500 Subject: [PATCH 36/42] Fix remaining blog issues --- .prettierignore | 1 + eleventy.config.cjs | 10 +- source/_includes/header.liquid | 5 +- source/_layouts/has_complimentary.liquid | 2 +- source/_layouts/has_navigation.liquid | 2 +- source/blog.liquid | 21 ++- source/blog/001-how-extend-works.md | 30 ++-- .../blog/002-a-change-in-plans-for-sass-33.md | 6 +- source/blog/003-sass-33-is-released.md | 27 ++-- source/blog/004-sass-34-is-released.md | 10 +- source/blog/005-cleaning-up-interpolation.md | 20 +-- ...-dropping-support-for-old-ruby-versions.md | 2 +- source/blog/008-sass-35-release-candidate.md | 6 +- source/blog/009-announcing-dart-sass.md | 24 ++- source/blog/010-dart-sass-is-on-chocolatey.md | 5 +- .../011-sass-and-browser-compatibility.md | 4 +- source/blog/012-dart-sass-is-in-beta.md | 15 +- source/blog/013-sass-35-is-released.md | 28 ++-- source/blog/014-dart-sass-100-is-released.md | 6 +- ...request-for-commentsimporting-css-files.md | 2 +- ...-watchcss-imports-and-css-compatibility.md | 12 +- ...chcontent-arguments-and-color-functions.md | 19 ++- ...est-for-comments-module-system-proposal.md | 82 +++++------ ...-for-commentsforward-slash-as-separator.md | 22 ++- source/blog/023-module-system-preview.md | 2 +- .../blog/024-the-module-system-is-launched.md | 59 ++++---- ...quest-for-comments-nested-map-functions.md | 14 +- .../026-request-for-comments-hwb-functions.md | 4 +- source/blog/027-libsass-is-deprecated.md | 12 +- ...8-request-for-comments-first-class-calc.md | 14 +- source/blog/029-node-fibers-discontinued.md | 24 +-- ...=> 030-request-for-comments-new-js-api.md} | 138 ++++++++++-------- ...md => 031-new-js-api-release-candidate.md} | 2 +- source/blog/032-embedded-sass-is-live.md | 4 +- ...est-for-comments-strict-unary-operators.md | 16 +- .../034-request-for-comments-color-spaces.md | 64 ++++---- .../035-security-alert-tar-permissions.md | 12 +- source/blog/blog.11tydata.yml | 3 +- source/index.liquid | 5 +- 39 files changed, 373 insertions(+), 361 deletions(-) rename source/blog/{030-request-for-comments-new-js-api.html.md => 030-request-for-comments-new-js-api.md} (87%) rename source/blog/{031-new-js-api-release-candidate.html.md => 031-new-js-api-release-candidate.md} (97%) diff --git a/.prettierignore b/.prettierignore index 21676bc38..176f47e01 100644 --- a/.prettierignore +++ b/.prettierignore @@ -7,6 +7,7 @@ /_site/ /old_source/ /source/_data/versionCache.json +/source/blog/*.md coverage/ node_modules/ source/assets/dist/ diff --git a/eleventy.config.cjs b/eleventy.config.cjs index f97c5a3f7..97c4d2a92 100644 --- a/eleventy.config.cjs +++ b/eleventy.config.cjs @@ -66,7 +66,7 @@ module.exports = (eleventyConfig) => { ); // Filters... - eleventyConfig.addLiquidFilter('truncateHTML', (post, words = 250) => { + eleventyConfig.addLiquidFilter('truncateHTML', (post, words = 170) => { return truncate(post, words, { byWords: true }); }); @@ -94,6 +94,14 @@ module.exports = (eleventyConfig) => { page.url.startsWith('/documentation/js-api/'), ); + eleventyConfig.addLiquidFilter('getBlogSlug', (page) => + page.fileSlug.replace(/^(\d*-)/, ''), + ); + + eleventyConfig.addLiquidFilter('replaceInternalLinks', (content, url) => + content.replace(/href="#/g, `href="${url}#`), + ); + eleventyConfig.addPlugin(EleventyRenderPlugin); eleventyConfig.addPlugin(syntaxHighlight); diff --git a/source/_includes/header.liquid b/source/_includes/header.liquid index 0ac8fa17c..32124d677 100644 --- a/source/_includes/header.liquid +++ b/source/_includes/header.liquid @@ -16,7 +16,10 @@

    - Sass + Sass

    {% renderFile 'source/_includes/header_nav.md' %} diff --git a/source/_layouts/has_complimentary.liquid b/source/_layouts/has_complimentary.liquid index 7822a68d5..5c3fd71a6 100644 --- a/source/_layouts/has_complimentary.liquid +++ b/source/_layouts/has_complimentary.liquid @@ -5,7 +5,7 @@ layout: base
    - +
    {% render 'intro', before_introduction: before_introduction, introduction: introduction, center_introduction: center_introduction %} {{ content }} diff --git a/source/_layouts/has_navigation.liquid b/source/_layouts/has_navigation.liquid index cf5e2ecb5..48d175925 100644 --- a/source/_layouts/has_navigation.liquid +++ b/source/_layouts/has_navigation.liquid @@ -8,7 +8,7 @@ layout: base {{ navigation | markdown }}
    - +
    {% render 'intro', before_introduction: before_introduction, introduction: introduction, center_introduction: center_introduction %} {{ content }} diff --git a/source/blog.liquid b/source/blog.liquid index 6dc30227b..382953328 100644 --- a/source/blog.liquid +++ b/source/blog.liquid @@ -13,23 +13,28 @@ permalink: '/blog/{% if pagination.pageNumber > 0 %}page/{{ pagination.pageNumbe {% assign pages = pagination.pages.size %} {% if pages > 1 %} -

    Page {{ pageNumber }} of {{ pagination.pages.size }}

    - {% if pagination.page.previous %} -

    Previous page

    +

    Page {{ pageNumber }} of {{ pages }}

    + {% if pagination.href.previous %} +

    + Previous page +

    {% endif %} {% endif %}
      {% for post in posts %}
    • -

      {{ post.data.title }}

      +

      + {{ post.data.title }} +

      {% render 'attribution', date: post.date, author: post.data.author %} - {% # @@@ This shouls also replace internal links with links to the page %} - {{ post.content | truncateHTML }} + {{ post.content | truncateHTML | replaceInternalLinks: post.url }}
    • {% endfor %}
    -{% if pagination.page.next %} -

    Next page

    +{% if pagination.href.next %} +

    + Next page +

    {% endif %} diff --git a/source/blog/001-how-extend-works.md b/source/blog/001-how-extend-works.md index 248f8673b..1d5e2881c 100644 --- a/source/blog/001-how-extend-works.md +++ b/source/blog/001-how-extend-works.md @@ -33,44 +33,46 @@ Following are a set of primitive objects, definitions, and operations that are necessary for implementing `@extend`. Implementing these is left as an exercise for the reader. -- A selector object is obviously necessary, since `@extend` is all about +* A selector object is obviously necessary, since `@extend` is all about selectors. Selectors will need to be parsed thoroughly and semantically. It's necessary for the implementation to know a fair amount of the meaning behind the various different forms of selectors. -- A custom data structure I call a "subset map" is also necessary. A subset map +* A custom data structure I call a "subset map" is also necessary. A subset map has two operations: `Map.set(Set, Object)` and `Map.get(Set) => [Object]`. The former associates a value with a set of keys in the map. The latter looks up - all values that are associated with _subsets_ of a set of keys. For example: + all values that are associated with *subsets* of a set of keys. For example: - map.set([1, 2], 'value1') - map.set([2, 3], 'value2) - map.set([3, 4], 'value3') - map.get([1, 2, 3]) => ['value1', 'value2'] + ```ruby + map.set([1, 2], 'value1') + map.set([2, 3], 'value2') + map.set([3, 4], 'value3') + map.get([1, 2, 3]) => ['value1', 'value2'] + ``` -- A selector `S1` is a "superselector" of a selector `S2` if every element +* A selector `S1` is a "superselector" of a selector `S2` if every element matched by `S2` is also matched by `S1`. For example, `.foo` is a superselector of `.foo.bar`, `a` is a superselector of `div a`, and `*` is a superselector of everything. The inverse of a superselector is a "subselector". -- An operation `unify(Compound Selector, Compound Selector) => Compound -Selector` that returns a selector that matches exactly those elements matched +* An operation `unify(Compound Selector, Compound Selector) => Compound + Selector` that returns a selector that matches exactly those elements matched by both input selectors. For example, `unify(.foo, .bar)` returns `.foo.bar`. This only needs to work for compound or simpler selectors. This operation can fail (e.g. `unify(a, h1)`), in which case it should return `null`. -- An operation `trim([Selector List]) => Selector List` that removes complex +* An operation `trim([Selector List]) => Selector List` that removes complex selectors that are subselectors of other complex selectors in the input. It takes the input as multiple selector lists and only checks for subselectors across these lists since the prior `@extend` process won't produce intra-list subselectors. For example, if it's passed `[[a], [.foo a]]` it would return `[a]` since `.foo a` is a subselector of `a`. -- An operation `paths([[Object]]) => [[Object]]` that returns a list of all +* An operation `paths([[Object]]) => [[Object]]` that returns a list of all possible paths through a list of choices for each step. For example, `paths([[1, 2], [3], [4, 5, 6]])` returns `[[1, 3, 4], [1, 3, 5], [1, 3, 6], -[2, 3, 4], [2, 3, 5], [2, 3, 6]]`. + [2, 3, 4], [2, 3, 5], [2, 3, 6]]`. ## The Algorithm @@ -142,7 +144,7 @@ so I wanted to explain it in detail. At a high level, the "weave" operation is pretty easy to understand. It's best to think of it as expanding a "parenthesized selector". Imagine you could write `.foo (.bar a)` and it would match every `a` element that has both a `.foo` -parent element _and_ a `.bar` parent element. `weave` makes this happen. +parent element *and* a `.bar` parent element. `weave` makes this happen. In order to match this `a` element, you need to expand `.foo (.bar a)` into the following selector list: `.foo .bar a, .foo.bar a, .bar .foo a`. This matches diff --git a/source/blog/002-a-change-in-plans-for-sass-33.md b/source/blog/002-a-change-in-plans-for-sass-33.md index 20b2a355a..4746fe3d3 100644 --- a/source/blog/002-a-change-in-plans-for-sass-33.md +++ b/source/blog/002-a-change-in-plans-for-sass-33.md @@ -44,8 +44,7 @@ Here's a small snippet of SCSS that demonstrates the issue. See if you can figure it out: ```scss -.foo, -.bar { +.foo, .bar { @at-root #{&}-suffix { color: blue; } @@ -120,6 +119,5 @@ to devote a large chunk of time to getting 3.3 out the door after I come back from winter vacation, so hopefully (no promises) it'll be released some time in January. -[^1]: - The `@at-root` is necessary since Sass can't reliably figure out whether +[^1]: The `@at-root` is necessary since Sass can't reliably figure out whether `&` was used in the selector like it can when `&` is used without `#{}`. diff --git a/source/blog/003-sass-33-is-released.md b/source/blog/003-sass-33-is-released.md index 86cf0c1e8..a72ecc692 100644 --- a/source/blog/003-sass-33-is-released.md +++ b/source/blog/003-sass-33-is-released.md @@ -10,7 +10,7 @@ This release has a lot of exciting new features that you can read about in full in [the changelog](/documentation/file.SASS_CHANGELOG.html), but there are three that I want to draw your attention to in particular. -# Maps in SassScript +## Maps in SassScript As language designers, most of our job is to listen to feedback from users and act upon it. This is tricker than it sounds: users are very good at knowing the @@ -32,11 +32,7 @@ first-class data structure. The syntax is designed to be very similar to that used for `@media` queries. They look like this: ```scss -$map: ( - key1: value1, - key2: value2, - key3: value3, -); +$map: (key1: value1, key2: value2, key3: value3); ``` Unlike lists, maps must always be surrounded by parentheses. `()`, which @@ -49,15 +45,15 @@ functions](/documentation/Sass/Script/Functions.html#map_functions) that allow user-defined mixins and functions to use them. Here are a few particularly useful ones: -- `map-get($map, $key)` looks up a value in a map using its key. For example, +* `map-get($map, $key)` looks up a value in a map using its key. For example, using the example above, `map-get($map, key2)` would return `value2`. -- `map-merge($map1, $map2)` merges two maps together. The keys in `$map2` +* `map-merge($map1, $map2)` merges two maps together. The keys in `$map2` overwrite those in `$map1`, so this is also a good way to add values to a map. For example, `map-merge($map, (key1: new-value))` would return `(key1: -new-value, key2: value2, key3: value3)`. + new-value, key2: value2, key3: value3)`. -- `map-remove($map, $key)` removes a value in a map. For example, +* `map-remove($map, $key)` removes a value in a map. For example, `map-remove($map, $key)` would return `(key: value2, key3: value3)`. In addition to the new map functions, all the existing list functions also work @@ -89,7 +85,7 @@ h3 { } ``` -# Source Maps +## Source Maps Continuing the map theme, Sass 3.3 comes with support for generating source maps when compiling to CSS. Source maps are a standard format for telling browsers @@ -104,7 +100,7 @@ maps is pass the `--sourcemap` flag. Sass will automatically generate a make sure your `.scss` or `.sass` file is visible to the browser, and you'll be good to go. -# More Flexible `&` +## More Flexible `&` When we released Sass 3.0, we added support for SCSS, which meant we had to actually parse all the selectors in the document. This meant that you couldn't @@ -123,7 +119,7 @@ In Sass 3.3, we're loosening these restrictions. You can now write `&-suffix` work. If this fails to apply—for example, if `&` is `*`—Sass will print a helpful error message. -# Deprecation: Variable Scope and `!global` +## Deprecation: Variable Scope and `!global` We don't always get everything right the first time, and in order to make Sass the best language it can be we occasionally have to change old behavior. @@ -150,7 +146,7 @@ print a deprecation warning suggesting that the user add `!global`. Right now, `!global` doesn't do much other than make the warning go away, but in a future release it will work as I described above. -# That's All +## That's All Actually, there's a lot more, but that's all I have room for in this post. If you want to see the full assortment of new features, check out [the @@ -158,6 +154,5 @@ changelog](/documentation/file.SASS_CHANGELOG.html#330_7_March_2014). You can also play with the new features on [SassMeister](http://sassmeister.com/) or on your own computer by running `gem update sass`. Enjoy! -[^1]: - Some languages call them "hashes", "dictionaries", or "associative +[^1]: Some languages call them "hashes", "dictionaries", or "associative arrays". JavaScript calls them "objects" for weird historical reasons. diff --git a/source/blog/004-sass-34-is-released.md b/source/blog/004-sass-34-is-released.md index 2302a65a1..680d1adbc 100644 --- a/source/blog/004-sass-34-is-released.md +++ b/source/blog/004-sass-34-is-released.md @@ -13,7 +13,7 @@ little improvements you can read about in [the changelog](/documentation/file.SASS_CHANGELOG.html)). As the version name suggests, both of these features have to do with selectors. -# Using `&` in SassScript +## Using `&` in SassScript "SassScript" is what we call the mini-language Sass uses for variables, property values, and so forth. It's mostly just CSS values, but it also supports custom @@ -37,7 +37,7 @@ break when they contained commas](/blog/a-change-in-plans-for-sass-33). Because of that, we decided to delay it for a version to give us time to come up with its compantion feature: selector functions. -# Selector Functions +## Selector Functions The problem with just exposing `&` was that the only way to use it with other selectors was by glomming them together as strings. This works okay in simple @@ -63,17 +63,17 @@ its selectors, where `selector-append()` doesn't. This means that Another function I like a lot is **`selector-replace()`**. This does a search-and-replace of one selector within another, but it's a lot more clever than your basic string replace. It uses Sass's `@extend` logic to replace -selectors _semantically_, as though every element matched by the replacement +selectors *semantically*, as though every element matched by the replacement selector was also matched by the replaced selector. For example, `selector-replace(".foo.bar.baz", ".foo.baz", ".qux")` returns `.bar.qux`. The last really powerful function I want to draw your attention to is **`selector-unify()`**. This takes two selectors and returns a new selector that -matches only elements that are matched by _both_ input selectors. This is an +matches only elements that are matched by *both* input selectors. This is an operation Sass uses a lot internally, and now users can access it as well. For example, `selector-unify(".foo.bar", ".bar.baz")` will return `.foo.bar.baz`. -# What's Next? +## What's Next? I won't rule out the possibility of Sass 3.5 existing, but [Chris](https://twitter.com/chriseppstein) and I plan to focus pretty hard on diff --git a/source/blog/005-cleaning-up-interpolation.md b/source/blog/005-cleaning-up-interpolation.md index 86d1eac81..c69c1b6ae 100644 --- a/source/blog/005-cleaning-up-interpolation.md +++ b/source/blog/005-cleaning-up-interpolation.md @@ -11,7 +11,7 @@ expression. In most of those places it just plops the value into the surrounding text. It's straightforward, easy to understand, and useful, which is exactly what we want from a feature. -Unfortunately, that's only true in _most places_. For complicated historical +Unfortunately, that's only true in *most places*. For complicated historical reasons, there's one place where interpolation goes a little bit bananas: inside an expression but outside quotes. Most of the time, it makes sense; if you write `display: -#{$prefix}-box`, you'll get what you expect. But if any operators @@ -22,13 +22,13 @@ the text `name + 3`. This is really weird behavior. Why does `+` behave differently here than it does everywhere else? Why is it treated as plain text when `$name` gets evaluated normally? This behavior is confusing, inconsistent, and not particularly useful, -which are very much _not_ things we want in a feature. So why do they exist in +which are very much *not* things we want in a feature. So why do they exist in the first place? ## Complicated Historical Reasons -_If you don't care for a history lesson, skip on down to [A Brave New -World](#a-brave-new-world)._ +*If you don't care for a history lesson, skip on down to [A Brave New +World](#a-brave-new-world).* Way back in the dawn of time, when the indented syntax was the only syntax, Sass had a distinction between "static" and "dynamic" properties. A static property @@ -71,8 +71,8 @@ minimum of pain. This was mostly straightforward, since the old expression syntax was pretty much universally invalid CSS or something that emitted its CSS value anyway. But interpolation proved tricky. Backwards compatibility is really important to us, -so we wanted to be sure that all the places interpolation was used—or _could -theoretically be used_—in Sass 2 would continue to work in Sass 3, even though +so we wanted to be sure that all the places interpolation was used—or *could +theoretically be used*—in Sass 2 would continue to work in Sass 3, even though everything around them was now fully parsed. Our solution was to make basically anything around `#{}` that wasn't obviously @@ -113,8 +113,8 @@ reasons), but `12px+#{$line-height}` won't. I won't go into the gory details of how we got deprecation working here; that's what the [GitHub issue](https://github.com/sass/sass/issues/1778) is for. Suffice it to say that it involved a lot of special cases, including some where -a deprecation warning can be printed based on how a value is _used_ rather than -how it's _written_. I'm pretty happy with where it ended up, though; I suspect +a deprecation warning can be printed based on how a value is *used* rather than +how it's *written*. I'm pretty happy with where it ended up, though; I suspect it'll catch 99% of cases that will actually break in practice. Another exciting bonus was the ability to automatically update code. This @@ -127,7 +127,7 @@ long way there. The final step once the deprecation was in place was to move to [the `main` branch](https://github.com/sass/sass/commits/main) (which will eventually become Sass 4), rip out all the old behavior, and implement the new. And it was -_wonderful_. Deleting gross code and replacing it with something clean feels +*wonderful*. Deleting gross code and replacing it with something clean feels like taking a shower after spending a day hiking through dust under a hot sun. And after working on this feature for weeks, I was happy to see the other end of it. @@ -148,6 +148,6 @@ prereleases pretty stable, but there's also a chance you'll run into a bug. If you do find a bug, please file it on [the issue tracker](https://github.com/sass/sass/issues). Even if it's something as simple as a typo, we want to know. If we've deprecated something that should be valid, -we _especially_ want to know. And if you just have a question, feel free to +we *especially* want to know. And if you just have a question, feel free to tweet at [@SassCSS](https://twitter.com/SassCSS) or post it on the [mailing list](https://groups.google.com/forum/#!forum/sass-lang). diff --git a/source/blog/006-dropping-support-for-old-ruby-versions.md b/source/blog/006-dropping-support-for-old-ruby-versions.md index 8087160d6..767c59536 100644 --- a/source/blog/006-dropping-support-for-old-ruby-versions.md +++ b/source/blog/006-dropping-support-for-old-ruby-versions.md @@ -37,7 +37,7 @@ We decided to use the analytics data for sass-lang.com to approximate the proportion of our user base that was still using operating systems that shipped with old Ruby versions. Before we looked at the data, we decided that we would drop support for a Ruby version if it had been retired by the Ruby maintainers, -_and_ less than 2% of our visitors across the previous month were using an OS +*and* less than 2% of our visitors across the previous month were using an OS that shipped it by default. Once we did that, we looked at the data. 34.3% of our visitors were using OS X, diff --git a/source/blog/008-sass-35-release-candidate.md b/source/blog/008-sass-35-release-candidate.md index e9ae6cbba..533758def 100644 --- a/source/blog/008-sass-35-release-candidate.md +++ b/source/blog/008-sass-35-release-candidate.md @@ -22,7 +22,7 @@ some time to add some new features, which are the focus of this release. Sass 3.5 now fully supports [CSS custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables). These posed a particular challenge for us, since the custom property syntax is -_extremely_ broad. You can put just about anything on the right-hand side. For +*extremely* broad. You can put just about anything on the right-hand side. For example, this is totally valid, meaningful CSS: ```css @@ -31,7 +31,7 @@ example, this is totally valid, meaningful CSS: } ``` -In particular, this means that SassScript expressions are _also_ valid CSS, +In particular, this means that SassScript expressions are *also* valid CSS, which poses a problem for our goal of CSS compatibility. Wherever possible, we want valid CSS to mean the same thing in Sass as it does in CSS. So treating custom properties just like normal properties—which we did in 3.4—wasn't a good @@ -49,7 +49,7 @@ to impossible to represent in Sass: } ``` -On the other hand, we needed _some_ way of including dynamic SassScript values +On the other hand, we needed *some* way of including dynamic SassScript values in custom properties. So we decided on a compromise: we'd treat custom properties like we do selectors and at-rule values, and only allow `#{}` as a means of including Sass values. While technically this is plain CSS, it's a very diff --git a/source/blog/009-announcing-dart-sass.md b/source/blog/009-announcing-dart-sass.md index 899a84a5b..e65725f43 100644 --- a/source/blog/009-announcing-dart-sass.md +++ b/source/blog/009-announcing-dart-sass.md @@ -43,20 +43,19 @@ can be healthy, but it can also mean that neither solution is as good as it needs to be. That's what we found when, in May, [Marcel officially left the LibSass team](http://blog.sass-lang.com/posts/734390-thank-you-marcel)[^1]. -[^1]: - I say "officially" because he's still contributing to the project when he +[^1]: I say "officially" because he's still contributing to the project when he can, just not in an official maintainer capacity. Without two people's worth of effort, we were no longer sure that LibSass could keep pace with the speed Chris and I wanted to introduce changes into the language. And it had been clear for a long time that Ruby Sass was far too slow for use cases involving large stylesheets. We needed a new implementation, one -that could generate CSS quickly _and_ add new features quickly. +that could generate CSS quickly *and* add new features quickly. ## Why Dart? We considered a number of possible languages, and ended up deciding on Dart for -a number of reasons. First, it's _really fast_—the Dart VM is generally much +a number of reasons. First, it's *really fast*—the Dart VM is generally much faster than JavaScript VMs, and [early benchmarks](https://github.com/sass/dart-sass/blob/main/perf.md)[^2] indicate that, for large stylesheets, Dart Sass is 5-10x faster than Ruby Sass and only @@ -64,9 +63,8 @@ about 1.5x slower than LibSass. I'll hazard a guess that it would be about 1.5-2x faster than an idiomatic JS implementation, but I can't say for sure. And Dart's performance continues to get better all the time. -[^2]: - Caveats apply: I'm not a benchmarking expert, and these tests were _ad - hoc_ and run against non-representative source stylesheets. If anyone is +[^2]: Caveats apply: I'm not a benchmarking expert, and these tests were *ad + hoc* and run against non-representative source stylesheets. If anyone is interested in working on more scientific benchmarks, please let me know! At the same time, Dart is easy to work with—much more so than C++, and to some @@ -77,8 +75,8 @@ new implementation, and Dart is the language that I'm personally most comfortable with at the moment (when I'm not working on Sass, I'm on the Dart team). Using Dart gives me a lot of extra velocity. -Unlike Ruby or JavaScript, Dart is _statically typed_, so every value's type can -be figured out without running the code. Unlike C++, it's _garbage collected_, +Unlike Ruby or JavaScript, Dart is *statically typed*, so every value's type can +be figured out without running the code. Unlike C++, it's *garbage collected*, so we don't have to worry as much about cleaning up after ourselves. This makes it easy to write, easy to modify, and easy to maintain. Maybe even more importantly, it makes it easy to translate to other programming languages, which @@ -138,20 +136,20 @@ slow as to be infeasible for many of our largest users. Before we release the first stable version of Dart Sass, there are a few big things on our to-do list: -- Full sass-spec compatibility. There are still a bunch of corners of the +* Full sass-spec compatibility. There are still a bunch of corners of the language where Dart Sass does the wrong thing, especially with respect to `@extend`. I don't expect any individual incompatibility to be especially difficult to address, and sass-spec is pretty comprehensive, so it's just a matter of steadily reducing the number of failing specs until it hits zero. -- Close-enough node-sass `render()` compatibility in the npm package. The +* Close-enough node-sass `render()` compatibility in the npm package. The node-sass `render()` API is the main entrypoint to LibSass in the JavaScript world. It's how build systems run Sass, how users define custom Sass functions, and how [Eyeglass](https://github.com/sass-eyeglass/eyeglass) passes modules to Sass. We want to support this API with enough fidelity that the existing ecosystem works with JS-compiled Dart Sass. -- Dart Sass compatibility in Ruby Sass. There are some cases where Dart Sass +* Dart Sass compatibility in Ruby Sass. There are some cases where Dart Sass intentionally differs from Ruby Sass, particularly when Ruby Sass's behavior is considered a bug. We should add deprecation messages in Ruby Sass and, if we can do so with minimal disruption, add support for the new behavior. @@ -170,7 +168,7 @@ Sass and a 3.5 release of LibSass. At that point we'll set our sight on the big features and start working towards Sass 4.0 and its brand new module system. Dart Sass is a big change, but it's an exciting one as well. It'll allow us to -get new features into users' hands faster, and to make those features _run_ +get new features into users' hands faster, and to make those features *run* faster. It'll make it possible for users to trivially install and run the reference implementation. And it'll give us a performant way to run Sass in pure JavaScript Sass for the first time ever. The benefits are large and tangible, diff --git a/source/blog/010-dart-sass-is-on-chocolatey.md b/source/blog/010-dart-sass-is-on-chocolatey.md index 346c97c95..890b0989a 100644 --- a/source/blog/010-dart-sass-is-on-chocolatey.md +++ b/source/blog/010-dart-sass-is-on-chocolatey.md @@ -21,7 +21,7 @@ package](https://chocolatey.org/packages/sass) on [Chocolatey](https://chocolatey.org/), the Windows package manager. You can install it now using: -``` +```shellsession $ choco install sass -prerelease ``` @@ -39,8 +39,7 @@ out with that, let us know—[this issue](https://github.com/sass/dart-sass/issues/97) would be a great place to start! -[^1]: - There's also [an open +[^1]: There's also [an open issue](https://github.com/dart-lang/sdk/issues/27596) for bundling the VM and the snapshot into a single executable file, which would allow us to pare down our distribution to a single file. diff --git a/source/blog/011-sass-and-browser-compatibility.md b/source/blog/011-sass-and-browser-compatibility.md index a826a4354..ff758c434 100644 --- a/source/blog/011-sass-and-browser-compatibility.md +++ b/source/blog/011-sass-and-browser-compatibility.md @@ -7,7 +7,7 @@ date: 2017-02-10 17:46:00 -8 One of the core design principles of Sass has always been to **understand CSS as little as possible**. As a CSS preprocessor of course we have to understand the syntax of CSS, but as much as we can we try to avoid caring about the -_semantics_—the meaning behind the styles. This means that Sass has no idea +*semantics*—the meaning behind the styles. This means that Sass has no idea which properties are valid, which HTML elements actually exist, or even to a large extent what the syntax of most @-rules is. @@ -15,7 +15,7 @@ We get a lot of benefit from this. The less built-in knowledge Sass has about CSS, the less likely it is to work poorly with new CSS features. Imagine having to file a feature request every time you want to use a new CSS property—that would suck! Instead, older versions of Sass will happily keep working unless the -actual _syntax_ changes, which is much rarer. +actual *syntax* changes, which is much rarer. Because of this decoupling, we've never needed to worry much about browser compatibility. Sass just passes whatever CSS its given on through. It's up to diff --git a/source/blog/012-dart-sass-is-in-beta.md b/source/blog/012-dart-sass-is-in-beta.md index 63e88e4b1..91b58e48a 100644 --- a/source/blog/012-dart-sass-is-in-beta.md +++ b/source/blog/012-dart-sass-is-in-beta.md @@ -11,8 +11,7 @@ that I love to curl up on the armchair in my living room and write some code. This weekend, that meant finishing up the last few outstanding `@extend` bugs, finally **making Dart Sass fully sass-spec compatible**[^1]. -[^1]: - Technically there are still two specs marked as "TODO". These test UTF-16 +[^1]: Technically there are still two specs marked as "TODO". These test UTF-16 support, which is currently [blocked on Dart support](https://github.com/dart-lang/sdk/issues/11744). @@ -55,17 +54,17 @@ work with Dart Sass as well. As with all Dart Sass releases, 1.0.0-beta.1 is available on many platforms. Give it a try on whichever is easiest for you: -- Standalone tarballs are [available on +* Standalone tarballs are [available on GitHub](https://github.com/sass/dart-sass/releases/tag/1.0.0-beta.1), which you can just download and run from the command line. -- [Chocolatey](https://chocolatey.org) users on Windows can just run `choco -install sass --pre` (or `choco upgrade sass --pre` if you already have it). +* [Chocolatey](https://chocolatey.org) users on Windows can just run `choco + install sass --pre` (or `choco upgrade sass --pre` if you already have it). -- You can get the pure-JavaScript version from npm by running `npm install -g -dart-sass`. +* You can get the pure-JavaScript version from npm by running `npm install -g + dart-sass`. -- Or if you're a Dart user, you can run `pub global activate sass`. +* Or if you're a Dart user, you can run `pub global activate sass`. I'm very pleased to have 1.0.0-beta.1 tagged and out in the world, but the work of a language maintainer is never done. I'm back to work, and if I hustle, diff --git a/source/blog/013-sass-35-is-released.md b/source/blog/013-sass-35-is-released.md index bf727a54b..ea7cfbb83 100644 --- a/source/blog/013-sass-35-is-released.md +++ b/source/blog/013-sass-35-is-released.md @@ -13,15 +13,15 @@ Most of the major features in 3.5 were already in the release candidate, which [you can read about here](/blog/sass-35-release-candidate). But there are a handful of other changes that have been added since then: -- Sass now supports the [the `::slotted()` +* Sass now supports the [the `::slotted()` pseudo-element](https://drafts.csswg.org/css-scoping-1/#slotted-pseudo), including extending its selector arguments. -- [The `var()` function](https://www.w3.org/TR/css-variables-1/#using-variables) +* [The `var()` function](https://www.w3.org/TR/css-variables-1/#using-variables) may be safely passed to the CSS color functions `rgb()`, `rgba()`, `hsl()`, and `hsla()`. -- Transparent colors created by Sass's color functions will now be written as +* Transparent colors created by Sass's color functions will now be written as `rgba(0, 0, 0, 0)` rather than `transparent` to work around a bug in Internet Explorer. Colors written as `transparent` in the document will still be emitted as written. @@ -33,46 +33,46 @@ keeping Ruby Sass compatible with Dart Sass in the short term. Sass 3.5 begins to implement those plans by adding support for a number of small behavioral extensions added by Dart Sass: -- It's no longer an error to `@extend` a selector that appears in the +* It's no longer an error to `@extend` a selector that appears in the stylesheet, but for which unification fails. The purpose of extension errors was to prevent typos, which weren't occurring in this case. -- Pseudo selectors that take arguments can now take any argument that matches +* Pseudo selectors that take arguments can now take any argument that matches CSS's [`` syntax](https://drafts.csswg.org/css-syntax-3/#typedef-declaration-value). This will provide better forwards-compatibility with new selectors. -- Pseudo selectors that contain placeholder selectors as well as +* Pseudo selectors that contain placeholder selectors as well as non-placeholders—for example, `:matches(.foo, %bar)`—will no longer be eliminated. This matches the definition of a placeholder as a selector that matches nothing. -- You can now vary the indentation within an indented-syntax file, as long as it +* You can now vary the indentation within an indented-syntax file, as long as it still defines a consistent tree structure. There are also some deprecations for functionality that's not supported in Ruby Sass: -- Extending compound selectors, such as `@extend .foo.bar`, is deprecated. This +* Extending compound selectors, such as `@extend .foo.bar`, is deprecated. This never followed the stated semantics of extend: elements that match the extending selector are styled as though they matches the extended selector. - When you write `h1 {@extend .a.b}`, this _should_ mean that all `h1` elements + When you write `h1 {@extend .a.b}`, this *should* mean that all `h1` elements are styled as though they match `.a.b`—that is, as though they have `class="a -b"`, which means they'd match both `.a` and `.b` separately. But instead we - extend only selectors that contain _both_ `.a` and `.b`, which is incorrect. + b"`, which means they'd match both `.a` and `.b` separately. But instead we + extend only selectors that contain *both* `.a` and `.b`, which is incorrect. -- Color arithmetic is deprecated. Channel-by-channel arithmetic doesn't +* Color arithmetic is deprecated. Channel-by-channel arithmetic doesn't correspond closely to intuitive understandings of color. Sass's suite of [color functions](/documentation/Sass/Script/Functions.html#other_color_functions) are a much cleaner and more comprehensible way of manipulating colors dynamically. -- The reference combinator, `/foo/`, is deprecated since it hasn't been in the +* The reference combinator, `/foo/`, is deprecated since it hasn't been in the CSS specification for some time and is being removed from Chrome soon. -- The old-style `:name value` property syntax is deprecated. This syntax is not +* The old-style `:name value` property syntax is deprecated. This syntax is not widely used, and is unnecessarily different from CSS. ### LibSass Compatibility diff --git a/source/blog/014-dart-sass-100-is-released.md b/source/blog/014-dart-sass-100-is-released.md index 4aa00af62..214fd1e9d 100644 --- a/source/blog/014-dart-sass-100-is-released.md +++ b/source/blog/014-dart-sass-100-is-released.md @@ -83,13 +83,13 @@ easiest for you: just download and run from the command line. - You can get the pure-JavaScript version from npm by running `npm install -g -sass`. + sass`. - [Chocolatey](https://chocolatey.org/) users on Windows can run `choco install -sass` (or `choco upgrade sass` if you already have it). + sass` (or `choco upgrade sass` if you already have it). - [Homebrew](https://brew.sh/) users on Mac OS X can run `brew install -sass/sass/sass` (or `brew upgrade sass` if you already have it). + sass/sass/sass` (or `brew upgrade sass` if you already have it). - Or if you're a Dart user, you can run `pub global activate sass`. diff --git a/source/blog/016-request-for-commentsimporting-css-files.md b/source/blog/016-request-for-commentsimporting-css-files.md index 96f61c35e..35181838b 100644 --- a/source/blog/016-request-for-commentsimporting-css-files.md +++ b/source/blog/016-request-for-commentsimporting-css-files.md @@ -1,5 +1,5 @@ --- -title: 'Request For Comments: Importing CSS Files' +title: "Request For Comments: Importing CSS Files" author: Natalie Weizenbaum date: 2018-07-09 11:19:00 -8 --- diff --git a/source/blog/017-feature-watchcss-imports-and-css-compatibility.md b/source/blog/017-feature-watchcss-imports-and-css-compatibility.md index 424a1229f..0c569d275 100644 --- a/source/blog/017-feature-watchcss-imports-and-css-compatibility.md +++ b/source/blog/017-feature-watchcss-imports-and-css-compatibility.md @@ -1,5 +1,5 @@ --- -title: 'Feature Watch: CSS Imports and CSS Compatibility' +title: "Feature Watch: CSS Imports and CSS Compatibility" author: Natalie Weizenbaum date: 2018-08-13 14:17:00 -8 --- @@ -50,13 +50,13 @@ to use these CSS functions... until now. Dart Sass 1.11 will intelligently decide whether to use the plain CSS functions or the built-in Sass functions based on whether or not you're passing in dynamic Sass values. For example: -- The Sass function will be called if you pass a variable, like `max($width, -100px)`. -- The Sass function will be called if you call another Sass function, like +* The Sass function will be called if you pass a variable, like `max($width, + 100px)`. +* The Sass function will be called if you call another Sass function, like `max(compute-width(), 100px)`. -- It will compile to a plain CSS function if you just use plain CSS numbers, +* It will compile to a plain CSS function if you just use plain CSS numbers, like `max(50% + 10px, 100px)`. -- It will still compile to a plain CSS function even if you use interpolation, +* It will still compile to a plain CSS function even if you use interpolation, like `max(50% + #{$width / 2}, #{$width})`. This preserves backwards-compatibility with existing uses of the Sass functions, diff --git a/source/blog/018-feature-watchcontent-arguments-and-color-functions.md b/source/blog/018-feature-watchcontent-arguments-and-color-functions.md index f659ead51..ce0f59bbe 100644 --- a/source/blog/018-feature-watchcontent-arguments-and-color-functions.md +++ b/source/blog/018-feature-watchcontent-arguments-and-color-functions.md @@ -1,5 +1,5 @@ --- -title: 'Feature Watch: Content Arguments and Color Functions' +title: "Feature Watch: Content Arguments and Color Functions" author: Natalie Weizenbaum date: 2018-11-14 14:14:00 -8 --- @@ -8,7 +8,7 @@ Dart Sass 1.15, released today and available [on npm](https://npmjs.com/package/sass) and [all other distribution channels](/install), brings with it a number of highly-anticipated new Sass features. This is also the first release of Dart Sass with major new language -features that _aren't_ just for CSS compatibility. That's a big accomplishment, +features that *aren't* just for CSS compatibility. That's a big accomplishment, and we intend to continue that pattern moving forward! ### `@content` Arguments @@ -27,7 +27,7 @@ mixin. @mixin media($types...) { @each $type in $types { @media #{$type} { - @content ($type); + @content($type); } } } @@ -92,12 +92,11 @@ support for all their definitions to `rgb()` and `hsl()`. All in all, this means that the function calls like all of the following are newly supported in Sass: - -- `rgb(0 255 0)`, `rgb(0% 100% 0%)`, `rgb(0 255 0 / 0.5)`, and `rgb(0, 255, 0, -0.5)`; -- `hsl(0 100% 50%)`, `hsl(0 100% 50% / 0.5)`, and `hsl(0, 100%, 50%, 0.5)`; -- `rgba(0, 255, 0)` and `hsla(0, 100%, 50%)`; -- and `rgb($color, 0.5)`. +* `rgb(0 255 0)`, `rgb(0% 100% 0%)`, `rgb(0 255 0 / 0.5)`, and `rgb(0, 255, 0, + 0.5)`; +* `hsl(0 100% 50%)`, `hsl(0 100% 50% / 0.5)`, and `hsl(0, 100%, 50%, 0.5)`; +* `rgba(0, 255, 0)` and `hsla(0, 100%, 50%)`; +* and `rgb($color, 0.5)`. This change is fully backwards-compatible, so all the arguments to `rgb()`, `hsl()`, `rgba()`, and `hsla()` that previously worked will continue to do so. @@ -117,7 +116,7 @@ This works just how you'd expect: ```scss @mixin viewport($prefixes) { @each $prefix in $prefixes { - @- #{$prefix}-viewport { + @-#{$prefix}-viewport { @content; } } diff --git a/source/blog/019-request-for-comments-module-system-proposal.md b/source/blog/019-request-for-comments-module-system-proposal.md index e9f2401aa..b765906d2 100644 --- a/source/blog/019-request-for-comments-module-system-proposal.md +++ b/source/blog/019-request-for-comments-module-system-proposal.md @@ -1,5 +1,5 @@ --- -title: 'Request For Comments: Module System' +title: "Request For Comments: Module System" author: Natalie Weizenbaum date: 2018-11-27 13:10:00 -8 --- @@ -36,21 +36,21 @@ These are the philosophical design goals for the module system as a whole. While they don't uniquely specify a system, they do represent the underlying motivations behind many of the lower-level design decisions. -- **Locality**. The module system should make it possible to understand a Sass +* **Locality**. The module system should make it possible to understand a Sass file by looking only at that file. An important aspect of this is that names in the file should be resolved based on the contents of the file rather than the global state of the compilation. This also applies to authoring: an author should be able to be confident that a name is safe to use as long as it doesn't conflict with any name visible in the file. -- **Encapsulation**. The module system should allow authors, particularly +* **Encapsulation**. The module system should allow authors, particularly library authors, to choose what API they expose. They should be able to define entities for internal use without making those entities available for external users to access or modify. The organization of a library's implementation into files should be flexible enough to change without changing the user-visible API. -- **Configuration**. Sass is unusual among languages in that its design leads to +* **Configuration**. Sass is unusual among languages in that its design leads to the use of files whose entire purpose is to produce side effects—specifically, to emit CSS. There's also a broader class of libraries that may not emit CSS directly, but do define configuration variables that are used in computations, @@ -63,14 +63,14 @@ These are goals that are based less on philosophy than on practicality. For the most part, they're derived from user feedback that we've collected about `@import` over the years. -- **Import once**. Because `@import` is a literal textual inclusion, multiple +* **Import once**. Because `@import` is a literal textual inclusion, multiple `@import`s of the same Sass file within the scope of a compilation will compile and run that file multiple times. At best this hurts compilation time for little benefit, and it can also contribute to bloated CSS output when the styles themselves are duplicated. The new module system should only compile a file once. -- **Backwards compatibility**. We want to make it as easy as possible for people +* **Backwards compatibility**. We want to make it as easy as possible for people to migrate to the new module system, and that means making it work in conjunction with existing stylesheets that use `@import`. Existing stylesheets that only use `@import` should have identical importing behavior to earlier @@ -83,24 +83,24 @@ These are potential goals that we have explicitly decided to avoid pursuing as part of this proposal for various reasons. Some of them may be on the table for future work, but we don't consider them to be blocking the module system. -- **Dynamic imports**. Allowing the path to a module to be defined dynamically, +* **Dynamic imports**. Allowing the path to a module to be defined dynamically, whether by including variables or including it in a conditional block, moves away from being declarative. In addition to making stylesheets harder to read, this makes any sort of static analysis more difficult (and actually impossible in the general case). It also limits the possibility of future implementation optimizations. -- **Importing multiple files at once**. In addition to the long-standing reason +* **Importing multiple files at once**. In addition to the long-standing reason that this hasn't been supported—that it opens authors up to sneaky and difficult-to-debug ordering bugs—this violates the principle of locality by obfuscating which files are imported and thus where names come from. -- **Extend-only imports**. The idea of importing a file so that the CSS it +* **Extend-only imports**. The idea of importing a file so that the CSS it generates isn't emitted unless it's `@extend`ed is cool, but it's also a lot of extra work. This is the most likely feature to end up in a future release, but it's not central enough to include in the initial module system. -- **Context-independent modules**. It's tempting to try to make the loaded form +* **Context-independent modules**. It's tempting to try to make the loaded form of a module, including the CSS it generates and the resolved values of all its variables, totally independent of the entrypoint that cause it to be loaded. This would make it possible to share loaded modules across multiple @@ -119,7 +119,7 @@ future work, but we don't consider them to be blocking the module system. and potentially even constant-folded variable values and CSS trees. Full context independence isn't likely to provide much value in addition to that. -- **Increased strictness**. Large teams with many people often want stricter +* **Increased strictness**. Large teams with many people often want stricter rules around how Sass stylesheets are written, to enforce best practices and quickly catch mistakes. It's tempting to use a new module system as a lever to push strictness further; for example, we could make it harder to have partials @@ -127,7 +127,7 @@ future work, but we don't consider them to be blocking the module system. people avoid to the new built-in modules. As tempting as it is, though, we want to make all existing use-cases as easy - as possible in the new system, _even if we think they should be avoided_. This + as possible in the new system, *even if we think they should be avoided*. This module system is already a major departure from the existing behavior, and will require a substantial amount of work from Sass users to support. We want to make this transition as easy as possible, and part of that is avoiding @@ -138,7 +138,7 @@ future work, but we don't consider them to be blocking the module system. about increased strictness in the form of lints or TypeScript-style `--strict-*` flags. -- **Code splitting**. The ability to split monolithic CSS into separate chunks +* **Code splitting**. The ability to split monolithic CSS into separate chunks that can be served lazily is important for maintaining quick load times for very large applications. However, it's orthogonal to the problems that this module system is trying to solve. This system is primarily concerned with @@ -166,7 +166,7 @@ accessible in the current stylesheet. By default, variables, mixins, and functions are available in a namespace based on the basename of the URL. ```scss -@use 'bootstrap'; +@use "bootstrap"; .element { @include bootstrap.float-left; @@ -176,16 +176,16 @@ functions are available in a namespace based on the basename of the URL. In addition to namespacing, there are a few important differences between `@use` and `@import`: -- `@use` only executes a stylesheet and includes its CSS once, no matter how +* `@use` only executes a stylesheet and includes its CSS once, no matter how many times that stylesheet is used. -- `@use` only makes names available in the current stylesheet, as opposed to +* `@use` only makes names available in the current stylesheet, as opposed to globally. -- Members whose names begin with `-` or `_` are private to the current +* Members whose names begin with `-` or `_` are private to the current stylesheet with `@use`. -- If a stylesheet includes `@extend`, that extension is only applied to +* If a stylesheet includes `@extend`, that extension is only applied to stylesheets it imports, not stylesheets that import it. -Note that placeholder selectors are _not_ namespaced, but they _do_ respect +Note that placeholder selectors are *not* namespaced, but they *do* respect privacy. #### Controlling Namespaces @@ -194,7 +194,7 @@ Although a `@use` rule's default namespace is determined by the basename of its URL, it can also be set explicitly using `as`. ```scss -@use 'bootstrap' as b; +@use "bootstrap" as b; .element { @include b.float-left; @@ -206,7 +206,7 @@ top-level namespace. Note that if multiple modules expose members with the same name and are used with `as *`, Sass will produce an error. ```scss -@use 'bootstrap' as *; +@use "bootstrap" as *; .element { @include float-left; @@ -231,7 +231,7 @@ p { ``` ```scss -@use 'bootstrap' with ( +@use "bootstrap" with ( $paragraph-margin-bottom: 1.2rem ); ``` @@ -251,9 +251,9 @@ within those files. Unlike `@use`, forward doesn't add any namespaces to names. ```scss // bootstrap.scss -@forward 'functions'; -@forward 'variables'; -@forward 'mixins'; +@forward "functions"; +@forward "variables"; +@forward "mixins"; ``` #### Visibility Controls @@ -261,13 +261,13 @@ within those files. Unlike `@use`, forward doesn't add any namespaces to names. A `@forward` rule can choose to show only specific names: ```scss -@forward 'functions' show color-yiq; +@forward "functions" show color-yiq; ``` It can also hide names that are intended to be library-private: ```scss -@forward 'functions' hide assert-ascending; +@forward "functions" hide assert-ascending; ``` #### Extra Prefixing @@ -278,24 +278,20 @@ which adds a prefix to every member name that's forwarded: ```scss // material/_index.scss -@forward 'theme' as theme-*; +@forward "theme" as theme-*; ``` This way users can use the all-in-one module with well-scoped names for theme variables: ```scss -@use 'material' with ( - $theme-primary: blue -); +@use "material" with ($theme-primary: blue); ``` or they can use the child module with simpler names: ```scss -@use 'material/theme' with ( - $primary: blue -); +@use "material/theme" with ($primary: blue); ``` ### `@import` Compatibility @@ -303,11 +299,11 @@ or they can use the child module with simpler names: The Sass ecosystem won't switch to `@use` overnight, so in the meantime it needs to interoperate well with `@import`. This is supported in both directions: -- When a file that contains `@import`s is `@use`d, everything in its global +* When a file that contains `@import`s is `@use`d, everything in its global namespace is treated as a single module. This module's members are then referred to using its namespace as normal. -- When a file that contains `@use`s is `@import`ed, everything in its public API +* When a file that contains `@use`s is `@import`ed, everything in its public API is added to the importing stylesheet's global scope. This allows a library to control what specific names it exports, even for users who `@import` it rather than `@use` it. @@ -339,7 +335,7 @@ loaded dynamically. ## Frequently Asked Questions -- **Why this privacy model?** We considered a number of models for declaring +* **Why this privacy model?** We considered a number of models for declaring members to be private, including a JS-like model where only members that were explicitly exported from a module were visible and a C#-like model with an explicit `@private` keyword. These models involve a lot more boilerplate, @@ -348,7 +344,7 @@ loaded dynamically. provides a degree of compatibility with conventions libraries are already using. -- **Can I make a member library-private?** There's no language-level notion of a +* **Can I make a member library-private?** There's no language-level notion of a "library", so library-privacy isn't built in either. However, members used by one module aren't automatically visible to downstream modules. If a module isn't [`@forward`ed](#forward) through a library's main stylesheet, it won't @@ -357,15 +353,15 @@ loaded dynamically. stylesheets that aren't intended to be used directly by their users in a directory named `src`. -- **How do I make my library configurable?** If you have a large library made up +* **How do I make my library configurable?** If you have a large library made up of many source files that all share some core `!default`-based configuration, we recommend that you define that configuration in a file that gets forwarded from your library's entrypoint and used by your library's files. For example: ```scss // bootstrap.scss -@forward 'variables'; -@use 'reboot'; +@forward "variables"; +@use "reboot"; ``` ```scss @@ -375,7 +371,7 @@ $paragraph-margin-bottom: 1rem !default; ```scss // _reboot.scss -@use 'variables' as *; +@use "variables" as *; p { margin-top: 0; @@ -385,7 +381,7 @@ p { ```scss // User's stylesheet -@use 'bootstrap' with ( +@use "bootstrap" with ( $paragraph-margin-bottom: 1.2rem ); ``` diff --git a/source/blog/022-request-for-commentsforward-slash-as-separator.md b/source/blog/022-request-for-commentsforward-slash-as-separator.md index 3cbbafe15..d561b6cdf 100644 --- a/source/blog/022-request-for-commentsforward-slash-as-separator.md +++ b/source/blog/022-request-for-commentsforward-slash-as-separator.md @@ -1,5 +1,5 @@ --- -title: 'Request For Comments: Forward Slash as Separator' +title: "Request For Comments: Forward Slash as Separator" author: Natalie Weizenbaum date: 2019-05-06 16:15:00 -8 --- @@ -22,7 +22,7 @@ will likely eventually become untenable. [CSS Grid]: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-row [CSS Color Level 4]: https://drafts.csswg.org/css-color/#rgb-functions -As such, we're planning to redefine `/` to be _only_ a separator. Rather than +As such, we're planning to redefine `/` to be *only* a separator. Rather than creating an unquoted string (as it currently does when at least one operand isn't a number), it will create a list with a new slash separator. For example, `1 / 2 / 3` will be a three-element slash-separated list. Division will instead @@ -37,22 +37,20 @@ This is a major breaking change to existing Sass semantics, so we'll roll it out in a three-stage process: 1. The first stage won't introduce any breaking changes. It will: - - - Add a `divide()` function which will work exactly like the `/` operator + * Add a `divide()` function which will work exactly like the `/` operator does today, except that it will produce deprecation warnings for any non-number arguments. - - Add slash-separated lists to Sass's object models, _without_ a literal + * Add slash-separated lists to Sass's object models, *without* a literal syntax for creating them. That will come later, since it would otherwise be a breaking change. - - Add a `slash-list()` function that will create slash-separated lists. - - Produce deprecation warnings for all `/` operations that are interpreted as + * Add a `slash-list()` function that will create slash-separated lists. + * Produce deprecation warnings for all `/` operations that are interpreted as division. -2. The second stage _will_ be a breaking change. It will: - - - Make `/` exclusively a list separator. - - Make `divide()` throw errors for non-number arguments. - - Deprecate the `slash-list()` function, since it will now be redundant. +2. The second stage *will* be a breaking change. It will: + * Make `/` exclusively a list separator. + * Make `divide()` throw errors for non-number arguments. + * Deprecate the `slash-list()` function, since it will now be redundant. 3. The third stage will just remove the `slash-list()` function. This is not a priority, and will be delayed until the next major version release. diff --git a/source/blog/023-module-system-preview.md b/source/blog/023-module-system-preview.md index abdf7b4f6..2d0f81a27 100644 --- a/source/blog/023-module-system-preview.md +++ b/source/blog/023-module-system-preview.md @@ -30,7 +30,7 @@ $ choco install sass --version 1.23.0.modulebeta-1 $ pub global activate sass 1.23.0-module.beta.1 ``` -Note that 1.23.0 may not _actually_ be the final version number for the stable +Note that 1.23.0 may not *actually* be the final version number for the stable module system release, it's just the next minor version number in Dart Sass's release series. diff --git a/source/blog/024-the-module-system-is-launched.md b/source/blog/024-the-module-system-is-launched.md index 85c37f056..d1161153d 100644 --- a/source/blog/024-the-module-system-is-launched.md +++ b/source/blog/024-the-module-system-is-launched.md @@ -8,25 +8,25 @@ The Sass team has known for years that the `@import` rule, one of the earliest additions to Sass, wasn't as good as we wanted it. It caused a litany of problems for our users: -- It was next to impossible to figure out where a given variable, mixin, or +* It was next to impossible to figure out where a given variable, mixin, or function (collectively called "members") was originally defined, since anything defined in one stylesheet was available to all stylesheets that were imported after it. -- Even if you chose to explicitly import every stylesheet that defined members +* Even if you chose to explicitly import every stylesheet that defined members you used, you'd end up with duplicate CSS and strange side-effects, because stylesheets were reloaded from scratch every time they were imported. -- It wasn't safe to use terse and simple names because there was always a +* It wasn't safe to use terse and simple names because there was always a possibility that some other stylesheet elsewhere in your application would use the same name and mess up your logic. To be safe users had to manually add long, awkward namespaces to everything they defined. -- Library authors had no way to ensure that their private helpers wouldn't be +* Library authors had no way to ensure that their private helpers wouldn't be accessed by downstream users, causing confusion and backwards-compatibility headaches. -- The [`@extend` rule][] could affect any selector anywhere in the stylesheet, +* The [`@extend` rule][] could affect any selector anywhere in the stylesheet, not just those that its author explicitly chose to extend. [`@extend` rule]: /documentation/at-rules/extend @@ -38,7 +38,7 @@ years, we've discussed, designed, and developed a brand-new module system that solves these problems and more, and today we're excited to announce that it's available in Dart Sass 1.23.0. -Please note that the module system is _fully backwards-compatible_. No existing +Please note that the module system is *fully backwards-compatible*. No existing features have been removed or deprecated, and your current Sass stylesheets will keep working just as they always have. We designed the module system to be [fully interoperable with `@import`](#import-compatibility) to make it easy for @@ -56,7 +56,7 @@ in a namespace based on the basename of the URL. [`@use` rule]: /documentation/at-rules/use ```scss -@use 'bootstrap'; +@use "bootstrap"; .element { background-color: bootstrap.$body-bg; @@ -67,15 +67,16 @@ in a namespace based on the basename of the URL. In addition to namespacing, there are a few important differences between `@use` and `@import`: -- `@use` only executes a stylesheet and includes its CSS once, no matter how +* `@use` only executes a stylesheet and includes its CSS once, no matter how many times that stylesheet is used. -- `@use` only makes names available in the current stylesheet, as opposed to globally. -- Members whose names begin with `-` or `_` are private to the current +* `@use` only makes names available in the current stylesheet, as opposed to + globally. +* Members whose names begin with `-` or `_` are private to the current stylesheet with `@use`. -- If a stylesheet includes `@extend`, that extension is only applied to +* If a stylesheet includes `@extend`, that extension is only applied to stylesheets it imports, not stylesheets that import it. -Note that placeholder selectors are _not_ namespaced, but they _do_ respect +Note that placeholder selectors are *not* namespaced, but they *do* respect privacy. ### Controlling Namespaces @@ -84,7 +85,7 @@ Although a `@use` rule's default namespace is determined by the basename of its URL, it can also be set explicitly using `as`. ```scss -@use 'bootstrap' as b; +@use "bootstrap" as b; .element { @include b.float-left; @@ -96,7 +97,7 @@ top-level namespace. Note that if multiple modules expose members with the same name and are used with `as *`, Sass will produce an error. ```scss -@use 'bootstrap' as *; +@use "bootstrap" as *; .element { @include float-left; @@ -121,7 +122,7 @@ p { ``` ```scss -@use 'bootstrap' with ( +@use "bootstrap" with ( $paragraph-margin-bottom: 1.2rem ); ``` @@ -144,9 +145,9 @@ to names. ```scss // bootstrap.scss -@forward 'functions'; -@forward 'variables'; -@forward 'mixins'; +@forward "functions"; +@forward "variables"; +@forward "mixins"; ``` ### Visibility Controls @@ -154,13 +155,13 @@ to names. A `@forward` rule can choose to show only specific names: ```scss -@forward 'functions' show color-yiq; +@forward "functions" show color-yiq; ``` It can also hide names that are intended to be library-private: ```scss -@forward 'functions' hide assert-ascending; +@forward "functions" hide assert-ascending; ``` ### Extra Prefixing @@ -171,24 +172,20 @@ which adds a prefix to every member name that's forwarded: ```scss // material/_index.scss -@forward 'theme' as theme-*; +@forward "theme" as theme-*; ``` This way users can use the all-in-one module with well-scoped names for theme variables: ```scss -@use 'material' with ( - $theme-primary: blue -); +@use "material" with ($theme-primary: blue); ``` or they can use the child module with simpler names: ```scss -@use 'material/theme' with ( - $primary: blue -); +@use "material/theme" with ($primary: blue); ``` ## Built-In Modules @@ -256,11 +253,11 @@ to [interoperate well with `@import`](/documentation/at-rules/import#import-and-modules). This is supported in both directions: -- When a file that contains `@import`s is `@use`d, everything in its global +* When a file that contains `@import`s is `@use`d, everything in its global namespace is treated as a single module. This module's members are then referred to using its namespace as normal. -- When a file that contains `@use`s is `@import`ed, everything in its public API +* When a file that contains `@use`s is `@import`ed, everything in its public API is added to the importing stylesheet's global scope. This allows a library to control what specific names it exports, even for users who `@import` it rather than `@use` it. @@ -351,8 +348,8 @@ support for `@import` on the following timeline: latest), we will drop support for `@import` and most global functions entirely. This 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 diff --git a/source/blog/025-request-for-comments-nested-map-functions.md b/source/blog/025-request-for-comments-nested-map-functions.md index cd0c2545e..fcbc7cc6d 100644 --- a/source/blog/025-request-for-comments-nested-map-functions.md +++ b/source/blog/025-request-for-comments-nested-map-functions.md @@ -1,5 +1,5 @@ --- -title: 'Request for Comments: Nested Map Functions' +title: "Request for Comments: Nested Map Functions" author: Natalie Weizenbaum date: 2020-9-16 14:40:00 -8 --- @@ -37,11 +37,11 @@ For example, let's take the following simplified configuration map: ```scss $config: ( - 'colors': ( - 'primary': red, - 'secondary': blue, - ), -); + "colors": ( + "primary": red, + "secondary": blue + ) +) ``` For this map, `map.get($config, "colors", "primary")` gets the value of the @@ -114,7 +114,7 @@ For example, `map.deep-remove($config, "colors", "secondary")` will return ### `map.deep-merge()` The final new function may be the most exciting. `map.deep-merge($map1, $map2)` -works just like `map.merge()`, except that any nested maps are _also_ merged, +works just like `map.merge()`, except that any nested maps are *also* merged, including maps within those maps and so on. This makes it easy to combine two configuration maps that have the same structure without having to manually merge each level by hand. diff --git a/source/blog/026-request-for-comments-hwb-functions.md b/source/blog/026-request-for-comments-hwb-functions.md index f45de705d..931d8abb6 100644 --- a/source/blog/026-request-for-comments-hwb-functions.md +++ b/source/blog/026-request-for-comments-hwb-functions.md @@ -1,5 +1,5 @@ --- -title: 'Request for Comments: HWB Functions' +title: "Request for Comments: HWB Functions" author: Natalie Weizenbaum date: 2020-10-06 16:00:00 -8 --- @@ -35,7 +35,7 @@ colors use the same sRGB colorspace as all other Sass color values, colors created this way are fully compatible with all existing Sass color functions and will be emitted as their RGB equivalents for maximum browser compatibility. -Note that _unlike_ `rgb()` and `hsl()`, the proposal doesn't add this function +Note that *unlike* `rgb()` and `hsl()`, the proposal doesn't add this function to the global scope yet. This is because Sass has a policy of never adding support for new CSS syntax before at least one browser implements it. Specs have a tendency to change until they're locked in by browsers, and if Sass ends up diff --git a/source/blog/027-libsass-is-deprecated.md b/source/blog/027-libsass-is-deprecated.md index cc3a46078..3fee03213 100644 --- a/source/blog/027-libsass-is-deprecated.md +++ b/source/blog/027-libsass-is-deprecated.md @@ -18,18 +18,18 @@ with the fast pace of language development in both CSS and Sass. I'll go into detail about what this means below, but here are the major points: -- We no longer recommend LibSass for new Sass projects. Use [Dart Sass] instead. +* We no longer recommend LibSass for new Sass projects. Use [Dart Sass] instead. [Dart Sass]: https://sass-lang.com/dart-sass -- We recommend all existing LibSass users make plans to eventually move onto +* We recommend all existing LibSass users make plans to eventually move onto Dart Sass, and that all Sass libraries make plans to eventually drop support for LibSass. -- We're no longer planning to add any new features to LibSass, including +* We're no longer planning to add any new features to LibSass, including compatibility with new CSS features. -- LibSass and Node Sass will continue to be maintained indefinitely on a +* LibSass and Node Sass will continue to be maintained indefinitely on a best-effort basis, including fixing major bugs and security issues and maintaining compatibility with the latest Node versions. @@ -79,10 +79,10 @@ maintenance releases indefinitely. LibSass today has two major benefits over Dart Sass: -- **Portability**: since it's written in C++, it's easy to embed LibSass within +* **Portability**: since it's written in C++, it's easy to embed LibSass within other programming languages and provide a native-feeling API. -- **Performance**: calling out to LibSass via the C++ API is very fast relative +* **Performance**: calling out to LibSass via the C++ API is very fast relative to the speeds of code written directly in scripting languages. In particular, this means LibSass is substantially faster in JavaScript than Dart Sass-compiled-to-JS (although it's comparable to Dart Sass's command-line diff --git a/source/blog/028-request-for-comments-first-class-calc.md b/source/blog/028-request-for-comments-first-class-calc.md index 9e843f7f9..4793064ca 100644 --- a/source/blog/028-request-for-comments-first-class-calc.md +++ b/source/blog/028-request-for-comments-first-class-calc.md @@ -1,5 +1,5 @@ --- -title: 'Request for Comments: First-Class Calc' +title: "Request for Comments: First-Class Calc" author: Natalie Weizenbaum date: 2021-3-15 1:35:00 -8 --- @@ -41,17 +41,17 @@ represents the (simplified) expression that can be resolved in the browser. For example: -- `calc(1px + 10px)` will return the number `11px`. +* `calc(1px + 10px)` will return the number `11px`. -- Similarly, if `$length` is `10px`, `calc(1px + $length)` will return `11px`. +* Similarly, if `$length` is `10px`, `calc(1px + $length)` will return `11px`. -- However, `calc(1px + 10%)` will return the calc `calc(1px + 10%)`. +* However, `calc(1px + 10%)` will return the calc `calc(1px + 10%)`. -- If `$length` is `calc(1px + 10%)`, `calc(1px + $length)` will return +* If `$length` is `calc(1px + 10%)`, `calc(1px + $length)` will return `calc(2px + 10%)`. -- Sass functions can be used directly in `calc()`, so `calc(1% + -math.round(15.3px))` returns `calc(1% + 15px)`. +* Sass functions can be used directly in `calc()`, so `calc(1% + + math.round(15.3px))` returns `calc(1% + 15px)`. Note that calculations cannot generally be used in place of numbers. For example, `1px + calc(1px + 10%)` will produce an error, as will diff --git a/source/blog/029-node-fibers-discontinued.md b/source/blog/029-node-fibers-discontinued.md index 4478d871a..01abce741 100644 --- a/source/blog/029-node-fibers-discontinued.md +++ b/source/blog/029-node-fibers-discontinued.md @@ -1,5 +1,5 @@ --- -title: 'The Discontinuation of node-fibers' +title: "The Discontinuation of node-fibers" author: Natalie Weizenbaum date: 2021-3-26 15:00:00 -8 --- @@ -29,8 +29,8 @@ In order to understand how we got here, it's important to know two pieces of history. First, why does Dart Sass use `node-fibers` in the first place? And second, why is `node-fibers` dying? -_This section is fairly technical, so feel free to [skip ahead] if you don't care -about the gory details._ +*This section is fairly technical, so feel free to [skip ahead] if you don't care +about the gory details.* [skip ahead]: #reclaiming-performance @@ -51,7 +51,7 @@ For Node Sass, the performance difference between `render()` and `renderSync()` was negligible, because it was built on C++ code which had few restrictions on how it handled asynchrony. However, Dart Sass runs as pure JavaScript, which makes it subject to JavaScript's strict async rules. Asynchrony in JavaScript is -_contagious_, which means that if any function (such as an importer plugin) is +*contagious*, which means that if any function (such as an importer plugin) is asynchronous, then everything that calls it must be asynchronous, and so on until the entire program is asynchronous. @@ -101,16 +101,16 @@ plugins, but it will pay dividends immediately. ### Embedded Dart Sass While it's not ready for prime-time yet, the Sass team is working on a project -called "embedded Dart Sass". This involves running Dart Sass as a _subprocess_, +called "embedded Dart Sass". This involves running Dart Sass as a *subprocess*, rather than a library, and communicating with it using a special protocol. This provides several important improvements over the existing alternatives: -- Unlike running `sass` from the command line, this will still work with plugins +* Unlike running `sass` from the command line, this will still work with plugins like the webpack importer. In fact, we plan to match the existing JavaScript - API as closely as possible. This will probably run asynchronous plugins _even - faster_ than synchronous ones. + API as closely as possible. This will probably run asynchronous plugins *even + faster* than synchronous ones. -- Unlike the existing JS-compiled version, this will use the Dart VM. Due to the +* Unlike the existing JS-compiled version, this will use the Dart VM. Due to the more static nature of the Dart language, the Dart VM runs Sass substantially faster than Node.js, which will provide about a 2x speed improvement for large stylesheets. @@ -126,7 +126,7 @@ tires. We've explored the possibility of running the pure-JS Dart Sass in a Node.js worker thread. Worker threads work a bit like fibers in that they make it possible for synchronous code to wait for asynchronous callbacks to run. -Unfortunately, they're also _extremely_ restrictive about what sorts of +Unfortunately, they're also *extremely* restrictive about what sorts of information can be passed across the thread boundary, which makes it much harder to use them to wrap a complex API like Sass's. @@ -141,7 +141,7 @@ up on [the GitHub issue]! There's one other potential solution, although it would take true dedication to turn into reality. It would in principle be possible to add a new API to V8 that -would _officially_ support the hooks `node-fibers` needs to do its good work. +would *officially* support the hooks `node-fibers` needs to do its good work. This would allow the package to return gloriously to life and Sass to make `render()` fast on into the future. @@ -153,7 +153,7 @@ to help an engineer who's willing to give it a shot. This isn't a contribution for the faint of heart, though: it requires knowledge of C++, a willingness to learn at least the basics of the `node-fibers` codebase and V8's isolate APIs, and skills in both API design and human interaction to -negotiate a stable API that will meet the needs of `node-fibers` _and_ that the +negotiate a stable API that will meet the needs of `node-fibers` *and* that the V8 team feels comfortable committing to maintain. But if you're interested, please don't hesitate to [reach out]! diff --git a/source/blog/030-request-for-comments-new-js-api.html.md b/source/blog/030-request-for-comments-new-js-api.md similarity index 87% rename from source/blog/030-request-for-comments-new-js-api.html.md rename to source/blog/030-request-for-comments-new-js-api.md index 83c75ce64..db1dd896a 100644 --- a/source/blog/030-request-for-comments-new-js-api.html.md +++ b/source/blog/030-request-for-comments-new-js-api.md @@ -1,5 +1,5 @@ --- -title: 'Request for Comments: New JS API' +title: "Request for Comments: New JS API" author: Natalie Weizenbaum date: 2021-08-05 15:30:00 -8 --- @@ -12,10 +12,10 @@ years, and it addresses many of the shortcomings of the existing API. The API has four main components, all of which I'll cover in this post: -- [The core compilation API](#compilation) -- [The logger API](#loggers) -- [The importer API](#importers) -- [The function API](#functions) +* [The core compilation API](#compilation) +* [The logger API](#loggers) +* [The importer API](#importers) +* [The function API](#functions) As you read on, remember that this API is still just a proposal. We want to hear from you, our users, whether it meets your needs and how we can improve it @@ -37,18 +37,18 @@ quite difficult: [deprecated]: /blog/libsass-is-deprecated [LibSass]: /libsass -- The importer API was built around file paths rather than URLs, and was tightly - coupled to the physical filesystem. This made it impossible to override _all_ +* The importer API was built around file paths rather than URLs, and was tightly + coupled to the physical filesystem. This made it impossible to override *all* file-based loads and present a fully virtual filesystem, and caused custom Node importers to interact poorly with the new [module system]. -- The function API was built around mutable value objects, which runs counter to +* The function API was built around mutable value objects, which runs counter to Sass's immutable nature. It also provided no utility methods (such as looking up a key in a map) to make it easier to implement idiomatic custom functions, and didn't provide access to crucial information about values such as whether strings were quoted. -- All of the asynchronous functions were callback-based rather than +* All of the asynchronous functions were callback-based rather than promise-based. [module system]: https://sass-lang.com/blog/the-module-system-is-launched @@ -64,21 +64,24 @@ syntax to clarify exactly what they take and return, but you can always call them from plain JS: ```ts -function compile(path: string, options?: Options<'sync'>): CompileResult; +function compile( + path: string, + options?: Options<'sync'> +): CompileResult; function compileString( source: string, - options?: StringOptions<'sync'>, + options?: StringOptions<'sync'> ): CompileResult; function compileAsync( path: string, - options?: Options<'async'>, + options?: Options<'async'> ): Promise; function compileStringAsync( source: string, - options?: StringOptions<'async'>, + options?: StringOptions<'async'> ): Promise; ``` @@ -86,38 +89,38 @@ The `compile()` and `compileAsync()` functions load a Sass file from a path on disk, whereas `compileString()` and `compileStringAsync()` compile Sass source code passed in as a string. All these take the following options: -- `alertAscii`: Whether errors and warnings should use only ASCII characters (as +* `alertAscii`: Whether errors and warnings should use only ASCII characters (as opposed to, for example, Unicode box-drawing characters). -- `alertColor`: Whether errors and warnings should use terminal colors. -- `loadPaths`: A list of file paths to use to look up files to load, just like +* `alertColor`: Whether errors and warnings should use terminal colors. +* `loadPaths`: A list of file paths to use to look up files to load, just like `includePaths` in the old API. -- `importers`: A list of [custom importers](#importers) to use to load Sass +* `importers`: A list of [custom importers](#importers) to use to load Sass source files. -- `functions`: An object whose keys are Sass function signatures and whose +* `functions`: An object whose keys are Sass function signatures and whose values are [custom functions](#functions). -- `quietDeps`: Whether to silence deprecation warnings in dependencies. -- `logger`: The [custom logger](#loggers) to use to emit warnings and debug +* `quietDeps`: Whether to silence deprecation warnings in dependencies. +* `logger`: The [custom logger](#loggers) to use to emit warnings and debug messages. -- `sourceMap`: Whether to generate a source map during compilation. -- `style`: The output style, `'compressed'` or `'expanded'`. -- `verbose`: Whether to emit every deprecation warning encountered. +* `sourceMap`: Whether to generate a source map during compilation. +* `style`: The output style, `'compressed'` or `'expanded'`. +* `verbose`: Whether to emit every deprecation warning encountered. The `compileString()` and `compileStringAsync()` functions take a few additional options: -- `syntax`: The syntax of the file, `'scss'` (the default), `'indented'`, or +* `syntax`: The syntax of the file, `'scss'` (the default), `'indented'`, or `'css'`. -- `url`: The [canonical URL](#canonicalizing) of the file. -- `importer`: The [custom importer](#importers) to treat as the file's source. +* `url`: The [canonical URL](#canonicalizing) of the file. +* `importer`: The [custom importer](#importers) to treat as the file's source. If this is passed, this importer will be used to resolve relative loads from this stylesheet. All these functions return an object with the following fields: -- `css`: The compiled CSS, as a string. -- `loadedUrls`: All the URLs loaded during the compilation, in no particular +* `css`: The compiled CSS, as a string. +* `loadedUrls`: All the URLs loaded during the compilation, in no particular order. -- `sourceMap`: The source map for the file if `sourceMap: true` was passed, as +* `sourceMap`: The source map for the file if `sourceMap: true` was passed, as a decoded object. As with the Node Sass API, the synchronous functions will be substantially @@ -131,7 +134,7 @@ support the `fibers` option for speeding up asynchronous compilation, since [the The logger API gives you more fine-grained control over how and when warnings and debug messages are emitted. Unlike other aspects of this proposal, a -`logger` option will also be added to the _old_ API to allow you to control your +`logger` option will also be added to the *old* API to allow you to control your messages there without needing to upgrade to the new API immediately. A logger implements the following interface: @@ -144,21 +147,24 @@ interface Logger { deprecation: boolean; span?: SourceSpan; stack?: string; - }, + } ): void; - debug?(message: string, options: { span: SourceSpan }): void; + debug?( + message: string, + options: {span: SourceSpan} + ): void; } ``` The `warn` function handles warnings, including both warnings from the compiler itself and from `@warn` rules. It's passed: -- The warning message -- A flag indicating whether it's specifically a deprecation warning -- A span indicating where the warning was located, if it comes from a specific +* The warning message +* A flag indicating whether it's specifically a deprecation warning +* A span indicating where the warning was located, if it comes from a specific location -- The Sass stack trace at the point at which the warning was encountered, if it +* The Sass stack trace at the point at which the warning was encountered, if it was encountered during execution The `debug` function handles only `@debug` rules, and is just passed the message @@ -181,7 +187,10 @@ that _loads_ a canonical URL. // Importers for compileAsync() and compileStringAsync() are the same, except // they may return Promises as well. interface Importer { - canonicalize(url: string, options: { fromImport: boolean }): URL | null; + canonicalize( + url: string, + options: {fromImport: boolean} + ): URL | null; load(canonicalUrl: URL): ImporterResult | null; } @@ -229,18 +238,18 @@ not clear from the document itself whether that refers to a file that exists relative to the stylesheet or to another importer or load path. Here's how the importer API resolves that ambiguity: -- First, the relative URL is resolved relative to the canonical URL of the +* First, the relative URL is resolved relative to the canonical URL of the stylesheet that contained the `@use` (or `@forward` or `@import`). For example, if the canonical URL is `file:///path/to/my/_styles.scss`, then the resolved URL will be `file:///path/to/my/variables`. -- This URL is then passed to the `canonicalize()` method of the importer that +* This URL is then passed to the `canonicalize()` method of the importer that loaded the old stylesheet. (That means it's important for your importers to support absolute URLs!) If the importer recognizes it, it returns the canonical value which is then passed to that importer's `load()`; otherwise, it returns `null`. -- If the old stylesheet's importer didn't recognize the URL, it's passed to all +* If the old stylesheet's importer didn't recognize the URL, it's passed to all the `importers`' canonicalize functions in the order they appear in `options`, then checked for in all the `loadPaths`. If none of those recognizes it, the load fails. @@ -260,9 +269,9 @@ tree (for `@import`). The `load()` method returns an object with the following fields: -- `css`: The text of the loaded stylesheet. -- `syntax`: The syntax of the file: `'scss'`, `'indented'`, or `'css'`. -- `sourceMapUrl`: An optional browser-accessible `URL` to include in source maps +* `css`: The text of the loaded stylesheet. +* `syntax`: The syntax of the file: `'scss'`, `'indented'`, or `'css'`. +* `sourceMapUrl`: An optional browser-accessible `URL` to include in source maps when referring to this file. ### `FileImporter` @@ -276,7 +285,7 @@ physical filesystem easier. It doesn't require the caller to implement interface FileImporter { findFileUrl( url: string, - options: { fromImport: boolean }, + options: {fromImport: boolean} ): FileImporterResult | null; } ``` @@ -284,10 +293,10 @@ interface FileImporter { The `findFileUrl()` method takes a relative URL and returns an object with the following fields: -- `url`: The absolute `file:` URL of the file to load. This URL doesn't need to +* `url`: The absolute `file:` URL of the file to load. This URL doesn't need to be fully canonicalized: the Sass compiler will take care of resolving partials, file extensions, index files, and so on. -- `sourceMapUrl`: An optional browser-accessible `URL` to include in source maps +* `sourceMapUrl`: An optional browser-accessible `URL` to include in source maps when referring to this file. ## Functions @@ -300,8 +309,8 @@ type CustomFunctionCallback = (args: Value[]) => Value; The only differences are: -- Async functions return a `Promise` rather than calling a callback. -- The value types themselves are different. +* Async functions return a `Promise` rather than calling a callback. +* The value types themselves are different. The second point is pretty substantial, though! The new value types are much more fleshed out than the old versions. Let's start with the parent class: @@ -403,27 +412,27 @@ abstract class Value { There are a couple important things to note here: -- Because CSS doesn't have a strong syntactic differentiation between a single +* Because CSS doesn't have a strong syntactic differentiation between a single element and a list containing one element, any Sass value may be treated as though it's a list. The `Value` makes it easy to follow this convention by making the `asList()`, `hasBrackets()`, and `separator()` getters available for every `Value`. -- The list returned this was and the map returned by `asMap()` are immutable +* The list returned this was and the map returned by `asMap()` are immutable types from the [`immutable` package]. This reflects Sass's built-in immutability of all its types. Although these values can't be modified directly, their APIs make it easy and efficient to create new values with changes applied. -- Sass's list-indexing conventions are different than JavaScript's. The +* Sass's list-indexing conventions are different than JavaScript's. The `sassIndexToListIndex()` function makes it easy to convert from Sass index to JS index. -- In Sass, any value may be used in a boolean context, with `false` +* In Sass, any value may be used in a boolean context, with `false` and `null` counting as "falsey" values. The `isTruthy` getter makes this convention easy to follow. -- The `assert*()` functions make it easy to ensure that you're being passed the +* The `assert*()` functions make it easy to ensure that you're being passed the arguments you expect, and to throw an idiomatic error if you're not. They're particularly useful for TypeScript users since they'll automatically narrow the type of the `Value`. @@ -447,7 +456,7 @@ class SassColor extends Value { red: number, green: number, blue: number, - alpha?: number, + alpha?: number ): SassColor; /** Creates an HSL color. */ @@ -455,7 +464,7 @@ class SassColor extends Value { hue: number, saturation: number, lightness: number, - alpha?: number, + alpha?: number ): SassColor; /** Creates an HWB color. */ @@ -463,7 +472,7 @@ class SassColor extends Value { hue: number, whiteness: number, blackness: number, - alpha?: number, + alpha?: number ): SassColor; /** The color's red channel. */ @@ -691,7 +700,7 @@ class SassString extends Value { options?: { /** @default true */ quotes: boolean; - }, + } ); /** Creates an empty string`. */ @@ -736,7 +745,7 @@ class SassList extends Value { separator?: ListSeparator; /** @default false */ brackets?: boolean; - }, + } ); /** Creates an empty Sass list. */ @@ -779,7 +788,10 @@ class SassFunction extends Value { * Creates a Sass function value with the given `signature` that calls * `callback` when it's invoked. */ - constructor(signature: string, callback: CustomFunctionCallback); + constructor( + signature: string, + callback: CustomFunctionCallback + ); } ``` @@ -788,10 +800,10 @@ class SassFunction extends Value { If you want to know more about these proposals and see their most up-to-date forms, they're available on GitHub to view in full: -- [Compile API proposal](https://github.com/sass/sass/tree/main/proposal/new-js-api.d.ts) -- [Logger proposal](https://github.com/sass/sass/blob/main/proposal/js-logger.d.ts) -- [Importer proposal](https://github.com/sass/sass/blob/main/proposal/new-js-importer.d.ts) -- [Functions and values proposal](https://github.com/sass/sass/blob/main/proposal/new-function-and-values-api.d.ts) +* [Compile API proposal](https://github.com/sass/sass/tree/main/proposal/new-js-api.d.ts) +* [Logger proposal](https://github.com/sass/sass/blob/main/proposal/js-logger.d.ts) +* [Importer proposal](https://github.com/sass/sass/blob/main/proposal/new-js-importer.d.ts) +* [Functions and values proposal](https://github.com/sass/sass/blob/main/proposal/new-function-and-values-api.d.ts) We're eager for feedback, so please [let us know what you think]! The proposals in question will be open for at least a month after this blog post goes live, diff --git a/source/blog/031-new-js-api-release-candidate.html.md b/source/blog/031-new-js-api-release-candidate.md similarity index 97% rename from source/blog/031-new-js-api-release-candidate.html.md rename to source/blog/031-new-js-api-release-candidate.md index f54d95fdd..93e05c5ef 100644 --- a/source/blog/031-new-js-api-release-candidate.html.md +++ b/source/blog/031-new-js-api-release-candidate.md @@ -1,5 +1,5 @@ --- -title: 'New JS API Release Candidate is Live' +title: "New JS API Release Candidate is Live" author: Natalie Weizenbaum date: 2021-11-20 16:15:00 -8 --- diff --git a/source/blog/032-embedded-sass-is-live.md b/source/blog/032-embedded-sass-is-live.md index 9edc5a8c3..70afe4f29 100644 --- a/source/blog/032-embedded-sass-is-live.md +++ b/source/blog/032-embedded-sass-is-live.md @@ -1,5 +1,5 @@ --- -title: 'Embedded Sass is Live' +title: "Embedded Sass is Live" author: Natalie Weizenbaum date: 2022-02-01 2:00:00 -8 --- @@ -23,7 +23,7 @@ The `sass-embedded` package fully supports the [new JS API] as well as the [legacy API] other than a few cosmetic options. You can use it as a drop-in replacement for the `sass` package, and it should work with all the same build plugins and libraries. Note that `sass-embedded` is a bit faster in -_asynchronous_ mode than it is in synchronous mode (whereas the `sass` package +*asynchronous* mode than it is in synchronous mode (whereas the `sass` package was faster in synchronous mode). For substantial Sass files, running `sass-embedded` in either mode will generally be much faster than `sass`. diff --git a/source/blog/033-request-for-comments-strict-unary-operators.md b/source/blog/033-request-for-comments-strict-unary-operators.md index 3a7dcbe65..2736aa497 100644 --- a/source/blog/033-request-for-comments-strict-unary-operators.md +++ b/source/blog/033-request-for-comments-strict-unary-operators.md @@ -1,11 +1,11 @@ --- -title: 'Request for Comments: Strict Unary Operators' +title: "Request for Comments: Strict Unary Operators" author: Natalie Weizenbaum date: 2022-06-15 15:30:00 -8 --- Do you know what `margin: $a -$b` does in Sass? If you said "the same thing as -`margin: $a (-$b)`, I'm sorry, but you're wrong. It's _actually_ the same thing +`margin: $a (-$b)`, I'm sorry, but you're wrong. It's *actually* the same thing as `margin: $a - $b`. Don't worry, you're not the first person to get tripped up by this weird corner of Sass's parser! But our new language proposal aims to fix that. @@ -22,15 +22,15 @@ automatically update your stylesheets. **Deprecated:** -- `$a -$b` will no longer be allowed, because it's unclear what the author +* `$a -$b` will no longer be allowed, because it's unclear what the author intended and the current behavior is likely to be incorrect. **Still allowed:** -- `$a - $b` will continue to work, since it's clearly supposed to indicate +* `$a - $b` will continue to work, since it's clearly supposed to indicate subtraction. -- `$a (-$b)` will continue to work, since the parentheses make the unary minus +* `$a (-$b)` will continue to work, since the parentheses make the unary minus unambiguous. The `$a - $b` or `$a (-$b)` options are supported by all widely-used Sass @@ -66,11 +66,11 @@ not to do that for two reasons: behavior of existing syntax than it is to make one that just forbids the syntax entirely. It requires more releases and more different versions of Sass with different behaviors. It also opens the door for a stylesheet that - upgrades many versions at once to switch to the new behavior _without - producing an error_, which could lead to the worst-case scenario: shipping + upgrades many versions at once to switch to the new behavior *without + producing an error*, which could lead to the worst-case scenario: shipping incorrect styles. -2. It's not obvious that `$a -$b` _should_ parse as `$a (-$b)` in every case. +2. It's not obvious that `$a -$b` *should* parse as `$a (-$b)` in every case. Users coming from other programming languages may expect it to parse the same way it does in those languages. Even in Sass, `$a -$b` will continue to be a valid binary operation within `calc()`. It may not be elegant style, but diff --git a/source/blog/034-request-for-comments-color-spaces.md b/source/blog/034-request-for-comments-color-spaces.md index 7152ccf76..2af8696e5 100644 --- a/source/blog/034-request-for-comments-color-spaces.md +++ b/source/blog/034-request-for-comments-color-spaces.md @@ -1,13 +1,13 @@ --- -title: 'Request for Comments: Color Spaces' +title: "Request for Comments: Color Spaces" author: Miriam Suzanne and Natalie Weizenbaum date: 2022-09-21 13:00:00 -8 --- There's been a lot of exciting work in the CSS color specifications lately, and as it begins to land in browsers we've been preparing to add support for it in -Sass as well. The first and largest part of that is adding support for _color -spaces_ to Sass, which represents a huge (but largely backwards-compatible) +Sass as well. The first and largest part of that is adding support for *color +spaces* to Sass, which represents a huge (but largely backwards-compatible) rethinking of the way colors work. Historically, all colors in CSS have existed in the same color space, known as @@ -16,21 +16,21 @@ color name, they represented the same set of visible colors you could tell a screen to display. While this is conceptually simple, there are some major downsides: -- As monitors have improved over time, they've become capable of displaying more +* As monitors have improved over time, they've become capable of displaying more colors than can be represented in the sRGB color space. -- sRGB, even when you're using it via `hsl()`, doesn't correspond very well with +* sRGB, even when you're using it via `hsl()`, doesn't correspond very well with how humans perceive colors. Cyan looks noticeably lighter than purple with the same saturation and lightness values. -- There's no way to represent domain- or device-specific color spaces, such as +* There's no way to represent domain- or device-specific color spaces, such as the [CMYK] color space that's used by printers. [CMYK]: https://en.wikipedia.org/wiki/CMYK_color_model Color spaces solve all of these problems. Now not every color has a red, green, and blue channel (which can be interpreted as hue, saturation, and lightness). -Instead, every color has a specific _color space_ which specifies which +Instead, every color has a specific *color space* which specifies which channels it has. For example, the color `oklch(80% 50% 90deg)` has `oklch` as its color space, `80%` lightness, `50%` chroma, and `90deg` hue. @@ -48,31 +48,31 @@ defines Sassified versions of all the color functions in [CSS Color Level There are several rules of thumb for working with color spaces in Sass: -- The `rgb`, `hsl`, and `hwb` spaces are considered "legacy spaces", and will +* The `rgb`, `hsl`, and `hwb` spaces are considered "legacy spaces", and will often get special handling for the sake of backwards compatibility. Colors defined using hex notation or CSS color names are considered part of the `rgb` color space. Legacy colors are emitted in the most compatible format. This matches CSS's own backwards-compatibility behavior. -- Otherwise, any color defined in a given space will remain in that space, and +* Otherwise, any color defined in a given space will remain in that space, and be emitted in that space. -- Authors can explicitly convert a color's space by using `color.to-space()`. +* Authors can explicitly convert a color's space by using `color.to-space()`. This can be useful to enforce non-legacy behavior, by converting into a non-legacy space, or to ensure the color output is compatible with older browsers by converting colors into a legacy space before emitting. -- The `srgb` color space is equivalent to `rgb`, except that one is a legacy +* The `srgb` color space is equivalent to `rgb`, except that one is a legacy space, and the other is not. They also use different coordinate systems, with `rgb()` accepting a range from 0-255, and `srgb` using a range of 0-1. -- Color functions that allow specifying a color space for manipulation will +* Color functions that allow specifying a color space for manipulation will always use the source color space by default. When an explicit space is provided for manipulation, the resulting color will still be returned in the same space as the origin color. For `color.mix()`, the first color parameter is considered the origin color. -- All legacy and RGB-style spaces represent bounded gamuts of color. Since +* All legacy and RGB-style spaces represent bounded gamuts of color. Since mapping colors into gamut is a lossy process, it should generally be left to browsers, which can map colors as-needed, based on the capabilities of a display. For that reason, out-of-gamut channel values are maintained by Sass @@ -82,7 +82,7 @@ There are several rules of thumb for working with color spaces in Sass: colors as well. Authors can also perform explicit gamut mapping with the `color.to-gamut()` function. -- Legacy browsers require colors in the `srgb` gamut. However, most modern +* Legacy browsers require colors in the `srgb` gamut. However, most modern displays support the wider `display-p3` gamut. ### Standard CSS Color Functions @@ -144,10 +144,10 @@ to the given space. $brand: hsl(0 100% 25.1%); // result: 25.1% -$hsl-lightness: color.channel($brand, 'lightness'); +$hsl-lightness: color.channel($brand, "lightness"); // result: 37.67% -$oklch-lightness: color.channel($brand, 'lightness', $space: oklch); +$oklch-lightness: color.channel($brand, "lightness", $space: oklch); ``` #### `color.space()` @@ -180,10 +180,10 @@ indicates that a channel's value won't affect how a color is displayed. $grey: hsl(0 0% 60%); // result: true, because saturation is 0 -$hue-powerless: color.is-powerless($grey, 'hue'); +$hue-powerless: color.is-powerless($grey, "hue"); // result: false -$hue-powerless: color.is-powerless($grey, 'lightness'); +$hue-powerless: color.is-powerless($grey, "lightness"); ``` #### `color.same()` @@ -238,20 +238,20 @@ A number of existing functions only make sense for legacy colors, and so are being deprecated in favor of color-space-friendly functions like `color.channel()` and `color.adjust()`: -- `color.red()` -- `color.green()` -- `color.blue()` -- `color.hue()` -- `color.saturation()` -- `color.lightness()` -- `color.whiteness()` -- `color.blackness()` -- `adjust-hue()` -- `saturate()` -- `desaturate()` -- `transparentize()`/`fade-out()` -- `opacify()`/`fade-in()` -- `lighten()`/`darken()` +* `color.red()` +* `color.green()` +* `color.blue()` +* `color.hue()` +* `color.saturation()` +* `color.lightness()` +* `color.whiteness()` +* `color.blackness()` +* `adjust-hue()` +* `saturate()` +* `desaturate()` +* `transparentize()`/`fade-out()` +* `opacify()`/`fade-in()` +* `lighten()`/`darken()` ## Let Us Know What You Think! diff --git a/source/blog/035-security-alert-tar-permissions.md b/source/blog/035-security-alert-tar-permissions.md index 9539a2730..37a968fa4 100644 --- a/source/blog/035-security-alert-tar-permissions.md +++ b/source/blog/035-security-alert-tar-permissions.md @@ -1,5 +1,5 @@ --- -title: 'Security Alert: Tar Permissions' +title: "Security Alert: Tar Permissions" author: Natalie Weizenbaum date: 2022-12-09 16:00:00 -8 --- @@ -30,18 +30,18 @@ If you're using the `sass-embedded` package, do the same thing for While we don't expect this issue to be a problem for the vast majority of users, it does affect the following groups: -- Users who downloaded the stand-alone Dart Sass, Dart Sass Embedded, or Sass +* Users who downloaded the stand-alone Dart Sass, Dart Sass Embedded, or Sass Migrator `.tar.gz` archives from the Dart Sass website and extracted them as the Unix root user. -- Users who installed the `sass-embedded` npm package as the Unix root user +* Users who installed the `sass-embedded` npm package as the Unix root user prior to version 1.54.5. -- Users who installed the "non-native" version of the community-maintained +* Users who installed the "non-native" version of the community-maintained `sass-embedded` RubyGems package as the Unix root user prior to version 1.56.2. -- Users on multi-user systems who downloaded the stand-alone Dart Sass, Dart +* Users on multi-user systems who downloaded the stand-alone Dart Sass, Dart Sass Embedded, or Sass Migrator `.tar.gz` archives from the Dart Sass website and explicitly passed the `-p`/`--preserve-permissions` flag when extracting them. @@ -57,7 +57,7 @@ using without needing to upgrade to the latest version. This is a privilege-escalation issue, which means it could allow a hypothetical attacker with access to a low-privilege account on your computer to escalate their access to your account's privileges. However, this also means that it's -not a risk _unless_ an attacker already has access to an account on your +not a risk *unless* an attacker already has access to an account on your machine. ## What went wrong? diff --git a/source/blog/blog.11tydata.yml b/source/blog/blog.11tydata.yml index 91e3bcf8d..1cf6aa325 100644 --- a/source/blog/blog.11tydata.yml +++ b/source/blog/blog.11tydata.yml @@ -1,5 +1,4 @@ layout: blog tags: - blog -# @@@ This should strip the `id` from the slug first -permalink: '/blog/{{ page.fileSlug }}/index.html' +permalink: '/blog/{{ page | getBlogSlug }}/index.html' diff --git a/source/index.liquid b/source/index.liquid index 41631fbed..deecf2e8d 100644 --- a/source/index.liquid +++ b/source/index.liquid @@ -42,6 +42,9 @@ eleventyComputed:

    - Glasses + Glasses

    From ab5d1654dd6a7d2b798c7061f8ae141978ead65f Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Thu, 9 Mar 2023 17:32:49 -0500 Subject: [PATCH 37/42] Refactor 11ty helpers --- eleventy.config.js | 52 ++++------------- source/helpers/components.ts | 34 ----------- .../helpers/{ => components}/codeExample.ts | 2 +- .../helpers/{ => components}/compatibility.ts | 2 +- source/helpers/components/index.ts | 57 +++++++++++++++++++ source/helpers/dates.ts | 8 +++ source/helpers/{page.ts => pages.ts} | 8 +++ source/helpers/type.ts | 18 ++++++ 8 files changed, 104 insertions(+), 77 deletions(-) delete mode 100644 source/helpers/components.ts rename source/helpers/{ => components}/codeExample.ts (98%) rename source/helpers/{ => components}/compatibility.ts (97%) create mode 100644 source/helpers/components/index.ts rename source/helpers/{page.ts => pages.ts} (54%) diff --git a/eleventy.config.js b/eleventy.config.js index ce4791078..771c3dc26 100644 --- a/eleventy.config.js +++ b/eleventy.config.js @@ -4,13 +4,12 @@ const { EleventyRenderPlugin } = require('@11ty/eleventy'); const syntaxHighlight = require('@11ty/eleventy-plugin-syntaxhighlight'); const yaml = require('js-yaml'); -const codeExample = require('./source/helpers/codeExample.ts').default; -const compatibility = require('./source/helpers/compatibility.ts'); -const components = require('./source/helpers/components.ts'); -const dates = require('./source/helpers/dates.ts'); +const componentsPlugin = + require('./source/helpers/components/index.ts').default; +const datesPlugin = require('./source/helpers/dates.ts').default; const { liquidEngine, markdownEngine } = require('./source/helpers/engines.ts'); -const page = require('./source/helpers/page.ts'); -const type = require('./source/helpers/type.ts'); +const pagesPlugin = require('./source/helpers/pages.ts').default; +const typePlugin = require('./source/helpers/type.ts').default; /** @param {import('@11ty/eleventy').UserConfig} eleventyConfig */ module.exports = (eleventyConfig) => { @@ -27,42 +26,13 @@ module.exports = (eleventyConfig) => { yaml.load(contents), ); - // Components - eleventyConfig.addPairedLiquidShortcode('code', components.codeBlock); - eleventyConfig.addPairedLiquidShortcode('codeExample', codeExample); - // Ideally this could be used with named args, but that's not supported yet in - // 11ty's implementation of LiquidJS: - // https://github.com/11ty/eleventy/issues/2679 - // In the meantime, the args are: `dart`, `libsass`, `ruby`, `feature` - eleventyConfig.addPairedLiquidShortcode( - 'compatibility', - compatibility.compatibility, - ); - eleventyConfig.addPairedLiquidShortcode('funFact', components.funFact); - eleventyConfig.addLiquidFilter('implStatus', compatibility.implStatus); - - // Type - eleventyConfig.addLiquidShortcode('lorem', type.getLorem); - eleventyConfig.addPairedLiquidShortcode('markdown', type.markdown); - eleventyConfig.addLiquidFilter('markdown', type.markdown); - eleventyConfig.addPairedLiquidShortcode( - 'markdownInline', - type.markdownInline, - ); - eleventyConfig.addLiquidFilter('markdownInline', type.markdownInline); - eleventyConfig.addPairedLiquidShortcode('typogr', type.typogr); - eleventyConfig.addLiquidFilter('typogr', type.typogr); - - // Dates - eleventyConfig.addLiquidFilter( - 'formatDistanceToNow', - dates.formatDistanceToNow, - ); - - // Page - eleventyConfig.addLiquidFilter('isTypedoc', page.isTypedoc); + // register filters and shortcodes + eleventyConfig.addPlugin(componentsPlugin); + eleventyConfig.addPlugin(datesPlugin); + eleventyConfig.addPlugin(pagesPlugin); + eleventyConfig.addPlugin(typePlugin); - // plugins + // other plugins eleventyConfig.addPlugin(EleventyRenderPlugin); eleventyConfig.addPlugin(syntaxHighlight); diff --git a/source/helpers/components.ts b/source/helpers/components.ts deleted file mode 100644 index 6f26b490f..000000000 --- a/source/helpers/components.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { highlight, languages } from 'prismjs'; -import PrismLoader from 'prismjs/components/index'; - -import { liquidEngine } from './engines'; - -/** - * Returns HTML for a fun fact that's not directly relevant to the main - * documentation. - */ -export const funFact = async (contents: string) => - liquidEngine.renderFile('fun_fact', { - contents, - }); - -/** - * Returns HTML for a code block with syntax highlighting via [Prism][]. - * - * This should be equivalent to the [11ty `{% highlight %}` tag][hl-tag], except - * this tag can wrap dynamic content (partials, variables, etc), while the 11ty - * tag only wraps plain text. - * - * [Prism]: https://prismjs.com/ - * [hl-tag]: https://www.11ty.dev/docs/plugins/syntaxhighlight/#usage - * - * @see https://prismjs.com/ - */ -export const codeBlock = (contents: string, language: string) => { - if (!languages[language]) { - PrismLoader(language); - } - const html = highlight(contents, languages[language], language); - const attr = `language-${language}`; - return `
    ${html}
    `; -}; diff --git a/source/helpers/codeExample.ts b/source/helpers/components/codeExample.ts similarity index 98% rename from source/helpers/codeExample.ts rename to source/helpers/components/codeExample.ts index 1097ab14f..57cfe35b4 100644 --- a/source/helpers/codeExample.ts +++ b/source/helpers/components/codeExample.ts @@ -1,6 +1,6 @@ import sass from 'sass'; -import { liquidEngine } from './engines'; +import { liquidEngine } from '../engines'; /** * Renders a code example. diff --git a/source/helpers/compatibility.ts b/source/helpers/components/compatibility.ts similarity index 97% rename from source/helpers/compatibility.ts rename to source/helpers/components/compatibility.ts index 5db58edc6..f0d92bb7b 100644 --- a/source/helpers/compatibility.ts +++ b/source/helpers/components/compatibility.ts @@ -1,4 +1,4 @@ -import { liquidEngine } from './engines'; +import { liquidEngine } from '../engines'; /** * Renders a status dashboard for each implementation's support for a feature. diff --git a/source/helpers/components/index.ts b/source/helpers/components/index.ts new file mode 100644 index 000000000..9b073a7fe --- /dev/null +++ b/source/helpers/components/index.ts @@ -0,0 +1,57 @@ +import { highlight, languages } from 'prismjs'; +import PrismLoader from 'prismjs/components/index'; + +import { liquidEngine } from '../engines'; +import { default as codeExample } from './codeExample'; +import { compatibility, implStatus } from './compatibility'; + +export { codeExample }; +export { compatibility, implStatus }; + +/** + * Returns HTML for a fun fact that's not directly relevant to the main + * documentation. + */ +export const funFact = async (contents: string) => + liquidEngine.renderFile('fun_fact', { + contents, + }); + +/** + * Returns HTML for a code block with syntax highlighting via [Prism][]. + * + * This should be equivalent to the [11ty `{% highlight %}` tag][hl-tag], except + * this tag can wrap dynamic content (partials, variables, etc), while the 11ty + * tag only wraps plain text. + * + * [Prism]: https://prismjs.com/ + * [hl-tag]: https://www.11ty.dev/docs/plugins/syntaxhighlight/#usage + * + * @see https://prismjs.com/ + */ +export const codeBlock = (contents: string, language: string) => { + if (!languages[language]) { + PrismLoader(language); + } + const html = highlight(contents, languages[language], language); + const attr = `language-${language}`; + return `
    ${html}
    `; +}; + +/* eslint-disable @typescript-eslint/no-unsafe-member-access, + @typescript-eslint/no-unsafe-call, + @typescript-eslint/no-explicit-any */ +export default function componentsPlugin(eleventyConfig: any) { + // filters... + eleventyConfig.addLiquidFilter('implStatus', implStatus); + + // paired shortcodes... + eleventyConfig.addPairedLiquidShortcode('code', codeBlock); + eleventyConfig.addPairedLiquidShortcode('codeExample', codeExample); + // Ideally this could be used with named args, but that's not supported yet in + // 11ty's implementation of LiquidJS: + // https://github.com/11ty/eleventy/issues/2679 + // In the meantime, the args are: `dart`, `libsass`, `ruby`, `feature` + eleventyConfig.addPairedLiquidShortcode('compatibility', compatibility); + eleventyConfig.addPairedLiquidShortcode('funFact', funFact); +} diff --git a/source/helpers/dates.ts b/source/helpers/dates.ts index 25cb36143..314b774fb 100644 --- a/source/helpers/dates.ts +++ b/source/helpers/dates.ts @@ -7,3 +7,11 @@ import formatDistanceToNowBase from 'date-fns/formatDistanceToNow'; */ export const formatDistanceToNow = (date: string) => formatDistanceToNowBase(new Date(date)); + +/* eslint-disable @typescript-eslint/no-unsafe-member-access, + @typescript-eslint/no-unsafe-call, + @typescript-eslint/no-explicit-any */ +export default function datesPlugin(eleventyConfig: any) { + // filters... + eleventyConfig.addLiquidFilter('formatDistanceToNow', formatDistanceToNow); +} diff --git a/source/helpers/page.ts b/source/helpers/pages.ts similarity index 54% rename from source/helpers/page.ts rename to source/helpers/pages.ts index ccd60163f..9c4c5e4fb 100644 --- a/source/helpers/page.ts +++ b/source/helpers/pages.ts @@ -13,3 +13,11 @@ interface Page { */ export const isTypedoc = (page: Page) => page.url ? page.url.startsWith('/documentation/js-api/') : false; + +/* eslint-disable @typescript-eslint/no-unsafe-member-access, + @typescript-eslint/no-unsafe-call, + @typescript-eslint/no-explicit-any */ +export default function pagesPlugin(eleventyConfig: any) { + // filters... + eleventyConfig.addLiquidFilter('isTypedoc', isTypedoc); +} diff --git a/source/helpers/type.ts b/source/helpers/type.ts index a154ea43d..bdd84c52e 100644 --- a/source/helpers/type.ts +++ b/source/helpers/type.ts @@ -43,3 +43,21 @@ export const markdownInline = (content: string) => * @see https://github.com/ekalinin/typogr.js */ export const typogr = (content: string) => typogrify(content); + +/* eslint-disable @typescript-eslint/no-unsafe-member-access, + @typescript-eslint/no-unsafe-call, + @typescript-eslint/no-explicit-any */ +export default function typePlugin(eleventyConfig: any) { + // filters... + eleventyConfig.addLiquidFilter('markdown', markdown); + eleventyConfig.addLiquidFilter('markdownInline', markdownInline); + eleventyConfig.addLiquidFilter('typogr', typogr); + + // shortcodes... + eleventyConfig.addLiquidShortcode('lorem', getLorem); + + // paired shortcodes... + eleventyConfig.addPairedLiquidShortcode('markdown', markdown); + eleventyConfig.addPairedLiquidShortcode('markdownInline', markdownInline); + eleventyConfig.addPairedLiquidShortcode('typogr', typogr); +} From 525f3beda2ecbf7d1668898e0c5ffc5c0a0df010 Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Fri, 10 Mar 2023 16:18:02 -0500 Subject: [PATCH 38/42] Add padding to code examples to ensure same height. --- .../code_examples/code_example.liquid | 6 +- source/_includes/code_examples/panel.liquid | 3 +- source/helpers/components/codeExample.ts | 127 ++++++++++++++++++ source/helpers/components/index.ts | 9 +- 4 files changed, 139 insertions(+), 6 deletions(-) diff --git a/source/_includes/code_examples/code_example.liquid b/source/_includes/code_examples/code_example.liquid index 1c27fe02f..3188b3193 100644 --- a/source/_includes/code_examples/code_example.liquid +++ b/source/_includes/code_examples/code_example.liquid @@ -15,13 +15,13 @@ {% endif %} {% if code.scss.size %} - {% render 'code_examples/panel', name: 'SCSS Syntax', syntax: 'scss', id: exampleName, examples: code.scss, enabled: true %} + {% render 'code_examples/panel', name: 'SCSS Syntax', syntax: 'scss', id: exampleName, examples: code.scss, paddings: code.scssPaddings, enabled: true %} {% endif %} {% if code.sass.size %} {% assign enabled = code.scss.size == 0 %} - {% render 'code_examples/panel', name: 'Sass Syntax', syntax: 'sass', id: exampleName, examples: code.sass, enabled: enabled %} + {% render 'code_examples/panel', name: 'Sass Syntax', syntax: 'sass', id: exampleName, examples: code.sass, paddings: code.sassPaddings, enabled: enabled %} {% endif %} {% if code.css.size %} - {% render 'code_examples/panel', name: 'CSS Output', syntax: 'css', id: exampleName, examples: code.css, enabled: false %} + {% render 'code_examples/panel', name: 'CSS Output', syntax: 'css', id: exampleName, examples: code.css, paddings: code.cssPaddings, enabled: false %} {% endif %}
    diff --git a/source/_includes/code_examples/panel.liquid b/source/_includes/code_examples/panel.liquid index d0647fa75..c2a165cae 100644 --- a/source/_includes/code_examples/panel.liquid +++ b/source/_includes/code_examples/panel.liquid @@ -4,6 +4,7 @@ >

    {{ name }}

    {% for example in examples %} - {% code syntax %}{{ example | strip }}{% endcode %} + {% assign padding = paddings[forloop.index0] | default: 0 %} + {% code syntax, padding %}{{ example | strip }}{% endcode %} {% endfor %}
    diff --git a/source/helpers/components/codeExample.ts b/source/helpers/components/codeExample.ts index 57cfe35b4..ddb520742 100644 --- a/source/helpers/components/codeExample.ts +++ b/source/helpers/components/codeExample.ts @@ -104,6 +104,12 @@ const generateCodeExample = ( const cssExamples = cssContents?.split('\n---\n').map((str) => str.trim()) ?? []; + const { scssPaddings, sassPaddings, cssPaddings } = getPaddings( + scssExamples, + sassExamples, + cssExamples, + ); + const { canSplit, maxSourceWidth, maxCSSWidth } = getCanSplit( scssExamples, sassExamples, @@ -123,11 +129,132 @@ const generateCodeExample = ( scss: scssExamples, sass: sassExamples, css: cssExamples, + scssPaddings, + sassPaddings, + cssPaddings, canSplit, splitLocation, }; }; +/** + * Calculate the lines of padding to add to the bottom of each section so + * that it lines up with the same section in the other syntax. + */ +const getPaddings = ( + scssExamples: string[], + sassExamples: string[], + cssExamples: string[], +) => { + const scssPaddings: number[] = []; + const sassPaddings: number[] = []; + const cssPaddings: number[] = []; + const maxSections = Math.max( + scssExamples.length, + sassExamples.length, + cssExamples.length, + ); + Array.from({ length: maxSections }).forEach((_, i) => { + const scssLines = (scssExamples[i] || '').split('\n').length; + const sassLines = (sassExamples[i] || '').split('\n').length; + const cssLines = (cssExamples[i] || '').split('\n').length; + + // Whether the current section is the last section for the given syntax. + const isLastScssSection = i === scssExamples.length - 1; + const isLastSassSection = i === sassExamples.length - 1; + const isLastCssSection = i === cssExamples.length - 1; + + // The maximum lines for any syntax in this section, ignoring syntaxes for + // which this is the last section. + const maxLines = Math.max( + isLastScssSection ? 0 : scssLines, + isLastSassSection ? 0 : sassLines, + isLastCssSection ? 0 : cssLines, + ); + + scssPaddings.push( + getPadding({ + isLastSection: isLastScssSection, + comparisonA: sassExamples.slice(i), + comparisonB: cssExamples.slice(i), + lines: scssLines, + maxLines, + }), + ); + + sassPaddings.push( + getPadding({ + isLastSection: isLastSassSection, + comparisonA: scssExamples.slice(i), + comparisonB: cssExamples.slice(i), + lines: sassLines, + maxLines, + }), + ); + + cssPaddings.push( + getPadding({ + isLastSection: isLastCssSection, + comparisonA: scssExamples.slice(i), + comparisonB: sassExamples.slice(i), + lines: cssLines, + maxLines, + }), + ); + }); + + return { scssPaddings, sassPaddings, cssPaddings }; +}; + +/** + * Make sure the last section has as much padding as all the rest of + * the other syntaxes' sections. + */ +const getPadding = ({ + isLastSection, + comparisonA, + comparisonB, + lines, + maxLines, +}: { + isLastSection: boolean; + comparisonA: string[]; + comparisonB: string[]; + lines: number; + maxLines: number; +}) => { + let padding = 0; + if (isLastSection) { + padding = getTotalPadding(comparisonA, comparisonB) - lines - 2; + } else if (maxLines > lines) { + padding = maxLines - lines; + } + return Math.max(padding, 0); +}; + +/** + * Returns the number of lines of padding that's needed to match the height of + * the `
    `s generated for `sections1` and `sections2`.
    + */
    +const getTotalPadding = (sections1: string[], sections2: string[]) => {
    +  sections1 ||= [];
    +  sections2 ||= [];
    +  return Array.from({
    +    length: Math.max(sections1.length, sections2.length),
    +  }).reduce((sum: number, _, i) => {
    +    // Add 2 lines to each additional section: 1 for the extra padding, and 1
    +    // for the extra margin.
    +    return (
    +      sum +
    +      Math.max(
    +        (sections1[i] || '').split('\n').length,
    +        (sections2[i] || '').split('\n').length,
    +      ) +
    +      2
    +    );
    +  }, 0);
    +};
    +
     const getCanSplit = (
       scssExamples: string[],
       sassExamples: string[],
    diff --git a/source/helpers/components/index.ts b/source/helpers/components/index.ts
    index 9b073a7fe..42362fd88 100644
    --- a/source/helpers/components/index.ts
    +++ b/source/helpers/components/index.ts
    @@ -29,11 +29,16 @@ export const funFact = async (contents: string) =>
      *
      * @see https://prismjs.com/
      */
    -export const codeBlock = (contents: string, language: string) => {
    +export const codeBlock = (
    +  contents: string,
    +  language: string,
    +  padding = 0,
    +) => {
       if (!languages[language]) {
         PrismLoader(language);
       }
    -  const html = highlight(contents, languages[language], language);
    +  const code = `${contents}${'\n'.repeat(padding + 1)}`;
    +  const html = highlight(code, languages[language], language);
       const attr = `language-${language}`;
       return `
    ${html}
    `; }; From 629838b4e4a9d093455ac23ffd33f38718a3d7b3 Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Fri, 10 Mar 2023 16:20:13 -0500 Subject: [PATCH 39/42] lint --- source/helpers/components/index.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/source/helpers/components/index.ts b/source/helpers/components/index.ts index 42362fd88..7a2b148b0 100644 --- a/source/helpers/components/index.ts +++ b/source/helpers/components/index.ts @@ -29,11 +29,7 @@ export const funFact = async (contents: string) => * * @see https://prismjs.com/ */ -export const codeBlock = ( - contents: string, - language: string, - padding = 0, -) => { +export const codeBlock = (contents: string, language: string, padding = 0) => { if (!languages[language]) { PrismLoader(language); } From 6930ad1022808f36ab2f56b27f6ff85180b7f1d1 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 13 Mar 2023 08:06:33 +0000 Subject: [PATCH 40/42] chore(deps): Automated dependency upgrades --- package.json | 14 +- yarn.lock | 366 ++++++++++++++++++++++++++++++--------------------- 2 files changed, 220 insertions(+), 160 deletions(-) diff --git a/package.json b/package.json index 4b2c8633e..6d5f1369f 100644 --- a/package.json +++ b/package.json @@ -52,16 +52,16 @@ "@types/jquery": "^3.5.16", "@types/jqueryui": "^1.12.16", "@types/node": "^16", - "@typescript-eslint/eslint-plugin": "^5.54.0", - "@typescript-eslint/parser": "^5.54.0", + "@typescript-eslint/eslint-plugin": "^5.54.1", + "@typescript-eslint/parser": "^5.54.1", "date-fns": "^2.29.3", "deep-equal": "^2.2.0", - "eslint": "^8.35.0", - "eslint-config-prettier": "^8.6.0", + "eslint": "^8.36.0", + "eslint-config-prettier": "^8.7.0", "eslint-import-resolver-typescript": "^3.5.3", "eslint-plugin-import": "^2.27.5", "eslint-plugin-simple-import-sort": "^10.0.0", - "jquery": "^3.6.3", + "jquery": "^3.6.4", "jquery-ui": "^1.13.2", "js-yaml": "^4.1.0", "kleur": "^4.1.5", @@ -72,8 +72,8 @@ "netlify-plugin-11ty": "^1.3.0", "npm-run-all": "^4.1.5", "prettier": "^2.8.4", - "rollup": "^3.18.0", - "sass": "^1.58.3", + "rollup": "^3.19.1", + "sass": "^1.59.2", "semver-parser": "^4.1.3", "stylelint": "^15.2.0", "stylelint-config-standard-scss": "^7.0.1", diff --git a/yarn.lock b/yarn.lock index ae2eddc0b..3d936ba87 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1433,27 +1433,45 @@ __metadata: languageName: node linkType: hard -"@eslint/eslintrc@npm:^2.0.0": - version: 2.0.0 - resolution: "@eslint/eslintrc@npm:2.0.0" +"@eslint-community/eslint-utils@npm:^4.2.0": + version: 4.2.0 + resolution: "@eslint-community/eslint-utils@npm:4.2.0" + dependencies: + eslint-visitor-keys: ^3.3.0 + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + checksum: 82fdd1cc2a5d169def0e665ec790580ef708e7df9c91f20006595dc90e3bd42ec31c8976a2eeccd336286301a72e937c0ddf3ab4b7377d7014997c36333a7d22 + languageName: node + linkType: hard + +"@eslint-community/regexpp@npm:^4.4.0": + version: 4.4.0 + resolution: "@eslint-community/regexpp@npm:4.4.0" + checksum: 2d127af0c752b80e8a782eacfe996a86925d21de92da3ffc6f9e615e701145e44a62e26bdd88bfac2cd76779c39ba8d9875a91046ec5e7e5f23cb647c247ea6a + languageName: node + linkType: hard + +"@eslint/eslintrc@npm:^2.0.1": + version: 2.0.1 + resolution: "@eslint/eslintrc@npm:2.0.1" dependencies: ajv: ^6.12.4 debug: ^4.3.2 - espree: ^9.4.0 + espree: ^9.5.0 globals: ^13.19.0 ignore: ^5.2.0 import-fresh: ^3.2.1 js-yaml: ^4.1.0 minimatch: ^3.1.2 strip-json-comments: ^3.1.1 - checksum: 31119c8ca06723d80384f18f5c78e0530d8e6306ad36379868650131a8b10dd7cffd7aff79a5deb3a2e9933660823052623d268532bae9538ded53d5b19a69a6 + checksum: 56b9192a687a450db53a7b883daf9f0f447c43b3510189cf88808a7a2467c2a302a42a50f184cc6d5a9faf3d1df890a2ef0fd0d60b751f32a3e9dfea717c6b48 languageName: node linkType: hard -"@eslint/js@npm:8.35.0": - version: 8.35.0 - resolution: "@eslint/js@npm:8.35.0" - checksum: 6687ceff659a6d617e37823f809dc9c4b096535961a81acead27d26b1a51a4cf608a5e59d831ddd57f24f6f8bb99340a4a0e19f9c99b390fbb4b275f51ed5f5e +"@eslint/js@npm:8.36.0": + version: 8.36.0 + resolution: "@eslint/js@npm:8.36.0" + checksum: b7d6b84b823c8c7784be390741196617565527b1f7c0977fde9455bfb57fd88f81c074a03dd878757d2c33fa29f24291e9ecbc1425710f067917324b55e1bf3a languageName: node linkType: hard @@ -1814,9 +1832,9 @@ __metadata: linkType: hard "@types/node@npm:*": - version: 18.14.5 - resolution: "@types/node@npm:18.14.5" - checksum: 415fb0edc132baa9580f1b7a381a3f10b662f5d7a7d11641917fa0961788ccede3272badc414aadc47306e9fc35c5f6c59159ac470b46d3f3a15fb0446224c8c + version: 18.15.1 + resolution: "@types/node@npm:18.15.1" + checksum: c63a40786919ef77c1dd26f60ffb1ed76c8b608fb156942e4d600d4536e06c19d09463a66cd76e6415f90cd281d7a1a4683e7cfd9a6f0927491853c56ffa17bf languageName: node linkType: hard @@ -1855,13 +1873,13 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:^5.54.0": - version: 5.54.0 - resolution: "@typescript-eslint/eslint-plugin@npm:5.54.0" +"@typescript-eslint/eslint-plugin@npm:^5.54.1": + version: 5.54.1 + resolution: "@typescript-eslint/eslint-plugin@npm:5.54.1" dependencies: - "@typescript-eslint/scope-manager": 5.54.0 - "@typescript-eslint/type-utils": 5.54.0 - "@typescript-eslint/utils": 5.54.0 + "@typescript-eslint/scope-manager": 5.54.1 + "@typescript-eslint/type-utils": 5.54.1 + "@typescript-eslint/utils": 5.54.1 debug: ^4.3.4 grapheme-splitter: ^1.0.4 ignore: ^5.2.0 @@ -1875,43 +1893,43 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 4fdb520b8e0f6b9eb878206ddfa4212522f170d1507d7aba8a975159a198efa37af6d2d17982dd560317452d0748f2e2da5dd7347b172bc4446d1c5562ce2e94 + checksum: 76476c08ca0142a9bf6e2381f5cd1c037d86fbafa9c0dded4a97bd3b23b5962dd2c3943bade11b21d674195674f0e36dbf80faa15a1906f5a2ca1f699baf1dd5 languageName: node linkType: hard -"@typescript-eslint/parser@npm:^5.54.0": - version: 5.54.0 - resolution: "@typescript-eslint/parser@npm:5.54.0" +"@typescript-eslint/parser@npm:^5.54.1": + version: 5.54.1 + resolution: "@typescript-eslint/parser@npm:5.54.1" dependencies: - "@typescript-eslint/scope-manager": 5.54.0 - "@typescript-eslint/types": 5.54.0 - "@typescript-eslint/typescript-estree": 5.54.0 + "@typescript-eslint/scope-manager": 5.54.1 + "@typescript-eslint/types": 5.54.1 + "@typescript-eslint/typescript-estree": 5.54.1 debug: ^4.3.4 peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 368d6dd85be42c3f518f0ddeed23ecd1d3c9484a77ae291ee4e08e2703ed379bed613bde014cd8ab2a3e06e85dd8aef201112ae5e3d2a07deba29ae80bb1fe06 + checksum: f466513d306ca926b97c2cec1eebaf2cd15d45bd5633a4358f23ba9a4de1b0ec4630b1c20abc395943934ed1d2ef65f545fd6737c317a7abe579612101e8a83f languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:5.54.0": - version: 5.54.0 - resolution: "@typescript-eslint/scope-manager@npm:5.54.0" +"@typescript-eslint/scope-manager@npm:5.54.1": + version: 5.54.1 + resolution: "@typescript-eslint/scope-manager@npm:5.54.1" dependencies: - "@typescript-eslint/types": 5.54.0 - "@typescript-eslint/visitor-keys": 5.54.0 - checksum: e50f12396de0ddb94aab119bdd5f4769b80dd2c273e137fd25e5811e25114d7a3d3668cdb3c454aca9537e940744881d62a1fed2ec86f07f60533dc7382ae15c + "@typescript-eslint/types": 5.54.1 + "@typescript-eslint/visitor-keys": 5.54.1 + checksum: 9add24cf3a7852634ad0680a827646860ac4698a6ac8aae31e8b781e29f59e84b51f0cdaacffd0747811012647f01b51969d988da9b302ead374ceebffbe204b languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:5.54.0": - version: 5.54.0 - resolution: "@typescript-eslint/type-utils@npm:5.54.0" +"@typescript-eslint/type-utils@npm:5.54.1": + version: 5.54.1 + resolution: "@typescript-eslint/type-utils@npm:5.54.1" dependencies: - "@typescript-eslint/typescript-estree": 5.54.0 - "@typescript-eslint/utils": 5.54.0 + "@typescript-eslint/typescript-estree": 5.54.1 + "@typescript-eslint/utils": 5.54.1 debug: ^4.3.4 tsutils: ^3.21.0 peerDependencies: @@ -1919,23 +1937,23 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 9cb5b52c7277bdf74b9ea3282fc40f41fda90ea4b1d33039044476e43cf05a766b1294e7d45f429594f2776828f7d17729cfa4ea027315f3df883e748ba57514 + checksum: 0073838b782b7f4619775be124ca6643fec43a2d56043eaf3ceb100960a5193f14ac747b28ce17a5c9ac643fdee8abda82a7d905c81521358de7b27a2dcbc9af languageName: node linkType: hard -"@typescript-eslint/types@npm:5.54.0": - version: 5.54.0 - resolution: "@typescript-eslint/types@npm:5.54.0" - checksum: 0f66b1b93078f3afea6dfcd3d4e2f0abea4f60cd0c613c2cf13f85098e5bf786185484c9846ed80b6c4272de2c31a70c5a8aacb91314cf1b6da7dcb8855cb7ac +"@typescript-eslint/types@npm:5.54.1": + version: 5.54.1 + resolution: "@typescript-eslint/types@npm:5.54.1" + checksum: 84a8f725cfa10646af389659e09c510c38d82c65960c7b613f844a264acc0e197471cba03f3e8f4b6411bc35dca28922c8352a7bd44621411c73fd6dd4096da2 languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:5.54.0": - version: 5.54.0 - resolution: "@typescript-eslint/typescript-estree@npm:5.54.0" +"@typescript-eslint/typescript-estree@npm:5.54.1": + version: 5.54.1 + resolution: "@typescript-eslint/typescript-estree@npm:5.54.1" dependencies: - "@typescript-eslint/types": 5.54.0 - "@typescript-eslint/visitor-keys": 5.54.0 + "@typescript-eslint/types": 5.54.1 + "@typescript-eslint/visitor-keys": 5.54.1 debug: ^4.3.4 globby: ^11.1.0 is-glob: ^4.0.3 @@ -1944,35 +1962,35 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 377c75c34c4f95b7ab6218c1d96a6db3ea6ed6727711b6a09354582fe0157861dc1b6fb9e3f7113cd09741f713735d59d5ab5845457f5733a4ebad7470bf600a + checksum: ea42bdb4832fa96fa1121237c9b664ac4506e2836646651e08a8542c8601d78af6c288779707f893ca4c884221829bb7d7b4b43c4a9c3ed959519266d03a139b languageName: node linkType: hard -"@typescript-eslint/utils@npm:5.54.0": - version: 5.54.0 - resolution: "@typescript-eslint/utils@npm:5.54.0" +"@typescript-eslint/utils@npm:5.54.1": + version: 5.54.1 + resolution: "@typescript-eslint/utils@npm:5.54.1" dependencies: "@types/json-schema": ^7.0.9 "@types/semver": ^7.3.12 - "@typescript-eslint/scope-manager": 5.54.0 - "@typescript-eslint/types": 5.54.0 - "@typescript-eslint/typescript-estree": 5.54.0 + "@typescript-eslint/scope-manager": 5.54.1 + "@typescript-eslint/types": 5.54.1 + "@typescript-eslint/typescript-estree": 5.54.1 eslint-scope: ^5.1.1 eslint-utils: ^3.0.0 semver: ^7.3.7 peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: b8f344fc2961c7af530b93e53d5a17b5084cdf550b381082e3fb7f349ef16e718d9eebde1b9fc2d8fc4ecf8d60d334b004359977247554265c1afc87323bed37 + checksum: 8f428ea4d338ce85d55fd0c9ae2b217b323f29f51b7c9f8077fef7001ca21d28b032c5e5165b67ae6057aef69edb0e7a164c3c483703be6f3e4e574248bbc399 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:5.54.0": - version: 5.54.0 - resolution: "@typescript-eslint/visitor-keys@npm:5.54.0" +"@typescript-eslint/visitor-keys@npm:5.54.1": + version: 5.54.1 + resolution: "@typescript-eslint/visitor-keys@npm:5.54.1" dependencies: - "@typescript-eslint/types": 5.54.0 + "@typescript-eslint/types": 5.54.1 eslint-visitor-keys: ^3.3.0 - checksum: 17fc323c09e6272b603cdaec30a99916600fbbb737e1fbc8c1727a487753b4363cea112277fa43e0562bff34bdd1de9ad73ff9433118b1fd469b112fad0313ca + checksum: 3a691abd2a43b86a0c41526d14a2afcc93a2e0512b5f8b9ec43f6029c493870808036eae5ee4fc655d26e1999017c4a4dffb241f47c36c2a1238ec9fbd08719c languageName: node linkType: hard @@ -2153,6 +2171,16 @@ __metadata: languageName: node linkType: hard +"array-buffer-byte-length@npm:^1.0.0": + version: 1.0.0 + resolution: "array-buffer-byte-length@npm:1.0.0" + dependencies: + call-bind: ^1.0.2 + is-array-buffer: ^3.0.1 + checksum: 044e101ce150f4804ad19c51d6c4d4cfa505c5b2577bd179256e4aa3f3f6a0a5e9874c78cd428ee566ac574c8a04d7ce21af9fe52e844abfdccb82b33035a7c3 + languageName: node + linkType: hard + "array-differ@npm:^1.0.0": version: 1.0.0 resolution: "array-differ@npm:1.0.0" @@ -2502,9 +2530,9 @@ __metadata: linkType: hard "caniuse-lite@npm:^1.0.30001449": - version: 1.0.30001460 - resolution: "caniuse-lite@npm:1.0.30001460" - checksum: dad91eb82aa65aecf33ad6a04ad620b9df6f0152020dc6c1874224e8c6f4aa50695f585201b3dfcd2760b3c43326a86c9505cc03af856698fbef67b267ef786f + version: 1.0.30001465 + resolution: "caniuse-lite@npm:1.0.30001465" + checksum: c991ecdfff378a22b268f9b1eb732d003c8ad89db3241a4cdec3b3ec3354aa966a44171cb806c90abe2e3f0573d67dc29a7dce2478b1f070b23747c392244c5d languageName: node linkType: hard @@ -2719,11 +2747,11 @@ __metadata: linkType: hard "core-js-compat@npm:^3.25.1": - version: 3.29.0 - resolution: "core-js-compat@npm:3.29.0" + version: 3.29.1 + resolution: "core-js-compat@npm:3.29.1" dependencies: browserslist: ^4.21.5 - checksum: ca5d370296c15ebd5f961dae6b6a24a153a84937bff58543099b7f1c407e8d5bbafafa7ca27e65baad522ece762d6356e1d6ea9efa99815f6fefd150fac7e8a5 + checksum: 7260f6bbaa98836cda09a3b61aa721149d3ae95040302fb3b27eb153ae9bbddc8dee5249e72004cdc9552532029de4d50a5b2b066c37414421d2929d6091b18f languageName: node linkType: hard @@ -3009,13 +3037,13 @@ __metadata: languageName: node linkType: hard -"dom-serializer@npm:0, dom-serializer@npm:~0.1.0": - version: 0.1.1 - resolution: "dom-serializer@npm:0.1.1" +"dom-serializer@npm:0": + version: 0.2.2 + resolution: "dom-serializer@npm:0.2.2" dependencies: - domelementtype: ^1.3.0 - entities: ^1.1.1 - checksum: 4f6a3eff802273741931cfd3c800fab4e683236eed10628d6605f52538a6bc0ce4770f3ca2ad68a27412c103ae9b6cdaed3c0a8e20d2704192bde497bc875215 + domelementtype: ^2.0.1 + entities: ^2.0.0 + checksum: 376344893e4feccab649a14ca1a46473e9961f40fe62479ea692d4fee4d9df1c00ca8654811a79c1ca7b020096987e1ca4fb4d7f8bae32c1db800a680a0e5d5e languageName: node linkType: hard @@ -3041,6 +3069,16 @@ __metadata: languageName: node linkType: hard +"dom-serializer@npm:~0.1.0": + version: 0.1.1 + resolution: "dom-serializer@npm:0.1.1" + dependencies: + domelementtype: ^1.3.0 + entities: ^1.1.1 + checksum: 4f6a3eff802273741931cfd3c800fab4e683236eed10628d6605f52538a6bc0ce4770f3ca2ad68a27412c103ae9b6cdaed3c0a8e20d2704192bde497bc875215 + languageName: node + linkType: hard + "domelementtype@npm:1, domelementtype@npm:^1.3.0, domelementtype@npm:^1.3.1": version: 1.3.1 resolution: "domelementtype@npm:1.3.1" @@ -3082,7 +3120,7 @@ __metadata: languageName: node linkType: hard -"domutils@npm:1.5.1, domutils@npm:^1.5.1": +"domutils@npm:1.5.1": version: 1.5.1 resolution: "domutils@npm:1.5.1" dependencies: @@ -3092,6 +3130,16 @@ __metadata: languageName: node linkType: hard +"domutils@npm:^1.5.1": + version: 1.7.0 + resolution: "domutils@npm:1.7.0" + dependencies: + dom-serializer: 0 + domelementtype: 1 + checksum: f60a725b1f73c1ae82f4894b691601ecc6ecb68320d87923ac3633137627c7865725af813ae5d188ad3954283853bcf46779eb50304ec5d5354044569fcefd2b + languageName: node + linkType: hard + "domutils@npm:^2.8.0": version: 2.8.0 resolution: "domutils@npm:2.8.0" @@ -3122,20 +3170,20 @@ __metadata: linkType: hard "ejs@npm:^3.1.8": - version: 3.1.8 - resolution: "ejs@npm:3.1.8" + version: 3.1.9 + resolution: "ejs@npm:3.1.9" dependencies: jake: ^10.8.5 bin: ejs: bin/cli.js - checksum: 1d40d198ad52e315ccf37e577bdec06e24eefdc4e3c27aafa47751a03a0c7f0ec4310254c9277a5f14763c3cd4bbacce27497332b2d87c74232b9b1defef8efc + checksum: af6f10eb815885ff8a8cfacc42c6b6cf87daf97a4884f87a30e0c3271fedd85d76a3a297d9c33a70e735b97ee632887f85e32854b9cdd3a2d97edf931519a35f languageName: node linkType: hard "electron-to-chromium@npm:^1.4.284": - version: 1.4.320 - resolution: "electron-to-chromium@npm:1.4.320" - checksum: ea2c02bc286c0471ed7ad9b61225f6561921cf5f24a060cd1c46c2ea9932283ab924f66c370fbe5a229225dc1f747b395c943a0f5a9d058b72f561b1d8225787 + version: 1.4.328 + resolution: "electron-to-chromium@npm:1.4.328" + checksum: 82c1617a77e40ac4ca5011749318a2fee8f8c75f8b517fcff7602219c85fd97a9fab2d5a1353ea10fb7f9c7d18acb90c9ed58c2292256f81e2ffa42ee66c4b0b languageName: node linkType: hard @@ -3235,16 +3283,16 @@ __metadata: linkType: hard "es-abstract@npm:^1.19.0, es-abstract@npm:^1.20.4": - version: 1.21.1 - resolution: "es-abstract@npm:1.21.1" + version: 1.21.2 + resolution: "es-abstract@npm:1.21.2" dependencies: + array-buffer-byte-length: ^1.0.0 available-typed-arrays: ^1.0.5 call-bind: ^1.0.2 es-set-tostringtag: ^2.0.1 es-to-primitive: ^1.2.1 - function-bind: ^1.1.1 function.prototype.name: ^1.1.5 - get-intrinsic: ^1.1.3 + get-intrinsic: ^1.2.0 get-symbol-description: ^1.0.0 globalthis: ^1.0.3 gopd: ^1.0.1 @@ -3252,8 +3300,8 @@ __metadata: has-property-descriptors: ^1.0.0 has-proto: ^1.0.1 has-symbols: ^1.0.3 - internal-slot: ^1.0.4 - is-array-buffer: ^3.0.1 + internal-slot: ^1.0.5 + is-array-buffer: ^3.0.2 is-callable: ^1.2.7 is-negative-zero: ^2.0.2 is-regex: ^1.1.4 @@ -3261,17 +3309,18 @@ __metadata: is-string: ^1.0.7 is-typed-array: ^1.1.10 is-weakref: ^1.0.2 - object-inspect: ^1.12.2 + object-inspect: ^1.12.3 object-keys: ^1.1.1 object.assign: ^4.1.4 regexp.prototype.flags: ^1.4.3 safe-regex-test: ^1.0.0 + string.prototype.trim: ^1.2.7 string.prototype.trimend: ^1.0.6 string.prototype.trimstart: ^1.0.6 typed-array-length: ^1.0.4 unbox-primitive: ^1.0.2 which-typed-array: ^1.1.9 - checksum: 23ff60d42d17a55d150e7bcedbdb065d4077a8b98c436e0e2e1ef4dd532a6d78a56028673de0bd8ed464a43c46ba781c50d9af429b6a17e44dbd14c7d7fb7926 + checksum: 037f55ee5e1cdf2e5edbab5524095a4f97144d95b94ea29e3611b77d852fd8c8a40e7ae7101fa6a759a9b9b1405f188c3c70928f2d3cd88d543a07fc0d5ad41a languageName: node linkType: hard @@ -3358,14 +3407,14 @@ __metadata: languageName: node linkType: hard -"eslint-config-prettier@npm:^8.6.0": - version: 8.6.0 - resolution: "eslint-config-prettier@npm:8.6.0" +"eslint-config-prettier@npm:^8.7.0": + version: 8.7.0 + resolution: "eslint-config-prettier@npm:8.7.0" peerDependencies: eslint: ">=7.0.0" bin: eslint-config-prettier: bin/cli.js - checksum: ff0d0dfc839a556355422293428637e8d35693de58dabf8638bf0b6529131a109d0b2ade77521aa6e54573bb842d7d9d322e465dd73dd61c7590fa3834c3fa81 + checksum: b05bc7f2296ce3e0925c14147849706544870e0382d38af2352d709a6cf8521bdaff2bd8e5021f1780e570775a8ffa1d2bac28b8065d90d43a3f1f98fd26ce52 languageName: node linkType: hard @@ -3489,12 +3538,14 @@ __metadata: languageName: node linkType: hard -"eslint@npm:^8.35.0": - version: 8.35.0 - resolution: "eslint@npm:8.35.0" +"eslint@npm:^8.36.0": + version: 8.36.0 + resolution: "eslint@npm:8.36.0" dependencies: - "@eslint/eslintrc": ^2.0.0 - "@eslint/js": 8.35.0 + "@eslint-community/eslint-utils": ^4.2.0 + "@eslint-community/regexpp": ^4.4.0 + "@eslint/eslintrc": ^2.0.1 + "@eslint/js": 8.36.0 "@humanwhocodes/config-array": ^0.11.8 "@humanwhocodes/module-importer": ^1.0.1 "@nodelib/fs.walk": ^1.2.8 @@ -3505,9 +3556,8 @@ __metadata: doctrine: ^3.0.0 escape-string-regexp: ^4.0.0 eslint-scope: ^7.1.1 - eslint-utils: ^3.0.0 eslint-visitor-keys: ^3.3.0 - espree: ^9.4.0 + espree: ^9.5.0 esquery: ^1.4.2 esutils: ^2.0.2 fast-deep-equal: ^3.1.3 @@ -3529,24 +3579,23 @@ __metadata: minimatch: ^3.1.2 natural-compare: ^1.4.0 optionator: ^0.9.1 - regexpp: ^3.2.0 strip-ansi: ^6.0.1 strip-json-comments: ^3.1.0 text-table: ^0.2.0 bin: eslint: bin/eslint.js - checksum: 6212173691d90b1bc94dd3d640e1f210374b30c3905fc0a15e501cf71c6ca52aa3d80ea7a9a245adaaed26d6019169e01fb6881b3f2885b188d37069c749308c + checksum: e9a961fc3b3de5cff5a1cb2c92eeffaa7e155a715489e30b3e1e76f186bd1255e0481e09564f2094733c0b1dbd3453499fb72ae7c043c83156e11e6d965b2304 languageName: node linkType: hard -"espree@npm:^9.4.0": - version: 9.4.1 - resolution: "espree@npm:9.4.1" +"espree@npm:^9.5.0": + version: 9.5.0 + resolution: "espree@npm:9.5.0" dependencies: acorn: ^8.8.0 acorn-jsx: ^5.3.2 eslint-visitor-keys: ^3.3.0 - checksum: 4d266b0cf81c7dfe69e542c7df0f246e78d29f5b04dda36e514eb4c7af117ee6cfbd3280e560571ed82ff6c9c3f0003c05b82583fc7a94006db7497c4fe4270e + checksum: a7f110aefb6407e0d3237aa635ab3cea87106ae63748dd23c67031afccc640d04c4209fca2daf16e2233c82efb505faead0fb84097478fd9cc6e8f8dd80bf99d languageName: node linkType: hard @@ -4268,9 +4317,9 @@ __metadata: linkType: hard "immutable@npm:^4.0.0": - version: 4.2.4 - resolution: "immutable@npm:4.2.4" - checksum: 3be84eded37b05e65cad57bfba630bc1bf170c498b7472144bc02d2650cc9baef79daf03574a9c2e41d195ebb55a1c12c9b312f41ee324b653927b24ad8bcaa7 + version: 4.3.0 + resolution: "immutable@npm:4.3.0" + checksum: bbd7ea99e2752e053323543d6ff1cc71a4b4614fa6121f321ca766db2bd2092f3f1e0a90784c5431350b7344a4f792fa002eac227062d59b9377b6c09063b58b languageName: node linkType: hard @@ -4336,7 +4385,7 @@ __metadata: languageName: node linkType: hard -"internal-slot@npm:^1.0.4": +"internal-slot@npm:^1.0.4, internal-slot@npm:^1.0.5": version: 1.0.5 resolution: "internal-slot@npm:1.0.5" dependencies: @@ -4381,7 +4430,7 @@ __metadata: languageName: node linkType: hard -"is-array-buffer@npm:^3.0.1": +"is-array-buffer@npm:^3.0.1, is-array-buffer@npm:^3.0.2": version: 3.0.2 resolution: "is-array-buffer@npm:3.0.2" dependencies: @@ -4741,10 +4790,10 @@ __metadata: languageName: node linkType: hard -"jquery@npm:>=1.8.0 <4.0.0, jquery@npm:^3.6.3": - version: 3.6.3 - resolution: "jquery@npm:3.6.3" - checksum: 0fd366bdcaa0c84a7a8751ce20f8192290141913978b5059574426d9b01f4365daa675f95aab3eec94fd794d27b08d32078a2236bef404b8ba78073009988ce6 +"jquery@npm:>=1.8.0 <4.0.0, jquery@npm:^3.6.4": + version: 3.6.4 + resolution: "jquery@npm:3.6.4" + checksum: 8354f7bd0a0424aa714ee1b6b1ef74b410f834eb5c8501682289b358bc151f11677f11188b544f3bb49309d6ec4d15d1a5de175661250c206b06185a252f706f languageName: node linkType: hard @@ -4935,15 +4984,15 @@ __metadata: linkType: hard "linkedom@npm:^0.14.19": - version: 0.14.22 - resolution: "linkedom@npm:0.14.22" + version: 0.14.24 + resolution: "linkedom@npm:0.14.24" dependencies: css-select: ^5.1.0 cssom: ^0.5.0 html-escaper: ^3.0.3 htmlparser2: ^8.0.1 uhyphen: ^0.1.0 - checksum: 56024a50ac69e5a232a0679a52069dfd5cb211147f46b9fe30573464b02703bc88dc89a5362fa445b04c38d9d58029f307797ede5cb55a98c648869e5ce08e8b + checksum: 1204b453f9dee4f682031d7f7c98bbf6992f3349db2340628694c2bdc1d70376da1d71d7f0bd5f865dbed7ea82e136f70a85b8b7e40431348dd144112b37ca2d languageName: node linkType: hard @@ -5474,9 +5523,9 @@ __metadata: linkType: hard "minipass@npm:^4.0.0": - version: 4.2.4 - resolution: "minipass@npm:4.2.4" - checksum: c664f2ae4401408d1e7a6e4f50aca45f87b1b0634bc9261136df5c378e313e77355765f73f59c4a5abcadcdf43d83fcd3eb14e4a7cdcce8e36508e2290345753 + version: 4.2.5 + resolution: "minipass@npm:4.2.5" + checksum: 4f9c19af23a5d4a9e7156feefc9110634b178a8cff8f8271af16ec5ebf7e221725a97429952c856f5b17b30c2065ebd24c81722d90c93d2122611d75b952b48f languageName: node linkType: hard @@ -5770,7 +5819,7 @@ __metadata: languageName: node linkType: hard -"object-inspect@npm:^1.12.2, object-inspect@npm:^1.9.0": +"object-inspect@npm:^1.12.3, object-inspect@npm:^1.9.0": version: 1.12.3 resolution: "object-inspect@npm:1.12.3" checksum: dabfd824d97a5f407e6d5d24810d888859f6be394d8b733a77442b277e0808860555176719c5905e765e3743a7cada6b8b0a3b85e5331c530fd418cc8ae991db @@ -6418,13 +6467,13 @@ __metadata: linkType: hard "readable-stream@npm:^3.1.1, readable-stream@npm:^3.6.0": - version: 3.6.1 - resolution: "readable-stream@npm:3.6.1" + version: 3.6.2 + resolution: "readable-stream@npm:3.6.2" dependencies: inherits: ^2.0.3 string_decoder: ^1.1.1 util-deprecate: ^1.0.1 - checksum: b7ab0508dba3c37277b9e43c0a970ea27635375698859a687f558c3c9393154b6c4f39c3aa5689641de183fffa26771bc1a45878ddde0236ad18fc8fdfde50ea + checksum: bdcbe6c22e846b6af075e32cf8f4751c2576238c5043169a1c221c92ee2878458a816a4ea33f4c67623c0b6827c8a400409bfb3cf0bf3381392d0b1dfb52ac8d languageName: node linkType: hard @@ -6515,8 +6564,8 @@ __metadata: linkType: hard "regexpu-core@npm:^5.3.1": - version: 5.3.1 - resolution: "regexpu-core@npm:5.3.1" + version: 5.3.2 + resolution: "regexpu-core@npm:5.3.2" dependencies: "@babel/regjsgen": ^0.8.0 regenerate: ^1.4.2 @@ -6524,7 +6573,7 @@ __metadata: regjsparser: ^0.9.1 unicode-match-property-ecmascript: ^2.0.0 unicode-match-property-value-ecmascript: ^2.1.0 - checksum: 446fbbb79059afcd64d11ea573276e2df97ee7ad45aa452834d3b2aef7edf7bfe206c310f57f9345d8c95bfedbf9c16a9529f9219a05ae6a6b0d6f0dbe523b33 + checksum: 95bb97088419f5396e07769b7de96f995f58137ad75fac5811fb5fe53737766dfff35d66a0ee66babb1eb55386ef981feaef392f9df6d671f3c124812ba24da2 languageName: node linkType: hard @@ -6622,9 +6671,9 @@ __metadata: languageName: node linkType: hard -"rollup@npm:^3.18.0": - version: 3.18.0 - resolution: "rollup@npm:3.18.0" +"rollup@npm:^3.19.1": + version: 3.19.1 + resolution: "rollup@npm:3.19.1" dependencies: fsevents: ~2.3.2 dependenciesMeta: @@ -6632,7 +6681,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: 0bcd1abb1cc383abdd09b5594de862ecb2f946e950954bb472a370289bdc4499aea8d04477be55ce205450d973d38ad255f0dc6926162500a251d73bf0e60e6f + checksum: f78198c6de224b26650c70b16db156762d1fcceeb375d34fb2c76fc5b23a78f712c3c881d3248e6f277a511589e20d50c247bcf5c7920f1ddc0a43cadf9f0140 languageName: node linkType: hard @@ -6687,16 +6736,16 @@ __metadata: "@types/jquery": ^3.5.16 "@types/jqueryui": ^1.12.16 "@types/node": ^16 - "@typescript-eslint/eslint-plugin": ^5.54.0 - "@typescript-eslint/parser": ^5.54.0 + "@typescript-eslint/eslint-plugin": ^5.54.1 + "@typescript-eslint/parser": ^5.54.1 date-fns: ^2.29.3 deep-equal: ^2.2.0 - eslint: ^8.35.0 - eslint-config-prettier: ^8.6.0 + eslint: ^8.36.0 + eslint-config-prettier: ^8.7.0 eslint-import-resolver-typescript: ^3.5.3 eslint-plugin-import: ^2.27.5 eslint-plugin-simple-import-sort: ^10.0.0 - jquery: ^3.6.3 + jquery: ^3.6.4 jquery-ui: ^1.13.2 js-yaml: ^4.1.0 kleur: ^4.1.5 @@ -6707,8 +6756,8 @@ __metadata: netlify-plugin-11ty: ^1.3.0 npm-run-all: ^4.1.5 prettier: ^2.8.4 - rollup: ^3.18.0 - sass: ^1.58.3 + rollup: ^3.19.1 + sass: ^1.59.2 semver-parser: ^4.1.3 stylelint: ^15.2.0 stylelint-config-standard-scss: ^7.0.1 @@ -6719,16 +6768,16 @@ __metadata: languageName: unknown linkType: soft -"sass@npm:^1.58.3": - version: 1.58.3 - resolution: "sass@npm:1.58.3" +"sass@npm:^1.59.2": + version: 1.59.2 + resolution: "sass@npm:1.59.2" dependencies: chokidar: ">=3.0.0 <4.0.0" immutable: ^4.0.0 source-map-js: ">=0.6.2 <2.0.0" bin: sass: sass.js - checksum: 35a2b98c037ef80fdc93c9b0be846e6ccc7d75596351a37ee79c397e66666d0a754c52c4696e746c0aff32327471e185343ca349e998a58340411adc9d0489a5 + checksum: ab015ac49beb1252373023cc79b687aabd7850a7f450250b2fbe4eb3f64b0aef6759f8c7b33234221788a0e42cdd3999edfb5995218e474123b99cb126773e30 languageName: node linkType: hard @@ -6969,12 +7018,12 @@ __metadata: linkType: hard "spdx-correct@npm:^3.0.0": - version: 3.1.1 - resolution: "spdx-correct@npm:3.1.1" + version: 3.2.0 + resolution: "spdx-correct@npm:3.2.0" dependencies: spdx-expression-parse: ^3.0.0 spdx-license-ids: ^3.0.0 - checksum: 77ce438344a34f9930feffa61be0eddcda5b55fc592906ef75621d4b52c07400a97084d8701557b13f7d2aae0cb64f808431f469e566ef3fe0a3a131dcb775a6 + checksum: e9ae98d22f69c88e7aff5b8778dc01c361ef635580e82d29e5c60a6533cc8f4d820803e67d7432581af0cc4fb49973125076ee3b90df191d153e223c004193b2 languageName: node linkType: hard @@ -6996,9 +7045,9 @@ __metadata: linkType: hard "spdx-license-ids@npm:^3.0.0": - version: 3.0.12 - resolution: "spdx-license-ids@npm:3.0.12" - checksum: 92a4dddce62ce1db6fe54a7a839cf85e06abc308fc83b776a55b44e4f1906f02e7ebd506120847039e976bbbad359ea8bdfafb7925eae5cd7e73255f02e0b7d6 + version: 3.0.13 + resolution: "spdx-license-ids@npm:3.0.13" + checksum: 3469d85c65f3245a279fa11afc250c3dca96e9e847f2f79d57f466940c5bb8495da08a542646086d499b7f24a74b8d0b42f3fc0f95d50ff99af1f599f6360ad7 languageName: node linkType: hard @@ -7065,6 +7114,17 @@ __metadata: languageName: node linkType: hard +"string.prototype.trim@npm:^1.2.7": + version: 1.2.7 + resolution: "string.prototype.trim@npm:1.2.7" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.4 + es-abstract: ^1.20.4 + checksum: 05b7b2d6af63648e70e44c4a8d10d8cc457536df78b55b9d6230918bde75c5987f6b8604438c4c8652eb55e4fc9725d2912789eb4ec457d6995f3495af190c09 + languageName: node + linkType: hard + "string.prototype.trimend@npm:^1.0.6": version: 1.0.6 resolution: "string.prototype.trimend@npm:1.0.6" @@ -7349,8 +7409,8 @@ __metadata: linkType: hard "terser@npm:^5.15.1": - version: 5.16.5 - resolution: "terser@npm:5.16.5" + version: 5.16.6 + resolution: "terser@npm:5.16.6" dependencies: "@jridgewell/source-map": ^0.3.2 acorn: ^8.5.0 @@ -7358,7 +7418,7 @@ __metadata: source-map-support: ~0.5.20 bin: terser: bin/terser - checksum: f2c1a087fac7f4ff04b1b4e79bffc52e2fc0b068b98912bfcc0b341184c284c30c19ed73f76ac92b225b71668f7f8fc586d99a7e50a29cdc1c916cb1265522ec + checksum: f763a7bcc7b98cb2bfc41434f7b92bfe8a701a12c92ea6049377736c8e6de328240d654a20dfe15ce170fd783491b9873fad9f4cd8fee4f6c6fb8ca407859dee languageName: node linkType: hard @@ -7820,8 +7880,8 @@ __metadata: linkType: hard "ws@npm:^8.12.0": - version: 8.12.1 - resolution: "ws@npm:8.12.1" + version: 8.13.0 + resolution: "ws@npm:8.13.0" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ">=5.0.2" @@ -7830,7 +7890,7 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 97301c1c4d838fc81bd413f370f75c12aabe44527b31323b761eab3043a9ecb7e32ffd668548382c9a6a5ad3a1c3a9249608e8338e6b939f2f9540f1e21970b5 + checksum: 53e991bbf928faf5dc6efac9b8eb9ab6497c69feeb94f963d648b7a3530a720b19ec2e0ec037344257e05a4f35bd9ad04d9de6f289615ffb133282031b18c61c languageName: node linkType: hard From ad12e8ac7e30de8c6aafadc89a3ef81a3e91ca24 Mon Sep 17 00:00:00 2001 From: Jonny Gerig Meyer Date: Mon, 13 Mar 2023 16:33:21 -0400 Subject: [PATCH 41/42] Fix margin for multiple stacked code example blocks --- source/assets/sass/components/_sass-syntax-switcher.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/assets/sass/components/_sass-syntax-switcher.scss b/source/assets/sass/components/_sass-syntax-switcher.scss index 94d9dfb69..bf2a99ebb 100644 --- a/source/assets/sass/components/_sass-syntax-switcher.scss +++ b/source/assets/sass/components/_sass-syntax-switcher.scss @@ -110,7 +110,7 @@ // syntax switcher is exactly equal to two lines, so there's no visual jitter // when switching between syntaxes. pre + pre { - margin-top: 22px; + margin-top: 1rem; } } From 6bb1c207a07498b5b3f49f255fef2bf3bdf3ea1c Mon Sep 17 00:00:00 2001 From: Stacy Kvernmo Date: Mon, 13 Mar 2023 17:06:52 -0500 Subject: [PATCH 42/42] define new breakpoints for code tabs --- source/assets/sass/components/_sass-syntax-switcher.scss | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/source/assets/sass/components/_sass-syntax-switcher.scss b/source/assets/sass/components/_sass-syntax-switcher.scss index bf2a99ebb..3f3114da4 100644 --- a/source/assets/sass/components/_sass-syntax-switcher.scss +++ b/source/assets/sass/components/_sass-syntax-switcher.scss @@ -1,4 +1,3 @@ -@use '../functions'; @use '../visual-design/theme'; @use '../visual-design/typography'; @@ -110,7 +109,7 @@ // syntax switcher is exactly equal to two lines, so there's no visual jitter // when switching between syntaxes. pre + pre { - margin-top: 1rem; + margin-top: var(--sl-gutter); } } @@ -233,13 +232,15 @@ html .ui-button.ui-state-disabled:active { } } -@media screen and (min-width: functions.sl-px-to-rem(1500px)) { +// custom breakpoint to make the split tabs work with a double nav column +@media screen and (min-width: 93.75rem) { body.documentation { @include -split-css-tabs; } } -@media screen and (min-width: functions.sl-px-to-rem(1000px)) { +// custom breakpoint to make the split tabs work with a single nav column +@media screen and (min-width: 76rem) { body.guide { @include -split-css-tabs; }