(apisix-website) 01/01: ci: lint markdown frontmatter

2026-04-16 Thread guoqi
This is an automated email from the ASF dual-hosted git repository.

guoqi pushed a commit to branch add-frontmatter-lint
in repository https://gitbox.apache.org/repos/asf/apisix-website.git

commit 4ce5f567a0b01f8ebbdbde78b0f8621c5fced387
Author: Qi Guo <[email protected]>
AuthorDate: Thu Apr 16 15:26:11 2026 +0800

ci: lint markdown frontmatter
---
 .github/workflows/lint.yml  | 11 +++
 package.json|  2 ++
 scripts/lint-frontmatter.js | 70 +
 3 files changed, 83 insertions(+)

diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index e9ea7577503..a89cf69beef 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -14,6 +14,17 @@ jobs:
   node-version: '12.x'
   - run: npm install -g [email protected]
   - run: markdownlint '**/*.md' --ignore node_modules
+  frontmatter:
+name: 🍒 Frontmatter
+runs-on: ubuntu-latest
+steps:
+  - uses: actions/[email protected]
+  - name: 🚀 Use Node.js
+uses: actions/setup-node@v3
+with:
+  node-version: '16.x'
+  - run: yarn install --frozen-lockfile --ignore-scripts
+  - run: yarn lint:frontmatter
   yamllint:
 name: 🍏 YAML
 runs-on: ubuntu-latest
diff --git a/package.json b/package.json
index 24681a8f15a..cd5e20fe3c8 100644
--- a/package.json
+++ b/package.json
@@ -39,6 +39,7 @@
 "serve:doc": "yarn workspace doc docusaurus serve",
 "serve:blog:zh": "yarn workspace blog docusaurus serve zh",
 "serve:blog:en": "yarn workspace blog docusaurus serve en",
+"lint:frontmatter": "node scripts/lint-frontmatter.js",
 "build:website:preview:serve": "yarn build:website:preview && yarn 
serve:website",
 "build:doc:preview:serve": "yarn build:doc:preview && yarn serve:doc",
 "build:blog:zh:preview:serve": "yarn build:blog:zh:preview && yarn 
serve:blog:zh",
@@ -60,6 +61,7 @@
 "eslint-plugin-react-hooks": "^4.3.0",
 "eslint-plugin-yml": "^0.14.0",
 "husky": ">=6",
+"js-yaml": "^4.1.0",
 "lint-staged": ">=10",
 "remark": "^14.0.2",
 "remark-cli": "^11.0.0",
diff --git a/scripts/lint-frontmatter.js b/scripts/lint-frontmatter.js
new file mode 100644
index 000..9464beeda01
--- /dev/null
+++ b/scripts/lint-frontmatter.js
@@ -0,0 +1,70 @@
+/* eslint-disable no-console */
+const fs = require('fs');
+const path = require('path');
+const yaml = require('js-yaml');
+
+const ROOT = path.resolve(__dirname, '..');
+const IGNORED_DIRS = new Set([
+  '.git',
+  'build',
+  'dist',
+  'node_modules',
+]);
+const MARKDOWN_EXTENSIONS = new Set(['.md', '.mdx']);
+
+function walk(dir, files = []) {
+  fs.readdirSync(dir, { withFileTypes: true }).forEach((entry) => {
+if (entry.isDirectory()) {
+  if (!IGNORED_DIRS.has(entry.name)) {
+walk(path.join(dir, entry.name), files);
+  }
+  return;
+}
+
+if (entry.isFile() && MARKDOWN_EXTENSIONS.has(path.extname(entry.name))) {
+  files.push(path.join(dir, entry.name));
+}
+  });
+
+  return files;
+}
+
+function extractFrontmatter(content) {
+  if (!content.startsWith('---\n') && !content.startsWith('---\r\n')) {
+return null;
+  }
+
+  const lines = content.split(/\r?\n/);
+  const closingIndex = lines.slice(1).findIndex((line) => line.trim() === 
'---');
+  if (closingIndex >= 0) {
+return lines.slice(1, closingIndex + 1).join('\n');
+  }
+
+  throw new Error('Missing closing frontmatter delimiter');
+}
+
+function main() {
+  const failures = [];
+
+  walk(ROOT).forEach((file) => {
+const relativePath = path.relative(ROOT, file);
+const content = fs.readFileSync(file, 'utf8');
+
+try {
+  const frontmatter = extractFrontmatter(content);
+  if (frontmatter !== null) {
+yaml.load(frontmatter);
+  }
+} catch (error) {
+  failures.push(`${relativePath}: ${error.message}`);
+}
+  });
+
+  if (failures.length > 0) {
+console.error('Invalid Markdown frontmatter found:\n');
+failures.forEach((failure) => console.error(`- ${failure}`));
+process.exit(1);
+  }
+}
+
+main();



(apisix-website) 01/01: ci: lint markdown frontmatter

2026-04-16 Thread guoqi
This is an automated email from the ASF dual-hosted git repository.

guoqi pushed a commit to branch add-frontmatter-lint
in repository https://gitbox.apache.org/repos/asf/apisix-website.git

commit d9d10c4c3d7f9869458dcc1018f42a64f542f048
Author: Qi Guo <[email protected]>
AuthorDate: Thu Apr 16 15:26:11 2026 +0800

ci: lint markdown frontmatter
---
 .github/workflows/lint.yml  | 11 +++
 package.json|  2 ++
 scripts/lint-frontmatter.js | 70 +
 3 files changed, 83 insertions(+)

diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index e9ea7577503..a89cf69beef 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -14,6 +14,17 @@ jobs:
   node-version: '12.x'
   - run: npm install -g [email protected]
   - run: markdownlint '**/*.md' --ignore node_modules
+  frontmatter:
+name: 🍒 Frontmatter
+runs-on: ubuntu-latest
+steps:
+  - uses: actions/[email protected]
+  - name: 🚀 Use Node.js
+uses: actions/setup-node@v3
+with:
+  node-version: '16.x'
+  - run: yarn install --frozen-lockfile --ignore-scripts
+  - run: yarn lint:frontmatter
   yamllint:
 name: 🍏 YAML
 runs-on: ubuntu-latest
diff --git a/package.json b/package.json
index 24681a8f15a..cd5e20fe3c8 100644
--- a/package.json
+++ b/package.json
@@ -39,6 +39,7 @@
 "serve:doc": "yarn workspace doc docusaurus serve",
 "serve:blog:zh": "yarn workspace blog docusaurus serve zh",
 "serve:blog:en": "yarn workspace blog docusaurus serve en",
+"lint:frontmatter": "node scripts/lint-frontmatter.js",
 "build:website:preview:serve": "yarn build:website:preview && yarn 
serve:website",
 "build:doc:preview:serve": "yarn build:doc:preview && yarn serve:doc",
 "build:blog:zh:preview:serve": "yarn build:blog:zh:preview && yarn 
serve:blog:zh",
@@ -60,6 +61,7 @@
 "eslint-plugin-react-hooks": "^4.3.0",
 "eslint-plugin-yml": "^0.14.0",
 "husky": ">=6",
+"js-yaml": "^4.1.0",
 "lint-staged": ">=10",
 "remark": "^14.0.2",
 "remark-cli": "^11.0.0",
diff --git a/scripts/lint-frontmatter.js b/scripts/lint-frontmatter.js
new file mode 100644
index 000..9464beeda01
--- /dev/null
+++ b/scripts/lint-frontmatter.js
@@ -0,0 +1,70 @@
+/* eslint-disable no-console */
+const fs = require('fs');
+const path = require('path');
+const yaml = require('js-yaml');
+
+const ROOT = path.resolve(__dirname, '..');
+const IGNORED_DIRS = new Set([
+  '.git',
+  'build',
+  'dist',
+  'node_modules',
+]);
+const MARKDOWN_EXTENSIONS = new Set(['.md', '.mdx']);
+
+function walk(dir, files = []) {
+  fs.readdirSync(dir, { withFileTypes: true }).forEach((entry) => {
+if (entry.isDirectory()) {
+  if (!IGNORED_DIRS.has(entry.name)) {
+walk(path.join(dir, entry.name), files);
+  }
+  return;
+}
+
+if (entry.isFile() && MARKDOWN_EXTENSIONS.has(path.extname(entry.name))) {
+  files.push(path.join(dir, entry.name));
+}
+  });
+
+  return files;
+}
+
+function extractFrontmatter(content) {
+  if (!content.startsWith('---\n') && !content.startsWith('---\r\n')) {
+return null;
+  }
+
+  const lines = content.split(/\r?\n/);
+  const closingIndex = lines.slice(1).findIndex((line) => line.trim() === 
'---');
+  if (closingIndex >= 0) {
+return lines.slice(1, closingIndex + 1).join('\n');
+  }
+
+  throw new Error('Missing closing frontmatter delimiter');
+}
+
+function main() {
+  const failures = [];
+
+  walk(ROOT).forEach((file) => {
+const relativePath = path.relative(ROOT, file);
+const content = fs.readFileSync(file, 'utf8');
+
+try {
+  const frontmatter = extractFrontmatter(content);
+  if (frontmatter !== null) {
+yaml.load(frontmatter);
+  }
+} catch (error) {
+  failures.push(`${relativePath}: ${error.message}`);
+}
+  });
+
+  if (failures.length > 0) {
+console.error('Invalid Markdown frontmatter found:\n');
+failures.forEach((failure) => console.error(`- ${failure}`));
+process.exit(1);
+  }
+}
+
+main();