Add exclude option to scss_lint gem for UrlFormat
Asked Answered
D

1

8

I'm using gem scss_lint for scss linting. The issue I'm having is that I have variables in some of my strings in the css for the url so the linter reports an error:

I think there should be a way to exclude certain things in the check. I see that data: has been whitelisted but we use variables in our css sometimes because it is put into a cms.

UrlFormat: Invalid URL '/response/${siteId}/artifact/${campaignAndToolPath}/assets/fonts/roboto-light-webfont.woff2': bad URI(is not URI?): /response/${siteId}/artifact/${campaignAndToolPath}/assets/fonts/roboto-light-webfont.woff2

The code it is erroring on is:

@font-face {
  font-family: 'roboto';
  src: url('/response/${siteId}/artifact/${campaignAndToolPath}/assets/fonts/roboto-italic-webfont.woff2') format('woff2'),
       url('/response/${siteId}/artifact/${campaignAndToolPath}/assets/fonts/roboto-italic-webfont.woff') format('woff');
  font-weight: $regular;
  font-style: italic;
}

Maybe having a way to do

UrlFormat:
  enabled: true
  ignore or exclude: [
     - '${everythingbetween}'
     - '{{everything between}}'
  ]

I'm not well versed in Ruby in order to write something to allow for the checking of such variables and either ignoring the variable itself or the whole line.

Would someone be interested in tackling this?

The Ruby code for it is.

require 'uri'

module SCSSLint
  # Checks the format of URLs for unnecessary protocols or domains.
  class Linter::UrlFormat < Linter
    include LinterRegistry

  def visit_script_funcall(node)
    return unless node.name == 'url'

    if url_string?(node.args[0])
      url = node.args[0].value.value.to_s
      check_url(url, node)
    end

    yield
  end

  def visit_prop(node)
    if url_literal?(node.value)
      url = node.value.to_sass.sub(/^url\((.*)\)$/, '\\1')
      check_url(url, node)
    end

    yield
  end

  private

    def url_literal?(prop_value)
      return unless prop_value.is_a?(Sass::Script::Tree::Literal)
      return unless prop_value.value.is_a?(Sass::Script::Value::String)
      return unless prop_value.value.type == :identifier

      prop_value.to_sass.start_with?('url(')
    end

    def url_string?(arg)
      return unless arg.is_a?(Sass::Script::Tree::Literal)
      return unless arg.value.is_a?(Sass::Script::Value::String)

      arg.value.type == :string
    end

    def check_url(url, node)
      return if url.start_with?('data:')
      uri = URI(url)

      if uri.scheme || uri.host
        add_lint(node, "URL `#{url}` should not contain protocol or domain")
      end
    rescue URI::Error => ex
      add_lint(node, "Invalid URL `#{url}`: #{ex}")
    end
  end
end

I think maybe the solution would be to just ignore the variable in the way it does for the data: and not error unless the UrlFormat in fact is invalid because of missing quotes or something.

Any help would be appreciated.

Dextrous answered 13/3, 2017 at 13:55 Comment(0)
S
4

This should work: The change I made was this line return if url.include?('${') . It ignores urls that contain the string ${ the same way it ignores urls that start with data:.

def check_url(url, node)
  return if url.start_with?('data:') || url.include?('${')
  uri = URI(url)

  if uri.scheme || uri.host
    add_lint(node, "URL `#{url}` should not contain protocol or domain")
  end
rescue URI::Error => ex
  add_lint(node, "Invalid URL `#{url}`: #{ex}")
end
Spark answered 22/3, 2017 at 6:19 Comment(2)
Thanks! Didn't realize it was that simple lol. This should work for the spec right? context 'when URL contains a variable' do let(:url) { '${' } it { should_not report_lint } endDextrous
It looks fine :)Spark

© 2022 - 2024 — McMap. All rights reserved.