@@ -257,9 +257,36 @@ export function parseLines(
257257 content : string ,
258258 options : CodeBlockParseLinesOptions ,
259259) : CodeBlockParsedLines {
260- let code = content . replace ( / \n $ / , '' ) ;
261- const { language, magicComments, metastring} = options ;
260+ const parsedLines : CodeBlockParsedLines = {
261+ code : content . replace ( / \n $ / , '' ) ,
262+ lineClassNames : { } ,
263+ } ;
264+
262265 // Highlighted lines specified in props: don't parse the content
266+ if ( fillLineClassNamesFromMetastring ( parsedLines , options ) ) {
267+ return parsedLines ;
268+ }
269+
270+ fillLineClassNamesFromCode ( parsedLines , options ) ;
271+
272+ return parsedLines ;
273+ }
274+
275+ /**
276+ * Parses {@link CodeBlockParsedLines.lineClassNames} from the given metastring and fills
277+ * it into {@link parsedLines}.
278+ * @param parsedLines The object to fill the parsed class names into.
279+ * @param options The options to configure the parsing behavior.
280+ * @throws {Error } Will throw an error if the metastring contains highlighted lines, but there are no magic comments configured.
281+ * @returns `true` if the metastring contained any highlighted lines, otherwise `false`.
282+ */
283+ function fillLineClassNamesFromMetastring (
284+ parsedLines : CodeBlockParsedLines ,
285+ options : CodeBlockParseLinesOptions ,
286+ ) : boolean {
287+ const { magicComments, metastring} = options ;
288+ const { lineClassNames} = parsedLines ;
289+
263290 if ( metastring && metastringLinesRangeRegex . test ( metastring ) ) {
264291 const linesRange = metastring . match ( metastringLinesRangeRegex ) ! . groups !
265292 . range ! ;
@@ -269,14 +296,35 @@ export function parseLines(
269296 ) ;
270297 }
271298 const metastringRangeClassName = magicComments [ 0 ] ! . className ;
272- const lines = rangeParser ( linesRange )
299+ rangeParser ( linesRange )
273300 . filter ( ( n ) => n > 0 )
274- . map ( ( n ) => [ n - 1 , [ metastringRangeClassName ] ] as [ number , string [ ] ] ) ;
275- return { lineClassNames : Object . fromEntries ( lines ) , code} ;
301+ . forEach ( ( n ) => {
302+ lineClassNames [ n - 1 ] = [ metastringRangeClassName ] ;
303+ } ) ;
304+ return true ;
276305 }
306+
307+ return false ;
308+ }
309+
310+ /**
311+ * Parses {@link CodeBlockParsedLines.lineClassNames} from the magic comments contained in the source code,
312+ * The magic comments are erased from {@link CodeBlockParsedLines.code} during this process.
313+ * @param parsedLines The object to fill the parsed class names into.
314+ * @param options The options to configure the parsing behavior.
315+ */
316+ function fillLineClassNamesFromCode (
317+ parsedLines : CodeBlockParsedLines ,
318+ options : CodeBlockParseLinesOptions ,
319+ ) {
320+ const { language, magicComments} = options ;
321+ const { code, lineClassNames} = parsedLines ;
322+
323+ // only parse if there is a language specified
277324 if ( language === undefined ) {
278- return { lineClassNames : { } , code } ;
325+ return ;
279326 }
327+
280328 const directiveRegex = getAllMagicCommentDirectiveStyles (
281329 language ,
282330 magicComments ,
@@ -323,15 +371,13 @@ export function parseLines(
323371 }
324372 lines . splice ( lineNumber , 1 ) ;
325373 }
326- code = lines . join ( '\n' ) ;
327- const lineClassNames : { [ lineIndex : number ] : string [ ] } = { } ;
374+ parsedLines . code = lines . join ( '\n' ) ;
328375 Object . entries ( blocks ) . forEach ( ( [ className , { range} ] ) => {
329376 rangeParser ( range ) . forEach ( ( l ) => {
330377 lineClassNames [ l ] ??= [ ] ;
331378 lineClassNames [ l ] ! . push ( className ) ;
332379 } ) ;
333380 } ) ;
334- return { lineClassNames, code} ;
335381}
336382
337383export function getPrismCssVariables ( prismTheme : PrismTheme ) : CSSProperties {
0 commit comments