Skip to content

Commit

Permalink
Support parsing of existing files
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-yevsyukov committed Dec 22, 2023
1 parent 2c37e7d commit 0ea587c
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 1 deletion.
37 changes: 36 additions & 1 deletion psi-java/src/main/kotlin/io/spine/tools/psi/java/Parser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ import com.intellij.ide.highlighter.JavaFileType
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFileFactory
import com.intellij.psi.PsiJavaFile
import java.io.File
import java.time.Instant
import com.intellij.openapi.vfs.local.CoreLocalFileSystem
import com.intellij.psi.PsiManager
import java.util.*

/**
Expand All @@ -42,6 +45,14 @@ public class Parser(private val project: Project) {
PsiFileFactory.getInstance(project)
}

private val localFileSystem by lazy {
CoreLocalFileSystem()
}

private val psiManager by lazy {
PsiManager.getInstance(project)
}

/**
* Creates a new instance of [PsiJavaFile] with the given code and auto-generated name.
*
Expand All @@ -50,14 +61,34 @@ public class Parser(private val project: Project) {
public fun parse(javaSource: String): PsiJavaFile =
syntheticFile(javaSource)

/**
* Parses the given file and returns the corresponding [PsiJavaFile].
*/
public fun parse(file: File): PsiJavaFile {
require(file.toString().endsWith(FILE_SUFFIX)) {
"The file `$file` must have the `$FILE_SUFFIX` extension."
}
require(file.exists()) {
"The file `$file` does not exist."
}
val found = localFileSystem.findFileByIoFile(file)
require(found != null) {
"Unable to locate the file `$file` in the local file system."
}
psiManager.findFile(found)?.let {
return it as PsiJavaFile
}
error("Unable to parse the file `$file`.")
}

/**
* Creates a new instance of `PsiJavaFile` with the given content, auto-generated name, and
* the current time as the modification timestamp.
*
* The instance also has the event system enabled to allow obtaining `VirtualFile` instance.
*/
private fun syntheticFile(javaSource: String): PsiJavaFile {
val fileName = "__to_parse_${UUID.randomUUID()}__.java"
val fileName = "__to_parse_${UUID.randomUUID()}__$FILE_SUFFIX"
val modificationStamp = Instant.now().toEpochMilli()
val file = fileFactory.createFileFromText(
fileName,
Expand All @@ -68,4 +99,8 @@ public class Parser(private val project: Project) {
)
return file as PsiJavaFile
}

private companion object {
const val FILE_SUFFIX = ".java"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright 2023, TeamDev. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Redistribution and use in source and/or binary forms, with or without
* modification, must retain the above copyright notice and the following
* disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package io.spine.tools.psi.java

import java.io.File
import io.kotest.matchers.shouldNotBe
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.api.io.TempDir

@DisplayName("Parsing of existing Java file should")
class FileParsingSpec: ParsingTest() {

companion object {

lateinit var file: File
private const val fileName = "FileOnDisk.java"

@BeforeAll
@JvmStatic
fun createFile(@TempDir tempDir: File) {
file = tempDir.resolve(fileName)
val code = readResource(fileName)
file.writeText(code)
}
}

@Test
fun `parse existing file`() {
val psiFile = parser.parse(file)
psiFile shouldNotBe null
}

@Test
fun `require file to have proper extension`() {
assertThrows<IllegalArgumentException> {
parser.parse(File("file.txt"))
}
}

@Test
fun `not parse non-existing file`() {
val nonExistingFile = File("non-existing-file.java")
assertThrows<IllegalArgumentException> {
parser.parse(nonExistingFile)
}
}
}
8 changes: 8 additions & 0 deletions psi-java/src/test/resources/FileOnDisk.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* This is a stub Java source file to test pasing existing Java files.
*/
class FileOnDisk {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}

0 comments on commit 0ea587c

Please sign in to comment.