Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Repo sync #34407

Merged
merged 1 commit into from
Aug 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion data/reusables/contributing/content-linter-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,5 @@
| GHD035 | rai-reusable-usage | RAI articles and reusables can only reference reusable content in the data/reusables/rai directory | error | feature, rai |
| GHD036 | image-no-gif | Image must not be a gif, styleguide reference: contributing/style-guide-and-content-model/style-guide.md#images | error | images |
| GHD038 | expired-content | Expired content must be remediated. | error | expired |
| GHD039 | expiring-soon | Content that expires soon should be proactively addressed. | warning | expired |
| GHD039 | expiring-soon | Content that expires soon should be proactively addressed. | warning | expired |
| [GHD040](https://github.com/github/docs/blob/main/src/content-linter/README.md) | table-liquid-versioning | Tables must use the correct liquid versioning format | error | tables |
2 changes: 2 additions & 0 deletions src/content-linter/lib/linting-rules/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { liquidIfTags, liquidIfVersionTags, liquidIfVersionVersions } from './li
import { raiReusableUsage } from './rai-reusable-usage.js'
import { imageNoGif } from './image-no-gif.js'
import { expiredContent, expiringSoon } from './expired-content.js'
import { tableLiquidVersioning } from './table-liquid-versioning.js'

const noDefaultAltText = markdownlintGitHub.find((elem) =>
elem.names.includes('no-default-alt-text'),
Expand Down Expand Up @@ -73,5 +74,6 @@ export const gitHubDocsMarkdownlint = {
imageNoGif,
expiredContent,
expiringSoon,
tableLiquidVersioning,
],
}
83 changes: 83 additions & 0 deletions src/content-linter/lib/linting-rules/table-liquid-versioning.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { addError, filterTokens } from 'markdownlint-rule-helpers'

// Detects a Markdown table delimiter row
const delimiterRegexPure = /(\s)*(:)?(-+)(:)?(\s)*(\|)/
// Detects a Markdown table delimiter row with a Liquid tag
const delimiterRegex = /(\s)*(:)?(-+)(:)?(\s)*(\|).*({%.*(ifversion|else|endif).*%})/
// Detects a Liquid versioning tag
const liquidRegex = /^{%-?\s*(ifversion|else|endif).*-?%}/
// Detects a Markdown table row with a Liquid versioning tag
const liquidAfterRowRegex = /(\|{1}).*(\|{1}).*{%\s*(ifversion|else|endif).*%}$/

export const tableLiquidVersioning = {
names: ['GHD040', 'table-liquid-versioning'],
description: 'Tables must use the correct liquid versioning format',
severity: 'error',
tags: ['tables'],
information: new URL('https://github.com/github/docs/blob/main/src/content-linter/README.md'),
function: function GHD040(params, onError) {
const lines = params.lines
let inTable = false
for (let i = 0; i < lines.length; i++) {
const line = lines[i]

if (inTable && (!line || isPreviousLineIndented(lines[i], lines[i - 1]))) {
inTable = false
continue
}

if (delimiterRegexPure.test(line)) {
// A table with rows is at least 3 lines
if (lines[i - 1] && lines[i + 1]) {
inTable = true
if (liquidAfterRowRegex.test(lines[i - 1])) {
addError(
onError,
i,
'Liquid conditionals that version rows of data should be placed on their own line in the format `| {% ifversion enterprise %} |`.',
lines[i - 1],
null,
)
}
if (delimiterRegex.test(line)) {
addError(
onError,
i + 1,
'Liquid conditionals that version rows of data should be placed on their own line in the format `| {% ifversion enterprise %} |`.',
line,
null,
)
}
continue
}
}
if (inTable) {
if (liquidRegex.test(line)) {
addError(
onError,
i + 1,
'Liquid conditionals that version rows of data should be placed on their own line in the format `| {% ifversion enterprise %} |`. If the conditional is on its own line but is not related to the table, ensure there is one new line beween a Liquid version tag and the table.',
line,
null,
)
}
if (liquidAfterRowRegex.test(line)) {
addError(
onError,
i + 1,
'Liquid conditionals that version rows of data should be placed on their own line in the format `| {% ifversion enterprise %} |`.',
line,
null,
)
}
}
}
},
}

function isPreviousLineIndented(line, previousLine) {
if (!line || !previousLine) return false
const numWhitespaceLine = line.length - line.trimLeft().length
const numWhitespacePrevLine = previousLine.length - previousLine.trimLeft().length
return numWhitespaceLine < numWhitespacePrevLine
}
5 changes: 5 additions & 0 deletions src/content-linter/style/github-docs.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,11 @@ const githubDocsConfig = {
severity: 'warning',
'partial-markdown-files': true,
},
'table-liquid-versioning': {
// GH040
severity: 'error',
'partial-markdown-files': true,
},
}

export const githubDocsFrontmatterConfig = {
Expand Down
59 changes: 59 additions & 0 deletions src/content-linter/tests/fixtures/tables.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
title: Examples of tables in Markdown
descriptions: Examples of tables in Markdown
versions:
fpt: '*'
ghes: '*'
ghec: '*'
---

## Good

| Package manager | Languages | Recommended formats | All supported formats |
| --- | --- | --- | ---|
| {% ifversion volvo %} |
| Cargo | Rust | `Cargo.lock` | `Cargo.toml`, `Cargo.lock` |
| {% endif %} |

| Package manager | Languages | Recommended formats | All supported formats |
| --- | --- | --- | ---|
| {%- ifversion volvo %} |
| Cargo | Rust | `Cargo.lock` | `Cargo.toml`, `Cargo.lock` |
| {%- endif %} |

{% ifversion volvo %}

1. This is a list with a table
| Package manager | Languages | Recommended formats | All supported formats |
| --- | --- | --- | ---|
| {%- ifversion volvo %} |
| Cargo | Rust | `Cargo.lock` | `Cargo.toml`, `Cargo.lock` |
| {%- endif %} |
{% endif %}

## Bad

| Package manager | Languages | Recommended formats | All supported formats |
| --- | --- | --- | ---|
{%- ifversion volvo %}
| Cargo | Rust | `Cargo.lock` | `Cargo.toml`, `Cargo.lock` |
{%- endif %}

| Package manager | Languages | Recommended formats | All supported formats |
| --- | --- | --- | ---|{% ifversion volvo %}
| Cargo | Rust | `Cargo.lock` | `Cargo.toml`, `Cargo.lock` |{% endif %}

{% ifversion volvo %}

| Package manager | Languages | Recommended formats | All supported formats |
| --- | --- | --- | ---|
| Cargo | Rust | `Cargo.lock` | `Cargo.toml`, `Cargo.lock` |
{% endif %}

Package manager | Languages | Recommended formats | All supported formats {% ifversion fpt %}
:- | :- | :- | :-{% endif %}{% ifversion volvo %}
Cargo | Rust | `Cargo.lock` | `Cargo.toml`, `Cargo.lock` {% endif %}

| Package manager | Languages | Recommended formats | All supported formats | {% ifversion fpt %}
| :- | :- | :- | :-|{% endif %}{% ifversion volvo %}
|Cargo | Rust | `Cargo.lock` | `Cargo.toml`, `Cargo.lock`| {% endif %}
17 changes: 17 additions & 0 deletions src/content-linter/tests/unit/table-liquid-versioning.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { describe, expect, test } from 'vitest'

import { runRule } from '../../lib/init-test.js'
import { tableLiquidVersioning } from '../../lib/linting-rules/table-liquid-versioning.js'

const FIXTURE_FILEPATH = 'src/content-linter/tests/fixtures/tables.md'

describe(tableLiquidVersioning.names.join(' - '), () => {
test('non-early access file with early access references fails', async () => {
const result = await runRule(tableLiquidVersioning, { files: [FIXTURE_FILEPATH] })
const errors = result[FIXTURE_FILEPATH]
expect(errors.length).toBe(11)
const lineNumbers = errors.map((error) => error.lineNumber)
const expectedErrorLines = [38, 40, 43, 44, 51, 53, 54, 55, 57, 58, 59]
expect(JSON.stringify(lineNumbers)).toEqual(JSON.stringify(expectedErrorLines))
})
})
Loading