Skip to content

Commit 18e669f

Browse files
committedDec 17, 2023
file-extension: add option to disallow extensionless
1 parent 655ba54 commit 18e669f

File tree

2 files changed

+137
-18
lines changed

2 files changed

+137
-18
lines changed
 

‎packages/remark-lint-file-extension/index.js

+80-12
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,46 @@
1515
*
1616
* Warn for unexpected extensions.
1717
*
18-
* > 👉 **Note**: does not warn when files have no file extensions (such as
19-
* > `AUTHORS` or `LICENSE`).
20-
*
2118
* ###### Parameters
2219
*
23-
* * `options` (`Array<string>` or `string`, default: `['mdx', 'md']`)
24-
* — allowed file extension(s)
20+
* * `options` ([`Extensions`][api-extensions] or [`Options`][api-options],
21+
* optional)
22+
* — configuration
2523
*
2624
* ###### Returns
2725
*
2826
* Transform ([`Transformer` from `unified`][github-unified-transformer]).
2927
*
28+
* ### `Extensions`
29+
*
30+
* File extension(s) (TypeScript type).
31+
*
32+
* ###### Type
33+
*
34+
* ```ts
35+
* type Extensions = Array<string> | string
36+
* ```
37+
*
38+
* ### `Options`
39+
*
40+
* Configuration (TypeScript type).
41+
*
42+
* ###### Fields
43+
*
44+
* * `allowExtensionless` (`boolean`, default: `true`)
45+
* — allow no file extension such as `AUTHORS` or `LICENSE`
46+
* * `extensions` ([`Extensions`][api-extensions], default: `['mdx', 'md']`)
47+
* — allowed file extension(s)
48+
*
3049
* ## Recommendation
3150
*
3251
* Use `md` as it’s the most common.
3352
* Also use `md` when your markdown contains common syntax extensions (such as
3453
* GFM, frontmatter, or math).
3554
* Do not use `md` for MDX: use `mdx` instead.
3655
*
56+
* [api-extensions]: #extensions
57+
* [api-options]: #options
3758
* [api-remark-lint-file-extension]: #unifieduseremarklintfileextension-options
3859
* [github-unified-transformer]: https://github.com/unifiedjs/unified#transformer
3960
*
@@ -45,21 +66,44 @@
4566
* {"name": "readme.md"}
4667
*
4768
* @example
69+
* {"name": "readme.mdx"}
70+
*
71+
* @example
4872
* {"name": "readme"}
4973
*
5074
* @example
51-
* {"name": "readme.mkd", "label": "output", "positionless": true}
75+
* {"config": {"allowExtensionless": false}, "label": "output", "name": "readme", "positionless": true}
76+
*
77+
* 1:1: Incorrect extension: use `mdx` or `md`
78+
*
79+
* @example
80+
* {"label": "output", "name": "readme.mkd", "positionless": true}
5281
*
5382
* 1:1: Incorrect extension: use `mdx` or `md`
5483
*
5584
* @example
56-
* {"name": "readme.mkd", "config": "mkd"}
85+
* {"config": "mkd", "name": "readme.mkd"}
86+
*
87+
* @example
88+
* {"config": ["mkd"], "name": "readme.mkd"}
5789
*/
5890

5991
/**
6092
* @typedef {import('mdast').Root} Root
6193
*/
6294

95+
/**
96+
* @typedef {ReadonlyArray<string> | string} Extensions
97+
* File extension(s).
98+
*
99+
* @typedef Options
100+
* Configuration.
101+
* @property {boolean | null | undefined} [allowExtensionless=true]
102+
* Allow no file extension such as `AUTHORS` or `LICENSE` (default: `true`).
103+
* @property {Extensions | null | undefined} [extensions=['mdx', 'md']]
104+
* Allowed file extension(s) (default: `['mdx', 'md']`).
105+
*/
106+
63107
import {lintRule} from 'unified-lint-rule'
64108
import {quotation} from 'quotation'
65109

@@ -76,18 +120,42 @@ const remarkLintFileExtension = lintRule(
76120
/**
77121
* @param {Root} _
78122
* Tree.
79-
* @param {ReadonlyArray<string> | string | null | undefined} [options='md']
80-
* Configuration (default: `'md'`).
123+
* @param {Readonly<Extensions> | Readonly<Options> | null | undefined} [options]
124+
* Configuration (optional).
81125
* @returns {undefined}
82126
* Nothing.
83127
*/
84128
function (_, file, options) {
85-
const extensions =
86-
typeof options === 'string' ? [options] : options || defaultExtensions
129+
let extensions = defaultExtensions
130+
let allowExtensionless = true
131+
/** @type {Readonly<Extensions> | null | undefined} */
132+
let extensionsValue
133+
134+
if (Array.isArray(options)) {
135+
// TS fails on `isArray` w/ readonly.
136+
extensionsValue = /** @type {ReadonlyArray<string>} */ (options)
137+
} else if (typeof options === 'string') {
138+
extensionsValue = options
139+
} else if (options) {
140+
// TS fails on `isArray` w/ readonly.
141+
const settings = /** @type {Options} */ (options)
142+
extensionsValue = settings.extensions
143+
144+
if (settings.allowExtensionless === false) {
145+
allowExtensionless = false
146+
}
147+
}
148+
149+
if (Array.isArray(extensionsValue)) {
150+
extensions = /** @type {ReadonlyArray<string>} */ (extensionsValue)
151+
} else if (typeof extensionsValue === 'string') {
152+
extensions = [extensionsValue]
153+
}
154+
87155
const extname = file.extname
88156
const extension = extname ? extname.slice(1) : undefined
89157

90-
if (extension && !extensions.includes(extension)) {
158+
if (extension ? !extensions.includes(extension) : !allowExtensionless) {
91159
file.message(
92160
'Incorrect extension: use ' +
93161
listFormat.format(quotation(extensions, '`'))

‎packages/remark-lint-file-extension/readme.md

+57-6
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
* [Use](#use)
2222
* [API](#api)
2323
* [`unified().use(remarkLintFileExtension[, options])`](#unifieduseremarklintfileextension-options)
24+
* [`Extensions`](#extensions)
25+
* [`Options`](#options)
2426
* [Recommendation](#recommendation)
2527
* [Examples](#examples)
2628
* [Compatibility](#compatibility)
@@ -116,26 +118,47 @@ On the CLI in a config file (here a `package.json`):
116118
## API
117119

118120
This package exports no identifiers.
119-
It exports no additional [TypeScript][typescript] types.
121+
It exports the [TypeScript][typescript] types
122+
[`Extensions`][api-extensions] and
123+
[`Options`][api-options].
120124
The default export is
121125
[`remarkLintFileExtension`][api-remark-lint-file-extension].
122126

123127
### `unified().use(remarkLintFileExtension[, options])`
124128

125129
Warn for unexpected extensions.
126130

127-
> 👉 **Note**: does not warn when files have no file extensions (such as
128-
> `AUTHORS` or `LICENSE`).
129-
130131
###### Parameters
131132

132-
* `options` (`Array<string>` or `string`, default: `['mdx', 'md']`)
133-
— allowed file extension(s)
133+
* `options` ([`Extensions`][api-extensions] or [`Options`][api-options],
134+
optional)
135+
— configuration
134136

135137
###### Returns
136138

137139
Transform ([`Transformer` from `unified`][github-unified-transformer]).
138140

141+
### `Extensions`
142+
143+
File extension(s) (TypeScript type).
144+
145+
###### Type
146+
147+
```ts
148+
type Extensions = Array<string> | string
149+
```
150+
151+
### `Options`
152+
153+
Configuration (TypeScript type).
154+
155+
###### Fields
156+
157+
* `allowExtensionless` (`boolean`, default: `true`)
158+
— allow no file extension such as `AUTHORS` or `LICENSE`
159+
* `extensions` ([`Extensions`][api-extensions], default: `['mdx', 'md']`)
160+
— allowed file extension(s)
161+
139162
## Recommendation
140163
141164
Use `md` as it’s the most common.
@@ -151,12 +174,28 @@ Do not use `md` for MDX: use `mdx` instead.
151174
152175
No messages.
153176
177+
##### `readme.mdx`
178+
179+
###### Out
180+
181+
No messages.
182+
154183
##### `readme`
155184
156185
###### Out
157186
158187
No messages.
159188
189+
##### `readme`
190+
191+
When configured with `{ allowExtensionless: false }`.
192+
193+
###### Out
194+
195+
```text
196+
1:1: Incorrect extension: use `mdx` or `md`
197+
```
198+
160199
##### `readme.mkd`
161200
162201
###### Out
@@ -173,6 +212,14 @@ When configured with `'mkd'`.
173212
174213
No messages.
175214
215+
##### `readme.mkd`
216+
217+
When configured with `[ 'mkd' ]`.
218+
219+
###### Out
220+
221+
No messages.
222+
176223
## Compatibility
177224
178225
Projects maintained by the unified collective are compatible with maintained
@@ -198,6 +245,10 @@ abide by its terms.
198245
199246
[MIT][file-license] © [Titus Wormer][author]
200247
248+
[api-extensions]: #extensions
249+
250+
[api-options]: #options
251+
201252
[api-remark-lint-file-extension]: #unifieduseremarklintfileextension-options
202253
203254
[author]: https://wooorm.com

0 commit comments

Comments
 (0)
Please sign in to comment.