@@ -16,6 +16,7 @@ import {
16
16
ReleaseContext ,
17
17
ReleasesContext ,
18
18
} from '#site/providers/releaseProvider' ;
19
+ import type { DownloadSnippet } from '#site/types/download' ;
19
20
import type { ReleaseContextType } from '#site/types/release' ;
20
21
import { INSTALL_METHODS } from '#site/util/download' ;
21
22
@@ -26,80 +27,109 @@ import { INSTALL_METHODS } from '#site/util/download';
26
27
// by Shiki to render the highlighted syntax. Hence XSS attacks or JavaScript injections are not possible.
27
28
const interpreter = createSval ( { } , 'script' ) ;
28
29
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 ) => {
31
34
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 ;
38
37
} ;
39
38
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
+ ) ;
42
51
43
- const { installMethod, os, packageManager, release } =
44
- useContext ( ReleaseContext ) ;
52
+ const packageManagerSnippet = snippets . find (
53
+ ( { name } ) => name === context . packageManager . toLowerCase ( )
54
+ ) ;
45
55
46
- const t = useTranslations ( ) ;
56
+ // Only process if both snippets are available
57
+ if ( ! installMethodSnippet || ! packageManagerSnippet ) {
58
+ return '' ;
59
+ }
47
60
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
+ ) ;
53
82
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'
59
88
) ;
89
+ } , [ snippets , context ] ) ;
90
+ } ;
60
91
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
64
99
) ;
65
100
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
+ } ;
82
111
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 ( ) ;
87
119
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 ) ;
90
122
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 ) ;
93
125
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 === '' ;
100
129
101
130
return (
102
131
< div className = "mb-6 mt-4 flex flex-col gap-2" >
132
+ { /* NoScript warning */ }
103
133
< noscript >
104
134
< AlertBox
105
135
title = { t ( 'components.common.alertBox.warning' ) }
@@ -116,9 +146,11 @@ const ReleaseCodeBox: FC = () => {
116
146
</ AlertBox >
117
147
</ noscript >
118
148
119
- < WithReleaseAlertBox status = { release . status } />
149
+ { /* Release status alert */ }
150
+ < WithReleaseAlertBox status = { context . release . status } />
120
151
121
- { ! currentPlatform || currentPlatform . recommended || (
152
+ { /* Community platform notice */ }
153
+ { platformInfo . exists && ! platformInfo . recommended && (
122
154
< AlertBox
123
155
title = { t ( 'components.common.alertBox.info' ) }
124
156
level = "info"
@@ -128,19 +160,21 @@ const ReleaseCodeBox: FC = () => {
128
160
</ AlertBox >
129
161
) }
130
162
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]" >
133
166
< code dangerouslySetInnerHTML = { { __html : parsedSnippets } } />
134
167
</ CodeBox >
135
168
</ Skeleton >
136
169
170
+ { /* Platform info footer */ }
137
171
< 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 } ) } { ' ' }
140
174
{ t . rich ( 'layouts.download.codeBox.externalSupportInfo' , {
141
- platform : label ,
175
+ platform : platformInfo . label ,
142
176
link : text => (
143
- < LinkWithArrow href = { url } >
177
+ < LinkWithArrow href = { platformInfo . url } >
144
178
< b > { text } </ b >
145
179
</ LinkWithArrow >
146
180
) ,
0 commit comments