From 29af25282b7244475e3591dc4bb08476b5d2ec79 Mon Sep 17 00:00:00 2001 From: Michal Zgliczynski Date: Tue, 3 Dec 2024 11:16:25 +0100 Subject: [PATCH 1/9] Accept single Analysis class to JsTsSensor --- .../plugins/javascript/JavaScriptPlugin.java | 7 ++-- .../javascript/analysis/AbstractAnalysis.java | 10 +++-- .../analysis/AnalysisWithProgram.java | 11 +++++- .../analysis/AnalysisWithWatchProgram.java | 19 +++++++++- .../javascript/analysis/JsTsSensor.java | 37 ++----------------- .../javascript/analysis/TsConfigProvider.java | 7 ++++ .../JavaScriptEslintBasedSensorTest.java | 19 ++++++---- .../javascript/analysis/JsTsSensorTest.java | 20 ++++++---- 8 files changed, 74 insertions(+), 56 deletions(-) diff --git a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/JavaScriptPlugin.java b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/JavaScriptPlugin.java index e677830b7e6..1717e4992a8 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/JavaScriptPlugin.java +++ b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/JavaScriptPlugin.java @@ -153,8 +153,6 @@ public void define(Context context) { RulesBundles.class, JsTsChecks.class, AnalysisWarningsWrapper.class, - AnalysisWithProgram.class, - AnalysisWithWatchProgram.class, AnalysisProcessor.class, YamlSensor.class, HtmlSensor.class, @@ -288,7 +286,8 @@ public void define(Context context) { EslintReportSensor.class, EslintRulesDefinition.class, TslintReportSensor.class, - TslintRulesDefinition.class + TslintRulesDefinition.class, + AnalysisWithProgram.class ); context.addExtension( @@ -357,7 +356,7 @@ public void addSonarLintExtensions( SonarLintPluginAPIVersion sonarLintPluginAPIVersion ) { if (sonarLintPluginAPIVersion.isDependencyAvailable()) { - context.addExtension(TsConfigCacheImpl.class); + context.addExtensions(TsConfigCacheImpl.class, AnalysisWithWatchProgram.class); } else { LOG.debug("Error while trying to inject SonarLint extensions"); } diff --git a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AbstractAnalysis.java b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AbstractAnalysis.java index d2d6d4df644..5ce310be37f 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AbstractAnalysis.java +++ b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AbstractAnalysis.java @@ -40,7 +40,7 @@ import org.sonar.plugins.javascript.bridge.protobuf.Node; import org.sonar.plugins.javascript.utils.ProgressReport; -abstract class AbstractAnalysis { +public abstract class AbstractAnalysis { private static final Logger LOG = LoggerFactory.getLogger(AbstractAnalysis.class); static final String PROGRESS_REPORT_TITLE = "Progress of JavaScript/TypeScript analysis"; @@ -72,7 +72,7 @@ protected static String inputFileLanguage(InputFile file) { : JavaScriptLanguage.KEY; } - void initialize(SensorContext context, JsTsChecks checks, AnalysisMode analysisMode, AnalysisConsumers consumers) { + void initialize(SensorContext context, JsTsChecks checks, AnalysisMode analysisMode, AnalysisConsumers consumers) throws IOException { LOG.debug("Initializing {}", getClass().getName()); this.context = context; contextUtils = new ContextUtils(context); @@ -85,7 +85,7 @@ protected boolean isJavaScript(InputFile file) { return inputFileLanguage(file).equals(JavaScriptLanguage.KEY); } - abstract void analyzeFiles(List inputFiles, List tsConfigs) throws IOException; + abstract void analyzeFiles(List inputFiles) throws IOException; protected void analyzeFile(InputFile file, @Nullable List tsConfigs, @Nullable TsProgram tsProgram, boolean dirtyPackageJSONCache) throws IOException { if (context.isCancelled()) { @@ -159,4 +159,8 @@ private BridgeServer.JsAnalysisRequest getJsAnalysisRequest( shouldClearDependenciesCache ); } + + protected String createTsConfigFile(String content) throws IOException { + return bridgeServer.createTsConfigFile(content).getFilename(); + } } diff --git a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithProgram.java b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithProgram.java index 9dc2368878b..d401ee6817e 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithProgram.java +++ b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithProgram.java @@ -35,6 +35,8 @@ import org.sonar.plugins.javascript.utils.ProgressReport; import org.sonarsource.api.sonarlint.SonarLintSide; +import static org.sonar.plugins.javascript.analysis.TsConfigProvider.getTsConfigs; + @ScannerSide @SonarLintSide public class AnalysisWithProgram extends AbstractAnalysis { @@ -49,7 +51,14 @@ public AnalysisWithProgram( } @Override - void analyzeFiles(List inputFiles, List tsConfigs) throws IOException { + void analyzeFiles(List inputFiles) throws IOException { + var tsConfigs = getTsConfigs( + contextUtils, + this::createTsConfigFile + ); + if (tsConfigs.isEmpty()) { + LOG.info("No tsconfig.json file found"); + } progressReport = new ProgressReport(PROGRESS_REPORT_TITLE, PROGRESS_REPORT_PERIOD); progressReport.start(inputFiles.size(), inputFiles.iterator().next().toString()); boolean success = false; diff --git a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithWatchProgram.java b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithWatchProgram.java index 37cb06c25d4..a6a149b783e 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithWatchProgram.java +++ b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithWatchProgram.java @@ -19,18 +19,27 @@ import java.io.IOException; import java.util.List; import javax.annotation.Nullable; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.sensor.SensorContext; import org.sonar.api.scanner.ScannerSide; +import org.sonar.plugins.javascript.bridge.AnalysisMode; import org.sonar.plugins.javascript.bridge.AnalysisWarningsWrapper; import org.sonar.plugins.javascript.bridge.BridgeServer; import org.sonar.plugins.javascript.sonarlint.TsConfigCache; import org.sonar.plugins.javascript.utils.ProgressReport; import org.sonarsource.api.sonarlint.SonarLintSide; +import static org.sonar.plugins.javascript.analysis.TsConfigProvider.getTsConfigs; + @ScannerSide @SonarLintSide public class AnalysisWithWatchProgram extends AbstractAnalysis { + private static final Logger LOG = LoggerFactory.getLogger(AnalysisWithWatchProgram.class); + TsConfigCache tsConfigCache; public AnalysisWithWatchProgram( @@ -52,7 +61,15 @@ public AnalysisWithWatchProgram( } @Override - public void analyzeFiles(List inputFiles, List tsConfigs) throws IOException { + public void analyzeFiles(List inputFiles) throws IOException { + var tsConfigs = getTsConfigs( + contextUtils, + this::createTsConfigFile, + tsConfigCache + ); + if (tsConfigs.isEmpty()) { + LOG.info("No tsconfig.json file found"); + } boolean success = false; progressReport = new ProgressReport(PROGRESS_REPORT_TITLE, PROGRESS_REPORT_PERIOD); try { diff --git a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/JsTsSensor.java b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/JsTsSensor.java index 07a575e8f83..a573be42f9b 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/JsTsSensor.java +++ b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/JsTsSensor.java @@ -16,13 +16,9 @@ */ package org.sonar.plugins.javascript.analysis; -import static org.sonar.plugins.javascript.analysis.TsConfigProvider.getTsConfigs; - import java.io.IOException; import java.util.List; import java.util.stream.StreamSupport; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.sonar.api.batch.DependedUpon; import org.sonar.api.batch.fs.FilePredicate; import org.sonar.api.batch.fs.FileSystem; @@ -33,31 +29,24 @@ import org.sonar.plugins.javascript.TypeScriptLanguage; import org.sonar.plugins.javascript.bridge.AnalysisMode; import org.sonar.plugins.javascript.bridge.BridgeServer; -import org.sonar.plugins.javascript.sonarlint.TsConfigCache; @DependedUpon("js-analysis") public class JsTsSensor extends AbstractBridgeSensor { - private static final Logger LOG = LoggerFactory.getLogger(JsTsSensor.class); - private final AnalysisWithProgram analysisWithProgram; - private final AnalysisWithWatchProgram analysisWithWatchProgram; + private final AbstractAnalysis analysis; private final JsTsChecks checks; private final AnalysisConsumers consumers; - private final TsConfigCache tsConfigCache; public JsTsSensor( JsTsChecks checks, BridgeServer bridgeServer, - AnalysisWithProgram analysisWithProgram, - AnalysisWithWatchProgram analysisWithWatchProgram, + AbstractAnalysis analysis, AnalysisConsumers consumers ) { super(bridgeServer, "JS/TS"); - this.analysisWithProgram = analysisWithProgram; - this.analysisWithWatchProgram = analysisWithWatchProgram; this.checks = checks; this.consumers = consumers; - this.tsConfigCache = analysisWithWatchProgram.tsConfigCache; + this.analysis = analysis; } @Override @@ -88,26 +77,8 @@ protected void analyzeFiles(List inputFiles) throws IOException { exclusions ); - var tsConfigs = getTsConfigs( - contextUtils, - this::createTsConfigFile, - tsConfigCache - ); - AbstractAnalysis analysis; - if (shouldAnalyzeWithProgram()) { - analysis = analysisWithProgram; - } else { - analysis = analysisWithWatchProgram; - } - if (tsConfigs.isEmpty()) { - LOG.info("No tsconfig.json file found"); - } analysis.initialize(context, checks, analysisMode, consumers); - analysis.analyzeFiles(inputFiles, tsConfigs); + analysis.analyzeFiles(inputFiles); consumers.doneAnalysis(); } - - private String createTsConfigFile(String content) throws IOException { - return bridgeServer.createTsConfigFile(content).getFilename(); - } } diff --git a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/TsConfigProvider.java b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/TsConfigProvider.java index a34f65a03d3..6a279e8cb02 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/TsConfigProvider.java +++ b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/TsConfigProvider.java @@ -71,6 +71,13 @@ interface TsConfigFileCreator { this.cache = cache; } + static List getTsConfigs( + ContextUtils contextUtils, + TsConfigProvider.TsConfigFileCreator tsConfigFileCreator + ) throws IOException { + return getTsConfigs(contextUtils, tsConfigFileCreator, null); + } + /** * Relying on (in order of priority) * 1. Property sonar.typescript.tsconfigPath(s) diff --git a/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/analysis/JavaScriptEslintBasedSensorTest.java b/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/analysis/JavaScriptEslintBasedSensorTest.java index 1d74106031f..ea616d56239 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/analysis/JavaScriptEslintBasedSensorTest.java +++ b/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/analysis/JavaScriptEslintBasedSensorTest.java @@ -385,7 +385,7 @@ void should_save_only_nosonar_metric_in_sonarlint() throws Exception { when(bridgeServerMock.loadTsConfig(any())).thenReturn(tsConfigFile); context.setRuntime(SonarRuntimeImpl.forSonarLint(Version.create(4, 4))); - var sensor = createSensor(); + var sensor = createSonarLintSensor(); sensor.execute(context); assertThat(inputFile.hasNoSonarAt(7)).isTrue(); @@ -531,7 +531,6 @@ void should_skip_analysis_when_no_files() { checks(ESLINT_BASED_RULE), bridgeServerMock, analysisWithProgram, - analysisWithWatchProgram, new AnalysisConsumers() ); javaScriptEslintBasedSensor.execute(context); @@ -548,7 +547,6 @@ void handle_missing_node() throws Exception { checks(ESLINT_BASED_RULE), bridgeServerMock, analysisWithProgram, - analysisWithWatchProgram, new AnalysisConsumers() ); createInputFile(context); @@ -611,7 +609,6 @@ void should_not_create_parsing_issue_when_no_rule() throws IOException { checks(ESLINT_BASED_RULE), bridgeServerMock, analysisWithProgram, - analysisWithWatchProgram, new AnalysisConsumers() ) .execute(context); @@ -639,7 +636,7 @@ void should_send_content_on_sonarlint() throws Exception { when(bridgeServerMock.analyzeJavaScript(any())).thenReturn(new AnalysisResponse()); var captor = ArgumentCaptor.forClass(JsAnalysisRequest.class); - createSensor().execute(ctx); + createSonarLintSensor().execute(ctx); verify(bridgeServerMock).analyzeJavaScript(captor.capture()); assertThat(captor.getValue().fileContent()) .isEqualTo("if (cond)\n" + "doFoo(); \n" + "else \n" + "doFoo();"); @@ -651,7 +648,7 @@ void should_send_content_on_sonarlint() throws Exception { ctx.setNextCache(mock(WriteCache.class)); createInputFile(ctx); - createSensor().execute(ctx); + createSonarLintSensor().execute(ctx); verify(bridgeServerMock).analyzeJavaScript(captor.capture()); assertThat(captor.getValue().fileContent()).isNull(); } @@ -781,12 +778,20 @@ private DefaultInputFile createTestInputFile(SensorContextTester context) { return inputFile; } + private JsTsSensor createSonarLintSensor() { + return new JsTsSensor( + checks(ESLINT_BASED_RULE, "S2260", "S1451"), + bridgeServerMock, + analysisWithWatchProgram, + new AnalysisConsumers() + ); + } + private JsTsSensor createSensor() { return new JsTsSensor( checks(ESLINT_BASED_RULE, "S2260", "S1451"), bridgeServerMock, analysisWithProgram, - analysisWithWatchProgram, new AnalysisConsumers() ); } diff --git a/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/analysis/JsTsSensorTest.java b/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/analysis/JsTsSensorTest.java index 70a20d6db58..166c7baddea 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/analysis/JsTsSensorTest.java +++ b/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/analysis/JsTsSensorTest.java @@ -302,7 +302,7 @@ void should_raise_a_parsing_error() throws IOException { ) ); createInputFile(context); - createSensor().execute(context); + createSonarLintSensor().execute(context); Collection issues = context.allIssues(); assertThat(issues).hasSize(1); Issue issue = issues.iterator().next(); @@ -349,7 +349,7 @@ void should_send_content_on_sonarlint() throws Exception { new TsConfigFile("tsconfig.json", singletonList(file.absolutePath()), emptyList()) ); ArgumentCaptor captor = ArgumentCaptor.forClass(JsAnalysisRequest.class); - createSensor().execute(ctx); + createSonarLintSensor().execute(ctx); verify(bridgeServerMock).analyzeTypeScript(captor.capture()); assertThat(captor.getValue().fileContent()) .isEqualTo("if (cond)\n" + "doFoo(); \n" + "else \n" + "doFoo();"); @@ -532,7 +532,7 @@ void should_analyze_by_tsconfig() throws Exception { .thenReturn(new TsConfigFile(tsconfig3, singletonList(file3.absolutePath()), emptyList())); ArgumentCaptor captor = ArgumentCaptor.forClass(JsAnalysisRequest.class); - createSensor().execute(context); + createSonarLintSensor().execute(context); verify(bridgeServerMock, times(4)).analyzeTypeScript(captor.capture()); assertThat(captor.getAllValues()) .extracting(req -> req.filePath()) @@ -750,7 +750,7 @@ void should_resolve_project_references_from_tsconfig() throws Exception { ); ArgumentCaptor captor = ArgumentCaptor.forClass(JsAnalysisRequest.class); - createSensor().execute(context); + createSonarLintSensor().execute(context); // Only 2 calls, as we already find the necessary tsconfig (src/tsconfig.app.json) on the 2nd call verify(bridgeServerMock, times(2)).loadTsConfig(anyString()); @@ -806,7 +806,7 @@ void should_fail_fast_with_parsing_error_without_line() throws IOException { @Test void stop_analysis_if_cancelled() throws Exception { - JsTsSensor sensor = createSensor(); + JsTsSensor sensor = createSonarLintSensor(); createInputFile(context); setSonarLintRuntime(context); createTsConfigFile(); @@ -906,7 +906,6 @@ public void doneAnalysis() { checks(ESLINT_BASED_RULE, "S2260"), bridgeServerMock, analysisWithProgram(), - analysisWithWatchProgram(), new AnalysisConsumers(List.of(consumer)) ); @@ -997,7 +996,6 @@ private JsTsSensor createSensorWithConsumer(JsAnalysisConsumer consumer) { checks(ESLINT_BASED_RULE, "S2260"), bridgeServerMock, analysisWithProgram(), - analysisWithWatchProgram(), new AnalysisConsumers(List.of(consumer)) ); } @@ -1007,6 +1005,14 @@ private JsTsSensor createSensor() { checks(ESLINT_BASED_RULE, "S2260"), bridgeServerMock, analysisWithProgram(), + new AnalysisConsumers() + ); + } + + private JsTsSensor createSonarLintSensor() { + return new JsTsSensor( + checks(ESLINT_BASED_RULE, "S2260"), + bridgeServerMock, analysisWithWatchProgram(), new AnalysisConsumers() ); From 59789d291480ed62442f4089886cda34353a820c Mon Sep 17 00:00:00 2001 From: Michal Zgliczynski Date: Tue, 3 Dec 2024 11:17:42 +0100 Subject: [PATCH 2/9] remove unnecessary throws annotation --- .../org/sonar/plugins/javascript/analysis/AbstractAnalysis.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AbstractAnalysis.java b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AbstractAnalysis.java index 5ce310be37f..4b930aea20e 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AbstractAnalysis.java +++ b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AbstractAnalysis.java @@ -72,7 +72,7 @@ protected static String inputFileLanguage(InputFile file) { : JavaScriptLanguage.KEY; } - void initialize(SensorContext context, JsTsChecks checks, AnalysisMode analysisMode, AnalysisConsumers consumers) throws IOException { + void initialize(SensorContext context, JsTsChecks checks, AnalysisMode analysisMode, AnalysisConsumers consumers) { LOG.debug("Initializing {}", getClass().getName()); this.context = context; contextUtils = new ContextUtils(context); From cbe050aa6e1430868ffebc0a90d1fd207efa56d1 Mon Sep 17 00:00:00 2001 From: Michal Zgliczynski Date: Tue, 3 Dec 2024 11:35:06 +0100 Subject: [PATCH 3/9] Simplify JavaScriptPluginTest --- .../analysis/AnalysisWithWatchProgram.java | 10 +--------- .../javascript/JavaScriptPluginTest.java | 19 +++++++------------ 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithWatchProgram.java b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithWatchProgram.java index a6a149b783e..acdc78c659a 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithWatchProgram.java +++ b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithWatchProgram.java @@ -42,19 +42,11 @@ public class AnalysisWithWatchProgram extends AbstractAnalysis { TsConfigCache tsConfigCache; - public AnalysisWithWatchProgram( - BridgeServer bridgeServer, - AnalysisProcessor analysisProcessor, - AnalysisWarningsWrapper analysisWarnings - ) { - this(bridgeServer, analysisProcessor, analysisWarnings, null); - } - public AnalysisWithWatchProgram( BridgeServer bridgeServer, AnalysisProcessor analysisProcessor, AnalysisWarningsWrapper analysisWarnings, - @Nullable TsConfigCache tsConfigCache + TsConfigCache tsConfigCache ) { super(bridgeServer, analysisProcessor, analysisWarnings); this.tsConfigCache = tsConfigCache; diff --git a/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/JavaScriptPluginTest.java b/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/JavaScriptPluginTest.java index 57180f2e8c2..d5d92d330a8 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/JavaScriptPluginTest.java +++ b/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/JavaScriptPluginTest.java @@ -37,11 +37,9 @@ class JavaScriptPluginTest { - private static final int BASE_EXTENSIONS = 37; - private static final int JS_ADDITIONAL_EXTENSIONS = 4; - private static final int TS_ADDITIONAL_EXTENSIONS = 3; - private static final int CSS_ADDITIONAL_EXTENSIONS = 3; - private static final int SONARLINT_ADDITIONAL_EXTENSIONS = 1; + private static final int BASE_EXTENSIONS = 35; + private static final int SCANNER_EXTENSIONS = 11; + private static final int SONARLINT_ADDITIONAL_EXTENSIONS = 2; public static final Version LTS_VERSION = Version.create(7, 9); @@ -49,26 +47,23 @@ class JavaScriptPluginTest { public LogTesterJUnit5 logTester = new LogTesterJUnit5().setLevel(Level.DEBUG); @Test - void count_extensions_lts() throws Exception { + void count_extensions_lts() { Plugin.Context context = setupContext( SonarRuntimeImpl.forSonarQube(LTS_VERSION, SonarQubeSide.SERVER, SonarEdition.COMMUNITY) ); assertThat(context.getExtensions()) .hasSize( - BASE_EXTENSIONS + - JS_ADDITIONAL_EXTENSIONS + - TS_ADDITIONAL_EXTENSIONS + - CSS_ADDITIONAL_EXTENSIONS + BASE_EXTENSIONS + SCANNER_EXTENSIONS ); } @Test - void should_contain_right_properties_number() throws Exception { + void should_contain_right_properties_number() { assertThat(properties()).hasSize(13); } @Test - void count_extensions_for_sonarlint() throws Exception { + void count_extensions_for_sonarlint() { Plugin.Context context = setupContext(SonarRuntimeImpl.forSonarLint(LTS_VERSION)); assertThat(context.getExtensions()).hasSize(BASE_EXTENSIONS + SONARLINT_ADDITIONAL_EXTENSIONS); } From c58fb02c40b2fff82fdbaa1e07c1794a069e58a6 Mon Sep 17 00:00:00 2001 From: Michal Zgliczynski Date: Tue, 3 Dec 2024 11:57:29 +0100 Subject: [PATCH 4/9] Remove unused annotations and imports --- .../plugins/javascript/analysis/AnalysisWithProgram.java | 1 - .../plugins/javascript/analysis/AnalysisWithWatchProgram.java | 4 ---- 2 files changed, 5 deletions(-) diff --git a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithProgram.java b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithProgram.java index d401ee6817e..78e7a2b1568 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithProgram.java +++ b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithProgram.java @@ -38,7 +38,6 @@ import static org.sonar.plugins.javascript.analysis.TsConfigProvider.getTsConfigs; @ScannerSide -@SonarLintSide public class AnalysisWithProgram extends AbstractAnalysis { private static final Logger LOG = LoggerFactory.getLogger(AnalysisWithProgram.class); diff --git a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithWatchProgram.java b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithWatchProgram.java index acdc78c659a..e9eb9adb36f 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithWatchProgram.java +++ b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithWatchProgram.java @@ -18,14 +18,11 @@ import java.io.IOException; import java.util.List; -import javax.annotation.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.batch.sensor.SensorContext; import org.sonar.api.scanner.ScannerSide; -import org.sonar.plugins.javascript.bridge.AnalysisMode; import org.sonar.plugins.javascript.bridge.AnalysisWarningsWrapper; import org.sonar.plugins.javascript.bridge.BridgeServer; import org.sonar.plugins.javascript.sonarlint.TsConfigCache; @@ -34,7 +31,6 @@ import static org.sonar.plugins.javascript.analysis.TsConfigProvider.getTsConfigs; -@ScannerSide @SonarLintSide public class AnalysisWithWatchProgram extends AbstractAnalysis { From cb352536f6bebd9402d6d985ecebab85824fd4a9 Mon Sep 17 00:00:00 2001 From: Michal Zgliczynski Date: Tue, 3 Dec 2024 11:58:00 +0100 Subject: [PATCH 5/9] more remove --- .../sonar/plugins/javascript/analysis/AnalysisWithProgram.java | 1 - .../plugins/javascript/analysis/AnalysisWithWatchProgram.java | 1 - 2 files changed, 2 deletions(-) diff --git a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithProgram.java b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithProgram.java index 78e7a2b1568..8a42bf22d15 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithProgram.java +++ b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithProgram.java @@ -33,7 +33,6 @@ import org.sonar.plugins.javascript.bridge.BridgeServer.TsProgram; import org.sonar.plugins.javascript.bridge.BridgeServer.TsProgramRequest; import org.sonar.plugins.javascript.utils.ProgressReport; -import org.sonarsource.api.sonarlint.SonarLintSide; import static org.sonar.plugins.javascript.analysis.TsConfigProvider.getTsConfigs; diff --git a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithWatchProgram.java b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithWatchProgram.java index e9eb9adb36f..0978942e54f 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithWatchProgram.java +++ b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithWatchProgram.java @@ -22,7 +22,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.scanner.ScannerSide; import org.sonar.plugins.javascript.bridge.AnalysisWarningsWrapper; import org.sonar.plugins.javascript.bridge.BridgeServer; import org.sonar.plugins.javascript.sonarlint.TsConfigCache; From 1c16b0f930d453cc445bd6d4d776c3b6a6178462 Mon Sep 17 00:00:00 2001 From: Michal Zgliczynski Date: Tue, 3 Dec 2024 11:58:48 +0100 Subject: [PATCH 6/9] Remove more --- .../sonar/plugins/javascript/sonarlint/TsConfigCacheImpl.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/sonarlint/TsConfigCacheImpl.java b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/sonarlint/TsConfigCacheImpl.java index 08174cf69d5..c3b9c4eef76 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/sonarlint/TsConfigCacheImpl.java +++ b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/sonarlint/TsConfigCacheImpl.java @@ -30,7 +30,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.scanner.ScannerSide; import org.sonar.plugins.javascript.JavaScriptFilePredicate; import org.sonar.plugins.javascript.analysis.TsConfigOrigin; import org.sonar.plugins.javascript.bridge.BridgeServer; @@ -39,7 +38,6 @@ import org.sonarsource.sonarlint.plugin.api.module.file.ModuleFileEvent; import org.sonarsource.sonarlint.plugin.api.module.file.ModuleFileListener; -@ScannerSide @SonarLintSide(lifespan = SonarLintSide.MODULE) public class TsConfigCacheImpl implements TsConfigCache, ModuleFileListener { private static final Logger LOG = LoggerFactory.getLogger(TsConfigCacheImpl.class); From 2aa338ee885377ac96d6f280318de881c6b6d3bc Mon Sep 17 00:00:00 2001 From: Victor Diez Date: Tue, 3 Dec 2024 16:35:55 +0100 Subject: [PATCH 7/9] Separate logic in TsConfigProvider --- .../javascript/analysis/AbstractAnalysis.java | 1 + .../analysis/AbstractBridgeSensor.java | 13 +- .../analysis/AnalysisWithProgram.java | 10 +- .../analysis/AnalysisWithWatchProgram.java | 12 +- .../javascript/analysis/ContextUtils.java | 2 +- .../javascript/analysis/TsConfigProvider.java | 118 ++++++------------ .../analysis/TsConfigCacheTest.java | 10 +- .../analysis/TsConfigProviderTest.java | 45 +++---- 8 files changed, 66 insertions(+), 145 deletions(-) diff --git a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AbstractAnalysis.java b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AbstractAnalysis.java index 4b930aea20e..7ce0108d39e 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AbstractAnalysis.java +++ b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AbstractAnalysis.java @@ -66,6 +66,7 @@ public abstract class AbstractAnalysis { this.analysisWarnings = analysisWarnings; } + protected static String inputFileLanguage(InputFile file) { return JavaScriptFilePredicate.isTypeScriptFile(file) ? TypeScriptLanguage.KEY diff --git a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AbstractBridgeSensor.java b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AbstractBridgeSensor.java index 366be5a6793..b6799526b49 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AbstractBridgeSensor.java +++ b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AbstractBridgeSensor.java @@ -16,6 +16,8 @@ */ package org.sonar.plugins.javascript.analysis; +import static org.sonar.plugins.javascript.nodejs.NodeCommandBuilderImpl.NODE_EXECUTABLE_PROPERTY; + import java.io.IOException; import java.util.Arrays; import java.util.List; @@ -33,8 +35,6 @@ import org.sonar.plugins.javascript.nodejs.NodeCommandException; import org.sonar.plugins.javascript.utils.Exclusions; -import static org.sonar.plugins.javascript.nodejs.NodeCommandBuilderImpl.NODE_EXECUTABLE_PROPERTY; - public abstract class AbstractBridgeSensor implements Sensor { private static final Logger LOG = LoggerFactory.getLogger(AbstractBridgeSensor.class); @@ -109,13 +109,4 @@ protected void logErrorOrWarn(String msg, Throwable e) { protected abstract void analyzeFiles(List inputFiles) throws IOException; protected abstract List getInputFiles(); - - protected boolean shouldAnalyzeWithProgram() { - if (contextUtils.isSonarLint()) { - LOG.debug("Will use AnalysisWithWatchProgram because we are in SonarLint context"); - return false; - } - LOG.debug("Will use AnalysisWithProgram"); - return true; - } } diff --git a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithProgram.java b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithProgram.java index 8a42bf22d15..cfa6cc63f94 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithProgram.java +++ b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithProgram.java @@ -34,8 +34,6 @@ import org.sonar.plugins.javascript.bridge.BridgeServer.TsProgramRequest; import org.sonar.plugins.javascript.utils.ProgressReport; -import static org.sonar.plugins.javascript.analysis.TsConfigProvider.getTsConfigs; - @ScannerSide public class AnalysisWithProgram extends AbstractAnalysis { @@ -50,13 +48,7 @@ public AnalysisWithProgram( @Override void analyzeFiles(List inputFiles) throws IOException { - var tsConfigs = getTsConfigs( - contextUtils, - this::createTsConfigFile - ); - if (tsConfigs.isEmpty()) { - LOG.info("No tsconfig.json file found"); - } + var tsConfigs = TsConfigProvider.getTsConfigs(contextUtils, this::createTsConfigFile); progressReport = new ProgressReport(PROGRESS_REPORT_TITLE, PROGRESS_REPORT_PERIOD); progressReport.start(inputFiles.size(), inputFiles.iterator().next().toString()); boolean success = false; diff --git a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithWatchProgram.java b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithWatchProgram.java index 0978942e54f..0788773b64f 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithWatchProgram.java +++ b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithWatchProgram.java @@ -18,7 +18,6 @@ import java.io.IOException; import java.util.List; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.batch.fs.InputFile; @@ -28,8 +27,6 @@ import org.sonar.plugins.javascript.utils.ProgressReport; import org.sonarsource.api.sonarlint.SonarLintSide; -import static org.sonar.plugins.javascript.analysis.TsConfigProvider.getTsConfigs; - @SonarLintSide public class AnalysisWithWatchProgram extends AbstractAnalysis { @@ -49,14 +46,7 @@ public AnalysisWithWatchProgram( @Override public void analyzeFiles(List inputFiles) throws IOException { - var tsConfigs = getTsConfigs( - contextUtils, - this::createTsConfigFile, - tsConfigCache - ); - if (tsConfigs.isEmpty()) { - LOG.info("No tsconfig.json file found"); - } + TsConfigProvider.initializeTsConfigCache(contextUtils, this::createTsConfigFile, tsConfigCache); boolean success = false; progressReport = new ProgressReport(PROGRESS_REPORT_TITLE, PROGRESS_REPORT_PERIOD); try { diff --git a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/ContextUtils.java b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/ContextUtils.java index bc507289290..77ff58de34b 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/ContextUtils.java +++ b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/ContextUtils.java @@ -22,7 +22,7 @@ import org.sonar.api.batch.sensor.SensorContext; import org.sonar.plugins.javascript.JavaScriptPlugin; -class ContextUtils { +public class ContextUtils { /** * Internal property to enable SonarArmor (disabled by default), now called Jasmin diff --git a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/TsConfigProvider.java b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/TsConfigProvider.java index 6a279e8cb02..f126fe69134 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/TsConfigProvider.java +++ b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/TsConfigProvider.java @@ -18,6 +18,8 @@ import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; +import static org.sonar.plugins.javascript.analysis.LookupConfigProviderFilter.FileFilter; +import static org.sonar.plugins.javascript.analysis.LookupConfigProviderFilter.PathFilter; import com.google.gson.Gson; import java.io.File; @@ -41,8 +43,6 @@ import org.sonar.api.batch.fs.FileSystem; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.sensor.SensorContext; -import static org.sonar.plugins.javascript.analysis.LookupConfigProviderFilter.FileFilter; -import static org.sonar.plugins.javascript.analysis.LookupConfigProviderFilter.PathFilter; import org.sonar.plugins.javascript.JavaScriptFilePredicate; import org.sonar.plugins.javascript.sonarlint.TsConfigCache; import org.sonarsource.analyzer.commons.FileProvider; @@ -55,6 +55,7 @@ public class TsConfigProvider { interface Provider { List tsconfigs(SensorContext context) throws IOException; + TsConfigOrigin type(); } @@ -71,11 +72,8 @@ interface TsConfigFileCreator { this.cache = cache; } - static List getTsConfigs( - ContextUtils contextUtils, - TsConfigProvider.TsConfigFileCreator tsConfigFileCreator - ) throws IOException { - return getTsConfigs(contextUtils, tsConfigFileCreator, null); + TsConfigProvider(List providers) { + this(providers, null); } /** @@ -84,24 +82,21 @@ static List getTsConfigs( * 2. Looking up file system * 3. Creating a tmp tsconfig.json listing all files */ - static List getTsConfigs( - ContextUtils contextUtils, - TsConfigProvider.TsConfigFileCreator tsConfigFileCreator, - @Nullable TsConfigCache tsConfigCache - ) throws IOException { - var defaultProvider = contextUtils.isSonarLint() - ? new TsConfigProvider.WildcardTsConfigProvider(tsConfigCache, tsConfigFileCreator) - : new TsConfigProvider.DefaultTsConfigProvider(tsConfigFileCreator, JavaScriptFilePredicate::getJsTsPredicate); - - - var provider = new TsConfigProvider( - List.of(new PropertyTsConfigProvider(), new LookupTsConfigProvider(tsConfigCache), defaultProvider), - tsConfigCache - ); - + static List getTsConfigs(ContextUtils contextUtils, TsConfigProvider.TsConfigFileCreator tsConfigFileCreator) throws IOException { + var provider = new TsConfigProvider(List.of(new PropertyTsConfigProvider(), new LookupTsConfigProvider(), new TsConfigProvider.DefaultTsConfigProvider(tsConfigFileCreator, JavaScriptFilePredicate::getJsTsPredicate))); return provider.tsconfigs(contextUtils.context()); } + /** + * Fill tsConfigCache with the tsconfigs found in the order listed by the + * providers. No need to return the list of tsconfigs + * because we get the tsconfig file from the cache. + */ + static void initializeTsConfigCache(ContextUtils contextUtils, TsConfigProvider.TsConfigFileCreator tsConfigFileCreator, TsConfigCache tsConfigCache) throws IOException { + var provider = new TsConfigProvider(List.of(new PropertyTsConfigProvider(), new LookupTsConfigProvider(tsConfigCache), new TsConfigProvider.WildcardTsConfigProvider(tsConfigCache, tsConfigFileCreator)), tsConfigCache); + provider.tsconfigs(contextUtils.context()); + } + List tsconfigs(SensorContext context) throws IOException { for (Provider provider : providers) { List tsconfigs = provider.tsconfigs(context); @@ -121,25 +116,14 @@ List tsconfigs(SensorContext context) throws IOException { static class PropertyTsConfigProvider implements Provider { @Override public List tsconfigs(SensorContext context) { - if ( - !context.config().hasKey(TSCONFIG_PATHS) && - !context.config().hasKey(TSCONFIG_PATHS_ALIAS) - ) { + if (!context.config().hasKey(TSCONFIG_PATHS) && !context.config().hasKey(TSCONFIG_PATHS_ALIAS)) { return emptyList(); } - String property = context.config().hasKey(TSCONFIG_PATHS) - ? TSCONFIG_PATHS - : TSCONFIG_PATHS_ALIAS; - Set patterns = new HashSet<>( - Arrays.asList(context.config().getStringArray(property)) - ); + String property = context.config().hasKey(TSCONFIG_PATHS) ? TSCONFIG_PATHS : TSCONFIG_PATHS_ALIAS; + Set patterns = new HashSet<>(Arrays.asList(context.config().getStringArray(property))); - LOG.info( - "Resolving TSConfig files using '{}' from property {}", - String.join(",", patterns), - property - ); + LOG.info("Resolving TSConfig files using '{}' from property {}", String.join(",", patterns), property); File baseDir = context.fileSystem().baseDir(); @@ -186,10 +170,15 @@ private static Path getFilePath(File baseDir, String path) { static class LookupTsConfigProvider implements Provider { private final TsConfigCache cache; + LookupTsConfigProvider(@Nullable TsConfigCache cache) { this.cache = cache; } + LookupTsConfigProvider() { + this(null); + } + @Override public List tsconfigs(SensorContext context) { if (cache != null) { @@ -279,11 +268,7 @@ public TsConfigOrigin type() { public final List tsconfigs(SensorContext context) throws IOException { if (context.runtime().getProduct() != product) { // we don't support per analysis temporary files in SonarLint see https://jira.sonarsource.com/browse/SLCORE-235 - LOG.warn( - "Generating temporary tsconfig is not supported by {} in {} context.", - getClass().getSimpleName(), - context.runtime().getProduct() - ); + LOG.warn("Generating temporary tsconfig is not supported by {} in {} context.", getClass().getSimpleName(), context.runtime().getProduct()); return emptyList(); } return getDefaultTsConfigs(context); @@ -296,10 +281,7 @@ static class DefaultTsConfigProvider extends GeneratedTsConfigFileProvider { private final Function filePredicateProvider; private final TsConfigFileCreator tsConfigFileCreator; - DefaultTsConfigProvider( - TsConfigFileCreator tsConfigFileCreator, - Function filePredicate - ) { + DefaultTsConfigProvider(TsConfigFileCreator tsConfigFileCreator, Function filePredicate) { super(SonarProduct.SONARQUBE); this.tsConfigFileCreator = tsConfigFileCreator; this.filePredicateProvider = filePredicate; @@ -307,9 +289,7 @@ static class DefaultTsConfigProvider extends GeneratedTsConfigFileProvider { @Override List getDefaultTsConfigs(SensorContext context) throws IOException { - var inputFiles = context - .fileSystem() - .inputFiles(filePredicateProvider.apply(context.fileSystem())); + var inputFiles = context.fileSystem().inputFiles(filePredicateProvider.apply(context.fileSystem())); var tsConfig = new TsConfig(inputFiles, null); var tsconfigFile = writeToJsonFile(tsConfig); LOG.debug("Using generated tsconfig.json file {}", tsconfigFile.getAbsolutePath()); @@ -326,16 +306,12 @@ static class WildcardTsConfigProvider extends GeneratedTsConfigFileProvider { static final String MAX_FILES_PROPERTY = "sonar.javascript.sonarlint.typechecking.maxfiles"; static final int DEFAULT_MAX_FILES_FOR_TYPE_CHECKING = 20_000; - private static final Map> defaultWildcardTsConfig = - new ConcurrentHashMap<>(); + private static final Map> defaultWildcardTsConfig = new ConcurrentHashMap<>(); final TsConfigCache tsConfigCache; final TsConfigFileCreator tsConfigFileCreator; - WildcardTsConfigProvider( - @Nullable TsConfigCache tsConfigCache, - TsConfigFileCreator tsConfigFileCreator - ) { + WildcardTsConfigProvider(@Nullable TsConfigCache tsConfigCache, TsConfigFileCreator tsConfigFileCreator) { super(SonarProduct.SONARLINT); this.tsConfigCache = tsConfigCache; this.tsConfigFileCreator = tsConfigFileCreator; @@ -343,9 +319,7 @@ static class WildcardTsConfigProvider extends GeneratedTsConfigFileProvider { private static String getProjectRoot(SensorContext context) { var projectBaseDir = context.fileSystem().baseDir().getAbsolutePath(); - return "/".equals(File.separator) - ? projectBaseDir - : projectBaseDir.replace(File.separator, "/"); + return "/".equals(File.separator) ? projectBaseDir : projectBaseDir.replace(File.separator, "/"); } @Override @@ -354,10 +328,7 @@ List getDefaultTsConfigs(SensorContext context) { if (deactivated) { return emptyList(); } else { - return defaultWildcardTsConfig.computeIfAbsent( - getProjectRoot(context), - this::writeTsConfigFileFor - ); + return defaultWildcardTsConfig.computeIfAbsent(getProjectRoot(context), this::writeTsConfigFileFor); } } @@ -377,30 +348,17 @@ static boolean isBeyondLimit(SensorContext context, int projectSize) { } else { // TypeScript type checking mechanism creates performance issues for large projects. Analyzing a file can take more than a minute in // SonarLint, and it can even lead to runtime errors due to Node.js being out of memory during the process. - LOG.warn( - "Turning off type-checking of JavaScript files due to the project size exceeding the limit ({} files)", - typeCheckingLimit - ); + LOG.warn("Turning off type-checking of JavaScript files due to the project size exceeding the limit ({} files)", typeCheckingLimit); LOG.warn("This may cause rules dependent on type information to not behave as expected"); - LOG.warn( - "Check the list of impacted rules at https://rules.sonarsource.com/javascript/tag/type-dependent" - ); - LOG.warn( - "To turn type-checking back on, increase the \"{}\" property value", - MAX_FILES_PROPERTY - ); - LOG.warn( - "Please be aware that this could potentially impact the performance of the analysis" - ); + LOG.warn("Check the list of impacted rules at https://rules.sonarsource.com/javascript/tag/type-dependent"); + LOG.warn("To turn type-checking back on, increase the \"{}\" property value", MAX_FILES_PROPERTY); + LOG.warn("Please be aware that this could potentially impact the performance of the analysis"); } return beyondLimit; } static int getTypeCheckingLimit(SensorContext context) { - return Math.max( - context.config().getInt(MAX_FILES_PROPERTY).orElse(DEFAULT_MAX_FILES_FOR_TYPE_CHECKING), - 0 - ); + return Math.max(context.config().getInt(MAX_FILES_PROPERTY).orElse(DEFAULT_MAX_FILES_FOR_TYPE_CHECKING), 0); } } } diff --git a/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/analysis/TsConfigCacheTest.java b/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/analysis/TsConfigCacheTest.java index 2cbda5521b6..bedda7f9166 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/analysis/TsConfigCacheTest.java +++ b/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/analysis/TsConfigCacheTest.java @@ -100,7 +100,7 @@ void test() throws Exception { Files.createFile(tsConfigPath); } SensorContextTester ctx = SensorContextTester.create(baseDir); - TsConfigProvider.getTsConfigs(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); + TsConfigProvider.initializeTsConfigCache(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); when(bridgeServerMock.loadTsConfig(any())) .thenAnswer(invocationOnMock -> { @@ -156,7 +156,7 @@ void testResolvesReferences() throws IOException { Files.createFile(tsconfig2); SensorContextTester ctx = SensorContextTester.create(baseDir); - TsConfigProvider.getTsConfigs(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); + TsConfigProvider.initializeTsConfigCache(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); when(bridgeServerMock.loadTsConfig(any())).thenAnswer(invocationOnMock -> { String tsConfigPath = (String) invocationOnMock.getArguments()[0]; if (tsConfigPath.equals(tsConfigFile1.getFilename())) { @@ -203,7 +203,7 @@ void testPropertyTsConfigChanged() throws IOException { "tsconfig.*.json,tsconfig.json" ) ); - TsConfigProvider.getTsConfigs(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); + TsConfigProvider.initializeTsConfigCache(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); when(bridgeServerMock.loadTsConfig(any())).thenReturn(tsConfigFile); var foundTsConfig = tsConfigCache.getTsConfigForInputFile(file1); @@ -217,7 +217,7 @@ void testPropertyTsConfigChanged() throws IOException { var propertyCachedTsConfig = tsConfigCache.listCachedTsConfigs(TsConfigOrigin.PROPERTY); assertThat(propertyCachedTsConfig).containsExactly(tsconfig1.toAbsolutePath().toString()); - TsConfigProvider.getTsConfigs(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); + TsConfigProvider.initializeTsConfigCache(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); propertyCachedTsConfig = tsConfigCache.listCachedTsConfigs(TsConfigOrigin.PROPERTY); assertThat(propertyCachedTsConfig).containsExactlyInAnyOrder(tsconfig1.toAbsolutePath().toString(), tsconfig2.toAbsolutePath().toString()); } @@ -252,7 +252,7 @@ private Pair prepareFileAndTsConfig() throws IOExceptio Files.createFile(tsconfig1); SensorContextTester ctx = SensorContextTester.create(baseDir); - TsConfigProvider.getTsConfigs(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); + TsConfigProvider.initializeTsConfigCache(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); when(bridgeServerMock.loadTsConfig(any())).thenReturn(tsConfigFile); return Pair.of(file1, tsConfigFile); } diff --git a/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/analysis/TsConfigProviderTest.java b/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/analysis/TsConfigProviderTest.java index 1dae2f2da8c..b9522b52c82 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/analysis/TsConfigProviderTest.java +++ b/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/analysis/TsConfigProviderTest.java @@ -25,6 +25,7 @@ import static org.sonar.plugins.javascript.analysis.TsConfigProvider.TsConfigFileCreator; import static org.sonar.plugins.javascript.analysis.TsConfigProvider.WildcardTsConfigProvider; import static org.sonar.plugins.javascript.analysis.TsConfigProvider.getTsConfigs; +import static org.sonar.plugins.javascript.analysis.TsConfigProvider.initializeTsConfigCache; import java.io.File; import java.io.IOException; @@ -33,18 +34,13 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; -import java.util.Optional; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.api.io.TempDir; -import org.sonar.api.batch.fs.internal.DefaultFileSystem; import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.fs.internal.TestInputFileBuilder; -import org.sonar.api.batch.sensor.SensorContext; import org.sonar.api.batch.sensor.internal.SensorContextTester; -import org.sonar.api.config.Configuration; import org.sonar.api.config.internal.MapSettings; import org.sonar.api.impl.utils.DefaultTempFolder; import org.sonar.api.internal.SonarRuntimeImpl; @@ -92,8 +88,7 @@ void should_lookup_tsconfig_files() throws Exception { List tsconfigs = getTsConfigs( new ContextUtils(ctx), - this::tsConfigFileCreator, - null + this::tsConfigFileCreator ); assertThat(tsconfigs) .containsExactlyInAnyOrder( @@ -120,8 +115,7 @@ void should_use_tsconfig_from_property() throws Exception { List tsconfigs = getTsConfigs( new ContextUtils(ctx), - this::tsConfigFileCreator, - null + this::tsConfigFileCreator ); String absolutePath = baseDir.resolve("custom.tsconfig.json").toAbsolutePath().toString(); assertThat(tsconfigs).containsExactly(absolutePath); @@ -143,8 +137,7 @@ void should_use_absolute_path_from_property() throws Exception { List tsconfigs = getTsConfigs( new ContextUtils(ctx), - this::tsConfigFileCreator, - null + this::tsConfigFileCreator ); assertThat(tsconfigs).containsExactly(absolutePath); } @@ -168,8 +161,7 @@ void should_use_multiple_tsconfigs_from_property() throws Exception { List tsconfigs = getTsConfigs( new ContextUtils(ctx), - this::tsConfigFileCreator, - null + this::tsConfigFileCreator ); assertThat(tsconfigs) .containsExactlyInAnyOrder( @@ -205,8 +197,7 @@ void should_use_matching_tsconfigs_from_property() throws Exception { List tsconfigs = getTsConfigs( new ContextUtils(ctx), - this::tsConfigFileCreator, - null + this::tsConfigFileCreator ); assertThat(tsconfigs) .containsExactlyInAnyOrder( @@ -227,8 +218,7 @@ void should_use_tsconfigs_from_property_alias() throws Exception { List tsconfigs = getTsConfigs( new ContextUtils(ctx), - this::tsConfigFileCreator, - null + this::tsConfigFileCreator ); assertThat(tsconfigs).contains(baseDir.resolve("tsconfig.json").toAbsolutePath().toString()); assertThat(logger.logs(LoggerLevel.INFO)) @@ -246,14 +236,13 @@ void should_create_tsconfig() throws Exception { List tsconfigs = getTsConfigs( new ContextUtils(ctx), - this::tsConfigFileCreator, - null + this::tsConfigFileCreator ); assertThat(tsconfigs).hasSize(1); String tsconfig = Files.readString(Paths.get(tsconfigs.get(0))); assertThat(tsconfig) .isEqualToIgnoringCase( - String.format("{\"files\":[\"%s/file1.ts\",\"%s/file2.ts\"],\"compilerOptions\":{\"allowJs\":true,\"noImplicitAny\":true}}", baseDir.toString().replaceAll("[\\\\/]", "/"), baseDir.toString().replaceAll("[\\\\/]", "/")) + String.format("{\"files\":[\"%s/file1.ts\",\"%s/file2.ts\"],\"compilerOptions\":{\"allowJs\":true,\"noImplicitAny\":true}}", baseDir.toRealPath().toString().replaceAll("[\\\\/]", "/"), baseDir.toRealPath().toString().replaceAll("[\\\\/]", "/")) ); } @@ -264,9 +253,9 @@ void should_create_wildcard_tsconfig() throws Exception { createInputFile(ctx, "file1.js"); createInputFile(ctx, "file2.js"); var tsConfigCache = tsConfigCache(); - var tsconfigs = getTsConfigs(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); + initializeTsConfigCache(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); - assertThat(tsconfigs) + assertThat(tsConfigCache.listCachedTsConfigs(TsConfigOrigin.FALLBACK)) .hasSize(1) .extracting(path -> Files.readString(Paths.get(path))) .contains( @@ -283,7 +272,7 @@ void should_not_recreate_wildcard_tsconfig_in_sonarlint() throws Exception { ctx.setRuntime(SonarRuntimeImpl.forSonarLint(Version.create(4, 4))); var tsConfigCache = tsConfigCache(); - var originalTsConfigs = getTsConfigs(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); + initializeTsConfigCache(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); var tsconfigs = new WildcardTsConfigProvider( @@ -291,7 +280,7 @@ void should_not_recreate_wildcard_tsconfig_in_sonarlint() throws Exception { TsConfigProviderTest::createTsConfigFile ) .tsconfigs(ctx); - assertThat(tsconfigs).isEqualTo(originalTsConfigs); + assertThat(tsconfigs).isEqualTo(tsConfigCache.listCachedTsConfigs(TsConfigOrigin.FALLBACK)); } @Test @@ -303,8 +292,8 @@ void should_not_create_wildcard_tsconfig_in_sonarlint() throws Exception { createInputFile(ctx, "file2.js"); var tsConfigCache = tsConfigCache(); - var tsconfigs = getTsConfigs(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); - assertThat(tsconfigs).isEmpty(); + initializeTsConfigCache(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); + assertThat(tsConfigCache.listCachedTsConfigs(TsConfigOrigin.FALLBACK)).isEmpty(); } @Test @@ -337,7 +326,7 @@ void should_check_javascript_files() throws IOException { createInputFile(ctx, "node_modules/dep.js"); var tsConfigCache = tsConfigCache(); - getTsConfigs(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); + initializeTsConfigCache(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); assertThat(logger.logs()).contains("Turning on type-checking of JavaScript files"); } @@ -353,7 +342,7 @@ void should_detect_projects_with_too_many_files() throws IOException { createInputFile(ctx, "file3.cjs"); createInputFile(ctx, "file4.cts"); var tsConfigCache = tsConfigCache(); - getTsConfigs(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); + initializeTsConfigCache(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); assertThat(WildcardTsConfigProvider.isBeyondLimit(ctx, tsConfigCache.getProjectSize())).isTrue(); assertThat(logger.logs()) .contains( From 8c73032439f534954863b01ebc19d176f3eac227 Mon Sep 17 00:00:00 2001 From: Michal Zgliczynski Date: Tue, 3 Dec 2024 17:02:10 +0100 Subject: [PATCH 8/9] fix 2 SQ issues --- .../plugins/javascript/analysis/AnalysisWithWatchProgram.java | 4 ---- .../sonar/plugins/javascript/analysis/TsConfigProvider.java | 3 ++- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithWatchProgram.java b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithWatchProgram.java index 0788773b64f..72476e380f0 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithWatchProgram.java +++ b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AnalysisWithWatchProgram.java @@ -18,8 +18,6 @@ import java.io.IOException; import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.sonar.api.batch.fs.InputFile; import org.sonar.plugins.javascript.bridge.AnalysisWarningsWrapper; import org.sonar.plugins.javascript.bridge.BridgeServer; @@ -30,8 +28,6 @@ @SonarLintSide public class AnalysisWithWatchProgram extends AbstractAnalysis { - private static final Logger LOG = LoggerFactory.getLogger(AnalysisWithWatchProgram.class); - TsConfigCache tsConfigCache; public AnalysisWithWatchProgram( diff --git a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/TsConfigProvider.java b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/TsConfigProvider.java index f126fe69134..272b5927be4 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/TsConfigProvider.java +++ b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/TsConfigProvider.java @@ -123,7 +123,8 @@ public List tsconfigs(SensorContext context) { String property = context.config().hasKey(TSCONFIG_PATHS) ? TSCONFIG_PATHS : TSCONFIG_PATHS_ALIAS; Set patterns = new HashSet<>(Arrays.asList(context.config().getStringArray(property))); - LOG.info("Resolving TSConfig files using '{}' from property {}", String.join(",", patterns), property); + var patternString = String.join(",", patterns); + LOG.info("Resolving TSConfig files using '{}' from property {}", patternString, property); File baseDir = context.fileSystem().baseDir(); From b551027e8652aed2f717bf1c11b53b728083617b Mon Sep 17 00:00:00 2001 From: Michal Zgliczynski Date: Wed, 4 Dec 2024 14:43:14 +0100 Subject: [PATCH 9/9] format --- .../javascript/analysis/TsConfigProvider.java | 108 ++++++++++--- .../analysis/TsConfigCacheTest.java | 148 ++++++++++++----- .../analysis/TsConfigProviderTest.java | 150 +++++++----------- 3 files changed, 256 insertions(+), 150 deletions(-) diff --git a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/TsConfigProvider.java b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/TsConfigProvider.java index 272b5927be4..c12eefe1b0d 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/TsConfigProvider.java +++ b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/TsConfigProvider.java @@ -82,8 +82,20 @@ interface TsConfigFileCreator { * 2. Looking up file system * 3. Creating a tmp tsconfig.json listing all files */ - static List getTsConfigs(ContextUtils contextUtils, TsConfigProvider.TsConfigFileCreator tsConfigFileCreator) throws IOException { - var provider = new TsConfigProvider(List.of(new PropertyTsConfigProvider(), new LookupTsConfigProvider(), new TsConfigProvider.DefaultTsConfigProvider(tsConfigFileCreator, JavaScriptFilePredicate::getJsTsPredicate))); + static List getTsConfigs( + ContextUtils contextUtils, + TsConfigProvider.TsConfigFileCreator tsConfigFileCreator + ) throws IOException { + var provider = new TsConfigProvider( + List.of( + new PropertyTsConfigProvider(), + new LookupTsConfigProvider(), + new TsConfigProvider.DefaultTsConfigProvider( + tsConfigFileCreator, + JavaScriptFilePredicate::getJsTsPredicate + ) + ) + ); return provider.tsconfigs(contextUtils.context()); } @@ -92,8 +104,19 @@ static List getTsConfigs(ContextUtils contextUtils, TsConfigProvider.TsC * providers. No need to return the list of tsconfigs * because we get the tsconfig file from the cache. */ - static void initializeTsConfigCache(ContextUtils contextUtils, TsConfigProvider.TsConfigFileCreator tsConfigFileCreator, TsConfigCache tsConfigCache) throws IOException { - var provider = new TsConfigProvider(List.of(new PropertyTsConfigProvider(), new LookupTsConfigProvider(tsConfigCache), new TsConfigProvider.WildcardTsConfigProvider(tsConfigCache, tsConfigFileCreator)), tsConfigCache); + static void initializeTsConfigCache( + ContextUtils contextUtils, + TsConfigProvider.TsConfigFileCreator tsConfigFileCreator, + TsConfigCache tsConfigCache + ) throws IOException { + var provider = new TsConfigProvider( + List.of( + new PropertyTsConfigProvider(), + new LookupTsConfigProvider(tsConfigCache), + new TsConfigProvider.WildcardTsConfigProvider(tsConfigCache, tsConfigFileCreator) + ), + tsConfigCache + ); provider.tsconfigs(contextUtils.context()); } @@ -114,14 +137,21 @@ List tsconfigs(SensorContext context) throws IOException { } static class PropertyTsConfigProvider implements Provider { + @Override public List tsconfigs(SensorContext context) { - if (!context.config().hasKey(TSCONFIG_PATHS) && !context.config().hasKey(TSCONFIG_PATHS_ALIAS)) { + if ( + !context.config().hasKey(TSCONFIG_PATHS) && !context.config().hasKey(TSCONFIG_PATHS_ALIAS) + ) { return emptyList(); } - String property = context.config().hasKey(TSCONFIG_PATHS) ? TSCONFIG_PATHS : TSCONFIG_PATHS_ALIAS; - Set patterns = new HashSet<>(Arrays.asList(context.config().getStringArray(property))); + String property = context.config().hasKey(TSCONFIG_PATHS) + ? TSCONFIG_PATHS + : TSCONFIG_PATHS_ALIAS; + Set patterns = new HashSet<>( + Arrays.asList(context.config().getStringArray(property)) + ); var patternString = String.join(",", patterns); LOG.info("Resolving TSConfig files using '{}' from property {}", patternString, property); @@ -170,6 +200,7 @@ private static Path getFilePath(File baseDir, String path) { } static class LookupTsConfigProvider implements Provider { + private final TsConfigCache cache; LookupTsConfigProvider(@Nullable TsConfigCache cache) { @@ -229,7 +260,9 @@ public TsConfigOrigin type() { } abstract static class GeneratedTsConfigFileProvider implements Provider { + static class TsConfig { + List files; Map compilerOptions = new LinkedHashMap<>(); List include; @@ -244,7 +277,6 @@ static class TsConfig { this.include = include; } - List writeFileWith(TsConfigFileCreator tsConfigFileCreator) { try { return singletonList(tsConfigFileCreator.createTsConfigFile(new Gson().toJson(this))); @@ -269,7 +301,11 @@ public TsConfigOrigin type() { public final List tsconfigs(SensorContext context) throws IOException { if (context.runtime().getProduct() != product) { // we don't support per analysis temporary files in SonarLint see https://jira.sonarsource.com/browse/SLCORE-235 - LOG.warn("Generating temporary tsconfig is not supported by {} in {} context.", getClass().getSimpleName(), context.runtime().getProduct()); + LOG.warn( + "Generating temporary tsconfig is not supported by {} in {} context.", + getClass().getSimpleName(), + context.runtime().getProduct() + ); return emptyList(); } return getDefaultTsConfigs(context); @@ -279,10 +315,14 @@ public final List tsconfigs(SensorContext context) throws IOException { } static class DefaultTsConfigProvider extends GeneratedTsConfigFileProvider { + private final Function filePredicateProvider; private final TsConfigFileCreator tsConfigFileCreator; - DefaultTsConfigProvider(TsConfigFileCreator tsConfigFileCreator, Function filePredicate) { + DefaultTsConfigProvider( + TsConfigFileCreator tsConfigFileCreator, + Function filePredicate + ) { super(SonarProduct.SONARQUBE); this.tsConfigFileCreator = tsConfigFileCreator; this.filePredicateProvider = filePredicate; @@ -290,7 +330,9 @@ static class DefaultTsConfigProvider extends GeneratedTsConfigFileProvider { @Override List getDefaultTsConfigs(SensorContext context) throws IOException { - var inputFiles = context.fileSystem().inputFiles(filePredicateProvider.apply(context.fileSystem())); + var inputFiles = context + .fileSystem() + .inputFiles(filePredicateProvider.apply(context.fileSystem())); var tsConfig = new TsConfig(inputFiles, null); var tsconfigFile = writeToJsonFile(tsConfig); LOG.debug("Using generated tsconfig.json file {}", tsconfigFile.getAbsolutePath()); @@ -304,15 +346,20 @@ private File writeToJsonFile(TsConfig tsConfig) throws IOException { } static class WildcardTsConfigProvider extends GeneratedTsConfigFileProvider { + static final String MAX_FILES_PROPERTY = "sonar.javascript.sonarlint.typechecking.maxfiles"; static final int DEFAULT_MAX_FILES_FOR_TYPE_CHECKING = 20_000; - private static final Map> defaultWildcardTsConfig = new ConcurrentHashMap<>(); + private static final Map> defaultWildcardTsConfig = + new ConcurrentHashMap<>(); final TsConfigCache tsConfigCache; final TsConfigFileCreator tsConfigFileCreator; - WildcardTsConfigProvider(@Nullable TsConfigCache tsConfigCache, TsConfigFileCreator tsConfigFileCreator) { + WildcardTsConfigProvider( + @Nullable TsConfigCache tsConfigCache, + TsConfigFileCreator tsConfigFileCreator + ) { super(SonarProduct.SONARLINT); this.tsConfigCache = tsConfigCache; this.tsConfigFileCreator = tsConfigFileCreator; @@ -320,16 +367,22 @@ static class WildcardTsConfigProvider extends GeneratedTsConfigFileProvider { private static String getProjectRoot(SensorContext context) { var projectBaseDir = context.fileSystem().baseDir().getAbsolutePath(); - return "/".equals(File.separator) ? projectBaseDir : projectBaseDir.replace(File.separator, "/"); + return "/".equals(File.separator) + ? projectBaseDir + : projectBaseDir.replace(File.separator, "/"); } @Override List getDefaultTsConfigs(SensorContext context) { - boolean deactivated = tsConfigCache == null || isBeyondLimit(context, tsConfigCache.getProjectSize()); + boolean deactivated = + tsConfigCache == null || isBeyondLimit(context, tsConfigCache.getProjectSize()); if (deactivated) { return emptyList(); } else { - return defaultWildcardTsConfig.computeIfAbsent(getProjectRoot(context), this::writeTsConfigFileFor); + return defaultWildcardTsConfig.computeIfAbsent( + getProjectRoot(context), + this::writeTsConfigFileFor + ); } } @@ -349,17 +402,30 @@ static boolean isBeyondLimit(SensorContext context, int projectSize) { } else { // TypeScript type checking mechanism creates performance issues for large projects. Analyzing a file can take more than a minute in // SonarLint, and it can even lead to runtime errors due to Node.js being out of memory during the process. - LOG.warn("Turning off type-checking of JavaScript files due to the project size exceeding the limit ({} files)", typeCheckingLimit); + LOG.warn( + "Turning off type-checking of JavaScript files due to the project size exceeding the limit ({} files)", + typeCheckingLimit + ); LOG.warn("This may cause rules dependent on type information to not behave as expected"); - LOG.warn("Check the list of impacted rules at https://rules.sonarsource.com/javascript/tag/type-dependent"); - LOG.warn("To turn type-checking back on, increase the \"{}\" property value", MAX_FILES_PROPERTY); - LOG.warn("Please be aware that this could potentially impact the performance of the analysis"); + LOG.warn( + "Check the list of impacted rules at https://rules.sonarsource.com/javascript/tag/type-dependent" + ); + LOG.warn( + "To turn type-checking back on, increase the \"{}\" property value", + MAX_FILES_PROPERTY + ); + LOG.warn( + "Please be aware that this could potentially impact the performance of the analysis" + ); } return beyondLimit; } static int getTypeCheckingLimit(SensorContext context) { - return Math.max(context.config().getInt(MAX_FILES_PROPERTY).orElse(DEFAULT_MAX_FILES_FOR_TYPE_CHECKING), 0); + return Math.max( + context.config().getInt(MAX_FILES_PROPERTY).orElse(DEFAULT_MAX_FILES_FOR_TYPE_CHECKING), + 0 + ); } } } diff --git a/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/analysis/TsConfigCacheTest.java b/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/analysis/TsConfigCacheTest.java index bedda7f9166..6274e6ce702 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/analysis/TsConfigCacheTest.java +++ b/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/analysis/TsConfigCacheTest.java @@ -30,7 +30,6 @@ import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; - import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -61,6 +60,7 @@ class TsConfigCacheTest { @Mock private BridgeServerImpl bridgeServerMock; + private TsConfigCacheImpl tsConfigCache; @TempDir @@ -82,16 +82,33 @@ public void setUp() { void test() throws Exception { List files = Arrays.asList("dir1/file1.ts", "dir2/file2.ts", "dir3/file3.ts"); - List inputFiles = files .stream() - .map(f -> TestInputFileBuilder.create("moduleKey", baseDir.toFile(), baseDir.resolve(f).toFile()).build()) + .map(f -> + TestInputFileBuilder.create( + "moduleKey", + baseDir.toFile(), + baseDir.resolve(f).toFile() + ).build() + ) .collect(Collectors.toList()); List tsConfigFiles = Arrays.asList( - new TsConfigFile(absolutePath(baseDir, "dir1/tsconfig.json"), singletonList(inputFiles.get(0).absolutePath()), emptyList()), - new TsConfigFile(absolutePath(baseDir, "dir2/tsconfig.json"), singletonList(inputFiles.get(1).absolutePath()), emptyList()), - new TsConfigFile(absolutePath(baseDir, "dir3/tsconfig.json"), singletonList(inputFiles.get(2).absolutePath()), emptyList()) + new TsConfigFile( + absolutePath(baseDir, "dir1/tsconfig.json"), + singletonList(inputFiles.get(0).absolutePath()), + emptyList() + ), + new TsConfigFile( + absolutePath(baseDir, "dir2/tsconfig.json"), + singletonList(inputFiles.get(1).absolutePath()), + emptyList() + ), + new TsConfigFile( + absolutePath(baseDir, "dir3/tsconfig.json"), + singletonList(inputFiles.get(2).absolutePath()), + emptyList() + ) ); for (var tsConfigFile : tsConfigFiles) { @@ -100,13 +117,20 @@ void test() throws Exception { Files.createFile(tsConfigPath); } SensorContextTester ctx = SensorContextTester.create(baseDir); - TsConfigProvider.initializeTsConfigCache(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); + TsConfigProvider.initializeTsConfigCache( + new ContextUtils(ctx), + this::tsConfigFileCreator, + tsConfigCache + ); - when(bridgeServerMock.loadTsConfig(any())) - .thenAnswer(invocationOnMock -> { - String tsConfigPath = (String) invocationOnMock.getArguments()[0]; - return tsConfigFiles.stream().filter(tsConfigFile -> tsConfigPath.endsWith(tsConfigFile.getFilename())).findFirst().get(); - }); + when(bridgeServerMock.loadTsConfig(any())).thenAnswer(invocationOnMock -> { + String tsConfigPath = (String) invocationOnMock.getArguments()[0]; + return tsConfigFiles + .stream() + .filter(tsConfigFile -> tsConfigPath.endsWith(tsConfigFile.getFilename())) + .findFirst() + .get(); + }); for (var i = 0; i < files.size(); i++) { var tsConfigFile = tsConfigCache.getTsConfigForInputFile(inputFiles.get(i)); @@ -116,7 +140,11 @@ void test() throws Exception { @Test void failsToLoad() { - assertThat(tsConfigCache.getTsConfigForInputFile(TestInputFileBuilder.create("foo", "file1.ts").setLanguage(TypeScriptLanguage.KEY).build())).isNull(); + assertThat( + tsConfigCache.getTsConfigForInputFile( + TestInputFileBuilder.create("foo", "file1.ts").setLanguage(TypeScriptLanguage.KEY).build() + ) + ).isNull(); } @Test @@ -134,7 +162,10 @@ void testClearCacheOnTsConfigChange() throws IOException { var fileAndTsConfig = prepareFileAndTsConfig(); var file1 = fileAndTsConfig.getLeft(); var tsConfigFile = fileAndTsConfig.getRight(); - var tsConfigInputFile = TestInputFileBuilder.create(baseDir.toString(), "tsconfig.json").build(); + var tsConfigInputFile = TestInputFileBuilder.create( + baseDir.toString(), + "tsconfig.json" + ).build(); var foundTsConfig = tsConfigCache.getTsConfigForInputFile(file1); assertThat(foundTsConfig.getFilename()).isEqualTo(tsConfigFile.getFilename()); @@ -147,16 +178,30 @@ void testClearCacheOnTsConfigChange() throws IOException { @Test void testResolvesReferences() throws IOException { - var file1 = TestInputFileBuilder.create(baseDir.toString(), "file1.ts").setLanguage(TypeScriptLanguage.KEY).build(); + var file1 = TestInputFileBuilder.create(baseDir.toString(), "file1.ts") + .setLanguage(TypeScriptLanguage.KEY) + .build(); Path tsconfig1 = baseDir.resolve("tsconfig.json"); Path tsconfig2 = baseDir.resolve("tsconfig2.json"); - var tsConfigFile1 = new TsConfigFile(tsconfig1.toAbsolutePath().toString(), emptyList(), singletonList(tsconfig2.toAbsolutePath().toString())); - var tsConfigFile2 = new TsConfigFile(tsconfig2.toAbsolutePath().toString(), singletonList(file1.absolutePath()), emptyList()); + var tsConfigFile1 = new TsConfigFile( + tsconfig1.toAbsolutePath().toString(), + emptyList(), + singletonList(tsconfig2.toAbsolutePath().toString()) + ); + var tsConfigFile2 = new TsConfigFile( + tsconfig2.toAbsolutePath().toString(), + singletonList(file1.absolutePath()), + emptyList() + ); Files.createFile(tsconfig1); Files.createFile(tsconfig2); SensorContextTester ctx = SensorContextTester.create(baseDir); - TsConfigProvider.initializeTsConfigCache(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); + TsConfigProvider.initializeTsConfigCache( + new ContextUtils(ctx), + this::tsConfigFileCreator, + tsConfigCache + ); when(bridgeServerMock.loadTsConfig(any())).thenAnswer(invocationOnMock -> { String tsConfigPath = (String) invocationOnMock.getArguments()[0]; if (tsConfigPath.equals(tsConfigFile1.getFilename())) { @@ -171,7 +216,8 @@ void testResolvesReferences() throws IOException { @ParameterizedTest @EnumSource(ModuleFileEvent.Type.class) - void testResolvesTsConfigsOnProjectFileChanges(ModuleFileEvent.Type operationType) throws IOException { + void testResolvesTsConfigsOnProjectFileChanges(ModuleFileEvent.Type operationType) + throws IOException { var fileAndTsConfig = prepareFileAndTsConfig(); var file1 = fileAndTsConfig.getLeft(); var tsConfigFile = fileAndTsConfig.getRight(); @@ -191,42 +237,59 @@ void testResolvesTsConfigsOnProjectFileChanges(ModuleFileEvent.Type operationTyp @Test void testPropertyTsConfigChanged() throws IOException { - var file1 = TestInputFileBuilder.create(baseDir.toString(), "file1.ts").setLanguage(TypeScriptLanguage.KEY).build(); + var file1 = TestInputFileBuilder.create(baseDir.toString(), "file1.ts") + .setLanguage(TypeScriptLanguage.KEY) + .build(); Path tsconfig1 = baseDir.resolve("tsconfig.json"); Files.createFile(tsconfig1); - var tsConfigFile = new TsConfigFile(tsconfig1.toAbsolutePath().toString(), singletonList(file1.absolutePath()), emptyList()); + var tsConfigFile = new TsConfigFile( + tsconfig1.toAbsolutePath().toString(), + singletonList(file1.absolutePath()), + emptyList() + ); SensorContextTester ctx = SensorContextTester.create(baseDir); - ctx.setSettings( - new MapSettings() - .setProperty( - TSCONFIG_PATHS, - "tsconfig.*.json,tsconfig.json" - ) + ctx.setSettings(new MapSettings().setProperty(TSCONFIG_PATHS, "tsconfig.*.json,tsconfig.json")); + TsConfigProvider.initializeTsConfigCache( + new ContextUtils(ctx), + this::tsConfigFileCreator, + tsConfigCache ); - TsConfigProvider.initializeTsConfigCache(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); when(bridgeServerMock.loadTsConfig(any())).thenReturn(tsConfigFile); var foundTsConfig = tsConfigCache.getTsConfigForInputFile(file1); assertThat(foundTsConfig.getFilename()).isEqualTo(tsConfigFile.getFilename()); Path tsconfig2 = baseDir.resolve("tsconfig.app.json"); - var tsConfigInputFile = TestInputFileBuilder.create(baseDir.toString(), "tsconfig.app.json").build(); + var tsConfigInputFile = TestInputFileBuilder.create( + baseDir.toString(), + "tsconfig.app.json" + ).build(); Files.createFile(tsconfig2); var fileEvent = DefaultModuleFileEvent.of(tsConfigInputFile, ModuleFileEvent.Type.CREATED); tsConfigCache.process(fileEvent); var propertyCachedTsConfig = tsConfigCache.listCachedTsConfigs(TsConfigOrigin.PROPERTY); assertThat(propertyCachedTsConfig).containsExactly(tsconfig1.toAbsolutePath().toString()); - TsConfigProvider.initializeTsConfigCache(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); + TsConfigProvider.initializeTsConfigCache( + new ContextUtils(ctx), + this::tsConfigFileCreator, + tsConfigCache + ); propertyCachedTsConfig = tsConfigCache.listCachedTsConfigs(TsConfigOrigin.PROPERTY); - assertThat(propertyCachedTsConfig).containsExactlyInAnyOrder(tsconfig1.toAbsolutePath().toString(), tsconfig2.toAbsolutePath().toString()); + assertThat(propertyCachedTsConfig).containsExactlyInAnyOrder( + tsconfig1.toAbsolutePath().toString(), + tsconfig2.toAbsolutePath().toString() + ); } @Test void testPackageJsonChanged() throws IOException { Path packageJson = baseDir.resolve("package.json"); Files.createFile(packageJson); - var packageJsonFileInput = TestInputFileBuilder.create(baseDir.toString(), packageJson.getFileName().toString()).build(); + var packageJsonFileInput = TestInputFileBuilder.create( + baseDir.toString(), + packageJson.getFileName().toString() + ).build(); var fileEvent = DefaultModuleFileEvent.of(packageJsonFileInput, ModuleFileEvent.Type.MODIFIED); tsConfigCache.process(fileEvent); // We should mark the dependency cache to be cleared @@ -239,20 +302,33 @@ void testPackageJsonChanged() throws IOException { void testTSConfigChangedDoesntClearDependencyCache() throws IOException { Path tsconfig = baseDir.resolve("tsconfig.json"); Files.createFile(tsconfig); - var packageJsonFileInput = TestInputFileBuilder.create(baseDir.toString(), tsconfig.getFileName().toString()).build(); + var packageJsonFileInput = TestInputFileBuilder.create( + baseDir.toString(), + tsconfig.getFileName().toString() + ).build(); var fileEvent = DefaultModuleFileEvent.of(packageJsonFileInput, ModuleFileEvent.Type.MODIFIED); tsConfigCache.process(fileEvent); assertThat(tsConfigCache.getAndResetShouldClearDependenciesCache()).isFalse(); } private Pair prepareFileAndTsConfig() throws IOException { - var file1 = TestInputFileBuilder.create(baseDir.toString(), "file1.ts").setLanguage(TypeScriptLanguage.KEY).build(); + var file1 = TestInputFileBuilder.create(baseDir.toString(), "file1.ts") + .setLanguage(TypeScriptLanguage.KEY) + .build(); Path tsconfig1 = baseDir.resolve("tsconfig.json"); - var tsConfigFile = new TsConfigFile(tsconfig1.toAbsolutePath().toString(), singletonList(file1.absolutePath()), emptyList()); + var tsConfigFile = new TsConfigFile( + tsconfig1.toAbsolutePath().toString(), + singletonList(file1.absolutePath()), + emptyList() + ); Files.createFile(tsconfig1); SensorContextTester ctx = SensorContextTester.create(baseDir); - TsConfigProvider.initializeTsConfigCache(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); + TsConfigProvider.initializeTsConfigCache( + new ContextUtils(ctx), + this::tsConfigFileCreator, + tsConfigCache + ); when(bridgeServerMock.loadTsConfig(any())).thenReturn(tsConfigFile); return Pair.of(file1, tsConfigFile); } diff --git a/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/analysis/TsConfigProviderTest.java b/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/analysis/TsConfigProviderTest.java index b9522b52c82..32ec486326f 100644 --- a/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/analysis/TsConfigProviderTest.java +++ b/sonar-plugin/sonar-javascript-plugin/src/test/java/org/sonar/plugins/javascript/analysis/TsConfigProviderTest.java @@ -86,15 +86,11 @@ void should_lookup_tsconfig_files() throws Exception { createInputFile(ctx, "file1.ts"); createInputFile(ctx, "file2.ts"); - List tsconfigs = getTsConfigs( - new ContextUtils(ctx), - this::tsConfigFileCreator + List tsconfigs = getTsConfigs(new ContextUtils(ctx), this::tsConfigFileCreator); + assertThat(tsconfigs).containsExactlyInAnyOrder( + tsconfig1.toAbsolutePath().toString(), + tsconfig2.toAbsolutePath().toString() ); - assertThat(tsconfigs) - .containsExactlyInAnyOrder( - tsconfig1.toAbsolutePath().toString(), - tsconfig2.toAbsolutePath().toString() - ); } String tsConfigFileCreator(String content) throws IOException { @@ -108,22 +104,15 @@ void should_use_tsconfig_from_property() throws Exception { Path baseDir = tempFolder.newDir().toPath(); Files.createFile(baseDir.resolve("custom.tsconfig.json")); SensorContextTester ctx = SensorContextTester.create(baseDir); - ctx.setSettings( - new MapSettings().setProperty(TSCONFIG_PATHS, "custom.tsconfig.json") - ); + ctx.setSettings(new MapSettings().setProperty(TSCONFIG_PATHS, "custom.tsconfig.json")); createInputFile(ctx, "file.ts"); - List tsconfigs = getTsConfigs( - new ContextUtils(ctx), - this::tsConfigFileCreator - ); + List tsconfigs = getTsConfigs(new ContextUtils(ctx), this::tsConfigFileCreator); String absolutePath = baseDir.resolve("custom.tsconfig.json").toAbsolutePath().toString(); assertThat(tsconfigs).containsExactly(absolutePath); - assertThat(logger.logs(LoggerLevel.INFO)) - .contains( - "Resolving TSConfig files using 'custom.tsconfig.json' from property " + - TSCONFIG_PATHS - ); + assertThat(logger.logs(LoggerLevel.INFO)).contains( + "Resolving TSConfig files using 'custom.tsconfig.json' from property " + TSCONFIG_PATHS + ); } @Test @@ -135,10 +124,7 @@ void should_use_absolute_path_from_property() throws Exception { ctx.setSettings(new MapSettings().setProperty(TSCONFIG_PATHS, absolutePath)); createInputFile(ctx, "file.ts"); - List tsconfigs = getTsConfigs( - new ContextUtils(ctx), - this::tsConfigFileCreator - ); + List tsconfigs = getTsConfigs(new ContextUtils(ctx), this::tsConfigFileCreator); assertThat(tsconfigs).containsExactly(absolutePath); } @@ -159,21 +145,16 @@ void should_use_multiple_tsconfigs_from_property() throws Exception { ) ); - List tsconfigs = getTsConfigs( - new ContextUtils(ctx), - this::tsConfigFileCreator + List tsconfigs = getTsConfigs(new ContextUtils(ctx), this::tsConfigFileCreator); + assertThat(tsconfigs).containsExactlyInAnyOrder( + baseDir.resolve("base.tsconfig.json").toAbsolutePath().toString(), + baseDir.resolve("custom.tsconfig.json").toAbsolutePath().toString(), + baseDir.resolve("extended.tsconfig.json").toAbsolutePath().toString() + ); + assertThat(logger.logs(LoggerLevel.INFO)).contains( + "Resolving TSConfig files using 'base.tsconfig.json,custom.tsconfig.json,extended.tsconfig.json' from property " + + TSCONFIG_PATHS ); - assertThat(tsconfigs) - .containsExactlyInAnyOrder( - baseDir.resolve("base.tsconfig.json").toAbsolutePath().toString(), - baseDir.resolve("custom.tsconfig.json").toAbsolutePath().toString(), - baseDir.resolve("extended.tsconfig.json").toAbsolutePath().toString() - ); - assertThat(logger.logs(LoggerLevel.INFO)) - .contains( - "Resolving TSConfig files using 'base.tsconfig.json,custom.tsconfig.json,extended.tsconfig.json' from property " + - TSCONFIG_PATHS - ); } @Test @@ -189,21 +170,14 @@ void should_use_matching_tsconfigs_from_property() throws Exception { SensorContextTester ctx = SensorContextTester.create(baseDir); ctx.setSettings( new MapSettings() - .setProperty( - TSCONFIG_PATHS, - "**/tsconfig.settings.json,**/tsconfig.custom.json" - ) + .setProperty(TSCONFIG_PATHS, "**/tsconfig.settings.json,**/tsconfig.custom.json") ); - List tsconfigs = getTsConfigs( - new ContextUtils(ctx), - this::tsConfigFileCreator + List tsconfigs = getTsConfigs(new ContextUtils(ctx), this::tsConfigFileCreator); + assertThat(tsconfigs).containsExactlyInAnyOrder( + baseDir.resolve("tsconfig.settings.json").toAbsolutePath().toString(), + baseDir.resolve(Paths.get("dir", "tsconfig.settings.json")).toAbsolutePath().toString() ); - assertThat(tsconfigs) - .containsExactlyInAnyOrder( - baseDir.resolve("tsconfig.settings.json").toAbsolutePath().toString(), - baseDir.resolve(Paths.get("dir", "tsconfig.settings.json")).toAbsolutePath().toString() - ); } @Test @@ -212,20 +186,13 @@ void should_use_tsconfigs_from_property_alias() throws Exception { Files.createFile(baseDir.resolve("tsconfig.json")); SensorContextTester ctx = SensorContextTester.create(baseDir); - ctx.setSettings( - new MapSettings().setProperty(TSCONFIG_PATHS_ALIAS, "tsconfig.json") - ); + ctx.setSettings(new MapSettings().setProperty(TSCONFIG_PATHS_ALIAS, "tsconfig.json")); - List tsconfigs = getTsConfigs( - new ContextUtils(ctx), - this::tsConfigFileCreator - ); + List tsconfigs = getTsConfigs(new ContextUtils(ctx), this::tsConfigFileCreator); assertThat(tsconfigs).contains(baseDir.resolve("tsconfig.json").toAbsolutePath().toString()); - assertThat(logger.logs(LoggerLevel.INFO)) - .contains( - "Resolving TSConfig files using 'tsconfig.json' from property " + - TSCONFIG_PATHS_ALIAS - ); + assertThat(logger.logs(LoggerLevel.INFO)).contains( + "Resolving TSConfig files using 'tsconfig.json' from property " + TSCONFIG_PATHS_ALIAS + ); } @Test @@ -234,16 +201,16 @@ void should_create_tsconfig() throws Exception { createInputFile(ctx, "file1.ts"); createInputFile(ctx, "file2.ts"); - List tsconfigs = getTsConfigs( - new ContextUtils(ctx), - this::tsConfigFileCreator - ); + List tsconfigs = getTsConfigs(new ContextUtils(ctx), this::tsConfigFileCreator); assertThat(tsconfigs).hasSize(1); String tsconfig = Files.readString(Paths.get(tsconfigs.get(0))); - assertThat(tsconfig) - .isEqualToIgnoringCase( - String.format("{\"files\":[\"%s/file1.ts\",\"%s/file2.ts\"],\"compilerOptions\":{\"allowJs\":true,\"noImplicitAny\":true}}", baseDir.toRealPath().toString().replaceAll("[\\\\/]", "/"), baseDir.toRealPath().toString().replaceAll("[\\\\/]", "/")) - ); + assertThat(tsconfig).isEqualToIgnoringCase( + String.format( + "{\"files\":[\"%s/file1.ts\",\"%s/file2.ts\"],\"compilerOptions\":{\"allowJs\":true,\"noImplicitAny\":true}}", + baseDir.toRealPath().toString().replaceAll("[\\\\/]", "/"), + baseDir.toRealPath().toString().replaceAll("[\\\\/]", "/") + ) + ); } @Test @@ -274,12 +241,10 @@ void should_not_recreate_wildcard_tsconfig_in_sonarlint() throws Exception { var tsConfigCache = tsConfigCache(); initializeTsConfigCache(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); - var tsconfigs = - new WildcardTsConfigProvider( - tsConfigCache, - TsConfigProviderTest::createTsConfigFile - ) - .tsconfigs(ctx); + var tsconfigs = new WildcardTsConfigProvider( + tsConfigCache, + TsConfigProviderTest::createTsConfigFile + ).tsconfigs(ctx); assertThat(tsconfigs).isEqualTo(tsConfigCache.listCachedTsConfigs(TsConfigOrigin.FALLBACK)); } @@ -307,10 +272,7 @@ void should_not_fail_on_exception() throws Exception { var fileWriter = mock(TsConfigFileCreator.class); when(fileWriter.createTsConfigFile(anyString())).thenThrow(IOException.class); - var wildcardTsConfigProvider = new WildcardTsConfigProvider( - tsConfigCache, - fileWriter - ); + var wildcardTsConfigProvider = new WildcardTsConfigProvider(tsConfigCache, fileWriter); assertThat(wildcardTsConfigProvider.tsconfigs(ctx)).isEmpty(); } @@ -334,27 +296,29 @@ void should_check_javascript_files() throws IOException { void should_detect_projects_with_too_many_files() throws IOException { logger.setLevel(LoggerLevel.WARN); var ctx = SensorContextTester.create(baseDir); - ctx.setSettings( - new MapSettings().setProperty(WildcardTsConfigProvider.MAX_FILES_PROPERTY, 3) - ); + ctx.setSettings(new MapSettings().setProperty(WildcardTsConfigProvider.MAX_FILES_PROPERTY, 3)); createInputFile(ctx, "file1.js"); createInputFile(ctx, "file2.ts"); createInputFile(ctx, "file3.cjs"); createInputFile(ctx, "file4.cts"); var tsConfigCache = tsConfigCache(); initializeTsConfigCache(new ContextUtils(ctx), this::tsConfigFileCreator, tsConfigCache); - assertThat(WildcardTsConfigProvider.isBeyondLimit(ctx, tsConfigCache.getProjectSize())).isTrue(); - assertThat(logger.logs()) - .contains( - "Turning off type-checking of JavaScript files due to the project size exceeding the limit (3 files)", - "This may cause rules dependent on type information to not behave as expected", - "Check the list of impacted rules at https://rules.sonarsource.com/javascript/tag/type-dependent", - "To turn type-checking back on, increase the \"" + WildcardTsConfigProvider.MAX_FILES_PROPERTY + "\" property value", - "Please be aware that this could potentially impact the performance of the analysis" - ); + assertThat( + WildcardTsConfigProvider.isBeyondLimit(ctx, tsConfigCache.getProjectSize()) + ).isTrue(); + assertThat(logger.logs()).contains( + "Turning off type-checking of JavaScript files due to the project size exceeding the limit (3 files)", + "This may cause rules dependent on type information to not behave as expected", + "Check the list of impacted rules at https://rules.sonarsource.com/javascript/tag/type-dependent", + "To turn type-checking back on, increase the \"" + + WildcardTsConfigProvider.MAX_FILES_PROPERTY + + "\" property value", + "Please be aware that this could potentially impact the performance of the analysis" + ); } - private void createInputFile(SensorContextTester context, String relativePath) throws IOException { + private void createInputFile(SensorContextTester context, String relativePath) + throws IOException { DefaultInputFile inputFile = new TestInputFileBuilder(baseDir.toString(), relativePath) .setLanguage("ts") .setContents("if (cond)\ndoFoo(); \nelse \ndoFoo();")