1616
1717package com.google.firebase.gradle.plugins
1818
19+ import java.io.File
1920import org.w3c.dom.Element
2021import org.w3c.dom.NodeList
2122
@@ -26,16 +27,14 @@ fun String.remove(regex: Regex) = replace(regex, "")
2627fun String.remove (str : String ) = replace(str, " " )
2728
2829/* *
29- * Returns a sequence containing all elements.
30- *
31- * The operation is _terminal_.
30+ * Joins a variable amount of [strings][Any.toString] to a single [String] split by newlines (`\n`).
3231 *
33- * Syntax sugar for :
34- * ```
35- * take(count())
32+ * For example :
33+ * ```kotlin
34+ * println(multiLine("Hello", "World", "!")) // "Hello\nWorld\n!"
3635 * ```
3736 */
38- public fun < T > Sequence<T>. takeAll (): Sequence < T > = take(count() )
37+ fun multiLine ( vararg strings : Any? ) = strings.joinToString( " \n " )
3938
4039/* *
4140 * Converts an [Element] to an Artifact string.
@@ -77,19 +76,30 @@ fun Element.toArtifactString() =
7776 * ```
7877 *
7978 * @throws NoSuchElementException if the [Element] does not have descendant [Element]s with tags
80- * that match the components of an Artifact string; groupId, artifactId, version .
79+ * that match the components of an Artifact string; groupId and artifactId .
8180 */
8281fun Element.toMavenName () = " ${textByTag(" groupId" )} :${textByTag(" artifactId" )} "
8382
8483/* *
85- * Finds a descendant [Element] by a given [tag], and returns the [textContent]
86- * [Element.getTextContent] of it.
84+ * Finds a descendant [Element] by a [tag], and returns the [textContent][Element.getTextContent] of
85+ * it.
8786 *
8887 * @param tag the XML tag to filter for (the special value "*" matches all tags)
8988 * @throws NoSuchElementException if an [Element] with the given [tag] does not exist
9089 * @see findElementsByTag
90+ * @see textByTagOrNull
91+ */
92+ fun Element.textByTag (tag : String ) =
93+ textByTagOrNull(tag) ? : throw RuntimeException (" Element tag was missing: $tag " )
94+
95+ /* *
96+ * Finds a descendant [Element] by a [tag], and returns the [textContent][Element.getTextContent] of
97+ * it, or null if it couldn't be found.
98+ *
99+ * @param tag the XML tag to filter for (the special value "*" matches all tags)
100+ * @see textByTag
91101 */
92- fun Element.textByTag (tag : String ) = findElementsByTag(tag).first() .textContent
102+ fun Element.textByTagOrNull (tag : String ) = findElementsByTag(tag).firstOrNull()? .textContent
93103
94104/* *
95105 * Finds a descendant [Element] by a given [tag], or creates a new one.
@@ -99,7 +109,7 @@ fun Element.textByTag(tag: String) = findElementsByTag(tag).first().textContent
99109 * @param tag the XML tag to filter for (the special value "*" matches all tags)
100110 * @see findElementsByTag
101111 */
102- fun Element.findOrCreate (tag : String ) =
112+ fun Element.findOrCreate (tag : String ): Element =
103113 findElementsByTag(tag).firstOrNull() ? : ownerDocument.createElement(tag).also { appendChild(it) }
104114
105115/* *
@@ -118,27 +128,21 @@ fun Element.findElementsByTag(tag: String) =
118128 * Yields the items of this [NodeList] as a [Sequence].
119129 *
120130 * [NodeList] does not typically offer an iterator. This extension method offers a means to loop
121- * through a NodeList's [item][NodeList.item] method, while also taking into account its [length]
122- * [NodeList.getLength] property to avoid an [IndexOutOfBoundsException].
131+ * through a NodeList's [item][NodeList.item] method, while also taking into account the element's
132+ * [length][ NodeList.getLength] property to avoid an [IndexOutOfBoundsException].
123133 *
124134 * Additionally, this operation is _intermediate_ and _stateless_.
125135 */
126- fun NodeList.children () = sequence {
127- for (index in 0 .. length) {
128- yield (item(index))
136+ fun NodeList.children (removeDOMSections : Boolean = true) = sequence {
137+ for (index in 0 until length) {
138+ val child = item(index)
139+
140+ if (! removeDOMSections || ! child.nodeName.startsWith(" #" )) {
141+ yield (child)
142+ }
129143 }
130144}
131145
132- /* *
133- * Joins a variable amount of [strings][Any.toString] to a single [String] split by newlines (`\n`).
134- *
135- * For example:
136- * ```kotlin
137- * println(multiLine("Hello", "World", "!")) // "Hello\nWorld\n!"
138- * ```
139- */
140- fun multiLine (vararg strings : Any? ) = strings.joinToString(" \n " )
141-
142146/* *
143147 * Returns the first match of a regular expression in the [input], beginning at the specified
144148 * [startIndex].
@@ -152,6 +156,26 @@ fun Regex.findOrThrow(input: CharSequence, startIndex: Int = 0) =
152156 find(input, startIndex)
153157 ? : throw RuntimeException (multiLine(" No match found for the given input:" , input.toString()))
154158
159+ /* *
160+ * Returns the value of the first capture group.
161+ *
162+ * Intended to be used in [MatchResult] that are only supposed to capture a single entry.
163+ */
164+ val MatchResult .firstCapturedValue: String
165+ get() = groupValues[1 ]
166+
167+ /* *
168+ * Returns a sequence containing all elements.
169+ *
170+ * The operation is _terminal_.
171+ *
172+ * Syntax sugar for:
173+ * ```
174+ * take(count())
175+ * ```
176+ */
177+ fun <T > Sequence<T>.takeAll (): Sequence <T > = take(count())
178+
155179/* *
156180 * Creates a [Pair] out of an [Iterable] with only two elements.
157181 *
@@ -212,14 +236,6 @@ fun List<String>.replaceMatches(regex: Regex, transform: (MatchResult) -> String
212236 }
213237}
214238
215- /* *
216- * Returns the value of the first capture group.
217- *
218- * Intended to be used in [MatchResult] that are only supposed to capture a single entry.
219- */
220- val MatchResult .firstCapturedValue: String
221- get() = groupValues[1 ]
222-
223239/* *
224240 * Creates a diff between two lists.
225241 *
@@ -250,3 +266,23 @@ infix fun <T> List<T>.diff(other: List<T>): List<Pair<T?, T?>> {
250266 * ```
251267 */
252268fun <T > List<T>.coerceToSize (targetSize : Int ) = List (targetSize) { getOrNull(it) }
269+
270+ /* *
271+ * The [path][File.path] represented as a qualified unix path.
272+ *
273+ * Useful when a system expects a unix path, but you need to be able to run it on non unix systems.
274+ *
275+ * @see absoluteUnixPath
276+ */
277+ val File .unixPath: String
278+ get() = path.replace(" \\ " , " /" )
279+
280+ /* *
281+ * The [absolutePath][File.getAbsolutePath] represented as a qualified unix path.
282+ *
283+ * Useful when a system expects a unix path, but you need to be able to run it on non unix systems.
284+ *
285+ * @see unixPath
286+ */
287+ val File .absoluteUnixPath: String
288+ get() = absolutePath.replace(" \\ " , " /" )
0 commit comments