Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make attribute traits inheritable #280

Merged
merged 3 commits into from
Jun 25, 2024
Merged
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
8 changes: 3 additions & 5 deletions buildSrc/src/main/kotlin/kotlinx/html/generate/attributes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,12 @@ fun Appendable.attributeProperty(
}

fun Appendable.facade(repository: Repository, facade: AttributeFacade) {
val facadeName = facade.name.capitalize() + "Facade"

clazz(Clazz(facadeName, isInterface = true, parents = listOf("Tag"))) {
clazz(Clazz(facade.className, isInterface = true, parents = facade.parents)) {
}

facade.attributes.filter { !isAttributeExcluded(it.name) }.forEach { attribute ->
facade.declaredAttributes.filter { !isAttributeExcluded(it.name) }.forEach { attribute ->
if (attribute.name.isLowerCase() || attribute.name.lowercase() !in facade.attributeNames) {
attributeProperty(repository, attribute, receiver = facadeName, indent = 0)
attributeProperty(repository, attribute, receiver = facade.className, indent = 0)
}
}
}
Expand Down
9 changes: 3 additions & 6 deletions buildSrc/src/main/kotlin/kotlinx/html/generate/main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ fun generate(pkg: String, todir: String, jsdir: String, wasmJsDir: String) {
}

repository.attributeFacades.values.forEach { facade ->
facade.attributes.filter { it.enumValues.isNotEmpty() }.filter { !isAttributeExcluded(it.name) }
facade.declaredAttributes.filter { it.enumValues.isNotEmpty() }.filter { !isAttributeExcluded(it.name) }
.forEach { attribute ->
genEnumAttribute(attribute)
}
Expand Down Expand Up @@ -307,17 +307,14 @@ private fun generateConsumerTags(
}

private fun generateEventAttrs(repository: Repository, file: String, pkg: String) {
val isEventAttribute = { attributeName: String ->
attributeName.startsWith("on")
}
val isEventAttribute = { attributeName: String -> attributeName.startsWith("on") }
val properties = sequence {
repository
.attributeFacades
.filter { facade -> facade.value.attributeNames.any(isEventAttribute) }
.forEach { facade ->
facade.value.attributes.filter { it.name.startsWith("on") }.forEach {
val parentName = facade.value.name.capitalize() + "Facade"
val parent = ClassName("kotlinx.html", parentName)
val parent = ClassName("kotlinx.html", facade.value.className)

yield(eventProperty(parent, it, shouldUnsafeCast = false))
}
Expand Down
10 changes: 9 additions & 1 deletion buildSrc/src/main/kotlin/kotlinx/html/generate/model.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,15 @@ class Repository {
var unionsByGroups: Map<String, List<GroupUnion>> = emptyMap()
}

data class AttributeFacade(val name: String, val attributes: List<AttributeInfo>, val required: Set<String>) {
data class AttributeFacade(
val name: String,
val declaredAttributes: List<AttributeInfo>,
val required: Set<String>,
val inheritedFacades: List<AttributeFacade>,
) {
val className = name.capitalize() + "Facade"
val attributes: List<AttributeInfo> = declaredAttributes + inheritedFacades.flatMap { it.attributes }
val parents = if (inheritedFacades.isNotEmpty()) inheritedFacades.map { it.className } else listOf("Tag")
val attributeNames = attributes.map { it.name }.toSet()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import java.util.*

fun generateParentInterfaces(repository: Repository, todir: String, packg: String) {
val allParentIfaces = repository.tags.values.filterIgnored().map { tag ->
val parentAttributeIfaces = tag.attributeGroups.map { it.name.humanize().capitalize() + "Facade" }
val parentAttributeIfaces = tag.attributeGroups.map { it.className }
val parentElementIfaces = tag.tagGroupNames.map { it.humanize().capitalize() }
val sum = parentAttributeIfaces + parentElementIfaces

Expand Down
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/kotlinx/html/generate/tagsgen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ private const val BLOCK_LAMBDA = "block"
private const val CONTENT_LAMBDA = "{+content}"

fun Appendable.tagClass(repository: Repository, tag: TagInfo, excludeAttributes: Set<String>) {
val parentAttributeIfaces = tag.attributeGroups.map { it.name.capitalize() + "Facade" }
val parentAttributeIfaces = tag.attributeGroups.map { it.className }
val parentElementIfaces = tag.tagGroupNames.map { it.humanize().capitalize() }
val allParentIfaces = parentAttributeIfaces + parentElementIfaces
val betterParentIfaces = humanizeJoin(allParentIfaces)
Expand Down
74 changes: 59 additions & 15 deletions buildSrc/src/main/kotlin/kotlinx/html/generate/xsdparser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@ fun handleAttributeDeclaration(prefix: String, attributeDeclaration: XSAttribute

if (type.isUnion) {
val enumEntries = type.asUnion()
.filter { it.isRestriction }
.map { it.asRestriction() }
.flatMap { it.declaredFacets ?: emptyList() }
.filter { it.name == "enumeration" }
.map { it.value.value }
.asSequence()
.filter { it.isRestriction }
.map { it.asRestriction() }
.flatMap { it.declaredFacets ?: emptyList() }
.filter { it.name == "enumeration" }
.map { it.value.value }
.toList()

return AttributeInfo(name, AttributeType.STRING, enumValues = enumEntries.toAttributeValues(), enumTypeName = prefix.capitalize() + name.humanize().capitalize())
} else if (type.isPrimitive || type.name in setOf<String?>("integer", "string", "boolean", "decimal")) {
Expand Down Expand Up @@ -74,13 +76,36 @@ fun AttributeInfo.handleSpecialType(tagName: String = ""): AttributeInfo = speci
this.copy(type = type)
} ?: this

private fun parseAttributeFacade(repository: Repository, attributeGroup: XSAttGroupDecl): AttributeFacade {
val requiredNames = HashSet<String>()
val facadeAttributes = attributeGroup.declaredAttributeUses.map { attributeUse ->
val attributeDeclaration = attributeUse.decl
if (attributeUse.isRequired) {
requiredNames.add(attributeDeclaration.name)
}

handleAttributeDeclaration("", attributeDeclaration).handleSpecialType()
}.filter { !it.name.startsWith("On") }.sortedBy { it.name }
val inheritedFacades = attributeGroup.attGroups.map { parseAttributeFacade(repository, it) }
inheritedFacades.forEach { repository.attributeFacades[it.name] = it }
return AttributeFacade(attributeGroup.name, facadeAttributes, requiredNames, inheritedFacades)
}

fun fillRepository(repository: Repository) {
val parser = XSOMParser(SAXParserFactory.newInstance())
parser.parse(SCHEME_URL)
val schema = parser.result.getSchema(HTML_NAMESPACE)

val alreadyIncluded = TreeSet<String> { a, b -> a.compareTo(b, true) }
schema.attGroupDecls.values.sortedByDescending { it.attributeUses.size }.forEach { attributeGroup ->
if (!repository.attributeFacades.containsKey(attributeGroup.name)) {
repository.attributeFacades[attributeGroup.name] = parseAttributeFacade(repository, attributeGroup)
}
/*
repository.attributeFacades.computeIfAbsent(attributeGroup.name) { _ ->
parseAttributeFacade(repository, attributeGroup)
}
*/
/*
val requiredNames = HashSet<String>()
val facadeAttributes = attributeGroup.attributeUses.map { attributeUse ->
val attributeDeclaration = attributeUse.decl
Expand All @@ -96,9 +121,10 @@ fun fillRepository(repository: Repository) {
val name = attributeGroup.name

if (facadeAttributes.isNotEmpty()) {
repository.attributeFacades[name] = AttributeFacade(name, facadeAttributes, requiredNames)
repository.attributeFacades[name] = AttributeFacade(name, facadeAttributes, requiredNames, emptyList())
alreadyIncluded.addAll(facadeAttributes.map { it.name })
}
*/
}

schema.modelGroupDecls.values.forEach { modelGroupDeclaration ->
Expand All @@ -120,16 +146,20 @@ fun fillRepository(repository: Repository) {
val name = elementDeclaration.name
val type = elementDeclaration.type
val suggestedNames = HashSet<String>()
globalSuggestedAttributes.get(name)?.let {
suggestedNames.addAll(it.filter { !it.startsWith("-") })
globalSuggestedAttributes[name]?.let { attributes ->
suggestedNames.addAll(attributes.filter { !it.startsWith("-") })
}
val excluded = globalSuggestedAttributes.get(name)?.filter { it.startsWith("-") }?.map { it.removePrefix("-") } ?: emptyList()
val excluded = globalSuggestedAttributes[name]
?.filter { it.startsWith("-") }
?.map { it.removePrefix("-") }
?.toSet()
?: emptySet()

val tagInfo: TagInfo
if (type.isComplexType) {
val complex = type.asComplexType()
val groupDeclarations = complex.attGroups.flatMap { flattenGroups(it) }.distinct().toList()
val attributeGroups = groupDeclarations.map { repository.attributeFacades[it.name] }.filterNotNull()
val groupDeclarations = complex.attGroups.distinct().sortedBy { it.name }
val attributeGroups = groupDeclarations.mapNotNull { repository.attributeFacades[it.name] }

val attributes = complex.declaredAttributeUses.map {
if (it.isRequired) {
Expand All @@ -146,7 +176,13 @@ fun fillRepository(repository: Repository) {
if (contentTerm != null) {
flattenTerm(contentTerm, children, modelGroupNames)
if (contentTerm.isModelGroup) {
directChildren.addAll(contentTerm.asModelGroup().children.map { it.term }.filter { it.isElementDecl }.map { it.asElementDecl().name })
directChildren.addAll(
contentTerm.asModelGroup()
.children
.map { it.term }
.filter { it.isElementDecl }
.map { it.asElementDecl().name },
)
}
}

Expand All @@ -157,7 +193,15 @@ fun fillRepository(repository: Repository) {
suggestedNames.addAll(attributeGroups.flatMap { it.attributes }.filter { it.name in globalSuggestedAttributeNames }.map { it.name })
suggestedNames.removeAll(excluded)

tagInfo = TagInfo(name, children.toList().sorted(), directChildren, attributeGroups, attributes, suggestedNames, modelGroupNames.sorted().toList())
tagInfo = TagInfo(
name = name,
possibleChildren = children.toList().sorted(),
directChildren = directChildren,
attributeGroups = attributeGroups,
attributes = attributes,
suggestedAttributes = suggestedNames,
tagGroupNames = modelGroupNames.sorted(),
)
} else {
throw UnsupportedOperationException()
}
Expand All @@ -172,4 +216,4 @@ private val xsdToType = mapOf(
"boolean" to AttributeType.BOOLEAN,
"string" to AttributeType.STRING,
"anyURI" to AttributeType.STRING // TODO links
)
)
Loading
Loading