11'use strict' ;
22
3+ import { createTypeAnnotationHandler } from '@doc-kit/core/plugins/type-annotations/highlighter.mjs' ;
34import { toJsxRuntime } from 'hast-util-to-jsx-runtime' ;
45import { renderToString } from 'preact-render-to-string' ;
56import { Fragment , jsx , jsxs } from 'preact/jsx-runtime' ;
@@ -38,21 +39,33 @@ const render = children =>
3839 ) ;
3940
4041/**
41- * Turns the `<code>` of highlighted code into a JSX `<code>` holding its
42- * markup as it is.
42+ * The attributes and the markup of the `<code>` of highlighted code.
4343 *
4444 * @param {import('hast').Element } code - The `<code>`
45+ * @returns {{ attributes: Record<string, unknown>, html: string } }
46+ */
47+ const toMarkup = ( {
48+ properties : { class : className , ...properties } ,
49+ children,
50+ } ) => ( {
51+ attributes : {
52+ className : [ className ] . flat ( ) . join ( ' ' ) || undefined ,
53+ ...properties ,
54+ } ,
55+ html : render ( children ) ,
56+ } ) ;
57+
58+ /**
59+ * A JSX `<code>` holding highlighted markup as it is.
60+ *
61+ * @param {ReturnType<typeof toMarkup> } markup
4562 * @param {boolean } [inline] - Whether it's a type's, rather than a block's
4663 */
47- const embedCode = (
48- { properties : { class : className , ...properties } , children } ,
49- inline = false
50- ) =>
64+ const createCodeElement = ( { attributes, html } , inline = false ) =>
5165 createJSXElement ( 'code' , {
5266 inline,
53- className : [ className ] . flat ( ) . join ( ' ' ) || undefined ,
54- ...properties ,
55- dangerouslySetInnerHTML : { __html : render ( children ) } ,
67+ ...attributes ,
68+ dangerouslySetInnerHTML : { __html : html } ,
5669 } ) ;
5770
5871/**
@@ -68,7 +81,7 @@ export const embedHighlightedBlocks = tree => {
6881
6982 if ( node . tagName === 'pre' && code ?. tagName === 'code' ) {
7083 if ( isHighlighted ( node ) ) {
71- node . children [ 0 ] = embedCode ( code ) ;
84+ node . children [ 0 ] = createCodeElement ( toMarkup ( code ) ) ;
7285 }
7386
7487 return SKIP ;
@@ -79,25 +92,46 @@ export const embedHighlightedBlocks = tree => {
7992} ;
8093
8194/**
82- * Wraps a `typeAnnotation` handler of `remark-rehype`, embedding the types it
83- * highlights.
95+ * Creates the `typeAnnotation` handler of `remark-rehype` highlighting types
96+ * and embedding them.
97+ *
98+ * Every highlighted type is kept, by highlighter: the same few hundred types
99+ * are highlighted thousands of times, `{string}` alone on most pages.
84100 *
85- * @param {(state: import('mdast-util-to-hast ').State, node: import('mdast').Node) => import('hast').Element } handler
86- * @returns {typeof handler }
101+ * @param {() => import('@doc-kit/core/plugins/shiki/highlighter.mjs ').SyntaxHighlighter } getHighlighter - Gives the highlighter, once a type is highlighted
102+ * @returns {(state: import('mdast-util-to-hast').State, node: import('mdast').Node) => import('hast').ElementContent }
87103 */
88- export const embedHighlightedTypes = handler => ( state , node ) => {
89- const result = handler ( state , node ) ;
104+ export const embedHighlightedTypes = getHighlighter => {
105+ const highlight = createTypeAnnotationHandler ( getHighlighter ) ;
106+ const highlighted = new WeakMap ( ) ;
90107
91- // A type that didn't parse, or links nowhere, isn't highlighted
92- if ( ! isHighlighted ( result ) ) {
93- return result ;
94- }
108+ return ( state , node ) => {
109+ const highlighter = getHighlighter ( ) ;
110+
111+ if ( ! highlighted . has ( highlighter ) ) {
112+ highlighted . set ( highlighter , new Map ( ) ) ;
113+ }
114+
115+ const types = highlighted . get ( highlighter ) ;
116+ const key = JSON . stringify ( [ node . value , node . data ] ) ;
117+
118+ if ( ! types . has ( key ) ) {
119+ const result = highlight ( state , node ) ;
120+
121+ // A type that didn't parse, or links nowhere, isn't highlighted
122+ if ( ! isHighlighted ( result ) ) {
123+ return result ;
124+ }
125+
126+ types . set ( key , toMarkup ( result ) ) ;
127+ }
95128
96- const code = embedCode ( result , true ) ;
129+ const code = createCodeElement ( types . get ( key ) , true ) ;
97130
98- state . patch ( node , code ) ;
131+ state . patch ( node , code ) ;
99132
100- return code ;
133+ return code ;
134+ } ;
101135} ;
102136
103137/**
0 commit comments