Loading lib/jsduck/css/sass_parser.rb 0 → 100644 +79 −0 Original line number Diff line number Diff line require 'sass' module JsDuck module Css # Parses SCSS using the official SASS parser. class SassParser def initialize(input, options = {}) @input = input @docs = [] end # Returns an array of docsets like the Js::Parser does. def parse root = Sass::Engine.new(@input, :syntax => :scss).to_tree find_doc_comments(root.children) @docs end private def find_doc_comments(nodes) prev_comment = nil nodes.each do |node| if node.class == Sass::Tree::CommentNode if node.type == :normal && node.value[0] =~ /\A\/\*\*/ prev_comment = node.value[0] else prev_comment = nil end elsif prev_comment @docs << { :comment => prev_comment, :linenr => 0, :code => analyze_code(node), :type => :doc_comment, } prev_comment = nil end find_doc_comments(node.children) end end def analyze_code(node) if node.class == Sass::Tree::VariableNode return { :tagname => :css_var, :name => "$" + node.name, :default => node.expr.to_s, :type => "*", } elsif node.class == Sass::Tree::MixinDefNode return { :tagname => :css_mixin, :name => node.name, :params => build_params(node.args), } else # Default to property like in Js::Parser. return {:tagname => :property} end end def build_params(mixin_args) mixin_args.map do |arg| { :name => "$" + arg[0].name, :default => arg[1] ? arg[1].to_s : nil, :type => "*", } end end end end end spec/css_sass_parser_spec.rb 0 → 100644 +143 −0 Original line number Diff line number Diff line require 'jsduck/css/sass_parser' describe JsDuck::Css::SassParser do def parse(string) JsDuck::Css::SassParser.new(string).parse end describe "parsing empty string" do let(:docs) { parse("") } it "finds no documentation" do docs.length.should == 0 end end describe "parsing SCSS without doc-comments" do let(:docs) do parse(<<-EOCSS) // some comment a:href { color: green; } /* Shallalalaaa */ $foo: 10em !default; /*! Goul */ @mixin goul { font-weight: bold; } EOCSS end it "finds no documentation" do docs.length.should == 0 end end describe "parsing SCSS with lots of doc-comments" do let(:docs) do parse(<<-EOCSS) /** some comment */ a:href { color: green; } /** Shallalalaaa */ $foo: 10em !default; /** Goul */ @mixin goul { /** Me too! */ font-weight: bold; } EOCSS end it "finds them all" do docs.length.should == 4 end end describe "parsing SCSS variable" do let(:var) do parse(<<-EOCSS)[0] /** My variable */ $foo: 10em !default; EOCSS end it "detects comment" do var[:comment].should == "/** My variable */" end it "detects :css_var type" do var[:code][:tagname].should == :css_var end it "detects name" do var[:code][:name].should == "$foo" end it "detects default value" do var[:code][:default].should == "10em" end end describe "parsing SCSS mixin" do let(:var) do parse(<<-EOCSS)[0] /** My mixin */ @mixin foo($alpha, $beta: 2px) { color: $alpha; } EOCSS end it "detects comment" do var[:comment].should == "/** My mixin */" end it "detects :css_mixin type" do var[:code][:tagname].should == :css_mixin end it "detects name" do var[:code][:name].should == "foo" end it "detects correct number of parameters" do var[:code][:params].length.should == 2 end it "detects name of first param" do var[:code][:params][0][:name].should == "$alpha" end it "detects no default value for first param" do var[:code][:params][0][:default].should == nil end it "detects name of second param" do var[:code][:params][1][:name].should == "$beta" end it "detects default value for second param" do var[:code][:params][1][:default].should == "2px" end end describe "parsing other SCSS code" do let(:var) do parse(<<-EOCSS)[0] /** My docs */ .some-class a:href { color: #0f0; } EOCSS end it "detects comment" do var[:comment].should == "/** My docs */" end it "detects code as :property" do var[:code][:tagname].should == :property end end end Loading
lib/jsduck/css/sass_parser.rb 0 → 100644 +79 −0 Original line number Diff line number Diff line require 'sass' module JsDuck module Css # Parses SCSS using the official SASS parser. class SassParser def initialize(input, options = {}) @input = input @docs = [] end # Returns an array of docsets like the Js::Parser does. def parse root = Sass::Engine.new(@input, :syntax => :scss).to_tree find_doc_comments(root.children) @docs end private def find_doc_comments(nodes) prev_comment = nil nodes.each do |node| if node.class == Sass::Tree::CommentNode if node.type == :normal && node.value[0] =~ /\A\/\*\*/ prev_comment = node.value[0] else prev_comment = nil end elsif prev_comment @docs << { :comment => prev_comment, :linenr => 0, :code => analyze_code(node), :type => :doc_comment, } prev_comment = nil end find_doc_comments(node.children) end end def analyze_code(node) if node.class == Sass::Tree::VariableNode return { :tagname => :css_var, :name => "$" + node.name, :default => node.expr.to_s, :type => "*", } elsif node.class == Sass::Tree::MixinDefNode return { :tagname => :css_mixin, :name => node.name, :params => build_params(node.args), } else # Default to property like in Js::Parser. return {:tagname => :property} end end def build_params(mixin_args) mixin_args.map do |arg| { :name => "$" + arg[0].name, :default => arg[1] ? arg[1].to_s : nil, :type => "*", } end end end end end
spec/css_sass_parser_spec.rb 0 → 100644 +143 −0 Original line number Diff line number Diff line require 'jsduck/css/sass_parser' describe JsDuck::Css::SassParser do def parse(string) JsDuck::Css::SassParser.new(string).parse end describe "parsing empty string" do let(:docs) { parse("") } it "finds no documentation" do docs.length.should == 0 end end describe "parsing SCSS without doc-comments" do let(:docs) do parse(<<-EOCSS) // some comment a:href { color: green; } /* Shallalalaaa */ $foo: 10em !default; /*! Goul */ @mixin goul { font-weight: bold; } EOCSS end it "finds no documentation" do docs.length.should == 0 end end describe "parsing SCSS with lots of doc-comments" do let(:docs) do parse(<<-EOCSS) /** some comment */ a:href { color: green; } /** Shallalalaaa */ $foo: 10em !default; /** Goul */ @mixin goul { /** Me too! */ font-weight: bold; } EOCSS end it "finds them all" do docs.length.should == 4 end end describe "parsing SCSS variable" do let(:var) do parse(<<-EOCSS)[0] /** My variable */ $foo: 10em !default; EOCSS end it "detects comment" do var[:comment].should == "/** My variable */" end it "detects :css_var type" do var[:code][:tagname].should == :css_var end it "detects name" do var[:code][:name].should == "$foo" end it "detects default value" do var[:code][:default].should == "10em" end end describe "parsing SCSS mixin" do let(:var) do parse(<<-EOCSS)[0] /** My mixin */ @mixin foo($alpha, $beta: 2px) { color: $alpha; } EOCSS end it "detects comment" do var[:comment].should == "/** My mixin */" end it "detects :css_mixin type" do var[:code][:tagname].should == :css_mixin end it "detects name" do var[:code][:name].should == "foo" end it "detects correct number of parameters" do var[:code][:params].length.should == 2 end it "detects name of first param" do var[:code][:params][0][:name].should == "$alpha" end it "detects no default value for first param" do var[:code][:params][0][:default].should == nil end it "detects name of second param" do var[:code][:params][1][:name].should == "$beta" end it "detects default value for second param" do var[:code][:params][1][:default].should == "2px" end end describe "parsing other SCSS code" do let(:var) do parse(<<-EOCSS)[0] /** My docs */ .some-class a:href { color: #0f0; } EOCSS end it "detects comment" do var[:comment].should == "/** My docs */" end it "detects code as :property" do var[:code][:tagname].should == :property end end end