Skip to content

Commit

Permalink
feat!: map known code block languages to respective file extensions (#…
Browse files Browse the repository at this point in the history
…246)

* feat: map known code block languages to respective file extensions

* chore: add missing verb in test case description

* chore: resolve README lint errors

* fix: remove mapping from code block language node to javascript

* docs: explain code block language mapping

* docs: make language mappings more explicit

Co-authored-by: Nicholas C. Zakas <nicholas@humanwhocodes.com>

* docs: use backticks instead of code blocks

Co-authored-by: Francesco Trotta <github@fasttime.org>

---------

Co-authored-by: Nicholas C. Zakas <nicholas@humanwhocodes.com>
Co-authored-by: Francesco Trotta <github@fasttime.org>
  • Loading branch information
3 people committed Apr 29, 2024
1 parent 00adccb commit 096cff4
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 15 deletions.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,14 @@ You can manually include the Markdown processor by setting the `processor` optio

Each fenced code block inside a Markdown document has a virtual filename appended to the Markdown file's path.

The virtual filename's extension will match the fenced code block's syntax tag, so for example, <code>```js</code> code blocks in <code>README.md</code> would match <code>README.md/*.js</code>.
The virtual filename's extension will match the fenced code block's syntax tag, except for the following:

* `javascript` and `ecmascript` are mapped to `js`
* `typescript` is mapped to `ts`
* `markdown` is mapped to `md`

For example, ```` ```js ```` code blocks in `README.md` would match `README.md/*.js` and ```` ```typescript ```` in `CONTRIBUTING.md` would match `CONTRIBUTING.md/*.ts`.

You can use glob patterns for these virtual filenames to customize configuration for code blocks without affecting regular code.
For more information on configuring processors, refer to the [ESLint documentation](https://eslint.org/docs/user-guide/configuring#specifying-processor).

Expand Down
8 changes: 7 additions & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,13 @@ module.exports = [
},
rules: {
"lines-around-comment": "off",
"n/no-missing-import": "off"
"n/no-missing-import": "off",
"no-var": "off",
"padding-line-between-statements": "off",
"no-console": "off",
"no-alert": "off",
"eslint-comments/require-description": "off",
"jsdoc/require-jsdoc": "off"
}
}
];
28 changes: 20 additions & 8 deletions lib/processor.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,13 @@ function getBlockRangeMap(text, node, comments) {
return rangeMap;
}

const languageToFileExtension = {
javascript: "js",
ecmascript: "js",
typescript: "ts",
markdown: "md"
};

/**
* Extracts lintable code blocks from Markdown text.
* @param {string} text The text of the file.
Expand Down Expand Up @@ -295,14 +302,19 @@ function preprocess(text, filename) {
}
});

return blocks.map((block, index) => ({
filename: `${index}.${block.lang.trim().split(" ")[0]}`,
text: [
...block.comments,
block.value,
""
].join("\n")
}));
return blocks.map((block, index) => {
const [language] = block.lang.trim().split(" ");
const fileExtension = Object.hasOwn(languageToFileExtension, language) ? languageToFileExtension[language] : language;

return {
filename: `${index}.${fileExtension}`,
text: [
...block.comments,
block.value,
""
].join("\n")
};
});
}

/**
Expand Down
22 changes: 17 additions & 5 deletions tests/lib/processor.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ describe("processor", () => {
"```js",
"backticks",
"```",
"~~~javascript",
"~~~js",
"tildes",
"~~~"
].join("\n");
Expand All @@ -124,7 +124,7 @@ describe("processor", () => {
assert.strictEqual(blocks.length, 2);
assert.strictEqual(blocks[0].filename, "0.js");
assert.strictEqual(blocks[0].text, "backticks\n");
assert.strictEqual(blocks[1].filename, "1.javascript");
assert.strictEqual(blocks[1].filename, "1.js");
assert.strictEqual(blocks[1].text, "tildes\n");
});

Expand Down Expand Up @@ -255,7 +255,7 @@ describe("processor", () => {
const blocks = processor.preprocess(code);

assert.strictEqual(blocks.length, 1);
assert.strictEqual(blocks[0].filename, "0.javascript");
assert.strictEqual(blocks[0].filename, "0.js");
});

it("should find code fences with node info string", () => {
Expand Down Expand Up @@ -330,6 +330,18 @@ describe("processor", () => {
assert.strictEqual(blocks[0].filename, "0.js");
});

it("should translate the language to its file extension with leading whitespace and trailing characters", () => {
const code = [
"``` javascript CUSTOM",
"var answer = 6 * 7;",
"```"
].join("\n");
const blocks = processor.preprocess(code);

assert.strictEqual(blocks.length, 1);
assert.strictEqual(blocks[0].filename, "0.js");
});

it("should find code fences not surrounded by blank lines", () => {
const code = [
"<!-- eslint-disable -->",
Expand Down Expand Up @@ -408,7 +420,7 @@ describe("processor", () => {
"var answer = 6 * 7;",
"```",
"",
"```javascript",
"```js",
"console.log(answer);",
"```",
"",
Expand All @@ -419,7 +431,7 @@ describe("processor", () => {
assert.strictEqual(blocks.length, 2);
assert.strictEqual(blocks[0].filename, "0.js");
assert.strictEqual(blocks[0].text, "var answer = 6 * 7;\n");
assert.strictEqual(blocks[1].filename, "1.javascript");
assert.strictEqual(blocks[1].filename, "1.js");
assert.strictEqual(blocks[1].text, "console.log(answer);\n");
});

Expand Down

0 comments on commit 096cff4

Please sign in to comment.