'use strict'
var refractorCsharp = require('./csharp.js')
module.exports = cshtml
cshtml.displayName = 'cshtml'
cshtml.aliases = ['razor']
function cshtml(Prism) {
  Prism.register(refractorCsharp)
  // Docs:
  // https://docs.microsoft.com/en-us/aspnet/core/razor-pages/?view=aspnetcore-5.0&tabs=visual-studio
  // https://docs.microsoft.com/en-us/aspnet/core/mvc/views/razor?view=aspnetcore-5.0
  ;(function (Prism) {
    var commentLike = /\/(?![/*])|\/\/.*[\r\n]|\/\*[^*]*(?:\*(?!\/)[^*]*)*\*\//
      .source
    var stringLike =
      /@(?!")|"(?:[^\r\n\\"]|\\.)*"|@"(?:[^\\"]|""|\\[\s\S])*"(?!")/.source +
      '|' +
      /'(?:(?:[^\r\n'\\]|\\.|\\[Uux][\da-fA-F]{1,8})'|(?=[^\\](?!')))/.source
    /**
     * Creates a nested pattern where all occurrences of the string `<<self>>` are replaced with the pattern itself.
     *
     * @param {string} pattern
     * @param {number} depthLog2
     * @returns {string}
     */
    function nested(pattern, depthLog2) {
      for (var i = 0; i < depthLog2; i++) {
        pattern = pattern.replace(/<self>/g, function () {
          return '(?:' + pattern + ')'
        })
      }
      return pattern
        .replace(/<self>/g, '[^\\s\\S]')
        .replace(/<str>/g, '(?:' + stringLike + ')')
        .replace(/<comment>/g, '(?:' + commentLike + ')')
    }
    var round = nested(/\((?:[^()'"@/]|<str>|<comment>|<self>)*\)/.source, 2)
    var square = nested(/\[(?:[^\[\]'"@/]|<str>|<comment>|<self>)*\]/.source, 2)
    var curly = nested(/\{(?:[^{}'"@/]|<str>|<comment>|<self>)*\}/.source, 2)
    var angle = nested(/<(?:[^<>'"@/]|<str>|<comment>|<self>)*>/.source, 2) // Note about the above bracket patterns:
    // They all ignore HTML expressions that might be in the C# code. This is a problem because HTML (like strings and
    // comments) is parsed differently. This is a huge problem because HTML might contain brackets and quotes which
    // messes up the bracket and string counting implemented by the above patterns.
    //
    // This problem is not fixable because 1) HTML expression are highly context sensitive and very difficult to detect
    // and 2) they require one capturing group at every nested level. See the `tagRegion` pattern to admire the
    // complexity of an HTML expression.
    //
    // To somewhat alleviate the problem a bit, the patterns for characters (e.g. 'a') is very permissive, it also
    // allows invalid characters to support HTML expressions like this: <p>That's it!</p>.
    var tagAttrs =
      /(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?/
        .source
    var tagContent = /(?!\d)[^\s>\/=$<%]+/.source + tagAttrs + /\s*\/?>/.source
    var tagRegion =
      /\B@?/.source +
      '(?:' +
      /<([a-zA-Z][\w:]*)/.source +
      tagAttrs +
      /\s*>/.source +
      '(?:' +
      (/[^<]/.source +
        '|' + // all tags that are not the start tag
        // eslint-disable-next-line regexp/strict
        /<\/?(?!\1\b)/.source +
        tagContent +
        '|' + // nested start tag
        nested(
          // eslint-disable-next-line regexp/strict
          /<\1/.source +
            tagAttrs +
            /\s*>/.source +
            '(?:' +
            (/[^<]/.source +
              '|' + // all tags that are not the start tag
              // eslint-disable-next-line regexp/strict
              /<\/?(?!\1\b)/.source +
              tagContent +
              '|' +
              '<self>') +
            ')*' + // eslint-disable-next-line regexp/strict
            /<\/\1\s*>/.source,
          2
        )) +
      ')*' + // eslint-disable-next-line regexp/strict
      /<\/\1\s*>/.source +
      '|' +
      /</.source +
      tagContent +
      ')' // Now for the actual language definition(s):
    //
    // Razor as a language has 2 parts:
    //  1) CSHTML: A markup-like language that has been extended with inline C# code expressions and blocks.
    //  2) C#+HTML: A variant of C# that can contain CSHTML tags as expressions.
    //
    // In the below code, both CSHTML and C#+HTML will be create as separate language definitions that reference each
    // other. However, only CSHTML will be exported via `Prism.languages`.
    Prism.languages.cshtml = Prism.languages.extend('markup', {})
    var csharpWithHtml = Prism.languages.insertBefore(
      'csharp',
      'string',
      {
        html: {
          pattern: RegExp(tagRegion),
          greedy: true,
          inside: Prism.languages.cshtml
        }
      },
      {
        csharp: Prism.languages.extend('csharp', {})
      }
    )
    var cs = {
      pattern: /\S[\s\S]*/,
      alias: 'language-csharp',
      inside: csharpWithHtml
    }
    Prism.languages.insertBefore('cshtml', 'prolog', {
      'razor-comment': {
        pattern: /@\*[\s\S]*?\*@/,
        greedy: true,
        alias: 'comment'
      },
      block: {
        pattern: RegExp(
          /(^|[^@])@/.source +
            '(?:' +
            [
              // @{ ... }
              curly, // @code{ ... }
              /(?:code|functions)\s*/.source + curly, // @for (...) { ... }
              /(?:for|foreach|lock|switch|using|while)\s*/.source +
                round +
                /\s*/.source +
                curly, // @do { ... } while (...);
              /do\s*/.source +
                curly +
                /\s*while\s*/.source +
                round +
                /(?:\s*;)?/.source, // @try { ... } catch (...) { ... } finally { ... }
              /try\s*/.source +
                curly +
                /\s*catch\s*/.source +
                round +
                /\s*/.source +
                curly +
                /\s*finally\s*/.source +
                curly, // @if (...) {...} else if (...) {...} else {...}
              /if\s*/.source +
                round +
                /\s*/.source +
                curly +
                '(?:' +
                /\s*else/.source +
                '(?:' +
                /\s+if\s*/.source +
                round +
                ')?' +
                /\s*/.source +
                curly +
                ')*'
            ].join('|') +
            ')'
        ),
        lookbehind: true,
        greedy: true,
        inside: {
          keyword: /^@\w*/,
          csharp: cs
        }
      },
      directive: {
        pattern:
          /^([ \t]*)@(?:addTagHelper|attribute|implements|inherits|inject|layout|model|namespace|page|preservewhitespace|removeTagHelper|section|tagHelperPrefix|using)(?=\s).*/m,
        lookbehind: true,
        greedy: true,
        inside: {
          keyword: /^@\w+/,
          csharp: cs
        }
      },
      value: {
        pattern: RegExp(
          /(^|[^@])@/.source +
            /(?:await\b\s*)?/.source +
            '(?:' +
            /\w+\b/.source +
            '|' +
            round +
            ')' +
            '(?:' +
            /[?!]?\.\w+\b/.source +
            '|' +
            round +
            '|' +
            square +
            '|' +
            angle +
            round +
            ')*'
        ),
        lookbehind: true,
        greedy: true,
        alias: 'variable',
        inside: {
          keyword: /^@/,
          csharp: cs
        }
      },
      'delegate-operator': {
        pattern: /(^|[^@])@(?=<)/,
        lookbehind: true,
        alias: 'operator'
      }
    })
    Prism.languages.razor = Prism.languages.cshtml
  })(Prism)
}
