From 9da643aff4b86dbd60f81ed3d2f26105fd7f4ecd Mon Sep 17 00:00:00 2001 From: SaekiRaku Date: Sun, 31 May 2020 23:58:27 +0800 Subject: [PATCH 1/4] Add support for ES Module --- constructor/build.js | 21 ++ index.mjs | 765 +++++++++++++++++++++++++++++++++++++++++++ package.json | 8 +- 3 files changed, 792 insertions(+), 2 deletions(-) create mode 100644 constructor/build.js create mode 100644 index.mjs diff --git a/constructor/build.js b/constructor/build.js new file mode 100644 index 0000000..0a5d878 --- /dev/null +++ b/constructor/build.js @@ -0,0 +1,21 @@ +const path = require("path"); +const rollup = require("rollup/dist/rollup.js").rollup; +const commonjs = require("@rollup/plugin-commonjs"); + +const PATH_ROOT = path.resolve(__dirname, "../"); + +let inputOptions = { + input: path.resolve(PATH_ROOT, "index.js"), + plugins: [commonjs()], + external: ["acorn"] +} + +let outputOptions = { + output: { + file: path.resolve(PATH_ROOT, "index.mjs"), + format: "esm", + banner: "// DO NOT edit this file, it's auto generate from 'constructor/build.js', any changes will be overwrite. \n" + } +} + +rollup(inputOptions).then(bundle => bundle.write(outputOptions)); \ No newline at end of file diff --git a/index.mjs b/index.mjs new file mode 100644 index 0000000..2e37cf5 --- /dev/null +++ b/index.mjs @@ -0,0 +1,765 @@ +// DO NOT edit this file, it's auto generate from 'constructor/build.js', any changes will be overwrite. + +import acorn from 'acorn'; + +function createCommonjsModule(fn, basedir, module) { + return module = { + path: basedir, + exports: {}, + require: function (path, base) { + return commonjsRequire(path, (base === undefined || base === null) ? module.path : base); + } + }, fn(module, module.exports), module.exports; +} + +function commonjsRequire () { + throw new Error('Dynamic requires are not currently supported by @rollup/plugin-commonjs'); +} + +var xhtml = { + quot: '\u0022', + amp: '&', + apos: '\u0027', + lt: '<', + gt: '>', + nbsp: '\u00A0', + iexcl: '\u00A1', + cent: '\u00A2', + pound: '\u00A3', + curren: '\u00A4', + yen: '\u00A5', + brvbar: '\u00A6', + sect: '\u00A7', + uml: '\u00A8', + copy: '\u00A9', + ordf: '\u00AA', + laquo: '\u00AB', + not: '\u00AC', + shy: '\u00AD', + reg: '\u00AE', + macr: '\u00AF', + deg: '\u00B0', + plusmn: '\u00B1', + sup2: '\u00B2', + sup3: '\u00B3', + acute: '\u00B4', + micro: '\u00B5', + para: '\u00B6', + middot: '\u00B7', + cedil: '\u00B8', + sup1: '\u00B9', + ordm: '\u00BA', + raquo: '\u00BB', + frac14: '\u00BC', + frac12: '\u00BD', + frac34: '\u00BE', + iquest: '\u00BF', + Agrave: '\u00C0', + Aacute: '\u00C1', + Acirc: '\u00C2', + Atilde: '\u00C3', + Auml: '\u00C4', + Aring: '\u00C5', + AElig: '\u00C6', + Ccedil: '\u00C7', + Egrave: '\u00C8', + Eacute: '\u00C9', + Ecirc: '\u00CA', + Euml: '\u00CB', + Igrave: '\u00CC', + Iacute: '\u00CD', + Icirc: '\u00CE', + Iuml: '\u00CF', + ETH: '\u00D0', + Ntilde: '\u00D1', + Ograve: '\u00D2', + Oacute: '\u00D3', + Ocirc: '\u00D4', + Otilde: '\u00D5', + Ouml: '\u00D6', + times: '\u00D7', + Oslash: '\u00D8', + Ugrave: '\u00D9', + Uacute: '\u00DA', + Ucirc: '\u00DB', + Uuml: '\u00DC', + Yacute: '\u00DD', + THORN: '\u00DE', + szlig: '\u00DF', + agrave: '\u00E0', + aacute: '\u00E1', + acirc: '\u00E2', + atilde: '\u00E3', + auml: '\u00E4', + aring: '\u00E5', + aelig: '\u00E6', + ccedil: '\u00E7', + egrave: '\u00E8', + eacute: '\u00E9', + ecirc: '\u00EA', + euml: '\u00EB', + igrave: '\u00EC', + iacute: '\u00ED', + icirc: '\u00EE', + iuml: '\u00EF', + eth: '\u00F0', + ntilde: '\u00F1', + ograve: '\u00F2', + oacute: '\u00F3', + ocirc: '\u00F4', + otilde: '\u00F5', + ouml: '\u00F6', + divide: '\u00F7', + oslash: '\u00F8', + ugrave: '\u00F9', + uacute: '\u00FA', + ucirc: '\u00FB', + uuml: '\u00FC', + yacute: '\u00FD', + thorn: '\u00FE', + yuml: '\u00FF', + OElig: '\u0152', + oelig: '\u0153', + Scaron: '\u0160', + scaron: '\u0161', + Yuml: '\u0178', + fnof: '\u0192', + circ: '\u02C6', + tilde: '\u02DC', + Alpha: '\u0391', + Beta: '\u0392', + Gamma: '\u0393', + Delta: '\u0394', + Epsilon: '\u0395', + Zeta: '\u0396', + Eta: '\u0397', + Theta: '\u0398', + Iota: '\u0399', + Kappa: '\u039A', + Lambda: '\u039B', + Mu: '\u039C', + Nu: '\u039D', + Xi: '\u039E', + Omicron: '\u039F', + Pi: '\u03A0', + Rho: '\u03A1', + Sigma: '\u03A3', + Tau: '\u03A4', + Upsilon: '\u03A5', + Phi: '\u03A6', + Chi: '\u03A7', + Psi: '\u03A8', + Omega: '\u03A9', + alpha: '\u03B1', + beta: '\u03B2', + gamma: '\u03B3', + delta: '\u03B4', + epsilon: '\u03B5', + zeta: '\u03B6', + eta: '\u03B7', + theta: '\u03B8', + iota: '\u03B9', + kappa: '\u03BA', + lambda: '\u03BB', + mu: '\u03BC', + nu: '\u03BD', + xi: '\u03BE', + omicron: '\u03BF', + pi: '\u03C0', + rho: '\u03C1', + sigmaf: '\u03C2', + sigma: '\u03C3', + tau: '\u03C4', + upsilon: '\u03C5', + phi: '\u03C6', + chi: '\u03C7', + psi: '\u03C8', + omega: '\u03C9', + thetasym: '\u03D1', + upsih: '\u03D2', + piv: '\u03D6', + ensp: '\u2002', + emsp: '\u2003', + thinsp: '\u2009', + zwnj: '\u200C', + zwj: '\u200D', + lrm: '\u200E', + rlm: '\u200F', + ndash: '\u2013', + mdash: '\u2014', + lsquo: '\u2018', + rsquo: '\u2019', + sbquo: '\u201A', + ldquo: '\u201C', + rdquo: '\u201D', + bdquo: '\u201E', + dagger: '\u2020', + Dagger: '\u2021', + bull: '\u2022', + hellip: '\u2026', + permil: '\u2030', + prime: '\u2032', + Prime: '\u2033', + lsaquo: '\u2039', + rsaquo: '\u203A', + oline: '\u203E', + frasl: '\u2044', + euro: '\u20AC', + image: '\u2111', + weierp: '\u2118', + real: '\u211C', + trade: '\u2122', + alefsym: '\u2135', + larr: '\u2190', + uarr: '\u2191', + rarr: '\u2192', + darr: '\u2193', + harr: '\u2194', + crarr: '\u21B5', + lArr: '\u21D0', + uArr: '\u21D1', + rArr: '\u21D2', + dArr: '\u21D3', + hArr: '\u21D4', + forall: '\u2200', + part: '\u2202', + exist: '\u2203', + empty: '\u2205', + nabla: '\u2207', + isin: '\u2208', + notin: '\u2209', + ni: '\u220B', + prod: '\u220F', + sum: '\u2211', + minus: '\u2212', + lowast: '\u2217', + radic: '\u221A', + prop: '\u221D', + infin: '\u221E', + ang: '\u2220', + and: '\u2227', + or: '\u2228', + cap: '\u2229', + cup: '\u222A', + 'int': '\u222B', + there4: '\u2234', + sim: '\u223C', + cong: '\u2245', + asymp: '\u2248', + ne: '\u2260', + equiv: '\u2261', + le: '\u2264', + ge: '\u2265', + sub: '\u2282', + sup: '\u2283', + nsub: '\u2284', + sube: '\u2286', + supe: '\u2287', + oplus: '\u2295', + otimes: '\u2297', + perp: '\u22A5', + sdot: '\u22C5', + lceil: '\u2308', + rceil: '\u2309', + lfloor: '\u230A', + rfloor: '\u230B', + lang: '\u2329', + rang: '\u232A', + loz: '\u25CA', + spades: '\u2660', + clubs: '\u2663', + hearts: '\u2665', + diams: '\u2666' +}; + +var acornJsx = createCommonjsModule(function (module) { + + + +const hexNumber = /^[\da-fA-F]+$/; +const decimalNumber = /^\d+$/; + +// The map to `acorn-jsx` tokens from `acorn` namespace objects. +const acornJsxMap = new WeakMap(); + +// Get the original tokens for the given `acorn` namespace object. +function getJsxTokens(acorn) { + acorn = acorn.Parser.acorn || acorn; + let acornJsx = acornJsxMap.get(acorn); + if (!acornJsx) { + const tt = acorn.tokTypes; + const TokContext = acorn.TokContext; + const TokenType = acorn.TokenType; + const tc_oTag = new TokContext('...', true, true); + const tokContexts = { + tc_oTag: tc_oTag, + tc_cTag: tc_cTag, + tc_expr: tc_expr + }; + const tokTypes = { + jsxName: new TokenType('jsxName'), + jsxText: new TokenType('jsxText', {beforeExpr: true}), + jsxTagStart: new TokenType('jsxTagStart'), + jsxTagEnd: new TokenType('jsxTagEnd') + }; + + tokTypes.jsxTagStart.updateContext = function() { + this.context.push(tc_expr); // treat as beginning of JSX expression + this.context.push(tc_oTag); // start opening tag context + this.exprAllowed = false; + }; + tokTypes.jsxTagEnd.updateContext = function(prevType) { + let out = this.context.pop(); + if (out === tc_oTag && prevType === tt.slash || out === tc_cTag) { + this.context.pop(); + this.exprAllowed = this.curContext() === tc_expr; + } else { + this.exprAllowed = true; + } + }; + + acornJsx = { tokContexts: tokContexts, tokTypes: tokTypes }; + acornJsxMap.set(acorn, acornJsx); + } + + return acornJsx; +} + +// Transforms JSX element name to string. + +function getQualifiedJSXName(object) { + if (!object) + return object; + + if (object.type === 'JSXIdentifier') + return object.name; + + if (object.type === 'JSXNamespacedName') + return object.namespace.name + ':' + object.name.name; + + if (object.type === 'JSXMemberExpression') + return getQualifiedJSXName(object.object) + '.' + + getQualifiedJSXName(object.property); +} + +module.exports = function(options) { + options = options || {}; + return function(Parser) { + return plugin({ + allowNamespaces: options.allowNamespaces !== false, + allowNamespacedObjects: !!options.allowNamespacedObjects + }, Parser); + }; +}; + +// This is `tokTypes` of the peer dep. +// This can be different instances from the actual `tokTypes` this plugin uses. +Object.defineProperty(module.exports, "tokTypes", { + get: function get_tokTypes() { + return getJsxTokens(acorn).tokTypes; + }, + configurable: true, + enumerable: true +}); + +function plugin(options, Parser) { + const acorn$1 = Parser.acorn || acorn; + const acornJsx = getJsxTokens(acorn$1); + const tt = acorn$1.tokTypes; + const tok = acornJsx.tokTypes; + const tokContexts = acorn$1.tokContexts; + const tc_oTag = acornJsx.tokContexts.tc_oTag; + const tc_cTag = acornJsx.tokContexts.tc_cTag; + const tc_expr = acornJsx.tokContexts.tc_expr; + const isNewLine = acorn$1.isNewLine; + const isIdentifierStart = acorn$1.isIdentifierStart; + const isIdentifierChar = acorn$1.isIdentifierChar; + + return class extends Parser { + // Expose actual `tokTypes` and `tokContexts` to other plugins. + static get acornJsx() { + return acornJsx; + } + + // Reads inline JSX contents token. + jsx_readToken() { + let out = '', chunkStart = this.pos; + for (;;) { + if (this.pos >= this.input.length) + this.raise(this.start, 'Unterminated JSX contents'); + let ch = this.input.charCodeAt(this.pos); + + switch (ch) { + case 60: // '<' + case 123: // '{' + if (this.pos === this.start) { + if (ch === 60 && this.exprAllowed) { + ++this.pos; + return this.finishToken(tok.jsxTagStart); + } + return this.getTokenFromCode(ch); + } + out += this.input.slice(chunkStart, this.pos); + return this.finishToken(tok.jsxText, out); + + case 38: // '&' + out += this.input.slice(chunkStart, this.pos); + out += this.jsx_readEntity(); + chunkStart = this.pos; + break; + + case 62: // '>' + case 125: // '}' + this.raise( + this.pos, + "Unexpected token `" + this.input[this.pos] + "`. Did you mean `" + + (ch === 62 ? ">" : "}") + "` or " + "`{\"" + this.input[this.pos] + "\"}" + "`?" + ); + + default: + if (isNewLine(ch)) { + out += this.input.slice(chunkStart, this.pos); + out += this.jsx_readNewLine(true); + chunkStart = this.pos; + } else { + ++this.pos; + } + } + } + } + + jsx_readNewLine(normalizeCRLF) { + let ch = this.input.charCodeAt(this.pos); + let out; + ++this.pos; + if (ch === 13 && this.input.charCodeAt(this.pos) === 10) { + ++this.pos; + out = normalizeCRLF ? '\n' : '\r\n'; + } else { + out = String.fromCharCode(ch); + } + if (this.options.locations) { + ++this.curLine; + this.lineStart = this.pos; + } + + return out; + } + + jsx_readString(quote) { + let out = '', chunkStart = ++this.pos; + for (;;) { + if (this.pos >= this.input.length) + this.raise(this.start, 'Unterminated string constant'); + let ch = this.input.charCodeAt(this.pos); + if (ch === quote) break; + if (ch === 38) { // '&' + out += this.input.slice(chunkStart, this.pos); + out += this.jsx_readEntity(); + chunkStart = this.pos; + } else if (isNewLine(ch)) { + out += this.input.slice(chunkStart, this.pos); + out += this.jsx_readNewLine(false); + chunkStart = this.pos; + } else { + ++this.pos; + } + } + out += this.input.slice(chunkStart, this.pos++); + return this.finishToken(tt.string, out); + } + + jsx_readEntity() { + let str = '', count = 0, entity; + let ch = this.input[this.pos]; + if (ch !== '&') + this.raise(this.pos, 'Entity must start with an ampersand'); + let startPos = ++this.pos; + while (this.pos < this.input.length && count++ < 10) { + ch = this.input[this.pos++]; + if (ch === ';') { + if (str[0] === '#') { + if (str[1] === 'x') { + str = str.substr(2); + if (hexNumber.test(str)) + entity = String.fromCharCode(parseInt(str, 16)); + } else { + str = str.substr(1); + if (decimalNumber.test(str)) + entity = String.fromCharCode(parseInt(str, 10)); + } + } else { + entity = xhtml[str]; + } + break; + } + str += ch; + } + if (!entity) { + this.pos = startPos; + return '&'; + } + return entity; + } + + // Read a JSX identifier (valid tag or attribute name). + // + // Optimized version since JSX identifiers can't contain + // escape characters and so can be read as single slice. + // Also assumes that first character was already checked + // by isIdentifierStart in readToken. + + jsx_readWord() { + let ch, start = this.pos; + do { + ch = this.input.charCodeAt(++this.pos); + } while (isIdentifierChar(ch) || ch === 45); // '-' + return this.finishToken(tok.jsxName, this.input.slice(start, this.pos)); + } + + // Parse next token as JSX identifier + + jsx_parseIdentifier() { + let node = this.startNode(); + if (this.type === tok.jsxName) + node.name = this.value; + else if (this.type.keyword) + node.name = this.type.keyword; + else + this.unexpected(); + this.next(); + return this.finishNode(node, 'JSXIdentifier'); + } + + // Parse namespaced identifier. + + jsx_parseNamespacedName() { + let startPos = this.start, startLoc = this.startLoc; + let name = this.jsx_parseIdentifier(); + if (!options.allowNamespaces || !this.eat(tt.colon)) return name; + var node = this.startNodeAt(startPos, startLoc); + node.namespace = name; + node.name = this.jsx_parseIdentifier(); + return this.finishNode(node, 'JSXNamespacedName'); + } + + // Parses element name in any form - namespaced, member + // or single identifier. + + jsx_parseElementName() { + if (this.type === tok.jsxTagEnd) return ''; + let startPos = this.start, startLoc = this.startLoc; + let node = this.jsx_parseNamespacedName(); + if (this.type === tt.dot && node.type === 'JSXNamespacedName' && !options.allowNamespacedObjects) { + this.unexpected(); + } + while (this.eat(tt.dot)) { + let newNode = this.startNodeAt(startPos, startLoc); + newNode.object = node; + newNode.property = this.jsx_parseIdentifier(); + node = this.finishNode(newNode, 'JSXMemberExpression'); + } + return node; + } + + // Parses any type of JSX attribute value. + + jsx_parseAttributeValue() { + switch (this.type) { + case tt.braceL: + let node = this.jsx_parseExpressionContainer(); + if (node.expression.type === 'JSXEmptyExpression') + this.raise(node.start, 'JSX attributes must only be assigned a non-empty expression'); + return node; + + case tok.jsxTagStart: + case tt.string: + return this.parseExprAtom(); + + default: + this.raise(this.start, 'JSX value should be either an expression or a quoted JSX text'); + } + } + + // JSXEmptyExpression is unique type since it doesn't actually parse anything, + // and so it should start at the end of last read token (left brace) and finish + // at the beginning of the next one (right brace). + + jsx_parseEmptyExpression() { + let node = this.startNodeAt(this.lastTokEnd, this.lastTokEndLoc); + return this.finishNodeAt(node, 'JSXEmptyExpression', this.start, this.startLoc); + } + + // Parses JSX expression enclosed into curly brackets. + + jsx_parseExpressionContainer() { + let node = this.startNode(); + this.next(); + node.expression = this.type === tt.braceR + ? this.jsx_parseEmptyExpression() + : this.parseExpression(); + this.expect(tt.braceR); + return this.finishNode(node, 'JSXExpressionContainer'); + } + + // Parses following JSX attribute name-value pair. + + jsx_parseAttribute() { + let node = this.startNode(); + if (this.eat(tt.braceL)) { + this.expect(tt.ellipsis); + node.argument = this.parseMaybeAssign(); + this.expect(tt.braceR); + return this.finishNode(node, 'JSXSpreadAttribute'); + } + node.name = this.jsx_parseNamespacedName(); + node.value = this.eat(tt.eq) ? this.jsx_parseAttributeValue() : null; + return this.finishNode(node, 'JSXAttribute'); + } + + // Parses JSX opening tag starting after '<'. + + jsx_parseOpeningElementAt(startPos, startLoc) { + let node = this.startNodeAt(startPos, startLoc); + node.attributes = []; + let nodeName = this.jsx_parseElementName(); + if (nodeName) node.name = nodeName; + while (this.type !== tt.slash && this.type !== tok.jsxTagEnd) + node.attributes.push(this.jsx_parseAttribute()); + node.selfClosing = this.eat(tt.slash); + this.expect(tok.jsxTagEnd); + return this.finishNode(node, nodeName ? 'JSXOpeningElement' : 'JSXOpeningFragment'); + } + + // Parses JSX closing tag starting after ''); + } + } + let fragmentOrElement = openingElement.name ? 'Element' : 'Fragment'; + + node['opening' + fragmentOrElement] = openingElement; + node['closing' + fragmentOrElement] = closingElement; + node.children = children; + if (this.type === tt.relational && this.value === "<") { + this.raise(this.start, "Adjacent JSX elements must be wrapped in an enclosing tag"); + } + return this.finishNode(node, 'JSX' + fragmentOrElement); + } + + // Parse JSX text + + jsx_parseText() { + let node = this.parseLiteral(this.value); + node.type = "JSXText"; + return node; + } + + // Parses entire JSX element from current position. + + jsx_parseElement() { + let startPos = this.start, startLoc = this.startLoc; + this.next(); + return this.jsx_parseElementAt(startPos, startLoc); + } + + parseExprAtom(refShortHandDefaultPos) { + if (this.type === tok.jsxText) + return this.jsx_parseText(); + else if (this.type === tok.jsxTagStart) + return this.jsx_parseElement(); + else + return super.parseExprAtom(refShortHandDefaultPos); + } + + readToken(code) { + let context = this.curContext(); + + if (context === tc_expr) return this.jsx_readToken(); + + if (context === tc_oTag || context === tc_cTag) { + if (isIdentifierStart(code)) return this.jsx_readWord(); + + if (code == 62) { + ++this.pos; + return this.finishToken(tok.jsxTagEnd); + } + + if ((code === 34 || code === 39) && context == tc_oTag) + return this.jsx_readString(code); + } + + if (code === 60 && this.exprAllowed && this.input.charCodeAt(this.pos + 1) !== 33) { + ++this.pos; + return this.finishToken(tok.jsxTagStart); + } + return super.readToken(code); + } + + updateContext(prevType) { + if (this.type == tt.braceL) { + var curContext = this.curContext(); + if (curContext == tc_oTag) this.context.push(tokContexts.b_expr); + else if (curContext == tc_expr) this.context.push(tokContexts.b_tmpl); + else super.updateContext(prevType); + this.exprAllowed = true; + } else if (this.type === tt.slash && prevType === tok.jsxTagStart) { + this.context.length -= 2; // do not consider JSX expr -> JSX open tag -> ... anymore + this.context.push(tc_cTag); // reconsider as closing tag context + this.exprAllowed = false; + } else { + return super.updateContext(prevType); + } + } + }; +} +}); + +export default acornJsx; diff --git a/package.json b/package.json index 37fceab..5cd2868 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "description": "Modern, fast React.js JSX parser", "homepage": "https://github.com/acornjs/acorn-jsx", "version": "5.2.0", + "module": "index.mjs", "maintainers": [ { "name": "Ingvar Stepanyan", @@ -16,12 +17,15 @@ }, "license": "MIT", "scripts": { - "test": "node test/run.js" + "test": "node test/run.js", + "prepublishOnly": "node constructor/build.js" }, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0" }, "devDependencies": { - "acorn": "^7.0.0" + "@rollup/plugin-commonjs": "^12.0.0", + "acorn": "^7.0.0", + "rollup": "^2.12.0" } } From 9ff4c426cabc5a2c859590c54b54701fbf2ced15 Mon Sep 17 00:00:00 2001 From: SaekiRaku Date: Mon, 1 Jun 2020 10:15:46 +0800 Subject: [PATCH 2/4] Transoform all codes to ES6 import/export syntax, and generate CommonJS module by rollup. --- constructor/build.js | 10 ++++---- index.mjs => index.cjs.js | 48 ++++++++++++++------------------------- index.js | 19 ++++++++++++---- package.json | 8 ++++--- test/driver.js | 8 +++---- test/run.js | 10 ++++---- test/tests-jsx.js | 19 +++++++++++----- test/tests-misc.js | 17 +++++++++----- xhtml.js | 2 +- 9 files changed, 75 insertions(+), 66 deletions(-) rename index.mjs => index.cjs.js (95%) diff --git a/constructor/build.js b/constructor/build.js index 0a5d878..6e190cc 100644 --- a/constructor/build.js +++ b/constructor/build.js @@ -1,19 +1,17 @@ -const path = require("path"); -const rollup = require("rollup/dist/rollup.js").rollup; -const commonjs = require("@rollup/plugin-commonjs"); +import path from "path"; +import { rollup } from "rollup"; const PATH_ROOT = path.resolve(__dirname, "../"); let inputOptions = { input: path.resolve(PATH_ROOT, "index.js"), - plugins: [commonjs()], external: ["acorn"] } let outputOptions = { output: { - file: path.resolve(PATH_ROOT, "index.mjs"), - format: "esm", + file: path.resolve(PATH_ROOT, "index.cjs.js"), + format: "cjs", banner: "// DO NOT edit this file, it's auto generate from 'constructor/build.js', any changes will be overwrite. \n" } } diff --git a/index.mjs b/index.cjs.js similarity index 95% rename from index.mjs rename to index.cjs.js index 2e37cf5..fd0bd96 100644 --- a/index.mjs +++ b/index.cjs.js @@ -1,22 +1,10 @@ // DO NOT edit this file, it's auto generate from 'constructor/build.js', any changes will be overwrite. -import acorn from 'acorn'; - -function createCommonjsModule(fn, basedir, module) { - return module = { - path: basedir, - exports: {}, - require: function (path, base) { - return commonjsRequire(path, (base === undefined || base === null) ? module.path : base); - } - }, fn(module, module.exports), module.exports; -} +'use strict'; -function commonjsRequire () { - throw new Error('Dynamic requires are not currently supported by @rollup/plugin-commonjs'); -} +var acorn = require('acorn'); -var xhtml = { +var XHTMLEntities = { quot: '\u0022', amp: '&', apos: '\u0027', @@ -272,10 +260,6 @@ var xhtml = { diams: '\u2666' }; -var acornJsx = createCommonjsModule(function (module) { - - - const hexNumber = /^[\da-fA-F]+$/; const decimalNumber = /^\d+$/; @@ -344,7 +328,7 @@ function getQualifiedJSXName(object) { getQualifiedJSXName(object.property); } -module.exports = function(options) { +var acornJsx = function(options) { options = options || {}; return function(Parser) { return plugin({ @@ -356,7 +340,7 @@ module.exports = function(options) { // This is `tokTypes` of the peer dep. // This can be different instances from the actual `tokTypes` this plugin uses. -Object.defineProperty(module.exports, "tokTypes", { +Object.defineProperty(acornJsx, "tokTypes", { get: function get_tokTypes() { return getJsxTokens(acorn).tokTypes; }, @@ -364,18 +348,21 @@ Object.defineProperty(module.exports, "tokTypes", { enumerable: true }); +// let tokTypes = acornJsx.tokTypes; +// export { tokTypes }; + function plugin(options, Parser) { - const acorn$1 = Parser.acorn || acorn; - const acornJsx = getJsxTokens(acorn$1); - const tt = acorn$1.tokTypes; + const acorn = Parser.acorn || acorn; + const acornJsx = getJsxTokens(acorn); + const tt = acorn.tokTypes; const tok = acornJsx.tokTypes; - const tokContexts = acorn$1.tokContexts; + const tokContexts = acorn.tokContexts; const tc_oTag = acornJsx.tokContexts.tc_oTag; const tc_cTag = acornJsx.tokContexts.tc_cTag; const tc_expr = acornJsx.tokContexts.tc_expr; - const isNewLine = acorn$1.isNewLine; - const isIdentifierStart = acorn$1.isIdentifierStart; - const isIdentifierChar = acorn$1.isIdentifierChar; + const isNewLine = acorn.isNewLine; + const isIdentifierStart = acorn.isIdentifierStart; + const isIdentifierChar = acorn.isIdentifierChar; return class extends Parser { // Expose actual `tokTypes` and `tokContexts` to other plugins. @@ -491,7 +478,7 @@ function plugin(options, Parser) { entity = String.fromCharCode(parseInt(str, 10)); } } else { - entity = xhtml[str]; + entity = XHTMLEntities[str]; } break; } @@ -760,6 +747,5 @@ function plugin(options, Parser) { } }; } -}); -export default acornJsx; +module.exports = acornJsx; diff --git a/index.js b/index.js index 0ff263c..582d4d9 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,7 @@ 'use strict'; -const XHTMLEntities = require('./xhtml'); +import * as acorn from "acorn"; +import XHTMLEntities from './xhtml'; const hexNumber = /^[\da-fA-F]+$/; const decimalNumber = /^\d+$/; @@ -70,7 +71,7 @@ function getQualifiedJSXName(object) { getQualifiedJSXName(object.property); } -module.exports = function(options) { +var acornJsx = function(options) { options = options || {}; return function(Parser) { return plugin({ @@ -82,16 +83,24 @@ module.exports = function(options) { // This is `tokTypes` of the peer dep. // This can be different instances from the actual `tokTypes` this plugin uses. -Object.defineProperty(module.exports, "tokTypes", { +Object.defineProperty(acornJsx, "tokTypes", { get: function get_tokTypes() { - return getJsxTokens(require("acorn")).tokTypes; + return getJsxTokens(acorn).tokTypes; }, configurable: true, enumerable: true }); + +export default acornJsx; + +// If use this, rollup will bundle as `exports.default` and `exports.tokTypes`. That make the CommonJS users have to change their require code like `require("acorn-jsx").default`. + +// let tokTypes = acornJsx.tokTypes; +// export { tokTypes }; + function plugin(options, Parser) { - const acorn = Parser.acorn || require("acorn"); + const acorn = Parser.acorn || acorn; const acornJsx = getJsxTokens(acorn); const tt = acorn.tokTypes; const tok = acornJsx.tokTypes; diff --git a/package.json b/package.json index 5cd2868..fc919b0 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,8 @@ "description": "Modern, fast React.js JSX parser", "homepage": "https://github.com/acornjs/acorn-jsx", "version": "5.2.0", - "module": "index.mjs", + "main": "index.cjs.js", + "module": "index.js", "maintainers": [ { "name": "Ingvar Stepanyan", @@ -17,8 +18,8 @@ }, "license": "MIT", "scripts": { - "test": "node test/run.js", - "prepublishOnly": "node constructor/build.js" + "test": "node -r esm test/run.js", + "prepublishOnly": "node -r esm constructor/build.js" }, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0" @@ -26,6 +27,7 @@ "devDependencies": { "@rollup/plugin-commonjs": "^12.0.0", "acorn": "^7.0.0", + "esm": "^3.2.25", "rollup": "^2.12.0" } } diff --git a/test/driver.js b/test/driver.js index 8d3df48..dfa70cb 100644 --- a/test/driver.js +++ b/test/driver.js @@ -1,16 +1,16 @@ var tests = []; -exports.test = function(code, ast, options, pluginOptions) { +export function test(code, ast, options, pluginOptions) { tests.push({code, ast, options, pluginOptions}); }; -exports.testFail = function(code, message, options, pluginOptions) { +export function testFail(code, message, options, pluginOptions) { tests.push({code, error: message, options, pluginOptions}); }; -exports.testAssert = function(code, assert, options) { +export function testAssert(code, assert, options) { tests.push({code, assert, options}); }; -exports.runTests = function(config, callback) { +export function runTests(config, callback) { var parse = config.parse; for (var i = 0; i < tests.length; ++i) { diff --git a/test/run.js b/test/run.js index b9d98bf..40dd471 100644 --- a/test/run.js +++ b/test/run.js @@ -1,6 +1,8 @@ -var driver = require("./driver.js"); -require("./tests-jsx.js"); -require("./tests-misc.js"); +import * as driver from "./driver.js"; +import "./tests-jsx.js"; +import "./tests-misc.js"; +import * as acorn from "acorn"; +import jsx from "../index.js"; function group(name) { if (typeof console === "object" && console.group) { @@ -18,7 +20,7 @@ function log(title, message) { if (typeof console === "object") console.log(title, message); } -const acorn = require("acorn"), jsx = require("..") +// const acorn = require("acorn"), jsx = require("..") const Parser = acorn.Parser.extend(jsx()) var stats, modes = { diff --git a/test/tests-jsx.js b/test/tests-jsx.js index c44c605..4af4f26 100644 --- a/test/tests-jsx.js +++ b/test/tests-jsx.js @@ -20,6 +20,13 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +import { test } from "./driver.js"; +import { testFail } from "./driver.js"; +import acornJsx from "../index.js"; +import { tokTypes as acornTokens } from "acorn"; + +let jsxTokens = acornJsx.tokTypes; + var fbTestFixture = { // Taken and adapted from esprima-fb/fbtest.js. 'JSX': { @@ -3725,12 +3732,12 @@ var fbTestFixture = { } }; -if (typeof exports !== "undefined") { - var test = require("./driver.js").test; - var testFail = require("./driver.js").testFail; - var jsxTokens = require("..").tokTypes; - var acornTokens = require("acorn").tokTypes; -} +// if (typeof exports !== "undefined") { +// var test = require("./driver.js").test; +// var testFail = require("./driver.js").testFail; +// var jsxTokens = require("..").tokTypes; +// var acornTokens = require("acorn").tokTypes; +// } testFail("var x =
one
two
;", "Adjacent JSX elements must be wrapped in an enclosing tag (1:22)"); diff --git a/test/tests-misc.js b/test/tests-misc.js index 82a03dd..2522650 100644 --- a/test/tests-misc.js +++ b/test/tests-misc.js @@ -1,11 +1,16 @@ "use strict"; -if (typeof exports !== "undefined") { - var assert = require("assert"); - var acorn = require("acorn"); - var jsx = require(".."); - var testAssert = require("./driver.js").testAssert; -} +import assert from "assert"; +import * as acorn from "acorn"; +import jsx from "../index.js"; +import { testAssert } from "./driver"; + +// if (typeof exports !== "undefined") { +// var assert = require("assert"); +// var acorn = require("acorn"); +// var jsx = require(".."); +// var testAssert = require("./driver.js").testAssert; +// } testAssert("// the enhanced Parser instance should have a static property 'acornJsx'.", function() { const JsxParser = acorn.Parser.extend(jsx()); diff --git a/xhtml.js b/xhtml.js index c152009..8f5aa79 100644 --- a/xhtml.js +++ b/xhtml.js @@ -1,4 +1,4 @@ -module.exports = { +export default { quot: '\u0022', amp: '&', apos: '\u0027', From b399342d1038335c82e0611420e8b6576e705757 Mon Sep 17 00:00:00 2001 From: SaekiRaku Date: Tue, 2 Jun 2020 10:45:25 +0800 Subject: [PATCH 3/4] Removed all leftover comments, and change var acornJsx to function declaration. --- index.cjs.js | 8 ++------ index.js | 7 +------ test/run.js | 1 - test/tests-jsx.js | 7 ------- test/tests-misc.js | 7 ------- 5 files changed, 3 insertions(+), 27 deletions(-) diff --git a/index.cjs.js b/index.cjs.js index fd0bd96..458740d 100644 --- a/index.cjs.js +++ b/index.cjs.js @@ -328,7 +328,7 @@ function getQualifiedJSXName(object) { getQualifiedJSXName(object.property); } -var acornJsx = function(options) { +function acornJsx(options) { options = options || {}; return function(Parser) { return plugin({ @@ -336,8 +336,7 @@ var acornJsx = function(options) { allowNamespacedObjects: !!options.allowNamespacedObjects }, Parser); }; -}; - +} // This is `tokTypes` of the peer dep. // This can be different instances from the actual `tokTypes` this plugin uses. Object.defineProperty(acornJsx, "tokTypes", { @@ -348,9 +347,6 @@ Object.defineProperty(acornJsx, "tokTypes", { enumerable: true }); -// let tokTypes = acornJsx.tokTypes; -// export { tokTypes }; - function plugin(options, Parser) { const acorn = Parser.acorn || acorn; const acornJsx = getJsxTokens(acorn); diff --git a/index.js b/index.js index 582d4d9..b6fb14a 100644 --- a/index.js +++ b/index.js @@ -71,7 +71,7 @@ function getQualifiedJSXName(object) { getQualifiedJSXName(object.property); } -var acornJsx = function(options) { +function acornJsx(options) { options = options || {}; return function(Parser) { return plugin({ @@ -94,11 +94,6 @@ Object.defineProperty(acornJsx, "tokTypes", { export default acornJsx; -// If use this, rollup will bundle as `exports.default` and `exports.tokTypes`. That make the CommonJS users have to change their require code like `require("acorn-jsx").default`. - -// let tokTypes = acornJsx.tokTypes; -// export { tokTypes }; - function plugin(options, Parser) { const acorn = Parser.acorn || acorn; const acornJsx = getJsxTokens(acorn); diff --git a/test/run.js b/test/run.js index 40dd471..e462920 100644 --- a/test/run.js +++ b/test/run.js @@ -20,7 +20,6 @@ function log(title, message) { if (typeof console === "object") console.log(title, message); } -// const acorn = require("acorn"), jsx = require("..") const Parser = acorn.Parser.extend(jsx()) var stats, modes = { diff --git a/test/tests-jsx.js b/test/tests-jsx.js index 4af4f26..92e055e 100644 --- a/test/tests-jsx.js +++ b/test/tests-jsx.js @@ -3732,13 +3732,6 @@ var fbTestFixture = { } }; -// if (typeof exports !== "undefined") { -// var test = require("./driver.js").test; -// var testFail = require("./driver.js").testFail; -// var jsxTokens = require("..").tokTypes; -// var acornTokens = require("acorn").tokTypes; -// } - testFail("var x =
one
two
;", "Adjacent JSX elements must be wrapped in an enclosing tag (1:22)"); testFail("", "Unexpected token (1:4)"); diff --git a/test/tests-misc.js b/test/tests-misc.js index 2522650..4e81e64 100644 --- a/test/tests-misc.js +++ b/test/tests-misc.js @@ -5,13 +5,6 @@ import * as acorn from "acorn"; import jsx from "../index.js"; import { testAssert } from "./driver"; -// if (typeof exports !== "undefined") { -// var assert = require("assert"); -// var acorn = require("acorn"); -// var jsx = require(".."); -// var testAssert = require("./driver.js").testAssert; -// } - testAssert("// the enhanced Parser instance should have a static property 'acornJsx'.", function() { const JsxParser = acorn.Parser.extend(jsx()); assert(JsxParser.acornJsx); From 12f4a5be9edf2914817d0208c9da495f75703442 Mon Sep 17 00:00:00 2001 From: guoqiqi Date: Fri, 13 Nov 2020 12:57:51 +0800 Subject: [PATCH 4/4] add index.cjs.js to the .gitignore --- .gitignore | 1 + index.cjs.js | 747 --------------------------------------------------- 2 files changed, 1 insertion(+), 747 deletions(-) delete mode 100644 index.cjs.js diff --git a/.gitignore b/.gitignore index d502512..f85f137 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /node_modules /package-lock.json +index.cjs.js \ No newline at end of file diff --git a/index.cjs.js b/index.cjs.js deleted file mode 100644 index 458740d..0000000 --- a/index.cjs.js +++ /dev/null @@ -1,747 +0,0 @@ -// DO NOT edit this file, it's auto generate from 'constructor/build.js', any changes will be overwrite. - -'use strict'; - -var acorn = require('acorn'); - -var XHTMLEntities = { - quot: '\u0022', - amp: '&', - apos: '\u0027', - lt: '<', - gt: '>', - nbsp: '\u00A0', - iexcl: '\u00A1', - cent: '\u00A2', - pound: '\u00A3', - curren: '\u00A4', - yen: '\u00A5', - brvbar: '\u00A6', - sect: '\u00A7', - uml: '\u00A8', - copy: '\u00A9', - ordf: '\u00AA', - laquo: '\u00AB', - not: '\u00AC', - shy: '\u00AD', - reg: '\u00AE', - macr: '\u00AF', - deg: '\u00B0', - plusmn: '\u00B1', - sup2: '\u00B2', - sup3: '\u00B3', - acute: '\u00B4', - micro: '\u00B5', - para: '\u00B6', - middot: '\u00B7', - cedil: '\u00B8', - sup1: '\u00B9', - ordm: '\u00BA', - raquo: '\u00BB', - frac14: '\u00BC', - frac12: '\u00BD', - frac34: '\u00BE', - iquest: '\u00BF', - Agrave: '\u00C0', - Aacute: '\u00C1', - Acirc: '\u00C2', - Atilde: '\u00C3', - Auml: '\u00C4', - Aring: '\u00C5', - AElig: '\u00C6', - Ccedil: '\u00C7', - Egrave: '\u00C8', - Eacute: '\u00C9', - Ecirc: '\u00CA', - Euml: '\u00CB', - Igrave: '\u00CC', - Iacute: '\u00CD', - Icirc: '\u00CE', - Iuml: '\u00CF', - ETH: '\u00D0', - Ntilde: '\u00D1', - Ograve: '\u00D2', - Oacute: '\u00D3', - Ocirc: '\u00D4', - Otilde: '\u00D5', - Ouml: '\u00D6', - times: '\u00D7', - Oslash: '\u00D8', - Ugrave: '\u00D9', - Uacute: '\u00DA', - Ucirc: '\u00DB', - Uuml: '\u00DC', - Yacute: '\u00DD', - THORN: '\u00DE', - szlig: '\u00DF', - agrave: '\u00E0', - aacute: '\u00E1', - acirc: '\u00E2', - atilde: '\u00E3', - auml: '\u00E4', - aring: '\u00E5', - aelig: '\u00E6', - ccedil: '\u00E7', - egrave: '\u00E8', - eacute: '\u00E9', - ecirc: '\u00EA', - euml: '\u00EB', - igrave: '\u00EC', - iacute: '\u00ED', - icirc: '\u00EE', - iuml: '\u00EF', - eth: '\u00F0', - ntilde: '\u00F1', - ograve: '\u00F2', - oacute: '\u00F3', - ocirc: '\u00F4', - otilde: '\u00F5', - ouml: '\u00F6', - divide: '\u00F7', - oslash: '\u00F8', - ugrave: '\u00F9', - uacute: '\u00FA', - ucirc: '\u00FB', - uuml: '\u00FC', - yacute: '\u00FD', - thorn: '\u00FE', - yuml: '\u00FF', - OElig: '\u0152', - oelig: '\u0153', - Scaron: '\u0160', - scaron: '\u0161', - Yuml: '\u0178', - fnof: '\u0192', - circ: '\u02C6', - tilde: '\u02DC', - Alpha: '\u0391', - Beta: '\u0392', - Gamma: '\u0393', - Delta: '\u0394', - Epsilon: '\u0395', - Zeta: '\u0396', - Eta: '\u0397', - Theta: '\u0398', - Iota: '\u0399', - Kappa: '\u039A', - Lambda: '\u039B', - Mu: '\u039C', - Nu: '\u039D', - Xi: '\u039E', - Omicron: '\u039F', - Pi: '\u03A0', - Rho: '\u03A1', - Sigma: '\u03A3', - Tau: '\u03A4', - Upsilon: '\u03A5', - Phi: '\u03A6', - Chi: '\u03A7', - Psi: '\u03A8', - Omega: '\u03A9', - alpha: '\u03B1', - beta: '\u03B2', - gamma: '\u03B3', - delta: '\u03B4', - epsilon: '\u03B5', - zeta: '\u03B6', - eta: '\u03B7', - theta: '\u03B8', - iota: '\u03B9', - kappa: '\u03BA', - lambda: '\u03BB', - mu: '\u03BC', - nu: '\u03BD', - xi: '\u03BE', - omicron: '\u03BF', - pi: '\u03C0', - rho: '\u03C1', - sigmaf: '\u03C2', - sigma: '\u03C3', - tau: '\u03C4', - upsilon: '\u03C5', - phi: '\u03C6', - chi: '\u03C7', - psi: '\u03C8', - omega: '\u03C9', - thetasym: '\u03D1', - upsih: '\u03D2', - piv: '\u03D6', - ensp: '\u2002', - emsp: '\u2003', - thinsp: '\u2009', - zwnj: '\u200C', - zwj: '\u200D', - lrm: '\u200E', - rlm: '\u200F', - ndash: '\u2013', - mdash: '\u2014', - lsquo: '\u2018', - rsquo: '\u2019', - sbquo: '\u201A', - ldquo: '\u201C', - rdquo: '\u201D', - bdquo: '\u201E', - dagger: '\u2020', - Dagger: '\u2021', - bull: '\u2022', - hellip: '\u2026', - permil: '\u2030', - prime: '\u2032', - Prime: '\u2033', - lsaquo: '\u2039', - rsaquo: '\u203A', - oline: '\u203E', - frasl: '\u2044', - euro: '\u20AC', - image: '\u2111', - weierp: '\u2118', - real: '\u211C', - trade: '\u2122', - alefsym: '\u2135', - larr: '\u2190', - uarr: '\u2191', - rarr: '\u2192', - darr: '\u2193', - harr: '\u2194', - crarr: '\u21B5', - lArr: '\u21D0', - uArr: '\u21D1', - rArr: '\u21D2', - dArr: '\u21D3', - hArr: '\u21D4', - forall: '\u2200', - part: '\u2202', - exist: '\u2203', - empty: '\u2205', - nabla: '\u2207', - isin: '\u2208', - notin: '\u2209', - ni: '\u220B', - prod: '\u220F', - sum: '\u2211', - minus: '\u2212', - lowast: '\u2217', - radic: '\u221A', - prop: '\u221D', - infin: '\u221E', - ang: '\u2220', - and: '\u2227', - or: '\u2228', - cap: '\u2229', - cup: '\u222A', - 'int': '\u222B', - there4: '\u2234', - sim: '\u223C', - cong: '\u2245', - asymp: '\u2248', - ne: '\u2260', - equiv: '\u2261', - le: '\u2264', - ge: '\u2265', - sub: '\u2282', - sup: '\u2283', - nsub: '\u2284', - sube: '\u2286', - supe: '\u2287', - oplus: '\u2295', - otimes: '\u2297', - perp: '\u22A5', - sdot: '\u22C5', - lceil: '\u2308', - rceil: '\u2309', - lfloor: '\u230A', - rfloor: '\u230B', - lang: '\u2329', - rang: '\u232A', - loz: '\u25CA', - spades: '\u2660', - clubs: '\u2663', - hearts: '\u2665', - diams: '\u2666' -}; - -const hexNumber = /^[\da-fA-F]+$/; -const decimalNumber = /^\d+$/; - -// The map to `acorn-jsx` tokens from `acorn` namespace objects. -const acornJsxMap = new WeakMap(); - -// Get the original tokens for the given `acorn` namespace object. -function getJsxTokens(acorn) { - acorn = acorn.Parser.acorn || acorn; - let acornJsx = acornJsxMap.get(acorn); - if (!acornJsx) { - const tt = acorn.tokTypes; - const TokContext = acorn.TokContext; - const TokenType = acorn.TokenType; - const tc_oTag = new TokContext('...', true, true); - const tokContexts = { - tc_oTag: tc_oTag, - tc_cTag: tc_cTag, - tc_expr: tc_expr - }; - const tokTypes = { - jsxName: new TokenType('jsxName'), - jsxText: new TokenType('jsxText', {beforeExpr: true}), - jsxTagStart: new TokenType('jsxTagStart'), - jsxTagEnd: new TokenType('jsxTagEnd') - }; - - tokTypes.jsxTagStart.updateContext = function() { - this.context.push(tc_expr); // treat as beginning of JSX expression - this.context.push(tc_oTag); // start opening tag context - this.exprAllowed = false; - }; - tokTypes.jsxTagEnd.updateContext = function(prevType) { - let out = this.context.pop(); - if (out === tc_oTag && prevType === tt.slash || out === tc_cTag) { - this.context.pop(); - this.exprAllowed = this.curContext() === tc_expr; - } else { - this.exprAllowed = true; - } - }; - - acornJsx = { tokContexts: tokContexts, tokTypes: tokTypes }; - acornJsxMap.set(acorn, acornJsx); - } - - return acornJsx; -} - -// Transforms JSX element name to string. - -function getQualifiedJSXName(object) { - if (!object) - return object; - - if (object.type === 'JSXIdentifier') - return object.name; - - if (object.type === 'JSXNamespacedName') - return object.namespace.name + ':' + object.name.name; - - if (object.type === 'JSXMemberExpression') - return getQualifiedJSXName(object.object) + '.' + - getQualifiedJSXName(object.property); -} - -function acornJsx(options) { - options = options || {}; - return function(Parser) { - return plugin({ - allowNamespaces: options.allowNamespaces !== false, - allowNamespacedObjects: !!options.allowNamespacedObjects - }, Parser); - }; -} -// This is `tokTypes` of the peer dep. -// This can be different instances from the actual `tokTypes` this plugin uses. -Object.defineProperty(acornJsx, "tokTypes", { - get: function get_tokTypes() { - return getJsxTokens(acorn).tokTypes; - }, - configurable: true, - enumerable: true -}); - -function plugin(options, Parser) { - const acorn = Parser.acorn || acorn; - const acornJsx = getJsxTokens(acorn); - const tt = acorn.tokTypes; - const tok = acornJsx.tokTypes; - const tokContexts = acorn.tokContexts; - const tc_oTag = acornJsx.tokContexts.tc_oTag; - const tc_cTag = acornJsx.tokContexts.tc_cTag; - const tc_expr = acornJsx.tokContexts.tc_expr; - const isNewLine = acorn.isNewLine; - const isIdentifierStart = acorn.isIdentifierStart; - const isIdentifierChar = acorn.isIdentifierChar; - - return class extends Parser { - // Expose actual `tokTypes` and `tokContexts` to other plugins. - static get acornJsx() { - return acornJsx; - } - - // Reads inline JSX contents token. - jsx_readToken() { - let out = '', chunkStart = this.pos; - for (;;) { - if (this.pos >= this.input.length) - this.raise(this.start, 'Unterminated JSX contents'); - let ch = this.input.charCodeAt(this.pos); - - switch (ch) { - case 60: // '<' - case 123: // '{' - if (this.pos === this.start) { - if (ch === 60 && this.exprAllowed) { - ++this.pos; - return this.finishToken(tok.jsxTagStart); - } - return this.getTokenFromCode(ch); - } - out += this.input.slice(chunkStart, this.pos); - return this.finishToken(tok.jsxText, out); - - case 38: // '&' - out += this.input.slice(chunkStart, this.pos); - out += this.jsx_readEntity(); - chunkStart = this.pos; - break; - - case 62: // '>' - case 125: // '}' - this.raise( - this.pos, - "Unexpected token `" + this.input[this.pos] + "`. Did you mean `" + - (ch === 62 ? ">" : "}") + "` or " + "`{\"" + this.input[this.pos] + "\"}" + "`?" - ); - - default: - if (isNewLine(ch)) { - out += this.input.slice(chunkStart, this.pos); - out += this.jsx_readNewLine(true); - chunkStart = this.pos; - } else { - ++this.pos; - } - } - } - } - - jsx_readNewLine(normalizeCRLF) { - let ch = this.input.charCodeAt(this.pos); - let out; - ++this.pos; - if (ch === 13 && this.input.charCodeAt(this.pos) === 10) { - ++this.pos; - out = normalizeCRLF ? '\n' : '\r\n'; - } else { - out = String.fromCharCode(ch); - } - if (this.options.locations) { - ++this.curLine; - this.lineStart = this.pos; - } - - return out; - } - - jsx_readString(quote) { - let out = '', chunkStart = ++this.pos; - for (;;) { - if (this.pos >= this.input.length) - this.raise(this.start, 'Unterminated string constant'); - let ch = this.input.charCodeAt(this.pos); - if (ch === quote) break; - if (ch === 38) { // '&' - out += this.input.slice(chunkStart, this.pos); - out += this.jsx_readEntity(); - chunkStart = this.pos; - } else if (isNewLine(ch)) { - out += this.input.slice(chunkStart, this.pos); - out += this.jsx_readNewLine(false); - chunkStart = this.pos; - } else { - ++this.pos; - } - } - out += this.input.slice(chunkStart, this.pos++); - return this.finishToken(tt.string, out); - } - - jsx_readEntity() { - let str = '', count = 0, entity; - let ch = this.input[this.pos]; - if (ch !== '&') - this.raise(this.pos, 'Entity must start with an ampersand'); - let startPos = ++this.pos; - while (this.pos < this.input.length && count++ < 10) { - ch = this.input[this.pos++]; - if (ch === ';') { - if (str[0] === '#') { - if (str[1] === 'x') { - str = str.substr(2); - if (hexNumber.test(str)) - entity = String.fromCharCode(parseInt(str, 16)); - } else { - str = str.substr(1); - if (decimalNumber.test(str)) - entity = String.fromCharCode(parseInt(str, 10)); - } - } else { - entity = XHTMLEntities[str]; - } - break; - } - str += ch; - } - if (!entity) { - this.pos = startPos; - return '&'; - } - return entity; - } - - // Read a JSX identifier (valid tag or attribute name). - // - // Optimized version since JSX identifiers can't contain - // escape characters and so can be read as single slice. - // Also assumes that first character was already checked - // by isIdentifierStart in readToken. - - jsx_readWord() { - let ch, start = this.pos; - do { - ch = this.input.charCodeAt(++this.pos); - } while (isIdentifierChar(ch) || ch === 45); // '-' - return this.finishToken(tok.jsxName, this.input.slice(start, this.pos)); - } - - // Parse next token as JSX identifier - - jsx_parseIdentifier() { - let node = this.startNode(); - if (this.type === tok.jsxName) - node.name = this.value; - else if (this.type.keyword) - node.name = this.type.keyword; - else - this.unexpected(); - this.next(); - return this.finishNode(node, 'JSXIdentifier'); - } - - // Parse namespaced identifier. - - jsx_parseNamespacedName() { - let startPos = this.start, startLoc = this.startLoc; - let name = this.jsx_parseIdentifier(); - if (!options.allowNamespaces || !this.eat(tt.colon)) return name; - var node = this.startNodeAt(startPos, startLoc); - node.namespace = name; - node.name = this.jsx_parseIdentifier(); - return this.finishNode(node, 'JSXNamespacedName'); - } - - // Parses element name in any form - namespaced, member - // or single identifier. - - jsx_parseElementName() { - if (this.type === tok.jsxTagEnd) return ''; - let startPos = this.start, startLoc = this.startLoc; - let node = this.jsx_parseNamespacedName(); - if (this.type === tt.dot && node.type === 'JSXNamespacedName' && !options.allowNamespacedObjects) { - this.unexpected(); - } - while (this.eat(tt.dot)) { - let newNode = this.startNodeAt(startPos, startLoc); - newNode.object = node; - newNode.property = this.jsx_parseIdentifier(); - node = this.finishNode(newNode, 'JSXMemberExpression'); - } - return node; - } - - // Parses any type of JSX attribute value. - - jsx_parseAttributeValue() { - switch (this.type) { - case tt.braceL: - let node = this.jsx_parseExpressionContainer(); - if (node.expression.type === 'JSXEmptyExpression') - this.raise(node.start, 'JSX attributes must only be assigned a non-empty expression'); - return node; - - case tok.jsxTagStart: - case tt.string: - return this.parseExprAtom(); - - default: - this.raise(this.start, 'JSX value should be either an expression or a quoted JSX text'); - } - } - - // JSXEmptyExpression is unique type since it doesn't actually parse anything, - // and so it should start at the end of last read token (left brace) and finish - // at the beginning of the next one (right brace). - - jsx_parseEmptyExpression() { - let node = this.startNodeAt(this.lastTokEnd, this.lastTokEndLoc); - return this.finishNodeAt(node, 'JSXEmptyExpression', this.start, this.startLoc); - } - - // Parses JSX expression enclosed into curly brackets. - - jsx_parseExpressionContainer() { - let node = this.startNode(); - this.next(); - node.expression = this.type === tt.braceR - ? this.jsx_parseEmptyExpression() - : this.parseExpression(); - this.expect(tt.braceR); - return this.finishNode(node, 'JSXExpressionContainer'); - } - - // Parses following JSX attribute name-value pair. - - jsx_parseAttribute() { - let node = this.startNode(); - if (this.eat(tt.braceL)) { - this.expect(tt.ellipsis); - node.argument = this.parseMaybeAssign(); - this.expect(tt.braceR); - return this.finishNode(node, 'JSXSpreadAttribute'); - } - node.name = this.jsx_parseNamespacedName(); - node.value = this.eat(tt.eq) ? this.jsx_parseAttributeValue() : null; - return this.finishNode(node, 'JSXAttribute'); - } - - // Parses JSX opening tag starting after '<'. - - jsx_parseOpeningElementAt(startPos, startLoc) { - let node = this.startNodeAt(startPos, startLoc); - node.attributes = []; - let nodeName = this.jsx_parseElementName(); - if (nodeName) node.name = nodeName; - while (this.type !== tt.slash && this.type !== tok.jsxTagEnd) - node.attributes.push(this.jsx_parseAttribute()); - node.selfClosing = this.eat(tt.slash); - this.expect(tok.jsxTagEnd); - return this.finishNode(node, nodeName ? 'JSXOpeningElement' : 'JSXOpeningFragment'); - } - - // Parses JSX closing tag starting after ''); - } - } - let fragmentOrElement = openingElement.name ? 'Element' : 'Fragment'; - - node['opening' + fragmentOrElement] = openingElement; - node['closing' + fragmentOrElement] = closingElement; - node.children = children; - if (this.type === tt.relational && this.value === "<") { - this.raise(this.start, "Adjacent JSX elements must be wrapped in an enclosing tag"); - } - return this.finishNode(node, 'JSX' + fragmentOrElement); - } - - // Parse JSX text - - jsx_parseText() { - let node = this.parseLiteral(this.value); - node.type = "JSXText"; - return node; - } - - // Parses entire JSX element from current position. - - jsx_parseElement() { - let startPos = this.start, startLoc = this.startLoc; - this.next(); - return this.jsx_parseElementAt(startPos, startLoc); - } - - parseExprAtom(refShortHandDefaultPos) { - if (this.type === tok.jsxText) - return this.jsx_parseText(); - else if (this.type === tok.jsxTagStart) - return this.jsx_parseElement(); - else - return super.parseExprAtom(refShortHandDefaultPos); - } - - readToken(code) { - let context = this.curContext(); - - if (context === tc_expr) return this.jsx_readToken(); - - if (context === tc_oTag || context === tc_cTag) { - if (isIdentifierStart(code)) return this.jsx_readWord(); - - if (code == 62) { - ++this.pos; - return this.finishToken(tok.jsxTagEnd); - } - - if ((code === 34 || code === 39) && context == tc_oTag) - return this.jsx_readString(code); - } - - if (code === 60 && this.exprAllowed && this.input.charCodeAt(this.pos + 1) !== 33) { - ++this.pos; - return this.finishToken(tok.jsxTagStart); - } - return super.readToken(code); - } - - updateContext(prevType) { - if (this.type == tt.braceL) { - var curContext = this.curContext(); - if (curContext == tc_oTag) this.context.push(tokContexts.b_expr); - else if (curContext == tc_expr) this.context.push(tokContexts.b_tmpl); - else super.updateContext(prevType); - this.exprAllowed = true; - } else if (this.type === tt.slash && prevType === tok.jsxTagStart) { - this.context.length -= 2; // do not consider JSX expr -> JSX open tag -> ... anymore - this.context.push(tc_cTag); // reconsider as closing tag context - this.exprAllowed = false; - } else { - return super.updateContext(prevType); - } - } - }; -} - -module.exports = acornJsx;