Repository: facebook/docusaurus
File: packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts (TypeScript)

Code before:
 * @param options The options to configure the parsing behavior.
 * @throws {Error} Will throw an error if the metastring contains highlighted lines, but there are no magic comments configured.
 * @returns `true` if the metastring contained any highlighted lines, otherwise `false`.
 */
function fillLineClassNamesFromMetastring(
  parsedLines: CodeBlockParsedLines,
  options: CodeBlockParseLinesOptions,
): boolean {
  const {magicComments, metastring} = options;
  const {lineClassNames} = parsedLines;

  if (metastring && metastringLinesRangeRegex.test(metastring)) {
    const linesRange = metastring.match(metastringLinesRangeRegex)!.groups!
      .range!;
    if (magicComments.length === 0) {
      throw new Error(
        `A highlight range has been given in code block's metastring (\`\`\` ${metastring}), but no magic comment config is available. Docusaurus applies the first magic comment entry's className for metastring ranges.`,
      );
    }
    const metastringRangeClassName = magicComments[0]!.className;
    rangeParser(linesRange)
      .filter((n) => n > 0)
      .forEach((n) => {
        lineClassNames[n - 1] = [metastringRangeClassName];
      });
    return true;
  }

  return false;
}

/**
 * Parses {@link CodeBlockParsedLines.lineClassNames} from the magic comments contained in the source code,
 * The magic comments are erased from {@link CodeBlockParsedLines.code} during this process.
 * @param parsedLines The object to fill the parsed class names into.
 * @param options The options to configure the parsing behavior.
 */
function fillLineClassNamesFromCode(
  parsedLines: CodeBlockParsedLines,
  options: CodeBlockParseLinesOptions,
) {
  const {language, magicComments} = options;
  const {code, lineClassNames} = parsedLines;

  // only parse if there is a language specified
  if (language === undefined) {
    return;
  }

  const directiveRegex = getAllMagicCommentDirectiveStyles(
    language,

Review comment (suggestion):
I don't see a good reason to move from functional style to imperative side effect style mutating a function input

Please prefer pure functions over functions that mutate their parameters and create side effects. Avoid the word "fill" too, implying that a side effect will happen.

Code after:
    magicComments
      .filter((d) => d.block)
      .map(({className, block}) => [block!.start, className]),
  );
  const blockEndToClassName: {[comment: string]: string} = Object.fromEntries(
    magicComments
      .filter((d) => d.block)
      .map(({className, block}) => [block!.end, className]),
  );
  for (let lineNumber = 0; lineNumber < lines.length; ) {
    const line = lines[lineNumber]!;
    const match = line.match(directiveRegex);
    if (!match) {
      // Lines without directives are unchanged
      lineNumber += 1;
      continue;
    }
    const directive = match
      .slice(1)
      .find((item: string | undefined) => item !== undefined)!;
    if (lineToClassName[directive]) {
      blocks[lineToClassName[directive]!]!.range += `${lineNumber},`;
    } else if (blockStartToClassName[directive]) {
      blocks[blockStartToClassName[directive]!]!.start = lineNumber;
    } else if (blockEndToClassName[directive]) {
      blocks[blockEndToClassName[directive]!]!.range += `${
        blocks[blockEndToClassName[directive]!]!.start
      }-${lineNumber - 1},`;
    }
    lines.splice(lineNumber, 1);
  }
  code = lines.join('\n');
  const lineClassNames: {[lineIndex: number]: string[]} = {};
  Object.entries(blocks).forEach(([className, {range}]) => {
    rangeParser(range).forEach((l) => {
      lineClassNames[l] ??= [];
      lineClassNames[l]!.push(className);
    });
  });
  return {lineClassNames, code};
}

export function getPrismCssVariables(prismTheme: PrismTheme): CSSProperties {
  const mapping: PrismThemeEntry = {
    color: '--prism-color',
    backgroundColor: '--prism-background-color',
  };

  const properties: {[key: string]: string} = {};
  Object.entries(prismTheme.plain).forEach(([key, value]) => {
    const varName = mapping[key as keyof PrismThemeEntry];