<commit_before>package com.emberjs.resolver

import com.emberjs.cli.EmberCliProjectConfigurator
import com.emberjs.utils.emberRoot
import com.intellij.lang.javascript.DialectDetector
import com.intellij.lang.javascript.frameworks.amd.JSModuleReference
import com.intellij.lang.javascript.frameworks.modules.JSExactFileReference
import com.intellij.lang.javascript.psi.resolve.JSModuleReferenceContributor
import com.intellij.openapi.util.TextRange
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.*
import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReference
import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceSet
import java.util.regex.Pattern

/**
 * Resolves absolute imports from the ember application root, e.g.
 * ```
 * import FooController from 'my-app/controllers/foo'
 * ```
 *
 * Navigating to `FooController` will browse to `/app/controllers/foo.js`
 */
class EmberAppReferenceContributor : JSModuleReferenceContributor {
    override fun getAllReferences(unquotedRefText: String, host: PsiElement, offset: Int, provider: PsiReferenceProvider?): Array<out PsiReference> {
        return getCommonJSModuleReferences(unquotedRefText, host, offset, provider)
    }

    override fun getCommonJSModuleReferences(unquotedRefText: String, host: PsiElement, offset: Int, provider: PsiReferenceProvider?): Array<out PsiReference> {
        val appRoot = host.emberRoot ?: return emptyArray()
        val appName = getAppName(appRoot) ?: return emptyArray()

        val importPath = unquotedRefText.removePrefix(appName + "/")
        if (unquotedRefText == importPath) {
            // only match ember app imports
            return emptyArray()
        }

        /** Search the `/app` and `/addon` directories of the root and each in-repo-addon */
        val roots = listOf("${appRoot.path}/app", "${appRoot.path}/addon")
            .plus(EmberCliProjectConfigurator.inRepoAddons(appRoot).map { it.path })
            .map { JSExactFileReference(host, TextRange.create(offset, offset + appName.length), listOf(it), null) }

        val refs = object : FileReferenceSet(importPath, host, offset + appName.length + 1, provider, false, true, DialectDetector.JAVASCRIPT_FILE_TYPES_ARRAY) {
            override fun createFileReference(range: TextRange, index: Int, text: String?): FileReference {
                return object : JSModuleReference(text, index, range, this, "file.js", true) {<commit_msg>Navigate to imports from node_modules<commit_after>package com.emberjs.resolver

import com.emberjs.cli.EmberCliProjectConfigurator
import com.emberjs.utils.emberRoot
import com.emberjs.utils.isInRepoAddon
import com.emberjs.utils.parents
import com.intellij.lang.javascript.DialectDetector
import com.intellij.lang.javascript.frameworks.amd.JSModuleReference
import com.intellij.lang.javascript.frameworks.modules.JSExactFileReference
import com.intellij.lang.javascript.psi.resolve.JSModuleReferenceContributor
import com.intellij.openapi.util.TextRange
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.*
import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReference
import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceSet
import java.util.regex.Pattern

/**
 * Resolves absolute imports from the ember application root, e.g.
 * ```
 * import FooController from 'my-app/controllers/foo'
 * ```
 *
 * Navigating to `FooController` will browse to `/app/controllers/foo.js`
 */
class EmberAppReferenceContributor : JSModuleReferenceContributor {
    override fun getAllReferences(unquotedRefText: String, host: PsiElement, offset: Int, provider: PsiReferenceProvider?): Array<out PsiReference> {
        return getCommonJSModuleReferences(unquotedRefText, host, offset, provider)
    }

    override fun getCommonJSModuleReferences(unquotedRefText: String, host: PsiElement, offset: Int, provider: PsiReferenceProvider?): Array<out PsiReference> {
        if (unquotedRefText.startsWith('.')) {
            // only for absolute imports
            return emptyArray()
        }

        val appName = unquotedRefText.substringBefore('/')
        val importPath = unquotedRefText.removePrefix(appName + "/")
        if (unquotedRefText == importPath) {
            // only for imports with slashes
            return emptyArray()
        }

        val appRoot = host.containingFile.virtualFile.parents
                .find { it.findChild("package.json") != null && !it.isInRepoAddon }
                ?: return emptyArray()

        val modules = when {
            getAppName(appRoot) == appName ->
                // local import from this app/addon
                listOf(appRoot) + EmberCliProjectConfigurator.inRepoAddons(appRoot)

            else ->
                // check node_modules
                listOfNotNull(host.emberRoot?.findChild("node_modules")?.findChild(appName))
        }

        /** Search the `/app` and `/addon` directories of the root and each in-repo-addon */
        val roots = modules
                .flatMap { listOfNotNull(it.findChild("app"), it.findChild("addon")) }
                .map { JSExactFileReference(host, TextRange.create(offset, offset + appName.length), listOf(it.path), null) }

        val refs = object : FileReferenceSet(importPath, host, offset + appName.length + 1, provider, false, true, DialectDetector.JAVASCRIPT_FILE_TYPES_ARRAY) {
            override fun createFileReference(range: TextRange, index: Int, text: String?): FileReference {
                return object : JSModuleReference(text, index, range, this, "file.js", true) {
{'fraction_non_alphanumeric': 0.10302708443972385, 'fraction_numerical': 0.0003540449637103912, 'mean_word_length': 3.7240802675585285, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6958375', 'n_tokens_mistral': 1669, 'n_tokens_neox': 1624, 'n_words': 344}