eslint-mdx
Advanced tools
Comparing version 1.13.0 to 1.14.0
@@ -6,2 +6,13 @@ # Change Log | ||
# [1.14.0](https://github.com/mdx-js/eslint-mdx/compare/v1.13.0...v1.14.0) (2021-07-11) | ||
### Features | ||
* bump all upgradable deps, fix related usage ([#321](https://github.com/mdx-js/eslint-mdx/issues/321)) ([ea49cac](https://github.com/mdx-js/eslint-mdx/commit/ea49cacaedf72fb0bcf61aa84c3c0ea5e58f9733)) | ||
# [1.13.0](https://github.com/mdx-js/eslint-mdx/compare/v1.12.0...v1.13.0) (2021-04-29) | ||
@@ -8,0 +19,0 @@ |
@@ -6,109 +6,95 @@ import path from 'path'; | ||
/// <reference path="../typings.d.ts" /> | ||
const FALLBACK_PARSERS = [ | ||
'@typescript-eslint/parser', | ||
'@babel/eslint-parser', | ||
'babel-eslint', | ||
'espree', | ||
"@typescript-eslint/parser", | ||
"@babel/eslint-parser", | ||
"babel-eslint", | ||
"espree" | ||
]; | ||
const JSX_TYPES = ['JSXElement', 'JSXFragment']; | ||
const JSX_TYPES = ["JSXElement", "JSXFragment"]; | ||
const isJsxNode = (node) => JSX_TYPES.includes(node.type); | ||
// eslint-disable-next-line sonarjs/cognitive-complexity | ||
const normalizeParser = (parser) => { | ||
if (parser) { | ||
if (typeof parser === 'string') { | ||
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires | ||
parser = require(parser); | ||
} | ||
if (typeof parser === 'object') { | ||
parser = | ||
('parseForESLint' in parser && parser.parseForESLint) || | ||
('parse' in parser && parser.parse); | ||
} | ||
if (typeof parser !== 'function') { | ||
throw new TypeError(`Invalid custom parser for \`eslint-mdx\`: ${parser}`); | ||
} | ||
return [parser]; | ||
if (parser) { | ||
if (typeof parser === "string") { | ||
parser = require(parser); | ||
} | ||
const parsers = []; | ||
// try to load FALLBACK_PARSERS automatically | ||
for (const fallback of FALLBACK_PARSERS) { | ||
try { | ||
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires | ||
const fallbackParser = require(fallback); | ||
/* istanbul ignore next */ | ||
const parserFn = 'parseForESLint' in fallbackParser | ||
? // eslint-disable-next-line @typescript-eslint/unbound-method | ||
fallbackParser.parseForESLint | ||
: // eslint-disable-next-line @typescript-eslint/unbound-method | ||
fallbackParser.parse; | ||
/* istanbul ignore else */ | ||
if (parserFn) { | ||
parsers.push(parserFn); | ||
} | ||
} | ||
catch (_a) { } | ||
if (typeof parser === "object") { | ||
parser = "parseForESLint" in parser && parser.parseForESLint || "parse" in parser && parser.parse; | ||
} | ||
return parsers; | ||
if (typeof parser !== "function") { | ||
throw new TypeError(`Invalid custom parser for \`eslint-mdx\`: ${parser}`); | ||
} | ||
return [parser]; | ||
} | ||
const parsers = []; | ||
for (const fallback of FALLBACK_PARSERS) { | ||
try { | ||
const fallbackParser = require(fallback); | ||
const parserFn = "parseForESLint" in fallbackParser ? fallbackParser.parseForESLint : fallbackParser.parse; | ||
if (parserFn) { | ||
parsers.push(parserFn); | ||
} | ||
} catch (e) { | ||
} | ||
} | ||
return parsers; | ||
}; | ||
const normalizePosition = (loc) => { | ||
const start = loc.start.offset; | ||
const end = loc.end.offset; | ||
return { | ||
range: [start, end], | ||
loc, | ||
start, | ||
end, | ||
}; | ||
const start = loc.start.offset; | ||
const end = loc.end.offset; | ||
return { | ||
range: [start, end], | ||
loc, | ||
start, | ||
end | ||
}; | ||
}; | ||
const hasProperties = (obj, properties) => typeof obj === 'object' && | ||
obj && | ||
properties.every(property => property in obj); | ||
// fix #292 | ||
const hasProperties = (obj, properties) => typeof obj === "object" && obj && properties.every((property) => property in obj); | ||
const getPositionAt = (code, offset) => { | ||
let currOffset = 0; | ||
const lines = code.split('\n'); | ||
// eslint-disable-next-line unicorn/no-for-loop | ||
for (let index = 0; index < lines.length; index++) { | ||
const line = index + 1; | ||
const nextOffset = currOffset + lines[index].length; | ||
if (nextOffset >= offset) { | ||
return { | ||
line, | ||
column: offset - currOffset, | ||
}; | ||
} | ||
currOffset = nextOffset + 1; // add a line break `\n` offset | ||
let currOffset = 0; | ||
const lines = code.split("\n"); | ||
for (let index = 0; index < lines.length; index++) { | ||
const line = index + 1; | ||
const nextOffset = currOffset + lines[index].length; | ||
if (nextOffset >= offset) { | ||
return { | ||
line, | ||
column: offset - currOffset | ||
}; | ||
} | ||
currOffset = nextOffset + 1; | ||
} | ||
}; | ||
const restoreNodeLocation = (node, point) => { | ||
if (node && typeof node === 'object') { | ||
for (const value of Object.values(node)) { | ||
restoreNodeLocation(value, point); | ||
} | ||
if (node && typeof node === "object") { | ||
for (const value of Object.values(node)) { | ||
restoreNodeLocation(value, point); | ||
} | ||
if (!hasProperties(node, ['loc', 'range'])) { | ||
return node; | ||
} | ||
if (!hasProperties(node, ["loc", "range"])) { | ||
return node; | ||
} | ||
let { | ||
loc: { start: startLoc, end: endLoc }, | ||
range: [start, end] | ||
} = node; | ||
const range = [start += point.offset, end += point.offset]; | ||
return Object.assign(node, { | ||
start, | ||
end, | ||
range, | ||
loc: { | ||
start: { | ||
line: point.line + startLoc.line, | ||
column: startLoc.column + (startLoc.line === 1 ? point.column : 0) | ||
}, | ||
end: { | ||
line: point.line + endLoc.line, | ||
column: endLoc.column + (endLoc.line === 1 ? point.column : 0) | ||
} | ||
} | ||
let { loc: { start: startLoc, end: endLoc }, range: [start, end], } = node; | ||
const range = [(start += point.offset), (end += point.offset)]; | ||
return Object.assign(node, { | ||
start, | ||
end, | ||
range, | ||
loc: { | ||
start: { | ||
line: point.line + startLoc.line, | ||
column: startLoc.column + (startLoc.line === 1 ? point.column : 0), | ||
}, | ||
end: { | ||
line: point.line + endLoc.line, | ||
column: endLoc.column + (endLoc.line === 1 ? point.column : 0), | ||
}, | ||
}, | ||
}); | ||
}); | ||
}; | ||
const arrayify = (...args) => args.reduce((arr, curr) => { | ||
arr.push(...(Array.isArray(curr) ? curr : curr == null ? [] : [curr])); | ||
return arr; | ||
arr.push(...Array.isArray(curr) ? curr : curr == null ? [] : [curr]); | ||
return arr; | ||
}, []); | ||
@@ -118,33 +104,24 @@ const first = (items) => items && items[0]; | ||
// based on https://github.com/mdx-js/mdx/blob/master/packages/remark-mdx/tag.js | ||
const dotAllPolyfill = '[\0-\uFFFF]'; | ||
const attributeName = '[a-zA-Z_:][a-zA-Z0-9:._-]*'; | ||
const unquoted = '[^"\'=<>`\\u0000-\\u0020]+'; | ||
const dotAllPolyfill = "[\0-\uFFFF]"; | ||
const attributeName = "[a-zA-Z_:][a-zA-Z0-9:._-]*"; | ||
const unquoted = "[^\"'=<>`\\u0000-\\u0020]+"; | ||
const singleQuoted = "'[^']*'"; | ||
const doubleQuoted = '"[^"]*"'; | ||
const jsProps = '{.*}'.replace('.', dotAllPolyfill); | ||
const attributeValue = '(?:' + | ||
unquoted + | ||
'|' + | ||
singleQuoted + | ||
'|' + | ||
doubleQuoted + | ||
'|' + | ||
jsProps + | ||
')'; | ||
const attribute = '(?:\\s+' + attributeName + '(?:\\s*=\\s*' + attributeValue + ')?)'; | ||
const openTag = '<[A-Za-z]*[A-Za-z0-9\\.\\-]*' + attribute + '*\\s*>'; | ||
const closeTag = '<\\s*\\/[A-Za-z]*[A-Za-z0-9\\.\\-]*\\s*>'; | ||
const selfClosingTag = '<[A-Za-z]*[A-Za-z0-9\\.\\-]*' + attribute + '*\\s*\\/?>'; | ||
const comment = '<!---->|<!--(?:-?[^>-])(?:-?[^-])*-->'; | ||
const commentOpen = '(<!---*)'; | ||
const commentClose = '(-*-->)'; | ||
const jsProps = "{.*}".replace(".", dotAllPolyfill); | ||
const attributeValue = "(?:" + unquoted + "|" + singleQuoted + "|" + doubleQuoted + "|" + jsProps + ")"; | ||
const attribute = "(?:\\s+" + attributeName + "(?:\\s*=\\s*" + attributeValue + ")?)"; | ||
const openTag = "<[A-Za-z]*[A-Za-z0-9\\.\\-]*" + attribute + "*\\s*>"; | ||
const closeTag = "<\\s*\\/[A-Za-z]*[A-Za-z0-9\\.\\-]*\\s*>"; | ||
const selfClosingTag = "<[A-Za-z]*[A-Za-z0-9\\.\\-]*" + attribute + "*\\s*\\/?>"; | ||
const comment = "<!---->|<!--(?:-?[^>-])(?:-?[^-])*-->"; | ||
const commentOpen = "(<!---*)"; | ||
const commentClose = "(-*-->)"; | ||
const commentContent = `${commentOpen}([\\s\\S]*?)${commentClose}`; | ||
const OPEN_TAG_REGEX = new RegExp(`^(?:${openTag})$`); | ||
const CLOSE_TAG_REGEX = new RegExp(`^(?:${closeTag})$`); | ||
const OPEN_CLOSE_TAG_REGEX = new RegExp(`^(?:${openTag + '[^<]*' + closeTag})$`); | ||
const OPEN_CLOSE_TAG_REGEX = new RegExp(`^(?:${openTag + "[^<]*" + closeTag})$`); | ||
const SELF_CLOSING_TAG_REGEX = new RegExp(`^(?:${selfClosingTag})$`); | ||
const COMMENT_REGEX = new RegExp(`^(?:${comment})$`); | ||
const COMMENT_CONTENT_REGEX = new RegExp(commentContent); | ||
const COMMENT_CONTENT_REGEX_GLOBAL = new RegExp(commentContent, 'g'); | ||
const COMMENT_CONTENT_REGEX_GLOBAL = new RegExp(commentContent, "g"); | ||
const isOpenTag = (text) => OPEN_TAG_REGEX.test(text.trim()); | ||
@@ -156,380 +133,386 @@ const isCloseTag = (text) => CLOSE_TAG_REGEX.test(text.trim()); | ||
var __defProp$1 = Object.defineProperty; | ||
var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols; | ||
var __hasOwnProp$1 = Object.prototype.hasOwnProperty; | ||
var __propIsEnum$1 = Object.prototype.propertyIsEnumerable; | ||
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; | ||
var __spreadValues$1 = (a, b) => { | ||
for (var prop in b || (b = {})) | ||
if (__hasOwnProp$1.call(b, prop)) | ||
__defNormalProp$1(a, prop, b[prop]); | ||
if (__getOwnPropSymbols$1) | ||
for (var prop of __getOwnPropSymbols$1(b)) { | ||
if (__propIsEnum$1.call(b, prop)) | ||
__defNormalProp$1(a, prop, b[prop]); | ||
} | ||
return a; | ||
}; | ||
class Traverse { | ||
constructor({ code, enter }) { | ||
this.code = code; | ||
this._enter = enter; | ||
constructor({ code, enter }) { | ||
this.code = code; | ||
this._enter = enter; | ||
} | ||
combineLeftJsxNodes(jsxNodes, parent) { | ||
var _a; | ||
const start = jsxNodes[0].position.start; | ||
const end = __spreadValues$1({}, last(jsxNodes).position.end); | ||
if (parent && ((_a = parent.position.indent) == null ? void 0 : _a.length) > 0) { | ||
end.offset += parent.position.indent.reduce((acc, indent, index) => acc + (index ? indent + 1 : 0), 0); | ||
} | ||
combineLeftJsxNodes(jsxNodes, parent) { | ||
var _a; | ||
const start = jsxNodes[0].position.start; | ||
const end = Object.assign({}, last(jsxNodes).position.end); | ||
// fix #279 | ||
if (parent && ((_a = parent.position.indent) === null || _a === void 0 ? void 0 : _a.length) > 0) { | ||
end.offset += parent.position.indent.reduce((acc, indent, index) => acc + (index ? indent + 1 : 0), 0); | ||
} | ||
return { | ||
type: 'jsx', | ||
data: jsxNodes[0].data, | ||
value: this.code.slice(start.offset, end.offset), | ||
position: { | ||
start, | ||
end, | ||
}, | ||
}; | ||
} | ||
// fix #7 | ||
combineJsxNodes(nodes, parent) { | ||
let offset = 0; | ||
let hasOpenTag = false; | ||
const jsxNodes = []; | ||
const { length } = nodes; | ||
// eslint-disable-next-line sonarjs/cognitive-complexity | ||
return nodes.reduce((acc, node, index) => { | ||
if (node.type === 'jsx') { | ||
const value = node.value; | ||
if (isOpenTag(value)) { | ||
offset++; | ||
hasOpenTag = true; | ||
jsxNodes.push(node); | ||
} | ||
else { | ||
if (isCloseTag(value)) { | ||
offset--; | ||
jsxNodes.push(node); | ||
} | ||
else if (isComment(value) || | ||
isSelfClosingTag(value) || | ||
isOpenCloseTag(value)) { | ||
jsxNodes.push(node); | ||
} | ||
else { | ||
// #272, we consider the first jsx node as open tag although it's not precise | ||
if (!index) { | ||
offset++; | ||
hasOpenTag = true; | ||
} | ||
try { | ||
// fix #138 | ||
jsxNodes.push(...arrayify(parser.normalizeJsxNode(node, parent))); | ||
} | ||
catch (_a) { | ||
// #272 related | ||
/* istanbul ignore else */ | ||
if (offset) { | ||
jsxNodes.push(node); | ||
} | ||
else { | ||
// should never happen, just for robustness | ||
const { start } = node.position; | ||
throw Object.assign(new SyntaxError('unknown jsx node: ' + JSON.stringify(value)), { | ||
lineNumber: start.line, | ||
column: start.column, | ||
index: start.offset, | ||
}); | ||
} | ||
} | ||
} | ||
if (!offset) { | ||
// fix #158 | ||
const firstOpenTagIndex = jsxNodes.findIndex(node => typeof node.value === 'string' && isOpenTag(node.value)); | ||
if (firstOpenTagIndex === -1) { | ||
if (hasOpenTag) { | ||
acc.push(this.combineLeftJsxNodes(jsxNodes, parent)); | ||
} | ||
else { | ||
acc.push(...jsxNodes); | ||
} | ||
} | ||
else { | ||
acc.push(...jsxNodes.slice(0, firstOpenTagIndex), this.combineLeftJsxNodes(jsxNodes.slice(firstOpenTagIndex), parent)); | ||
} | ||
jsxNodes.length = 0; | ||
} | ||
} | ||
return { | ||
type: "jsx", | ||
data: jsxNodes[0].data, | ||
value: this.code.slice(start.offset, end.offset), | ||
position: { | ||
start, | ||
end | ||
} | ||
}; | ||
} | ||
combineJsxNodes(nodes, parent) { | ||
let offset = 0; | ||
let hasOpenTag = false; | ||
const jsxNodes = []; | ||
const { length } = nodes; | ||
return nodes.reduce((acc, node, index) => { | ||
if (node.type === "jsx") { | ||
const value = node.value; | ||
if (isOpenTag(value)) { | ||
offset++; | ||
hasOpenTag = true; | ||
jsxNodes.push(node); | ||
} else { | ||
if (isCloseTag(value)) { | ||
offset--; | ||
jsxNodes.push(node); | ||
} else if (isComment(value) || isSelfClosingTag(value) || isOpenCloseTag(value)) { | ||
jsxNodes.push(node); | ||
} else { | ||
if (!index) { | ||
offset++; | ||
hasOpenTag = true; | ||
} | ||
else if (offset) { | ||
try { | ||
jsxNodes.push(...arrayify(parser.normalizeJsxNode(node, parent))); | ||
} catch (e) { | ||
if (offset) { | ||
jsxNodes.push(node); | ||
} else { | ||
const { start } = node.position; | ||
throw Object.assign(new SyntaxError("unknown jsx node: " + JSON.stringify(value)), { | ||
lineNumber: start.line, | ||
column: start.column, | ||
index: start.offset | ||
}); | ||
} | ||
} | ||
else { | ||
acc.push(node); | ||
} | ||
if (index === length - 1 && jsxNodes.length > 0) { | ||
} | ||
if (!offset) { | ||
const firstOpenTagIndex = jsxNodes.findIndex((node2) => typeof node2.value === "string" && isOpenTag(node2.value)); | ||
if (firstOpenTagIndex === -1) { | ||
if (hasOpenTag) { | ||
acc.push(this.combineLeftJsxNodes(jsxNodes, parent)); | ||
} else { | ||
acc.push(...jsxNodes); | ||
} | ||
} else { | ||
acc.push(...jsxNodes.slice(0, firstOpenTagIndex), this.combineLeftJsxNodes(jsxNodes.slice(firstOpenTagIndex), parent)); | ||
} | ||
return acc; | ||
}, []); | ||
} | ||
traverse(node, parent) { | ||
/* istanbul ignore if */ | ||
if (!node) { | ||
// should never happen, just for robustness | ||
return; | ||
jsxNodes.length = 0; | ||
} | ||
} | ||
let children = node.children; | ||
if (children) { | ||
const parent = node; | ||
children = node.children = this.combineJsxNodes(children, parent); | ||
for (const child of children) { | ||
this.traverse(child, parent); | ||
} | ||
} | ||
this._enter(node, parent); | ||
} else if (offset) { | ||
jsxNodes.push(node); | ||
} else { | ||
acc.push(node); | ||
} | ||
if (index === length - 1 && jsxNodes.length > 0) { | ||
acc.push(this.combineLeftJsxNodes(jsxNodes, parent)); | ||
} | ||
return acc; | ||
}, []); | ||
} | ||
traverse(node, parent) { | ||
if (!node) { | ||
return; | ||
} | ||
if ("children" in node) { | ||
const parent2 = node; | ||
parent2.children = this.combineJsxNodes(parent2.children, parent2); | ||
for (const child of parent2.children) { | ||
this.traverse(child, parent2); | ||
} | ||
} | ||
this._enter(node, parent); | ||
} | ||
} | ||
const traverse = (root, options) => new Traverse(options).traverse(root); | ||
var __defProp = Object.defineProperty; | ||
var __defProps = Object.defineProperties; | ||
var __getOwnPropDescs = Object.getOwnPropertyDescriptors; | ||
var __getOwnPropSymbols = Object.getOwnPropertySymbols; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
var __propIsEnum = Object.prototype.propertyIsEnumerable; | ||
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; | ||
var __spreadValues = (a, b) => { | ||
for (var prop in b || (b = {})) | ||
if (__hasOwnProp.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
if (__getOwnPropSymbols) | ||
for (var prop of __getOwnPropSymbols(b)) { | ||
if (__propIsEnum.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
} | ||
return a; | ||
}; | ||
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); | ||
const mdProcessor = unified().use(remarkParse).freeze(); | ||
const mdxProcessor = mdProcessor().use(remarkMdx).freeze(); | ||
const AST_PROPS = ['body', 'comments', 'tokens']; | ||
const ES_NODE_TYPES = ['export', 'import', 'jsx']; | ||
const LOC_ERROR_PROPERTIES = ['column', 'lineNumber']; | ||
const DEFAULT_EXTENSIONS = ['.mdx']; | ||
const MARKDOWN_EXTENSIONS = ['.md']; | ||
const AST_PROPS = ["body", "comments", "tokens"]; | ||
const ES_NODE_TYPES = ["export", "import", "jsx"]; | ||
const LOC_ERROR_PROPERTIES = ["column", "lineNumber"]; | ||
const DEFAULT_EXTENSIONS = [".mdx"]; | ||
const MARKDOWN_EXTENSIONS = [".md"]; | ||
const DEFAULT_PARSER_OPTIONS = { | ||
comment: true, | ||
ecmaFeatures: { | ||
jsx: true, | ||
}, | ||
ecmaVersion: new Date().getUTCFullYear(), | ||
sourceType: 'module', | ||
tokens: true, | ||
filePath: '__placeholder__.mdx', | ||
// required for @typescript-eslint/parser | ||
// reference: https://github.com/typescript-eslint/typescript-eslint/pull/2028 | ||
loc: true, | ||
range: true, | ||
comment: true, | ||
ecmaFeatures: { | ||
jsx: true | ||
}, | ||
ecmaVersion: new Date().getUTCFullYear(), | ||
sourceType: "module", | ||
tokens: true, | ||
filePath: "__placeholder__.mdx", | ||
loc: true, | ||
range: true | ||
}; | ||
const JSX_WRAPPER_START = '<$>'; | ||
const JSX_WRAPPER_END = '</$>'; | ||
const JSX_WRAPPER_START = "<$>"; | ||
const JSX_WRAPPER_END = "</$>"; | ||
const OFFSET = JSX_WRAPPER_START.length; | ||
class Parser { | ||
constructor() { | ||
// @internal | ||
this._options = DEFAULT_PARSER_OPTIONS; | ||
this.parse = this.parse.bind(this); | ||
this.parseForESLint = this.parseForESLint.bind(this); | ||
constructor() { | ||
this._options = DEFAULT_PARSER_OPTIONS; | ||
this.parse = this.parse.bind(this); | ||
this.parseForESLint = this.parseForESLint.bind(this); | ||
} | ||
normalizeJsxNode(node, parent, options = this._options) { | ||
const value = node.value; | ||
if (node.type !== "jsx" || isComment(value)) { | ||
return node; | ||
} | ||
normalizeJsxNode(node, parent, options = this._options) { | ||
const value = node.value; | ||
if (node.type !== 'jsx' || isComment(value)) { | ||
return node; | ||
} | ||
const commentContent = COMMENT_CONTENT_REGEX.exec(value); | ||
if (commentContent) { | ||
const comments = []; | ||
const { position: { start: { line, column, offset: startOffset }, }, data, } = node; | ||
Object.assign(node, { | ||
data: Object.assign(Object.assign({}, data), { jsxType: 'JSXElementWithHTMLComments', comments, | ||
// jsx in paragraph is considered as plain html in mdx, what means html style comments are valid | ||
// TODO: in this case, jsx style comments could be a mistake | ||
inline: !!parent && parent.type !== 'root' }), | ||
value: value.replace(COMMENT_CONTENT_REGEX_GLOBAL, (matched, $0, $1, $2, offset) => { | ||
const endOffset = offset + matched.length; | ||
const startLines = value.slice(0, offset).split('\n'); | ||
const endLines = value.slice(0, endOffset).split('\n'); | ||
const fixed = `{/${'*'.repeat($0.length - 2)}${$1}${'*'.repeat($2.length - 2)}/}`; | ||
const startLineOffset = startLines.length - 1; | ||
const endLineOffset = endLines.length - 1; | ||
comments.push({ | ||
fixed, | ||
// ! eslint ast column is 0-indexed, but unified is 1-indexed | ||
loc: { | ||
start: { | ||
line: line + startLineOffset, | ||
column: last(startLines).length + | ||
(startLineOffset ? 0 : column - 1), | ||
offset: startOffset + offset, | ||
}, | ||
end: { | ||
line: line + endLineOffset, | ||
column: last(endLines).length + (endLineOffset ? 0 : column - 1), | ||
offset: startOffset + endOffset, | ||
}, | ||
}, | ||
origin: matched, | ||
}); | ||
return fixed; | ||
}), | ||
}); | ||
} | ||
return this._normalizeJsxNodes(node, options); | ||
const commentContent = COMMENT_CONTENT_REGEX.exec(value); | ||
if (commentContent) { | ||
const comments = []; | ||
const { | ||
position: { | ||
start: { line, column, offset: startOffset } | ||
}, | ||
data | ||
} = node; | ||
Object.assign(node, { | ||
data: __spreadProps(__spreadValues({}, data), { | ||
jsxType: "JSXElementWithHTMLComments", | ||
comments, | ||
inline: !!parent && parent.type !== "root" | ||
}), | ||
value: value.replace(COMMENT_CONTENT_REGEX_GLOBAL, (matched, $0, $1, $2, offset) => { | ||
const endOffset = offset + matched.length; | ||
const startLines = value.slice(0, offset).split("\n"); | ||
const endLines = value.slice(0, endOffset).split("\n"); | ||
const fixed = `{/${"*".repeat($0.length - 2)}${$1}${"*".repeat($2.length - 2)}/}`; | ||
const startLineOffset = startLines.length - 1; | ||
const endLineOffset = endLines.length - 1; | ||
comments.push({ | ||
fixed, | ||
loc: { | ||
start: { | ||
line: line + startLineOffset, | ||
column: last(startLines).length + (startLineOffset ? 0 : column - 1), | ||
offset: startOffset + offset | ||
}, | ||
end: { | ||
line: line + endLineOffset, | ||
column: last(endLines).length + (endLineOffset ? 0 : column - 1), | ||
offset: startOffset + endOffset | ||
} | ||
}, | ||
origin: matched | ||
}); | ||
return fixed; | ||
}) | ||
}); | ||
} | ||
parse(code, options) { | ||
return this.parseForESLint(code, options).ast; | ||
return this._normalizeJsxNodes(node, options); | ||
} | ||
parse(code, options) { | ||
return this.parseForESLint(code, options).ast; | ||
} | ||
parseForESLint(code, options) { | ||
const extname = path.extname(options.filePath); | ||
const isMdx = DEFAULT_EXTENSIONS.concat(options.extensions || []).includes(extname); | ||
const isMarkdown = MARKDOWN_EXTENSIONS.concat(options.markdownExtensions || []).includes(extname); | ||
if (!isMdx && !isMarkdown) { | ||
return this._eslintParse(code, options); | ||
} | ||
parseForESLint(code, options) { | ||
const extname = path.extname(options.filePath); | ||
const isMdx = DEFAULT_EXTENSIONS.concat(options.extensions || []).includes(extname); | ||
const isMarkdown = MARKDOWN_EXTENSIONS.concat(options.markdownExtensions || []).includes(extname); | ||
if (!isMdx && !isMarkdown) { | ||
return this._eslintParse(code, options); | ||
const root = (isMdx ? mdxProcessor : mdProcessor).parse(code); | ||
this._ast = __spreadProps(__spreadValues({}, normalizePosition(root.position)), { | ||
type: "Program", | ||
sourceType: options.sourceType || "module", | ||
body: [], | ||
comments: [], | ||
tokens: [] | ||
}); | ||
this._services = { | ||
JSXElementsWithHTMLComments: [] | ||
}; | ||
if (isMdx) { | ||
traverse(root, { | ||
code, | ||
enter: (node, parent) => { | ||
if (!ES_NODE_TYPES.includes(node.type)) { | ||
return; | ||
} | ||
for (const normalizedNode of arrayify(this.normalizeJsxNode(node, parent, options))) { | ||
this._nodeToAst(code, normalizedNode, options); | ||
} | ||
} | ||
const root = (isMdx ? mdxProcessor : mdProcessor).parse(code); | ||
this._ast = Object.assign(Object.assign({}, normalizePosition(root.position)), { type: 'Program', sourceType: options.sourceType || 'module', body: [], comments: [], tokens: [] }); | ||
this._services = { | ||
JSXElementsWithHTMLComments: [], | ||
}; | ||
if (isMdx) { | ||
traverse(root, { | ||
code, | ||
enter: (node, parent) => { | ||
if (!ES_NODE_TYPES.includes(node.type)) { | ||
return; | ||
} | ||
for (const normalizedNode of arrayify(this.normalizeJsxNode(node, parent, options))) { | ||
this._nodeToAst(code, normalizedNode, options); | ||
} | ||
}, | ||
}); | ||
} | ||
return { | ||
ast: this._ast, | ||
services: this._services, | ||
}; | ||
}); | ||
} | ||
// @internal | ||
_eslintParse(code, options) { | ||
if (!this._parsers || options.parser !== this._options.parser) { | ||
this._parsers = normalizeParser(options.parser); | ||
return { | ||
ast: this._ast, | ||
services: this._services | ||
}; | ||
} | ||
_eslintParse(code, options) { | ||
if (!this._parsers || options.parser !== this._options.parser) { | ||
this._parsers = normalizeParser(options.parser); | ||
} | ||
if (options.filePath && this._options !== options) { | ||
Object.assign(this._options, options); | ||
} | ||
let program; | ||
let parseError; | ||
for (const parser2 of this._parsers) { | ||
try { | ||
program = parser2(code, this._options); | ||
break; | ||
} catch (err) { | ||
if (!parseError) { | ||
parseError = err; | ||
} | ||
/* istanbul ignore else */ | ||
if (options.filePath && this._options !== options) { | ||
Object.assign(this._options, options); | ||
} | ||
let program; | ||
let parseError; | ||
for (const parser of this._parsers) { | ||
try { | ||
program = parser(code, this._options); | ||
break; | ||
} | ||
catch (err) { | ||
if (!parseError) { | ||
parseError = err; | ||
} | ||
} | ||
} | ||
if (!program && parseError) { | ||
throw parseError; | ||
} | ||
/* istanbul ignore next */ | ||
return ('ast' in program && program.ast | ||
? program | ||
: { ast: program }); | ||
} | ||
} | ||
// fix adjacent JSX nodes | ||
// @internal | ||
// eslint-disable-next-line sonarjs/cognitive-complexity | ||
_normalizeJsxNodes(node, options) { | ||
const value = node.value; | ||
let program; | ||
try { | ||
// wrap into single element which is valid jsx but not valid jsx in mdx, so that it won't break on adjacent JSX nodes | ||
program = this._eslintParse(`${JSX_WRAPPER_START}${value}${JSX_WRAPPER_END}`, options).ast; | ||
if (!program && parseError) { | ||
throw parseError; | ||
} | ||
return "ast" in program && program.ast ? program : { ast: program }; | ||
} | ||
_normalizeJsxNodes(node, options) { | ||
const value = node.value; | ||
let program; | ||
try { | ||
program = this._eslintParse(`${JSX_WRAPPER_START}${value}${JSX_WRAPPER_END}`, options).ast; | ||
} catch (err) { | ||
if (hasProperties(err, LOC_ERROR_PROPERTIES)) { | ||
const { | ||
position: { start } | ||
} = node; | ||
if ("index" in err) { | ||
err.index += start.offset - OFFSET; | ||
} else if ("pos" in err) { | ||
err.pos += start.offset - OFFSET; | ||
} | ||
catch (err) { | ||
if (hasProperties(err, LOC_ERROR_PROPERTIES)) { | ||
const { position: { start }, } = node; | ||
/* istanbul ignore else */ | ||
if ('index' in err) { | ||
err.index += start.offset - OFFSET; | ||
} | ||
else if ('pos' in err) { | ||
err.pos += start.offset - OFFSET; | ||
} | ||
err.column = | ||
/* istanbul ignore next */ | ||
err.lineNumber > 1 ? err.column : err.column + start.column - OFFSET; | ||
err.lineNumber += start.line - 1; | ||
throw err; | ||
} | ||
return node; | ||
} | ||
const { expression } = program.body[0]; | ||
if (!isJsxNode(expression) || expression.children.length <= 1) { | ||
return node; | ||
} | ||
const { position: { start: { line, offset }, }, data, } = node; | ||
return expression.children.reduce((nodes, jsNode) => { | ||
if (!isJsxNode(jsNode)) { | ||
return nodes; | ||
} | ||
/* istanbul ignore next */ | ||
const { start: nodeStart, end: nodeEnd, loc: { start, end } = { | ||
start: { column: nodeStart, line: 1 }, | ||
end: { column: nodeEnd, line: 1 }, | ||
}, range = [nodeStart, nodeEnd], } = jsNode; | ||
const startLine = line + start.line - 1; | ||
const endLine = line + end.line - 1; | ||
const startOffset = range[0] - OFFSET; | ||
const endOffset = range[1] - OFFSET; | ||
nodes.push({ | ||
type: 'jsx', | ||
data: nodes.length > 0 ? null : data, | ||
value: value.slice(startOffset, endOffset), | ||
position: { | ||
start: { | ||
line: startLine, | ||
column: line === startLine ? start.column - OFFSET : start.column, | ||
offset: offset + startOffset, | ||
}, | ||
end: { | ||
line: endLine, | ||
column: line === startLine ? end.column - OFFSET : end.column, | ||
offset: offset + endOffset, | ||
}, | ||
}, | ||
}); | ||
return nodes; | ||
}, []); | ||
err.column = err.lineNumber > 1 ? err.column : err.column + start.column - OFFSET; | ||
err.lineNumber += start.line - 1; | ||
throw err; | ||
} | ||
return node; | ||
} | ||
// @internal | ||
_nodeToAst(code, node, options) { | ||
if (node.data && node.data.jsxType === 'JSXElementWithHTMLComments') { | ||
this._services.JSXElementsWithHTMLComments.push(node); | ||
const { expression } = program.body[0]; | ||
if (!isJsxNode(expression) || expression.children.length <= 1) { | ||
return node; | ||
} | ||
const { | ||
position: { | ||
start: { line, offset } | ||
}, | ||
data | ||
} = node; | ||
return expression.children.reduce((nodes, jsNode) => { | ||
if (!isJsxNode(jsNode)) { | ||
return nodes; | ||
} | ||
const { | ||
start: nodeStart, | ||
end: nodeEnd, | ||
loc: { start, end } = { | ||
start: { column: nodeStart, line: 1 }, | ||
end: { column: nodeEnd, line: 1 } | ||
}, | ||
range = [nodeStart, nodeEnd] | ||
} = jsNode; | ||
const startLine = line + start.line - 1; | ||
const endLine = line + end.line - 1; | ||
const startOffset = range[0] - OFFSET; | ||
const endOffset = range[1] - OFFSET; | ||
nodes.push({ | ||
type: "jsx", | ||
data: nodes.length > 0 ? null : data, | ||
value: value.slice(startOffset, endOffset), | ||
position: { | ||
start: { | ||
line: startLine, | ||
column: line === startLine ? start.column - OFFSET : start.column, | ||
offset: offset + startOffset | ||
}, | ||
end: { | ||
line: endLine, | ||
column: line === startLine ? end.column - OFFSET : end.column, | ||
offset: offset + endOffset | ||
} | ||
} | ||
const value = node.value; | ||
const { loc, start, end } = normalizePosition(node.position); | ||
// fix #4 | ||
if (isComment(value)) { | ||
const comment = COMMENT_CONTENT_REGEX.exec(value)[2]; | ||
this._ast.comments.push({ | ||
type: 'Block', | ||
value: comment, | ||
loc, | ||
range: [start, end], | ||
}); | ||
return; | ||
} | ||
const startLine = loc.start.line - 1; // ! line is 1-indexed, change to 0-indexed to simplify usage | ||
let program; | ||
try { | ||
program = this._eslintParse(value, options).ast; | ||
} | ||
catch (e) { | ||
/* istanbul ignore if */ | ||
if (hasProperties(e, LOC_ERROR_PROPERTIES)) { | ||
// should be handled by `_normalizeJsxNodes`, just for robustness | ||
e.index += start; | ||
e.column = e.lineNumber > 1 ? e.column : e.column + loc.start.column; | ||
e.lineNumber += startLine; | ||
} | ||
throw e; | ||
} | ||
const startPoint = { | ||
line: startLine, | ||
// #279 related | ||
column: getPositionAt(code, start).column, | ||
offset: start, | ||
}; | ||
for (const prop of AST_PROPS) | ||
this._ast[prop].push( | ||
// ts doesn't understand the mixed type | ||
...program[prop].map((item) => restoreNodeLocation(item, startPoint))); | ||
}); | ||
return nodes; | ||
}, []); | ||
} | ||
_nodeToAst(code, node, options) { | ||
if (node.data && node.data.jsxType === "JSXElementWithHTMLComments") { | ||
this._services.JSXElementsWithHTMLComments.push(node); | ||
} | ||
const value = node.value; | ||
const { loc, start, end } = normalizePosition(node.position); | ||
if (isComment(value)) { | ||
const comment = COMMENT_CONTENT_REGEX.exec(value)[2]; | ||
this._ast.comments.push({ | ||
type: "Block", | ||
value: comment, | ||
loc, | ||
range: [start, end] | ||
}); | ||
return; | ||
} | ||
const startLine = loc.start.line - 1; | ||
let program; | ||
try { | ||
program = this._eslintParse(value, options).ast; | ||
} catch (e) { | ||
if (hasProperties(e, LOC_ERROR_PROPERTIES)) { | ||
e.index += start; | ||
e.column = e.lineNumber > 1 ? e.column : e.column + loc.start.column; | ||
e.lineNumber += startLine; | ||
} | ||
throw e; | ||
} | ||
const startPoint = { | ||
line: startLine, | ||
column: getPositionAt(code, start).column, | ||
offset: start | ||
}; | ||
for (const prop of AST_PROPS) | ||
this._ast[prop].push(...program[prop].map((item) => restoreNodeLocation(item, startPoint))); | ||
} | ||
} | ||
const parser = new Parser(); | ||
// eslint-disable-next-line @typescript-eslint/unbound-method | ||
const { parse, parseForESLint } = parser; | ||
export { AST_PROPS, CLOSE_TAG_REGEX, COMMENT_CONTENT_REGEX, COMMENT_CONTENT_REGEX_GLOBAL, COMMENT_REGEX, DEFAULT_EXTENSIONS, DEFAULT_PARSER_OPTIONS, ES_NODE_TYPES, FALLBACK_PARSERS, JSX_TYPES, LOC_ERROR_PROPERTIES, MARKDOWN_EXTENSIONS, OPEN_CLOSE_TAG_REGEX, OPEN_TAG_REGEX, Parser, SELF_CLOSING_TAG_REGEX, Traverse, arrayify, closeTag, comment, commentClose, commentContent, commentOpen, first, getPositionAt, hasProperties, isCloseTag, isComment, isJsxNode, isOpenCloseTag, isOpenTag, isSelfClosingTag, last, mdProcessor, mdxProcessor, normalizeParser, normalizePosition, openTag, parse, parseForESLint, parser, restoreNodeLocation, selfClosingTag, traverse }; |
1006
lib/esm.js
@@ -1,2 +0,1 @@ | ||
import { __assign, __spreadArray } from 'tslib'; | ||
import path from 'path'; | ||
@@ -7,560 +6,511 @@ import remarkMdx from 'remark-mdx'; | ||
/// <reference path="../typings.d.ts" /> | ||
var FALLBACK_PARSERS = [ | ||
'@typescript-eslint/parser', | ||
'@babel/eslint-parser', | ||
'babel-eslint', | ||
'espree', | ||
const FALLBACK_PARSERS = [ | ||
"@typescript-eslint/parser", | ||
"@babel/eslint-parser", | ||
"babel-eslint", | ||
"espree" | ||
]; | ||
var JSX_TYPES = ['JSXElement', 'JSXFragment']; | ||
var isJsxNode = function (node) { | ||
return JSX_TYPES.includes(node.type); | ||
}; | ||
// eslint-disable-next-line sonarjs/cognitive-complexity | ||
var normalizeParser = function (parser) { | ||
if (parser) { | ||
if (typeof parser === 'string') { | ||
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires | ||
parser = require(parser); | ||
} | ||
if (typeof parser === 'object') { | ||
parser = | ||
('parseForESLint' in parser && parser.parseForESLint) || | ||
('parse' in parser && parser.parse); | ||
} | ||
if (typeof parser !== 'function') { | ||
throw new TypeError("Invalid custom parser for `eslint-mdx`: " + parser); | ||
} | ||
return [parser]; | ||
const JSX_TYPES = ["JSXElement", "JSXFragment"]; | ||
const isJsxNode = (node) => JSX_TYPES.includes(node.type); | ||
const normalizeParser = (parser) => { | ||
if (parser) { | ||
if (typeof parser === "string") { | ||
parser = require(parser); | ||
} | ||
var parsers = []; | ||
// try to load FALLBACK_PARSERS automatically | ||
for (var _i = 0, FALLBACK_PARSERS_1 = FALLBACK_PARSERS; _i < FALLBACK_PARSERS_1.length; _i++) { | ||
var fallback = FALLBACK_PARSERS_1[_i]; | ||
try { | ||
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires | ||
var fallbackParser = require(fallback); | ||
/* istanbul ignore next */ | ||
var parserFn = 'parseForESLint' in fallbackParser | ||
? // eslint-disable-next-line @typescript-eslint/unbound-method | ||
fallbackParser.parseForESLint | ||
: // eslint-disable-next-line @typescript-eslint/unbound-method | ||
fallbackParser.parse; | ||
/* istanbul ignore else */ | ||
if (parserFn) { | ||
parsers.push(parserFn); | ||
} | ||
} | ||
catch (_a) { } | ||
if (typeof parser === "object") { | ||
parser = "parseForESLint" in parser && parser.parseForESLint || "parse" in parser && parser.parse; | ||
} | ||
return parsers; | ||
if (typeof parser !== "function") { | ||
throw new TypeError(`Invalid custom parser for \`eslint-mdx\`: ${parser}`); | ||
} | ||
return [parser]; | ||
} | ||
const parsers = []; | ||
for (const fallback of FALLBACK_PARSERS) { | ||
try { | ||
const fallbackParser = require(fallback); | ||
const parserFn = "parseForESLint" in fallbackParser ? fallbackParser.parseForESLint : fallbackParser.parse; | ||
if (parserFn) { | ||
parsers.push(parserFn); | ||
} | ||
} catch (e) { | ||
} | ||
} | ||
return parsers; | ||
}; | ||
var normalizePosition = function (loc) { | ||
var start = loc.start.offset; | ||
var end = loc.end.offset; | ||
return { | ||
range: [start, end], | ||
loc: loc, | ||
start: start, | ||
end: end, | ||
}; | ||
const normalizePosition = (loc) => { | ||
const start = loc.start.offset; | ||
const end = loc.end.offset; | ||
return { | ||
range: [start, end], | ||
loc, | ||
start, | ||
end | ||
}; | ||
}; | ||
var hasProperties = function (obj, properties) { | ||
return typeof obj === 'object' && | ||
obj && | ||
properties.every(function (property) { return property in obj; }); | ||
}; | ||
// fix #292 | ||
var getPositionAt = function (code, offset) { | ||
var currOffset = 0; | ||
var lines = code.split('\n'); | ||
// eslint-disable-next-line unicorn/no-for-loop | ||
for (var index = 0; index < lines.length; index++) { | ||
var line = index + 1; | ||
var nextOffset = currOffset + lines[index].length; | ||
if (nextOffset >= offset) { | ||
return { | ||
line: line, | ||
column: offset - currOffset, | ||
}; | ||
} | ||
currOffset = nextOffset + 1; // add a line break `\n` offset | ||
const hasProperties = (obj, properties) => typeof obj === "object" && obj && properties.every((property) => property in obj); | ||
const getPositionAt = (code, offset) => { | ||
let currOffset = 0; | ||
const lines = code.split("\n"); | ||
for (let index = 0; index < lines.length; index++) { | ||
const line = index + 1; | ||
const nextOffset = currOffset + lines[index].length; | ||
if (nextOffset >= offset) { | ||
return { | ||
line, | ||
column: offset - currOffset | ||
}; | ||
} | ||
currOffset = nextOffset + 1; | ||
} | ||
}; | ||
var restoreNodeLocation = function (node, point) { | ||
if (node && typeof node === 'object') { | ||
for (var _i = 0, _a = Object.values(node); _i < _a.length; _i++) { | ||
var value = _a[_i]; | ||
restoreNodeLocation(value, point); | ||
} | ||
const restoreNodeLocation = (node, point) => { | ||
if (node && typeof node === "object") { | ||
for (const value of Object.values(node)) { | ||
restoreNodeLocation(value, point); | ||
} | ||
if (!hasProperties(node, ['loc', 'range'])) { | ||
return node; | ||
} | ||
if (!hasProperties(node, ["loc", "range"])) { | ||
return node; | ||
} | ||
let { | ||
loc: { start: startLoc, end: endLoc }, | ||
range: [start, end] | ||
} = node; | ||
const range = [start += point.offset, end += point.offset]; | ||
return Object.assign(node, { | ||
start, | ||
end, | ||
range, | ||
loc: { | ||
start: { | ||
line: point.line + startLoc.line, | ||
column: startLoc.column + (startLoc.line === 1 ? point.column : 0) | ||
}, | ||
end: { | ||
line: point.line + endLoc.line, | ||
column: endLoc.column + (endLoc.line === 1 ? point.column : 0) | ||
} | ||
} | ||
var _b = node.loc, startLoc = _b.start, endLoc = _b.end, _c = node.range, start = _c[0], end = _c[1]; | ||
var range = [(start += point.offset), (end += point.offset)]; | ||
return Object.assign(node, { | ||
start: start, | ||
end: end, | ||
range: range, | ||
loc: { | ||
start: { | ||
line: point.line + startLoc.line, | ||
column: startLoc.column + (startLoc.line === 1 ? point.column : 0), | ||
}, | ||
end: { | ||
line: point.line + endLoc.line, | ||
column: endLoc.column + (endLoc.line === 1 ? point.column : 0), | ||
}, | ||
}, | ||
}); | ||
}); | ||
}; | ||
var arrayify = function () { | ||
var args = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
args[_i] = arguments[_i]; | ||
} | ||
return args.reduce(function (arr, curr) { | ||
arr.push.apply(arr, (Array.isArray(curr) ? curr : curr == null ? [] : [curr])); | ||
return arr; | ||
}, []); | ||
}; | ||
var first = function (items) { return items && items[0]; }; | ||
var last = function (items) { | ||
return items && items[items.length - 1]; | ||
}; | ||
const arrayify = (...args) => args.reduce((arr, curr) => { | ||
arr.push(...Array.isArray(curr) ? curr : curr == null ? [] : [curr]); | ||
return arr; | ||
}, []); | ||
const first = (items) => items && items[0]; | ||
const last = (items) => items && items[items.length - 1]; | ||
// based on https://github.com/mdx-js/mdx/blob/master/packages/remark-mdx/tag.js | ||
var dotAllPolyfill = '[\0-\uFFFF]'; | ||
var attributeName = '[a-zA-Z_:][a-zA-Z0-9:._-]*'; | ||
var unquoted = '[^"\'=<>`\\u0000-\\u0020]+'; | ||
var singleQuoted = "'[^']*'"; | ||
var doubleQuoted = '"[^"]*"'; | ||
var jsProps = '{.*}'.replace('.', dotAllPolyfill); | ||
var attributeValue = '(?:' + | ||
unquoted + | ||
'|' + | ||
singleQuoted + | ||
'|' + | ||
doubleQuoted + | ||
'|' + | ||
jsProps + | ||
')'; | ||
var attribute = '(?:\\s+' + attributeName + '(?:\\s*=\\s*' + attributeValue + ')?)'; | ||
var openTag = '<[A-Za-z]*[A-Za-z0-9\\.\\-]*' + attribute + '*\\s*>'; | ||
var closeTag = '<\\s*\\/[A-Za-z]*[A-Za-z0-9\\.\\-]*\\s*>'; | ||
var selfClosingTag = '<[A-Za-z]*[A-Za-z0-9\\.\\-]*' + attribute + '*\\s*\\/?>'; | ||
var comment = '<!---->|<!--(?:-?[^>-])(?:-?[^-])*-->'; | ||
var commentOpen = '(<!---*)'; | ||
var commentClose = '(-*-->)'; | ||
var commentContent = commentOpen + "([\\s\\S]*?)" + commentClose; | ||
var OPEN_TAG_REGEX = new RegExp("^(?:" + openTag + ")$"); | ||
var CLOSE_TAG_REGEX = new RegExp("^(?:" + closeTag + ")$"); | ||
var OPEN_CLOSE_TAG_REGEX = new RegExp("^(?:" + (openTag + '[^<]*' + closeTag) + ")$"); | ||
var SELF_CLOSING_TAG_REGEX = new RegExp("^(?:" + selfClosingTag + ")$"); | ||
var COMMENT_REGEX = new RegExp("^(?:" + comment + ")$"); | ||
var COMMENT_CONTENT_REGEX = new RegExp(commentContent); | ||
var COMMENT_CONTENT_REGEX_GLOBAL = new RegExp(commentContent, 'g'); | ||
var isOpenTag = function (text) { return OPEN_TAG_REGEX.test(text.trim()); }; | ||
var isCloseTag = function (text) { return CLOSE_TAG_REGEX.test(text.trim()); }; | ||
var isComment = function (text) { return COMMENT_REGEX.test(text.trim()); }; | ||
var isOpenCloseTag = function (text) { | ||
return OPEN_CLOSE_TAG_REGEX.test(text.trim()); | ||
}; | ||
var isSelfClosingTag = function (text) { | ||
return SELF_CLOSING_TAG_REGEX.test(text.trim()); | ||
}; | ||
const dotAllPolyfill = "[\0-\uFFFF]"; | ||
const attributeName = "[a-zA-Z_:][a-zA-Z0-9:._-]*"; | ||
const unquoted = "[^\"'=<>`\\u0000-\\u0020]+"; | ||
const singleQuoted = "'[^']*'"; | ||
const doubleQuoted = '"[^"]*"'; | ||
const jsProps = "{.*}".replace(".", dotAllPolyfill); | ||
const attributeValue = "(?:" + unquoted + "|" + singleQuoted + "|" + doubleQuoted + "|" + jsProps + ")"; | ||
const attribute = "(?:\\s+" + attributeName + "(?:\\s*=\\s*" + attributeValue + ")?)"; | ||
const openTag = "<[A-Za-z]*[A-Za-z0-9\\.\\-]*" + attribute + "*\\s*>"; | ||
const closeTag = "<\\s*\\/[A-Za-z]*[A-Za-z0-9\\.\\-]*\\s*>"; | ||
const selfClosingTag = "<[A-Za-z]*[A-Za-z0-9\\.\\-]*" + attribute + "*\\s*\\/?>"; | ||
const comment = "<!---->|<!--(?:-?[^>-])(?:-?[^-])*-->"; | ||
const commentOpen = "(<!---*)"; | ||
const commentClose = "(-*-->)"; | ||
const commentContent = `${commentOpen}([\\s\\S]*?)${commentClose}`; | ||
const OPEN_TAG_REGEX = new RegExp(`^(?:${openTag})$`); | ||
const CLOSE_TAG_REGEX = new RegExp(`^(?:${closeTag})$`); | ||
const OPEN_CLOSE_TAG_REGEX = new RegExp(`^(?:${openTag + "[^<]*" + closeTag})$`); | ||
const SELF_CLOSING_TAG_REGEX = new RegExp(`^(?:${selfClosingTag})$`); | ||
const COMMENT_REGEX = new RegExp(`^(?:${comment})$`); | ||
const COMMENT_CONTENT_REGEX = new RegExp(commentContent); | ||
const COMMENT_CONTENT_REGEX_GLOBAL = new RegExp(commentContent, "g"); | ||
const isOpenTag = (text) => OPEN_TAG_REGEX.test(text.trim()); | ||
const isCloseTag = (text) => CLOSE_TAG_REGEX.test(text.trim()); | ||
const isComment = (text) => COMMENT_REGEX.test(text.trim()); | ||
const isOpenCloseTag = (text) => OPEN_CLOSE_TAG_REGEX.test(text.trim()); | ||
const isSelfClosingTag = (text) => SELF_CLOSING_TAG_REGEX.test(text.trim()); | ||
var Traverse = /** @class */ (function () { | ||
function Traverse(_a) { | ||
var code = _a.code, enter = _a.enter; | ||
this.code = code; | ||
this._enter = enter; | ||
var __defProp$1 = Object.defineProperty; | ||
var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols; | ||
var __hasOwnProp$1 = Object.prototype.hasOwnProperty; | ||
var __propIsEnum$1 = Object.prototype.propertyIsEnumerable; | ||
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; | ||
var __spreadValues$1 = (a, b) => { | ||
for (var prop in b || (b = {})) | ||
if (__hasOwnProp$1.call(b, prop)) | ||
__defNormalProp$1(a, prop, b[prop]); | ||
if (__getOwnPropSymbols$1) | ||
for (var prop of __getOwnPropSymbols$1(b)) { | ||
if (__propIsEnum$1.call(b, prop)) | ||
__defNormalProp$1(a, prop, b[prop]); | ||
} | ||
Traverse.prototype.combineLeftJsxNodes = function (jsxNodes, parent) { | ||
var _a; | ||
var start = jsxNodes[0].position.start; | ||
var end = __assign({}, last(jsxNodes).position.end); | ||
// fix #279 | ||
if (parent && ((_a = parent.position.indent) === null || _a === void 0 ? void 0 : _a.length) > 0) { | ||
end.offset += parent.position.indent.reduce(function (acc, indent, index) { return acc + (index ? indent + 1 : 0); }, 0); | ||
} | ||
return { | ||
type: 'jsx', | ||
data: jsxNodes[0].data, | ||
value: this.code.slice(start.offset, end.offset), | ||
position: { | ||
start: start, | ||
end: end, | ||
}, | ||
}; | ||
return a; | ||
}; | ||
class Traverse { | ||
constructor({ code, enter }) { | ||
this.code = code; | ||
this._enter = enter; | ||
} | ||
combineLeftJsxNodes(jsxNodes, parent) { | ||
var _a; | ||
const start = jsxNodes[0].position.start; | ||
const end = __spreadValues$1({}, last(jsxNodes).position.end); | ||
if (parent && ((_a = parent.position.indent) == null ? void 0 : _a.length) > 0) { | ||
end.offset += parent.position.indent.reduce((acc, indent, index) => acc + (index ? indent + 1 : 0), 0); | ||
} | ||
return { | ||
type: "jsx", | ||
data: jsxNodes[0].data, | ||
value: this.code.slice(start.offset, end.offset), | ||
position: { | ||
start, | ||
end | ||
} | ||
}; | ||
// fix #7 | ||
Traverse.prototype.combineJsxNodes = function (nodes, parent) { | ||
var _this = this; | ||
var offset = 0; | ||
var hasOpenTag = false; | ||
var jsxNodes = []; | ||
var length = nodes.length; | ||
// eslint-disable-next-line sonarjs/cognitive-complexity | ||
return nodes.reduce(function (acc, node, index) { | ||
if (node.type === 'jsx') { | ||
var value = node.value; | ||
if (isOpenTag(value)) { | ||
offset++; | ||
hasOpenTag = true; | ||
jsxNodes.push(node); | ||
} | ||
else { | ||
if (isCloseTag(value)) { | ||
offset--; | ||
jsxNodes.push(node); | ||
} | ||
else if (isComment(value) || | ||
isSelfClosingTag(value) || | ||
isOpenCloseTag(value)) { | ||
jsxNodes.push(node); | ||
} | ||
else { | ||
// #272, we consider the first jsx node as open tag although it's not precise | ||
if (!index) { | ||
offset++; | ||
hasOpenTag = true; | ||
} | ||
try { | ||
// fix #138 | ||
jsxNodes.push.apply(jsxNodes, arrayify(parser.normalizeJsxNode(node, parent))); | ||
} | ||
catch (_a) { | ||
// #272 related | ||
/* istanbul ignore else */ | ||
if (offset) { | ||
jsxNodes.push(node); | ||
} | ||
else { | ||
// should never happen, just for robustness | ||
var start = node.position.start; | ||
throw Object.assign(new SyntaxError('unknown jsx node: ' + JSON.stringify(value)), { | ||
lineNumber: start.line, | ||
column: start.column, | ||
index: start.offset, | ||
}); | ||
} | ||
} | ||
} | ||
if (!offset) { | ||
// fix #158 | ||
var firstOpenTagIndex = jsxNodes.findIndex(function (node) { return typeof node.value === 'string' && isOpenTag(node.value); }); | ||
if (firstOpenTagIndex === -1) { | ||
if (hasOpenTag) { | ||
acc.push(_this.combineLeftJsxNodes(jsxNodes, parent)); | ||
} | ||
else { | ||
acc.push.apply(acc, jsxNodes); | ||
} | ||
} | ||
else { | ||
acc.push.apply(acc, __spreadArray(__spreadArray([], jsxNodes.slice(0, firstOpenTagIndex)), [_this.combineLeftJsxNodes(jsxNodes.slice(firstOpenTagIndex), parent)])); | ||
} | ||
jsxNodes.length = 0; | ||
} | ||
} | ||
} | ||
combineJsxNodes(nodes, parent) { | ||
let offset = 0; | ||
let hasOpenTag = false; | ||
const jsxNodes = []; | ||
const { length } = nodes; | ||
return nodes.reduce((acc, node, index) => { | ||
if (node.type === "jsx") { | ||
const value = node.value; | ||
if (isOpenTag(value)) { | ||
offset++; | ||
hasOpenTag = true; | ||
jsxNodes.push(node); | ||
} else { | ||
if (isCloseTag(value)) { | ||
offset--; | ||
jsxNodes.push(node); | ||
} else if (isComment(value) || isSelfClosingTag(value) || isOpenCloseTag(value)) { | ||
jsxNodes.push(node); | ||
} else { | ||
if (!index) { | ||
offset++; | ||
hasOpenTag = true; | ||
} | ||
else if (offset) { | ||
try { | ||
jsxNodes.push(...arrayify(parser.normalizeJsxNode(node, parent))); | ||
} catch (e) { | ||
if (offset) { | ||
jsxNodes.push(node); | ||
} else { | ||
const { start } = node.position; | ||
throw Object.assign(new SyntaxError("unknown jsx node: " + JSON.stringify(value)), { | ||
lineNumber: start.line, | ||
column: start.column, | ||
index: start.offset | ||
}); | ||
} | ||
} | ||
else { | ||
acc.push(node); | ||
} | ||
if (!offset) { | ||
const firstOpenTagIndex = jsxNodes.findIndex((node2) => typeof node2.value === "string" && isOpenTag(node2.value)); | ||
if (firstOpenTagIndex === -1) { | ||
if (hasOpenTag) { | ||
acc.push(this.combineLeftJsxNodes(jsxNodes, parent)); | ||
} else { | ||
acc.push(...jsxNodes); | ||
} | ||
} else { | ||
acc.push(...jsxNodes.slice(0, firstOpenTagIndex), this.combineLeftJsxNodes(jsxNodes.slice(firstOpenTagIndex), parent)); | ||
} | ||
if (index === length - 1 && jsxNodes.length > 0) { | ||
acc.push(_this.combineLeftJsxNodes(jsxNodes, parent)); | ||
} | ||
return acc; | ||
}, []); | ||
}; | ||
Traverse.prototype.traverse = function (node, parent) { | ||
/* istanbul ignore if */ | ||
if (!node) { | ||
// should never happen, just for robustness | ||
return; | ||
jsxNodes.length = 0; | ||
} | ||
} | ||
var children = node.children; | ||
if (children) { | ||
var parent_1 = node; | ||
children = node.children = this.combineJsxNodes(children, parent_1); | ||
for (var _i = 0, children_1 = children; _i < children_1.length; _i++) { | ||
var child = children_1[_i]; | ||
this.traverse(child, parent_1); | ||
} | ||
} | ||
this._enter(node, parent); | ||
}; | ||
return Traverse; | ||
}()); | ||
var traverse = function (root, options) { | ||
return new Traverse(options).traverse(root); | ||
}; | ||
} else if (offset) { | ||
jsxNodes.push(node); | ||
} else { | ||
acc.push(node); | ||
} | ||
if (index === length - 1 && jsxNodes.length > 0) { | ||
acc.push(this.combineLeftJsxNodes(jsxNodes, parent)); | ||
} | ||
return acc; | ||
}, []); | ||
} | ||
traverse(node, parent) { | ||
if (!node) { | ||
return; | ||
} | ||
if ("children" in node) { | ||
const parent2 = node; | ||
parent2.children = this.combineJsxNodes(parent2.children, parent2); | ||
for (const child of parent2.children) { | ||
this.traverse(child, parent2); | ||
} | ||
} | ||
this._enter(node, parent); | ||
} | ||
} | ||
const traverse = (root, options) => new Traverse(options).traverse(root); | ||
var mdProcessor = unified().use(remarkParse).freeze(); | ||
var mdxProcessor = mdProcessor().use(remarkMdx).freeze(); | ||
var AST_PROPS = ['body', 'comments', 'tokens']; | ||
var ES_NODE_TYPES = ['export', 'import', 'jsx']; | ||
var LOC_ERROR_PROPERTIES = ['column', 'lineNumber']; | ||
var DEFAULT_EXTENSIONS = ['.mdx']; | ||
var MARKDOWN_EXTENSIONS = ['.md']; | ||
var DEFAULT_PARSER_OPTIONS = { | ||
comment: true, | ||
ecmaFeatures: { | ||
jsx: true, | ||
}, | ||
ecmaVersion: new Date().getUTCFullYear(), | ||
sourceType: 'module', | ||
tokens: true, | ||
filePath: '__placeholder__.mdx', | ||
// required for @typescript-eslint/parser | ||
// reference: https://github.com/typescript-eslint/typescript-eslint/pull/2028 | ||
loc: true, | ||
range: true, | ||
var __defProp = Object.defineProperty; | ||
var __defProps = Object.defineProperties; | ||
var __getOwnPropDescs = Object.getOwnPropertyDescriptors; | ||
var __getOwnPropSymbols = Object.getOwnPropertySymbols; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
var __propIsEnum = Object.prototype.propertyIsEnumerable; | ||
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; | ||
var __spreadValues = (a, b) => { | ||
for (var prop in b || (b = {})) | ||
if (__hasOwnProp.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
if (__getOwnPropSymbols) | ||
for (var prop of __getOwnPropSymbols(b)) { | ||
if (__propIsEnum.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
} | ||
return a; | ||
}; | ||
var JSX_WRAPPER_START = '<$>'; | ||
var JSX_WRAPPER_END = '</$>'; | ||
var OFFSET = JSX_WRAPPER_START.length; | ||
var Parser = /** @class */ (function () { | ||
function Parser() { | ||
// @internal | ||
this._options = DEFAULT_PARSER_OPTIONS; | ||
this.parse = this.parse.bind(this); | ||
this.parseForESLint = this.parseForESLint.bind(this); | ||
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); | ||
const mdProcessor = unified().use(remarkParse).freeze(); | ||
const mdxProcessor = mdProcessor().use(remarkMdx).freeze(); | ||
const AST_PROPS = ["body", "comments", "tokens"]; | ||
const ES_NODE_TYPES = ["export", "import", "jsx"]; | ||
const LOC_ERROR_PROPERTIES = ["column", "lineNumber"]; | ||
const DEFAULT_EXTENSIONS = [".mdx"]; | ||
const MARKDOWN_EXTENSIONS = [".md"]; | ||
const DEFAULT_PARSER_OPTIONS = { | ||
comment: true, | ||
ecmaFeatures: { | ||
jsx: true | ||
}, | ||
ecmaVersion: new Date().getUTCFullYear(), | ||
sourceType: "module", | ||
tokens: true, | ||
filePath: "__placeholder__.mdx", | ||
loc: true, | ||
range: true | ||
}; | ||
const JSX_WRAPPER_START = "<$>"; | ||
const JSX_WRAPPER_END = "</$>"; | ||
const OFFSET = JSX_WRAPPER_START.length; | ||
class Parser { | ||
constructor() { | ||
this._options = DEFAULT_PARSER_OPTIONS; | ||
this.parse = this.parse.bind(this); | ||
this.parseForESLint = this.parseForESLint.bind(this); | ||
} | ||
normalizeJsxNode(node, parent, options = this._options) { | ||
const value = node.value; | ||
if (node.type !== "jsx" || isComment(value)) { | ||
return node; | ||
} | ||
Parser.prototype.normalizeJsxNode = function (node, parent, options) { | ||
if (options === void 0) { options = this._options; } | ||
var value = node.value; | ||
if (node.type !== 'jsx' || isComment(value)) { | ||
return node; | ||
} | ||
var commentContent = COMMENT_CONTENT_REGEX.exec(value); | ||
if (commentContent) { | ||
var comments_1 = []; | ||
var _a = node.position.start, line_1 = _a.line, column_1 = _a.column, startOffset_1 = _a.offset, data = node.data; | ||
Object.assign(node, { | ||
data: __assign(__assign({}, data), { jsxType: 'JSXElementWithHTMLComments', comments: comments_1, | ||
// jsx in paragraph is considered as plain html in mdx, what means html style comments are valid | ||
// TODO: in this case, jsx style comments could be a mistake | ||
inline: !!parent && parent.type !== 'root' }), | ||
value: value.replace(COMMENT_CONTENT_REGEX_GLOBAL, function (matched, $0, $1, $2, offset) { | ||
var endOffset = offset + matched.length; | ||
var startLines = value.slice(0, offset).split('\n'); | ||
var endLines = value.slice(0, endOffset).split('\n'); | ||
var fixed = "{/" + '*'.repeat($0.length - 2) + $1 + '*'.repeat($2.length - 2) + "/}"; | ||
var startLineOffset = startLines.length - 1; | ||
var endLineOffset = endLines.length - 1; | ||
comments_1.push({ | ||
fixed: fixed, | ||
// ! eslint ast column is 0-indexed, but unified is 1-indexed | ||
loc: { | ||
start: { | ||
line: line_1 + startLineOffset, | ||
column: last(startLines).length + | ||
(startLineOffset ? 0 : column_1 - 1), | ||
offset: startOffset_1 + offset, | ||
}, | ||
end: { | ||
line: line_1 + endLineOffset, | ||
column: last(endLines).length + (endLineOffset ? 0 : column_1 - 1), | ||
offset: startOffset_1 + endOffset, | ||
}, | ||
}, | ||
origin: matched, | ||
}); | ||
return fixed; | ||
}), | ||
}); | ||
} | ||
return this._normalizeJsxNodes(node, options); | ||
const commentContent = COMMENT_CONTENT_REGEX.exec(value); | ||
if (commentContent) { | ||
const comments = []; | ||
const { | ||
position: { | ||
start: { line, column, offset: startOffset } | ||
}, | ||
data | ||
} = node; | ||
Object.assign(node, { | ||
data: __spreadProps(__spreadValues({}, data), { | ||
jsxType: "JSXElementWithHTMLComments", | ||
comments, | ||
inline: !!parent && parent.type !== "root" | ||
}), | ||
value: value.replace(COMMENT_CONTENT_REGEX_GLOBAL, (matched, $0, $1, $2, offset) => { | ||
const endOffset = offset + matched.length; | ||
const startLines = value.slice(0, offset).split("\n"); | ||
const endLines = value.slice(0, endOffset).split("\n"); | ||
const fixed = `{/${"*".repeat($0.length - 2)}${$1}${"*".repeat($2.length - 2)}/}`; | ||
const startLineOffset = startLines.length - 1; | ||
const endLineOffset = endLines.length - 1; | ||
comments.push({ | ||
fixed, | ||
loc: { | ||
start: { | ||
line: line + startLineOffset, | ||
column: last(startLines).length + (startLineOffset ? 0 : column - 1), | ||
offset: startOffset + offset | ||
}, | ||
end: { | ||
line: line + endLineOffset, | ||
column: last(endLines).length + (endLineOffset ? 0 : column - 1), | ||
offset: startOffset + endOffset | ||
} | ||
}, | ||
origin: matched | ||
}); | ||
return fixed; | ||
}) | ||
}); | ||
} | ||
return this._normalizeJsxNodes(node, options); | ||
} | ||
parse(code, options) { | ||
return this.parseForESLint(code, options).ast; | ||
} | ||
parseForESLint(code, options) { | ||
const extname = path.extname(options.filePath); | ||
const isMdx = DEFAULT_EXTENSIONS.concat(options.extensions || []).includes(extname); | ||
const isMarkdown = MARKDOWN_EXTENSIONS.concat(options.markdownExtensions || []).includes(extname); | ||
if (!isMdx && !isMarkdown) { | ||
return this._eslintParse(code, options); | ||
} | ||
const root = (isMdx ? mdxProcessor : mdProcessor).parse(code); | ||
this._ast = __spreadProps(__spreadValues({}, normalizePosition(root.position)), { | ||
type: "Program", | ||
sourceType: options.sourceType || "module", | ||
body: [], | ||
comments: [], | ||
tokens: [] | ||
}); | ||
this._services = { | ||
JSXElementsWithHTMLComments: [] | ||
}; | ||
Parser.prototype.parse = function (code, options) { | ||
return this.parseForESLint(code, options).ast; | ||
}; | ||
Parser.prototype.parseForESLint = function (code, options) { | ||
var _this = this; | ||
var extname = path.extname(options.filePath); | ||
var isMdx = DEFAULT_EXTENSIONS.concat(options.extensions || []).includes(extname); | ||
var isMarkdown = MARKDOWN_EXTENSIONS.concat(options.markdownExtensions || []).includes(extname); | ||
if (!isMdx && !isMarkdown) { | ||
return this._eslintParse(code, options); | ||
if (isMdx) { | ||
traverse(root, { | ||
code, | ||
enter: (node, parent) => { | ||
if (!ES_NODE_TYPES.includes(node.type)) { | ||
return; | ||
} | ||
for (const normalizedNode of arrayify(this.normalizeJsxNode(node, parent, options))) { | ||
this._nodeToAst(code, normalizedNode, options); | ||
} | ||
} | ||
var root = (isMdx ? mdxProcessor : mdProcessor).parse(code); | ||
this._ast = __assign(__assign({}, normalizePosition(root.position)), { type: 'Program', sourceType: options.sourceType || 'module', body: [], comments: [], tokens: [] }); | ||
this._services = { | ||
JSXElementsWithHTMLComments: [], | ||
}; | ||
if (isMdx) { | ||
traverse(root, { | ||
code: code, | ||
enter: function (node, parent) { | ||
if (!ES_NODE_TYPES.includes(node.type)) { | ||
return; | ||
} | ||
for (var _i = 0, _a = arrayify(_this.normalizeJsxNode(node, parent, options)); _i < _a.length; _i++) { | ||
var normalizedNode = _a[_i]; | ||
_this._nodeToAst(code, normalizedNode, options); | ||
} | ||
}, | ||
}); | ||
} | ||
return { | ||
ast: this._ast, | ||
services: this._services, | ||
}; | ||
}); | ||
} | ||
return { | ||
ast: this._ast, | ||
services: this._services | ||
}; | ||
// @internal | ||
Parser.prototype._eslintParse = function (code, options) { | ||
if (!this._parsers || options.parser !== this._options.parser) { | ||
this._parsers = normalizeParser(options.parser); | ||
} | ||
_eslintParse(code, options) { | ||
if (!this._parsers || options.parser !== this._options.parser) { | ||
this._parsers = normalizeParser(options.parser); | ||
} | ||
if (options.filePath && this._options !== options) { | ||
Object.assign(this._options, options); | ||
} | ||
let program; | ||
let parseError; | ||
for (const parser2 of this._parsers) { | ||
try { | ||
program = parser2(code, this._options); | ||
break; | ||
} catch (err) { | ||
if (!parseError) { | ||
parseError = err; | ||
} | ||
/* istanbul ignore else */ | ||
if (options.filePath && this._options !== options) { | ||
Object.assign(this._options, options); | ||
} | ||
} | ||
if (!program && parseError) { | ||
throw parseError; | ||
} | ||
return "ast" in program && program.ast ? program : { ast: program }; | ||
} | ||
_normalizeJsxNodes(node, options) { | ||
const value = node.value; | ||
let program; | ||
try { | ||
program = this._eslintParse(`${JSX_WRAPPER_START}${value}${JSX_WRAPPER_END}`, options).ast; | ||
} catch (err) { | ||
if (hasProperties(err, LOC_ERROR_PROPERTIES)) { | ||
const { | ||
position: { start } | ||
} = node; | ||
if ("index" in err) { | ||
err.index += start.offset - OFFSET; | ||
} else if ("pos" in err) { | ||
err.pos += start.offset - OFFSET; | ||
} | ||
var program; | ||
var parseError; | ||
for (var _i = 0, _a = this._parsers; _i < _a.length; _i++) { | ||
var parser_1 = _a[_i]; | ||
try { | ||
program = parser_1(code, this._options); | ||
break; | ||
} | ||
catch (err) { | ||
if (!parseError) { | ||
parseError = err; | ||
} | ||
} | ||
} | ||
if (!program && parseError) { | ||
throw parseError; | ||
} | ||
/* istanbul ignore next */ | ||
return ('ast' in program && program.ast | ||
? program | ||
: { ast: program }); | ||
}; | ||
// fix adjacent JSX nodes | ||
// @internal | ||
// eslint-disable-next-line sonarjs/cognitive-complexity | ||
Parser.prototype._normalizeJsxNodes = function (node, options) { | ||
var value = node.value; | ||
var program; | ||
try { | ||
// wrap into single element which is valid jsx but not valid jsx in mdx, so that it won't break on adjacent JSX nodes | ||
program = this._eslintParse("" + JSX_WRAPPER_START + value + JSX_WRAPPER_END, options).ast; | ||
} | ||
catch (err) { | ||
if (hasProperties(err, LOC_ERROR_PROPERTIES)) { | ||
var start = node.position.start; | ||
/* istanbul ignore else */ | ||
if ('index' in err) { | ||
err.index += start.offset - OFFSET; | ||
} | ||
else if ('pos' in err) { | ||
err.pos += start.offset - OFFSET; | ||
} | ||
err.column = | ||
/* istanbul ignore next */ | ||
err.lineNumber > 1 ? err.column : err.column + start.column - OFFSET; | ||
err.lineNumber += start.line - 1; | ||
throw err; | ||
} | ||
return node; | ||
} | ||
var expression = program.body[0].expression; | ||
if (!isJsxNode(expression) || expression.children.length <= 1) { | ||
return node; | ||
} | ||
var _a = node.position.start, line = _a.line, offset = _a.offset, data = node.data; | ||
return expression.children.reduce(function (nodes, jsNode) { | ||
if (!isJsxNode(jsNode)) { | ||
return nodes; | ||
} | ||
/* istanbul ignore next */ | ||
var nodeStart = jsNode.start, nodeEnd = jsNode.end, _a = jsNode.loc, _b = _a === void 0 ? { | ||
start: { column: nodeStart, line: 1 }, | ||
end: { column: nodeEnd, line: 1 }, | ||
} : _a, start = _b.start, end = _b.end, _c = jsNode.range, range = _c === void 0 ? [nodeStart, nodeEnd] : _c; | ||
var startLine = line + start.line - 1; | ||
var endLine = line + end.line - 1; | ||
var startOffset = range[0] - OFFSET; | ||
var endOffset = range[1] - OFFSET; | ||
nodes.push({ | ||
type: 'jsx', | ||
data: nodes.length > 0 ? null : data, | ||
value: value.slice(startOffset, endOffset), | ||
position: { | ||
start: { | ||
line: startLine, | ||
column: line === startLine ? start.column - OFFSET : start.column, | ||
offset: offset + startOffset, | ||
}, | ||
end: { | ||
line: endLine, | ||
column: line === startLine ? end.column - OFFSET : end.column, | ||
offset: offset + endOffset, | ||
}, | ||
}, | ||
}); | ||
return nodes; | ||
}, []); | ||
}; | ||
// @internal | ||
Parser.prototype._nodeToAst = function (code, node, options) { | ||
var _a; | ||
if (node.data && node.data.jsxType === 'JSXElementWithHTMLComments') { | ||
this._services.JSXElementsWithHTMLComments.push(node); | ||
} | ||
var value = node.value; | ||
var _b = normalizePosition(node.position), loc = _b.loc, start = _b.start, end = _b.end; | ||
// fix #4 | ||
if (isComment(value)) { | ||
var comment = COMMENT_CONTENT_REGEX.exec(value)[2]; | ||
this._ast.comments.push({ | ||
type: 'Block', | ||
value: comment, | ||
loc: loc, | ||
range: [start, end], | ||
}); | ||
return; | ||
} | ||
var startLine = loc.start.line - 1; // ! line is 1-indexed, change to 0-indexed to simplify usage | ||
var program; | ||
try { | ||
program = this._eslintParse(value, options).ast; | ||
} | ||
catch (e) { | ||
/* istanbul ignore if */ | ||
if (hasProperties(e, LOC_ERROR_PROPERTIES)) { | ||
// should be handled by `_normalizeJsxNodes`, just for robustness | ||
e.index += start; | ||
e.column = e.lineNumber > 1 ? e.column : e.column + loc.start.column; | ||
e.lineNumber += startLine; | ||
} | ||
throw e; | ||
} | ||
var startPoint = { | ||
err.column = err.lineNumber > 1 ? err.column : err.column + start.column - OFFSET; | ||
err.lineNumber += start.line - 1; | ||
throw err; | ||
} | ||
return node; | ||
} | ||
const { expression } = program.body[0]; | ||
if (!isJsxNode(expression) || expression.children.length <= 1) { | ||
return node; | ||
} | ||
const { | ||
position: { | ||
start: { line, offset } | ||
}, | ||
data | ||
} = node; | ||
return expression.children.reduce((nodes, jsNode) => { | ||
if (!isJsxNode(jsNode)) { | ||
return nodes; | ||
} | ||
const { | ||
start: nodeStart, | ||
end: nodeEnd, | ||
loc: { start, end } = { | ||
start: { column: nodeStart, line: 1 }, | ||
end: { column: nodeEnd, line: 1 } | ||
}, | ||
range = [nodeStart, nodeEnd] | ||
} = jsNode; | ||
const startLine = line + start.line - 1; | ||
const endLine = line + end.line - 1; | ||
const startOffset = range[0] - OFFSET; | ||
const endOffset = range[1] - OFFSET; | ||
nodes.push({ | ||
type: "jsx", | ||
data: nodes.length > 0 ? null : data, | ||
value: value.slice(startOffset, endOffset), | ||
position: { | ||
start: { | ||
line: startLine, | ||
// #279 related | ||
column: getPositionAt(code, start).column, | ||
offset: start, | ||
}; | ||
for (var _i = 0, AST_PROPS_1 = AST_PROPS; _i < AST_PROPS_1.length; _i++) { | ||
var prop = AST_PROPS_1[_i]; | ||
(_a = this._ast[prop]).push.apply(_a, program[prop].map(function (item) { | ||
return restoreNodeLocation(item, startPoint); | ||
})); | ||
column: line === startLine ? start.column - OFFSET : start.column, | ||
offset: offset + startOffset | ||
}, | ||
end: { | ||
line: endLine, | ||
column: line === startLine ? end.column - OFFSET : end.column, | ||
offset: offset + endOffset | ||
} | ||
} | ||
}); | ||
return nodes; | ||
}, []); | ||
} | ||
_nodeToAst(code, node, options) { | ||
if (node.data && node.data.jsxType === "JSXElementWithHTMLComments") { | ||
this._services.JSXElementsWithHTMLComments.push(node); | ||
} | ||
const value = node.value; | ||
const { loc, start, end } = normalizePosition(node.position); | ||
if (isComment(value)) { | ||
const comment = COMMENT_CONTENT_REGEX.exec(value)[2]; | ||
this._ast.comments.push({ | ||
type: "Block", | ||
value: comment, | ||
loc, | ||
range: [start, end] | ||
}); | ||
return; | ||
} | ||
const startLine = loc.start.line - 1; | ||
let program; | ||
try { | ||
program = this._eslintParse(value, options).ast; | ||
} catch (e) { | ||
if (hasProperties(e, LOC_ERROR_PROPERTIES)) { | ||
e.index += start; | ||
e.column = e.lineNumber > 1 ? e.column : e.column + loc.start.column; | ||
e.lineNumber += startLine; | ||
} | ||
throw e; | ||
} | ||
const startPoint = { | ||
line: startLine, | ||
column: getPositionAt(code, start).column, | ||
offset: start | ||
}; | ||
return Parser; | ||
}()); | ||
var parser = new Parser(); | ||
// eslint-disable-next-line @typescript-eslint/unbound-method | ||
var parse = parser.parse, parseForESLint = parser.parseForESLint; | ||
for (const prop of AST_PROPS) | ||
this._ast[prop].push(...program[prop].map((item) => restoreNodeLocation(item, startPoint))); | ||
} | ||
} | ||
const parser = new Parser(); | ||
const { parse, parseForESLint } = parser; | ||
export { AST_PROPS, CLOSE_TAG_REGEX, COMMENT_CONTENT_REGEX, COMMENT_CONTENT_REGEX_GLOBAL, COMMENT_REGEX, DEFAULT_EXTENSIONS, DEFAULT_PARSER_OPTIONS, ES_NODE_TYPES, FALLBACK_PARSERS, JSX_TYPES, LOC_ERROR_PROPERTIES, MARKDOWN_EXTENSIONS, OPEN_CLOSE_TAG_REGEX, OPEN_TAG_REGEX, Parser, SELF_CLOSING_TAG_REGEX, Traverse, arrayify, closeTag, comment, commentClose, commentContent, commentOpen, first, getPositionAt, hasProperties, isCloseTag, isComment, isJsxNode, isOpenCloseTag, isOpenTag, isSelfClosingTag, last, mdProcessor, mdxProcessor, normalizeParser, normalizePosition, openTag, parse, parseForESLint, parser, restoreNodeLocation, selfClosingTag, traverse }; |
@@ -119,2 +119,3 @@ "use strict"; | ||
exports.arrayify = arrayify; | ||
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain -- test coverage | ||
const first = (items) => items && items[0]; | ||
@@ -121,0 +122,0 @@ exports.first = first; |
import type { AST, Linter } from 'eslint'; | ||
import unified from 'unified'; | ||
import type { Node, Parent } from 'unist'; | ||
import type { ParserOptions } from './types'; | ||
import type { Node, Parent, ParserOptions } from './types'; | ||
export declare const mdProcessor: unified.FrozenProcessor<unified.Settings>; | ||
@@ -15,3 +14,3 @@ export declare const mdxProcessor: unified.FrozenProcessor<unified.Settings>; | ||
constructor(); | ||
normalizeJsxNode(node: Node, parent?: Parent, options?: ParserOptions): Node | Node[]; | ||
normalizeJsxNode(node: Node, parent?: Parent, options?: ParserOptions): Node<string> | Node<string>[]; | ||
parse(code: string, options: ParserOptions): AST.Program; | ||
@@ -18,0 +17,0 @@ parseForESLint(code: string, options: ParserOptions): Linter.ESLintParseResult; |
@@ -147,5 +147,3 @@ "use strict"; | ||
/* istanbul ignore next */ | ||
return ('ast' in program && program.ast | ||
? program | ||
: { ast: program }); | ||
return ('ast' in program && program.ast ? program : { ast: program }); | ||
} | ||
@@ -152,0 +150,0 @@ // fix adjacent JSX nodes |
@@ -1,3 +0,2 @@ | ||
import type { Node, Parent } from 'unist'; | ||
import type { TraverseOptions } from './types'; | ||
import type { Node, Parent, TraverseOptions } from './types'; | ||
export declare class Traverse { | ||
@@ -7,5 +6,5 @@ code: string; | ||
combineLeftJsxNodes(jsxNodes: Node[], parent?: Parent): Node; | ||
combineJsxNodes(nodes: Node[], parent?: Parent): Node[]; | ||
combineJsxNodes(nodes: Node[], parent?: Parent): Node<string>[]; | ||
traverse(node: Node, parent?: Parent): void; | ||
} | ||
export declare const traverse: (root: Parent, options: TraverseOptions) => void; |
@@ -118,7 +118,6 @@ "use strict"; | ||
} | ||
let children = node.children; | ||
if (children) { | ||
if ('children' in node) { | ||
const parent = node; | ||
children = node.children = this.combineJsxNodes(children, parent); | ||
for (const child of children) { | ||
parent.children = this.combineJsxNodes(parent.children, parent); | ||
for (const child of parent.children) { | ||
this.traverse(child, parent); | ||
@@ -125,0 +124,0 @@ } |
import type { JSXElement, JSXFragment } from '@babel/types'; | ||
import type { AST, Linter } from 'eslint'; | ||
import type { Node, Parent, Point } from 'unist'; | ||
import type { Node as _Node, Parent as _Parent, Point } from 'unist'; | ||
export interface Node<T = string> extends _Node { | ||
value?: T; | ||
} | ||
export interface Parent<T = string> extends _Parent { | ||
children: Array<Node<T>>; | ||
} | ||
export declare type Arrayable<T> = T[] | readonly T[]; | ||
@@ -10,10 +16,10 @@ export declare type ValueOf<T> = T extends { | ||
} ? N : never; | ||
export declare type JsxNode = (JSXElement | JSXFragment) & { | ||
export declare type JsxNode = { | ||
range: [number, number]; | ||
}; | ||
} & (JSXElement | JSXFragment); | ||
export declare type ParserFn = (code: string, options: Linter.ParserOptions) => AST.Program | Linter.ESLintParseResult; | ||
export declare type ParserConfig = { | ||
parse: ParserFn; | ||
} | { | ||
parseForESLint: ParserFn; | ||
} | { | ||
parse: ParserFn; | ||
}; | ||
@@ -27,6 +33,6 @@ export interface LocationError { | ||
export interface ParserOptions extends Linter.ParserOptions { | ||
extensions?: string | string[]; | ||
markdownExtensions?: string | string[]; | ||
extensions?: string[] | string; | ||
markdownExtensions?: string[] | string; | ||
filePath?: string; | ||
parser?: string | ParserConfig | ParserFn; | ||
parser?: ParserConfig | ParserFn | string; | ||
} | ||
@@ -33,0 +39,0 @@ export declare type Traverser = (node: Node, parent?: Parent) => void; |
{ | ||
"name": "eslint-mdx", | ||
"version": "1.13.0", | ||
"version": "1.14.0", | ||
"description": "ESLint Parser for MDX", | ||
@@ -38,6 +38,6 @@ "repository": "git+https://github.com/mdx-js/eslint-mdx.git", | ||
"remark-parse": "^8.0.3", | ||
"tslib": "^2.2.0", | ||
"tslib": "^2.3.0", | ||
"unified": "^9.2.1" | ||
}, | ||
"gitHead": "ebf3923730d1079b553991883c016e0c2f384bf7" | ||
"gitHead": "18283932bc37541dd6cbde2d678816a4ac94209c" | ||
} |
@@ -13,4 +13,3 @@ <p align="center"> | ||
[![Travis](https://img.shields.io/travis/com/mdx-js/eslint-mdx.svg)](https://travis-ci.com/mdx-js/eslint-mdx) | ||
[![Codacy Grade](https://img.shields.io/codacy/grade/4ea8225261c04837995a858676caae4b)](https://www.codacy.com/app/JounQin/eslint-mdx) | ||
[![GitHub Actions](https://github.com/mdx-js/eslint-mdx/workflows/CI/badge.svg)](https://github.com/mdx-js/eslint-mdx/actions/workflows/ci.yml) | ||
[![Codecov](https://img.shields.io/codecov/c/gh/mdx-js/eslint-mdx)](https://codecov.io/gh/mdx-js/eslint-mdx) | ||
@@ -24,3 +23,2 @@ [![type-coverage](https://img.shields.io/badge/dynamic/json.svg?label=type-coverage&prefix=%E2%89%A5&suffix=%&query=$.typeCoverage.atLeast&uri=https%3A%2F%2Fraw.githubusercontent.com%2Fmdx-js%2Feslint-mdx%2Fmaster%2Fpackage.json)](https://github.com/plantain-00/type-coverage) | ||
[![lerna](https://img.shields.io/badge/maintained%20with-lerna-cc00ff.svg)](https://lerna.js.org) | ||
[![codechecks.io](https://raw.githubusercontent.com/codechecks/docs/master/images/badges/badge-default.svg?sanitize=true)](https://codechecks.io) | ||
@@ -27,0 +25,0 @@ > [ESLint][] Parser/Plugin for [MDX][], helps you lint all ES syntaxes. |
declare module 'remark-mdx' { | ||
import type * as unified from 'unified' | ||
const mdx: unified.Attacher | ||
export = mdx | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
116323
1729
261
Updatedtslib@^2.3.0