prism-markup-templating.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. (function (Prism) {
  2. /**
  3. * Returns the placeholder for the given language id and index.
  4. *
  5. * @param {string} language
  6. * @param {string|number} index
  7. * @returns {string}
  8. */
  9. function getPlaceholder(language, index) {
  10. return '___' + language.toUpperCase() + index + '___';
  11. }
  12. Object.defineProperties(Prism.languages['markup-templating'] = {}, {
  13. buildPlaceholders: {
  14. /**
  15. * Tokenize all inline templating expressions matching `placeholderPattern`.
  16. *
  17. * If `replaceFilter` is provided, only matches of `placeholderPattern` for which `replaceFilter` returns
  18. * `true` will be replaced.
  19. *
  20. * @param {object} env The environment of the `before-tokenize` hook.
  21. * @param {string} language The language id.
  22. * @param {RegExp} placeholderPattern The matches of this pattern will be replaced by placeholders.
  23. * @param {(match: string) => boolean} [replaceFilter]
  24. */
  25. value: function (env, language, placeholderPattern, replaceFilter) {
  26. if (env.language !== language) {
  27. return;
  28. }
  29. var tokenStack = env.tokenStack = [];
  30. env.code = env.code.replace(placeholderPattern, function (match) {
  31. if (typeof replaceFilter === 'function' && !replaceFilter(match)) {
  32. return match;
  33. }
  34. var i = tokenStack.length;
  35. var placeholder;
  36. // Check for existing strings
  37. while (env.code.indexOf(placeholder = getPlaceholder(language, i)) !== -1) {
  38. ++i;
  39. }
  40. // Create a sparse array
  41. tokenStack[i] = match;
  42. return placeholder;
  43. });
  44. // Switch the grammar to markup
  45. env.grammar = Prism.languages.markup;
  46. }
  47. },
  48. tokenizePlaceholders: {
  49. /**
  50. * Replace placeholders with proper tokens after tokenizing.
  51. *
  52. * @param {object} env The environment of the `after-tokenize` hook.
  53. * @param {string} language The language id.
  54. */
  55. value: function (env, language) {
  56. if (env.language !== language || !env.tokenStack) {
  57. return;
  58. }
  59. // Switch the grammar back
  60. env.grammar = Prism.languages[language];
  61. var j = 0;
  62. var keys = Object.keys(env.tokenStack);
  63. function walkTokens(tokens) {
  64. for (var i = 0; i < tokens.length; i++) {
  65. // all placeholders are replaced already
  66. if (j >= keys.length) {
  67. break;
  68. }
  69. var token = tokens[i];
  70. if (typeof token === 'string' || (token.content && typeof token.content === 'string')) {
  71. var k = keys[j];
  72. var t = env.tokenStack[k];
  73. var s = typeof token === 'string' ? token : token.content;
  74. var placeholder = getPlaceholder(language, k);
  75. var index = s.indexOf(placeholder);
  76. if (index > -1) {
  77. ++j;
  78. var before = s.substring(0, index);
  79. var middle = new Prism.Token(language, Prism.tokenize(t, env.grammar), 'language-' + language, t);
  80. var after = s.substring(index + placeholder.length);
  81. var replacement = [];
  82. if (before) {
  83. replacement.push.apply(replacement, walkTokens([before]));
  84. }
  85. replacement.push(middle);
  86. if (after) {
  87. replacement.push.apply(replacement, walkTokens([after]));
  88. }
  89. if (typeof token === 'string') {
  90. tokens.splice.apply(tokens, [i, 1].concat(replacement));
  91. } else {
  92. token.content = replacement;
  93. }
  94. }
  95. } else if (token.content /* && typeof token.content !== 'string' */) {
  96. walkTokens(token.content);
  97. }
  98. }
  99. return tokens;
  100. }
  101. walkTokens(env.tokens);
  102. }
  103. }
  104. });
  105. }(Prism));