Skip to content

Commit 61fef8b

Browse files
lumirlumirCopilot
andauthored
feat(eslint-plugin-mark): create code-lang-shorthand and dummy rules (#13)
This pull request introduces a new ESLint rule to enforce the use of shorthand for code block language identifiers and includes corresponding updates to the configuration, rule definition, tests, and rule exports. New ESLint rule for shorthand code block language identifiers: * [`packages/eslint-plugin-mark/src/rules/code-lang-shorthand/code-lang-shorthand.js`](diffhunk://#diff-6502c3e17c3ed74bdc42a42b44982988f8ec9f559d0a5d0afbeec6f7ece1e41bR1-R212): Added a new rule to enforce the use of shorthand for code block language identifiers, including meta information, schema, and rule definition. * [`packages/eslint-plugin-mark/src/rules/code-lang-shorthand/code-lang-shorthand.test.js`](diffhunk://#diff-18f9af089d57586ea0832f9a98f452a2e931db45929f9c10bc54a700ed9411a0R1-R247): Added tests for the new `code-lang-shorthand` rule, covering various scenarios including valid and invalid cases, options handling, and case insensitivity. * [`packages/eslint-plugin-mark/src/rules/code-lang-shorthand/index.js`](diffhunk://#diff-f35328507dee7b405405502b54606c3bcdd15410dc747435ce1f99606b04dea3R1-R3): Exported the new `code-lang-shorthand` rule. * [`packages/eslint-plugin-mark/src/configs/all.js`](diffhunk://#diff-dcdf50541cdda584e7b5e20419349e2a8760d86d4d140d12dbd1d97b3084703fR35): Updated the configuration to include the new `mark/code-lang-shorthand` rule. * [`packages/eslint-plugin-mark/src/rules/index.js`](diffhunk://#diff-8bd6342bada2eb43bbaea244fd51588f57f5ec17967476e31bbf0408aaa82ed1R1-R12): Added the `code-lang-shorthand` rule to the list of exported rules. Additional minor changes: * Added references to external repositories in `.gitkeep` files for various rules. [[1]](diffhunk://#diff-7ff05802fc4a1d5074d8a0af498c0a17a44f19750684d216995ce918aef312ddR1) [[2]](diffhunk://#diff-14e8afb3c825972be38f9135867b85df670f14f5a3837e8cf078ef1dfeb95badR1) [[3]](diffhunk://#diff-9fb3a02b8be16b00a06688dbc53bfdb97f818a94e3502eeb35b559e197072b34R1) [[4]](diffhunk://#diff-b1f4c89e4870adcd6309018b2abc8b948e2b10c6b6e1e9ee03402390a9a2c9dfR1) [[5]](diffhunk://#diff-12f212746a4f9df7419cd1119cd4cc9f631ba1ff5cbfaf5f9b836abb4d4e528dR1) [[6]](diffhunk://#diff-6565fdc2a5429445525d2875db780b2f66cae4864137b3495006d5e987b4e36eR1-R2) --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 4da7a28 commit 61fef8b

File tree

26 files changed

+492
-10
lines changed

26 files changed

+492
-10
lines changed

CONTRIBUTING.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,33 +12,33 @@ All packages are located in the `packages` directory, and the documentation can
1212

1313
1. Clone it to your local directory. ([Git](https://git-scm.com/downloads) is required.)
1414

15-
```bash
15+
```sh
1616
git clone https://github.com/lumirlumir/npm-eslint-plugin-mark.git
1717
```
1818

1919
1. Move to the `npm-eslint-plugin-mark` directory.
2020

21-
```bash
21+
```sh
2222
cd npm-eslint-plugin-mark
2323
```
2424

2525
1. Install npm packages. ([Node.js](https://nodejs.org/en) is required.)
2626

27-
```bash
27+
```sh
2828
npm install
2929
```
3030

3131
1. Edit codes.
3232

3333
1. Create `my-branch` branch.
3434

35-
```bash
35+
```sh
3636
git switch -c my-branch
3737
```
3838

3939
1. Commit your changes. (`husky` and `lint-staged` will lint your changed files!)
4040

41-
```bash
41+
```sh
4242
git commit -am "<type>[optional scope]: <description>"
4343
```
4444

packages/eslint-plugin-mark/src/configs/all.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export default function all(parserMode) {
3232
...base(parserMode),
3333
name: `mark/all/${parserMode}`,
3434
rules: {
35+
'mark/code-lang-shorthand': 'error',
3536
'mark/no-curly-quotes': 'error',
3637
'mark/no-double-spaces': 'error',
3738
},

packages/eslint-plugin-mark/src/rules/allowed-urls/.gitkeep

Whitespace-only changes.
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
/**
2+
* @fileoverview Rule to enforce the use of shorthand for code block language identifiers.
3+
* @author 루밀LuMir(lumirlumir)
4+
* @see https://shiki.style/languages#bundled-languages
5+
* @see https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries
6+
* @see https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/entries
7+
*/
8+
9+
// --------------------------------------------------------------------------------
10+
// Import
11+
// --------------------------------------------------------------------------------
12+
13+
import { getFileName } from '../../core/helpers/index.js';
14+
15+
// --------------------------------------------------------------------------------
16+
// Typedefs
17+
// --------------------------------------------------------------------------------
18+
19+
/**
20+
* @typedef {import("@eslint/markdown").RuleModule} RuleModule
21+
* @typedef {import("mdast").Code} Code
22+
*/
23+
24+
// --------------------------------------------------------------------------------
25+
// Helpers
26+
// --------------------------------------------------------------------------------
27+
28+
/** @type {Record<string, string>} */
29+
const langShorthandMap = Object.freeze({
30+
asciidoc: 'adoc',
31+
batch: 'bat',
32+
berry: 'be',
33+
bsl: '1c',
34+
cadence: 'cdc',
35+
clojure: 'clj',
36+
codeql: 'ql',
37+
coffeescript: 'coffee',
38+
'common-lisp': 'lisp',
39+
csharp: 'c#',
40+
cypher: 'cql',
41+
dockerfile: 'docker',
42+
'emacs-lisp': 'elisp',
43+
erlang: 'erl',
44+
fluent: 'ftl',
45+
'fortran-fixed-form': 'f',
46+
fsharp: 'f#',
47+
'glimmer-js': 'gjs',
48+
'glimmer-ts': 'gts',
49+
graphql: 'gql',
50+
handlebars: 'hbs',
51+
haskell: 'hs',
52+
properties: 'ini',
53+
javascript: 'js',
54+
jssm: 'fsl',
55+
julia: 'jl',
56+
kotlin: 'kt',
57+
kusto: 'kql',
58+
lean4: 'lean',
59+
makefile: 'make',
60+
markdown: 'md',
61+
mermaid: 'mmd',
62+
mipsasm: 'mips',
63+
narrat: 'nar',
64+
nextflow: 'nf',
65+
nushell: 'nu',
66+
'objective-c': 'objc',
67+
pot: 'po',
68+
potx: 'po',
69+
powershell: 'ps',
70+
protobuf: 'proto',
71+
jade: 'pug',
72+
python: 'py',
73+
perl6: 'raku',
74+
regexp: 'regex',
75+
ruby: 'rb',
76+
rust: 'rs',
77+
'1c-query': 'sdbl',
78+
shaderlab: 'shader',
79+
shellscript: 'sh',
80+
shell: 'sh',
81+
bash: 'sh',
82+
zsh: 'sh',
83+
shellsession: 'console',
84+
'closure-templates': 'soy',
85+
splunk: 'spl',
86+
stylus: 'styl',
87+
talonscript: 'talon',
88+
terraform: 'tf',
89+
text: 'txt',
90+
typescript: 'ts',
91+
typespec: 'tsp',
92+
typst: 'typ',
93+
vimscript: 'vim',
94+
vyper: 'vy',
95+
wikitext: 'wiki',
96+
mediawiki: 'wiki',
97+
wolfram: 'wl',
98+
yaml: 'yml',
99+
});
100+
101+
// --------------------------------------------------------------------------------
102+
// Rule Definition
103+
// --------------------------------------------------------------------------------
104+
105+
/** @type {RuleModule} */
106+
export default {
107+
meta: {
108+
type: 'problem',
109+
110+
docs: {
111+
// @ts-ignore -- TODO: https://github.com/eslint/eslint/issues/19521, https://github.com/eslint/eslint/issues/19523
112+
name: getFileName(import.meta.url),
113+
recommended: true,
114+
description: 'Enforce the use of shorthand for code block language identifiers',
115+
url: 'https://github.com/lumirlumir/npm-eslint-plugin-mark',
116+
},
117+
118+
fixable: 'code',
119+
120+
schema: [
121+
{
122+
type: 'object',
123+
properties: {
124+
ignores: {
125+
type: 'array',
126+
items: {
127+
enum: Object.keys(langShorthandMap),
128+
},
129+
},
130+
override: {
131+
type: 'object',
132+
additionalProperties: {
133+
type: 'string',
134+
},
135+
},
136+
},
137+
additionalProperties: false,
138+
},
139+
],
140+
141+
defaultOptions: [
142+
{
143+
ignores: [],
144+
override: {},
145+
},
146+
],
147+
148+
messages: {
149+
codeLangShorthand: '`{{ lang }}` should be shortened to `{{ langShorthand }}`.',
150+
},
151+
152+
language: 'markdown',
153+
154+
dialects: ['commonmark', 'gfm'],
155+
},
156+
157+
create(context) {
158+
return {
159+
/** @param {Code} node */
160+
code(node) {
161+
const langShorthandMapMerged = Object.fromEntries(
162+
Object.entries({
163+
...langShorthandMap,
164+
...context.options[0].override, // `override` option handling.
165+
})
166+
.map(([key, value]) => [key.toLowerCase(), value.toLowerCase()]) // Normalize keys and values.
167+
.filter(([key]) => !context.options[0].ignores.includes(key)), // `ignores` option handling.
168+
);
169+
const langShorthand = langShorthandMapMerged[node.lang?.toLowerCase()]; // Normalize lang.
170+
171+
if (langShorthand === undefined) return;
172+
173+
// @ts-ignore -- TODO: https://github.com/eslint/markdown/issues/323
174+
const match = context.sourceCode.getText(node).match(node.lang);
175+
176+
const matchIndexStart = match.index;
177+
const matchIndexEnd = matchIndexStart + match[0].length;
178+
179+
context.report({
180+
loc: {
181+
start: {
182+
line: node.position.start.line,
183+
column: node.position.start.column + matchIndexStart,
184+
},
185+
end: {
186+
line: node.position.start.line,
187+
column: node.position.start.column + matchIndexEnd,
188+
},
189+
},
190+
191+
data: {
192+
lang: node.lang, // Original lang.
193+
langShorthand,
194+
},
195+
196+
messageId: 'codeLangShorthand',
197+
198+
fix(fixer) {
199+
return fixer.replaceTextRange(
200+
[
201+
node.position.start.offset + matchIndexStart,
202+
node.position.start.offset + matchIndexEnd,
203+
],
204+
langShorthand,
205+
);
206+
},
207+
});
208+
},
209+
};
210+
},
211+
};

0 commit comments

Comments
 (0)