diff options
| author | Amaury Levé | 2018-06-13 18:24:11 +0200 | 
|---|---|---|
| committer | GitHub | 2018-06-13 18:24:11 +0200 | 
| commit | b3887099d35a9d8909c00f43ca194cc02ba0b16a (patch) | |
| tree | 5e5c1e1f99f205d0627743d4734303b7d560b14a /sonar-css-plugin | |
| parent | df153ba45fffa47f1bff7a4201d5fd16fc7b3445 (diff) | |
| download | sonar-css-b3887099d35a9d8909c00f43ca194cc02ba0b16a.tar.bz2 | |
Add syntax highlighting for strings and comments (#43)
Diffstat (limited to 'sonar-css-plugin')
6 files changed, 211 insertions, 9 deletions
| diff --git a/sonar-css-plugin/pom.xml b/sonar-css-plugin/pom.xml index 0ceb4b0..a1b3ecc 100644 --- a/sonar-css-plugin/pom.xml +++ b/sonar-css-plugin/pom.xml @@ -56,6 +56,11 @@              <groupId>org.awaitility</groupId>              <artifactId>awaitility</artifactId>          </dependency> +        <dependency> +            <groupId>commons-lang</groupId> +            <artifactId>commons-lang</artifactId> +            <version>2.6</version> +        </dependency>      </dependencies>      <build> @@ -111,7 +116,7 @@                              <rules>                                  <requireFilesSize>                                      <minsize>10000</minsize> -                                    <maxsize>50000</maxsize> +                                    <maxsize>200000</maxsize>                                      <files>                                          <file>${project.build.directory}/${project.build.finalName}.jar</file>                                      </files> diff --git a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssPlugin.java b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssPlugin.java index 07b4feb..65e6453 100644 --- a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssPlugin.java +++ b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/CssPlugin.java @@ -34,6 +34,7 @@ public class CssPlugin implements Plugin {    @Override    public void define(Context context) {      context.addExtensions( +      MetricSensor.class,        CssLanguage.class,        SonarWayProfile.class, diff --git a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/MetricSensor.java b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/MetricSensor.java new file mode 100644 index 0000000..fb9c522 --- /dev/null +++ b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/MetricSensor.java @@ -0,0 +1,86 @@ +/* + * SonarCSS + * Copyright (C) 2018-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. + */ +package org.sonar.css.plugin; + +import org.sonar.api.batch.fs.FileSystem; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.sensor.Sensor; +import org.sonar.api.batch.sensor.SensorContext; +import org.sonar.api.batch.sensor.SensorDescriptor; +import org.sonar.api.batch.sensor.highlighting.NewHighlighting; +import org.sonar.api.batch.sensor.highlighting.TypeOfText; +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; + +import javax.script.ScriptException; + +import java.io.IOException; +import java.util.Optional; + +public class MetricSensor implements Sensor { + +  private static final Logger LOG = Loggers.get(MetricSensor.class); + +  @Override +  public void describe(SensorDescriptor descriptor) { +    descriptor +      .onlyOnLanguage(CssLanguage.KEY); +  } + +  @Override +  public void execute(SensorContext context) { +    FileSystem fileSystem = context.fileSystem(); +    Iterable<InputFile> inputFiles = fileSystem.inputFiles(fileSystem.predicates().hasLanguage(CssLanguage.KEY)); + +    Tokenizer tokenizer = new Tokenizer(); + +    for (InputFile input : inputFiles) { +      saveHighlights(context, input, tokenizer); +    } +  } + +  private static void saveHighlights(SensorContext sensorContext, InputFile input, Tokenizer tokenizer) { +    try { +      NewHighlighting highlighting = sensorContext.newHighlighting().onFile(input); +      tokenizer.tokenize(input.contents()) +        .forEach(token -> getHighlightingType(token).ifPresent(type -> +          highlighting.highlight(token.startLine, token.startColumn, token.endLine, token.endColumn, type))); +      highlighting.save(); + +    } catch (ScriptException e) { +      LOG.error(String.format("Failed to tokenize file '%s'", input.toString()), e); +    } catch (IOException e) { +      LOG.error(String.format("Failed to read file '%s'", input.toString()), e); +    } +  } + +  private static Optional<TypeOfText> getHighlightingType(Token token) { +    switch (token.type) { +      case COMMENT: +        return Optional.of(TypeOfText.COMMENT); + +      case STRING: +        return Optional.of(TypeOfText.STRING); + +      default: +        return Optional.empty(); +    } +  } +} diff --git a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/Tokenizer.java b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/Tokenizer.java index 8f03492..220bfaa 100644 --- a/sonar-css-plugin/src/main/java/org/sonar/css/plugin/Tokenizer.java +++ b/sonar-css-plugin/src/main/java/org/sonar/css/plugin/Tokenizer.java @@ -26,16 +26,15 @@ import java.util.ArrayList;  import java.util.List;  import java.util.Map;  import javax.script.ScriptEngine; -import javax.script.ScriptEngineManager;  import javax.script.ScriptException; -import org.sonar.api.internal.apachecommons.lang.StringEscapeUtils; +import jdk.nashorn.api.scripting.NashornScriptEngineFactory; +import org.apache.commons.lang.StringEscapeUtils;  import org.sonar.css.plugin.Token.Type;  public class Tokenizer {    public List<Token> tokenize(String css) throws ScriptException { -    ScriptEngineManager factory = new ScriptEngineManager(); -    ScriptEngine engine = factory.getEngineByName("JavaScript"); +    ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine();      InputStream tokenizeScript = Tokenizer.class.getClassLoader().getResourceAsStream("tokenize.js");      engine.eval(new InputStreamReader(tokenizeScript, StandardCharsets.UTF_8));      String cssInput = "tokenize('" + StringEscapeUtils.escapeJavaScript(css) + "')"; @@ -105,7 +104,7 @@ public class Tokenizer {      if (value instanceof Double) {        return ((Double) value).intValue();      } else if (value instanceof Integer) { -      return  (Integer) value; +      return (Integer) value;      } else {        throw new IllegalStateException("Failed to convert to number: " + value);      } diff --git a/sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssPluginTest.java b/sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssPluginTest.java index 3da86ca..33bd4dd 100644 --- a/sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssPluginTest.java +++ b/sonar-css-plugin/src/test/java/org/sonar/css/plugin/CssPluginTest.java @@ -28,15 +28,14 @@ import org.sonar.api.utils.Version;  import static org.assertj.core.api.Assertions.assertThat; -  public class CssPluginTest {    @Test -  public void count_extensions() throws Exception { +  public void count_extensions() {      SonarRuntime runtime = SonarRuntimeImpl.forSonarQube(Version.create(6, 7), SonarQubeSide.SCANNER);      Plugin.Context context = new Plugin.Context(runtime);      Plugin underTest = new CssPlugin();      underTest.define(context); -    assertThat(context.getExtensions()).hasSize(3); +    assertThat(context.getExtensions()).hasSize(4);    }  } diff --git a/sonar-css-plugin/src/test/java/org/sonar/css/plugin/MetricSensorTest.java b/sonar-css-plugin/src/test/java/org/sonar/css/plugin/MetricSensorTest.java new file mode 100644 index 0000000..c93c16a --- /dev/null +++ b/sonar-css-plugin/src/test/java/org/sonar/css/plugin/MetricSensorTest.java @@ -0,0 +1,112 @@ +/* + * SonarCSS + * Copyright (C) 2018-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. + */ +package org.sonar.css.plugin; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.batch.fs.internal.TestInputFileBuilder; +import org.sonar.api.batch.sensor.highlighting.TypeOfText; +import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor; +import org.sonar.api.batch.sensor.internal.SensorContextTester; + +import static org.assertj.core.api.Assertions.assertThat; + +public class MetricSensorTest { + +  private DefaultInputFile inputFile; +  private SensorContextTester sensorContext; + +  @Rule +  public TemporaryFolder tempFolder = new TemporaryFolder(); + +  @Before +  public void setUp() { +    sensorContext = SensorContextTester.create(tempFolder.getRoot()); +  } + +  @Test +  public void should_describe() { +    DefaultSensorDescriptor desc = new DefaultSensorDescriptor(); +    new MetricSensor().describe(desc); + +    assertThat(desc.languages()).containsOnly("css"); +  } + +  @Test +  public void empty_input() throws Exception { +    highlight("foo"); + +    assertThat(sensorContext.highlightingTypeAt(inputFile.key(), 1, 0)).isEmpty(); +    assertThat(sensorContext.highlightingTypeAt(inputFile.key(), 1, 1)).isEmpty(); +  } + +  @Test +  public void singleline_multiline_comment() throws IOException { +    highlight("/* some comment */"); + +    assertHighlighting(1, 1, 17, TypeOfText.COMMENT); +  } + +  @Test +  public void multiline_comment() throws IOException { +    String content = "/* some comment\nmultiline */"; +    highlight(content); + +    assertHighlighting(1, 1, 15, TypeOfText.COMMENT); +    assertHighlighting(2, 1, 11, TypeOfText.COMMENT); +  } + +  @Test +  public void string() throws IOException { +    String content = "\"foo\""; +    highlight(content); + +    assertHighlighting(1, 1, content.length() - 1, TypeOfText.STRING); +  } + +  private void highlight(String content) throws IOException { +    File file = tempFolder.newFile(); +    inputFile = new TestInputFileBuilder("moduleKey", file.getName()) +      .setLanguage("css") +      .setContents(content) +      .build(); + +    sensorContext.fileSystem().add(inputFile); + +    new MetricSensor().execute(sensorContext); +  } + +  private void assertHighlighting(int line, int column, int length, TypeOfText type) { +    if (column < 1) { +      throw new IllegalStateException("Column should be greater than or equal to 1"); +    } + +    for (int i = column; i < column + length; i++) { +      List<TypeOfText> typeOfTexts = sensorContext.highlightingTypeAt(inputFile.key(), line, i); +      assertThat(typeOfTexts).containsOnly(type); +    } +  } +} | 
