diff --git a/build.gradle.kts b/build.gradle.kts index 62ae641..9cb9eb0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,7 +12,7 @@ plugins { } group = "no.item.xp.plugin" -version = "2.7.0" +version = "2.8.0-SNAPSHOT" kotlin { jvmToolchain(11) diff --git a/src/main/kotlin/no/item/xp/plugin/GenerateCodeTask.kt b/src/main/kotlin/no/item/xp/plugin/GenerateCodeTask.kt index c304ce8..1c922b8 100644 --- a/src/main/kotlin/no/item/xp/plugin/GenerateCodeTask.kt +++ b/src/main/kotlin/no/item/xp/plugin/GenerateCodeTask.kt @@ -93,6 +93,7 @@ open class GenerateCodeTask it.getXmlFile().set(change.file) it.getTargetFile().set(targetFile) it.getMixins().value(mixins) + it.getMixinsImportPath().value(resolveMixinsImportPath(targetFile, rootOutputDir)) it.getSingleQuote().value(singleQuote) it.getPrependText().value(prependText) } @@ -129,12 +130,12 @@ open class GenerateCodeTask logger.error(left.message) }, { right -> - val fileContent = renderTypeModelAsTypeScript(right) - val targetFilePath = Paths.get(rootOutputDir.absolutePath, fileInJar.entry.name) val indexFilePath = Paths.get(targetFilePath.parent.toString(), "index.d.ts") val targetFile = File(indexFilePath.toUri()) + val fileContent = renderTypeModelAsTypeScript(right, resolveMixinsImportPath(targetFile, rootOutputDir)) + writeTargetFile(targetFile, fileContent, prependText, singleQuote) logger.lifecycle("Updated file: ${Path.of(targetFile.toURI()).toUri()}") }, diff --git a/src/main/kotlin/no/item/xp/plugin/GenerateTypeScriptWorkAction.kt b/src/main/kotlin/no/item/xp/plugin/GenerateTypeScriptWorkAction.kt index b7bb3e1..d309515 100644 --- a/src/main/kotlin/no/item/xp/plugin/GenerateTypeScriptWorkAction.kt +++ b/src/main/kotlin/no/item/xp/plugin/GenerateTypeScriptWorkAction.kt @@ -26,6 +26,8 @@ interface CodegenWorkParameters : WorkParameters { fun getMixins(): ListProperty + fun getMixinsImportPath(): Property + fun getPrependText(): Property fun getSingleQuote(): Property @@ -39,6 +41,7 @@ abstract class GenerateTypeScriptWorkAction : WorkAction val file = parameters.getXmlFile().get().asFile val targetFile = parameters.getTargetFile().get().asFile val mixins = parameters.getMixins().get() + val mixinsImportPath = parameters.getMixinsImportPath().get() parseXml(file.inputStream()) .flatMap { doc -> doc.getFormNode() } @@ -58,9 +61,9 @@ abstract class GenerateTypeScriptWorkAction : WorkAction { val fileContent = if (file.absolutePath.endsWith(concatFileName("resources", "site", "site.xml"))) { - renderSiteConfig(it) + renderSiteConfig(it, mixinsImportPath) } else { - renderTypeModelAsTypeScript(it) + renderTypeModelAsTypeScript(it, mixinsImportPath) } writeTargetFile(targetFile, fileContent, parameters.getPrependText().get(), parameters.getSingleQuote().get()) diff --git a/src/main/kotlin/no/item/xp/plugin/models/ObjectTypeModelField.kt b/src/main/kotlin/no/item/xp/plugin/models/ObjectTypeModelField.kt index fa04d37..db09a3d 100644 --- a/src/main/kotlin/no/item/xp/plugin/models/ObjectTypeModelField.kt +++ b/src/main/kotlin/no/item/xp/plugin/models/ObjectTypeModelField.kt @@ -92,11 +92,14 @@ data class ObjectField( override val isNullable: Boolean, override val isArray: Boolean, val fields: List, + // Name of the mixin, if it is the only form field. The type will then be imported instead of inlined. + val mixinName: String? = null, ) : ObjectTypeModelField() { constructor( field: ObjectTypeModelField, fields: List, - ) : this(field.name, field.comment, field.isNullable, field.isArray, fields) + mixinName: String? = null, + ) : this(field.name, field.comment, field.isNullable, field.isArray, fields, mixinName) } data class UnknownField( diff --git a/src/main/kotlin/no/item/xp/plugin/parser/ParseInterfaceModel.kt b/src/main/kotlin/no/item/xp/plugin/parser/ParseInterfaceModel.kt index 138171d..1cb191f 100644 --- a/src/main/kotlin/no/item/xp/plugin/parser/ParseInterfaceModel.kt +++ b/src/main/kotlin/no/item/xp/plugin/parser/ParseInterfaceModel.kt @@ -58,6 +58,23 @@ private fun findMixinFields( return mixins.find { it.nameWithoutExtension == mixinName }?.fields ?: emptyList() } +/** + * Returns the name of the mixin if it is the only form field in [itemsNode], and the mixin exists + */ +fun findSingleMixinName( + itemsNode: Node, + mixins: List, +): String? { + val mixinName = + itemsNode + .getChildNodesAtXPath(xpathInputType) + .singleOrNull() + ?.takeIf { it.nodeName == "mixin" } + ?.getNodeAttribute("name") + + return mixinName?.takeIf { name -> mixins.any { it.nameWithoutExtension == name } } +} + fun parseConfigOptionValue(inputNode: Node): List { return inputNode .getChildNodesAtXPath(getXpathExpressionFromString("config/option/@value")) diff --git a/src/main/kotlin/no/item/xp/plugin/parser/ParseItemSet.kt b/src/main/kotlin/no/item/xp/plugin/parser/ParseItemSet.kt index 6d1410d..69da0fe 100644 --- a/src/main/kotlin/no/item/xp/plugin/parser/ParseItemSet.kt +++ b/src/main/kotlin/no/item/xp/plugin/parser/ParseItemSet.kt @@ -10,10 +10,13 @@ fun parseItemSet( mixins: List, ): ObjectField? { val unknownField = parseUnknownField(itemSetNode) + val itemsNode = itemSetNode.getChildNodeAtXPath("items") val subFields = - itemSetNode.getChildNodeAtXPath("items") + itemsNode ?.let { parseFields(it, mixins).getOrNull() } ?: emptyList() - return unknownField?.let { ObjectField(it, subFields) } + val mixinName = itemsNode?.let { findSingleMixinName(it, mixins) } + + return unknownField?.let { ObjectField(it, subFields, mixinName) } } diff --git a/src/main/kotlin/no/item/xp/plugin/parser/ParseOptionSet.kt b/src/main/kotlin/no/item/xp/plugin/parser/ParseOptionSet.kt index 71f2bd2..dd01e94 100644 --- a/src/main/kotlin/no/item/xp/plugin/parser/ParseOptionSet.kt +++ b/src/main/kotlin/no/item/xp/plugin/parser/ParseOptionSet.kt @@ -39,5 +39,7 @@ private fun parseOptionSetFieldOption( itemsNode ?.let { parseFields(it, mixins).getOrNull() } ?: emptyList() - return ObjectField(optionNode.getNodeAttribute("name")!!, optionComment, true, false, fields) + val mixinName = itemsNode?.let { findSingleMixinName(it, mixins) } + + return ObjectField(optionNode.getNodeAttribute("name")!!, optionComment, true, false, fields, mixinName) } diff --git a/src/main/kotlin/no/item/xp/plugin/renderers/RenderSiteConfig.kt b/src/main/kotlin/no/item/xp/plugin/renderers/RenderSiteConfig.kt index efe3416..14ad9f1 100644 --- a/src/main/kotlin/no/item/xp/plugin/renderers/RenderSiteConfig.kt +++ b/src/main/kotlin/no/item/xp/plugin/renderers/RenderSiteConfig.kt @@ -3,8 +3,11 @@ package no.item.xp.plugin.renderers import no.item.xp.plugin.models.ObjectTypeModel import no.item.xp.plugin.renderers.ts.renderInterfaceModelField -fun renderSiteConfig(model: ObjectTypeModel): String { - val fieldList = model.fields.joinToString("\n\n") { renderInterfaceModelField(it, 3) } +fun renderSiteConfig( + model: ObjectTypeModel, + mixinsImportPath: String, +): String { + val fieldList = model.fields.joinToString("\n\n") { renderInterfaceModelField(it, 3, mixinsImportPath) } return """ #export type SiteConfig = XP.SiteConfig; diff --git a/src/main/kotlin/no/item/xp/plugin/renderers/ts/RenderInterfaceModelField.kt b/src/main/kotlin/no/item/xp/plugin/renderers/ts/RenderInterfaceModelField.kt index 257fc79..8cd2bc5 100644 --- a/src/main/kotlin/no/item/xp/plugin/renderers/ts/RenderInterfaceModelField.kt +++ b/src/main/kotlin/no/item/xp/plugin/renderers/ts/RenderInterfaceModelField.kt @@ -14,6 +14,7 @@ import no.item.xp.plugin.models.UnknownField fun renderInterfaceModelField( field: ObjectTypeModelField, indent: Int, + mixinsImportPath: String, ): String { return when (field) { is StringField, @@ -27,14 +28,19 @@ fun renderInterfaceModelField( is UnionOfStringLiteralField -> simpleFieldAsString(field, joinOptionList(field.optionList), indent) is OptionSetField -> if (field.isMultiSelect) { - renderOptionSetFieldMultiChoice(field, indent) + renderOptionSetFieldMultiChoice(field, indent, mixinsImportPath) } else { - renderOptionSetField(field, indent) + renderOptionSetField(field, indent, mixinsImportPath) } - is ObjectField -> renderObjectField(field, indent) + is ObjectField -> renderObjectField(field, indent, mixinsImportPath) } } +fun renderMixinTypeReference( + mixinName: String, + mixinsImportPath: String, +): String = "import(\"$mixinsImportPath/$mixinName\").${getTypeName(mixinName)}" + private fun simpleFieldAsString( field: ObjectTypeModelField, innerType: String, diff --git a/src/main/kotlin/no/item/xp/plugin/renderers/ts/RenderObjectField.kt b/src/main/kotlin/no/item/xp/plugin/renderers/ts/RenderObjectField.kt index 82f4ac2..b8dd06a 100644 --- a/src/main/kotlin/no/item/xp/plugin/renderers/ts/RenderObjectField.kt +++ b/src/main/kotlin/no/item/xp/plugin/renderers/ts/RenderObjectField.kt @@ -5,10 +5,21 @@ import no.item.xp.plugin.models.ObjectField fun renderObjectField( field: ObjectField, indentLevel: Int, + mixinsImportPath: String, ): String { val indentation = createIndentation(indentLevel) - val fieldList = field.fields.joinToString("\n\n") { renderInterfaceModelField(it, indentLevel + 1) } + if (field.mixinName != null) { + val typeReference = renderMixinTypeReference(field.mixinName, mixinsImportPath) + val fieldType = if (field.isArray) "Array<$typeReference>" else typeReference + + return """ + #${renderComment(field.comment, indentLevel)} + #$indentation${escapeName(field.name)}${if (field.isNullable) "?" else ""}: $fieldType; + """.trimMargin("#") + } + + val fieldList = field.fields.joinToString("\n\n") { renderInterfaceModelField(it, indentLevel + 1, mixinsImportPath) } return """ #${renderComment(field.comment, indentLevel)} diff --git a/src/main/kotlin/no/item/xp/plugin/renderers/ts/RenderOptionSetField.kt b/src/main/kotlin/no/item/xp/plugin/renderers/ts/RenderOptionSetField.kt index 3dd8400..ebc8685 100644 --- a/src/main/kotlin/no/item/xp/plugin/renderers/ts/RenderOptionSetField.kt +++ b/src/main/kotlin/no/item/xp/plugin/renderers/ts/RenderOptionSetField.kt @@ -6,9 +6,10 @@ import no.item.xp.plugin.models.OptionSetField fun renderOptionSetField( field: OptionSetField, indentLevel: Int, + mixinsImportPath: String, ): String { val indentation = createIndentation(indentLevel) - val options = field.optionList.joinToString("\n") { renderOptionSetFieldOption(it, indentLevel + 2) } + val options = field.optionList.joinToString("\n") { renderOptionSetFieldOption(it, indentLevel + 2, mixinsImportPath) } return """ #${renderComment(field.comment, indentLevel)} @@ -20,11 +21,19 @@ fun renderOptionSetField( private fun renderOptionSetFieldOption( fieldOption: ObjectField, indentLevel: Int, + mixinsImportPath: String, ): String { val indentation0 = createIndentation(indentLevel - 1) val indentation1 = createIndentation(indentLevel) val indentation2 = createIndentation(indentLevel + 1) - val content = fieldOption.fields.joinToString("\n\n") { renderInterfaceModelField(it, indentLevel + 2) } + val content = fieldOption.fields.joinToString("\n\n") { renderInterfaceModelField(it, indentLevel + 2, mixinsImportPath) } + + val optionType = + when { + fieldOption.mixinName != null -> renderMixinTypeReference(fieldOption.mixinName, mixinsImportPath) + ";" + fieldOption.fields.isNotEmpty() -> "{\n$content\n#$indentation2};" + else -> "Record;" + } return """ #$indentation0| { @@ -34,9 +43,7 @@ private fun renderOptionSetFieldOption( #${indentation2}_selected: "${fieldOption.name}"; # #${renderComment(fieldOption.comment, indentLevel + 1)} - #$indentation2${escapeName( - fieldOption.name, - )}: ${if (fieldOption.fields.isNotEmpty()) "{\n$content" else "Record;"}${if (fieldOption.fields.isNotEmpty()) "\n#$indentation2};" else ""} + #$indentation2${escapeName(fieldOption.name)}: $optionType #$indentation1} """.trimMargin("#") } diff --git a/src/main/kotlin/no/item/xp/plugin/renderers/ts/RenderOptionSetFieldMultiChoice.kt b/src/main/kotlin/no/item/xp/plugin/renderers/ts/RenderOptionSetFieldMultiChoice.kt index 5321b81..e1c96e2 100644 --- a/src/main/kotlin/no/item/xp/plugin/renderers/ts/RenderOptionSetFieldMultiChoice.kt +++ b/src/main/kotlin/no/item/xp/plugin/renderers/ts/RenderOptionSetFieldMultiChoice.kt @@ -6,13 +6,17 @@ import no.item.xp.plugin.models.OptionSetField fun renderOptionSetFieldMultiChoice( field: OptionSetField, indentLevel: Int, + mixinsImportPath: String, ): String { val indentation0 = createIndentation(indentLevel) val indentation1 = createIndentation(indentLevel + 1) val optionNames = field.optionList.joinToString(" | ") { "\"${it.name}\"" } - val options = field.optionList.joinToString("\n$indentation1\n") { renderMultiSelectOptionSetFieldOption(it, indentLevel) } + val options = + field.optionList.joinToString("\n$indentation1\n") { + renderMultiSelectOptionSetFieldOption(it, indentLevel, mixinsImportPath) + } return """ #${renderComment(field.comment, indentLevel)} @@ -30,14 +34,20 @@ fun renderOptionSetFieldMultiChoice( private fun renderMultiSelectOptionSetFieldOption( fieldOption: ObjectField, indentLevel: Int, + mixinsImportPath: String, ): String { val indentation = createIndentation(indentLevel + 1) - val content = fieldOption.fields.joinToString("\n\n") { renderInterfaceModelField(it, indentLevel + 2) } + val content = fieldOption.fields.joinToString("\n\n") { renderInterfaceModelField(it, indentLevel + 2, mixinsImportPath) } + + val optionType = + when { + fieldOption.mixinName != null -> renderMixinTypeReference(fieldOption.mixinName, mixinsImportPath) + fieldOption.fields.isNotEmpty() -> "{\n$content\n#$indentation}" + else -> "Record" + } return """ #${renderComment(fieldOption.comment, indentLevel + 1)} - #$indentation${escapeName( - fieldOption.name, - )}: ${if (fieldOption.fields.isNotEmpty()) "{\n$content" else "Record"}${if (fieldOption.fields.isNotEmpty()) "\n#$indentation}" else ""}; + #$indentation${escapeName(fieldOption.name)}: $optionType; """.trimMargin("#") } diff --git a/src/main/kotlin/no/item/xp/plugin/renderers/ts/RenderTypeModelAsTypeScript.kt b/src/main/kotlin/no/item/xp/plugin/renderers/ts/RenderTypeModelAsTypeScript.kt index 409affa..0110759 100644 --- a/src/main/kotlin/no/item/xp/plugin/renderers/ts/RenderTypeModelAsTypeScript.kt +++ b/src/main/kotlin/no/item/xp/plugin/renderers/ts/RenderTypeModelAsTypeScript.kt @@ -2,8 +2,11 @@ package no.item.xp.plugin.renderers.ts import no.item.xp.plugin.models.ObjectTypeModel -fun renderTypeModelAsTypeScript(model: ObjectTypeModel): String { - val fieldList = model.fields.joinToString("\n\n") { renderInterfaceModelField(it, 1) } +fun renderTypeModelAsTypeScript( + model: ObjectTypeModel, + mixinsImportPath: String, +): String { + val fieldList = model.fields.joinToString("\n\n") { renderInterfaceModelField(it, 1, mixinsImportPath) } return """ #export type ${getTypeName(model.nameWithoutExtension)} = { diff --git a/src/main/kotlin/no/item/xp/plugin/util/TargetFile.kt b/src/main/kotlin/no/item/xp/plugin/util/TargetFile.kt index d6215ca..5995e45 100644 --- a/src/main/kotlin/no/item/xp/plugin/util/TargetFile.kt +++ b/src/main/kotlin/no/item/xp/plugin/util/TargetFile.kt @@ -52,6 +52,20 @@ fun getTargetFile( return File(getTargetDirectory(inputFile, rootDir), "index.d.ts") } +/** + * Returns the relative import path from the directory of [targetFile] to the generated mixins in [rootDir] + */ +fun resolveMixinsImportPath( + targetFile: File, + rootDir: File, +): String { + val mixinsDir = File(rootDir.absoluteFile, concatFileName("site", "mixins")).toPath() + val targetDir = targetFile.absoluteFile.parentFile.toPath() + val relativePath = normalizeFilePath(targetDir.relativize(mixinsDir).toString()) + + return if (relativePath.startsWith(".")) relativePath else "./$relativePath" +} + fun simpleFilePath(file: File): String = file.canonicalPath.substringAfter("""resources${File.separatorChar}""") fun normalizeFilePath(filePath: String): String = filePath.replace(File.separatorChar, '/') diff --git a/src/test/kotlin/no/item/xp/plugin/parser/ParseSetWithMixinTest.kt b/src/test/kotlin/no/item/xp/plugin/parser/ParseSetWithMixinTest.kt new file mode 100644 index 0000000..77c35f1 --- /dev/null +++ b/src/test/kotlin/no/item/xp/plugin/parser/ParseSetWithMixinTest.kt @@ -0,0 +1,127 @@ +package no.item.xp.plugin.parser + +import no.item.xp.plugin.extensions.getChildNodeAtXPath +import no.item.xp.plugin.models.ObjectField +import no.item.xp.plugin.models.ObjectTypeModel +import no.item.xp.plugin.models.OptionSetField +import no.item.xp.plugin.models.StringField +import no.item.xp.plugin.stringToXMLDocument +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import kotlin.test.assertEquals + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class ParseSetWithMixinTest { + private val urlField = StringField("url", "Url", false, false) + private val mixins = listOf(ObjectTypeModel("link", listOf(urlField))) + + @Test + fun `parse ItemSet with only a mixin`() { + // language=XML + val xml = + """ + + + + + + + + """ + + val result = parseItemSet(stringToXMLDocument(xml).getChildNodeAtXPath("item-set")!!, mixins) + + assertEquals( + ObjectField("links", "Links", true, true, listOf(urlField), "link"), + result, + ) + } + + @Test + fun `parse ItemSet with a mixin and other fields`() { + // language=XML + val xml = + """ + + + + + + + + + + + + """ + + val result = parseItemSet(stringToXMLDocument(xml).getChildNodeAtXPath("item-set")!!, mixins) + + assertEquals( + ObjectField("links", "Links", true, true, listOf(StringField("title", "Title", true, false), urlField), null), + result, + ) + } + + @Test + fun `parse ItemSet with only an unknown mixin`() { + // language=XML + val xml = + """ + + + + + + + + """ + + val result = parseItemSet(stringToXMLDocument(xml).getChildNodeAtXPath("item-set")!!, mixins) + + assertEquals( + ObjectField("links", "Links", true, true, emptyList(), null), + result, + ) + } + + @Test + fun `parse OptionSet option with only a mixin`() { + // language=XML + val xml = + """ + + + + + + + + + """ + + val result = parseOptionSet(stringToXMLDocument(xml).getChildNodeAtXPath("option-set")!!, mixins) + + assertEquals( + OptionSetField( + "myLink", + "Link", + false, + false, + false, + listOf( + ObjectField("none", "None", true, false, emptyList(), null), + ObjectField("internal", "Internal", true, false, listOf(urlField), "link"), + ), + ), + result, + ) + } +} diff --git a/src/test/kotlin/no/item/xp/plugin/renderers/ts/RenderMixinReferenceTest.kt b/src/test/kotlin/no/item/xp/plugin/renderers/ts/RenderMixinReferenceTest.kt new file mode 100644 index 0000000..95bace7 --- /dev/null +++ b/src/test/kotlin/no/item/xp/plugin/renderers/ts/RenderMixinReferenceTest.kt @@ -0,0 +1,148 @@ +package no.item.xp.plugin.renderers.ts + +import no.item.xp.plugin.models.* +import org.junit.jupiter.api.Test +import kotlin.test.assertEquals + +class RenderMixinReferenceTest { + private val mixinFields = listOf(StringField("url", "Url", false, false)) + + private val options = + listOf( + ObjectField("none", "None", true, false, emptyList()), + ObjectField("internal", "Internal", true, false, mixinFields, "link-internal"), + ) + + @Test + fun `render item set with only a mixin`() { + val result = + renderTypeModelAsTypeScript( + ObjectTypeModel( + "my-type", + listOf( + ObjectField("links", "Links", true, true, mixinFields, "link"), + ObjectField("mainLink", "Main link", false, false, mixinFields, "link"), + ), + ), + "../../mixins", + ) + + assertEquals( + //language=TypeScript + """ + #export type MyType = { + # /** + # * Links + # */ + # links?: Array; + # + # /** + # * Main link + # */ + # mainLink: import("../../mixins/link").Link; + #}; + #""".trimMargin( + //language= + "#", + ), + result, + ) + } + + @Test + fun `render option set with an option with only a mixin`() { + val result = + renderTypeModelAsTypeScript( + ObjectTypeModel( + "my-type", + listOf( + OptionSetField("myLink", "Link", false, false, false, options), + ), + ), + "../../mixins", + ) + + assertEquals( + //language=TypeScript + """ + #export type MyType = { + # /** + # * Link + # */ + # myLink: + # | { + # /** + # * Selected + # */ + # _selected: "none"; + # + # /** + # * None + # */ + # none: Record; + # } + # | { + # /** + # * Selected + # */ + # _selected: "internal"; + # + # /** + # * Internal + # */ + # internal: import("../../mixins/link-internal").LinkInternal; + # }; + #}; + #""".trimMargin( + //language= + "#", + ), + result, + ) + } + + @Test + fun `render multiselect option set with an option with only a mixin`() { + val result = + renderTypeModelAsTypeScript( + ObjectTypeModel( + "my-type", + listOf( + OptionSetField("myLinks", "Links", false, false, true, options), + ), + ), + "..", + ) + + assertEquals( + //language=TypeScript + """ + #export type MyType = { + # /** + # * Links + # */ + # myLinks: { + # /** + # * Selected + # */ + # _selected: Array<"none" | "internal">; + # + # /** + # * None + # */ + # none: Record; + # + # /** + # * Internal + # */ + # internal: import("../link-internal").LinkInternal; + # }; + #}; + #""".trimMargin( + //language= + "#", + ), + result, + ) + } +} diff --git a/src/test/kotlin/no/item/xp/plugin/renderers/ts/RenderObjectTypeModelTest.kt b/src/test/kotlin/no/item/xp/plugin/renderers/ts/RenderObjectTypeModelTest.kt index 7e72fb8..cba77b9 100644 --- a/src/test/kotlin/no/item/xp/plugin/renderers/ts/RenderObjectTypeModelTest.kt +++ b/src/test/kotlin/no/item/xp/plugin/renderers/ts/RenderObjectTypeModelTest.kt @@ -19,6 +19,7 @@ class RenderObjectTypeModelTest { UnionOfStringLiteralField("favouriteColor", "Favourite color", false, false, listOf("red", "green", "blue")), ), ), + "../../mixins", ) assertEquals( diff --git a/src/test/kotlin/no/item/xp/plugin/renderers/ts/RenderOptionSetFieldTest.kt b/src/test/kotlin/no/item/xp/plugin/renderers/ts/RenderOptionSetFieldTest.kt index b0cbdd6..83480ab 100644 --- a/src/test/kotlin/no/item/xp/plugin/renderers/ts/RenderOptionSetFieldTest.kt +++ b/src/test/kotlin/no/item/xp/plugin/renderers/ts/RenderOptionSetFieldTest.kt @@ -39,6 +39,7 @@ class RenderOptionSetFieldTest { ), ), ), + "../../mixins", ) assertEquals( @@ -119,6 +120,7 @@ class RenderOptionSetFieldTest { ), ), ), + "../../mixins", ) assertEquals( @@ -192,6 +194,7 @@ class RenderOptionSetFieldTest { ), ), ), + "../../mixins", ) assertEquals( diff --git a/src/test/kotlin/no/item/xp/plugin/util/ResolveMixinsImportPathTest.kt b/src/test/kotlin/no/item/xp/plugin/util/ResolveMixinsImportPathTest.kt new file mode 100644 index 0000000..19ba7f0 --- /dev/null +++ b/src/test/kotlin/no/item/xp/plugin/util/ResolveMixinsImportPathTest.kt @@ -0,0 +1,30 @@ +package no.item.xp.plugin.util + +import org.junit.jupiter.api.Test +import java.io.File +import kotlin.test.assertEquals + +class ResolveMixinsImportPathTest { + private val rootDir = File(".xp-codegen").absoluteFile + + @Test + fun `resolve from content type`() { + val targetFile = File(rootDir, concatFileName("site", "content-types", "article", "index.d.ts")) + + assertEquals("../../mixins", resolveMixinsImportPath(targetFile, rootDir)) + } + + @Test + fun `resolve from mixin`() { + val targetFile = File(rootDir, concatFileName("site", "mixins", "link", "index.d.ts")) + + assertEquals("..", resolveMixinsImportPath(targetFile, rootDir)) + } + + @Test + fun `resolve from site config`() { + val targetFile = File(rootDir, concatFileName("site", "index.d.ts")) + + assertEquals("./mixins", resolveMixinsImportPath(targetFile, rootDir)) + } +}