diff --git a/src/main/java/dev/blachut/svelte/lang/inspections/SvelteAddImportExecutor.kt b/src/main/java/dev/blachut/svelte/lang/inspections/SvelteAddImportExecutor.kt
new file mode 100644
index 00000000..17c365bf
--- /dev/null
+++ b/src/main/java/dev/blachut/svelte/lang/inspections/SvelteAddImportExecutor.kt
@@ -0,0 +1,100 @@
+package dev.blachut.svelte.lang.inspections
+
+import com.intellij.lang.ecmascript6.psi.ES6ImportDeclaration
+import com.intellij.lang.ecmascript6.psi.ES6ImportExportDeclarationPart
+import com.intellij.lang.ecmascript6.psi.impl.ES6CreateImportUtil
+import com.intellij.lang.ecmascript6.psi.impl.ES6ImportPsiUtil
+import com.intellij.lang.ecmascript6.psi.impl.ES6ImportPsiUtil.CreateImportExportInfo
+import com.intellij.lang.javascript.DialectDetector
+import com.intellij.lang.javascript.formatter.JSCodeStyleSettings
+import com.intellij.lang.javascript.psi.JSEmbeddedContent
+import com.intellij.lang.typescript.psi.TypeScriptAutoImportUtil
+import com.intellij.openapi.editor.Editor
+import com.intellij.openapi.util.text.StringUtil
+import com.intellij.psi.PsiElement
+import com.intellij.psi.XmlElementFactory
+import com.intellij.psi.xml.XmlTag
+import dev.blachut.svelte.lang.SvelteHTMLLanguage
+import dev.blachut.svelte.lang.parsing.js.SvelteJSScriptContentProvider
+import dev.blachut.svelte.lang.psi.SvelteHtmlFile
+import dev.blachut.svelte.lang.psi.findAncestorScript
+
+/**
+ * Adapted from com.intellij.lang.ecmascript6.actions.ES6AddImportExecutor
+ */
+class SvelteAddImportExecutor(val editor: Editor?, val place: PsiElement) {
+ fun createImportOrUseExisting(info: CreateImportExportInfo, externalModule: PsiElement?, quotedModuleName: String): Boolean {
+ val type = info.importType
+ val scope = findOrCreateScriptContent()
+
+ return if (tryToUseExistingImport(info, quotedModuleName, externalModule, scope)) {
+ true
+ } else {
+ val importPsi = createTypeScriptOrES6Import(quotedModuleName, info)
+ if (importPsi == null) {
+ false
+ } else {
+ if (importPsi is ES6ImportDeclaration && type !== ES6ImportPsiUtil.ImportExportType.BARE) {
+ ES6CreateImportUtil.findPlaceAndInsertES6Import(scope, importPsi, StringUtil.unquoteString(quotedModuleName), editor)
+ } else {
+ ES6CreateImportUtil.findPlaceAndInsertAnyImport(scope, importPsi, editor)
+ }
+ true
+ }
+ }
+ }
+
+ private fun findOrCreateScriptContent(): JSEmbeddedContent {
+ val parentScript = findAncestorScript(place)
+ if (parentScript != null) {
+ // parent module or instance script
+ return SvelteJSScriptContentProvider.getJsEmbeddedContent(parentScript)!!
+ }
+
+ val currentFile = place.containingFile as SvelteHtmlFile
+ val instanceScript = currentFile.instanceScript
+ if (instanceScript != null) {
+ // TODO empty tag
+ return SvelteJSScriptContentProvider.getJsEmbeddedContent(instanceScript)!!
+ }
+
+ val elementFactory = XmlElementFactory.getInstance(currentFile.project)
+ val emptyInstanceScript = elementFactory.createTagFromText("", SvelteHTMLLanguage.INSTANCE)
+ val moduleScript = currentFile.moduleScript
+ val document = currentFile.document!!
+
+ val script = if (moduleScript != null) {
+ document.addAfter(emptyInstanceScript, moduleScript) as XmlTag
+ } else {
+ document.addBefore(emptyInstanceScript, document.firstChild) as XmlTag
+ }
+
+ return SvelteJSScriptContentProvider.getJsEmbeddedContent(script)!!
+ }
+
+ private fun tryToUseExistingImport(info: CreateImportExportInfo, quotedModuleOrNamespaceName: String, externalModule: PsiElement?, scope: PsiElement): Boolean {
+ val parent: PsiElement = place.parent
+ if (parent is ES6ImportExportDeclarationPart) {
+ val grandParent = parent.declaration
+ if (grandParent is ES6ImportDeclaration && grandParent.getFromClause() == null) {
+ ES6CreateImportUtil.insertFromClause(parent, grandParent, quotedModuleOrNamespaceName)
+ return true
+ }
+ }
+ val importType = info.importType
+ return if (JSCodeStyleSettings.isMergeImports(place) && importType.isES6) {
+ val possibleImport = ES6ImportPsiUtil.findExistingES6Import(scope, externalModule, quotedModuleOrNamespaceName, info)
+ possibleImport != null && ES6ImportPsiUtil.tryToAddImportToExistingDeclaration(possibleImport, info)
+ } else {
+ false
+ }
+ }
+
+ private fun createTypeScriptOrES6Import(externalModuleName: String, info: CreateImportExportInfo): PsiElement? {
+ return if (!info.importType.isES6 && !DialectDetector.isJavaScript(place)) {
+ TypeScriptAutoImportUtil.createTypeScriptImport(place, info, externalModuleName)
+ } else {
+ ES6ImportPsiUtil.createImportOrExport(place, info, externalModuleName)
+ }
+ }
+}
diff --git a/src/main/java/dev/blachut/svelte/lang/inspections/SvelteImportES6ModuleFix.kt b/src/main/java/dev/blachut/svelte/lang/inspections/SvelteImportES6ModuleFix.kt
new file mode 100644
index 00000000..0ff7a5e7
--- /dev/null
+++ b/src/main/java/dev/blachut/svelte/lang/inspections/SvelteImportES6ModuleFix.kt
@@ -0,0 +1,42 @@
+package dev.blachut.svelte.lang.inspections
+
+import com.intellij.lang.ecmascript6.psi.impl.ES6ImportPsiUtil.CreateImportExportInfo
+import com.intellij.lang.ecmascript6.psi.impl.ES6ImportPsiUtil.ImportExportType
+import com.intellij.lang.javascript.modules.ImportES6ModuleFix
+import com.intellij.lang.javascript.modules.JSModuleFixDescriptor
+import com.intellij.lang.javascript.modules.JSPlaceTail
+import com.intellij.openapi.editor.Editor
+import com.intellij.psi.PsiElement
+
+class SvelteImportES6ModuleFix(node: PsiElement, descriptor: JSModuleFixDescriptor, tail: JSPlaceTail?, quoteString: String?, needHint: Boolean) : ImportES6ModuleFix(node, descriptor, tail, quoteString, needHint) {
+ override fun executeImpl(element: PsiElement, editor: Editor?, scope: PsiElement) {
+ SvelteAddImportExecutor(editor, element).createImportOrUseExisting(importData, null, myQuotes + this.path + myQuotes)
+ replaceReferences(element, editor)
+ }
+
+ private val importData: ImportData
+ get() {
+ val importedName = myFixDescriptor.importedName
+ val type = myFixDescriptor.importType
+ val exportedName = myFixDescriptor.exportedName
+ return if (exportedName != null) {
+ val typeToUse = type ?: ImportExportType.SPECIFIER
+ if (exportedName == importedName) ImportData(this, importedName, typeToUse) else ImportData(this, exportedName, importedName, typeToUse)
+ } else if (type != null) {
+ ImportData(this, importedName, type)
+ } else if (myTail != null) {
+ val tail = myTail.strings[0]
+ ImportData(this, tail ?: importedName, ImportExportType.SPECIFIER)
+ } else {
+ ImportData(this, importedName, ImportExportType.IMPORT_BINDING_ALL)
+ }
+ }
+
+ private class ImportData : CreateImportExportInfo {
+ internal constructor(fix: ImportES6ModuleFix?, exportedName: String?, importedName: String, importType: ImportExportType?) : super(exportedName, importedName, importType!!, true, false)
+ internal constructor(fix: ImportES6ModuleFix, importedName: String, importType: ImportExportType?) : super(null, importedName, importType!!, true, false)
+ }
+
+
+
+}
diff --git a/src/main/java/dev/blachut/svelte/lang/inspections/SvelteModulesDependenciesElementVisitor.kt b/src/main/java/dev/blachut/svelte/lang/inspections/SvelteModulesDependenciesElementVisitor.kt
index e7e7a7d8..3db83d4b 100644
--- a/src/main/java/dev/blachut/svelte/lang/inspections/SvelteModulesDependenciesElementVisitor.kt
+++ b/src/main/java/dev/blachut/svelte/lang/inspections/SvelteModulesDependenciesElementVisitor.kt
@@ -2,7 +2,9 @@ package dev.blachut.svelte.lang.inspections
import com.intellij.codeInspection.ProblemsHolder
import com.intellij.lang.javascript.JavaScriptBundle
-import com.intellij.lang.javascript.modules.*
+import com.intellij.lang.javascript.modules.JSBaseModulesDependenciesElementVisitor
+import com.intellij.lang.javascript.modules.JsModulesSuggester
+import com.intellij.lang.javascript.modules.ModuleReferenceInfo
import com.intellij.psi.PsiElement
import com.intellij.psi.ResolveResult
@@ -12,6 +14,6 @@ internal class SvelteModulesDependenciesElementVisitor(holder: ProblemsHolder) :
}
override fun createSuggester(node: PsiElement, info: ModuleReferenceInfo, resolveResults: Array): JsModulesSuggester? {
- return if (!NodeModuleUtil.isWrappedInAmdDefinition(node)) ES6ModulesSuggester(info, node) else null
+ return SvelteModulesSuggester(info, node)
}
}
diff --git a/src/main/java/dev/blachut/svelte/lang/inspections/SvelteModulesSuggester.kt b/src/main/java/dev/blachut/svelte/lang/inspections/SvelteModulesSuggester.kt
new file mode 100644
index 00000000..597587af
--- /dev/null
+++ b/src/main/java/dev/blachut/svelte/lang/inspections/SvelteModulesSuggester.kt
@@ -0,0 +1,53 @@
+package dev.blachut.svelte.lang.inspections
+
+import com.intellij.codeInspection.LocalQuickFix
+import com.intellij.lang.javascript.formatter.JSCodeStyleSettings
+import com.intellij.lang.javascript.modules.ES6ModulesSuggester
+import com.intellij.lang.javascript.modules.JSModuleFixDescriptor
+import com.intellij.lang.javascript.modules.JSPlaceTail
+import com.intellij.lang.javascript.modules.ModuleReferenceInfo
+import com.intellij.psi.PsiElement
+import com.intellij.psi.ResolveResult
+import com.intellij.psi.SmartPointerManager
+import com.intellij.util.containers.ContainerUtil
+import com.intellij.util.containers.MultiMap
+import java.util.*
+
+class SvelteModulesSuggester(info: ModuleReferenceInfo, node: PsiElement) : ES6ModulesSuggester(info, node) {
+ override fun findFixes(resolveResults: Array): MultiMap {
+ var descriptors = this.find(resolveResults, false)
+ if (descriptors.isEmpty()) {
+ return MultiMap.empty()
+ } else {
+ descriptors = ContainerUtil.filter(descriptors) { descriptorx: JSModuleFixDescriptor ->
+ val fromPath = descriptorx.fromPath
+ val idx = fromPath.indexOf("node_modules")
+ idx < 0 || fromPath.indexOf("test", idx) <= 0 && fromPath.indexOf("examples", idx) <= 0
+ }
+ val quoteString = JSCodeStyleSettings.getQuote(myNode)
+ val list: MutableList = ArrayList()
+ val result = MultiMap.createLinked()
+ val size = descriptors.size
+ val var7: Iterator<*> = descriptors.iterator()
+ while (var7.hasNext()) {
+ val descriptor = var7.next() as JSModuleFixDescriptor
+ val hint = size == 1 && myModuleReferenceInfo.needHint()
+ list.add(SvelteImportES6ModuleFix(myNode, descriptor, null as JSPlaceTail?, quoteString, hint))
+ }
+ result.putValues(myNode, list)
+ val parent = myModuleReferenceInfo.parentRef
+ if (parent != null) {
+ val project = myNode.project
+ val secondWordList: MutableList = ArrayList(list)
+ val var10: Iterator<*> = descriptors.iterator()
+ while (var10.hasNext()) {
+ val descriptor = var10.next() as JSModuleFixDescriptor
+ val tail = JSPlaceTail(SmartPointerManager.getInstance(project).createSmartPsiElementPointer(parent), arrayOf(myModuleReferenceInfo.parentName))
+ secondWordList.add(SvelteImportES6ModuleFix(parent, descriptor, tail, quoteString, false))
+ }
+ result.putValues(parent, secondWordList)
+ }
+ return result
+ }
+ }
+}
diff --git a/src/main/java/dev/blachut/svelte/lang/psi/SvelteHtmlFile.kt b/src/main/java/dev/blachut/svelte/lang/psi/SvelteHtmlFile.kt
index 4d3cdfbf..3c7dee0c 100644
--- a/src/main/java/dev/blachut/svelte/lang/psi/SvelteHtmlFile.kt
+++ b/src/main/java/dev/blachut/svelte/lang/psi/SvelteHtmlFile.kt
@@ -22,7 +22,7 @@ class SvelteHtmlFile(viewProvider: FileViewProvider) : HtmlFileImpl(viewProvider
document ?: return true
val parentScript = findAncestorScript(place)
- if (parentScript != null && parentScript.getAttributeValue("context") == "module") {
+ if (parentScript != null && isModuleScript(parentScript)) {
// place is inside module script, nothing more to process
return true
} else if (parentScript != null) {
@@ -40,9 +40,13 @@ class SvelteHtmlFile(viewProvider: FileViewProvider) : HtmlFileImpl(viewProvider
}
}
-private fun findAncestorScript(place: PsiElement): XmlTag? {
+fun findAncestorScript(place: PsiElement): XmlTag? {
val parentScript = PsiTreeUtil.findFirstContext(place, false) {
it is XmlTag && HtmlUtil.isScriptTag(it)
}
return parentScript as XmlTag?
}
+
+fun isModuleScript(tag: XmlTag): Boolean {
+ return HtmlUtil.isScriptTag(tag) && tag.getAttributeValue("context") == "module"
+}