Skip to content

Commit aaeb118

Browse files
committed
Work on allowing the library to (mostly) work on nodejs. Note that any
DOM access is not supported (and the tests will just ignore dom)
1 parent 77953e7 commit aaeb118

File tree

14 files changed

+308
-93
lines changed

14 files changed

+308
-93
lines changed

core/base/build.gradle.kts

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import org.jetbrains.kotlin.gradle.dsl.HasConfigurableKotlinCompilerOptions
2727
import org.jetbrains.kotlin.gradle.dsl.JsMainFunctionExecutionMode
2828
import org.jetbrains.kotlin.gradle.dsl.JsModuleKind
2929
import org.jetbrains.kotlin.gradle.dsl.JsSourceMapEmbedMode
30-
import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl
30+
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
3131

3232
plugins {
3333
alias(libs.plugins.dokka)

core/base/src/commonTest/kotlin/nl/adaptivity/xmlutil/TestDom.kt

+49-33
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ package nl.adaptivity.xmlutil
2323
import nl.adaptivity.xmlutil.dom2.Element
2424
import nl.adaptivity.xmlutil.dom2.documentElement
2525
import nl.adaptivity.xmlutil.serialization.writeAsXML
26+
import nl.adaptivity.xmlutil.test.multiplatform.Target
27+
import nl.adaptivity.xmlutil.test.multiplatform.testTarget
2628
import kotlin.test.Test
2729
import kotlin.test.assertEquals
2830

@@ -33,12 +35,14 @@ class TestDom {
3335
*/
3436
@Test
3537
fun test_getElementsByTagName_withNestedTags_worksCorrectly() {
36-
val element = getTestElementRoot()
38+
if (testTarget != Target.Node) {
39+
val element = getTestElementRoot()
3740
//.decodeFromString(Element.serializer(), NESTED_ELEMENTS_TAG_SOUP)
38-
val children = element.getElementsByTagName("child").toList()
39-
assertEquals(16, children.size)
40-
children.forEachIndexed { index, node ->
41-
assertEquals((node as Element).getAttribute("prop"), index.toString())
41+
val children = element.getElementsByTagName("child").toList()
42+
assertEquals(16, children.size)
43+
children.forEachIndexed { index, node ->
44+
assertEquals((node as Element).getAttribute("prop"), index.toString())
45+
}
4246
}
4347
}
4448

@@ -47,12 +51,14 @@ class TestDom {
4751
*/
4852
@Test
4953
fun test_getElementsByTagNameWildcard_withNestedTags_worksCorrectly() {
50-
val element = getTestElementRoot()
54+
if (testTarget != Target.Node) {
55+
val element = getTestElementRoot()
5156
//.decodeFromString(Element.serializer(), NESTED_ELEMENTS_TAG_SOUP)
52-
val children = element.getElementsByTagName("*").toList()
53-
assertEquals(16, children.size)
54-
children.forEachIndexed { index, node ->
55-
assertEquals((node as Element).getAttribute("prop"), index.toString())
57+
val children = element.getElementsByTagName("*").toList()
58+
assertEquals(16, children.size)
59+
children.forEachIndexed { index, node ->
60+
assertEquals((node as Element).getAttribute("prop"), index.toString())
61+
}
5662
}
5763
}
5864

@@ -61,12 +67,14 @@ class TestDom {
6167
*/
6268
@Test
6369
fun test_getElementsByTagNameNS_withNestedTags_worksCorrectly() {
64-
val element = getTestElementRoot()
70+
if (testTarget != Target.Node) {
71+
val element = getTestElementRoot()
6572
//.decodeFromString(Element.serializer(), NESTED_ELEMENTS_TAG_SOUP)
66-
val children = element.getElementsByTagNameNS("", "child").toList()
67-
assertEquals(16, children.size)
68-
children.forEachIndexed { index, node ->
69-
assertEquals((node as Element).getAttribute("prop"), index.toString())
73+
val children = element.getElementsByTagNameNS("", "child").toList()
74+
assertEquals(16, children.size)
75+
children.forEachIndexed { index, node ->
76+
assertEquals((node as Element).getAttribute("prop"), index.toString())
77+
}
7078
}
7179
}
7280

@@ -75,12 +83,14 @@ class TestDom {
7583
*/
7684
@Test
7785
fun test_getElementsByTagNameNSWildcard_withNestedTags_worksCorrectly() {
78-
val element = getTestElementRoot()
86+
if (testTarget != Target.Node) {
87+
val element = getTestElementRoot()
7988
//.decodeFromString(Element.serializer(), NESTED_ELEMENTS_TAG_SOUP)
80-
val children = element.getElementsByTagNameNS("*", "*").toList()
81-
assertEquals(16, children.size)
82-
children.forEachIndexed { index, node ->
83-
assertEquals((node as Element).getAttribute("prop"), index.toString())
89+
val children = element.getElementsByTagNameNS("*", "*").toList()
90+
assertEquals(16, children.size)
91+
children.forEachIndexed { index, node ->
92+
assertEquals((node as Element).getAttribute("prop"), index.toString())
93+
}
8494
}
8595
}
8696

@@ -89,12 +99,14 @@ class TestDom {
8999
*/
90100
@Test
91101
fun test_getElementsByTagNameNSWildcardPart_withNestedTags_worksCorrectly() {
92-
val element = getTestElementRoot()
102+
if (testTarget != Target.Node) {
103+
val element = getTestElementRoot()
93104
//.decodeFromString(Element.serializer(), NESTED_ELEMENTS_TAG_SOUP)
94-
val children = element.getElementsByTagNameNS("*", "child").toList()
95-
assertEquals(16, children.size)
96-
children.forEachIndexed { index, node ->
97-
assertEquals((node as Element).getAttribute("prop"), index.toString())
105+
val children = element.getElementsByTagNameNS("*", "child").toList()
106+
assertEquals(16, children.size)
107+
children.forEachIndexed { index, node ->
108+
assertEquals((node as Element).getAttribute("prop"), index.toString())
109+
}
98110
}
99111
}
100112

@@ -103,11 +115,13 @@ class TestDom {
103115
*/
104116
@Test
105117
fun test_getElementsByTagNameNSWildcardPartLocal_withNestedTags_worksCorrectly() {
106-
val element = getTestElementRoot()
107-
val children = element.getElementsByTagNameNS("", "*").toList()
108-
assertEquals(16, children.size)
109-
children.forEachIndexed { index, node ->
110-
assertEquals((node as Element).getAttribute("prop"), index.toString())
118+
if (testTarget != Target.Node) {
119+
val element = getTestElementRoot()
120+
val children = element.getElementsByTagNameNS("", "*").toList()
121+
assertEquals(16, children.size)
122+
children.forEachIndexed { index, node ->
123+
assertEquals((node as Element).getAttribute("prop"), index.toString())
124+
}
111125
}
112126
}
113127

@@ -116,9 +130,11 @@ class TestDom {
116130
*/
117131
@Test
118132
fun test_getElementsByTagNameNSWildcardNonMatchingLocal_withNestedTags_worksCorrectly() {
119-
val element = getTestElementRoot()
120-
val children = element.getElementsByTagNameNS("xx", "*").toList()
121-
assertEquals(0, children.size)
133+
if (testTarget != Target.Node) {
134+
val element = getTestElementRoot()
135+
val children = element.getElementsByTagNameNS("xx", "*").toList()
136+
assertEquals(0, children.size)
137+
}
122138
}
123139

124140
companion object {

core/base/src/commonTest/kotlin/nl/adaptivity/xmlutil/TestKtXmlReader.kt

+17-13
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import nl.adaptivity.xmlutil.core.impl.multiplatform.StringReader
2727
import nl.adaptivity.xmlutil.core.impl.multiplatform.StringWriter
2828
import nl.adaptivity.xmlutil.core.impl.multiplatform.use
2929
import nl.adaptivity.xmlutil.test.TestCommonReader
30+
import nl.adaptivity.xmlutil.test.multiplatform.Target
31+
import nl.adaptivity.xmlutil.test.multiplatform.testTarget
3032
import kotlin.test.Test
3133
import kotlin.test.assertEquals
3234

@@ -51,28 +53,30 @@ class TestKtXmlReader : TestCommonReader() {
5153

5254
@Test
5355
override fun testProcessingInstructionDom() {
54-
val domWriter = DomWriter()
55-
testProcessingInstruction(::createReader) { domWriter }
56+
if (testTarget != Target.Node) {
57+
val domWriter = DomWriter()
58+
testProcessingInstruction(::createReader) { domWriter }
5659

57-
val expectedXml = """
60+
val expectedXml = """
5861
<?xpacket begin='' id='from_166'?>
5962
<a:root xmlns:a="foo" a:b="42">bar</a:root>
6063
<?xpacket end='w'?>
6164
"""
62-
val expected = xmlStreaming.newReader(expectedXml)
63-
val actual = xmlStreaming.newReader(domWriter.target)
64-
assertXmlEquals(expected, actual)
65+
val expected = xmlStreaming.newReader(expectedXml)
66+
val actual = xmlStreaming.newReader(domWriter.target)
67+
assertXmlEquals(expected, actual)
6568

66-
val fromDom = StringWriter()
67-
KtXmlWriter(fromDom, xmlDeclMode = XmlDeclMode.None).use { writer ->
68-
xmlStreaming.newReader(domWriter.target).use { reader ->
69-
while (reader.hasNext()) {
70-
reader.next()
71-
reader.writeCurrent(writer)
69+
val fromDom = StringWriter()
70+
KtXmlWriter(fromDom, xmlDeclMode = XmlDeclMode.None).use { writer ->
71+
xmlStreaming.newReader(domWriter.target).use { reader ->
72+
while (reader.hasNext()) {
73+
reader.next()
74+
reader.writeCurrent(writer)
75+
}
7276
}
7377
}
78+
assertXmlEquals(expectedXml, fromDom.toString())
7479
}
75-
assertXmlEquals(expectedXml, fromDom.toString())
7680
}
7781

7882
@Test

core/base/src/commonTest/kotlin/nl/adaptivity/xmlutil/TestXmlWriter.kt

+22-18
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
package nl.adaptivity.xmlutil
2222

2323
import nl.adaptivity.xmlutil.core.impl.multiplatform.use
24+
import nl.adaptivity.xmlutil.test.multiplatform.Target
25+
import nl.adaptivity.xmlutil.test.multiplatform.testTarget
2426
import nl.adaptivity.xmlutil.util.CompactFragment
2527
import kotlin.test.Test
2628
import kotlin.test.assertEquals
@@ -225,28 +227,30 @@ class TestXmlWriter {
225227

226228
@Test
227229
fun testWriteDomSmartTag() {
228-
val expected = "<a xmlns=\"ns/a\"><b xmlns=\"ns/b\"><c xmlns=\"\" val=\"value\"/></b></a>"
229-
val builder = StringBuilder()
230-
val dw = DomWriter()
231-
dw.let { out ->
232-
out.smartStartTag("ns/a", "a", "") {
233-
smartStartTag("ns/b", "b", "") {
234-
smartStartTag("", "c", "")
235-
attribute("", "val", "", "value")
236-
endTag("", "c", "")
230+
if (testTarget != Target.Node) {
231+
val expected = "<a xmlns=\"ns/a\"><b xmlns=\"ns/b\"><c xmlns=\"\" val=\"value\"/></b></a>"
232+
val builder = StringBuilder()
233+
val dw = DomWriter()
234+
dw.let { out ->
235+
out.smartStartTag("ns/a", "a", "") {
236+
smartStartTag("ns/b", "b", "") {
237+
smartStartTag("", "c", "")
238+
attribute("", "val", "", "value")
239+
endTag("", "c", "")
240+
}
237241
}
238242
}
239-
}
240-
xmlStreaming.newWriter(builder, false).use { out ->
241-
val input = xmlStreaming.newReader(dw.target)
242-
while (input.hasNext()) {
243-
input.next()
244-
if (! input.eventType.isIgnorable)
245-
input.writeCurrent(out)
243+
xmlStreaming.newWriter(builder, false).use { out ->
244+
val input = xmlStreaming.newReader(dw.target)
245+
while (input.hasNext()) {
246+
input.next()
247+
if (!input.eventType.isIgnorable)
248+
input.writeCurrent(out)
249+
}
246250
}
247-
}
248251

249-
assertEquals(expected, builder.toString().replace(" />", "/>"))
252+
assertEquals(expected, builder.toString().replace(" />", "/>"))
253+
}
250254

251255
}
252256

core/base/src/jsMain/kotlin/nl/adaptivity/xmlutil/XmlStreaming.js.kt

+6
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ public actual object XmlStreaming : IXmlStreaming {
7171
}
7272

7373
public actual override fun newReader(input: CharSequence): XmlReader {
74+
// fall back to generic reader for contexts without DOM (Node etc.)
75+
if (jsTypeOf(js("DOMParser")) == "undefined") return newGenericReader(input)
76+
7477
val str = when { // Ignore initial BOM (it parses incorrectly without exception)
7578
input[0] == '\ufeff' -> input.subSequence(1, input.length)
7679
else -> input
@@ -100,6 +103,9 @@ public actual object XmlStreaming : IXmlStreaming {
100103
repairNamespaces: Boolean /*= false*/,
101104
xmlDeclMode: XmlDeclMode /*= XmlDeclMode.None*/,
102105
): XmlWriter {
106+
// fall back to generic reader for contexts without DOM (Node etc.)
107+
if (jsTypeOf(js("DOMParser")) == "undefined") return newGenericWriter(output, repairNamespaces, xmlDeclMode)
108+
103109
return AppendingWriter(output, DomWriter(xmlDeclMode))
104110
}
105111

core/base/src/jsMain/kotlin/nl/adaptivity/xmlutil/core/impl/dom/DOMImplementationImpl.kt

+7-1
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,17 @@ import nl.adaptivity.xmlutil.core.impl.idom.IDOMImplementation
2525
import nl.adaptivity.xmlutil.core.impl.idom.IDocument
2626
import nl.adaptivity.xmlutil.core.impl.idom.IDocumentType
2727
import org.w3c.dom.DOMImplementation
28+
import org.w3c.dom.parsing.DOMParser
2829
import nl.adaptivity.xmlutil.dom.DOMImplementation as DOMImplementation1
2930
import nl.adaptivity.xmlutil.dom.DocumentType as DocumentType1
3031

3132
internal object DOMImplementationImpl : IDOMImplementation {
32-
val delegate: DOMImplementation get() = document.implementation
33+
val delegate: DOMImplementation by lazy {
34+
when (document) {
35+
null -> DOMParser().parseFromString("<root></root>", "text/xml").implementation
36+
else -> document.implementation
37+
}
38+
}
3339

3440
override val supportsWhitespaceAtToplevel: Boolean get() = true
3541

testutil/api/testutil.api

+16
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,19 @@ public abstract class nl/adaptivity/xmlutil/test/TestCommonReader {
4242
public fun testWhiteSpaceWithEntity ()V
4343
}
4444

45+
public final class nl/adaptivity/xmlutil/test/multiplatform/Platform_commonJvmKt {
46+
public static final fun getTestTarget ()Lnl/adaptivity/xmlutil/test/multiplatform/Target;
47+
}
48+
49+
public final class nl/adaptivity/xmlutil/test/multiplatform/Target : java/lang/Enum {
50+
public static final field Browser Lnl/adaptivity/xmlutil/test/multiplatform/Target;
51+
public static final field Java Lnl/adaptivity/xmlutil/test/multiplatform/Target;
52+
public static final field Native Lnl/adaptivity/xmlutil/test/multiplatform/Target;
53+
public static final field Node Lnl/adaptivity/xmlutil/test/multiplatform/Target;
54+
public static final field Wasi Lnl/adaptivity/xmlutil/test/multiplatform/Target;
55+
public static final field Wasm Lnl/adaptivity/xmlutil/test/multiplatform/Target;
56+
public static fun getEntries ()Lkotlin/enums/EnumEntries;
57+
public static fun valueOf (Ljava/lang/String;)Lnl/adaptivity/xmlutil/test/multiplatform/Target;
58+
public static fun values ()[Lnl/adaptivity/xmlutil/test/multiplatform/Target;
59+
}
60+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright (c) 2025.
3+
*
4+
* This file is part of xmlutil.
5+
*
6+
* This file is licenced to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You should have received a copy of the license with the source distribution.
9+
* Alternatively, you may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing,
14+
* software distributed under the License is distributed on an
15+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
* KIND, either express or implied. See the License for the
17+
* specific language governing permissions and limitations
18+
* under the License.
19+
*/
20+
21+
package nl.adaptivity.xmlutil.test.multiplatform
22+
23+
actual val testTarget: Target
24+
get() = Target.Java

0 commit comments

Comments
 (0)