Repository: FontoXML/fontoxpath
Pull request #515 (2022-07-28 14:58:57)

Improve trace message
Do note that I've changed the following to our trace logging:
* Nodes are now serialized if a serialized is provided in the options
* We now log the type (and now type string) of the original value instead of the atomized value which was always cast to a string.

bundlemon[bot]: <!-- bundlemon -->
## BundleMon

  
  
  
  
  
  
  
<details>
<summary>Unchanged files (2)</summary>

Status | Path | Size | Limits
:------------: | ------------ | :------------: | :------------:
:white_check_mark: | fontoxpath.esm.js<br/> | 81.74KB | -
:white_check_mark: | fontoxpath.js<br/> | 81.63KB | -
</details>



Total files change -3B 0%

Final result: :white_check_mark:

[View report in BundleMon website ➡️](https://app.bundlemon.dev/projects/609024effb87a20009a6b096/reports/62e2a4903fb16506948016d5)

---
<p align="center"><a href="https://app.bundlemon.dev/projects/609024effb87a20009a6b096/reports?branch=improve-trace&resolution=all" target="_blank" rel="noreferrer noopener">Current branch size history</a> | <a href="https://app.bundlemon.dev/projects/609024effb87a20009a6b096/reports?branch=master&resolution=days" target="_blank" rel="noreferrer noopener">Target branch size history</a></p>
coveralls: 
[![Coverage Status](https://coveralls.io/builds/51239215/badge)](https://coveralls.io/builds/51239215)

Coverage increased (+0.005%) to 91.127% when pulling **878ffb1ffe19a12e89733092bf4326f31e5586cf on improve-trace** into **1e1346ccd14a2fdb1138e53b05a12d44e98aa152 on master**.


Patch:
diff --git a/demo/main.ts b/demo/main.ts
index 8ed28435..ec3e426e 100644
--- a/demo/main.ts
+++ b/demo/main.ts
@@ -176,6 +176,7 @@ async function runUpdatingXQuery(script: string) {
 				console.log(m);
 			},
 		},
+		xmlSerializer: new XMLSerializer(),
 	});
 
 	resultText.innerText = JSON.stringify(result, jsonXmlReplacer, '  ');
@@ -197,6 +198,7 @@ async function runNormalXPath(script: string, asXQuery: boolean) {
 				console.log(m);
 			},
 		},
+		xmlSerializer: new XMLSerializer(),
 	});
 
 	for (let item = await it.next(); !item.done; item = await it.next()) {
diff --git a/src/evaluateUpdatingExpression.ts b/src/evaluateUpdatingExpression.ts
index d2f2f662..e866e78b 100644
--- a/src/evaluateUpdatingExpression.ts
+++ b/src/evaluateUpdatingExpression.ts
@@ -13,7 +13,7 @@ import UpdatingExpressionResult from './expressions/UpdatingExpressionResult';
 import { IterationHint, IterationResult } from './expressions/util/iterators';
 import INodesFactory from './nodesFactory/INodesFactory';
 import { ReturnType } from './parsing/convertXDMReturnValue';
-import { Language, Logger } from './types/Options';
+import { Language, Logger, XMLSerializer } from './types/Options';
 
 /**
  * Type that contains a collection of options for the updating expression exaluation.
@@ -28,6 +28,7 @@ import { Language, Logger } from './types/Options';
  * namespaceResolver		- Callback to do namespace resolving.
  * nodesFactory				- Reference to a nodes factory object.
  * returnType				- The type that the evaluation function will return.
+ * xmlSerializer			- An XML serializer that can serialize nodes. Used when the `fn:serialize` function is called with a node.
  */
 export type UpdatingOptions = {
 	debug?: boolean;
@@ -38,6 +39,7 @@ export type UpdatingOptions = {
 	namespaceResolver?: (s: string) => string | null;
 	nodesFactory?: INodesFactory;
 	returnType?: ReturnType;
+	xmlSerializer?: XMLSerializer;
 };
 
 /**
diff --git a/src/expressions/functions/builtInFunctions_debugging.ts b/src/expressions/functions/builtInFunctions_debugging.ts
index 4e0c6bf9..efc5e1dc 100644
--- a/src/expressions/functions/builtInFunctions_debugging.ts
+++ b/src/expressions/functions/builtInFunctions_debugging.ts
@@ -1,7 +1,10 @@
+import { NodePointer } from '../../domClone/Pointer';
+import realizeDom from '../../domClone/realizeDom';
 import atomize from '../dataTypes/atomize';
 import castToType from '../dataTypes/castToType';
+import isSubtypeOf from '../dataTypes/isSubtypeOf';
 import sequenceFactory from '../dataTypes/sequenceFactory';
-import { SequenceMultiplicity, ValueType } from '../dataTypes/Value';
+import { SequenceMultiplicity, ValueType, valueTypeToString } from '../dataTypes/Value';
 import { BUILT_IN_NAMESPACE_URIS } from '../staticallyKnownNamespaces';
 import { BuiltinDeclarationType } from './builtInFunctions';
 import FunctionDefinitionType from './FunctionDefinitionType';
@@ -14,18 +17,23 @@ const fnTrace: FunctionDefinitionType = (
 	label
 ) => {
 	return arg.mapAll((allItems) => {
-		const argumentAsStrings = atomize(sequenceFactory.create(allItems), executionParameters)
-			.map((value) => castToType(value, ValueType.XSSTRING))
-			.getAllValues();
-
 		let newMessage = '';
-		for (let i = 0; i < argumentAsStrings.length; i++) {
-			newMessage +=
-				'{type: ' +
-				argumentAsStrings[i].type +
-				', value: ' +
-				argumentAsStrings[i].value +
-				'}\n';
+		for (let i = 0; i < allItems.length; i++) {
+			const value = allItems[i];
+			const argumentAsString =
+				executionParameters.xmlSerializer && isSubtypeOf(value.type, ValueType.NODE)
+					? executionParameters.xmlSerializer.serializeToString(
+							realizeDom(
+								value.value as NodePointer,
+								executionParameters,
+								false
+							) as Node
+					  )
+					: atomize(sequenceFactory.singleton(value), executionParameters)
+							.map((atomizedValue) => castToType(atomizedValue, ValueType.XSSTRING))
+							.first().value;
+
+			newMessage += `{type: ${valueTypeToString(value.type)}, value: ${argumentAsString}}\n`;
 		}
 		if (label !== undefined) {
 			newMessage += label.first().value;
diff --git a/src/types/Options.ts b/src/types/Options.ts
index d2515780..07fc2fa1 100644
--- a/src/types/Options.ts
+++ b/src/types/Options.ts
@@ -57,7 +57,7 @@ export type FunctionNameResolver = (
 export type NamespaceResolver = (prefix: string) => string | null;
 
 /**
- * An XML serializer that can serialzie nodes. Used when the `fn:serialize` function is called with
+ * An XML serializer that can serialize nodes. Used when the `fn:serialize` function is called with
  * a node
  *
  * @public


Test patch:
diff --git a/test/specs/parsing/functions/functions.debugging.tests.ts b/test/specs/parsing/functions/functions.debugging.tests.ts
index 6129b5ee..3046e1ec 100644
--- a/test/specs/parsing/functions/functions.debugging.tests.ts
+++ b/test/specs/parsing/functions/functions.debugging.tests.ts
@@ -1,25 +1,52 @@
 import * as chai from 'chai';
 import { evaluateXPathToBoolean } from 'fontoxpath';
 import * as sinon from 'sinon';
+import * as slimdom from 'slimdom';
+import jsonMlMapper from 'test-helpers/jsonMlMapper';
 
 describe('debugging functions', () => {
 	describe('fn:trace', () => {
 		let consoleSpy = null;
+		let documentNode: slimdom.Document;
+
 		beforeEach(() => {
+			documentNode = new slimdom.Document();
 			consoleSpy = sinon.spy(console, 'log');
 		});
+
 		afterEach(() => {
 			if (consoleSpy) {
 				consoleSpy.restore();
 				consoleSpy = null;
 			}
 		});
+
 		it('returns the input', () => chai.assert.isTrue(evaluateXPathToBoolean('trace(true())')));
+
 		it('accepts two parameters', () =>
 			chai.assert.isTrue(evaluateXPathToBoolean('trace(true(), "message")')));
+
 		it('outputs the trace', () => {
 			evaluateXPathToBoolean('trace(true())');
 			chai.assert.isTrue(consoleSpy.called);
 		});
+
+		it('serializes nodes', () => {
+			jsonMlMapper.parse(['someElement', 'Some text.'], documentNode);
+			evaluateXPathToBoolean(
+				'trace((., 42, ./someElement/text()))',
+				documentNode,
+				undefined,
+				undefined,
+				{
+					xmlSerializer: new slimdom.XMLSerializer(),
+				}
+			);
+			chai.assert.isTrue(consoleSpy.called);
+			chai.assert.equal(
+				consoleSpy.args[0],
+				'{type: document-node(), value: <someElement>Some text.</someElement>}\n{type: xs:integer, value: 42}\n{type: text(), value: Some text.}\n'
+			);
+		});
 	});
 });