| module.exports = function (fork) { |
| fork.use(require("./es7")); |
| |
| var types = fork.use(require("../lib/types")); |
| var def = types.Type.def; |
| var or = types.Type.or; |
| var defaults = fork.use(require("../lib/shared")).defaults; |
| |
| def("JSXAttribute") |
| .bases("Node") |
| .build("name", "value") |
| .field("name", or(def("JSXIdentifier"), def("JSXNamespacedName"))) |
| .field("value", or( |
| def("Literal"), // attr="value" |
| def("JSXExpressionContainer"), // attr={value} |
| null // attr= or just attr |
| ), defaults["null"]); |
| |
| def("JSXIdentifier") |
| .bases("Identifier") |
| .build("name") |
| .field("name", String); |
| |
| def("JSXNamespacedName") |
| .bases("Node") |
| .build("namespace", "name") |
| .field("namespace", def("JSXIdentifier")) |
| .field("name", def("JSXIdentifier")); |
| |
| def("JSXMemberExpression") |
| .bases("MemberExpression") |
| .build("object", "property") |
| .field("object", or(def("JSXIdentifier"), def("JSXMemberExpression"))) |
| .field("property", def("JSXIdentifier")) |
| .field("computed", Boolean, defaults.false); |
| |
| var JSXElementName = or( |
| def("JSXIdentifier"), |
| def("JSXNamespacedName"), |
| def("JSXMemberExpression") |
| ); |
| |
| def("JSXSpreadAttribute") |
| .bases("Node") |
| .build("argument") |
| .field("argument", def("Expression")); |
| |
| var JSXAttributes = [or( |
| def("JSXAttribute"), |
| def("JSXSpreadAttribute") |
| )]; |
| |
| def("JSXExpressionContainer") |
| .bases("Expression") |
| .build("expression") |
| .field("expression", def("Expression")); |
| |
| def("JSXElement") |
| .bases("Expression") |
| .build("openingElement", "closingElement", "children") |
| .field("openingElement", def("JSXOpeningElement")) |
| .field("closingElement", or(def("JSXClosingElement"), null), defaults["null"]) |
| .field("children", [or( |
| def("JSXElement"), |
| def("JSXExpressionContainer"), |
| def("JSXText"), |
| def("Literal") // TODO Esprima should return JSXText instead. |
| )], defaults.emptyArray) |
| .field("name", JSXElementName, function () { |
| // Little-known fact: the `this` object inside a default function |
| // is none other than the partially-built object itself, and any |
| // fields initialized directly from builder function arguments |
| // (like openingElement, closingElement, and children) are |
| // guaranteed to be available. |
| return this.openingElement.name; |
| }, true) // hidden from traversal |
| .field("selfClosing", Boolean, function () { |
| return this.openingElement.selfClosing; |
| }, true) // hidden from traversal |
| .field("attributes", JSXAttributes, function () { |
| return this.openingElement.attributes; |
| }, true); // hidden from traversal |
| |
| def("JSXOpeningElement") |
| .bases("Node") // TODO Does this make sense? Can't really be an JSXElement. |
| .build("name", "attributes", "selfClosing") |
| .field("name", JSXElementName) |
| .field("attributes", JSXAttributes, defaults.emptyArray) |
| .field("selfClosing", Boolean, defaults["false"]); |
| |
| def("JSXClosingElement") |
| .bases("Node") // TODO Same concern. |
| .build("name") |
| .field("name", JSXElementName); |
| |
| def("JSXText") |
| .bases("Literal") |
| .build("value") |
| .field("value", String); |
| |
| def("JSXEmptyExpression").bases("Expression").build(); |
| |
| }; |