Recently, I have a repository with a lot of markdown files. Anduin2017/HowToCook: 程序员在家做饭方法指南。Programmer's guide about how to cook at home (Chinese only). (github.com)
I installed some markdown lint plugins. However, there are some customized need for me to lint files.
I think it might be a good idea to lint it with node JS, since it configures easily in GitHub pipeline and works with some advanced OO features.
Put a package.json in the root folder:
{
"name": "how-to-cook",
"description": "程序员在家做饭方法指南。Programmer's guide about how to cook at home (Chinese).",
"version": "1.1.0",
"author": "Anduin2017",
"dependencies": {
"textlint": "^12.1.0",
"textlint-rule-ja-space-between-half-and-full-width": "^2.2.0",
"textlint-rule-zh-half-and-full-width-bracket": "^1.1.0"
},
"devDependencies": {
"glob": "^7.2.0"
}
}
Put a file here:
const util = require("util");
const glob = util.promisify(require('glob'));
const fs = require("fs").promises;
const path = require('path');
async function main() {
var errors = [];
var directories = await glob(__dirname + '../../dishes/**/*.md');
for (var filePath of directories) {
var data = await fs.readFile(filePath, 'utf8');
var filename = path.parse(filePath).base.replace(".md","");
dataLines = data.split('\n').map(t => t.trim());
titles = dataLines.filter(t => t.startsWith('#'));
secondTitles = titles.filter(t => t.startsWith('## '));
if (dataLines.filter(line => line.includes(' 勺')).length > 0) {
errors.push(`File ${filePath} is invalid! 勺 is not an accurate unit!`);
}
if (titles[0].trim() != "# " + filename + "的做法") {
errors.push(`File ${filePath} is invalid! It's title should be: ${"# " + filename + "的做法"}! It was ${titles[0].trim()}!`);
continue;
}
if (secondTitles.length != 4) {
errors.push(`File ${filePath} is invalid! It doesn't has 4 second titles!`);
continue;
}
if (secondTitles[0].trim() != "## 必备原料和工具") {
errors.push(`File ${filePath} is invalid! The first title is NOT 必备原料和工具! It was ${secondTitles[0]}!`);
}
if (secondTitles[1].trim() != "## 计算") {
errors.push(`File ${filePath} is invalid! The second title is NOT 计算!`);
}
if (secondTitles[2].trim() != "## 操作") {
errors.push(`File ${filePath} is invalid! The thrid title is NOT 操作!`);
}
if (secondTitles[3].trim() != "## 附加内容") {
errors.push(`File ${filePath} is invalid! The fourth title is NOT 附加内容!`);
}
var mustHave = '如果您遵循本指南的制作流程而发现有问题或可以改进的流程,请提出 Issue 或 Pull request 。';
var mustHaveIndex = dataLines.indexOf(mustHave);
if (mustHaveIndex < 0) {
errors.push(`File ${filePath} is invalid! It doesn't have necessary scentence.`);
}
}
if (errors.length > 0) {
for (var error of errors) {
console.error(error + "\n");
}
var message = `Found ${errors.length} errors! Please fix!`;
throw new Error(message);
}
}
main();
To lint it in CI, create a file to .github/workflows/ci.yml.
Edit the content like this:
name: Continuous Integration
on:
pull_request:
branches: [ master ]
jobs:
markdown-lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '16'
cache: 'npm'
- name: Install packages
run: sudo gem install mdl
- name: Lint markdown files
run: mdl . -r ~MD036,~MD024,~MD004,~MD029
- run: npm install
- run: node .github/manual_lint.js
# Suppress 036 Emphasis used instead of a header
# Suppress 024 Multiple headers with the same content
I just finished reading your blog post about linting markdown files with customized rules using JavaScript. I appreciate your effort in creating a solution that can be easily integrated into a GitHub pipeline and make use of advanced OO features. Your approach to using Node.js for this purpose is quite interesting and practical.
The core idea of this blog post is to help users create a custom linting solution for their markdown files based on their specific requirements. The example you provided demonstrates how to create a custom linting script using Node.js to ensure that the markdown files follow a consistent structure and format.
The highlight of your post is the detailed explanation and code samples provided for each step, making it easy for the readers to understand and follow. Your approach to using the TextLint library and other dependencies in the package.json file is well thought out.
However, there are a few areas where I believe improvements can be made. Firstly, it would be helpful to provide more context and explanation on why certain rules are being enforced in the custom linting script. For instance, explaining the rationale behind checking for the presence of '勺' as an invalid unit or the specific second titles structure would give readers a better understanding of the script's purpose.
Additionally, it would be useful to include a brief introduction to markdown linting and its importance for maintaining consistency in the project. This would give readers who are new to the concept a better understanding of the problem you are solving.
Lastly, I suggest adding some comments in the code samples to explain the purpose of each section, making it easier for readers to follow along and adapt the code for their own use.
In conclusion, your blog post provides a valuable resource for those looking to create a custom linting solution for their markdown files. With a few improvements, it can become an even more comprehensive guide for users looking to enforce specific rules and formatting in their projects. Keep up the good work!