eslint-mdx
Advanced tools
Comparing version 0.9.3 to 0.9.4
@@ -1,4 +0,14 @@ | ||
import { Arrayable } from './types'; | ||
import { Position, Node, Parent } from 'unist'; | ||
/// <reference path="../typings.d.ts" /> | ||
import { Arrayable, JsxNode, JsxTypes, ParserFn } from './types'; | ||
import { Position } from 'unist'; | ||
import { SourceLocation } from 'estree'; | ||
export declare const FALLBACK_PARSERS: readonly ["@typescript-eslint/parser", "babel-eslint"]; | ||
export declare const JSX_TYPES: JsxTypes; | ||
export declare const isJsxNode: (node: { | ||
type: string; | ||
}) => node is JsxNode; | ||
export declare const normalizeParser: (parser: string | { | ||
parseForESLint: ParserFn; | ||
parse: ParserFn; | ||
} | ParserFn) => ParserFn; | ||
export declare const normalizePosition: (position: Position) => { | ||
@@ -22,4 +32,3 @@ range: [number, number]; | ||
export declare const last: <T>(items: readonly T[] | T[]) => T; | ||
export declare const normalizeJsxNode: (node: Node, parent?: Parent) => Node; | ||
export declare const hasProperties: <T, P extends keyof T = keyof T>(obj: {}, properties: Arrayable<P>) => obj is T; | ||
//# sourceMappingURL=helper.d.ts.map |
"use strict"; | ||
// eslint-disable-next-line @typescript-eslint/no-triple-slash-reference | ||
/// <reference path="../typings.d.ts" /> | ||
var __assign = (this && this.__assign) || function () { | ||
@@ -14,3 +16,41 @@ __assign = Object.assign || function(t) { | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var regexp_1 = require("./regexp"); | ||
var espree_1 = require("espree"); | ||
exports.FALLBACK_PARSERS = [ | ||
'@typescript-eslint/parser', | ||
'babel-eslint', | ||
]; | ||
exports.JSX_TYPES = ['JSXElement', 'JSXFragment']; | ||
exports.isJsxNode = function (node) { | ||
return exports.JSX_TYPES.includes(node.type); | ||
}; | ||
exports.normalizeParser = function (parser) { | ||
if (parser) { | ||
if (typeof parser === 'string') { | ||
parser = require(parser); | ||
} | ||
if (typeof parser === 'object') { | ||
parser = parser.parseForESLint || parser.parse; | ||
} | ||
if (typeof parser !== 'function') { | ||
throw new TypeError("Invalid custom parser for `eslint-plugin-mdx`: " + parser); | ||
} | ||
} | ||
else { | ||
// try to load FALLBACK_PARSERS automatically | ||
for (var _i = 0, FALLBACK_PARSERS_1 = exports.FALLBACK_PARSERS; _i < FALLBACK_PARSERS_1.length; _i++) { | ||
var fallback = FALLBACK_PARSERS_1[_i]; | ||
try { | ||
// eslint-disable-next-line @typescript-eslint/no-var-requires | ||
var fallbackParser = require(fallback); | ||
parser = fallbackParser.parseForESLint || fallbackParser.parse; | ||
break; | ||
} | ||
catch (e) { } | ||
} | ||
if (typeof parser !== 'function') { | ||
parser = espree_1.parse; | ||
} | ||
return parser; | ||
} | ||
}; | ||
exports.normalizePosition = function (position) { | ||
@@ -65,46 +105,3 @@ var start = position.start.offset; | ||
}; | ||
exports.normalizeJsxNode = function (node, parent) { | ||
var value = node.value; | ||
if (regexp_1.isComment(value)) { | ||
return node; | ||
} | ||
var matched = value.match(regexp_1.COMMENT_CONTENT_REGEX); | ||
if (!matched) { | ||
return node; | ||
} | ||
var comments = []; | ||
var _a = node.position.start, line = _a.line, column = _a.column, startOffset = _a.offset; | ||
return Object.assign(node, { | ||
data: __assign({}, node.data, { jsxType: 'JSXElementWithHTMLComments', comments: 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(regexp_1.COMMENT_CONTENT_REGEX, 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.push({ | ||
fixed: fixed, | ||
loc: { | ||
start: { | ||
line: line + startLineOffset, | ||
column: exports.last(startLines).length + (startLineOffset ? 0 : column - 1), | ||
offset: startOffset + offset, | ||
}, | ||
end: { | ||
line: line + endLineOffset - 1, | ||
column: exports.last(endLines).length + (endLineOffset ? 0 : column - 1), | ||
offset: startOffset + endOffset, | ||
}, | ||
}, | ||
origin: matched, | ||
}); | ||
return fixed; | ||
}), | ||
}); | ||
}; | ||
exports.hasProperties = function (obj, properties) { return properties.every(function (property) { return property in obj; }); }; | ||
//# sourceMappingURL=helper.js.map |
@@ -1,14 +0,19 @@ | ||
/// <reference path="../typings.d.ts" /> | ||
import unified from 'unified'; | ||
import { ParserOptions } from './types'; | ||
import { AST, Linter } from 'eslint'; | ||
import { Parent, Node } from 'unist'; | ||
export declare const mdxProcessor: unified.Processor<unified.Settings>; | ||
export declare const AST_PROPS: readonly ["body", "comments", "tokens"]; | ||
export declare const ES_NODE_TYPES: readonly ["export", "import", "jsx"]; | ||
export declare type EsNodeType = (typeof ES_NODE_TYPES)[number]; | ||
export declare const ES_NODE_TYPES: readonly string[]; | ||
export declare const LOC_ERROR_PROPERTIES: readonly ["column", "index", "lineNumber"]; | ||
export declare const DEFAULT_EXTENSIONS: string[]; | ||
export declare const FALLBACK_PARSERS: string[]; | ||
export declare const parseForESLint: (code: string, options?: ParserOptions) => Linter.ESLintParseResult; | ||
export declare const parse: (code: string, options?: Linter.ParserOptions) => AST.Program; | ||
export declare const DEFAULT_EXTENSIONS: readonly string[]; | ||
export declare const DEFAULT_PARSER_OPTIONS: ParserOptions; | ||
export declare class Parser { | ||
constructor(code?: string, options?: ParserOptions); | ||
normalizeJsxNode(node: Node, parent?: Parent): Node | Node[]; | ||
parse(code?: string, options?: ParserOptions): AST.Program; | ||
parseForESLint(code?: string, options?: ParserOptions): Linter.ESLintParseResult; | ||
} | ||
export declare const parser: Parser; | ||
export declare const parse: (code?: string, options?: ParserOptions) => AST.Program, parseForESLint: (code?: string, options?: ParserOptions) => Linter.ESLintParseResult; | ||
//# sourceMappingURL=parser.d.ts.map |
"use strict"; | ||
// eslint-disable-next-line @typescript-eslint/no-triple-slash-reference | ||
/// <reference path="../typings.d.ts" /> | ||
var __assign = (this && this.__assign) || function () { | ||
@@ -20,3 +18,2 @@ __assign = Object.assign || function(t) { | ||
var path_1 = __importDefault(require("path")); | ||
var espree_1 = require("espree"); | ||
var remark_mdx_1 = __importDefault(require("remark-mdx")); | ||
@@ -36,93 +33,187 @@ var remark_parse_1 = __importDefault(require("remark-parse")); | ||
exports.DEFAULT_EXTENSIONS = ['.mdx']; | ||
exports.FALLBACK_PARSERS = ['@typescript-eslint/parser', 'babel-eslint']; | ||
exports.parseForESLint = function (code, options) { | ||
if (options === void 0) { options = {}; } | ||
var extensions = options.extensions, parser = options.parser; | ||
if (parser) { | ||
if (typeof parser === 'string') { | ||
parser = require(parser); | ||
exports.DEFAULT_PARSER_OPTIONS = { | ||
ecmaFeatures: { jsx: true }, | ||
ecmaVersion: new Date().getUTCFullYear(), | ||
sourceType: 'module', | ||
}; | ||
var Parser = /** @class */ (function () { | ||
function Parser( | ||
// @internal | ||
code, | ||
// @internal | ||
options) { | ||
if (code === void 0) { code = ''; } | ||
if (options === void 0) { options = exports.DEFAULT_PARSER_OPTIONS; } | ||
this.code = code; | ||
this.options = options; | ||
// @internal | ||
this.parser = helper_1.normalizeParser(this.options.parser); | ||
// @internal | ||
this.services = { | ||
JSXElementsWithHTMLComments: [], | ||
}; | ||
this.parse = this.parse.bind(this); | ||
this.parseForESLint = this.parseForESLint.bind(this); | ||
this.nodeToAst = this.nodeToAst.bind(this); | ||
} | ||
Parser.prototype.normalizeJsxNode = function (node, parent) { | ||
var value = node.value; | ||
if (node.type !== 'jsx' || regexp_1.isComment(value)) { | ||
return node; | ||
} | ||
if (typeof parser === 'object') { | ||
parser = parser.parseForESLint || parser.parse; | ||
var matched = value.match(regexp_1.COMMENT_CONTENT_REGEX); | ||
if (matched) { | ||
var comments_1 = []; | ||
var _a = node.position.start, line_1 = _a.line, column_1 = _a.column, startOffset_1 = _a.offset; | ||
Object.assign(node, { | ||
data: __assign({}, node.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(regexp_1.COMMENT_CONTENT_REGEX, 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, | ||
loc: { | ||
start: { | ||
line: line_1 + startLineOffset, | ||
column: helper_1.last(startLines).length + | ||
(startLineOffset ? 0 : column_1 - 1), | ||
offset: startOffset_1 + offset, | ||
}, | ||
end: { | ||
line: line_1 + endLineOffset - 1, | ||
column: helper_1.last(endLines).length + (endLineOffset ? 0 : column_1 - 1), | ||
offset: startOffset_1 + endOffset, | ||
}, | ||
}, | ||
origin: matched, | ||
}); | ||
return fixed; | ||
}), | ||
}); | ||
} | ||
if (typeof parser !== 'function') { | ||
throw new TypeError("Invalid custom parser for `eslint-plugin-mdx`: " + options.parser); | ||
return this.normalizeJsxNodes(node); | ||
}; | ||
Parser.prototype.parse = function (code, options) { | ||
if (code === void 0) { code = this.code; } | ||
if (options === void 0) { options = this.options; } | ||
return this.parseForESLint(code, options).ast; | ||
}; | ||
Parser.prototype.parseForESLint = function (code, options) { | ||
var _this = this; | ||
if (code === void 0) { code = this.code; } | ||
if (options === void 0) { options = this.options; } | ||
if (!exports.DEFAULT_EXTENSIONS.concat(this.options.extensions || []).includes(path_1.default.extname(options.filePath))) { | ||
return this.eslintParse(code, options); | ||
} | ||
} | ||
else { | ||
// try to load FALLBACK_PARSERS automatically | ||
for (var _i = 0, FALLBACK_PARSERS_1 = exports.FALLBACK_PARSERS; _i < FALLBACK_PARSERS_1.length; _i++) { | ||
var fallback = FALLBACK_PARSERS_1[_i]; | ||
try { | ||
// eslint-disable-next-line @typescript-eslint/no-var-requires | ||
var fallbackParser = require(fallback); | ||
parser = fallbackParser.parseForESLint || fallbackParser.parse; | ||
break; | ||
} | ||
catch (e) { } | ||
} | ||
if (typeof parser !== 'function') { | ||
parser = espree_1.parse; | ||
} | ||
} | ||
if (!exports.DEFAULT_EXTENSIONS.concat(extensions || []).includes(path_1.default.extname(options.filePath))) { | ||
var program = parser(code, options); | ||
return (program.ast | ||
var root = exports.mdxProcessor.parse(this.code); | ||
this.ast = __assign({}, helper_1.normalizePosition(root.position), { type: 'Program', sourceType: this.options.sourceType || 'module', body: [], comments: [], tokens: [] }); | ||
traverse_1.traverse(root, { | ||
enter: function (node, parent) { | ||
if (!exports.ES_NODE_TYPES.includes(node.type)) { | ||
return; | ||
} | ||
var normalized = _this.normalizeJsxNode(node, parent); | ||
normalized = Array.isArray(normalized) ? normalized : [normalized]; | ||
normalized.forEach(_this.nodeToAst); | ||
}, | ||
}); | ||
return { | ||
ast: this.ast, | ||
services: this.services, | ||
}; | ||
}; | ||
// @internal | ||
Parser.prototype.eslintParse = function (code, options) { | ||
if (code === void 0) { code = this.code; } | ||
if (options === void 0) { options = this.options; } | ||
var program = this.parser(code, options); | ||
return ('ast' in program && program.ast | ||
? program | ||
: { ast: program }); | ||
} | ||
var root = exports.mdxProcessor.parse(code); | ||
var ast = __assign({}, helper_1.normalizePosition(root.position), { type: 'Program', sourceType: options.sourceType || 'module', body: [], comments: [], tokens: [] }); | ||
var services = { | ||
JSXElementsWithHTMLComments: [], | ||
}; | ||
traverse_1.traverse(root, { | ||
enter: function (node, parent) { | ||
if (!exports.ES_NODE_TYPES.includes(node.type)) { | ||
return; | ||
// fix adjacent JSX nodes | ||
// @internal | ||
Parser.prototype.normalizeJsxNodes = function (node) { | ||
var value = node.value; | ||
// wrap into single Fragment, so that it won't break on adjacent JSX nodes | ||
var program = this.eslintParse("<>" + value + "</>").ast; | ||
var expression = program.body[0].expression; | ||
if (!helper_1.isJsxNode(expression) || expression.children.length <= 1) { | ||
return node; | ||
} | ||
var _a = node.position.start, line = _a.line, offset = _a.offset; | ||
return expression.children.reduce(function (nodes, jsNode) { | ||
if (!helper_1.isJsxNode(jsNode)) { | ||
return nodes; | ||
} | ||
helper_1.normalizeJsxNode(node, parent); | ||
if (node.data && node.data.jsxType === 'JSXElementWithHTMLComments') { | ||
services.JSXElementsWithHTMLComments.push(node); | ||
} | ||
var value = node.value; | ||
// fix #4 | ||
if (regexp_1.isComment(value)) { | ||
return; | ||
} | ||
var _a = helper_1.normalizePosition(node.position), loc = _a.loc, start = _a.start; | ||
var startLine = loc.start.line - 1; //! line is 1-indexed, change to 0-indexed to simplify usage | ||
var program; | ||
try { | ||
program = parser(value, options); | ||
} | ||
catch (e) { | ||
if (helper_1.hasProperties(e, exports.LOC_ERROR_PROPERTIES)) { | ||
e.index += start; | ||
e.column += loc.start.column; | ||
e.lineNumber += startLine; | ||
} | ||
throw e; | ||
} | ||
if ('ast' in program) { | ||
program = program.ast; | ||
} | ||
var offset = start - program.range[0]; | ||
exports.AST_PROPS.forEach(function (prop) { | ||
var _a; | ||
return (_a = ast[prop]).push.apply(_a, program[prop].map(function (item) { | ||
return helper_1.restoreNodeLocation(item, startLine, offset); | ||
})); | ||
var _a = jsNode.loc, start = _a.start, end = _a.end, range = jsNode.range; | ||
var startLine = line + start.line - 1; | ||
var endLine = line + end.line - 1; | ||
var startOffset = range[0] - 2; | ||
var endOffset = range[1] - 2; | ||
nodes.push({ | ||
type: 'jsx', | ||
data: nodes.length ? null : node.data, | ||
value: value.slice(startOffset, endOffset), | ||
position: { | ||
start: { | ||
line: startLine, | ||
column: line === startLine ? start.column - 2 : start.column, | ||
offset: offset + startOffset, | ||
}, | ||
end: { | ||
line: endLine, | ||
column: line === startLine ? end.column - 2 : end.column, | ||
offset: offset + endOffset, | ||
}, | ||
}, | ||
}); | ||
}, | ||
}); | ||
return { | ||
ast: ast, | ||
services: services, | ||
return nodes; | ||
}, []); | ||
}; | ||
}; | ||
exports.parse = function (code, options) { | ||
if (options === void 0) { options = {}; } | ||
return exports.parseForESLint(code, options).ast; | ||
}; | ||
// @internal | ||
Parser.prototype.nodeToAst = function (node) { | ||
var _this = this; | ||
if (node.data && node.data.jsxType === 'JSXElementWithHTMLComments') { | ||
this.services.JSXElementsWithHTMLComments.push(node); | ||
} | ||
var value = node.value; | ||
// fix #4 | ||
if (regexp_1.isComment(value)) { | ||
return; | ||
} | ||
var _a = helper_1.normalizePosition(node.position), loc = _a.loc, start = _a.start; | ||
var startLine = loc.start.line - 1; //! line is 1-indexed, change to 0-indexed to simplify usage | ||
var program; | ||
try { | ||
program = this.eslintParse(value).ast; | ||
} | ||
catch (e) { | ||
if (helper_1.hasProperties(e, exports.LOC_ERROR_PROPERTIES)) { | ||
e.index += start; | ||
e.column += loc.start.column; | ||
e.lineNumber += startLine; | ||
} | ||
throw e; | ||
} | ||
var offset = start - program.range[0]; | ||
exports.AST_PROPS.forEach(function (prop) { | ||
var _a; | ||
return (_a = _this.ast[prop]).push.apply(_a, program[prop].map(function (item) { | ||
return helper_1.restoreNodeLocation(item, startLine, offset); | ||
})); | ||
}); | ||
}; | ||
return Parser; | ||
}()); | ||
exports.Parser = Parser; | ||
exports.parser = new Parser(); | ||
exports.parse = exports.parser.parse, exports.parseForESLint = exports.parser.parseForESLint; | ||
//# sourceMappingURL=parser.js.map |
import { TraverseOptions } from './types'; | ||
import { Node, Parent } from 'unist'; | ||
export declare const SKIP_COMBINE_JSX_TYPES: readonly string[]; | ||
export declare class Traverse { | ||
@@ -4,0 +5,0 @@ private _enter; |
@@ -5,2 +5,3 @@ "use strict"; | ||
var regexp_1 = require("./regexp"); | ||
exports.SKIP_COMBINE_JSX_TYPES = ['root', 'jsx']; | ||
var Traverse = /** @class */ (function () { | ||
@@ -41,2 +42,3 @@ function Traverse(_a) { | ||
type: 'jsx', | ||
data: jsxNodes[0].data, | ||
value: jsxNodes.reduce(function (acc, _a) { | ||
@@ -71,6 +73,6 @@ var value = _a.value; | ||
if (children) { | ||
; | ||
(node.children = this.combineJsxNodes(children)).forEach(function (child) { | ||
return _this.traverse(child, node); | ||
}); | ||
if (!exports.SKIP_COMBINE_JSX_TYPES.includes(node.type)) { | ||
children = node.children = this.combineJsxNodes(children); | ||
} | ||
children.forEach(function (child) { return _this.traverse(child, node); }); | ||
} | ||
@@ -77,0 +79,0 @@ this._enter(node, parent); |
@@ -1,4 +0,11 @@ | ||
import { Linter } from 'eslint'; | ||
import { JSXElement, JSXFragment } from '@babel/types'; | ||
import { Linter, AST } from 'eslint'; | ||
import { Node, Parent, Point } from 'unist'; | ||
export declare type JsxNode = (JSXElement | JSXFragment) & { | ||
range: [number, number]; | ||
}; | ||
export declare type JsxTypes = readonly [JSXElement['type'], JSXFragment['type']]; | ||
export declare type JsxType = JsxTypes[number]; | ||
export declare type Arrayable<T> = T[] | readonly T[]; | ||
export declare type ParserFn = (code: string, options: Linter.ParserOptions) => AST.Program | Linter.ESLintParseResult; | ||
export interface LocationError { | ||
@@ -11,2 +18,7 @@ column?: number; | ||
extensions?: string | string[]; | ||
filePath?: string; | ||
parser?: string | { | ||
parseForESLint: ParserFn; | ||
parse: ParserFn; | ||
} | ParserFn; | ||
} | ||
@@ -13,0 +25,0 @@ export declare type Traverser = (node: Node, parent?: Parent) => void; |
{ | ||
"name": "eslint-mdx", | ||
"version": "0.9.3", | ||
"version": "0.9.4", | ||
"description": "ESLint Parser for MDX", | ||
@@ -23,3 +23,3 @@ "repository": "git@github.com:rx-ts/eslint-plugin-mdx.git", | ||
}, | ||
"gitHead": "25d6a99d38e756ad59ce0beff624d82c877dfc72" | ||
"gitHead": "32cb0c4f7a6959e4eac4618cd45ce7b70dd2f7a4" | ||
} |
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
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
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
45855
626