nwsapi icon indicating copy to clipboard operation
nwsapi copied to clipboard

:scope not working when the context has a class name that uses special characters

Open jordimarimon opened this issue 11 months ago • 3 comments

Minimal example that breaks in the latest nwsapi (I have downloaded the nwsapi.js file from github today):

<!DOCTYPE html>
<html lang="en">
	<head>
		<title>test nwsapi</title>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1">
		<style>
			@media (min-width: 768px) {
				.md\:p-4 {
					padding: 1rem;
				}
			}
		</style>
	</head>
	<body class="md:p-4">

		<div data-test="foo"></div>

		<script type="text/javascript" src="nwsapi.js" onload="NW.Dom.install()"></script>

		<script>
			console.log(document.body.querySelector(":scope > [data-test=\"foo\"]"));
		</script>>

	</body>
</html>

This throws Uncaught DOMException: unknown pseudo-class selector ':p-4>[data-test="foo"]' but if I try the query selector API provided by the browser it works.

I'm using tailwind which makes use of special characters in the class names and I was running tests with jest using jsdom as the environment and it's when I encounter the error.

Is this use case something that nwsapi would be open to support?

I will try to help by finding out how this could be fixed and in case that I do find it, I could open a PR if it's okay?

jordimarimon avatar Mar 05 '24 18:03 jordimarimon

I think I have found where the error is thrown:

https://github.com/dperini/nwsapi/blob/master/src/nwsapi.js#L896-L1277

I think it's because :p-4 is not a valid pseudo class. If I were open to help, does nwsapi would want to support class names that use :?

jordimarimon avatar Mar 05 '24 20:03 jordimarimon

After looking more into it, I have found one possible solution, although maybe it's not the way you want to approach this.

I have added in the makeref implementation to escape the class name:

// replace ':scope' pseudo-class with element references
  makeref =
    function(selectors, element) {
      // DOCUMENT_NODE (9)
      if (element.nodeType === 9) {
        element = element.documentElement;
      }

      return selectors.replace(/:scope/ig,
        element.localName +
        (element.id ? '#' + element.id : '') +
        (element.className ? '.' + escape(element.classList[0]) : ''));
    },

  // This is not the correct way to escape special characters in an identifier, it's just a proof of concept
  escape = function(string) {
    return string.replace(/[!"#$%&'()*+,./;<=>?@\[\\\]^`{|}~\t\n\v\f:]/, match => '\\' + match);
  },

Because when using :scope in the selector, the class name is being retrieved from the DOM, it's not properly escaped.

I think nwsapi should escape the class name when replacing :scope. Also, the id may need to be escaped as well.

jordimarimon avatar Mar 06 '24 06:03 jordimarimon

@jordimarimon thank you so much for the contribution. Like you did, I would have also escaped special characters

This fix will be in next revision. I will commit as soon as I am back to my desk. By an unlucky accident nwsapi-2.2.8 should be postponed for almost two more weeks.

dperini avatar Mar 08 '24 05:03 dperini