From d07f664450ddaaebb44127a4bd057763d13d3f82 Mon Sep 17 00:00:00 2001 From: Feuerfuchs Date: Sun, 1 Nov 2020 20:55:14 +0100 Subject: Init --- .gitignore | 5 + .npmignore | 6 + .sass-lint.yml | 14 + .vscode/tasks.json | 38 + README.md | 346 +++ jsconfig.json | 6 + package.json | 42 + src/_bem.scss | 62 + src/_contexts.scss | 315 +++ src/_easing.scss | 483 ++++ src/_functions.scss | 328 +++ src/_gradients.scss | 600 +++++ src/_harmony.scss | 94 + src/_math.scss | 62 + src/_props.scss | 281 +++ src/_responsive.scss | 406 ++++ src/_vars.scss | 16 + src/bem-shortcodes.scss | 349 +++ src/bem/_block.scss | 392 +++ src/bem/_debug.scss | 16 + src/bem/_element.scss | 622 +++++ src/bem/_functions.scss | 26 + src/bem/_modifier.scss | 246 ++ src/bem/_multi.scss | 131 + src/bem/_state.scss | 146 ++ src/bem/_suffix.scss | 118 + src/bem/_theme.scss | 61 + src/bem/_validators.scss | 176 ++ src/bem/_vars.scss | 108 + src/harmony-shortcodes.scss | 35 + src/main.scss | 10 + src/prep.scss | 2 + src/responsive-shortcodes.scss | 14 + test/_bem.scss | 19 + test/_contexts.scss | 65 + test/_functions.scss | 103 + test/_gradients.scss | 264 ++ test/_harmony.scss | 249 ++ test/_math.scss | 21 + test/_props.scss | 282 +++ test/_responsive.scss | 9 + test/bem/_examples.scss | 224 ++ test/bem/_iro-bem-at-theme.scss | 55 + test/bem/_iro-bem-block.scss | 85 + test/bem/_iro-bem-composed-of.scss | 149 ++ test/bem/_iro-bem-element.scss | 491 ++++ test/bem/_iro-bem-modifier.scss | 654 +++++ test/bem/_iro-bem-multi.scss | 591 +++++ test/bem/_iro-bem-next-twin-element.scss | 153 ++ test/bem/_iro-bem-related-element.scss | 459 ++++ test/bem/_iro-bem-state.scss | 177 ++ test/bem/_iro-bem-suffix.scss | 94 + test/test.js | 4 + test/test.scss | 16 + yarn.lock | 3842 ++++++++++++++++++++++++++++++ 55 files changed, 13562 insertions(+) create mode 100644 .gitignore create mode 100644 .npmignore create mode 100644 .sass-lint.yml create mode 100644 .vscode/tasks.json create mode 100644 README.md create mode 100644 jsconfig.json create mode 100644 package.json create mode 100644 src/_bem.scss create mode 100644 src/_contexts.scss create mode 100644 src/_easing.scss create mode 100644 src/_functions.scss create mode 100644 src/_gradients.scss create mode 100644 src/_harmony.scss create mode 100644 src/_math.scss create mode 100644 src/_props.scss create mode 100644 src/_responsive.scss create mode 100644 src/_vars.scss create mode 100644 src/bem-shortcodes.scss create mode 100644 src/bem/_block.scss create mode 100644 src/bem/_debug.scss create mode 100644 src/bem/_element.scss create mode 100644 src/bem/_functions.scss create mode 100644 src/bem/_modifier.scss create mode 100644 src/bem/_multi.scss create mode 100644 src/bem/_state.scss create mode 100644 src/bem/_suffix.scss create mode 100644 src/bem/_theme.scss create mode 100644 src/bem/_validators.scss create mode 100644 src/bem/_vars.scss create mode 100644 src/harmony-shortcodes.scss create mode 100644 src/main.scss create mode 100644 src/prep.scss create mode 100644 src/responsive-shortcodes.scss create mode 100644 test/_bem.scss create mode 100644 test/_contexts.scss create mode 100644 test/_functions.scss create mode 100644 test/_gradients.scss create mode 100644 test/_harmony.scss create mode 100644 test/_math.scss create mode 100644 test/_props.scss create mode 100644 test/_responsive.scss create mode 100644 test/bem/_examples.scss create mode 100644 test/bem/_iro-bem-at-theme.scss create mode 100644 test/bem/_iro-bem-block.scss create mode 100644 test/bem/_iro-bem-composed-of.scss create mode 100644 test/bem/_iro-bem-element.scss create mode 100644 test/bem/_iro-bem-modifier.scss create mode 100644 test/bem/_iro-bem-multi.scss create mode 100644 test/bem/_iro-bem-next-twin-element.scss create mode 100644 test/bem/_iro-bem-related-element.scss create mode 100644 test/bem/_iro-bem-state.scss create mode 100644 test/bem/_iro-bem-suffix.scss create mode 100644 test/test.js create mode 100644 test/test.scss create mode 100644 yarn.lock diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dc8af33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +node_modules +sassdoc +.sassdoc +test/**/*.css +yarn-error.log \ No newline at end of file diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..6185438 --- /dev/null +++ b/.npmignore @@ -0,0 +1,6 @@ +node_modules +sassdoc +.sassdoc +.pages +test/**/*.css +yarn-error.log \ No newline at end of file diff --git a/.sass-lint.yml b/.sass-lint.yml new file mode 100644 index 0000000..93f03da --- /dev/null +++ b/.sass-lint.yml @@ -0,0 +1,14 @@ +options: + merge-default-rules: true + formatter: visualstudio +rules: + indentation: + - 1 + - size: 4 + property-sort-order: + - 1 + - order: recess + leading-zero: + - 1 + - include: true + space-around-operator: 0 diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..f6545ad --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,38 @@ +{ + "version": "2.0.0", + "runner": "terminal", + "command": "npm", + "tasks": [ + { + "label": "lint", + "command": "npm", + "args": [ + "run", + "livelint" + ], + "type": "shell", + "isBackground": true, + "problemMatcher": [ + { + "owner": "sass-lint", + "fileLocation": "relative", + "pattern": [ + { + "regexp": "^(.*)\\((\\d+),(\\d+)\\): (info|warning|error) (.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + ], + "background": { + "activeOnStart": false, + "beginsPattern": "^BEGIN LINT", + "endsPattern": "^END LINT" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..62b15cc --- /dev/null +++ b/README.md @@ -0,0 +1,346 @@ +# iro-sass + +iro-sass is a [Sass](http://sass-lang.com/) library that I developed to create websites. + +Its main feature is a **[BEM system](#bem-system)**, though it also includes some other useful features: + +- Easing background gradients +- Context stacks: A temporary data storage +- Property trees]: A persistent data storage +- Responsive properties: A generalization of responsive typography +- Modular scales + +All features are explained in greater detail in the [Wiki](https://git.vulpes.one/Feuerfuchs/iro-sass/wiki). +The rest of this document is a quick overview over what iro-sass has to offer. + +- [iro-sass](#iro-sass) + - [Getting started](#getting-started) + - [Development](#development) + - [Changelog](#changelog) + - [Known issues](#known-issues) + - [Features](#features) + - [BEM system](#bem-system) + - [Easing background gradients](#easing-background-gradients) + - [Context stacks](#context-stacks) + - [Property trees](#property-trees) + - [Responsive properties](#responsive-properties) + - [Modular scales](#modular-scales) + +## Getting started + +Install the package [iro-sass](https://www.npmjs.com/package/iro-sass) from the npm repository using the package manager of your choice. + +- npm: `npm install iro-sass` +- yarn: `yarn add iro-sass` + +Then include iro-sass in your Sass stylesheet: + +```scss +@import 'iro-sass/src/main'; +// (overrides) +// files that depend on iro-sass +``` + +iro-sass uses function, mixin and variable names that are prefixed with 'iro-' to avoid clashes with other libraries. +There are, however, shorter versions of many mixins and functions available (referred to as "shortcodes"). +Just import one of these files to use a certain set of shortcodes: + +- `iro-sass/src/bem-shortcodes`: BEM +- `iro-sass/src/responsive-shortcodes`: Responsive properties +- `iro-sass/src/harmony-shortcodes`: Modular scales + +**Note:** If the 'node_modules' folder isn't a search path for Sass imports, you have to prefix your imports with the path to 'node_modules'. +An import might then look like this: `@import 'node_modules/iro-sass/src/main';` + +## Development + +Clone the repository, then run `npm install` or `yarn` to install all dependencies. + +The following npm scripts are available: + +- `lint`: Lint the source code with [sass-lint](https://www.npmjs.com/package/sass-lint). +- `livelint`: Lint automatically whenever the code changes. +- `doc`: Generate the SassDoc documentation with [sassdoc](http://sassdoc.com/). +- `test`: Run unit tests with [sass-true](https://www.npmjs.com/package/sass-true) and [Mocha](https://mochajs.org/). + +## Changelog + +[Changelog](https://git.vulpes.one/Feuerfuchs/iro-sass/blob/main/CHANGELOG.md) + +## Known issues + +Check out the [issue tracker](https://git.vulpes.one/Feuerfuchs/iro-sass/issues). + +## Features + +### BEM system + +iro-sass' main feature is its BEM system which was developed over the course of two years. Features include: + +- **Full [BEM](https://en.bem.info/) and [BEMIT](https://csswizardry.com/2015/08/bemit-taking-the-bem-naming-convention-a-step-further/) support:** Namespaced blocks, suffixes, states, and so on. +- **Robustness:** Most selector-related operations use Sass' native selector functions instead of manual parsing and assembling. +- **Quality:** All mixins generate optimal selectors with a minimal degree of specificity. +- **Safety:** All mixins perform checks if they are used correctly. +- **Flexibility:** Mix BEM selectors and other selectors however you like — the BEM system will adapt. +- **Strictness:** The BEM system allows you to define rules that control how the BEM mixins may or may not be used. + +Below is a basic example showing how the BEM system can be used: + +```scss +@include iro-bem-object('media') { + display: flex; + align-items: flex-start; + justify-content: flex-start; + + @include iro-bem-element('image') { + display: block; + flex: 0 0 auto; + order: 1; + overflow: hidden; + } + + @include iro-bem-element('body') { + order: 2; + } + + @include iro-bem-modifier('rtl') { + justify-content: flex-end; + + @include iro-bem-element('image') { + order: 2; + } + + @include iro-bem-element('body') { + order: 1; + } + } +} +``` + +The result is this CSS: + +```css +.o-media { + display: flex; + align-items: flex-start; + justify-content: flex-start; +} + +.o-media__image { + display: block; + flex: 0 0 auto; + order: 1; + overflow: hidden; +} + +.o-media__body { + order: 2; +} + +.o-media--rtl { + justify-content: flex-end; +} + +.o-media--rtl .o-media__image { + order: 2; +} + +.o-media--rtl .o-media__body { + order: 1; +} +``` + +### Easing background gradients + +The background gradients generated by browsers usually have a pretty hard transition from one color to another. In some situations, this results in a clearly visible edge where the transition ends. + +[Andreas Larsen wrote an article on CSS-Tricks](https://css-tricks.com/easing-linear-gradients/) where this whole problem is explained in detail. +He also developed a solution, a [PostCSS plugin](https://github.com/larsenwork/postcss-easing-gradients) which automatically converts linear gradients using an easing function into regular linear-gradients. + +This solution works for simple use cases, but unfortunately it wasn't suitable for me. +First, I wanted to use easing radial-gradients as well, which aren't supported by the PostCSS plugin. +And second, I wanted to freely position the color stops and not be locked to 0% for the start and 100% for the end. + +The easing gradients provided by iro-sass address the above problems. +Moreover, they have one more major feature: You can use multiple color stops with varying easing functions. + +The syntax is kept as close to the [new CSSWG proposal](https://github.com/w3c/csswg-drafts/issues/1332) as possible to make the transition to the native easing gradients easier later on. + +Example usage: + +```scss +.test { + background-image: iro-easing-linear-gradient( + to right, + #000 2em, + #f00, + ease-in-out-sine, + transparent 10em + ); +} +``` + +This will generate a linear-gradient where black normally fades into red, from 2em to 6em. +Then, red *smoothly* fades into transparent, from 6em to 10em. +After that, the gradient remains transparent. + +### Context stacks + +Context stacks are a temporary data storage and, as the name suggests, are used like a conventional stack data structure. +This means: Whenever you want to store a context -- which is an identifier and any kind of data, such as a map, a list, a string, etc... -- you push it to the stack. +From then on, this context is publicly accessible. +In order to remove it, you pop the stack. + +This feature becomes extremely useful when paired with mixins and their `@content` directive: Pushing a context to the stack before `@content` and popping the stack afterwards gives it the role of a call stack. +Thats how the BEM system, for example, attaches metadata to the selectors it generates. +These information are used to generate optimal selectors without much parsing. + +Below is an example of how context stacks can be used: + +```scss +$context-id: 'some-context-stack'; + +@mixin anything($p) { + @include iro-context-push($context-id, 'anything', ( + --this: 1, + --is: true, + --the: 'test', + --data: $p + )); + + @content; + + @include iro-context-pop($context-id); +} + +// Usage: + +.test { + @include anything('hello') { + $context-data: nth(iro-context-get($context-id, 'anything'), 2); + $this: map-get($context-data, --this); // 1 + $is: map-get($context-data, --is); // true + $the: map-get($context-data, --the); // 'test' + $data: map-get($context-data, --data); // 'hello' + } +} +``` + +### Property trees + +Property trees are basically global maps that are immutable as long as you just use the intended functions. + +It's a very simple feature, but it makes managing large sets of structured data much easier. + +Example usage: + +```scss +@include iro-props-save(( + --accent: #f00, + --accent-text: #fff, + + --background: #fff, + --text: #222, + + --link: ( + --idle: ( + --text: #000, + --underline: #f00 + ), + --hover: ( + --text: #f00, + --underline: #f00 + ) + ) +), 'light'); + +// Usage: + +p { + color: iro-props-get(--text, 'light'); // #222 + background-color: iro-props-get(--background, 'light'); // #fff +} + +a { + color: iro-props-get(--link --idle --text, 'light'); // #000 + border-bottom: 1px solid iro-props-get(--link --idle --underline, 'light'); // #f00 + text-decoration: none; + + &:hover { + color: iro-props-get(--link --hover --text, 'light'); // #f00 + border-bottom-color: iro-props-get(--link --hover --underline, 'light'); // #f00 + } +} +``` + +### Responsive properties + +Responsive properties allow you to assign values to properties depending on the current viewport width. +iro-sass provides a large number of mixins for this task to cover many use cases. +The most simple one is the following: + +```scss +.title { + @include iro-responsive-property(padding, ( 20rem: 2.1rem, 40rem: 2.6rem, 60rem: 3.5rem )); +} +``` + +The padding will be 2.1rem if the viewport is 20rem wide, 2.6rem if it's 40rem wide, and 3.5rem if it's 60rem wide. +If the viewport is narrower than 20rem, the padding will stick with 2.1rem. +If the viewport is wider than 60rem, the padding will stick with 3.5rem. + +By default, iro-sass will dynamically scale the property value between viewport widths, which is technique known from [fluid typography](https://css-tricks.com/snippets/css/fluid-typography/). +This behavior can be switched off if it's undesired. + +If you use [include-media](https://include-media.com/), all responsive mixins also support named viewports. +The example above could then be written like this: + +```scss +.title { + @include iro-responsive-property(padding, ( phone: 2.1rem, tablet: 2.6rem, desktop: 3.5rem )); +} +``` + +### Modular scales + +From the description of [modularscale-sass](https://github.com/modularscale/modularscale-sass): + +> A modular scale is a list of values that share the same relationship. These values are often used to size type and create a sense of harmony in a design. Proportions within modular scales are all around us from the spacing of the joints on our fingers to branches on trees. These natural proportions have been used since the time of the ancient Greeks in architecture and design and can be a tremendously helpful tool to leverage for web designers. + +iro-sass provides a mixin to create basic and multi-stranded modular scales. +It's a lightweight alternative to modularscale-sass. + +Example with a multi-stranded modular scale: + +```scss +$mod-scale: 1em 2em, 1.1; + +h1 { + font-size: iro-harmony-modular-scale(3, $mod-scale...); // Will be: 1.128em +} +h2 { + font-size: iro-harmony-modular-scale(2, $mod-scale...); // Will be: 1.1em +} +h3 { + font-size: iro-harmony-modular-scale(1, $mod-scale...); // Will be: 1.026em +} +``` + +Combined with iro-sass' responsive properties: + +```scss +$responsive-mod-scale: ( + 320px: (1rem 2rem, 1.1), + 640px: (1rem 2rem, 1.2) +); + +h1 { + @include iro-responsive-modular-scale(font-size, 3, $responsive-mod-scale); +} +h2 { + @include iro-responsive-modular-scale(font-size, 2, $responsive-mod-scale); +} +h3 { + @include iro-responsive-modular-scale(font-size, 1, $responsive-mod-scale); +} +``` diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..e0cc6bb --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "allowSyntheticDefaultImports": true, + "checkJs": true + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..d4eb18b --- /dev/null +++ b/package.json @@ -0,0 +1,42 @@ +{ + "name": "iro-sass", + "version": "1.0.0", + "author": "Feuerfuchs ", + "license": "MIT", + "description": "A mixin-based Sass framework that makes it easier to work with BEM, organize variables and more.", + "main": "src/main.scss", + "keywords": [ + "sass", + "scss", + "library", + "iro", + "bem", + "bemit", + "gradients", + "easing", + "variables" + ], + "repository": { + "type": "git", + "url": "git+https://git.vulpes.one/Feuerfuchs/iro-sass.git" + }, + "bugs": { + "url": "https://git.vulpes.one/Feuerfuchs/iro-sass/issues" + }, + "homepage": "https://git.vulpes.one/Feuerfuchs/iro-sass", + "devDependencies": { + "mocha": "^8.2.0", + "nodemon": "^2.0.6", + "sass": "^1.28.0", + "sass-lint": "^1.12.1", + "sass-true": "^6.0.1", + "sassdoc": "^2.7.3" + }, + "scripts": { + "prepublishOnly": "npm run test", + "lint": "sass-lint '{src,test}/**/*.scss' -q -v || true", + "livelint": "nodemon --watch src --watch test -e scss -x 'echo \"BEGIN LINT\" && npm run lint && echo \"END LINT\"'", + "doc": "sassdoc src", + "test": "mocha test/test.js" + } +} diff --git a/src/_bem.scss b/src/_bem.scss new file mode 100644 index 0000000..b6032ea --- /dev/null +++ b/src/_bem.scss @@ -0,0 +1,62 @@ +//// +/// BEM. +/// +/// BEM is a methodology for structuring websites and is mostly known for it's CSS naming convention. +/// BEMIT is in extension of this methodology and allows you to give blocks a more fine-grained purpose +/// than BEM alone would let you do. +/// +/// Sass does support BEM quite well thanks to the ampersand (&) and the @at-root directive. However, +/// there is no way to make sure users adhere to the BEM or BEMIT methodology. +/// That's where the mixins in this file come into play: They automatically generate the right selectors +/// and perform checks regarding the nesting order, nesting depth, and so on. +/// +/// There are comments in the mixins explaining what selector is generated. The EBNF grammar is as follows: +/// +/// (* Shorthands for block, element, modifier, suffix *) +/// entity_shorthand = "b" "e" "m" "s" "t" ; +/// +/// (* One or multiple BEMIT entities that were generated with an earlier mixin invocation *) +/// existing_entities = "{" entity_shorthand { "," entity_shorthand } "}" ; +/// +/// (* A BEM entity that doesn't depend on a parent entity *) +/// generated_independent_entity = "block" ; +/// +/// (* A BEM entity that is attached to a parent entity *) +/// generated_attached_entity = existing_entities ( "__element" | "--modifier" | "@suffix" ) ; +/// +/// (* A selector created by the user, such as "&:hover", "> a", and so on *) +/// manual_selector_part = "[manual selector]" ; +/// +/// (* A part of the selector that may or may not be in the generated result *) +/// optional_selector_part = "(" ( existing_entities | manual_selector_part ) ")" ; +/// +/// (* One part of the selector *) +/// selector_part = existing_entities | manual_selector_part | optional_selector_part | generated_independent_entity | generated_attached_entity ; +/// +/// (* How the left and right selector are related, i.e. space means right is a descendant of left, and dot means right specializes left *) +/// selector_link = " " | "." ; +/// +/// (* The whole selector *) +/// selector = selector_part { ( selector_link ) selector_part } ; +/// +/// @link https://en.bem.info/ Information about BEM +/// @link https://csswizardry.com/2015/08/bemit-taking-the-bem-naming-convention-a-step-further/ Information about BEMIT +/// +/// @group BEM +/// +/// @access public +//// + +@import 'bem/vars'; +@import 'bem/functions'; +@import 'bem/validators'; +@import 'bem/block'; +@import 'bem/element'; +@import 'bem/modifier'; +@import 'bem/suffix'; +@import 'bem/state'; +@import 'bem/theme'; +@import 'bem/multi'; +@import 'bem/debug'; + +@include iro-context-stack-create($iro-bem-context-id); diff --git a/src/_contexts.scss b/src/_contexts.scss new file mode 100644 index 0000000..556fde3 --- /dev/null +++ b/src/_contexts.scss @@ -0,0 +1,315 @@ +//// +/// Context handling. +/// +/// Contexts allow you to pass data between mixins and let you enforce a certain nesting order. +/// It's an essential part for the BEM-related mixins. +/// +/// If you want to create a new context, the easiest pattern is to create a new mixin and wrap +/// the @content between a pair of iro-context-push and iro-context-pop. +/// From within the @content, you can access the context's data with iro-context-get. +/// To make the compilation fail if a certain nesting order is violated, use +/// iro-context-assert-stack-must-contain and iro-context-assert-stack-must-not-contain. +/// +/// @group Contexts +/// +/// @access public +//// + +/// +/// Map of all context stacks. +/// +/// @type map +/// +/// @access private +/// +$iro-context-stacks: (); + +/// +/// Create a new context stack. +/// +/// @param {string} $stack-id - ID of context stack +/// +/// @throw If context stack already exists +/// +@mixin iro-context-stack-create($stack-id) { + $noop: iro-context-stack-create($stack-id); +} + +/// +/// Create a new context stack. +/// +/// @param {string} $stack-id - ID of context stack +/// +@function iro-context-stack-create($stack-id) { + @if map-has-key($iro-context-stacks, $stack-id) { + @error 'Context stack "#{inspect($stack-id)}" does not exist.'; + } + + $iro-context-stacks: map-merge($iro-context-stacks, ($stack-id: ())) !global; + + @return null; +} + +/// +/// Clear a context stack. +/// +/// @param {string} $stack-id - ID of context stack +/// +@mixin iro-context-stack-clear($stack-id) { + $noop: iro-context-stack-clear($stack-id); +} + +/// +/// Clear a context stack. +/// +/// @param {string} $stack-id - ID of context stack +/// +@function iro-context-stack-clear($stack-id) { + @if not map-has-key($iro-context-stacks, $stack-id) { + @error 'Context stack "#{inspect($stack-id)}" does not exist.'; + } + + $context-stack: (); + $iro-context-stacks: map-merge($iro-context-stacks, ($stack-id: $context-stack)) !global; + + @return null; +} + +/// +/// Delete a context stack. +/// +/// @param {string} $stack-id - ID of context stack +/// +@mixin iro-context-stack-delete($stack-id) { + $noop: iro-context-stack-delete($stack-id); +} + +/// +/// Delete a context stack. +/// +/// @param {string} $stack-id - ID of context stack +/// +@function iro-context-stack-delete($stack-id) { + @if not map-has-key($iro-context-stacks, $stack-id) { + @error 'Context stack "#{inspect($stack-id)}" does not exist.'; + } + + $iro-context-stacks: map-remove($iro-context-stacks, $stack-id) !global; + + @return null; +} + +/// +/// Push a new context to a context stack. +/// +/// @param {string} $stack-id - ID of context stack to use +/// @param {string} $id - ID of new context +/// @param {any} $data [()] - Data that belongs to the context +/// +@mixin iro-context-push($stack-id, $id, $data: ()) { + $noop: iro-context-push($stack-id, $id, $data); +} + +/// +/// Push a new context to a context stack. +/// +/// @param {string} $stack-id - ID of context stack to use +/// @param {string} $id - ID of new context +/// @param {any} $data [()] - Data that belongs to the context +/// +/// @return {list} A list with two items: 1 = context id, 2 = context data +/// +@function iro-context-push($stack-id, $id, $data: ()) { + @if not map-has-key($iro-context-stacks, $stack-id) { + @error 'Context stack "#{inspect($stack-id)}" does not exist.'; + } + + $context: $id $data; + $context-stack: map-get($iro-context-stacks, $stack-id); + $context-stack: append($context-stack, $context); + $iro-context-stacks: map-merge($iro-context-stacks, ($stack-id: $context-stack)) !global; + + @return $context; +} + +/// +/// Pop the latest context from a context stack. +/// +/// @param {string} $stack-id - ID of context stack to use +/// +/// @throw If context stack doesn't exist +/// +@mixin iro-context-pop($stack-id) { + $noop: iro-context-pop($stack-id); +} + +/// +/// Pop the latest context from a context stack. +/// +/// @param {string} $stack-id - ID of context stack to use +/// +/// @return {list} A list with two items: 1 = context id, 2 = context data +/// +@function iro-context-pop($stack-id) { + @if not map-has-key($iro-context-stacks, $stack-id) { + @error 'Context stack "#{inspect($stack-id)}" does not exist.'; + } + + $context-stack: map-get($iro-context-stacks, $stack-id); + + @if length($context-stack) == 0 { + @error 'Context stack "#{inspect($stack-id)}" is already empty.'; + } + + $popped-context: nth($context-stack, -1); + + @if length($context-stack) == 1 { + $context-stack: (); + } @else { + $context-stack: iro-list-slice($context-stack, 1, length($context-stack) - 1); + } + + $iro-context-stacks: map-merge($iro-context-stacks, ($stack-id: $context-stack)) !global; + + @return $popped-context; +} + +/// +/// Assert that a context stack must contain one of the given context IDs. +/// +/// @param {string} $stack-id - ID of context stack to use +/// @param {list} $context-ids - Context IDs +/// @param {bool} $check-head-only [false] - If false, all items will be checked. If true, only the head will be checked. +/// +/// @throw If assertion fails +/// +@mixin iro-context-assert-stack-must-contain($stack-id, $context-ids, $check-head-only: false) { + @if not iro-context-stack-contains($stack-id, $context-ids, $check-head-only) { + @error 'Must be called inside of contexts "#{inspect($context-ids)}".'; + } +} + +/// +/// Assert that a context stack must not contain any of the given context IDs. +/// +/// @param {string} $stack-id - ID of context stack to use +/// @param {list} $context-ids - Context IDs +/// @param {bool} $check-head-only [false] - If false, all items will be checked. If true, only the head will be checked. +/// +/// @throw If assertion fails +/// +@mixin iro-context-assert-stack-must-not-contain($stack-id, $context-ids, $check-head-only: false) { + @if iro-context-stack-contains($stack-id, $context-ids, $check-head-only) { + @error 'Must not be called inside of contexts "#{inspect($context-ids)}".'; + } +} + +/// +/// Check if a context stack contains one of the given context IDs. +/// +/// @param {string} $stack-id - ID of context stack to use +/// @param {list} $context-ids - Context IDs +/// @param {bool} $check-head-only [false] - If false, all items will be checked. If true, only the head will be checked. +/// +/// @return {bool} `true` if the context stack contains one of the context IDs, otherwise `false` +/// +@function iro-context-stack-contains($stack-id, $context-ids, $check-head-only: false) { + @if not map-has-key($iro-context-stacks, $stack-id) { + @error 'Context stack "#{inspect($stack-id)}" does not exist.'; + } + + $context-stack: map-get($iro-context-stacks, $stack-id); + + @if length($context-stack) == 0 { + @return false; + } + + $end-idx: if($check-head-only, length($context-stack), 1); + + @for $i from length($context-stack) through $end-idx { + $context: nth($context-stack, $i); + + @each $chk-context in $context-ids { + @if nth($context, 1) == $chk-context { + @return true; + } + } + } + + @return false; +} + +/// +/// Assert that a context stack must contain a number of contexts smaller than $max-count. +/// +/// @param {string} $stack-id - ID of context stack to use +/// @param {number} $max-count - Maximum number ofg contexts in context stack +/// +/// @throw If assertion fails +/// +@mixin iro-context-assert-stack-count($stack-id, $max-count) { + @if iro-context-stack-count($stack-id) > $max-count { + @error 'Maximum context count "#{inspect($max-count)}" exceeded.'; + } +} + +/// +/// Get the number of contexts from a context stack. +/// +/// @param {string} $stack-id - ID of context stack to use +/// +/// @return {number} The number of contexts +/// +@function iro-context-stack-count($stack-id) { + @if not map-has-key($iro-context-stacks, $stack-id) { + @error 'Context stack "#{inspect($stack-id)}" does not exist.'; + } + + $context-stack: map-get($iro-context-stacks, $stack-id); + + @return length($context-stack); +} + +/// +/// Get a specific context from the stack. +/// +/// @param {string} $stack-id - ID of context stack to use +/// @param {number | string | list} $type-or-level - If this is a number (!= 0), the nth context from the head will be returned. If it is a string, the first context with a matching ID will be returned. If it is a list, the first context that matches one of the IDs in the list will be returned. +/// +/// @return {list} Null if no match was found, otherwise a list with two items: 1. context ID, 2. context data. +/// +@function iro-context-get($stack-id, $type-or-level: null) { + @if not map-has-key($iro-context-stacks, $stack-id) { + @error 'Context stack "#{inspect($stack-id)}" does not exist.'; + } + + $context-stack: map-get($iro-context-stacks, $stack-id); + + @if length($context-stack) == 0 { + @return null; + } + + @if type-of($type-or-level) == number { + $context: nth($context-stack, -$type-or-level); + + @return $context; + } @else { + @for $i from -1 through -(length($context-stack)) { + $context: nth($context-stack, $i); + + @if type-of($type-or-level) == list { + @for $j from 1 through length($type-or-level) { + $ctx: nth($type-or-level, $j); + + @if nth($context, 1) == $ctx { + @return $context; + } + } + } @else if nth($context, 1) == $type-or-level { + @return $context; + } + } + } + + @return null; +} diff --git a/src/_easing.scss b/src/_easing.scss new file mode 100644 index 0000000..c41635b --- /dev/null +++ b/src/_easing.scss @@ -0,0 +1,483 @@ +//// +/// Easing. +/// +/// A collection of easing functions which are commonly used for animations. +/// This code is based on https://github.com/gre/bezier-easing. +/// +/// @group Easing +/// +/// @access public +//// + +/// +/// @access private +/// +$iro-cubic-bezier-sample-pool: (); + +/// +/// Sample pool size for cubic bezier calculations. +/// +$iro-cubic-bezier-sample-pool-size: 10 !default; + +/// +/// Minimum slope required to use the Newton-Raphson method for cubic bezier calculations. +/// +$iro-cubic-bezier-newton-min-slope: 0.001 !default; + +/// +/// Number of iterations of the Newton-Raphson method. +/// +$iro-cubic-bezier-newton-iters: 4 !default; + +/// +/// Precision of the subdivision method for cubic bezier calculations. +/// +$iro-cubic-bezier-subdiv-precision: 0.0000001 !default; + +/// +/// Maximum iterations of the subdivision method for cubic bezier calculations. +/// +$iro-cubic-bezier-subdiv-max-iters: 10 !default; + +/// +/// A cubic bezier function identical to the CSS cubic-bezier function. +/// +/// @param {number} $x1 - X of first point +/// @param {number} $y1 - Y of first point +/// @param {number} $x2 - X of second point +/// @param {number} $y2 - Y of second point +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-cubic-bezier($x1, $y1, $x2, $y2, $x) { + // + // Cover simple cases + // + + @if ($x1 == $y1) and ($x2 == $y2) { + @return $x; + } + @if $x == 0 { + @return 0; + } + @if $x == 1 { + @return 1; + } + + // + // Generate samples + // + + $sample-pool-key: $x1 + '_' + $x2; + + @if not map-has-key($iro-cubic-bezier-sample-pool, $sample-pool-key) { + $samples: (); + + @for $i from 0 through $iro-cubic-bezier-sample-pool-size { + $samples: append($samples, iro-cubic-bezier-func($x1, $x2, $i / $iro-cubic-bezier-sample-pool-size)); + } + + $iro-cubic-bezier-sample-pool: map-merge($iro-cubic-bezier-sample-pool, ($sample-pool-key: $samples)) !global; + } + + // + // Calculate cubic bezier + // + + @return iro-cubic-bezier-func($y1, $y2, iro-cubic-bezier-t-for-x($x1, $x2, $x)); +} + +/// +/// @access private +/// +@function iro-cubic-bezier-func-a($p1, $p2) { + @return 1 - 3 * $p2 + 3 * $p1; +} + +/// +/// @access private +/// +@function iro-cubic-bezier-func-b($p1, $p2) { + @return 3 * $p2 - 6 * $p1; +} + +/// +/// @access private +/// +@function iro-cubic-bezier-func-c($p1) { + @return 3 * $p1; +} + +/// +/// One-dimensional cubic bezier function. +/// +/// @access private +/// +@function iro-cubic-bezier-func($p1, $p2, $t) { + @return ((iro-cubic-bezier-func-a($p1, $p2) * $t + iro-cubic-bezier-func-b($p1, $p2)) * $t + iro-cubic-bezier-func-c($p1)) * $t; +} + +/// +/// Derivative of the one-dimensional cubic bezier function. +/// +/// @access private +/// +@function iro-cubic-bezier-func-slope($p1, $p2, $t) { + @return 3 * iro-cubic-bezier-func-a($p1, $p2) * $t * $t + 2 * iro-cubic-bezier-func-b($p1, $p2) * $t + iro-cubic-bezier-func-c($p1); +} + +/// +/// Newton-Raphson method to calculate the t parameter for a given x parameter. +/// +/// @access private +/// +@function iro-cubic-bezier-newton-raphson($x1, $x2, $x, $t) { + @for $i from 1 through $iro-cubic-bezier-newton-iters { + $cur-slope: iro-cubic-bezier-func-slope($x1, $x2, $t); + + @if $cur-slope == 0 { + @return $t; + } + + $cur-x: iro-cubic-bezier-func($x1, $x2, $t) - $x; + $t: $t - $cur-x / $cur-slope; + } + + @return $t; +} + +/// +/// Subdivision method to calculate the t parameter for a given x parameter. +/// +/// @access private +/// +@function iro-cubic-bezier-binary-subdivide($x1, $x2, $x, $a, $b) { + $cur-x: 0; + $cur-t: 0; + $i: 0; + + @while $i < $iro-cubic-bezier-subdiv-max-iters { + $cur-t: $a + ($b - $a) / 2; + $cur-x: iro-cubic-bezier-func($x1, $x2, $cur-t) - $x; + + @if $cur-x > 0 { + $b: $cur-t; + } @else { + $a: $cur-t; + } + + @if abs($cur-x) < $iro-cubic-bezier-subdiv-precision { + @return $cur-t; + } + } + + @return $cur-t; +} + +/// +/// Calculate the t parameter for a given x parameter. +/// +/// @access private +/// +@function iro-cubic-bezier-t-for-x($x1, $x2, $x) { + $sample-pool-key: $x1 + '_' + $x2; + $samples: map-get($iro-cubic-bezier-sample-pool, $sample-pool-key); + + $intv-start: 0; + $cur-sample: 1; + $last-sample: $iro-cubic-bezier-sample-pool-size; + + @while ($cur-sample != $last-sample) and (nth($samples, $cur-sample) <= $x) { + $intv-start: $intv-start + (1 / $iro-cubic-bezier-sample-pool-size); + $cur-sample: $cur-sample + 1; + } + $cur-sample: $cur-sample - 1; + + $dist: ($x - nth($samples, $cur-sample)) / (nth($samples, $cur-sample + 1) - nth($samples, $cur-sample)); + $guess-t: $intv-start + $dist / $iro-cubic-bezier-sample-pool-size; + + $init-slope: iro-cubic-bezier-func-slope($x1, $x2, $guess-t); + @if $init-slope >= $iro-cubic-bezier-newton-min-slope { + @return iro-cubic-bezier-newton-raphson($x1, $x2, $x, $guess-t); + } @else if $init-slope == 0 { + @return $guess-t; + } @else { + @return iro-cubic-bezier-binary-subdivide($x1, $x2, $x, $intv-start, $intv-start + 1 / $iro-cubic-bezier-sample-pool-size); + } +} + +/// +/// Sinusoidal easing function (in direction). +/// +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-ease($x) { + @return iro-cubic-bezier(0.25, 0.1, 0.25, 1, $x); +} + +/// +/// Sinusoidal easing function (in direction). +/// +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-ease-in($x) { + @return iro-cubic-bezier(0.42, 0, 1, 1, $x); +} + +/// +/// Sinusoidal easing function (out direction). +/// +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-ease-out($x) { + @return iro-cubic-bezier(0, 0, 0.58, 1, $x); +} + +/// +/// Sinusoidal easing function (in-out direction). +/// +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-ease-in-out($x) { + @return iro-cubic-bezier(0.42, 0, 0.58, 1, $x); +} + +/// +/// Sinusoidal easing function (in direction). +/// +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-ease-in-sine($x) { + @return iro-cubic-bezier(0.47, 0, 0.745, 0.715, $x); +} + +/// +/// Sinusoidal easing function (out direction). +/// +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-ease-out-sine($x) { + @return iro-cubic-bezier(0.39, 0.575, 0.565, 1, $x); +} + +/// +/// Sinusoidal easing function (in-out direction). +/// +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-ease-in-out-sine($x) { + @return iro-cubic-bezier(0.445, 0.05, 0.55, 0.95, $x); +} + +/// +/// Quadratic easing function (in direction). +/// +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-ease-in-quad($x) { + @return iro-cubic-bezier(0.55, 0.085, 0.68, 0.53, $x); +} + +/// +/// Quadratic easing function (out direction). +/// +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-ease-out-quad($x) { + @return iro-cubic-bezier(0.25, 0.46, 0.45, 0.94, $x); +} + +/// +/// Quadratic easing function (in-out direction). +/// +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-ease-in-out-quad($x) { + @return iro-cubic-bezier(0.455, 0.03, 0.515, 0.955, $x); +} + +/// +/// Cubic easing function (in direction). +/// +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-ease-in-cubic($x) { + @return iro-cubic-bezier(0.55, 0.055, 0.675, 0.19, $x); +} + +/// +/// Cubic easing function (out direction). +/// +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-ease-out-cubic($x) { + @return iro-cubic-bezier(0.215, 0.61, 0.355, 1, $x); +} + +/// +/// Cubic easing function (in-out direction). +/// +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-ease-in-out-cubic($x) { + @return iro-cubic-bezier(0.645, 0.045, 0.355, 1, $x); +} + +/// +/// Quart easing function (in direction). +/// +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-ease-in-quart($x) { + @return iro-cubic-bezier(0.895, 0.03, 0.685, 0.22, $x); +} + +/// +/// Quart easing function (out direction). +/// +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-ease-out-quart($x) { + @return iro-cubic-bezier(0.165, 0.84, 0.44, 1, $x); +} + +/// +/// Quart easing function (in-out direction). +/// +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-ease-in-out-quart($x) { + @return iro-cubic-bezier(0.77, 0, 0.175, 1, $x); +} + +/// +/// Quint easing function (in direction). +/// +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-ease-in-quint($x) { + @return iro-cubic-bezier(0.755, 0.05, 0.855, 0.06, $x); +} + +/// +/// Quint easing function (out direction). +/// +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-ease-out-quint($x) { + @return iro-cubic-bezier(0.23, 1, 0.32, 1, $x); +} + +/// +/// Quint easing function (in-out direction). +/// +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-ease-in-out-quint($x) { + @return iro-cubic-bezier(0.86, 0, 0.07, 1, $x); +} + +/// +/// Exponential easing function (in direction). +/// +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-ease-in-expo($x) { + @return iro-cubic-bezier(0.95, 0.05, 0.795, 0.035, $x); +} + +/// +/// Exponential easing function (out direction). +/// +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-ease-out-expo($x) { + @return iro-cubic-bezier(0.19, 1, 0.22, 1, $x); +} + +/// +/// Exponential easing function (in-out direction). +/// +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-ease-in-out-expo($x) { + @return iro-cubic-bezier(1, 0, 0, 1, $x); +} + +/// +/// Circular easing function (in direction). +/// +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-ease-in-circ($x) { + @return iro-cubic-bezier(0.6, 0.04, 0.98, 0.335, $x); +} + +/// +/// Circular easing function (out direction). +/// +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-ease-out-circ($x) { + @return iro-cubic-bezier(0.075, 0.82, 0.165, 1, $x); +} + +/// +/// Circular easing function (in-out direction). +/// +/// @param {number} $x - Progress between 0 and 1 inclusive +/// +/// @return {number} +/// +@function iro-ease-in-out-circ($x) { + @return iro-cubic-bezier(0.785, 0.135, 0.15, 0.86, $x); +} diff --git a/src/_functions.scss b/src/_functions.scss new file mode 100644 index 0000000..2f34dc4 --- /dev/null +++ b/src/_functions.scss @@ -0,0 +1,328 @@ +//// +/// Various functions. +/// +/// This file contains various and mostly unrelated functions. Some of which +/// are used in this framework, while others are just there and may be used. +/// +/// @group Functions +/// +/// @access public +//// + +/// +/// Replace a substring with a new string. +/// +/// @param {string} $string - String to search +/// @param {string} $search - Substring that gets replaced +/// @param {string} $replace - String that replaces $search +/// +/// @return {string} A string with all instances of $search replaced with $replace +/// +@function iro-str-replace($string, $search, $replace) { + $index: str-index($string, $search); + + @if $index { + @return str-slice($string, 1, $index - 1) + $replace + iro-str-replace(str-slice($string, $index + str-length($search)), $search, $replace); + } + + @return $string; +} + +/// +/// Concatenate all items from $list. +/// +/// @param {list} $list +/// @param {number} $glue - Delimiter +/// +/// @return {string} +/// +@function iro-str-implode($list, $glue: '') { + $result: ''; + + @each $item in $list { + $result: $result + if(length($item) > 1, iro-str-implode($item, $glue), $item); + + @if $item != nth($list, length($list)) { + $result: $result + $glue; + } + } + + @return $result; +} + +/// +/// Extract a subset from the given list. +/// +/// @param {list} $list +/// @param {number} $start [1] - Indices before this value will be discarded +/// @param {number} $end [length($list)] - Indices starting after this value will be discarded +/// +/// @return {list} A slice of the list +/// +@function iro-list-slice($list, $start: 1, $end: length($list)) { + $result: (); + + @for $i from $start through $end { + @if $i != 0 { + $result: append($result, nth($list, $i), list-separator($list)); + } + } + + @return $result; +} + +/// +/// Add a new item to the beginning of a list. +/// +/// @param {list} $list +/// @param {number} $value +/// +/// @return {list} A list with $value at the beginning, followed by the other items +/// +@function iro-list-prepend($list, $value) { + $result: append((), $value, list-separator($list)); + + @if length($list) > 0 { + @for $i from 1 through length($list) { + $result: append($result, nth($list, $i), list-separator($list)); + } + } + + @return $result; +} + +/// +/// Sort numeric items in a list. +/// +/// The implementation is based on the algorithm on the German Wikipedia article +/// about quicksort: https://de.wikipedia.org/wiki/Quicksort#Pseudocode +/// +/// @param {list} $l +/// +/// @return {list} Sorted list +/// +@function iro-quicksort($l, $left: 1, $right: length($l)) { + @if $left < $right { + $pvr: iro-quicksort-partition($l, $left, $right); + $pivot: nth($pvr, 1); + $l: nth($pvr, 2); + $l: iro-quicksort($l, $left, $pivot); + $l: iro-quicksort($l, $pivot + 1, $right); + } + + @return $l; +} + +/// +/// @access private +/// +@function iro-quicksort-partition($l, $left, $right) { + $start: true; + $i: $left; + $j: $right - 1; + $pivot: nth($l, $right); + + @while ($i < $j) or $start { + @while (nth($l, $i) < $pivot) and ($i < $right - 1) { + $i: $i + 1; + } + + @while (nth($l, $j)>= $pivot) and ($j > $left) { + $j: $j - 1; + } + + @if $i < $j { + $i-val: nth($l, $i); + $l: set-nth($l, $i, nth($l, $j)); + $l: set-nth($l, $j, $i-val); + } + + $start: false; + } + + @if nth($l, $i) > $pivot { + $i-val: nth($l, $i); + $l: set-nth($l, $i, nth($l, $right)); + $l: set-nth($l, $right, $i-val); + } + + @return $i $l; +} + +/// +/// Try to get the value for the given key from the given map. If it doesn't contain that key, +/// return the provided default value instead. +/// +/// @param {map} $map +/// @param {string} $key +/// @param {any} $default +/// +/// @return {any} Either the value assigned to $key or $default +/// +@function iro-map-get-default($map, $key, $default) { + @return if(map-has-key($map, $key), map-get($map, $key), $default); +} + +/// +/// Get the value for a map within a map (or deeper). +/// +/// @param {map} $map +/// @param {string | list} $key +/// @param {any} $default [null] +/// +/// @return {any} Either the value assigned to $key or $default +/// +@function iro-map-get-deep($map, $key, $default: null) { + $value: null; + + @if type-of($key) == list { + $value: $map; + + @each $k in $key { + $value: map-get($value, $k); + + @if $value == null { + @return $default; + } + } + } @else { + $value: map-get($map, $key); + + @if $value == null { + @return $default; + } + } + + @return $value; +} + +/// +/// Merge two maps recursively. +/// +/// @param {map} $map1 +/// @param {map} $map2 +/// +/// @return {map} The result of a recursive merge of $map1 and $map2 +/// +@function iro-map-merge-recursive($map1, $map2) { + @if type-of($map1) != map or type-of($map2) != map { + @error 'Two maps expected.'; + } + + $result: $map1; + + @each $key, $value in $map2 { + @if type-of(map-get($result, $key)) == map and type-of($value) == map { + $result: map-merge($result, ($key: iro-map-merge-recursive(map-get($result, $key), $value))); + } @else { + $result: map-merge($result, ($key: $value)); + } + } + + @return $result; +} + +/// +/// Get the contents of a map as a user-friendly string representation. +/// +/// @param {map} $map +/// +/// @return {string} +/// +@function iro-map-print($map) { + $output: ''; + + @each $key, $value in $map { + $value-str: ''; + + @if type-of($value) == map { + $value-str: '[ ' + iro-map-print($value) + ' ]'; + } @else if type-of($value) == list { + $value-str: '[ ' + iro-str-implode($value, ', ') + ' ]'; + } @else if type-of($value) == string { + $value-str: '\'' + $value + '\''; + } @else { + $value-str: $value; + } + + @if $output == '' { + $output: $key + ': ' + $value-str; + } @else { + $output: $output + ', ' + $key + ': ' + $value-str; + } + } + + @return $output; +} + +/// +/// Check if the given selector ends with one of the provided suffixes. +/// +/// @param {selector} $selector +/// @param {selector} $suffixes +/// +/// @return {bool} `true` if the selector matches at least one suffix, otherwise `false`. +/// +@function iro-selector-suffix-match($selector, $suffixes) { + $match: true; + + @each $sel in $selector { + @if $match { + $sel-match: false; + + @each $suffix in $suffixes { + @if not $sel-match { + $suf-match: true; + + @for $i from 1 through length($suffix) { + @if $suf-match and (nth($sel, -$i) != nth($suffix, -$i)) { + $suf-match: false; + } + } + + @if $suf-match { + $sel-match: true; + } + } + } + + @if not $sel-match { + $match: false; + } + } + } + + @return $match; +} + +/// +/// Remove the unit from any variable. +/// +/// @param {any} $n +/// +/// @return {number} Unit-less variable +/// +@function iro-strip-unit($n) { + @return $n / ($n * 0 + 1); +} + +/// +/// Convert a pixel value to a rem value. +/// +/// @param {number} $size - Pixel value to convert +/// @param {number} $base [$iro-root-size] - Reference base font size used for conversion +/// +/// @return {number} Pixel value converted to rem +/// +@function iro-px-to-rem($size, $base: $iro-root-size) { + @return $size / $base * 1rem; +} + +/// +/// A mixin with the sole purpose of letting you use temporary variables without polluting the global namespace. +/// +/// @content +/// +@mixin iro-execute { + @content; +} diff --git a/src/_gradients.scss b/src/_gradients.scss new file mode 100644 index 0000000..7c52d63 --- /dev/null +++ b/src/_gradients.scss @@ -0,0 +1,600 @@ +//// +/// Smoother background gradients. +/// +/// The default background gradients produced by any browser have a quite harsh transition between +/// colors. This is especially apparent if you, for example, use a strong fade-out gradient to make +/// text in front of a background more readable. +/// +/// The function in this file generates smoother gradients by using easing functions of the user's +/// choice. +/// It's essentially a more flexible alternative to the PostCSS plugin "PostCSS Easing Gradients": +/// https://github.com/larsenwork/postcss-easing-gradients +/// +/// @group Background gradients +/// +/// @access public +//// + +/// +/// Number of intermediate color stops generated to achieve easing. +/// A higher value results in better quality, but also much more generated code. +/// +/// @type number +/// +$iro-easing-gradient-steps: 10 !default; + +/// +/// Generate a new easing background gradient. +/// This function is intended to be as similar as possible to the newly proposed syntax for +/// linear-gradient and radial-gradient which includes easing hints. +/// +/// @param {string} $type - Either 'linear' or 'radial', which means the gradient will be either a linear-gradient or a radial-gradient. +/// @param {string} $dir - The direction of the gradient. Depending on $type, this value must be a valid direction for linear-gradient or radial-gradient. +/// @param {color | list} $stop - A color stop as used for linear-gradient or radial-gradient. +/// @param {arglist} $stops - More color stops as used for linear-gradient or radial-gradient. Between two color stops, you may also define an easing hint such as `ease-in-out`, `cubic-bezier 0.42 0 0.58 1`, `steps 3 jump-end`, and so on. +/// +/// @return {string} A linear-gradient or radial-gradient with an alternative transitioning behavior. +/// +/// @throw If $type is invalid +/// +/// @link https://github.com/w3c/csswg-drafts/issues/1332 The new CSSWG proposal +/// +/// @example scss - A smoother linear gradient +/// .background { +/// background-image: iro-easing-gradient( +/// linear, +/// to top, +/// #000, +/// in-out-sine, +/// transparent +/// ); +/// } +/// +/// // Generates: +/// +/// .background { +/// background-image: linear-gradient( +/// to top, +/// black 0%, +/// rgba(0, 0, 0, 0.975528) 10%, +/// rgba(0, 0, 0, 0.904508) 20%, +/// rgba(0, 0, 0, 0.793893) 30%, +/// rgba(0, 0, 0, 0.654508) 40%, +/// rgba(0, 0, 0, 0.5) 50%, +/// rgba(0, 0, 0, 0.345492) 60%, +/// rgba(0, 0, 0, 0.206107) 70%, +/// rgba(0, 0, 0, 0.0954915) 80%, +/// rgba(0, 0, 0, 0.0244717) 90%, +/// rgba(0, 0, 0, 3.78257e-11) 100% +/// ); +/// } +/// +/// @example scss - A smoother radial gradient +/// .background { +/// background-image: iro-easing-gradient( +/// radial, +/// 50em 16em at 0 0, +/// #000, +/// in-out-sine, +/// transparent +/// ); +/// } +/// +/// // Generates: +/// +/// .background { +/// background-image: radial-gradient( +/// 50em 16em at 0 0, +/// black 0%, +/// rgba(0, 0, 0, 0.975528) 10%, +/// rgba(0, 0, 0, 0.904508) 20%, +/// rgba(0, 0, 0, 0.793893) 30%, +/// rgba(0, 0, 0, 0.654508) 40%, +/// rgba(0, 0, 0, 0.5) 50%, +/// rgba(0, 0, 0, 0.345492) 60%, +/// rgba(0, 0, 0, 0.206107) 70%, +/// rgba(0, 0, 0, 0.0954915) 80%, +/// rgba(0, 0, 0, 0.0244717) 90%, +/// rgba(0, 0, 0, 3.78257e-11) 100% +/// ); +/// } +/// +/// @example scss - A smoother linear gradient with complex color positions +/// .background { +/// background-image: iro-easing-gradient( +/// linear, +/// to top, +/// #000 20%, +/// in-out-sine, +/// transparent calc(20% + 25em) +/// ); +/// } +/// +/// // Generates: +/// +/// .background { +/// background-image: linear-gradient( +/// to top, +/// black 20%, +/// rgba(0, 0, 0, 0.975528) calc(20% + (20% + 25em - 20%) * 0.1), +/// rgba(0, 0, 0, 0.904508) calc(20% + (20% + 25em - 20%) * 0.2), +/// rgba(0, 0, 0, 0.793893) calc(20% + (20% + 25em - 20%) * 0.3), +/// rgba(0, 0, 0, 0.654508) calc(20% + (20% + 25em - 20%) * 0.4), +/// rgba(0, 0, 0, 0.5) calc(20% + (20% + 25em - 20%) * 0.5), +/// rgba(0, 0, 0, 0.345492) calc(20% + (20% + 25em - 20%) * 0.6), +/// rgba(0, 0, 0, 0.206107) calc(20% + (20% + 25em - 20%) * 0.7), +/// rgba(0, 0, 0, 0.0954915) calc(20% + (20% + 25em - 20%) * 0.8), +/// rgba(0, 0, 0, 0.0244717) calc(20% + (20% + 25em - 20%) * 0.9), +/// transparent calc(20% + 25em)) +/// ); +/// } +/// +@function iro-easing-gradient($type, $dir, $stop, $stops...) { + $pos-template: null; + $stops: iro-list-prepend($stops, $stop); + + $last-positioned-stop: 1; + $generated-stops: (); + + // + // Generate gradient + // + + @for $i from 1 through length($stops) { + $stop: nth($stops, $i); + + @if $i == 1 { + @if not iro-easing-gradient-is-color-stop($stop) { + @error 'The first color stop argument must be a color stop.'; + } + + @if type-of($stop) == color { + // + // The first color stop is unpositioned. The default position for the first + // color stop is 0, which is explicitly added for easier calculations. + // + + $stop: $stop 0; + $stops: set-nth($stops, $i, $stop); + } + + $generated-stops: append($generated-stops, iro-str-implode($stop, ' ')); + } @else if iro-easing-gradient-is-positioned-color-stop($stop) or ($i == length($stops)) { + @if not iro-easing-gradient-is-color-stop($stop) { + @error 'The last color stop argument must be a color stop.'; + } + + // + // Either the current stops list item is a positioned color stop, or the end of + // the stops list has been reached. + // + + @if (type-of($stop) == color) and ($i == length($stops)) { + // + // The current stop is an unpositioned color stop, which means this is the end + // of the stops list. The default position for the last color stop is 100%, which + // is explicitly added for easier calculations. + // + + $stop: $stop 100%; + $stops: set-nth($stops, $i, $stop); + } + + // + // Now the current color stop is guaranteed to be a positioned color stop. + // + + @if $i > $last-positioned-stop + 1 { + // + // There is at least one stops list item (unpositioned color stop or easing function) + // between the last positioned color stop and the current stops list item. Interpolate + // the positions of all stops list items that are color stops. + // + + $interpolated-stops: iro-easing-gradient-interpolate-stop-positions( + nth($stops, $last-positioned-stop), + iro-list-slice($stops, $last-positioned-stop + 1, $i - 1), + $stop + ); + + $new-stops: join( + iro-list-slice($stops, 1, $last-positioned-stop), + $interpolated-stops + ); + $new-stops: join( + $new-stops, + iro-list-slice($stops, $i) + ); + $stops: $new-stops; + } + + // + // Now all color stops between this one and the last positioned one have + // interpolated positions. + // Next task is to perform an easing transition between all color stops that + // have an easing function specified. The rest can be left alone since the + // browser will automatically apply a linear transition between them. + // + + $j: $last-positioned-stop + 1; + @while $j <= $i { + $easing: null; + $prev-stop: nth($stops, $j - 1); + $next-stop: nth($stops, $j); + + @if not iro-easing-gradient-is-color-stop($next-stop) { + $j: $j + 1; + + $easing: $next-stop; + $next-stop: nth($stops, $j); + + @if not iro-easing-gradient-is-color-stop($next-stop) { + @error 'There can be at most one interpolation hint between to color stops.'; + } + } + + @if $easing != null { + @if type-of($easing) == number { + @error 'Midpoint shifts are not supported.'; + } + + $easing-func: null; + $easing-args: (); + + @if type-of($easing) == list { + $easing-args: iro-list-slice($easing, 2); + $easing: nth($easing, 1); + } + + $generated-stops: join( + $generated-stops, + iro-easing-gradient-ease-stops($prev-stop, $next-stop, $easing, $easing-args) + ); + } @else { + $generated-stops: append($generated-stops, iro-str-implode($next-stop, ' ')); + } + + $j: $j + 1; + } + + $last-positioned-stop: $i; + } + } + + @if $type == 'linear' { + @return linear-gradient($dir, unquote(iro-str-implode($generated-stops, ', '))); + } @else if $type == 'radial' { + @return radial-gradient($dir, unquote(iro-str-implode($generated-stops, ', '))); + } @else { + @error 'Invalid gradient type: #{inspect($type)}.'; + } +} + +/// +/// Alias for iro-easing-gradient('linear',...) +/// +/// @see {function} iro-easing-gradient +/// +@function iro-easing-linear-gradient($dir, $stop, $stops...) { + @return iro-easing-gradient('linear', $dir, $stop, $stops...); +} + +/// +/// Alias for iro-easing-gradient('radial',...) +/// +/// @see {function} iro-easing-gradient +/// +@function iro-easing-radial-gradient($dir, $stop, $stops...) { + @return iro-easing-gradient('radial', $dir, $stop, $stops...); +} + +/// +/// Generate a smooth transition from one color stop to another using the provided easing function. +/// +/// @access private +/// +@function iro-easing-gradient-ease-stops($prev-stop, $next-stop, $easing, $easing-args: ()) { + @if $easing == 'steps' { + $steps: null; + $jump: null; + + @if length($easing-args) > 1 { + $steps: nth($easing-args, 1); + $jump: nth($easing-args, 2); + } @else { + $steps: nth($easing-args, 1); + $jump: jump-end; + } + + @return iro-easing-gradient-steps-stops($prev-stop, $next-stop, $steps, $jump); + } @else { + $easing-func: null; + @if function-exists('iro-' + $easing) { + $easing-func: get-function('iro-' + $easing); + } @else { + $easing-func: get-function($easing); + } + + @return iro-easing-gradient-bezier-stops($prev-stop, $next-stop, $easing-func, $easing-args); + } +} + +/// +/// Generate a smooth transition from one color stop to another using the provided cubic-bezier function. +/// +/// @access private +/// +@function iro-easing-gradient-bezier-stops($prev-stop, $next-stop, $easing-func, $easing-args: ()) { + $prev-stop-color: nth($prev-stop, 1); + $prev-stop-pos: nth($prev-stop, 2); + $next-stop-color: nth($next-stop, 1); + $next-stop-pos: nth($next-stop, 2); + + $stops: (); + + @if ((type-of($prev-stop-pos) == number) and (type-of($next-stop-pos) == number) and (unit($prev-stop-pos) == unit($next-stop-pos))) or ($prev-stop-pos == 0) or ($next-stop-pos == 0) { + // + // The transition color stop positions can be statically calculated. + // + + $distance: $next-stop-pos - $prev-stop-pos; + + @for $i from 1 through $iro-easing-gradient-steps { + $perc: $i / $iro-easing-gradient-steps; + + $color: null; + $pos: $prev-stop-pos + $perc * $distance; + @if $perc == 1 { + $color: $next-stop-color; + } @else { + $color: mix($next-stop-color, $prev-stop-color, call($easing-func, append($easing-args, $perc)...) * 100%); + } + + $stops: append($stops, $color + ' ' + $pos); + } + } @else { + // + // The transition color stop positions have to be dynamically calculated with the calc() function. + // + + @if type-of($prev-stop-pos) != number { + // must be calc() + @if (type-of($prev-stop-pos) != string) or (str-index($prev-stop-pos, 'calc(') != 1) { + @error 'Invalid color stop position: #{inspect($prev-stop-pos)}'; + } + + $prev-stop-pos: str-slice($prev-stop-pos, 6, str-length($prev-stop-pos) - 1); + } + + @if type-of($next-stop-pos) != number { + // must be calc() + @if (type-of($next-stop-pos) != string) or (str-index($next-stop-pos, 'calc(') != 1) { + @error 'Invalid color stop position: #{inspect($next-stop-pos)}'; + } + + $next-stop-pos: str-slice($next-stop-pos, 6, str-length($next-stop-pos) - 1); + } + + @for $i from 1 through $iro-easing-gradient-steps { + $perc: $i / $iro-easing-gradient-steps; + + $color: null; + $pos: null; + @if $perc == 1 { + $color: $next-stop-color; + $pos: calc(#{$next-stop-pos}); + } @else { + $color: mix($next-stop-color, $prev-stop-color, call($easing-func, append($easing-args, $perc)...) * 100%); + $pos: calc(#{$prev-stop-pos} + (#{$next-stop-pos} - #{$prev-stop-pos}) * #{$perc}); + } + + $stops: append($stops, $color + ' ' + $pos); + } + } + + @return $stops; +} + +/// +/// Generate a step transition from one color stop to another. +/// +/// @access private +/// +@function iro-easing-gradient-steps-stops($prev-stop, $next-stop, $steps, $jump: jump-end) { + $prev-stop-color: nth($prev-stop, 1); + $prev-stop-pos: nth($prev-stop, 2); + $next-stop-color: nth($next-stop, 1); + $next-stop-pos: nth($next-stop, 2); + + $stops: (); + + @if ((type-of($prev-stop-pos) == number) and (type-of($next-stop-pos) == number) and (unit($prev-stop-pos) == unit($next-stop-pos))) or ($prev-stop-pos == 0) or ($next-stop-pos == 0) { + // + // The transition color stop positions can be statically calculated. + // + + $distance: $next-stop-pos - $prev-stop-pos; + + @for $i from 1 through $steps { + $x1: ($i - 1) / $steps; + $x2: $i / $steps; + $y: null; + + @if $jump == jump-start { + $y: $i / $steps; + } @else if $jump == jump-end { + $y: ($i - 1) / $steps; + } @else if $jump == jump-both { + $y: $i / ($steps + 1); + } @else if $jump == jump-none { + $y: ($i - 1) / ($steps - 1); + } @else { + @error 'Invalid $jump: #{inspect($jump)}'; + } + + $color: null; + $pos1: if($x1 == 0, $prev-stop-pos, $prev-stop-pos + $x1 * $distance); + $pos2: if($x2 == 1, $next-stop-pos, $prev-stop-pos + $x2 * $distance); + + @if $y == 0 { + $color: $prev-stop-color; + } @else if $y == 1 { + $color: $next-stop-color; + } @else { + $color: mix($next-stop-color, $prev-stop-color, $y * 100%); + } + + $stops: append($stops, $color + ' ' + $pos1); + $stops: append($stops, $color + ' ' + $pos2); + } + } @else { + // + // The transition color stop positions have to be dynamically calculated with the calc() function. + // + + @if type-of($prev-stop-pos) != number { + // must be calc() + @if (type-of($prev-stop-pos) != string) or (str-index($prev-stop-pos, 'calc(') != 1) { + @error 'Invalid color stop position: #{inspect($prev-stop-pos)}'; + } + + $prev-stop-pos: str-slice($prev-stop-pos, 6, str-length($prev-stop-pos) - 1); + } + + @if type-of($next-stop-pos) != number { + // must be calc() + @if (type-of($next-stop-pos) != string) or (str-index($next-stop-pos, 'calc(') != 1) { + @error 'Invalid color stop position: #{inspect($next-stop-pos)}'; + } + + $next-stop-pos: str-slice($next-stop-pos, 6, str-length($next-stop-pos) - 1); + } + + @for $i from 1 through $steps { + $x1: ($i - 1) / $steps; + $x2: $i / $steps; + $y: null; + + @if $jump == jump-start { + $y: $i / $steps; + } @else if $jump == jump-end { + $y: ($i - 1) / $steps; + } @else if $jump == jump-both { + $y: $i / ($steps + 1); + } @else if $jump == jump-none { + $y: ($i - 1) / ($steps - 1); + } @else { + @error 'Invalid $jump: #{inspect($jump)}'; + } + + $color: null; + $pos1: if($x1 == 0, $prev-stop-pos, calc(#{$prev-stop-pos} + (#{$next-stop-pos} - #{$prev-stop-pos}) * #{$x1})); + $pos2: if($x2 == 1, $next-stop-pos, calc(#{$prev-stop-pos} + (#{$next-stop-pos} - #{$prev-stop-pos}) * #{$x2})); + + @if $y == 0 { + $color: $prev-stop-color; + } @else if $y == 1 { + $color: $next-stop-color; + } @else { + $color: mix($next-stop-color, $prev-stop-color, $y * 100%); + } + + $stops: append($stops, $color + ' ' + $pos1); + $stops: append($stops, $color + ' ' + $pos2); + } + } + + @return $stops; +} + +/// +/// Interpolate the positions of multiple color stops between two color stops whose positions are set. +/// +/// @access private +/// +@function iro-easing-gradient-interpolate-stop-positions($prev-stop, $stops, $next-stop) { + $prev-stop-pos: nth($prev-stop, 2); + $next-stop-pos: nth($next-stop, 2); + + $stops-num: 0; + @for $i from 1 through length($stops) { + $stop: nth($stops, $i); + @if iro-easing-gradient-is-color-stop($stop) { + $stops-num: $stops-num + 1; + } + } + + $i: 1; + $cur-stop-num: 1; + + @if ((type-of($prev-stop-pos) == number) and (type-of($next-stop-pos) == number) and (unit($prev-stop-pos) == unit($next-stop-pos))) or ($prev-stop-pos == 0) or ($next-stop-pos == 0) { + // + // The color stop positions can be statically calculated. + // + + $distance: $next-stop-pos - $prev-stop-pos; + + @for $i from 1 through length($stops) { + $stop: nth($stops, $i); + @if iro-easing-gradient-is-color-stop($stop) { + $pos: $prev-stop-pos + $distance / ($stops-num + 1) * $cur-stop-num; + $stops: set-nth($stops, $i, $stop $pos); + + $cur-stop-num: $cur-stop-num + 1; + } + } + } @else { + // + // The color stop positions have to be dynamically calculated with the calc() function. + // + + @if type-of($prev-stop-pos) != number { + // must be calc() + @if (type-of($prev-stop-pos) != string) or (str-index($prev-stop-pos, 'calc(') != 1) { + @error 'Invalid color stop position: #{inspect($prev-stop-pos)}'; + } + + $prev-stop-pos: str-slice($prev-stop-pos, 6, str-length($prev-stop-pos) - 1); + } + + @if type-of($next-stop-pos) != number { + // must be calc() + @if (type-of($next-stop-pos) != string) or (str-index($next-stop-pos, 'calc(') != 1) { + @error 'Invalid color stop position: #{inspect($next-stop-pos)}'; + } + + $next-stop-pos: str-slice($next-stop-pos, 6, str-length($next-stop-pos) - 1); + } + + @for $i from 1 through length($stops) { + $stop: nth($stops, $i); + @if iro-easing-gradient-is-color-stop($stop) { + $perc: $cur-stop-num / ($stops-num + 1); + $pos: calc(#{$prev-stop-pos} + (#{$next-stop-pos} - #{$prev-stop-pos}) * #{$perc}); + $stops: set-nth($stops, $i, $stop $pos); + + $cur-stop-num: $cur-stop-num + 1; + } + } + } + + @return $stops; +} + +/// +/// Check if the input is a valid color stop. +/// +/// @access private +/// +@function iro-easing-gradient-is-color-stop($input) { + @return (type-of($input) == color) or iro-easing-gradient-is-positioned-color-stop($input); +} + +/// +/// Check if the input is a valid positioned color stop. +/// +/// @access private +/// +@function iro-easing-gradient-is-positioned-color-stop($input) { + @return (type-of($input) == list) and (type-of(nth($input, 1)) == color); +} diff --git a/src/_harmony.scss b/src/_harmony.scss new file mode 100644 index 0000000..c3c8633 --- /dev/null +++ b/src/_harmony.scss @@ -0,0 +1,94 @@ +//// +/// Harmony. +/// +/// Contains functions to make a design appear more harmonic. +/// +/// @group Harmony +/// +/// @access public +//// + +/// +/// Adjust a value to a modular scale. +/// +/// For a more sophisticated solution, check out [modularscale-sass](https://github.com/modularscale/modularscale-sass). +/// +/// @link http://alistapart.com/article/more-meaningful-typography An article about modular scales by Tim Brown +/// +/// @param {number} $times - Number of iterations. If positive, $base will be multiplied with $ratio. If negative, $base will be divided by $ratio. +/// @param {number | list} $base - Single base value or, for a multi-stranded modular scale, a list of base values +/// @param {number} $ratio - Ratio +/// +/// @return {number} +/// +@function iro-harmony-modular-scale($times, $base, $ratio) { + @if type-of($base) == number { + @return $base * iro-math-pow($ratio, $times); + } + + $main-base: nth($base, 1); + $norm-bases: (); + + @each $b in iro-list-slice($base, 2) { + @if $b > $main-base { + @while $b > $main-base { + $b: $b / $ratio; + } + $b: $b * $ratio; + } @else if $b < $main-base { + @while $b < $main-base { + $b: $b * $ratio; + } + } + + $norm-bases: append($norm-bases, $b); + } + + $all-bases: append($norm-bases, $main-base); + $all-bases: iro-quicksort($all-bases); + + $base-index: $times % length($all-bases) + 1; + $exp: floor($times / length($all-bases)); + + @return nth($all-bases, $base-index) * iro-math-pow($ratio, $exp); +} + +/// +/// Combine responsive properties with modular scales to achieve responsive modular scales. +/// +/// @param {string | list} $props - Property or list of properties to set +/// @param {number} $times - Number of iterations. See iro-harmony-modular-scale for more information. +/// @param {number} $responsive-map - A map with keys = viewports and values = modular scales +/// @param {bool} $fluid [true] - If enabled, property values will smoothly transition from one viewport to the next +/// +/// @see {function} iro-harmony-modular-scale +/// +/// @example scss - Responsive font sizes between 2 viewports based on modular scales +/// $ms: ( +/// 320px: (1rem 2rem, 1.1), +/// 640px: (1rem 2rem, 1.2) +/// ); +/// +/// h1 { +/// @include iro-responsive-modular-scale(font-size, 3, $ms); +/// } +/// +/// h2 { +/// @include iro-responsive-modular-scale(font-size, 2, $ms); +/// } +/// +/// h3 { +/// @include iro-responsive-modular-scale(font-size, 1, $ms); +/// } +/// +@mixin iro-responsive-modular-scale($props, $times, $responsive-map, $fluid: true) { + $new-map: (); + + @each $key, $value in $responsive-map { + $new-map: map-merge($new-map, ( + $key: iro-harmony-modular-scale($times, $value...) + )); + } + + @include iro-responsive-property($props, $new-map, $fluid); +} diff --git a/src/_math.scss b/src/_math.scss new file mode 100644 index 0000000..9b71bf6 --- /dev/null +++ b/src/_math.scss @@ -0,0 +1,62 @@ +//// +/// Basic mathematical functions. +/// +/// @group Math functions +/// +/// @access public +//// + +/// +/// Perform exponentiation. Only integer exponents are supported. +/// +/// @param {number} $base +/// @param {number} $exp +/// +/// @return {number} +/// +/// @example scss - Exponentiation with a positive exponent +/// $result: iro-math-pow(3, 2); // The value of $result is 3^2 = 9 +/// +/// @example scss - Exponentiation with a negative exponent +/// $result: iro-math-pow(2, -3); // The value of $result is 1/(2^3) = 1/8 +/// +@function iro-math-pow($base, $exp) { + $value: 1; + + @if $exp > 0 { + @for $i from 1 through $exp { + $value: $value * $base; + } + } @else if $exp < 0 { + @for $i from 1 through -$exp { + $value: $value / $base; + } + } + + @return $value; +} + +/// +/// Clamp a number between a minimum and maximum value. +/// +/// @param {number} $value - Value to clamp +/// @param {number} $min - Minimum value +/// @param {number} $max - Maximum value +/// +/// @return {number} +/// +/// @example scss +/// $result: iro-math-clamp(20, 0, 10); // The value of $result is 10 +/// +/// @example scss +/// $result: iro-math-clamp(50, 20, 100); // The value of $result is 50 +/// +@function iro-math-clamp($value, $min, $max) { + @if $value < $min { + @return $min; + } + @if $value > $max { + @return $max; + } + @return $value; +} diff --git a/src/_props.scss b/src/_props.scss new file mode 100644 index 0000000..7377c88 --- /dev/null +++ b/src/_props.scss @@ -0,0 +1,281 @@ +//// +/// Property trees. +/// +/// Property trees allow you to organize properties in a tree structure (internally nested maps). +/// The intended use is to store all your properties at the beginning and for the rest of the +/// stylesheet you just get them. +/// +/// @group Property trees +/// +/// @access public +//// + +/// +/// The maximum depth of resolved iro-prop-ref() references. +/// +/// @type number +/// +$iro-props-native-assing-max-depth: 2 !default; + +/// +/// Indicate if property names must start with two dashes (--). +/// This is required if property trees are also used for native CSS custom properties. +/// +/// @type bool +/// +$iro-props-enforce-double-dashes: true !default; + +/// +/// Default tree name to use if no name is specified. +/// +/// @type string +/// +$iro-props-default-tree: 'default' !default; + +/// +/// List of all created property trees. +/// +/// @type list +/// +/// @access private +/// +$iro-props-trees: (); + +/// +/// Save a property tree. If a tree with the sane name already exists, the trees +/// will be merged. +/// +/// @param {map} $map - Map containing properties +/// @param {string} $tree [$iro-props-default-tree] - ID the map is saved as +/// @param {bool} $merge [false] - If a tree named $tree already exists and this value is set to true, they will be merged. Otherwise an error will be emitted. +/// +@mixin iro-props-save($map, $tree: $iro-props-default-tree, $merge: false) { + $noop: iro-props-save($map, $tree, $merge); +} + +/// +/// Save a property tree. +/// +/// @param {map} $map - Map containing properties +/// @param {string} $tree [$iro-props-default-tree] - ID the map is saved as +/// @param {bool} $merge [false] - If a tree named $tree already exists and this value is set to true, they will be merged. Otherwise an error will be emitted. +/// +@function iro-props-save($map, $tree: $iro-props-default-tree, $merge: false) { + $prop-map: null; + + @if $iro-props-enforce-double-dashes { + @if not iro-props-validate($map) { + @error 'Property tree keys must start with two dashes (--). If you don\'t use property trees for native CSS custom properties, set $iro-props-enforce-double-dashes to false.'; + } + } + + @if map-has-key($iro-props-trees, $tree) { + @if $merge { + $map: iro-map-merge-recursive(map-get($iro-props-trees, $tree), $map); + } @else { + @error 'Property tree #{inspect($tree)} does already exist.'; + } + } + + $iro-props-trees: map-merge($iro-props-trees, ($tree: $map)) !global; + + @return null; +} + +/// +/// Delete a property tree. +/// +/// @param {string} $tree [$iro-props-default-tree] - ID of the tree to be deleted +/// +@mixin iro-props-delete($tree: $iro-props-default-tree) { + $noop: iro-props-delete($tree); +} + +/// +/// Unset a property tree. +/// +/// @param {string} $tree [$iro-props-default-tree] - ID of the tree to be deleted +/// +/// @throw If the property tree does not exist +/// +@function iro-props-delete($tree: $iro-props-default-tree) { + @if not map-has-key($iro-props-trees, $tree) { + @error 'Property tree "#{inspect($tree)}" does not exist.'; + } + + $iro-props-trees: map-remove($iro-props-trees, $tree) !global; + + @return null; +} + +/// +/// Access a whole property or a subsection (i.e. value) of it. +/// +/// @param {string | list} $key [null] - Key of the property to read. If this is a list of keys, the map will be traversed in that order. +/// @param {string} $tree [$iro-props-default-tree] - ID of the property tree to use +/// @param {any} $default [null] - Default value to return of no match was found. If null, this function will throw an error instead. +/// +/// @return {any} Value assigned to property or $default +/// +/// @throw If there was no match for $key and $default is null +/// +@function iro-props-get($key: (), $tree: $iro-props-default-tree, $default: null) { + @if not map-has-key($iro-props-trees, $tree) { + @error 'Unknown tree "#{$tree}".'; + } + + $result: map-get($iro-props-trees, $tree); + + @if type-of($key) == list { + $stop: false; + + @each $k in $key { + @if map-has-key($result, $k) and not $stop { + $result: map-get($result, $k); + + @if type-of($result) == list and nth($result, 1) == 'iro-prop-ref' { + @if length($result) == 2 { + $result: iro-props-get($tree: nth($result, 2)); + } @else { + $result: iro-props-get(nth($result, 3), nth($result, 2)); + } + } + } @else { + $stop: true; + } + } + + @if $stop { + $result: null; + } + } @else { + $result: map-get($result, $key); + + @if type-of($result) == list and nth($result, 1) == 'iro-prop-ref' { + @if length($result) == 2 { + $result: iro-props-get($tree: nth($result, 2)); + } @else { + $result: iro-props-get(nth($result, 3), nth($result, 2)); + } + } + } + + @if $result == null { + @if $default == null { + @error '"#{$key}" is null.'; + } @else { + @return $default; + } + } + + @return $result; +} + +/// +/// Generate a var() function call to get native CSS custom property. +/// +/// @param {string | list} $key - Key of the property to read. If this is a list of keys, the map will be traversed in that order. +/// @param {string | null} $tree [null] - Optional tree to check if the property actually exists. +/// @param {any} $default [null] - Default value to return of no match was found. +/// +/// @return {string} var() +/// +@function iro-props-get-native($key, $tree: null, $default: null) { + @if $tree != null { + $noop: iro-props-get($key, $tree, $default); + } + + $native-var: ''; + + @if type-of($key) == list { + @each $subkey in $key { + $native-var: $native-var + $subkey; + } + } @else { + $native-var: $key; + } + + @if $default == null { + @return var(#{$native-var}); + } @else { + @return var(#{$native-var}, #{$default}); + } +} + +/// +/// Generate assignments for native CSS custom properties with the values from the specified tree. +/// +/// @param {string} $tree [$iro-props-default-tree] - ID of the property tree to use +/// @param {string} $root [()] - Sub-tree to use for assignment +/// +@mixin iro-props-assign-native($tree: $iro-props-default-tree, $root: (), $skip: ()) { + $map: iro-props-get($root, $tree); + $map: map-remove($map, $skip...); + + @include iro-props-assign-native-internal($map); +} + +/// +/// @access private +/// +@mixin iro-props-assign-native-internal($map, $prefix: '', $ref-depth: $iro-props-native-assing-max-depth) { + @each $key, $value in $map { + $rd: $ref-depth; + @if type-of($value) == list and nth($value, 1) == 'iro-prop-ref' { + @if $ref-depth != 0 { + $rd: $rd - 1; + @if length($value) == 2 { + $value: iro-props-get($tree: nth($value, 2)); + } @else { + $value: iro-props-get(nth($value, 3), nth($value, 2)); + } + } @else { + $value: null; + } + } + @if type-of($value) != map { + #{$prefix + $key}: #{$value}; + } @else { + @include iro-props-assign-native-internal($value, $prefix + $key, $rd); + } + } +} + +/// +/// Validate property names. +/// +/// @access private +/// +@function iro-props-validate($map) { + @each $key, $value in $map { + @if str-index($key, '--') != 1 { + @return false; + } + + @if type-of($value) == map { + @if not iro-props-validate($value) { + @return false; + } + } + } + + @return true; +} + +/// +/// Generate a reference to another tree. Dereferencing is lazy, so you may specify a tree that hasn't been created yet. +/// +/// @param {string} $tree [$iro-props-default-tree] - ID of the property tree to use +/// @param {string | list} $key - Key of the property to read. If this is a list of keys, the map will be traversed in that order. +/// +/// @return {list} A special list that let's Ignis know that this is a lazy value. +/// +/// @throw If there was no match for $key and $default is null +/// +@function iro-props-ref($tree: $iro-props-default-tree, $key: null) { + @if $key == null { + @return ('iro-prop-ref' $tree); + } @else { + @return ('iro-prop-ref' $tree $key); + } +} diff --git a/src/_responsive.scss b/src/_responsive.scss new file mode 100644 index 0000000..6f2a416 --- /dev/null +++ b/src/_responsive.scss @@ -0,0 +1,406 @@ +//// +/// responsive properties. +/// +/// The mixins and functions in this file allow you to scale any px- or rem-based value depending on +/// the available viewport width. One popular use case is the dynamic scaling of fonts. +/// +/// The code in this file is based on an article by Niklas Postulart: +/// http://niklaspostulart.de/2015/10/sass-responsive-type-mixin +/// +/// The following adjustments were made: +/// - Support any property passed by the user, not just font-size +/// - Allow multiple target viewports / values +/// - Provide a variant of the mixin which integrates include-media for media queries +/// +/// @group Responsive +/// +/// @access public +//// + +/// +/// If true, named viewports will be supported if a compatible $breakpoints map exists. +/// This is the case for [include-media](https://include-media.com/), for example. +/// +/// @type bool +/// +$iro-responsive-support-named-viewports: true !default; + +/// +/// Context ID used for responsive environment-related mixins. +/// +/// @type string +/// +$iro-responsive-context-id: 'responsive' !default; + +/// +/// Scale a property uniformly between a specific set of target viewports / values. +/// +/// @param {string | list} $props - Property or list of properties to set +/// @param {number} $responsive-map - A map with keys = viewports and values = target value +/// @param {bool} $fluid [true] - If enabled, property values will smoothly transition from one viewport to the next +/// @param {bool} $vertical [false] - If enabled, property viewport height will be used instead of viewport width +/// +/// @example scss - Responsive font-size between 2 viewports +/// .something { +/// @include iro-responsive-property(font-size, ( 320px: 20px, 720px: 30px )); +/// } +/// +/// // Generates: +/// +/// @media (min-width: 320px) and (max-width: 720px) { +/// .something { +/// font-size: calc(20px + 10 * ((100vw - 20px) / 400)); +/// } +/// } +/// +/// @media (max-width: 320px) { +/// .something { +/// font-size: 20px; +/// } +/// } +/// +/// @media (min-width: 720px) { +/// .something { +/// font-size: 30px; +/// } +/// } +/// +/// @example scss - Responsive font-size between 3 viewports +/// .something { +/// @include iro-responsive-property(font-size, ( 320px: 20px, 720px: 30px, 1280px: 40px )); +/// } +/// +/// // Generates: +/// +/// @media (min-width: 320px) and (max-width: 720px) { +/// .something { +/// font-size: calc(20px + 10 * ((100vw - 20px) / 400)); +/// } +/// } +/// +/// @media (min-width: 720px) and (max-width: 1280px) { +/// .something { +/// font-size: calc(30px + 10 * ((100vw - 30px) / 400)); +/// } +/// } +/// +/// @media (max-width: 320px) { +/// .something { +/// font-size: 20px; +/// } +/// } +/// +/// @media (min-width: 720px) { +/// .something { +/// font-size: 30px; +/// } +/// } +/// +@mixin iro-responsive-property($props, $responsive-map, $fluid: true, $vertical: false) { + @include iro-responsive-env(map-keys($responsive-map), $fluid, $vertical) { + @if type-of($props) == list { + @each $prop in $props { + #{$prop}: iro-responsive-set(map-values($responsive-map)); + } + } @else { + #{$props}: iro-responsive-set(map-values($responsive-map)); + } + } +} + +/// +/// Create a new responsive environment by specifying a set of viewports. +/// Inside a responsive environment, use the iro-responsive-set function to make a property scale automatically. +/// +/// @param {list} $viewports - Viewports sorted in ascending order +/// @param {bool} $fluid [true] - If enabled, property values will smoothly transition from one viewport to the next +/// @param {bool} $vertical [false] - If enabled, property viewport height will be used instead of viewport width +/// +/// @content +/// +/// @see {function} iro-responsive-set +/// +/// @example scss - Responsive font-size between 2 viewports +/// .something { +/// @include iro-responsive-env((320px, 720px)) { +/// font-size: iro-responsive-set(20px, 30px); +/// } +/// } +/// +/// // Generates: +/// +/// @media (min-width: 320px) and (max-width: 720px) { +/// .something { +/// font-size: calc(20px + 10 * ((100vw - 20px) / 400)); +/// } +/// } +/// +/// @media (max-width: 320px) { +/// .something { +/// font-size: 20px; +/// } +/// } +/// +/// @media (min-width: 720px) { +/// .something { +/// font-size: 30px; +/// } +/// } +/// +@mixin iro-responsive-env($viewports, $fluid: true, $vertical: false) { + @if length($viewports) <= 1 { + @error '$viewports must contain at least two viewports.'; + } + + $new-viewports: (); + + @each $viewport in $viewports { + @if $iro-responsive-support-named-viewports and global-variable-exists(breakpoints) { + @if map-has-key($breakpoints, $viewport) { + $viewport: map-get($breakpoints, $viewport); + } + } + + @if (type-of($viewport) != number) or unitless($viewport) { + @error '$viewports contains invalid viewports.'; + } + + $new-viewports: append($new-viewports, $viewport); + } + + $viewports: iro-quicksort($new-viewports); + + @if $new-viewports != $viewports { + @error '$viewports was not sorted in ascending order.'; + } + + @if $fluid { + $first-vp: nth($viewports, 1); + $last-vp: nth($viewports, length($viewports)); + + @include iro-context-push($iro-responsive-context-id, 'env', ( + 'viewports': $viewports, + 'mode': set, + 'index': 1, + 'fluid': $fluid, + 'vertical': $vertical, + )); + + @content; + + @include iro-context-pop($iro-responsive-context-id); + + @for $i from 1 to length($viewports) { + $prev-vp: nth($viewports, $i); + $next-vp: nth($viewports, $i + 1); + + @if not $vertical { + @media (min-width: $prev-vp) and (max-width: $next-vp) { + @include iro-context-push($iro-responsive-context-id, 'env', ( + 'viewports': $viewports, + 'mode': transition, + 'index': $i, + 'fluid': $fluid, + 'vertical': $vertical, + )); + + @content; + + @include iro-context-pop($iro-responsive-context-id); + } + } @else { + @media (min-height: $prev-vp) and (max-height: $next-vp) { + @include iro-context-push($iro-responsive-context-id, 'env', ( + 'viewports': $viewports, + 'mode': transition, + 'index': $i, + 'fluid': $fluid, + 'vertical': $vertical, + )); + + @content; + + @include iro-context-pop($iro-responsive-context-id); + } + } + } + + @if not $vertical { + @media (min-width: $last-vp) { + @include iro-context-push($iro-responsive-context-id, 'env', ( + 'viewports': $viewports, + 'mode': set, + 'index': length($viewports), + 'fluid': $fluid, + 'vertical': $vertical, + )); + + @content; + + @include iro-context-pop($iro-responsive-context-id); + } + } @else { + @media (min-height: $last-vp) { + @include iro-context-push($iro-responsive-context-id, 'env', ( + 'viewports': $viewports, + 'mode': set, + 'index': length($viewports), + 'fluid': $fluid, + 'vertical': $vertical, + )); + + @content; + + @include iro-context-pop($iro-responsive-context-id); + } + } + } @else { + @include iro-context-push($iro-responsive-context-id, 'env', ( + 'viewports': $viewports, + 'mode': set, + 'index': 1, + 'fluid': $fluid, + 'vertical': $vertical, + )); + + @content; + + @include iro-context-pop($iro-responsive-context-id); + + @for $i from 2 through length($viewports) { + $vp: nth($viewports, $i); + + @if not $vertical { + @media (min-width: $vp) { + @include iro-context-push($iro-responsive-context-id, 'env', ( + 'viewports': $viewports, + 'mode': set, + 'index': $i + )); + + @content; + + @include iro-context-pop($iro-responsive-context-id); + } + } @else { + @media (min-height: $vp) { + @include iro-context-push($iro-responsive-context-id, 'env', ( + 'viewports': $viewports, + 'mode': set, + 'index': $i + )); + + @content; + + @include iro-context-pop($iro-responsive-context-id); + } + } + } + } +} + +/// +/// Make a property scale automatically inside a responsive environment. +/// +/// @param {list} $values - Value for each viewport in the responsive environment. The first value will be used for the first viewport, the second value for the second viewport, and so on. +/// +/// @return {number|string} +/// +@function iro-responsive-set($values, $without-calc: false) { + $noop: iro-context-assert-stack-must-contain($iro-responsive-context-id, 'env'); + + $data: nth(iro-context-get($iro-responsive-context-id, 'env'), 2); + $viewports: map-get($data, 'viewports'); + $mode: map-get($data, 'mode'); + $fluid: map-get($data, 'fluid'); + $vertical: map-get($data, 'vertical'); + + @if length($values) != length($viewports) { + @error '$values must contain the same number of items as the responsive environment\'s $viewports.'; + } + + @if $mode == set { + @return nth($values, map-get($data, 'index')); + } @else { + $index: map-get($data, 'index'); + $prev-vp: nth($viewports, $index); + $next-vp: nth($viewports, $index + 1); + $prev-value: nth($values, $index); + $next-value: nth($values, $index + 1); + + @return iro-responsive-fluid-calc($prev-value, $next-value, $prev-vp, $next-vp, $vertical, $without-calc); + } +} + +/// +/// Generate the calc() function that uniformly scales a value from $min-value to $max-value depending +/// on the viewport width. +/// +/// @param {number} $min-value - Minimum value +/// @param {number} $max-value - Maximum value +/// @param {number} $min-viewport - Minimum viewport size +/// @param {number} $max-viewport - Maximum viewport size +/// @param {bool} $vertical [false] - If enabled, property viewport height will be used instead of viewport width +/// +/// @access private +/// +@function iro-responsive-fluid-calc($min-value, $max-value, $min-viewport, $max-viewport, $vertical: false, $without-calc: false) { + $value-unit: unit($min-value); + $max-value-unit: unit($max-value); + $viewport-unit: unit($min-viewport); + $max-viewport-unit: unit($max-viewport); + + @if $min-value == 0 { + $value-unit: $max-value-unit; + } + @if $max-value == 0 { + $max-value-unit: $value-unit; + } + @if $min-viewport == 0 { + $viewport-unit: $max-viewport-unit; + } + @if $max-viewport == 0 { + $max-viewport-unit: $viewport-unit; + } + + @if ($value-unit != $max-value-unit) or ($viewport-unit != $max-viewport-unit) { + @error 'Units of $min-value and $max-value, $min-viewport and $max-viewport must match.'; + } + + @if ($value-unit == rem) and ($viewport-unit == px) { + $min-viewport: iro-px-to-rem($min-viewport); + $max-viewport: iro-px-to-rem($max-viewport); + $viewport-unit: rem; + } @else if ($value-unit == px) and ($viewport-unit == rem) { + $min-value: iro-px-to-rem($min-value); + $max-value: iro-px-to-rem($max-value); + $value-unit: rem; + } + + @if $value-unit != $viewport-unit { + @error 'This combination of units is not supported.'; + } + + $value-diff: iro-strip-unit($max-value - $min-value); + $viewport-diff: iro-strip-unit($max-viewport - $min-viewport); + + $calc: ''; + + @if $min-value != 0 { + $calc: '#{$min-value} + '; + } + + @if not $vertical { + $calc: unquote('#{$calc}#{$value-diff} * ((100vw - #{$min-viewport}) / #{$viewport-diff})'); + } @else { + $calc: unquote('#{$calc}#{$value-diff} * ((100vh - #{$min-viewport}) / #{$viewport-diff})'); + } + + @if $without-calc { + @return $calc; + } @else { + @return calc(#{$calc}); + } +} + +@include iro-context-stack-create($iro-responsive-context-id); diff --git a/src/_vars.scss b/src/_vars.scss new file mode 100644 index 0000000..ce6efda --- /dev/null +++ b/src/_vars.scss @@ -0,0 +1,16 @@ +//// +/// Variables. +/// +/// Global variables that are used throughout the framework. +/// +/// @group Global variables +/// +/// @access public +//// + +/// +/// Reference root font size in px that is used for px -> rem conversions. +/// +/// @type number +/// +$iro-root-size: 16px !default; diff --git a/src/bem-shortcodes.scss b/src/bem-shortcodes.scss new file mode 100644 index 0000000..11abeed --- /dev/null +++ b/src/bem-shortcodes.scss @@ -0,0 +1,349 @@ +//// +/// Shorter version of the bem-related mixins. Useful to reduce clutter. +/// +/// @group BEM shortcodes +/// +/// @access public +//// + +/// +/// @alias iro-bem-block +/// +@mixin block($name, $type: null) { + @include iro-bem-block($name, $type: null) { + @content; + } +} + +/// +/// @alias block +/// +@mixin b($name, $type: null) { + @include block($name, $type: null) { + @content; + } +} + +/// +/// @alias iro-bem-object +/// +@mixin object($name) { + @include iro-bem-object($name) { + @content; + } +} + +/// +/// @alias object +/// +@mixin ob($name) { + @include object($name) { + @content; + } +} + +/// +/// @alias iro-bem-component +/// +@mixin component($name) { + @include iro-bem-component($name) { + @content; + } +} + +/// +/// @alias component +/// +@mixin cb($name) { + @include component($name) { + @content; + } +} + +/// +/// @alias iro-bem-layout +/// +@mixin layout($name) { + @include iro-bem-layout($name) { + @content; + } +} + +/// +/// @alias layout +/// +@mixin lb($name) { + @include layout($name) { + @content; + } +} + +/// +/// @alias iro-bem-utility +/// +@mixin utility($name) { + @include iro-bem-utility($name) { + @content; + } +} + +/// +/// @alias utility +/// +@mixin ub($name) { + @include utility($name) { + @content; + } +} + +/// +/// @alias iro-bem-scope +/// +@mixin scope($name) { + @include iro-bem-scope($name) { + @content; + } +} + +/// +/// @alias scope +/// +@mixin sb($name) { + @include scope($name) { + @content; + } +} + +/// +/// @alias iro-bem-theme +/// +@mixin theme($name) { + @include iro-bem-theme($name) { + @content; + } +} + +/// +/// @alias theme +/// +@mixin tb($name) { + @include theme($name) { + @content; + } +} + +/// +/// @alias iro-bem-js +/// +@mixin js($name) { + @include iro-bem-js($name) { + @content; + } +} + +/// +/// @alias iro-bem-qa +/// +@mixin qa($name) { + @include iro-bem-qa($name) { + @content; + } +} + +/// +/// @alias iro-bem-hack +/// +@mixin hack($name) { + @include iro-bem-hack($name) { + @content; + } +} + +/// +/// @alias iro-bem-composed-of +/// +@mixin composed-of($block, $blocks...) { + @include iro-bem-composed-of($block, $blocks...) { + @content; + } +} + +/// +/// @alias composed-of +/// +@mixin co($block, $blocks...) { + @include composed-of($block, $blocks...) { + @content; + } +} + +/// +/// @alias iro-bem-element +/// +@mixin element($name, $names...) { + @include iro-bem-element($name, $names...) { + @content; + } +} + +/// +/// @alias element +/// +@mixin e($name, $names...) { + @include element($name, $names...) { + @content; + } +} + +/// +/// @alias iro-bem-related-element +/// +@mixin related-element($sign, $name, $names...) { + @include iro-bem-related-element($sign, $name, $names...) { + @content; + } +} + +/// +/// @alias related-element +/// +@mixin re($sign, $name, $names...) { + @include related-element($sign, $name, $names...) { + @content; + } +} + +/// +/// @alias iro-bem-sibling-element +/// +@mixin sibling-element($name, $names...) { + @include iro-bem-sibling-element($name, $names...) { + @content; + } +} + +/// +/// @alias sibling-element +/// +@mixin se($name, $names...) { + @include sibling-element($name, $names...) { + @content; + } +} + +/// +/// @alias iro-bem-next-element +/// +@mixin next-element($name, $names...) { + @include iro-bem-next-element($name, $names...) { + @content; + } +} + +/// +/// @alias next-element +/// +@mixin ne($name, $names...) { + @include next-element($name, $names...) { + @content; + } +} + +/// +/// @alias iro-bem-next-twin-element +/// +@mixin next-twin-element { + @include iro-bem-next-twin-element { + @content; + } +} + +/// +/// @alias next-twin-element +/// +@mixin te { + @include next-twin-element { + @content; + } +} + +/// +/// @alias iro-bem-modifier +/// +@mixin modifier($name, $names...) { + @include iro-bem-modifier($name, $names...) { + @content; + } +} + +/// +/// @alias modifier +/// +@mixin m($name, $names...) { + @include modifier($name, $names...) { + @content; + } +} + +/// +/// @alias iro-bem-suffix +/// +@mixin suffix($name) { + @include iro-bem-suffix($name) { + @content; + } +} + +/// +/// @alias suffix +/// +@mixin s($name) { + @include suffix($name) { + @content; + } +} + +/// +/// @alias iro-bem-is +/// +@mixin is($state, $states...) { + @include iro-bem-is($state, $states...) { + @content; + } +} + +/// +/// @alias iro-bem-has +/// +@mixin has($state, $states...) { + @include iro-bem-has($state, $states...) { + @content; + } +} + +/// +/// @alias iro-bem-at-theme +/// +@mixin at-theme($name, $names...) { + @include iro-bem-at-theme($name, $names...) { + @content; + } +} + +/// +/// @alias theme +/// +@mixin at($name, $names...) { + @include at-theme($name, $names...) { + @content; + } +} + +/// +/// @alias iro-bem-multi +/// +@mixin multi($first, $others...) { + @include iro-bem-multi($first, $others...) { + @content; + } +} diff --git a/src/bem/_block.scss b/src/bem/_block.scss new file mode 100644 index 0000000..d065891 --- /dev/null +++ b/src/bem/_block.scss @@ -0,0 +1,392 @@ +//// +/// @group BEM +/// +/// @access public +//// + +/// +/// Generate a new block. +/// +/// This mixin simply creates a new block with the name {namespace}_{name}, +/// where {namespace} is the prefix assigned to $type and {name} is the +/// block's name. +/// +/// @param {string} $name - Block name +/// @param {string} $type [null] - BEMIT namespace of the block +/// +/// @content +/// +/// @throw If $type is invalid +/// @throw If the block is preceded by another block, element, modifier or suffix +/// +/// @example scss - Creating a new block +/// @include iro-bem-block('something', 'component') { +/// /* some definitions */ +/// } +/// +/// // Generates: +/// +/// .c-something { +/// /* some definitions */ +/// } +/// +@mixin iro-bem-block($name, $type: null) { + $result: iro-bem-block($name, $type); + $selector: nth($result, 1); + $context: nth($result, 2); + + @include iro-bem-validate( + 'block', + (name: $name, type: $type), + $selector, + $context + ); + + @if $type != null { + $iro-bem-blocks: append($iro-bem-blocks, $name + '_' + $type) !global; + } @else { + $iro-bem-blocks: append($iro-bem-blocks, $name) !global; + } + + @include iro-context-push($iro-bem-context-id, $context...); + @at-root #{$selector} { + @content; + } + @include iro-context-pop($iro-bem-context-id); +} + +/// +/// Generate a new block. Check the respective mixin documentation for more information. +/// +/// @return {list} A list with two items: 1. selector, 2. context or `null` +/// +/// @see {mixin} iro-bem-block +/// +@function iro-bem-block($name, $type: null) { + // + // Possible outcomes: + // - ({b,e,m,s}) block + // + + $noop: iro-context-assert-stack-count($iro-bem-context-id, $iro-bem-max-depth); + + $selector: null; + $base-selector: null; + + @if $type != null { + $namespace: map-get($iro-bem-namespaces, $type); + + @if not $namespace { + @error '"#{$type}" is not a valid type.'; + } + + $base-selector: selector-parse('.' + $namespace + '-' + $name); + + @if $type != 'theme' or & { + $selector: $base-selector; + } @else if not & { + $selector: iro-bem-theme-selector($name); + } + } @else { + $base-selector: selector-parse('.' + $name); + $selector: $base-selector; + } + + @if & { + $selector: selector-nest(&, $selector); + } + + $context: 'block', ( + 'name': $name, + 'type': $type, + 'selector': $selector, + 'base-selector': $base-selector + ); + + @return $selector $context; +} + +/// +/// Generate a new object block. It's a shorthand for iro-bem-block($name, 'object'). +/// +/// @param {string} $name - Object block name +/// +/// @content +/// +@mixin iro-bem-object($name) { + @include iro-bem-block($name, 'object') { + @content; + } +} + +/// +/// Generate a new object block. Check the respective mixin documentation for more information. +/// +/// @return {list} A list with two items: 1. selector, 2. context or `null` +/// +/// @see {mixin} iro-bem-object +/// +@function iro-bem-object($name) { + @return iro-bem-block($name, 'object'); +} + +/// +/// Generate a new component block. It's a shorthand for iro-bem-block($name, 'component'). +/// +/// @param {string} $name - Component block name +/// +/// @content +/// +@mixin iro-bem-component($name) { + @include iro-bem-block($name, 'component') { + @content; + } +} + +/// +/// Generate a new component block. Check the respective mixin documentation for more information. +/// +/// @return {list} A list with two items: 1. selector, 2. context or `null` +/// +/// @see {mixin} iro-bem-component +/// +@function iro-bem-component($name) { + @return iro-bem-block($name, 'component'); +} + +/// +/// Generate a new layout block. It's a shorthand for iro-bem-block($name, 'layout'). +/// +/// @param {string} $name - Layout block name +/// +/// @content +/// +@mixin iro-bem-layout($name) { + @include iro-bem-block($name, 'layout') { + @content; + } +} + +/// +/// Generate a new layout block. Check the respective mixin documentation for more information. +/// +/// @return {list} A list with two items: 1. selector, 2. context or `null` +/// +/// @see {mixin} iro-bem-layout +/// +@function iro-bem-layout($name) { + @return iro-bem-block($name, 'layout'); +} + +/// +/// Generate a new utility block. It's a shorthand for iro-bem-block($name, 'utility'). +/// +/// @param {string} $name - Utility block name +/// +/// @content +/// +@mixin iro-bem-utility($name) { + @include iro-bem-block($name, 'utility') { + @content; + } +} + +/// +/// Generate a new utility block. Check the respective mixin documentation for more information. +/// +/// @return {list} A list with two items: 1. selector, 2. context or `null` +/// +/// @see {mixin} iro-bem-utility +/// +@function iro-bem-utility($name) { + @return iro-bem-block($name, 'utility'); +} + +/// +/// Generate a new scope block. It's a shorthand for iro-bem-block($name, 'scope'). +/// +/// @param {string} $name - Scope block name +/// +/// @content +/// +@mixin iro-bem-scope($name) { + @include iro-bem-block($name, 'scope') { + @content; + } +} + +/// +/// Generate a new scope block. Check the respective mixin documentation for more information. +/// +/// @return {list} A list with two items: 1. selector, 2. context or `null` +/// +/// @see {mixin} iro-bem-scope +/// +@function iro-bem-scope($name) { + @return iro-bem-block($name, 'scope'); +} + +/// +/// Generate a new theme block. It's a shorthand for iro-bem-block($name, 'theme'). +/// +/// @param {string} $name - Theme block name +/// +/// @content +/// +@mixin iro-bem-theme($name) { + @include iro-bem-block($name, 'theme') { + @content; + } +} + +/// +/// Generate a new theme block. Check the respective mixin documentation for more information. +/// +/// @return {list} A list with two items: 1. selector, 2. context or `null` +/// +/// @see {mixin} iro-bem-theme +/// +@function iro-bem-theme($name) { + @return iro-bem-block($name, 'theme'); +} + +/// +/// Generate a new JS block. It's a shorthand for iro-bem-block($name, 'js'). +/// +/// @param {string} $name - JS block name +/// +/// @content +/// +@mixin iro-bem-js($name) { + @include iro-bem-block($name, 'js') { + @content; + } +} + +/// +/// Generate a new JS block. Check the respective mixin documentation for more information. +/// +/// @return {list} A list with two items: 1. selector, 2. context or `null` +/// +/// @see {mixin} iro-bem-js +/// +@function iro-bem-js($name) { + @return iro-bem-block($name, 'js'); +} + +/// +/// Generate a new QA block. It's a shorthand for iro-bem-block($name, 'qa'). +/// +/// @param {string} $name - QA block name +/// +/// @content +/// +@mixin iro-bem-qa($name) { + @include iro-bem-block($name, 'qa') { + @content; + } +} + +/// +/// Generate a new QA block. Check the respective mixin documentation for more information. +/// +/// @return {list} A list with two items: 1. selector, 2. context or `null` +/// +/// @see {mixin} iro-bem-qa +/// +@function iro-bem-qa($name) { + @return iro-bem-block($name, 'qa'); +} + +/// +/// Generate a new hack block. It's a shorthand for iro-bem-block($name, 'hack'). +/// +/// @param {string} $name - Hack block name +/// +/// @content +/// +@mixin iro-bem-hack($name) { + @include iro-bem-block($name, 'hack') { + @content; + } +} + +/// +/// Generate a new hack block. Check the respective mixin documentation for more information. +/// +/// @return {list} A list with two items: 1. selector, 2. context or `null` +/// +/// @see {mixin} iro-bem-hack +/// +@function iro-bem-hack($name) { + @return iro-bem-block($name, 'hack'); +} + +/// +/// Assert that a block or element is composed of another block. In BEM, such a relationship is referred to +/// as a "mix": https://en.bem.info/methodology/key-concepts/#mix +/// +/// Compilation will fail if the foreign block doesn't exist. This way, you can ensure that blocks are +/// defined in the right order so that composed blocks/elements will actually override the foreign +/// declarations without having to artificially increase the specificity. +/// +/// @param {string | list} $block - Either first block name, or list with two items: 1. block name, 2. block type +/// @param {string | list} $blocks - Either other block names, or list with two items: 1. block name, 2. block type +/// +/// @throw If a block type is invalid +/// @throw If a block doesn't exist +/// +/// @example scss - Successful assertion +/// @include iro-bem-component('someBlock') { +/// /* some definitions */ +/// } +/// +/// @include iro-bem-component('anotherBlock') { +/// /* some definitions */ +/// +/// @include iro-bem-element('elem') { +/// @include iro-bem-composed-of('someBlock' 'component'); +/// +/// /* some definitions */ +/// } +/// } +/// +/// // Intended use:
...
+/// +/// @example scss - Failing assertion +/// @include iro-bem-component('anotherBlock') { +/// /* some definitions */ +/// +/// @include iro-bem-element('elem') { +/// @include iro-bem-composed-of('someBlock' 'component'); +/// +/// /* some definitions */ +/// } +/// } +/// +/// @include iro-bem-component('someBlock') { +/// /* some definitions */ +/// } +/// +/// // Compilation will fail because c-someBlock is defined after c-anotherBlock__elem +/// +@mixin iro-bem-composed-of($block, $blocks...) { + @each $block in iro-list-prepend($blocks, $block) { + @if type-of($block) == string { + @if not index($iro-bem-blocks, $block) { + @error 'Block "#{$block}" does not exist.'; + } + } @else { + $name: nth($block, 1); + $type: nth($block, 2); + + @if not map-get($iro-bem-namespaces, $type) { + @error '"#{$type}" is not a valid type.'; + } + + @if not index($iro-bem-blocks, $name + '_' + $type) { + @error 'Block "#{$name}" does not exist.'; + } + } + } +} diff --git a/src/bem/_debug.scss b/src/bem/_debug.scss new file mode 100644 index 0000000..e69083c --- /dev/null +++ b/src/bem/_debug.scss @@ -0,0 +1,16 @@ +//// +/// @group BEM +/// +/// @access public +//// + +@if $iro-bem-debug { + @each $type, $color in $iro-bem-debug-colors { + $namespace: map-get($iro-bem-namespaces, $type); + + [class^='#{$namespace}-'], + [class*=' #{$namespace}-'] { + outline: 5px solid $color; + } + } +} diff --git a/src/bem/_element.scss b/src/bem/_element.scss new file mode 100644 index 0000000..b3d2fee --- /dev/null +++ b/src/bem/_element.scss @@ -0,0 +1,622 @@ +//// +/// @group BEM +/// +/// @access public +//// + +/// +/// Generate a new BEM element. +/// +/// The element will be generated according to the BEM naming convention. +/// If the parent selector doesn't match the block selector, the element will be +/// nested inside the parent selector. This means, you may nest elements inside +/// other elements, modifiers or any kind of selector such as &:hover. +/// +/// @param {string} $name - First element name +/// @param {string} $names - More element names +/// +/// @content +/// +/// @throw If the element is not preceded by a block, element, modifier or suffix. +/// +/// @example scss - Element for a block +/// @include iro-bem-component('block') { +/// /* some block definitions */ +/// +/// @include iro-bem-element('elem') { +/// /* some element definitions */ +/// } +/// } +/// +/// // Generates: +/// +/// .c-block { +/// /* some block definitions */ +/// } +/// +/// .c-block__elem { +/// /* some element definitions */ +/// } +/// +/// @example scss - Element that is affected by the user hovering the block +/// @include iro-bem-component('block') { +/// /* some block definitions */ +/// +/// @include iro-bem-element('elem') { +/// background-color: #eee; +/// } +/// +/// &:hover { +/// @include iro-bem-element('elem') { +/// background-color: #000; +/// } +/// } +/// } +/// +/// // Generates: +/// +/// .c-block { +/// /* some block definitions */ +/// } +/// +/// .c-block__elem { +/// background-color: #eee; +/// } +/// +/// .c-block:hover .c-block__elem { +/// background-color: #000; +/// } +/// +/// @example scss - Multiple elements +/// @include iro-bem-component('block') { +/// /* some block definitions */ +/// +/// @include iro-bem-element('elem1', 'elem2') { +/// /* some element definitions */ +/// } +/// } +/// +/// // Generates: +/// +/// .c-block { +/// /* some block definitions */ +/// } +/// +/// .c-block__elem1, .c-block__elem2 { +/// /* some element definitions */ +/// } +/// +@mixin iro-bem-element($name, $names...) { + $result: iro-bem-element($name, $names...); + $selector: nth($result, 1); + $context: nth($result, 2); + + @include iro-bem-validate( + 'element', + (name: $name, names: $names), + $selector, + $context + ); + + @include iro-context-push($iro-bem-context-id, $context...); + @at-root #{$selector} { + @content; + } + @include iro-context-pop($iro-bem-context-id); +} + +/// +/// Generate a new BEM element. Check the respective mixin documentation for more information. +/// +/// @return {list} A list with two items: 1. selector, 2. context or `null` +/// +/// @see {mixin} iro-bem-element +/// +@function iro-bem-element($name, $names...) { + $noop: iro-context-assert-stack-count($iro-bem-context-id, $iro-bem-max-depth); + $noop: iro-context-assert-stack-must-contain($iro-bem-context-id, 'block'); + + $parent-context: iro-context-get($iro-bem-context-id, 'block' 'element'); + + $selector: (); + $parts-data: (); + + @if nth($parent-context, 1) == 'element' { + @if $iro-bem-element-nesting-policy == 'disallow' { + @error 'Element nesting is forbidden.'; + } + + @if $iro-bem-element-nesting-policy == 'append' { + $element-selector: map-get(nth($parent-context, 2), 'selector'); + + @if not iro-selector-suffix-match(&, $element-selector) { + @error 'A nested element must be an immediate children of the parent element.'; + } + + // + // Possible outcomes: + // - {e}__element + // - [manual selector] {e}__element + // + + @each $name in join($name, $names) { + $sel: selector-append(&, $iro-bem-element-separator + $name); + $selector: join($selector, $sel, comma); + $parts-data: append($parts-data, ( + 'name': $name, + 'selector': $sel + )); + } + } + + $parent-context: iro-context-get($iro-bem-context-id, 'block'); + } + + @if length($selector) == 0 { + $parent-selector: map-get(nth($parent-context, 2), 'selector'); + + @if iro-selector-suffix-match(&, $parent-selector) { + // + // Possible outcomes: + // - {b}__element + // - [manual selector] {b}__element + // + + @each $name in join($name, $names) { + $sel: selector-append(&, $iro-bem-element-separator + $name); + $selector: join($selector, $sel, comma); + $parts-data: append($parts-data, ( + 'name': $name, + 'selector': $sel + )); + } + } @else { + // + // Possible outcomes: + // - {b} [manual selector] {b}__element + // - {e,m,s} ([manual selector]) {b}__element + // + + @if nth($parent-context, 1) != 'block' { + $parent-context: iro-context-get($iro-bem-context-id, 'block'); + } + + $block-base-selector: map-get(nth($parent-context, 2), 'base-selector'); + + @each $name in join($name, $names) { + $sel: selector-nest(&, selector-append($block-base-selector, $iro-bem-element-separator + $name)); + $selector: join($selector, $sel, comma); + $parts-data: append($parts-data, ( + 'name': $name, + 'selector': $sel + )); + } + } + } + + $context: 'element', ( + 'parts': $parts-data, + 'selector': $selector + ); + + @return $selector $context; +} + +/// +/// Generate a BEM element that is related to the current element. +/// +/// The generated element selector is appended to the current element selector. The $sign +/// determines the relationship. +/// +/// @param {string} $sign - Relationshop sign, either '+' or '~' +/// @param {string} $name - First element name +/// @param {string} $names - More element names +/// +/// @content +/// +/// @throw If the element is not preceded by an element. +/// +/// @example scss - A sibling element to a single element +/// @include iro-bem-component('block') { +/// @include iro-bem-element('elem') { +/// /* some element definitions */ +/// +/// @include iro-bem-related-element('~', 'sibling') { +/// /* some sibling element definitions */ +/// } +/// } +/// } +/// +/// // Generates: +/// +/// .c-block__elem { +/// /* some element definitions */ +/// } +/// +/// .c-block__elem ~ .c-block__sibling { +/// /* some sibling element definitions */ +/// } +/// +/// @example scss - A successor element to a single element +/// @include iro-bem-component('block') { +/// @include iro-bem-element('elem') { +/// /* some element definitions */ +/// +/// @include iro-bem-related-element('+', 'successor') { +/// /* some successor element definitions */ +/// } +/// } +/// } +/// +/// // Generates: +/// +/// .c-block__elem { +/// /* some element definitions */ +/// } +/// +/// .c-block__elem + .c-block__successor { +/// /* some successor element definitions */ +/// } +/// +/// @example scss - A successor element to multiple elements +/// @include iro-bem-component('block') { +/// @include iro-bem-element('elem1', 'elem2') { +/// /* some element definitions */ +/// +/// @include iro-bem-related-element('+', 'successor') { +/// /* some successor element definitions */ +/// } +/// } +/// } +/// +/// // Generates: +/// +/// .c-block__elem1, .c-block__elem2 { +/// /* some element definitions */ +/// } +/// +/// .c-block__elem1 + .c-block__successor, .c-block__elem2 + .c-block__successor { +/// /* some successor element definitions */ +/// } +/// +@mixin iro-bem-related-element($sign, $name, $names...) { + $result: iro-bem-related-element($sign, $name, $names...); + $selector: nth($result, 1); + $context: nth($result, 2); + + @include iro-bem-validate( + 'related-element', + (sign: $sign, name: $name, names: $names), + $selector, + $context + ); + + @include iro-context-push($iro-bem-context-id, $context...); + @at-root #{$selector} { + @content; + } + @include iro-context-pop($iro-bem-context-id); +} + +/// +/// Generate a new BEM element that is related to the current element. +/// Check the respective mixin documentation for more information. +/// +/// @return {list} A list with two items: 1. selector, 2. context or `null` +/// +/// @see {mixin} iro-bem-related-element +/// +@function iro-bem-related-element($sign, $name, $names...) { + // + // Generating this selector is simple: Take the latest block context, use it + // to generate the element part, and insert it at the end of the current selector. + // Possible outcomes: + // - {e} ({m,s}) ([manual selector]) + {e} + // - {e} ({m,s}) ([manual selector]) ~ {e} + // + + $noop: iro-context-assert-stack-count($iro-bem-context-id, $iro-bem-max-depth); + $noop: iro-context-assert-stack-must-contain($iro-bem-context-id, 'element'); + + @if $sign != '+' and $sign != '~' { + @error 'Invalid relationship sign #{inspect($sign)}.'; + } + + $block-context: iro-context-get($iro-bem-context-id, 'block'); + $block-base-selector: map-get(nth($block-context, 2), 'base-selector'); + + $selector: (); + $parts-data: (); + + @each $name in join($name, $names) { + $sel: selector-nest(&, $sign, selector-append($block-base-selector, $iro-bem-element-separator + $name)); + $selector: join($selector, $sel, comma); + $parts-data: append($parts-data, ( + 'name': $name, + 'selector': $sel + )); + } + + $context: 'element', ( + 'parts': $parts-data, + 'selector': $selector + ); + + @return $selector $context; +} + +/// +/// Generate a BEM element that is a sibling of the current element. +/// +/// It's a shorthand for iro-bem-related-element('~', $name). +/// +/// @param {string} $name - First element name +/// @param {list} $names - List of more element names +/// +/// @content +/// +@mixin iro-bem-sibling-element($name, $names...) { + @include iro-bem-related-element('~', $name, $names...) { + @content; + } +} + +/// +/// Generate a new BEM element that is a sibling of the current element. +/// Check the respective mixin documentation for more information. +/// +/// @return {list} A list with two items: 1. selector, 2. context or `null` +/// +/// @see {mixin} iro-bem-sibling-element +/// +@function iro-bem-sibling-element($name, $names...) { + @return iro-bem-related-element('~', $name, $names...); +} + +/// +/// Generate a BEM element that is the successor of the current element. +/// +/// It's a shorthand for iro-bem-related-element('+', $name). +/// +/// @param {string} $name - First element name +/// @param {string} $names - More element names +/// +/// @content +/// +@mixin iro-bem-next-element($name, $names...) { + @include iro-bem-related-element('+', $name, $names...) { + @content; + } +} + +/// +/// Generate a new BEM element that is the successor of the current element. +/// Check the respective mixin documentation for more information. +/// +/// @return {list} A list with two items: 1. selector, 2. context or `null` +/// +/// @see {mixin} iro-bem-next-element +/// +@function iro-bem-next-element($name, $names...) { + @return iro-bem-related-element('+', $name, $names...); +} + +/// +/// Generate the current BEM element as a successor of itself. +/// +/// If this is applied to a single element, it behaves exactly the same as +/// iro-bem-related-element('+', name); +/// However, if it is applied to multiple elements, each twin element only will influence +/// their other twin, which is not replicable with iro-bem-related-element. +/// +/// @content +/// +/// @example scss - Two twin elements +/// @include iro-bem-component('block') { +/// @include iro-bem-element('elem') { +/// /* some element definitions */ +/// +/// @include iro-bem-next-twin-element { +/// /* some twin element definitions */ +/// } +/// } +/// } +/// +/// // Generates: +/// +/// .c-block__elem { +/// /* some element definitions */ +/// } +/// +/// .c-block__elem + .c-block__elem { +/// /* some twin element definitions */ +/// } +/// +/// @example scss - Multiple twin elements +/// @include iro-bem-component('block') { +/// @include iro-bem-element('elem1', 'elem2') { +/// /* some element definitions */ +/// +/// @include iro-bem-next-twin-element { +/// /* some twin element definitions */ +/// } +/// } +/// } +/// +/// // Generates: +/// +/// .c-block__elem1, .c-block__elem2 { +/// /* some element definitions */ +/// } +/// +/// .c-block__elem1 + .c-block__elem1, .c-block__elem2 + .c-block__elem2 { +/// /* some twin element definitions */ +/// } +/// +@mixin iro-bem-related-twin-element($sign) { + $result: iro-bem-related-twin-element($sign); + $selector: nth($result, 1); + $context: nth($result, 2); + + @include iro-bem-validate( + 'next-twin-element', + (), + $selector, + $context + ); + + @include iro-context-push($iro-bem-context-id, $context...); + @at-root #{$selector} { + @content; + } + @include iro-context-pop($iro-bem-context-id); +} + +/// +/// Generate the current BEM element as a successor of itself. +/// Check the respective mixin documentation for more information. +/// +/// @return {list} A list with two items: 1. selector, 2. context or `null` +/// +/// @see {mixin} iro-bem-next-twin-element +/// +@function iro-bem-related-twin-element($sign) { + $noop: iro-context-assert-stack-count($iro-bem-context-id, $iro-bem-max-depth); + $noop: iro-context-assert-stack-must-contain($iro-bem-context-id, 'element'); + + $element-context: iro-context-get($iro-bem-context-id, 'element'); + $element-selector: map-get(nth($element-context, 2), 'selector'); + + $block-context: iro-context-get($iro-bem-context-id, 'block'); + $block-base-selector: map-get(nth($block-context, 2), 'base-selector'); + + $selector: (); + $parts-data: (); + + // + // To determine the twin for each element, iterate the sub-selectors from the current selector + // and check if it contains the currently inspected element. This has to be done with string + // comparison since none of Sass selector functions is of use here. + // Finally, the current twin will be appended to the extracted sub-selector as a successor + // element. + // + @each $part-data in map-get(nth($element-context, 2), 'parts') { + $part-selector: map-get($part-data, 'selector'); + $part-name: map-get($part-data, 'name'); + + $sel: (); + @if iro-selector-suffix-match(&, $element-selector) { + // + // This mixin is included in the selector the last element mixin created. + // Possible outcomes: + // - {e} + {e} + // - [manual selector] {e} + {e} + // + + @each $s in & { + @each $ps in $part-selector { + @if nth($s, -1) == nth($ps, -1) { + $sel-ent: selector-nest($s, $sign, selector-append($block-base-selector, $iro-bem-element-separator + $part-name)); + $sel: join($sel, $sel-ent, comma); + } + } + } + } @else { + // + // This mixin is NOT included in the selector the last element mixin created. + // Possible outcomes: + // - {e} {m,s} + {e} + // - {e} [manual selector] + {e} + // - {e} {m,s} [manual selector] + {e} + // + + @each $s in & { + @each $ps in $part-selector { + @if str-index(inspect($s), inspect($ps)) { + $char-index: str-length(inspect($ps)) + 1; + $match: index(' ' ':' ',', str-slice(inspect($s), $char-index, $char-index)) != null; + + @if not $match { + @each $separator in $iro-bem-element-separator $iro-bem-modifier-separator $iro-bem-suffix-separator { + @if str-slice(inspect($s), $char-index, $char-index + str-length($separator) - 1) == $separator { + $match: true; + } + } + } + + @if $match { + $sel-ent: selector-nest($s, '+', selector-append($block-base-selector, $iro-bem-element-separator + $part-name)); + $sel: join($sel, $sel-ent, comma); + } + } + } + } + } + @if length($sel) != length($part-selector) { + @error 'Could not generate twin element selector.'; + } + + $selector: join($selector, $sel, comma); + $parts-data: append($parts-data, ( + 'name': $part-name, + 'selector': $sel + )); + } + + $context: 'element', ( + 'parts': $parts-data, + 'selector': $selector + ); + + @return $selector $context; +} + +/// +/// Generate the current BEM element as a sibling of itself. +/// +/// It's a shorthand for iro-bem-related-twin-element('~'). +/// +/// @content +/// +@mixin iro-bem-sibling-twin-element { + @include iro-bem-related-twin-element('~') { + @content; + } +} + +/// +/// Generate the current BEM element as a sibling of itself. +/// Check the respective mixin documentation for more information. +/// +/// @return {list} A list with two items: 1. selector, 2. context or `null` +/// +/// @see {mixin} iro-bem-sibling-twin-element +/// +@function iro-bem-sibling-twin-element() { + @return iro-bem-related-twin-element('~'); +} + +/// +/// Generate the current BEM element as a next sibling of itself. +/// +/// It's a shorthand for iro-bem-related-twin-element('+', $name). +/// +/// @content +/// +@mixin iro-bem-next-twin-element { + @include iro-bem-related-twin-element('+') { + @content; + } +} + +/// +/// Generate the current BEM element as a next sibling of itself. +/// Check the respective mixin documentation for more information. +/// +/// @return {list} A list with two items: 1. selector, 2. context or `null` +/// +/// @see {mixin} iro-bem-next-twin-element +/// +@function iro-bem-next-twin-element() { + @return iro-bem-related-twin-element('+'); +} diff --git a/src/bem/_functions.scss b/src/bem/_functions.scss new file mode 100644 index 0000000..4bb95c4 --- /dev/null +++ b/src/bem/_functions.scss @@ -0,0 +1,26 @@ +//// +/// @group BEM +/// +/// @access public +//// + +/// +/// @access private +/// +@function iro-bem-theme-selector($name, $names...) { + $namespace: map-get($iro-bem-namespaces, 'theme'); + $selector: null; + + @each $name in join($name, $names) { + $sel: '.' + $namespace + '-' + $name; + + @if $selector == null { + $selector: join(selector-parse($sel), selector-parse('[class*=\' t-\'] ' + $sel), comma); + $selector: join($selector, selector-parse('[class^=\'t-\'] ' + $sel), comma); + } @else { + $selector: selector-nest($selector, $sel); + } + } + + @return $selector; +} diff --git a/src/bem/_modifier.scss b/src/bem/_modifier.scss new file mode 100644 index 0000000..e1f9507 --- /dev/null +++ b/src/bem/_modifier.scss @@ -0,0 +1,246 @@ +//// +/// @group BEM +/// +/// @access public +//// + +/// +/// Generate a new BEM modifier. +/// +/// If the parent context is block or element, the modifier will modify said block or element according +/// to the BEM naming convention. +/// +/// If the parent context is a modifier or suffix, then the modifier will depend on said modifier or suffix. +/// Depending on $extend, the meaning of this dependency (and the resulting selector) varies: +/// If it's false (default), you signalize that the modifier also exists by itself, but it changes its +/// behavior when the parent modifier or suffix is set. +/// If it's true, you signalize that the modifier extends the parent modifier or suffix and can only be +/// used in conjunction with it. +/// +/// @param {string | list} $name - First element name or list with two items: 1. first element name, 2. bool indicating if the modifier is extending +/// @param {string | list} $names - More element names or lists with two items: 1. element name, 2. bool indicating if the modifier is extending +/// +/// @content +/// +/// @throw If the element is not preceded by a block, element, modifier or suffix. +/// +/// @example scss - Modifier that modifies a block or element +/// @include iro-bem-component('block') { +/// @include iro-bem-modifier('mod') { +/// background-color: #eee; +/// } +/// +/// @include iro-bem-element('elem') { +/// @include iro-bem-modifier('mod') { +/// background-color: #222; +/// } +/// } +/// } +/// +/// // Generates: +/// +/// .c-block--mod { +/// background-color: #eee; +/// } +/// +/// .c-block__elem--mod { +/// background-color: #222; +/// } +/// +/// @example scss - Modifier nested in another modifier, not extending +/// @include iro-bem-component('block') { +/// @include iro-bem-modifier('mod') { +/// background-color: #eee; +/// } +/// +/// @include iro-bem-modifier('dark') { +/// /* some definitions */ +/// +/// @include iro-bem-modifier('mod') { +/// background-color: #222; +/// } +/// } +/// } +/// +/// // Generates: +/// +/// .c-block--mod { +/// background-color: #eee; +/// } +/// +/// .c-block--dark { +/// /* some definitions */ +/// } +/// +/// .c-block--dark.c-block--mod { +/// background-color: #222; +/// } +/// +/// @example scss - Modifier nested in another modifier, extending +/// @include iro-bem-component('block') { +/// @include iro-bem-modifier('mod') { +/// background-color: #eee; +/// } +/// +/// @include iro-bem-modifier('dark') { +/// /* some definitions */ +/// +/// @include iro-bem-modifier('mod' true) { +/// background-color: #222; +/// } +/// } +/// } +/// +/// // Generates: +/// +/// .c-block--mod { +/// background-color: #eee; +/// } +/// +/// .c-block--dark { +/// /* some definitions */ +/// } +/// +/// .c-block--dark--mod { +/// background-color: #222; +/// } +/// +@mixin iro-bem-modifier($name, $names...) { + $result: iro-bem-modifier($name, $names...); + $selector: nth($result, 1); + $context: nth($result, 2); + + @include iro-bem-validate( + 'modifier', + (name: $name, names: $names), + $selector, + $context + ); + + @include iro-context-push($iro-bem-context-id, $context...); + @at-root #{$selector} { + @content; + } + @include iro-context-pop($iro-bem-context-id); +} + +/// +/// Generate a new BEM modifier. Check the respective mixin documentation for more information. +/// +/// @return {list} A list with two items: 1. selector, 2. context or `null` +/// +/// @see {mixin} iro-bem-modifier +/// +@function iro-bem-modifier($name, $names...) { + $noop: iro-context-assert-stack-count($iro-bem-context-id, $iro-bem-max-depth); + $noop: iro-context-assert-stack-must-contain($iro-bem-context-id, 'block'); + + $parent-context: iro-context-get($iro-bem-context-id, 'block' 'element' 'modifier' 'suffix'); + $parent-selector: map-get(nth($parent-context, 2), 'selector'); + $selector: (); + $parts-data: (); + + @if not iro-selector-suffix-match(&, $parent-selector) { + // + // The current selector doesn't match the parent selector. + // The user manually added a selector between parent context and this modifier call. + // This case is forbidden because any outcome semantically wouldn't make sense: + // - {b,e,m,s} [manual selector] {b,e,m,s}--modifier + // - {b,e,m,s}--modifier [manual selector] + // The first case would make the modifier behave like an element. + // The second case is unintuitive, the code would be more clear by nesting the manual + // selector in the modifier instead. + // + + @error 'A modifier must be an immediate child of the parent context'; + } + + @each $name in iro-list-prepend($names, $name) { + $extend: false; + @if type-of($name) == list { + $extend: nth($name, 2); + $name: nth($name, 1); + } + + @if index('block' 'element', nth($parent-context, 1)) or $extend == true { + // + // Either the parent context is block or element, or a modifier or suffix + // is to be extended. The modifier part can simply be appended. + // Possible outcomes: + // - {b,e,m,s}--modifier + // + + $sel: selector-append(&, $iro-bem-modifier-separator + $name); + $selector: join($selector, $sel, comma); + $parts-data: append($parts-data, ( + 'name': $name, + 'selector': $sel + )); + } @else { + // + // Parent context is modifier, suffix or state and $extend is false. + // + + $be-context: iro-context-get($iro-bem-context-id, 'block' 'element'); + + @if nth($be-context, 1) == 'element' { + // + // Latest context is element. Since element contexts can consist of multiple single + // elements, inspect all elements and append its selector with the suffix "--$name". + // This has to be done with string comparison since none of Sass selector functions + // is of use here. + // Possible outcomes: + // - {m,s}.{e}--modifier + // + + $nsel: (); + + @each $elem-part-data in map-get(nth($be-context, 2), 'parts') { + $elem-part-selector: map-get($elem-part-data, 'selector'); + + $sel: (); + @each $s in & { + @each $ps in $elem-part-selector { + @if str-index(inspect($s), inspect($ps) + $iro-bem-modifier-separator) or str-index(inspect($s), inspect($ps) + $iro-bem-suffix-separator) { + $sel: join($sel, selector-unify($s, selector-append($ps, $iro-bem-modifier-separator + $name)), comma); + } + } + } + @if length($sel) == 0 { + @error 'Could not generate modifier selector.'; + } + + $nsel: join($nsel, $sel, comma); + } + + $selector: join($selector, $nsel, comma); + $parts-data: append($parts-data, ( + 'name': $name, + 'selector': $nsel + )); + } @else { + // + // Latest context is block. Just append the modifier part. + // Possible outcomes: + // - {m,s}.{b}--modifier + // + + $block-base-selector: map-get(nth($be-context, 2), 'base-selector'); + + $sel: selector-append(&, $block-base-selector, $iro-bem-modifier-separator + $name); + $selector: join($selector, $sel, comma); + $parts-data: append($parts-data, ( + 'name': $name, + 'selector': $sel + )); + } + } + } + + $context: 'modifier', ( + 'parts': $parts-data, + 'selector': $selector + ); + + @return $selector $context; +} diff --git a/src/bem/_multi.scss b/src/bem/_multi.scss new file mode 100644 index 0000000..9e47ce4 --- /dev/null +++ b/src/bem/_multi.scss @@ -0,0 +1,131 @@ +//// +/// @group BEM +/// +/// @access public +//// + +/// +/// Generate multiple entities (BEM or not) at once. +/// +/// NOTE: This mixin does not generate perfectly optimized selectors in order to keep track of contexts. +/// +/// @param {string | list} $first - First selector. Either a string for a manual selector, or a list with the first items standing for a BEM selector function (optionally suffixed by a colon) and other items being passed as arguments to said function. +/// @param {string | list} $others - Other selectors. Either a string for a manual selector, or a list with the first items standing for a BEM selector function (optionally suffixed by a colon) and other items being passed as arguments to said function. +/// +/// @content +/// +/// @example scss - Creating multiple elements, a modifier and an anchor +/// @include iro-bem-object('buttonstrip') { +/// display: none; +/// +/// @include iro-bem-multi('modifier' 'mod', 'element' 'button' 'separator', '> a') { +/// display: block; +/// } +/// } +/// +/// // Generates: +/// +/// .o-buttonstrip { +/// display: none; +/// } +/// +/// .o-buttonstrip--mod { +/// display: block; +/// } +/// +/// .o-buttonstrip__button, { +/// .o-buttonstrip__separator { +/// display: block; +/// } +/// +/// .o-buttonstrip > a { +/// display: block; +/// } +/// +/// @example scss - Creating multiple elements, a modifier and an anchor - optional colons included +/// @include iro-bem-object('buttonstrip') { +/// display: none; +/// +/// @include iro-bem-multi('modifier:' 'mod', 'element:' 'button' 'separator', '> a') { +/// display: block; +/// } +/// } +/// +/// // Generates: +/// +/// .o-buttonstrip { +/// display: none; +/// } +/// +/// .o-buttonstrip--mod { +/// display: block; +/// } +/// +/// .o-buttonstrip__button, { +/// .o-buttonstrip__separator { +/// display: block; +/// } +/// +/// .o-buttonstrip > a { +/// display: block; +/// } +/// +@mixin iro-bem-multi($first, $others...) { + @include iro-context-assert-stack-count($iro-bem-context-id, $iro-bem-max-depth); + + @each $entity in iro-list-prepend($others, $first) { + $is-manual-selector: false; + + @if type-of($entity) == string and not function-exists('iro-bem-' + $entity) { + $is-manual-selector: true; + } + + @if $is-manual-selector { + $sel: if(&, selector-nest(&, $entity), selector-parse($entity)); + + @at-root #{$sel} { + @content; + } + } @else { + $entity-func-id: null; + + @if type-of($entity) == list { + $entity-func-id: nth($entity, 1); + $entity: iro-list-slice($entity, 2); + } @else { + $entity-func-id: $entity; + $entity: (); + } + + @if str-slice($entity-func-id, str-length($entity-func-id)) == ':' { + $entity-func-id: str-slice($entity-func-id, 1, str-length($entity-func-id) - 1); + } + + $sel-func: null; + + @if function-exists('iro-bem-' + $entity-func-id) { + $sel-func: get-function('iro-bem-' + $entity-func-id); + } @else if function-exists($entity-func-id) { + $sel-func: get-function($entity-func-id); + } + + @if $sel-func == null { + @error 'Function "#{inspect($entity-func-id)}" was not found.'; + } + + $entity-result: call($sel-func, $entity...); + $entity-result-selector: nth($entity-result, 1); + $entity-result-context: nth($entity-result, 2); + + @if $entity-result-context != null { + @include iro-context-push($iro-bem-context-id, $entity-result-context...); + } + @at-root #{$entity-result-selector} { + @content; + } + @if $entity-result-context != null { + @include iro-context-pop($iro-bem-context-id); + } + } + } +} diff --git a/src/bem/_state.scss b/src/bem/_state.scss new file mode 100644 index 0000000..4a85bbb --- /dev/null +++ b/src/bem/_state.scss @@ -0,0 +1,146 @@ +//// +/// @group BEM +/// +/// @access public +//// + +/// +/// Create a new state rule. +/// +/// @param {string} $state - First state name +/// @param {list} $states - List of more state names +/// +/// @content +/// +/// @example scss - Using single is-state +/// @include iro-bem-object('menu') { +/// display: none; +/// +/// @include iro-bem-state('is', open') { +/// display: block; +/// } +/// } +/// +/// // Generates: +/// +/// .o-menu { +/// display: none; +/// } +/// +/// .o-menu.is-open { +/// display: block; +/// } +/// +/// @example scss - Using multiple is-states +/// @include iro-bem-object('menu') { +/// display: none; +/// +/// @include iro-bem-state('is', open', 'visible') { +/// display: block; +/// } +/// } +/// +/// // Generates: +/// +/// .o-menu { +/// display: none; +/// } +/// +/// .o-menu.is-open, +/// .o-menu.is-visible { +/// display: block; +/// } +/// +@mixin iro-bem-state($prefix, $state, $states...) { + $result: iro-bem-state($prefix, $state, $states...); + $selector: nth($result, 1); + $context: nth($result, 2); + + @include iro-bem-validate( + 'state', + (prefix: $prefix, state: $state, states: $states), + $selector, + $context + ); + + @include iro-context-push($iro-bem-context-id, $context...); + @at-root #{$selector} { + @content; + } + @include iro-context-pop($iro-bem-context-id); +} + +/// +/// Generate a new state. +/// +/// @return {list} A list with two items: 1. selector, 2. context or `null` +/// +/// @see {mixin} iro-bem-has +/// +@function iro-bem-state($prefix, $state, $states...) { + $selector: (); + $parts-data: (); + + @each $state in join($state, $states) { + $sel: selector-parse('.#{$prefix}-#{$state}'); + @if & { + $sel: selector-append(&, $sel); + } + $selector: join($selector, $sel, comma); + $parts-data: append($parts-data, ( + 'name': $state, + 'selector': $sel + )); + } + + $context: 'state', ( + 'parts': $parts-data, + 'selector': $selector + ); + + @return $selector $context; +} + +/// +/// Create a new has-state modifier. +/// +/// It's a shorthand for iro-bem-state('is', $state, $states...). +/// +@mixin iro-bem-is($state, $states...) { + @include iro-bem-state('is', $state, $states...) { + @content; + } +} + +/// +/// Generate a new is-state modifier. Check the respective mixin documentation for more information. +/// +/// @return {list} A list with two items: 1. selector, 2. context or `null` +/// +/// @see {mixin} iro-bem-is +/// +@function iro-bem-is($state, $states...) { + @return iro-bem-state('is', $state, $states...); +} + +/// +/// Create a new has-state modifier. +/// +/// It's a shorthand for iro-bem-state('has', $state, $states...). +/// +@mixin iro-bem-has($state, $states...) { + @include iro-bem-state('has', $state, $states...) { + @content; + } +} + +/// +/// Generate a new has-state modifier. Check the respective mixin documentation for more information. +/// +/// @return {list} A list with two items: 1. selector, 2. context or `null` +/// +/// @see {mixin} iro-bem-has +/// +@function iro-bem-has($state, $states...) { + @return iro-bem-state('has', $state, $states...); +} diff --git a/src/bem/_suffix.scss b/src/bem/_suffix.scss new file mode 100644 index 0000000..b103c9f --- /dev/null +++ b/src/bem/_suffix.scss @@ -0,0 +1,118 @@ +//// +/// @group BEM +/// +/// @access public +//// + +/// +/// Generate a new suffix. +/// +/// @param {string} $name - Suffix name +/// +/// @content +/// +/// @throw If the element is not preceded by a block or modifier. +/// +/// @example scss - Using a suffix +/// @include iro-bem-utility('hidden') { +/// display: none; +/// +/// @media (max-width: 320px) { +/// @include iro-bem-suffix('phone') { +/// display: none; +/// } +/// } +/// +/// @media (max-width: 768px) { +/// @include iro-bem-suffix('tablet') { +/// display: none; +/// } +/// } +/// } +/// +/// // Generates: +/// +/// .u-hidden { +/// display: none; +/// } +/// +/// @media (max-width: 320px) { +/// .u-hidden@phone { +/// display: none; +/// } +/// } +/// +/// @media (max-width: 768px) { +/// .u-hidden@tablet { +/// display: none; +/// } +/// } +/// +@mixin iro-bem-suffix($name) { + $result: iro-bem-suffix($name); + $selector: nth($result, 1); + $context: nth($result, 2); + + @include iro-bem-validate( + 'suffix', + (name: $name), + $selector, + $context + ); + + @include iro-context-push($iro-bem-context-id, $context...); + @at-root #{$selector} { + @content; + } + @include iro-context-pop($iro-bem-context-id); +} + +/// +/// Generate a new suffix. Check the respective mixin documentation for more information. +/// +/// @return {list} A list with two items: 1. selector, 2. context or `null` +/// +/// @see {mixin} iro-bem-suffix +/// +@function iro-bem-suffix($name) { + // + // Suffixes can be used on block, element and modifier. + // + + $noop: iro-context-assert-stack-count($iro-bem-context-id, $iro-bem-max-depth); + $noop: iro-context-assert-stack-must-contain($iro-bem-context-id, 'block'); + $noop: iro-context-assert-stack-must-not-contain($iro-bem-context-id, 'suffix'); + + $parent-context: iro-context-get($iro-bem-context-id, 'block' 'element' 'modifier'); + $parent-selector: map-get(nth($parent-context, 2), 'selector'); + + @if not iro-selector-suffix-match(&, $parent-selector) { + // + // The current selector doesn't match the parent selector. + // The user manually added a selector between parent context and this suffix call. + // This case is forbidden because any outcome semantically wouldn't make sense: + // - {b,e,m} [manual selector] {b,e,m}@suffix + // - {b,e,m}@suffix [manual selector] + // The first case would make the modifier behave like an element. + // The second case is unintuitive, the code would be more clear by nesting the manual + // selector in the suffix instead. + // + + @error 'A suffix must be an immediate child of the parent context'; + } + + // + // The suffix part can simply be appended. + // Possible outcomes: + // - {b,e,m}@suffix + // + + $selector: selector-append(&, $iro-bem-suffix-separator + $name); + + $context: 'suffix', ( + 'name': $name, + 'selector': $selector + ); + + @return $selector $context; +} diff --git a/src/bem/_theme.scss b/src/bem/_theme.scss new file mode 100644 index 0000000..b4bcc76 --- /dev/null +++ b/src/bem/_theme.scss @@ -0,0 +1,61 @@ +//// +/// @group BEM +/// +/// @access public +//// + +/// +/// Declare new rules for the current block for when this theme is active. +/// +/// @param {string} $name - First theme block name +/// @param {string} $names - More theme block names +/// +/// @content +/// +@mixin iro-bem-at-theme($name, $names...) { + $result: iro-bem-at-theme($name, $names...); + $selector: nth($result, 1); + $context: nth($result, 2); + + @include iro-bem-validate( + 'at-theme', + (name: $name, names: $names), + $selector, + $context + ); + + @include iro-context-push($iro-bem-context-id, $context...); + @at-root #{$selector} { + @content; + } + @include iro-context-pop($iro-bem-context-id); +} + +/// +/// Declare new rules for the current block for when this theme is active. +/// Check the respective mixin documentation for more information. +/// +/// @return {list} A list with two items: 1. selector, 2. context or `null` +/// +/// @see {mixin} iro-bem-at-theme +/// +@function iro-bem-at-theme($name, $names...) { + $noop: iro-context-assert-stack-must-contain($iro-bem-context-id, 'block'); + + $parent-context: iro-context-get($iro-bem-context-id, 'block'); + $parent-selector: map-get(nth($parent-context, 2), 'selector'); + + @if not iro-selector-suffix-match(&, $parent-selector) { + @error 'An at-theme rule must be an immediate child of a block'; + } + + $selector: iro-bem-theme-selector($name, $names...); + $selector: selector-nest($selector, &); + + $context: 'at-theme', ( + 'name': join($name, $names), + 'selector': $selector + ); + + @return $selector $context; +} diff --git a/src/bem/_validators.scss b/src/bem/_validators.scss new file mode 100644 index 0000000..eb09a60 --- /dev/null +++ b/src/bem/_validators.scss @@ -0,0 +1,176 @@ +//// +/// Validators are custom functions that will be called before a BEM entity is created. +/// They check if the current mixin usage is valid or not and thus they are a flexible way to +/// let you implement your own rules. +/// +/// Validator functions receive the following information: +/// - BEM entity type +/// - Arguments passed to the mixin +/// - The generated selector +/// - The generated context, if any +/// +/// Additionally, the context stack used by the BEM system can be examined. +/// +/// @group BEM +/// +/// @access public +//// + +/// +/// A list of validator functions. +/// +/// @type list +/// +/// @access private +/// +$iro-bem-validators: (); + +/// +/// Register one or multiple validator functions. +/// +/// A validator function is a function that accepts 4 arguments: +/// 1. BEM entity type (string) +/// 2. Arguments passed to the mixin (map) +/// 3. The generated selector (selector) +/// 4. The generated context (list, may be null) +/// +/// The function must return a list with two items: +/// 1. `true` if the mixin usage is valid, otherwise `false`, +/// 2. a string with a rejection reason (empty if the usage is valid). +/// +/// @param {string} $func-name - First function name. +/// @param {string} $func-names - Other function names. +/// +@mixin iro-bem-add-validator($func-name, $func-names...) { + $noop: iro-bem-add-validator($func-name, $func-names...); +} + +/// +/// Register one or multiple validator functions. Check the respective mixin documentation for more information. +/// +/// @see {mixin} iro-bem-add-validator +/// +@function iro-bem-add-validator($func-name, $func-names...) { + @each $fn-name in join($func-name, $func-names) { + $fn: get-function($fn-name); + $iro-bem-validators: map-merge($iro-bem-validators, ($fn-name: $fn)) !global; + } + @return null; +} + +/// +/// Unregister one or multiple validator functions. +/// +/// @param {string} $func-name - First function name. +/// @param {string} $func-names - Other function names. +/// +@mixin iro-bem-remove-validator($func-name, $func-names...) { + $noop: iro-bem-remove-validator($func-name, $func-names...); +} + +/// +/// Unregister one or multiple validator functions. Check the respective mixin documentation for more information. +/// +/// @see {mixin} iro-bem-remove-validator +/// +@function iro-bem-remove-validator($func-name, $func-names...) { + $iro-bem-validators: map-remove($iro-bem-validators, $func-name, $func-names...) !global; + @return null; +} + +/// +/// @access private +/// +@mixin iro-bem-validate($type, $args, $selector, $context) { + @each $id, $fn in $iro-bem-validators { + $result: call($fn, $type, $args, $selector, $context); + @if not nth($result, 1) { + @error 'A BEM validator rejected this mixin usage due to the following reason: #{nth($result, 2)}'; + } + } +} + +// +// --------------------------------------------------------------------------------------------------------- +// Built-in validators +// --------------------------------------------------------------------------------------------------------- +// + +/// +/// A validator that makes sure blocks are declared in the right order, determined by the +/// namespace used. +/// +@function iro-bem-validator--enforce-namespace-order($type, $args, $selector, $context) { + @if not global-variable-exists(iro-bem-namespace-order) { + $iro-bem-namespace-order: map-keys($iro-bem-namespaces) !global; + } + @if not global-variable-exists(iro-bem-cur-namespace-index) { + $iro-bem-cur-namespace-index: 1 !global; + } + + @if $type == 'block' { + $block-type: map-get($args, 'type'); + + @if $block-type != null { + $ns-index: index($iro-bem-namespace-order, $block-type); + + @if $ns-index != null { + @if $ns-index < $iro-bem-cur-namespace-index { + @return false 'Namespace "#{$block-type}" comes before current namespace #{nth($iro-bem-namespace-order, $iro-bem-cur-namespace-index)}'; + } + + $iro-bem-cur-namespace-index: $ns-index !global; + } + } + } + + @return true ''; +} + +/// +/// A validator that makes all BEM entities immutable. +/// +@function iro-bem-validator--immutable-entities($type, $args, $selector, $context) { + @if not global-variable-exists(iro-bem-generated-selectors) { + $iro-bem-generated-selectors: () !global; + } + + $block-name: null; + $block-type: null; + $block-id: null; + + @if $type == 'block' { + $block-name: map-get($args, 'name'); + $block-type: map-get($args, 'type'); + } @else { + $block-context: iro-context-get($iro-bem-context-id, 'block'); + $block-name: map-get(nth($block-context, 2), 'name'); + $block-type: map-get(nth($block-context, 2), 'type'); + } + + @if $block-type != null { + $block-id: $block-name + '_' + $block-type; + } @else { + $block-id: $block-name; + } + + @if $type == 'block' { + @if map-has-key($iro-bem-generated-selectors, $block-id) { + @return false 'Entity "#{$type}" with arguments [ #{iro-map-print($args)} ] was already defined.'; + } + + $iro-bem-generated-selectors: map-merge($iro-bem-generated-selectors, ($block-id: ())) !global; + } @else { + $selectors: map-get($iro-bem-generated-selectors, $block-id); + + @if index($selectors, $selector) { + @return false 'Entity "#{$type}" with arguments [ #{iro-map-print($args)} ] was already defined.'; + } + + $selectors: append($selectors, $selector); + + $iro-bem-generated-selectors: map-merge($iro-bem-generated-selectors, ($block-id: $selectors)) !global; + } + + @return true ''; +} diff --git a/src/bem/_vars.scss b/src/bem/_vars.scss new file mode 100644 index 0000000..5942d4f --- /dev/null +++ b/src/bem/_vars.scss @@ -0,0 +1,108 @@ +//// +/// @group BEM +/// +/// @access public +//// + +/// +/// Separating character sequence for elements. +/// +/// @type string +/// +$iro-bem-element-separator: '__' !default; + +/// +/// Separating character sequence for modifiers. +/// +/// @type string +/// +$iro-bem-modifier-separator: '--' !default; + +/// +/// Separating character sequence for BEMIT suffixes. +/// +/// @type string +/// +$iro-bem-suffix-separator: '\\@' !default; + +/// +/// Prefixes for all BEMIT namespaces. +/// +/// @prop {string} utility ['u'] - Utility namespace +/// @prop {string} object ['o'] - Object namespace +/// @prop {string} component ['c'] - Component namespace +/// @prop {string} layout ['l'] - Layout namespace +/// @prop {string} scope ['s'] - Scope namespace +/// @prop {string} theme ['t'] - Theme namespace +/// @prop {string} js ['js'] - JS namespace +/// @prop {string} qa ['qa'] - QA namespace +/// @prop {string} hack ['_'] - Hack namespace +/// +/// @type map +/// +$iro-bem-namespaces: ( + object: 'o', + component: 'c', + layout: 'l', + scope: 's', + theme: 't', + utility: 'u', + js: 'js', + qa: 'qa', + hack: '_' +) !default; + +/// +/// A list of all generated blocks. +/// +/// @type list +/// +/// @access private +/// +$iro-bem-blocks: (); + +/// +/// Maximum nesting depth of BEM mixins. The large default value means there is no effective limit. +/// +/// @type number +/// +$iro-bem-max-depth: 99 !default; + +/// +/// Indicates how nested elements should be handled. +/// +/// 'allow' means elements will be nested, i.e. the result will be {e} {b}__element. +/// 'disallow' means an error will be emitted. +/// 'append' means the element name will be appended to the parent element, i.e. the result will be {e}__element. +/// Any other value is treated as 'allow'. +/// +/// @type string +/// +$iro-bem-element-nesting-policy: 'allow' !default; + +/// +/// Context ID used for all BEM-related mixins. +/// +/// @type string +/// +$iro-bem-context-id: 'bem' !default; + +/// +/// Debug mode. +/// +/// @type bool +/// +$iro-bem-debug: false !default; + +/// +/// Colors assigned to namespaces. +/// +/// @type map +/// +$iro-bem-debug-colors: ( + object: #ffa500, + component: #00f, + layout: #ff0, + utility: #008000, + hack: #f00 +) !default; diff --git a/src/harmony-shortcodes.scss b/src/harmony-shortcodes.scss new file mode 100644 index 0000000..3307a7e --- /dev/null +++ b/src/harmony-shortcodes.scss @@ -0,0 +1,35 @@ +//// +/// Shorter version of the harmony-related functions. Useful to reduce clutter. +/// +/// @group Harmony shortcodes +/// +/// @access public +//// + +/// +/// @alias iro-harmony-modular-scale +/// +@function modular-scale($times, $base, $ratio) { + @include iro-harmony-modular-scale($times, $base, $ratio); +} + +/// +/// @alias modular-scale +/// +@function ms($times, $base, $ratio) { + @include modular-scale($times, $base, $ratio); +} + +/// +/// @alias iro-responsive-modular-scale +/// +@mixin responsive-modular-scale($prop, $times, $responsive-map) { + @include iro-responsive-modular-scale($prop, $times, $responsive-map); +} + +/// +/// @alias responsive-modular-scale +/// +@mixin responsive-ms($prop, $times, $responsive-map) { + @include responsive-modular-scale($prop, $times, $responsive-map); +} diff --git a/src/main.scss b/src/main.scss new file mode 100644 index 0000000..5b1b3d1 --- /dev/null +++ b/src/main.scss @@ -0,0 +1,10 @@ +@import 'functions'; +@import 'math'; +@import 'vars'; +@import 'contexts'; +@import 'bem'; +@import 'props'; +@import 'harmony'; +@import 'responsive'; +@import 'easing'; +@import 'gradients'; diff --git a/src/prep.scss b/src/prep.scss new file mode 100644 index 0000000..616165d --- /dev/null +++ b/src/prep.scss @@ -0,0 +1,2 @@ +@import 'functions'; +@import 'math'; diff --git a/src/responsive-shortcodes.scss b/src/responsive-shortcodes.scss new file mode 100644 index 0000000..e43dfc0 --- /dev/null +++ b/src/responsive-shortcodes.scss @@ -0,0 +1,14 @@ +//// +/// Shorter version of the responsive-related mixins. Useful to reduce clutter. +/// +/// @group Responsive shortcodes +/// +/// @access public +//// + +/// +/// @alias iro-responsive-property +/// +@mixin responsive($props, $responsive-map, $fluid: true, $vertical: false) { + @include iro-responsive-property($props, $responsive-map, $fluid, $vertical); +} diff --git a/test/_bem.scss b/test/_bem.scss new file mode 100644 index 0000000..30ed131 --- /dev/null +++ b/test/_bem.scss @@ -0,0 +1,19 @@ +@include describe('BEM') { + // + // The following unit tests only test the BEM mixins. + // Since they are wrappers for the BEM functions, the latter are + // automatically covered. + // + + @import 'bem/iro-bem-block'; + @import 'bem/iro-bem-composed-of'; + @import 'bem/iro-bem-at-theme'; + @import 'bem/iro-bem-element'; + @import 'bem/iro-bem-related-element'; + @import 'bem/iro-bem-next-twin-element'; + @import 'bem/iro-bem-modifier'; + @import 'bem/iro-bem-suffix'; + @import 'bem/iro-bem-state'; + @import 'bem/iro-bem-multi'; + @import 'bem/examples'; +} diff --git a/test/_contexts.scss b/test/_contexts.scss new file mode 100644 index 0000000..1b0e602 --- /dev/null +++ b/test/_contexts.scss @@ -0,0 +1,65 @@ +@include describe('Contexts') { + @include it('Creating / deleting context stacks') { + @include assert-equal(iro-context-stack-create('test'), null, 'Check if context stack was created'); + @include assert-equal(iro-context-stack-delete('test'), null, 'Check if context stack was deleted'); + } + + @include it('Adding / removing contexts') { + @include assert-equal(iro-context-stack-create('test'), null, 'Check if context stack was created'); + + @include assert-equal(iro-context-push('test', 'ctx', 1234), 'ctx' 1234, 'Check if context 1 was pushed'); + @include assert-equal(iro-context-push('test', 'another', 'text'), 'another' 'text', 'Check if context 2 was pushed'); + @include assert-equal(iro-context-push('test', 'ctx', 56), 'ctx' 56, 'Check if context 3 was pushed'); + + @include assert-equal(iro-context-pop('test'), 'ctx' 56, 'Check if context 3 was popped'); + @include assert-equal(iro-context-pop('test'), 'another' 'text', 'Check if context 2 was popped'); + @include assert-equal(iro-context-pop('test'), 'ctx' 1234, 'Check if context 1 was popped'); + + @include assert-equal(iro-context-stack-delete('test'), null, 'Check if context stack was deleted'); + } + + @include it('Clearing / counting context stacks') { + @include assert-equal(iro-context-stack-create('test'), null, 'Check if context stack was created'); + + @include assert-equal(iro-context-push('test', 'ctx', 1234), 'ctx' 1234, 'Check if context 1 was pushed'); + @include assert-equal(iro-context-push('test', 'another', 'text'), 'another' 'text', 'Check if context 2 was pushed'); + @include assert-equal(iro-context-push('test', 'ctx', 56), 'ctx' 56, 'Check if context 3 was pushed'); + + @include assert-equal(iro-context-stack-count('test'), 3, 'Check if context stack contains 3 contexts'); + @include assert-equal(iro-context-pop('test'), 'ctx' 56, 'Check if context 3 was popped'); + @include assert-equal(iro-context-stack-count('test'), 2, 'Check if context stack contains 2 contexts'); + @include assert-equal(iro-context-stack-clear('test'), null, 'Check if context stack was cleared'); + @include assert-equal(iro-context-stack-count('test'), 0, 'Check if context stack contains no contexts'); + + @include assert-equal(iro-context-stack-delete('test'), null, 'Check if context stack was deleted'); + } + + @include it('Retrieving contexts') { + @include assert-equal(iro-context-stack-create('test'), null, 'Check if context stack was created'); + + @include assert-equal(iro-context-push('test', 'ctx', 1234), 'ctx' 1234, 'Check if context 1 was pushed'); + @include assert-equal(iro-context-push('test', 'another', 'text'), 'another' 'text', 'Check if context 2 was pushed'); + @include assert-equal(iro-context-push('test', 'ctx', 56), 'ctx' 56, 'Check if context 3 was pushed'); + + @include assert-equal(iro-context-get('test', 1), 'ctx' 56, 'Check if context at position 1 is context 3'); + @include assert-equal(iro-context-get('test', 'ctx'), 'ctx' 56, 'Check if latest context with id "ctx" is context 3'); + @include assert-equal(iro-context-get('test', 2), 'another' 'text', 'Check if latest context with id "another" is context 2'); + + @include assert-equal(iro-context-pop('test'), 'ctx' 56, 'Check if context 3 was popped'); + + @include assert-equal(iro-context-get('test', 1), 'another' 'text', 'Check if context at position 1 is context 2'); + @include assert-equal(iro-context-get('test', -1), 'ctx' 1234, 'Check if latest context with id "ctx" is context 1'); + + @include assert-equal(iro-context-push('test', 'more', 'string'), 'more' 'string', 'Check if context 4 was pushed'); + + @include assert-equal(iro-context-get('test', 1), 'more' 'string', 'Check if context at position 1 is context 4'); + @include assert-equal(iro-context-get('test', 'more'), 'more' 'string', 'Check if latest context with id "more" is context 4'); + + @include assert-equal(iro-context-pop('test'), 'more' 'string', 'Check if context 4 was popped'); + @include assert-equal(iro-context-pop('test'), 'another' 'text', 'Check if context 2 was popped'); + + @include assert-equal(iro-context-get('test', 1), iro-context-get('test', -1), 'Check if first and last context are context 1'); + + @include assert-equal(iro-context-stack-delete('test'), null, 'Check if context stack was deleted'); + } +} diff --git a/test/_functions.scss b/test/_functions.scss new file mode 100644 index 0000000..54e37c5 --- /dev/null +++ b/test/_functions.scss @@ -0,0 +1,103 @@ +@include describe('Functions') { + @include it('iro-str-replace') { + $str: 'Hello world!'; + + @include assert-equal(iro-str-replace($str, 'world', 'neighbor'), 'Hello neighbor!', 'Replace "world" with "neighbor"'); + @include assert-equal(iro-str-replace($str, 'neighbor', 'moon'), 'Hello world!', 'Replace "neighbor" with "moon"'); + @include assert-equal(iro-str-replace($str, 'Hello', 'Bye'), 'Bye world!', 'Replace "Hello" with "Bye"'); + } + + @include it('iro-list-slice') { + $list: 'this' 'is' 'a' 'list'; + + @include assert-equal(iro-list-slice($list, 2), 'is' 'a' 'list', 'Discard first item'); + @include assert-equal(iro-list-slice($list, 1, 3), 'this' 'is' 'a', 'Keep first 3 items'); + @include assert-equal(iro-list-slice($list, 2, 3), 'is' 'a', 'Extract list from index 2 to 3'); + @include assert-equal(iro-list-slice($list, -1, -1), join((), 'list'), 'Keep last item'); + @include assert-equal(iro-list-slice($list, -1, 1), 'list' 'this', 'Extract first and last item'); + } + + @include it('iro-list-prepend') { + $list: 'this' 'is' 'a' 'list'; + + @include assert-equal(iro-list-prepend($list, 'and'), 'and' 'this' 'is' 'a' 'list', 'Prepend "and"'); + @include assert-equal(iro-list-prepend($list, 2), 2 'this' 'is' 'a' 'list', 'Prepend 2'); + } + + @include it('iro-quicksort') { + @include assert-equal(iro-quicksort(1 2 3 4 5), 1 2 3 4 5, 'Already sorted list of 5 items'); + @include assert-equal(iro-quicksort(1 3 2), 1 2 3, 'Random list of 3 items'); + @include assert-equal(iro-quicksort(6 3 7 3 8 1 4), 1 3 3 4 6 7 8, 'Random list of 7 items, one duplicate'); + @include assert-equal(iro-quicksort(1 1 1 1), 1 1 1 1, 'List of 4 identical items'); + } + + @include it('iro-map-get-default') { + $map: ('key': 'value', 'another': 'item'); + + @include assert-equal(iro-map-get-default($map, 'another', 0), map-get($map, 'another'), 'Get existing value'); + @include assert-equal(iro-map-get-default($map, 'index', 'nothing'), 'nothing', 'Get missing value'); + } + + @include it('iro-map-get-deep') { + $map: ( + 'key': 'value', + 'sub': ( + 'item1': 1, + 'item2': 2, + 'subsub': ( + 'item1': 11, + 'item2': 12, + ) + ) + ); + + @include assert-equal(iro-map-get-deep($map, 'key'), map-get($map, 'key'), 'Get value in root level'); + @include assert-equal(iro-map-get-deep($map, 'sub' 'item1'), map-get(map-get($map, 'sub'), 'item1'), 'Get value in first level'); + @include assert-equal(iro-map-get-deep($map, 'sub' 'item2'), map-get(map-get($map, 'sub'), 'item2'), 'Get value in first level'); + @include assert-equal(iro-map-get-deep($map, 'sub' 'subsub' 'item1'), map-get(map-get(map-get($map, 'sub'), 'subsub'), 'item1'), 'Get value in second level'); + @include assert-equal(iro-map-get-deep($map, 'sub' 'subsub' 'item2'), map-get(map-get(map-get($map, 'sub'), 'subsub'), 'item2'), 'Get value in second level'); + } + + @include it('iro-map-merge-recursive') { + $map1: ( + 'key': 'value', + 'sub': ( + 'item1': 1, + 'item3': 2 + ) + ); + $map2: ( + 'another': 'item', + 'sub': ( + 'item1': 0, + 'item2': 1 + ) + ); + + $expected: ( + 'key': 'value', + 'another': 'item', + 'sub': ( + 'item1': 0, + 'item2': 1, + 'item3': 2 + ) + ); + + @include assert-equal(iro-map-merge-recursive($map1, $map2), $expected); + } + + @include it('iro-strip-unit') { + @include assert-true(unitless(iro-strip-unit(1em)), 'Remove unit from 1em'); + @include assert-true(unitless(iro-strip-unit(2rem)), 'Remove unit from 2rem'); + @include assert-true(unitless(iro-strip-unit(3px)), 'Remove unit from 3px'); + @include assert-true(unitless(iro-strip-unit(4)), 'Remove unit from 4'); + @include assert-true(unitless(iro-strip-unit(5pt)), 'Remove unit from 5pt'); + } + + @include it('iro-px-to-rem') { + @include assert-equal(iro-px-to-rem(16px, 16px), 1rem, 'Convert 16px'); + @include assert-equal(iro-px-to-rem(32px, 16px), 2rem, 'Convert 16px'); + @include assert-equal(iro-px-to-rem(8px, 16px), 0.5rem, 'Convert 16px'); + } +} diff --git a/test/_gradients.scss b/test/_gradients.scss new file mode 100644 index 0000000..c1145aa --- /dev/null +++ b/test/_gradients.scss @@ -0,0 +1,264 @@ +// sass-lint:disable no-color-literals zero-unit + +@include describe('Gradients') { + @include it('iro-easing-gradient') { + $gradient1: iro-easing-gradient( + linear, + to right, + #000, + ease-in-quad, + transparent + ); + + $expected1: linear-gradient( + to right, + #000 0, + mix(transparent, #000, iro-ease-in-quad(0.25) * 100%) 25%, + mix(transparent, #000, iro-ease-in-quad(0.5) * 100%) 50%, + mix(transparent, #000, iro-ease-in-quad(0.75) * 100%) 75%, + transparent 100% + ); + + @include assert-equal($gradient1, $expected1, 'Simple linear gradient'); + + // --------------------------------------------------------------------------- + + $gradient2: iro-easing-gradient( + radial, + 1em 2em at 50% 60%, + #000, + ease-out-cubic, + transparent + ); + + $expected2: radial-gradient( + 1em 2em at 50% 60%, + #000 0, + mix(transparent, #000, iro-ease-out-cubic(0.25) * 100%) 25%, + mix(transparent, #000, iro-ease-out-cubic(0.5) * 100%) 50%, + mix(transparent, #000, iro-ease-out-cubic(0.75) * 100%) 75%, + transparent 100% + ); + + @include assert-equal($gradient2, $expected2, 'Simple radial gradient'); + + // --------------------------------------------------------------------------- + + $gradient3: iro-easing-gradient( + linear, + to right, + #000 2em, + ease-in-quad, + transparent 10em + ); + + $expected3: linear-gradient( + to right, + #000 2em, + mix(transparent, #000, iro-ease-in-quad(0.25) * 100%) 4em, + mix(transparent, #000, iro-ease-in-quad(0.5) * 100%) 6em, + mix(transparent, #000, iro-ease-in-quad(0.75) * 100%) 8em, + transparent 10em + ); + + @include assert-equal($gradient3, $expected3, 'Linear gradient with positioned color stops'); + + // --------------------------------------------------------------------------- + + $gradient4: iro-easing-gradient( + linear, + to right, + #000 20%, + ease-in-quad, + transparent calc(20% + 10em) + ); + + $expected4: linear-gradient( + to right, + #000 20%, + mix(transparent, #000, iro-ease-in-quad(0.25) * 100%) calc(20% + (20% + 10em - 20%) * 0.25), + mix(transparent, #000, iro-ease-in-quad(0.5) * 100%) calc(20% + (20% + 10em - 20%) * 0.5), + mix(transparent, #000, iro-ease-in-quad(0.75) * 100%) calc(20% + (20% + 10em - 20%) * 0.75), + transparent calc(20% + 10em) + ); + + @include assert-equal($gradient4, $expected4, 'More advanced linear gradient with positioned color stops'); + + // --------------------------------------------------------------------------- + + $gradient5: iro-easing-gradient( + linear, + to right, + #000 2em, + #f00 7em, + ease-in-quad, + transparent 10em + ); + + $expected5: linear-gradient( + to right, + #000 2em, + #f00 7em, + mix(transparent, #f00, iro-ease-in-quad(0.25) * 100%) 7em + 3em * 0.25, + mix(transparent, #f00, iro-ease-in-quad(0.5) * 100%) 7em + 3em * 0.5, + mix(transparent, #f00, iro-ease-in-quad(0.75) * 100%) 7em + 3em * 0.75, + transparent 10em + ); + + @include assert-equal($gradient5, $expected5, 'Linear gradient with 3 positioned color stops, 1 easing transitions'); + + // --------------------------------------------------------------------------- + + $gradient6: iro-easing-gradient( + linear, + to right, + #000 2em, + ease-in-quad, + #f00 7em, + ease-in-quad, + transparent 10em + ); + + $expected6: linear-gradient( + to right, + #000 2em, + mix(#f00, #000, iro-ease-in-quad(0.25) * 100%) 2em + 5em * 0.25, + mix(#f00, #000, iro-ease-in-quad(0.5) * 100%) 2em + 5em * 0.5, + mix(#f00, #000, iro-ease-in-quad(0.75) * 100%) 2em + 5em * 0.75, + #f00 7em, + mix(transparent, #f00, iro-ease-in-quad(0.25) * 100%) 7em + 3em * 0.25, + mix(transparent, #f00, iro-ease-in-quad(0.5) * 100%) 7em + 3em * 0.5, + mix(transparent, #f00, iro-ease-in-quad(0.75) * 100%) 7em + 3em * 0.75, + transparent 10em + ); + + @include assert-equal($gradient6, $expected6, 'Linear gradient with 3 positioned color stops, 2 easing transitions'); + + // --------------------------------------------------------------------------- + + $gradient7: iro-easing-gradient( + linear, + to right, + #000 2em, + ease-in-quad, + #f00, + ease-in-quad, + transparent 10em + ); + + $expected7: linear-gradient( + to right, + #000 2em, + mix(#f00, #000, iro-ease-in-quad(0.25) * 100%) 2em + 4em * 0.25, + mix(#f00, #000, iro-ease-in-quad(0.5) * 100%) 2em + 4em * 0.5, + mix(#f00, #000, iro-ease-in-quad(0.75) * 100%) 2em + 4em * 0.75, + #f00 6em, + mix(transparent, #f00, iro-ease-in-quad(0.25) * 100%) 6em + 4em * 0.25, + mix(transparent, #f00, iro-ease-in-quad(0.5) * 100%) 6em + 4em * 0.5, + mix(transparent, #f00, iro-ease-in-quad(0.75) * 100%) 6em + 4em * 0.75, + transparent 10em + ); + + @include assert-equal($gradient7, $expected7, 'Linear gradient with 2 / 3 positioned color stops, 2 easing transitions'); + + // --------------------------------------------------------------------------- + + $gradient8: iro-easing-gradient( + linear, + to right, + #000, + ease-in-quad, + #f00, + ease-in-quad, + transparent + ); + + $expected8: linear-gradient( + to right, + #000 0, + mix(#f00, #000, iro-ease-in-quad(0.25) * 100%) 50% * 0.25, + mix(#f00, #000, iro-ease-in-quad(0.5) * 100%) 50% * 0.5, + mix(#f00, #000, iro-ease-in-quad(0.75) * 100%) 50% * 0.75, + #f00 50%, + mix(transparent, #f00, iro-ease-in-quad(0.25) * 100%) 50% + 50% * 0.25, + mix(transparent, #f00, iro-ease-in-quad(0.5) * 100%) 50% + 50% * 0.5, + mix(transparent, #f00, iro-ease-in-quad(0.75) * 100%) 50% + 50% * 0.75, + transparent 100% + ); + + @include assert-equal($gradient8, $expected8, 'Linear gradient with 0 / 3 positioned color stops, 2 easing transitions'); + + // --------------------------------------------------------------------------- + + $gradient9: iro-easing-gradient( + linear, + to right, + #000, + ease-in-quad, + #f00, + ease-in-quad, + transparent 20em + ); + + $expected9: linear-gradient( + to right, + #000 0, + mix(#f00, #000, iro-ease-in-quad(0.25) * 100%) 10em * 0.25, + mix(#f00, #000, iro-ease-in-quad(0.5) * 100%) 10em * 0.5, + mix(#f00, #000, iro-ease-in-quad(0.75) * 100%) 10em * 0.75, + #f00 10em, + mix(transparent, #f00, iro-ease-in-quad(0.25) * 100%) 10em + 10em * 0.25, + mix(transparent, #f00, iro-ease-in-quad(0.5) * 100%) 10em + 10em * 0.5, + mix(transparent, #f00, iro-ease-in-quad(0.75) * 100%) 10em + 10em * 0.75, + transparent 20em + ); + + @include assert-equal($gradient9, $expected9, 'Linear gradient with 1 / 3 positioned color stops, 2 easing transitions'); + + // --------------------------------------------------------------------------- + + $gradient10: iro-easing-gradient( + linear, + to right, + #000, + cubic-bezier 0.47 0 0.745 0.715, + transparent + ); + + $expected10: linear-gradient( + to right, + #000 0, + mix(transparent, #000, iro-cubic-bezier(0.47, 0, 0.745, 0.715, 0.25) * 100%) 25%, + mix(transparent, #000, iro-cubic-bezier(0.47, 0, 0.745, 0.715, 0.5) * 100%) 50%, + mix(transparent, #000, iro-cubic-bezier(0.47, 0, 0.745, 0.715, 0.75) * 100%) 75%, + transparent 100% + ); + + @include assert-equal($gradient10, $expected10, 'Simple linear gradient with custom cubic-bezier easing'); + + // --------------------------------------------------------------------------- + + $gradient11: iro-easing-gradient( + linear, + to right, + #000, + steps 4 jump-start, + transparent + ); + + $expected11: linear-gradient( + to right, + #000 0, + mix(transparent, #000, 0.25 * 100%) 0, + mix(transparent, #000, 0.25 * 100%) 25%, + mix(transparent, #000, 0.5 * 100%) 25%, + mix(transparent, #000, 0.5 * 100%) 50%, + mix(transparent, #000, 0.75 * 100%) 50%, + mix(transparent, #000, 0.75 * 100%) 75%, + transparent 75%, + transparent 100% + ); + + @include assert-equal($gradient11, $expected11, 'Simple linear gradient with custom steps easing'); + } +} diff --git a/test/_harmony.scss b/test/_harmony.scss new file mode 100644 index 0000000..25560f0 --- /dev/null +++ b/test/_harmony.scss @@ -0,0 +1,249 @@ +@function _limit-decimals($n) { + @return floor($n * 1000) / 1000; +} + +@include describe('Harmony') { + @include it('iro-harmony-modular-scale') { + @include assert-equal(_limit-decimals(iro-harmony-modular-scale(0, 1em, 1.1)), 1em, 'Zero iterations, 1em base, 1.1 scale'); + @include assert-equal(_limit-decimals(iro-harmony-modular-scale(1, 1em, 1.1)), 1.1em, '1 iteration, 1em base, 1.1 scale'); + @include assert-equal(_limit-decimals(iro-harmony-modular-scale(2, 2px, 1.2)), 2.88px, '2 iterations, 2px base, 1.2 scale'); + @include assert-equal(_limit-decimals(iro-harmony-modular-scale(-1, 2rem, 2)), 1rem, '-1 iteration, 2rem base, 2 scale'); + @include assert-equal(_limit-decimals(iro-harmony-modular-scale(-2, 2rem, 2)), 0.5rem, '-2 iterations, 2rem base, 2 scale'); + + @include assert-equal(_limit-decimals(iro-harmony-modular-scale(0, 1em 2em, 1.1)), 1em, 'Zero iterations, 1em 2em base, 1.1 scale'); + @include assert-equal(_limit-decimals(iro-harmony-modular-scale(1, 1em 2em, 1.1)), 1.026em, '1 iteration, 1em 2em base, 1.1 scale'); + @include assert-equal(_limit-decimals(iro-harmony-modular-scale(2, 1em 2em, 1.1)), 1.1em, '2 iterations, 1em 2em base, 1.1 scale'); + @include assert-equal(_limit-decimals(iro-harmony-modular-scale(-1, 1em 1.5em, 1.2)), 0.868em, '-1 iteration, 1em 2em base, 1.1 scale'); + @include assert-equal(_limit-decimals(iro-harmony-modular-scale(-2, 1em 1.5em, 1.2)), 0.833em, '-2 iterations, 1em 2em base, 1.1 scale'); + } + + @include it('iro-responsive-modular-scale') { + @include assert('Single-stranded, fluid') { + $ms: ( + 320px: (1rem, 1.1), + 640px: (1rem, 1.2) + ); + + $rem320px: iro-px-to-rem(320px); + $rem640px: iro-px-to-rem(640px); + $diff320px: iro-strip-unit($rem640px - $rem320px); + + @include output { + h3 { + @include iro-responsive-modular-scale(font-size, 0, $ms); + } + + h2 { + @include iro-responsive-modular-scale(font-size, 1, $ms); + } + + h1 { + @include iro-responsive-modular-scale(font-size, 2, $ms); + } + } + + @include expect { + h3 { + font-size: 1rem; + + @media (min-width: 320px) and (max-width: 640px) { + font-size: calc(1rem + 0 * ((100vw - #{$rem320px}) / #{$diff320px})); + } + + @media (min-width: 640px) { + font-size: 1rem; + } + } + + h2 { + font-size: 1.1rem; + + @media (min-width: 320px) and (max-width: 640px) { + font-size: calc(1.1rem + 0.1 * ((100vw - #{$rem320px}) / #{$diff320px})); + } + + @media (min-width: 640px) { + font-size: 1.2rem; + } + } + + h1 { + font-size: 1.21rem; + + @media (min-width: 320px) and (max-width: 640px) { + font-size: calc(1.21rem + 0.23 * ((100vw - #{$rem320px}) / #{$diff320px})); + } + + @media (min-width: 640px) { + font-size: 1.44rem; + } + } + } + } + + @include assert('Single-stranded, non-fluid') { + $ms: ( + 320px: (1rem, 1.1), + 640px: (1rem, 1.2) + ); + + $rem320px: iro-px-to-rem(320px); + $rem640px: iro-px-to-rem(640px); + $diff320px: iro-strip-unit($rem640px - $rem320px); + + @include output { + h3 { + @include iro-responsive-modular-scale(font-size, 0, $ms, false); + } + + h2 { + @include iro-responsive-modular-scale(font-size, 1, $ms, false); + } + + h1 { + @include iro-responsive-modular-scale(font-size, 2, $ms, false); + } + } + + @include expect { + h3 { + font-size: 1rem; + + @media (min-width: 640px) { + font-size: 1rem; + } + } + + h2 { + font-size: 1.1rem; + + @media (min-width: 640px) { + font-size: 1.2rem; + } + } + + h1 { + font-size: 1.21rem; + + @media (min-width: 640px) { + font-size: 1.44rem; + } + } + } + } + + @include assert('Double-stranded, fluid') { + $ms: ( + 320px: (1rem 2rem, 1.1), + 640px: (1rem 2rem, 1.2) + ); + + $rem320px: iro-px-to-rem(320px); + $rem640px: iro-px-to-rem(640px); + $diff320px: iro-strip-unit($rem640px - $rem320px); + + @include output { + h3 { + @include iro-responsive-modular-scale(font-size, 0, $ms); + } + + h2 { + @include iro-responsive-modular-scale(font-size, 1, $ms); + } + + h1 { + @include iro-responsive-modular-scale(font-size, 2, $ms); + } + } + + @include expect { + h3 { + font-size: 1rem; + + @media (min-width: 320px) and (max-width: 640px) { + font-size: calc(1rem + 0 * ((100vw - #{$rem320px}) / #{$diff320px})); + } + + @media (min-width: 640px) { + font-size: 1rem; + } + } + + h2 { + font-size: 1.0263162365rem; + + @media (min-width: 320px) and (max-width: 640px) { + font-size: calc(1.0263162365rem + 0.1310911709 * ((100vw - #{$rem320px}) / #{$diff320px})); + } + + @media (min-width: 640px) { + font-size: 1.1574074074rem; + } + } + + h1 { + font-size: 1.1rem; + + @media (min-width: 320px) and (max-width: 640px) { + font-size: calc(1.1rem + 0.1 * ((100vw - #{$rem320px}) / #{$diff320px})); + } + + @media (min-width: 640px) { + font-size: 1.2rem; + } + } + } + } + + @include assert('Double-stranded, non-fluid') { + $ms: ( + 320px: (1rem 2rem, 1.1), + 640px: (1rem 2rem, 1.2) + ); + + $rem320px: iro-px-to-rem(320px); + $rem640px: iro-px-to-rem(640px); + $diff320px: iro-strip-unit($rem640px - $rem320px); + + @include output { + h3 { + @include iro-responsive-modular-scale(font-size, 0, $ms, false); + } + + h2 { + @include iro-responsive-modular-scale(font-size, 1, $ms, false); + } + + h1 { + @include iro-responsive-modular-scale(font-size, 2, $ms, false); + } + } + + @include expect { + h3 { + font-size: 1rem; + + @media (min-width: 640px) { + font-size: 1rem; + } + } + + h2 { + font-size: 1.0263162365rem;; + + @media (min-width: 640px) { + font-size: 1.1574074074rem;; + } + } + + h1 { + font-size: 1.1rem; + + @media (min-width: 640px) { + font-size: 1.2rem; + } + } + } + } + } +} diff --git a/test/_math.scss b/test/_math.scss new file mode 100644 index 0000000..5f40499 --- /dev/null +++ b/test/_math.scss @@ -0,0 +1,21 @@ +// sass-lint:disable empty-args + +@include describe('Math') { + @include it('iro-math-pow') { + @include assert-equal(iro-math-pow(2, 2), 2 * 2, '2^2'); + @include assert-equal(iro-math-pow(2, 3), 2 * 2 * 2, '2^3'); + @include assert-equal(iro-math-pow(4, 3), 4 * 4 * 4, '4^3'); + @include assert-equal(iro-math-pow(3, -1), 1 / 3, '3^(-1)'); + @include assert-equal(iro-math-pow(4, -2), 1 / (4 * 4), '4^(-2)'); + @include assert-equal(iro-math-pow(3, 0), 1, '3^0'); + } + + @include it('iro-math-clamp') { + @include assert-equal(iro-math-clamp(0, 0, 10), 0, '0 in [0, 10]'); + @include assert-equal(iro-math-clamp(10, 0, 10), 10, '10 in [0, 10]'); + @include assert-equal(iro-math-clamp(20, 0, 10), 10, '20 in [0, 10]'); + @include assert-equal(iro-math-clamp(3, 10, 20), 10, '3 in [10, 20]'); + @include assert-equal(iro-math-clamp(-5, -30, -10), -10, '-5 in [-30, -10]'); + @include assert-equal(iro-math-clamp(-5, -30, -2), -5, '-5 in [-30, -2]'); + } +} diff --git a/test/_props.scss b/test/_props.scss new file mode 100644 index 0000000..4e0a5b4 --- /dev/null +++ b/test/_props.scss @@ -0,0 +1,282 @@ +// sass-lint:disable empty-args + +@include describe('Property trees') { + @include it('Validate names') { + $map-valid: ( + --background: #fff, + --text: #000, + --buttons: ( + --primary: ( + --background: #f00, + --text: #fff + ) + ) + ); + + $map-invalid: ( + --background: #fff, + --text: #000, + --buttons: ( + --primary: ( + background: #f00, + text: #fff + ) + ) + ); + + @include assert-equal(iro-props-validate($map-valid), true, 'Check valid map'); + @include assert-equal(iro-props-validate($map-invalid), false, 'Check invalid map'); + } + + @include it('Save / Delete') { + $map: ( + --background: #fff, + --text: #000, + --buttons: ( + --primary: ( + --background: #f00, + --text: #fff + ), + --default: ( + --background: #ddd, + --text: #000 + ) + ) + ); + + @include assert-equal(iro-props-save($map), null, 'Save default tree'); + @include assert-equal(iro-props-delete(), null, 'Delete default tree'); + } + + @include it('Read') { + $map1: ( + --background: #fff, + --text: #000, + --buttons: ( + --primary: ( + --background: #f00, + --text: #fff + ), + --default: ( + --background: #ddd, + --text: #000 + ) + ) + ); + + $map2: ( + --background: #222, + --text: #fff, + --buttons: ( + --primary: ( + --background: #f00, + --text: #fff + ), + --default: ( + --background: #444, + --text: #fff + ) + ) + ); + + @include assert-equal(iro-props-save($map1), null, 'Save default tree'); + @include assert-equal(iro-props-save($map2, 'test'), null, 'Save "test" tree'); + + @include assert-equal(iro-props-get(--background), map-get($map1, --background), 'Get --background in default'); + @include assert-equal(iro-props-get(--buttons --primary --background), map-get(map-get(map-get($map1, --buttons), --primary), --background), 'Get --buttons --primary --background in default'); + @include assert-equal(iro-props-get(--buttons --default --text), map-get(map-get(map-get($map1, --buttons), --default), --text), 'Get --buttons --default --text in default'); + @include assert-equal(iro-props-get(--box, $default: false), false, 'Get nonexistent in default'); + + @include assert-equal(iro-props-get(--background, 'test'), map-get($map2, --background), 'Get --background in "test"'); + @include assert-equal(iro-props-get(--buttons --primary --background, 'test'), map-get(map-get(map-get($map2, --buttons), --primary), --background), 'Get --buttons --primary --background in "test"'); + @include assert-equal(iro-props-get(--buttons --default --text, 'test'), map-get(map-get(map-get($map2, --buttons), --default), --text), 'Get --buttons --default --text in "test"'); + @include assert-equal(iro-props-get(--box, 'test', $default: false), false, 'Get nonexistent in "test"'); + + @include assert-equal(iro-props-delete(), null, 'Delete default tree'); + @include assert-equal(iro-props-delete('test'), null, 'Delete "test" tree'); + } + + @include it('Overwrite') { + $map1: ( + --background: #fff, + --text: #000, + --buttons: ( + --primary: ( + --background: #f00, + --text: #fff + ) + ) + ); + + $map2: ( + --background: #eee, + --buttons: ( + --primary: ( + --background: #00f + ), + --default: ( + --background: #444, + --text: #fff + ) + ) + ); + + @include assert-equal(iro-props-save($map1), null, 'Save default tree'); + + @include assert-equal(iro-props-get(), $map1, 'Before update, get whole map'); + @include assert-equal(iro-props-get(--background), map-get($map1, --background), 'Before update, get --background'); + @include assert-equal(iro-props-get(--text), map-get($map1, --text), 'Before update, get --text'); + @include assert-equal(iro-props-get(--buttons --primary --background), map-get(map-get(map-get($map1, --buttons), --primary), --background), 'Before update, get --buttons --primary --background'); + @include assert-equal(iro-props-get(--buttons --default --text, $default: false), false, 'Before update, get --buttons --default --text (returns default)'); + + @include assert-equal(iro-props-save($map2, $merge: true), null, 'Overwrite default tree'); + + @include assert-equal(iro-props-get(), iro-map-merge-recursive($map1, $map2), 'After update, get whole map'); + @include assert-equal(iro-props-get(--background), map-get($map2, --background), 'After update, get --background'); + @include assert-equal(iro-props-get(--text), map-get($map1, --text), 'After update, get --text'); + @include assert-equal(iro-props-get(--buttons --primary --background), map-get(map-get(map-get($map2, --buttons), --primary), --background), 'After update, get --buttons --primary --background'); + @include assert-equal(iro-props-get(--buttons --default --text), map-get(map-get(map-get($map2, --buttons), --default), --text), 'After update, get --buttons --default --text'); + + @include assert-equal(iro-props-delete(), null, 'Delete default tree'); + } + + @include it('Native assignment') { + @include assert('Simple') { + $map: ( + --background: #fff, + --text: #000, + --buttons: ( + --primary: ( + --background: #f00, + --text: #fff + ), + --default: ( + --background: #ddd, + --text: #000 + ) + ) + ); + + @include iro-props-save($map); + + @include output { + @include iro-props-assign-native; + } + + @include expect { + --background: #{map-get($map, --background)}; + --text: #{map-get($map, --text)}; + --buttons--primary--background: #{map-get(map-get(map-get($map, --buttons), --primary), --background)}; + --buttons--primary--text: #{map-get(map-get(map-get($map, --buttons), --primary), --text)}; + --buttons--default--background: #{map-get(map-get(map-get($map, --buttons), --default), --background)}; + --buttons--default--text: #{map-get(map-get(map-get($map, --buttons), --default), --text)}; + } + + @include iro-props-delete; + } + + @include assert('Filtered') { + $map: ( + --background: #fff, + --text: #000, + --buttons: ( + --primary: ( + --background: #f00, + --text: #fff + ), + --default: ( + --background: #ddd, + --text: #000 + ) + ) + ); + + @include iro-props-save($map); + + @include output { + @include iro-props-assign-native($skip: --buttons); + } + + @include expect { + --background: #{map-get($map, --background)}; + --text: #{map-get($map, --text)}; + } + + @include iro-props-delete; + } + } + + @include it('Native get') { + $map: ( + --background: #fff, + --text: #000, + --buttons: ( + --primary: ( + --background: #f00, + --text: #fff + ), + --default: ( + --background: #ddd, + --text: #000 + ) + ) + ); + + @include assert-equal(iro-props-save($map), null, 'Save default tree'); + + @include assert-equal(iro-props-get-native(--background), var(--background), 'Get --background'); + @include assert-equal(iro-props-get-native(--buttons --primary --text), var(--buttons--primary--text), 'Get --buttons --primary --text'); + @include assert-equal(iro-props-get-native(--buttons --secondary --text, $default: false), var(--buttons--secondary--text, false), 'Get --buttons --secondary --text with default'); + + @include assert-equal(iro-props-delete(), null, 'Delete default tree'); + } + + @include it('References') { + $map1: ( + --background: #fff, + --text: #000, + --buttons: ( + --primary: ( + --background: #f00, + --text: #fff + ) + ) + ); + + $map2: ( + --background: #eee, + --buttons: ( + --primary: ( + --background: iro-props-ref($key: --background) + ), + --default: iro-props-ref($key: --buttons --primary) + ) + ); + + @include assert-equal(iro-props-save($map1), null, 'Save default tree'); + @include assert-equal(iro-props-save($map2, 'second'), null, 'Save "second" tree'); + + @include assert-equal(iro-props-get(--buttons --primary --background, 'second'), map-get($map1, --background), 'Get referenced value'); + @include assert-equal(iro-props-get-native(--buttons --primary --background, 'second'), var(--buttons--primary--background), 'Get referenced value, native'); + + @include assert-equal(iro-props-get(--buttons --default, 'second'), map-get(map-get($map1, --buttons), --primary), 'Get referenced subtree, whole'); + @include assert-equal(iro-props-get(--buttons --default --background, 'second'), map-get(map-get(map-get($map1, --buttons), --primary), --background), 'Get referenced subtree, inner value'); + @include assert-equal(iro-props-get-native(--buttons --default --background, 'second'), var(--buttons--default--background), 'Get referenced subtree, native'); + + @include assert('Native assignment') { + @include output { + @include iro-props-assign-native('second'); + } + + @include expect { + --background: #{map-get($map2, --background)}; + --buttons--primary--background: #{map-get($map1, --background)}; + --buttons--default--background: #{map-get(map-get(map-get($map1, --buttons), --primary), --background)}; + --buttons--default--text: #{map-get(map-get(map-get($map1, --buttons), --primary), --text)}; + } + } + + @include assert-equal(iro-props-delete(), null, 'Delete default tree'); + @include assert-equal(iro-props-delete('second'), null, 'Delete "second" tree'); + } +} diff --git a/test/_responsive.scss b/test/_responsive.scss new file mode 100644 index 0000000..cdda40c --- /dev/null +++ b/test/_responsive.scss @@ -0,0 +1,9 @@ +@include describe('Responsive') { + @include it('iro-responsive-fluid-calc') { + $rem600px: iro-px-to-rem(600px); + $rem800px: iro-px-to-rem(800px); + + @include assert-equal(iro-responsive-fluid-calc(2rem, 4rem, 600px, 800px), 'calc(2rem + 2 * ((100vw - #{$rem600px}) / #{iro-strip-unit($rem800px - $rem600px)}))', 'Responsive value from 2rem to 4rem over 600px to 800px'); + @include assert-equal(iro-responsive-fluid-calc(4px, 12px, 600px, 800px), 'calc(4px + 8 * ((100vw - 600px) / 200))', 'Responsive value from 4px to 12px over 600px to 800px'); + } +} diff --git a/test/bem/_examples.scss b/test/bem/_examples.scss new file mode 100644 index 0000000..243ee35 --- /dev/null +++ b/test/bem/_examples.scss @@ -0,0 +1,224 @@ +// sass-lint:disable class-name-format force-element-nesting force-pseudo-nesting mixins-before-declarations no-empty-rulesets + +// +// Included test cases: +// - /// 1 /// - Media object +// - /// 2 /// - Tabs +/// - /// 3 /// - Accordion +// + +@include it('Examples') { + @include assert('Media object') { /// 1 /// + @include output { + @include iro-bem-object('media') { + display: flex; + align-items: flex-start; + justify-content: flex-start; + + @include iro-bem-element('image') { + display: block; + flex: 0 0 auto; + order: 1; + overflow: hidden; + } + + @include iro-bem-element('body') { + order: 2; + } + + @include iro-bem-modifier('rtl') { + justify-content: flex-end; + + @include iro-bem-element('image') { + order: 2; + } + + @include iro-bem-element('body') { + order: 1; + } + } + } + } + + @include expect { + .o-media { + display: flex; + align-items: flex-start; + justify-content: flex-start; + } + + .o-media__image { + display: block; + flex: 0 0 auto; + order: 1; + overflow: hidden; + } + + .o-media__body { + order: 2; + } + + .o-media--rtl { + justify-content: flex-end; + + .o-media__image { + order: 2; + } + + .o-media__body { + order: 1; + } + } + } + } + + @include assert('Tabs') { /// 2 /// + @include output { + @include iro-bem-component('tabs') { + position: relative; + + @include iro-bem-element('tab') { + float: left; + } + + @include iro-bem-element('tabRadio') { + position: absolute; + top: -9999px; + left: -9999px; + + &:checked { + @include iro-bem-sibling-element('tabLabel') { + font-weight: bold; + } + + @include iro-bem-sibling-element('tabContent') { + display: block; + } + } + } + + @include iro-bem-element('tabLabel') { + cursor: pointer; + + &:hover, + &:active { + text-decoration: underline; + } + } + + @include iro-bem-element('tabContent') { + position: absolute; + left: 0; + display: none; + } + } + } + + @include expect { + .c-tabs { + position: relative; + } + + .c-tabs__tab { + float: left; + } + + .c-tabs__tabRadio { + position: absolute; + top: -9999px; + left: -9999px; + } + + .c-tabs__tabRadio:checked ~ .c-tabs__tabLabel { + font-weight: bold; + } + + .c-tabs__tabRadio:checked ~ .c-tabs__tabContent { + display: block; + } + + .c-tabs__tabLabel { + cursor: pointer; + } + + .c-tabs__tabLabel:hover, + .c-tabs__tabLabel:active { + text-decoration: underline; + } + + .c-tabs__tabContent { + position: absolute; + left: 0; + display: none; + } + } + } + + @include assert('Accordion') { /// 3 /// + @include output { + @include iro-bem-component('accordion') { + @include iro-bem-element('section') { + // nothing to do + } + + @include iro-bem-element('sectionCheckbox') { + position: absolute; + top: -9999px; + left: -9999px; + + &:checked { + @include iro-bem-sibling-element('sectionLabel') { + font-weight: bold; + } + + @include iro-bem-sibling-element('sectionContent') { + display: block; + } + } + } + + @include iro-bem-element('sectionLabel') { + cursor: pointer; + + &:hover, + &:active { + text-decoration: underline; + } + } + + @include iro-bem-element('sectionContent') { + display: none; + } + } + } + + @include expect { + .c-accordion__sectionCheckbox { + position: absolute; + top: -9999px; + left: -9999px; + } + + .c-accordion__sectionCheckbox:checked ~ .c-accordion__sectionLabel { + font-weight: bold; + } + + .c-accordion__sectionCheckbox:checked ~ .c-accordion__sectionContent { + display: block; + } + + .c-accordion__sectionLabel { + cursor: pointer; + } + + .c-accordion__sectionLabel:hover, + .c-accordion__sectionLabel:active { + text-decoration: underline; + } + + .c-accordion__sectionContent { + display: none; + } + } + } +} diff --git a/test/bem/_iro-bem-at-theme.scss b/test/bem/_iro-bem-at-theme.scss new file mode 100644 index 0000000..d2d0696 --- /dev/null +++ b/test/bem/_iro-bem-at-theme.scss @@ -0,0 +1,55 @@ +// sass-lint:disable class-name-format force-element-nesting force-pseudo-nesting mixins-before-declarations + +// +// Included test cases: +// - /// 1 /// - single theme +// - /// 2 /// - with sub-theme +// + +@include it('iro-bem-at-theme') { + @include assert('single theme') { /// 1 /// + @include output(false) { + @include iro-bem-block('something') { + @include iro-bem-at-theme('theme') { + font-size: 2em; + } + } + } + + @include expect(false) { + .t-theme .something, + [class*=' t-'] .t-theme .something, + [class^='t-'] .t-theme .something { + font-size: 2em; + } + } + } + + @include assert('with sub-theme') { /// 2 /// + @include output(false) { + @include iro-bem-block('something') { + @include iro-bem-at-theme('theme') { + font-size: 2em; + } + + @include iro-bem-at-theme('theme', 'subtheme') { + font-size: 3em; + } + } + } + + @include expect(false) { + .t-theme .something, + [class*=' t-'] .t-theme .something, + [class^='t-'] .t-theme .something { + font-size: 2em; + } + + .t-theme .t-subtheme .something, + [class*=' t-'] .t-theme .t-subtheme .something, + [class^='t-'] .t-theme .t-subtheme .something { + font-size: 3em; + } + } + } +} diff --git a/test/bem/_iro-bem-block.scss b/test/bem/_iro-bem-block.scss new file mode 100644 index 0000000..a93d803 --- /dev/null +++ b/test/bem/_iro-bem-block.scss @@ -0,0 +1,85 @@ +// sass-lint:disable class-name-format force-element-nesting force-pseudo-nesting mixins-before-declarations + +// +// Included test cases: +// - /// 1 /// - without namespace +// - /// 2 /// - with namespace +// - /// 3 /// - nested +// - /// 4 /// - within selector +// + +@include it('iro-bem-block') { + @include assert('without namespace') { /// 1 /// + @include output(false) { + @include iro-bem-block('something') { + font-size: 1em; + } + } + + @include expect(false) { + .something { + font-size: 1em; + } + } + } + + @each $ns in map-keys($iro-bem-namespaces) { + @include assert('with namespace "#{$ns}"') { /// 2 /// + @include output(false) { + @include iro-bem-block('something', $ns) { + font-size: 1em; + } + } + + @include expect(false) { + @if $ns != 'theme' { + .#{map-get($iro-bem-namespaces, $ns)}-something { + font-size: 1em; + } + } @else { + .t-something, + [class*=' t-'] .t-something, + [class^='t-'] .t-something { + font-size: 1em; + } + } + } + } + } + + @include assert('nested') { /// 3 /// + @include output(false) { + @include iro-bem-theme('theme') { + @include iro-bem-theme('subtheme') { + @include iro-bem-block('something') { + font-size: 2em; + } + } + } + } + + @include expect(false) { + .t-theme .t-subtheme .something, + [class*=' t-'] .t-theme .t-subtheme .something, + [class^='t-'] .t-theme .t-subtheme .something { + font-size: 2em; + } + } + } + + @include assert('within selector') { /// 4 /// + @include output(false) { + .sel { + @include iro-bem-block('something') { + font-size: 2em; + } + } + } + + @include expect(false) { + .sel .something { + font-size: 2em; + } + } + } +} diff --git a/test/bem/_iro-bem-composed-of.scss b/test/bem/_iro-bem-composed-of.scss new file mode 100644 index 0000000..e724eb8 --- /dev/null +++ b/test/bem/_iro-bem-composed-of.scss @@ -0,0 +1,149 @@ +// sass-lint:disable class-name-format force-element-nesting force-pseudo-nesting mixins-before-declarations + +// +// Included test cases: +// - /// 1 /// - without namespace, single +// - /// 2 /// - with namespace, single +// - /// 3 /// - without namespace, multiple +// - /// 4 /// - with namespace, multiple +// + +@include it('iro-bem-composed-of') { + @include assert('without namespace, single') { /// 1 /// + @include output(false) { + @include iro-bem-block('something') { + font-size: 1em; + } + + @include iro-bem-block('another') { + @include iro-bem-composed-of('something'); + + font-size: 2em; + } + } + + @include expect(false) { + .something { + font-size: 1em; + } + + .another { + font-size: 2em; + } + } + } + + @each $ns in map-keys($iro-bem-namespaces) { + @include assert('with namespace "#{$ns}", single') { /// 2 /// + @include output(false) { + @include iro-bem-block('something', $ns) { + font-size: 1em; + } + + @include iro-bem-block('another') { + @include iro-bem-composed-of('something' $ns); + + font-size: 2em; + } + } + + @include expect(false) { + @if $ns != 'theme' { + .#{map-get($iro-bem-namespaces, $ns)}-something { + font-size: 1em; + } + } @else { + .t-something, + [class*=' t-'] .t-something, + [class^='t-'] .t-something { + font-size: 1em; + } + } + + .another { + font-size: 2em; + } + } + } + } + + @include assert('without namespace, multiple') { /// 3 /// + @include output(false) { + @include iro-bem-block('something') { + font-size: 1em; + } + + @include iro-bem-block('somethingElse') { + font-size: 1em; + } + + @include iro-bem-block('another') { + @include iro-bem-composed-of('something', 'somethingElse'); + + font-size: 2em; + } + } + + @include expect(false) { + .something { + font-size: 1em; + } + + .somethingElse { + font-size: 1em; + } + + .another { + font-size: 2em; + } + } + } + + @each $ns in map-keys($iro-bem-namespaces) { + @include assert('with namespace "#{$ns}", multiple') { /// 4 /// + @include output(false) { + @include iro-bem-block('something', $ns) { + font-size: 1em; + } + + @include iro-bem-block('somethingElse', $ns) { + font-size: 1em; + } + + @include iro-bem-block('another') { + @include iro-bem-composed-of('something' $ns, 'somethingElse' $ns); + + font-size: 2em; + } + } + + @include expect(false) { + @if $ns != 'theme' { + .#{map-get($iro-bem-namespaces, $ns)}-something { + font-size: 1em; + } + + .#{map-get($iro-bem-namespaces, $ns)}-somethingElse { + font-size: 1em; + } + } @else { + .t-something, + [class*=' t-'] .t-something, + [class^='t-'] .t-something { + font-size: 1em; + } + + .t-somethingElse, + [class*=' t-'] .t-somethingElse, + [class^='t-'] .t-somethingElse { + font-size: 1em; + } + } + + .another { + font-size: 2em; + } + } + } + } +} diff --git a/test/bem/_iro-bem-element.scss b/test/bem/_iro-bem-element.scss new file mode 100644 index 0000000..f69f133 --- /dev/null +++ b/test/bem/_iro-bem-element.scss @@ -0,0 +1,491 @@ +// sass-lint:disable class-name-format force-element-nesting force-pseudo-nesting mixins-before-declarations + +// +// Included test cases: +// - /// 1 /// - single element +// - /// 2 /// - single element, manual selector in-between +// - /// 3 /// - single element, modifier in-between +// - /// 4 /// - single element, nested +// - /// 5 /// - single element, nested, manual selector in-between +// - /// 6 /// - single element, nested, modifier in-between +// - /// 7 /// - single element, in at-theme +// - /// 8 /// - multiple elements +// - /// 9 /// - multiple elements, manual selector in-between +// - /// 10 /// - multiple elements, modifier in-between +// - /// 11 /// - multiple elements, nested +// - /// 12 /// - multiple elements, nested, manual selector in-between +// - /// 13 /// - multiple elements, nested, modifier in-between +// - /// 14 /// - single element, in at-theme +// + +@include it('iro-bem-element') { + @include assert('single element') { /// 1 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child') { + font-size: 2em; + } + } + } + + @include expect { + .something__child { + font-size: 2em; + } + } + } + + @include assert('single element, manual selector in-between') { /// 2 /// + @include output(false) { + @include iro-bem-block('something') { + &:hover { + @include iro-bem-element('child1') { + font-size: 2em; + } + } + + .test & { + @include iro-bem-element('child2') { + font-size: 2em; + } + } + } + } + + @include expect(false) { + .something:hover .something__child1 { + font-size: 2em; + } + + .test .something__child2 { + font-size: 2em; + } + } + } + + @include assert('single element, modifier in-between') { /// 3 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-modifier('mod') { + @include iro-bem-element('child') { + font-size: 2em; + } + } + } + } + + @include expect { + .something--mod .something__child { + font-size: 2em; + } + } + } + + @include assert('single element, nested') { /// 4 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child') { + font-size: 2em; + + @include iro-bem-element('subchild') { + font-size: 3em; + } + } + } + } + + @include expect { + .something__child { + font-size: 2em; + } + + .something__child .something__subchild { + font-size: 3em; + } + } + } + + @include assert('single element, nested, manual selector in-between') { /// 5 /// + @include output(false) { + @include iro-bem-block('something') { + &:hover { + @include iro-bem-element('child1') { + font-size: 2em; + + @include iro-bem-element('subchild1') { + font-size: 3em; + } + } + } + + .test & { + @include iro-bem-element('child2') { + font-size: 2em; + + @include iro-bem-element('subchild2') { + font-size: 3em; + } + } + } + + @include iro-bem-element('child3') { + font-size: 2em; + + &:hover { + @include iro-bem-element('subchild3') { + font-size: 3em; + } + } + + .test & { + @include iro-bem-element('subchild4') { + font-size: 3em; + } + } + } + } + } + + @include expect(false) { + .something:hover .something__child1 { + font-size: 2em; + } + + .something:hover .something__child1 .something__subchild1 { + font-size: 3em; + } + + .test .something__child2 { + font-size: 2em; + } + + .test .something__child2 .something__subchild2 { + font-size: 3em; + } + + .something__child3 { + font-size: 2em; + } + + .something__child3:hover .something__subchild3 { + font-size: 3em; + } + + .test .something__child3 .something__subchild4 { + font-size: 3em; + } + } + } + + @include assert('single element, nested, modifier in-between') { /// 6 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-modifier('mod') { + @include iro-bem-element('child') { + font-size: 2em; + + @include iro-bem-element('subchild') { + font-size: 3em; + } + } + } + + @include iro-bem-element('child') { + font-size: 2em; + + @include iro-bem-modifier('mod') { + @include iro-bem-element('subchild') { + font-size: 3em; + } + } + } + } + } + + @include expect { + .something--mod .something__child { + font-size: 2em; + } + + .something--mod .something__child .something__subchild { + font-size: 3em; + } + + .something__child { + font-size: 2em; + } + + .something__child--mod .something__subchild { + font-size: 3em; + } + } + } + + @include assert('single element, in at-theme') { /// 7 /// + @include output(false) { + @include iro-bem-block('something') { + @include iro-bem-at-theme('dark') { + @include iro-bem-element('child') { + font-size: 2em; + } + } + } + } + + @include expect(false) { + .t-dark .something__child, + [class*=' t-'] .t-dark .something__child, + [class^='t-'] .t-dark .something__child { + font-size: 2em; + } + } + } + + @include assert('multiple elements') { /// 8 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child1', 'child2') { + font-size: 2em; + } + } + } + + @include expect { + .something__child1, + .something__child2 { + font-size: 2em; + } + } + } + + @include assert('multiple elements, manual selector in-between') { /// 9 /// + @include output(false) { + @include iro-bem-block('something') { + &:hover { + @include iro-bem-element('child1', 'child2') { + font-size: 2em; + } + } + + .test & { + @include iro-bem-element('child3', 'child4') { + font-size: 2em; + } + } + } + } + + @include expect(false) { + .something:hover .something__child1, + .something:hover .something__child2 { + font-size: 2em; + } + + .test .something__child3, + .test .something__child4 { + font-size: 2em; + } + } + } + + @include assert('multiple elements, modifier in-between') { /// 10 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-modifier('mod') { + @include iro-bem-element('child1', 'child2') { + font-size: 2em; + } + } + } + } + + @include expect { + .something--mod .something__child1, + .something--mod .something__child2 { + font-size: 2em; + } + } + } + + @include assert('multiple elements, nested') { /// 11 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child1', 'child2') { + font-size: 2em; + + @include iro-bem-element('subchild1') { + font-size: 3em; + } + } + + @include iro-bem-element('child3') { + font-size: 2em; + + @include iro-bem-element('subchild2', 'subchild3') { + font-size: 3em; + } + } + } + } + + @include expect { + .something__child1, + .something__child2 { + font-size: 2em; + } + + .something__child1 .something__subchild1, + .something__child2 .something__subchild1 { + font-size: 3em; + } + + .something__child3 { + font-size: 2em; + } + + .something__child3 .something__subchild2, + .something__child3 .something__subchild3 { + font-size: 3em; + } + } + } + + @include assert('multiple elements, nested, manual selector in-between') { /// 12 /// + @include output(false) { + @include iro-bem-block('something') { + @include iro-bem-element('child1', 'child2') { + font-size: 2em; + + &:hover { + @include iro-bem-element('subchild1') { + font-size: 3em; + } + } + + .test & { + @include iro-bem-element('subchild2') { + font-size: 3em; + } + } + } + + @include iro-bem-element('child3') { + font-size: 2em; + + &:hover { + @include iro-bem-element('subchild3', 'subchild4') { + font-size: 3em; + } + } + + .test & { + @include iro-bem-element('subchild5', 'subchild6') { + font-size: 3em; + } + } + } + } + } + + @include expect(false) { + .something__child1, + .something__child2 { + font-size: 2em; + } + + .something__child1:hover .something__subchild1, + .something__child2:hover .something__subchild1 { + font-size: 3em; + } + + .test .something__child1 .something__subchild2, + .test .something__child2 .something__subchild2 { + font-size: 3em; + } + + .something__child3 { + font-size: 2em; + } + + .something__child3:hover .something__subchild3, + .something__child3:hover .something__subchild4 { + font-size: 3em; + } + + .test .something__child3 .something__subchild5, + .test .something__child3 .something__subchild6 { + font-size: 3em; + } + } + } + + @include assert('multiple elements, nested, modifier in-between') { /// 13 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child1', 'child2') { + font-size: 2em; + + @include iro-bem-modifier('mod') { + @include iro-bem-element('subchild1') { + font-size: 3em; + } + } + } + + @include iro-bem-element('child3') { + font-size: 2em; + + @include iro-bem-modifier('mod') { + @include iro-bem-element('subchild2', 'subchild3') { + font-size: 3em; + } + } + } + } + } + + @include expect { + .something__child1, + .something__child2 { + font-size: 2em; + } + + .something__child1--mod .something__subchild1, + .something__child2--mod .something__subchild1 { + font-size: 3em; + } + + .something__child3 { + font-size: 2em; + } + + .something__child3--mod .something__subchild2, + .something__child3--mod .something__subchild3 { + font-size: 3em; + } + } + } + + @include assert('multiple elements, in at-theme') { /// 14 /// + @include output(false) { + @include iro-bem-block('something') { + @include iro-bem-at-theme('dark') { + @include iro-bem-element('child1', 'child2') { + font-size: 2em; + } + } + } + } + + @include expect(false) { + .t-dark .something__child1, + [class*=' t-'] .t-dark .something__child1, + [class^='t-'] .t-dark .something__child1, + .t-dark .something__child2, + [class*=' t-'] .t-dark .something__child2, + [class^='t-'] .t-dark .something__child2 { + font-size: 2em; + } + } + } +} diff --git a/test/bem/_iro-bem-modifier.scss b/test/bem/_iro-bem-modifier.scss new file mode 100644 index 0000000..60e2fe4 --- /dev/null +++ b/test/bem/_iro-bem-modifier.scss @@ -0,0 +1,654 @@ +// sass-lint:disable class-name-format force-element-nesting force-pseudo-nesting mixins-before-declarations + +// +// Included test cases: +// - /// 1 /// - block modifier +// - /// 2 /// - block modifier, in at-theme +// - /// 3 /// - element modifier, single element +// - /// 4 /// - element modifier, multiple elements +// - /// 5 /// - element modifier, single related element +// - /// 6 /// - element modifier, multiple related elements +// - /// 7 /// - element modifier, single element, manual selector before +// - /// 8 /// - element modifier, multiple elements, manual selector before +// - /// 9 /// - element modifier, single related element, manual selector before +// - /// 10 /// - element modifier, multiple related elements, manual selector before +// - /// 11 /// - element modifier, in at-theme +// - /// 12 /// - nested block modifiers, extending +// - /// 13 /// - nested element modifiers, extending +// - /// 14 /// - block and element modifiers, single element +// - /// 15 /// - block and element modifiers, multiple elements +// + +@include it('iro-bem-modifier') { + @include assert('block modifier') { /// 1 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-modifier('mod') { + font-size: 1.5em; + + @include iro-bem-modifier('submod') { + font-size: 1.75em; + } + } + } + } + + @include expect { + .something--mod { + font-size: 1.5em; + } + + .something--mod.something--submod { + font-size: 1.75em; + } + } + } + + @include assert('block modifier, in at-theme') { /// 2 /// + @include output(false) { + @include iro-bem-block('something') { + @include iro-bem-at-theme('dark') { + @include iro-bem-modifier('mod') { + font-size: 1.5em; + + @include iro-bem-modifier('submod') { + font-size: 1.75em; + } + } + } + } + } + + @include expect(false) { + .t-dark .something--mod, + [class*=' t-'] .t-dark .something--mod, + [class^='t-'] .t-dark .something--mod { + font-size: 1.5em; + } + + .t-dark .something--mod.something--submod, + [class*=' t-'] .t-dark .something--mod.something--submod, + [class^='t-'] .t-dark .something--mod.something--submod { + font-size: 1.75em; + } + } + } + + @include assert('element modifier, single element') { /// 3 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child') { + @include iro-bem-modifier('mod') { + font-size: 2.5em; + + @include iro-bem-modifier('submod') { + font-size: 2.75em; + } + } + } + } + } + + @include expect { + .something__child--mod { + font-size: 2.5em; + } + + .something__child--mod.something__child--submod { + font-size: 2.75em; + } + } + } + + @include assert('element modifier, multiple elements') { /// 4 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child1', 'child2') { + @include iro-bem-modifier('mod') { + font-size: 2.5em; + + @include iro-bem-modifier('submod') { + font-size: 2.75em; + } + } + } + } + } + + @include expect { + .something__child1--mod, + .something__child2--mod { + font-size: 2.5em; + } + + .something__child1--mod.something__child1--submod, + .something__child2--mod.something__child2--submod { + font-size: 2.75em; + } + } + } + + @include assert('element modifier, single related element') { /// 5 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child1') { + @include iro-bem-next-element('child2') { + @include iro-bem-modifier('mod') { + font-size: 2.5em; + + @include iro-bem-modifier('submod') { + font-size: 2.75em; + } + } + } + } + } + } + + @include expect { + .something__child1 + .something__child2--mod { + font-size: 2.5em; + } + + .something__child1 + .something__child2--mod.something__child2--submod { + font-size: 2.75em; + } + } + } + + @include assert('element modifier, multiple related elements') { /// 6 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child1') { + @include iro-bem-next-element('child2', 'child3') { + @include iro-bem-modifier('mod') { + font-size: 2.5em; + + @include iro-bem-modifier('submod') { + font-size: 2.75em; + } + } + } + } + } + } + + @include expect { + .something__child1 + .something__child2--mod, + .something__child1 + .something__child3--mod { + font-size: 2.5em; + } + + .something__child1 + .something__child2--mod.something__child2--submod, + .something__child1 + .something__child3--mod.something__child3--submod { + font-size: 2.75em; + } + } + } + + @include assert('element modifier, single element, manual selector before') { /// 7 /// + @include output(false) { + @include iro-bem-block('something') { + &:hover { + @include iro-bem-element('child1') { + @include iro-bem-modifier('mod') { + font-size: 2.5em; + + @include iro-bem-modifier('submod') { + font-size: 2.75em; + } + } + } + } + + .test & { + @include iro-bem-element('child2') { + @include iro-bem-modifier('mod') { + font-size: 2.5em; + + @include iro-bem-modifier('submod') { + font-size: 2.75em; + } + } + } + } + } + } + + @include expect(false) { + .something:hover .something__child1--mod { + font-size: 2.5em; + } + + .something:hover .something__child1--mod.something__child1--submod { + font-size: 2.75em; + } + + .test .something__child2--mod { + font-size: 2.5em; + } + + .test .something__child2--mod.something__child2--submod { + font-size: 2.75em; + } + } + } + + @include assert('element modifier, multiple elements, manual selector before') { /// 8 /// + @include output(false) { + @include iro-bem-block('something') { + &:hover { + @include iro-bem-element('child1', 'child2') { + @include iro-bem-modifier('mod') { + font-size: 2.5em; + + @include iro-bem-modifier('submod') { + font-size: 2.75em; + } + } + } + } + + .test & { + @include iro-bem-element('child3', 'child4') { + @include iro-bem-modifier('mod') { + font-size: 2.5em; + + @include iro-bem-modifier('submod') { + font-size: 2.75em; + } + } + } + } + } + } + + @include expect(false) { + .something:hover .something__child1--mod, + .something:hover .something__child2--mod { + font-size: 2.5em; + } + + .something:hover .something__child1--mod.something__child1--submod, + .something:hover .something__child2--mod.something__child2--submod { + font-size: 2.75em; + } + + .test .something__child3--mod, + .test .something__child4--mod { + font-size: 2.5em; + } + + .test .something__child3--mod.something__child3--submod, + .test .something__child4--mod.something__child4--submod { + font-size: 2.75em; + } + } + } + + @include assert('element modifier, single related element, manual selector before') { /// 9 /// + @include output(false) { + @include iro-bem-block('something') { + &:hover { + @include iro-bem-element('child1') { + @include iro-bem-next-element('child2') { + @include iro-bem-modifier('mod1') { + font-size: 2.5em; + + @include iro-bem-modifier('submod1') { + font-size: 2.75em; + } + } + } + } + } + + .test & { + @include iro-bem-element('child3') { + @include iro-bem-next-element('child4') { + @include iro-bem-modifier('mod1') { + font-size: 2.5em; + + @include iro-bem-modifier('submod1') { + font-size: 2.75em; + } + } + } + } + } + + @include iro-bem-element('child5') { + &:hover { + @include iro-bem-next-element('child6') { + @include iro-bem-modifier('mod2') { + font-size: 2.5em; + + @include iro-bem-modifier('submod2') { + font-size: 2.75em; + } + } + } + } + + .test & { + @include iro-bem-next-element('child7') { + @include iro-bem-modifier('mod2') { + font-size: 2.5em; + + @include iro-bem-modifier('submod2') { + font-size: 2.75em; + } + } + } + } + } + } + } + + @include expect(false) { + .something:hover .something__child1 + .something__child2--mod1 { + font-size: 2.5em; + } + + .something:hover .something__child1 + .something__child2--mod1.something__child2--submod1 { + font-size: 2.75em; + } + + .test .something__child3 + .something__child4--mod1 { + font-size: 2.5em; + } + + .test .something__child3 + .something__child4--mod1.something__child4--submod1 { + font-size: 2.75em; + } + + .something__child5:hover + .something__child6--mod2 { + font-size: 2.5em; + } + + .something__child5:hover + .something__child6--mod2.something__child6--submod2 { + font-size: 2.75em; + } + + .test .something__child5 + .something__child7--mod2 { + font-size: 2.5em; + } + + .test .something__child5 + .something__child7--mod2.something__child7--submod2 { + font-size: 2.75em; + } + } + } + + @include assert('element modifier, multiple related elements, manual selector before') { /// 10 /// + @include output(false) { + @include iro-bem-block('something') { + &:hover { + @include iro-bem-element('child1') { + @include iro-bem-next-element('child2', 'child3') { + @include iro-bem-modifier('mod1') { + font-size: 2.5em; + + @include iro-bem-modifier('submod1') { + font-size: 2.75em; + } + } + } + } + } + + .test & { + @include iro-bem-element('child4') { + @include iro-bem-next-element('child5', 'child6') { + @include iro-bem-modifier('mod1') { + font-size: 2.5em; + + @include iro-bem-modifier('submod1') { + font-size: 2.75em; + } + } + } + } + } + + @include iro-bem-element('child7') { + &:hover { + @include iro-bem-next-element('child8', 'child9') { + @include iro-bem-modifier('mod2') { + font-size: 2.5em; + + @include iro-bem-modifier('submod2') { + font-size: 2.75em; + } + } + } + } + + .test & { + @include iro-bem-next-element('child10', 'child11') { + @include iro-bem-modifier('mod2') { + font-size: 2.5em; + + @include iro-bem-modifier('submod2') { + font-size: 2.75em; + } + } + } + } + } + } + } + + @include expect(false) { + .something:hover .something__child1 + .something__child2--mod1, + .something:hover .something__child1 + .something__child3--mod1 { + font-size: 2.5em; + } + + .something:hover .something__child1 + .something__child2--mod1.something__child2--submod1, + .something:hover .something__child1 + .something__child3--mod1.something__child3--submod1 { + font-size: 2.75em; + } + + .test .something__child4 + .something__child5--mod1, + .test .something__child4 + .something__child6--mod1 { + font-size: 2.5em; + } + + .test .something__child4 + .something__child5--mod1.something__child5--submod1, + .test .something__child4 + .something__child6--mod1.something__child6--submod1 { + font-size: 2.75em; + } + + .something__child7:hover + .something__child8--mod2, + .something__child7:hover + .something__child9--mod2 { + font-size: 2.5em; + } + + .something__child7:hover + .something__child8--mod2.something__child8--submod2, + .something__child7:hover + .something__child9--mod2.something__child9--submod2 { + font-size: 2.75em; + } + + .test .something__child7 + .something__child10--mod2, + .test .something__child7 + .something__child11--mod2 { + font-size: 2.5em; + } + + .test .something__child7 + .something__child10--mod2.something__child10--submod2, + .test .something__child7 + .something__child11--mod2.something__child11--submod2 { + font-size: 2.75em; + } + } + } + + /* + @include assert('element modifier, in at-theme') { /// 11 /// + @include output(false) { + @include iro-bem-block('something') { + @include iro-bem-at-theme('dark') { + @include iro-bem-element('child') { + @include iro-bem-modifier('mod') { + font-size: 2.5em; + + @include iro-bem-modifier('submod') { + font-size: 2.75em; + } + } + } + } + } + } + + @include expect(false) { + .t-dark .something__child--mod, + [class*=' t-'] .t-dark .something__child--mod, + [class^='t-'] .t-dark .something__child--mod { + font-size: 2.5em; + } + + .t-dark .something__child--mod.something__child--submod, + [class*=' t-'] .t-dark .something__child--mod.something__child--submod, + [class^='t-'] .t-dark .something__child--mod.something__child--submod { + font-size: 2.75em; + } + } + } + */ + + @include assert('nested block modifiers, extending') { /// 12 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-modifier('mod') { + font-size: 1.5em; + + @include iro-bem-modifier('submod' true) { + font-size: 1.75em; + } + } + } + } + + @include expect { + .something--mod { + font-size: 1.5em; + } + + .something--mod--submod { + font-size: 1.75em; + } + } + } + + @include assert('nested element modifiers, extending') { /// 13 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child') { + @include iro-bem-modifier('mod') { + font-size: 2.5em; + + @include iro-bem-modifier('submod' true) { + font-size: 2.75em; + } + } + } + } + } + + @include expect { + .something__child--mod { + font-size: 2.5em; + } + + .something__child--mod--submod { + font-size: 2.75em; + } + } + } + + @include assert('block and element modifiers, single element') { /// 14 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-modifier('mod1') { + font-size: 1.5em; + + @include iro-bem-modifier('submod1') { + font-size: 1.75em; + } + + @include iro-bem-element('child') { + @include iro-bem-modifier('mod2') { + font-size: 2.5em; + + @include iro-bem-modifier('submod2') { + font-size: 2.75em; + } + } + } + } + } + } + + @include expect { + .something--mod1 { + font-size: 1.5em; + } + + .something--mod1.something--submod1 { + font-size: 1.75em; + } + + .something--mod1 .something__child--mod2 { + font-size: 2.5em; + } + + .something--mod1 .something__child--mod2.something__child--submod2 { + font-size: 2.75em; + } + } + } + + @include assert('block and element modifiers, multiple elements') { /// 15 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-modifier('mod1') { + font-size: 1.5em; + + @include iro-bem-modifier('submod') { + font-size: 1.75em; + } + + @include iro-bem-element('child1', 'child2') { + @include iro-bem-modifier('mod2') { + font-size: 2.5em; + + @include iro-bem-modifier('submod2') { + font-size: 2.75em; + } + } + } + } + } + } + + @include expect { + .something--mod1 { + font-size: 1.5em; + } + + .something--mod1.something--submod1 { + font-size: 1.75em; + } + + .something--mod1 .something__child1--mod2, + .something--mod1 .something__child2--mod2 { + font-size: 2.5em; + } + + .something--mod1 .something__child1--mod2.something__child1--submod2, + .something--mod1 .something__child2--mod2.something__child2--submod2 { + font-size: 2.75em; + } + } + } +} diff --git a/test/bem/_iro-bem-multi.scss b/test/bem/_iro-bem-multi.scss new file mode 100644 index 0000000..84bbca2 --- /dev/null +++ b/test/bem/_iro-bem-multi.scss @@ -0,0 +1,591 @@ +// sass-lint:disable class-name-format force-element-nesting force-pseudo-nesting mixins-before-declarations + +// +// Included test cases: +// - /// 1 /// - in root, 2 blocks +// - /// 2 /// - in root, 1 block, 1 manual selector +// - /// 3 /// - in block, 2 elements +// - /// 4 /// - in block, 1 element, 1 modifier +// - /// 5 /// - in block, 1 element, 1 extending modifier +// - /// 6 /// - in block, 1 element, 1 & selector +// - /// 7 /// - in block, 1 element, 1 manual selector +// - /// 8 /// - in element, 2 elements, 1 modifier +// - /// 9 /// - in element, 1 element, 1 & selector +// - /// 10 /// - in element in manual selector, 2 elements +// - /// 11 /// - in element in manual selector, 1 element, 1 & selector +// - /// 12 /// - in multiple elements, 2 elements, 1 modifier +// - /// 13 /// - in multiple elements, 1 element, 1 & selector +// - /// 14 /// - in related elements, 2 elements, 1 modifier +// - /// 15 /// - in related elements, 1 element, 1 & selector +// - /// 16 /// - in element, 2 related elements, 1 modifier +// - /// 17 /// - in element, 1 twin element, 1 modifier +// - /// 18 /// - in multiple elements, 1 twin element, 1 modifier +// + +@include it('iro-bem-state') { + @include assert('in root, 2 blocks') { /// 1 /// + @include output { + @include iro-bem-multi('component:' 'block1', 'object:' 'block2') { + font-size: 1em; + + @include iro-bem-element('child2') { + font-size: 2em; + } + } + } + + @include expect { + .c-block1 { + font-size: 1em; + } + + .c-block1__child2 { + font-size: 2em; + } + + .o-block2 { + font-size: 1em; + } + + .o-block2__child2 { + font-size: 2em; + } + } + } + + @include assert('in root, 1 block, 1 manual selector') { /// 2 /// + @include output { + @include iro-bem-multi('component:' 'block1', 'a:hover') { + font-size: 1em; + } + } + + @include expect { + .c-block1 { + font-size: 1em; + } + + a:hover { + font-size: 1em; + } + } + } + + @include assert('in block, 2 elements') { /// 3 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-multi('element:' 'child1' 'child2') { + font-size: 2em; + + @include iro-bem-modifier('mod') { + font-size: 2.5em; + } + } + } + } + + @include expect { + .something__child1, + .something__child2 { + font-size: 2em; + } + + .something__child1--mod, + .something__child2--mod { + font-size: 2.5em; + } + } + } + + @include assert('in block, 1 element, 1 modifier') { /// 4 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-multi('element:' 'child', 'modifier:' 'mod1') { + font-size: 2em; + + @include iro-bem-modifier('mod2') { + font-size: 2.5em; + } + } + } + } + + @include expect { + .something__child { + font-size: 2em; + } + + .something__child--mod2 { + font-size: 2.5em; + } + + .something--mod1 { + font-size: 2em; + } + + .something--mod1.something--mod2 { + font-size: 2.5em; + } + } + } + + @include assert('in block, 1 element, 1 extending modifier') { /// 5 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-multi('element:' 'child', 'modifier:' 'mod1') { + font-size: 2em; + + @include iro-bem-modifier('mod2' true) { + font-size: 2.5em; + } + } + } + } + + @include expect { + .something__child { + font-size: 2em; + } + + .something__child--mod2 { + font-size: 2.5em; + } + + .something--mod1 { + font-size: 2em; + } + + .something--mod1--mod2 { + font-size: 2.5em; + } + } + } + + @include assert('in block, 1 element, 1 & selector') { /// 6 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-multi('&', 'element:' 'child') { + font-size: 2em; + + @include iro-bem-modifier('mod') { + font-size: 2.5em; + } + } + } + } + + @include expect { + .something { + font-size: 2em; + } + + .something--mod { + font-size: 2.5em; + } + + .something__child { + font-size: 2em; + } + + .something__child--mod { + font-size: 2.5em; + } + } + } + + @include assert('in block, 1 element, 1 manual selector') { /// 7 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-multi('> a:hover', 'element:' 'child1') { + font-size: 2em; + + @include iro-bem-element('child2') { + font-size: 3em; + } + } + } + } + + @include expect { + .something > a:hover { + font-size: 2em; + } + + .something > a:hover .something__child2 { + font-size: 3em; + } + + .something__child1 { + font-size: 2em; + } + + .something__child1 .something__child2 { + font-size: 3em; + } + } + } + + @include assert('in element, 2 elements, 1 modifier') { /// 8 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child') { + @include iro-bem-multi('element:' 'subchild1' 'subchild2', 'modifier:' 'mod1') { + font-size: 3em; + + @include iro-bem-modifier('mod2') { + font-size: 3.5em; + } + } + } + } + } + + @include expect { + .something__child .something__subchild1, + .something__child .something__subchild2 { + font-size: 3em; + } + + .something__child .something__subchild1--mod2, + .something__child .something__subchild2--mod2 { + font-size: 3.5em; + } + + .something__child--mod1 { + font-size: 3em; + } + + .something__child--mod1.something__child--mod2 { + font-size: 3.5em; + } + } + } + + @include assert('in element, 1 element, 1 & selector') { /// 9 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child') { + @include iro-bem-multi('element:' 'subchild', '&') { + font-size: 3em; + + @include iro-bem-modifier('mod') { + font-size: 3.5em; + } + } + } + } + } + + @include expect { + .something__child .something__subchild { + font-size: 3em; + } + + .something__child .something__subchild--mod { + font-size: 3.5em; + } + + .something__child { + font-size: 3em; + } + + .something__child--mod { + font-size: 3.5em; + } + } + } + + @include assert('in element in manual selector, 2 elements') { /// 10 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child') { + &:hover { + @include iro-bem-multi('element:' 'subchild1' 'subchild2') { + font-size: 3em; + + @include iro-bem-modifier('mod2') { + font-size: 3.5em; + } + } + } + } + } + } + + @include expect { + .something__child:hover .something__subchild1, + .something__child:hover .something__subchild2 { + font-size: 3em; + } + + .something__child:hover .something__subchild1--mod2, + .something__child:hover .something__subchild2--mod2 { + font-size: 3.5em; + } + } + } + + @include assert('in element in manual selector, 1 element, 1 & selector') { /// 11 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child') { + &:hover { + @include iro-bem-multi('element:' 'subchild', '&') { + font-size: 3em; + } + } + } + } + } + + @include expect { + .something__child:hover .something__subchild { + font-size: 3em; + } + + .something__child:hover { + font-size: 3em; + } + } + } + + @include assert('in multiple elements, 2 elements, 1 modifier') { /// 12 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child1', 'child2') { + @include iro-bem-multi('element:' 'subchild1' 'subchild2', 'modifier:' 'mod') { + font-size: 3em; + } + } + } + } + + @include expect { + .something__child1 .something__subchild1, + .something__child2 .something__subchild1, + .something__child1 .something__subchild2, + .something__child2 .something__subchild2 { + font-size: 3em; + } + + .something__child1--mod, + .something__child2--mod { + font-size: 3em; + } + } + } + + @include assert('in multiple elements, 1 element, 1 & selector') { /// 13 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child1', 'child2') { + @include iro-bem-multi('element:' 'subchild', '&') { + font-size: 3em; + + @include iro-bem-modifier('mod') { + font-size: 3.5em; + } + } + } + } + } + + @include expect { + .something__child1 .something__subchild, + .something__child2 .something__subchild { + font-size: 3em; + } + + .something__child1 .something__subchild--mod, + .something__child2 .something__subchild--mod { + font-size: 3.5em; + } + + .something__child1, + .something__child2 { + font-size: 3em; + } + + .something__child1--mod, + .something__child2--mod { + font-size: 3.5em; + } + } + } + + @include assert('in related elements, 2 elements, 1 modifier') { /// 14 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child1') { + @include iro-bem-next-element('child2', 'child3') { + @include iro-bem-multi('element:' 'subchild1' 'subchild2', 'modifier:' 'mod') { + font-size: 3em; + } + } + } + } + } + + @include expect { + .something__child1 + .something__child2 .something__subchild1, + .something__child1 + .something__child3 .something__subchild1, + .something__child1 + .something__child2 .something__subchild2, + .something__child1 + .something__child3 .something__subchild2 { + font-size: 3em; + } + + .something__child1 + .something__child2--mod, + .something__child1 + .something__child3--mod { + font-size: 3em; + } + } + } + + @include assert('in related elements, 1 element, 1 & selector') { /// 15 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child1') { + @include iro-bem-next-element('child2', 'child3') { + @include iro-bem-multi('element:' 'subchild', '&') { + font-size: 4em; + + @include iro-bem-modifier('mod') { + font-size: 4.5em; + } + } + } + } + } + } + + @include expect { + .something__child1 + .something__child2 .something__subchild, + .something__child1 + .something__child3 .something__subchild { + font-size: 4em; + } + + .something__child1 + .something__child2 .something__subchild--mod, + .something__child1 + .something__child3 .something__subchild--mod { + font-size: 4.5em; + } + + .something__child1 + .something__child2, + .something__child1 + .something__child3 { + font-size: 4em; + } + + .something__child1 + .something__child2--mod, + .something__child1 + .something__child3--mod { + font-size: 4.5em; + } + } + } + + @include assert('in element, 2 related elements, 1 modifier') { /// 16 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child1') { + @include iro-bem-multi('next-element:' 'child2' 'child3', 'modifier:' 'mod1') { + font-size: 3em; + + @include iro-bem-modifier('mod2') { + font-size: 3.5em; + } + } + } + } + } + + @include expect { + .something__child1 + .something__child2, + .something__child1 + .something__child3 { + font-size: 3em; + } + + .something__child1 + .something__child2--mod2, + .something__child1 + .something__child3--mod2 { + font-size: 3.5em; + } + + .something__child1--mod1 { + font-size: 3em; + } + + .something__child1--mod1.something__child1--mod2 { + font-size: 3.5em; + } + } + } + + @include assert('in element, 1 twin element, 1 modifier') { /// 17 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child') { + @include iro-bem-multi('next-twin-element', 'modifier:' 'mod1') { + font-size: 3em; + + @include iro-bem-modifier('mod2') { + font-size: 3.5em; + } + } + } + } + } + + @include expect { + .something__child + .something__child { + font-size: 3em; + } + + .something__child + .something__child--mod2 { + font-size: 3.5em; + } + + .something__child--mod1 { + font-size: 3em; + } + + .something__child--mod1.something__child--mod2 { + font-size: 3.5em; + } + } + } + + @include assert('in multiple elements, 1 twin element, 1 modifier') { /// 18 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child1', 'child2') { + @include iro-bem-multi('next-twin-element', 'modifier:' 'mod1') { + font-size: 3em; + + @include iro-bem-modifier('mod2') { + font-size: 3.5em; + } + } + } + } + } + + @include expect { + .something__child1 + .something__child1, + .something__child2 + .something__child2 { + font-size: 3em; + } + + .something__child1 + .something__child1--mod2, + .something__child2 + .something__child2--mod2 { + font-size: 3.5em; + } + + .something__child1--mod1, + .something__child2--mod1 { + font-size: 3em; + } + + .something__child1--mod1.something__child1--mod2, + .something__child2--mod1.something__child2--mod2 { + font-size: 3.5em; + } + } + } +} diff --git a/test/bem/_iro-bem-next-twin-element.scss b/test/bem/_iro-bem-next-twin-element.scss new file mode 100644 index 0000000..96fc3a9 --- /dev/null +++ b/test/bem/_iro-bem-next-twin-element.scss @@ -0,0 +1,153 @@ +// sass-lint:disable class-name-format force-element-nesting force-pseudo-nesting mixins-before-declarations + +// +// Included test cases: +// - /// 1 /// - single element +// - /// 2 /// - single element, manual selector in-between +// - /// 3 /// - single element, modifier in-between +// - /// 4 /// - multiple elements +// - /// 5 /// - multiple elements, manual selector in-between +// - /// 6 /// - multiple elements, modifier in-between +// + +@include it('iro-bem-next-twin-element') { + @include assert('single element') { /// 1 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child') { + @include iro-bem-next-twin-element { + font-size: 2em; + } + } + } + } + + @include expect { + .something__child + .something__child { + font-size: 2em; + } + } + } + + @include assert('single element, manual selector in-between') { /// 2 /// + @include output(false) { + @include iro-bem-block('something') { + @include iro-bem-element('child') { + &:hover { + @include iro-bem-next-twin-element { + font-size: 2em; + } + } + + .test & { + @include iro-bem-next-twin-element { + font-size: 2em; + } + } + } + } + } + + @include expect(false) { + .something__child:hover + .something__child { + font-size: 2em; + } + + .test .something__child + .something__child { + font-size: 2em; + } + } + } + + @include assert('single element, modifier in-between') { /// 3 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child') { + @include iro-bem-modifier('mod') { + @include iro-bem-next-twin-element { + font-size: 2.5em; + } + } + } + } + } + + @include expect { + .something__child--mod + .something__child { + font-size: 2.5em; + } + } + } + + @include assert('multiple elements') { /// 4 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child1', 'child2') { + @include iro-bem-next-twin-element { + font-size: 2em; + } + } + } + } + + @include expect { + .something__child1 + .something__child1, + .something__child2 + .something__child2 { + font-size: 2em; + } + } + } + + @include assert('multiple elements, manual selector in-between') { /// 5 /// + @include output(false) { + @include iro-bem-block('something') { + @include iro-bem-element('child1', 'child2') { + &:hover { + @include iro-bem-next-twin-element { + font-size: 2em; + } + } + + .test & { + @include iro-bem-next-twin-element { + font-size: 2em; + } + } + } + } + } + + @include expect(false) { + .something__child1:hover + .something__child1, + .something__child2:hover + .something__child2 { + font-size: 2em; + } + + .test .something__child1 + .something__child1, + .test .something__child2 + .something__child2 { + font-size: 2em; + } + } + } + + @include assert('multiple elements, modifier in-between') { /// 6 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child1', 'child2') { + @include iro-bem-modifier('mod') { + @include iro-bem-next-twin-element { + font-size: 2.5em; + } + } + } + } + } + + @include expect { + .something__child1--mod + .something__child1, + .something__child2--mod + .something__child2 { + font-size: 2.5em; + } + } + } +} diff --git a/test/bem/_iro-bem-related-element.scss b/test/bem/_iro-bem-related-element.scss new file mode 100644 index 0000000..b0c6b94 --- /dev/null +++ b/test/bem/_iro-bem-related-element.scss @@ -0,0 +1,459 @@ +// sass-lint:disable class-name-format force-element-nesting force-pseudo-nesting mixins-before-declarations + +// +// Included test cases: +// - /// 1 /// - single element, single related element +// - /// 2 /// - single element, single related element, manual selector in-between +// - /// 3 /// - single element, single related element, modifier in-between +// - /// 4 /// - single element, multiple related elements +// - /// 5 /// - single element, multiple related elements, manual selector in-between +// - /// 6 /// - single element, multiple related elements, modifier in-between +// - /// 7 /// - multiple elements, single related element +// - /// 8 /// - multiple elements, single related element, manual selector in-between +// - /// 9 /// - multiple elements, single related element, modifier in-between +// - /// 10 /// - multiple elements, multiple related elements +// - /// 11 /// - multiple elements, multiple related elements, manual selector in-between +// - /// 12 /// - multiple elements, multiple related elements, modifier in-between +// + +@include it('iro-bem-related-element') { + @include assert('single element, single related element') { /// 1 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child') { + @include iro-bem-related-element('+', 'subchild1') { + font-size: 2em; + } + + @include iro-bem-related-element('~', 'subchild2') { + font-size: 2em; + } + } + } + } + + @include expect { + .something__child + .something__subchild1 { + font-size: 2em; + } + + .something__child ~ .something__subchild2 { + font-size: 2em; + } + } + } + + @include assert('single element, single related element, manual selector in-between') { /// 2 /// + @include output(false) { + @include iro-bem-block('something') { + @include iro-bem-element('child') { + &:hover { + @include iro-bem-related-element('+', 'subchild1') { + font-size: 2em; + } + + @include iro-bem-related-element('~', 'subchild2') { + font-size: 2em; + } + } + + .test & { + @include iro-bem-related-element('+', 'subchild3') { + font-size: 2em; + } + + @include iro-bem-related-element('~', 'subchild4') { + font-size: 2em; + } + } + } + } + } + + @include expect(false) { + .something__child:hover + .something__subchild1 { + font-size: 2em; + } + + .something__child:hover ~ .something__subchild2 { + font-size: 2em; + } + + .test .something__child + .something__subchild3 { + font-size: 2em; + } + + .test .something__child ~ .something__subchild4 { + font-size: 2em; + } + } + } + + @include assert('single element, single related element, modifier in-between') { /// 3 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child') { + @include iro-bem-modifier('mod') { + @include iro-bem-related-element('+', 'subchild1') { + font-size: 2.5em; + } + + @include iro-bem-related-element('~', 'subchild2') { + font-size: 2.5em; + } + } + } + } + } + + @include expect { + .something__child--mod + .something__subchild1 { + font-size: 2.5em; + } + + .something__child--mod ~ .something__subchild2 { + font-size: 2.5em; + } + } + } + + @include assert('single element, multiple related elements') { /// 4 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child') { + @include iro-bem-related-element('+', 'subchild1', 'subchild2') { + font-size: 2.5em; + } + + @include iro-bem-related-element('~', 'subchild3', 'subchild4') { + font-size: 2.5em; + } + } + } + } + + @include expect { + .something__child + .something__subchild1, + .something__child + .something__subchild2 { + font-size: 2.5em; + } + + .something__child ~ .something__subchild3, + .something__child ~ .something__subchild4 { + font-size: 2.5em; + } + } + } + + @include assert('single element, multiple related elements, manual selector in-between') { /// 5 /// + @include output(false) { + @include iro-bem-block('something') { + @include iro-bem-element('child') { + &:hover { + @include iro-bem-related-element('+', 'subchild1', 'subchild2') { + font-size: 2.5em; + } + + @include iro-bem-related-element('~', 'subchild3', 'subchild4') { + font-size: 2.5em; + } + } + + .test & { + @include iro-bem-related-element('+', 'subchild5', 'subchild6') { + font-size: 2.5em; + } + + @include iro-bem-related-element('~', 'subchild7', 'subchild8') { + font-size: 2.5em; + } + } + } + } + } + + @include expect(false) { + .something__child:hover + .something__subchild1, + .something__child:hover + .something__subchild2 { + font-size: 2.5em; + } + + .something__child:hover ~ .something__subchild3, + .something__child:hover ~ .something__subchild4 { + font-size: 2.5em; + } + + .test .something__child + .something__subchild5, + .test .something__child + .something__subchild6 { + font-size: 2.5em; + } + + .test .something__child ~ .something__subchild7, + .test .something__child ~ .something__subchild8 { + font-size: 2.5em; + } + } + } + + @include assert('single element, multiple related elements, modifier in-between') { /// 6 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child') { + @include iro-bem-modifier('mod') { + @include iro-bem-related-element('+', 'subchild1', 'subchild2') { + font-size: 2.5em; + } + + @include iro-bem-related-element('~', 'subchild3', 'subchild4') { + font-size: 2.5em; + } + } + } + } + } + + @include expect { + .something__child--mod + .something__subchild1, + .something__child--mod + .something__subchild2 { + font-size: 2.5em; + } + + .something__child--mod ~ .something__subchild3, + .something__child--mod ~ .something__subchild4 { + font-size: 2.5em; + } + } + } + + @include assert('multiple elements, single related element') { /// 7 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child1', 'child2') { + @include iro-bem-related-element('+', 'subchild1') { + font-size: 2em; + } + + @include iro-bem-related-element('~', 'subchild2') { + font-size: 2em; + } + } + } + } + + @include expect { + .something__child1 + .something__subchild1, + .something__child2 + .something__subchild1 { + font-size: 2em; + } + + .something__child1 ~ .something__subchild2, + .something__child2 ~ .something__subchild2 { + font-size: 2em; + } + } + } + + @include assert('multiple elements, single related element, manual selector in-between') { /// 8 /// + @include output(false) { + @include iro-bem-block('something') { + @include iro-bem-element('child1', 'child2') { + &:hover { + @include iro-bem-related-element('+', 'subchild1') { + font-size: 2em; + } + + @include iro-bem-related-element('~', 'subchild2') { + font-size: 2em; + } + } + + .test & { + @include iro-bem-related-element('+', 'subchild3') { + font-size: 2em; + } + + @include iro-bem-related-element('~', 'subchild4') { + font-size: 2em; + } + } + } + } + } + + @include expect(false) { + .something__child1:hover + .something__subchild1, + .something__child2:hover + .something__subchild1 { + font-size: 2em; + } + + .something__child1:hover ~ .something__subchild2, + .something__child2:hover ~ .something__subchild2 { + font-size: 2em; + } + + .test .something__child1 + .something__subchild3, + .test .something__child2 + .something__subchild3 { + font-size: 2em; + } + + .test .something__child1 ~ .something__subchild4, + .test .something__child2 ~ .something__subchild4 { + font-size: 2em; + } + } + } + + @include assert('multiple elements, single related element, modifier in-between') { /// 9 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child1', 'child2') { + @include iro-bem-modifier('mod') { + @include iro-bem-related-element('+', 'subchild1') { + font-size: 2.5em; + } + + @include iro-bem-related-element('~', 'subchild2') { + font-size: 2.5em; + } + } + } + } + } + + @include expect { + .something__child1--mod + .something__subchild1, + .something__child2--mod + .something__subchild1 { + font-size: 2.5em; + } + + .something__child1--mod ~ .something__subchild2, + .something__child2--mod ~ .something__subchild2 { + font-size: 2.5em; + } + } + } + + @include assert('multiple elements, multiple related elements') { /// 10 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child1', 'child2') { + @include iro-bem-related-element('+', 'subchild1', 'subchild2') { + font-size: 2em; + } + + @include iro-bem-related-element('~', 'subchild3', 'subchild4') { + font-size: 2em; + } + } + } + } + + @include expect { + .something__child1 + .something__subchild1, + .something__child2 + .something__subchild1, + .something__child1 + .something__subchild2, + .something__child2 + .something__subchild2 { + font-size: 2em; + } + + .something__child1 ~ .something__subchild3, + .something__child2 ~ .something__subchild3, + .something__child1 ~ .something__subchild4, + .something__child2 ~ .something__subchild4 { + font-size: 2em; + } + } + } + + @include assert('multiple elements, multiple related elements, manual selector in-between') { /// 11 /// + @include output(false) { + @include iro-bem-block('something') { + @include iro-bem-element('child1', 'child2') { + &:hover { + @include iro-bem-related-element('+', 'subchild1', 'subchild2') { + font-size: 2em; + } + + @include iro-bem-related-element('~', 'subchild3', 'subchild4') { + font-size: 2em; + } + } + + .test & { + @include iro-bem-related-element('+', 'subchild5', 'subchild6') { + font-size: 2em; + } + + @include iro-bem-related-element('~', 'subchild7', 'subchild8') { + font-size: 2em; + } + } + } + } + } + + @include expect(false) { + .something__child1:hover + .something__subchild1, + .something__child2:hover + .something__subchild1, + .something__child1:hover + .something__subchild2, + .something__child2:hover + .something__subchild2 { + font-size: 2em; + } + + .something__child1:hover ~ .something__subchild3, + .something__child2:hover ~ .something__subchild3, + .something__child1:hover ~ .something__subchild4, + .something__child2:hover ~ .something__subchild4 { + font-size: 2em; + } + + .test .something__child1 + .something__subchild5, + .test .something__child2 + .something__subchild5, + .test .something__child1 + .something__subchild6, + .test .something__child2 + .something__subchild6 { + font-size: 2em; + } + + .test .something__child1 ~ .something__subchild7, + .test .something__child2 ~ .something__subchild7, + .test .something__child1 ~ .something__subchild8, + .test .something__child2 ~ .something__subchild8 { + font-size: 2em; + } + } + } + + @include assert('multiple elements, multiple related elements, modifier in-between') { /// 12 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child1', 'child2') { + @include iro-bem-modifier('mod') { + @include iro-bem-related-element('+', 'subchild1', 'subchild2') { + font-size: 2em; + } + + @include iro-bem-related-element('~', 'subchild3', 'subchild4') { + font-size: 2em; + } + } + } + } + } + + @include expect { + .something__child1--mod + .something__subchild1, + .something__child2--mod + .something__subchild1, + .something__child1--mod + .something__subchild2, + .something__child2--mod + .something__subchild2 { + font-size: 2em; + } + + .something__child1--mod ~ .something__subchild3, + .something__child2--mod ~ .something__subchild3, + .something__child1--mod ~ .something__subchild4, + .something__child2--mod ~ .something__subchild4 { + font-size: 2em; + } + } + } +} diff --git a/test/bem/_iro-bem-state.scss b/test/bem/_iro-bem-state.scss new file mode 100644 index 0000000..57eb233 --- /dev/null +++ b/test/bem/_iro-bem-state.scss @@ -0,0 +1,177 @@ +// sass-lint:disable class-name-format force-element-nesting force-pseudo-nesting mixins-before-declarations + +// +// Included test cases: +// - /// 1 /// - single block, single state +// - /// 2 /// - single element, single state +// - /// 3 /// - single block, multiple states +// - /// 4 /// - single element, multiple states +// - /// 5 /// - multiple elements, single state +// - /// 6 /// - multiple elements, multiple states +// + +@include it('iro-bem-state') { + @include assert('single block, single state') { /// 1 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-is('active') { + font-size: 1.25em; + } + + @include iro-bem-has('state') { + font-size: 1.75em; + } + } + } + + @include expect { + .something.is-active { + font-size: 1.25em; + } + + .something.has-state { + font-size: 1.75em; + } + } + } + + @include assert('single element, single state') { /// 2 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child') { + @include iro-bem-is('active') { + font-size: 2.25em; + } + + @include iro-bem-has('state') { + font-size: 2.75em; + } + } + } + } + + @include expect { + .something__child.is-active { + font-size: 2.25em; + } + + .something__child.has-state { + font-size: 2.75em; + } + } + } + + @include assert('single block, multiple states') { /// 3 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-is('active', 'primary') { + font-size: 1.25em; + } + + @include iro-bem-has('state', 'indicator') { + font-size: 1.75em; + } + } + } + + @include expect { + .something.is-active, + .something.is-primary { + font-size: 1.25em; + } + + .something.has-state, + .something.has-indicator { + font-size: 1.75em; + } + } + } + + @include assert('single element, multiple states') { /// 4 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child') { + @include iro-bem-is('active', 'primary') { + font-size: 2.25em; + } + + @include iro-bem-has('state', 'indicator') { + font-size: 2.75em; + } + } + } + } + + @include expect { + .something__child.is-active, + .something__child.is-primary { + font-size: 2.25em; + } + + .something__child.has-state, + .something__child.has-indicator { + font-size: 2.75em; + } + } + } + + @include assert('multiple elements, single state') { /// 5 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child1', 'child2') { + @include iro-bem-is('active') { + font-size: 2.25em; + } + + @include iro-bem-has('state') { + font-size: 2.75em; + } + } + } + } + + @include expect { + .something__child1.is-active, + .something__child2.is-active { + font-size: 2.25em; + } + + .something__child1.has-state, + .something__child2.has-state { + font-size: 2.75em; + } + } + } + + @include assert('multiple elements, multiple states') { /// 6 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child1', 'child2') { + @include iro-bem-is('active', 'primary') { + font-size: 2.25em; + } + + @include iro-bem-has('state', 'indicator') { + font-size: 2.75em; + } + } + } + } + + @include expect { + .something__child1.is-active, + .something__child2.is-active, + .something__child1.is-primary, + .something__child2.is-primary { + font-size: 2.25em; + } + + .something__child1.has-state, + .something__child2.has-state, + .something__child1.has-indicator, + .something__child2.has-indicator { + font-size: 2.75em; + } + } + } +} diff --git a/test/bem/_iro-bem-suffix.scss b/test/bem/_iro-bem-suffix.scss new file mode 100644 index 0000000..c6ca787 --- /dev/null +++ b/test/bem/_iro-bem-suffix.scss @@ -0,0 +1,94 @@ +// sass-lint:disable class-name-format force-element-nesting force-pseudo-nesting mixins-before-declarations + +// +// Included test cases: +// - /// 1 /// - block suffix +// - /// 2 /// - element suffix +// - /// 3 /// - modifier suffix +// - /// 4 /// - multiple element suffix +// + +@include it('iro-bem-suffix') { + @include assert('block suffix') { /// 1 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-suffix('sm') { + font-size: 1.5em; + } + } + } + + @include expect { + .something\@sm { + font-size: 1.5em; + } + } + } + + @include assert('element suffix') { /// 2 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child') { + @include iro-bem-suffix('sm') { + font-size: 2.5em; + } + } + } + } + + @include expect { + .something__child\@sm { + font-size: 2.5em; + } + } + } + + @include assert('modifier suffix') { /// 3 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-modifier('mod1') { + @include iro-bem-suffix('sm') { + font-size: 1.75em; + } + } + + @include iro-bem-element('child') { + @include iro-bem-modifier('mod2') { + @include iro-bem-suffix('sm') { + font-size: 2.75em; + } + } + } + } + } + + @include expect { + .something--mod1\@sm { + font-size: 1.75em; + } + + .something__child--mod2\@sm { + font-size: 2.75em; + } + } + } + + @include assert('multiple element suffix') { /// 4 /// + @include output { + @include iro-bem-block('something') { + @include iro-bem-element('child1', 'child2') { + @include iro-bem-suffix('sm') { + font-size: 2.5em; + } + } + } + } + + @include expect { + .something__child1\@sm, + .something__child2\@sm { + font-size: 2.5em; + } + } + } +} diff --git a/test/test.js b/test/test.js new file mode 100644 index 0000000..94d16da --- /dev/null +++ b/test/test.js @@ -0,0 +1,4 @@ +const path = require("path"); +const sassTrue = require("sass-true"); + +sassTrue.runSass({ file: path.join(__dirname, "test.scss") }, { describe, it }); diff --git a/test/test.scss b/test/test.scss new file mode 100644 index 0000000..9e3cf6b --- /dev/null +++ b/test/test.scss @@ -0,0 +1,16 @@ +@import '../src/main'; + +@import 'true'; + +$iro-easing-gradient-steps: 4; + +@import 'functions'; +@import 'math'; +@import 'contexts'; +@import 'bem'; +@import 'responsive'; +@import 'harmony'; +@import 'gradients'; +@import 'props'; + +@include report; diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..e8623cd --- /dev/null +++ b/yarn.lock @@ -0,0 +1,3842 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@sindresorhus/is@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" + integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== + +"@szmarczak/http-timer@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" + integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== + dependencies: + defer-to-connect "^1.0.1" + +"@types/color-name@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" + integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== + +"@ungap/promise-all-settled@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" + integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== + +a-sync-waterfall@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz#75b6b6aa72598b497a125e7a2770f14f4c8a1fa7" + integrity sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA== + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + +acorn-jsx@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" + dependencies: + acorn "^3.0.4" + +acorn@^3.0.4: + version "3.3.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + +acorn@^5.2.1: + version "5.3.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.3.0.tgz#7446d39459c54fb49a80e6ee6478149b940ec822" + +ajv-keywords@^1.0.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" + +ajv@^4.7.0: + version "4.11.8" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" + dependencies: + co "^4.6.0" + json-stable-stringify "^1.0.1" + +ansi-align@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb" + integrity sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw== + dependencies: + string-width "^3.0.0" + +ansi-colors@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + +ansi-escapes@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-regex@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" + integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" + integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== + dependencies: + "@types/color-name" "^1.1.1" + color-convert "^2.0.1" + +ansi-styles@^4.2.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +anymatch@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" + integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +append-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/append-buffer/-/append-buffer-1.0.2.tgz#d8220cf466081525efea50614f3de6514dfa58f1" + integrity sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE= + dependencies: + buffer-equal "^1.0.0" + +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +argparse@^1.0.7: + version "1.0.9" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + +arrify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + +asap@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + +async-each@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + integrity sha1-GdOGodntxufByF04iu28xW0zYC0= + +atob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a" + +atob@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +babel-runtime@^6.22.0, babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +binary-extensions@^1.0.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" + +binary-extensions@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" + integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== + +boxen@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64" + integrity sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ== + dependencies: + ansi-align "^3.0.0" + camelcase "^5.3.1" + chalk "^3.0.0" + cli-boxes "^2.2.0" + string-width "^4.1.0" + term-size "^2.1.0" + type-fest "^0.8.1" + widest-line "^3.1.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.1, braces@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + +buffer-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-1.0.0.tgz#59616b498304d556abd466966b22eeda3eca5fbe" + integrity sha1-WWFrSYME1Var1GaWayLu2j7KX74= + +buffer-from@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.0.0.tgz#4cb8832d23612589b0406e9e2956c17f06fdf531" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +cacheable-request@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" + integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^3.0.0" + lowercase-keys "^2.0.0" + normalize-url "^4.1.0" + responselike "^1.0.2" + +call-bind@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.0.tgz#24127054bb3f9bdcb4b1fb82418186072f77b8ce" + integrity sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.0" + +caller-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + dependencies: + callsites "^0.2.0" + +callsites@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + +camel-case@3.0.x: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" + dependencies: + no-case "^2.2.0" + upper-case "^1.1.1" + +camelcase@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + +camelcase@^5.0.0, camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.0.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" + integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== + +cdocparser@^0.13.0: + version "0.13.0" + resolved "https://registry.yarnpkg.com/cdocparser/-/cdocparser-0.13.0.tgz#1ba98a1e1e1668e2bfb35d41761e9e4645d731ba" + dependencies: + escape-string-regexp "^1.0.2" + lodash.assign "^2.4.1" + strip-indent "^1.0.0" + +chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@^4.0.0, chalk@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" + integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chokidar@3.4.3, "chokidar@>=2.0.0 <4.0.0": + version "3.4.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.3.tgz#c1df38231448e45ca4ac588e6c79573ba6a57d5b" + integrity sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ== + dependencies: + anymatch "~3.1.1" + braces "~3.0.2" + glob-parent "~5.1.0" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.5.0" + optionalDependencies: + fsevents "~2.1.2" + +chokidar@^2.0.0: + version "2.1.6" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.6.tgz#b6cad653a929e244ce8a834244164d241fa954c5" + integrity sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.1" + braces "^2.3.2" + glob-parent "^3.1.0" + inherits "^2.0.3" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^3.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.2.1" + upath "^1.1.1" + optionalDependencies: + fsevents "^1.2.7" + +chokidar@^3.2.2: + version "3.3.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.1.tgz#c84e5b3d18d9a4d77558fef466b1bf16bbeb3450" + integrity sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg== + dependencies: + anymatch "~3.1.1" + braces "~3.0.2" + glob-parent "~5.1.0" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.3.0" + optionalDependencies: + fsevents "~2.1.2" + +chownr@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" + +chroma-js@^1.2.2: + version "1.3.6" + resolved "https://registry.yarnpkg.com/chroma-js/-/chroma-js-1.3.6.tgz#22dd7220ef6b55dcfcb8ef92982baaf55dced45d" + +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + +circular-json@^0.3.1: + version "0.3.3" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +clean-css@4.2.x: + version "4.2.1" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.1.tgz#2d411ef76b8569b6d0c84068dabe85b0aa5e5c17" + integrity sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g== + dependencies: + source-map "~0.6.0" + +cli-boxes@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.0.tgz#538ecae8f9c6ca508e3c3c95b453fe93cb4c168d" + integrity sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w== + +cli-cursor@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + dependencies: + restore-cursor "^1.0.1" + +cli-width@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" + +cliui@^3.0.3: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + +clone-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" + integrity sha1-4+JbIHrE5wGvch4staFnksrD3Fg= + +clone-response@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" + integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= + dependencies: + mimic-response "^1.0.0" + +clone-stats@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1" + +clone-stats@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680" + integrity sha1-s3gt/4u1R04Yuba/D9/ngvh3doA= + +clone@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" + +clone@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + +clone@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= + +cloneable-readable@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.1.3.tgz#120a00cb053bfb63a222e709f9683ea2e11d8cec" + integrity sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ== + dependencies: + inherits "^2.0.1" + process-nextick-args "^2.0.0" + readable-stream "^2.3.5" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0: + version "1.9.2" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.2.tgz#49881b8fba67df12a96bdf3f56c0aab9e7913147" + dependencies: + color-name "1.1.1" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +commander@2.17.x, commander@~2.17.1: + version "2.17.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" + integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== + +commander@^2.8.1: + version "2.12.2" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" + +component-emitter@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +concat-stream@^1.4.6: + version "1.6.0" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" + dependencies: + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +concat-stream@^1.4.7: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +concat-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-2.0.0.tgz#414cf5af790a48c60ab9be4527d56d5e41133cb1" + integrity sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.0.2" + typedarray "^0.0.6" + +configstore@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" + integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== + dependencies: + dot-prop "^5.2.0" + graceful-fs "^4.1.2" + make-dir "^3.0.0" + unique-string "^2.0.0" + write-file-atomic "^3.0.0" + xdg-basedir "^4.0.0" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +convert-source-map@^1.5.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== + dependencies: + safe-buffer "~5.1.1" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + +core-js@^2.4.0: + version "2.5.5" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.5.tgz#b14dde936c640c0579a6b50cabcc132dd6127e3b" + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +crypto-random-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" + integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== + +css@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/css/-/css-3.0.0.tgz#4447a4d58fdd03367c516ca9f64ae365cee4aa5d" + integrity sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ== + dependencies: + inherits "^2.0.4" + source-map "^0.6.1" + source-map-resolve "^0.6.0" + +d@1: + version "1.0.0" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" + dependencies: + es5-ext "^0.10.9" + +dargs@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/dargs/-/dargs-4.1.0.tgz#03a9dbb4b5c2f139bf14ae53f0b8a2a6a86f4e17" + dependencies: + number-is-nan "^1.0.0" + +debug@4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.2.0.tgz#7f150f93920e94c58f5574c2fd01a3110effe7f1" + integrity sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg== + dependencies: + ms "2.1.2" + +debug@^2.1.1, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + dependencies: + ms "2.0.0" + +debug@^3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +decamelize@^1.1.1, decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + +decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= + dependencies: + mimic-response "^1.0.0" + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + +defer-to-connect@^1.0.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" + integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== + +define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +del@^2.0.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + dependencies: + globby "^5.0.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + rimraf "^2.2.8" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + +diff@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +docopt@^0.6.1: + version "0.6.2" + resolved "https://registry.yarnpkg.com/docopt/-/docopt-0.6.2.tgz#b28e9e2220da5ec49f7ea5bb24a47787405eeb11" + +doctrine@^1.2.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + +dot-prop@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.2.0.tgz#c34ecc29556dc45f1f4c22697b6f4904e0cc4fcb" + integrity sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A== + dependencies: + is-obj "^2.0.0" + +duplexer2@^0.1.2: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" + dependencies: + readable-stream "^2.0.2" + +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + +duplexify@^3.6.0: + version "3.7.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" + integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +end-of-stream@^1.0.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== + dependencies: + once "^1.4.0" + +end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +ends-with@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/ends-with/-/ends-with-0.2.0.tgz#2f9da98d57a50cfda4571ce4339000500f4e6b8a" + +es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: + version "0.10.37" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.37.tgz#0ee741d148b80069ba27d020393756af257defc3" + dependencies: + es6-iterator "~2.0.1" + es6-symbol "~3.1.1" + +es6-denodeify@^0.1.0: + version "0.1.5" + resolved "https://registry.yarnpkg.com/es6-denodeify/-/es6-denodeify-0.1.5.tgz#31d4d5fe9c5503e125460439310e16a2a3f39c1f" + +es6-iterator@^2.0.1, es6-iterator@~2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-map@^0.1.3: + version "0.1.5" + resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" + dependencies: + d "1" + es5-ext "~0.10.14" + es6-iterator "~2.0.1" + es6-set "~0.1.5" + es6-symbol "~3.1.1" + event-emitter "~0.3.5" + +es6-promise@^3.0.2: + version "3.3.1" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613" + +es6-promise@^4.2.6: + version "4.2.6" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.6.tgz#b685edd8258886365ea62b57d30de28fadcd974f" + integrity sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q== + +es6-set@~0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" + dependencies: + d "1" + es5-ext "~0.10.14" + es6-iterator "~2.0.1" + es6-symbol "3.1.1" + event-emitter "~0.3.5" + +es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" + dependencies: + d "1" + es5-ext "~0.10.14" + +es6-weak-map@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" + dependencies: + d "1" + es5-ext "^0.10.14" + es6-iterator "^2.0.1" + es6-symbol "^3.1.1" + +escape-goat@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" + integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q== + +escape-string-regexp@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +escope@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" + dependencies: + es6-map "^0.1.3" + es6-weak-map "^2.0.1" + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint@^2.7.0: + version "2.13.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-2.13.1.tgz#e4cc8fa0f009fb829aaae23855a29360be1f6c11" + dependencies: + chalk "^1.1.3" + concat-stream "^1.4.6" + debug "^2.1.1" + doctrine "^1.2.2" + es6-map "^0.1.3" + escope "^3.6.0" + espree "^3.1.6" + estraverse "^4.2.0" + esutils "^2.0.2" + file-entry-cache "^1.1.1" + glob "^7.0.3" + globals "^9.2.0" + ignore "^3.1.2" + imurmurhash "^0.1.4" + inquirer "^0.12.0" + is-my-json-valid "^2.10.0" + is-resolvable "^1.0.0" + js-yaml "^3.5.1" + json-stable-stringify "^1.0.0" + levn "^0.3.0" + lodash "^4.0.0" + mkdirp "^0.5.0" + optionator "^0.8.1" + path-is-absolute "^1.0.0" + path-is-inside "^1.0.1" + pluralize "^1.2.1" + progress "^1.1.8" + require-uncached "^1.0.2" + shelljs "^0.6.0" + strip-json-comments "~1.0.1" + table "^3.7.8" + text-table "~0.2.0" + user-home "^2.0.0" + +espree@^3.1.6: + version "3.5.2" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.2.tgz#756ada8b979e9dcfcdb30aad8d1a9304a905e1ca" + dependencies: + acorn "^5.2.1" + acorn-jsx "^3.0.0" + +esprima@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" + +esrecurse@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163" + dependencies: + estraverse "^4.1.0" + object-assign "^4.0.1" + +estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + +event-emitter@~0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + dependencies: + d "1" + es5-ext "~0.10.14" + +exit-hook@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" + +extend@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +fast-levenshtein@~2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + +figures@^1.3.5: + version "1.7.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + dependencies: + escape-string-regexp "^1.0.5" + object-assign "^4.1.0" + +file-entry-cache@^1.1.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-1.3.1.tgz#44c61ea607ae4be9c1402f41f44270cbfe334ff8" + dependencies: + flat-cache "^1.2.1" + object-assign "^4.0.1" + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-index@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/find-index/-/find-index-0.1.1.tgz#675d358b2ca3892d795a1ab47232f8b6e2e0dde4" + +find-up@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +flat-cache@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" + dependencies: + circular-json "^0.3.1" + del "^2.0.2" + graceful-fs "^4.1.2" + write "^0.2.1" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +flush-write-stream@^1.0.2: + version "1.1.1" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" + integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== + dependencies: + inherits "^2.0.3" + readable-stream "^2.3.6" + +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + dependencies: + map-cache "^0.2.2" + +front-matter@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/front-matter/-/front-matter-2.1.2.tgz#f75983b9f2f413be658c93dfd7bd8ce4078f5cdb" + dependencies: + js-yaml "^3.4.6" + +fs-extra@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-2.1.2.tgz#046c70163cef9aad46b0e4a7fa467fb22d71de35" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + +fs-extra@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-3.0.1.tgz#3794f378c58b342ea7dbbb23095109c4b3b62291" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^3.0.0" + universalify "^0.1.0" + +fs-minipass@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" + dependencies: + minipass "^2.2.1" + +fs-mkdirp-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz#0b7815fc3201c6a69e14db98ce098c16935259eb" + integrity sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes= + dependencies: + graceful-fs "^4.1.11" + through2 "^2.0.3" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.7.tgz#4851b664a3783e52003b3c66eb0eee1074933aa4" + integrity sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw== + dependencies: + nan "^2.9.2" + node-pre-gyp "^0.10.0" + +fsevents@~2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.2.tgz#4c0a1fb34bc68e543b4b82a9ec392bfbda840805" + integrity sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +generate-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" + +generate-object-property@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + dependencies: + is-property "^1.0.0" + +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.0.1.tgz#94a9768fcbdd0595a1c9273aacf4c89d075631be" + integrity sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + +get-stdin@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + +get-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-stream@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9" + integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw== + dependencies: + pump "^3.0.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob-parent@~5.1.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" + integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== + dependencies: + is-glob "^4.0.1" + +glob-stream@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-6.1.0.tgz#7045c99413b3eb94888d83ab46d0b404cc7bdde4" + integrity sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ= + dependencies: + extend "^3.0.0" + glob "^7.1.1" + glob-parent "^3.1.0" + is-negated-glob "^1.0.0" + ordered-read-streams "^1.0.0" + pumpify "^1.3.5" + readable-stream "^2.1.5" + remove-trailing-separator "^1.0.1" + to-absolute-glob "^2.0.0" + unique-stream "^2.0.2" + +glob2base@0.0.12: + version "0.0.12" + resolved "https://registry.yarnpkg.com/glob2base/-/glob2base-0.0.12.tgz#9d419b3e28f12e83a362164a277055922c9c0d56" + dependencies: + find-index "^0.1.1" + +glob@7.1.6, glob@^7.1.1, glob@^7.1.3, glob@^7.1.6: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@~7.1.1: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-dirs@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.0.1.tgz#acdf3bb6685bcd55cb35e8a052266569e9469201" + integrity sha512-5HqUqdhkEovj2Of/ms3IeS/EekcO54ytHRLV4PEY2rhRwrHXLQjeVEES0Lhka0xwNDtGYn58wyC4s5+MHsOO6A== + dependencies: + ini "^1.3.5" + +globals@^9.2.0: + version "9.18.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" + +globby@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + dependencies: + array-union "^1.0.1" + arrify "^1.0.0" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +globule@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.1.tgz#5dffb1b191f22d20797a9369b49eab4e9839696d" + dependencies: + glob "~7.1.1" + lodash "~4.17.10" + minimatch "~3.0.2" + +gonzales-pe-sl@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/gonzales-pe-sl/-/gonzales-pe-sl-4.2.3.tgz#6a868bc380645f141feeb042c6f97fcc71b59fe6" + dependencies: + minimist "1.1.x" + +got@^9.6.0: + version "9.6.0" + resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" + integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== + dependencies: + "@sindresorhus/is" "^0.14.0" + "@szmarczak/http-timer" "^1.1.2" + cacheable-request "^6.0.0" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^4.1.0" + lowercase-keys "^1.0.1" + mimic-response "^1.0.1" + p-cancelable "^1.0.0" + to-readable-stream "^1.0.0" + url-parse-lax "^3.0.0" + +graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +growl@1.10.5: + version "1.10.5" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" + integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has-yarn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" + integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +he@1.2.0, he@1.2.x: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +html-minifier@^3.5.21: + version "3.5.21" + resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.21.tgz#d0040e054730e354db008463593194015212d20c" + integrity sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA== + dependencies: + camel-case "3.0.x" + clean-css "4.2.x" + commander "2.17.x" + he "1.2.x" + param-case "2.1.x" + relateurl "0.2.x" + uglify-js "3.4.x" + +http-cache-semantics@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" + integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== + +iconv-lite@^0.4.4: + version "0.4.23" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ignore-by-default@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" + +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + dependencies: + minimatch "^3.0.4" + +ignore@^3.1.2: + version "3.3.7" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021" + +import-lazy@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + +inherits@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ini@^1.3.5, ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + +inquirer@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" + dependencies: + ansi-escapes "^1.1.0" + ansi-regex "^2.0.0" + chalk "^1.0.0" + cli-cursor "^1.0.1" + cli-width "^2.0.0" + figures "^1.3.5" + lodash "^4.3.0" + readline2 "^1.0.1" + run-async "^0.1.0" + rx-lite "^3.1.2" + string-width "^1.0.1" + strip-ansi "^3.0.0" + through "^2.3.6" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + +is-absolute@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-1.0.0.tgz#395e1ae84b11f26ad1795e73c17378e48a301576" + integrity sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA== + dependencies: + is-relative "^1.0.0" + is-windows "^1.0.1" + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + dependencies: + kind-of "^6.0.0" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + +is-ci@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== + dependencies: + ci-info "^2.0.0" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + dependencies: + kind-of "^6.0.0" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" + dependencies: + is-extglob "^2.1.1" + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + +is-installed-globally@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141" + integrity sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g== + dependencies: + global-dirs "^2.0.1" + is-path-inside "^3.0.1" + +is-my-json-valid@^2.10.0: + version "2.17.1" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.17.1.tgz#3da98914a70a22f0a8563ef1511a246c6fc55471" + dependencies: + generate-function "^2.0.0" + generate-object-property "^1.1.0" + jsonpointer "^4.0.0" + xtend "^4.0.0" + +is-negated-glob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-negated-glob/-/is-negated-glob-1.0.0.tgz#6910bca5da8c95e784b5751b976cf5a10fee36d2" + integrity sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI= + +is-npm@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d" + integrity sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig== + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + dependencies: + kind-of "^3.0.2" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + +is-path-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + +is-path-in-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" + dependencies: + is-path-inside "^1.0.0" + +is-path-inside@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" + dependencies: + path-is-inside "^1.0.1" + +is-path-inside@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.2.tgz#f5220fc82a3e233757291dddc9c5877f2a1f3017" + integrity sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg== + +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + dependencies: + isobject "^3.0.1" + +is-property@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + +is-relative@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d" + integrity sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA== + dependencies: + is-unc-path "^1.0.0" + +is-resolvable@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.1.tgz#acca1cd36dbe44b974b924321555a70ba03b1cf4" + +is-typedarray@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +is-unc-path@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-1.0.0.tgz#d731e8898ed090a12c352ad2eaed5095ad322c9d" + integrity sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ== + dependencies: + unc-path-regex "^0.1.2" + +is-utf8@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + +is-valid-glob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-1.0.0.tgz#29bf3eff701be2d4d315dbacc39bc39fe8f601aa" + integrity sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao= + +is-windows@^1.0.1, is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + +is-yarn-global@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" + integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + +js-yaml@3.14.0, js-yaml@^3.14.0: + version "3.14.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" + integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^3.4.6, js-yaml@^3.5.1, js-yaml@^3.5.4: + version "3.10.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +json-buffer@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= + +json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + dependencies: + jsonify "~0.0.0" + +jsonfile@^2.1.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonfile@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + +jsonpointer@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" + +keyv@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" + integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== + dependencies: + json-buffer "3.0.0" + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + +known-css-properties@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.3.0.tgz#a3d135bbfc60ee8c6eacf2f7e7e6f2d4755e49a4" + +latest-version@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" + integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA== + dependencies: + package-json "^6.3.0" + +lazystream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4" + dependencies: + readable-stream "^2.0.5" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + dependencies: + invert-kv "^1.0.0" + +lead@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lead/-/lead-1.0.0.tgz#6f14f99a37be3a9dd784f5495690e5903466ee42" + integrity sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI= + dependencies: + flush-write-stream "^1.0.2" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash._basebind@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash._basebind/-/lodash._basebind-2.4.1.tgz#e940b9ebdd27c327e0a8dab1b55916c5341e9575" + dependencies: + lodash._basecreate "~2.4.1" + lodash._setbinddata "~2.4.1" + lodash._slice "~2.4.1" + lodash.isobject "~2.4.1" + +lodash._basecreate@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash._basecreate/-/lodash._basecreate-2.4.1.tgz#f8e6f5b578a9e34e541179b56b8eeebf4a287e08" + dependencies: + lodash._isnative "~2.4.1" + lodash.isobject "~2.4.1" + lodash.noop "~2.4.1" + +lodash._basecreatecallback@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash._basecreatecallback/-/lodash._basecreatecallback-2.4.1.tgz#7d0b267649cb29e7a139d0103b7c11fae84e4851" + dependencies: + lodash._setbinddata "~2.4.1" + lodash.bind "~2.4.1" + lodash.identity "~2.4.1" + lodash.support "~2.4.1" + +lodash._basecreatewrapper@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash._basecreatewrapper/-/lodash._basecreatewrapper-2.4.1.tgz#4d31f2e7de7e134fbf2803762b8150b32519666f" + dependencies: + lodash._basecreate "~2.4.1" + lodash._setbinddata "~2.4.1" + lodash._slice "~2.4.1" + lodash.isobject "~2.4.1" + +lodash._createwrapper@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash._createwrapper/-/lodash._createwrapper-2.4.1.tgz#51d6957973da4ed556e37290d8c1a18c53de1607" + dependencies: + lodash._basebind "~2.4.1" + lodash._basecreatewrapper "~2.4.1" + lodash._slice "~2.4.1" + lodash.isfunction "~2.4.1" + +lodash._isnative@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash._isnative/-/lodash._isnative-2.4.1.tgz#3ea6404b784a7be836c7b57580e1cdf79b14832c" + +lodash._objecttypes@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash._objecttypes/-/lodash._objecttypes-2.4.1.tgz#7c0b7f69d98a1f76529f890b0cdb1b4dfec11c11" + +lodash._setbinddata@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash._setbinddata/-/lodash._setbinddata-2.4.1.tgz#f7c200cd1b92ef236b399eecf73c648d17aa94d2" + dependencies: + lodash._isnative "~2.4.1" + lodash.noop "~2.4.1" + +lodash._shimkeys@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash._shimkeys/-/lodash._shimkeys-2.4.1.tgz#6e9cc9666ff081f0b5a6c978b83e242e6949d203" + dependencies: + lodash._objecttypes "~2.4.1" + +lodash._slice@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash._slice/-/lodash._slice-2.4.1.tgz#745cf41a53597b18f688898544405efa2b06d90f" + +lodash.assign@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-2.4.1.tgz#84c39596dd71181a97b0652913a7c9675e49b1aa" + dependencies: + lodash._basecreatecallback "~2.4.1" + lodash._objecttypes "~2.4.1" + lodash.keys "~2.4.1" + +lodash.bind@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-2.4.1.tgz#5d19fa005c8c4d236faf4742c7b7a1fcabe29267" + dependencies: + lodash._createwrapper "~2.4.1" + lodash._slice "~2.4.1" + +lodash.capitalize@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz#f826c9b4e2a8511d84e3aca29db05e1a4f3b72a9" + +lodash.difference@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c" + +lodash.identity@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash.identity/-/lodash.identity-2.4.1.tgz#6694cffa65fef931f7c31ce86c74597cf560f4f1" + +lodash.isfunction@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-2.4.1.tgz#2cfd575c73e498ab57e319b77fa02adef13a94d1" + +lodash.isobject@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-2.4.1.tgz#5a2e47fe69953f1ee631a7eba1fe64d2d06558f5" + dependencies: + lodash._objecttypes "~2.4.1" + +lodash.kebabcase@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36" + +lodash.keys@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-2.4.1.tgz#48dea46df8ff7632b10d706b8acb26591e2b3727" + dependencies: + lodash._isnative "~2.4.1" + lodash._shimkeys "~2.4.1" + lodash.isobject "~2.4.1" + +lodash.noop@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash.noop/-/lodash.noop-2.4.1.tgz#4fb54f816652e5ae10e8f72f717a388c7326538a" + +lodash.support@~2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/lodash.support/-/lodash.support-2.4.1.tgz#320e0b67031673c28d7a2bb5d9e0331a45240515" + dependencies: + lodash._isnative "~2.4.1" + +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + +lodash@^4.0.0, lodash@~4.17.10: + version "4.17.10" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" + +lodash@^4.17.19: + version "4.17.20" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" + integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== + +lodash@^4.3.0: + version "4.17.4" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" + +log-symbols@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.0.0.tgz#69b3cc46d20f448eccdb75ea1fa733d9e821c920" + integrity sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA== + dependencies: + chalk "^4.0.0" + +lower-case@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" + +lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + +lowercase-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" + integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== + +make-dir@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.0.2.tgz#04a1acbf22221e1d6ef43559f43e05a90dbb4392" + integrity sha512-rYKABKutXa6vXTXhoV18cBE7PaewPXHe/Bdq4v+ZLMhxbWApkFFplT0LcbMW+6BbjnQXzZ/sAvSE/JdguApG5w== + dependencies: + semver "^6.0.0" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + dependencies: + object-visit "^1.0.0" + +marked@^0.6.2: + version "0.6.3" + resolved "https://registry.yarnpkg.com/marked/-/marked-0.6.3.tgz#79babad78af638ba4d522a9e715cdfdd2429e946" + integrity sha512-Fqa7eq+UaxfMriqzYLayfqAE40WN03jf+zHjT18/uXNuzjq3TY0XTbrAoPeqSJrAmPz11VuUA+kBPYOhHt9oOQ== + +memoize-decorator@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/memoize-decorator/-/memoize-decorator-1.0.2.tgz#605a41715c4171db192a90098b00ab8d6e1102f5" + +merge@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" + +micromatch@^3.1.10, micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +mimic-response@^1.0.0, mimic-response@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + +min-indent@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== + +minimatch@3.0.4, minimatch@^3.0.4, minimatch@~3.0.2: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@1.1.x: + version "1.1.3" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.1.3.tgz#3bedfd91a92d39016fcfaa1c681e8faa1a1efda8" + +minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +minipass@^2.2.1, minipass@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.3.tgz#a7dcc8b7b833f5d368759cce544dccb55f50f233" + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" + dependencies: + minipass "^2.2.1" + +mixin-deep@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp@^0.5.0, mkdirp@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +mocha@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-8.2.0.tgz#f8aa79110b4b5a6580c65d4dd8083c425282624e" + integrity sha512-lEWEMq2LMfNJMKeuEwb5UELi+OgFDollXaytR5ggQcHpzG3NP/R7rvixAvF+9/lLsTWhWG+4yD2M70GsM06nxw== + dependencies: + "@ungap/promise-all-settled" "1.1.2" + ansi-colors "4.1.1" + browser-stdout "1.3.1" + chokidar "3.4.3" + debug "4.2.0" + diff "4.0.2" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.1.6" + growl "1.10.5" + he "1.2.0" + js-yaml "3.14.0" + log-symbols "4.0.0" + minimatch "3.0.4" + ms "2.1.2" + nanoid "3.1.12" + serialize-javascript "5.0.1" + strip-json-comments "3.1.1" + supports-color "7.2.0" + which "2.0.2" + wide-align "1.1.3" + workerpool "6.0.2" + yargs "13.3.2" + yargs-parser "13.1.2" + yargs-unparser "2.0.0" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +multipipe@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-1.0.2.tgz#cc13efd833c9cda99f224f868461b8e1a3fd939d" + integrity sha1-zBPv2DPJzamfIk+GhGG44aP9k50= + dependencies: + duplexer2 "^0.1.2" + object-assign "^4.1.0" + +mute-stream@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" + +nan@^2.9.2: + version "2.10.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" + +nanoid@3.1.12: + version "3.1.12" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.12.tgz#6f7736c62e8d39421601e4a0c77623a97ea69654" + integrity sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +needle@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d" + dependencies: + debug "^2.1.2" + iconv-lite "^0.4.4" + sax "^1.2.4" + +no-case@^2.2.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac" + dependencies: + lower-case "^1.1.1" + +node-pre-gyp@^0.10.0: + version "0.10.3" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + +nodemon@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.6.tgz#1abe1937b463aaf62f0d52e2b7eaadf28cc2240d" + integrity sha512-4I3YDSKXg6ltYpcnZeHompqac4E6JeAMpGm8tJnB9Y3T0ehasLa4139dJOcCrB93HHrUMsCrKtoAlXTqT5n4AQ== + dependencies: + chokidar "^3.2.2" + debug "^3.2.6" + ignore-by-default "^1.0.1" + minimatch "^3.0.4" + pstree.remy "^1.1.7" + semver "^5.7.1" + supports-color "^5.5.0" + touch "^3.1.0" + undefsafe "^2.0.3" + update-notifier "^4.1.0" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + dependencies: + abbrev "1" + osenv "^0.1.4" + +nopt@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" + dependencies: + abbrev "1" + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-url@^4.1.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129" + integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ== + +now-and-later@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/now-and-later/-/now-and-later-2.0.1.tgz#8e579c8685764a7cc02cb680380e94f43ccb1f7c" + integrity sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ== + dependencies: + once "^1.3.2" + +npm-bundled@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308" + +npm-packlist@^1.1.6: + version "1.1.10" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.10.tgz#1039db9e985727e464df066f4cf0ab6ef85c398a" + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + +npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +nunjucks@^3.1.7: + version "3.2.0" + resolved "https://registry.yarnpkg.com/nunjucks/-/nunjucks-3.2.0.tgz#53e95f43c9555e822e8950008a201b1002d49933" + integrity sha512-YS/qEQ6N7qCnUdm6EoYRBfJUdWNT0PpKbbRnogV2XyXbBm2STIP1O6yrdZHgwMVK7fIYUx7i8+yatEixnXSB1w== + dependencies: + a-sync-waterfall "^1.0.0" + asap "^2.0.3" + yargs "^3.32.0" + optionalDependencies: + chokidar "^2.0.0" + +object-assign@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" + +object-assign@^4.0.1, object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + dependencies: + isobject "^3.0.0" + +object.assign@^4.0.4: + version "4.1.2" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + has-symbols "^1.0.1" + object-keys "^1.1.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + dependencies: + isobject "^3.0.1" + +once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +onetime@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + +optionator@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + +ordered-read-streams@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz#77c0cb37c41525d64166d990ffad7ec6a0e1363e" + integrity sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4= + dependencies: + readable-stream "^2.0.1" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + dependencies: + lcid "^1.0.0" + +os-tmpdir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +p-cancelable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" + integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== + +p-limit@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.0.2.tgz#1664e010af3cadc681baafd3e2a437be7b0fb5fe" + integrity sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg== + dependencies: + p-try "^2.0.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +package-json@^6.3.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" + integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ== + dependencies: + got "^9.6.0" + registry-auth-token "^4.0.0" + registry-url "^5.0.0" + semver "^6.2.0" + +param-case@2.1.x: + version "2.1.1" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247" + dependencies: + no-case "^2.2.0" + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-is-inside@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + +picomatch@^2.0.4, picomatch@^2.0.7, picomatch@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" + integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +pluralize@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + +prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= + +process-nextick-args@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + +process-nextick-args@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + +progress@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" + +pstree.remy@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.7.tgz#c76963a28047ed61542dc361aa26ee55a7fa15f3" + integrity sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A== + +pump@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.5: + version "1.5.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== + dependencies: + duplexify "^3.6.0" + inherits "^2.0.3" + pump "^2.0.0" + +pupa@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.0.1.tgz#dbdc9ff48ffbea4a26a069b6f9f7abb051008726" + integrity sha512-hEJH0s8PXLY/cdXh66tNEQGndDrIKNqNC5xmrysZy3i5C3oEoLna7YAOad+7u125+zH1HNXUmGEkrhb3c2VriA== + dependencies: + escape-goat "^2.0.0" + +q@1.*: + version "1.5.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +rc@^1.2.7, rc@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +"readable-stream@>=1.1.13-1 <1.2.0-0": + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^2.2.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + safe-buffer "~5.1.1" + string_decoder "~1.0.3" + util-deprecate "~1.0.1" + +readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.0.2: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +readdirp@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.3.0.tgz#984458d13a1e42e2e9f5841b129e162f369aff17" + integrity sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ== + dependencies: + picomatch "^2.0.7" + +readdirp@~3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" + integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ== + dependencies: + picomatch "^2.2.1" + +readline2@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + mute-stream "0.0.5" + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +registry-auth-token@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.1.1.tgz#40a33be1e82539460f94328b0f7f0f84c16d9479" + integrity sha512-9bKS7nTl9+/A1s7tnPeGrUpRcVY+LUh7bfFgzpndALdPfXQBfQV77rQVtqgUV3ti4vc/Ik81Ex8UJDWDQ12zQA== + dependencies: + rc "^1.2.8" + +registry-url@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009" + integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw== + dependencies: + rc "^1.2.8" + +relateurl@0.2.x: + version "0.2.7" + resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" + +remove-bom-buffer@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz#c2bf1e377520d324f623892e33c10cac2c252b53" + integrity sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ== + dependencies: + is-buffer "^1.1.5" + is-utf8 "^0.2.1" + +remove-bom-stream@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz#05f1a593f16e42e1fb90ebf59de8e569525f9523" + integrity sha1-BfGlk/FuQuH7kOv1nejlaVJflSM= + dependencies: + remove-bom-buffer "^3.0.0" + safe-buffer "^5.1.0" + through2 "^2.0.3" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +replace-ext@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924" + +replace-ext@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.1.tgz#2d6d996d04a15855d967443631dd5f77825b016a" + integrity sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw== + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +require-uncached@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + dependencies: + caller-path "^0.1.0" + resolve-from "^1.0.0" + +resolve-from@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + +resolve-options@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/resolve-options/-/resolve-options-1.1.0.tgz#32bb9e39c06d67338dc9378c0d6d6074566ad131" + integrity sha1-MrueOcBtZzONyTeMDW1gdFZq0TE= + dependencies: + value-or-function "^3.0.0" + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + +responselike@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= + dependencies: + lowercase-keys "^1.0.0" + +restore-cursor@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + dependencies: + exit-hook "^1.0.0" + onetime "^1.0.0" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + +rimraf@2.*, rimraf@^2.2.8, rimraf@^2.6.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + dependencies: + glob "^7.0.5" + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +run-async@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" + dependencies: + once "^1.3.0" + +rx-lite@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" + +safe-buffer@^5.1.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + dependencies: + ret "~0.1.10" + +safe-wipe@0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/safe-wipe/-/safe-wipe-0.2.5.tgz#dbb331be98d32fee660372999ee5d1ae89ab2fdd" + integrity sha512-MwTNf4YrRqCHsB5jUzOVdXoRbW4jkhgTvhlyfiaxox8EP7cOCiD4ydMOQCxDPR9KpvwdBSM2dQHScV1m85k8wQ== + dependencies: + extend "^3.0.2" + q "1.*" + rimraf "2.*" + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + +sass-convert@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/sass-convert/-/sass-convert-0.5.2.tgz#b1ed42b0e8d6fe98ec7ed6e78a38e26564860f06" + dependencies: + concat-stream "^1.4.7" + dargs "^4.0.0" + ends-with "^0.2.0" + es6-denodeify "^0.1.0" + es6-promise "^3.0.2" + memoize-decorator "^1.0.2" + object-assign "^3.0.0" + semver "^5.0.1" + semver-regex "^1.0.0" + through2 "^2.0.0" + which "^1.0.5" + +sass-lint@^1.12.1: + version "1.13.1" + resolved "https://registry.yarnpkg.com/sass-lint/-/sass-lint-1.13.1.tgz#5fd2b2792e9215272335eb0f0dc607f61e8acc8f" + integrity sha512-DSyah8/MyjzW2BWYmQWekYEKir44BpLqrCFsgs9iaWiVTcwZfwXHF586hh3D1n+/9ihUNMfd8iHAyb9KkGgs7Q== + dependencies: + commander "^2.8.1" + eslint "^2.7.0" + front-matter "2.1.2" + fs-extra "^3.0.1" + glob "^7.0.0" + globule "^1.0.0" + gonzales-pe-sl "^4.2.3" + js-yaml "^3.5.4" + known-css-properties "^0.3.0" + lodash.capitalize "^4.1.0" + lodash.kebabcase "^4.0.0" + merge "^1.2.0" + path-is-absolute "^1.0.0" + util "^0.10.3" + +sass-true@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/sass-true/-/sass-true-6.0.1.tgz#c159fa27df2f9ee22bb624a851144a8af7dc8a32" + integrity sha512-Ow72fStIgw+qRRUc0r77emeWry06a3e1hXtadPEzDL/GFiEjtQKZel5fr+gu85zC8JYmLkZofMn6x9b/sq+wfg== + dependencies: + chalk "^4.1.0" + css "^3.0.0" + lodash "^4.17.19" + +sass@^1.28.0: + version "1.28.0" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.28.0.tgz#546f1308ff74cc4ec2ad735fd35dc18bc3f51f72" + integrity sha512-9FWX/0wuE1KxwfiP02chZhHaPzu6adpx9+wGch7WMOuHy5npOo0UapRI3FNSHva2CczaYJu2yNUBN8cCSqHz/A== + dependencies: + chokidar ">=2.0.0 <4.0.0" + +sassdoc-extras@^2.5.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/sassdoc-extras/-/sassdoc-extras-2.5.1.tgz#4365a0463c9a085d588c213a06c82beb85966400" + integrity sha512-/+ilEnk1H1hG9nympL1GIFWhAczzoclyDzgzfphIg46nsT/dWJuzWYHyzIpduc/nTVwKeQfmTz0ZVvy12QMkrQ== + dependencies: + marked "^0.6.2" + +sassdoc-theme-default@^2.8.3: + version "2.8.3" + resolved "https://registry.yarnpkg.com/sassdoc-theme-default/-/sassdoc-theme-default-2.8.3.tgz#092854a5654aa5c2820983fbe669dfbff2ef7bd1" + integrity sha512-KEl1ghIAwkkBGiYvkwVFepOA8IDEqgKsm0fGHUIcepcXiIp2SoHA0ZC5TZFjwaTrs296K1QK5WL4QtjNhS76+g== + dependencies: + babel-runtime "^6.22.0" + chroma-js "^1.2.2" + es6-denodeify "^0.1.0" + es6-promise "^4.2.6" + extend "^3.0.2" + fs-extra "^2.0.0" + html-minifier "^3.5.21" + nunjucks "^3.1.7" + sassdoc-extras "^2.5.0" + +sassdoc@^2.7.3: + version "2.7.3" + resolved "https://registry.yarnpkg.com/sassdoc/-/sassdoc-2.7.3.tgz#dfde10e6cc090c28578298f985f92df7d4c6ddbc" + integrity sha512-ccHlaOVoyGHF41xzj09n9WrECRHSGesFVq2EwX6DGMQdG0+avrxaLiuMLD26QfGyF2qcXVt07w5ifP5KZqy1Qw== + dependencies: + ansi-styles "^4.2.1" + babel-runtime "^6.26.0" + chalk "^2.4.2" + concat-stream "^2.0.0" + docopt "^0.6.1" + glob "^7.1.6" + glob2base "0.0.12" + js-yaml "^3.14.0" + lodash.difference "^4.5.0" + lodash.uniq "^4.5.0" + minimatch "^3.0.4" + mkdirp "^1.0.4" + multipipe "1.0.2" + rimraf "^3.0.2" + safe-wipe "0.2.5" + sass-convert "^0.5.0" + sassdoc-theme-default "^2.8.3" + scss-comment-parser "^0.8.4" + strip-indent "^3.0.0" + through2 "1.1.1" + update-notifier "^4.1.0" + vinyl-fs "^3.0.3" + vinyl-source-stream "1.1.2" + vinyl-string "^1.0.2" + +sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + +scss-comment-parser@^0.8.4: + version "0.8.4" + resolved "https://registry.yarnpkg.com/scss-comment-parser/-/scss-comment-parser-0.8.4.tgz#8e82c3fcf7fdbbb7f172f8955e2aa88b685f86d8" + integrity sha512-ERw4BODvM22n8Ke8hJxuH3fKXLm0Q4chfUNHwDSOAExCths2ZXq8PT32vms4R9Om6dffRSXzzGZS1p38UU4EAg== + dependencies: + cdocparser "^0.13.0" + +semver-diff@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b" + integrity sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg== + dependencies: + semver "^6.3.0" + +semver-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-1.0.0.tgz#92a4969065f9c70c694753d55248fc68f8f652c9" + +semver@^5.0.1, semver@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + +semver@^5.7.1: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +serialize-javascript@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4" + integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA== + dependencies: + randombytes "^2.1.0" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-value@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.1" + to-object-path "^0.3.0" + +set-value@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +shelljs@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.6.1.tgz#ec6211bed1920442088fe0f70b2837232ed2c8a8" + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +slice-ansi@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +source-map-resolve@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + dependencies: + atob "^2.1.1" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-resolve@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.6.0.tgz#3d9df87e236b53f16d01e58150fc7711138e5ed2" + integrity sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w== + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + +source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + +source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2", string-width@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^3.0.0, string-width@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string-width@^4.0.0, string-width@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" + integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +string_decoder@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" + dependencies: + safe-buffer "~5.1.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + +strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-ansi@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" + integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== + dependencies: + ansi-regex "^5.0.0" + +strip-indent@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + dependencies: + get-stdin "^4.0.1" + +strip-indent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" + integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== + dependencies: + min-indent "^1.0.0" + +strip-json-comments@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +strip-json-comments@~1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +supports-color@7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^5.3.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" + integrity sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w== + dependencies: + has-flag "^3.0.0" + +supports-color@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" + integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== + dependencies: + has-flag "^4.0.0" + +table@^3.7.8: + version "3.8.3" + resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" + dependencies: + ajv "^4.7.0" + ajv-keywords "^1.0.0" + chalk "^1.1.1" + lodash "^4.0.0" + slice-ansi "0.0.4" + string-width "^2.0.0" + +tar@^4: + version "4.4.4" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.4.tgz#ec8409fae9f665a4355cc3b4087d0820232bb8cd" + dependencies: + chownr "^1.0.1" + fs-minipass "^1.2.5" + minipass "^2.3.3" + minizlib "^1.1.0" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.2" + +term-size@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.0.tgz#1f16adedfe9bdc18800e1776821734086fcc6753" + integrity sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw== + +text-table@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + +through2-filter@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-2.0.0.tgz#60bc55a0dacb76085db1f9dae99ab43f83d622ec" + dependencies: + through2 "~2.0.0" + xtend "~4.0.0" + +through2@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/through2/-/through2-1.1.1.tgz#0847cbc4449f3405574dbdccd9bb841b83ac3545" + dependencies: + readable-stream ">=1.1.13-1 <1.2.0-0" + xtend ">=4.0.0 <4.1.0-0" + +through2@^2.0.0, through2@^2.0.3, through2@~2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" + dependencies: + readable-stream "^2.1.5" + xtend "~4.0.1" + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +to-absolute-glob@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz#1865f43d9e74b0822db9f145b78cff7d0f7c849b" + integrity sha1-GGX0PZ50sIItufFFt4z/fQ98hJs= + dependencies: + is-absolute "^1.0.0" + is-negated-glob "^1.0.0" + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + dependencies: + kind-of "^3.0.2" + +to-readable-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" + integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +to-through@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-through/-/to-through-2.0.0.tgz#fc92adaba072647bc0b67d6b03664aa195093af6" + integrity sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY= + dependencies: + through2 "^2.0.3" + +touch@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" + dependencies: + nopt "~1.0.10" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +uglify-js@3.4.x: + version "3.4.9" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3" + integrity sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q== + dependencies: + commander "~2.17.1" + source-map "~0.6.1" + +unc-path-regex@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa" + integrity sha1-5z3T17DXxe2G+6xrCufYxqadUPo= + +undefsafe@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.3.tgz#6b166e7094ad46313b2202da7ecc2cd7cc6e7aae" + integrity sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A== + dependencies: + debug "^2.2.0" + +union-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^0.4.3" + +unique-stream@^2.0.2: + version "2.2.1" + resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-2.2.1.tgz#5aa003cfbe94c5ff866c4e7d668bb1c4dbadb369" + dependencies: + json-stable-stringify "^1.0.0" + through2-filter "^2.0.0" + +unique-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" + integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== + dependencies: + crypto-random-string "^2.0.0" + +universalify@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7" + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +upath@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068" + integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q== + +update-notifier@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-4.1.3.tgz#be86ee13e8ce48fb50043ff72057b5bd598e1ea3" + integrity sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A== + dependencies: + boxen "^4.2.0" + chalk "^3.0.0" + configstore "^5.0.1" + has-yarn "^2.1.0" + import-lazy "^2.1.0" + is-ci "^2.0.0" + is-installed-globally "^0.3.1" + is-npm "^4.0.0" + is-yarn-global "^0.3.0" + latest-version "^5.0.0" + pupa "^2.0.1" + semver-diff "^3.1.1" + xdg-basedir "^4.0.0" + +upper-case@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + +url-parse-lax@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= + dependencies: + prepend-http "^2.0.0" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + +user-home@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" + dependencies: + os-homedir "^1.0.0" + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +util@^0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + dependencies: + inherits "2.0.1" + +value-or-function@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/value-or-function/-/value-or-function-3.0.0.tgz#1c243a50b595c1be54a754bfece8563b9ff8d813" + integrity sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM= + +vinyl-fs@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-3.0.3.tgz#c85849405f67428feabbbd5c5dbdd64f47d31bc7" + integrity sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng== + dependencies: + fs-mkdirp-stream "^1.0.0" + glob-stream "^6.1.0" + graceful-fs "^4.0.0" + is-valid-glob "^1.0.0" + lazystream "^1.0.0" + lead "^1.0.0" + object.assign "^4.0.4" + pumpify "^1.3.5" + readable-stream "^2.3.3" + remove-bom-buffer "^3.0.0" + remove-bom-stream "^1.2.0" + resolve-options "^1.1.0" + through2 "^2.0.0" + to-through "^2.0.0" + value-or-function "^3.0.0" + vinyl "^2.0.0" + vinyl-sourcemap "^1.1.0" + +vinyl-source-stream@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vinyl-source-stream/-/vinyl-source-stream-1.1.2.tgz#62b53a135610a896e98ca96bee3a87f008a8e780" + integrity sha1-YrU6E1YQqJbpjKlr7jqH8Aio54A= + dependencies: + through2 "^2.0.3" + vinyl "^0.4.3" + +vinyl-sourcemap@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz#92a800593a38703a8cdb11d8b300ad4be63b3e16" + integrity sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY= + dependencies: + append-buffer "^1.0.2" + convert-source-map "^1.5.0" + graceful-fs "^4.1.6" + normalize-path "^2.1.1" + now-and-later "^2.0.0" + remove-bom-buffer "^3.0.0" + vinyl "^2.0.0" + +vinyl-string@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/vinyl-string/-/vinyl-string-1.0.2.tgz#3a249efeb0d36c4cb0a5e59e30d68e54f739d8e3" + dependencies: + vinyl "^1.1.1" + +vinyl@^0.4.3: + version "0.4.6" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.4.6.tgz#2f356c87a550a255461f36bbeb2a5ba8bf784847" + dependencies: + clone "^0.2.0" + clone-stats "^0.0.1" + +vinyl@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884" + dependencies: + clone "^1.0.0" + clone-stats "^0.0.1" + replace-ext "0.0.1" + +vinyl@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.2.1.tgz#23cfb8bbab5ece3803aa2c0a1eb28af7cbba1974" + integrity sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw== + dependencies: + clone "^2.1.1" + clone-buffer "^1.0.0" + clone-stats "^1.0.0" + cloneable-readable "^1.0.0" + remove-trailing-separator "^1.0.1" + replace-ext "^1.0.0" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which@2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +which@^1.0.5: + version "1.3.0" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" + dependencies: + isexe "^2.0.0" + +wide-align@1.1.3, wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + +widest-line@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" + integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== + dependencies: + string-width "^4.0.0" + +window-size@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" + integrity sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY= + +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + +workerpool@6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.0.2.tgz#e241b43d8d033f1beb52c7851069456039d1d438" + integrity sha512-DSNyvOpFKrNusaaUwk+ej6cBj1bmhLcBfj80elGk+ZIo5JSkq+unB1dLKEOcNfJDZgjGICfhQ0Q5TbP0PvF4+Q== + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +write-file-atomic@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + +write@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + dependencies: + mkdirp "^0.5.1" + +xdg-basedir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" + integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== + +"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@~4.0.0, xtend@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +y18n@^3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + +y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + +yallist@^3.0.0, yallist@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" + +yargs-parser@13.1.2, yargs-parser@^13.1.2: + version "13.1.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" + integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-unparser@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@13.3.2: + version "13.3.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" + integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.2" + +yargs@^3.32.0: + version "3.32.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.32.0.tgz#03088e9ebf9e756b69751611d2a5ef591482c995" + integrity sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU= + dependencies: + camelcase "^2.0.1" + cliui "^3.0.3" + decamelize "^1.1.1" + os-locale "^1.4.0" + string-width "^1.0.1" + window-size "^0.1.4" + y18n "^3.2.0" -- cgit v1.2.3-54-g00ecf