diff --git a/README.md b/README.md
index fbd1850..9775d6a 100644
--- a/README.md
+++ b/README.md
@@ -5,12 +5,15 @@
[![Downloads](https://img.shields.io/jetbrains/plugin/d/com.github.warningimhack3r.npmupdatedependencies.svg)](https://plugins.jetbrains.com/plugin/com.github.warningimhack3r.npmupdatedependencies)
## Description
+
Update your npm dependencies with a single click.
-This plugin will update all the dependencies in your `package.json` file to the latest version, or the satisfying version depending on your choice.
+This plugin will update all the dependencies in your `package.json` file to the latest version, or the satisfying
+version depending on your choice.
## Features
+
- Update a dependency to the latest or satisfying version
- Support for custom registries and private packages
- Keep comparators (e.g. `^`, `~`, `>`, `<`, `>=`, `<=`) when replacing versions
@@ -18,6 +21,7 @@ This plugin will update all the dependencies in your `package.json` file to the
- Batch update all dependencies (latest or satisfying), all deprecated dependencies
- Get notified of deprecated dependencies with a banner
- See your outdated dependencies at a glance in the status bar
+- Exclude dependencies or versions from the scan
- Configure everything in the settings
- Manually invalidate the cache in case of issues
- ...and more!
@@ -25,6 +29,7 @@ This plugin will update all the dependencies in your `package.json` file to the
## Usage
There are 3 ways to invoke the extension menu:
+
- Hover over an annotated dependency and click the action you want to perform
- Right click in the package.json file and select the extension from the context menu
- Use the Tools menu
@@ -33,25 +38,22 @@ Configuration options are available in the settings.
> Works by fetching [registry.npmjs.org](https://registry.npmjs.org).
> Rewrite of the existing [npm-dependency-checker](https://github.com/unger1984/npm-dependency-checker) plugin.
-
-## Planned Features
-- Show changelog for each dependency
-- Automatically install upgraded dependencies when saving the package.json file?
## Installation
- Using IDE built-in plugin system:
-
- Settings/Preferences > Plugins > Marketplace > Search for "npm-update-dependencies" >
+
+ Settings/Preferences > Plugins > Marketplace > Search for "
+ npm-update-dependencies" >
Install Plugin
-
+
- Manually:
- Download the [latest release](https://github.com/WarningImHack3r/npm-update-dependencies/releases/latest) and install it manually using
+ Download the [latest release](https://github.com/WarningImHack3r/npm-update-dependencies/releases/latest) and install
+ it manually using
Settings/Preferences > Plugins > ⚙️ > Install plugin from disk...
-
---
Plugin based on the [IntelliJ Platform Plugin Template][template].
diff --git a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/backend/engine/NPMJSClient.kt b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/backend/engine/NPMJSClient.kt
index a472a6a..b27a5b8 100644
--- a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/backend/engine/NPMJSClient.kt
+++ b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/backend/engine/NPMJSClient.kt
@@ -5,8 +5,8 @@ import com.google.gson.JsonObject
import com.google.gson.JsonParser
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
+import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.project.Project
-import com.jetbrains.rd.util.printlnError
import java.net.URI
import java.net.http.HttpClient
import java.net.http.HttpRequest
@@ -16,27 +16,46 @@ import java.net.http.HttpResponse
class NPMJSClient(private val project: Project) {
companion object {
private const val NPMJS_REGISTRY = "https://registry.npmjs.org"
+ private val log = logger()
+
+ @JvmStatic
+ fun getInstance(project: Project): NPMJSClient = project.service()
}
private fun getRegistry(packageName: String): String {
- val registryForPackage = project.service().packageRegistries
- val availableRegistries = project.service().registries
- return registryForPackage[packageName] ?: ShellRunner.execute(
+ log.info("Getting registry for package $packageName")
+ val registryForPackage = NUDState.getInstance(project).packageRegistries
+ val availableRegistries = RegistriesScanner.getInstance(project).registries
+ return registryForPackage[packageName].also {
+ if (it != null) {
+ log.debug("Registry for package $packageName found in cache: $it")
+ }
+ } ?: ShellRunner.execute(
arrayOf("npm", "v", packageName, "dist.tarball")
)?.trim()?.let { dist ->
val computedRegistry = dist.ifEmpty {
+ log.debug("No dist.tarball found for package $packageName, trying all registries")
availableRegistries.parallelMap { registry ->
ShellRunner.execute(
arrayOf("npm", "v", packageName, "dist.tarball", "--registry=$registry")
)?.trim()?.let { regDist ->
regDist.ifEmpty { null }
}
- }.firstNotNullOfOrNull { it } ?: return@let null
+ }.firstNotNullOfOrNull { it }.also {
+ if (it != null) {
+ log.debug("Found dist.tarball for package $packageName in registry $it")
+ }
+ } ?: return@let null.also {
+ log.debug("No dist.tarball found for package $packageName in any registry")
+ }
}
val registry = "${computedRegistry.substringBefore("/$packageName")}/"
+ log.info("Computed registry for package $packageName: $registry")
registryForPackage[packageName] = registry
registry
- } ?: NPMJS_REGISTRY
+ } ?: NPMJS_REGISTRY.also {
+ log.info("Using default registry for package $packageName")
+ }
}
private fun getResponseBody(uri: URI): String {
@@ -53,7 +72,7 @@ class NPMJSClient(private val project: Project) {
try {
responseBody = getResponseBody(URI(uri))
} catch (e: Exception) {
- printlnError("Error while getting response body from $uri: ${e.message}")
+ log.warn("Error while getting response body from $uri", e)
return null
}
return try {
@@ -63,40 +82,72 @@ class NPMJSClient(private val project: Project) {
null
}
} catch (e: Exception) {
- printlnError("Error while parsing response body from $uri: ${e.message}")
+ log.warn("Error while parsing response body from $uri", e)
null
}
}
fun getLatestVersion(packageName: String): String? {
+ log.info("Getting latest version for package $packageName")
val registry = getRegistry(packageName)
val json = getBodyAsJSON("${registry}/$packageName/latest")
- return json?.get("version")?.asString ?: ShellRunner.execute(
+ return json?.get("version")?.asString.also {
+ if (it != null) {
+ log.info("Latest version for package $packageName found in cache: $it")
+ }
+ } ?: ShellRunner.execute(
arrayOf("npm", "v", packageName, "version", "--registry=$registry")
- )?.trim()?.let { it.ifEmpty { null } }
+ )?.trim()?.let { it.ifEmpty { null } }.also {
+ if (it != null) {
+ log.info("Latest version for package $packageName found: $it")
+ } else {
+ log.warn("Latest version for package $packageName not found")
+ }
+ }
}
fun getAllVersions(packageName: String): List? {
+ log.info("Getting all versions for package $packageName")
val registry = getRegistry(packageName)
val json = getBodyAsJSON("${registry}/$packageName")
- return json?.get("versions")?.asJsonObject?.keySet()?.toList() ?: ShellRunner.execute(
+ return json?.get("versions")?.asJsonObject?.keySet()?.toList().also {
+ if (it != null) {
+ log.info("All versions for package $packageName found in cache: $it")
+ }
+ } ?: ShellRunner.execute(
arrayOf("npm", "v", packageName, "versions", "--json", "--registry=$registry")
)?.trim()?.let { versions ->
if (versions.isEmpty()) {
+ log.warn("All versions for package $packageName not found")
return null
} else if (versions.startsWith("[")) {
JsonParser.parseString(versions).asJsonArray.map { it.asString }
} else {
listOf(versions.replace("\"", ""))
}
+ }.also { versions ->
+ if (versions != null) {
+ log.info("All versions for package $packageName found: $versions")
+ }
}
}
fun getPackageDeprecation(packageName: String): String? {
+ log.info("Getting deprecation status for package $packageName")
val registry = getRegistry(packageName)
val json = getBodyAsJSON("${registry}/$packageName/latest")
- return json?.get("deprecated")?.asString ?: ShellRunner.execute(
+ return json?.get("deprecated")?.asString.also {
+ if (it != null) {
+ log.info("Deprecation status for package $packageName found in cache: $it")
+ }
+ } ?: ShellRunner.execute(
arrayOf("npm", "v", packageName, "deprecated", "--registry=$registry")
- )?.trim()?.let { it.ifEmpty { null } }
+ )?.trim()?.let { it.ifEmpty { null } }.also {
+ if (it != null) {
+ log.info("Deprecation status for package $packageName found: $it")
+ } else {
+ log.warn("Deprecation status for package $packageName not found")
+ }
+ }
}
}
diff --git a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/backend/engine/NUDState.kt b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/backend/engine/NUDState.kt
index 0d838e6..74d920b 100644
--- a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/backend/engine/NUDState.kt
+++ b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/backend/engine/NUDState.kt
@@ -4,9 +4,16 @@ import com.github.warningimhack3r.npmupdatedependencies.backend.data.Deprecation
import com.github.warningimhack3r.npmupdatedependencies.backend.data.ScanResult
import com.github.warningimhack3r.npmupdatedependencies.ui.statusbar.StatusBarHelper
import com.intellij.openapi.components.Service
+import com.intellij.openapi.components.service
+import com.intellij.openapi.project.Project
@Service(Service.Level.PROJECT)
class NUDState {
+ companion object {
+ @JvmStatic
+ fun getInstance(project: Project): NUDState = project.service()
+ }
+
val availableUpdates = mutableMapOf()
val deprecations = mutableMapOf()
val packageRegistries = mutableMapOf()
diff --git a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/backend/engine/PackageUpdateChecker.kt b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/backend/engine/PackageUpdateChecker.kt
index 7a1cb64..2cf3c5d 100644
--- a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/backend/engine/PackageUpdateChecker.kt
+++ b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/backend/engine/PackageUpdateChecker.kt
@@ -6,11 +6,19 @@ import com.github.warningimhack3r.npmupdatedependencies.settings.NUDSettingsStat
import com.github.warningimhack3r.npmupdatedependencies.ui.helpers.NUDHelper
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
+import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.project.Project
import org.semver4j.Semver
@Service(Service.Level.PROJECT)
class PackageUpdateChecker(private val project: Project) {
+ companion object {
+ private val log = logger()
+
+ @JvmStatic
+ fun getInstance(project: Project): PackageUpdateChecker = project.service()
+ }
+
private fun isVersionUpgradable(version: String): Boolean {
return !(version.startsWith("http")
|| version.startsWith("git")
@@ -22,7 +30,13 @@ class PackageUpdateChecker(private val project: Project) {
return comparator.split(" ").any { comp ->
val comparatorVersion = NUDHelper.Regex.semverPrefix.replace(comp, "")
if (comparatorVersion.trim().isEmpty()) return@any false
- Semver.coerce(comparatorVersion)?.let { version.isGreaterThan(it) } == true
+ Semver.coerce(comparatorVersion)?.let { version.isGreaterThan(it) }.also {
+ when (it) {
+ true -> log.debug("Version $version is greater than $comparatorVersion")
+ false -> log.debug("Version $version is not greater than $comparatorVersion")
+ else -> log.warn("Comparator version $comparatorVersion is invalid (comparator: $comp)")
+ }
+ } == true
}
}
@@ -38,39 +52,52 @@ class PackageUpdateChecker(private val project: Project) {
private fun getVersionExcludingFilter(packageName: String, version: Semver): String? {
return NUDSettingsState.instance.excludedVersions[packageName]?.let { excludedVersions ->
+ log.debug("Excluded versions for $packageName: $excludedVersions")
excludedVersions.firstOrNull { excludedVersion ->
- version.satisfies(excludedVersion)
+ version.satisfies(excludedVersion).also { satisfies ->
+ if (satisfies) {
+ log.debug("Version $version satisfies excluded version $excludedVersion")
+ } else {
+ log.debug("Version $version does not satisfy excluded version $excludedVersion")
+ }
+ }
}
}
}
fun areUpdatesAvailable(packageName: String, comparator: String): ScanResult? {
- val availableUpdates = project.service().availableUpdates
+ log.info("Checking for updates for $packageName with comparator $comparator")
+ val availableUpdates = NUDState.getInstance(project).availableUpdates
if (!isVersionUpgradable(comparator)) {
if (availableUpdates.containsKey(packageName)) {
availableUpdates.remove(packageName)
}
+ log.warn("Comparator $comparator is not upgradable, removing cached versions for $packageName")
return null
}
// Check if an update has already been found
availableUpdates[packageName]?.let { cachedVersions ->
if (areVersionsMatchingComparatorNeeds(cachedVersions.versions, comparator)) {
+ log.info("Cached versions for $packageName are still valid, returning them")
return cachedVersions
}
}
// Check if an update is available
- val npmjsClient = project.service()
+ val npmjsClient = NPMJSClient.getInstance(project)
var newestVersion = npmjsClient.getLatestVersion(packageName)?.let {
Semver.coerce(it)
- } ?: return null
+ } ?: return null.also {
+ log.warn("No latest version found for $packageName")
+ }
var satisfyingVersion: Semver? = null
val updateAvailable = isVersionMoreRecentThanComparator(newestVersion, comparator)
if (!updateAvailable) {
if (availableUpdates.containsKey(packageName)) {
availableUpdates.remove(packageName)
}
+ log.info("No update available for $packageName, removing cached versions")
return null
}
@@ -81,6 +108,7 @@ class PackageUpdateChecker(private val project: Project) {
|| newestVersion.build.isNotEmpty()
|| !newestVersion.satisfies(comparator)
) {
+ log.debug("Latest version $newestVersion is excluded, a beta, or does not satisfy the comparator")
val allVersions = npmjsClient.getAllVersions(packageName)?.mapNotNull { version ->
Semver.coerce(version)
}?.sortedDescending() ?: emptyList()
@@ -94,11 +122,14 @@ class PackageUpdateChecker(private val project: Project) {
} else if (version.preRelease.isEmpty() && version.build.isEmpty()
&& isVersionMoreRecentThanComparator(version, comparator)
) {
+ log.debug("Found latest version $version that satisfies the comparator, excluding filters: $filtersAffectingVersions")
latest = version
break
}
}
- newestVersion = latest ?: return null // No version greater than the comparator and not filtered
+ newestVersion = latest ?: return null.also { // No version greater than the comparator and not filtered
+ log.warn("No latest version found for $packageName that satisfies the comparator")
+ }
// Find satisfying version
if (!newestVersion.satisfies(comparator)) {
@@ -111,6 +142,7 @@ class PackageUpdateChecker(private val project: Project) {
&& version.satisfies(comparator)
&& isVersionMoreRecentThanComparator(version, comparator)
}
+ log.debug("Found satisfying version $satisfyingVersion for $packageName, excluding filters: $filtersAffectingVersions")
}
}
@@ -118,6 +150,7 @@ class PackageUpdateChecker(private val project: Project) {
Versions(newestVersion, satisfyingVersion),
filtersAffectingVersions
).also {
+ log.info("Found updates for $packageName: $it")
availableUpdates[packageName] = it
}
}
diff --git a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/backend/engine/RegistriesScanner.kt b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/backend/engine/RegistriesScanner.kt
index 71d95be..7950381 100644
--- a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/backend/engine/RegistriesScanner.kt
+++ b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/backend/engine/RegistriesScanner.kt
@@ -1,12 +1,23 @@
package com.github.warningimhack3r.npmupdatedependencies.backend.engine
import com.intellij.openapi.components.Service
+import com.intellij.openapi.components.service
+import com.intellij.openapi.diagnostic.logger
+import com.intellij.openapi.project.Project
@Service(Service.Level.PROJECT)
class RegistriesScanner {
+ companion object {
+ private val log = logger()
+
+ @JvmStatic
+ fun getInstance(project: Project): RegistriesScanner = project.service()
+ }
+
var registries: List = emptyList()
fun scan() {
+ log.info("Starting to scan registries")
// Run `npm config ls` to get the list of registries
val config = ShellRunner.execute(arrayOf("npm", "config", "ls")) ?: return
registries = config.lines().asSequence().filter { line ->
@@ -24,5 +35,6 @@ class RegistriesScanner {
.replace("\"", "")
}
}.map { it.removeSuffix("/") }.distinct().toList()
+ log.info("Found registries: $registries")
}
}
diff --git a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/backend/engine/ShellRunner.kt b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/backend/engine/ShellRunner.kt
index 5f02b93..ca08b12 100644
--- a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/backend/engine/ShellRunner.kt
+++ b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/backend/engine/ShellRunner.kt
@@ -1,8 +1,9 @@
package com.github.warningimhack3r.npmupdatedependencies.backend.engine
-import com.jetbrains.rd.util.printlnError
+import com.intellij.openapi.diagnostic.logger
object ShellRunner {
+ private val log = logger()
private val failedCommands = mutableSetOf()
private fun isWindows() = System.getProperty("os.name").lowercase().contains("win")
@@ -11,8 +12,10 @@ object ShellRunner {
val commandName = command.firstOrNull() ?: return null
if (isWindows() && failedCommands.contains(commandName)) {
command[0] = "$commandName.cmd"
+ log.warn("Retrying command with .cmd extension: \"${command.joinToString(" ")}\"")
}
return try {
+ log.debug("Executing \"${command.joinToString(" ")}\"")
val process = ProcessBuilder(*command)
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.start()
@@ -23,7 +26,7 @@ object ShellRunner {
failedCommands.add(commandName)
return execute(arrayOf("$commandName.cmd") + command.drop(1).toTypedArray())
}
- printlnError("Error while executing \"${command.joinToString(" ")}\": ${e.message}")
+ log.warn("Error while executing \"${command.joinToString(" ")}\"", e)
null
}
}
diff --git a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/settings/NUDSettingsComponent.kt b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/settings/NUDSettingsComponent.kt
index 93c069e..49b8208 100644
--- a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/settings/NUDSettingsComponent.kt
+++ b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/settings/NUDSettingsComponent.kt
@@ -8,7 +8,6 @@ import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
import com.intellij.ide.DataManager
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.application.runInEdt
-import com.intellij.openapi.components.service
import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.options.ex.Settings
import com.intellij.openapi.project.ProjectManager
@@ -188,7 +187,7 @@ class NUDSettingsComponent {
ProjectManager.getInstance().openProjects.forEach { project ->
// Clear the cache for packages with excluded versions
settings.excludedVersions.keys.forEach { packageName ->
- project.service().availableUpdates.remove(packageName)
+ NUDState.getInstance(project).availableUpdates.remove(packageName)
}
// if project's currently open file is package.json, re-analyze it
FileEditorManager.getInstance(project).selectedTextEditor?.let { editor ->
diff --git a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/annotation/DeprecationAnnotator.kt b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/annotation/DeprecationAnnotator.kt
index 5147d31..0d9294a 100644
--- a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/annotation/DeprecationAnnotator.kt
+++ b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/annotation/DeprecationAnnotator.kt
@@ -13,7 +13,7 @@ import com.intellij.json.psi.JsonProperty
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.lang.annotation.ExternalAnnotator
import com.intellij.lang.annotation.HighlightSeverity
-import com.intellij.openapi.components.service
+import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
@@ -24,6 +24,9 @@ class DeprecationAnnotator : DumbAware, ExternalAnnotator<
Pair>,
Map
>() {
+ companion object {
+ private val log = logger()
+ }
override fun collectInformation(file: PsiFile): Pair> =
Pair(file.project, AnnotatorsCommon.getInfo(file))
@@ -32,19 +35,23 @@ class DeprecationAnnotator : DumbAware, ExternalAnnotator<
val (project, info) = collectedInfo
if (info.isEmpty()) return emptyMap()
- var state = project.service()
+ var state = NUDState.getInstance(project)
if (!state.isScanningForRegistries && state.packageRegistries.isEmpty()) {
state.isScanningForRegistries = true
- project.service().scan()
+ log.debug("No registries found, scanning for registries...")
+ RegistriesScanner.getInstance(project).scan()
+ log.debug("Registries scanned")
state.isScanningForRegistries = false
}
while (state.isScanningForRegistries || state.isScanningForDeprecations) {
// Wait for the registries to be scanned and avoid multiple scans at the same time
+ log.debug("Waiting for registries to be scanned...")
}
- state = project.service()
- val npmjsClient = project.service()
+ log.debug("Scanning for deprecations...")
+ state = NUDState.getInstance(project)
+ val npmjsClient = NPMJSClient.getInstance(project)
return info
.also {
// Remove from the cache all deprecations that are no longer in the file
@@ -106,11 +113,13 @@ class DeprecationAnnotator : DumbAware, ExternalAnnotator<
}
}
}.filterNotNull().toMap().also {
+ log.debug("Deprecations scanned, ${it.size} found")
state.isScanningForDeprecations = false
}
}
override fun apply(file: PsiFile, annotationResult: Map, holder: AnnotationHolder) {
+ if (annotationResult.isNotEmpty()) log.debug("Creating annotations...")
annotationResult.forEach { (property, deprecation) ->
holder.newAnnotation(HighlightSeverity.ERROR, deprecation.reason)
.range(property.textRange)
@@ -137,6 +146,7 @@ class DeprecationAnnotator : DumbAware, ExternalAnnotator<
.create()
}
if (annotationResult.isNotEmpty()) {
+ log.debug("Annotations created, updating banner")
EditorNotifications.getInstance(file.project).updateAllNotifications()
}
}
diff --git a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/annotation/UpdatesAnnotator.kt b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/annotation/UpdatesAnnotator.kt
index 6e54e7f..3bdcbc4 100644
--- a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/annotation/UpdatesAnnotator.kt
+++ b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/annotation/UpdatesAnnotator.kt
@@ -16,7 +16,7 @@ import com.intellij.json.psi.JsonProperty
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.lang.annotation.ExternalAnnotator
import com.intellij.lang.annotation.HighlightSeverity
-import com.intellij.openapi.components.service
+import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
@@ -27,6 +27,9 @@ class UpdatesAnnotator : DumbAware, ExternalAnnotator<
Pair>,
Map
>() {
+ companion object {
+ private val log = logger()
+ }
override fun collectInformation(file: PsiFile): Pair> =
Pair(file.project, AnnotatorsCommon.getInfo(file))
@@ -35,19 +38,23 @@ class UpdatesAnnotator : DumbAware, ExternalAnnotator<
val (project, info) = collectedInfo
if (info.isEmpty()) return emptyMap()
- var state = project.service()
+ var state = NUDState.getInstance(project)
if (!state.isScanningForRegistries && state.packageRegistries.isEmpty()) {
state.isScanningForRegistries = true
- project.service().scan()
+ log.debug("No registries found, scanning for registries...")
+ RegistriesScanner.getInstance(project).scan()
+ log.debug("Registries scanned")
state.isScanningForRegistries = false
}
while (state.isScanningForRegistries || state.isScanningForUpdates) {
// Wait for the registries to be scanned and avoid multiple scans at the same time
+ log.debug("Waiting for registries to be scanned...")
}
- state = project.service()
- val updateChecker = project.service()
+ log.debug("Scanning for updates...")
+ state = NUDState.getInstance(project)
+ val updateChecker = PackageUpdateChecker.getInstance(project)
return info
.also {
// Remove from the cache all properties that are no longer in the file
@@ -67,11 +74,13 @@ class UpdatesAnnotator : DumbAware, ExternalAnnotator<
Pair(property.jsonProperty, scanResult)
} else null
}.filterNotNull().toMap().also {
+ log.debug("Updates scanned, ${it.size} found")
state.isScanningForUpdates = false
}
}
override fun apply(file: PsiFile, annotationResult: Map, holder: AnnotationHolder) {
+ if (annotationResult.isNotEmpty()) log.debug("Creating annotations...")
annotationResult.forEach { (property, scanResult) ->
val versions = scanResult.versions
val text = "An update is available!" + if (scanResult.affectedByFilters.isNotEmpty()) {
@@ -120,5 +129,6 @@ class UpdatesAnnotator : DumbAware, ExternalAnnotator<
.needsUpdateOnTyping()
.create()
}
+ if (annotationResult.isNotEmpty()) log.debug("Annotations created")
}
}
diff --git a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/banner/DeprecationBanner.kt b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/banner/DeprecationBanner.kt
index 15bd824..874a40e 100644
--- a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/banner/DeprecationBanner.kt
+++ b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/banner/DeprecationBanner.kt
@@ -5,7 +5,7 @@ import com.github.warningimhack3r.npmupdatedependencies.backend.engine.NUDState
import com.github.warningimhack3r.npmupdatedependencies.settings.NUDSettingsState
import com.github.warningimhack3r.npmupdatedependencies.ui.helpers.ActionsCommon
import com.intellij.icons.AllIcons
-import com.intellij.openapi.components.service
+import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.fileEditor.FileEditor
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
@@ -20,14 +20,22 @@ import java.util.function.Function
import javax.swing.JComponent
class DeprecationBanner : EditorNotificationProvider {
+ companion object {
+ private val log = logger()
+ }
override fun collectNotificationData(
project: Project,
file: VirtualFile
): Function = Function { _ ->
val psiFile = PsiManager.getInstance(project).findFile(file)
- val deprecations = project.service().deprecations
+ val deprecations = NUDState.getInstance(project).deprecations
if (psiFile == null || file.name != "package.json" || deprecations.isEmpty() || !NUDSettingsState.instance.showDeprecationBanner) {
+ when {
+ psiFile == null -> log.warn("Leaving: cannot find PSI file for ${file.name} @ ${file.path}")
+ deprecations.isEmpty() -> log.debug("Leaving: no deprecations found")
+ !NUDSettingsState.instance.showDeprecationBanner -> log.debug("Leaving: deprecation banner is disabled")
+ }
return@Function null
}
val deprecationsCount = deprecations.size
diff --git a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/helpers/ActionsCommon.kt b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/helpers/ActionsCommon.kt
index 8cc1263..419a450 100644
--- a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/helpers/ActionsCommon.kt
+++ b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/helpers/ActionsCommon.kt
@@ -5,7 +5,6 @@ import com.github.warningimhack3r.npmupdatedependencies.backend.engine.NUDState
import com.github.warningimhack3r.npmupdatedependencies.backend.extensions.stringValue
import com.github.warningimhack3r.npmupdatedependencies.settings.NUDSettingsState
import com.intellij.json.psi.JsonProperty
-import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import com.intellij.psi.impl.source.tree.LeafPsiElement
@@ -24,7 +23,7 @@ object ActionsCommon {
fun updateAll(file: PsiFile, kind: Versions.Kind) {
getAllDependencies(file)
.mapNotNull { property ->
- file.project.service().availableUpdates[property.name]?.let { scanResult ->
+ NUDState.getInstance(file.project).availableUpdates[property.name]?.let { scanResult ->
val newVersion = scanResult.versions.from(kind) ?: scanResult.versions.orderedAvailableKinds(kind)
.firstOrNull { it != kind }?.let { scanResult.versions.from(it) } ?: return@mapNotNull null
val prefix = NUDHelper.Regex.semverPrefix.find(property.value?.stringValue() ?: "")?.value ?: ""
@@ -43,7 +42,7 @@ object ActionsCommon {
}
fun replaceAllDeprecations(file: PsiFile) {
- val deprecations = file.project.service().deprecations
+ val deprecations = NUDState.getInstance(file.project).deprecations
getAllDependencies(file)
.mapNotNull { property ->
deprecations[property.name]?.let { deprecation ->
@@ -112,7 +111,7 @@ object ActionsCommon {
}
fun deleteAllDeprecations(file: PsiFile) {
- val deprecations = file.project.service().deprecations
+ val deprecations = NUDState.getInstance(file.project).deprecations
getAllDependencies(file)
.mapNotNull { property ->
if (deprecations.containsKey(property.name)) property else null
diff --git a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/helpers/NUDHelper.kt b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/helpers/NUDHelper.kt
index 3631070..d54945f 100644
--- a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/helpers/NUDHelper.kt
+++ b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/helpers/NUDHelper.kt
@@ -18,7 +18,8 @@ object NUDHelper {
WriteCommandAction.runWriteCommandAction(
file.project, description,
"com.github.warningimhack3r.npmupdatedependencies",
- action, file)
+ action, file
+ )
}
if (async) {
ApplicationManager.getApplication().invokeLater(writeAction)
@@ -33,7 +34,11 @@ object NUDHelper {
.firstChild
}
- fun getClosestElementMatching(match: (PsiElement) -> Boolean, element: PsiElement, cls: Class = PsiElement::class.java): PsiElement? {
+ fun getClosestElementMatching(
+ match: (PsiElement) -> Boolean,
+ element: PsiElement,
+ cls: Class = PsiElement::class.java
+ ): PsiElement? {
var sibling = element.nextSibling
while (sibling != null) {
if (sibling.javaClass == cls && match(sibling)) {
diff --git a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/listeners/OnSaveListener.kt b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/listeners/OnSaveListener.kt
index 361a551..0432f00 100644
--- a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/listeners/OnSaveListener.kt
+++ b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/listeners/OnSaveListener.kt
@@ -7,7 +7,6 @@ import com.github.warningimhack3r.npmupdatedependencies.settings.NUDSettingsStat
import com.github.warningimhack3r.npmupdatedependencies.ui.helpers.ActionsCommon
import com.github.warningimhack3r.npmupdatedependencies.ui.helpers.NUDHelper
import com.intellij.codeInsight.hint.HintManager
-import com.intellij.openapi.components.service
import com.intellij.openapi.editor.Document
import com.intellij.openapi.fileEditor.FileDocumentManagerListener
import com.intellij.openapi.fileEditor.FileEditorManager
@@ -21,11 +20,12 @@ import javax.swing.JLabel
class OnSaveListener(val project: Project) : FileDocumentManagerListener {
override fun beforeDocumentSaving(document: Document) {
- val state = project.service()
+ val state = NUDState.getInstance(project)
// Initial checks
val file = PsiDocumentManager.getInstance(project).getPsiFile(document) ?: return
if (file.name != "package.json" || !NUDSettingsState.instance.autoFixOnSave
- || (state.availableUpdates.isEmpty() && state.deprecations.isEmpty())) return
+ || (state.availableUpdates.isEmpty() && state.deprecations.isEmpty())
+ ) return
// Create a set of actions to perform
val actionsToPerform = mutableSetOf<() -> Unit>()
@@ -47,6 +47,7 @@ class OnSaveListener(val project: Project) : FileDocumentManagerListener {
Deprecation.Action.REPLACE -> actionsToPerform.add {
ActionsCommon.replaceAllDeprecations(file)
}
+
Deprecation.Action.REMOVE -> actionsToPerform.add {
ActionsCommon.deleteAllDeprecations(file)
}
diff --git a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/quickfix/BlacklistVersionFix.kt b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/quickfix/BlacklistVersionFix.kt
index 4e74613..51ab5a4 100644
--- a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/quickfix/BlacklistVersionFix.kt
+++ b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/quickfix/BlacklistVersionFix.kt
@@ -6,7 +6,6 @@ import com.github.warningimhack3r.npmupdatedependencies.settings.NUDSettingsStat
import com.github.warningimhack3r.npmupdatedependencies.ui.helpers.QuickFixesCommon
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
import com.intellij.codeInsight.intention.impl.BaseIntentionAction
-import com.intellij.openapi.components.service
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
@@ -35,6 +34,6 @@ class BlacklistVersionFix(
DaemonCodeAnalyzer.getInstance(project).restart(it)
}
// Clear the cache
- project.service().availableUpdates.remove(dependencyName)
+ NUDState.getInstance(project).availableUpdates.remove(dependencyName)
}
}
diff --git a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/quickfix/DeprecatedDependencyFix.kt b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/quickfix/DeprecatedDependencyFix.kt
index 82b930e..8e85d38 100644
--- a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/quickfix/DeprecatedDependencyFix.kt
+++ b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/quickfix/DeprecatedDependencyFix.kt
@@ -9,7 +9,6 @@ import com.github.warningimhack3r.npmupdatedependencies.ui.helpers.NUDHelper
import com.github.warningimhack3r.npmupdatedependencies.ui.helpers.QuickFixesCommon
import com.intellij.codeInsight.intention.impl.BaseIntentionAction
import com.intellij.json.psi.JsonProperty
-import com.intellij.openapi.components.service
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
@@ -71,7 +70,7 @@ class DeprecatedDependencyFix(
property.delete()
}
}
- project.service().deprecations.remove(property.name)
+ NUDState.getInstance(project).deprecations.remove(property.name)
ActionsCommon.deprecationsCompletion(project)
}
}
diff --git a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/statusbar/StatusBarFactory.kt b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/statusbar/StatusBarFactory.kt
index 61daa22..800f2d0 100644
--- a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/statusbar/StatusBarFactory.kt
+++ b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/statusbar/StatusBarFactory.kt
@@ -4,7 +4,6 @@ import com.github.warningimhack3r.npmupdatedependencies.backend.engine.NUDState
import com.github.warningimhack3r.npmupdatedependencies.settings.NUDSettingsState
import com.intellij.dvcs.ui.LightActionGroup
import com.intellij.ide.DataManager
-import com.intellij.openapi.components.service
import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.fileEditor.OpenFileDescriptor
import com.intellij.openapi.project.DumbAwareAction
@@ -24,6 +23,7 @@ class StatusBarFactory : StatusBarEditorBasedWidgetFactory() {
companion object {
const val ID = "NpmUpdateDependenciesStatusBarEditorFactory"
}
+
override fun getId(): String = ID
override fun getDisplayName(): String = "NPM Update Dependencies Status Bar"
@@ -48,6 +48,7 @@ class WidgetBar(project: Project) : EditorBasedWidget(project), StatusBarWidget.
companion object {
const val ID = "NpmUpdateDependenciesStatusBarWidgetBar"
}
+
private var currentStatus = Status.UNAVAILABLE
enum class Status {
@@ -123,13 +124,13 @@ class WidgetBar(project: Project) : EditorBasedWidget(project), StatusBarWidget.
"Available Changes",
LightActionGroup().apply {
addSeparator("Updates")
- addAll(project.service().availableUpdates.toSortedMap().map { update ->
+ addAll(NUDState.getInstance(project).availableUpdates.toSortedMap().map { update ->
DumbAwareAction.create(update.key) {
openPackageJson(update.key)
}
})
addSeparator("Deprecations")
- addAll(project.service().deprecations.toSortedMap().map { deprecation ->
+ addAll(NUDState.getInstance(project).deprecations.toSortedMap().map { deprecation ->
DumbAwareAction.create(deprecation.key) {
openPackageJson(deprecation.key)
}
@@ -143,7 +144,7 @@ class WidgetBar(project: Project) : EditorBasedWidget(project), StatusBarWidget.
override fun getSelectedValue(): String? {
if (!NUDSettingsState.instance.showStatusBarWidget) return null
- val state = project.service()
+ val state = NUDState.getInstance(project)
return when (currentStatus) {
Status.UNAVAILABLE -> null
Status.GATHERING_REGISTRIES -> "Gathering registries..."
@@ -160,12 +161,14 @@ class WidgetBar(project: Project) : EditorBasedWidget(project), StatusBarWidget.
deprecated == 0 -> "$outdated update${if (outdated == 1) "" else "s"}"
else -> "$outdated update${if (outdated == 1) "" else "s"}, $deprecated deprecation${if (deprecated == 1) "" else "s"}"
}
+
StatusBarMode.COMPACT -> when {
outdated == 0 && deprecated == 0 -> null
outdated == 0 -> "$deprecated D"
deprecated == 0 -> "$outdated U"
else -> "$outdated U / $deprecated D"
}
+
null -> null
}
}
@@ -174,7 +177,7 @@ class WidgetBar(project: Project) : EditorBasedWidget(project), StatusBarWidget.
// Custom
fun update() {
- val state = project.service()
+ val state = NUDState.getInstance(project)
currentStatus = when {
project.isDisposed || !NUDSettingsState.instance.showStatusBarWidget -> Status.UNAVAILABLE
state.isScanningForRegistries -> Status.GATHERING_REGISTRIES
diff --git a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/statusbar/StatusBarHelper.kt b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/statusbar/StatusBarHelper.kt
index 587ba36..f1784bd 100644
--- a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/statusbar/StatusBarHelper.kt
+++ b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/statusbar/StatusBarHelper.kt
@@ -1,15 +1,21 @@
package com.github.warningimhack3r.npmupdatedependencies.ui.statusbar
+import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.project.ProjectManager
import com.intellij.openapi.wm.WindowManager
object StatusBarHelper {
+ private val log = logger()
fun updateWidget() {
+ log.info("Updating widget")
val projectManager = ProjectManager.getInstanceIfCreated() ?: return
for (project in projectManager.openProjects) {
- val widgetBar = WindowManager.getInstance().getStatusBar(project).getWidget(WidgetBar.ID) as? WidgetBar ?: continue
+ log.debug("Updating widget for project ${project.name}")
+ val widgetBar =
+ WindowManager.getInstance().getStatusBar(project).getWidget(WidgetBar.ID) as? WidgetBar ?: continue
widgetBar.update()
+ log.debug("Widget updated for project ${project.name}")
}
}
}
diff --git a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/statusbar/StatusBarItemChooserDialog.kt b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/statusbar/StatusBarItemChooserDialog.kt
index 9a3d23e..626dca4 100644
--- a/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/statusbar/StatusBarItemChooserDialog.kt
+++ b/src/main/kotlin/com/github/warningimhack3r/npmupdatedependencies/ui/statusbar/StatusBarItemChooserDialog.kt
@@ -49,14 +49,17 @@ class StatusBarItemChooserDialog(items: Collection) : JDialog() {
selectedItem = null
dispose()
}
+
KeyEvent.VK_ENTER -> {
selectedItem = itemList.selectedIndex
dispose()
}
+
KeyEvent.VK_UP -> {
itemList.selectedIndex = (itemList.selectedIndex - 1 + items.size) % items.size
itemList.ensureIndexIsVisible(itemList.selectedIndex)
}
+
KeyEvent.VK_DOWN -> {
itemList.selectedIndex = (itemList.selectedIndex + 1) % items.size
itemList.ensureIndexIsVisible(itemList.selectedIndex)
@@ -117,6 +120,7 @@ class StatusBarItemChooserDialog(items: Collection) : JDialog() {
selectedItem = null
dispose()
}
+
KeyEvent.VK_ENTER -> {
selectedItem = itemList.selectedIndex
dispose()
@@ -124,7 +128,11 @@ class StatusBarItemChooserDialog(items: Collection) : JDialog() {
}
}
})
- val scrollPane = JBScrollPane(itemList, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER)
+ val scrollPane = JBScrollPane(
+ itemList,
+ ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
+ ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER
+ )
scrollPane.preferredSize = Dimension(WIDTH, (itemList.getCellBounds(0, 0)?.height?.plus(1) ?: 20).let {
if (items.size > 10) it * 10 else it * items.size
})