Repository: go-gitea/gitea
File: web_src/js/markup/mermaid.ts (TypeScript)

Code before:
  if (!frontmatter) return null;
  try {
    return (loadYaml(frontmatter) as {config: MermaidConfig})?.config;
  } catch {
    console.error('invalid or unsupported mermaid init YAML config', frontmatter);
  }
  return null;
}

function parseJsonInitConfig(source: string): MermaidConfig | null {
  // https://mermaid.js.org/config/directives.html#declaring-directives
  // TODO: mermaid is quite hacky for the "JSON" pattern, it can have other root keys
  //       and it can even accept invalid JSON string like:
  //       %%{initialize: { 'logLevel': 'fatal', "theme":'dark', 'startOnLoad': true } }%%
  // To keep things simple, Gitea only supports "init" directive with valid JSON string at the moment.
  const jsonInitConfigRegex = /%%\{\s*init\s*:\s*(.*?)\}%%/s;
  const jsonInit = (jsonInitConfigRegex.exec(source) || [])[1];
  if (!jsonInit) return null;
  try {
    return JSON.parse(jsonInit);
  } catch {
    console.error('invalid or unsupported mermaid init JSON config', jsonInit);
  }
  return null;
}

function isElk(layoutOrRenderer: string | undefined) {
  return Boolean(layoutOrRenderer === 'elk' || layoutOrRenderer?.startsWith?.('elk.'));
}

function configContainsElk(config: MermaidConfig | null) {
  return isElk(config?.layout) || Object.values(config || {}).some((value) => isElk(value?.defaultRenderer));
}

/** detect whether mermaid sources contain elk layout configuration */
export function sourcesContainElk(sources: Array<string>) {
  for (const source of sources) {
    if (isSourceTooLarge(source)) continue;

    const yamlConfig = parseYamlInitConfig(source);
    if (configContainsElk(yamlConfig)) return true;

    const jsonConfig = parseJsonInitConfig(source);
    if (configContainsElk(jsonConfig)) return true;
  }

  return false;
}

async function loadMermaid(sources: Array<string>) {
  const mermaidPromise = import(/* webpackChunkName: "mermaid" */'mermaid');

Review comment (suggestion):
```suggestion

/** checks if either `config.layout` or `config.*.defaultRender` contains a elk layout. */
```

Code after:
  if (!frontmatter) return null;
  try {
    return (loadYaml(frontmatter) as {config: MermaidConfig})?.config;
  } catch {
    console.error('invalid or unsupported mermaid init YAML config', frontmatter);
  }
  return null;
}

function parseJsonInitConfig(source: string): MermaidConfig | null {
  // https://mermaid.js.org/config/directives.html#declaring-directives
  // Do as dirty as mermaid does: https://github.com/mermaid-js/mermaid/blob/develop/packages/mermaid/src/utils.ts
  // It can even accept invalid JSON string like:
  // %%{initialize: { 'logLevel': 'fatal', "theme":'dark', 'startOnLoad': true } }%%
  const jsonInitConfigRegex = /%%\{\s*(init|initialize)\s*:\s*(.*?)\}%%/s;
  const jsonInitText = (jsonInitConfigRegex.exec(source) || [])[2];
  if (!jsonInitText) return null;
  try {
    const processed = jsonInitText.trim().replace(/'/g, '"');
    return JSON.parse(processed);
  } catch {
    console.error('invalid or unsupported mermaid init JSON config', jsonInitText);
  }
  return null;
}

function configValueIsElk(layoutOrRenderer: string | undefined) {
  if (typeof layoutOrRenderer !== 'string') return false;
  return layoutOrRenderer === 'elk' || layoutOrRenderer.startsWith('elk.');
}

function configContainsElk(config: MermaidConfig | null) {
  if (!config) return false;
  // Check the layout from the following properties:
  // * config.layout
  // * config.{any-diagram-config}.defaultRenderer
  //   Although only a few diagram types like "flowchart" support "defaultRenderer",
  //   as long as there is no side effect, here do a general check for all properties of "config", for ease of maintenance
  return configValueIsElk(config.layout) || Object.values(config).some((value) => configValueIsElk(value?.defaultRenderer));
}

/** detect whether mermaid sources contain elk layout configuration */
export function sourcesContainElk(sources: Array<string>) {
  for (const source of sources) {
    if (isSourceTooLarge(source)) continue;

    const yamlConfig = parseYamlInitConfig(source);
    if (configContainsElk(yamlConfig)) return true;

    const jsonConfig = parseJsonInitConfig(source);
    if (configContainsElk(jsonConfig)) return true;