Grabbed dndbeyond's source code
``` ~/go/bin/sourcemapper -output ddb -jsurl https://media.dndbeyond.com/character-app/static/js/main.90aa78c5.js ```
This commit is contained in:
@@ -0,0 +1 @@
|
||||
module.exports = __WEBPACK_EXTERNAL_MODULE__297__;
|
||||
+496
@@ -0,0 +1,496 @@
|
||||
'use strict';
|
||||
|
||||
const XHTMLEntities = require('./xhtml');
|
||||
|
||||
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('<tag', false);
|
||||
const tc_cTag = new TokContext('</tag', false);
|
||||
const tc_expr = new TokContext('<tag>...</tag>', 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', {startsExpr: true}),
|
||||
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,
|
||||
autoCloseVoidElements: !!options.autoCloseVoidElements,
|
||||
}, 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(require("acorn")).tokTypes;
|
||||
},
|
||||
configurable: true,
|
||||
enumerable: true
|
||||
});
|
||||
|
||||
function plugin(options, Parser) {
|
||||
const acorn = Parser.acorn || require("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);
|
||||
const VOID_ELEMENTS = [
|
||||
'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen',
|
||||
'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr'
|
||||
]
|
||||
if (options.autoCloseVoidElements && nodeName && VOID_ELEMENTS.includes(nodeName.name)) {
|
||||
node.selfClosing = true;
|
||||
}
|
||||
return this.finishNode(node, nodeName ? 'JSXOpeningElement' : 'JSXOpeningFragment');
|
||||
}
|
||||
|
||||
// Parses JSX closing tag starting after '</'.
|
||||
|
||||
jsx_parseClosingElementAt(startPos, startLoc) {
|
||||
let node = this.startNodeAt(startPos, startLoc);
|
||||
let nodeName = this.jsx_parseElementName();
|
||||
if (nodeName) node.name = nodeName;
|
||||
this.expect(tok.jsxTagEnd);
|
||||
return this.finishNode(node, nodeName ? 'JSXClosingElement' : 'JSXClosingFragment');
|
||||
}
|
||||
|
||||
// Parses entire JSX element, including it's opening tag
|
||||
// (starting after '<'), attributes, contents and closing tag.
|
||||
|
||||
jsx_parseElementAt(startPos, startLoc) {
|
||||
let node = this.startNodeAt(startPos, startLoc);
|
||||
let children = [];
|
||||
let openingElement = this.jsx_parseOpeningElementAt(startPos, startLoc);
|
||||
let closingElement = null;
|
||||
|
||||
if (!openingElement.selfClosing) {
|
||||
contents: for (;;) {
|
||||
switch (this.type) {
|
||||
case tok.jsxTagStart:
|
||||
startPos = this.start; startLoc = this.startLoc;
|
||||
this.next();
|
||||
if (this.eat(tt.slash)) {
|
||||
closingElement = this.jsx_parseClosingElementAt(startPos, startLoc);
|
||||
break contents;
|
||||
}
|
||||
children.push(this.jsx_parseElementAt(startPos, startLoc));
|
||||
break;
|
||||
|
||||
case tok.jsxText:
|
||||
children.push(this.parseExprAtom());
|
||||
break;
|
||||
|
||||
case tt.braceL:
|
||||
children.push(this.jsx_parseExpressionContainer());
|
||||
break;
|
||||
|
||||
default:
|
||||
this.unexpected();
|
||||
}
|
||||
}
|
||||
if (getQualifiedJSXName(closingElement.name) !== getQualifiedJSXName(openingElement.name)) {
|
||||
this.raise(
|
||||
closingElement.start,
|
||||
'Expected corresponding JSX closing tag for <' + getQualifiedJSXName(openingElement.name) + '>');
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
+255
@@ -0,0 +1,255 @@
|
||||
module.exports = {
|
||||
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'
|
||||
};
|
||||
+5292
File diff suppressed because it is too large
Load Diff
+5261
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,349 @@
|
||||
/* global JSX */
|
||||
import * as Acorn from 'acorn'
|
||||
import * as AcornJSX from 'acorn-jsx'
|
||||
import React, { Fragment, ComponentType, ExoticComponent } from 'react'
|
||||
import ATTRIBUTES from '../constants/attributeNames'
|
||||
import { canHaveChildren, canHaveWhitespace } from '../constants/specialTags'
|
||||
import { randomHash } from '../helpers/hash'
|
||||
import { parseStyle } from '../helpers/parseStyle'
|
||||
import { resolvePath } from '../helpers/resolvePath'
|
||||
|
||||
type ParsedJSX = JSX.Element | boolean | string
|
||||
type ParsedTree = ParsedJSX | ParsedJSX[] | null
|
||||
export type TProps = {
|
||||
allowUnknownElements?: boolean,
|
||||
autoCloseVoidElements?: boolean,
|
||||
bindings?: { [key: string]: unknown; },
|
||||
blacklistedAttrs?: Array<string | RegExp>,
|
||||
blacklistedTags?: string[],
|
||||
className?: string,
|
||||
components?: Record<string, ComponentType | ExoticComponent>,
|
||||
componentsOnly?: boolean,
|
||||
disableFragments?: boolean,
|
||||
disableKeyGeneration?: boolean,
|
||||
jsx?: string,
|
||||
onError?: (error: Error) => void,
|
||||
showWarnings?: boolean,
|
||||
renderError?: (props: { error: string }) => JSX.Element | null,
|
||||
renderInWrapper?: boolean,
|
||||
renderUnrecognized?: (tagName: string) => JSX.Element | null,
|
||||
}
|
||||
type Scope = Record<string, any>
|
||||
|
||||
/* eslint-disable consistent-return */
|
||||
export default class JsxParser extends React.Component<TProps> {
|
||||
static displayName = 'JsxParser'
|
||||
static defaultProps: TProps = {
|
||||
allowUnknownElements: true,
|
||||
autoCloseVoidElements: false,
|
||||
bindings: {},
|
||||
blacklistedAttrs: [/^on.+/i],
|
||||
blacklistedTags: ['script'],
|
||||
className: '',
|
||||
components: {},
|
||||
componentsOnly: false,
|
||||
disableFragments: false,
|
||||
disableKeyGeneration: false,
|
||||
jsx: '',
|
||||
onError: () => { },
|
||||
showWarnings: false,
|
||||
renderError: undefined,
|
||||
renderInWrapper: true,
|
||||
renderUnrecognized: () => null,
|
||||
}
|
||||
|
||||
private ParsedChildren: ParsedTree = null
|
||||
|
||||
#parseJSX = (jsx: string): JSX.Element | JSX.Element[] | null => {
|
||||
const parser = Acorn.Parser.extend(AcornJSX.default({
|
||||
autoCloseVoidElements: this.props.autoCloseVoidElements,
|
||||
}))
|
||||
const wrappedJsx = `<root>${jsx}</root>`
|
||||
let parsed: AcornJSX.Expression[] = []
|
||||
try {
|
||||
// @ts-ignore - AcornJsx doesn't have typescript typings
|
||||
parsed = parser.parse(wrappedJsx, { ecmaVersion: 'latest' })
|
||||
// @ts-ignore - AcornJsx doesn't have typescript typings
|
||||
parsed = parsed.body[0].expression.children || []
|
||||
} catch (error) {
|
||||
if (this.props.showWarnings) console.warn(error) // eslint-disable-line no-console
|
||||
if (this.props.onError) this.props.onError(error)
|
||||
if (this.props.renderError) {
|
||||
return this.props.renderError({ error: String(error) })
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
return parsed.map(p => this.#parseExpression(p)).filter(Boolean)
|
||||
}
|
||||
|
||||
#parseExpression = (expression: AcornJSX.Expression, scope?: Scope): any => {
|
||||
switch (expression.type) {
|
||||
case 'JSXAttribute':
|
||||
if (expression.value === null) return true
|
||||
return this.#parseExpression(expression.value, scope)
|
||||
case 'JSXElement':
|
||||
case 'JSXFragment':
|
||||
return this.#parseElement(expression, scope)
|
||||
case 'JSXExpressionContainer':
|
||||
return this.#parseExpression(expression.expression, scope)
|
||||
case 'JSXText':
|
||||
const key = this.props.disableKeyGeneration ? undefined : randomHash()
|
||||
return this.props.disableFragments
|
||||
? expression.value
|
||||
: <Fragment key={key}>{expression.value}</Fragment>
|
||||
case 'ArrayExpression':
|
||||
return expression.elements.map(ele => this.#parseExpression(ele, scope)) as ParsedTree
|
||||
case 'BinaryExpression':
|
||||
/* eslint-disable eqeqeq,max-len */
|
||||
switch (expression.operator) {
|
||||
case '-': return this.#parseExpression(expression.left) - this.#parseExpression(expression.right)
|
||||
case '!=': return this.#parseExpression(expression.left) != this.#parseExpression(expression.right)
|
||||
case '!==': return this.#parseExpression(expression.left) !== this.#parseExpression(expression.right)
|
||||
case '*': return this.#parseExpression(expression.left) * this.#parseExpression(expression.right)
|
||||
case '**': return this.#parseExpression(expression.left) ** this.#parseExpression(expression.right)
|
||||
case '/': return this.#parseExpression(expression.left) / this.#parseExpression(expression.right)
|
||||
case '%': return this.#parseExpression(expression.left) % this.#parseExpression(expression.right)
|
||||
case '+': return this.#parseExpression(expression.left) + this.#parseExpression(expression.right)
|
||||
case '<': return this.#parseExpression(expression.left) < this.#parseExpression(expression.right)
|
||||
case '<=': return this.#parseExpression(expression.left) <= this.#parseExpression(expression.right)
|
||||
case '==': return this.#parseExpression(expression.left) == this.#parseExpression(expression.right)
|
||||
case '===': return this.#parseExpression(expression.left) === this.#parseExpression(expression.right)
|
||||
case '>': return this.#parseExpression(expression.left) > this.#parseExpression(expression.right)
|
||||
case '>=': return this.#parseExpression(expression.left) >= this.#parseExpression(expression.right)
|
||||
/* eslint-enable eqeqeq,max-len */
|
||||
}
|
||||
return undefined
|
||||
case 'CallExpression':
|
||||
const parsedCallee = this.#parseExpression(expression.callee)
|
||||
if (parsedCallee === undefined) {
|
||||
this.props.onError!(new Error(`The expression '${expression.callee}' could not be resolved, resulting in an undefined return value.`))
|
||||
return undefined
|
||||
}
|
||||
return parsedCallee(...expression.arguments.map(
|
||||
arg => this.#parseExpression(arg, expression.callee),
|
||||
))
|
||||
case 'ConditionalExpression':
|
||||
return this.#parseExpression(expression.test)
|
||||
? this.#parseExpression(expression.consequent)
|
||||
: this.#parseExpression(expression.alternate)
|
||||
case 'ExpressionStatement':
|
||||
return this.#parseExpression(expression.expression)
|
||||
case 'Identifier':
|
||||
if (scope && expression.name in scope) {
|
||||
return scope[expression.name]
|
||||
}
|
||||
return (this.props.bindings || {})[expression.name]
|
||||
|
||||
case 'Literal':
|
||||
return expression.value
|
||||
case 'LogicalExpression':
|
||||
const left = this.#parseExpression(expression.left)
|
||||
if (expression.operator === '||' && left) return left
|
||||
if ((expression.operator === '&&' && left) || (expression.operator === '||' && !left)) {
|
||||
return this.#parseExpression(expression.right)
|
||||
}
|
||||
return false
|
||||
case 'MemberExpression':
|
||||
return this.#parseMemberExpression(expression, scope)
|
||||
case 'ObjectExpression':
|
||||
const object: Record<string, any> = {}
|
||||
expression.properties.forEach(prop => {
|
||||
object[prop.key.name! || prop.key.value!] = this.#parseExpression(prop.value)
|
||||
})
|
||||
return object
|
||||
case 'TemplateElement':
|
||||
return expression.value.cooked
|
||||
case 'TemplateLiteral':
|
||||
return [...expression.expressions, ...expression.quasis]
|
||||
.sort((a, b) => {
|
||||
if (a.start < b.start) return -1
|
||||
return 1
|
||||
})
|
||||
.map(item => this.#parseExpression(item))
|
||||
.join('')
|
||||
case 'UnaryExpression':
|
||||
switch (expression.operator) {
|
||||
case '+': return expression.argument.value
|
||||
case '-': return -expression.argument.value
|
||||
case '!': return !expression.argument.value
|
||||
}
|
||||
return undefined
|
||||
case 'ArrowFunctionExpression':
|
||||
if (expression.async || expression.generator) {
|
||||
this.props.onError?.(new Error('Async and generator arrow functions are not supported.'))
|
||||
}
|
||||
return (...args: any[]) : any => {
|
||||
const functionScope: Record<string, any> = {}
|
||||
expression.params.forEach((param, idx) => {
|
||||
functionScope[param.name] = args[idx]
|
||||
})
|
||||
return this.#parseExpression(expression.body, functionScope)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#parseMemberExpression = (expression: AcornJSX.MemberExpression, scope?: Scope): any => {
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
let { object } = expression
|
||||
const path = [expression.property?.name ?? JSON.parse(expression.property?.raw ?? '""')]
|
||||
|
||||
if (expression.object.type !== 'Literal') {
|
||||
while (object && ['MemberExpression', 'Literal'].includes(object?.type)) {
|
||||
const { property } = (object as AcornJSX.MemberExpression)
|
||||
if ((object as AcornJSX.MemberExpression).computed) {
|
||||
path.unshift(this.#parseExpression(property!, scope))
|
||||
} else {
|
||||
path.unshift(property?.name ?? JSON.parse(property?.raw ?? '""'))
|
||||
}
|
||||
|
||||
object = (object as AcornJSX.MemberExpression).object
|
||||
}
|
||||
}
|
||||
|
||||
const target = this.#parseExpression(object, scope)
|
||||
try {
|
||||
let parent = target
|
||||
const member = path.reduce((value, next) => {
|
||||
parent = value
|
||||
return value[next]
|
||||
}, target)
|
||||
if (typeof member === 'function') return member.bind(parent)
|
||||
|
||||
return member
|
||||
} catch {
|
||||
const name = (object as AcornJSX.MemberExpression)?.name || 'unknown'
|
||||
this.props.onError!(new Error(`Unable to parse ${name}["${path.join('"]["')}"]}`))
|
||||
}
|
||||
}
|
||||
|
||||
#parseName = (element: AcornJSX.JSXIdentifier | AcornJSX.JSXMemberExpression): string => {
|
||||
if (element.type === 'JSXIdentifier') { return element.name }
|
||||
return `${this.#parseName(element.object)}.${this.#parseName(element.property)}`
|
||||
}
|
||||
|
||||
#parseElement = (
|
||||
element: AcornJSX.JSXElement | AcornJSX.JSXFragment,
|
||||
scope?: Scope,
|
||||
): JSX.Element | JSX.Element[] | null => {
|
||||
const { allowUnknownElements, components, componentsOnly, onError } = this.props
|
||||
const { children: childNodes = [] } = element
|
||||
const openingTag = element.type === 'JSXElement'
|
||||
? element.openingElement
|
||||
: element.openingFragment
|
||||
const { attributes = [] } = openingTag
|
||||
const name = element.type === 'JSXElement'
|
||||
? this.#parseName(openingTag.name)
|
||||
: ''
|
||||
|
||||
const blacklistedAttrs = (this.props.blacklistedAttrs || [])
|
||||
.map(attr => (attr instanceof RegExp ? attr : new RegExp(attr, 'i')))
|
||||
const blacklistedTags = (this.props.blacklistedTags || [])
|
||||
.map(tag => tag.trim().toLowerCase()).filter(Boolean)
|
||||
|
||||
if (/^(html|head|body)$/i.test(name)) {
|
||||
return childNodes.map(c => this.#parseElement(c, scope)) as JSX.Element[]
|
||||
}
|
||||
const tagName = name.trim().toLowerCase()
|
||||
if (blacklistedTags.indexOf(tagName) !== -1) {
|
||||
onError!(new Error(`The tag <${name}> is blacklisted, and will not be rendered.`))
|
||||
return null
|
||||
}
|
||||
|
||||
if (name !== '' && !resolvePath(components, name)) {
|
||||
if (componentsOnly) {
|
||||
onError!(new Error(`The component <${name}> is unrecognized, and will not be rendered.`))
|
||||
return this.props.renderUnrecognized!(name)
|
||||
}
|
||||
|
||||
if (!allowUnknownElements && document.createElement(name) instanceof HTMLUnknownElement) {
|
||||
onError!(new Error(`The tag <${name}> is unrecognized in this browser, and will not be rendered.`))
|
||||
return this.props.renderUnrecognized!(name)
|
||||
}
|
||||
}
|
||||
|
||||
let children
|
||||
const component = element.type === 'JSXElement'
|
||||
? resolvePath(components, name)
|
||||
: Fragment
|
||||
|
||||
if (component || canHaveChildren(name)) {
|
||||
children = childNodes.map(node => this.#parseExpression(node, scope))
|
||||
if (!component && !canHaveWhitespace(name)) {
|
||||
children = children.filter(child => (
|
||||
typeof child !== 'string' || !/^\s*$/.test(child)
|
||||
))
|
||||
}
|
||||
|
||||
if (children.length === 0) {
|
||||
children = undefined
|
||||
} else if (children.length === 1) {
|
||||
[children] = children
|
||||
} else if (children.length > 1 && !this.props.disableKeyGeneration) {
|
||||
// Add `key` to any child that is a react element (by checking if it has `.type`) if one
|
||||
// does not already exist.
|
||||
children = children.map((child, key) => (
|
||||
(child?.type && !child?.key) ? { ...child, key: child.key || key } : child
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
const props: { [key: string]: any } = {
|
||||
key: this.props.disableKeyGeneration ? undefined : randomHash(),
|
||||
}
|
||||
attributes.forEach( // eslint-disable-next-line max-len
|
||||
(expr: AcornJSX.JSXAttribute | AcornJSX.JSXAttributeExpression | AcornJSX.JSXSpreadAttribute) => {
|
||||
if (expr.type === 'JSXAttribute') {
|
||||
const rawName = expr.name.name
|
||||
const attributeName = ATTRIBUTES[rawName] || rawName
|
||||
// if the value is null, this is an implicitly "true" prop, such as readOnly
|
||||
const value = this.#parseExpression(expr, scope)
|
||||
|
||||
const matches = blacklistedAttrs.filter(re => re.test(attributeName))
|
||||
if (matches.length === 0) {
|
||||
props[attributeName] = value
|
||||
}
|
||||
} else if (
|
||||
(expr.type === 'JSXSpreadAttribute' && expr.argument.type === 'Identifier')
|
||||
|| expr.argument!.type === 'MemberExpression'
|
||||
) {
|
||||
const value = this.#parseExpression(expr.argument!, scope)
|
||||
if (typeof value === 'object') {
|
||||
Object.keys(value).forEach(rawName => {
|
||||
const attributeName: string = ATTRIBUTES[rawName] || rawName
|
||||
const matches = blacklistedAttrs.filter(re => re.test(attributeName))
|
||||
if (matches.length === 0) {
|
||||
props[attributeName] = value[rawName]
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
if (typeof props.style === 'string') {
|
||||
props.style = parseStyle(props.style)
|
||||
}
|
||||
const lowerName = name.toLowerCase()
|
||||
if (lowerName === 'option') {
|
||||
children = children.props.children
|
||||
}
|
||||
|
||||
return React.createElement(component || lowerName, props, children)
|
||||
}
|
||||
|
||||
render = (): JSX.Element => {
|
||||
const jsx = (this.props.jsx || '').trim().replace(/<!DOCTYPE([^>]*)>/g, '')
|
||||
this.ParsedChildren = this.#parseJSX(jsx)
|
||||
const className = [...new Set(['jsx-parser', ...String(this.props.className).split(' ')])]
|
||||
.filter(Boolean)
|
||||
.join(' ')
|
||||
|
||||
return (
|
||||
this.props.renderInWrapper
|
||||
? <div className={className}>{this.ParsedChildren}</div>
|
||||
: <>{this.ParsedChildren}</>
|
||||
)
|
||||
}
|
||||
}
|
||||
/* eslint-enable consistent-return */
|
||||
@@ -0,0 +1,7 @@
|
||||
export default {
|
||||
class: 'className',
|
||||
for: 'htmlFor',
|
||||
maxlength: 'maxLength',
|
||||
colspan: 'colSpan',
|
||||
rowspan: 'rowSpan',
|
||||
} as Record<string, string>
|
||||
@@ -0,0 +1,35 @@
|
||||
const VOID_ELEMENTS = [
|
||||
'area',
|
||||
'base',
|
||||
'br',
|
||||
'col',
|
||||
'embed',
|
||||
'hr',
|
||||
'img',
|
||||
'input',
|
||||
'keygen',
|
||||
'link',
|
||||
'menuitem',
|
||||
'meta',
|
||||
'param',
|
||||
'source',
|
||||
'track',
|
||||
'wbr',
|
||||
]
|
||||
|
||||
const NO_WHITESPACE = [
|
||||
'table',
|
||||
'tbody',
|
||||
'tfoot',
|
||||
'thead',
|
||||
'tr',
|
||||
]
|
||||
|
||||
export default VOID_ELEMENTS
|
||||
|
||||
export function canHaveChildren(tagName: string): boolean {
|
||||
return VOID_ELEMENTS.indexOf(tagName.toLowerCase()) === -1
|
||||
}
|
||||
export function canHaveWhitespace(tagName: string): boolean {
|
||||
return NO_WHITESPACE.indexOf(tagName.toLowerCase()) !== -1
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Converts a string from other cases to camelCase
|
||||
* @param string the value to camelCase
|
||||
* @example
|
||||
* camelCase('foo-bar') // 'fooBar'
|
||||
*/
|
||||
export const camelCase = (string: string) => string
|
||||
.replace(/([A-Z])([A-Z])/g, '$1 $2')
|
||||
.replace(/([a-z])([A-Z])/g, '$1 $2')
|
||||
.replace(/[^a-zA-Z\u00C0-\u00ff]/g, ' ')
|
||||
.toLowerCase()
|
||||
.split(' ')
|
||||
.filter(value => value)
|
||||
.map((s, i) => (i > 0 ? s[0].toUpperCase() + s.slice(1) : s))
|
||||
.join('')
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Hashes a value
|
||||
* @param value the value to hash
|
||||
* @param radix the base-n to hash into (default 16)
|
||||
*/
|
||||
export const hash = (value: string = '', radix: number = 16): string => {
|
||||
const string = String(value)
|
||||
let h = 0
|
||||
string.split('').forEach((char: string) => {
|
||||
/* eslint-disable no-bitwise */
|
||||
h = ((h << 5) - h) + char.charCodeAt(0)
|
||||
h &= h // Convert to 32-bit integer
|
||||
/* eslint-enable no-bitwise */
|
||||
})
|
||||
return Math.abs(h).toString(radix)
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashes a Math.random() value, returning it in base16
|
||||
*/
|
||||
export const randomHash = () => hash(Math.random().toString())
|
||||
@@ -0,0 +1,29 @@
|
||||
import { camelCase } from './camelCase'
|
||||
|
||||
type Style = string | Partial<CSSStyleDeclaration>
|
||||
|
||||
/**
|
||||
* Converts a CSS Style string
|
||||
* @param {string | Partial<CSSStyleDeclaration>} style A string to convert, or object to return
|
||||
* @returns {Partial<CSSStyleDeclaration>} a partial CSSStyleDeclaration
|
||||
*/
|
||||
export const parseStyle = (style: Style): Partial<CSSStyleDeclaration> | undefined => {
|
||||
switch (typeof style) {
|
||||
case 'string':
|
||||
return style.split(';').filter(r => r)
|
||||
.reduce((map, rule) => {
|
||||
const name = rule.slice(0, rule.indexOf(':')).trim()
|
||||
const value = rule.slice(rule.indexOf(':') + 1).trim()
|
||||
|
||||
return {
|
||||
...map,
|
||||
[camelCase(name)]: value,
|
||||
}
|
||||
}, {})
|
||||
case 'object':
|
||||
return style
|
||||
|
||||
default:
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
const pathToArrayPath = (path: string) => {
|
||||
if (path == null || path === '') return []
|
||||
return path.split('.')
|
||||
}
|
||||
|
||||
const resolveArrayPath = (object: any, path: string[]): string | undefined => {
|
||||
const [property, ...subPath] = path
|
||||
if (object == null || property == null) {
|
||||
return undefined
|
||||
}
|
||||
return subPath.length === 0
|
||||
? object[property]
|
||||
: resolveArrayPath(object[property], subPath)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the result of a path query from an object
|
||||
* @param {any} object the object to search
|
||||
* @param {string} path the path, whose value will be retrieved
|
||||
* @returns {any} the value (undefined if the path doesn't exist)
|
||||
* @example
|
||||
* resolvePath({ foo: { bar: { baz: 3 } } }, 'foo.bar.baz') // 3
|
||||
*/
|
||||
export const resolvePath = (object: any, path: string): any => (
|
||||
resolveArrayPath(object, pathToArrayPath(path))
|
||||
)
|
||||
@@ -0,0 +1,23 @@
|
||||
// The module cache
|
||||
var __webpack_module_cache__ = {};
|
||||
|
||||
// The require function
|
||||
function __webpack_require__(moduleId) {
|
||||
// Check if module is in cache
|
||||
if(__webpack_module_cache__[moduleId]) {
|
||||
return __webpack_module_cache__[moduleId].exports;
|
||||
}
|
||||
// Create a new module (and put it into the cache)
|
||||
var module = __webpack_module_cache__[moduleId] = {
|
||||
// no module.id needed
|
||||
// no module.loaded needed
|
||||
exports: {}
|
||||
};
|
||||
|
||||
// Execute the module function
|
||||
__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||
|
||||
// Return the exports of the module
|
||||
return module.exports;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// getDefaultExport function for compatibility with non-harmony modules
|
||||
__webpack_require__.n = (module) => {
|
||||
var getter = module && module.__esModule ?
|
||||
() => (module['default']) :
|
||||
() => (module);
|
||||
__webpack_require__.d(getter, { a: getter });
|
||||
return getter;
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
// define getter functions for harmony exports
|
||||
__webpack_require__.d = (exports, definition) => {
|
||||
for(var key in definition) {
|
||||
if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
|
||||
Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
|
||||
@@ -0,0 +1,7 @@
|
||||
// define __esModule on exports
|
||||
__webpack_require__.r = (exports) => {
|
||||
if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
||||
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
||||
}
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
// module exports must be returned from runtime so entry inlining is disabled
|
||||
// startup
|
||||
// Load entry module and return exports
|
||||
return __webpack_require__(272);
|
||||
@@ -0,0 +1,11 @@
|
||||
(function webpackUniversalModuleDefinition(root, factory) {
|
||||
if(typeof exports === 'object' && typeof module === 'object')
|
||||
module.exports = factory(require("react"));
|
||||
else if(typeof define === 'function' && define.amd)
|
||||
define("react-jsx-parser", ["react"], factory);
|
||||
else if(typeof exports === 'object')
|
||||
exports["react-jsx-parser"] = factory(require("react"));
|
||||
else
|
||||
root["react-jsx-parser"] = factory(root["react"]);
|
||||
})(this, function(__WEBPACK_EXTERNAL_MODULE__297__) {
|
||||
return
|
||||
Reference in New Issue
Block a user