jsx icon indicating copy to clipboard operation
jsx copied to clipboard

RFC: Standardizing `$:` namespace escaping

Open iMrDJAi opened this issue 1 year ago • 0 comments

RFC: Standardizing $: namespace escaping

Intro

JSX has proven to be very useful when it's about writing clients for XML-based APIs. It allows constructing XML requests while keeping all the JSX templating features and syntax highlighting. My company uses this approach to communicate with our different hotel/flight suppliers that provide XML API interfaces, which is quite common in the travel industry.

To achieve all of that, we have developed our custom automatic JSX runtime (xml-jsx-runtime) that takes care of transforming the JSX syntax into XML strings.

Problem

During the development of our JSX runtime, we have run into some limitations concerning the JSX standard itself:

  • children attribute name is reserved by JSX to pass child elements. Thus, we cannot specify it in elements.
  • Elements cannot have capitalized tag names since they are treated as value-based elements.

These issues render JSX unusable in certain scenarios.

Proposal

Fortunately, a solution was found! Our technique uses a special namespace that helps escaping such forbidden tag/attribute names. We have chosen $: due to the following considerations:

  • The $ character is not valid in a namespace prefix according to the XML standard, but JSX supports it. Thus, it is meaningless and can be ignored by the parser (Not a breaking change).
  • $: is short, simple, and easy to type, which makes it a great choice for the purpose.

By adopting this, JSX will be able to process Capitalized tag names and reserved attributes by default.

Demonstration

Take a look at these examples from the xml-jsx-runtime README:

/** @jsxImportSource xml-jsx-runtime/runtime */
import { js2xml } from 'xml-js'

const xml = js2xml(
  <room adults={2} $:children={1} />
  /**
   * Or
   * <room adults={2} {...{'$:children': 1}} />
   * if you environment doesn't support XML namespaces
   */
)

console.log(xml)
/** Output:
 * <room adults="2" children="1"/>
 */
/** @jsxImportSource xml-jsx-runtime/runtime */
import { js2xml } from 'xml-js'

const xml = js2xml(
  <$:Element />
)

console.log(xml)
/** Output:
 * <Element />
 */

iMrDJAi avatar Mar 14 '24 14:03 iMrDJAi