From d998b901ac1a8b2351cd74aa3397172fba9ccce4 Mon Sep 17 00:00:00 2001 From: Seena Rowhani Date: Wed, 2 May 2018 15:01:28 -0400 Subject: [PATCH] feat(resolver): hex-notation --- src/config/default.yml | 3 +- src/resolvers/hex-notation.ts | 38 +++++++++ test/sass/hex-notation.sass | 31 ++++++++ test/sass/hex-notation.scss | 33 ++++++++ test/src/resolvers/hex-notation.ts | 123 +++++++++++++++++++++++++++++ 5 files changed, 227 insertions(+), 1 deletion(-) create mode 100644 src/resolvers/hex-notation.ts create mode 100644 test/sass/hex-notation.sass create mode 100644 test/sass/hex-notation.scss create mode 100644 test/src/resolvers/hex-notation.ts diff --git a/src/config/default.yml b/src/config/default.yml index 3f2d1601..cd80583c 100644 --- a/src/config/default.yml +++ b/src/config/default.yml @@ -10,7 +10,7 @@ resolvers: attribute-quotes: 1 border-zero: 1 no-color-keywords: 1 - no-css-comments: 1 + no-css-comments: 0 no-important: 1 no-trailing-zero: 1 space-after-bang: 1 @@ -21,3 +21,4 @@ resolvers: empty-line-between-blocks: 1 url-quotes: 1 zero-unit: 1 + hex-notation: 1 diff --git a/src/resolvers/hex-notation.ts b/src/resolvers/hex-notation.ts new file mode 100644 index 00000000..0f177223 --- /dev/null +++ b/src/resolvers/hex-notation.ts @@ -0,0 +1,38 @@ +import BaseResolver from './base-resolver'; +import AbstractSyntaxTree, { TreeNode } from './typings/abstract-syntax-tree'; +import SlRule from './typings/sass-lint-rule'; + +export default class HexNotation extends BaseResolver { + private _letterRegex: RegExp; + + constructor(ast: AbstractSyntaxTree, parser: SlRule) { + super(ast, parser); + this._letterRegex = /[a-z]/i; + } + + public fix(): AbstractSyntaxTree { + const { ast } = this; + + ast.traverseByType('color', (colorNode: TreeNode) => { + const content = colorNode.content.toString(); + + if (content.match(this._letterRegex)) { + if (this.shouldBeUppercase()) { + colorNode.content = content.toUpperCase(); + } else if (this.shouldBeLowercase()) { + colorNode.content = content.toLowerCase(); + } + } + }); + + return ast; + } + + private shouldBeUppercase(): boolean { + return this.parser.options.style === 'uppercase'; + } + + private shouldBeLowercase(): boolean { + return this.parser.options.style === 'lowercase'; + } +} diff --git a/test/sass/hex-notation.sass b/test/sass/hex-notation.sass new file mode 100644 index 00000000..107f22bf --- /dev/null +++ b/test/sass/hex-notation.sass @@ -0,0 +1,31 @@ +// numbers only won't match +$foo-color: #123 + +.foo + background: linear-gradient(top, #cc2, #44d) + color: #fff + + +$bar-color: #123456 + +.bar + background: linear-gradient(top, #CC2, #44D) + color: #FFF + + +.qux + color: #cC2 + + +$lower-numbers-color: #123cc2 +$upper-lower-color: #CCCCCc + +$map-vals: (mixed: #123Cde) + +// check that only hex colours are being parsed + +$literal-color: red +$rgb-color: rgb(255, 255, 255) +$rgba-color: rgba(0, 0, 0, .1) +$hsl-color: hsl(40, 50%, 50%) +$hsla-color: hsla(40, 50%, 50%, .3) diff --git a/test/sass/hex-notation.scss b/test/sass/hex-notation.scss new file mode 100644 index 00000000..49e8b76b --- /dev/null +++ b/test/sass/hex-notation.scss @@ -0,0 +1,33 @@ +// numbers only won't match +$foo-color: #123; + +.foo { + background: linear-gradient(top, #cc2, #44d); + color: #fff; +} + +$bar-color: #123456; + +.bar { + background: linear-gradient(top, #CC2, #44D); + color: #FFF; +} + +.qux { + color: #cC2; +} + +$lower-numbers-color: #123cc2; +$upper-lower-color: #CCCCCc; + +$map-vals: ( + mixed: #123Cde, +); + +// check that only hex colours are being parsed + +$literal-color: red; +$rgb-color: rgb(255, 255, 255); +$rgba-color: rgba(0, 0, 0, .1); +$hsl-color: hsl(40, 50%, 50%); +$hsla-color: hsla(40, 50%, 50%, .3); diff --git a/test/src/resolvers/hex-notation.ts b/test/src/resolvers/hex-notation.ts new file mode 100644 index 00000000..6a1d81fe --- /dev/null +++ b/test/src/resolvers/hex-notation.ts @@ -0,0 +1,123 @@ +import resolve, { detect, lint } from '@test/helpers/resolve'; + +describe('hex-notation', () => { + describe('scss', () => { + describe('[style=default]', () => { + const options = { 'hex-notation': 1 }; + it('resolves', done => { + const filename = 'test/sass/hex-notation.scss'; + resolve(filename, options, (_, __, resolvedTree) => { + const preResolve = lint(filename, options); + const postResolve = detect(resolvedTree.toString(), 'scss', options); + + expect(preResolve.warningCount).toBe(6); + expect(postResolve.warningCount).toBe(0); + done(); + }); + }); + }); + describe('[style=lowercase]', () => { + const options = { + 'hex-notation': [ + 1, + { + style: 'lowercase', + }, + ], + }; + it('resolves', done => { + const filename = 'test/sass/hex-notation.sass'; + resolve(filename, options, (_, __, resolvedTree) => { + const preResolve = lint(filename, options); + const postResolve = detect(resolvedTree.toString(), 'sass', options); + + expect(preResolve.warningCount).toBe(6); + expect(postResolve.warningCount).toBe(0); + done(); + }); + }); + }); + describe('[style=uppercase]', () => { + const options = { + 'hex-notation': [ + 1, + { + style: 'uppercase', + }, + ], + }; + it('resolves', done => { + const filename = 'test/sass/hex-notation.sass'; + resolve(filename, options, (_, __, resolvedTree) => { + const preResolve = lint(filename, options); + const postResolve = detect(resolvedTree.toString(), 'sass', options); + + expect(preResolve.warningCount).toBe(7); + expect(postResolve.warningCount).toBe(0); + done(); + }); + }); + }); + }); + describe('sass', () => { + describe('[style=default]', () => { + const options = { 'hex-notation': 1 }; + it('resolves', done => { + const filename = 'test/sass/hex-notation.sass'; + resolve(filename, options, (_, __, resolvedTree) => { + const preResolve = lint(filename, options); + const postResolve = detect(resolvedTree.toString(), 'sass', options); + + expect(preResolve.warningCount).toBe(6); + expect(postResolve.warningCount).toBe(0); + done(); + }); + }); + }); + describe('[style=lowercase]', () => { + const options = { + 'hex-notation': [ + 1, + { + style: 'lowercase', + }, + ], + }; + it('resolves', done => { + const filename = 'test/sass/hex-notation.sass'; + resolve(filename, options, (_, __, resolvedTree) => { + const preResolve = lint(filename, options); + const postResolve = detect(resolvedTree.toString(), 'sass', options); + require('fs').writeFileSync( + 'test/sass/hex-notation-1.sass', + resolvedTree.toString(), + ); + expect(preResolve.warningCount).toBe(6); + expect(postResolve.warningCount).toBe(0); + done(); + }); + }); + }); + describe('[style=uppercase]', () => { + const options = { + 'hex-notation': [ + 1, + { + style: 'uppercase', + }, + ], + }; + it('resolves', done => { + const filename = 'test/sass/hex-notation.sass'; + resolve(filename, options, (_, __, resolvedTree) => { + const preResolve = lint(filename, options); + const postResolve = detect(resolvedTree.toString(), 'sass', options); + + expect(preResolve.warningCount).toBe(7); + expect(postResolve.warningCount).toBe(0); + done(); + }); + }); + }); + }); +});