Dan Bray
Dan Bray

Reputation: 7832

SCSS linter for Codemirror

How can I make linter work in Codemirror for SCSS mode?

If I use css-lint.js then I receive errors such as, Unknown @ rule: &mixin.

Upvotes: 2

Views: 1360

Answers (1)

blackmiaool
blackmiaool

Reputation: 5374

The result below is mainly based on sass-lint

Live demo:

http://blackmiaool.com/soa/43127937/cm.html

Source Code

https://github.com/blackmiaool/sass-lint

and

https://github.com/blackmiaool/soa/tree/gh-pages/43127937

How?

It's really a big project, allow me to introduce it step by step.

What do we have?

You want a scss-linter, but there is just a css-linter in codemirror now. And there is a sass-lint which has 1k star on github. The sass-lint just support nodejs environment (it depends on fs, path and something alike) and can be used to lint scss.

What should we do?

According to css-lint, we should have a scss-lint.js which registers the scss linter and a scsslint.js which is used to lint scss. Now let's do it.

scss-lint.js

Just refer to css-lint.js, our scss-lint.js is this:

// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE


(function (mod) {
    if (typeof exports == "object" && typeof module == "object") // CommonJS
        mod(require("../../lib/codemirror"));
    else if (typeof define == "function" && define.amd) // AMD
        define(["../../lib/codemirror"], mod);
    else // Plain browser env
        mod(CodeMirror);
})(function (CodeMirror) {
    "use strict";

    CodeMirror.registerHelper("lint", "scss", function (text, options) {        
        var found = [];
        if (!window.SCSSLint) return found;
        var results = SCSSLint.verify(text, options),
            messages = results.messages,
            message = null;
        for (var i = 0; i < messages.length; i++) {
            message = messages[i];
            var startLine = message.line - 1,
                endLine = message.line - 1,
                startCol = message.col - 1,
                endCol = message.col;
            found.push({
                from: CodeMirror.Pos(startLine, startCol),
                to: CodeMirror.Pos(endLine, endCol),
                message: message.message,
                severity: message.type
            });
        }
        return found;
    });

});

It depends on window.SCSSLint.

from scss-lint to scsslint.js

  1. We don't actually have files, so we just use its lintText function.

  2. We run it in browser, so better to avoid yaml. Change yaml files to json.

  3. We don't have fs and path in browser, so just replace them with requiring json.

  4. We need a tool to integrate all the file in the project into a single file, so we use webpack here.

  5. Many other details.

Finally

Use it in browser:

html:

<script src="./dist/scsslint.js"></script>
<script src="./cm/scss-lint.js"></script>

js:

CodeMirror.fromTextArea(document.getElementById("code-css"), {
    lineNumbers: true,
    mode: "text/x-scss",
    gutters: ["CodeMirror-lint-markers"],
    lint: {
        options: {
            rules: {//try to remove this rule
                "no-empty-rulesets": 1,
            }
        }
    }
});

How to build your own scsslint?

  1. Download my answer repo
  2. Enter the 43127937 directory
  3. Clone my sass-lint there
  4. Enter the sass-lint directory
  5. npm i && cd .. && npm i && webpack
  6. check the dist directory

And

My sass-lint fork is supposed to be published to npm, but it's mostly not my work. I will ask the maintainers of the orignal repo what they think about it.

TL;DR

Insert this snippet to your html:

<script src="http://blackmiaool.com/soa/43127937/dist/scsslint.js"></script>
<script src="http://blackmiaool.com/soa/43127937/cm/scss-lint.js"></script>

Config your codemirror like this:

CodeMirror.fromTextArea(document.getElementById("code-css"), {
  lineNumbers: true,
  mode: "text/x-scss",
  gutters: ["CodeMirror-lint-markers"],
  lint: {
    options: {
      rules: {
        "no-empty-rulesets": 1,
      }
    }
  }
});

Upvotes: 4

Related Questions