highlightjs-cshtml-razor
Version:
highlight.js syntax definition for ASP.NET Razor CSHTML language
396 lines (391 loc) • 11.6 kB
JavaScript
/*
* Language: cshtml-razor
* Requires: xml.js, csharp.js, css.js, javascript.js
* Author: Roman Resh <romanresh@live.com>
*/
module.exports = function (hljs) {
var SPECIAL_SYMBOL_CLASSNAME = "built_in";
var CONTENT_REPLACER = {};
var closed_brace = {
begin: "}",
className: SPECIAL_SYMBOL_CLASSNAME,
endsParent: true
};
var braces = {
begin: "{",
end: "}",
contains: [hljs.QUOTE_STRING_MODE, 'self']
};
var csbraces = {
begin: "{",
end: "}",
contains: ['self'],
skip: true
};
var razor_comment = hljs.COMMENT(
'@\\*',
'\\*@',
{
relevance: 10
}
);
var razor_inline_expresion = {
begin: '@[A-Za-z0-9\\._:-]+',
returnBegin: true,
end: "(\\r|\\n|<|\\s|\"|')",
subLanguage: 'csharp',
contains: [
{
begin: '@',
className: SPECIAL_SYMBOL_CLASSNAME
},
{
begin: '\\[',
end: '\\]',
skip: true
}
,
{
begin: '\\(',
end: '\\)',
skip: true
}
],
returnEnd: true
};
var razor_text_block = {
begin: "[@]{0,1}<text>",
returnBegin: true,
end: "</text>",
returnEnd: true,
subLanguage: "cshtml-razor",
contains: [
{
begin: "[@]{0,1}<text>",
className: SPECIAL_SYMBOL_CLASSNAME
},
{
begin: "</text>",
className: SPECIAL_SYMBOL_CLASSNAME,
endsParent: true
}
]
};
var razor_escape_at = {
variants: [
{ begin: "@@" },
{ begin: "[a-zA-Z]+@" }
],
skip: true
};
var razor_parentheses_block = {
begin: "@\\(",
end: "\\)",
returnBegin: true,
returnEnd: true,
subLanguage: 'csharp',
contains: [
{
begin: "@\\(",
className: SPECIAL_SYMBOL_CLASSNAME
},
{
begin: "\\(",
end: "\\)",
subLanguage: 'csharp',
contains: [hljs.QUOTE_STRING_MODE, 'self', razor_text_block]
},
razor_text_block,
{
begin: "\\)",
className: SPECIAL_SYMBOL_CLASSNAME,
endsParent: true
}
]
};
var xml_blocks = getXmlBlocks(hljs, [razor_inline_expresion, razor_parentheses_block]);
var razor_directives_prefix = "^\\s*@(page|model|using|inherits|inject|layout)";
var razor_directives = {
begin: razor_directives_prefix + "[^\\r\\n{\\(]*$",
end: "$",
returnBegin: true,
returnEnd: true,
contains: [
{
begin: razor_directives_prefix,
className: SPECIAL_SYMBOL_CLASSNAME
},
{
variants: [
{ begin: "\\r|\\n", endsParent: true },
{ begin: "\\s[^\\r\\n]+", end: "$" },
{ begin: "$" }
],
className: "type",
endsParent: true
}
]
};
var cs_code_block_variants = [
{ begin: "@\\{", end: "}" },
{ begin: "@code\\s*\\{", end: "}" }
];
var razor_block = {
variants: cs_code_block_variants,
returnBegin: true,
returnEnd: true,
subLanguage: 'csharp',
contains: [
{
begin: "@(code\\s*)?\\{",
className: SPECIAL_SYMBOL_CLASSNAME
},
CONTENT_REPLACER,
csbraces,
closed_brace
]
};
var razor_helper_block = {
begin: "^\\s*@helper[\\s]*[^{]+[\\s]*{",
returnBegin: true,
returnEnd: true,
end: "}",
subLanguage: "cshtml-razor",
contains: [
{ begin: "@helper", className: SPECIAL_SYMBOL_CLASSNAME },
{ begin: "{", className: SPECIAL_SYMBOL_CLASSNAME },
closed_brace
]
};
var razor_code_block_variants = [
{ begin: "@for[\\s]*\\([^{]+[\\s]*{", end: "}" },
{ begin: "@if[\\s]*\\([^{]+[\\s]*{", end: "}" },
{ begin: "@switch[\\s]*\\([^{]+[\\s]*{", end: "}" },
{ begin: "@while[\\s]*\\([^{]+[\\s]*{", end: "}" },
{ begin: "@using[\\s]*\\([^{]+[\\s]*{", end: "}" },
{ begin: "@lock[\\s]*\\([^{]+[\\s]*{", end: "}" },
{ begin: "@foreach[\\s]*\\([^{]+[\\s]*{", end: "}" }
];
var razor_code_block = {
variants: razor_code_block_variants,
returnBegin: true,
returnEnd: true,
subLanguage: 'csharp',
contains: [
{
variants: razor_code_block_variants.map(function (v) { return { begin: v.begin }; }),
returnBegin: true,
contains: [
{ begin: "@", className: SPECIAL_SYMBOL_CLASSNAME },
{
variants: razor_code_block_variants.map(function (v) { return { begin: v.begin.substr(1, v.begin.length - 2) }; }),
subLanguage: 'csharp'
},
{ begin: "{", className: SPECIAL_SYMBOL_CLASSNAME }
]
},
CONTENT_REPLACER,
{
variants: [
{ begin: "}[\\s]*else\\sif[\\s]*\\([^{]+[\\s]*{" },
{ begin: "}[\\s]*else[\\s]*{" }
],
returnBegin: true,
contains: [
{ begin: "}", className: SPECIAL_SYMBOL_CLASSNAME },
{
variants: [
{ begin: "[\\s]*else\\sif[\\s]*\\([^{]+[\\s]*{" },
{ begin: "[\\s]*else[\\s]*" }
],
subLanguage: 'csharp'
},
{
begin: "{",
className: SPECIAL_SYMBOL_CLASSNAME
}
]
},
braces,
closed_brace
]
};
var razor_try_block = {
begin: "@try[\\s]*{",
end: "}",
returnBegin: true,
returnEnd: true,
subLanguage: 'csharp',
contains: [
{ begin: "@", className: SPECIAL_SYMBOL_CLASSNAME },
{ begin: "try[\\s]*{", subLanguage: 'csharp' },
{
variants: [
{ begin: "}[\\s]*catch[\\s]*\\([^\\)]+\\)[\\s]*{" },
{ begin: "}[\\s]*finally[\\s]*{" }
],
returnBegin: true,
contains: [
{ begin: "}", className: SPECIAL_SYMBOL_CLASSNAME },
{
variants: [
{ begin: "[\\s]*catch[\\s]*\\([^\\)]+\\)[\\s]*", },
{ begin: "[\\s]*finally[\\s]*", },
],
subLanguage: 'csharp'
},
{ begin: "{", className: SPECIAL_SYMBOL_CLASSNAME }
]
},
CONTENT_REPLACER,
braces,
closed_brace
]
};
var section_begin = "@section[\\s]+[a-zA-Z0-9]+[\\s]*{";
var razor_section_block = {
begin: section_begin,
returnBegin: true,
returnEnd: true,
end: "}",
subLanguage: 'cshtml-razor',
contains: [
{
begin: section_begin,
className: SPECIAL_SYMBOL_CLASSNAME
},
braces,
closed_brace
]
};
var rasor_await = {
begin: "@await ",
returnBegin: true,
subLanguage: 'csharp',
end: "(\\r|\\n|<|\\s)",
contains: [
{
begin: "@await ",
className: SPECIAL_SYMBOL_CLASSNAME
},
{
begin: "[<\\r\\n]",
endsParent: true
}
]
};
var contains = [
razor_directives,
razor_helper_block,
razor_block,
razor_code_block,
razor_section_block,
rasor_await,
razor_try_block,
razor_escape_at,
razor_text_block,
razor_comment,
razor_parentheses_block,
{
className: 'meta',
begin: '<!DOCTYPE', end: '>',
relevance: 10,
contains: [{ begin: '\\[', end: '\\]' }]
},
{
begin: '<\\!\\[CDATA\\[', end: '\\]\\]>',
relevance: 10
}
].concat(xml_blocks);
[razor_block, razor_code_block, razor_try_block]
.forEach(function (mode) {
var razorModes = contains.filter(function (c) { return c !== mode; });
var replacerIndex = mode.contains.indexOf(CONTENT_REPLACER);
mode.contains.splice.apply(mode.contains, [replacerIndex, 1].concat(razorModes));
});
return {
aliases: ['cshtml', 'razor', 'razor-cshtml', 'cshtml-razor'],
contains: contains
};
};
function getXmlBlocks(hljs, additional_blocks) {
var xml_comment = hljs.COMMENT(
'<!--',
'-->',
{
relevance: 10
}
);
var string = {
className: 'string',
variants: [
{ begin: /"/, end: /"/, contains: additional_blocks },
{ begin: /'/, end: /'/, contains: additional_blocks },
{ begin: /[^\s"'=<>`]+/ }
]
};
var xml_tag_internal = {
endsWithParent: true,
illegal: /</,
relevance: 0,
contains: [
{
className: 'attr',
begin: '[A-Za-z0-9\\._:-]+',
relevance: 0
},
{
begin: /=\s*/,
relevance: 0,
contains: [string]
}
]
};
return [
{
className: 'meta',
begin: '<!DOCTYPE', end: '>',
relevance: 10,
contains: [{ begin: '\\[', end: '\\]' }]
},
xml_comment,
{
begin: '<\\!\\[CDATA\\[', end: '\\]\\]>',
relevance: 10
},
{
className: 'meta',
begin: /<\?xml/, end: /\?>/, relevance: 10
},
{
className: 'tag',
begin: '<style(?=\\s|>|$)', end: '>',
keywords: { name: 'style' },
contains: [xml_tag_internal],
starts: {
end: '</style>', returnEnd: true,
subLanguage: ['css', 'xml']
}
},
{
className: 'tag',
begin: '<script(?=\\s|>|$)', end: '>',
keywords: { name: 'script' },
contains: [xml_tag_internal],
starts: {
end: '\<\/script\>', returnEnd: true,
subLanguage: ['actionscript', 'javascript', 'handlebars', 'xml']
}
},
{
className: 'tag',
begin: '</?', end: '/?>',
contains: [
{
className: 'name', begin: /[^\/><\s]+/, relevance: 0
},
xml_tag_internal
]
}
].concat(additional_blocks);
}