prism-ftl.js 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. (function (Prism) {
  2. // https://freemarker.apache.org/docs/dgui_template_exp.html
  3. // FTL expression with 4 levels of nesting supported
  4. var FTL_EXPR = /[^<()"']|\((?:<expr>)*\)|<(?!#--)|<#--(?:[^-]|-(?!->))*-->|"(?:[^\\"]|\\.)*"|'(?:[^\\']|\\.)*'/.source;
  5. for (var i = 0; i < 2; i++) {
  6. FTL_EXPR = FTL_EXPR.replace(/<expr>/g, function () { return FTL_EXPR; });
  7. }
  8. FTL_EXPR = FTL_EXPR.replace(/<expr>/g, /[^\s\S]/.source);
  9. var ftl = {
  10. 'comment': /<#--[\s\S]*?-->/,
  11. 'string': [
  12. {
  13. // raw string
  14. pattern: /\br("|')(?:(?!\1)[^\\]|\\.)*\1/,
  15. greedy: true
  16. },
  17. {
  18. pattern: RegExp(/("|')(?:(?!\1|\$\{)[^\\]|\\.|\$\{(?:(?!\})(?:<expr>))*\})*\1/.source.replace(/<expr>/g, function () { return FTL_EXPR; })),
  19. greedy: true,
  20. inside: {
  21. 'interpolation': {
  22. pattern: RegExp(/((?:^|[^\\])(?:\\\\)*)\$\{(?:(?!\})(?:<expr>))*\}/.source.replace(/<expr>/g, function () { return FTL_EXPR; })),
  23. lookbehind: true,
  24. inside: {
  25. 'interpolation-punctuation': {
  26. pattern: /^\$\{|\}$/,
  27. alias: 'punctuation'
  28. },
  29. rest: null
  30. }
  31. }
  32. }
  33. }
  34. ],
  35. 'keyword': /\b(?:as)\b/,
  36. 'boolean': /\b(?:false|true)\b/,
  37. 'builtin-function': {
  38. pattern: /((?:^|[^?])\?\s*)\w+/,
  39. lookbehind: true,
  40. alias: 'function'
  41. },
  42. 'function': /\b\w+(?=\s*\()/,
  43. 'number': /\b\d+(?:\.\d+)?\b/,
  44. 'operator': /\.\.[<*!]?|->|--|\+\+|&&|\|\||\?{1,2}|[-+*/%!=<>]=?|\b(?:gt|gte|lt|lte)\b/,
  45. 'punctuation': /[,;.:()[\]{}]/
  46. };
  47. ftl.string[1].inside.interpolation.inside.rest = ftl;
  48. Prism.languages.ftl = {
  49. 'ftl-comment': {
  50. // the pattern is shortened to be more efficient
  51. pattern: /^<#--[\s\S]*/,
  52. alias: 'comment'
  53. },
  54. 'ftl-directive': {
  55. pattern: /^<[\s\S]+>$/,
  56. inside: {
  57. 'directive': {
  58. pattern: /(^<\/?)[#@][a-z]\w*/i,
  59. lookbehind: true,
  60. alias: 'keyword'
  61. },
  62. 'punctuation': /^<\/?|\/?>$/,
  63. 'content': {
  64. pattern: /\s*\S[\s\S]*/,
  65. alias: 'ftl',
  66. inside: ftl
  67. }
  68. }
  69. },
  70. 'ftl-interpolation': {
  71. pattern: /^\$\{[\s\S]*\}$/,
  72. inside: {
  73. 'punctuation': /^\$\{|\}$/,
  74. 'content': {
  75. pattern: /\s*\S[\s\S]*/,
  76. alias: 'ftl',
  77. inside: ftl
  78. }
  79. }
  80. }
  81. };
  82. Prism.hooks.add('before-tokenize', function (env) {
  83. // eslint-disable-next-line regexp/no-useless-lazy
  84. var pattern = RegExp(/<#--[\s\S]*?-->|<\/?[#@][a-zA-Z](?:<expr>)*?>|\$\{(?:<expr>)*?\}/.source.replace(/<expr>/g, function () { return FTL_EXPR; }), 'gi');
  85. Prism.languages['markup-templating'].buildPlaceholders(env, 'ftl', pattern);
  86. });
  87. Prism.hooks.add('after-tokenize', function (env) {
  88. Prism.languages['markup-templating'].tokenizePlaceholders(env, 'ftl');
  89. });
  90. }(Prism));