UNPKG

17.3 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5var tslib = require('tslib');
6var package_json = require('eslint/package.json');
7var eslintMdx = require('eslint-mdx');
8var reactNoUnescapedEntities = require('eslint-plugin-react/lib/rules/no-unescaped-entities');
9var esLintNoUnusedExpressions = require('eslint/lib/rules/no-unused-expressions');
10var path = require('path');
11var vfile = require('vfile');
12var cosmiconfig = require('cosmiconfig');
13var remarkMdx = require('remark-mdx');
14var remarkParse = require('remark-parse');
15var remarkStringify = require('remark-stringify');
16var unified = require('unified');
17
18function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
19
20var reactNoUnescapedEntities__default = /*#__PURE__*/_interopDefaultLegacy(reactNoUnescapedEntities);
21var esLintNoUnusedExpressions__default = /*#__PURE__*/_interopDefaultLegacy(esLintNoUnusedExpressions);
22var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
23var vfile__default = /*#__PURE__*/_interopDefaultLegacy(vfile);
24var remarkMdx__default = /*#__PURE__*/_interopDefaultLegacy(remarkMdx);
25var remarkParse__default = /*#__PURE__*/_interopDefaultLegacy(remarkParse);
26var remarkStringify__default = /*#__PURE__*/_interopDefaultLegacy(remarkStringify);
27var unified__default = /*#__PURE__*/_interopDefaultLegacy(unified);
28
29var base = {
30 parser: 'eslint-mdx',
31 plugins: ['mdx'],
32};
33
34var getGlobals = function (sources, initialGlobals) {
35 if (initialGlobals === void 0) { initialGlobals = {}; }
36 return (Array.isArray(sources)
37 ? sources
38 : Object.keys(sources)).reduce(function (globals, source) {
39 var _a;
40 return Object.assign(globals, (_a = {},
41 _a[source] = false,
42 _a));
43 }, initialGlobals);
44};
45
46var rebass;
47try {
48 // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
49 rebass = require('rebass');
50}
51catch (_a) {
52 // `rebass`(or `reflexbox` actually) requires `react` as peerDependency, but not all projects using `mdx` are `React` based, so we fallback to hardcoded `rebass` Components here
53 /* istanbul ignore next */
54 rebass = ['Box', 'Flex', 'Text', 'Heading', 'Link', 'Button', 'Image', 'Card'];
55}
56var overrides$1 = tslib.__assign(tslib.__assign({}, base), { globals: getGlobals(rebass, {
57 React: false,
58 }), rules: {
59 'lines-between-class-members': 0,
60 'react/jsx-no-undef': [
61 2,
62 {
63 allowGlobals: true,
64 },
65 ],
66 'react/react-in-jsx-scope': 0,
67 } });
68
69var minorVersion = +package_json.version.split('.').slice(0, 2).join('.');
70var recommended = tslib.__assign(tslib.__assign({}, base), { rules: {
71 'mdx/no-jsx-html-comments': 2,
72 'mdx/no-unescaped-entities': 1,
73 'mdx/no-unused-expressions': 2,
74 'mdx/remark': 1,
75 'no-unused-expressions': 0,
76 'react/no-unescaped-entities': 0,
77 } });
78var OVERRIDES_AVAILABLE_VERSION = 6.4;
79// overrides in npm pkg is supported after v6.4.0
80// istanbul ignore else
81if (minorVersion >= OVERRIDES_AVAILABLE_VERSION) {
82 var overrides = [
83 {
84 files: '*.mdx',
85 extends: 'plugin:mdx/overrides',
86 },
87 ];
88 try {
89 // eslint-disable-next-line node/no-extraneous-require
90 require.resolve('prettier');
91 // eslint-disable-next-line node/no-extraneous-require
92 require.resolve('eslint-plugin-prettier');
93 overrides.push({
94 files: '*.md',
95 rules: {
96 'prettier/prettier': [
97 2,
98 {
99 parser: 'markdown',
100 },
101 ],
102 },
103 });
104 }
105 catch (_a) { }
106 Object.assign(recommended, {
107 overrides: overrides,
108 });
109}
110
111var index = /*#__PURE__*/Object.freeze({
112 __proto__: null,
113 base: base,
114 overrides: overrides$1,
115 recommended: recommended
116});
117
118var noJsxHtmlComments = {
119 meta: {
120 type: 'problem',
121 docs: {
122 description: 'Forbid invalid html style comments in jsx block',
123 category: 'SyntaxError',
124 recommended: true,
125 },
126 messages: {
127 jsxHtmlComments: 'html style comments are invalid in jsx: {{ origin }}',
128 },
129 fixable: 'code',
130 },
131 create: function (context) {
132 return {
133 ExpressionStatement: function (node) {
134 var invalidNodes = context.parserServices
135 .JSXElementsWithHTMLComments;
136 if (!eslintMdx.JSX_TYPES.includes(node.expression.type) ||
137 node.parent.type !== 'Program' ||
138 !invalidNodes ||
139 invalidNodes.length === 0) {
140 return;
141 }
142 var invalidNode = invalidNodes.shift();
143 if (invalidNode.data.inline) {
144 return;
145 }
146 var comments = invalidNode.data.comments;
147 var _loop_1 = function (fixed, loc, origin_1) {
148 context.report({
149 messageId: 'jsxHtmlComments',
150 data: {
151 origin: origin_1,
152 },
153 loc: loc,
154 node: node,
155 fix: function (fixer) {
156 return fixer.replaceTextRange([loc.start.offset, loc.end.offset], fixed);
157 },
158 });
159 };
160 for (var _i = 0, comments_1 = comments; _i < comments_1.length; _i++) {
161 var _a = comments_1[_i], fixed = _a.fixed, loc = _a.loc, origin_1 = _a.origin;
162 _loop_1(fixed, loc, origin_1);
163 }
164 },
165 };
166 },
167};
168
169/// <reference path="../../typings.d.ts" />
170// copied from `eslint-plugin-react`
171var DEFAULTS = [
172 {
173 char: '>',
174 alternatives: ['&gt;'],
175 },
176 {
177 char: '"',
178 alternatives: ['&quot;', '&ldquo;', '&#34;', '&rdquo;'],
179 },
180 {
181 char: "'",
182 alternatives: ['&apos;', '&lsquo;', '&#39;', '&rsquo;'],
183 },
184 {
185 char: '}',
186 alternatives: ['&#125;'],
187 },
188];
189var EXPRESSION = 'Literal, JSXText';
190var noUnescapedEntities = tslib.__assign(tslib.__assign({}, reactNoUnescapedEntities__default['default']), { create: function (context) {
191 var _a;
192 var configuration = (context.options[0] || {});
193 var entities = configuration.forbid || DEFAULTS;
194 return _a = {},
195 // eslint-disable-next-line sonarjs/cognitive-complexity
196 _a[EXPRESSION] = function (node) {
197 var parent = node.parent, loc = node.loc;
198 if (!eslintMdx.isJsxNode(parent)) {
199 return;
200 }
201 while (parent) {
202 if (parent.parent.type === 'Program') {
203 break;
204 }
205 else {
206 parent = parent.parent;
207 }
208 }
209 var _a = loc.start, startLine = _a.line, startColumn = _a.column, _b = loc.end, endLine = _b.line, endColumn = _b.column;
210 var lines = context.getSourceCode().lines;
211 var firstLineOffset = parent.loc.start.line < startLine
212 ? 0
213 : lines
214 .slice(startLine - 1, endLine)
215 .join('\n')
216 .search(eslintMdx.openTag);
217 /* istanbul ignore if */
218 if (firstLineOffset < 0) {
219 // should never happen, just for robustness
220 firstLineOffset = 0;
221 }
222 for (var i = startLine; i <= endLine; i++) {
223 var rawLine = lines[i - 1];
224 var start = 0;
225 var end = rawLine.length;
226 if (i === startLine) {
227 start = startColumn + firstLineOffset;
228 }
229 if (i === endLine) {
230 end = endColumn;
231 if (i === startLine) {
232 end += firstLineOffset;
233 }
234 }
235 rawLine = rawLine.slice(start, end);
236 for (var _i = 0, entities_1 = entities; _i < entities_1.length; _i++) {
237 var entity = entities_1[_i];
238 // eslint-disable-next-line unicorn/no-for-loop
239 for (var index = 0; index < rawLine.length; index++) {
240 var char = rawLine[index];
241 if (typeof entity === 'string') {
242 if (char === entity) {
243 context.report({
244 loc: { line: i, column: start + index },
245 message: "HTML entity, `" + entity + "` , must be escaped.",
246 node: node,
247 });
248 }
249 }
250 else if (char === entity.char) {
251 context.report({
252 loc: { line: i, column: start + index },
253 message: "`" + entity.char + "` can be escaped with " + entity.alternatives
254 .map(function (alt) { return '``'.split('').join(alt); })
255 .join(', ') + ".",
256 node: node,
257 });
258 }
259 }
260 }
261 }
262 },
263 _a;
264 } });
265
266/// <reference path="../../typings.d.ts" />
267var noUnusedExpressions = tslib.__assign(tslib.__assign({}, esLintNoUnusedExpressions__default['default']), { create: function (context) {
268 var esLintRuleListener = esLintNoUnusedExpressions__default['default'].create(context);
269 return {
270 ExpressionStatement: function (node) {
271 if (eslintMdx.isJsxNode(node.expression) && node.parent.type === 'Program') {
272 return;
273 }
274 esLintRuleListener.ExpressionStatement(node);
275 },
276 };
277 } });
278
279var requirePkg = function (plugin, prefix, filePath) {
280 if (filePath && /^\.\.?([/\\]|$)/.test(plugin)) {
281 plugin = path__default['default'].resolve(path__default['default'].dirname(filePath), plugin);
282 }
283 prefix = prefix.endsWith('-') ? prefix : prefix + '-';
284 var packages = [
285 plugin,
286 plugin.startsWith('@')
287 ? plugin.replace('/', '/' + prefix)
288 : prefix + plugin,
289 ];
290 var error;
291 for (var _i = 0, packages_1 = packages; _i < packages_1.length; _i++) {
292 var pkg = packages_1[_i];
293 try {
294 // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
295 return require(pkg);
296 }
297 catch (err) {
298 if (!error) {
299 error = err;
300 }
301 }
302 }
303 throw error;
304};
305var searchSync;
306var remarkProcessor;
307var getRemarkProcessor = function (searchFrom, isMdx) {
308 if (!searchSync) {
309 searchSync = cosmiconfig.cosmiconfigSync('remark', {
310 packageProp: 'remarkConfig',
311 }).search;
312 }
313 if (!remarkProcessor) {
314 remarkProcessor = unified__default['default']().use(remarkParse__default['default']).freeze();
315 }
316 /* istanbul ignore next */
317 var result = searchSync(searchFrom) || {};
318 /* istanbul ignore next */
319 var _a = (result.config ||
320 {}), _b = _a.plugins, plugins = _b === void 0 ? [] : _b, settings = _a.settings;
321 try {
322 // disable this rule automatically since we already have a parser option `extensions`
323 // eslint-disable-next-line node/no-extraneous-require
324 plugins.push([require.resolve('remark-lint-file-extension'), false]);
325 }
326 catch (_c) {
327 // just ignore if the package does not exist
328 }
329 var initProcessor = remarkProcessor().use({ settings: settings }).use(remarkStringify__default['default']);
330 if (isMdx) {
331 initProcessor.use(remarkMdx__default['default']);
332 }
333 return plugins
334 .reduce(function (processor, pluginWithSettings) {
335 var _a = Array.isArray(pluginWithSettings)
336 ? pluginWithSettings
337 : [pluginWithSettings], plugin = _a[0], pluginSettings = _a.slice(1);
338 return processor.use.apply(processor, tslib.__spreadArray([
339 /* istanbul ignore next */
340 typeof plugin === 'string'
341 ? requirePkg(plugin, 'remark', result.filepath)
342 : plugin], pluginSettings));
343 }, initProcessor)
344 .freeze();
345};
346
347var remark = {
348 meta: {
349 type: 'layout',
350 docs: {
351 description: 'Linter integration with remark plugins',
352 category: 'Stylistic Issues',
353 recommended: true,
354 },
355 messages: {
356 remarkReport: '{{ source }}:{{ ruleId }} - {{ reason }}',
357 },
358 fixable: 'code',
359 },
360 create: function (context) {
361 var filename = context.getFilename();
362 var extname = path__default['default'].extname(filename);
363 var sourceCode = context.getSourceCode();
364 var options = context.parserOptions;
365 var isMdx = eslintMdx.DEFAULT_EXTENSIONS.concat(options.extensions || []).includes(extname);
366 var isMarkdown = eslintMdx.MARKDOWN_EXTENSIONS.concat(options.markdownExtensions || []).includes(extname);
367 return {
368 Program: function (node) {
369 /* istanbul ignore if */
370 if (!isMdx && !isMarkdown) {
371 return;
372 }
373 var sourceText = sourceCode.getText(node);
374 var remarkProcessor = getRemarkProcessor(filename, isMdx);
375 var file = vfile__default['default']({
376 path: filename,
377 contents: sourceText,
378 });
379 try {
380 remarkProcessor.processSync(file);
381 }
382 catch (err) {
383 /* istanbul ignore next */
384 if (!file.messages.includes(err)) {
385 file.message(err).fatal = true;
386 }
387 }
388 var _loop_1 = function (source, reason, ruleId, start, end) {
389 context.report({
390 messageId: 'remarkReport',
391 data: {
392 reason: reason,
393 source: source,
394 ruleId: ruleId,
395 },
396 loc: {
397 // ! eslint ast column is 0-indexed, but unified is 1-indexed
398 start: tslib.__assign(tslib.__assign({}, start), { column: start.column - 1 }),
399 end: tslib.__assign(tslib.__assign({}, end), { column: end.column - 1 }),
400 },
401 node: node,
402 fix: function (fixer) {
403 /* istanbul ignore if */
404 if (start.offset == null) {
405 return null;
406 }
407 var range = [
408 start.offset,
409 /* istanbul ignore next */
410 end.offset == null ? start.offset + 1 : end.offset,
411 ];
412 var partialText = sourceText.slice.apply(sourceText, range);
413 var fixed = remarkProcessor.processSync(partialText).toString();
414 return fixer.replaceTextRange(range,
415 /* istanbul ignore next */
416 partialText.endsWith('\n') ? fixed : fixed.slice(0, -1));
417 },
418 });
419 };
420 for (var _i = 0, _a = file.messages; _i < _a.length; _i++) {
421 var _b = _a[_i], source = _b.source, reason = _b.reason, ruleId = _b.ruleId, _c = _b.location, start = _c.start, end = _c.end;
422 _loop_1(source, reason, ruleId, start, end);
423 }
424 },
425 };
426 },
427};
428
429var rules = {
430 'no-jsx-html-comments': noJsxHtmlComments,
431 'no-unescaped-entities': noUnescapedEntities,
432 'no-unused-expressions': noUnusedExpressions,
433 remark: remark,
434};
435
436exports.configs = index;
437exports.getGlobals = getGlobals;
438exports.getRemarkProcessor = getRemarkProcessor;
439exports.noJsxHtmlComments = noJsxHtmlComments;
440exports.noUnescapedEntities = noUnescapedEntities;
441exports.noUnusedExpressions = noUnusedExpressions;
442exports.remark = remark;
443exports.requirePkg = requirePkg;
444exports.rules = rules;