Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file removed .gradle/9.1.0/checksums/checksums.lock
Binary file not shown.
Binary file removed .gradle/9.1.0/checksums/md5-checksums.bin
Binary file not shown.
Binary file removed .gradle/9.1.0/checksums/sha1-checksums.bin
Binary file not shown.
Binary file removed .gradle/9.1.0/fileChanges/last-build.bin
Binary file not shown.
Binary file removed .gradle/9.1.0/fileHashes/fileHashes.lock
Binary file not shown.
Empty file removed .gradle/9.1.0/gc.properties
Empty file.
Binary file removed .gradle/buildOutputCleanup/buildOutputCleanup.lock
Binary file not shown.
2 changes: 0 additions & 2 deletions .gradle/buildOutputCleanup/cache.properties

This file was deleted.

Empty file removed .gradle/vcs-1/gc.properties
Empty file.
7 changes: 7 additions & 0 deletions src/commonMain/kotlin/org/litlfred/fmlrunner/FmlRunner.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ class FmlRunner {
return compiler.compile(fmlContent)
}

/**
* Validate FML syntax without full compilation
*/
fun validateFmlSyntax(fmlContent: String): FmlSyntaxValidationResult {
return compiler.validateSyntax(fmlContent)
}

/**
* Execute StructureMap on input content
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -464,4 +464,30 @@ class FmlCompiler {
)
}
}

/**
* Validate FML syntax without full compilation
*/
fun validateSyntax(fmlContent: String): FmlSyntaxValidationResult {
return try {
// Tokenize
val tokenizer = FmlTokenizer(fmlContent)
val tokens = tokenizer.tokenize()

// Parse for syntax validation (without requiring complete StructureMap)
val parser = FmlParser(tokens)
val result = parser.parse()

FmlSyntaxValidationResult(
valid = result.success,
errors = result.errors,
warnings = result.warnings
)
} catch (e: Exception) {
FmlSyntaxValidationResult(
valid = false,
errors = listOf("Syntax validation failed: ${e.message}")
)
}
}
}
10 changes: 10 additions & 0 deletions src/commonMain/kotlin/org/litlfred/fmlrunner/types/FhirTypes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,16 @@ data class FmlCompilationResult(
val warnings: List<String> = emptyList()
)

/**
* FML Syntax Validation Result
*/
@Serializable
data class FmlSyntaxValidationResult(
val valid: Boolean,
val errors: List<String> = emptyList(),
val warnings: List<String> = emptyList()
)

/**
* Execution Result for StructureMap execution
*/
Expand Down
94 changes: 94 additions & 0 deletions src/commonTest/kotlin/org/litlfred/fmlrunner/BasicTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,98 @@ class FmlRunnerTest {

assertTrue(result.success, "Execution should succeed")
}

@Test
fun testValidFmlSyntaxValidation() {
val runner = FmlRunner()
val validFmlContent = """
map "http://example.org/StructureMap/Patient" = "PatientTransform"

group main(source src, target tgt) {
src.name -> tgt.fullName;
src.active -> tgt.isActive;
}
""".trimIndent()

val result = runner.validateFmlSyntax(validFmlContent)
assertTrue(result.valid, "Valid FML syntax should pass validation")
assertTrue(result.errors.isEmpty(), "No errors should be reported for valid syntax")
}

@Test
fun testInvalidFmlSyntaxValidation_MissingMapKeyword() {
val runner = FmlRunner()
val invalidFmlContent = """
"http://example.org/StructureMap/Patient" = "PatientTransform"

group main(source src, target tgt) {
src.name -> tgt.fullName;
}
""".trimIndent()

val result = runner.validateFmlSyntax(invalidFmlContent)
assertTrue(!result.valid, "Invalid FML syntax should fail validation")
assertTrue(result.errors.isNotEmpty(), "Errors should be reported for invalid syntax")
assertTrue(result.errors.any { it.contains("map") || it.contains("Expected") },
"Error should mention missing 'map' keyword")
}

@Test
fun testInvalidFmlSyntaxValidation_MalformedGroup() {
val runner = FmlRunner()
val invalidFmlContent = """
map "http://example.org/StructureMap/Patient" = "PatientTransform"

group main(source src, target tgt {
src.name -> tgt.fullName;
}
""".trimIndent()

val result = runner.validateFmlSyntax(invalidFmlContent)
assertTrue(!result.valid, "Invalid FML syntax should fail validation")
assertTrue(result.errors.isNotEmpty(), "Errors should be reported for malformed syntax")
}

@Test
fun testInvalidFmlSyntaxValidation_EmptyContent() {
val runner = FmlRunner()
val emptyContent = ""

val result = runner.validateFmlSyntax(emptyContent)
assertTrue(!result.valid, "Empty content should fail validation")
assertTrue(result.errors.isNotEmpty(), "Errors should be reported for empty content")
}

@Test
fun testInvalidFmlSyntaxValidation_MissingClosingBrace() {
val runner = FmlRunner()
val invalidFmlContent = """
map "http://example.org/StructureMap/Patient" = "PatientTransform"

group main(source src, target tgt) {
src.name -> tgt.fullName;
""".trimIndent()

val result = runner.validateFmlSyntax(invalidFmlContent)
assertTrue(!result.valid, "Invalid FML syntax should fail validation")
assertTrue(result.errors.isNotEmpty(), "Errors should be reported for missing closing brace")
}

@Test
fun testComplexValidFmlSyntaxValidation() {
val runner = FmlRunner()
val complexValidFmlContent = """
map "http://example.org/StructureMap/Complex" = "ComplexTransform"

group main(source src, target tgt) {
src.name -> tgt.fullName;
src.active -> tgt.isActive;
src.email -> tgt.contactEmail;
}
""".trimIndent()

val result = runner.validateFmlSyntax(complexValidFmlContent)
assertTrue(result.valid, "Complex valid FML syntax should pass validation")
assertTrue(result.errors.isEmpty(), "No errors should be reported for complex valid syntax")
}
}