Skip to content

Commit 7b5e748

Browse files
authored
feat: support specifying remarkConfigPath manually (#589)
1 parent a51a027 commit 7b5e748

File tree

15 files changed

+129
-27
lines changed

15 files changed

+129
-27
lines changed

.changeset/large-items-thank.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"eslint-plugin-mdx": minor
3+
"eslint-mdx": minor
4+
---
5+
6+
feat: support specifying `remarkConfigPath` manually

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ npm i -D eslint-plugin-mdx
100100
// optional, if you want to disable language mapper, set it to `false`
101101
// if you want to override the default language mapper inside, you can provide your own
102102
"mdx/language-mapper": {},
103+
// optional, same as the `parserOptions.ignoreRemarkConfig`, you have to specify it twice unfortunately
104+
"mdx/ignore-remark-config": true,
105+
// optional, same as the `parserOptions.remarkConfigPath`, you have to specify it twice unfortunately
106+
"mdx/remark-config-path": "path/to/your/remarkrc",
103107
},
104108
}
105109
```
@@ -120,6 +124,10 @@ export default [
120124
// optional, if you want to disable language mapper, set it to `false`
121125
// if you want to override the default language mapper inside, you can provide your own
122126
languageMapper: {},
127+
// optional, same as the `parserOptions.ignoreRemarkConfig`, you have to specify it twice unfortunately
128+
ignoreRemarkConfig: true,
129+
// optional, same as the `parserOptions.remarkConfigPath`, you have to specify it twice unfortunately
130+
remarkConfigPath: 'path/to/your/remarkrc',
123131
}),
124132
},
125133
{
@@ -148,6 +156,8 @@ eslint . --ext js,md,mdx
148156

149157
3. `ignoreRemarkConfig` (`boolean`): Ignore the `remark` configuration defined in the project.
150158

159+
4. `remarkConfigPath` (`string`): Specify the path to the `remark` configuration file, could be relative to `CWD` or absolute path.
160+
151161
## Parser API
152162

153163
### `MDXCode`

packages/eslint-mdx/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ npm i -D eslint-plugin-mdx
100100
// optional, if you want to disable language mapper, set it to `false`
101101
// if you want to override the default language mapper inside, you can provide your own
102102
"mdx/language-mapper": {},
103+
// optional, same as the `parserOptions.ignoreRemarkConfig`, you have to specify it twice unfortunately
104+
"mdx/ignore-remark-config": true,
105+
// optional, same as the `parserOptions.remarkConfigPath`, you have to specify it twice unfortunately
106+
"mdx/remark-config-path": "path/to/your/remarkrc",
103107
},
104108
}
105109
```
@@ -120,6 +124,10 @@ export default [
120124
// optional, if you want to disable language mapper, set it to `false`
121125
// if you want to override the default language mapper inside, you can provide your own
122126
languageMapper: {},
127+
// optional, same as the `parserOptions.ignoreRemarkConfig`, you have to specify it twice unfortunately
128+
ignoreRemarkConfig: true,
129+
// optional, same as the `parserOptions.remarkConfigPath`, you have to specify it twice unfortunately
130+
remarkConfigPath: 'path/to/your/remarkrc',
123131
}),
124132
},
125133
{
@@ -148,6 +156,8 @@ eslint . --ext js,md,mdx
148156

149157
3. `ignoreRemarkConfig` (`boolean`): Ignore the `remark` configuration defined in the project.
150158

159+
4. `remarkConfigPath` (`string`): Specify the path to the `remark` configuration file, could be relative to `CWD` or absolute path.
160+
151161
## Parser API
152162

153163
### `MDXCode`

packages/eslint-mdx/src/parser.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export class Parser {
2626
filePath,
2727
sourceType,
2828
ignoreRemarkConfig,
29+
remarkConfigPath,
2930
extensions,
3031
markdownExtensions,
3132
}: ParserOptions,
@@ -55,6 +56,7 @@ export class Parser {
5556
code,
5657
isMdx,
5758
ignoreRemarkConfig,
59+
remarkConfigPath,
5860
})
5961
} catch (err: unknown) {
6062
/* istanbul ignore if */

packages/eslint-mdx/src/types.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export interface ParserOptions extends Linter.ParserOptions {
1010
markdownExtensions?: string[] | string
1111
filePath?: string
1212
ignoreRemarkConfig?: boolean
13+
remarkConfigPath?: string
1314
}
1415

1516
export interface NormalPosition {
@@ -22,13 +23,17 @@ export interface NormalPosition {
2223
range: [number, number]
2324
}
2425

25-
export interface WorkerOptions {
26+
export interface SyncOptions {
27+
cwd?: string
28+
ignoreRemarkConfig?: boolean
29+
remarkConfigPath?: string
30+
}
31+
32+
export interface WorkerOptions extends SyncOptions {
2633
filePath: string
2734
code: string
28-
cwd?: string
2935
isMdx: boolean
3036
process?: boolean
31-
ignoreRemarkConfig?: boolean
3237
}
3338

3439
export interface WorkerParseResult {

packages/eslint-mdx/src/worker.ts

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,19 +86,26 @@ const ignoreCheckCache = new Map<
8686
(filePath: string) => Promise<boolean>
8787
>()
8888

89-
const getRemarkConfig = async (filePath: string, cwd: string) => {
90-
let configLoad = configLoadCache.get(cwd)
89+
const getRemarkConfig = async (
90+
filePath: string,
91+
cwd: string,
92+
remarkConfigPath?: string,
93+
) => {
94+
const cacheKey = remarkConfigPath ? `${cwd}\0${remarkConfigPath}` : cwd
95+
96+
let configLoad = configLoadCache.get(cacheKey)
9197

9298
if (!configLoad) {
9399
const config = new Configuration({
94100
cwd,
95101
packageField: 'remarkConfig',
96102
pluginPrefix: 'remark',
97103
rcName: '.remarkrc',
104+
rcPath: remarkConfigPath,
98105
detectConfig: true,
99106
})
100107
configLoad = promisify(config.load.bind(config))
101-
configLoadCache.set(cwd, configLoad)
108+
configLoadCache.set(cacheKey, configLoad)
102109
}
103110

104111
if (!Ignore) {
@@ -109,7 +116,7 @@ const getRemarkConfig = async (filePath: string, cwd: string) => {
109116
)) as { Ignore: IgnoreClass })
110117
}
111118

112-
let ignoreCheck = ignoreCheckCache.get(cwd)
119+
let ignoreCheck = ignoreCheckCache.get(cacheKey)
113120

114121
if (!ignoreCheck) {
115122
const ignore = new Ignore({
@@ -118,7 +125,7 @@ const getRemarkConfig = async (filePath: string, cwd: string) => {
118125
detectIgnore: true,
119126
})
120127
ignoreCheck = promisify(ignore.check.bind(ignore))
121-
ignoreCheckCache.set(cwd, ignoreCheck)
128+
ignoreCheckCache.set(cacheKey, ignoreCheck)
122129
}
123130

124131
return configLoad(filePath)
@@ -142,6 +149,7 @@ export const getRemarkProcessor = async (
142149
isMdx: boolean,
143150
ignoreRemarkConfig?: boolean,
144151
cwd = process.cwd(),
152+
remarkConfigPath?: string,
145153
) => {
146154
const initCacheKey = `${String(isMdx)}-${cwd}\0${filePath}`
147155

@@ -153,7 +161,7 @@ export const getRemarkProcessor = async (
153161

154162
const result = ignoreRemarkConfig
155163
? null
156-
: await getRemarkConfig(filePath, cwd)
164+
: await getRemarkConfig(filePath, cwd, remarkConfigPath)
157165

158166
const cacheKey = result?.filePath
159167
? `${String(isMdx)}-${result.filePath}`
@@ -227,6 +235,8 @@ runAsWorker(
227235
isMdx,
228236
process,
229237
ignoreRemarkConfig,
238+
remarkConfigPath,
239+
// eslint-disable-next-line sonarjs/cognitive-complexity
230240
}: WorkerOptions): Promise<WorkerResult> => {
231241
sharedTokens.length = 0
232242

@@ -245,6 +255,7 @@ runAsWorker(
245255
isMdx,
246256
ignoreRemarkConfig,
247257
cwd,
258+
remarkConfigPath,
248259
)
249260

250261
const fileOptions: VFileOptions = {
@@ -254,7 +265,9 @@ runAsWorker(
254265
}
255266

256267
if (process) {
257-
if (await ignoreCheckCache.get(cwd)(filePath)) {
268+
const cacheKey = remarkConfigPath ? `${cwd}\0${remarkConfigPath}` : cwd
269+
270+
if (await ignoreCheckCache.get(cacheKey)(filePath)) {
258271
return {
259272
messages: [],
260273
}

packages/eslint-plugin-mdx/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ npm i -D eslint-plugin-mdx
100100
// optional, if you want to disable language mapper, set it to `false`
101101
// if you want to override the default language mapper inside, you can provide your own
102102
"mdx/language-mapper": {},
103+
// optional, same as the `parserOptions.ignoreRemarkConfig`, you have to specify it twice unfortunately
104+
"mdx/ignore-remark-config": true,
105+
// optional, same as the `parserOptions.remarkConfigPath`, you have to specify it twice unfortunately
106+
"mdx/remark-config-path": "path/to/your/remarkrc",
103107
},
104108
}
105109
```
@@ -120,6 +124,10 @@ export default [
120124
// optional, if you want to disable language mapper, set it to `false`
121125
// if you want to override the default language mapper inside, you can provide your own
122126
languageMapper: {},
127+
// optional, same as the `parserOptions.ignoreRemarkConfig`, you have to specify it twice unfortunately
128+
ignoreRemarkConfig: true,
129+
// optional, same as the `parserOptions.remarkConfigPath`, you have to specify it twice unfortunately
130+
remarkConfigPath: 'path/to/your/remarkrc',
123131
}),
124132
},
125133
{
@@ -148,6 +156,8 @@ eslint . --ext js,md,mdx
148156

149157
3. `ignoreRemarkConfig` (`boolean`): Ignore the `remark` configuration defined in the project.
150158

159+
4. `remarkConfigPath` (`string`): Specify the path to the `remark` configuration file, could be relative to `CWD` or absolute path.
160+
151161
## Parser API
152162

153163
### `MDXCode`

packages/eslint-plugin-mdx/src/processors/markdown.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import fs from 'node:fs'
44
import path from 'node:path'
55

66
import type { AST, Linter, Rule } from 'eslint'
7-
import { performSyncWork } from 'eslint-mdx'
7+
import { type SyncOptions, performSyncWork } from 'eslint-mdx'
88
import type { Node, Parent, Nodes, Root, RootContentMap } from 'mdast'
99
import type { MdxFlowExpression, MdxTextExpression } from 'mdast-util-mdx'
1010

@@ -293,14 +293,19 @@ function getOnDiskFilepath(filepath: string): string {
293293
* @param filename The filename of the file
294294
* @returns Source code blocks to lint.
295295
*/
296-
function preprocess(sourceText: string, filename: string) {
296+
function preprocess(
297+
sourceText: string,
298+
filename: string,
299+
syncOptions: SyncOptions,
300+
) {
297301
// istanbul ignore next
298302
const text = sourceText.startsWith(BOM) ? sourceText.slice(1) : sourceText
299303
const { root } = performSyncWork({
300304
filePath: getOnDiskFilepath(filename),
301305
code: text,
302306
// FIXME: how to read `extensions` and `markdownExtensions` parser options?
303307
isMdx: filename.endsWith('.mdx'),
308+
...syncOptions,
304309
})
305310
const blocks: CodeBlock[] = []
306311

packages/eslint-plugin-mdx/src/processors/options.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,10 @@ ESLinter.prototype.verify = function (
4848
) ?? config
4949
).settings ?? {}) as ESLintMdxSettings
5050

51-
processorOptions.lintCodeBlocks = settings['mdx/code-blocks'] === true
51+
processorOptions.lintCodeBlocks = settings['mdx/code-blocks']
5252
processorOptions.languageMapper = settings['mdx/language-mapper']
53+
processorOptions.ignoreRemarkConfig = settings['mdx/ignore-remark-config']
54+
processorOptions.remarkConfigPath = settings['mdx/remark-config-path']
5355

5456
// call original Linter#verify
5557
return verify.call(this, code, config, options as ESLint.Linter.LintOptions)

packages/eslint-plugin-mdx/src/processors/remark.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,31 @@ import { getShortLang } from './helpers.js'
77
import { markdownProcessor } from './markdown.js'
88
import { processorOptions as defaultProcessorOptions } from './options.js'
99

10-
export const createRemarkProcessor = (
11-
processorOptions = defaultProcessorOptions,
12-
): Linter.Processor => ({
10+
export const createRemarkProcessor = ({
11+
languageMapper,
12+
lintCodeBlocks,
13+
...syncOptions
14+
} = defaultProcessorOptions): Linter.Processor => ({
1315
meta: {
1416
name: 'mdx/remark',
1517
version: meta.version,
1618
},
1719
supportsAutofix: true,
1820
preprocess(text, filename) {
19-
if (!processorOptions.lintCodeBlocks) {
21+
if (!lintCodeBlocks) {
2022
return [text]
2123
}
2224

2325
return [
2426
text,
2527
...markdownProcessor
26-
.preprocess(text, filename)
28+
.preprocess(text, filename, syncOptions)
2729
.map(({ text, filename }) => ({
2830
text,
2931
filename:
3032
filename.slice(0, filename.lastIndexOf('.')) +
3133
'.' +
32-
getShortLang(filename, processorOptions.languageMapper),
34+
getShortLang(filename, languageMapper),
3335
})),
3436
]
3537
},

0 commit comments

Comments
 (0)