This is an example implementation of a Literal JSX parser, built with nearley.js + moo.
Literal JSX is a lightweight format for interchanging content structures potentially rich in shape and data. It extends JSON by adding an "Element" node type, which is shaped as JSX, but which can only contain literal (JSON) data structures. For more information, see http://literal-jsx.org/.
import {
// converts LJSX to an AST similar to Babel's output
parseAST,
// converts LJSX directly to a value
// (you can optionally pass it a component hydration factory)
parseValue,
// create a moo lexer like the one used under the hood
makeLexer,
// the nearley.js generated grammar
grammar,
// for if you want to stream feed the nearley.js parser
Parser
} from "literal-jsx";
Note: line/col numbers come from moo, and are 1-based; offsets are 0-based.
Literal JSX is a conservative extension of JSON, so in particular, it will parse any JSON data structure.
parseValue(`{ "normal": ["json", "data"] }`);
// { normal: ["json", "data"] }
Parse some typical JSX. By default, JSX elements are described by nodes of the shape { _JSXElement: true, name, attributes, children }
.
parseValue(`<Button size="large" primary>Hi {"there"}</Button>`);
// { _JSXElement: true,
// name: "Button",
// attributes: { size: "large", primary: true },
// children: ["Hi ", "there"] }
If you pass it a factory function (such as a simple wrapper around React.createElement
that does a component lookup by name), it will use that factory function to hydrate the JSX. For example:
const components = {
Button,
NavBar
};
const h = (name, attrs, ...children) =>
React.createElement(components[name] || name, attrs, ...children);
parseValue(`<Button size="large" primary>Hi {"there"}</Button>`, h);
// React.createElement(Button, { size: "large", primary: true }, "Hi ", "there")