Skip to content

Commit a44db46

Browse files
committed
Add Data, Settings types to augment shared data
1 parent 40f0329 commit a44db46

File tree

6 files changed

+80
-10
lines changed

6 files changed

+80
-10
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ node_modules/
55
*.log
66
yarn.lock
77
!/index.d.ts
8+
!/test/types.d.ts

index.d.ts

+55
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export type {
77
Compiler,
88
CompilerClass,
99
CompilerFunction,
10+
// `Data` is typed and exposed below.
1011
Pluggable,
1112
PluggableList,
1213
Plugin,
@@ -18,6 +19,7 @@ export type {
1819
ProcessCallback,
1920
Processor,
2021
RunCallback,
22+
// `Settings` is typed and exposed below.
2123
TransformCallback,
2224
Transformer
2325
} from './lib/index.js'
@@ -40,6 +42,8 @@ export {unified} from './lib/index.js'
4042
* ReactNode: ReactNode
4143
* }
4244
* }
45+
*
46+
* export {} // You may not need this, but it makes sure the file is a module.
4347
* ```
4448
*
4549
* Use {@link CompileResults `CompileResults`} to access the values.
@@ -49,3 +53,54 @@ export interface CompileResultMap {
4953
Uint8Array: Uint8Array
5054
string: string
5155
}
56+
57+
/**
58+
* Interface of known data that can be supported by all plugins.
59+
*
60+
* Typically, options can be given to a specific plugin, but sometimes it makes
61+
* sense to have information shared with several plugins.
62+
* For example, a list of HTML elements that are self-closing, which is needed
63+
* during all phases.
64+
*
65+
* To type this, do something like:
66+
*
67+
* ```ts
68+
* declare module 'unified' {
69+
* interface Data {
70+
* htmlVoidElements?: Array<string> | undefined
71+
* }
72+
* }
73+
*
74+
* export {} // You may not need this, but it makes sure the file is a module.
75+
* ```
76+
*/
77+
export interface Data {
78+
settings?: Settings | undefined
79+
}
80+
81+
/**
82+
* Interface of known extra options, that can be supported by parser and
83+
* compilers.
84+
*
85+
* This exists so that users can use packages such as `remark`, which configure
86+
* both parsers and compilers (in this case `remark-parse` and
87+
* `remark-stringify`), and still provide options for them.
88+
*
89+
* When you make parsers or compilers, that could be packaged up together,
90+
* you should support `this.data('settings')` as input and merge it with
91+
* explicitly passed `options`.
92+
* Then, to type it, using `remark-stringify` as an example, do something like:
93+
*
94+
* ```ts
95+
* declare module 'unified' {
96+
* interface Settings {
97+
* bullet: '*' | '+' | '-'
98+
* // …
99+
* }
100+
* }
101+
*
102+
* export {} // You may not need this, but it makes sure the file is a module.
103+
* ```
104+
*/
105+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
106+
export interface Settings {}

lib/index.js

+12-9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* @typedef {import('vfile').VFileValue} VFileValue
88
*
99
* @typedef {import('../index.js').CompileResultMap} CompileResultMap
10+
* @typedef {import('../index.js').Data} Data
1011
*/
1112

1213
/**
@@ -518,7 +519,7 @@ export class Processor extends CallableInstance {
518519
*
519520
* @deprecated
520521
* This is a private internal property and should not be used.
521-
* @type {{settings?: Record<string, unknown>} & Record<string, unknown>}
522+
* @type {Data}
522523
*/
523524
this.namespace = {}
524525

@@ -573,26 +574,28 @@ export class Processor extends CallableInstance {
573574
* > 👉 **Note**: setting information cannot occur on *frozen* processors.
574575
* > Call the processor first to create a new unfrozen processor.
575576
*
577+
* @template {keyof Data} Key
578+
*
576579
* @overload
577-
* @returns {Record<string, unknown>}
580+
* @returns {Data}
578581
*
579582
* @overload
580-
* @param {Record<string, unknown>} dataset
583+
* @param {Data} dataset
581584
* @returns {Processor<ParseTree, HeadTree, TailTree, CompileTree, CompileResult>}
582585
*
583586
* @overload
584-
* @param {string} key
585-
* @returns {unknown}
587+
* @param {Key} key
588+
* @returns {Data[Key]}
586589
*
587590
* @overload
588-
* @param {string} key
589-
* @param {unknown} value
591+
* @param {Key} key
592+
* @param {Data[Key]} value
590593
* @returns {Processor<ParseTree, HeadTree, TailTree, CompileTree, CompileResult>}
591594
*
592-
* @param {Record<string, unknown> | string} [key]
595+
* @param {Data | Key} [key]
593596
* Key to get or set, or entire dataset to set, or nothing to get the
594597
* entire dataset (optional).
595-
* @param {unknown} [value]
598+
* @param {Data[Key]} [value]
596599
* Value to set (optional).
597600
* @returns {unknown}
598601
* The processor that `data` is called on when settings, the value at `key`

test/data.js

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ test('`data`', async function (t) {
1818
})
1919

2020
await t.test('should not yield data prototypal fields', async function () {
21+
// @ts-expect-error: `toString` is not a typed key of `Data`.
22+
// But it exists on objects, so we test that here.
2123
assert.equal(unified().data('toString'), undefined)
2224
})
2325

test/types.d.ts

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
declare module 'unified' {
2+
interface Data {
3+
baz?: 'qux' | undefined
4+
foo?: 'bar' | undefined
5+
x?: boolean | undefined
6+
}
7+
}
8+
9+
export {} // You may not need this, but it makes sure the file is a module.

tsconfig.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@
1111
"target": "es2020"
1212
},
1313
"exclude": ["coverage/", "node_modules/"],
14-
"include": ["**/*.js", "index.d.ts"]
14+
"include": ["**/*.js", "test/types.d.ts", "index.d.ts"]
1515
}

0 commit comments

Comments
 (0)