summaryrefslogtreecommitdiff
path: root/compiler/src/main/kotlin/com/android/databinding/main.kt
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/src/main/kotlin/com/android/databinding/main.kt')
-rw-r--r--compiler/src/main/kotlin/com/android/databinding/main.kt204
1 files changed, 152 insertions, 52 deletions
diff --git a/compiler/src/main/kotlin/com/android/databinding/main.kt b/compiler/src/main/kotlin/com/android/databinding/main.kt
index 70d69d6e..686bca36 100644
--- a/compiler/src/main/kotlin/com/android/databinding/main.kt
+++ b/compiler/src/main/kotlin/com/android/databinding/main.kt
@@ -48,7 +48,15 @@ import com.android.databinding.vo.LayoutExprBinding
import com.android.databinding.vo.VariableScope
import com.android.databinding.vo.VariableDefinition
import com.android.databinding.vo.BindingTarget
-
+import javax.xml.namespace.NamespaceContext
+import com.android.databinding.ext.forEach
+import javax.xml.transform.TransformerFactory
+import javax.xml.transform.stream.StreamResult
+import javax.xml.transform.dom.DOMSource
+import java.io.FileOutputStream
+import com.android.databinding.ext.toArrayList
+import com.android.databinding.util.XmlEditor
+import com.android.databinding.util.Log
public class KLayoutParser(val appPkg : String, val resourceFolders : kotlin.Iterable<File>,
@@ -57,6 +65,7 @@ public class KLayoutParser(val appPkg : String, val resourceFolders : kotlin.Ite
var dbr : DataBinderRenderer by Delegates.notNull()
var styler : AttrRenderer by Delegates.notNull()
val viewExprBinderRenderers = arrayListOf<ViewExprBinderRenderer>()
+ var processed = false
public var classAnalyzer : ClassAnalyzer by Delegates.notNull()
val outputResDir by Delegates.lazy { File(outputResBaseDir, "values") }
@@ -69,6 +78,15 @@ public class KLayoutParser(val appPkg : String, val resourceFolders : kotlin.Ite
File(outputBaseDir.getAbsolutePath() + "/" + dbr.pkg.replace('.','/'))
}
+ class object {
+ val XPATH_VARIABLE_DEFINITIONS = "//variable"
+ val XPATH_IMPORT_DEFINITIONS = "//import"
+ //val XPATH_BINDING_EXPR = "//@*[starts-with(name(), 'bind')]"
+ val XPATH_STATIC_BINDING_EXPR = "//@*[starts-with(name(), 'bind')]"
+ val XPATH_BINDING_2_EXPR = "//@*[starts-with(., '{') and substring(., string-length(.)) = '}']"
+ val XPATH_BINDING_ELEMENTS = "$XPATH_BINDING_2_EXPR/.."
+ }
+
public fun analyzeClasses() {
viewExprBinderRenderers.forEach {
it.lb.analyzeVariables()
@@ -77,7 +95,14 @@ public class KLayoutParser(val appPkg : String, val resourceFolders : kotlin.Ite
fun log (s : String) = System.out.println("LOG:$s");
- public fun process() {
+ public fun processIfNecessary() {
+ if (!processed) {
+ processed = true
+ process()
+ }
+ }
+
+ fun process() {
val xmlFiles = ArrayList<File>()
resourceFolders.filter({it.exists()}).forEach {
findLayoutFolders(it).forEach {
@@ -87,7 +112,7 @@ public class KLayoutParser(val appPkg : String, val resourceFolders : kotlin.Ite
//viewBinderRenderers.clear()
for (xml in xmlFiles) {
log("xmlFile $xml")
- val exprBinding = parseXml3(xml)
+ val exprBinding = parseAndStripXml(xml)
if (exprBinding == null) {
log("no bindings in $xml, skipping")
continue
@@ -103,7 +128,7 @@ public class KLayoutParser(val appPkg : String, val resourceFolders : kotlin.Ite
public fun writeAttrFile() {
outputResDir.mkdirs()
- writeToFile(File(outputResDir, "bindingattrs.xml"), styler.render())
+// writeToFile(File(outputResDir, "bindingattrs.xml"), styler.render())
}
public fun writeDbrFile() : Unit = writeDbrFile(dbrOutputDir)
@@ -149,73 +174,133 @@ public class KLayoutParser(val appPkg : String, val resourceFolders : kotlin.Ite
private fun toLayoutId(name:String) : String =
name.substring(0, name.indexOf("."))
+ private fun stripBindingTags(xml : File) {
+ val res = XmlEditor.strip(xml)
+ if (res != null) {
+ Log.d{"file ${xml.getName()} has changed, overwriting ${xml.getAbsolutePath()}"}
+ xml.writeText(res)
+ }
+ }
+
+ private fun stripFileAndGetOriginal(xml : File) : File? {
+ System.out.println("parsing resourceY file ${xml.getAbsolutePath()}")
+ val factory = DocumentBuilderFactory.newInstance()
+ val builder = factory.newDocumentBuilder()
+ val doc = builder.parse(xml)
+ val xPathFactory = XPathFactory.newInstance()
+ val xPath = xPathFactory.newXPath()
+ val commentElementExpr = xPath.compile("//comment()[starts-with(., \" From: file:\")][last()]")
+ var commentElementNodes = commentElementExpr.evaluate(doc, XPathConstants.NODESET) as NodeList
+ System.out.println("comment element nodes count ${commentElementNodes.getLength()}")
+ if (commentElementNodes.getLength() == 0) {
+ System.out.println("cannot find comment element to find the actual file")
+ return null
+ }
+ val first = commentElementNodes.item(0)
+ val actualFilePath = first.getNodeValue().substring(" From: file:".length()).trim()
+ System.out.println("actual file to parse: ${actualFilePath}")
+ val actualFile = File(actualFilePath)
+ if (!actualFile.canRead()) {
+ System.out.println("cannot find original, skipping. ${actualFile.getAbsolutePath()}")
+ return null
+ }
+
+ // now if file has any binding expressions, find and delete them
+ val variableNodes = getVariableNodes(doc, xPath)
+ var changed = variableNodes.getLength() > 0 //TODO do we need to check more?
+ if (changed) {
+ stripBindingTags(xml)
+ }
+
+ return actualFile
+ }
+
+ private fun parseAndStripXml(xml : File) : LayoutExprBinding? {
+ val original = stripFileAndGetOriginal(xml)
+ return if (original == null) {
+ null
+ } else {
+ parseXml3(original)
+ }
+ }
+
private fun parseXml3(xml: File) : LayoutExprBinding? {
+ System.out.println("parsing file ${xml.getAbsolutePath()}")
val factory = DocumentBuilderFactory.newInstance()
val builder = factory.newDocumentBuilder()
val doc = builder.parse(xml)
+
val xPathFactory = XPathFactory.newInstance()
val xPath = xPathFactory.newXPath()
//
val layoutBinding = LayoutExprBinding(doc)
val exprParser = ExpressionParser()
- val varsExprs = xPath.compile("//@*[starts-with(name(), 'bind_var')]/..")
- val varNodes = varsExprs.evaluate(doc, XPathConstants.NODESET) as NodeList
- System.out.println("var node count" + varNodes.getLength())
- for (i in 0..varNodes.getLength() - 1) {
- val item = varNodes.item(i)
- System.out.println("checking variable node $item")
+ val varElementNodes = getVariableNodes(doc, xPath)
+
+ System.out.println("varX element node count" + varElementNodes.getLength())
+ val variableScope = VariableScope(doc)//all variables global for now
+ for (i in 0..varElementNodes.getLength() - 1) {
+ val item = varElementNodes.item(i)
+ System.out.println("checking variable element node $item")
val attributes = item.getAttributes()
- val variableScope = VariableScope(item)
- val attrCount = attributes.getLength()
- for (j in 0..(attrCount - 1)) {
- val attr = attributes.item(j)
- val name = attr.getNodeName()
- if (name.startsWith("bind_var:")) {
- variableScope.variables.add(VariableDefinition(name.substring("bind_var:".length), attr.getNodeValue()))
- }
- }
- layoutBinding.addVariableScope(variableScope)
+ val variableName = attributes.getNamedItem("name").getNodeValue()
+ val variableType = attributes.getNamedItem("type").getNodeValue()
+ System.out.println("name:$variableName type:$variableType")
+ variableScope.variables.add(VariableDefinition(variableName, variableType))
}
+ layoutBinding.addVariableScope(variableScope)
- val expr = xPath.compile("//@*[starts-with(name(), 'bind')]/..")
- val nodes = expr.evaluate(doc, XPathConstants.NODESET) as NodeList
- System.out.println("binding node count " + nodes.getLength())
- for (i in 0..nodes.getLength() - 1) {
- val item = nodes.item(i)
- System.out.println("checking node $item")
- val attributes = item.getAttributes()
+ val bindingNodes = getBindingNodes(doc, xPath)
+ System.out.println("binding node count " + bindingNodes.getLength())
+ bindingNodes.forEach { parent ->
+ System.out.println("binding node: $parent")
+ val attributes = parent.getAttributes()
val id = attributes.getNamedItem("android:id")
- if (id == null) {
- continue
- }
- val bindingTarget = BindingTarget(item, id.getNodeValue(), getFullViewClassName(item.getNodeName()))
- val attrCount = attributes.getLength()
- for (j in 0..(attrCount - 1)) {
- val attr = attributes.item(j)
- val name = attr.getNodeName()
- if (name.startsWith("bind:")) {
- bindingTarget.addBinding(name.substring("bind:".length), exprParser.parse(attr.getNodeValue()))
+ if (id != null) {
+ val bindingTarget = BindingTarget(parent, id.getNodeValue(), getFullViewClassName(parent.getNodeName()))
+ val attrCount = attributes.getLength()
+ for (j in 0..(attrCount - 1)) {
+ val attr = attributes.item(j)
+ val value = attr.getNodeValue()
+ if (value.first() == '{' && value.last() == '}') {
+ val name = attr.getNodeName().split(":").last()
+ val strippedValue = value.substring(1, value.length() - 1)
+ bindingTarget.addBinding(name, exprParser.parse(strippedValue))
+ }
}
+ layoutBinding.bindingTargets.add(bindingTarget)
}
- layoutBinding.bindingTargets.add(bindingTarget)
}
+// System.out.println("binding node count " + nodes.getLength())
+// for (i in 0..nodes.getLength() - 1) {
+// val item = nodes.item(i)
+// System.out.println("checking node $item")
+// val attributes = item.getAttributes()
+// val id = attributes.getNamedItem("android:id")
+// if (id == null) {
+// continue
+// }
+// val bindingTarget = BindingTarget(item, id.getNodeValue(), getFullViewClassName(item.getNodeName()))
+// val attrCount = attributes.getLength()
+// for (j in 0..(attrCount - 1)) {
+// val attr = attributes.item(j)
+// val name = attr.getNodeName()
+// if (name.startsWith("bind:")) {
+// bindingTarget.addBinding(name.substring("bind:".length), exprParser.parse(attr.getNodeValue()))
+// }
+// }
+// layoutBinding.bindingTargets.add(bindingTarget)
+// }
- val convExpr = xPath.compile("//@*[starts-with(name(), 'bind_static')]/..")
- val convNodes = convExpr.evaluate(doc, XPathConstants.NODESET) as NodeList
- System.out.println("converter node count " + nodes.getLength())
- for (i in 0..convNodes.getLength() - 1) {
- val item = convNodes.item(i)
- System.out.println("checking conv node $item")
+ val imports = getImportNodes(doc, xPath)
+ System.out.println("import node count " + imports.getLength())
+ imports.forEach { item ->
val attributes = item.getAttributes()
- val attrCount = attributes.getLength()
- for (j in 0..(attrCount - 1)) {
- val attr = attributes.item(j)
- val name = attr.getNodeName()
- if (name.startsWith("bind_static:")) {
- layoutBinding.addStaticClass(name.substring("bind_static:".length), attr.getNodeValue())
- }
- }
+ val type = attributes.getNamedItem("type").getNodeValue()
+ System.out.println("type ${type}")
+ val alias = attributes.getNamedItem("alias")?.getNodeValue() ?: type.split("\\.").last();
+ layoutBinding.addStaticClass(alias, type)
}
if (exprParser.model.variables.size == 0) {
return null
@@ -225,6 +310,21 @@ public class KLayoutParser(val appPkg : String, val resourceFolders : kotlin.Ite
return layoutBinding
}
+ private fun getBindingNodes(doc: Document, xPath: XPath): NodeList {
+ val expr = xPath.compile(XPATH_BINDING_ELEMENTS)
+ return expr.evaluate(doc, XPathConstants.NODESET) as NodeList
+ }
+
+ private fun getVariableNodes(doc: Document?, xPath: XPath): NodeList {
+ val expr = xPath.compile(XPATH_VARIABLE_DEFINITIONS)
+ return expr.evaluate(doc, XPathConstants.NODESET) as NodeList
+ }
+
+ private fun getImportNodes(doc: Document?, xPath: XPath): NodeList {
+ val expr = xPath.compile(XPATH_IMPORT_DEFINITIONS)
+ return expr.evaluate(doc, XPathConstants.NODESET) as NodeList
+ }
+
private fun findLayoutFolders(resources: File): Array<File> {
val filenameFilter = object : FilenameFilter {
override fun accept(dir: File, name: String): Boolean {