diff --git a/.github/linters/.markdownlint.yml b/.github/linters/.markdownlint.yml deleted file mode 100644 index 7c89f2e2..00000000 --- a/.github/linters/.markdownlint.yml +++ /dev/null @@ -1,51 +0,0 @@ ---- -########################### -########################### -## Markdown Linter rules ## -########################### -########################### - -# Linter rules doc: -# - https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md -# -# Note: -# To comment out a single error: -# -# any violations you want -# -# - -# Default state for all rules -default: false - -################# -# Rules by tags # -################# -blanks-around-fences: true # Fenced code blocks should be surrounded by blank lines -blanks-around-headings: true # Headings should be surrounded by blank lines -blanks-around-lists: true # Lists should be surrounded by blank lines -code-block-style: - style: "fenced" -code-fence-style: - style: "backtick" -emphasis-style: - style: "consistent" -fenced-code-language: true # Fenced code blocks should have a language specified -heading-start-left: true # Headings must start at the beginning of the line -heading-style: - style: "atx" -hr-style: true # Horizontal rule style -list-indent: true # Inconsistent indentation for list items at the same level -no-empty-links: true -no-missing-space-atx: true # No space after hash on atx style heading -no-multiple-blanks: true # Multiple consecutive blank lines -no-reversed-links: true -no-space-in-code: true -no-space-in-emphasis: true -no-space-in-links: true -no-trailing-spaces: true -single-trailing-newline: true # Files should end with a single newline character -strong-style: - style: "consistent" -ul-style: - style: "consistent" diff --git a/.github/workflows/test-pull-request.yml b/.github/workflows/test-pull-request.yml index 5be49b28..cda686f3 100644 --- a/.github/workflows/test-pull-request.yml +++ b/.github/workflows/test-pull-request.yml @@ -8,7 +8,6 @@ name: Latest Pull Request # Documentation: # - Workflow: https://help.github.com/en/articles/workflow-syntax-for-github-actions -# - SuperLinter: https://github.com/github/super-linter # - Markdown linter: https://github.com/DavidAnson/markdownlint # - Link validation: https://github.com/remarkjs/remark-validate-links @@ -38,27 +37,6 @@ jobs: ########################## - name: Checkout Code uses: actions/checkout@v3 - with: - # Full git history is needed to get a proper list of changed files - # within `super-linter` - fetch-depth: 0 - - name: Load Super Linter Environment - run: cat ".github/super-linter.env" >> "$GITHUB_ENV" - - ################################ - # Run Linters against code base # - ################################ - - name: Lint Code Base - # - # Use full version number to avoid cases when a next - # released version is buggy - # About slim image: https://github.com/github/super-linter#slim-image - uses: github/super-linter/slim@v4.10.1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - DEFAULT_BRANCH: main - VALIDATE_ALL_CODEBASE: false - VALIDATE_GITHUB_ACTIONS: true - name: Setup Node v16 for Yarn v3 uses: actions/setup-node@v3 @@ -80,6 +58,11 @@ jobs: with: cmd: install + - name: Lint Markdown files + run: node scripts/lint-check.js + env: + YARN_ENABLE_IMMUTABLE_INSTALLS: false + - name: Check internal links uses: borales/actions-yarn@v3 with: diff --git a/.markdownlint-cli2.cjs b/.markdownlint-cli2.cjs new file mode 100644 index 00000000..9c944c38 --- /dev/null +++ b/.markdownlint-cli2.cjs @@ -0,0 +1,24 @@ +module.exports = { + "globs": ["**/*.md"], + "defaultSeverity": "error", + "configuration": { + "default": false, + // Rules that will fail PR validation (errors) + "MD009": true, // no-trailing-spaces + "MD012": true, // no-multiple-blanks + "MD013": false, // line-length - disabled for now due to potential issues + "MD041": true, // first-line-heading + + // Rules that will show warnings but not fail PR (warnings) + "MD025": true, // single-h1 (multiple top-level headings) - will be handled in workflow + "MD024": true, // no-duplicate-heading - will be handled in workflow + "MD026": true, // no-trailing-punctuation-in-heading - will be handled in workflow + }, + "frontMatter": { + "title": "title" + }, + "ignores": [ + "**/node_modules", + "**/dist" + ] +}; diff --git a/.markdownlint.yml b/.markdownlint.yml deleted file mode 120000 index d709e3e4..00000000 --- a/.markdownlint.yml +++ /dev/null @@ -1 +0,0 @@ -.github/linters/.markdownlint.yml \ No newline at end of file diff --git a/.markdownlint.yml b/.markdownlint.yml new file mode 100644 index 00000000..7126ff64 --- /dev/null +++ b/.markdownlint.yml @@ -0,0 +1,13 @@ +--- +# Markdown Linter Configuration +# Only enabling the no-multiple-h1 rule as requested + +# Disable all rules by default +default: false + +# Only enable the rule we want to check +single-h1: + severity: error + +MD013: + severity: warning diff --git a/package.json b/package.json index ff531c8d..cac2bc24 100644 --- a/package.json +++ b/package.json @@ -30,13 +30,15 @@ "build": "gatsby build", "serve": "gatsby serve", "clean": "gatsby clean", - "lint": "docker run --rm -e RUN_LOCAL=true --env-file '.github/super-linter.env' -v \"$PWD\":/tmp/lint github/super-linter:slim-v4.10.1", - "buildNavigation": "npx --yes github:AdobeDocs/adp-devsite-utils buildNavigation -v", - "buildRedirections": "npx --yes github:AdobeDocs/adp-devsite-utils buildRedirections -v", - "renameFiles": "npx --yes github:AdobeDocs/adp-devsite-utils renameFiles -v", - "normalizeLinks": "npx --yes github:AdobeDocs/adp-devsite-utils normalizeLinks -v", - "checkLinks": "npx --yes github:AdobeDocs/adp-devsite-utils checkLinks -v", - "buildSiteWideBanner": "npx --yes github:AdobeDocs/adp-devsite-utils buildSiteWideBanner -v" + "lint": "markdownlint-cli2 '**/*.md' --config .markdownlint-cli2.cjs", + "lint:check": "markdownlint-cli2 '**/*.md' --config .markdownlint-cli2.cjs --fix", + "test:links": "node check-links.js", + "buildNavigation": "node buildNavigation.js", + "buildRedirections": "node buildRedirections.js", + "renameFiles": "node renameFiles.js", + "normalizeLinks": "node normalizeLinks.js", + "checkLinks": "node check-links.js", + "buildSiteWideBanner": "node buildSiteWideBanner.js" }, "remarkConfig": { "plugins": [ @@ -47,7 +49,7 @@ "devDependencies": { "express": "5.1.0", "glob": "11.0.0", - "markdown-link-check": "^3.13.7", + "markdownlint-cli2": "^0.19.0", "remark-cli": "^11.0.0", "remark-validate-links": "^12.1.0" } diff --git a/scripts/lint-check.js b/scripts/lint-check.js new file mode 100644 index 00000000..d1461e70 --- /dev/null +++ b/scripts/lint-check.js @@ -0,0 +1,117 @@ +const fs = require('fs'); +const path = require('path'); + +// Custom markdown linting implementation +function customLintMarkdown() { + console.log('🔧 Running custom markdown linting...'); + const errors = []; + const warnings = []; + + // Find all markdown files + const markdownFiles = []; + function findMarkdownFiles(dir) { + try { + const files = fs.readdirSync(dir); + for (const file of files) { + const filePath = path.join(dir, file); + const stat = fs.statSync(filePath); + if (stat.isDirectory() && !file.startsWith('.') && file !== 'node_modules' && file !== 'dist') { + findMarkdownFiles(filePath); + } else if (file.endsWith('.md')) { + markdownFiles.push(filePath); + } + } + } catch (err) { + // Skip directories we can't read + } + } + + findMarkdownFiles('.'); + console.log(`📁 Found ${markdownFiles.length} markdown files to lint`); + + for (const file of markdownFiles) { + try { + const content = fs.readFileSync(file, 'utf8'); + const lines = content.split('\n'); + + // Check for trailing spaces (MD009) + for (let i = 0; i < lines.length; i++) { + if (lines[i].endsWith(' ')) { + errors.push(`MD009: ${file}:${i + 1}: Trailing spaces`); + } + } + + // Check for multiple blank lines (MD012) + let blankLineCount = 0; + for (let i = 0; i < lines.length; i++) { + if (lines[i].trim() === '') { + blankLineCount++; + if (blankLineCount > 1) { + errors.push(`MD012: ${file}:${i + 1}: Multiple blank lines`); + } + } else { + blankLineCount = 0; + } + } + + // Check for first line heading (MD041) - but be more lenient + if (lines.length > 0) { + const firstLine = lines[0].trim(); + if (firstLine && !firstLine.startsWith('#') && !firstLine.startsWith('---') && !firstLine.startsWith(' 0) { + console.log('❌ Critical errors found:'); + customResult.errors.forEach(error => console.log(error)); + } + + if (customResult.warnings.length > 0) { + console.log('⚠️ Warnings found:'); + customResult.warnings.forEach(warning => console.log(warning)); + } + + // Check if there are any critical errors + if (customResult.errors.length > 0) { + console.log('❌ Found critical errors - PR validation failed'); + console.log(`Total critical errors: ${customResult.errors.length}`); + process.exit(1); + } + + if (customResult.warnings.length > 0) { + console.log('⚠️ Found style warnings (these won\'t fail the PR):'); + console.log(`Total warnings: ${customResult.warnings.length}`); + } + + console.log('✅ Linting completed successfully'); +} catch (error) { + console.log('❌ Linting failed:', error.message); + console.log('Error details:', error); + process.exit(1); +} \ No newline at end of file diff --git a/src/pages/config.md b/src/pages/config.md index 1c935a2a..1bb8b7fa 100644 --- a/src/pages/config.md +++ b/src/pages/config.md @@ -3,7 +3,7 @@ - versions: - [v2.0](/index.md) selected - - [v1.4](https://github.com/AdobeDocs/dev-site) + - [v1.4](https://github.com/AdobeDocs/dev-site) - pages: - [Cat Analytics](/index.md) diff --git a/src/pages/test/test-lint-levels.md b/src/pages/test/test-lint-levels.md new file mode 100644 index 00000000..d8c4892e --- /dev/null +++ b/src/pages/test/test-lint-levels.md @@ -0,0 +1,38 @@ +# Test Lint Rule Levels + +This file demonstrates different markdown linting rule levels. + +## Error Rules (Will Fail PR) + +### MD009 - No Trailing Spaces +This line has a trailing space: + +### MD012 - No Multiple Blanks + + +This line has multiple blank lines above it. + +### MD013 - Line Length +This is a very long line that exceeds the default line length limit and should trigger an error because it's too long and violates the line length rule. + +### MD041 - First Line Heading +This file starts with an h1 heading, which is correct. + +## Warning Rules (Will Show Warning but Pass PR) + +### MD025 - Single H1 (Multiple Top-Level Headings) +This file has one h1 heading at the top, which is correct. + +### MD024 - No Duplicate Heading +## Duplicate Heading +Some content here. +## Duplicate Heading +This duplicate heading should trigger a warning. + +### MD026 - No Trailing Punctuation in Heading +## Heading with trailing punctuation? + +## Summary + +- **Errors** (fail PR): trailing spaces, multiple blanks, long lines, missing first heading +- **Warnings** (pass PR): multiple h1s, duplicate headings, trailing punctuation in headings diff --git a/src/pages/test/test-lint-rules.md b/src/pages/test/test-lint-rules.md new file mode 100644 index 00000000..548249c2 --- /dev/null +++ b/src/pages/test/test-lint-rules.md @@ -0,0 +1,53 @@ +# Test Lint Rules + +This file contains test cases for various markdown linting rules. + +## Test Case 1: Valid - Single H1 + +This file has exactly one h1 heading (`# Test Lint Rules`) which is valid according to the `no-multiple-h1` rule. + +## Test Case 2: Valid - Multiple H2+ Headings + +### This is an H3 heading + +#### This is an H4 heading + +##### This is an H5 heading + +Multiple h2-h6 headings are allowed. + +## Test Case 3: Invalid Example (Commented Out) + +The following would violate the single-h1 rule: + + + +## Test Case 4: Valid - Mixed Heading Levels + +### Subsection 1 +Content for subsection 1. + +### Subsection 2 +Content for subsection 2. + +#### Sub-subsection +More detailed content. + +## Test Case 5: Valid - No Additional H1 + +This file demonstrates that having exactly one h1 at the top is valid, and all other headings should be h2 or lower. + +### Summary + +- ✅ One h1 heading at the top +- ✅ Multiple h2-h6 headings allowed +- ⚠️ Multiple h1 headings would show as warnings (not errors) +- ❌ No h1 heading would also fail (if required by other rules)