Skip to content

Commit a662be1

Browse files
wooormremcohaszing
andcommitted
Fix types of classic, automatic runtime
Co-authored-by: Remco Haszing <[email protected]>
1 parent 9b5ebe5 commit a662be1

27 files changed

+422
-37
lines changed

.gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
.DS_Store
2-
*.d.ts
32
*.log
43
coverage/
54
node_modules/
65
test/jsx-*.js
76
yarn.lock
7+
**/*.d.ts
8+
!lib/jsx-classic.d.ts
9+
!lib/jsx-automatic.d.ts

html.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/**
2+
* @typedef {import('./lib/index.js').Child} Child Acceptable child value
3+
* @typedef {import('./lib/index.js').Properties} Properties Acceptable properties value.
4+
*/
5+
6+
export {h} from './lib/html.js'

html/jsx-runtime.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/**
2+
* @typedef {import('../lib/runtime.js').JSXProps}} JSXProps
3+
*/
4+
5+
export * from '../lib/runtime-html.js'

index.js

+5
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
1+
/**
2+
* @typedef {import('./lib/index.js').Child} Child Acceptable child value
3+
* @typedef {import('./lib/index.js').Properties} Properties Acceptable properties value.
4+
*/
5+
16
export {h, s} from './lib/index.js'

jsx-runtime.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/**
2+
* @typedef {import('./lib/runtime.js').JSXProps}} JSXProps
3+
*/
4+
5+
export * from './lib/runtime-html.js'

lib/core.js

+16-18
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
/**
2-
* @typedef {import('hast').Root} HastRoot
3-
* @typedef {import('hast').Element} HastElement
2+
* @typedef {import('hast').Root} Root
3+
* @typedef {import('hast').Element} Element
44
* @typedef {import('hast').Properties} Properties
5-
* @typedef {HastRoot['children'][number]} HastChild
6-
* @typedef {import('property-information').html['property'][string]} Info
7-
* @typedef {typeof import('property-information').html} Schema
8-
*/
9-
10-
/**
11-
* @typedef {HastRoot|HastElement} HResult
5+
* @typedef {Root['children'][number]} Child
6+
* @typedef {Child|Root} Node
7+
* @typedef {import('property-information').Info} Info
8+
* @typedef {import('property-information').Schema} Schema
9+
*
10+
* @typedef {Root|Element} HResult
1211
* @typedef {string|number} HStyleValue
1312
* @typedef {Object.<string, HStyleValue>} HStyle
1413
* @typedef {string|number|boolean|null|undefined} HPrimitiveValue
@@ -17,9 +16,8 @@
1716
* @typedef {{[property: string]: HPropertyValue|HStyle}} HProperties
1817
*
1918
* @typedef {string|number|null|undefined} HPrimitiveChild
20-
* @typedef {HastChild|HastRoot} HNodeChild
21-
* @typedef {Array.<HPrimitiveChild|HNodeChild>} HArrayChild
22-
* @typedef {HPrimitiveChild|HNodeChild|HArrayChild} HChild
19+
* @typedef {Array.<Node|HPrimitiveChild>} HArrayChild
20+
* @typedef {Node|HPrimitiveChild|HArrayChild} HChild
2321
*/
2422

2523
import {find, normalize} from 'property-information'
@@ -42,10 +40,10 @@ export function core(schema, defaultTagName, caseSensitive) {
4240
const h =
4341
/**
4442
* @type {{
45-
* (): HastRoot
46-
* (selector: null|undefined, ...children: HChild[]): HastRoot
47-
* (selector: string, properties: HProperties, ...children: HChild[]): HastElement
48-
* (selector: string, ...children: HChild[]): HastElement
43+
* (): Root
44+
* (selector: null|undefined, ...children: HChild[]): Root
45+
* (selector: string, properties: HProperties, ...children: HChild[]): Element
46+
* (selector: string, ...children: HChild[]): Element
4947
* }}
5048
*/
5149
(
@@ -59,7 +57,7 @@ export function core(schema, defaultTagName, caseSensitive) {
5957
*/
6058
function (selector, properties, ...children) {
6159
var index = -1
62-
/** @type {HResult|HastElement} */
60+
/** @type {HResult} */
6361
var node
6462
/** @type {string} */
6563
var key
@@ -202,7 +200,7 @@ function addProperty(schema, properties, key, value) {
202200
}
203201

204202
/**
205-
* @param {Array.<HastChild>} nodes
203+
* @param {Array.<Child>} nodes
206204
* @param {HChild} value
207205
* @returns {void}
208206
*/

lib/html.js

+10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
/**
2+
* @typedef {import('./core.js').HChild} Child Acceptable child value
3+
* @typedef {import('./core.js').HProperties} Properties Acceptable properties value.
4+
*
5+
* @typedef {import('./jsx-classic').Element} h.JSX.Element
6+
* @typedef {import('./jsx-classic').IntrinsicAttributes} h.JSX.IntrinsicAttributes
7+
* @typedef {import('./jsx-classic').IntrinsicElements} h.JSX.IntrinsicElements
8+
* @typedef {import('./jsx-classic').ElementChildrenAttribute} h.JSX.ElementChildrenAttribute
9+
*/
10+
111
import {html} from 'property-information'
212
import {core} from './core.js'
313

lib/index.js

+5
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
1+
/**
2+
* @typedef {import('./core.js').HChild} Child Acceptable child value
3+
* @typedef {import('./core.js').HProperties} Properties Acceptable properties value.
4+
*/
5+
16
export {h} from './html.js'
27
export {s} from './svg.js'

lib/jsx-automatic.d.ts

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import {HProperties, HChild, HResult} from './core.js'
2+
3+
export namespace JSX {
4+
/**
5+
* This defines the return value of JSX syntax.
6+
*/
7+
type Element = HResult
8+
9+
/**
10+
* This disallows the use of functional components.
11+
*/
12+
type IntrinsicAttributes = never
13+
14+
/**
15+
* This defines the prop types for known elements.
16+
*
17+
* For `hastscript` this defines any string may be used in combination with `hast` `Properties`.
18+
*
19+
* This **must** be an interface.
20+
*/
21+
// eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style
22+
interface IntrinsicElements {
23+
[name: string]:
24+
| HProperties
25+
| {
26+
/**
27+
* The prop that matches `ElementChildrenAttribute` key defines the type of JSX children, defines the children type.
28+
*/
29+
children?: HChild
30+
}
31+
}
32+
33+
/**
34+
* The key of this interface defines as what prop children are passed.
35+
*/
36+
interface ElementChildrenAttribute {
37+
/**
38+
* Only the key matters, not the value.
39+
*/
40+
children?: never
41+
}
42+
}

lib/jsx-automatic.js

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Empty (only used for TypeScript).
2+
export {}

lib/jsx-classic.d.ts

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import {HProperties, HChild, HResult} from './core.js'
2+
3+
/**
4+
* This unique symbol is declared to specify the key on which JSX children are passed, without conflicting
5+
* with the Attributes type.
6+
*/
7+
declare const children: unique symbol
8+
9+
/**
10+
* This defines the return value of JSX syntax.
11+
*/
12+
export type Element = HResult
13+
14+
/**
15+
* This disallows the use of functional components.
16+
*/
17+
export type IntrinsicAttributes = never
18+
19+
/**
20+
* This defines the prop types for known elements.
21+
*
22+
* For `hastscript` this defines any string may be used in combination with `hast` `Properties`.
23+
*
24+
* This **must** be an interface.
25+
*/
26+
// eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style
27+
export interface IntrinsicElements {
28+
[name: string]:
29+
| HProperties
30+
| {
31+
/**
32+
* The prop that matches `ElementChildrenAttribute` key defines the type of JSX children, defines the children type.
33+
*/
34+
[children]?: HChild
35+
}
36+
}
37+
38+
/**
39+
* The key of this interface defines as what prop children are passed.
40+
*/
41+
export interface ElementChildrenAttribute {
42+
/**
43+
* Only the key matters, not the value.
44+
*/
45+
[children]?: never
46+
}

lib/jsx-classic.js

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Empty (only used for TypeScript).
2+
export {}

lib/runtime-html.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1+
// Export `JSX` as a global for TypeScript.
2+
export * from './jsx-automatic.js'
13
import {runtime} from './runtime.js'
24
import {h} from './html.js'
3-
45
export const {Fragment, jsx, jsxs} = runtime(h)

lib/runtime-svg.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1+
// Export `JSX` as a global for TypeScript.
2+
export * from './jsx-automatic.js'
13
import {runtime} from './runtime.js'
24
import {s} from './svg.js'
3-
45
export const {Fragment, jsx, jsxs} = runtime(s)

lib/runtime.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
2-
* @typedef {import('./core.js').HastElement} HastElement
3-
* @typedef {import('./core.js').HastRoot} HastRoot
2+
* @typedef {import('./core.js').Element} Element
3+
* @typedef {import('./core.js').Root} Root
44
* @typedef {import('./core.js').HResult} HResult
55
* @typedef {import('./core.js').HChild} HChild
66
* @typedef {import('./core.js').HProperties} HProperties
@@ -18,8 +18,8 @@ export function runtime(f) {
1818
const jsx =
1919
/**
2020
* @type {{
21-
* (type: null|undefined, props: {children?: HChild}, key?: string): HastRoot
22-
* (type: string, props: JSXProps, key?: string): HastElement
21+
* (type: null|undefined, props: {children?: HChild}, key?: string): Root
22+
* (type: string, props: JSXProps, key?: string): Element
2323
* }}
2424
*/
2525
(

lib/svg.js

+10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
/**
2+
* @typedef {import('./core.js').HChild} Child Acceptable child value
3+
* @typedef {import('./core.js').HProperties} Properties Acceptable properties value.
4+
*
5+
* @typedef {import('./jsx-classic').Element} s.JSX.Element
6+
* @typedef {import('./jsx-classic').IntrinsicAttributes} s.JSX.IntrinsicAttributes
7+
* @typedef {import('./jsx-classic').IntrinsicElements} s.JSX.IntrinsicElements
8+
* @typedef {import('./jsx-classic').ElementChildrenAttribute} s.JSX.ElementChildrenAttribute
9+
*/
10+
111
import {svg} from 'property-information'
212
import {core} from './core.js'
313
import {svgCaseSensitiveTagNames} from './svg-case-sensitive-tag-names.js'

package.json

+16-9
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,27 @@
2929
],
3030
"sideEffects": false,
3131
"type": "module",
32-
"main": "lib/index.js",
33-
"types": "lib/index.d.ts",
32+
"main": "index.js",
33+
"types": "index.d.ts",
3434
"exports": {
3535
".": "./index.js",
3636
"./index.js": "./index.js",
37-
"./html.js": "./lib/html.js",
38-
"./svg.js": "./lib/svg.js",
39-
"./jsx-runtime": "./lib/runtime-html.js",
40-
"./html/jsx-runtime": "./lib/runtime-html.js",
41-
"./svg/jsx-runtime": "./lib/runtime-svg.js"
37+
"./html.js": "./html.js",
38+
"./svg.js": "./svg.js",
39+
"./jsx-runtime": "./jsx-runtime.js",
40+
"./html/jsx-runtime": "./html/jsx-runtime.js",
41+
"./svg/jsx-runtime": "./svg/jsx-runtime.js"
4242
},
4343
"files": [
44-
"!lib/index.test-d.ts",
4544
"lib/",
45+
"html/",
46+
"svg/",
47+
"html.d.ts",
48+
"html.js",
49+
"svg.d.ts",
50+
"svg.js",
51+
"jsx-runtime.d.ts",
52+
"jsx-runtime.js",
4653
"index.d.ts",
4754
"index.js"
4855
],
@@ -78,7 +85,7 @@
7885
},
7986
"scripts": {
8087
"prepack": "npm run build && npm run format",
81-
"build": "rimraf \"{lib/**,test/**,script/**,}*.d.ts\" && tsc && tsd && type-coverage",
88+
"build": "rimraf \"{script/**,test/**,}*.d.ts\" \"lib/{core,html,index,runtime-html,runtime-svg,runtime,svg-case-sensitive-tag-names,svg}.d.ts\" && tsc && tsd && type-coverage",
8289
"generate": "node script/generate-jsx && node script/build",
8390
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix",
8491
"test-api": "node test/index.js",

svg.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/**
2+
* @typedef {import('./lib/index.js').Child} Child Acceptable child value
3+
* @typedef {import('./lib/index.js').Properties} Properties Acceptable properties value.
4+
*/
5+
6+
export {s} from './lib/svg.js'

svg/jsx-runtime.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/**
2+
* @typedef {import('../lib/runtime.js').JSXProps}} JSXProps
3+
*/
4+
5+
export * from '../lib/runtime-svg.js'

test-d/automatic-h.tsx

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/* @jsxRuntime automatic */
2+
/* @jsxImportSource .. */
3+
4+
import {expectType, expectError} from 'tsd'
5+
import {Root, Element} from 'hast'
6+
import {h} from '../index.js'
7+
import {Fragment, jsx, jsxs} from '../jsx-runtime.js'
8+
9+
type Result = Element | Root
10+
11+
// JSX automatic runtime.
12+
expectType<Root>(jsx(Fragment, {}))
13+
expectType<Root>(jsx(Fragment, {children: h('h')}))
14+
expectType<Element>(jsx('a', {}))
15+
expectType<Element>(jsx('a', {children: 'a'}))
16+
expectType<Element>(jsx('a', {children: h('h')}))
17+
expectType<Element>(jsxs('a', {children: ['a', 'b']}))
18+
expectType<Element>(jsxs('a', {children: [h('x'), h('y')]}))
19+
20+
expectType<Result>(<></>)
21+
expectType<Result>(<a />)
22+
expectType<Result>(<a b="c" />)
23+
expectType<Result>(<a b={'c'} />)
24+
expectType<Result>(<a>string</a>)
25+
expectType<Result>(<a>{['string', 'string']}</a>)
26+
expectType<Result>(
27+
<a>
28+
<></>
29+
</a>
30+
)
31+
expectType<Result>(<a>{h()}</a>)
32+
expectType<Result>(<a>{h('b')}</a>)
33+
expectType<Result>(
34+
<a>
35+
<b />c
36+
</a>
37+
)
38+
expectType<Result>(
39+
<a>
40+
<b />
41+
<c />
42+
</a>
43+
)
44+
expectType<Result>(<a>{[<b />, <c />]}</a>)
45+
expectType<Result>(<a>{[<b />, <c />]}</a>)
46+
expectType<Result>(<a>{[]}</a>)
47+
48+
expectError(<a invalid={[true]} />)
49+
50+
// This is where the automatic runtime differs from the classic runtime.
51+
// The automatic runtime the children prop to define JSX children, whereas it’s used as an attribute in the classic runtime.
52+
expectType<Result>(<a children={<b />} />)
53+
54+
declare function Bar(props?: Record<string, unknown>): Element
55+
expectError(<Bar />)

0 commit comments

Comments
 (0)