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 657adc10534..722c2c4bd36 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, @@ -282,7 +280,8 @@ public void define(Context context) { EslintReportSensor.class, EslintRulesDefinition.class, TslintReportSensor.class, - TslintRulesDefinition.class + TslintRulesDefinition.class, + AnalysisWithProgram.class ); context.addExtension( @@ -342,7 +341,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 fb74c30676d..afbad57af1e 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"; @@ -90,7 +90,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, @@ -180,4 +180,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/AbstractBridgeSensor.java b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/AbstractBridgeSensor.java index 13525e1c815..06950ad258f 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 @@ -106,13 +106,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 3287c328114..076fa77e0ad 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,10 +33,8 @@ 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; @ScannerSide -@SonarLintSide public class AnalysisWithProgram extends AbstractAnalysis { private static final Logger LOG = LoggerFactory.getLogger(AnalysisWithProgram.class); @@ -50,7 +48,8 @@ public AnalysisWithProgram( } @Override - void analyzeFiles(List inputFiles, List tsConfigs) throws IOException { + void analyzeFiles(List inputFiles) throws IOException { + 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 717fdd6c395..9c8b62fbc7e 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,41 +18,31 @@ import java.io.IOException; import java.util.List; -import javax.annotation.Nullable; 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; import org.sonar.plugins.javascript.utils.ProgressReport; import org.sonarsource.api.sonarlint.SonarLintSide; -@ScannerSide @SonarLintSide 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; } @Override - public void analyzeFiles(List inputFiles, List tsConfigs) throws IOException { + public void analyzeFiles(List inputFiles) throws IOException { + 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/JsTsSensor.java b/sonar-plugin/sonar-javascript-plugin/src/main/java/org/sonar/plugins/javascript/analysis/JsTsSensor.java index e0f1e148784..751ed3aecc4 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 @@ -89,22 +78,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 5d6b52e8c17..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 @@ -55,6 +55,7 @@ public class TsConfigProvider { interface Provider { List tsconfigs(SensorContext context) throws IOException; + TsConfigOrigin type(); } @@ -71,6 +72,10 @@ interface TsConfigFileCreator { this.cache = cache; } + TsConfigProvider(List providers) { + this(providers, null); + } + /** * Relying on (in order of priority) * 1. Property sonar.typescript.tsconfigPath(s) @@ -79,26 +84,40 @@ interface TsConfigFileCreator { */ static List getTsConfigs( ContextUtils contextUtils, - TsConfigProvider.TsConfigFileCreator tsConfigFileCreator, - @Nullable TsConfigCache tsConfigCache + TsConfigProvider.TsConfigFileCreator tsConfigFileCreator ) 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(), + 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), - defaultProvider + new TsConfigProvider.WildcardTsConfigProvider(tsConfigCache, tsConfigFileCreator) ), tsConfigCache ); - - return provider.tsconfigs(contextUtils.context()); + provider.tsconfigs(contextUtils.context()); } List tsconfigs(SensorContext context) throws IOException { @@ -134,11 +153,8 @@ public List tsconfigs(SensorContext context) { 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(); @@ -191,6 +207,10 @@ static class LookupTsConfigProvider implements Provider { this.cache = cache; } + LookupTsConfigProvider() { + this(null); + } + @Override public List tsconfigs(SensorContext context) { if (cache != null) { 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 bbbf0625054..08e0f343294 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 { 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 eaf540899ac..02e08d183e7 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 @@ -36,11 +36,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); @@ -48,25 +46,20 @@ 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 - ); + assertThat(context.getExtensions()).hasSize(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); } 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 d3e9dab9cef..ffdf84be48e 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 @@ -393,7 +393,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(); @@ -545,7 +545,6 @@ void should_skip_analysis_when_no_files() { checks(ESLINT_BASED_RULE), bridgeServerMock, analysisWithProgram, - analysisWithWatchProgram, new AnalysisConsumers() ); javaScriptEslintBasedSensor.execute(context); @@ -562,7 +561,6 @@ void handle_missing_node() throws Exception { checks(ESLINT_BASED_RULE), bridgeServerMock, analysisWithProgram, - analysisWithWatchProgram, new AnalysisConsumers() ); createInputFile(context); @@ -625,7 +623,6 @@ void should_not_create_parsing_issue_when_no_rule() throws IOException { checks(ESLINT_BASED_RULE), bridgeServerMock, analysisWithProgram, - analysisWithWatchProgram, new AnalysisConsumers() ).execute(context); Collection issues = context.allIssues(); @@ -653,7 +650,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();" @@ -666,7 +663,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(); } @@ -798,12 +795,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 6873e330ef9..bb4da3c1732 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(); @@ -347,7 +347,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();" @@ -538,7 +538,7 @@ void should_analyze_by_tsconfig() throws Exception { ); 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()) @@ -751,7 +751,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(); @@ -911,7 +911,6 @@ public void doneAnalysis() { checks(ESLINT_BASED_RULE, "S2260"), bridgeServerMock, analysisWithProgram(), - analysisWithWatchProgram(), new AnalysisConsumers(List.of(consumer)) ); @@ -1019,7 +1018,6 @@ private JsTsSensor createSensorWithConsumer(JsAnalysisConsumer consumer) { checks(ESLINT_BASED_RULE, "S2260"), bridgeServerMock, analysisWithProgram(), - analysisWithWatchProgram(), new AnalysisConsumers(List.of(consumer)) ); } @@ -1029,6 +1027,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() ); 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 b448ee41918..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 @@ -117,7 +117,11 @@ 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 -> { String tsConfigPath = (String) invocationOnMock.getArguments()[0]; @@ -193,7 +197,11 @@ 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())) { @@ -241,7 +249,11 @@ void testPropertyTsConfigChanged() throws IOException { ); SensorContextTester ctx = SensorContextTester.create(baseDir); ctx.setSettings(new MapSettings().setProperty(TSCONFIG_PATHS, "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); @@ -258,7 +270,11 @@ 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(), @@ -308,7 +324,11 @@ 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 fc5127e5c31..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 @@ -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,17 +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; @@ -89,7 +86,7 @@ void should_lookup_tsconfig_files() throws Exception { createInputFile(ctx, "file1.ts"); createInputFile(ctx, "file2.ts"); - List tsconfigs = getTsConfigs(new ContextUtils(ctx), this::tsConfigFileCreator, null); + List tsconfigs = getTsConfigs(new ContextUtils(ctx), this::tsConfigFileCreator); assertThat(tsconfigs).containsExactlyInAnyOrder( tsconfig1.toAbsolutePath().toString(), tsconfig2.toAbsolutePath().toString() @@ -110,7 +107,7 @@ void should_use_tsconfig_from_property() throws Exception { ctx.setSettings(new MapSettings().setProperty(TSCONFIG_PATHS, "custom.tsconfig.json")); createInputFile(ctx, "file.ts"); - List tsconfigs = getTsConfigs(new ContextUtils(ctx), this::tsConfigFileCreator, null); + 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( @@ -127,7 +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, null); + List tsconfigs = getTsConfigs(new ContextUtils(ctx), this::tsConfigFileCreator); assertThat(tsconfigs).containsExactly(absolutePath); } @@ -148,7 +145,7 @@ void should_use_multiple_tsconfigs_from_property() throws Exception { ) ); - List tsconfigs = getTsConfigs(new ContextUtils(ctx), this::tsConfigFileCreator, null); + 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(), @@ -176,7 +173,7 @@ void should_use_matching_tsconfigs_from_property() throws Exception { .setProperty(TSCONFIG_PATHS, "**/tsconfig.settings.json,**/tsconfig.custom.json") ); - List tsconfigs = getTsConfigs(new ContextUtils(ctx), this::tsConfigFileCreator, null); + 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() @@ -191,7 +188,7 @@ void should_use_tsconfigs_from_property_alias() throws Exception { SensorContextTester ctx = SensorContextTester.create(baseDir); ctx.setSettings(new MapSettings().setProperty(TSCONFIG_PATHS_ALIAS, "tsconfig.json")); - List tsconfigs = getTsConfigs(new ContextUtils(ctx), this::tsConfigFileCreator, null); + 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 @@ -204,14 +201,14 @@ void should_create_tsconfig() throws Exception { createInputFile(ctx, "file1.ts"); createInputFile(ctx, "file2.ts"); - List tsconfigs = getTsConfigs(new ContextUtils(ctx), this::tsConfigFileCreator, null); + 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.toString().replaceAll("[\\\\/]", "/"), - baseDir.toString().replaceAll("[\\\\/]", "/") + baseDir.toRealPath().toString().replaceAll("[\\\\/]", "/"), + baseDir.toRealPath().toString().replaceAll("[\\\\/]", "/") ) ); } @@ -223,9 +220,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( @@ -242,17 +239,13 @@ 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( tsConfigCache, TsConfigProviderTest::createTsConfigFile ).tsconfigs(ctx); - assertThat(tsconfigs).isEqualTo(originalTsConfigs); + assertThat(tsconfigs).isEqualTo(tsConfigCache.listCachedTsConfigs(TsConfigOrigin.FALLBACK)); } @Test @@ -264,8 +257,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 @@ -295,7 +288,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"); } @@ -309,7 +302,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();