Skip to content

Commit 648843e

Browse files
committed
feat: lint legacy OS names
1 parent ad8af04 commit 648843e

8 files changed

Lines changed: 179 additions & 0 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@alauda/doom": patch
3+
---
4+
5+
Add a lint rule that flags legacy MicroOS and KubeOS names in documentation.

.prettierignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
.yarn
2+
vendor
23
**/pyodide
34
# too big
45
fixture-docs/shared/crds/operator.tekton.dev_*.yaml

eslint.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export default defineConfig(
1515
{
1616
ignores: [
1717
'dist',
18+
'vendor',
1819
'**/lib',
1920
'**/pyodide',
2021
// main language is en which is different with docs

packages/doom/src/remark-lint/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export * from './no-empty-table-cell.ts'
1515
export * from './no-heading-punctuation.ts'
1616
export * from './no-heading-special-characters.ts'
1717
export * from './no-heading-sup-sub.ts'
18+
export * from './no-legacy-os-names.ts'
1819
export * from './no-multi-open-api-paths.ts'
1920
export * from './no-paragraph-indent.ts'
2021
export * from './no-unmatched-anchor.ts'
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import type { Root } from 'mdast'
2+
import type {
3+
MdxJsxAttribute,
4+
MdxJsxAttributeValueExpression,
5+
} from 'mdast-util-mdx-jsx'
6+
import { lintRule } from 'unified-lint-rule'
7+
import { visitParents } from 'unist-util-visit-parents'
8+
9+
const LEGACY_OS_NAME_REGEX =
10+
/(?<![\p{L}\p{N}])(?:micro\s*os|micros|kube\s*os)(?![\p{L}\p{N}])/giu
11+
12+
interface StringValueNode {
13+
value: string
14+
position?: Root['position']
15+
}
16+
17+
const isStringValueNode = (node: unknown): node is StringValueNode =>
18+
!!node &&
19+
typeof node === 'object' &&
20+
'value' in node &&
21+
typeof node.value === 'string'
22+
23+
const reportLegacyOSNames = (
24+
value: string,
25+
report: (legacyName: string) => void,
26+
) => {
27+
for (const { 0: legacyName } of value.matchAll(LEGACY_OS_NAME_REGEX)) {
28+
report(legacyName)
29+
}
30+
}
31+
32+
const createMessage = (legacyName: string) =>
33+
`Unexpected legacy OS name "${legacyName}", use "Alauda OS" or "alauda os" instead`
34+
35+
const getAttributeStringValue = (
36+
value: MdxJsxAttribute['value'],
37+
): string | undefined => {
38+
if (typeof value === 'string') {
39+
return value
40+
}
41+
42+
return (value as MdxJsxAttributeValueExpression).value
43+
}
44+
45+
export const noLegacyOSNames = lintRule<Root>(
46+
'doom-lint:no-legacy-os-names',
47+
(root, vfile) => {
48+
visitParents(root, (node, parents) => {
49+
if (!isStringValueNode(node)) {
50+
return
51+
}
52+
53+
reportLegacyOSNames(node.value, (legacyName) => {
54+
vfile.message(createMessage(legacyName), {
55+
ancestors: [...parents, node],
56+
place: node.position,
57+
})
58+
})
59+
})
60+
61+
visitParents(
62+
root,
63+
['mdxJsxFlowElement', 'mdxJsxTextElement'] as const,
64+
(element, parents) => {
65+
for (const attribute of element.attributes) {
66+
if (
67+
attribute.type !== 'mdxJsxAttribute' ||
68+
typeof attribute.value === 'boolean' ||
69+
attribute.value == null
70+
) {
71+
continue
72+
}
73+
74+
const value = getAttributeStringValue(attribute.value)
75+
if (value == null) {
76+
continue
77+
}
78+
79+
reportLegacyOSNames(value, (legacyName) => {
80+
vfile.message(createMessage(legacyName), {
81+
ancestors: [...parents, element],
82+
place: attribute.position,
83+
})
84+
})
85+
}
86+
},
87+
)
88+
},
89+
)

packages/doom/src/remarkrc.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import doomLint, {
1616
headingAnchorFormat,
1717
noDeepHeading,
1818
noDeepList,
19+
noLegacyOSNames,
1920
noMultiOpenAPIPaths,
2021
noParagraphIndent,
2122
noUnmatchedAnchor,
@@ -41,6 +42,7 @@ export default {
4142
headingAnchorFormat,
4243
noDeepHeading,
4344
noDeepList,
45+
noLegacyOSNames,
4446
noMultiOpenAPIPaths,
4547
noParagraphIndent,
4648
noUnmatchedAnchor,
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { describe, expect, test } from '@rstest/core'
2+
3+
import { lint, lintMdx } from './_helper.ts'
4+
5+
import { noLegacyOSNames } from '#remark-lint/no-legacy-os-names.ts'
6+
7+
describe('no-legacy-os-names', () => {
8+
test('allows Alauda OS names and unrelated words', async () => {
9+
const messages = await lint(
10+
noLegacyOSNames,
11+
[
12+
'Alauda OS image',
13+
'alauda os search query',
14+
'AlaudaOS-Clone',
15+
'microservices are unrelated',
16+
].join('\n'),
17+
)
18+
19+
expect(messages).toHaveLength(0)
20+
})
21+
22+
test('flags legacy OS names in markdown content', async () => {
23+
const messages = await lint(
24+
noLegacyOSNames,
25+
[
26+
'# MicroOS-Based Global Clusters',
27+
'',
28+
'Use Micro OS for x86.',
29+
'',
30+
'- micros global cluster',
31+
'',
32+
'| Source | Target |',
33+
'|---|---|',
34+
'| KubeOS | Alauda OS |',
35+
'| Kube OS | Alauda OS |',
36+
'',
37+
'`kubeos-clone`',
38+
].join('\n'),
39+
)
40+
41+
expect(messages).toHaveLength(6)
42+
expect(messages.map(String).join('\n')).toContain('MicroOS')
43+
expect(messages.map(String).join('\n')).toContain('Micro OS')
44+
expect(messages.map(String).join('\n')).toContain('micros')
45+
expect(messages.map(String).join('\n')).toContain('KubeOS')
46+
expect(messages.map(String).join('\n')).toContain('Kube OS')
47+
expect(messages.map(String).join('\n')).toContain('kubeos')
48+
})
49+
50+
test('flags legacy OS names in frontmatter and code blocks', async () => {
51+
const messages = await lint(
52+
noLegacyOSNames,
53+
[
54+
'---',
55+
'queries:',
56+
' - microos cluster path',
57+
'---',
58+
'',
59+
'```yaml',
60+
'name: kubeos-clone',
61+
'```',
62+
].join('\n'),
63+
)
64+
65+
expect(messages).toHaveLength(2)
66+
expect(messages.map(String).join('\n')).toContain('microos')
67+
expect(messages.map(String).join('\n')).toContain('kubeos')
68+
})
69+
70+
test('flags legacy OS names in MDX string attributes', async () => {
71+
const messages = await lintMdx(
72+
noLegacyOSNames,
73+
'<ExternalSiteLink children="MicroOS on Huawei DCS" />\n',
74+
)
75+
76+
expect(messages).toHaveLength(1)
77+
expect(String(messages[0])).toContain('MicroOS')
78+
})
79+
})

tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"path": "./packages/doom"
1818
}
1919
],
20+
"exclude": ["vendor"],
2021
"mdx": {
2122
"checkMdx": true
2223
}

0 commit comments

Comments
 (0)