Skip to content

Commit b385b4c

Browse files
committed
feat(remark-lint): add
1 parent ba6db41 commit b385b4c

25 files changed

+1174
-142
lines changed

apps/site/.remarkrc.json

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,3 @@
11
{
2-
"settings": {
3-
"bullet": "-",
4-
"resourceLink": true
5-
},
6-
"plugins": [
7-
"remark-frontmatter",
8-
"remark-preset-lint-node",
9-
["remark-gfm", false],
10-
["remark-lint-fenced-code-flag", false],
11-
["remark-lint-first-heading-level", false],
12-
["remark-lint-maximum-line-length", false],
13-
["remark-lint-no-file-name-articles", false],
14-
["remark-lint-no-literal-urls", false],
15-
["remark-lint-no-unused-definitions", false],
16-
["remark-lint-no-undefined-references", false],
17-
["remark-lint-prohibited-strings", false],
18-
["remark-lint-unordered-list-marker-style", "-"],
19-
["remark-preset-lint-node/remark-lint-nodejs-links.js", false]
20-
]
2+
"plugins": ["remark-frontmatter", "@node-core/remark-lint"]
213
}

apps/site/package.json

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
"@eslint/eslintrc": "~3.3.1",
8080
"@flarelabs-net/wrangler-build-time-fs-assets-polyfilling": "^0.0.0",
8181
"@next/eslint-plugin-next": "15.3.4",
82+
"@node-core/remark-lint": "workspace:*",
8283
"@opennextjs/cloudflare": "^1.3.0",
8384
"@playwright/test": "^1.53.2",
8485
"@testing-library/user-event": "~14.6.1",
@@ -91,17 +92,7 @@
9192
"global-jsdom": "^26.0.0",
9293
"handlebars": "4.7.8",
9394
"jsdom": "^26.0.0",
94-
"remark-frontmatter": "5.0.0",
95-
"remark-lint-fenced-code-flag": "^4.2.0",
96-
"remark-lint-first-heading-level": "^4.0.1",
97-
"remark-lint-maximum-line-length": "^4.1.1",
98-
"remark-lint-no-file-name-articles": "^3.0.1",
99-
"remark-lint-no-literal-urls": "^4.0.1",
100-
"remark-lint-no-undefined-references": "^5.0.2",
101-
"remark-lint-no-unused-definitions": "^4.0.2",
102-
"remark-lint-prohibited-strings": "^4.0.0",
103-
"remark-lint-unordered-list-marker-style": "^4.0.1",
104-
"remark-preset-lint-node": "5.1.2",
95+
"remark-frontmatter": "^5.0.0",
10596
"stylelint": "16.21.1",
10697
"stylelint-config-standard": "38.0.0",
10798
"stylelint-order": "7.0.0",

apps/site/pages/tr/about/index.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ Node.js, Ruby'nin [Event Machine][] ve Python'un [Twisted][] gibi sistemlere ben
5151

5252
HTTP, Node.js'de birinci sınıf bir vatandaştır ve akış ve düşük gecikme düşünülerek tasarlanmıştır. Bu, Node.js'in bir web kitaplığının veya çerçevesinin temeli için uygun olmasını sağlar.
5353

54-
Node.js'in iş parçacıkları olmadan tasarlanmış olması, çevrenizdeki birden fazla çekirdeği kullanamayacağınız anlamına gelmez. Çocuk süreçler, [child\_process.fork()][] API'si kullanılarak oluşturulabilir ve iletişim kurmak için tasarlanmıştır. Aynı arayüz üzerine inşa edilmiş olan [`cluster`][] modülü, çekirdekleriniz üzerinde yük dengelemeyi etkinleştirmek için süreçler arasında soket paylaşmanıza izin verir.
54+
Node.js'in iş parçacıkları olmadan tasarlanmış olması, çevrenizdeki birden fazla çekirdeği kullanamayacağınız anlamına gelmez. Çocuk süreçler, \[child\_process.fork()]\[] API'si kullanılarak oluşturulabilir ve iletişim kurmak için tasarlanmıştır. Aynı arayüz üzerine inşa edilmiş olan [`cluster`][] modülü, çekirdekleriniz üzerinde yük dengelemeyi etkinleştirmek için süreçler arasında soket paylaşmanıza izin verir.
5555

5656
[blokajlı ve Blokajlı Olmayan]: /learn/asynchronous-work/overview-of-blocking-vs-non-blocking
5757
[`child_process.fork()`]: https://nodejs.org/api/child_process.html
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"**/*.{js,mjs,ts,tsx,md,mdx}": ["prettier --check --write", "eslint --fix"],
3+
"**/*.{json,yml}": ["prettier --check --write"]
4+
}

packages/remark-lint/eslint.config.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import globals from 'globals';
2+
3+
import baseConfig from '../../eslint.config.js';
4+
5+
export default [
6+
...baseConfig,
7+
{
8+
languageOptions: {
9+
globals: globals.nodeBuiltin,
10+
parserOptions: {
11+
// Allow nullish syntax (i.e. "?." or "??"),
12+
// and top-level await
13+
ecmaVersion: 'latest',
14+
},
15+
},
16+
},
17+
];

packages/remark-lint/package.json

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
{
2+
"name": "@node-core/remark-lint",
3+
"type": "module",
4+
"exports": {
5+
".": "./src/index.mjs",
6+
"./api": "./src/api.mjs"
7+
},
8+
"scripts": {
9+
"lint": "turbo run lint:js",
10+
"lint:js": "eslint \"**/*.mjs\"",
11+
"lint:fix": "node --run lint -- -- --fix",
12+
"test": "node --run test:unit",
13+
"test:unit": "cross-env NODE_NO_WARNINGS=1 node --experimental-test-coverage --test \"**/*.test.mjs\""
14+
},
15+
"dependencies": {
16+
"remark-gfm": "~4.0.1",
17+
"remark-lint-blockquote-indentation": "^4.0.1",
18+
"remark-lint-checkbox-character-style": "^5.0.1",
19+
"remark-lint-checkbox-content-indent": "^5.0.1",
20+
"remark-lint-code-block-style": "^4.0.1",
21+
"remark-lint-definition-spacing": "^4.0.1",
22+
"remark-lint-fenced-code-flag": "^4.2.0",
23+
"remark-lint-fenced-code-marker": "^4.0.1",
24+
"remark-lint-file-extension": "^3.0.1",
25+
"remark-lint-final-definition": "^4.0.2",
26+
"remark-lint-heading-style": "^4.0.1",
27+
"remark-lint-maximum-line-length": "^4.1.1",
28+
"remark-lint-no-consecutive-blank-lines": "^5.0.1",
29+
"remark-lint-no-file-name-consecutive-dashes": "^3.0.1",
30+
"remark-lint-no-file-name-outer-dashes": "^3.0.1",
31+
"remark-lint-no-heading-indent": "^5.0.1",
32+
"remark-lint-no-literal-urls": "^4.0.1",
33+
"remark-lint-no-multiple-toplevel-headings": "^4.0.1",
34+
"remark-lint-no-shell-dollars": "^4.0.1",
35+
"remark-lint-no-table-indentation": "^5.0.1",
36+
"remark-lint-no-tabs": "^4.0.1",
37+
"remark-lint-no-trailing-spaces": "^3.0.2",
38+
"remark-lint-no-unused-definitions": "^4.0.2",
39+
"remark-lint-prohibited-strings": "^4.0.0",
40+
"remark-lint-rule-style": "^4.0.1",
41+
"remark-lint-strong-marker": "^4.0.1",
42+
"remark-lint-table-cell-padding": "^5.1.1",
43+
"remark-lint-table-pipes": "^5.0.1",
44+
"remark-lint-unordered-list-marker-style": "^4.0.1",
45+
"remark-preset-lint-recommended": "^7.0.1",
46+
"semver": "~7.7.2",
47+
"unified-lint-rule": "^3.0.1",
48+
"unist-util-visit": "^5.0.0",
49+
"yaml": "^2.8.0"
50+
},
51+
"devDependencies": {
52+
"cross-env": "catalog:",
53+
"dedent": "^1.6.0",
54+
"globals": "^16.3.0",
55+
"remark-parse": "^11.0.0",
56+
"unified": "^11.0.5"
57+
}
58+
}

packages/remark-lint/src/api.mjs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import remarkGfm from 'remark-gfm';
2+
import remarkLintFencedCodeFlag from 'remark-lint-fenced-code-flag';
3+
import remarkLintMaximumLineLength from 'remark-lint-maximum-line-length';
4+
import remarkLintNoUnusedDefinitions from 'remark-lint-no-unused-definitions';
5+
import remarkLintProhibitedStrings from 'remark-lint-prohibited-strings';
6+
import remarkLintUnorderedListMarkerStyle from 'remark-lint-unordered-list-marker-style';
7+
8+
import basePreset from './index.mjs';
9+
import duplicateStabilityNodes from './rules/duplicate-stability-nodes.mjs';
10+
import hashedSelfReference from './rules/hashed-self-reference.mjs';
11+
import orderedReferences from './rules/ordered-references.mjs';
12+
import yamlComments from './rules/yaml/index.mjs';
13+
14+
export default {
15+
settings: {
16+
...basePreset.settings,
17+
bullet: '*',
18+
},
19+
plugins: [
20+
remarkGfm,
21+
...basePreset.plugins,
22+
duplicateStabilityNodes,
23+
yamlComments,
24+
hashedSelfReference,
25+
orderedReferences,
26+
remarkLintNoUnusedDefinitions,
27+
[remarkLintFencedCodeFlag, { allowEmpty: false }],
28+
[remarkLintMaximumLineLength, 120],
29+
[remarkLintUnorderedListMarkerStyle, '*'],
30+
[
31+
remarkLintProhibitedStrings,
32+
[
33+
{ yes: 'End-of-Life' },
34+
{ no: 'filesystem', yes: 'file system' },
35+
{ yes: 'GitHub' },
36+
{ no: 'hostname', yes: 'host name' },
37+
{ yes: 'JavaScript' },
38+
{ no: '[Ll]ong[ -][Tt]erm [Ss]upport', yes: 'Long Term Support' },
39+
{ no: 'Node', yes: 'Node.js', ignoreNextTo: '-API' },
40+
{ yes: 'Node.js' },
41+
{ no: 'Node[Jj][Ss]', yes: 'Node.js' },
42+
{ no: "Node\\.js's?", yes: 'the Node.js' },
43+
{ no: '[Nn]ote that', yes: '<nothing>' },
44+
{ yes: 'RFC' },
45+
{ no: '[Rr][Ff][Cc]\\d+', yes: 'RFC <number>' },
46+
{ yes: 'TypeScript' },
47+
{ yes: 'Unix' },
48+
{ yes: 'Valgrind' },
49+
{ yes: 'V8' },
50+
],
51+
],
52+
],
53+
};

packages/remark-lint/src/index.mjs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import remarkLintBlockquoteIndentation from 'remark-lint-blockquote-indentation';
2+
import remarkLintCheckboxCharacterStyle from 'remark-lint-checkbox-character-style';
3+
import remarkLintCheckboxContentIndent from 'remark-lint-checkbox-content-indent';
4+
import remarkLintCodeBlockStyle from 'remark-lint-code-block-style';
5+
import remarkLintDefinitionSpacing from 'remark-lint-definition-spacing';
6+
import remarkLintFencedCodeMarker from 'remark-lint-fenced-code-marker';
7+
import remarkLintFileExtension from 'remark-lint-file-extension';
8+
import remarkLintFinalDefinition from 'remark-lint-final-definition';
9+
import remarkLintHeadingStyle from 'remark-lint-heading-style';
10+
import remarkLintNoConsecutiveBlankLines from 'remark-lint-no-consecutive-blank-lines';
11+
import remarkLintNoFileNameConsecutiveDashes from 'remark-lint-no-file-name-consecutive-dashes';
12+
import remarkLintNofileNameOuterDashes from 'remark-lint-no-file-name-outer-dashes';
13+
import remarkLintNoHeadingIndent from 'remark-lint-no-heading-indent';
14+
import remarkLintNoLiteralURLs from 'remark-lint-no-literal-urls';
15+
import remarkLintNoMultipleToplevelHeadings from 'remark-lint-no-multiple-toplevel-headings';
16+
import remarkLintNoShellDollars from 'remark-lint-no-shell-dollars';
17+
import remarkLintNoTableIndentation from 'remark-lint-no-table-indentation';
18+
import remarkLintNoTabs from 'remark-lint-no-tabs';
19+
import remarkLintNoTrailingSpaces from 'remark-lint-no-trailing-spaces';
20+
import remarkLintNoUnusedDefinitions from 'remark-lint-no-unused-definitions';
21+
import remarkLintRuleStyle from 'remark-lint-rule-style';
22+
import remarkLintStrongMarker from 'remark-lint-strong-marker';
23+
import remarkLintTableCellPadding from 'remark-lint-table-cell-padding';
24+
import remarkLintTablePipes from 'remark-lint-table-pipes';
25+
import remarkPresetLintRecommended from 'remark-preset-lint-recommended';
26+
27+
export default {
28+
settings: {
29+
tightDefinitions: true,
30+
emphasis: '_',
31+
bullet: '-',
32+
rule: '-',
33+
},
34+
plugins: [
35+
// Base plugins
36+
remarkPresetLintRecommended,
37+
38+
// Blockquote and list rules
39+
[remarkLintBlockquoteIndentation, 2],
40+
[remarkLintCheckboxCharacterStyle, { checked: 'x', unchecked: ' ' }],
41+
remarkLintCheckboxContentIndent,
42+
43+
// Code and formatting rules
44+
[remarkLintCodeBlockStyle, 'fenced'],
45+
[remarkLintFencedCodeMarker, '`'],
46+
[remarkLintRuleStyle, '---'],
47+
[remarkLintStrongMarker, '*'],
48+
49+
// File and filename rules
50+
[remarkLintFileExtension, 'md'],
51+
remarkLintNoFileNameConsecutiveDashes,
52+
remarkLintNofileNameOuterDashes,
53+
54+
// Heading and link rules
55+
remarkLintFinalDefinition,
56+
[remarkLintNoUnusedDefinitions, false],
57+
[remarkLintNoLiteralURLs, false],
58+
[remarkLintHeadingStyle, 'atx'],
59+
remarkLintNoHeadingIndent,
60+
remarkLintNoMultipleToplevelHeadings,
61+
62+
// Layout and spacing rules
63+
remarkLintDefinitionSpacing,
64+
remarkLintNoConsecutiveBlankLines,
65+
remarkLintNoTableIndentation,
66+
remarkLintNoTabs,
67+
remarkLintNoTrailingSpaces,
68+
[remarkLintTableCellPadding, 'padded'],
69+
remarkLintTablePipes,
70+
71+
// Shell and console rules
72+
remarkLintNoShellDollars,
73+
],
74+
};
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { describe, it } from 'node:test';
2+
3+
import dedent from 'dedent';
4+
5+
import duplicateStabilityNodes from '../duplicate-stability-nodes.mjs';
6+
import { testRule } from './utils.mjs';
7+
8+
const testCases = [
9+
{
10+
name: 'no stability nodes',
11+
input: dedent`
12+
# Heading 1
13+
14+
> No stability here.
15+
`,
16+
expected: [],
17+
},
18+
{
19+
name: 'single stability blockquote',
20+
input: dedent`
21+
# Heading 1
22+
23+
> Stability: 1.0
24+
`,
25+
expected: [],
26+
},
27+
{
28+
name: 'different stabilities under different headings',
29+
input: dedent`
30+
# Heading 1
31+
32+
> Stability: 1.0
33+
34+
## Heading 2
35+
36+
> Stability: 2.0
37+
`,
38+
expected: [],
39+
},
40+
{
41+
name: 'duplicate stability at deeper heading triggers message',
42+
input: dedent`
43+
# Heading 1
44+
45+
> Stability: 1.0
46+
47+
## Heading 2
48+
49+
> Stability: 1.0
50+
`,
51+
expected: ['Duplicate stability node'],
52+
},
53+
];
54+
55+
describe('duplicate-stability-nodes', () => {
56+
for (const { name, input, expected } of testCases) {
57+
it(name, () => testRule(duplicateStabilityNodes, input, expected));
58+
}
59+
});
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { describe, it } from 'node:test';
2+
3+
import hashedSelfReference from '../hashed-self-reference.mjs';
4+
import { testRule } from './utils.mjs';
5+
6+
const testCases = [
7+
{
8+
name: 'ignores links to other paths',
9+
input: '[external](./other.md)',
10+
path: 'docs/current.md',
11+
expected: [],
12+
},
13+
{
14+
name: 'accepts hashed self-reference',
15+
input: '[header](#my-heading)',
16+
path: 'docs/current.md',
17+
expected: [],
18+
},
19+
{
20+
name: 'reports self-reference with fragment',
21+
input: '[bad link](./current.md#section)',
22+
path: 'docs/current.md',
23+
expected: [
24+
'Self-reference must start with hash (expected "#section", got "./current.md#section")',
25+
],
26+
},
27+
{
28+
name: 'reports self-reference to path only',
29+
input: '[bad link](./current.md)',
30+
path: 'docs/current.md',
31+
expected: [
32+
'Self-reference must start with hash (expected "#", got "./current.md")',
33+
],
34+
},
35+
{
36+
name: 'ignores external links',
37+
input: '[nodejs](https://nodejs.org)',
38+
path: 'docs/current.md',
39+
expected: [],
40+
},
41+
];
42+
43+
describe('hashed-self-references', () => {
44+
for (const { name, input, expected, ...options } of testCases) {
45+
it(name, () =>
46+
testRule(hashedSelfReference, input, expected, {
47+
...options,
48+
cwd: process.cwd(),
49+
})
50+
);
51+
}
52+
});

0 commit comments

Comments
 (0)