From 73d2f25510278a9ec681a169c6cdc4628f8d74fa Mon Sep 17 00:00:00 2001 From: Remco Haszing Date: Sat, 31 Oct 2020 12:57:16 +0100 Subject: [PATCH 01/10] Add JSX support in type definition --- types/index.d.ts | 51 +++++++++++++++++++++++++++++++++---- types/{test.ts => test.tsx} | 38 +++++++++++++++++++++++++++ types/tsconfig.json | 1 + 3 files changed, 85 insertions(+), 5 deletions(-) rename types/{test.ts => test.tsx} (55%) diff --git a/types/index.d.ts b/types/index.d.ts index 9bfa1ed..6834147 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,8 +1,8 @@ // TypeScript Version: 3.7 -import {Attributes, Element, Node} from 'xast' +import * as xast from 'xast' -type Children = string | Node | Children[] +type Children = string | xast.Node | Children[] /** * Create XML trees in xast. @@ -10,7 +10,7 @@ type Children = string | Node | Children[] * @param name Qualified name. Case sensitive and can contain a namespace prefix (such as rdf:RDF). * @param children (Lists of) child nodes. When strings are encountered, they are mapped to Text nodes. */ -declare function xastscript(name: string, ...children: Children[]): Element +declare function xastscript(name: string, ...children: Children[]): xast.Element /** * Create XML trees in xast. @@ -21,8 +21,49 @@ declare function xastscript(name: string, ...children: Children[]): Element */ declare function xastscript( name: string, - attributes?: Attributes, + attributes?: xast.Attributes, ...children: Children[] -): Element +): xast.Element + +/** + * This namespace allows to use `xastscript` as a JSX implementation. + * + * This namespace is only used to support the use as JSX. It’s **not** intended for direct usage. + */ +declare namespace xastscript.JSX { + /** + * This defines the return value of JSX syntax. + */ + type Element = xast.Element + + /** + * This disallows the use of + */ + type IntrinsicAttributes = never + + /** + * This defines the prop types for known elements. + * + * For `xastscript` this defines any string may be used in combination with `xast` `Attributes`. + */ + interface IntrinsicElements { + [key: string]: xast.Attributes & { + /** + * The prop that matches `ElementChildrenAttribute` key defines the type of JSX children, defines the children type. + */ + ''?: Children + } + } + + /** + * The key of this interface defines as what prop children are passed. + */ + interface ElementChildrenAttribute { + /** + * Only the key matters, not the value. + */ + '': never + } +} export = xastscript diff --git a/types/test.ts b/types/test.tsx similarity index 55% rename from types/test.ts rename to types/test.tsx index 2965c93..3a3f6d2 100644 --- a/types/test.ts +++ b/types/test.tsx @@ -1,3 +1,6 @@ +/** @jsx x */ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import {Attributes, Element} from 'xast' import x = require('xastscript') x('urlset') // $ExpectType Element @@ -20,6 +23,41 @@ x('urlset', {xmlns}, x('loc'), x('loc')) // $ExpectType Element x('urlset', {xmlns}, [x('loc'), x('loc')]) // $ExpectType Element x('urlset', {xmlns}, []) // $ExpectType Element +// $ExpectType Element +const jsx0 = +// $ExpectType Element +const jsx1 = +// $ExpectType Element +const jsx2 = string +// $ExpectType Element +const jsx3 = {['string', 'string']} +// $ExpectType Element +const jsx4 = ( + + + string + +) +// $ExpectType Element +const jsx5 = ( + + + +) +// $ExpectType Element +const jsx6 = ( + + + + +) +// $ExpectType Element +const jsx7 = {[, ]} +// $ExpectType Element +const jsx8 = {[]} + +declare function Bar(props?: Attributes): Element +const bar = // $ExpectError x() // $ExpectError x(false) // $ExpectError x('urlset', x('loc'), {xmlns}) // $ExpectError diff --git a/types/tsconfig.json b/types/tsconfig.json index bb008c0..77bca49 100644 --- a/types/tsconfig.json +++ b/types/tsconfig.json @@ -1,6 +1,7 @@ { "compilerOptions": { "module": "commonjs", + "jsx": "react", "lib": ["es2015"], "noImplicitAny": true, "noImplicitThis": true, From 15f0f1703a65e1e5b56bc41c1c08437dada94e80 Mon Sep 17 00:00:00 2001 From: Remco Haszing Date: Mon, 23 Nov 2020 22:12:05 +0100 Subject: [PATCH 02/10] Revert unrelated change --- types/index.d.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/types/index.d.ts b/types/index.d.ts index e928ded..c8cef98 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -9,10 +9,7 @@ type Primitive = null | undefined | string | number /** * Extending Attributes to Support JS Primitive Types */ -// eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style -interface Attributes { - [attribute: string]: Primitive -} +type Attributes = Record /** * Create XML trees in xast. From 90d92567b4ac4338d2c5065ea66d04b85e99bea0 Mon Sep 17 00:00:00 2001 From: Remco Haszing Date: Mon, 23 Nov 2020 22:12:57 +0100 Subject: [PATCH 03/10] Finish unfinished sentence in jsdoc --- types/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/index.d.ts b/types/index.d.ts index c8cef98..59a9e03 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -58,7 +58,7 @@ declare namespace xastscript.JSX { type Element = xast.Element /** - * This disallows the use of + * This disallows the use of functional components. */ type IntrinsicAttributes = never From 36efe3bd4aa8cc719767ddb9829ac7fea1ef1c80 Mon Sep 17 00:00:00 2001 From: Remco Haszing Date: Mon, 23 Nov 2020 22:17:06 +0100 Subject: [PATCH 04/10] Use namespace imports to import xastscript in TypeScript --- types/test-jsx.tsx | 2 +- types/test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/types/test-jsx.tsx b/types/test-jsx.tsx index 97aa75e..52c17ed 100644 --- a/types/test-jsx.tsx +++ b/types/test-jsx.tsx @@ -1,5 +1,5 @@ import {Element} from 'xast' -import x = require('xastscript') +import * as x from 'xastscript' const xmlns = 'http://www.sitemaps.org/schemas/sitemap/0.9' diff --git a/types/test.ts b/types/test.ts index 524b9f5..437a9f6 100644 --- a/types/test.ts +++ b/types/test.ts @@ -1,4 +1,4 @@ -import x = require('xastscript') +import * as x from 'xastscript' x('urlset') // $ExpectType Element x('urlset', 'string') // $ExpectType Element From dbe6ead15b5e9319205552497643feef1af043da Mon Sep 17 00:00:00 2001 From: Remco Haszing Date: Mon, 23 Nov 2020 22:21:43 +0100 Subject: [PATCH 05/10] Document usage of JSX with TypeScript --- readme.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/readme.md b/readme.md index 96098b5..e020cd4 100644 --- a/readme.md +++ b/readme.md @@ -231,6 +231,19 @@ var x = require('xastscript') console.log() ``` +For [TypeScript][], this can be done by setting `"jsx": "react"` and +`"jsxFactory": "x"` in the compiler options. Fragments are not supported in +TypeScript. + +TypeScript also lets you configure this in a script: + +```tsx +/** @jsx x */ +import * as x from 'xastscript' + +console.log() +``` + ## Security XML can be a dangerous language: don’t trust user-provided data. @@ -327,3 +340,5 @@ abide by its terms. [babel]: https://github.com/babel/babel [babel-jsx]: https://github.com/babel/babel/tree/main/packages/babel-plugin-transform-react-jsx + +[typescript]: https://www.typescriptlang.org From b2d187ad6df68136831a3a077353f6ed533b3208 Mon Sep 17 00:00:00 2001 From: Remco Haszing Date: Mon, 23 Nov 2020 22:35:55 +0100 Subject: [PATCH 06/10] Fix jsx Element type assertions --- types/test-jsx.tsx | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/types/test-jsx.tsx b/types/test-jsx.tsx index 52c17ed..901787c 100644 --- a/types/test-jsx.tsx +++ b/types/test-jsx.tsx @@ -3,44 +3,34 @@ import * as x from 'xastscript' const xmlns = 'http://www.sitemaps.org/schemas/sitemap/0.9' -let jsx -// $ExpectType Element +let jsx: Element jsx = -// $ExpectType Element jsx = -// $ExpectType Element jsx = string -// $ExpectType Element jsx = {['string', 'string']} -// $ExpectType Element jsx = ( ) -// $ExpectType Element jsx = ( string ) -// $ExpectType Element jsx = ( ) -// $ExpectType Element jsx = ( ) -// $ExpectType Element jsx = {[, ]} -// $ExpectType Element jsx = {[]} jsx = // $ExpectError From 7ccd65a5a78648c1919d2c29069fd3eef4077177 Mon Sep 17 00:00:00 2001 From: Remco Haszing Date: Tue, 24 Nov 2020 09:20:17 +0100 Subject: [PATCH 07/10] Update types/index.d.ts Co-authored-by: Titus --- types/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/index.d.ts b/types/index.d.ts index 59a9e03..3a65df3 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -41,7 +41,7 @@ declare function xastscript( ): xast.Element /** - * This unique symbol is declared to specify they key on which JSX children are passed, without conflicting + * This unique symbol is declared to specify the key on which JSX children are passed, without conflicting * with the Attributes type. */ declare const children: unique symbol From 0eb0d4f2122a68163e48bd85a807e74f5f22117f Mon Sep 17 00:00:00 2001 From: Remco Haszing Date: Tue, 24 Nov 2020 09:24:49 +0100 Subject: [PATCH 08/10] Add link to TypeScript JSX documentation --- readme.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index e020cd4..4ab075e 100644 --- a/readme.md +++ b/readme.md @@ -233,7 +233,8 @@ console.log() For [TypeScript][], this can be done by setting `"jsx": "react"` and `"jsxFactory": "x"` in the compiler options. Fragments are not supported in -TypeScript. +TypeScript. For more details on configuring JSX for TypeScript, see the +[TypeScript JSX handbook page][]. TypeScript also lets you configure this in a script: @@ -342,3 +343,5 @@ abide by its terms. [babel-jsx]: https://github.com/babel/babel/tree/main/packages/babel-plugin-transform-react-jsx [typescript]: https://www.typescriptlang.org + +[typescript jsx handbook page]: https://www.typescriptlang.org/docs/handbook/jsx.html From de3f530a09028a2541d5e88c8cc41c7f59816217 Mon Sep 17 00:00:00 2001 From: Remco Haszing Date: Tue, 1 Dec 2020 21:36:04 +0100 Subject: [PATCH 09/10] Add support for Fragments This means the type of `hastscript.JSX.Element` had to be changed to `xast.Element | xast.Root`. This also means a minimum TypeScript version of 4.0 is required to test types. --- readme.md | 7 ++++--- types/index.d.ts | 4 ++-- types/test-jsx.tsx | 8 ++++++-- types/tsconfig.json | 1 + 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/readme.md b/readme.md index 4ab075e..6178401 100644 --- a/readme.md +++ b/readme.md @@ -231,15 +231,16 @@ var x = require('xastscript') console.log() ``` -For [TypeScript][], this can be done by setting `"jsx": "react"` and -`"jsxFactory": "x"` in the compiler options. Fragments are not supported in -TypeScript. For more details on configuring JSX for TypeScript, see the +For [TypeScript][], this can be done by setting `"jsx": "react"`, +`"jsxFactory": "x"`, and `"jsxFragmentFactory": "null"` in the compiler options. +For more details on configuring JSX for TypeScript, see the [TypeScript JSX handbook page][]. TypeScript also lets you configure this in a script: ```tsx /** @jsx x */ +/** @jsxFrag null */ import * as x from 'xastscript' console.log() diff --git a/types/index.d.ts b/types/index.d.ts index 3a65df3..ab001a2 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,4 +1,4 @@ -// TypeScript Version: 3.7 +// TypeScript Version: 4.0 import * as xast from 'xast' @@ -55,7 +55,7 @@ declare namespace xastscript.JSX { /** * This defines the return value of JSX syntax. */ - type Element = xast.Element + type Element = xast.Element | xast.Root /** * This disallows the use of functional components. diff --git a/types/test-jsx.tsx b/types/test-jsx.tsx index 901787c..68dd089 100644 --- a/types/test-jsx.tsx +++ b/types/test-jsx.tsx @@ -1,9 +1,9 @@ -import {Element} from 'xast' +import {Element, Root} from 'xast' import * as x from 'xastscript' const xmlns = 'http://www.sitemaps.org/schemas/sitemap/0.9' -let jsx: Element +let jsx: Element | Root jsx = jsx = jsx = string @@ -32,9 +32,13 @@ jsx = ( ) jsx = {[, ]} jsx = {[]} +jsx = <> jsx = // $ExpectError jsx = {{invalid: 'child'}} // $ExpectError +const element: Element = // $ExpectError +const root: Root = <> // $ExpectError + declare function Bar(props?: Record): Element const bar = // $ExpectError diff --git a/types/tsconfig.json b/types/tsconfig.json index f8cebb3..5d74cc2 100644 --- a/types/tsconfig.json +++ b/types/tsconfig.json @@ -3,6 +3,7 @@ "module": "commonjs", "jsx": "react", "jsxFactory": "x", + "jsxFragmentFactory": "null", "lib": ["es2015"], "noImplicitAny": true, "noImplicitThis": true, From c24b837402b277560f5939bf6cef74b252278f42 Mon Sep 17 00:00:00 2001 From: Remco Haszing Date: Wed, 2 Dec 2020 15:43:38 +0100 Subject: [PATCH 10/10] Change type of ElementChildrenAttribute[children] to never MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It’s value is not supposed to be used. --- types/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/index.d.ts b/types/index.d.ts index ab001a2..a9ed093 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -88,7 +88,7 @@ declare namespace xastscript.JSX { /** * Only the key matters, not the value. */ - [children]?: any + [children]?: never } }