@@ -16,6 +16,7 @@ import {
1616 ReleaseContext ,
1717 ReleasesContext ,
1818} from '#site/providers/releaseProvider' ;
19+ import type { DownloadSnippet } from '#site/types/download' ;
1920import type { ReleaseContextType } from '#site/types/release' ;
2021import { INSTALL_METHODS } from '#site/util/download' ;
2122
@@ -26,80 +27,109 @@ import { INSTALL_METHODS } from '#site/util/download';
2627// by Shiki to render the highlighted syntax. Hence XSS attacks or JavaScript injections are not possible.
2728const interpreter = createSval ( { } , 'script' ) ;
2829
29- const parseSnippet = ( s : string , releaseContext : ReleaseContextType ) => {
30- // Adds the release context to the interpreter context
30+ /**
31+ * Parses a snippet string using the interpreter with the given release context
32+ */
33+ const parseSnippet = ( snippet : string , releaseContext : ReleaseContextType ) => {
3134 interpreter . import ( { props : releaseContext } ) ;
32-
33- // Evaluates the JavaScript code applying the release context to the code
34- interpreter . run ( `exports.content = \`${ s } \`` ) ;
35-
36- // Sets the parsed raw string to be used by the JSX CodeBox
37- return String ( interpreter . exports . content ) ;
35+ interpreter . run ( `exports.content = \`${ snippet } \`` ) ;
36+ return interpreter . exports . content ;
3837} ;
3938
40- const ReleaseCodeBox : FC = ( ) => {
41- const { snippets } = useContext ( ReleasesContext ) ;
39+ /**
40+ * Custom hook to handle snippet processing logic
41+ */
42+ const useSnippetProcessor = (
43+ snippets : Array < DownloadSnippet > ,
44+ context : ReleaseContextType
45+ ) => {
46+ return useMemo ( ( ) => {
47+ // Find relevant snippets
48+ const installMethodSnippet = snippets . find (
49+ ( { name } ) => name === context . installMethod . toLowerCase ( )
50+ ) ;
4251
43- const { installMethod, os, packageManager, release } =
44- useContext ( ReleaseContext ) ;
52+ const packageManagerSnippet = snippets . find (
53+ ( { name } ) => name === context . packageManager . toLowerCase ( )
54+ ) ;
4555
46- const t = useTranslations ( ) ;
56+ // Only process if both snippets are available
57+ if ( ! installMethodSnippet || ! packageManagerSnippet ) {
58+ return '' ;
59+ }
4760
48- // Retrieves the current platform (Dropdown Item) based on the selected platform value
49- const currentPlatform = useMemo (
50- ( ) => INSTALL_METHODS . find ( ( { value } ) => value === installMethod ) ,
51- [ installMethod ]
52- ) ;
61+ const verifyNodeSnippet = snippets . find ( ( { name } ) => name === 'node' ) ;
62+
63+ const installCorepackSnippet =
64+ context . packageManager !== 'NPM' &&
65+ // Corepack is no longer distributed with Node.js v25
66+ context . release . major >= 25 &&
67+ snippets . find ( ( { name } ) => name === 'corepack' ) ;
68+
69+ // Combine and parse snippets
70+ const parsedContent = parseSnippet (
71+ [
72+ installMethodSnippet ,
73+ verifyNodeSnippet ,
74+ installCorepackSnippet ,
75+ packageManagerSnippet ,
76+ ]
77+ . filter ( Boolean )
78+ . map ( snippet => ( snippet as DownloadSnippet ) . content )
79+ . join ( '\n' ) ,
80+ context
81+ ) ;
5382
54- // Parses the snippets based on the selected platform, package manager, and release context
55- const parsedSnippets = useMemo ( ( ) => {
56- // Retrieves a snippet for the given Installation Method (aka Platform)
57- const installMethodSnippet = snippets . find (
58- ( { name } ) => name === installMethod . toLowerCase ( )
83+ // Convert to HTML using Shiki's highlighter
84+ // This is faster than JSX rendering as it avoids React runtime overhead
85+ return highlightToHtml (
86+ parsedContent ,
87+ context . os === 'WIN' ? 'ps1' : 'bash'
5988 ) ;
89+ } , [ snippets , context ] ) ;
90+ } ;
6091
61- // Retrieves a snippet for the given Package Manager to be bundled with the Platform snippet
62- const packageManagerSnippet = snippets . find (
63- ( { name } ) => name === packageManager . toLowerCase ( )
92+ /**
93+ * Custom hook to get current platform information
94+ */
95+ const usePlatformInfo = ( installMethod : string ) => {
96+ return useMemo ( ( ) => {
97+ const platform = INSTALL_METHODS . find (
98+ ( { value } ) => value === installMethod
6499 ) ;
65100
66- // Prevents numerous recalculations of `sval` and `Shiki` when not necessary
67- // As we only want to parse the snippets when both the Platform and Package Manager snippets are available
68- if ( installMethodSnippet && packageManagerSnippet ) {
69- const content = parseSnippet (
70- // Bundles the Platform and Package Manager snippets
71- `${ installMethodSnippet . content } \n${ packageManagerSnippet . content } ` ,
72- // Passes a partial state of only the things we need to the parser
73- { release, os } as ReleaseContextType
74- ) ;
75-
76- // We use Shikis's `hast-util-to-html` to convert the highlighted code into plain HTML (Pretty much using Rehype)
77- // This is actually faster than using `hast-util-to-jsx-runtime` and then rendering the JSX
78- // As it requires React's runtime to interpolate and build these components dynamically
79- // Which also leads to a lot o GC being emitted. (Tested via Profiling)
80- return highlightToHtml ( content , os === 'WIN' ? 'ps1' : 'bash' ) ;
81- }
101+ // Provide defaults for destructuring
102+ return {
103+ label : platform ?. label || '' ,
104+ url : platform ?. url || '' ,
105+ info : platform ?. info || 'layouts.download.codeBox.platformInfo.default' ,
106+ recommended : platform ?. recommended || false ,
107+ exists : ! ! platform ,
108+ } ;
109+ } , [ installMethod ] ) ;
110+ } ;
82111
83- return '' ;
84- // Only change to these specific properties which are relevant for the re-rendering of the CodeBox
85- // eslint-disable-next-line react-hooks/exhaustive-deps
86- } , [ release . versionWithPrefix , installMethod , os , packageManager ] ) ;
112+ /**
113+ * ReleaseCodeBox component displays installation instructions based on platform and context
114+ */
115+ const ReleaseCodeBox : FC = ( ) => {
116+ const { snippets } = useContext ( ReleasesContext ) ;
117+ const context = useContext ( ReleaseContext ) ;
118+ const t = useTranslations ( ) ;
87119
88- // Determines the code language based on the OS
89- const displayName = os === 'WIN' ? 'PowerShell' : 'Bash' ;
120+ // Process platform information
121+ const platformInfo = usePlatformInfo ( context . installMethod ) ;
90122
91- // Determines if the code box should render the skeleton loader
92- const renderSkeleton = os === 'LOADING' || installMethod === '' ;
123+ // Process snippets
124+ const parsedSnippets = useSnippetProcessor ( snippets , context ) ;
93125
94- // Defines fallbacks for the currentPlatform object
95- const {
96- label = '' ,
97- url = '' ,
98- info = 'layouts.download.codeBox.platformInfo.default' ,
99- } = currentPlatform ?? { } ;
126+ // UI state calculations
127+ const displayLanguage = context . os === 'WIN' ? 'PowerShell' : 'Bash' ;
128+ const isLoading = context . os === 'LOADING' || context . installMethod === '' ;
100129
101130 return (
102131 < div className = "mb-6 mt-4 flex flex-col gap-2" >
132+ { /* NoScript warning */ }
103133 < noscript >
104134 < AlertBox
105135 title = { t ( 'components.common.alertBox.warning' ) }
@@ -116,9 +146,11 @@ const ReleaseCodeBox: FC = () => {
116146 </ AlertBox >
117147 </ noscript >
118148
119- < WithReleaseAlertBox status = { release . status } />
149+ { /* Release status alert */ }
150+ < WithReleaseAlertBox status = { context . release . status } />
120151
121- { ! currentPlatform || currentPlatform . recommended || (
152+ { /* Community platform notice */ }
153+ { platformInfo . exists && ! platformInfo . recommended && (
122154 < AlertBox
123155 title = { t ( 'components.common.alertBox.info' ) }
124156 level = "info"
@@ -128,19 +160,21 @@ const ReleaseCodeBox: FC = () => {
128160 </ AlertBox >
129161 ) }
130162
131- < Skeleton loading = { renderSkeleton } >
132- < CodeBox language = { displayName } className = "min-h-[16.5rem]" >
163+ { /* Code display with skeleton loading */ }
164+ < Skeleton loading = { isLoading } >
165+ < CodeBox language = { displayLanguage } className = "min-h-[16.5rem]" >
133166 < code dangerouslySetInnerHTML = { { __html : parsedSnippets } } />
134167 </ CodeBox >
135168 </ Skeleton >
136169
170+ { /* Platform info footer */ }
137171 < span className = "text-center text-xs text-neutral-800 dark:text-neutral-200" >
138- < Skeleton loading = { renderSkeleton } hide = { ! currentPlatform } >
139- { t ( info , { platform : label } ) } { ' ' }
172+ < Skeleton loading = { isLoading } hide = { ! platformInfo . exists } >
173+ { t ( platformInfo . info , { platform : platformInfo . label } ) } { ' ' }
140174 { t . rich ( 'layouts.download.codeBox.externalSupportInfo' , {
141- platform : label ,
175+ platform : platformInfo . label ,
142176 link : text => (
143- < LinkWithArrow href = { url } >
177+ < LinkWithArrow href = { platformInfo . url } >
144178 < b > { text } </ b >
145179 </ LinkWithArrow >
146180 ) ,
0 commit comments