@riotjs/parser
Advanced tools
Comparing version 4.3.1 to 5.0.0
399
index.js
@@ -1,5 +0,1 @@ | ||
'use strict'; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
const JAVASCRIPT_OUTPUT_NAME = 'javascript'; | ||
@@ -24,14 +20,14 @@ const CSS_OUTPUT_NAME = 'css'; | ||
__proto__: null, | ||
JAVASCRIPT_OUTPUT_NAME: JAVASCRIPT_OUTPUT_NAME, | ||
CSS_OUTPUT_NAME: CSS_OUTPUT_NAME, | ||
TEMPLATE_OUTPUT_NAME: TEMPLATE_OUTPUT_NAME, | ||
JAVASCRIPT_TAG: JAVASCRIPT_TAG, | ||
STYLE_TAG: STYLE_TAG, | ||
TEXTAREA_TAG: TEXTAREA_TAG, | ||
IS_BOOLEAN: IS_BOOLEAN, | ||
IS_CUSTOM: IS_CUSTOM, | ||
IS_RAW: IS_RAW, | ||
IS_SELF_CLOSING: IS_SELF_CLOSING, | ||
IS_SPREAD: IS_SPREAD, | ||
IS_VOID: IS_VOID, | ||
IS_BOOLEAN: IS_BOOLEAN, | ||
IS_CUSTOM: IS_CUSTOM, | ||
IS_SPREAD: IS_SPREAD | ||
JAVASCRIPT_OUTPUT_NAME: JAVASCRIPT_OUTPUT_NAME, | ||
JAVASCRIPT_TAG: JAVASCRIPT_TAG, | ||
STYLE_TAG: STYLE_TAG, | ||
TEMPLATE_OUTPUT_NAME: TEMPLATE_OUTPUT_NAME, | ||
TEXTAREA_TAG: TEXTAREA_TAG | ||
}); | ||
@@ -56,10 +52,10 @@ | ||
__proto__: null, | ||
TAG: TAG, | ||
ATTR: ATTR, | ||
TEXT: TEXT, | ||
CDATA: CDATA, | ||
COMMENT: COMMENT, | ||
DOCTYPE: DOCTYPE, | ||
DOCUMENT: DOCUMENT, | ||
DOCTYPE: DOCTYPE, | ||
DOCUMENT_FRAGMENT: DOCUMENT_FRAGMENT | ||
DOCUMENT_FRAGMENT: DOCUMENT_FRAGMENT, | ||
TAG: TAG, | ||
TEXT: TEXT | ||
}); | ||
@@ -72,3 +68,4 @@ | ||
const unclosedNamedBlock = 'Unclosed "%1" block.'; | ||
const duplicatedNamedTag = 'Multiple inline "<%1>" tags are not supported.'; | ||
const duplicatedNamedTag = | ||
'Multiple inline "<%1>" tags are not supported.'; | ||
const unexpectedCharInExpression = 'Unexpected character %1.'; | ||
@@ -113,3 +110,3 @@ const unclosedExpression = 'Unclosed expression.'; | ||
style: /<\/style\s*>/gi, | ||
textarea: /<\/textarea\s*>/gi | ||
textarea: /<\/textarea\s*>/gi, | ||
}; | ||
@@ -182,3 +179,3 @@ | ||
let c; | ||
while (re.lastIndex = pos, re.exec(code)) { | ||
while (((re.lastIndex = pos), re.exec(code))) { | ||
pos = re.lastIndex; | ||
@@ -230,3 +227,3 @@ c = code[pos - 1]; | ||
'void', | ||
'yield' | ||
'yield', | ||
]; | ||
@@ -239,3 +236,4 @@ | ||
// The buffer to search must not include line-endings. | ||
const RE_LIT_REGEX = /^\/(?=[^*>/])[^[/\\]*(?:(?:\\.|\[(?:\\.|[^\]\\]*)*\])[^[\\/]*)*?\/[gimuy]*/; | ||
const RE_LIT_REGEX = | ||
/^\/(?=[^*>/])[^[/\\]*(?:(?:\\.|\[(?:\\.|[^\]\\]*)*\])[^[\\/]*)*?\/[gimuy]*/; | ||
@@ -262,4 +260,2 @@ // Valid characters for JavaScript variable names and literal numbers. | ||
/** | ||
@@ -278,5 +274,5 @@ * Check if the character in the `start` position within `code` can be a regex | ||
*/ | ||
/* istanbul ignore next */ | ||
/* c8 ignore next */ | ||
function skipRegex(code, start) { | ||
let pos = RE_DOT_CHAR.lastIndex = start++; | ||
let pos = (RE_DOT_CHAR.lastIndex = start++); | ||
@@ -288,3 +284,3 @@ // `exec()` will extract from the slash to the end of the line | ||
if (match) { | ||
const next = pos + match[0].length; // result comes from `re.match` | ||
const next = pos + match[0].length; // result comes from `re.match` | ||
@@ -305,15 +301,16 @@ pos = _prev(code, pos); | ||
} | ||
} else { | ||
if (c === '+' || c === '-') { | ||
// tricky case | ||
if (code[--pos] !== c || // if have a single operator or | ||
(pos = _prev(code, pos)) < 0 || // ...have `++` and no previous token | ||
beforeReSign.includes(c = code[pos])) { | ||
return next // ...this is a regex | ||
if ( | ||
code[--pos] !== c || // if have a single operator or | ||
(pos = _prev(code, pos)) < 0 || // ...have `++` and no previous token | ||
beforeReSign.includes((c = code[pos])) | ||
) { | ||
return next // ...this is a regex | ||
} | ||
} | ||
if (wordsEndChar.includes(c)) { // looks like a keyword? | ||
if (wordsEndChar.includes(c)) { | ||
// looks like a keyword? | ||
const end = pos + 1; | ||
@@ -397,22 +394,22 @@ | ||
switch (char) { | ||
case '[': | ||
case '(': | ||
case '{': | ||
stack.push(char === '[' ? ']' : char === '(' ? ')' : '}'); | ||
break | ||
case ')': | ||
case ']': | ||
case '}': | ||
if (char !== stack.pop()) { | ||
panic(code, unexpectedCharInExpression.replace('%1', char), index); | ||
} | ||
case '[': | ||
case '(': | ||
case '{': | ||
stack.push(char === '[' ? ']' : char === '(' ? ')' : '}'); | ||
break | ||
case ')': | ||
case ']': | ||
case '}': | ||
if (char !== stack.pop()) { | ||
panic(code, unexpectedCharInExpression.replace('%1', char), index); | ||
} | ||
if (char === '}' && stack[stack.length - 1] === $_ES6_BQ) { | ||
char = stack.pop(); | ||
} | ||
if (char === '}' && stack[stack.length - 1] === $_ES6_BQ) { | ||
char = stack.pop(); | ||
} | ||
index = idx + 1; | ||
break | ||
case '/': | ||
index = skipRegex(code, idx); | ||
index = idx + 1; | ||
break | ||
case '/': | ||
index = skipRegex(code, idx); | ||
} | ||
@@ -424,12 +421,12 @@ | ||
/** | ||
* Parses the code string searching the end of the expression. | ||
* It skips braces, quoted strings, regexes, and ES6 template literals. | ||
* | ||
* @function exprExtr | ||
* @param {string} code - Buffer to parse | ||
* @param {number} start - Position of the opening brace | ||
* @param {[string,string]} bp - Brackets pair | ||
* @returns {Object} Expression's end (after the closing brace) or -1 | ||
* if it is not an expr. | ||
*/ | ||
* Parses the code string searching the end of the expression. | ||
* It skips braces, quoted strings, regexes, and ES6 template literals. | ||
* | ||
* @function exprExtr | ||
* @param {string} code - Buffer to parse | ||
* @param {number} start - Position of the opening brace | ||
* @param {[string,string]} bp - Brackets pair | ||
* @returns {Object} Expression's end (after the closing brace) or -1 | ||
* if it is not an expr. | ||
*/ | ||
function exprExtr(code, start, bp) { | ||
@@ -446,3 +443,4 @@ const [openingBraces, closingBraces] = bp; | ||
while (match = re.exec(code)) { // eslint-disable-line | ||
while ((match = re.exec(code))) { | ||
// eslint-disable-line | ||
const idx = match.index; | ||
@@ -457,3 +455,3 @@ const str = match[0]; | ||
start, | ||
end | ||
end, | ||
} | ||
@@ -567,3 +565,3 @@ } | ||
} else { | ||
pushText(state, start, end, {expressions, unescape}); | ||
pushText(state, start, end, { expressions, unescape }); | ||
} | ||
@@ -609,8 +607,6 @@ | ||
expressions, | ||
end: match.index | ||
end: match.index, | ||
} | ||
} | ||
/** | ||
@@ -990,3 +986,3 @@ * Creates a regex for the given string and the left bracket. | ||
*/ | ||
const HTML_ELEMENTS_HAVING_VALUE_ATTRIBUTE_RE = listsToRegex(HTML_ELEMENTS_HAVING_VALUE_ATTRIBUTE_LIST); | ||
listsToRegex(HTML_ELEMENTS_HAVING_VALUE_ATTRIBUTE_LIST); | ||
@@ -1063,6 +1059,9 @@ /** | ||
const expressionsContentRe = memoize(brackets => RegExp(`(${brackets[0]}[^${brackets[1]}]*?${brackets[1]})`, 'g')); | ||
const isSpreadAttribute = name => SPREAD_OPERATOR.test(name); | ||
const expressionsContentRe = memoize((brackets) => | ||
RegExp(`(${brackets[0]}[^${brackets[1]}]*?${brackets[1]})`, 'g'), | ||
); | ||
const isSpreadAttribute = (name) => SPREAD_OPERATOR.test(name); | ||
const isAttributeExpression = (name, brackets) => name[0] === brackets[0]; | ||
const getAttributeEnd = (state, attr) => expr(state, attr, '[>/\\s]', attr.start); | ||
const getAttributeEnd = (state, attr) => | ||
expr(state, attr, '[>/\\s]', attr.start); | ||
@@ -1084,24 +1083,24 @@ /** | ||
switch (true) { | ||
case !ch: | ||
state.pos = data.length; // reaching the end of the buffer with | ||
// NodeTypes.ATTR will generate error | ||
break | ||
case ch[0] === '>': | ||
// closing char found. If this is a self-closing tag with the name of the | ||
// Root tag, we need decrement the counter as we are changing mode. | ||
state.pos = tag.end = _CH.lastIndex; | ||
if (tag[IS_SELF_CLOSING]) { | ||
state.scryle = null; // allow selfClosing script/style tags | ||
if (root && root.name === tag.name) { | ||
state.count--; // "pop" root tag | ||
case !ch: | ||
state.pos = data.length; // reaching the end of the buffer with | ||
// NodeTypes.ATTR will generate error | ||
break | ||
case ch[0] === '>': | ||
// closing char found. If this is a self-closing tag with the name of the | ||
// Root tag, we need decrement the counter as we are changing mode. | ||
state.pos = tag.end = _CH.lastIndex; | ||
if (tag[IS_SELF_CLOSING]) { | ||
state.scryle = null; // allow selfClosing script/style tags | ||
if (root && root.name === tag.name) { | ||
state.count--; // "pop" root tag | ||
} | ||
} | ||
} | ||
return TEXT | ||
case ch[0] === '/': | ||
state.pos = _CH.lastIndex; // maybe. delegate the validation | ||
tag[IS_SELF_CLOSING] = true; // the next loop | ||
break | ||
default: | ||
delete tag[IS_SELF_CLOSING]; // ensure unmark as selfclosing tag | ||
setAttribute(state, ch.index, tag); | ||
return TEXT | ||
case ch[0] === '/': | ||
state.pos = _CH.lastIndex; // maybe. delegate the validation | ||
tag[IS_SELF_CLOSING] = true; // the next loop | ||
break | ||
default: | ||
delete tag[IS_SELF_CLOSING]; // ensure unmark as selfclosing tag | ||
setAttribute(state, ch.index, tag); | ||
} | ||
@@ -1125,6 +1124,11 @@ | ||
const re = ATTR_START; // (\S[^>/=\s]*)(?:\s*=\s*([^>/])?)? g | ||
const start = re.lastIndex = expressionContent.lastIndex = pos; // first non-whitespace | ||
const start = (re.lastIndex = expressionContent.lastIndex = pos); // first non-whitespace | ||
const attrMatches = re.exec(data); | ||
const isExpressionName = isAttributeExpression(attrMatches[1], state.options.brackets); | ||
const match = isExpressionName ? [null, expressionContent.exec(data)[1], null] : attrMatches; | ||
const isExpressionName = isAttributeExpression( | ||
attrMatches[1], | ||
state.options.brackets, | ||
); | ||
const match = isExpressionName | ||
? [null, expressionContent.exec(data)[1], null] | ||
: attrMatches; | ||
@@ -1156,3 +1160,3 @@ if (match) { | ||
// If it not, this is an unquoted value and we need adjust the start. | ||
if (quote !== '"' && quote !== '\'') { | ||
if (quote !== '"' && quote !== "'") { | ||
quote = ''; // first char of value is not a quote | ||
@@ -1168,3 +1172,3 @@ valueStart--; // adjust the starting position | ||
valueStart, | ||
end: quote ? ++end : end | ||
end: quote ? ++end : end, | ||
}) | ||
@@ -1176,3 +1180,2 @@ } | ||
/** | ||
@@ -1190,6 +1193,8 @@ * Parse expression names <a {href}> | ||
start: attr.start, | ||
expressions: attr.expressions.map(expr => Object.assign(expr, { | ||
text: expr.text.replace(SPREAD_OPERATOR, '').trim() | ||
})), | ||
end: end | ||
expressions: attr.expressions.map((expr) => | ||
Object.assign(expr, { | ||
text: expr.text.replace(SPREAD_OPERATOR, '').trim(), | ||
}), | ||
), | ||
end: end, | ||
} | ||
@@ -1211,3 +1216,3 @@ } | ||
expressions: attr.expressions, | ||
end: end | ||
end: end, | ||
} | ||
@@ -1230,3 +1235,3 @@ } | ||
start, | ||
end | ||
end, | ||
}; | ||
@@ -1237,8 +1242,8 @@ | ||
switch (true) { | ||
case isSpreadAttribute(attr.name): | ||
return parseSpreadAttribute(state, attr) | ||
case isExpressionName === true: | ||
return parseExpressionNameAttribute(state, attr) | ||
default: | ||
return parseNomalAttribute(state, attr, quote) | ||
case isSpreadAttribute(attr.name): | ||
return parseSpreadAttribute(state, attr) | ||
case isExpressionName === true: | ||
return parseExpressionNameAttribute(state, attr) | ||
default: | ||
return parseNomalAttribute(state, attr, quote) | ||
} | ||
@@ -1288,3 +1293,3 @@ } | ||
end + str.length, | ||
data.substring(start, end + str.length) | ||
data.substring(start, end + str.length), | ||
); | ||
@@ -1313,3 +1318,3 @@ | ||
end, | ||
text | ||
text, | ||
}; | ||
@@ -1374,8 +1379,8 @@ } | ||
switch (true) { | ||
case str[0] === '!': | ||
return comment(state, data, start) | ||
case TAG_2C.test(str): | ||
return parseTag(state, start) | ||
default: | ||
return pushText(state, start, pos) // pushes the '<' as text | ||
case str[0] === '!': | ||
return comment(state, data, start) | ||
case TAG_2C.test(str): | ||
return parseTag(state, start) | ||
default: | ||
return pushText(state, start, pos) // pushes the '<' as text | ||
} | ||
@@ -1416,28 +1421,28 @@ } | ||
switch (true) { | ||
case typeof scryle === 'string': { | ||
const name = scryle; | ||
const re = RE_SCRYLE[name]; | ||
const match = execFromPos(re, pos, data); | ||
case typeof scryle === 'string': { | ||
const name = scryle; | ||
const re = RE_SCRYLE[name]; | ||
const match = execFromPos(re, pos, data); | ||
if (!match) { | ||
panic(data, unclosedNamedBlock.replace('%1', name), pos - 1); | ||
} | ||
if (!match) { | ||
panic(data, unclosedNamedBlock.replace('%1', name), pos - 1); | ||
} | ||
const start = match.index; | ||
const end = re.lastIndex; | ||
state.scryle = null; // reset the script/style flag now | ||
// write the tag content, if any | ||
if (start > pos) { | ||
parseSpecialTagsContent(state, name, match); | ||
const start = match.index; | ||
const end = re.lastIndex; | ||
state.scryle = null; // reset the script/style flag now | ||
// write the tag content, if any | ||
if (start > pos) { | ||
parseSpecialTagsContent(state, name, match); | ||
} | ||
// now the closing tag, either </script> or </style> | ||
pushTag(state, `/${name}`, start, end); | ||
break | ||
} | ||
// now the closing tag, either </script> or </style> | ||
pushTag(state, `/${name}`, start, end); | ||
break | ||
case data[pos] === '<': | ||
state.pos++; | ||
return TAG | ||
default: | ||
expr(state, null, '<', pos); | ||
} | ||
case data[pos] === '<': | ||
state.pos++; | ||
return TAG | ||
default: | ||
expr(state, null, '<', pos); | ||
} | ||
@@ -1492,9 +1497,8 @@ return TEXT | ||
function escapeReturn(string) { | ||
return string | ||
.replace(/\r/g, '\\r') | ||
.replace(/\n/g, '\\n') | ||
return string.replace(/\r/g, '\\r').replace(/\n/g, '\\n') | ||
} | ||
// check whether a tag has the 'src' attribute set like for example `<script src="">` | ||
const hasSrcAttribute = node => (node.attributes || []).some(attr => attr.name === 'src'); | ||
const hasSrcAttribute = (node) => | ||
(node.attributes || []).some((attr) => attr.name === 'src'); | ||
@@ -1526,3 +1530,3 @@ /** | ||
[CSS_OUTPUT_NAME]: store[STYLE_TAG], | ||
[JAVASCRIPT_OUTPUT_NAME]: store[JAVASCRIPT_TAG] | ||
[JAVASCRIPT_OUTPUT_NAME]: store[JAVASCRIPT_TAG], | ||
} | ||
@@ -1532,6 +1536,6 @@ }, | ||
/** | ||
* Process the current tag or text. | ||
* @param {Object} node - Raw pseudo-node from the parser | ||
* @returns {undefined} void function | ||
*/ | ||
* Process the current tag or text. | ||
* @param {Object} node - Raw pseudo-node from the parser | ||
* @returns {undefined} void function | ||
*/ | ||
push(node) { | ||
@@ -1541,21 +1545,21 @@ const store = this.store; | ||
switch (node.type) { | ||
case COMMENT: | ||
this.pushComment(store, node); | ||
break | ||
case TEXT: | ||
this.pushText(store, node); | ||
break | ||
case TAG: { | ||
const name = node.name; | ||
const closingTagChar = '/'; | ||
const [firstChar] = name; | ||
case COMMENT: | ||
this.pushComment(store, node); | ||
break | ||
case TEXT: | ||
this.pushText(store, node); | ||
break | ||
case TAG: { | ||
const name = node.name; | ||
const closingTagChar = '/'; | ||
const [firstChar] = name; | ||
if (firstChar === closingTagChar && !node.isVoid) { | ||
this.closeTag(store, node, name); | ||
} else if (firstChar !== closingTagChar) { | ||
this.openTag(store, node); | ||
if (firstChar === closingTagChar && !node.isVoid) { | ||
this.closeTag(store, node, name); | ||
} else if (firstChar !== closingTagChar) { | ||
this.openTag(store, node); | ||
} | ||
break | ||
} | ||
break | ||
} | ||
} | ||
}, | ||
@@ -1585,3 +1589,4 @@ pushComment(store, node) { | ||
const attrs = node.attributes; | ||
const isCoreTag = (JAVASCRIPT_TAG === name && !hasSrcAttribute(node) || name === STYLE_TAG); | ||
const isCoreTag = | ||
(JAVASCRIPT_TAG === name && !hasSrcAttribute(node)) || name === STYLE_TAG; | ||
@@ -1591,3 +1596,7 @@ if (isCoreTag) { | ||
if (store[name]) { | ||
panic(this.store.data, duplicatedNamedTag.replace('%1', name), node.start); | ||
panic( | ||
this.store.data, | ||
duplicatedNamedTag.replace('%1', name), | ||
node.start, | ||
); | ||
} | ||
@@ -1622,3 +1631,3 @@ | ||
attrs(attributes) { | ||
attributes.forEach(attr => { | ||
attributes.forEach((attr) => { | ||
if (attr.value) { | ||
@@ -1654,6 +1663,9 @@ this.split(attr, attr.value, attr.valueStart, true); | ||
expressions.forEach(expr => { | ||
expressions.forEach((expr) => { | ||
const text = source.slice(pos, expr.start - start); | ||
const code = expr.text; | ||
parts.push(this.sanitise(node, text, pack), escapeReturn(escapeSlashes(code).trim())); | ||
parts.push( | ||
this.sanitise(node, text, pack), | ||
escapeReturn(escapeSlashes(code).trim()), | ||
); | ||
pos = expr.end - start; | ||
@@ -1669,3 +1681,3 @@ }); | ||
node.parts = parts.filter(p => p); // remove the empty strings | ||
node.parts = parts.filter((p) => p); // remove the empty strings | ||
}, | ||
@@ -1687,3 +1699,3 @@ // unescape escaped brackets and split prefixes of expressions | ||
return pack ? cleanSpaces(text) : escapeReturn(text) | ||
} | ||
}, | ||
}); | ||
@@ -1697,3 +1709,3 @@ | ||
end: 0, | ||
nodes: [] | ||
nodes: [], | ||
}; | ||
@@ -1710,4 +1722,4 @@ | ||
script: null, | ||
data | ||
} | ||
data, | ||
}, | ||
}) | ||
@@ -1727,3 +1739,3 @@ } | ||
return { | ||
parse: (data) => parse(state(data)) | ||
parse: (data) => parse(state(data)), | ||
} | ||
@@ -1740,5 +1752,8 @@ } | ||
function createParserState(userOptions, builder, data) { | ||
const options = Object.assign({ | ||
brackets: ['{', '}'] | ||
}, userOptions); | ||
const options = Object.assign( | ||
{ | ||
brackets: ['{', '}'], | ||
}, | ||
userOptions, | ||
); | ||
@@ -1754,3 +1769,3 @@ return { | ||
builder: builder(data, options), | ||
data | ||
data, | ||
} | ||
@@ -1777,3 +1792,7 @@ } | ||
if (state.count) { | ||
panic(data, state.count > 0 ? unexpectedEndOfFile : rootTagNotFound, state.pos); | ||
panic( | ||
data, | ||
state.count > 0 ? unexpectedEndOfFile : rootTagNotFound, | ||
state.pos, | ||
); | ||
} | ||
@@ -1783,3 +1802,3 @@ | ||
data, | ||
output: state.builder.get() | ||
output: state.builder.get(), | ||
} | ||
@@ -1815,8 +1834,8 @@ } | ||
switch (type) { | ||
case TAG: | ||
return tag(state) | ||
case ATTR: | ||
return attr(state) | ||
default: | ||
return text(state) | ||
case TAG: | ||
return tag(state) | ||
case ATTR: | ||
return attr(state) | ||
default: | ||
return text(state) | ||
} | ||
@@ -1835,4 +1854,2 @@ } | ||
exports.constants = constants; | ||
exports.default = parser; | ||
exports.nodeTypes = nodeTypes; | ||
export { constants, parser as default, nodeTypes }; |
{ | ||
"name": "@riotjs/parser", | ||
"version": "4.3.1", | ||
"version": "5.0.0", | ||
"description": "The parser for Riot tags", | ||
"main": "./index.js", | ||
"module": "./src/index.js", | ||
"jsnext:main": "./src/index.js", | ||
"type": "module", | ||
"main": "./index.cjs", | ||
"module": "./index.js", | ||
"exports": { | ||
".": { | ||
"import": "./index.js", | ||
"require": "./index.cjs" | ||
} | ||
}, | ||
"license": "MIT", | ||
@@ -14,11 +20,11 @@ "engines": { | ||
"scripts": { | ||
"test": "nyc mocha ./test/index", | ||
"test": "c8 mocha ./test/index", | ||
"test-debug": "mocha --inspect-brk ./test", | ||
"cov": "nyc report --reporter=text-lcov | coveralls", | ||
"cov-html": "nyc report --reporter=html", | ||
"cov": "c8 report --reporter=lcov", | ||
"cov-html": "c8 report --reporter=html", | ||
"pretest": "npm run build", | ||
"lint": "eslint src test", | ||
"lint": "eslint src test && npx prettier --check ./", | ||
"build": "rollup -c", | ||
"samples": "node ./test/samples.js", | ||
"prepublish": "npm run build" | ||
"prepublishOnly": "npm run build" | ||
}, | ||
@@ -50,15 +56,16 @@ "files": [ | ||
"devDependencies": { | ||
"chai": "^4.2.0", | ||
"coveralls": "^3.1.0", | ||
"eslint": "^7.6.0", | ||
"eslint-config-riot": "^3.0.0", | ||
"mocha": "^8.1.1", | ||
"nyc": "^15.1.0", | ||
"rollup": "^2.23.0", | ||
"@riotjs/prettier-config": "^1.0.1", | ||
"c8": "^7.13.0", | ||
"chai": "^4.3.7", | ||
"eslint": "^8.39.0", | ||
"eslint-config-riot": "^4.0.0", | ||
"mocha": "^10.2.0", | ||
"prettier": "^2.8.8", | ||
"rollup": "^3.21.0", | ||
"rollup-plugin-node-resolve": "^5.2.0" | ||
}, | ||
"dependencies": { | ||
"curri": "^1.0.1", | ||
"curri": "^2.0.3", | ||
"dom-nodes": "^1.1.3" | ||
} | ||
} |
# parser | ||
[![Build Status][travis-image]][travis-url] | ||
[![Build Status][ci-image]][ci-url] | ||
[![Code Quality][codeclimate-image]][codeclimate-url] | ||
@@ -39,5 +39,5 @@ [![NPM version][npm-version-image]][npm-url] | ||
* Tags - HTMLElements, including SCRIPT and STYLE elements. | ||
* Comments - Ignored by default. | ||
* Text - Text nodes. | ||
- Tags - HTMLElements, including SCRIPT and STYLE elements. | ||
- Comments - Ignored by default. | ||
- Text - Text nodes. | ||
@@ -52,4 +52,4 @@ Opening tags can contain attributes. Text and attribute values can contain expressions. | ||
{ | ||
data, // String of the given html fragment with no changes. | ||
output // Array of objects with information about the parsed tags. | ||
data, // String of the given html fragment with no changes. | ||
output // Array of objects with information about the parsed tags. | ||
} | ||
@@ -62,8 +62,7 @@ ``` | ||
### Commands | ||
* Build: `npm run build` | ||
* Test: `npm t` | ||
* Samples: `npm run samples` | ||
- Build: `npm run build` | ||
- Test: `npm t` | ||
- Samples: `npm run samples` | ||
@@ -125,20 +124,15 @@ ## Tag names | ||
* `comments` - Pass `true` to preserve the comments. | ||
* `brackets` - Array of two string with the left/right brackets used to extract expressions. | ||
- `comments` - Pass `true` to preserve the comments. | ||
- `brackets` - Array of two string with the left/right brackets used to extract expressions. | ||
[travis-image]:https://img.shields.io/travis/riot/parser.svg?style=flat-square | ||
[travis-url]:https://travis-ci.org/riot/parser | ||
[license-image]:http://img.shields.io/badge/license-MIT-000000.svg?style=flat-square | ||
[license-url]:LICENSE.txt | ||
[npm-version-image]:http://img.shields.io/npm/v/@riotjs/parser.svg?style=flat-square | ||
[npm-downloads-image]:http://img.shields.io/npm/dm/@riotjs/parser.svg?style=flat-square | ||
[npm-url]:https://npmjs.org/package/@riotjs/parser | ||
[coverage-image]:https://img.shields.io/coveralls/riot/parser/master.svg?style=flat-square | ||
[coverage-url]:https://coveralls.io/r/riot/parser/?branch=master | ||
[codeclimate-image]:https://api.codeclimate.com/v1/badges/5db4f1c96a43e3736cf0/maintainability | ||
[codeclimate-url]:https://codeclimate.com/github/riot/parser | ||
[ci-image]: https://img.shields.io/github/actions/workflow/status/riot/parser/test.yml?style=flat-square | ||
[ci-url]: https://github.com/riot/parser/actions | ||
[license-image]: http://img.shields.io/badge/license-MIT-000000.svg?style=flat-square | ||
[license-url]: LICENSE.txt | ||
[npm-version-image]: http://img.shields.io/npm/v/@riotjs/parser.svg?style=flat-square | ||
[npm-downloads-image]: http://img.shields.io/npm/dm/@riotjs/parser.svg?style=flat-square | ||
[npm-url]: https://npmjs.org/package/@riotjs/parser | ||
[coverage-image]: https://img.shields.io/coveralls/riot/parser/master.svg?style=flat-square | ||
[coverage-url]: https://coveralls.io/r/riot/parser/?branch=master | ||
[codeclimate-image]: https://api.codeclimate.com/v1/badges/5db4f1c96a43e3736cf0/maintainability | ||
[codeclimate-url]: https://codeclimate.com/github/riot/parser |
@@ -5,8 +5,15 @@ import resolve from 'rollup-plugin-node-resolve' | ||
input: 'src/index.js', | ||
output: { | ||
name: 'parser', | ||
format: 'cjs', | ||
file: './index.js' | ||
}, | ||
plugins: [resolve()] | ||
} | ||
output: [ | ||
{ | ||
name: 'parser', | ||
format: 'cjs', | ||
file: './index.cjs', | ||
}, | ||
{ | ||
name: 'parser', | ||
format: 'esm', | ||
file: './index.js', | ||
}, | ||
], | ||
plugins: [resolve()], | ||
} |
@@ -19,2 +19,1 @@ import * as c from './constants' | ||
export default parser | ||
@@ -7,5 +7,6 @@ export const rootTagNotFound = 'Root tag not found.' | ||
export const unclosedNamedBlock = 'Unclosed "%1" block.' | ||
export const duplicatedNamedTag = 'Multiple inline "<%1>" tags are not supported.' | ||
export const duplicatedNamedTag = | ||
'Multiple inline "<%1>" tags are not supported.' | ||
export const expectedAndInsteadSaw = 'Expected "</%1>" and instead saw "<%2>".' | ||
export const unexpectedCharInExpression = 'Unexpected character %1.' | ||
export const unclosedExpression = 'Unclosed expression.' | ||
export const unclosedExpression = 'Unclosed expression.' |
@@ -14,2 +14,2 @@ /** | ||
export const DOCTYPE = 10 /* DOCTYPE */ | ||
export const DOCUMENT_FRAGMENT = 11 /* DOCUMENT_FRAGMENT */ | ||
export const DOCUMENT_FRAGMENT = 11 /* DOCUMENT_FRAGMENT */ |
@@ -1,3 +0,3 @@ | ||
import {ATTR, TAG} from './node-types' | ||
import {rootTagNotFound, unexpectedEndOfFile} from './messages' | ||
import { ATTR, TAG } from './node-types' | ||
import { rootTagNotFound, unexpectedEndOfFile } from './messages' | ||
import attr from './parsers/attribute' | ||
@@ -22,3 +22,3 @@ import curry from 'curri' | ||
return { | ||
parse: (data) => parse(state(data)) | ||
parse: (data) => parse(state(data)), | ||
} | ||
@@ -35,5 +35,8 @@ } | ||
function createParserState(userOptions, builder, data) { | ||
const options = Object.assign({ | ||
brackets: ['{', '}'] | ||
}, userOptions) | ||
const options = Object.assign( | ||
{ | ||
brackets: ['{', '}'], | ||
}, | ||
userOptions, | ||
) | ||
@@ -49,3 +52,3 @@ return { | ||
builder: builder(data, options), | ||
data | ||
data, | ||
} | ||
@@ -72,3 +75,7 @@ } | ||
if (state.count) { | ||
panic(data, state.count > 0 ? unexpectedEndOfFile : rootTagNotFound, state.pos) | ||
panic( | ||
data, | ||
state.count > 0 ? unexpectedEndOfFile : rootTagNotFound, | ||
state.pos, | ||
) | ||
} | ||
@@ -78,3 +85,3 @@ | ||
data, | ||
output: state.builder.get() | ||
output: state.builder.get(), | ||
} | ||
@@ -110,9 +117,9 @@ } | ||
switch (type) { | ||
case TAG: | ||
return tag(state) | ||
case ATTR: | ||
return attr(state) | ||
default: | ||
return text(state) | ||
case TAG: | ||
return tag(state) | ||
case ATTR: | ||
return attr(state) | ||
default: | ||
return text(state) | ||
} | ||
} | ||
} |
@@ -1,4 +0,4 @@ | ||
import {ATTR, TEXT} from '../node-types' | ||
import {ATTR_START, SPREAD_OPERATOR} from '../regex' | ||
import {IS_BOOLEAN, IS_SELF_CLOSING, IS_SPREAD} from '../constants' | ||
import { ATTR, TEXT } from '../node-types' | ||
import { ATTR_START, SPREAD_OPERATOR } from '../regex' | ||
import { IS_BOOLEAN, IS_SELF_CLOSING, IS_SPREAD } from '../constants' | ||
import addToCollection from '../utils/add-to-collection' | ||
@@ -8,9 +8,12 @@ import execFromPos from '../utils/exec-from-pos' | ||
import getChunk from '../utils/get-chunk' | ||
import {isBoolAttribute} from 'dom-nodes' | ||
import { isBoolAttribute } from 'dom-nodes' | ||
import memoize from '../utils/memoize' | ||
const expressionsContentRe = memoize(brackets => RegExp(`(${brackets[0]}[^${brackets[1]}]*?${brackets[1]})`, 'g')) | ||
const isSpreadAttribute = name => SPREAD_OPERATOR.test(name) | ||
const expressionsContentRe = memoize((brackets) => | ||
RegExp(`(${brackets[0]}[^${brackets[1]}]*?${brackets[1]})`, 'g'), | ||
) | ||
const isSpreadAttribute = (name) => SPREAD_OPERATOR.test(name) | ||
const isAttributeExpression = (name, brackets) => name[0] === brackets[0] | ||
const getAttributeEnd = (state, attr) => expr(state, attr, '[>/\\s]', attr.start) | ||
const getAttributeEnd = (state, attr) => | ||
expr(state, attr, '[>/\\s]', attr.start) | ||
@@ -32,24 +35,24 @@ /** | ||
switch (true) { | ||
case !ch: | ||
state.pos = data.length // reaching the end of the buffer with | ||
// NodeTypes.ATTR will generate error | ||
break | ||
case ch[0] === '>': | ||
// closing char found. If this is a self-closing tag with the name of the | ||
// Root tag, we need decrement the counter as we are changing mode. | ||
state.pos = tag.end = _CH.lastIndex | ||
if (tag[IS_SELF_CLOSING]) { | ||
state.scryle = null // allow selfClosing script/style tags | ||
if (root && root.name === tag.name) { | ||
state.count-- // "pop" root tag | ||
case !ch: | ||
state.pos = data.length // reaching the end of the buffer with | ||
// NodeTypes.ATTR will generate error | ||
break | ||
case ch[0] === '>': | ||
// closing char found. If this is a self-closing tag with the name of the | ||
// Root tag, we need decrement the counter as we are changing mode. | ||
state.pos = tag.end = _CH.lastIndex | ||
if (tag[IS_SELF_CLOSING]) { | ||
state.scryle = null // allow selfClosing script/style tags | ||
if (root && root.name === tag.name) { | ||
state.count-- // "pop" root tag | ||
} | ||
} | ||
} | ||
return TEXT | ||
case ch[0] === '/': | ||
state.pos = _CH.lastIndex // maybe. delegate the validation | ||
tag[IS_SELF_CLOSING] = true // the next loop | ||
break | ||
default: | ||
delete tag[IS_SELF_CLOSING] // ensure unmark as selfclosing tag | ||
setAttribute(state, ch.index, tag) | ||
return TEXT | ||
case ch[0] === '/': | ||
state.pos = _CH.lastIndex // maybe. delegate the validation | ||
tag[IS_SELF_CLOSING] = true // the next loop | ||
break | ||
default: | ||
delete tag[IS_SELF_CLOSING] // ensure unmark as selfclosing tag | ||
setAttribute(state, ch.index, tag) | ||
} | ||
@@ -73,6 +76,11 @@ | ||
const re = ATTR_START // (\S[^>/=\s]*)(?:\s*=\s*([^>/])?)? g | ||
const start = re.lastIndex = expressionContent.lastIndex = pos // first non-whitespace | ||
const start = (re.lastIndex = expressionContent.lastIndex = pos) // first non-whitespace | ||
const attrMatches = re.exec(data) | ||
const isExpressionName = isAttributeExpression(attrMatches[1], state.options.brackets) | ||
const match = isExpressionName ? [null, expressionContent.exec(data)[1], null] : attrMatches | ||
const isExpressionName = isAttributeExpression( | ||
attrMatches[1], | ||
state.options.brackets, | ||
) | ||
const match = isExpressionName | ||
? [null, expressionContent.exec(data)[1], null] | ||
: attrMatches | ||
@@ -104,3 +112,3 @@ if (match) { | ||
// If it not, this is an unquoted value and we need adjust the start. | ||
if (quote !== '"' && quote !== '\'') { | ||
if (quote !== '"' && quote !== "'") { | ||
quote = '' // first char of value is not a quote | ||
@@ -116,3 +124,3 @@ valueStart-- // adjust the starting position | ||
valueStart, | ||
end: quote ? ++end : end | ||
end: quote ? ++end : end, | ||
}) | ||
@@ -124,3 +132,2 @@ } | ||
/** | ||
@@ -138,6 +145,8 @@ * Parse expression names <a {href}> | ||
start: attr.start, | ||
expressions: attr.expressions.map(expr => Object.assign(expr, { | ||
text: expr.text.replace(SPREAD_OPERATOR, '').trim() | ||
})), | ||
end: end | ||
expressions: attr.expressions.map((expr) => | ||
Object.assign(expr, { | ||
text: expr.text.replace(SPREAD_OPERATOR, '').trim(), | ||
}), | ||
), | ||
end: end, | ||
} | ||
@@ -159,3 +168,3 @@ } | ||
expressions: attr.expressions, | ||
end: end | ||
end: end, | ||
} | ||
@@ -178,3 +187,3 @@ } | ||
start, | ||
end | ||
end, | ||
} | ||
@@ -185,9 +194,9 @@ | ||
switch (true) { | ||
case isSpreadAttribute(attr.name): | ||
return parseSpreadAttribute(state, attr) | ||
case isExpressionName === true: | ||
return parseExpressionNameAttribute(state, attr) | ||
default: | ||
return parseNomalAttribute(state, attr, quote) | ||
case isSpreadAttribute(attr.name): | ||
return parseSpreadAttribute(state, attr) | ||
case isExpressionName === true: | ||
return parseExpressionNameAttribute(state, attr) | ||
default: | ||
return parseNomalAttribute(state, attr, quote) | ||
} | ||
} |
@@ -1,5 +0,5 @@ | ||
import {COMMENT, TEXT} from '../node-types' | ||
import { COMMENT, TEXT } from '../node-types' | ||
import flush from '../utils/flush-parser-state' | ||
import panic from '../utils/panic' | ||
import {unclosedComment} from '../messages' | ||
import { unclosedComment } from '../messages' | ||
@@ -30,3 +30,3 @@ /** | ||
end + str.length, | ||
data.substring(start, end + str.length) | ||
data.substring(start, end + str.length), | ||
) | ||
@@ -55,5 +55,5 @@ | ||
end, | ||
text | ||
text, | ||
} | ||
} | ||
} |
@@ -5,3 +5,3 @@ import escapeStr from '../utils/escape-str' | ||
import pushText from '../utils/push-text' | ||
import {unexpectedEndOfFile} from '../messages' | ||
import { unexpectedEndOfFile } from '../messages' | ||
/** | ||
@@ -34,3 +34,3 @@ * Find the end of the attribute value or text node | ||
} else { | ||
pushText(state, start, end, {expressions, unescape}) | ||
pushText(state, start, end, { expressions, unescape }) | ||
} | ||
@@ -76,8 +76,6 @@ | ||
expressions, | ||
end: match.index | ||
end: match.index, | ||
} | ||
} | ||
/** | ||
@@ -103,2 +101,2 @@ * Creates a regex for the given string and the left bracket. | ||
return state.regexCache[str] | ||
} | ||
} |
@@ -1,3 +0,3 @@ | ||
import {ATTR, TEXT} from '../node-types' | ||
import {RE_SCRYLE, TAG_2C, TAG_NAME} from '../regex' | ||
import { ATTR, TEXT } from '../node-types' | ||
import { RE_SCRYLE, TAG_2C, TAG_NAME } from '../regex' | ||
import comment from './comment' | ||
@@ -22,8 +22,8 @@ import execFromPos from '../utils/exec-from-pos' | ||
switch (true) { | ||
case str[0] === '!': | ||
return comment(state, data, start) | ||
case TAG_2C.test(str): | ||
return parseTag(state, start) | ||
default: | ||
return pushText(state, start, pos) // pushes the '<' as text | ||
case str[0] === '!': | ||
return comment(state, data, start) | ||
case TAG_2C.test(str): | ||
return parseTag(state, start) | ||
default: | ||
return pushText(state, start, pos) // pushes the '<' as text | ||
} | ||
@@ -50,2 +50,2 @@ } | ||
return TEXT | ||
} | ||
} |
@@ -1,4 +0,4 @@ | ||
import {TAG, TEXT} from '../node-types' | ||
import {RE_SCRYLE} from '../regex' | ||
import {TEXTAREA_TAG} from '../constants' | ||
import { TAG, TEXT } from '../node-types' | ||
import { RE_SCRYLE } from '../regex' | ||
import { TEXTAREA_TAG } from '../constants' | ||
import execFromPos from '../utils/exec-from-pos' | ||
@@ -9,3 +9,3 @@ import expr from './expression' | ||
import pushText from '../utils/push-text' | ||
import {unclosedNamedBlock} from '../messages' | ||
import { unclosedNamedBlock } from '../messages' | ||
@@ -24,28 +24,28 @@ /** | ||
switch (true) { | ||
case typeof scryle === 'string': { | ||
const name = scryle | ||
const re = RE_SCRYLE[name] | ||
const match = execFromPos(re, pos, data) | ||
case typeof scryle === 'string': { | ||
const name = scryle | ||
const re = RE_SCRYLE[name] | ||
const match = execFromPos(re, pos, data) | ||
if (!match) { | ||
panic(data, unclosedNamedBlock.replace('%1', name), pos - 1) | ||
} | ||
if (!match) { | ||
panic(data, unclosedNamedBlock.replace('%1', name), pos - 1) | ||
} | ||
const start = match.index | ||
const end = re.lastIndex | ||
state.scryle = null // reset the script/style flag now | ||
// write the tag content, if any | ||
if (start > pos) { | ||
parseSpecialTagsContent(state, name, match) | ||
const start = match.index | ||
const end = re.lastIndex | ||
state.scryle = null // reset the script/style flag now | ||
// write the tag content, if any | ||
if (start > pos) { | ||
parseSpecialTagsContent(state, name, match) | ||
} | ||
// now the closing tag, either </script> or </style> | ||
pushTag(state, `/${name}`, start, end) | ||
break | ||
} | ||
// now the closing tag, either </script> or </style> | ||
pushTag(state, `/${name}`, start, end) | ||
break | ||
case data[pos] === '<': | ||
state.pos++ | ||
return TAG | ||
default: | ||
expr(state, null, '<', pos) | ||
} | ||
case data[pos] === '<': | ||
state.pos++ | ||
return TAG | ||
default: | ||
expr(state, null, '<', pos) | ||
} | ||
@@ -71,2 +71,2 @@ return TEXT | ||
} | ||
} | ||
} |
@@ -37,3 +37,3 @@ /** | ||
style: /<\/style\s*>/gi, | ||
textarea: /<\/textarea\s*>/gi | ||
textarea: /<\/textarea\s*>/gi, | ||
} | ||
@@ -40,0 +40,0 @@ |
@@ -21,3 +21,3 @@ /*--------------------------------------------------------------------- | ||
*/ | ||
import {COMMENT, TAG, TEXT} from './node-types' | ||
import { COMMENT, TAG, TEXT } from './node-types' | ||
import { | ||
@@ -31,6 +31,6 @@ CSS_OUTPUT_NAME, | ||
STYLE_TAG, | ||
TEMPLATE_OUTPUT_NAME | ||
TEMPLATE_OUTPUT_NAME, | ||
} from './constants' | ||
import {RAW_TAGS} from './regex' | ||
import {duplicatedNamedTag} from './messages' | ||
import { RAW_TAGS } from './regex' | ||
import { duplicatedNamedTag } from './messages' | ||
import panic from './utils/panic' | ||
@@ -44,9 +44,8 @@ | ||
function escapeReturn(string) { | ||
return string | ||
.replace(/\r/g, '\\r') | ||
.replace(/\n/g, '\\n') | ||
return string.replace(/\r/g, '\\r').replace(/\n/g, '\\n') | ||
} | ||
// check whether a tag has the 'src' attribute set like for example `<script src="">` | ||
const hasSrcAttribute = node => (node.attributes || []).some(attr => attr.name === 'src') | ||
const hasSrcAttribute = (node) => | ||
(node.attributes || []).some((attr) => attr.name === 'src') | ||
@@ -78,3 +77,3 @@ /** | ||
[CSS_OUTPUT_NAME]: store[STYLE_TAG], | ||
[JAVASCRIPT_OUTPUT_NAME]: store[JAVASCRIPT_TAG] | ||
[JAVASCRIPT_OUTPUT_NAME]: store[JAVASCRIPT_TAG], | ||
} | ||
@@ -84,6 +83,6 @@ }, | ||
/** | ||
* Process the current tag or text. | ||
* @param {Object} node - Raw pseudo-node from the parser | ||
* @returns {undefined} void function | ||
*/ | ||
* Process the current tag or text. | ||
* @param {Object} node - Raw pseudo-node from the parser | ||
* @returns {undefined} void function | ||
*/ | ||
push(node) { | ||
@@ -93,21 +92,21 @@ const store = this.store | ||
switch (node.type) { | ||
case COMMENT: | ||
this.pushComment(store, node) | ||
break | ||
case TEXT: | ||
this.pushText(store, node) | ||
break | ||
case TAG: { | ||
const name = node.name | ||
const closingTagChar = '/' | ||
const [firstChar] = name | ||
case COMMENT: | ||
this.pushComment(store, node) | ||
break | ||
case TEXT: | ||
this.pushText(store, node) | ||
break | ||
case TAG: { | ||
const name = node.name | ||
const closingTagChar = '/' | ||
const [firstChar] = name | ||
if (firstChar === closingTagChar && !node.isVoid) { | ||
this.closeTag(store, node, name) | ||
} else if (firstChar !== closingTagChar) { | ||
this.openTag(store, node) | ||
if (firstChar === closingTagChar && !node.isVoid) { | ||
this.closeTag(store, node, name) | ||
} else if (firstChar !== closingTagChar) { | ||
this.openTag(store, node) | ||
} | ||
break | ||
} | ||
break | ||
} | ||
} | ||
}, | ||
@@ -137,3 +136,4 @@ pushComment(store, node) { | ||
const attrs = node.attributes | ||
const isCoreTag = (JAVASCRIPT_TAG === name && !hasSrcAttribute(node) || name === STYLE_TAG) | ||
const isCoreTag = | ||
(JAVASCRIPT_TAG === name && !hasSrcAttribute(node)) || name === STYLE_TAG | ||
@@ -143,3 +143,7 @@ if (isCoreTag) { | ||
if (store[name]) { | ||
panic(this.store.data, duplicatedNamedTag.replace('%1', name), node.start) | ||
panic( | ||
this.store.data, | ||
duplicatedNamedTag.replace('%1', name), | ||
node.start, | ||
) | ||
} | ||
@@ -174,3 +178,3 @@ | ||
attrs(attributes) { | ||
attributes.forEach(attr => { | ||
attributes.forEach((attr) => { | ||
if (attr.value) { | ||
@@ -206,6 +210,9 @@ this.split(attr, attr.value, attr.valueStart, true) | ||
expressions.forEach(expr => { | ||
expressions.forEach((expr) => { | ||
const text = source.slice(pos, expr.start - start) | ||
const code = expr.text | ||
parts.push(this.sanitise(node, text, pack), escapeReturn(escapeSlashes(code).trim())) | ||
parts.push( | ||
this.sanitise(node, text, pack), | ||
escapeReturn(escapeSlashes(code).trim()), | ||
) | ||
pos = expr.end - start | ||
@@ -221,3 +228,3 @@ }) | ||
node.parts = parts.filter(p => p) // remove the empty strings | ||
node.parts = parts.filter((p) => p) // remove the empty strings | ||
}, | ||
@@ -239,3 +246,3 @@ // unescape escaped brackets and split prefixes of expressions | ||
return pack ? cleanSpaces(text) : escapeReturn(text) | ||
} | ||
}, | ||
}) | ||
@@ -249,3 +256,3 @@ | ||
end: 0, | ||
nodes: [] | ||
nodes: [], | ||
} | ||
@@ -262,5 +269,5 @@ | ||
script: null, | ||
data | ||
} | ||
data, | ||
}, | ||
}) | ||
} |
@@ -11,2 +11,2 @@ /** | ||
return collection | ||
} | ||
} |
@@ -11,2 +11,2 @@ /** | ||
return re.exec(string) | ||
} | ||
} |
@@ -7,4 +7,4 @@ /* | ||
*/ | ||
import skipES6TL, {$_ES6_BQ} from './skip-es6-tl' | ||
import {unclosedExpression, unexpectedCharInExpression} from '../messages' | ||
import skipES6TL, { $_ES6_BQ } from './skip-es6-tl' | ||
import { unclosedExpression, unexpectedCharInExpression } from '../messages' | ||
import escapeStr from './escape-str' | ||
@@ -69,22 +69,22 @@ import panic from './panic' | ||
switch (char) { | ||
case '[': | ||
case '(': | ||
case '{': | ||
stack.push(char === '[' ? ']' : char === '(' ? ')' : '}') | ||
break | ||
case ')': | ||
case ']': | ||
case '}': | ||
if (char !== stack.pop()) { | ||
panic(code, unexpectedCharInExpression.replace('%1', char), index) | ||
} | ||
case '[': | ||
case '(': | ||
case '{': | ||
stack.push(char === '[' ? ']' : char === '(' ? ')' : '}') | ||
break | ||
case ')': | ||
case ']': | ||
case '}': | ||
if (char !== stack.pop()) { | ||
panic(code, unexpectedCharInExpression.replace('%1', char), index) | ||
} | ||
if (char === '}' && stack[stack.length - 1] === $_ES6_BQ) { | ||
char = stack.pop() | ||
} | ||
if (char === '}' && stack[stack.length - 1] === $_ES6_BQ) { | ||
char = stack.pop() | ||
} | ||
index = idx + 1 | ||
break | ||
case '/': | ||
index = skipRegex(code, idx) | ||
index = idx + 1 | ||
break | ||
case '/': | ||
index = skipRegex(code, idx) | ||
} | ||
@@ -96,12 +96,12 @@ | ||
/** | ||
* Parses the code string searching the end of the expression. | ||
* It skips braces, quoted strings, regexes, and ES6 template literals. | ||
* | ||
* @function exprExtr | ||
* @param {string} code - Buffer to parse | ||
* @param {number} start - Position of the opening brace | ||
* @param {[string,string]} bp - Brackets pair | ||
* @returns {Object} Expression's end (after the closing brace) or -1 | ||
* if it is not an expr. | ||
*/ | ||
* Parses the code string searching the end of the expression. | ||
* It skips braces, quoted strings, regexes, and ES6 template literals. | ||
* | ||
* @function exprExtr | ||
* @param {string} code - Buffer to parse | ||
* @param {number} start - Position of the opening brace | ||
* @param {[string,string]} bp - Brackets pair | ||
* @returns {Object} Expression's end (after the closing brace) or -1 | ||
* if it is not an expr. | ||
*/ | ||
export default function exprExtr(code, start, bp) { | ||
@@ -118,3 +118,4 @@ const [openingBraces, closingBraces] = bp | ||
while (match = re.exec(code)) { // eslint-disable-line | ||
while ((match = re.exec(code))) { | ||
// eslint-disable-line | ||
const idx = match.index | ||
@@ -129,3 +130,3 @@ const str = match[0] | ||
start, | ||
end | ||
end, | ||
} | ||
@@ -144,2 +145,2 @@ } | ||
} | ||
} | ||
} |
@@ -11,2 +11,2 @@ /** | ||
return source.slice(start, end) | ||
} | ||
} |
@@ -18,2 +18,2 @@ /** | ||
} | ||
} | ||
} |
@@ -15,2 +15,2 @@ import formatError from './format-error' | ||
throw new Error(message) | ||
} | ||
} |
@@ -1,7 +0,4 @@ | ||
import { | ||
IS_CUSTOM, | ||
IS_VOID | ||
} from '../constants' | ||
import {isCustom, isVoid} from 'dom-nodes' | ||
import {TAG} from '../node-types' | ||
import { IS_CUSTOM, IS_VOID } from '../constants' | ||
import { isCustom, isVoid } from 'dom-nodes' | ||
import { TAG } from '../node-types' | ||
import flush from './flush-parser-state' | ||
@@ -48,2 +45,2 @@ | ||
state.last = last | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
import {TEXT} from '../node-types' | ||
import { TEXT } from '../node-types' | ||
import flush from './flush-parser-state' | ||
@@ -42,2 +42,2 @@ import getChunk from './get-chunk' | ||
return TEXT | ||
} | ||
} |
import formatError from './format-error' | ||
import {unclosedTemplateLiteral} from '../messages' | ||
import { unclosedTemplateLiteral } from '../messages' | ||
export const $_ES6_BQ = '`' | ||
@@ -20,3 +20,3 @@ | ||
let c | ||
while (re.lastIndex = pos, re.exec(code)) { | ||
while (((re.lastIndex = pos), re.exec(code))) { | ||
pos = re.lastIndex | ||
@@ -23,0 +23,0 @@ c = code[pos - 1] |
@@ -19,3 +19,3 @@ // forked from https://github.com/aMarCruz/skip-regex | ||
'void', | ||
'yield' | ||
'yield', | ||
] | ||
@@ -28,3 +28,4 @@ | ||
// The buffer to search must not include line-endings. | ||
const RE_LIT_REGEX = /^\/(?=[^*>/])[^[/\\]*(?:(?:\\.|\[(?:\\.|[^\]\\]*)*\])[^[\\/]*)*?\/[gimuy]*/ | ||
const RE_LIT_REGEX = | ||
/^\/(?=[^*>/])[^[/\\]*(?:(?:\\.|\[(?:\\.|[^\]\\]*)*\])[^[\\/]*)*?\/[gimuy]*/ | ||
@@ -51,4 +52,2 @@ // Valid characters for JavaScript variable names and literal numbers. | ||
/** | ||
@@ -67,5 +66,5 @@ * Check if the character in the `start` position within `code` can be a regex | ||
*/ | ||
/* istanbul ignore next */ | ||
/* c8 ignore next */ | ||
export default function skipRegex(code, start) { | ||
let pos = RE_DOT_CHAR.lastIndex = start++ | ||
let pos = (RE_DOT_CHAR.lastIndex = start++) | ||
@@ -77,3 +76,3 @@ // `exec()` will extract from the slash to the end of the line | ||
if (match) { | ||
const next = pos + match[0].length // result comes from `re.match` | ||
const next = pos + match[0].length // result comes from `re.match` | ||
@@ -94,15 +93,16 @@ pos = _prev(code, pos) | ||
} | ||
} else { | ||
if (c === '+' || c === '-') { | ||
// tricky case | ||
if (code[--pos] !== c || // if have a single operator or | ||
(pos = _prev(code, pos)) < 0 || // ...have `++` and no previous token | ||
beforeReSign.includes(c = code[pos])) { | ||
return next // ...this is a regex | ||
if ( | ||
code[--pos] !== c || // if have a single operator or | ||
(pos = _prev(code, pos)) < 0 || // ...have `++` and no previous token | ||
beforeReSign.includes((c = code[pos])) | ||
) { | ||
return next // ...this is a regex | ||
} | ||
} | ||
if (wordsEndChar.includes(c)) { // looks like a keyword? | ||
if (wordsEndChar.includes(c)) { | ||
// looks like a keyword? | ||
const end = pos + 1 | ||
@@ -109,0 +109,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2920
Yes
92519
9
30
135
+ Addedcurri@2.0.3(transitive)
- Removedcurri@1.0.1(transitive)
Updatedcurri@^2.0.3