eslint-markdown 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,6 +17,7 @@ export default function all(plugin: ESLint.Plugin): {
17
17
  readonly 'md/allow-image-url': "error";
18
18
  readonly 'md/allow-link-url': "error";
19
19
  readonly 'md/code-lang-shorthand': "error";
20
+ readonly 'md/consistent-code-style': "error";
20
21
  readonly 'md/consistent-delete-style': "error";
21
22
  readonly 'md/consistent-emphasis-style': "error";
22
23
  readonly 'md/consistent-strong-style': "error";
@@ -14,6 +14,7 @@ export default function stylistic(plugin: ESLint.Plugin): {
14
14
  };
15
15
  readonly language: "markdown/gfm";
16
16
  readonly rules: {
17
+ readonly 'md/consistent-code-style': "error";
17
18
  readonly 'md/consistent-delete-style': "error";
18
19
  readonly 'md/consistent-emphasis-style': "error";
19
20
  readonly 'md/consistent-strong-style': "error";
@@ -0,0 +1,43 @@
1
+ declare const _default: {
2
+ meta: {
3
+ type: "layout";
4
+ docs: {
5
+ description: string;
6
+ url: string;
7
+ recommended: boolean;
8
+ stylistic: true;
9
+ };
10
+ schema: {
11
+ type: "object";
12
+ properties: {
13
+ style: {
14
+ enum: string[];
15
+ };
16
+ };
17
+ additionalProperties: false;
18
+ }[];
19
+ defaultOptions: [{
20
+ style: "consistent";
21
+ }];
22
+ messages: {
23
+ style: string;
24
+ };
25
+ language: string;
26
+ dialects: string[];
27
+ };
28
+ create(context: import("@eslint/core").RuleContext<{
29
+ LangOptions: import("@eslint/markdown").MarkdownLanguageOptions;
30
+ Code: import("@eslint/markdown").MarkdownSourceCode;
31
+ RuleOptions: RuleOptions;
32
+ Node: import("mdast").Node;
33
+ MessageIds: "style";
34
+ }>): {
35
+ code(node: import("mdast").Code): void;
36
+ };
37
+ };
38
+ export default _default;
39
+ export type CodeStyle = "indent" | "fence-backtick" | "fence-tilde";
40
+ export type RuleOptions = [{
41
+ style: "consistent" | CodeStyle;
42
+ }];
43
+ export type MessageIds = "style";
@@ -39,9 +39,9 @@ declare const _default: {
39
39
  };
40
40
  };
41
41
  export default _default;
42
- export type UnorderedListMarker = "*" | "+" | "-";
42
+ export type UnorderedListStyle = "*" | "+" | "-";
43
43
  export type RuleOptions = [{
44
- style: "consistent" | "sublist" | UnorderedListMarker;
44
+ style: "consistent" | "sublist" | UnorderedListStyle;
45
45
  }];
46
46
  export type MessageIds = "style";
47
47
  import type { ListItem } from 'mdast';
@@ -2,6 +2,7 @@ declare const _default: {
2
2
  'allow-image-url': import("../core/types.js").RuleModule<import("./allow-image-url.js").RuleOptions, import("./allow-image-url.js").MessageIds>;
3
3
  'allow-link-url': import("../core/types.js").RuleModule<import("./allow-link-url.js").RuleOptions, import("./allow-link-url.js").MessageIds>;
4
4
  'code-lang-shorthand': import("../core/types.js").RuleModule<import("./code-lang-shorthand.js").RuleOptions, "codeLangShorthand">;
5
+ 'consistent-code-style': import("../core/types.js").RuleModule<import("./consistent-code-style.js").RuleOptions, "style">;
5
6
  'consistent-delete-style': import("../core/types.js").RuleModule<import("./consistent-delete-style.js").RuleOptions, "style">;
6
7
  'consistent-emphasis-style': import("../core/types.js").RuleModule<import("./consistent-emphasis-style.js").RuleOptions, "style">;
7
8
  'consistent-strong-style': import("../core/types.js").RuleModule<import("./consistent-strong-style.js").RuleOptions, "style">;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-markdown",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "description": "Lint your Markdown with ESLint.🛠️",
6
6
  "exports": {
@@ -41,6 +41,7 @@ export default function all(plugin) {
41
41
  'md/allow-image-url': 'error',
42
42
  'md/allow-link-url': 'error',
43
43
  'md/code-lang-shorthand': 'error',
44
+ 'md/consistent-code-style': 'error',
44
45
  'md/consistent-delete-style': 'error',
45
46
  'md/consistent-emphasis-style': 'error',
46
47
  'md/consistent-strong-style': 'error',
@@ -38,6 +38,7 @@ export default function stylistic(plugin) {
38
38
  },
39
39
  language: 'markdown/gfm',
40
40
  rules: {
41
+ 'md/consistent-code-style': 'error',
41
42
  'md/consistent-delete-style': 'error',
42
43
  'md/consistent-emphasis-style': 'error',
43
44
  'md/consistent-strong-style': 'error',
@@ -76,7 +76,7 @@ export default function ruleTester(ruleName, rule, tests) {
76
76
 
77
77
  it('`meta.docs.description` should exist and follow the convention', () => {
78
78
  ok(meta?.docs?.description);
79
- match(meta?.docs?.description, /^(Enforce|Require|Disallow) .+[^. ]$/);
79
+ match(meta?.docs?.description, /^(?:Enforce|Require|Disallow) .+[^. ]$/);
80
80
  });
81
81
 
82
82
  it('`meta.docs.url` should exist and end with the rule name', () => {
@@ -0,0 +1,129 @@
1
+ /**
2
+ * @fileoverview Rule to enforce consistent code style.
3
+ * @author 루밀LuMir(lumirlumir)
4
+ */
5
+
6
+ /*
7
+ * Note on autofix and suggestion safety:
8
+ * - Converting `fence-backtick` to `fence-tilde` is safe.
9
+ * - Converting `fence-backtick` to `indent` is not safe, as `lang` and `meta` information would be lost.
10
+ * - Converting `fence-tilde` to `fence-backtick` is safe.
11
+ * - Converting `fence-tilde` to `indent` is not safe, as `lang` and `meta` information would be lost.
12
+ * - Converting `indent` to `fence-backtick` is safe.
13
+ * - Converting `indent` to `fence-tilde` is safe.
14
+ */
15
+
16
+ // --------------------------------------------------------------------------------
17
+ // Import
18
+ // --------------------------------------------------------------------------------
19
+
20
+ import { URL_RULE_DOCS } from '../core/constants.js';
21
+
22
+ // --------------------------------------------------------------------------------
23
+ // Typedef
24
+ // --------------------------------------------------------------------------------
25
+
26
+ /**
27
+ * @import { RuleModule } from '../core/types.js';
28
+ * @typedef {'indent' | 'fence-backtick' | 'fence-tilde'} CodeStyle
29
+ * @typedef {[{ style: 'consistent' | CodeStyle }]} RuleOptions
30
+ * @typedef {'style'} MessageIds
31
+ */
32
+
33
+ // --------------------------------------------------------------------------------
34
+ // Helper
35
+ // --------------------------------------------------------------------------------
36
+
37
+ /**
38
+ * Get the current code style based on the given text.
39
+ * @param {string} text The text to determine the code style from.
40
+ * @returns {CodeStyle} The current code style.
41
+ */
42
+ function getCurrentCodeStyle(text) {
43
+ if (text === '`') {
44
+ return 'fence-backtick';
45
+ } else if (text === '~') {
46
+ return 'fence-tilde';
47
+ } else {
48
+ return 'indent';
49
+ }
50
+ }
51
+
52
+ // --------------------------------------------------------------------------------
53
+ // Rule Definition
54
+ // --------------------------------------------------------------------------------
55
+
56
+ /** @type {RuleModule<RuleOptions, MessageIds>} */
57
+ export default {
58
+ meta: {
59
+ type: 'layout',
60
+
61
+ docs: {
62
+ description: 'Enforce consistent code style',
63
+ url: URL_RULE_DOCS('consistent-code-style'),
64
+ recommended: false,
65
+ stylistic: true,
66
+ },
67
+
68
+ // fixable: 'code', // TODO
69
+
70
+ // hasSuggestions: true, // TODO
71
+
72
+ schema: [
73
+ {
74
+ type: 'object',
75
+ properties: {
76
+ style: {
77
+ enum: ['consistent', 'indent', 'fence-backtick', 'fence-tilde'],
78
+ },
79
+ },
80
+ additionalProperties: false,
81
+ },
82
+ ],
83
+
84
+ defaultOptions: [
85
+ {
86
+ style: 'consistent',
87
+ },
88
+ ],
89
+
90
+ messages: {
91
+ style: 'Code style should be `{{ style }}`.',
92
+ },
93
+
94
+ language: 'markdown',
95
+
96
+ dialects: ['commonmark', 'gfm'],
97
+ },
98
+
99
+ create(context) {
100
+ const { sourceCode } = context;
101
+ const [{ style }] = context.options;
102
+
103
+ /** @type {CodeStyle | null} */
104
+ let codeStyle = style === 'consistent' ? null : style;
105
+
106
+ return {
107
+ code(node) {
108
+ const [nodeStartOffset] = sourceCode.getRange(node);
109
+ const currentCodeStyle = getCurrentCodeStyle(sourceCode.text[nodeStartOffset]);
110
+
111
+ if (codeStyle === null) {
112
+ codeStyle = currentCodeStyle;
113
+ }
114
+
115
+ if (codeStyle !== currentCodeStyle) {
116
+ context.report({
117
+ node,
118
+
119
+ messageId: 'style',
120
+
121
+ data: {
122
+ style: codeStyle,
123
+ },
124
+ });
125
+ }
126
+ },
127
+ };
128
+ },
129
+ };
@@ -16,8 +16,8 @@ import { URL_RULE_DOCS } from '../core/constants.js';
16
16
  /**
17
17
  * @import { ListItem } from 'mdast';
18
18
  * @import { RuleModule } from '../core/types.js';
19
- * @typedef {'*' | '+' | '-'} UnorderedListMarker
20
- * @typedef {[{ style: 'consistent' | 'sublist' | UnorderedListMarker }]} RuleOptions
19
+ * @typedef {'*' | '+' | '-'} UnorderedListStyle
20
+ * @typedef {[{ style: 'consistent' | 'sublist' | UnorderedListStyle }]} RuleOptions
21
21
  * @typedef {'style'} MessageIds
22
22
  */
23
23
 
@@ -26,15 +26,15 @@ import { URL_RULE_DOCS } from '../core/constants.js';
26
26
  // --------------------------------------------------------------------------------
27
27
 
28
28
  /**
29
- * Get the next unordered list marker in sequence.
29
+ * Get the next unordered list style in sequence.
30
30
  * Inspired by [`markdownlint`](https://github.com/DavidAnson/markdownlint/blob/v0.40.0/lib/md004.mjs#L9).
31
- * @param {UnorderedListMarker} currentUnorderedListMarker The current unordered list marker.
32
- * @returns {UnorderedListMarker} The next unordered list marker.
31
+ * @param {UnorderedListStyle} currentUnorderedListStyle The current unordered list style.
32
+ * @returns {UnorderedListStyle} The next unordered list style.
33
33
  */
34
- function getNextUnorderedListMarker(currentUnorderedListMarker) {
35
- if (currentUnorderedListMarker === '-') {
34
+ function getNextUnorderedListStyle(currentUnorderedListStyle) {
35
+ if (currentUnorderedListStyle === '-') {
36
36
  return '+';
37
- } else if (currentUnorderedListMarker === '+') {
37
+ } else if (currentUnorderedListStyle === '+') {
38
38
  return '*';
39
39
  } else {
40
40
  return '-';
@@ -90,7 +90,7 @@ export default {
90
90
  const { sourceCode } = context;
91
91
  const [{ style }] = context.options;
92
92
 
93
- /** @type {Array<UnorderedListMarker | null | undefined>} */
93
+ /** @type {Array<UnorderedListStyle | null | undefined>} */
94
94
  const unorderedListStyle = [
95
95
  style === 'consistent' || style === 'sublist' ? null : style,
96
96
  ];
@@ -105,7 +105,7 @@ export default {
105
105
 
106
106
  'list[ordered=false] > listItem'(/** @type {ListItem} */ node) {
107
107
  const [nodeStartOffset] = sourceCode.getRange(node);
108
- const currentUnorderedListStyle = /** @type {UnorderedListMarker} */ (
108
+ const currentUnorderedListStyle = /** @type {UnorderedListStyle} */ (
109
109
  sourceCode.text[nodeStartOffset]
110
110
  );
111
111
  const currentListDepth = style === 'sublist' ? listDepth : 0;
@@ -115,7 +115,7 @@ export default {
115
115
  unorderedListStyle[currentListDepth] =
116
116
  // If the previous depth used the same style, use the next style in sequence.
117
117
  unorderedListStyle[currentListDepth - 1] === currentUnorderedListStyle
118
- ? getNextUnorderedListMarker(currentUnorderedListStyle)
118
+ ? getNextUnorderedListStyle(currentUnorderedListStyle)
119
119
  : currentUnorderedListStyle;
120
120
  }
121
121
 
@@ -6,6 +6,7 @@
6
6
  import allowImageUrl from './allow-image-url.js';
7
7
  import allowLinkUrl from './allow-link-url.js';
8
8
  import codeLangShorthand from './code-lang-shorthand.js';
9
+ import consistentCodeStyle from './consistent-code-style.js';
9
10
  import consistentDeleteStyle from './consistent-delete-style.js';
10
11
  import consistentEmphasisStyle from './consistent-emphasis-style.js';
11
12
  import consistentStrongStyle from './consistent-strong-style.js';
@@ -31,6 +32,7 @@ export default {
31
32
  'allow-image-url': allowImageUrl,
32
33
  'allow-link-url': allowLinkUrl,
33
34
  'code-lang-shorthand': codeLangShorthand,
35
+ 'consistent-code-style': consistentCodeStyle,
34
36
  'consistent-delete-style': consistentDeleteStyle,
35
37
  'consistent-emphasis-style': consistentEmphasisStyle,
36
38
  'consistent-strong-style': consistentStrongStyle,