├── .nvmrc
├── tests
├── yml
│ ├── .blank.yml
│ ├── extend
│ │ ├── find-file-test
│ │ │ └── .gitignore
│ │ ├── .extend-c.yml
│ │ └── .extend-b.yml
│ ├── .indentation-warn.yml
│ ├── .indentation-error.yml
│ ├── .max-0-warnings.yml
│ ├── .max-10-warnings.yml
│ ├── .max-100-warnings.yml
│ ├── .extend-a1.yml
│ ├── .extend-a2.yml
│ ├── .sass-lint.yml
│ │ └── .sass-lint.yml
│ ├── .error-output.yml
│ ├── .ignore-file.yml
│ └── .sasslintrc
│ │ └── .sasslintrc
├── sass
│ ├── empty-file.sass
│ ├── empty-file.scss
│ ├── final-newline--import.sass
│ ├── final-newline--import.scss
│ ├── final-newline--none.sass
│ ├── final-newline--space.sass
│ ├── ruleToggler-empty-comment.sass
│ ├── ruleToggler-empty-comment.scss
│ ├── success.scss
│ ├── final-newline--none.scss
│ ├── final-newline--return.sass
│ ├── no-important.sass
│ ├── ruleToggler-disable-all.sass
│ ├── ruleToggler-disable-all.scss
│ ├── final-newline--space.scss
│ ├── ruleToggler-disable-a-rule.sass
│ ├── ruleToggler-disable-a-rule.scss
│ ├── final-newline--return.scss
│ ├── no-important.scss
│ ├── ruleToggler-ignore-unknown.sass
│ ├── ruleToggler-ignore-unknown.scss
│ ├── placeholder-in-extend.sass
│ ├── ruleToggler-disable-a-block.sass
│ ├── ruleToggler-disable-multiple-rules.sass
│ ├── ruleToggler-disable-multiple-rules.scss
│ ├── final-newline--nested.sass
│ ├── no-ids.sass
│ ├── parse.scss
│ ├── ruleToggler-disable-a-block.scss
│ ├── placeholder-in-extend.scss
│ ├── ruleToggler-disable-a-line.sass
│ ├── final-newline--nested.scss
│ ├── no-extends.sass
│ ├── no-ids.scss
│ ├── ruleToggler-disable-a-line.scss
│ ├── no-warn.sass
│ ├── ruleToggler-disable-all-then-reenable.sass
│ ├── ruleToggler-disable-all-then-reenable.scss
│ ├── ruleToggler-disable-next-line.sass
│ ├── no-debug.sass
│ ├── no-extends.scss
│ ├── ruleToggler-disable-next-line.scss
│ ├── no-property-vendor-prefix.sass
│ ├── no-warn.scss
│ ├── no-debug.scss
│ ├── no-property-vendor-prefix.scss
│ ├── ruleToggler-disable-then-enable.sass
│ ├── leading-zero.sass
│ ├── ruleToggler-disable-then-enable.scss
│ ├── front-matter
│ │ └── front-matter.scss
│ ├── leading-zero.scss
│ ├── extends-before-mixins.sass
│ ├── no-empty-rulesets.scss
│ ├── quotes.sass
│ ├── extends-before-mixins.scss
│ ├── no-media-feature-vendor-prefix.sass
│ ├── no-universal-selectors.sass
│ ├── quotes.scss
│ ├── no-media-feature-vendor-prefix.scss
│ ├── space-before-colon.sass
│ ├── border-zero.sass
│ ├── url-quotes.sass
│ ├── space-before-colon.scss
│ ├── no-universal-selectors.scss
│ ├── url-quotes.scss
│ ├── no-selector-vendor-prefix.scss
│ ├── zero-unit.sass
│ ├── space-after-colon.sass
│ ├── no-selector-vendor-prefix.sass
│ ├── no-at-rule-vendor-prefix.sass
│ ├── zero-unit.scss
│ ├── no-value-vendor-prefix.scss
│ ├── ruleToggler-guarantee-order.sass
│ ├── ruleToggler-guarantee-order.scss
│ ├── border-zero.scss
│ ├── no-at-rule-vendor-prefix.scss
│ ├── property-units.sass
│ ├── no-disallowed-properties.sass
│ ├── no-value-vendor-prefix.sass
│ ├── space-after-colon.scss
│ ├── no-disallowed-property-values.sass
│ ├── no-trailing-whitespace.sass
│ ├── nesting-depth.sass
│ ├── no-trailing-zero.sass
│ ├── no-trailing-whitespace.scss
│ ├── extends-before-declarations.sass
│ ├── declarations-before-nesting.sass
│ ├── force-attribute-nesting.sass
│ ├── no-qualifying-elements.sass
│ ├── empty-args.sass
│ ├── extends-before-declarations.scss
│ ├── one-declaration-per-line.scss
│ ├── no-url-domains.sass
│ ├── no-url-protocols.sass
│ ├── no-disallowed-properties.scss
│ ├── no-disallowed-property-values.scss
│ ├── no-color-hex.sass
│ ├── no-trailing-zero.scss
│ ├── nesting-depth.scss
│ ├── no-qualifying-elements.scss
│ ├── bem-depth.sass
│ ├── no-url-domains.scss
│ ├── no-url-protocols.scss
│ ├── trailing-semicolon.scss
│ ├── no-color-hex.scss
│ ├── property-units.scss
│ ├── force-attribute-nesting.scss
│ ├── empty-args.scss
│ ├── declarations-before-nesting.scss
│ ├── hex-length.sass
│ ├── hex-notation.sass
│ ├── hex-length.scss
│ ├── variable-name-format.sass
│ ├── hex-notation.scss
│ ├── clean-import-paths.sass
│ ├── variable-name-format.scss
│ ├── space-after-comma.sass
│ ├── space-between-parens.sass
│ ├── no-color-keywords.sass
│ ├── id-name-format.sass
│ ├── space-after-comma.scss
│ ├── space-between-parens.scss
│ ├── bem-depth.scss
│ ├── no-css-comments.sass
│ ├── space-before-brace.scss
│ ├── force-pseudo-nesting.sass
│ ├── no-transition-all.sass
│ ├── no-color-keywords.scss
│ ├── clean-import-paths.scss
│ ├── no-css-comments.scss
│ ├── max-line-length.sass
│ ├── no-transition-all.scss
│ ├── id-name-format.scss
│ ├── max-line-length.scss
│ ├── variable-for-property.sass
│ ├── single-line-per-selector.sass
│ ├── selector-helpers
│ │ └── selector-helpers.scss
│ ├── variable-for-property.scss
│ ├── single-line-per-selector.scss
│ ├── property-sort-order.sass
│ ├── placeholder-name-format.sass
│ ├── force-element-nesting.sass
│ ├── mixins-before-declarations.sass
│ ├── force-pseudo-nesting.scss
│ ├── attribute-quotes.sass
│ ├── property-sort-order.scss
│ ├── space-before-bang.sass
│ ├── empty-line-between-blocks.sass
│ ├── no-duplicate-properties.sass
│ ├── placeholder-name-format.scss
│ └── space-before-bang.scss
├── cli
│ ├── cli-error.sass
│ ├── cli.scss
│ ├── cli-warn.scss
│ ├── cli.txt
│ ├── cli-error.scss
│ └── cli-clean.scss
├── dir-test
│ └── dir.scss
│ │ └── test.scss
├── testFile.txt
├── bom-utf8
│ ├── var-utf8-bom.scss
│ └── starts-with-mixin-utf8-bom.scss
├── formatters
│ └── fixtures
│ │ ├── broken.js
│ │ └── simple.js
├── helpers
│ ├── helpers.js
│ ├── loadConfigFile.js
│ ├── hasEOL.js
│ ├── stripQuotes.js
│ ├── stripBom.js
│ ├── getMessageType.js
│ ├── isNumber.js
│ ├── isLowerCase.js
│ ├── isUpperCase.js
│ ├── isEmptyLine.js
│ ├── isNestable.js
│ ├── stripLastSpace.js
│ ├── isCamelCase.js
│ ├── isPascalCase.js
│ └── propertySearch.js
└── rules
│ ├── no-empty-rulesets.js
│ ├── one-declaration-per-line.js
│ ├── trailing-semicolon.js
│ ├── space-before-brace.js
│ ├── _lint.js
│ ├── no-ids.js
│ ├── no-warn.js
│ ├── no-debug.js
│ ├── no-extends.js
│ ├── url-quotes.js
│ ├── no-color-hex.js
│ ├── no-important.js
│ ├── no-url-domains.js
│ ├── no-combinators.js
│ ├── no-invalid-hex.js
│ ├── no-css-comments.js
│ ├── no-trailing-zero.js
│ ├── no-color-keywords.js
│ ├── no-transition-all.js
│ ├── extends-before-mixins.js
│ ├── force-pseudo-nesting.js
│ ├── placeholder-in-extend.js
│ ├── force-element-nesting.js
│ ├── no-attribute-selectors.js
│ ├── no-trailing-whitespace.js
│ ├── no-universal-selectors.js
│ ├── force-attribute-nesting.js
│ ├── single-line-per-selector.js
│ ├── declarations-before-nesting.js
│ └── extends-before-declarations.js
├── .npmrc
├── .commitlintrc.yml
├── mocha.opts
├── data
├── pseudoElements.yml
└── pseudoClasses.yml
├── .npmignore
├── lib
├── format
│ └── formatters
│ │ ├── html-template-result.html
│ │ ├── html-template-message.html
│ │ ├── json.js
│ │ └── unix.js
├── rules
│ ├── no-ids.js
│ ├── no-important.js
│ ├── no-color-hex.js
│ ├── no-attribute-selectors.js
│ ├── no-universal-selectors.js
│ ├── no-invalid-hex.js
│ ├── no-css-comments.js
│ ├── max-file-line-count.js
│ ├── no-warn.js
│ ├── no-debug.js
│ ├── no-extends.js
│ ├── no-trailing-zero.js
│ ├── no-disallowed-properties.js
│ ├── url-quotes.js
│ ├── max-line-length.js
│ ├── no-url-domains.js
│ ├── one-declaration-per-line.js
│ ├── no-trailing-whitespace.js
│ ├── attribute-quotes.js
│ ├── space-after-bang.js
│ ├── placeholder-in-extend.js
│ └── no-empty-rulesets.js
├── exceptions.js
└── groot.js
├── docs
├── rules
│ ├── no-warn.md
│ ├── no-debug.md
│ ├── no-ids.md
│ ├── no-important.md
│ ├── no-extends.md
│ ├── no-empty-rulesets.md
│ ├── no-trailing-whitespace.md
│ ├── no-trailing-zero.md
│ ├── no-combinators.md
│ ├── single-line-per-selector.md
│ ├── extends-before-mixins.md
│ ├── no-color-keywords.md
│ ├── placeholder-in-extend.md
│ ├── extends-before-declarations.md
│ ├── no-transition-all.md
│ ├── one-declaration-per-line.md
│ ├── bem-depth.md
│ ├── no-universal-selectors.md
│ ├── url-quotes.md
│ ├── declarations-before-nesting.md
│ ├── max-file-line-count.md
│ ├── no-color-hex.md
│ ├── leading-zero.md
│ ├── pseudo-element.md
│ ├── quotes.md
│ ├── space-after-colon.md
│ ├── nesting-depth.md
│ ├── no-attribute-selectors.md
│ ├── space-before-colon.md
│ ├── space-after-bang.md
│ ├── space-before-bang.md
│ ├── no-disallowed-properties.md
│ ├── zero-unit.md
│ ├── final-newline.md
│ ├── force-element-nesting.md
│ ├── no-url-domains.md
│ ├── max-line-length.md
│ ├── space-after-comma.md
│ ├── mixins-before-declarations.md
│ ├── empty-args.md
│ ├── force-attribute-nesting.md
│ ├── trailing-semicolon.md
│ ├── no-css-comments.md
│ ├── space-before-brace.md
│ ├── hex-notation.md
│ ├── hex-length.md
│ ├── force-pseudo-nesting.md
│ ├── no-invalid-hex.md
│ ├── space-between-parens.md
│ ├── no-disallowed-property-values.md
│ ├── attribute-quotes.md
│ ├── border-zero.md
│ ├── indentation.md
│ ├── property-units.md
│ └── clean-import-paths.md
├── options
│ ├── cwd.md
│ ├── output-file.md
│ ├── cache-config.md
│ └── max-warnings.md
└── sass-lint.yml
├── .editorconfig
├── CODE_OF_CONDUCT.md
├── .travis.yml
├── appveyor.yml
├── .gitignore
├── .github
├── ISSUE_TEMPLATE.md
└── PULL_REQUEST_TEMPLATE.md
└── LICENSE
/.nvmrc:
--------------------------------------------------------------------------------
1 | 6
2 |
--------------------------------------------------------------------------------
/tests/yml/.blank.yml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/sass/empty-file.sass:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/sass/empty-file.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | message=:shipit: v%s
2 |
--------------------------------------------------------------------------------
/tests/yml/extend/find-file-test/.gitignore:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/cli/cli-error.sass:
--------------------------------------------------------------------------------
1 | #cli
2 | color: red
3 |
--------------------------------------------------------------------------------
/tests/cli/cli.scss:
--------------------------------------------------------------------------------
1 | .cli {
2 | color: red;
3 | }
4 |
--------------------------------------------------------------------------------
/tests/cli/cli-warn.scss:
--------------------------------------------------------------------------------
1 | .cli {
2 | color: red;
3 | }
4 |
--------------------------------------------------------------------------------
/tests/cli/cli.txt:
--------------------------------------------------------------------------------
1 | .cli {
2 | font-size: 100%;
3 | }
4 |
--------------------------------------------------------------------------------
/tests/sass/final-newline--import.sass:
--------------------------------------------------------------------------------
1 | @import 'foo'
2 |
--------------------------------------------------------------------------------
/tests/sass/final-newline--import.scss:
--------------------------------------------------------------------------------
1 | @import 'foo';
2 |
--------------------------------------------------------------------------------
/tests/sass/final-newline--none.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | content: bar
--------------------------------------------------------------------------------
/tests/cli/cli-error.scss:
--------------------------------------------------------------------------------
1 | #cli {
2 | color: red;
3 | }
4 |
--------------------------------------------------------------------------------
/tests/sass/final-newline--space.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | content: bar
--------------------------------------------------------------------------------
/tests/sass/ruleToggler-empty-comment.sass:
--------------------------------------------------------------------------------
1 | p
2 | /**/
3 |
--------------------------------------------------------------------------------
/tests/sass/ruleToggler-empty-comment.scss:
--------------------------------------------------------------------------------
1 | p {
2 | /**/
3 | }
--------------------------------------------------------------------------------
/tests/sass/success.scss:
--------------------------------------------------------------------------------
1 | .one {
2 | margin-top: 0;
3 | }
4 |
--------------------------------------------------------------------------------
/tests/yml/.indentation-warn.yml:
--------------------------------------------------------------------------------
1 | rules:
2 | indentation: 1
3 |
--------------------------------------------------------------------------------
/.commitlintrc.yml:
--------------------------------------------------------------------------------
1 | extends:
2 | - '@commitlint/config-conventional'
--------------------------------------------------------------------------------
/tests/sass/final-newline--none.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | content: bar;
3 | }
--------------------------------------------------------------------------------
/tests/sass/final-newline--return.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | content: bar
3 |
--------------------------------------------------------------------------------
/tests/sass/no-important.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | color: red !important
3 |
--------------------------------------------------------------------------------
/tests/sass/ruleToggler-disable-all.sass:
--------------------------------------------------------------------------------
1 | // sass-lint:disable-all
2 |
--------------------------------------------------------------------------------
/tests/sass/ruleToggler-disable-all.scss:
--------------------------------------------------------------------------------
1 | // sass-lint:disable-all
2 |
--------------------------------------------------------------------------------
/tests/yml/.indentation-error.yml:
--------------------------------------------------------------------------------
1 | rules:
2 | indentation: 2
3 |
--------------------------------------------------------------------------------
/tests/yml/.max-0-warnings.yml:
--------------------------------------------------------------------------------
1 | options:
2 | max-warnings: 0
3 |
--------------------------------------------------------------------------------
/tests/yml/.max-10-warnings.yml:
--------------------------------------------------------------------------------
1 | options:
2 | max-warnings: 10
3 |
--------------------------------------------------------------------------------
/tests/yml/.max-100-warnings.yml:
--------------------------------------------------------------------------------
1 | options:
2 | max-warnings: 100
3 |
--------------------------------------------------------------------------------
/tests/dir-test/dir.scss/test.scss:
--------------------------------------------------------------------------------
1 | #foo {
2 | content: '';
3 | }
4 |
--------------------------------------------------------------------------------
/tests/sass/final-newline--space.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | content: bar;
3 | }
--------------------------------------------------------------------------------
/tests/sass/ruleToggler-disable-a-rule.sass:
--------------------------------------------------------------------------------
1 | // sass-lint:disable a
2 |
--------------------------------------------------------------------------------
/tests/sass/ruleToggler-disable-a-rule.scss:
--------------------------------------------------------------------------------
1 | // sass-lint:disable a
2 |
--------------------------------------------------------------------------------
/tests/sass/final-newline--return.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | content: bar;
3 | }
4 |
--------------------------------------------------------------------------------
/tests/sass/no-important.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | color: red !important;
3 | }
4 |
--------------------------------------------------------------------------------
/tests/sass/ruleToggler-ignore-unknown.sass:
--------------------------------------------------------------------------------
1 | p
2 | //sass-lint:random a
3 |
--------------------------------------------------------------------------------
/tests/cli/cli-clean.scss:
--------------------------------------------------------------------------------
1 | $red: #f00;
2 |
3 | .cli {
4 | color: $red;
5 | }
6 |
--------------------------------------------------------------------------------
/tests/sass/ruleToggler-ignore-unknown.scss:
--------------------------------------------------------------------------------
1 | p {
2 | //sass-lint:random a
3 | }
--------------------------------------------------------------------------------
/tests/yml/extend/.extend-c.yml:
--------------------------------------------------------------------------------
1 | rules:
2 | no-ids: 1
3 | no-important: 2
4 |
--------------------------------------------------------------------------------
/mocha.opts:
--------------------------------------------------------------------------------
1 | -R spec
2 | -t 4000
3 | tests tests/formatters tests/helpers tests/rules
4 |
--------------------------------------------------------------------------------
/tests/sass/placeholder-in-extend.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | @extend .bar
3 | @extend %baz
4 |
--------------------------------------------------------------------------------
/tests/sass/ruleToggler-disable-a-block.sass:
--------------------------------------------------------------------------------
1 | p
2 | // sass-lint:disable-block a
3 |
--------------------------------------------------------------------------------
/tests/sass/ruleToggler-disable-multiple-rules.sass:
--------------------------------------------------------------------------------
1 | // sass-lint:disable a b, c d
2 |
--------------------------------------------------------------------------------
/tests/sass/ruleToggler-disable-multiple-rules.scss:
--------------------------------------------------------------------------------
1 | // sass-lint:disable a b, c d
2 |
--------------------------------------------------------------------------------
/tests/testFile.txt:
--------------------------------------------------------------------------------
1 | This is a test file that test's the loadConfigFile helper function.
--------------------------------------------------------------------------------
/tests/bom-utf8/var-utf8-bom.scss:
--------------------------------------------------------------------------------
1 | $my-color: red;
2 |
3 | body {
4 | color: $my-color;
5 | }
--------------------------------------------------------------------------------
/tests/sass/final-newline--nested.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | @if $foo == 'bar'
3 | content: 'bar'
4 |
--------------------------------------------------------------------------------
/tests/sass/no-ids.sass:
--------------------------------------------------------------------------------
1 | #foo
2 | content: 'bar'
3 |
4 |
5 | .bar#baz
6 | content: 'qux'
7 |
--------------------------------------------------------------------------------
/tests/sass/parse.scss:
--------------------------------------------------------------------------------
1 | .one {
2 | color: red;
3 | }
4 |
5 | #test
6 | color: blue;
7 | }
8 |
--------------------------------------------------------------------------------
/tests/sass/ruleToggler-disable-a-block.scss:
--------------------------------------------------------------------------------
1 | p {
2 | // sass-lint:disable-block a
3 | }
4 |
--------------------------------------------------------------------------------
/tests/sass/placeholder-in-extend.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | @extend .bar;
3 |
4 | @extend %baz;
5 | }
6 |
--------------------------------------------------------------------------------
/tests/sass/ruleToggler-disable-a-line.sass:
--------------------------------------------------------------------------------
1 | p
2 | border-color: red // sass-lint:disable-line a
3 |
--------------------------------------------------------------------------------
/tests/yml/.extend-a1.yml:
--------------------------------------------------------------------------------
1 | options:
2 | config-file: extend/.extend-c.yml
3 | rules:
4 | no-ids: 2
5 |
--------------------------------------------------------------------------------
/tests/yml/.extend-a2.yml:
--------------------------------------------------------------------------------
1 | options:
2 | config-file: extend/.extend-b.yml
3 | rules:
4 | no-ids: 2
5 |
--------------------------------------------------------------------------------
/tests/sass/final-newline--nested.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | @if $foo == 'bar' {
3 | content: 'bar';
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/tests/sass/no-extends.sass:
--------------------------------------------------------------------------------
1 | %foo
2 | color: red
3 |
4 |
5 | .bar
6 | @extend %foo
7 | content: 'baz'
8 |
--------------------------------------------------------------------------------
/tests/sass/no-ids.scss:
--------------------------------------------------------------------------------
1 | #foo {
2 | content: 'bar';
3 | }
4 |
5 | .bar#baz {
6 | content: 'qux';
7 | }
8 |
--------------------------------------------------------------------------------
/tests/sass/ruleToggler-disable-a-line.scss:
--------------------------------------------------------------------------------
1 | p {
2 | border-color: red; // sass-lint:disable-line a
3 | }
4 |
--------------------------------------------------------------------------------
/tests/bom-utf8/starts-with-mixin-utf8-bom.scss:
--------------------------------------------------------------------------------
1 | @mixin foo(
2 | $param: 'def'
3 | ) {
4 | color: red;
5 | }
6 |
--------------------------------------------------------------------------------
/tests/sass/no-warn.sass:
--------------------------------------------------------------------------------
1 | @warn 'foo'
2 |
3 | @function foo
4 | @warn 'bar'
5 |
6 |
7 | =baz
8 | @warn 'qux'
9 |
--------------------------------------------------------------------------------
/tests/sass/ruleToggler-disable-all-then-reenable.sass:
--------------------------------------------------------------------------------
1 | // sass-lint:disable-all
2 |
3 | // sass-lint:enable-all
4 |
--------------------------------------------------------------------------------
/tests/sass/ruleToggler-disable-all-then-reenable.scss:
--------------------------------------------------------------------------------
1 | // sass-lint:disable-all
2 |
3 | // sass-lint:enable-all
4 |
--------------------------------------------------------------------------------
/tests/sass/ruleToggler-disable-next-line.sass:
--------------------------------------------------------------------------------
1 | p
2 | // sass-lint:disable-next-line a
3 | border-color: red
4 |
--------------------------------------------------------------------------------
/tests/sass/no-debug.sass:
--------------------------------------------------------------------------------
1 | @debug 'foo'
2 |
3 | @function foo
4 | @debug 'bar'
5 |
6 |
7 | =baz
8 | @debug 'qux'
9 |
--------------------------------------------------------------------------------
/tests/sass/no-extends.scss:
--------------------------------------------------------------------------------
1 | %foo {
2 | color: red;
3 | }
4 |
5 | .bar {
6 | @extend %foo;
7 | content: 'baz';
8 | }
9 |
--------------------------------------------------------------------------------
/tests/sass/ruleToggler-disable-next-line.scss:
--------------------------------------------------------------------------------
1 | p {
2 | // sass-lint:disable-next-line a
3 | border-color: red;
4 | }
5 |
--------------------------------------------------------------------------------
/tests/yml/extend/.extend-b.yml:
--------------------------------------------------------------------------------
1 | options:
2 | config-file: .extend-c.yml
3 | rules:
4 | no-ids: 0
5 | no-mergeable-selectors: 2
6 |
--------------------------------------------------------------------------------
/tests/sass/no-property-vendor-prefix.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | -webkit-touch-callout: none
3 | -webkit-transform: scale(1)
4 | --custom-prop: 'test'
5 |
--------------------------------------------------------------------------------
/tests/sass/no-warn.scss:
--------------------------------------------------------------------------------
1 | @warn 'foo';
2 |
3 | @function foo {
4 | @warn 'bar';
5 | }
6 |
7 | @mixin baz {
8 | @warn 'qux';
9 | }
10 |
--------------------------------------------------------------------------------
/tests/sass/no-debug.scss:
--------------------------------------------------------------------------------
1 | @debug 'foo';
2 |
3 | @function foo {
4 | @debug 'bar';
5 | }
6 |
7 | @mixin baz {
8 | @debug 'qux';
9 | }
10 |
--------------------------------------------------------------------------------
/tests/sass/no-property-vendor-prefix.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | -webkit-touch-callout: none;
3 | -webkit-transform: scale(1);
4 | --custom-prop: 'test';
5 | }
6 |
--------------------------------------------------------------------------------
/tests/sass/ruleToggler-disable-then-enable.sass:
--------------------------------------------------------------------------------
1 | p
2 | // sass-lint:disable a
3 | border: none
4 | // sass-lint:enable a
5 | color: blue
6 |
--------------------------------------------------------------------------------
/tests/sass/leading-zero.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | border-radius: .5em 0em, 0.5em 1.0em
3 | height: .6em
4 | width: 100%
5 |
6 |
7 | @if (1 == 0)
8 | $foo: true
9 |
--------------------------------------------------------------------------------
/tests/sass/ruleToggler-disable-then-enable.scss:
--------------------------------------------------------------------------------
1 | p {
2 | // sass-lint:disable a
3 | border: none;
4 | // sass-lint:enable a
5 | color: blue;
6 | }
7 |
--------------------------------------------------------------------------------
/tests/sass/front-matter/front-matter.scss:
--------------------------------------------------------------------------------
1 | ---
2 | # Only the main Sass file needs front matter (the dashes are enough)
3 | ---
4 |
5 | .test {
6 | color: red;
7 | }
8 |
--------------------------------------------------------------------------------
/data/pseudoElements.yml:
--------------------------------------------------------------------------------
1 | after
2 | before
3 | cue
4 | first-letter
5 | first-line
6 | selection
7 | backdrop
8 | placeholder
9 | marker
10 | spelling-error
11 | grammar-error
12 |
--------------------------------------------------------------------------------
/tests/sass/leading-zero.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | border-radius: .5em 0em, 0.5em 1.0em;
3 | height: .6em;
4 | width: 100%;
5 | }
6 |
7 | @if (1 == 0) {
8 | $foo: true;
9 | }
10 |
--------------------------------------------------------------------------------
/tests/formatters/fixtures/broken.js:
--------------------------------------------------------------------------------
1 | var nonExistantFormatter = require('this-module-does-not-exist');
2 | module.exports = function (results) {
3 | return nonExistantFormatter(results);
4 | };
5 |
--------------------------------------------------------------------------------
/tests/sass/extends-before-mixins.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | @extend %waldo
3 | +foo
4 |
5 |
6 | .bar
7 | +foo
8 | @extend %waldo
9 |
10 |
11 | .baz
12 | @extend %waldo
13 | +foo
14 | @extend %qux
15 |
--------------------------------------------------------------------------------
/tests/yml/.sass-lint.yml/.sass-lint.yml:
--------------------------------------------------------------------------------
1 | options:
2 | formatter: json
3 | cache-config: false
4 | merge-default-rules: false
5 | files:
6 | include: '**/*.s+(a|c)ss'
7 | rules:
8 | no-color-keywords: 1
9 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .github
2 | coverage
3 | docs
4 | tests
5 | .editorconfig
6 | .eslintrc
7 | .gitignore
8 | .npmignore
9 | .npmrc
10 | .travis.yml
11 | .nvmrc
12 | appveyor.yml
13 | CONTRIBUTING.md
14 | CODE_OF_CONDUCT.md
15 |
--------------------------------------------------------------------------------
/lib/format/formatters/html-template-result.html:
--------------------------------------------------------------------------------
1 |
2 | |
3 | [+] <%- filePath %>
4 | <%- summary %>
5 | |
6 |
7 |
--------------------------------------------------------------------------------
/tests/yml/.error-output.yml:
--------------------------------------------------------------------------------
1 | options:
2 | formatter: stylish
3 | cache-config: false
4 | merge-default-rules: false
5 | files:
6 | include: '**/*.s+(a|c)ss'
7 | rules:
8 | no-ids: 2
9 | no-color-literals: 1
10 |
--------------------------------------------------------------------------------
/tests/sass/no-empty-rulesets.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 |
3 | }
4 |
5 | .bar {
6 | content: 'baz';
7 |
8 | .qux {}
9 | }
10 |
11 | .bar{}
12 |
13 | .baz {
14 | // a comment
15 | /* and
16 | yet
17 | another */
18 | }
19 |
--------------------------------------------------------------------------------
/tests/sass/quotes.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | content: 'hello'
3 |
4 |
5 | .bar
6 | content: "hello"
7 |
8 |
9 | .baz
10 | background-image: url('/foo/img.png')
11 |
12 |
13 | .qux
14 | background-image: url("/foo/img.png")
15 |
--------------------------------------------------------------------------------
/tests/yml/.ignore-file.yml:
--------------------------------------------------------------------------------
1 | options:
2 | formatter: stylish
3 | cache-config: false
4 | merge-default-rules: false
5 | files:
6 | include: '**/*.s+(a|c)ss'
7 | ignore: '**/cli.scss'
8 | rules:
9 | no-color-literals: 1
10 |
--------------------------------------------------------------------------------
/docs/rules/no-warn.md:
--------------------------------------------------------------------------------
1 | # No Warn
2 |
3 | Rule `no-warn` will enforce that `@warn` statements are not allowed to be used.
4 |
5 | ## Examples
6 |
7 | When enabled, the following are disallowed:
8 |
9 | ```scss
10 | @warn 'foo';
11 | ```
12 |
--------------------------------------------------------------------------------
/docs/rules/no-debug.md:
--------------------------------------------------------------------------------
1 | # No Debug
2 |
3 | Rule `no-debug` will enforce that `@debug` statements are not allowed to be used.
4 |
5 | ## Examples
6 |
7 | When enabled, the following are disallowed:
8 |
9 | ```scss
10 | @debug 'foo';
11 | ```
12 |
--------------------------------------------------------------------------------
/tests/sass/extends-before-mixins.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | @extend %waldo;
3 | @include foo;
4 | }
5 |
6 | .bar {
7 | @include foo;
8 | @extend %waldo;
9 | }
10 |
11 | .baz {
12 | @extend %waldo;
13 | @include foo;
14 | @extend %qux;
15 | }
16 |
--------------------------------------------------------------------------------
/tests/sass/no-media-feature-vendor-prefix.sass:
--------------------------------------------------------------------------------
1 | @media (-webkit-min-device-pixel-ratio: 1) and (max-width: 200px)
2 |
3 | @media (min--mox-device-pixel-ratio: 1)
4 |
5 | @media (-non-standard-min-resolution: 96dpi)
6 |
7 | @media (min-resolution: 96dpi)
8 |
--------------------------------------------------------------------------------
/tests/sass/no-universal-selectors.sass:
--------------------------------------------------------------------------------
1 | *
2 | content: 'foo'
3 |
4 | * [lang^=en]
5 | content: 'bar'
6 |
7 | *.warning
8 | content: 'baz'
9 |
10 | *#maincontent
11 | content: 'qux'
12 |
13 | *:before,
14 | *:after
15 | content: 'nurf'
16 |
--------------------------------------------------------------------------------
/tests/sass/quotes.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | content: 'hello';
3 | }
4 |
5 | .bar {
6 | content: "hello";
7 | }
8 |
9 | .baz {
10 | background-image: url('/foo/img.png');
11 | }
12 |
13 | .qux {
14 | background-image: url("/foo/img.png");
15 | }
16 |
--------------------------------------------------------------------------------
/docs/rules/no-ids.md:
--------------------------------------------------------------------------------
1 | # No IDs
2 |
3 | Rule `no-ids` will enforce that ID selectors are not allowed to be used.
4 |
5 | ## Examples
6 |
7 | When enabled, the following are disallowed:
8 |
9 | ```scss
10 | #foo {
11 | content: 'bar';
12 | }
13 | ```
14 |
--------------------------------------------------------------------------------
/tests/sass/no-media-feature-vendor-prefix.scss:
--------------------------------------------------------------------------------
1 | @media (-webkit-min-device-pixel-ratio: 1) and (max-width: 200px) {}
2 |
3 | @media (min--mox-device-pixel-ratio: 1) {}
4 |
5 | @media (-non-standard-min-resolution: 96dpi) {}
6 |
7 | @media (min-resolution: 96dpi) {}
8 |
--------------------------------------------------------------------------------
/tests/sass/space-before-colon.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | content :'foo'
3 |
4 |
5 | .bar
6 | content:'bar'
7 |
8 |
9 | .baz
10 | @media (max-width :50em) and (orientation:landscape)
11 | content: 'baz'
12 |
13 |
14 |
15 | $qux: 'qux'
16 | $norf :'norf'
17 |
--------------------------------------------------------------------------------
/tests/sass/border-zero.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | border: 0
3 |
4 |
5 | .bar
6 | border: none
7 |
8 |
9 | .baz
10 | border-right: 0
11 |
12 |
13 | .qux
14 | border-left: none
15 |
16 |
17 | .fail
18 | border-top: none
19 |
20 |
21 | .norf
22 | border: 1px
23 |
--------------------------------------------------------------------------------
/tests/sass/url-quotes.sass:
--------------------------------------------------------------------------------
1 | $foo: 'foo.png'
2 |
3 | .foo
4 | background-image: url('foo.png')
5 |
6 |
7 | .bar
8 | background-image: url(foo.png)
9 |
10 |
11 | .baz
12 | background-image: url($foo)
13 |
14 |
15 | .qux
16 | background-image: url('bar/' + $foo)
17 |
--------------------------------------------------------------------------------
/tests/yml/.sasslintrc/.sasslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "options": {
3 | "formatter": "json",
4 | "cache-config": false,
5 | "merge-default-rules": false
6 | },
7 | "files": {
8 | "include": "**/*.s+(a|c)ss"
9 | },
10 | "rules": {
11 | "no-color-keywords": 1
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/tests/sass/space-before-colon.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | content :'foo';
3 | }
4 |
5 | .bar {
6 | content:'bar';
7 | }
8 |
9 | .baz {
10 | @media (max-width :50em) and (orientation:landscape) {
11 | content: 'baz';
12 | }
13 | }
14 |
15 | $qux: 'qux';
16 | $norf :'norf';
17 |
--------------------------------------------------------------------------------
/docs/options/cwd.md:
--------------------------------------------------------------------------------
1 | # cwd
2 |
3 | Option `cwd` will determine a directory that sass-lint should use as the base directory when it looks for files / paths etc. This is useful for specifying standard directory structures across teams for example.
4 |
5 | ## Options
6 |
7 | * Default: `$ process.cwd();`
8 |
--------------------------------------------------------------------------------
/docs/options/output-file.md:
--------------------------------------------------------------------------------
1 | # Output File
2 |
3 | Option `output-file` will determine if formatted output should be written to a file. `output-file` should be set to a path plus file name relative to where Sass Lint is being run from. If not included, formatted output will be logged to the console.
4 |
--------------------------------------------------------------------------------
/docs/rules/no-important.md:
--------------------------------------------------------------------------------
1 | # No Important
2 |
3 | Rule `no-important` will enforce that important declarations are not allowed to be used.
4 |
5 | ## Examples
6 |
7 | When enabled, the following are disallowed:
8 |
9 | ```scss
10 | .foo {
11 | content: 'bar' !important;
12 | }
13 | ```
14 |
--------------------------------------------------------------------------------
/tests/sass/no-universal-selectors.scss:
--------------------------------------------------------------------------------
1 | * {
2 | content: 'foo';
3 | }
4 |
5 | * [lang^=en] {
6 | content: 'bar';
7 | }
8 |
9 | *.warning {
10 | content: 'baz';
11 | }
12 |
13 | *#maincontent {
14 | content: 'qux';
15 | }
16 |
17 | *:before,
18 | *:after {
19 | content: 'nurf';
20 | }
21 |
--------------------------------------------------------------------------------
/tests/sass/url-quotes.scss:
--------------------------------------------------------------------------------
1 | $foo: 'foo.png';
2 |
3 | .foo {
4 | background-image: url('foo.png');
5 | }
6 |
7 | .bar {
8 | background-image: url(foo.png);
9 | }
10 |
11 | .baz {
12 | background-image: url($foo);
13 | }
14 |
15 | .qux {
16 | background-image: url('bar/' + $foo);
17 | }
18 |
--------------------------------------------------------------------------------
/docs/rules/no-extends.md:
--------------------------------------------------------------------------------
1 | # No Extends
2 |
3 | Rule `no-extends` will enforce that extends are not allowed to be used.
4 |
5 | ## Examples
6 |
7 | When enabled, the following are disallowed:
8 |
9 | ```scss
10 | .foo {
11 | @extend %bar;
12 | @extend .bar;
13 | @extend #bar;
14 | }
15 | ```
16 |
--------------------------------------------------------------------------------
/tests/sass/no-selector-vendor-prefix.scss:
--------------------------------------------------------------------------------
1 | input::-moz-placeholder { color: red; }
2 | dialog::-webkit-backdrop { background: rgba(255, 0, 0, .25); }
3 | dialog::-webkit-non-standard { background: rgba(255, 0, 0, .25); }
4 |
5 | input::placeholder { color: red; }
6 | dialog::backdrop { background: rgba(255, 0, 0, .25); }
7 |
--------------------------------------------------------------------------------
/tests/sass/zero-unit.sass:
--------------------------------------------------------------------------------
1 | .baz
2 | border-right-width: 0px
3 |
4 |
5 | .foo
6 | margin: 0px
7 | padding: 0
8 |
9 |
10 | .bar
11 | padding: 5px 0 0px
12 |
13 |
14 | $foo: 0px
15 | $bar: '0px'
16 |
17 | .foo
18 | @if $bar == 0
19 | content: 'bar'
20 |
21 |
22 | @if $foo == '0px'
23 | content: 'foo'
24 |
--------------------------------------------------------------------------------
/tests/sass/space-after-colon.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | content: 'foo'
3 |
4 |
5 | .bar
6 | content:'bar'
7 |
8 |
9 | .baz
10 | @media (max-width: 50em) and (orientation:landscape)
11 | content: 'baz'
12 |
13 |
14 |
15 | $qux: 'qux'
16 | $norf:'norf'
17 |
18 | .foo
19 | @at-root button#{&}:hover
20 |
21 | .foo:hover
22 | +test
23 |
--------------------------------------------------------------------------------
/docs/rules/no-empty-rulesets.md:
--------------------------------------------------------------------------------
1 | # No Empty Rulesets
2 |
3 | Rule `no-empty-rulesets` will enforce that rulesets are not empty.
4 |
5 | ## Examples
6 |
7 | When enabled, the following are disallowed:
8 |
9 | ```scss
10 | .foo {
11 |
12 | }
13 |
14 | .bar {
15 | content: 'baz';
16 |
17 | .qux {}
18 | }
19 |
20 | .waldo {}
21 | ```
22 |
--------------------------------------------------------------------------------
/tests/sass/no-selector-vendor-prefix.sass:
--------------------------------------------------------------------------------
1 | input::-moz-placeholder
2 | color: red
3 |
4 | dialog::-webkit-backdrop
5 | background: rgba(255, 0, 0, .25)
6 |
7 | dialog::-webkit-non-standard
8 | background: rgba(255, 0, 0, .25)
9 |
10 | input::placeholder
11 | color: red
12 |
13 | dialog::backdrop
14 | background: rgba(255, 0, 0, .25)
15 |
--------------------------------------------------------------------------------
/tests/formatters/fixtures/simple.js:
--------------------------------------------------------------------------------
1 | module.exports = function (results) {
2 | var output = '';
3 |
4 | results.forEach(function (result) {
5 | var messages = result.messages;
6 | messages.forEach(function (message) {
7 | output += 'Problem on line ' + (message.line || 0) + '\n';
8 | });
9 | });
10 |
11 | return output;
12 | };
13 |
--------------------------------------------------------------------------------
/tests/sass/no-at-rule-vendor-prefix.sass:
--------------------------------------------------------------------------------
1 | @-webkit-keyframes test
2 | 0%
3 | top: 0
4 |
5 | @-ms-viewport
6 | orientation: landscape
7 |
8 | @-non-standard
9 | orientation: landscape
10 |
11 | @-non-standard-2
12 | orientation: landscape
13 |
14 | @keyframes test2
15 | 0%
16 | top: 0
17 |
18 | @viewport
19 | orientation: landscape
20 |
--------------------------------------------------------------------------------
/tests/sass/zero-unit.scss:
--------------------------------------------------------------------------------
1 | .baz {
2 | border-right-width: 0px;
3 | }
4 |
5 | .foo {
6 | margin: 0px;
7 | padding: 0;
8 | }
9 |
10 | .bar {
11 | padding: 5px 0 0px;
12 | }
13 |
14 | $foo: 0px;
15 | $bar: '0px';
16 |
17 | .foo {
18 | @if $bar == 0 {
19 | content: 'bar';
20 | }
21 |
22 | @if $foo == '0px' {
23 | content: 'foo';
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/tests/sass/no-value-vendor-prefix.scss:
--------------------------------------------------------------------------------
1 | .foo { display: -webkit-flex; }
2 | .bar { max-width: -moz-max-content; }
3 | .baz { background: -webkit-linear-gradient(bottom, #000, #fff); }
4 | .non-standard {display: -webkit-non-standard}
5 | .var {display: $-webkit-var}
6 |
7 | .foo { display: flex; }
8 | .bar { max-width: max-content; }
9 | .baz { background: linear-gradient(bottom, #000, #fff); }
10 |
--------------------------------------------------------------------------------
/docs/options/cache-config.md:
--------------------------------------------------------------------------------
1 | # Cache Config
2 |
3 | Option `cache-config` will tell Sass Lint to cache the current configuration for each invocation of sass-lint. This option is disabled by default but you may consider enabling it if you're not planning on modifying your `.sass-lint.yml` config file as there will be a small performance gain.
4 |
5 | ## Options
6 |
7 | * `true`/`false` (defaults to `false`)
8 |
--------------------------------------------------------------------------------
/tests/sass/ruleToggler-guarantee-order.sass:
--------------------------------------------------------------------------------
1 | p
2 | // sass-lint:disable a
3 | border: 0
4 | // sass-lint:disable-block a
5 | font-size: 100%
6 |
7 | a
8 | // sass-lint:disable a
9 | border: 0
10 | // sass-lint:disable-block a
11 | font-size: 100%
12 |
13 | li
14 | /* sass-lint:disable a
15 | /* sass-lint:disable a
16 | border: 0
17 | font-size: 100%
18 |
--------------------------------------------------------------------------------
/tests/sass/ruleToggler-guarantee-order.scss:
--------------------------------------------------------------------------------
1 | p {
2 | // sass-lint:disable a
3 | border: 0;
4 | // sass-lint:disable-block a
5 | font-size: 100%;
6 | }
7 |
8 | a { // sass-lint:disable a
9 | border: 0;
10 | // sass-lint:disable-block a
11 | font-size: 100%;
12 | }
13 |
14 | li { /* sass-lint:disable a */ /* sass-lint:disable a */
15 | border: 0;
16 | font-size: 100%;
17 | }
18 |
--------------------------------------------------------------------------------
/docs/rules/no-trailing-whitespace.md:
--------------------------------------------------------------------------------
1 | # No Trailing Whitespace
2 |
3 | Rule `no-trailing-whitespace` will enforce that trailing whitespace is not allowed.
4 |
5 | ## Examples
6 |
7 | When enabled, the following are disallowed (\s denotes spaces or tabs):
8 |
9 | ```scss
10 | .foo {\s
11 | margin: 1.5rem;
12 | }
13 |
14 | .foo {
15 | margin: .5rem;\s
16 | }
17 |
18 | .foo {
19 | margin: .4rem;
20 | }\s
21 | ```
22 |
--------------------------------------------------------------------------------
/docs/rules/no-trailing-zero.md:
--------------------------------------------------------------------------------
1 | # No Trailing Zero
2 |
3 | Rule `no-trailing-zero` will enforce that trailing zeros are not allowed.
4 |
5 | ## Examples
6 |
7 | When enabled, the following are disallowed:
8 |
9 | ```scss
10 | .foo {
11 | margin: 1.500rem;
12 | }
13 |
14 | .foo {
15 | margin: .500rem;
16 | }
17 |
18 | .foo {
19 | margin: 0.2500rem;
20 | }
21 |
22 | .foo {
23 | margin: 4.0rem;
24 | }
25 | ```
26 |
--------------------------------------------------------------------------------
/lib/format/formatters/html-template-message.html:
--------------------------------------------------------------------------------
1 |
2 | | <%= lineNumber %>:<%= columnNumber %> |
3 | <%= severityName %> |
4 | <%- message %> |
5 |
6 | <%= ruleId %>
7 | |
8 |
9 |
--------------------------------------------------------------------------------
/tests/sass/border-zero.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | border: 0;
3 | }
4 |
5 | .bar {
6 | border: none;
7 | }
8 |
9 | .baz {
10 | border-right: 0;
11 | }
12 |
13 | .qux {
14 | border-left: none;
15 | }
16 |
17 | .fail {
18 | border-top: none;
19 | }
20 |
21 | .norf {
22 | border: 1px;
23 | }
24 |
25 | .norf {
26 | // sass-lint:disable border-zero
27 | border: none;
28 | // sass-lint:enable border-zero
29 | }
30 |
--------------------------------------------------------------------------------
/docs/rules/no-combinators.md:
--------------------------------------------------------------------------------
1 | # No Combinators
2 |
3 | Rule `no-combinators` will warn against the use of combinators.
4 |
5 | ## Examples
6 |
7 | When enabled, the following are disallowed:
8 |
9 | ```scss
10 | .foo > .bar {
11 | content: 'foo';
12 | }
13 |
14 | .foo ~ .bar {
15 | content: 'bar';
16 | }
17 |
18 | .foo + .bar {
19 | content: 'baz';
20 | }
21 |
22 | .foo .bar {
23 | content: 'qux';
24 | }
25 | ```
26 |
--------------------------------------------------------------------------------
/tests/sass/no-at-rule-vendor-prefix.scss:
--------------------------------------------------------------------------------
1 | @-webkit-keyframes test {
2 | 0% {
3 | top: 0;
4 | }
5 | }
6 |
7 | @-ms-viewport {
8 | orientation: landscape;
9 | }
10 |
11 | @-non-standard {
12 | orientation: landscape;
13 | }
14 |
15 | @-non-standard-2 {
16 | orientation: landscape;
17 | }
18 |
19 | @keyframes test2 {
20 | 0% {
21 | top: 0;
22 | }
23 | }
24 |
25 | @viewport {
26 | orientation: landscape;
27 | }
28 |
--------------------------------------------------------------------------------
/docs/rules/single-line-per-selector.md:
--------------------------------------------------------------------------------
1 | # Single Line Per Selector
2 |
3 | Rule `single-line-per-selector` will enforce whether selectors should be placed on a new line.
4 |
5 | ## Examples
6 |
7 | When enabled, the following are allowed:
8 |
9 | ```scss
10 | .foo,
11 | .bar {
12 | content: 'baz';
13 | }
14 | ```
15 |
16 | When enabled, the following are disallowed:
17 |
18 | ```scss
19 | .foo, .bar {
20 | content: 'baz';
21 | }
22 | ```
23 |
--------------------------------------------------------------------------------
/tests/sass/property-units.sass:
--------------------------------------------------------------------------------
1 | .literal
2 | height: 3em
3 |
4 | .literal-property
5 | width: 3px
6 |
7 | .box-shadow
8 | box-shadow: 1em 1em black, 1em 1em black
9 |
10 | .background
11 | background: 1em solid white
12 |
13 | .function
14 | color: test(2em)
15 |
16 | // using literals as property names
17 | $sizes: 2em
18 |
19 | .literal-property
20 | width: 3px
21 | height: 0
22 | .red
23 | width: 4
24 | height: 5px
25 |
--------------------------------------------------------------------------------
/tests/sass/no-disallowed-properties.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | z-index: 10
3 | display: block
4 | .bar
5 | .baz
6 | z-index: 20
7 |
8 | .test
9 | @media (max-width: 100px)
10 | z-index: 10
11 |
12 | =test ($level)
13 | z-index: $level
14 | display: block
15 |
16 | @function myFunc($level)
17 | @return $level * 2
18 |
19 | .func-res
20 | z-index: myFunc(10)
21 | display: block
22 |
23 | interp
24 | z-index: #{20}
25 | display: block
26 |
--------------------------------------------------------------------------------
/tests/sass/no-value-vendor-prefix.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | display: -webkit-flex
3 |
4 | .bar
5 | max-width: -moz-max-content
6 |
7 | .baz
8 | background: -webkit-linear-gradient(bottom, #000, #fff)
9 |
10 | .non-standard
11 | border: 1px solid -webkit-non-standard
12 |
13 | .var
14 | display: $-webkit-var
15 |
16 | .foo
17 | display: flex
18 |
19 | .bar
20 | max-width: max-content
21 |
22 | .baz
23 | background: linear-gradient(bottom, #000, #fff)
24 |
--------------------------------------------------------------------------------
/tests/sass/space-after-colon.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | content: 'foo';
3 | }
4 |
5 | .bar {
6 | content:'bar';
7 | }
8 |
9 | .baz {
10 | @media (max-width: 50em) and (orientation:landscape) {
11 | content: 'baz';
12 | }
13 | }
14 |
15 | $qux: 'qux';
16 | $norf:'norf';
17 |
18 | .foo {
19 | @at-root button#{&}:hover {
20 | }
21 | }
22 |
23 | .foo:hover {
24 | @include test;
25 | }
26 |
27 | $map: {
28 | test:'red',
29 | other: blue,
30 | }
31 |
--------------------------------------------------------------------------------
/tests/sass/no-disallowed-property-values.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | z-index: 10
3 | display: block
4 | .bar
5 | .baz
6 | z-index: 20
7 |
8 | .test
9 | @media (max-width: 100px)
10 | z-index: 10
11 |
12 | =test ($level)
13 | z-index: $level
14 | display: block
15 |
16 | @function myFunc($level)
17 | @return $level * 2
18 |
19 | .func-res
20 | z-index: myFunc(10)
21 | display: block
22 |
23 | interp
24 | z-index: #{20}
25 | display: inline
26 |
--------------------------------------------------------------------------------
/tests/sass/no-trailing-whitespace.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | margin: 1.5rem
3 |
4 | // Two trailing spaces after selector
5 | .bar
6 | margin: 1.5rem
7 |
8 | // Two trailing spaces after property
9 | .baz
10 | margin: 1.5rem
11 |
12 | // Two trailing spaces between rules
13 | .qux
14 | margin: 1.5rem
15 |
16 |
17 | // Trailing tab after selector
18 | .cat
19 | margin: 1.5rem
20 |
21 | // Trailing tab after property
22 | .dog
23 | margin: 1.5rem
24 |
25 |
--------------------------------------------------------------------------------
/docs/rules/extends-before-mixins.md:
--------------------------------------------------------------------------------
1 | # Extends Before Mixins
2 |
3 | Rule `extends-before-mixins` will enforce that extends should be written before mixins in a ruleset.
4 |
5 | ## Examples
6 |
7 | When enabled, the following are allowed.:
8 |
9 | ```scss
10 | .foo {
11 | @extend %bar;
12 | @include baz;
13 | }
14 | ```
15 |
16 | When enabled, the following are disallowed:
17 |
18 | ```scss
19 | .foo {
20 | @include baz;
21 | @extend %bar;
22 | }
23 | ```
24 |
--------------------------------------------------------------------------------
/docs/rules/no-color-keywords.md:
--------------------------------------------------------------------------------
1 | # Color Keyword
2 |
3 | Rule `no-color-keywords` will enforce the use of hexadecimal color values rather than literals.
4 |
5 | ## Examples
6 |
7 | When enabled the following are allowed:
8 |
9 | ```scss
10 | $new-red: #ff0000;
11 |
12 | .foo {
13 | color: #ff0000;
14 | }
15 |
16 | ```
17 |
18 | When enabled the following are disallowed:
19 |
20 | ```scss
21 | $new-red: red;
22 |
23 | .foo {
24 | color: red;
25 | }
26 | ```
27 |
--------------------------------------------------------------------------------
/docs/rules/placeholder-in-extend.md:
--------------------------------------------------------------------------------
1 | # Placeholder in Extend
2 |
3 | Rule `placeholder-in-extend` will enforce whether extends should only include placeholder selectors.
4 |
5 | ## Examples
6 |
7 | When enabled, the following are allowed:
8 |
9 | ```scss
10 | .foo {
11 | @extend %bar;
12 | @extend .baz%qux;
13 | }
14 | ```
15 |
16 | When enabled, the following are disallowed:
17 |
18 | ```scss
19 | .foo {
20 | @extend .bar;
21 | @extend #baz;
22 | }
23 | ```
24 |
--------------------------------------------------------------------------------
/tests/sass/nesting-depth.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | padding: 5
3 |
4 | .bar
5 | content: 'baz'
6 |
7 | .qux,
8 | .fail
9 | content: 'bob'
10 |
11 | &:hover,
12 | &:active
13 | content: 'fail'
14 |
15 | .bar
16 | content: 'fail'
17 |
18 | .bar
19 | content: 'fail'
20 |
21 | .block
22 | content: 'bar'
23 |
24 | &__element
25 | content: 'bar'
26 |
27 |
28 | &--modifier
29 | content: 'bar'
30 |
--------------------------------------------------------------------------------
/tests/helpers/helpers.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var assert = require('assert'),
4 | helpers = require('../../lib/helpers');
5 |
6 | describe('helpers', function () {
7 | //////////////////////////////
8 | // Helpers is loaded
9 | //////////////////////////////
10 |
11 | it('helpers should not be undefined', function (done) {
12 |
13 | var loaded = typeof (helpers) === 'object' ? true : false;
14 |
15 | assert.equal(true, loaded);
16 | done();
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/docs/rules/extends-before-declarations.md:
--------------------------------------------------------------------------------
1 | # Extends Before Declarations
2 |
3 | Rule `extends-before-declarations` will enforce that extends should be written before declarations in a ruleset.
4 |
5 | ## Examples
6 |
7 | When enabled, the following are allowed:
8 |
9 | ```scss
10 | .foo {
11 | @extend %bar;
12 | content: 'baz';
13 | }
14 | ```
15 |
16 | When enabled, the following are disallowed:
17 |
18 | ```scss
19 | .foo {
20 | content: 'baz';
21 | @extend %bar;
22 | }
23 | ```
24 |
--------------------------------------------------------------------------------
/tests/sass/no-trailing-zero.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | margin: 1.5rem
3 |
4 |
5 | .foo
6 | margin: 1.500rem
7 |
8 |
9 | .foo
10 | margin: .5rem
11 |
12 |
13 | .foo
14 | margin: .500rem
15 |
16 |
17 | .foo
18 | margin: 0.25rem
19 |
20 |
21 | .foo
22 | margin: 0.2500rem
23 |
24 |
25 | .foo
26 | margin: 5.0rem
27 |
28 | .foo
29 | margin: 5.00rem
30 |
31 | .foo
32 | margin: .000rem
33 |
34 | .foo
35 | margin: 0.0rem
36 |
37 | .foo
38 | margin: .0rem
39 |
40 | .foo
41 | margin: 0
42 |
--------------------------------------------------------------------------------
/docs/rules/no-transition-all.md:
--------------------------------------------------------------------------------
1 | # No Transition All
2 |
3 | Rule `no-transition-all` will enforce whether the keyword `all` can be used with the `transition` or `transition-property` property.
4 |
5 | ## Examples
6 |
7 | When enabled the following are disallowed
8 |
9 | ```scss
10 | .foo {
11 | transition: all 2s;
12 | }
13 |
14 | .bar {
15 | transition-property: all 2s;
16 | }
17 |
18 | .quz {
19 | -webkit-transition: all 2s, height 2s, background-color 2s, -webkit-transform 2s;
20 | }
21 | ```
22 |
--------------------------------------------------------------------------------
/docs/rules/one-declaration-per-line.md:
--------------------------------------------------------------------------------
1 | # One Declaration Per Line
2 |
3 | Rule `one-declaration-per-line` will enforce that new declarations must begin on new lines.
4 |
5 | ## Examples
6 |
7 | When enabled, the following are allowed:
8 |
9 | ```scss
10 | .foo {
11 | content: 'baz';
12 | content: 'qux';
13 | }
14 | ```
15 |
16 | When enabled, the following are disallowed:
17 |
18 | ```scss
19 | .foo {content: 'baz', content: 'qux'};
20 |
21 | .foo {
22 | content: 'baz'; content: 'qux';
23 | }
24 | ```
25 |
--------------------------------------------------------------------------------
/tests/sass/no-trailing-whitespace.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | margin: 1.5rem;
3 | }
4 |
5 | // Two trailing spaces after selector
6 | .bar {
7 | margin: 1.5rem;
8 | }
9 |
10 | // Two trailing spaces after property
11 | .baz {
12 | margin: 1.5rem;
13 | }
14 |
15 | // Two trailing spaces after rule
16 | .qux {
17 | margin: 1.5rem;
18 | }
19 |
20 | // Trailing tab after selector
21 | .cat {
22 | margin: 1.5rem;
23 | }
24 |
25 | // Trailing tab after property
26 | .dog {
27 | margin: 1.5rem;
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 |
8 | [*]
9 |
10 | # Change these settings to your own preference
11 | indent_style = space
12 | indent_size = 2
13 |
14 | # We recommend you to keep these unchanged
15 | end_of_line = lf
16 | charset = utf-8
17 | trim_trailing_whitespace = true
18 | insert_final_newline = true
19 |
20 | [*.md]
21 | trim_trailing_whitespace = false
22 |
--------------------------------------------------------------------------------
/tests/sass/extends-before-declarations.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | @extend %waldo
3 | content: 'baz'
4 |
5 |
6 | .bar
7 | content: 'baz'
8 | @extend %waldo
9 |
10 |
11 | .qux
12 | content: 'baz'
13 | @extend %waldo
14 | content: 'where'
15 |
16 |
17 | .breakpoint
18 | content: 'baz'
19 | @extend %foo
20 |
21 | .foo
22 | content: 'where'
23 |
24 | @extend %waldo
25 |
26 |
27 | .bar
28 | @extend %waldo
29 | content: 'where'
30 |
31 |
32 | .foo-noextend
33 | +foo
34 | content: "bar"
35 |
--------------------------------------------------------------------------------
/docs/rules/bem-depth.md:
--------------------------------------------------------------------------------
1 | # BEM Depth
2 |
3 | Rule `bem-depth` will enforce how many elements a BEM selector can contain.
4 |
5 | ## Options
6 |
7 | * `max-depth`: number (defaults to `1`)
8 |
9 | ## Examples
10 |
11 | When enabled (assuming `max-depth: 1`) the following are disallowed:
12 |
13 | ```scss
14 |
15 | .block {
16 | &__element {
17 | &__subelement {
18 | // two elements
19 | }
20 | }
21 | }
22 |
23 | .block__element__subelement__subelement-two {
24 | // three elements
25 | }
26 | ```
27 |
--------------------------------------------------------------------------------
/docs/rules/no-universal-selectors.md:
--------------------------------------------------------------------------------
1 | # No Universal Selectors
2 |
3 | Rule `no-universal-selectors` will warn against the use of `*` (universal) selectors.
4 |
5 | ## Examples
6 |
7 | When enabled, the following are disallowed:
8 |
9 | ```scss
10 | * {
11 | content: 'foo';
12 | }
13 |
14 | * [lang^=en] {
15 | content: 'bar';
16 | }
17 |
18 | *.warning {
19 | content: 'baz';
20 | }
21 |
22 | *#maincontent {
23 | content: 'qux';
24 | }
25 |
26 | *:before,
27 | *:after {
28 | content: 'norf';
29 | }
30 | ```
31 |
--------------------------------------------------------------------------------
/tests/rules/no-empty-rulesets.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('no empty rulesets - scss', function () {
9 | var file = lint.file('no-empty-rulesets.scss');
10 |
11 | it('enforce', function (done) {
12 | lint.test(file, {
13 | 'no-empty-rulesets': 1
14 | }, function (data) {
15 | lint.assert.equal(4, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/tests/sass/declarations-before-nesting.sass:
--------------------------------------------------------------------------------
1 | .bar
2 | content: 'baz'
3 |
4 | .qux
5 | content: 'baz'
6 |
7 | .foo
8 | .bar
9 | content: 'where'
10 |
11 | content: 'baz'
12 |
13 | .baz
14 | content: 'where'
15 |
16 | content: 'baz'
17 |
18 | .foo
19 | .bar
20 | content: 'where'
21 |
22 | .baz
23 | content: 'quz'
24 |
25 | content: 'baz'
26 |
27 | content: 'baz'
28 |
29 | // issue #935 - ignore variables
30 | +foo
31 | #{$bar}
32 | content: 'foobar'
33 |
34 | $baz: 'qux'
35 |
--------------------------------------------------------------------------------
/tests/sass/force-attribute-nesting.sass:
--------------------------------------------------------------------------------
1 | // attribute should be nested
2 | input[type='text']
3 | border: 0
4 |
5 | // attribute should be nested
6 | input[type='radio']
7 | color: red
8 |
9 | // attribute should be nested
10 | a[target='_blank']
11 | content: ''
12 |
13 | input
14 | &[type='text']
15 | content: ''
16 |
17 | form
18 | // attribute should be nested
19 | input[type='text']
20 | padding: 0
21 |
22 | .form
23 | // attribute should be nested
24 | .class input[type='text']
25 | padding: 0
26 |
--------------------------------------------------------------------------------
/tests/sass/no-qualifying-elements.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | content: 'foo'
3 |
4 |
5 | div.foo
6 | content: 'foo'
7 |
8 |
9 | ul#foo
10 | content: 'foo'
11 |
12 |
13 | input[type='email']
14 | content: 'foo'
15 |
16 |
17 | .foo.bar
18 | content: 'foo'
19 |
20 |
21 | .foo .bar
22 | content: 'foo'
23 |
24 |
25 | .foo
26 | .bar
27 | content: 'foo'
28 |
29 |
30 |
31 | ul
32 | .foo
33 | content: 'foo'
34 |
35 |
36 |
37 | .foo[type='text']
38 | content: 'foo'
39 |
40 |
41 | #foo[type='email']
42 | content: 'foo'
43 |
--------------------------------------------------------------------------------
/tests/sass/empty-args.sass:
--------------------------------------------------------------------------------
1 | // No arguments with parenthesis
2 | =foo()
3 | color: red
4 |
5 |
6 | .foo
7 | +foo()
8 |
9 |
10 |
11 |
12 | // No arguments with no parenthesis
13 | =bar
14 | color: orange
15 |
16 |
17 | .bar
18 | +bar
19 |
20 |
21 |
22 |
23 | // Arguments with parenthesis
24 | =baz($color)
25 | color: $color
26 |
27 |
28 | $foo: blue
29 |
30 | .baz
31 | +baz($foo)
32 |
33 |
34 |
35 |
36 | // Parenthesis only where required
37 | =qux($color: lime)
38 | color: $color
39 |
40 |
41 | .qux
42 | +qux
43 |
--------------------------------------------------------------------------------
/docs/rules/url-quotes.md:
--------------------------------------------------------------------------------
1 | # URL Quotes
2 |
3 | Rule `url-quotes` will enforce that URLs are wrapped in quotes.
4 |
5 | ## Examples
6 |
7 | When enabled, the following are allowed:
8 |
9 | ```scss
10 | .foo {
11 | background-image: url('foo.png');
12 | }
13 |
14 | .qux {
15 | background-image: url('bar/' + $foo);
16 | }
17 |
18 | ```
19 |
20 | When enabled, the following are disallowed:
21 |
22 | ```scss
23 | .bar {
24 | background-image: url(foo.png);
25 | }
26 |
27 | .norf {
28 | background-image: url(bar/ + $foo);
29 | }
30 |
31 | ```
32 |
--------------------------------------------------------------------------------
/data/pseudoClasses.yml:
--------------------------------------------------------------------------------
1 | active
2 | any
3 | checked
4 | default
5 | dir
6 | disabled
7 | empty
8 | enabled
9 | first
10 | first-child
11 | first-of-type
12 | fullscreen
13 | focus
14 | hover
15 | indeterminate
16 | in-range
17 | invalid
18 | lang
19 | last-child
20 | last-of-type
21 | left
22 | link
23 | not
24 | nth-child
25 | nth-last-child
26 | nth-last-of-type
27 | nth-of-type
28 | only-child
29 | only-of-type
30 | optional
31 | out-of-range
32 | read-only
33 | read-write
34 | required
35 | right
36 | root
37 | scope
38 | target
39 | valid
40 | visited
41 |
--------------------------------------------------------------------------------
/tests/rules/one-declaration-per-line.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('one declaration per line - scss', function () {
9 | var file = lint.file('one-declaration-per-line.scss');
10 |
11 | it('enforce', function (done) {
12 | lint.test(file, {
13 | 'one-declaration-per-line': 1
14 | }, function (data) {
15 | lint.assert.equal(2, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/tests/sass/extends-before-declarations.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | @extend %waldo;
3 | content: 'baz';
4 | }
5 |
6 | .bar {
7 | content: 'baz';
8 | @extend %waldo;
9 | }
10 |
11 | .qux {
12 | content: 'baz';
13 | @extend %waldo;
14 | content: 'where';
15 | }
16 |
17 | .breakpoint {
18 | content: 'baz';
19 | @extend %foo;
20 |
21 | .foo {
22 | content: 'where';
23 |
24 | @extend %waldo;
25 | }
26 |
27 | .bar {
28 | @extend %waldo;
29 | content: 'where';
30 | }
31 | }
32 |
33 | .foo-noextend {
34 | @include foo;
35 | }
36 |
--------------------------------------------------------------------------------
/tests/sass/one-declaration-per-line.scss:
--------------------------------------------------------------------------------
1 | // Should cause issue
2 | .foo {
3 | content: 'baz'; content: 'qux';
4 | }
5 |
6 | .bar { color: red; content: 'bar'; }
7 |
8 | // Should be ok
9 | .foo {
10 | content: 'bar';
11 | }
12 |
13 | $foo: adjust-color(rgb(255, 0, 0), $lightness: -20%);
14 |
15 | .bar {
16 | color: adjust-color(rgb(255, 0, 0), $blue: 5);
17 | }
18 |
19 | .baz {
20 | color: scale-color(hsl(120, 70%, 80%), $lightness: 50%);
21 | }
22 |
23 | .qux {
24 | color: change-color(hsl(25, 100%, 80%), $lightness: 40%, $alpha: .8);
25 | }
26 |
--------------------------------------------------------------------------------
/docs/rules/declarations-before-nesting.md:
--------------------------------------------------------------------------------
1 | # Declarations Before Nesting
2 |
3 | Rule `declarations-before-nesting` will enforce that declarations should be written before nesting in a ruleset.
4 |
5 | ## Examples
6 |
7 | When enabled, the following are allowed:
8 |
9 | ```scss
10 | .foo {
11 | content: 'baz';
12 |
13 | .bar {
14 | content: 'qux';
15 | }
16 | }
17 | ```
18 |
19 | When enabled, the following are disallowed:
20 |
21 | ```scss
22 | .foo {
23 | .bar {
24 | content: 'qux';
25 | }
26 |
27 | content: 'baz';
28 | }
29 | ```
30 |
--------------------------------------------------------------------------------
/tests/sass/no-url-domains.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | background-image: url('https://foo.com/img/bar.png')
3 |
4 |
5 | .foo
6 | background-image: url('http://foo.com/img/bar.png')
7 |
8 |
9 | .foo
10 | background-image: url('//foo.com/img/bar.png')
11 |
12 |
13 | .foo
14 | background-image: url('/img/bar.png')
15 |
16 |
17 | .foo
18 | background-image: url('img/bar.png')
19 |
20 |
21 | .foo
22 | background-image: url('bar.png')
23 |
24 | .foo
25 | background-image: url('data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7')
26 |
--------------------------------------------------------------------------------
/tests/sass/no-url-protocols.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | background-image: url('https://foo.com/img/bar.png')
3 |
4 |
5 | .foo
6 | background-image: url('http://foo.com/img/bar.png')
7 |
8 |
9 | .foo
10 | background-image: url('//foo.com/img/bar.png')
11 |
12 |
13 | .foo
14 | background-image: url('/img/bar.png')
15 |
16 |
17 | .foo
18 | background-image: url('img/bar.png')
19 |
20 |
21 | .foo
22 | background-image: url('bar.png')
23 |
24 | .foo
25 | background-image: url('data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7')
26 |
--------------------------------------------------------------------------------
/tests/sass/no-disallowed-properties.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | z-index: 10;
3 | display: block;
4 |
5 | .bar {
6 | .baz {
7 | z-index: 20;
8 | }
9 | }
10 | }
11 |
12 | .test {
13 | @media (max-width: 100px) {
14 | z-index: 10;
15 | }
16 | }
17 |
18 | @mixin test ($level) {
19 | z-index: $level;
20 | display: block;
21 | }
22 |
23 |
24 | @function myFunc($level) {
25 | @return $level * 2;
26 | }
27 |
28 | .func-res {
29 | z-index: myFunc(10);
30 | display: block;
31 | }
32 |
33 | interp {
34 | z-index: #{20};
35 | display: block;
36 | }
37 |
--------------------------------------------------------------------------------
/docs/rules/max-file-line-count.md:
--------------------------------------------------------------------------------
1 | # Max File Line Count
2 |
3 | Rule `max-file-line-count` will enforce that a file's length doesn't exceed a certain number of lines
4 |
5 | ## Options
6 |
7 | * `length`: `number`, (defaults to 300)
8 |
9 | ## Examples
10 |
11 | When enabled, the following are disallowed:
12 |
13 | ```scss
14 | /*
15 | * line count is represented along the
16 | * left hand side of the following example
17 | */
18 | 1| .test {
19 | 2| color: red
20 | 3| }
21 | =====
22 | ~ snip ~
23 | =====
24 | 299| .bar {
25 | 300| color: blue;
26 | 301| }
27 | ```
28 |
--------------------------------------------------------------------------------
/docs/rules/no-color-hex.md:
--------------------------------------------------------------------------------
1 | # No Color Hex
2 |
3 | Rule `no-color-hex` will disallow the use of hexadecimal colors
4 |
5 | ## Examples
6 |
7 | When enabled the following are disallowed.
8 |
9 | ```scss
10 | $foo-color: #456;
11 |
12 | .bar {
13 | background: linear-gradient(top, #3ff, #ddd);
14 | }
15 |
16 | .baz {
17 | color: #fff;
18 | }
19 | ```
20 |
21 | When enabled the following are allowed:
22 |
23 | ```scss
24 | $foo-color: red;
25 |
26 | .bar {
27 | background: linear-gradient(top, blue, green);
28 | }
29 |
30 | .baz {
31 | color: white;
32 | }
33 | ```
34 |
--------------------------------------------------------------------------------
/lib/format/formatters/json.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview JSON reporter
3 | * @author Burak Yigit Kaya aka BYK
4 | *
5 | * Updated for use with sass-lint under MIT licence
6 | * @license https://github.com/sasstools/sass-lint/blob/master/lib/format/LICENSE
7 | */
8 |
9 | 'use strict';
10 |
11 | //------------------------------------------------------------------------------
12 | // Public Interface
13 | //------------------------------------------------------------------------------
14 |
15 | module.exports = function (results) {
16 | return JSON.stringify(results);
17 | };
18 |
--------------------------------------------------------------------------------
/tests/sass/no-disallowed-property-values.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | z-index: 10;
3 | display: block;
4 |
5 | .bar {
6 | .baz {
7 | z-index: 20;
8 | }
9 | }
10 | }
11 |
12 | .test {
13 | @media (max-width: 100px) {
14 | z-index: 10;
15 | }
16 | }
17 |
18 | @mixin test ($level) {
19 | z-index: $level;
20 | display: block;
21 | }
22 |
23 |
24 | @function myFunc($level) {
25 | @return $level * 2;
26 | }
27 |
28 | .func-res {
29 | z-index: myFunc(10);
30 | display: block;
31 | }
32 |
33 | interp {
34 | z-index: #{20};
35 | display: inline;
36 | }
37 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | Sass is more than a technology; Sass is driven by the community of individuals
2 | that power its development and use every day. As a community, we want to embrace
3 | the very differences that have made our collaboration so powerful, and work
4 | together to provide the best environment for learning, growing, and sharing of
5 | ideas. It is imperative that we keep Sass a fun, welcoming, challenging, and
6 | fair place to play.
7 |
8 | [The full community guidelines can be found on the Sass website.][link]
9 |
10 | [link]: http://sass-lang.com/community-guidelines
11 |
--------------------------------------------------------------------------------
/tests/sass/no-color-hex.sass:
--------------------------------------------------------------------------------
1 | $foo-color: #123
2 |
3 | .foo
4 | background: linear-gradient(top, #cc2, #44d)
5 | color: #fff
6 |
7 |
8 | $bar-color: #112233
9 |
10 | .bar
11 | background: linear-gradient(top, #cccc22, #4444dd)
12 | color: #ffffff
13 |
14 | .baz
15 | border-color: #123456
16 |
17 |
18 | // color literals, rgb and hsl values currently don't get returned
19 | // by the AST's color type
20 |
21 | $qux-color: red
22 | $rgb-color: rgb(255, 255, 255)
23 | $rgba-color: rgba(0, 0, 0, .1)
24 | $hsl-color: hsl(40, 50%, 50%)
25 | $hsla-color: hsla(40, 50%, 50%, .3)
26 |
--------------------------------------------------------------------------------
/tests/sass/no-trailing-zero.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | margin: 1.5rem;
3 | }
4 |
5 | .foo {
6 | margin: 1.500rem;
7 | }
8 |
9 | .foo {
10 | margin: .5rem;
11 | }
12 |
13 | .foo {
14 | margin: .500rem;
15 | }
16 |
17 | .foo {
18 | margin: 0.25rem;
19 | }
20 |
21 | .foo {
22 | margin: 0.2500rem;
23 | }
24 |
25 | .foo {
26 | margin: 5.0rem;
27 | }
28 |
29 | .foo {
30 | margin: 5.00rem;
31 | }
32 |
33 | .foo {
34 | margin: .000rem;
35 | }
36 |
37 | .foo {
38 | margin: 0.0rem;
39 | }
40 |
41 | .foo {
42 | margin: .0rem;
43 | }
44 |
45 | .foo {
46 | margin: 0;
47 | }
48 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - '6'
4 | - '9'
5 | - 'stable'
6 | cache:
7 | directories:
8 | - node_modules
9 | install:
10 | - npm install
11 | script:
12 | - npm test
13 | after_script:
14 | - npm run coverage
15 | jobs:
16 | include:
17 | - stage: deploy
18 | node_js: stable
19 | script: "npm run semantic-release"
20 | notifications:
21 | slack:
22 | secure: RrEbq2xE1hWdog4AckkaKDnIYYwo5VdjPcFNhRJbn/7KI0fKeZVCKZy1Ww7aaJGth7R7UX415sEV1U6RrjFyhnBb6Sh+rh8fKTvcvuTbENZW45SbtUD+xmgOvb2kfk4PzgD5Q457DpchAZD7W+E+9qr3xI3Uvh4II1uhDmSKiLI=
23 |
--------------------------------------------------------------------------------
/tests/sass/nesting-depth.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | padding: 5;
3 |
4 | .bar {
5 | content: 'baz';
6 |
7 | .qux,
8 | .fail {
9 | content: 'bob';
10 |
11 | &:hover,
12 | &:active {
13 | content: 'fail';
14 |
15 | .bar {
16 | content: 'fail';
17 | }
18 | }
19 |
20 | .bar {
21 | content: 'fail';
22 | }
23 | }
24 | }
25 | }
26 |
27 | .block {
28 | content: 'bar';
29 |
30 | &__element {
31 | content: 'bar';
32 |
33 |
34 | &--modifier {
35 | content: 'bar';
36 |
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/tests/sass/no-qualifying-elements.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | content: 'foo';
3 | }
4 |
5 | div.foo {
6 | content: 'foo';
7 | }
8 |
9 | ul#foo {
10 | content: 'foo';
11 | }
12 |
13 | input[type='email'] {
14 | content: 'foo';
15 | }
16 |
17 | .foo.bar {
18 | content: 'foo';
19 | }
20 |
21 | .foo .bar {
22 | content: 'foo';
23 | }
24 |
25 | .foo {
26 | .bar {
27 | content: 'foo';
28 | }
29 | }
30 |
31 | ul {
32 | .foo {
33 | content: 'foo';
34 | }
35 | }
36 |
37 | .foo[type='text'] {
38 | content: 'foo';
39 | }
40 |
41 | #foo[type='email'] {
42 | content: 'foo';
43 | }
44 |
--------------------------------------------------------------------------------
/lib/rules/no-ids.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var helpers = require('../helpers');
4 |
5 | module.exports = {
6 | 'name': 'no-ids',
7 | 'defaults': {},
8 | 'detect': function (ast, parser) {
9 | var result = [];
10 |
11 | ast.traverseByType('id', function (id) {
12 | result = helpers.addUnique(result, {
13 | 'ruleId': parser.rule.name,
14 | 'line': id.start.line,
15 | 'column': id.start.column,
16 | 'message': 'ID selectors not allowed',
17 | 'severity': parser.severity
18 | });
19 | });
20 |
21 | return result;
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/tests/helpers/loadConfigFile.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var assert = require('assert'),
4 | helpers = require('../../lib/helpers');
5 |
6 | describe('helpers - loadConfigFile', function () {
7 |
8 | //////////////////////////////
9 | // loadConfigFile
10 | //////////////////////////////
11 |
12 | it('loadConfigFile', function (done) {
13 |
14 | var result = helpers.loadConfigFile('../../tests/testFile.txt'),
15 | expect = 'This is a test file that test\'s the loadConfigFile helper function.';
16 |
17 | assert.equal(expect, result);
18 | done();
19 | });
20 | });
21 |
--------------------------------------------------------------------------------
/tests/sass/bem-depth.sass:
--------------------------------------------------------------------------------
1 | .one
2 | color: red
3 | &__two
4 | color: blue
5 | &__three
6 | color: green
7 | &__two-again
8 | color: pink
9 |
10 | .one__two
11 | color: red
12 | &--modifier
13 | color: blue
14 | &__three
15 | color: green
16 | &--modifier__three
17 | color: white
18 |
19 | .block
20 | color: red
21 |
22 | .block__element-one
23 | color: red
24 |
25 | .block__element-one__element-two
26 | color: red
27 |
28 | %one__two
29 | color: red
30 |
31 | %one__two__three
32 | color: blue
33 |
34 | %one__two__three__four
35 | color: blue
36 |
--------------------------------------------------------------------------------
/tests/sass/no-url-domains.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | background-image: url('https://foo.com/img/bar.png');
3 | }
4 |
5 | .foo {
6 | background-image: url('http://foo.com/img/bar.png');
7 | }
8 |
9 | .foo {
10 | background-image: url('//foo.com/img/bar.png');
11 | }
12 |
13 | .foo {
14 | background-image: url('/img/bar.png');
15 | }
16 |
17 | .foo {
18 | background-image: url('img/bar.png');
19 | }
20 |
21 | .foo {
22 | background-image: url('bar.png');
23 | }
24 |
25 | .foo {
26 | background-image: url('data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7');
27 | }
28 |
--------------------------------------------------------------------------------
/tests/sass/no-url-protocols.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | background-image: url('https://foo.com/img/bar.png');
3 | }
4 |
5 | .foo {
6 | background-image: url('http://foo.com/img/bar.png');
7 | }
8 |
9 | .foo {
10 | background-image: url('//foo.com/img/bar.png');
11 | }
12 |
13 | .foo {
14 | background-image: url('/img/bar.png');
15 | }
16 |
17 | .foo {
18 | background-image: url('img/bar.png');
19 | }
20 |
21 | .foo {
22 | background-image: url('bar.png');
23 | }
24 |
25 | .foo {
26 | background-image: url('data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7');
27 | }
28 |
--------------------------------------------------------------------------------
/docs/rules/leading-zero.md:
--------------------------------------------------------------------------------
1 | # Leading Zero
2 |
3 | Rule `leading-zero` will enforce whether or not decimal numbers should include a leading zero.
4 |
5 | ## Options
6 |
7 | * `include`: `true`/`false` (defaults to `false`)
8 |
9 | ## Examples
10 |
11 | When `include: false`, the following are allowed. When `include: true`, the following are disallowed:
12 |
13 | ```scss
14 | .foo {
15 | font-size: .5em;
16 | }
17 | ```
18 |
19 | When `include: true`, the following are allowed. When `include: false`, the following are disallowed:
20 |
21 | ```scss
22 | .foo {
23 | font-size: 0.5em;
24 | }
25 | ```
26 |
--------------------------------------------------------------------------------
/docs/rules/pseudo-element.md:
--------------------------------------------------------------------------------
1 | # Pseudo-element
2 |
3 | Rule `pseudo-element` will enforce that:
4 |
5 | * Pseudo-**elements** must start with **double colons**.
6 | * Pseudo-**classes** must start with **single colon**.
7 |
8 | ## Examples
9 |
10 | When enabled, the following are allowed:
11 |
12 | ```scss
13 | .foo::before {
14 | content: "bar";
15 | }
16 |
17 | .foo:hover {
18 | content: "bar";
19 | }
20 | ```
21 |
22 | When enabled, the following are disallowed:
23 |
24 | ```scss
25 | .foo:before {
26 | content: "bar";
27 | }
28 |
29 | .foo::hover {
30 | content: "bar";
31 | }
32 | ```
33 |
--------------------------------------------------------------------------------
/tests/sass/trailing-semicolon.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | content: 'bar'
3 | }
4 |
5 | .bar {
6 | content: 'qux';;
7 | padding: 0
8 |
9 | .qux {
10 | float: left;;
11 | content: 'waldo'
12 | }
13 | }
14 |
15 | .qux {
16 | font: {
17 | family: 'Arial';
18 | weight: bold;
19 | size: 2rem;
20 | }
21 | }
22 |
23 | .baz {
24 | font: {
25 | family: 'Arial';;
26 | weight: bold;
27 | size: 2rem
28 | }
29 | }
30 |
31 | .norf {
32 | border: {
33 | top: {
34 | color: red;;
35 |
36 | left: {
37 | radius: 5px
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/docs/rules/quotes.md:
--------------------------------------------------------------------------------
1 | # Quotes
2 |
3 | Rule `quotes` will enforce whether single quotes (`''`) or double quotes (`""`) should be used for all strings.
4 |
5 | ## Options
6 |
7 | * `style`: `single`/`double` (defaults to `single`)
8 |
9 | ## Examples
10 |
11 | When `style: single`, the following are allowed. When `style: double`, the following are disallowed:
12 |
13 | ```scss
14 | .foo {
15 | content: 'bar';
16 | }
17 | ```
18 |
19 | When `style: double`, the following are allowed. When `style: single`, the following are disallowed:
20 |
21 | ```scss
22 | .foo {
23 | content: "bar";
24 | }
25 | ```
26 |
--------------------------------------------------------------------------------
/tests/sass/no-color-hex.scss:
--------------------------------------------------------------------------------
1 | $foo-color: #123;
2 |
3 | .foo {
4 | background: linear-gradient(top, #cc2, #44d);
5 | color: #fff;
6 | }
7 |
8 | $bar-color: #112233;
9 |
10 | .bar {
11 | background: linear-gradient(top, #cccc22, #4444dd);
12 | color: #ffffff;
13 | }
14 |
15 | .baz {
16 | border-color: #123456;
17 | }
18 |
19 | // color literals, rgb and hsl values currently don't get returned
20 | // by the AST's color type
21 |
22 | $qux-color: red;
23 | $rgb-color: rgb(255, 255, 255);
24 | $rgba-color: rgba(0, 0, 0, .1);
25 | $hsl-color: hsl(40, 50%, 50%);
26 | $hsla-color: hsla(40, 50%, 50%, .3);
27 |
--------------------------------------------------------------------------------
/tests/sass/property-units.scss:
--------------------------------------------------------------------------------
1 | .literal {
2 | height: 3em;
3 | }
4 |
5 | .literal-property {
6 | width: 3px;
7 | }
8 |
9 | .box-shadow {
10 | box-shadow: 1em 1em black, 1em 1em black;
11 | }
12 |
13 | .background {
14 | background: 1em solid white;
15 | }
16 |
17 | .function {
18 | color: test(2em);
19 | }
20 |
21 | // using literals as property names
22 | $sizes: (
23 | small: 2em,
24 | big : (
25 | important: 2rem
26 | )
27 | );
28 |
29 | .literal-property {
30 | width: 3px;
31 | height: 0;
32 |
33 | .red {
34 | width: 4;
35 | height: 5px;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/docs/rules/space-after-colon.md:
--------------------------------------------------------------------------------
1 | # Space After Colon
2 |
3 | Rule `space-after-colon` will enforce whether or not a space should be included after a colon (`:`).
4 |
5 | ## Options
6 |
7 | * `include`: `true`/`false` (defaults to `true`)
8 |
9 | ## Examples
10 |
11 | When `include: true`, the following are allowed. When `include: false`, the following are disallowed:
12 |
13 | ```scss
14 | .foo {
15 | content: 'bar';
16 | }
17 | ```
18 |
19 | When `include: false`, the following are allowed. When `include: true`, the following are disallowed:
20 |
21 | ```scss
22 | .foo {
23 | content:'bar';
24 | }
25 | ```
26 |
--------------------------------------------------------------------------------
/tests/sass/force-attribute-nesting.scss:
--------------------------------------------------------------------------------
1 | // attribute should be nested
2 | input[type='text'] {
3 | border: 0;
4 | }
5 |
6 | // attribute should be nested
7 | input[type='radio'] {
8 | color: red;
9 | }
10 |
11 | // attribute should be nested
12 | a[target='_blank'] {
13 | content: '';
14 | }
15 |
16 | input {
17 | &[type='text'] {
18 | content: '';
19 | }
20 | }
21 |
22 | form {
23 | // attribute should be nested
24 | input[type='text'] {
25 | padding: 0;
26 | }
27 | }
28 |
29 | .form {
30 | // attribute should be nested
31 | .class input[type='text'] {
32 | padding: 0;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/docs/rules/nesting-depth.md:
--------------------------------------------------------------------------------
1 | # Nesting Depth
2 |
3 | Rule `nesting-depth` will enforce how deeply a selector can be nested.
4 |
5 | ## Options
6 |
7 | * `max-depth`: number (defaults to `2`)
8 |
9 | ## Examples
10 |
11 | When enabled (assuming `max-depth: 2`) the deepest element (`&:hover` and `&--modifier`) are at at depth 2. Any nested selector deeper is disallowed:
12 |
13 | ```scss
14 | .foo {
15 | .baz {
16 | &:hover {
17 | // Deepest Nest Allowed
18 | }
19 | }
20 | }
21 |
22 | .block {
23 | &__element {
24 | &--modifier {
25 | // Deepest Nest Allowed
26 | }
27 | }
28 | }
29 | ```
30 |
--------------------------------------------------------------------------------
/docs/rules/no-attribute-selectors.md:
--------------------------------------------------------------------------------
1 | # No Attribute Selectors
2 |
3 | Rule `no-attribute-selectors` will warn against the use of attribute selectors.
4 |
5 | ## Examples
6 |
7 | When enabled, the following are disallowed:
8 |
9 | ```scss
10 | [autoplay] {
11 | content: 'foo';
12 | }
13 |
14 | [lang=en] {
15 | content: 'bar';
16 | }
17 |
18 | [lang~=en-us] {
19 | content: 'baz';
20 | }
21 |
22 | [lang|=us] {
23 | content: 'qux';
24 | }
25 |
26 | [href^="#"] {
27 | content: 'norf';
28 | }
29 |
30 | [href$=".com"] {
31 | content: 'foo';
32 | }
33 |
34 | [href*=news] {
35 | content: 'bar';
36 | }
37 | ```
38 |
--------------------------------------------------------------------------------
/docs/rules/space-before-colon.md:
--------------------------------------------------------------------------------
1 | # Space Before Colon
2 |
3 | Rule `space-before-colon` will enforce whether or not a space should be included before a colon (`:`).
4 |
5 | ## Options
6 |
7 | * `include`: `true`/`false` (defaults to `false`)
8 |
9 | ## Examples
10 |
11 | When `include: false`, the following are allowed. When `include: true`, the following are disallowed:
12 |
13 | ```scss
14 | .foo {
15 | content: 'bar';
16 | }
17 | ```
18 |
19 | When `include: true`, the following are allowed. When `include: false`, the following are disallowed:
20 |
21 | ```scss
22 | .foo {
23 | content :'bar';
24 | }
25 | ```
26 |
--------------------------------------------------------------------------------
/lib/rules/no-important.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var helpers = require('../helpers');
4 |
5 | module.exports = {
6 | 'name': 'no-important',
7 | 'defaults': {},
8 | 'detect': function (ast, parser) {
9 | var result = [];
10 |
11 | ast.traverseByType('important', function (item) {
12 | result = helpers.addUnique(result, {
13 | 'ruleId': parser.rule.name,
14 | 'line': item.start.line,
15 | 'column': item.start.column,
16 | 'message': '!important not allowed',
17 | 'severity': parser.severity
18 | });
19 | });
20 |
21 | return result;
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/lib/exceptions.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var util = require('util');
4 |
5 | module.exports = {
6 | SassLintFailureError: function (message) {
7 | Error.captureStackTrace(this, this.constructor);
8 | this.name = 'SassLintFailureError';
9 | this.message = message;
10 | },
11 | MaxWarningsExceededError: function (message) {
12 | Error.captureStackTrace(this, this.constructor);
13 | this.name = 'MaxWarningsExceededError';
14 | this.message = message;
15 | }
16 | };
17 |
18 | util.inherits(module.exports.SassLintFailureError, Error);
19 | util.inherits(module.exports.MaxWarningsExceededError, Error);
20 |
--------------------------------------------------------------------------------
/lib/rules/no-color-hex.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var helpers = require('../helpers');
4 |
5 | module.exports = {
6 | 'name': 'no-color-hex',
7 | 'defaults': {},
8 | 'detect': function (ast, parser) {
9 | var result = [];
10 |
11 | ast.traverseByType('color', function (value) {
12 | result = helpers.addUnique(result, {
13 | 'ruleId': parser.rule.name,
14 | 'line': value.start.line,
15 | 'column': value.start.column,
16 | 'message': 'Hexadecimal colors should not be used',
17 | 'severity': parser.severity
18 | });
19 | });
20 | return result;
21 | }
22 | };
23 |
--------------------------------------------------------------------------------
/docs/rules/space-after-bang.md:
--------------------------------------------------------------------------------
1 | # Space After Bang
2 |
3 | Rule `space-after-bang` will enforce whether or not a space should be included after a bang (`!`).
4 |
5 | ## Options
6 |
7 | * `include`: `true`/`false` (defaults to `false`)
8 |
9 | ## Examples
10 |
11 | When `include: false`, the following are allowed. When `include: true`, the following are disallowed:
12 |
13 | ```scss
14 | .foo {
15 | content: 'bar' !important;
16 | }
17 | ```
18 |
19 | When `include: true`, the following are allowed. When `include: false`, the following are disallowed:
20 |
21 | ```scss
22 | .foo {
23 | content: 'bar' ! important;
24 | }
25 | ```
26 |
--------------------------------------------------------------------------------
/docs/rules/space-before-bang.md:
--------------------------------------------------------------------------------
1 | # Space Before Bang
2 |
3 | Rule `space-before-bang` will enforce whether or not a space should be included before a bang (`!`).
4 |
5 | ## Options
6 |
7 | * `include`: `true`/`false` (defaults to `true`)
8 |
9 | ## Examples
10 |
11 | When `include: true`, the following are allowed. When `include: false`, the following are disallowed:
12 |
13 | ```scss
14 | .foo {
15 | content: 'bar' !important;
16 | }
17 | ```
18 |
19 | When `include: false`, the following are allowed. When `include: true`, the following are disallowed:
20 |
21 | ```scss
22 | .foo {
23 | content: 'bar'!important;
24 | }
25 | ```
26 |
--------------------------------------------------------------------------------
/tests/sass/empty-args.scss:
--------------------------------------------------------------------------------
1 | // No arguments with parenthesis
2 | @mixin foo() {
3 | color: red;
4 | }
5 |
6 | .foo {
7 | @include foo();
8 | }
9 |
10 |
11 |
12 | // No arguments with no parenthesis
13 | @mixin bar {
14 | color: orange;
15 | }
16 |
17 | .bar {
18 | @include bar;
19 | }
20 |
21 |
22 |
23 | // Arguments with parenthesis
24 | @mixin baz($color) {
25 | color: $color;
26 | }
27 |
28 | $foo: blue;
29 |
30 | .baz {
31 | @include baz($foo);
32 | }
33 |
34 |
35 |
36 | // Parenthesis only where required
37 | @mixin qux($color: lime) {
38 | color: $color;
39 | }
40 |
41 | .qux {
42 | @include qux;
43 | }
44 |
--------------------------------------------------------------------------------
/tests/helpers/hasEOL.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var assert = require('assert'),
4 | helpers = require('../../lib/helpers');
5 |
6 | describe('helpers - hasEOL', function () {
7 |
8 | //////////////////////////////
9 | // hasEOL
10 | //////////////////////////////
11 |
12 | it('hasEOL - [\'\\n\' - true]', function (done) {
13 |
14 | var result = helpers.hasEOL('\n');
15 |
16 | assert.equal(true, result);
17 | done();
18 | });
19 |
20 | it('hasEOL - [\'\\r\\n\' - true]', function (done) {
21 |
22 | var result = helpers.hasEOL('\r\n');
23 |
24 | assert.equal(true, result);
25 | done();
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/tests/sass/declarations-before-nesting.scss:
--------------------------------------------------------------------------------
1 | .bar {
2 | content: 'baz';
3 |
4 | .qux {
5 | content: 'baz';
6 | }
7 | }
8 |
9 | .foo {
10 | .bar {
11 | content: 'where';
12 | }
13 |
14 | content: 'baz';
15 |
16 | .baz {
17 | content: 'where';
18 | }
19 |
20 | content: 'baz';
21 | }
22 |
23 | .foo {
24 | .bar {
25 | content: 'where';
26 |
27 | .baz {
28 | content: 'quz';
29 | }
30 |
31 | content: 'baz';
32 | }
33 |
34 | content: 'baz';
35 | }
36 |
37 | // issue #935 - ignore variables
38 | @mixin foo {
39 | #{$bar} {
40 | content: 'foobar';
41 | }
42 |
43 | $baz: 'qux';
44 | }
45 |
--------------------------------------------------------------------------------
/docs/rules/no-disallowed-properties.md:
--------------------------------------------------------------------------------
1 | # No Disallowed Properties
2 |
3 | Rule `no-disallowed-properties` will warn against the use of certain properties.
4 |
5 | ## Options
6 |
7 | * `properties`: `[array of disallowed properties]` (defaults to empty array `[]`).
8 |
9 | ## Examples
10 |
11 | When `properties` contains a property value of `z-index` as shown below:
12 |
13 | ```yaml
14 | no-disallowed-properties:
15 | - 1
16 | -
17 | 'properties':
18 | - 'z-index'
19 | ```
20 |
21 | The following would not be allowed:
22 |
23 | ```scss
24 |
25 | // z-index property is not allowed
26 | .foo {
27 | z-index: 10;
28 | }
29 |
30 | ```
31 |
--------------------------------------------------------------------------------
/lib/rules/no-attribute-selectors.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var helpers = require('../helpers');
4 |
5 | module.exports = {
6 | 'name': 'no-attribute-selectors',
7 | 'defaults': {},
8 | 'detect': function (ast, parser) {
9 | var result = [];
10 |
11 | ast.traverseByType('attributeSelector', function (item) {
12 | result = helpers.addUnique(result, {
13 | 'ruleId': parser.rule.name,
14 | 'line': item.start.line,
15 | 'column': item.start.column,
16 | 'message': 'Attribute selectors are not allowed',
17 | 'severity': parser.severity
18 | });
19 | });
20 |
21 | return result;
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/lib/rules/no-universal-selectors.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var helpers = require('../helpers');
4 |
5 | module.exports = {
6 | 'name': 'no-universal-selectors',
7 | 'defaults': {},
8 | 'detect': function (ast, parser) {
9 | var result = [];
10 |
11 | ast.traverseByType('universalSelector', function (node) {
12 | result = helpers.addUnique(result, {
13 | 'ruleId': parser.rule.name,
14 | 'line': node.start.line,
15 | 'column': node.start.column,
16 | 'message': '* (universal) selectors are not allowed',
17 | 'severity': parser.severity
18 | });
19 | });
20 |
21 | return result;
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/tests/sass/hex-length.sass:
--------------------------------------------------------------------------------
1 | $foo-color: #123
2 |
3 | .foo
4 | background: linear-gradient(top, #cc2, #44d)
5 | color: #fff
6 |
7 |
8 | $bar-color: #112233
9 |
10 | .bar
11 | background: linear-gradient(top, #cccc22, #4444dd)
12 | color: #ffffff
13 |
14 |
15 | // values that can't be shortened are ignored by the style:short rule
16 |
17 | .baz
18 | border-color: #123456
19 |
20 |
21 | // color literals, rgb and hsl values currently don't get returned
22 | // by the AST's color type
23 |
24 | $qux-color: red
25 | $rgb-color: rgb(255, 255, 255)
26 | $rgba-color: rgba(0, 0, 0, .1)
27 | $hsl-color: hsl(40, 50%, 50%)
28 | $hsla-color: hsla(40, 50%, 50%, .3)
29 |
--------------------------------------------------------------------------------
/tests/sass/hex-notation.sass:
--------------------------------------------------------------------------------
1 | // numbers only won't match
2 | $foo-color: #123
3 |
4 | .foo
5 | background: linear-gradient(top, #cc2, #44d)
6 | color: #fff
7 |
8 |
9 | $bar-color: #123456
10 |
11 | .bar
12 | background: linear-gradient(top, #CC2, #44D)
13 | color: #FFF
14 |
15 |
16 | .qux
17 | color: #cC2
18 |
19 |
20 | $lower-numbers-color: #123cc2
21 | $upper-lower-color: #CCCCCc
22 |
23 | $map-vals: (mixed: #123Cde)
24 |
25 | // check that only hex colours are being parsed
26 |
27 | $literal-color: red
28 | $rgb-color: rgb(255, 255, 255)
29 | $rgba-color: rgba(0, 0, 0, .1)
30 | $hsl-color: hsl(40, 50%, 50%)
31 | $hsla-color: hsla(40, 50%, 50%, .3)
32 |
--------------------------------------------------------------------------------
/tests/sass/hex-length.scss:
--------------------------------------------------------------------------------
1 | $foo-color: #123;
2 |
3 | .foo {
4 | background: linear-gradient(top, #cc2, #44d);
5 | color: #fff;
6 | }
7 |
8 | $bar-color: #112233;
9 |
10 | .bar {
11 | background: linear-gradient(top, #cccc22, #4444dd);
12 | color: #ffffff;
13 | }
14 |
15 | // values that can't be shortened are ignored by the style:short rule
16 |
17 | .baz {
18 | border-color: #123456;
19 | }
20 |
21 | // color literals, rgb and hsl values currently don't get returned
22 | // by the AST's color type
23 |
24 | $qux-color: red;
25 | $rgb-color: rgb(255, 255, 255);
26 | $rgba-color: rgba(0, 0, 0, .1);
27 | $hsl-color: hsl(40, 50%, 50%);
28 | $hsla-color: hsla(40, 50%, 50%, .3);
29 |
--------------------------------------------------------------------------------
/docs/rules/zero-unit.md:
--------------------------------------------------------------------------------
1 | # Zero Unit
2 |
3 | Rule `zero-unit` will enforce whether or not values of `0` used for length should be unitless.
4 |
5 | ## Options
6 |
7 | * `include`: `true`/`false` (defaults to `false`)
8 |
9 | ## Examples
10 |
11 | When `include: false`, the following are allowed. When `include: true`, the following are disallowed:
12 |
13 | ```scss
14 | .foo {
15 | margin: 0;
16 | }
17 |
18 | .bar {
19 | padding: 5px 0 0;
20 | }
21 | ```
22 |
23 | When `include: true`, the following are allowed. When `include: false`, the following are disallowed:
24 |
25 | ```scss
26 | .foo {
27 | margin: 0px;
28 | }
29 |
30 | .bar {
31 | padding: 5px 0px 0px;
32 | }
33 | ```
34 |
--------------------------------------------------------------------------------
/tests/sass/variable-name-format.sass:
--------------------------------------------------------------------------------
1 | $kabab-case: 1
2 | $snake_case: 1
3 | $camelCase: 1
4 | $PascalCase: 1
5 | $Camel_Snake_Case: 1
6 | $SCREAMING_SNAKE_CASE: 1
7 | $_with-leading-underscore: 1
8 |
9 | $strictbem: 1
10 | $strictbem__variable: 1
11 | $strictbem__variable_modifier: 1
12 | $strictbem_modifier__variable: 1
13 | $hyphenatedbem--modifier: 1
14 | $hyphenatedbem__variable: 1
15 | $hyphenatedbem__variable--modifier: 1
16 | $hyphenatedbem--modifier__variable: 1
17 |
18 | $_does_NOT-fitSTANDARD: 1
19 |
20 | .class
21 | width: $snake_case
22 |
23 | // Issue #901 - operators not recognized as separate tokens by gonzales-pe
24 | .content-main
25 | padding: $mobile-site-gutter*1.5
26 |
--------------------------------------------------------------------------------
/docs/rules/final-newline.md:
--------------------------------------------------------------------------------
1 | # Final Newline
2 |
3 | Rule `final-newline` will enforce whether or not files should end with a newline.
4 |
5 | ## Options
6 |
7 | * `include`: `true`/`false` (defaults to `true`)
8 |
9 | ## Examples
10 |
11 | When `include: true`, the following are allowed. When `include: false`, the following are disallowed:
12 |
13 | ```scss
14 | .foo {
15 | content: 'bar';
16 | }
17 | // Newline under this comment at end of file
18 |
19 | ```
20 |
21 | When `include: false`, the following are allowed. When `include: true`, the following are disallowed:
22 |
23 | ```scss
24 | .foo {
25 | content: 'bar';
26 | }
27 | // No newline under this comment at end of file
28 | ```
29 |
--------------------------------------------------------------------------------
/tests/sass/hex-notation.scss:
--------------------------------------------------------------------------------
1 | // numbers only won't match
2 | $foo-color: #123;
3 |
4 | .foo {
5 | background: linear-gradient(top, #cc2, #44d);
6 | color: #fff;
7 | }
8 |
9 | $bar-color: #123456;
10 |
11 | .bar {
12 | background: linear-gradient(top, #CC2, #44D);
13 | color: #FFF;
14 | }
15 |
16 | .qux {
17 | color: #cC2;
18 | }
19 |
20 | $lower-numbers-color: #123cc2;
21 | $upper-lower-color: #CCCCCc;
22 |
23 | $map-vals: (
24 | mixed: #123Cde,
25 | );
26 |
27 | // check that only hex colours are being parsed
28 |
29 | $literal-color: red;
30 | $rgb-color: rgb(255, 255, 255);
31 | $rgba-color: rgba(0, 0, 0, .1);
32 | $hsl-color: hsl(40, 50%, 50%);
33 | $hsla-color: hsla(40, 50%, 50%, .3);
34 |
--------------------------------------------------------------------------------
/lib/rules/no-invalid-hex.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var helpers = require('../helpers');
4 |
5 | module.exports = {
6 | 'name': 'no-invalid-hex',
7 | 'defaults': {},
8 | 'detect': function (ast, parser) {
9 | var result = [];
10 |
11 | ast.traverseByType('color', function (value) {
12 | if (!helpers.isValidHex(value.content)) {
13 | result = helpers.addUnique(result, {
14 | 'ruleId': parser.rule.name,
15 | 'line': value.start.line,
16 | 'column': value.start.column,
17 | 'message': 'Hexadecimal values must be a valid format',
18 | 'severity': parser.severity
19 | });
20 | }
21 | });
22 | return result;
23 | }
24 | };
25 |
--------------------------------------------------------------------------------
/lib/rules/no-css-comments.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var helpers = require('../helpers');
4 |
5 | module.exports = {
6 | 'name': 'no-css-comments',
7 | 'defaults': {},
8 | 'detect': function (ast, parser) {
9 | var result = [];
10 |
11 | ast.traverseByType('multilineComment', function (node) {
12 | if (node.content.charAt(0) !== '!') {
13 | result = helpers.addUnique(result, {
14 | 'ruleId': parser.rule.name,
15 | 'line': node.start.line,
16 | 'column': node.start.column,
17 | 'message': 'Multiline style comments should not be used',
18 | 'severity': parser.severity
19 | });
20 | }
21 | });
22 | return result;
23 | }
24 | };
25 |
--------------------------------------------------------------------------------
/tests/sass/clean-import-paths.sass:
--------------------------------------------------------------------------------
1 | // Clean paths
2 | @import foo
3 | @import bar/foo
4 |
5 | // Only filename extensions
6 | @import foo.scss
7 | @import bar/foo.scss
8 |
9 | // Only leading underscores
10 | @import _foo
11 | @import bar/_foo
12 |
13 | // Both leading underscores and filename extensions
14 | @import _foo.scss
15 | @import bar/_foo.scss
16 |
17 | // CSS imports - ignore
18 | @import url(fineprint.css)
19 | @import url(bluish.css) projection, tv
20 | @import custom.css
21 | @import url(chrome://communicator/skin/)
22 | @import common.css screen, projection
23 | @import url(landscape.css) screen and (orientation: landscape)
24 |
25 | @if variable-exists(google-fonts-url)
26 | @import url($google-fonts-url)
27 |
--------------------------------------------------------------------------------
/tests/sass/variable-name-format.scss:
--------------------------------------------------------------------------------
1 | $kabab-case: 1;
2 | $snake_case: 1;
3 | $camelCase: 1;
4 | $PascalCase: 1;
5 | $Camel_Snake_Case: 1;
6 | $SCREAMING_SNAKE_CASE: 1;
7 | $_with-leading-underscore: 1;
8 |
9 | $strictbem: 1;
10 | $strictbem__variable: 1;
11 | $strictbem__variable_modifier: 1;
12 | $strictbem_modifier__variable: 1;
13 | $hyphenatedbem--modifier: 1;
14 | $hyphenatedbem__variable: 1;
15 | $hyphenatedbem__variable--modifier: 1;
16 | $hyphenatedbem--modifier__variable: 1;
17 |
18 | $_does_NOT-fitSTANDARD: 1;
19 |
20 | .class {
21 | width: $snake_case;
22 | }
23 |
24 | // Issue #901 - operators not recognized as separate tokens by gonzales-pe
25 | .content-main {
26 | padding: $mobile-site-gutter*1.5;
27 | }
28 |
--------------------------------------------------------------------------------
/lib/rules/max-file-line-count.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var helpers = require('../helpers');
4 |
5 | module.exports = {
6 | 'name': 'max-file-line-count',
7 | 'defaults': {
8 | length: 300
9 | },
10 | 'detect': function (ast, parser) {
11 | var result = [];
12 |
13 | if (ast.end.line > parser.options.length) {
14 | result = helpers.addUnique(result, {
15 | 'ruleId': parser.rule.name,
16 | 'line': ast.end.line,
17 | 'column': 0,
18 | 'message': 'This file has ' + ast.end.line + ' lines, which exceeds the maximum of ' + parser.options.length + ' lines allowed.',
19 | 'severity': parser.severity
20 | });
21 | }
22 |
23 | return result;
24 | }
25 | };
26 |
--------------------------------------------------------------------------------
/tests/sass/space-after-comma.sass:
--------------------------------------------------------------------------------
1 | h1,h2
2 | content: 'foo'
3 |
4 |
5 | h3, h4
6 | content: 'foo'
7 |
8 |
9 | h5,
10 | h6
11 | content: 'foo'
12 |
13 |
14 | .foo
15 | box-shadow: 1px 1px black,1px 1px black
16 |
17 |
18 | .foo
19 | box-shadow: 1px 1px black, 1px 1px black
20 |
21 |
22 | .bar
23 | @include mixin('foo','bar')
24 |
25 |
26 | .bar
27 | @include mixin('foo', 'bar')
28 |
29 |
30 | @function foo($bar,$baz)
31 | @return $bar * $baz
32 |
33 |
34 | @function foo($bar, $baz)
35 | @return $bar * $baz
36 |
37 |
38 | =foo(
39 | $foo: true,
40 | $bar: false
41 | )
42 | content: 'foo'
43 |
44 |
45 | =foo(
46 | $foo: true, // Foo
47 | $bar: false /* Bar */
48 | )
49 | content: 'foo'
50 |
--------------------------------------------------------------------------------
/docs/rules/force-element-nesting.md:
--------------------------------------------------------------------------------
1 | # Force Element Nesting
2 |
3 | Rule `force-element-nesting` will enforce the nesting of elements
4 |
5 | ## Examples
6 |
7 | When enabled, the following are disallowed:
8 |
9 | ```scss
10 | div p {
11 | content: '';
12 | }
13 |
14 | .parent {
15 | &__child h1 {
16 | content: '';
17 | }
18 | }
19 |
20 | a[target="_blank"] span {
21 | content: '';
22 | }
23 | ```
24 |
25 | When enabled, the following are allowed:
26 |
27 | ```scss
28 | div {
29 | p {
30 | content: '';
31 | }
32 | }
33 |
34 | .parent {
35 | &__child {
36 | h1 {
37 | content: '';
38 | }
39 | }
40 | }
41 |
42 | a[target="_blank"] {
43 | span {
44 | content: '';
45 | }
46 | }
47 | ```
48 |
--------------------------------------------------------------------------------
/docs/rules/no-url-domains.md:
--------------------------------------------------------------------------------
1 | # No Url Domains
2 |
3 | Rule `no-url-domains` will enforce that domains are not used within urls.
4 |
5 | ## Examples
6 |
7 | When enabled, the following are allowed:
8 |
9 | ```scss
10 | .foo {
11 | background-image: url('/img/bar.png');
12 | }
13 |
14 | .foo {
15 | background-image: url('img/bar.png');
16 | }
17 |
18 | .foo {
19 | background-image: url('bar.png');
20 | }
21 | ```
22 |
23 | When enabled, the following are disallowed:
24 |
25 | ```scss
26 | .foo {
27 | background-image: url('https://foo.com/img/bar.png');
28 | }
29 |
30 | .foo {
31 | background-image: url('http://foo.com/img/bar.png');
32 | }
33 |
34 | .foo {
35 | background-image: url('//foo.com/img/bar.png');
36 | }
37 | ```
38 |
--------------------------------------------------------------------------------
/docs/rules/max-line-length.md:
--------------------------------------------------------------------------------
1 | # Max Line Length
2 |
3 | Rule `max-line-length` will enforce that lines do not exceed a max length / limit.
4 |
5 | ## Options
6 |
7 | * `length`: `number`, (defaults to 80)
8 |
9 | ## Examples
10 |
11 | When enabled, the following are disallowed:
12 |
13 | ```scss
14 | .really--long--class-name--that-unfortunately--isnt--very--succint--and-looks-stupid {
15 | color: red;
16 | }
17 |
18 | // ==============================================================================
19 | //
20 | // This comment is too long clearly, we should probably make sure we have a rule to
21 | // determine when we breach this length
22 | //
23 | // ==============================================================================
24 | ```
25 |
--------------------------------------------------------------------------------
/docs/rules/space-after-comma.md:
--------------------------------------------------------------------------------
1 | # Space After Comma
2 |
3 | Rule `space-after-comma` will enforce whether or not a space should be included after a comma (`,`).
4 |
5 | ## Options
6 |
7 | * `include`: `true`/`false` (defaults to `true`)
8 |
9 | ## Examples
10 |
11 | When `include: true`, the following are allowed. When `include: false`, the following are disallowed:
12 |
13 | ```scss
14 | .foo {
15 | @include baz('foo', 'bar');
16 |
17 | box-shadow: 1px 1px black, 1px 1px black;
18 | }
19 | ```
20 |
21 | When `include: false`, the following are allowed. When `include: true`, the following are disallowed:
22 |
23 | ```scss
24 | .foo {
25 | @include baz('foo','bar');
26 |
27 | box-shadow: 1px 1px black,1px 1px black;
28 | }
29 | ```
30 |
--------------------------------------------------------------------------------
/docs/rules/mixins-before-declarations.md:
--------------------------------------------------------------------------------
1 | # Mixins Before Declarations
2 |
3 | Rule `mixins-before-declarations` will enforce that mixins should be written before declarations in a ruleset.
4 |
5 | ## Options
6 |
7 | * `exclude`: `['breakpoint', 'mq']` (array of mixin names to be excluded from this rule)
8 |
9 | ## Examples
10 |
11 | When enabled, the following are allowed:
12 |
13 | ```scss
14 | .foo {
15 | @include bar;
16 | content: 'baz';
17 |
18 | @include breakpoint(500px) {
19 | content: 'qux';
20 | }
21 |
22 | @include mq(500px) {
23 | content: 'qux';
24 | }
25 | }
26 | ```
27 |
28 | When enabled, the following are disallowed:
29 |
30 | ```scss
31 | .foo {
32 | content: 'baz';
33 | @include baz;
34 | }
35 | ```
36 |
--------------------------------------------------------------------------------
/tests/sass/space-between-parens.sass:
--------------------------------------------------------------------------------
1 | @function foo( $bar)
2 | @return $bar
3 |
4 |
5 | @function baz()
6 | @return false
7 |
8 |
9 |
10 | =bar ($baz )
11 | content: $baz
12 |
13 |
14 | .foo
15 | +bar( 'Hello' )
16 | content: foo('bar')
17 | width: calc( 100% - 10px)
18 |
19 | // Top level mixin
20 | +hello(
21 | $foo,
22 | $bar,
23 | $baz
24 | )
25 |
26 | .foo
27 | // Nested Mixin
28 | +hello(
29 | $foo,
30 | $bar,
31 | $baz
32 | )
33 |
34 | // CSS built-in function
35 | background: transparent linear-gradient(
36 | to bottom,
37 | #ff0000 0%,
38 | #00ff00 40%,
39 | #0000ff 40%
40 | )
41 |
42 | // User-defined function
43 | content: goodbye(
44 | $foo,
45 | $bar
46 | )
47 |
--------------------------------------------------------------------------------
/docs/rules/empty-args.md:
--------------------------------------------------------------------------------
1 | # Empty Args
2 |
3 | Rule `empty-args` will enforce whether or not parenthesis should be included if no arguments are defined or used, when declaring or invoking a mixin.
4 |
5 | ## Options
6 |
7 | * `include`: `true`/`false` (defaults to `false`)
8 |
9 | ## Examples
10 |
11 | When `include: false`, the following are allowed. When `include: true`, the following are disallowed:
12 |
13 | ```scss
14 | @mixin bar {
15 | padding: 10px;
16 | }
17 |
18 | .bar {
19 | @include bar;
20 | }
21 | ```
22 |
23 | When `include: true`, the following are allowed. When `include: false`, the following are disallowed:
24 |
25 | ```scss
26 | @mixin foo() {
27 | padding: 10px;
28 | }
29 |
30 | .foo {
31 | @include foo();
32 | }
33 | ```
34 |
--------------------------------------------------------------------------------
/lib/rules/no-warn.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var helpers = require('../helpers');
4 |
5 | module.exports = {
6 | 'name': 'no-warn',
7 | 'defaults': {},
8 | 'detect': function (ast, parser) {
9 | var result = [];
10 |
11 | ast.traverseByType('atkeyword', function (keyword) {
12 | keyword.traverse(function (item) {
13 | if (item.content === 'warn') {
14 | result = helpers.addUnique(result, {
15 | 'ruleId': parser.rule.name,
16 | 'line': item.start.line,
17 | 'column': item.start.column,
18 | 'message': '@warn not allowed',
19 | 'severity': parser.severity
20 | });
21 | }
22 | });
23 | });
24 |
25 | return result;
26 | }
27 | };
28 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | # CRLF Line Endings
2 | init:
3 | - git config --global core.autocrlf true
4 |
5 | # Test against this version of Node.js
6 | environment:
7 | matrix:
8 | - nodejs_version: '6'
9 | - nodejs_version: '9'
10 | # Latest stable version of Node
11 | - nodejs_version: 'stable'
12 |
13 | # Install scripts. (runs after repo cloning)
14 | install:
15 | # Get the latest stable version of Node.js or io.js
16 | - ps: Install-Product node $env:nodejs_version
17 | # install modules
18 | - npm install
19 |
20 | # Post-install test scripts.
21 | test_script:
22 | # Output useful info for debugging.
23 | - node --version
24 | - npm --version
25 | # run tests
26 | - npm test
27 |
28 | # Don't actually build.
29 | build: off
30 |
--------------------------------------------------------------------------------
/lib/rules/no-debug.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var helpers = require('../helpers');
4 |
5 | module.exports = {
6 | 'name': 'no-debug',
7 | 'defaults': {},
8 | 'detect': function (ast, parser) {
9 | var result = [];
10 |
11 | ast.traverseByType('atkeyword', function (keyword) {
12 | keyword.traverse(function (item) {
13 | if (item.content === 'debug') {
14 | result = helpers.addUnique(result, {
15 | 'ruleId': parser.rule.name,
16 | 'line': item.start.line,
17 | 'column': item.start.column,
18 | 'message': '@debug not allowed',
19 | 'severity': parser.severity
20 | });
21 | }
22 | });
23 | });
24 |
25 | return result;
26 | }
27 | };
28 |
--------------------------------------------------------------------------------
/tests/sass/no-color-keywords.sass:
--------------------------------------------------------------------------------
1 | .literal
2 | color: mediumslateblue
3 |
4 |
5 | .linear-gradient-func
6 | background: linear-gradient(top, #fff, white)
7 |
8 |
9 | .box-shadow
10 | box-shadow: 1px 1px black, 1px 1px black
11 |
12 |
13 | .background
14 | background: 1px solid white
15 | content: 100
16 |
17 |
18 | .hex
19 | color: #fff
20 |
21 |
22 | $colors: ( $red: red, $blue : ( $orange: ( $yellow: yellow ) ) )
23 |
24 | $literal: mediumslateblue
25 | $hexVar: #fff
26 |
27 | $blue: #0050a0
28 | $brand-primary: $blue
29 |
30 | $other: rgba($blue, 0.3)
31 |
32 | // Issue #717 - rule trips over Sass color function names
33 | $colors: ( 'red': red($color), 'green': green($color), 'blue': blue($color) )
34 |
35 | $badge-bg: var(--red)
36 |
--------------------------------------------------------------------------------
/lib/rules/no-extends.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var helpers = require('../helpers');
4 |
5 | module.exports = {
6 | 'name': 'no-extends',
7 | 'defaults': {},
8 | 'detect': function (ast, parser) {
9 | var result = [];
10 |
11 | ast.traverseByType('atkeyword', function (keyword) {
12 | keyword.traverse(function (item) {
13 | if (item.content === 'extend') {
14 | result = helpers.addUnique(result, {
15 | 'ruleId': parser.rule.name,
16 | 'line': item.start.line,
17 | 'column': item.start.column,
18 | 'message': '@extend not allowed',
19 | 'severity': parser.severity
20 | });
21 | }
22 | });
23 | });
24 |
25 | return result;
26 | }
27 | };
28 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # OSX
11 | ._*
12 | .DS_Store
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 | .nyc_output
20 |
21 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
22 | .grunt
23 |
24 | # Compiled binary addons (http://nodejs.org/api/addons.html)
25 | build/Release
26 |
27 | # Dependency directory
28 | # Commenting this out is preferred by some people, see
29 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
30 | node_modules
31 |
32 | # Users Environment Variables
33 | .lock-wscript
34 |
--------------------------------------------------------------------------------
/tests/sass/id-name-format.sass:
--------------------------------------------------------------------------------
1 | #hyphenated-lowercase
2 | content: ''
3 |
4 | #snake_case
5 | content: ''
6 |
7 | #camelCase
8 | content: ''
9 |
10 | #PascalCase
11 | content: ''
12 |
13 | #Camel_Snake_Case
14 | content: ''
15 |
16 | #SCREAMING_SNAKE_CASE
17 | content: ''
18 |
19 | #_with-leading-underscore
20 | content: ''
21 |
22 | #_does_NOT-fitSTANDARD
23 | @extend #snake_case
24 |
25 | #hyphentated-lowercase
26 | color: blue
27 |
28 | &-with-suffix-extension
29 | color: green
30 |
31 | &-and-another
32 | color: red
33 |
34 | &-INVALID
35 | color: pink
36 |
37 | #one_parent,
38 | #two_parents,
39 | #third-invalid-parent
40 | width: 10px
41 |
42 | &_valid_child,
43 | &-invalid-child
44 | height: 10px
45 |
--------------------------------------------------------------------------------
/docs/rules/force-attribute-nesting.md:
--------------------------------------------------------------------------------
1 | # Force Attribute Nesting
2 |
3 | Rule `force-attribute-nesting` will enforce the nesting of attributes
4 |
5 |
6 | ## Examples
7 |
8 | When enabled, the following are disallowed:
9 | ```scss
10 | input[type='radio'] {
11 | color: red;
12 | }
13 |
14 | a[target='_blank'] {
15 | content: '';
16 | }
17 |
18 | .form {
19 | .class input[type='text'] {
20 | padding: 0;
21 | }
22 | }
23 | ```
24 |
25 | When enabled, the following are allowed:
26 |
27 | ```scss
28 | input {
29 | &[type='radio'] {
30 | color: red;
31 | }
32 | }
33 |
34 | a {
35 | &[target='_blank'] {
36 | content: '';
37 | }
38 | }
39 |
40 | .form {
41 | .class input {
42 | &[type='text'] {
43 | padding: 0;
44 | }
45 | }
46 | }
47 | ```
48 |
--------------------------------------------------------------------------------
/tests/helpers/stripQuotes.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var assert = require('assert'),
4 | helpers = require('../../lib/helpers');
5 |
6 | describe('helpers - stripQuotes', function () {
7 |
8 | //////////////////////////////
9 | // Strip quotes
10 | //////////////////////////////
11 |
12 | it('stripQuotes - [double quotes]', function (done) {
13 | var result = helpers.stripQuotes('"This is a string"'),
14 | expect = 'This is a string';
15 |
16 | assert.equal(expect, result);
17 | done();
18 | });
19 |
20 | it('stripQuotes - [single quotes]', function (done) {
21 | var result = helpers.stripQuotes('\'This is a string\''),
22 | expect = 'This is a string';
23 |
24 | assert.equal(expect, result);
25 | done();
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/tests/sass/space-after-comma.scss:
--------------------------------------------------------------------------------
1 | h1,h2 {
2 | content: 'foo';
3 | }
4 |
5 | h1, h2 {
6 | content: 'foo';
7 | }
8 |
9 | h1,
10 | h2 {
11 | content: 'foo';
12 | }
13 |
14 | .foo {
15 | box-shadow: 1px 1px black,1px 1px black;
16 | }
17 |
18 | .foo {
19 | box-shadow: 1px 1px black, 1px 1px black;
20 | }
21 |
22 | .bar {
23 | @include mixin('foo','bar');
24 | }
25 |
26 | .bar {
27 | @include mixin('foo', 'bar');
28 | }
29 |
30 | @function foo($bar,$baz) {
31 | @return $bar * $baz;
32 | }
33 |
34 | @function foo($bar, $baz) {
35 | @return $bar * $baz;
36 | }
37 |
38 | @mixin foo(
39 | $foo: true,
40 | $bar: false
41 | ) {
42 | content: 'foo';
43 | }
44 |
45 | @mixin foo(
46 | $foo: true, // Foo
47 | $bar: false /* Bar */
48 | ) {
49 | content: 'foo';
50 | }
51 |
--------------------------------------------------------------------------------
/tests/sass/space-between-parens.scss:
--------------------------------------------------------------------------------
1 | @function foo( $bar) {
2 | @return $bar;
3 | }
4 |
5 | @function baz() {
6 |
7 | }
8 |
9 | @mixin bar ($baz ) {
10 | content: $baz;
11 | }
12 |
13 | .foo {
14 | @include bar( 'Hello' );
15 | content: foo('bar');
16 | width: calc( 100% - 10px);
17 | }
18 |
19 | // Top level mixin
20 | @include hello(
21 | $foo,
22 | $bar,
23 | $baz
24 | );
25 |
26 | .foo {
27 | // Nested Mixin
28 | @include hello(
29 | $foo,
30 | $bar,
31 | $baz
32 | );
33 |
34 | // CSS built-in function
35 | background: transparent linear-gradient(
36 | to bottom,
37 | #ff0000 0%,
38 | #00ff00 40%,
39 | #0000ff 40%
40 | );
41 |
42 | // User-defined function
43 | content: goodbye(
44 | $foo,
45 | $bar
46 | );
47 | }
48 |
--------------------------------------------------------------------------------
/tests/sass/bem-depth.scss:
--------------------------------------------------------------------------------
1 | .one {
2 | color: red;
3 |
4 | &__two {
5 | color: blue;
6 |
7 | &__three {
8 | color: green;
9 | }
10 | }
11 |
12 | &__two-again {
13 | color: pink;
14 | }
15 | }
16 |
17 | .one__two {
18 | color: red;
19 |
20 | &--modifier {
21 | color: blue;
22 | }
23 |
24 | &__three {
25 | color: green;
26 | }
27 |
28 | &--modifier__three {
29 | color: white;
30 | }
31 | }
32 |
33 | .block {
34 | color: red;
35 | }
36 |
37 | .block__element-one {
38 | color: red;
39 | }
40 |
41 | .block__element-one__element-two {
42 | color: red;
43 | }
44 |
45 | %one__two {
46 | color: red;
47 | }
48 |
49 | %one__two__three {
50 | color: blue;
51 | }
52 |
53 | %one__two__three__four {
54 | color: blue;
55 | }
56 |
--------------------------------------------------------------------------------
/docs/rules/trailing-semicolon.md:
--------------------------------------------------------------------------------
1 | # Trailing Semicolon
2 |
3 | Rule `trailing-semicolon` will enforce whether the last declaration in a block should include a semicolon (`;`) or not (`.sass` syntax excluded).
4 |
5 | ## Options
6 |
7 | * `include`: `true`/`false` (defaults to `true`)
8 |
9 | ## Examples
10 |
11 | When `include: true`, the following are allowed. When `include: false`, the following are disallowed:
12 |
13 | ```scss
14 | .foo {
15 | content: 'bar';
16 | content: 'baz';
17 |
18 | .waldo {
19 | content: 'where';
20 | }
21 | }
22 | ```
23 |
24 | When `include: false`, the following are allowed. When `include: true`, the following are disallowed:
25 |
26 | ```scss
27 | .foo {
28 | content: 'bar';
29 | content: 'baz'
30 |
31 | .waldo {
32 | content: 'where'
33 | }
34 | }
35 | ```
36 |
--------------------------------------------------------------------------------
/lib/rules/no-trailing-zero.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var helpers = require('../helpers');
4 |
5 | var trailingZeroRegex = /^(\d+\.|\.)+(\d*?)0+$/;
6 |
7 | module.exports = {
8 | 'name': 'no-trailing-zero',
9 | 'defaults': {
10 | 'include': false
11 | },
12 | 'detect': function (ast, parser) {
13 | var result = [];
14 |
15 | ast.traverseByType('number', function (num) {
16 |
17 | if (num.content.match(trailingZeroRegex)) {
18 | result = helpers.addUnique(result, {
19 | 'ruleId': parser.rule.name,
20 | 'line': num.start.line,
21 | 'column': num.start.column,
22 | 'message': 'Don\'t include trailing zeros on numbers',
23 | 'severity': parser.severity
24 | });
25 | }
26 | });
27 |
28 | return result;
29 | }
30 | };
31 |
--------------------------------------------------------------------------------
/docs/rules/no-css-comments.md:
--------------------------------------------------------------------------------
1 | # No CSS Comments
2 |
3 | Rule `no-css-comments` will enforce the use of Sass single-line comments and disallow CSS comments. Bang comments (`/*! */`, will be printed even in minified mode) are still allowed.
4 |
5 | ## Examples
6 |
7 | When enabled the following are allowed:
8 |
9 | ```scss
10 |
11 | // This is a good comment
12 |
13 | // =========
14 | // This is a good comment
15 | // =========
16 |
17 | //////////////////
18 | // This is a good comment
19 | //////////////////
20 |
21 | /*! This is a good bang comment */
22 |
23 | /*!
24 | * This is a good bang comment
25 | **/
26 | ```
27 |
28 | When enabled the following are disallowed:
29 |
30 | ```scss
31 |
32 | /* This comment will appear in your compiled css */
33 |
34 | /*
35 | * Mulitline comments are bad
36 | */
37 | ```
38 |
--------------------------------------------------------------------------------
/tests/sass/no-css-comments.sass:
--------------------------------------------------------------------------------
1 | /* Bad */
2 | .foo
3 | content: ' '
4 |
5 |
6 | /*
7 | * Test Comment
8 | */
9 | .bar
10 | content: ' '
11 |
12 |
13 | // good comment
14 | .baz
15 | content: ' '
16 |
17 |
18 | /* comment */
19 | .qux
20 | content: ' '
21 |
22 |
23 | /*! Single Line Bang Comment */
24 | .bang-1
25 | content: ''
26 |
27 |
28 | // Multiline
29 | Sass
30 | Comment
31 | .bang-2
32 | content: 'bang'
33 |
34 |
35 | /*
36 | * Multiline Comments are bad
37 | */
38 | .test
39 | content: ' '
40 |
41 |
42 | // this is a good comment
43 | .class
44 | content: ' '
45 |
46 |
47 | // =========
48 | // This is a good comment
49 | // =========
50 | .blip
51 | content: ' '
52 |
53 |
54 | //////////////////
55 | // This is a good comment
56 | //////////////////
57 | .blop
58 | content: ' '
59 |
--------------------------------------------------------------------------------
/tests/sass/space-before-brace.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | content: 'bar';
3 | }
4 |
5 | .bar{
6 | content: 'baz';
7 | }
8 |
9 | .qux {
10 | content: 'bar';
11 | }
12 |
13 | @mixin foo {
14 | content: 'qux';
15 | }
16 |
17 | @mixin bar{
18 | content: 'qux';
19 | }
20 |
21 | .qux {
22 | content: 'bar';
23 | font:{
24 | family: fantasy;
25 | }
26 | @include breakpoint{
27 | content: bar;
28 | font: {
29 | family: fantasy;
30 | }
31 | }
32 | }
33 |
34 |
35 | .other {
36 | content: 'bar';
37 | font: {
38 | family: fantasy;
39 | }
40 | @include breakpoint {
41 | content: bar;
42 | font:{
43 | family: fantasy;
44 | }
45 | }
46 | }
47 |
48 | .selector {
49 | content: '';
50 |
51 | .mergeable {
52 | font: {
53 | family: fantasy;
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/docs/options/max-warnings.md:
--------------------------------------------------------------------------------
1 | # Max warnings
2 |
3 | An error will be thrown if the total number of warnings exceeds the `max-warnings` setting.
4 |
5 | > Please note, if you're using this option with the sass-lint CLI and you're specifying the `--no-exit / -q` option too, you will not see an error but an error code of 1 will still be thrown.
6 |
7 | ## Examples
8 |
9 | This can be set as a command-line option:
10 |
11 | ``` bash
12 | $ sass-lint --max-warnings 50
13 | ```
14 |
15 | In `.sass-lint.yml`:
16 |
17 | ``` yaml
18 | options:
19 | max-warnings: 50
20 | ```
21 |
22 | Or inside a script:
23 |
24 | ``` javascript
25 | var sassLint = require('sass-lint'),
26 | config = {options: {'max-warnings': 50}};
27 |
28 | results = sassLint.lintFiles('sass/**/*.scss', config)
29 | sassLint.failOnError(results, config);
30 | ```
31 |
--------------------------------------------------------------------------------
/tests/sass/force-pseudo-nesting.sass:
--------------------------------------------------------------------------------
1 | // shouldnt generate a nesting warning
2 | input[type='radio']
3 | color: red
4 |
5 | // shouldnt generate a nesting warning
6 | div p
7 | padding: 0
8 |
9 | // pseudo class should be nested
10 | p:last-child
11 | margin: 0
12 |
13 | // pseudo class should be nested
14 | p:nth-of-type(2)
15 | margin: 0
16 |
17 | // pseudo class should be nested
18 | input:read-only
19 | content: ''
20 |
21 | // pseudo element should be nested with the parent ident
22 | p::first-line
23 | color: #ff0000
24 | font-variant: small-caps
25 |
26 | .parent
27 | .child
28 | p::first-line
29 | color: #ff0000
30 |
31 | .parent
32 | .child
33 | .sub p::first-line
34 | color: #ff0000
35 |
36 | .parent
37 | .child
38 | .sub p
39 | &::first-line
40 | color: #ff0000
41 |
--------------------------------------------------------------------------------
/tests/helpers/stripBom.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var assert = require('assert'),
4 | helpers = require('../../lib/helpers'),
5 | fs = require('fs');
6 |
7 | describe('helpers - stripBom', function () {
8 |
9 | //////////////////////////////
10 | // Strip BOM
11 | //////////////////////////////
12 |
13 | it('should remove the BOM marker', function (done) {
14 | var file = fs.readFileSync('tests/bom-utf8/starts-with-mixin-utf8-bom.scss').toString();
15 | assert.equal(file.charCodeAt(0), 0xFEFF);
16 | assert.notEqual(helpers.stripBom(file).charCodeAt(0), 0xFEFF);
17 | done();
18 | });
19 |
20 | it('should throw an error if not passed a string', function (done) {
21 | assert.throws(
22 | function () {
23 | helpers.stripBom(8);
24 | }, Error
25 | );
26 | done();
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/tests/sass/no-transition-all.sass:
--------------------------------------------------------------------------------
1 | .test-single-pass
2 | -webkit-transition: width 2s
3 | transition: width 2s
4 |
5 | .test-single-fail
6 | -webkit-transition: all 2s
7 | transition: all 2s
8 |
9 | .test-mutliple-pass
10 | -webkit-transition: width 2s, height 2s, background-color 2s, -webkit-transform 2s
11 | transition: width 2s, height 2s, background-color 2s, transform 2s
12 |
13 | .test-mutliple-fail
14 | -webkit-transition: all 2s, height 2s, background-color 2s, -webkit-transform 2s
15 | transition: width 2s, height 2s, all 2s, transform 2s
16 |
17 | .test-trans-property-pass
18 | transition-property: none
19 | transition-property: width
20 | transition-property: test_05
21 | transition-property: -specific
22 | transition-property: sliding-vertically
23 |
24 | .test-trans-property-fail
25 | transition-property: all
26 |
--------------------------------------------------------------------------------
/docs/rules/space-before-brace.md:
--------------------------------------------------------------------------------
1 | # Space Before Brace
2 |
3 | Rule `space-before-brace` will enforce whether or not a space should be included before a brace (`{`).
4 |
5 | ## Options
6 |
7 | * `include`: `true`/`false` (defaults to `true`)
8 |
9 | ## Examples
10 |
11 | When `include: true`, the following are allowed. When `include: false`, the following are disallowed:
12 |
13 | ```scss
14 | .foo {
15 | content: 'bar';
16 |
17 | @include breakpoint {
18 | content: 'baz';
19 | }
20 | }
21 |
22 | @mixin foo {
23 | content: 'bar';
24 | }
25 | ```
26 |
27 | When `include: false`, the following are allowed. When `include: true`, the following are disallowed:
28 |
29 | ```scss
30 | .foo{
31 | content: 'bar';
32 |
33 | @include breakpoint{
34 | content: 'baz';
35 | }
36 | }
37 |
38 | @mixin foo{
39 | content: 'bar';
40 | }
41 | ```
42 |
--------------------------------------------------------------------------------
/lib/rules/no-disallowed-properties.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var helpers = require('../helpers');
4 |
5 | module.exports = {
6 | 'name': 'no-disallowed-properties',
7 | 'defaults': {
8 | 'properties': []
9 | },
10 | 'detect': function (ast, parser) {
11 | var result = [];
12 |
13 | ast.traverseByType('property', function (node) {
14 | var first = node.first();
15 | if (!first.is('ident') || parser.options.properties.indexOf(first.content) === -1) {
16 | return;
17 | }
18 | result = helpers.addUnique(result, {
19 | 'ruleId': parser.rule.name,
20 | 'line': node.start.line,
21 | 'column': node.start.column,
22 | 'message': 'Property `' + first.content + '` should not be used',
23 | 'severity': parser.severity
24 | });
25 | });
26 | return result;
27 | }
28 | };
29 |
--------------------------------------------------------------------------------
/tests/rules/trailing-semicolon.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('trailing semicolon - scss', function () {
9 | var file = lint.file('trailing-semicolon.scss');
10 |
11 | it('[include: true]', function (done) {
12 | lint.test(file, {
13 | 'trailing-semicolon': 1
14 | }, function (data) {
15 | lint.assert.equal(9, data.warningCount);
16 | done();
17 | });
18 | });
19 |
20 | it('[include: false]', function (done) {
21 | lint.test(file, {
22 | 'trailing-semicolon': [
23 | 1,
24 | {
25 | 'include': false
26 | }
27 | ]
28 | }, function (data) {
29 | lint.assert.equal(5, data.warningCount);
30 | done();
31 | });
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 | What version of Sass Lint are you using?
12 |
13 | Please include any relevant parts of your configuration
14 |
15 | What did you do? Please include the actual source code causing the issue.
16 |
17 | What did you expect to happen?
18 |
19 | What actually happened? Please include any error messages given to you by Sass Lint.
20 |
21 | If you're using a IDE plugin have you tried the CLI too?
22 |
--------------------------------------------------------------------------------
/tests/rules/space-before-brace.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('space before brace - scss', function () {
9 | var file = lint.file('space-before-brace.scss');
10 |
11 | it('[include: true]', function (done) {
12 | lint.test(file, {
13 | 'space-before-brace': 1
14 | }, function (data) {
15 | lint.assert.equal(5, data.warningCount);
16 | done();
17 | });
18 | });
19 |
20 | it('[include: false]', function (done) {
21 | lint.test(file, {
22 | 'space-before-brace': [
23 | 1,
24 | {
25 | 'include': false
26 | }
27 | ]
28 | }, function (data) {
29 | lint.assert.equal(11, data.warningCount);
30 | done();
31 | });
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/tests/sass/no-color-keywords.scss:
--------------------------------------------------------------------------------
1 | .literal {
2 | color: mediumslateblue;
3 | }
4 |
5 | .linear-gradient-func {
6 | background: linear-gradient(top, #fff, white);
7 | }
8 |
9 | .box-shadow {
10 | box-shadow: 1px 1px black, 1px 1px black;
11 | }
12 |
13 | .background {
14 | background: 1px solid white;
15 | content: 100;
16 | }
17 |
18 | .hex {
19 | color: #fff;
20 | }
21 |
22 | $colors: (
23 | $red: red,
24 | $blue : (
25 | $orange: (
26 | $yellow: yellow
27 | )
28 | )
29 | );
30 |
31 | $literal: mediumslateblue;
32 | $hexVar: #fff;
33 |
34 | $blue: #0050a0;
35 | $brand-primary: $blue;
36 |
37 | $other: rgba($blue, 0.3);
38 |
39 | // Issue #717 - rule trips over Sass color function names
40 | $colors: (
41 | 'red': red($color),
42 | 'green': green($color),
43 | 'blue': blue($color)
44 | );
45 |
46 | $badge-bg: var(--red);
47 |
--------------------------------------------------------------------------------
/lib/rules/url-quotes.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var helpers = require('../helpers');
4 |
5 | var isVarRegex = /^[$]/;
6 |
7 | module.exports = {
8 | 'name': 'url-quotes',
9 | 'defaults': {},
10 | 'detect': function (ast, parser) {
11 | var result = [];
12 |
13 | ast.traverseByType('uri', function (node) {
14 | node.traverse(function (item) {
15 | if (item.is('raw')) {
16 | if (!item.content.match(isVarRegex)) {
17 | result = helpers.addUnique(result, {
18 | 'ruleId': parser.rule.name,
19 | 'severity': parser.severity,
20 | 'line': item.start.line,
21 | 'column': item.start.column,
22 | 'message': 'Quotes around URLs are required'
23 | });
24 | }
25 | }
26 | });
27 | });
28 |
29 | return result;
30 | }
31 | };
32 |
--------------------------------------------------------------------------------
/tests/sass/clean-import-paths.scss:
--------------------------------------------------------------------------------
1 | // Clean paths
2 | @import 'foo';
3 | @import 'bar/foo';
4 |
5 | // Only filename extensions
6 | @import 'foo.scss';
7 | @import 'bar/foo.scss';
8 |
9 | // Only leading underscores
10 | @import '_foo';
11 | @import 'bar/_foo';
12 |
13 | // Both leading underscores and filename extensions
14 | @import '_foo.scss';
15 | @import 'bar/_foo.scss';
16 |
17 | // CSS imports - ignore
18 | @import url('fineprint.css');
19 | @import url('bluish.css') projection, tv;
20 | @import 'custom.css';
21 | @import url('chrome://communicator/skin/');
22 | @import 'common.css' screen, projection;
23 | @import url('landscape.css') screen and (orientation: landscape);
24 |
25 | @if variable-exists(google-fonts-url) {
26 | @import url($google-fonts-url);
27 | }
28 |
29 | // Test dot in filename
30 | @import '../../node_modules/inuit-normalize/generic.normalize';
31 |
--------------------------------------------------------------------------------
/tests/sass/no-css-comments.scss:
--------------------------------------------------------------------------------
1 | /* Bad */
2 | .foo {
3 | content: ' ';
4 | }
5 |
6 | /*
7 | * Test Comment
8 | */
9 | .bar {
10 | content: ' ';
11 | }
12 |
13 | // good comment
14 | .baz {
15 | content: ' ';
16 | }
17 |
18 | /* comment */
19 | .qux {
20 | content: ' ';
21 | }
22 |
23 | /*! Single Line Bang Comment */
24 | .bang-1 {
25 | content: '';
26 | }
27 |
28 | /*!
29 | * Multiline Bang Comment
30 | **/
31 | .bang-2 {
32 | content: 'bang';
33 | }
34 |
35 | /*
36 | * Multiline Comments are bad
37 | */
38 | .test {
39 | content: ' ';
40 | }
41 |
42 | // this is a good comment
43 | .class {
44 | content: ' ';
45 | }
46 |
47 | // =========
48 | // This is a good comment
49 | // =========
50 | .blip {
51 | content: ' ';
52 | }
53 |
54 | //////////////////
55 | // This is a good comment
56 | //////////////////
57 | .blop {
58 | content: ' ';
59 | }
60 |
--------------------------------------------------------------------------------
/tests/rules/_lint.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('../../index'),
4 | assert = require('assert'),
5 | fs = require('fs'),
6 | path = require('path');
7 |
8 | module.exports.file = function (file) {
9 | var result = {};
10 | file = path.join(process.cwd(), 'tests', 'sass', file);
11 |
12 | result = {
13 | 'text': fs.readFileSync(file),
14 | 'format': path.extname(file).replace('.', ''),
15 | 'filename': path.basename(file)
16 | };
17 |
18 | return result;
19 | };
20 |
21 | module.exports.test = function (text, options, cb) {
22 | var results;
23 |
24 | options = {
25 | 'options': {
26 | 'merge-default-rules': false,
27 | 'cache-config': false
28 | },
29 | 'rules': options
30 | };
31 |
32 | results = lint.lintText(text, options);
33 |
34 | cb(results);
35 | };
36 |
37 | module.exports.assert = assert;
38 |
--------------------------------------------------------------------------------
/tests/rules/no-ids.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('no ids - scss', function () {
9 | var file = lint.file('no-ids.scss');
10 |
11 | it('enforce', function (done) {
12 | lint.test(file, {
13 | 'no-ids': 1
14 | }, function (data) {
15 | lint.assert.equal(2, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
21 | //////////////////////////////
22 | // Sass syntax tests
23 | //////////////////////////////
24 | describe('no ids - sass', function () {
25 | var file = lint.file('no-ids.sass');
26 |
27 | it('enforce', function (done) {
28 | lint.test(file, {
29 | 'no-ids': 1
30 | }, function (data) {
31 | lint.assert.equal(2, data.warningCount);
32 | done();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/tests/rules/no-warn.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('no warn - scss', function () {
9 | var file = lint.file('no-warn.scss');
10 |
11 | it('enforce', function (done) {
12 | lint.test(file, {
13 | 'no-warn': 1
14 | }, function (data) {
15 | lint.assert.equal(3, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
21 | //////////////////////////////
22 | // Sass syntax tests
23 | //////////////////////////////
24 | describe('no warn - sass', function () {
25 | var file = lint.file('no-warn.sass');
26 |
27 | it('enforce', function (done) {
28 | lint.test(file, {
29 | 'no-warn': 1
30 | }, function (data) {
31 | lint.assert.equal(3, data.warningCount);
32 | done();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/tests/sass/max-line-length.sass:
--------------------------------------------------------------------------------
1 | .really--long--class-name--that-unfortunately--isnt--very--succint--and-looks-stupid
2 | color: red
3 |
4 | @function($aReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongVariableName)
5 | @return 'test'
6 |
7 | // ==============================================================================
8 | //
9 | // This comment is too long clearly, we should probably make sure we have a rule to
10 | // determine when we breach this length
11 | //
12 | // ==============================================================================
13 |
14 |
15 | // =============================================================================
16 | //
17 | // This comment comment on the other hand should be the perfect length, unless a
18 | // user decides to make their max line length === 79!
19 | //
20 | // =============================================================================
21 |
--------------------------------------------------------------------------------
/tests/rules/no-debug.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('no debug - scss', function () {
9 | var file = lint.file('no-debug.scss');
10 |
11 | it('enforce', function (done) {
12 | lint.test(file, {
13 | 'no-debug': 1
14 | }, function (data) {
15 | lint.assert.equal(3, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
21 | //////////////////////////////
22 | // Sass syntax tests
23 | //////////////////////////////
24 | describe('no debug - sass', function () {
25 | var file = lint.file('no-debug.sass');
26 |
27 | it('enforce', function (done) {
28 | lint.test(file, {
29 | 'no-debug': 1
30 | }, function (data) {
31 | lint.assert.equal(3, data.warningCount);
32 | done();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/tests/sass/no-transition-all.scss:
--------------------------------------------------------------------------------
1 | .test-single-pass {
2 | -webkit-transition: width 2s;
3 | transition: width 2s;
4 | }
5 |
6 | .test-single-fail {
7 | -webkit-transition: all 2s;
8 | transition: all 2s;
9 | }
10 |
11 | .test-mutliple-pass {
12 | -webkit-transition: width 2s, height 2s, background-color 2s, -webkit-transform 2s;
13 | transition: width 2s, height 2s, background-color 2s, transform 2s;
14 | }
15 |
16 | .test-mutliple-fail {
17 | -webkit-transition: all 2s, height 2s, background-color 2s, -webkit-transform 2s;
18 | transition: width 2s, height 2s, all 2s, transform 2s;
19 | }
20 |
21 | .test-trans-property-pass {
22 | transition-property: none;
23 | transition-property: width;
24 | transition-property: test_05;
25 | transition-property: -specific;
26 | transition-property: sliding-vertically;
27 | }
28 |
29 | .test-trans-property-fail {
30 | transition-property: all;
31 | }
32 |
--------------------------------------------------------------------------------
/lib/rules/max-line-length.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var helpers = require('../helpers');
4 |
5 | module.exports = {
6 | 'name': 'max-line-length',
7 | 'defaults': {
8 | length: 80
9 | },
10 | 'detect': function (ast, parser) {
11 | var result = [];
12 |
13 | ast.traverseByType('space', function (space) {
14 | var lineLength = 0;
15 | if (helpers.hasEOL(space.content)) {
16 | lineLength = space.start.column - 1;
17 | }
18 |
19 | if (lineLength > parser.options.length) {
20 | result = helpers.addUnique(result, {
21 | 'ruleId': parser.rule.name,
22 | 'severity': parser.severity,
23 | 'line': space.start.line,
24 | 'column': 0,
25 | 'message': 'line ' + space.start.line + ' exceeds the maximum line length of ' + parser.options.length
26 | });
27 | }
28 | });
29 |
30 | return result;
31 | }
32 | };
33 |
--------------------------------------------------------------------------------
/tests/rules/no-extends.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('no extends - scss', function () {
9 | var file = lint.file('no-extends.scss');
10 |
11 | it('enforce', function (done) {
12 | lint.test(file, {
13 | 'no-extends': 1
14 | }, function (data) {
15 | lint.assert.equal(1, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
21 | //////////////////////////////
22 | // Sass syntax tests
23 | //////////////////////////////
24 | describe('no extends - sass', function () {
25 | var file = lint.file('no-extends.sass');
26 |
27 | it('enforce', function (done) {
28 | lint.test(file, {
29 | 'no-extends': 1
30 | }, function (data) {
31 | lint.assert.equal(1, data.warningCount);
32 | done();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/tests/rules/url-quotes.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('url quotes - scss', function () {
9 | var file = lint.file('url-quotes.scss');
10 |
11 | it('enforce', function (done) {
12 | lint.test(file, {
13 | 'url-quotes': 1
14 | }, function (data) {
15 | lint.assert.equal(1, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
21 | //////////////////////////////
22 | // Sass syntax tests
23 | //////////////////////////////
24 | describe('url quotes - sass', function () {
25 | var file = lint.file('url-quotes.sass');
26 |
27 | it('enforce', function (done) {
28 | lint.test(file, {
29 | 'url-quotes': 1
30 | }, function (data) {
31 | lint.assert.equal(1, data.warningCount);
32 | done();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/tests/sass/id-name-format.scss:
--------------------------------------------------------------------------------
1 | #hyphenated-lowercase {
2 | content: '';
3 | }
4 |
5 | #snake_case {
6 | content: '';
7 | }
8 |
9 | #camelCase {
10 | content: '';
11 | }
12 |
13 | #PascalCase {
14 | content: '';
15 |
16 | #Camel_Snake_Case {
17 | content: '';
18 |
19 | #SCREAMING_SNAKE_CASE {
20 | content: '';
21 | }
22 | }
23 | }
24 |
25 | #_with-leading-underscore {
26 | content: '';
27 | }
28 |
29 | #_does_NOT-fitSTANDARD {
30 | @extend #snake_case;
31 | }
32 |
33 | #hyphentated-lowercase {
34 | color: blue;
35 |
36 | &-with-suffix-extension {
37 | color: green;
38 |
39 | &-and-another {
40 | color: red;
41 | }
42 | }
43 |
44 | &-INVALID {
45 | color: pink;
46 | }
47 | }
48 |
49 | #one_parent,
50 | #two_parents,
51 | #third-invalid-parent {
52 | width: 10px;
53 |
54 | &_valid_child,
55 | &-invalid-child {
56 | height: 10px;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/tests/sass/max-line-length.scss:
--------------------------------------------------------------------------------
1 | .really--long--class-name--that-unfortunately--isnt--very--succint--and-looks-stupid {
2 | color: red;
3 | }
4 |
5 | @function($aReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLongVariableName) {
6 | @return 'test';
7 | }
8 |
9 | // ==============================================================================
10 | //
11 | // This comment is too long clearly, we should probably make sure we have a rule to
12 | // determine when we breach this length
13 | //
14 | // ==============================================================================
15 |
16 |
17 | // =============================================================================
18 | //
19 | // This comment comment on the other hand should be the perfect length, unless a
20 | // user decides to make their max line length === 79!
21 | //
22 | // =============================================================================
23 |
--------------------------------------------------------------------------------
/tests/sass/variable-for-property.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | content: $content
3 | margin: $margin
4 |
5 | &__element
6 | margin: $margin
7 |
8 |
9 |
10 | =blue()
11 | margin: $margin
12 |
13 |
14 | .bar
15 | content: ' '
16 | margin: 0
17 |
18 | &__element
19 | margin: 0
20 |
21 |
22 |
23 | =red()
24 | margin: 0
25 |
26 | .test
27 | background: inherit
28 | background: initial
29 | background: transparent
30 | background: none
31 |
32 | // Issue #714 - !important and spaces were classed as erroneous value types
33 | .non-issue
34 | color: $gray-chateau !important
35 |
36 | .issue
37 | color: red !important
38 |
39 | .test
40 | color: map-get($blue)
41 |
42 | .interp-test
43 | color: #{var}
44 |
45 | // ensure interp is not flagged
46 |
47 | .func-name-test
48 | color: my-map-func(blue, light)
49 |
50 | .custom-prop
51 | // ensure custom properties are valid
52 | color: var(--my-prop)
53 |
--------------------------------------------------------------------------------
/tests/rules/no-color-hex.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('no color hex - scss', function () {
9 | var file = lint.file('no-color-hex.scss');
10 |
11 | it('enforce', function (done) {
12 | lint.test(file, {
13 | 'no-color-hex': 1
14 | }, function (data) {
15 | lint.assert.equal(9, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
21 | //////////////////////////////
22 | // Sass syntax tests
23 | //////////////////////////////
24 | describe('no color hex - sass', function () {
25 | var file = lint.file('no-color-hex.sass');
26 |
27 | it('enforce', function (done) {
28 | lint.test(file, {
29 | 'no-color-hex': 1
30 | }, function (data) {
31 | lint.assert.equal(9, data.warningCount);
32 | done();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/tests/rules/no-important.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('no important - scss', function () {
9 | var file = lint.file('no-important.scss');
10 |
11 | it('enforce', function (done) {
12 | lint.test(file, {
13 | 'no-important': 1
14 | }, function (data) {
15 | lint.assert.equal(1, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
21 | //////////////////////////////
22 | // Sass syntax tests
23 | //////////////////////////////
24 | describe('no important - sass', function () {
25 | var file = lint.file('no-important.sass');
26 |
27 | it('enforce', function (done) {
28 | lint.test(file, {
29 | 'no-important': 1
30 | }, function (data) {
31 | lint.assert.equal(1, data.warningCount);
32 | done();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/tests/sass/single-line-per-selector.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | content: 'foo'
3 |
4 |
5 | .foo.boo
6 | content: 'foo'
7 |
8 |
9 | .foo, .boo
10 | content: 'foo'
11 |
12 |
13 | .foo,.boo
14 | content: 'foo'
15 |
16 |
17 | .foo,
18 | .boo
19 | content: 'foo'
20 |
21 |
22 | .foo > a,.bar
23 | content: 'baz'
24 |
25 |
26 | .foo,
27 | .bar
28 | content: 'baz'
29 |
30 | .baz,
31 | .qux
32 | content: 'qux'
33 |
34 |
35 | .fail, .blog
36 | content: 'cats'
37 |
38 |
39 | .where,
40 | .waldo, .qux
41 | content: 'found'
42 |
43 | .foo
44 | .bar &,
45 | .baz &
46 | content: 'foo'
47 |
48 | .foo
49 | .bar &, .baz &
50 | content: 'foo'
51 |
52 | // Issue #789 - Issue with comments being warned as selector content on single lines
53 | button,
54 | html,
55 | html input[type='button'], // 6
56 | input[type='reset'],
57 | input[type='submit']
58 | -webkit-appearance: button; // 7
59 | cursor: pointer; // 8
60 |
--------------------------------------------------------------------------------
/docs/rules/hex-notation.md:
--------------------------------------------------------------------------------
1 | # Hex Notation
2 |
3 | Rule `hex-notation` will enforce the case of hexadecimal values
4 |
5 | ## Options
6 |
7 | * `style`: `lowercase`/`uppercase` (defaults to `lowercase`)
8 |
9 | ## Examples
10 |
11 | When `style: lowercase`, the following are allowed. When `style: uppercase`, the following are disallowed:
12 |
13 | ```scss
14 | $foo-color: #fff;
15 |
16 | .bar {
17 | background: linear-gradient(top, #cc2, #44d);
18 | }
19 |
20 | .baz {
21 | color: #12a;
22 | }
23 | ```
24 |
25 | When `style: uppercase`, the following are allowed. When `style: lowercase`, the following are disallowed:
26 |
27 | ```scss
28 | $foo-color: #FFF;
29 |
30 | .bar {
31 | background: linear-gradient(top, #CC2, #44D);
32 | }
33 |
34 | .baz {
35 | color: #12A;
36 | }
37 | ```
38 |
39 | In both cases the following will be allowed as the values contain only numbers:
40 |
41 | ```scss
42 | .qux {
43 | color: #123;
44 | }
45 | ```
46 |
--------------------------------------------------------------------------------
/tests/rules/no-url-domains.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('no url domains - scss', function () {
9 | var file = lint.file('no-url-domains.scss');
10 |
11 | it('enforce', function (done) {
12 | lint.test(file, {
13 | 'no-url-domains': 1
14 | }, function (data) {
15 | lint.assert.equal(3, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
21 | //////////////////////////////
22 | // Sass syntax tests
23 | //////////////////////////////
24 | describe('no url domains - sass', function () {
25 | var file = lint.file('no-url-domains.sass');
26 |
27 | it('enforce', function (done) {
28 | lint.test(file, {
29 | 'no-url-domains': 1
30 | }, function (data) {
31 | lint.assert.equal(3, data.warningCount);
32 | done();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/tests/rules/no-combinators.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('no combinators - scss', function () {
9 | var file = lint.file('no-combinators.scss');
10 |
11 | it('enforce', function (done) {
12 | lint.test(file, {
13 | 'no-combinators': 1
14 | }, function (data) {
15 | lint.assert.equal(23, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
21 | //////////////////////////////
22 | // Sass syntax tests
23 | //////////////////////////////
24 | describe('no combinators - sass', function () {
25 | var file = lint.file('no-combinators.sass');
26 |
27 | it('enforce', function (done) {
28 | lint.test(file, {
29 | 'no-combinators': 1
30 | }, function (data) {
31 | lint.assert.equal(23, data.warningCount);
32 | done();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/tests/rules/no-invalid-hex.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('no invalid hex - scss', function () {
9 | var file = lint.file('no-invalid-hex.scss');
10 |
11 | it('enforce', function (done) {
12 | lint.test(file, {
13 | 'no-invalid-hex': 1
14 | }, function (data) {
15 | lint.assert.equal(16, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
21 | //////////////////////////////
22 | // Sass syntax tests
23 | //////////////////////////////
24 | describe('no invalid hex - sass', function () {
25 | var file = lint.file('no-invalid-hex.sass');
26 |
27 | it('enforce', function (done) {
28 | lint.test(file, {
29 | 'no-invalid-hex': 1
30 | }, function (data) {
31 | lint.assert.equal(16, data.warningCount);
32 | done();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/docs/rules/hex-length.md:
--------------------------------------------------------------------------------
1 | # Hex Length
2 |
3 | Rule `hex-length` will enforce the length of hexadecimal values
4 |
5 | ## Options
6 |
7 | * `style`: `short`/`long` (defaults to `short`)
8 |
9 | ## Examples
10 |
11 | When `style: short`, the following are allowed. When `style: long`, the following are disallowed:
12 |
13 | ```scss
14 | $foo-color: #456;
15 |
16 | .bar {
17 | background: linear-gradient(top, #3ff, #ddd);
18 | }
19 |
20 | .baz {
21 | color: #fff;
22 | }
23 | ```
24 |
25 | When `style: long`, the following are allowed. When `style: short`, the following are disallowed:
26 |
27 | ```scss
28 | $foo-color: #445566;
29 |
30 | .bar {
31 | background: linear-gradient(top, #33ffff, #dddddd);
32 | }
33 |
34 | .baz {
35 | color: #ffffff;
36 | }
37 | ```
38 |
39 | In both cases the following will be allowed as the values cannot be shortened:
40 |
41 | ```scss
42 | $quz-color: #abcdef;
43 |
44 | .qux {
45 | color: #123456;
46 | }
47 | ```
48 |
--------------------------------------------------------------------------------
/tests/rules/no-css-comments.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('no css comments - scss', function () {
9 | var file = lint.file('no-css-comments.scss');
10 |
11 | it('enforce', function (done) {
12 | lint.test(file, {
13 | 'no-css-comments': 1
14 | }, function (data) {
15 | lint.assert.equal(4, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
21 | //////////////////////////////
22 | // Sass syntax tests
23 | //////////////////////////////
24 | describe('no css comments - sass', function () {
25 | var file = lint.file('no-css-comments.sass');
26 |
27 | it('enforce', function (done) {
28 | lint.test(file, {
29 | 'no-css-comments': 1
30 | }, function (data) {
31 | lint.assert.equal(4, data.warningCount);
32 | done();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/docs/rules/force-pseudo-nesting.md:
--------------------------------------------------------------------------------
1 | # Force Pseudo Nesting
2 |
3 | Rule `force-pseudo-nesting` will enforce the nesting of pseudo elements/classes.
4 |
5 |
6 | ## Examples
7 |
8 | When enabled, the following are disallowed:
9 | ```scss
10 | p:nth-of-type(2) {
11 | margin: 0;
12 | }
13 |
14 | .parent {
15 | .child {
16 | p::first-line {
17 | color: #ff0000;
18 | }
19 | }
20 | }
21 |
22 | .parent {
23 | .child {
24 | .sub p::first-line {
25 | color: #ff0000;
26 | }
27 | }
28 | }
29 | ```
30 |
31 | When enabled, the following are allowed:
32 |
33 | ```scss
34 | p {
35 | &:nth-of-type(2) {
36 | margin: 0;
37 | }
38 | }
39 |
40 | .parent {
41 | .child {
42 | p {
43 | &::first-line {
44 | color: #ff0000;
45 | }
46 | }
47 | }
48 | }
49 |
50 | .parent {
51 | .child {
52 | .sub p {
53 | &::first-line {
54 | color: #ff0000;
55 | }
56 | }
57 | }
58 | }
59 | ```
60 |
--------------------------------------------------------------------------------
/tests/helpers/getMessageType.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var assert = require('assert'),
4 | helpers = require('../../lib/helpers');
5 |
6 | describe('helpers - getMessageType', function () {
7 |
8 | //////////////////////////////
9 | // Get Message Type
10 | //////////////////////////////
11 |
12 | it('getMessageType - [severity: 1]', function (done) {
13 | var result = helpers.getMessageType({severity: 1}),
14 | expect = 'warning';
15 |
16 | assert.equal(expect, result);
17 | done();
18 | });
19 |
20 | it('getMessageType - [severity: 2]', function (done) {
21 | var result = helpers.getMessageType({severity: 2}),
22 | expect = 'error';
23 |
24 | assert.equal(expect, result);
25 | done();
26 | });
27 | it('getMessageType - []', function (done) {
28 | var result = helpers.getMessageType({}),
29 | expect = 'warning';
30 |
31 | assert.equal(expect, result);
32 | done();
33 | });
34 | });
35 |
--------------------------------------------------------------------------------
/tests/rules/no-trailing-zero.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('no trailing zero - scss', function () {
9 | var file = lint.file('no-trailing-zero.scss');
10 |
11 | it('enforce', function (done) {
12 | lint.test(file, {
13 | 'no-trailing-zero': 1
14 | }, function (data) {
15 | lint.assert.equal(8, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
21 | //////////////////////////////
22 | // Sass syntax tests
23 | //////////////////////////////
24 | describe('no trailing zero - sass', function () {
25 | var file = lint.file('no-trailing-zero.sass');
26 |
27 | it('enforce', function (done) {
28 | lint.test(file, {
29 | 'no-trailing-zero': 1
30 | }, function (data) {
31 | lint.assert.equal(8, data.warningCount);
32 | done();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/tests/rules/no-color-keywords.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('no color keywords - scss', function () {
9 | var file = lint.file('no-color-keywords.scss');
10 |
11 | it('enforce', function (done) {
12 | lint.test(file, {
13 | 'no-color-keywords': 1
14 | }, function (data) {
15 | lint.assert.equal(8, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
21 | //////////////////////////////
22 | // Sass syntax tests
23 | //////////////////////////////
24 | describe('no color keywords - sass', function () {
25 | var file = lint.file('no-color-keywords.sass');
26 |
27 | it('enforce', function (done) {
28 | lint.test(file, {
29 | 'no-color-keywords': 1
30 | }, function (data) {
31 | lint.assert.equal(8, data.warningCount);
32 | done();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/tests/rules/no-transition-all.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('no transition all - scss', function () {
9 | var file = lint.file('no-transition-all.scss');
10 |
11 | it('enforce', function (done) {
12 | lint.test(file, {
13 | 'no-transition-all': 1
14 | }, function (data) {
15 | lint.assert.equal(5, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
21 | //////////////////////////////
22 | // Sass syntax tests
23 | //////////////////////////////
24 | describe('no transition all - sass', function () {
25 | var file = lint.file('no-transition-all.sass');
26 |
27 | it('enforce', function (done) {
28 | lint.test(file, {
29 | 'no-transition-all': 1
30 | }, function (data) {
31 | lint.assert.equal(5, data.warningCount);
32 | done();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/tests/rules/extends-before-mixins.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('extends before mixins - scss', function () {
9 | var file = lint.file('extends-before-mixins.scss');
10 |
11 | it('enforce', function (done) {
12 | lint.test(file, {
13 | 'extends-before-mixins': 1
14 | }, function (data) {
15 | lint.assert.equal(2, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
21 | //////////////////////////////
22 | // Sass syntax tests
23 | //////////////////////////////
24 | describe('extends before mixins - sass', function () {
25 | var file = lint.file('extends-before-mixins.sass');
26 |
27 | it('enforce', function (done) {
28 | lint.test(file, {
29 | 'extends-before-mixins': 1
30 | }, function (data) {
31 | lint.assert.equal(2, data.warningCount);
32 | done();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/tests/rules/force-pseudo-nesting.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('force pseudo nesting - scss', function () {
9 | var file = lint.file('force-pseudo-nesting.scss');
10 |
11 | it('[default]', function (done) {
12 | lint.test(file, {
13 | 'force-pseudo-nesting': 1
14 | }, function (data) {
15 | lint.assert.equal(6, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
21 | //////////////////////////////
22 | // Sass syntax tests
23 | //////////////////////////////
24 | describe('force pseudo nesting - sass', function () {
25 | var file = lint.file('force-pseudo-nesting.sass');
26 |
27 | it('[default]', function (done) {
28 | lint.test(file, {
29 | 'force-pseudo-nesting': 1
30 | }, function (data) {
31 | lint.assert.equal(6, data.warningCount);
32 | done();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/tests/rules/placeholder-in-extend.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('placeholder in extend - scss', function () {
9 | var file = lint.file('placeholder-in-extend.scss');
10 |
11 | it('enforce', function (done) {
12 | lint.test(file, {
13 | 'placeholder-in-extend': 1
14 | }, function (data) {
15 | lint.assert.equal(1, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
21 | //////////////////////////////
22 | // Sass syntax tests
23 | //////////////////////////////
24 | describe('placeholder in extend - sass', function () {
25 | var file = lint.file('placeholder-in-extend.sass');
26 |
27 | it('enforce', function (done) {
28 | lint.test(file, {
29 | 'placeholder-in-extend': 1
30 | }, function (data) {
31 | lint.assert.equal(1, data.warningCount);
32 | done();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/tests/rules/force-element-nesting.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('force element nesting - scss', function () {
9 | var file = lint.file('force-element-nesting.scss');
10 |
11 | it('[default]', function (done) {
12 | lint.test(file, {
13 | 'force-element-nesting': 1
14 | }, function (data) {
15 | lint.assert.equal(10, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
21 | //////////////////////////////
22 | // Sass syntax tests
23 | //////////////////////////////
24 | describe('force element nesting - sass', function () {
25 | var file = lint.file('force-element-nesting.sass');
26 |
27 | it('[default]', function (done) {
28 | lint.test(file, {
29 | 'force-element-nesting': 1
30 | }, function (data) {
31 | lint.assert.equal(10, data.warningCount);
32 | done();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/tests/rules/no-attribute-selectors.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('no attribute selectors - scss', function () {
9 | var file = lint.file('no-attribute-selectors.scss');
10 |
11 | it('enforce', function (done) {
12 | lint.test(file, {
13 | 'no-attribute-selectors': 1
14 | }, function (data) {
15 | lint.assert.equal(21, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
21 | //////////////////////////////
22 | // Sass syntax tests
23 | //////////////////////////////
24 | describe('no attribute selectors - sass', function () {
25 | var file = lint.file('no-attribute-selectors.sass');
26 |
27 | it('enforce', function (done) {
28 | lint.test(file, {
29 | 'no-attribute-selectors': 1
30 | }, function (data) {
31 | lint.assert.equal(21, data.warningCount);
32 | done();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/tests/rules/no-trailing-whitespace.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('no trailing whitespace - scss', function () {
9 | var file = lint.file('no-trailing-whitespace.scss');
10 |
11 | it('enforce', function (done) {
12 | lint.test(file, {
13 | 'no-trailing-whitespace': 1
14 | }, function (data) {
15 | lint.assert.equal(5, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
21 | //////////////////////////////
22 | // Sass syntax tests
23 | //////////////////////////////
24 | describe('no trailing whitespace - sass', function () {
25 | var file = lint.file('no-trailing-whitespace.sass');
26 |
27 | it('enforce', function (done) {
28 | lint.test(file, {
29 | 'no-trailing-whitespace': 1
30 | }, function (data) {
31 | lint.assert.equal(5, data.warningCount);
32 | done();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/tests/rules/no-universal-selectors.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('no universal selectors - scss', function () {
9 | var file = lint.file('no-universal-selectors.scss');
10 |
11 | it('enforce', function (done) {
12 | lint.test(file, {
13 | 'no-universal-selectors': 1
14 | }, function (data) {
15 | lint.assert.equal(6, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
21 | //////////////////////////////
22 | // Sass syntax tests
23 | //////////////////////////////
24 | describe('no universal selectors - sass', function () {
25 | var file = lint.file('no-universal-selectors.sass');
26 |
27 | it('enforce', function (done) {
28 | lint.test(file, {
29 | 'no-universal-selectors': 1
30 | }, function (data) {
31 | lint.assert.equal(6, data.warningCount);
32 | done();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/lib/groot.js:
--------------------------------------------------------------------------------
1 | //////////////////////////////
2 | // Tree Abstraction
3 | //////////////////////////////
4 | 'use strict';
5 |
6 | var gonzales = require('gonzales-pe');
7 | var matter = require('gray-matter');
8 |
9 | module.exports = function (input, syntax, filename) {
10 | var tree;
11 | var result = matter(input, {});
12 | var text = result.content;
13 |
14 | if (result.matter) {
15 | var emptyLines = new Array(result.matter.split('\n').length + 2).join('\n');
16 | text = emptyLines + result.content;
17 | }
18 |
19 | try {
20 | tree = gonzales.parse(text, {
21 | 'syntax': syntax
22 | });
23 | }
24 | catch (e) {
25 | throw {
26 | message: e.message,
27 | file: filename,
28 | line: e.line
29 | };
30 | }
31 |
32 | if (typeof tree === 'undefined') {
33 | throw {
34 | message: 'Undefined tree',
35 | file: filename,
36 | text: text.toString(),
37 | tree: tree.toString()
38 | };
39 | }
40 |
41 | return tree;
42 | };
43 |
--------------------------------------------------------------------------------
/lib/rules/no-url-domains.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var helpers = require('../helpers'),
4 | url = require('url');
5 |
6 | module.exports = {
7 | 'name': 'no-url-domains',
8 | 'defaults': {},
9 | 'detect': function (ast, parser) {
10 | var result = [];
11 |
12 | ast.traverseByType('uri', function (uri) {
13 | uri.traverse(function (item) {
14 | if (item.is('string')) {
15 | var stripped = helpers.stripQuotes(item.content),
16 | parsedUrl = url.parse(stripped, false, true);
17 |
18 | if (parsedUrl.host && parsedUrl.protocol !== 'data:') {
19 | result = helpers.addUnique(result, {
20 | 'ruleId': parser.rule.name,
21 | 'severity': parser.severity,
22 | 'line': item.end.line,
23 | 'column': item.end.column,
24 | 'message': 'Domains in URLs are disallowed'
25 | });
26 | }
27 | }
28 | });
29 | });
30 |
31 | return result;
32 | }
33 | };
34 |
--------------------------------------------------------------------------------
/tests/rules/force-attribute-nesting.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('force attribute nesting - scss', function () {
9 | var file = lint.file('force-attribute-nesting.scss');
10 |
11 | it('[default]', function (done) {
12 | lint.test(file, {
13 | 'force-attribute-nesting': 1
14 | }, function (data) {
15 | lint.assert.equal(5, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
21 | //////////////////////////////
22 | // Sass syntax tests
23 | //////////////////////////////
24 | describe('force attribute nesting - sass', function () {
25 | var file = lint.file('force-attribute-nesting.sass');
26 |
27 | it('[default]', function (done) {
28 | lint.test(file, {
29 | 'force-attribute-nesting': 1
30 | }, function (data) {
31 | lint.assert.equal(5, data.warningCount);
32 | done();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/tests/rules/single-line-per-selector.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('single line per selector - scss', function () {
9 | var file = lint.file('single-line-per-selector.scss');
10 |
11 | it('enforce', function (done) {
12 | lint.test(file, {
13 | 'single-line-per-selector': 1
14 | }, function (data) {
15 | lint.assert.equal(6, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
21 | //////////////////////////////
22 | // Sass syntax tests
23 | //////////////////////////////
24 | describe('single line per selector - sass', function () {
25 | var file = lint.file('single-line-per-selector.sass');
26 |
27 | it('enforce', function (done) {
28 | lint.test(file, {
29 | 'single-line-per-selector': 1
30 | }, function (data) {
31 | lint.assert.equal(6, data.warningCount);
32 | done();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/tests/sass/selector-helpers/selector-helpers.scss:
--------------------------------------------------------------------------------
1 | .test{
2 | color: red;
3 | }
4 |
5 | #test{
6 | color: red;
7 | }
8 |
9 | %test {
10 | color: red;
11 | }
12 |
13 | .#{test} {
14 | color: red
15 | }
16 |
17 | .test, #test {
18 | color: red;
19 | }
20 |
21 | input[type="text"] {
22 | color: red;
23 | }
24 |
25 | .test > li {
26 | color: red;
27 | }
28 |
29 | span[lang~=en-us] {
30 | color: red;
31 | }
32 |
33 | .block__element-one {
34 | color: red;
35 | }
36 |
37 | @media (max-width: 200px) {
38 | color: red;
39 | }
40 |
41 | ##{$id} {
42 | color: red;
43 | }
44 |
45 | .right-element::-ms-backdrop {
46 | content: "right-prefixed-element";
47 | }
48 |
49 | .wrong-element:selection {
50 | content: "wrong-element";
51 | }
52 |
53 | p:nth-of-type(2) {
54 | margin: 0;
55 | }
56 |
57 | .test {
58 | &__test {
59 | color: red;
60 | }
61 | }
62 |
63 | tr:nth-child(even) {
64 | background: lighten($theme-color-primary, 50%);
65 | }
66 | tr:nth-child(odd) {
67 | background: #FFFFFF;
68 | }
69 |
--------------------------------------------------------------------------------
/lib/rules/one-declaration-per-line.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var helpers = require('../helpers');
4 |
5 | module.exports = {
6 | 'name': 'one-declaration-per-line',
7 | 'defaults': {},
8 | 'detect': function (ast, parser) {
9 | var result = [],
10 | lastLine = {};
11 |
12 | ast.traverseByType('declaration', function (declaration, i, parent) {
13 |
14 | if (declaration.start.line === lastLine.start || declaration.start.line === lastLine.end) {
15 | if (parent.type !== 'arguments') {
16 | result = helpers.addUnique(result, {
17 | 'ruleId': parser.rule.name,
18 | 'line': declaration.start.line,
19 | 'column': declaration.start.column,
20 | 'message': 'Only one declaration allowed per line',
21 | 'severity': parser.severity
22 | });
23 | }
24 | }
25 |
26 | lastLine.start = declaration.start.line;
27 | lastLine.end = declaration.end.line;
28 | });
29 |
30 | return result;
31 | }
32 | };
33 |
--------------------------------------------------------------------------------
/tests/helpers/isNumber.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var assert = require('assert'),
4 | helpers = require('../../lib/helpers');
5 |
6 | describe('helpers - isNumber', function () {
7 |
8 | //////////////////////////////
9 | // isNumber
10 | //////////////////////////////
11 |
12 | it('isNumber - [10 - true]', function (done) {
13 |
14 | var result = helpers.isNumber(10);
15 |
16 | assert.equal(true, result);
17 | done();
18 | });
19 |
20 | it('isNumber - [\'10\' - true]', function (done) {
21 |
22 | var result = helpers.isNumber('10');
23 |
24 | assert.equal(true, result);
25 | done();
26 | });
27 |
28 | it('isNumber - [\'ten\' - false]', function (done) {
29 |
30 | var result = helpers.isNumber('ten');
31 |
32 | assert.equal(false, result);
33 | done();
34 | });
35 |
36 | it('isNumber - [\'ff00ff\' - false]', function (done) {
37 |
38 | var result = helpers.isNumber('ff00ff');
39 |
40 | assert.equal(false, result);
41 | done();
42 | });
43 |
44 | });
45 |
--------------------------------------------------------------------------------
/tests/sass/variable-for-property.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | content: $content;
3 | margin: $margin;
4 |
5 | &__element {
6 | margin: $margin;
7 | }
8 | }
9 |
10 | @mixin blue() {
11 | margin: $margin;
12 | }
13 |
14 | .bar {
15 | content: ' ';
16 | margin: 0;
17 |
18 | &__element {
19 | margin: 0;
20 | }
21 | }
22 |
23 | @mixin red() {
24 | margin: 0;
25 | }
26 |
27 | .test {
28 | background: inherit;
29 | background: initial;
30 | background: transparent;
31 | background: none;
32 | }
33 |
34 | // Issue #714 - !important and spaces were classed as erroneous value types
35 | .t-neutral {
36 | color: $gray-chateau !important;
37 | }
38 |
39 | .t-neutral {
40 | color: red !important;
41 | }
42 |
43 | .test {
44 | color: map-get($blue);
45 | }
46 |
47 | .interp-test {
48 | color: #{var}; // ensure interp is not flagged
49 | }
50 |
51 | .func-name-test {
52 | color: my-map-func(blue, light);
53 | }
54 |
55 | .custom-prop {
56 | color: var(--my-prop); // ensure custom properties are valid
57 | }
58 |
--------------------------------------------------------------------------------
/tests/rules/declarations-before-nesting.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('declarations before nesting - scss', function () {
9 | var file = lint.file('declarations-before-nesting.scss');
10 |
11 | it('enforce', function (done) {
12 | lint.test(file, {
13 | 'declarations-before-nesting': 1
14 | }, function (data) {
15 | lint.assert.equal(4, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
21 | //////////////////////////////
22 | // Sass syntax tests
23 | //////////////////////////////
24 | describe('declarations before nesting - sass', function () {
25 | var file = lint.file('declarations-before-nesting.sass');
26 |
27 | it('enforce', function (done) {
28 | lint.test(file, {
29 | 'declarations-before-nesting': 1
30 | }, function (data) {
31 | lint.assert.equal(4, data.warningCount);
32 | done();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/tests/rules/extends-before-declarations.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var lint = require('./_lint');
4 |
5 | //////////////////////////////
6 | // SCSS syntax tests
7 | //////////////////////////////
8 | describe('extends before declarations - scss', function () {
9 | var file = lint.file('extends-before-declarations.scss');
10 |
11 | it('enforce', function (done) {
12 | lint.test(file, {
13 | 'extends-before-declarations': 1
14 | }, function (data) {
15 | lint.assert.equal(4, data.warningCount);
16 | done();
17 | });
18 | });
19 | });
20 |
21 | //////////////////////////////
22 | // Sass syntax tests
23 | //////////////////////////////
24 | describe('extends before declarations - sass', function () {
25 | var file = lint.file('extends-before-declarations.sass');
26 |
27 | it('enforce', function (done) {
28 | lint.test(file, {
29 | 'extends-before-declarations': 1
30 | }, function (data) {
31 | lint.assert.equal(4, data.warningCount);
32 | done();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
13 |
14 | **What do the changes you have made achieve?**
15 |
16 | **Are there any new warning messages?**
17 |
18 | **Have you written tests?**
19 |
20 | **Have you included relevant documentation**
21 |
22 | **Which issues does this resolve?**
23 |
24 | ``
25 |
--------------------------------------------------------------------------------
/docs/rules/no-invalid-hex.md:
--------------------------------------------------------------------------------
1 | # No Invalid Hex
2 |
3 | Rule `no-invalid-hex` will enforce that only valid of hexadecimal values are written.
4 |
5 | ## Examples
6 |
7 | When enabled any invalid hexadecimal characters will generate a warning/error:
8 |
9 | ```scss
10 |
11 | // must be 3 or 6 characters
12 | $invalid-long: #1234567;
13 | $invalid-med: #1234;
14 | $invalid-short: #12;
15 | $invalid-letters-long: #abcdefg;
16 | $invalid-letters-med: #abcd;
17 | $invalid-letters-short: #ab;
18 | $invalid-mixed-long: #1bcdefg;
19 | $invalid-mixed-med: #1bcd;
20 | $invalid-mixed-short: #1b;
21 | $invalid-mixed-letters-long: #abcdef7;
22 | $invalid-mixed-letters-med: #abc4;
23 | $invalid-mixed-letters-short: #a1;
24 |
25 | // mustn't contain invalid characters
26 | $invalid-character-map: (
27 | invalid-characters-upper-letters: #GHIJKL,
28 | invalid-characters-upper-letters-short: #GHI,
29 | even-more-invalid-map: (
30 | invalid-characters-lower-letters-short: #ghijkl,
31 | invalid-characters-lower-letters-short: #ghi
32 | )
33 | );
34 | ```
35 |
--------------------------------------------------------------------------------
/docs/rules/space-between-parens.md:
--------------------------------------------------------------------------------
1 | # Space Between Parens
2 |
3 | Rule `space-between-parens` will enforce whether or not a space should be included before the first item and after the last item inside parenthesis (`()`).
4 |
5 | ## Options
6 |
7 | * `include`: `true`/`false` (defaults to `false`)
8 |
9 | ## Examples
10 |
11 | When `include: false`, the following are allowed. When `include: true`, the following are disallowed:
12 |
13 | ```scss
14 | @function foo($bar) {
15 | @return $bar;
16 | }
17 |
18 | @mixin bar($baz) {
19 | content: $baz;
20 | }
21 |
22 | .foo {
23 | @include bar('Hello');
24 | content: foo('bar');
25 | width: calc(100% - 10px);
26 | }
27 | ```
28 |
29 | When `include: true`, the following are allowed. When `include: false`, the following are disallowed:
30 |
31 | ```scss
32 | @function foo( $bar ) {
33 | @return $bar;
34 | }
35 |
36 | @mixin bar($baz ) {
37 | content: $baz;
38 | }
39 |
40 | .foo {
41 | @include bar( 'Hello' );
42 | content: foo( 'bar');
43 | width: calc( 100% - 10px);
44 | }
45 | ```
46 |
--------------------------------------------------------------------------------
/tests/sass/single-line-per-selector.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | content: 'foo';
3 | }
4 |
5 | .foo.boo {
6 | content: 'foo';
7 | }
8 |
9 | .foo, .boo {
10 | content: 'foo';
11 | }
12 |
13 | .foo,.boo {
14 | content: 'foo';
15 | }
16 |
17 | .foo,
18 | .boo {
19 | content: 'foo';
20 | }
21 |
22 | .foo > a,.bar {
23 | content: 'baz';
24 | }
25 |
26 | .foo,
27 | .bar {
28 | content: 'baz';
29 |
30 | .baz,
31 | .qux {
32 | content: 'qux';
33 | }
34 |
35 | .fail, .blog {
36 | content: 'cats';
37 | }
38 |
39 | .where,
40 | .waldo, .qux {
41 | content: 'found';
42 | }
43 | }
44 |
45 | .foo {
46 | .bar &,
47 | .baz & {
48 | content: 'foo';
49 | }
50 | }
51 |
52 | .foo {
53 | .bar &, .baz & {
54 | content: 'foo';
55 | }
56 | }
57 |
58 | // Issue #789 - Issue with comments being warned as selector content on single lines
59 | button,
60 | html,
61 | html input[type='button'], // 6
62 | input[type='reset'],
63 | input[type='submit'] {
64 | -webkit-appearance: button; // 7
65 | cursor: pointer; // 8
66 | }
67 |
--------------------------------------------------------------------------------
/tests/helpers/isLowerCase.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var assert = require('assert'),
4 | helpers = require('../../lib/helpers');
5 |
6 | describe('helpers - isLowerCase', function () {
7 |
8 | //////////////////////////////
9 | // isLowerCase
10 | //////////////////////////////
11 |
12 | it('isLowerCase - [\'TEST\' - false]', function (done) {
13 |
14 | var result = helpers.isLowerCase('TEST');
15 |
16 | assert.equal(false, result);
17 | done();
18 | });
19 |
20 | it('isLowerCase - [\'test\' - true]', function (done) {
21 |
22 | var result = helpers.isLowerCase('test');
23 |
24 | assert.equal(true, result);
25 | done();
26 | });
27 |
28 | it('isLowerCase - [abcDEF - false]', function (done) {
29 |
30 | var result = helpers.isLowerCase('abcDEF');
31 |
32 | assert.equal(false, result);
33 | done();
34 | });
35 |
36 | it('isLowerCase - [\'123\' - false]', function (done) {
37 |
38 | var result = helpers.isLowerCase('123');
39 |
40 | assert.equal(false, result);
41 | done();
42 | });
43 | });
44 |
--------------------------------------------------------------------------------
/tests/helpers/isUpperCase.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var assert = require('assert'),
4 | helpers = require('../../lib/helpers');
5 |
6 | describe('helpers - isUpperCase', function () {
7 |
8 | //////////////////////////////
9 | // isUpperCase
10 | //////////////////////////////
11 |
12 | it('isUpperCase - [\'TEST\' - true]', function (done) {
13 |
14 | var result = helpers.isUpperCase('TEST');
15 |
16 | assert.equal(true, result);
17 | done();
18 | });
19 |
20 | it('isUpperCase - [\'test\' - false]', function (done) {
21 |
22 | var result = helpers.isUpperCase('test');
23 |
24 | assert.equal(false, result);
25 | done();
26 | });
27 |
28 | it('isUpperCase - [abcDEF - false]', function (done) {
29 |
30 | var result = helpers.isUpperCase('abcDEF');
31 |
32 | assert.equal(false, result);
33 | done();
34 | });
35 |
36 | it('isUpperCase - [\'123\' - false]', function (done) {
37 |
38 | var result = helpers.isUpperCase('123');
39 |
40 | assert.equal(false, result);
41 | done();
42 | });
43 |
44 | });
45 |
--------------------------------------------------------------------------------
/tests/sass/property-sort-order.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | height: 100vh
3 | display: block
4 | width: 100vw
5 | border: 1px
6 |
7 | .bar
8 | width: 50vw
9 | content: 'baz'
10 | border: 1px
11 | height: 100vw
12 |
13 |
14 | .other-property
15 | composes: heading
16 | height: 100vh
17 | display: block
18 | width: 100vw
19 | border: 1px
20 |
21 | .other-property-new
22 | height: 100vh
23 | display: block
24 | width: 100vw
25 | border: 1px
26 | composes: heading
27 |
28 | @function test($foo)
29 | // The line below causes the problem
30 | $bar: $foo
31 |
32 |
33 | =placeholder
34 | $placeholders: ':-webkit-input' ':-moz' '-moz' '-ms-input'
35 | @each $placeholder in $placeholders
36 |
37 | &:#{$placeholder}-placeholder
38 | @content
39 |
40 |
41 |
42 |
43 | @function em($target, $context: $base-font-size)
44 | @if not unitless($target)
45 | $target: strip-units($target)
46 |
47 | @if not unitless($context)
48 | $context: strip-units($context)
49 |
50 | @if $target == 0 @return 0
51 | @return $target / $context + 0em
52 |
--------------------------------------------------------------------------------
/tests/helpers/isEmptyLine.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var assert = require('assert'),
4 | helpers = require('../../lib/helpers');
5 |
6 | describe('helpers - isEmptyLine', function () {
7 |
8 | //////////////////////////////
9 | // isEmptyLine
10 | //////////////////////////////
11 |
12 | it('isEmptyLine - [\'\\n\\n\' - true]', function (done) {
13 |
14 | var result = helpers.isEmptyLine('\n\n');
15 |
16 | assert.equal(true, result);
17 | done();
18 | });
19 |
20 | it('isEmptyLine - [\'\\r\\n\\r\\n\' - true]', function (done) {
21 |
22 | var result = helpers.isEmptyLine('\r\n\r\n');
23 |
24 | assert.equal(true, result);
25 | done();
26 | });
27 |
28 | it('isEmptyLine - [\'\\n \\n\' - false]', function (done) {
29 |
30 | var result = helpers.isEmptyLine('\n \n');
31 |
32 | assert.equal(false, result);
33 | done();
34 | });
35 |
36 | it('isEmptyLine - [\'\\r\\nabc\\r\\n\' - false]', function (done) {
37 |
38 | var result = helpers.isEmptyLine('\r\nabc\r\n');
39 |
40 | assert.equal(false, result);
41 | done();
42 | });
43 | });
44 |
--------------------------------------------------------------------------------
/tests/sass/placeholder-name-format.sass:
--------------------------------------------------------------------------------
1 | %hyphenated-lowercase
2 | content: ''
3 |
4 | %snake_case
5 | content: ''
6 |
7 | %camelCase
8 | content: ''
9 |
10 | %PascalCase
11 | content: ''
12 |
13 | %Camel_Snake_Case
14 | content: ''
15 |
16 | %SCREAMING_SNAKE_CASE
17 | content: ''
18 |
19 | %_with-leading-underscore
20 | content: ''
21 |
22 | %strictbem
23 | content: ''
24 |
25 | %strictbem_modifier
26 | content: ''
27 |
28 | %strictbem__placeholder
29 | content: ''
30 |
31 | %strictbem__placeholder_modifier
32 | content: ''
33 |
34 | %strictbem_modifier__placeholder
35 | content: ''
36 |
37 | %hyphenatedbem--modifier
38 | content: ''
39 |
40 | %hyphenatedbem__placeholder
41 | content: ''
42 |
43 | %hyphenatedbem__placeholder--modifier
44 | content: ''
45 |
46 | %hyphenatedbem--modifier__placeholder
47 | content: ''
48 |
49 | %_does_NOT-fitSTANDARD
50 | content: ''
51 |
52 | .class
53 | @extend %snake_case
54 |
55 | // Issue: https://github.com/sasstools/sass-lint/issues/625
56 | // variables/interpolation should be ignored
57 | %#{$var}
58 | content: ''
59 |
--------------------------------------------------------------------------------
/tests/sass/force-element-nesting.sass:
--------------------------------------------------------------------------------
1 | // comments denote default rule behaviour
2 | // .new should become a nested selector
3 | h1.new > p
4 | color: #000
5 |
6 | // .test should become a nested selector
7 | .mergeable .test
8 | color: #000
9 |
10 | // shouldn't be nested
11 | .mergeable, .test
12 | color: #000
13 |
14 | // #h1.new should be nested within the parent class
15 | .mergeable #h1.new
16 | color: #000
17 |
18 | // #h1.new should be nested within the parent class
19 | .mergeable
20 | #h1.new
21 | color: #000
22 |
23 | // shouldn't be nested
24 | ul > li
25 | padding: 0
26 |
27 | // p should be nested
28 | div p
29 | padding: 0
30 |
31 | // shouldn't be nested
32 | div > p
33 | margin: 0
34 |
35 | // shouldn't be nested
36 | ul ~ p
37 | color: #ff0000
38 |
39 | // already nested
40 | .test
41 | .bar
42 | color: blue
43 |
44 | // 2 rules should be nested
45 | h1 .class .test
46 | content: ''
47 |
48 | .tester
49 | .class-test
50 | content: ''
51 | &__test h1
52 | content: ''
53 |
54 | // h1 should be nested
55 | input[type="text"] h1
56 | content: ''
57 |
--------------------------------------------------------------------------------
/tests/sass/mixins-before-declarations.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | +waldo
3 | content: 'baz'
4 |
5 |
6 | .bar
7 | content: 'baz'
8 | +waldo
9 |
10 |
11 | .qux
12 | content: 'baz'
13 | +waldo
14 | margin: 0
15 |
16 |
17 | .breakpoint
18 | content: 'baz'
19 |
20 | +breakpoint(500px)
21 | content: 'waldo'
22 |
23 |
24 | .foo
25 | content: 'where'
26 |
27 | +waldo
28 |
29 |
30 |
31 | &__element
32 | +element
33 | width: 100%
34 |
35 | +mq(500px)
36 | content: 'mq'
37 |
38 |
39 | +waldo
40 |
41 | &--modifier
42 | +foo('yo')
43 | +hello
44 | +test
45 | height: 100px
46 | +test-again
47 |
48 |
49 | // added from issue #230 https://github.com/sasstools/sass-lint/issues/230
50 |
51 | .area-current
52 | $active: #00acac
53 | $background: #2d353c
54 |
55 | +area-menu($active, $background)
56 |
57 | // added from issue #227 https://github.com/sasstools/sass-lint/issues/227
58 |
59 | @include hello
60 |
61 | @media (min-width: 50em)
62 | +hello
63 |
64 | @supports (display: flex)
65 | +hello
66 |
67 | @at-root
68 | +hello
69 |
--------------------------------------------------------------------------------
/tests/helpers/isNestable.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var assert = require('assert'),
4 | helpers = require('../../lib/helpers');
5 |
6 | describe('helpers - isNestable', function () {
7 |
8 | //////////////////////////////
9 | // isNestable
10 | //////////////////////////////
11 |
12 | it('isNestable - nest attribute in selector', function (done) {
13 | var elements = ['selector', 'class', 'id', 'attribute'],
14 | nestable = ['class', 'selector', 'attribute'],
15 | previous = 'selector',
16 | current = 'attribute';
17 |
18 | var result = helpers.isNestable(current, previous, elements, nestable);
19 |
20 | assert.equal(true, result);
21 | done();
22 | });
23 |
24 | it('isNestable - nest id in class', function (done) {
25 | var elements = ['selector', 'class', 'id', 'attribute'],
26 | nestable = ['class', 'selector', 'attribute'],
27 | previous = 'class',
28 | current = 'id';
29 |
30 | var result = helpers.isNestable(current, previous, elements, nestable);
31 |
32 | assert.equal(false, result);
33 | done();
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/docs/rules/no-disallowed-property-values.md:
--------------------------------------------------------------------------------
1 | # No Disallowed Property Values
2 |
3 | Rule `no-disallowed-property-values` will warn against the use of certain values for properties. Either a single string can be specified for a single disallowed value, or an array of disallowed property values.
4 |
5 | ## Options
6 |
7 | * `properties`: `{dictionary of properties mapped to string or array of strings representing values}` (defaults to empty dictionary `{}`).
8 |
9 | ## Examples
10 |
11 | When `properties` contains a the following options for disallowed values of `text-transform` and `white-space`:
12 |
13 | ```yaml
14 | no-disallowed-property-values:
15 | - 1
16 | -
17 | properties:
18 | text-transform: capitalize
19 | white-space: ['pre', 'pre-wrap']
20 | ```
21 |
22 | The following would not be allowed:
23 |
24 | ```scss
25 |
26 | // the capitalize value for text-transform is not allowed
27 | .foo {
28 | text-transform: capitalize;
29 | }
30 |
31 | // the pre and pre-wrap values for white-space are not allowed
32 | .bar {
33 | white-space: pre;
34 | }
35 | .baz {
36 | white-space: pre-wrap;
37 | }
38 | ```
39 |
--------------------------------------------------------------------------------
/tests/sass/force-pseudo-nesting.scss:
--------------------------------------------------------------------------------
1 | // shouldnt generate a nesting warning
2 | input[type='radio'] {
3 | color: red;
4 | }
5 |
6 | // shouldnt generate a nesting warning
7 | div p {
8 | padding: 0;
9 | }
10 |
11 | // pseudo class should be nested
12 | p:last-child {
13 | margin: 0;
14 | }
15 |
16 | // pseudo class should be nested
17 | p:nth-of-type(2) {
18 | margin: 0;
19 | }
20 |
21 |
22 | // pseudo class should be nested
23 | input:read-only {
24 | content: '';
25 | }
26 |
27 |
28 | // pseudo element should be nested with the parent ident
29 | p::first-line {
30 | color: #ff0000;
31 | font-variant: small-caps;
32 | }
33 |
34 |
35 | .parent {
36 | .child {
37 | // pseudo element should be nested with the parent ident
38 | p::first-line {
39 | color: #ff0000;
40 | }
41 | }
42 | }
43 |
44 | .parent {
45 | .child {
46 | // pseudo element should be nested with the parent ident
47 | .sub p::first-line {
48 | color: #ff0000;
49 | }
50 | }
51 | }
52 |
53 | .parent {
54 | .child {
55 | .sub p {
56 | &::first-line {
57 | color: #ff0000;
58 | }
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Sam Richard
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/tests/helpers/stripLastSpace.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var assert = require('assert'),
4 | helpers = require('../../lib/helpers');
5 |
6 | describe('helpers - stripLastSpace', function () {
7 |
8 | //////////////////////////////
9 | // stripLastSpace
10 | //////////////////////////////
11 |
12 | it('stripLastSpace - [\'selector \']', function (done) {
13 |
14 | var result = helpers.stripLastSpace('selector ');
15 |
16 | assert.equal('selector', result);
17 | done();
18 | });
19 |
20 | it('stripLastSpace - [\'selector test \']', function (done) {
21 |
22 | var result = helpers.stripLastSpace('selector test');
23 |
24 | assert.equal('selector test', result);
25 | done();
26 | });
27 |
28 | it('stripLastSpace - [\'selector\']', function (done) {
29 |
30 | var result = helpers.stripLastSpace('selector');
31 |
32 | assert.equal('selector', result);
33 | done();
34 | });
35 |
36 | it('stripLastSpace - [\'selector test\']', function (done) {
37 |
38 | var result = helpers.stripLastSpace('selector test');
39 |
40 | assert.equal('selector test', result);
41 | done();
42 | });
43 | });
44 |
--------------------------------------------------------------------------------
/docs/rules/attribute-quotes.md:
--------------------------------------------------------------------------------
1 | # Attribute Quotes
2 |
3 | Rule `attribute-quotes` will enforce the use of quotes in attribute values.
4 |
5 | ## Options
6 |
7 | * `include`: `true`/`false` (defaults to `true`)
8 |
9 | ## Examples
10 |
11 | ### `include`
12 |
13 | When `include: true`, the following are allowed. When `include: false`, the following are disallowed:
14 |
15 | ```scss
16 |
17 | span[lang="pt"] {
18 | color: green;
19 | }
20 |
21 | span[lang~="en-us"] {
22 | color: blue;
23 | }
24 |
25 | span[class^="main"] {
26 | background-color: yellow;
27 | }
28 |
29 | a[href*="example"] {
30 | background-color: #CCCCCC;
31 | }
32 |
33 | input[type="email" i] {
34 | border-color: blue;
35 | }
36 | ```
37 |
38 | When `include: false`, the following are allowed. When `include: true`, the following are disallowed:
39 |
40 | ```scss
41 |
42 | span[lang=pt] {
43 | color: green;
44 | }
45 |
46 | span[lang~=en-us] {
47 | color: blue;
48 | }
49 |
50 | span[class^=main] {
51 | background-color: yellow;
52 | }
53 |
54 | a[href*=example] {
55 | background-color: #CCCCCC;
56 | }
57 |
58 | input[type=email i] {
59 | border-color: blue;
60 | }
61 | ```
62 |
--------------------------------------------------------------------------------
/lib/rules/no-trailing-whitespace.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var helpers = require('../helpers');
4 |
5 | module.exports = {
6 | 'name': 'no-trailing-whitespace',
7 | 'defaults': {},
8 | 'detect': function (ast, parser) {
9 | var result = [];
10 | var trailing = (/( |\t)+\n/);
11 | var trailingCRLF = (/( |\t)+\r\n/);
12 |
13 | ast.traverseByType('space', function (space, i, parent) {
14 | var content = space.content;
15 | var nextIndex = i + 1;
16 | var next = parent.content[nextIndex];
17 |
18 | while (next && (next.is('space') || next.is('declarationDelimiter'))) {
19 | content += next.content;
20 | nextIndex++;
21 | next = parent.content[nextIndex];
22 | }
23 |
24 | if (trailing.test(content) || trailingCRLF.test(content)) {
25 | result = helpers.addUnique(result, {
26 | 'ruleId': parser.rule.name,
27 | 'severity': parser.severity,
28 | 'line': space.start.line,
29 | 'column': space.start.column,
30 | 'message': 'No trailing whitespace allowed'
31 | });
32 | }
33 | });
34 |
35 | return result;
36 | }
37 | };
38 |
39 |
--------------------------------------------------------------------------------
/tests/sass/attribute-quotes.sass:
--------------------------------------------------------------------------------
1 | span[lang]
2 | font-weight: bold
3 |
4 | ////////////////////////////
5 | // No Quotes - Default warnings
6 | ////////////////////////////
7 |
8 | span[lang=pt]
9 | color: green
10 |
11 | span[lang~=en-us]
12 | color: blue
13 |
14 | span[lang|=zh]
15 | color: red
16 |
17 | span[class^=main]
18 | background-color: yellow
19 |
20 | // Invalid CSS - must be ident or string
21 | // a[href^=#] {
22 | // background-color: gold;
23 | // }
24 | //
25 | // a[href$=.cn] {
26 | // color: red;
27 | // }
28 |
29 | a[href*=example]
30 | background-color: #CCCCCC
31 |
32 | input[type=email i]
33 | border-color: blue
34 |
35 | ////////////////////////////
36 | // Quotes - exclude option warnings
37 | ////////////////////////////
38 |
39 | span[lang="pt"]
40 | color: green
41 |
42 | span[lang~="en-us"]
43 | color: blue
44 |
45 | span[lang|="zh"]
46 | color: red
47 |
48 | span[class^="main"]
49 | background-color: yellow
50 |
51 | a[href^="#"]
52 | background-color: gold
53 |
54 | a[href$=".cn"]
55 | color: red
56 |
57 | a[href*="example"]
58 | background-color: #CCCCCC
59 |
60 | input[type="email" i]
61 | border-color: blue
62 |
--------------------------------------------------------------------------------
/lib/rules/attribute-quotes.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var helpers = require('../helpers');
4 |
5 | module.exports = {
6 | 'name': 'attribute-quotes',
7 | 'defaults': {
8 | 'include': true
9 | },
10 | 'detect': function (ast, parser) {
11 | var result = [];
12 |
13 | ast.traverseByType('attributeValue', function (item) {
14 | if (item.content[0].is('string') && !parser.options.include) {
15 | result = helpers.addUnique(result, {
16 | 'ruleId': parser.rule.name,
17 | 'line': item.start.line,
18 | 'column': item.start.column,
19 | 'message': 'Attribute values should not be surrounded by quotes',
20 | 'severity': parser.severity
21 | });
22 | }
23 | else if (item.content[0].is('ident') && parser.options.include) {
24 | result = helpers.addUnique(result, {
25 | 'ruleId': parser.rule.name,
26 | 'line': item.start.line,
27 | 'column': item.start.column,
28 | 'message': 'Attribute values should be surrounded by quotes',
29 | 'severity': parser.severity
30 | });
31 | }
32 | });
33 |
34 | return result;
35 | }
36 | };
37 |
--------------------------------------------------------------------------------
/tests/sass/property-sort-order.scss:
--------------------------------------------------------------------------------
1 | .foo {
2 | height: 100vh;
3 | display: block;
4 | width: 100vw;
5 | border: 1px;
6 |
7 | .bar {
8 | width: 50vw;
9 | content: 'baz';
10 | border: 1px;
11 | height: 100vw;
12 | }
13 | }
14 |
15 | .other-property {
16 | composes: heading;
17 | height: 100vh;
18 | display: block;
19 | width: 100vw;
20 | border: 1px;
21 | }
22 |
23 | .other-property-new {
24 | height: 100vh;
25 | display: block;
26 | width: 100vw;
27 | border: 1px;
28 | composes: heading;
29 | }
30 |
31 | @function test($foo) {
32 | // The line below causes the problem
33 | $bar: $foo;
34 | }
35 |
36 | @mixin placeholder {
37 | $placeholders: ':-webkit-input' ':-moz' '-moz' '-ms-input';
38 | @each $placeholder in $placeholders {
39 |
40 | &:#{$placeholder}-placeholder {
41 | @content;
42 | }
43 | }
44 | }
45 |
46 | @function em($target, $context: $base-font-size) {
47 | @if not unitless($target) {
48 | $target: strip-units($target);
49 | }
50 | @if not unitless($context) {
51 | $context: strip-units($context);
52 | }
53 | @if $target == 0 { @return 0 }
54 | @return $target / $context + 0em;
55 | }
56 |
--------------------------------------------------------------------------------
/tests/sass/space-before-bang.sass:
--------------------------------------------------------------------------------
1 | // Important
2 |
3 | .foo
4 | color: red!important
5 |
6 |
7 | .bar
8 | color: orange !important
9 |
10 |
11 | .baz
12 | color: green! important
13 |
14 |
15 | .quz
16 | color: pink ! important
17 |
18 |
19 | // Default
20 |
21 | $foo: red!default
22 |
23 | $foo: orange !default
24 |
25 | $foo: blue! default
26 |
27 | $foo: green ! default
28 |
29 | =testcase($important: null)
30 | @if $important == true
31 | $important: !important
32 |
33 | =testcaseFail($important: null)
34 | @if $important == true
35 | $important:!important
36 |
37 | =testcase($important: null)
38 | @if $important == true
39 | $important: ! important
40 |
41 | =testcaseFail($important: null)
42 | @if $important == true
43 | $important:! important
44 |
45 | =testcase($important: null)
46 | @if $important == true
47 | $color: red !default
48 |
49 | =testcaseFail($important: null)
50 | @if $important == true
51 | $color: red!default
52 |
53 | =testcaseFail($important: null)
54 | @if $important == true
55 | $color: red ! default
56 |
57 | =testcaseFail($important: null)
58 | @if $important == true
59 | $color: red! default
60 |
--------------------------------------------------------------------------------
/tests/sass/empty-line-between-blocks.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | content: 'foo'
3 |
4 | .foo
5 | content: 'foo'
6 | .bar
7 | content: 'bar'
8 |
9 | .foo
10 | @include bar
11 |
12 | .foo
13 | @include bar($qux)
14 | content: 'foo'
15 |
16 |
17 | .foo
18 | @include bar($qux)
19 | content: 'foo'
20 |
21 |
22 | .foo
23 |
24 | @include bar($qux)
25 | content: 'foo'
26 |
27 |
28 | .foo
29 | @include bar($qux)
30 | &:after
31 | content: 'foo'
32 |
33 |
34 |
35 | .foo
36 |
37 | &__bar
38 | content: 'foo'
39 |
40 |
41 | content: 'foo'
42 |
43 | .foo
44 | content: 'foo'
45 |
46 | &__bar
47 | content: 'foo'
48 |
49 |
50 | .foo
51 | content: 'foo'
52 |
53 | &__bar
54 | content: 'foo'
55 |
56 |
57 |
58 | .foo
59 | &:before
60 | content: 'foo'
61 |
62 |
63 | .foo
64 | content: 'foo'
65 |
66 | &::first-line
67 | content: 'foo'
68 |
69 |
70 | h1
71 | content: 'foo'
72 | h2
73 | content: 'foo'
74 | h3
75 | content: 'foo'
76 | h4
77 | content: 'foo'
78 |
79 |
80 | .foo + .bar
81 | content: 'foo'
82 | .foo + .bar,
83 | h2
84 | content: 'foo'
85 |
86 |
87 | [type=text]
88 | content: 'foo'
89 | h1.foo
90 | content: 'foo'
91 |
--------------------------------------------------------------------------------
/tests/sass/no-duplicate-properties.sass:
--------------------------------------------------------------------------------
1 | .foo
2 | margin: 0 0 15px
3 | padding: 10px
4 | margin: 0
5 |
6 | // excluded display will still fail here due to it not
7 | // following the previous display declaration
8 | .bar
9 | display: block
10 | width: 100%
11 | display: none
12 |
13 | // excluded display will still fail here due to it not
14 | // following the previous display declaration
15 | .baz
16 | display: block
17 | width: 50%
18 | display: none
19 |
20 | .qux
21 | background: rgb(200, 54, 54)
22 | background: rgba(200, 54, 54, 0.5)
23 |
24 | .break
25 | background: rgb(200, 54, 54)
26 | content: 'dec between background'
27 | background: rgba(200, 54, 54, 0.5)
28 |
29 | .display
30 | content: 'display'
31 | display: flex
32 | display: inline-block
33 |
34 | // issue #907 - interpolation/variable in property names
35 | $paint-border-1: top
36 | $paint-border-2: left
37 |
38 | .test
39 | border: $size solid transparent
40 | border-#{$paint-border-1}: $size solid $color
41 | border-#{$paint-border-2}: $size solid $color
42 | border-#{$paint-border-2}: $size solid $color
43 |
44 | // issue #935 - ignore variables
45 | +foo
46 | $i: 0
47 | $i: 1
48 |
--------------------------------------------------------------------------------
/docs/rules/border-zero.md:
--------------------------------------------------------------------------------
1 | # Border Zero
2 |
3 | Rule `border-zero` will enforce whether one should use `0` or `none` when specifying a zero `border` value
4 |
5 | ## Options
6 |
7 | * `convention`: `'0'`/`'none'` (defaults to `0`)
8 |
9 | > If an invalid convention is provided the rule will default back to `convention: '0'`. An extra warning/error will also be thrown on `line 1` `column 1` of a file with a lint issue to inform you of this fact.
10 |
11 | ## Examples
12 |
13 | When `convention: '0'`, the following are allowed. When `convention: 'none'`, the following are disallowed:
14 |
15 | ```scss
16 | .foo {
17 | border: 0;
18 | }
19 |
20 | .bar {
21 | border-right: 0;
22 | }
23 | ```
24 |
25 | When `convention: 'none'`, the following are allowed. When `convention: '0'`, the following are disallowed:
26 |
27 | ```scss
28 | .foo {
29 | border: none;
30 | }
31 |
32 | .bar {
33 | border-left: none;
34 | }
35 | ```
36 |
37 | ### Invalid conventions
38 |
39 | When the invalid convention `convention: 'zero'` is supplied, the following are allowed as the rule defaults to `convention: '0'`.
40 |
41 | ```scss
42 | .foo {
43 | border: none;
44 | }
45 |
46 | .bar {
47 | border-left: 0;
48 | }
49 | ```
50 |
--------------------------------------------------------------------------------
/docs/rules/indentation.md:
--------------------------------------------------------------------------------
1 | # Indentation
2 |
3 | Rule `indentation` will enforce an indentation size (tabs and spaces) and it will also ensure that tabs and spaces are not mixed.
4 |
5 | The mixed spaces and tabs warnings check will take into account what you have set in your config file whether it should expect to see spaces or tabs. If it encounters a tab anywhere in a file when your rule config doesn't specify tabs it will flag a lint warning, Similarly for any whitespace using spaces when tabs are specified. Obviously spaces between properties and values etc are ignored.
6 |
7 | ## Options
8 |
9 | * `size`: `number` or `'tab'` (defaults to `2` spaces)
10 |
11 | ## Examples
12 |
13 | When enabled (assuming `size: 2`) the following are allowed:
14 |
15 | ```scss
16 | .foo {
17 | content: 'bar';
18 |
19 | .baz {
20 | content: 'qux';
21 |
22 | // Waldo
23 | &--waldo {
24 | content: 'alpha';
25 | }
26 | }
27 | }
28 | ```
29 |
30 | When enabled (assuming `size: 2`) the following are disallowed:
31 |
32 | ```scss
33 | .foo {
34 | content: 'bar';
35 | .baz {
36 | content: 'qux';
37 | // Waldo
38 | &--waldo {
39 | content: 'alpha';
40 | }
41 | }
42 | }
43 | ```
44 |
--------------------------------------------------------------------------------
/docs/rules/property-units.md:
--------------------------------------------------------------------------------
1 | # Property Units
2 |
3 | Rule `property-units` will disallow the use of units not specified in `global` or `per-property`. Units specified `per-property` will override the `global` units for that property.
4 |
5 | ## Options
6 |
7 | * `global`: `['em', 'px', 'rem', etc]` defaults to [] or all units allowed
8 | * `per-property`: `{ width: ['rem', 'px', etc], height: ['rem', 'px', etc], }` defaults to {} or no property-specific units
9 |
10 | ## Examples
11 |
12 | When enabled, `global` is set to `['px']`, and `per-property` is set to `{ width: ['rem'] }` the following are disallowed.
13 |
14 | ```scss
15 | .literal {
16 | height: 3rem;
17 | }
18 |
19 | .literal-property {
20 | width: 3px;
21 | }
22 |
23 | .box-shadow {
24 | box-shadow: 1em 1em black, 1em 1em black;
25 | }
26 |
27 | .background {
28 | background: 1em solid white;
29 | }
30 |
31 | ```
32 |
33 | When enabled, `global` is set to `['em']`, and `per-property` is set to `{ width: ['rem'] }` the following are allowed.
34 |
35 | ```scss
36 |
37 | .variable {
38 | width: $sizes.small;
39 | }
40 |
41 | .function {
42 | color: test(2px);
43 | }
44 |
45 | // using literals as property names
46 | $sizes: (
47 | small: 2px
48 | );
49 | ```
50 |
--------------------------------------------------------------------------------
/lib/rules/space-after-bang.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var helpers = require('../helpers');
4 |
5 | module.exports = {
6 | 'name': 'space-after-bang',
7 | 'defaults': {
8 | 'include': false
9 | },
10 | 'detect': function (ast, parser) {
11 | var result = [],
12 | regex = /!\s/;
13 |
14 | ast.traverseByTypes(['important', 'default', 'global', 'optional'], function (block) {
15 | if (block.content.match(regex) !== null) {
16 | if (parser.options.include) {
17 | result = helpers.addUnique(result, {
18 | 'ruleId': parser.rule.name,
19 | 'line': block.start.line,
20 | 'column': block.start.column + 1,
21 | 'message': 'Bangs (!) should be followed by a space',
22 | 'severity': parser.severity
23 | });
24 | }
25 | else {
26 | result = helpers.addUnique(result, {
27 | 'ruleId': parser.rule.name,
28 | 'line': block.start.line,
29 | 'column': block.start.column,
30 | 'message': 'Bangs (!) should not be followed by a space',
31 | 'severity': parser.severity
32 | });
33 | }
34 | }
35 | });
36 |
37 | return result;
38 | }
39 | };
40 |
--------------------------------------------------------------------------------
/lib/rules/placeholder-in-extend.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var helpers = require('../helpers');
4 |
5 | module.exports = {
6 | 'name': 'placeholder-in-extend',
7 | 'defaults': {},
8 | 'detect': function (ast, parser) {
9 | var result = [];
10 |
11 | ast.traverseByType('atkeyword', function (keyword, i, parent) {
12 | keyword.forEach(function (item) {
13 | if (item.content === 'extend') {
14 |
15 | parent.forEach('selector', function (selector) {
16 | var placeholder = false;
17 |
18 | selector.content.forEach(function (selectorPiece) {
19 | if (selectorPiece.type === 'placeholder') {
20 | placeholder = true;
21 | }
22 | });
23 |
24 | if (!placeholder) {
25 | result = helpers.addUnique(result, {
26 | 'ruleId': parser.rule.name,
27 | 'line': selector.start.line,
28 | 'column': selector.start.column,
29 | 'message': '@extend must be used with a %placeholder',
30 | 'severity': parser.severity
31 | });
32 | }
33 | });
34 | }
35 | });
36 | });
37 |
38 | return result;
39 | }
40 | };
41 |
--------------------------------------------------------------------------------
/tests/helpers/isCamelCase.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var assert = require('assert'),
4 | helpers = require('../../lib/helpers');
5 |
6 | describe('helpers - isCamelCase', function () {
7 |
8 | //////////////////////////////
9 | // isCamelCase
10 | //////////////////////////////
11 |
12 | it('isCamelCase - [\'TEST\' - false]', function (done) {
13 |
14 | var result = helpers.isCamelCase('TEST');
15 |
16 | assert.equal(false, result);
17 | done();
18 | });
19 |
20 | it('isCamelCase - [\'test\' - true]', function (done) {
21 |
22 | var result = helpers.isCamelCase('test');
23 |
24 | assert.equal(true, result);
25 | done();
26 | });
27 |
28 | it('isCamelCase - [abcDEF - true]', function (done) {
29 |
30 | var result = helpers.isCamelCase('abcDEF');
31 |
32 | assert.equal(true, result);
33 | done();
34 | });
35 |
36 | it('isCamelCase - [\'123\' - false]', function (done) {
37 |
38 | var result = helpers.isCamelCase('123');
39 |
40 | assert.equal(false, result);
41 | done();
42 | });
43 |
44 | it('isCamelCase - [\'aBcDeF\' - true]', function (done) {
45 |
46 | var result = helpers.isCamelCase('aBcDeF');
47 |
48 | assert.equal(true, result);
49 | done();
50 | });
51 | });
52 |
--------------------------------------------------------------------------------
/docs/rules/clean-import-paths.md:
--------------------------------------------------------------------------------
1 | # Clean Import Paths
2 |
3 | Rule `clean-import-paths` will enforce whether or not `@import` paths should have leading underscores and/or filename extensions.
4 |
5 | ## Options
6 |
7 | * `leading-underscore`: `true`/`false` (defaults to `false`)
8 | * `filename-extension`: `true`/`false` (defaults to `false`)
9 |
10 |
11 | ## Examples
12 |
13 | ### `leading-underscore`
14 |
15 | When `leading-underscore: false`, the following are allowed. When `leading-underscore: true`, the following are disallowed:
16 |
17 | ```scss
18 | @import 'foo';
19 | @import 'bar/foo';
20 | ```
21 |
22 | When `leading-underscore: true`, the following are allowed. When `leading-underscore: false`, the following are disallowed:
23 |
24 | ```scss
25 | @import '_foo';
26 | @import '_bar/foo';
27 | ```
28 |
29 | ---
30 | ### `filename-extension`
31 |
32 | When `filename-extension: false`, the following are allowed. When `filename-extension: true`, the following are disallowed:
33 |
34 | ```scss
35 | @import 'foo';
36 | @import 'bar/foo';
37 | ```
38 |
39 | When `filename-extension: true`, the following are allowed. When `filename-extension: false`, the following are disallowed:
40 |
41 | ```scss
42 | @import 'foo.scss';
43 | @import 'bar/foo.scss';
44 | ```
45 |
--------------------------------------------------------------------------------
/tests/sass/placeholder-name-format.scss:
--------------------------------------------------------------------------------
1 | %hyphenated-lowercase {
2 | content: '';
3 | }
4 |
5 | %snake_case {
6 | content: '';
7 | }
8 |
9 | %camelCase {
10 | content: '';
11 | }
12 |
13 | %PascalCase {
14 | content: '';
15 | }
16 |
17 | %Camel_Snake_Case {
18 | content: '';
19 | }
20 |
21 | %SCREAMING_SNAKE_CASE {
22 | content: '';
23 | }
24 |
25 | %_with-leading-underscore {
26 | content: '';
27 | }
28 |
29 | %strictbem {
30 | content: '';
31 | }
32 |
33 | %strictbem_placeholder {
34 | content: '';
35 | }
36 |
37 | %strictbem__mixin {
38 | content: '';
39 | }
40 |
41 | %strictbem__mixin_placeholder {
42 | content: '';
43 | }
44 |
45 | %strictbem_placeholder__mixin {
46 | content: '';
47 | }
48 |
49 | %hyphenatedbem--placeholder {
50 | content: '';
51 | }
52 |
53 | %hyphenatedbem__mixin {
54 | content: '';
55 | }
56 |
57 | %hyphenatedbem__mixin--placeholder {
58 | content: '';
59 | }
60 |
61 | %hyphenatedbem--placeholder__mixin {
62 | content: '';
63 | }
64 |
65 | %_does_NOT-fitSTANDARD {
66 | content: '';
67 | }
68 |
69 | .class {
70 | @extend %snake_case;
71 | }
72 |
73 | // Issue: https://github.com/sasstools/sass-lint/issues/625
74 | // variables/interpolation should be ignored
75 | %#{$var} {
76 | content: '';
77 | }
78 |
--------------------------------------------------------------------------------
/tests/helpers/isPascalCase.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var assert = require('assert'),
4 | helpers = require('../../lib/helpers');
5 |
6 | describe('helpers - isPascalCase', function () {
7 |
8 | //////////////////////////////
9 | // isPascalCase
10 | //////////////////////////////
11 |
12 | it('isPascalCase - [\'TEST\' - true]', function (done) {
13 |
14 | var result = helpers.isPascalCase('TEST');
15 |
16 | assert.equal(true, result);
17 | done();
18 | });
19 |
20 | it('isPascalCase - [\'test\' - false]', function (done) {
21 |
22 | var result = helpers.isPascalCase('test');
23 |
24 | assert.equal(false, result);
25 | done();
26 | });
27 |
28 | it('isPascalCase - [AbcDEF - true]', function (done) {
29 |
30 | var result = helpers.isPascalCase('AbcDEF');
31 |
32 | assert.equal(true, result);
33 | done();
34 | });
35 |
36 | it('isPascalCase - [\'123\' - false]', function (done) {
37 |
38 | var result = helpers.isPascalCase('123');
39 |
40 | assert.equal(false, result);
41 | done();
42 | });
43 |
44 | it('isPascalCase - [\'ABcDeF\' - true]', function (done) {
45 |
46 | var result = helpers.isPascalCase('ABcDeF');
47 |
48 | assert.equal(true, result);
49 | done();
50 | });
51 | });
52 |
--------------------------------------------------------------------------------
/tests/helpers/propertySearch.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var assert = require('assert'),
4 | helpers = require('../../lib/helpers');
5 |
6 | var haystack = [
7 | {
8 | prop: 'a',
9 | propb: 'b'
10 | },
11 | {
12 | prop: 'c',
13 | propb: 'd'
14 | }
15 | ];
16 |
17 | describe('helpers - propertySearch', function () {
18 | //////////////////////////////
19 | // propertySearch
20 | //////////////////////////////
21 |
22 | it('propertySearch should not find a property', function (done) {
23 |
24 | var needle = 'e',
25 | property = 'prop',
26 | result = helpers.propertySearch(haystack, needle, property);
27 |
28 | assert.equal(-1, result);
29 | done();
30 | });
31 |
32 | it('propertySearch should find a property', function (done) {
33 |
34 | var needle = 'a',
35 | property = 'prop',
36 | result = helpers.propertySearch(haystack, needle, property);
37 |
38 | assert.equal(0, result);
39 | done();
40 | });
41 |
42 | it('propertySearch should find a deeper property', function (done) {
43 |
44 | var needle = 'd',
45 | property = 'propb',
46 | result = helpers.propertySearch(haystack, needle, property);
47 |
48 | assert.equal(1, result);
49 | done();
50 | });
51 | });
52 |
--------------------------------------------------------------------------------
/tests/sass/space-before-bang.scss:
--------------------------------------------------------------------------------
1 | // Important
2 |
3 | .foo {
4 | color:red!important;
5 | }
6 |
7 | .bar {
8 | color: orange !important;
9 | }
10 |
11 | .baz {
12 | color: green! important;
13 | }
14 |
15 | .quz {
16 | color: pink ! important;
17 | }
18 |
19 | // Default
20 |
21 | $foo: red!default;
22 |
23 | $foo: red !default;
24 |
25 | $foo: red! default;
26 |
27 | $foo: red ! default;
28 |
29 | @mixin testcase($important: null) {
30 | @if ($important == true) {$important: !important;}
31 | }
32 |
33 | @mixin testcaseFail($important: null) {
34 | @if ($important == true) {$important:!important;}
35 | }
36 |
37 | @mixin testcase($important: null) {
38 | @if ($important == true) {$important: ! important;}
39 | }
40 |
41 | @mixin testcaseFail($important: null) {
42 | @if ($important == true) {$important:! important;}
43 | }
44 |
45 | @mixin testcase($important: null) {
46 | @if ($important == true) {$color: red !default;}
47 | }
48 |
49 | @mixin testcaseFail($important: null) {
50 | @if ($important == true) {$color: red!default;}
51 | }
52 |
53 | @mixin testcase($important: null) {
54 | @if ($important == true) {$color: red ! default;}
55 | }
56 |
57 | @mixin testcaseFail($important: null) {
58 | @if ($important == true) {$color: red! default;}
59 | }
60 |
--------------------------------------------------------------------------------
/lib/format/formatters/unix.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileoverview unix-style formatter.
3 | * @author oshi-shinobu
4 | *
5 | * Updated for use with sass-lint under MIT licence
6 | * @license https://github.com/sasstools/sass-lint/blob/master/lib/format/LICENSE
7 | */
8 |
9 | 'use strict';
10 |
11 | const getMessageType = require('../../helpers').getMessageType;
12 |
13 | //------------------------------------------------------------------------------
14 | // Public Interface
15 | //------------------------------------------------------------------------------
16 |
17 | module.exports = function (results) {
18 |
19 | let output = '',
20 | total = 0;
21 |
22 | results.forEach(result => {
23 |
24 | const messages = result.messages;
25 |
26 | total += messages.length;
27 |
28 | messages.forEach(message => {
29 |
30 | output += `${result.filePath}:`;
31 | output += `${message.line || 0}:`;
32 | output += `${message.column || 0}:`;
33 | output += ` ${message.message} `;
34 | output += `[${getMessageType(message)}${message.ruleId ? `/${message.ruleId}` : ''}]`;
35 | output += '\n';
36 | });
37 | });
38 |
39 | if (total > 0) {
40 | output += `\n${total} problem${total !== 1 ? 's' : ''}`;
41 | }
42 |
43 | return output;
44 | };
45 |
--------------------------------------------------------------------------------
/docs/sass-lint.yml:
--------------------------------------------------------------------------------
1 | #########################
2 | ## Sample Sass Lint File
3 | #########################
4 | # Linter Options
5 | options:
6 | # Don't merge default rules
7 | merge-default-rules: false
8 | # Set the formatter to 'html'
9 | formatter: html
10 | # Output file instead of logging results
11 | output-file: 'linters/sass-lint.html'
12 | # Raise an error if more than 50 warnings are generated
13 | max-warnings: 50
14 | # File Options
15 | files:
16 | include: 'sass/**/*.s+(a|c)ss'
17 | ignore:
18 | - 'sass/vendor/**/*.*'
19 | # Rule Configuration
20 | rules:
21 | extends-before-mixins: 2
22 | extends-before-declarations: 2
23 | placeholder-in-extend: 2
24 | mixins-before-declarations:
25 | - 2
26 | -
27 | exclude:
28 | - breakpoint
29 | - mq
30 |
31 | no-warn: 1
32 | no-debug: 1
33 | no-ids: 2
34 | no-important: 2
35 | hex-notation:
36 | - 2
37 | -
38 | style: uppercase
39 | indentation:
40 | - 2
41 | -
42 | size: 2
43 | property-sort-order:
44 | - 1
45 | -
46 | order:
47 | - display
48 | - margin
49 | ignore-custom-properties: true
50 | variable-for-property:
51 | - 2
52 | -
53 | properties:
54 | - margin
55 | - content
56 |
--------------------------------------------------------------------------------
/lib/rules/no-empty-rulesets.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var helpers = require('../helpers');
4 |
5 | module.exports = {
6 | 'name': 'no-empty-rulesets',
7 | 'defaults': {},
8 | 'detect': function (ast, parser) {
9 | var result = [];
10 |
11 | ast.traverseByType('block', function (block) {
12 | var nonSpaceCount = 0,
13 | empty = false;
14 |
15 | if (block.content.length === 0) {
16 | empty = true;
17 | }
18 | else {
19 | block.traverse(function (item) {
20 | if (!helpers.isEqual(block, item)) {
21 | if (item.type !== 'space' &&
22 | item.type !== 'singlelineComment' &&
23 | item.type !== 'multilineComment') {
24 | nonSpaceCount++;
25 | }
26 | }
27 | });
28 | if (nonSpaceCount === 0) {
29 | empty = true;
30 | }
31 | }
32 |
33 | if (empty) {
34 | result = helpers.addUnique(result, {
35 | 'ruleId': parser.rule.name,
36 | 'severity': parser.severity,
37 | 'line': block.start.line,
38 | 'column': block.start.column,
39 | 'message': 'No empty blocks allowed'
40 | });
41 | }
42 | });
43 |
44 |
45 | return result;
46 | }
47 | };
48 |
--------------------------------------------------------------------------------