Skip to content

Commit

Permalink
Fixup tests
Browse files Browse the repository at this point in the history
  • Loading branch information
zglicz committed Oct 31, 2024
1 parent 6126c52 commit 537283f
Show file tree
Hide file tree
Showing 16 changed files with 248 additions and 486 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
import org.sonar.plugins.javascript.analysis.HtmlSensor;
import org.sonar.plugins.javascript.analysis.JsTsChecks;
import org.sonar.plugins.javascript.analysis.JsTsSensor;
import org.sonar.plugins.javascript.analysis.TsConfigCacheImpl;
import org.sonar.plugins.javascript.sonarlint.TsConfigCacheImpl;
import org.sonar.plugins.javascript.analysis.TsConfigProvider;
import org.sonar.plugins.javascript.analysis.YamlSensor;
import org.sonar.plugins.javascript.bridge.AnalysisWarningsWrapper;
Expand All @@ -59,7 +59,6 @@
import org.sonar.plugins.javascript.rules.JavaScriptRulesDefinition;
import org.sonar.plugins.javascript.rules.TslintRulesDefinition;
import org.sonar.plugins.javascript.rules.TypeScriptRulesDefinition;
import org.sonar.plugins.javascript.sonarlint.SonarLintTypeCheckingCheckerImpl;

public class JavaScriptPlugin implements Plugin {

Expand Down Expand Up @@ -121,10 +120,15 @@ public class JavaScriptPlugin implements Plugin {
public static final String TS_EXCLUSIONS_KEY = "sonar.typescript.exclusions";
public static final String[] EXCLUSIONS_DEFAULT_VALUE = new String[] {
"**/node_modules/**",
"**/node_modules",
"**/bower_components/**",
"**/bower_components",
"**/dist/**",
"**/dist",
"**/vendor/**",
"**/vendor",
"**/external/**",
"**/external",
"**/*.d.ts",
};

Expand Down Expand Up @@ -338,7 +342,6 @@ public void addSonarLintExtensions(
SonarLintPluginAPIVersion sonarLintPluginAPIVersion
) {
if (sonarLintPluginAPIVersion.isDependencyAvailable()) {
context.addExtension(SonarLintTypeCheckingCheckerImpl.class);
context.addExtension(TsConfigCacheImpl.class);
} else {
LOG.debug("Error while trying to inject SonarLint extensions");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
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.SonarLintTypeCheckingChecker;
import org.sonar.plugins.javascript.sonarlint.TsConfigCache;

@DependedUpon("js-analysis")
public class JsTsSensor extends AbstractBridgeSensor {
Expand All @@ -46,7 +46,6 @@ public class JsTsSensor extends AbstractBridgeSensor {
private final AnalysisWithProgram analysisWithProgram;
private final AnalysisWithWatchProgram analysisWithWatchProgram;
private final JsTsChecks checks;
private final SonarLintTypeCheckingChecker javaScriptProjectChecker;
private final AnalysisConsumers consumers;
private final TsConfigCache tsConfigCache;

Expand All @@ -57,30 +56,11 @@ public JsTsSensor(
AnalysisWithProgram analysisWithProgram,
AnalysisWithWatchProgram analysisWithWatchProgram,
AnalysisConsumers consumers
) {
this(
checks,
bridgeServer,
null,
analysisWithProgram,
analysisWithWatchProgram,
consumers
);
}

public JsTsSensor(
JsTsChecks checks,
BridgeServer bridgeServer,
@Nullable SonarLintTypeCheckingChecker javaScriptProjectChecker,
AnalysisWithProgram analysisWithProgram,
AnalysisWithWatchProgram analysisWithWatchProgram,
AnalysisConsumers consumers
) {
super(bridgeServer, "JS/TS");
this.analysisWithProgram = analysisWithProgram;
this.analysisWithWatchProgram = analysisWithWatchProgram;
this.checks = checks;
this.javaScriptProjectChecker = javaScriptProjectChecker;
this.consumers = consumers;
this.tsConfigCache = analysisWithWatchProgram.tsConfigCache;
}
Expand Down Expand Up @@ -115,7 +95,6 @@ protected void analyzeFiles(List<InputFile> inputFiles) throws IOException {

var tsConfigs = getTsConfigs(
contextUtils,
javaScriptProjectChecker,
this::createTsConfigFile,
tsConfigCache
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
*/
package org.sonar.plugins.javascript.analysis;

import static java.util.Arrays.stream;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.stream.Stream.concat;

import com.google.gson.Gson;
import java.io.File;
Expand All @@ -36,6 +38,7 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -44,8 +47,13 @@
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.config.Configuration;
import org.sonar.api.utils.WildcardPattern;
import org.sonar.plugins.javascript.JavaScriptFilePredicate;
import org.sonar.plugins.javascript.sonarlint.SonarLintTypeCheckingChecker;
import org.sonar.plugins.javascript.JavaScriptLanguage;
import org.sonar.plugins.javascript.JavaScriptPlugin;
import org.sonar.plugins.javascript.TypeScriptLanguage;
import org.sonar.plugins.javascript.sonarlint.TsConfigCache;
import org.sonarsource.analyzer.commons.FileProvider;

public class TsConfigProvider {
Expand Down Expand Up @@ -80,12 +88,11 @@ interface TsConfigFileCreator {
*/
static List<String> getTsConfigs(
ContextUtils contextUtils,
@Nullable SonarLintTypeCheckingChecker javaScriptProjectChecker,
TsConfigProvider.TsConfigFileCreator tsConfigFileCreator,
@Nullable TsConfigCache tsConfigCache
) throws IOException {
var defaultProvider = contextUtils.isSonarLint()
? new TsConfigProvider.WildcardTsConfigProvider(javaScriptProjectChecker, tsConfigFileCreator)
? new TsConfigProvider.WildcardTsConfigProvider(tsConfigCache, tsConfigFileCreator)
: new TsConfigProvider.DefaultTsConfigProvider(tsConfigFileCreator, JavaScriptFilePredicate::getJsTsPredicate);


Expand Down Expand Up @@ -192,9 +199,11 @@ public List<String> tsconfigs(SensorContext context) {
if (tsconfigs != null) {
return tsconfigs;
}

}
var fs = context.fileSystem();
var fileCount = 0;
var fileFilter = new FileFilter(context.config());
var pathFilter = new PathFilter(context.config());
var tsconfigs = new ArrayList<String>();
var dirs = new ArrayDeque<File>();
dirs.add(fs.baseDir());
Expand All @@ -205,20 +214,89 @@ public List<String> tsconfigs(SensorContext context) {
continue;
}
for (var file : files) {
if (file.isDirectory() && !"node_modules".equals(file.getName())) {
if (file.isDirectory() && !pathFilter.test(file.toPath())) {
dirs.add(file);
} else if ("tsconfig.json".equals(file.getName())) {
tsconfigs.add(file.getAbsolutePath());
} else {
if (fileFilter.test(file.toPath())) {
fileCount++;
} else if ("tsconfig.json".equals(file.getName())) {
tsconfigs.add(file.getAbsolutePath());
}
}
}
}
LOG.info("Found {} tsconfig.json file(s): {}", tsconfigs.size(), tsconfigs);
if (cache != null) {
cache.setProjectSize(fileCount);
}
return tsconfigs;
}

public TsConfigOrigin type() {
return TsConfigOrigin.LOOKUP;
}

static class FileFilter implements Predicate<Path> {

private final Set<String> extensions = new HashSet<>();

public FileFilter(Configuration config) {
extensions.addAll(
Arrays.asList(
config
.get(JavaScriptLanguage.FILE_SUFFIXES_KEY)
.orElse(JavaScriptLanguage.FILE_SUFFIXES_DEFVALUE)
.split(",")
)
);
extensions.addAll(
Arrays.asList(
config
.get(TypeScriptLanguage.FILE_SUFFIXES_KEY)
.orElse(TypeScriptLanguage.FILE_SUFFIXES_DEFVALUE)
.split(",")
)
);
}

@Override
public boolean test(Path path) {
return extensions.stream().anyMatch(ext -> path.toString().endsWith(ext));
}
}

static class PathFilter implements Predicate<Path> {

private final WildcardPattern[] exclusions;

public PathFilter(Configuration config) {
if (!isExclusionOverridden(config)) {
exclusions = WildcardPattern.create(JavaScriptPlugin.EXCLUSIONS_DEFAULT_VALUE);
} else {
WildcardPattern[] jsExcludedPatterns = WildcardPattern.create(
config.getStringArray(JavaScriptPlugin.JS_EXCLUSIONS_KEY)
);
WildcardPattern[] tsExcludedPatterns = WildcardPattern.create(
config.getStringArray(JavaScriptPlugin.TS_EXCLUSIONS_KEY)
);
exclusions =
concat(stream(jsExcludedPatterns), stream(tsExcludedPatterns))
.toArray(WildcardPattern[]::new);
}
}

private static boolean isExclusionOverridden(Configuration config) {
return (
config.get(JavaScriptPlugin.JS_EXCLUSIONS_KEY).isPresent() ||
config.get(JavaScriptPlugin.TS_EXCLUSIONS_KEY).isPresent()
);
}

@Override
public boolean test(Path path) {
return WildcardPattern.match(exclusions, path.toString().replaceAll("[\\\\/]", "/"));
}
}
}

abstract static class GeneratedTsConfigFileProvider implements Provider {
Expand Down Expand Up @@ -306,6 +384,9 @@ 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 String getProjectRoot(SensorContext context) {
var projectBaseDir = context.fileSystem().baseDir().getAbsolutePath();
return "/".equals(File.separator)
Expand All @@ -317,20 +398,20 @@ private static String getProjectRoot(SensorContext context) {
new ConcurrentHashMap<>();

final TsConfigFileCreator tsConfigFileCreator;
SonarLintTypeCheckingChecker checker;
final TsConfigCache tsConfigCache;

WildcardTsConfigProvider(
@Nullable SonarLintTypeCheckingChecker checker,
@Nullable TsConfigCache tsConfigCache,
TsConfigFileCreator tsConfigFileCreator
) {
super(SonarProduct.SONARLINT);
this.tsConfigFileCreator = tsConfigFileCreator;
this.checker = checker;
this.tsConfigCache = tsConfigCache;
}

@Override
List<String> getDefaultTsConfigs(SensorContext context) {
boolean deactivated = checker == null || checker.isBeyondLimit(context);
boolean deactivated = tsConfigCache == null || isBeyondLimit(context, tsConfigCache.getProjectSize());
if (deactivated) {
return emptyList();
} else {
Expand All @@ -347,5 +428,40 @@ List<String> writeTsConfigFileFor(String root) {
LOG.debug("Using generated tsconfig.json file using wildcards {}", file);
return file;
}

static boolean isBeyondLimit(SensorContext context, int projectSize) {
var typeCheckingLimit = getTypeCheckingLimit(context);

var beyondLimit = projectSize >= typeCheckingLimit;
if (!beyondLimit) {
LOG.info("Turning on type-checking of JavaScript files");
} 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("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"
);
}
return beyondLimit;
}

static int getTypeCheckingLimit(SensorContext context) {
return Math.max(
context.config().getInt(MAX_FILES_PROPERTY).orElse(DEFAULT_MAX_FILES_FOR_TYPE_CHECKING),
0
);
}
}
}

This file was deleted.

Loading

0 comments on commit 537283f

Please sign in to comment.