get-template-locals.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import { isKeyword } from './keywords';
  2. import { preprocess } from './parser/tokenizer-event-handlers';
  3. import traverse from './traversal/traverse';
  4. /**
  5. * Gets the correct Token from the Node based on it's type
  6. */
  7. function tokensFromType(node, scopedTokens, options) {
  8. if (node.type === 'PathExpression') {
  9. if (node.head.type === 'AtHead' || node.head.type === 'ThisHead') {
  10. return;
  11. }
  12. const possbleToken = node.head.name;
  13. if (scopedTokens.indexOf(possbleToken) === -1) {
  14. return possbleToken;
  15. }
  16. } else if (node.type === 'ElementNode') {
  17. const {
  18. tag
  19. } = node;
  20. const char = tag.charAt(0);
  21. if (char === ':' || char === '@') {
  22. return;
  23. }
  24. if (!options.includeHtmlElements && tag.indexOf('.') === -1 && tag.toLowerCase() === tag) {
  25. return;
  26. }
  27. if (tag.substr(0, 5) === 'this.') {
  28. return;
  29. }
  30. if (scopedTokens.indexOf(tag) !== -1) {
  31. return;
  32. }
  33. return tag;
  34. }
  35. }
  36. /**
  37. * Adds tokens to the tokensSet based on their node.type
  38. */
  39. function addTokens(tokensSet, node, scopedTokens, options) {
  40. const maybeTokens = tokensFromType(node, scopedTokens, options);
  41. (Array.isArray(maybeTokens) ? maybeTokens : [maybeTokens]).forEach(maybeToken => {
  42. if (maybeToken !== undefined && maybeToken[0] !== '@') {
  43. tokensSet.add(maybeToken.split('.')[0]);
  44. }
  45. });
  46. }
  47. /**
  48. * Parses and traverses a given handlebars html template to extract all template locals
  49. * referenced that could possible come from the praent scope. Can exclude known keywords
  50. * optionally.
  51. */
  52. export function getTemplateLocals(html, options = {
  53. includeHtmlElements: false,
  54. includeKeywords: false
  55. }) {
  56. const ast = preprocess(html);
  57. const tokensSet = new Set();
  58. const scopedTokens = [];
  59. traverse(ast, {
  60. Block: {
  61. enter({
  62. blockParams
  63. }) {
  64. blockParams.forEach(param => {
  65. scopedTokens.push(param);
  66. });
  67. },
  68. exit({
  69. blockParams
  70. }) {
  71. blockParams.forEach(() => {
  72. scopedTokens.pop();
  73. });
  74. }
  75. },
  76. ElementNode: {
  77. enter(node) {
  78. node.blockParams.forEach(param => {
  79. scopedTokens.push(param);
  80. });
  81. addTokens(tokensSet, node, scopedTokens, options);
  82. },
  83. exit({
  84. blockParams
  85. }) {
  86. blockParams.forEach(() => {
  87. scopedTokens.pop();
  88. });
  89. }
  90. },
  91. PathExpression(node) {
  92. addTokens(tokensSet, node, scopedTokens, options);
  93. }
  94. });
  95. let tokens = [];
  96. tokensSet.forEach(s => tokens.push(s));
  97. if (!(options === null || options === void 0 ? void 0 : options.includeKeywords)) {
  98. tokens = tokens.filter(token => !isKeyword(token));
  99. }
  100. return tokens;
  101. }
  102. //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3BhY2thZ2VzL0BnbGltbWVyL3N5bnRheC9saWIvZ2V0LXRlbXBsYXRlLWxvY2Fscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxTQUFTLFNBQVQsUUFBMEIsWUFBMUI7QUFDQSxTQUFTLFVBQVQsUUFBMkIsbUNBQTNCO0FBQ0EsT0FBTyxRQUFQLE1BQXFCLHNCQUFyQjtBQVFBOzs7O0FBR0EsU0FBUyxjQUFULENBQ0UsSUFERixFQUVFLFlBRkYsRUFHRSxPQUhGLEVBR21DO0FBRWpDLE1BQUksSUFBSSxDQUFDLElBQUwsS0FBYyxnQkFBbEIsRUFBb0M7QUFDbEMsUUFBSSxJQUFJLENBQUMsSUFBTCxDQUFVLElBQVYsS0FBbUIsUUFBbkIsSUFBK0IsSUFBSSxDQUFDLElBQUwsQ0FBVSxJQUFWLEtBQW1CLFVBQXRELEVBQWtFO0FBQ2hFO0FBQ0Q7O0FBRUQsVUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLElBQUwsQ0FBVSxJQUEvQjs7QUFFQSxRQUFJLFlBQVksQ0FBQyxPQUFiLENBQXFCLFlBQXJCLE1BQXVDLENBQUMsQ0FBNUMsRUFBK0M7QUFDN0MsYUFBTyxZQUFQO0FBQ0Q7QUFDRixHQVZELE1BVU8sSUFBSSxJQUFJLENBQUMsSUFBTCxLQUFjLGFBQWxCLEVBQWlDO0FBQ3RDLFVBQU07QUFBRSxNQUFBO0FBQUYsUUFBVSxJQUFoQjtBQUVBLFVBQU0sSUFBSSxHQUFHLEdBQUcsQ0FBQyxNQUFKLENBQVcsQ0FBWCxDQUFiOztBQUVBLFFBQUksSUFBSSxLQUFLLEdBQVQsSUFBZ0IsSUFBSSxLQUFLLEdBQTdCLEVBQWtDO0FBQ2hDO0FBQ0Q7O0FBRUQsUUFBSSxDQUFDLE9BQU8sQ0FBQyxtQkFBVCxJQUFnQyxHQUFHLENBQUMsT0FBSixDQUFZLEdBQVosTUFBcUIsQ0FBQyxDQUF0RCxJQUEyRCxHQUFHLENBQUMsV0FBSixPQUFzQixHQUFyRixFQUEwRjtBQUN4RjtBQUNEOztBQUVELFFBQUksR0FBRyxDQUFDLE1BQUosQ0FB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LE1BQU0sQ0FBQyxNQUFQLENBQWUsS0FBRCxJQUFXLENBQUMsU0FBUyxDQUFDLEtBQUQsQ0FBbkMsQ0FBVDtBQUNEOztBQUVELFNBQU8sTUFBUDtBQUNEIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgaXNLZXl3b3JkIH0gZnJvbSAnLi9rZXl3b3Jkcyc7XG5pbXBvcnQgeyBwcmVwcm9jZXNzIH0gZnJvbSAnLi9wYXJzZXIvdG9rZW5pemVyLWV2ZW50LWhhbmRsZXJzJztcbmltcG9ydCB0cmF2ZXJzZSBmcm9tICcuL3RyYXZlcnNhbC90cmF2ZXJzZSc7XG5pbXBvcnQgKiBhcyBBU1R2MSBmcm9tICcuL3YxL2FwaSc7XG5cbmludGVyZmFjZSBHZXRUZW1wbGF0ZUxvY2Fsc09wdGlvbnMge1xuICBpbmNsdWRlS2V5d29yZHM/OiBib29sZWFuO1xuICBpbmNsdWRlSHRtbEVsZW1lbnRzPzogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBHZXRzIHRoZSBjb3JyZWN0IFRva2VuIGZyb20gdGhlIE5vZGUgYmFzZWQgb24gaXQncyB0eXBlXG4gKi9cbmZ1bmN0aW9uIHRva2Vuc0Zyb21UeXBlKFxuICBub2RlOiBBU1R2MS5Ob2RlLFxuICBzY29wZWRUb2tlbnM6IHN0cmluZ1tdLFxuICBvcHRpb25zOiBHZXRUZW1wbGF0ZUxvY2Fsc09wdGlvbnNcbik6IHN0cmluZyB8IHZvaWQge1xuICBpZiAobm9kZS50eXBlID09PSAnUGF0aEV4cHJlc3Npb24nKSB7XG4gICAgaWYgKG5vZGUuaGVhZC50eXBlID09PSAnQXRIZWFkJyB8fCBub2RlLmhlYWQudHlwZSA9PT0gJ1RoaXNIZWFkJykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHBvc3NibGVUb2tlbiA9IG5vZGUuaGVhZC5uYW1lO1xuXG4gICAgaWYgKHNjb3BlZFRva2Vucy5pbmRleE9mKHBvc3NibGVUb2tlbikgPT09IC0xKSB7XG4gICAgICByZXR1cm4gcG9zc2JsZVRva2VuO1xuICAgIH1cbiAgfSBlbHNlIGlmIChub2RlLnR5cGUgPT09ICdFbGVtZW50Tm9kZScpIHtcbiAgICBjb25zdCB7IHRhZyB9ID0gbm9kZTtcblxuICAgIGNvbnN0IGNoYXIgPSB0YWcuY2hhckF0KDApO1xuXG4gICAgaWYgKGNoYXIgPT09ICc6JyB8fCBjaGFyID09PSAnQCcpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoIW9wdGlvbnMuaW5jbHVkZUh0bWxFbGVtZW50cyAmJiB0YWcuaW5kZXhPZignLicpID09PSAtMSAmJiB0YWcudG9Mb3dlckNhc2UoKSA9PT0gdGFnKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHRhZy5zdWJzdHIoMCwgNSkgPT09ICd0aGlzLicpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoc2NvcGVkVG9rZW5zLmluZGV4T2YodGFnKSAhPT0gLTEpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICByZXR1cm4gdGFnO1xuICB9XG59XG5cbi8qKlxuICogQWRkcyB0b2tlbnMgdG8gdGhlIHRva2Vuc1NldCBiYXNlZCBvbiB0aGVpciBub2RlLnR5cGVcbiAqL1xuZnVuY3Rpb24gYWRkVG9rZW5zKFxuICB0b2tlbnNTZXQ6IFNldDxzdHJpbmc+LFxuICBub2RlOiBBU1R2MS5Ob2RlLFxuICBzY29wZWRUb2tlbnM6IHN0cmluZ1tdLFxuICBvcHRpb25zOiBHZXRUZW1wbGF0ZUxvY2Fsc09wdGlvbnNcbikge1xuICBjb25zdCBtYXliZVRva2VucyA9IHRva2Vuc0Zyb21UeXBlKG5vZGUsIHNjb3BlZFRva2Vucywgb3B0aW9ucyk7XG5cbiAgKEFycmF5LmlzQXJyYXkobWF5YmVUb2tlbnMpID8gbWF5YmVUb2tlbnMgOiBbbWF5YmVUb2tlbnNdKS5mb3JFYWNoKChtYXliZVRva2VuKSA9PiB7XG4gICAgaWYgKG1heWJlVG9rZW4gIT09IHVuZGVmaW5lZCAmJiBtYXliZVRva2VuWzBdICE9PSAnQCcpIHtcbiAgICAgIHRva2Vuc1NldC5hZGQobWF5YmVUb2tlbi5zcGxpdCgnLicpWzBdKTtcbiAgICB9XG4gIH0pO1xufVxuXG4vKipcbiAqIFBhcnNlcyBhbmQgdHJhdmVyc2VzIGEgZ2l2ZW4gaGFuZGxlYmFycyBodG1sIHRlbXBsYXRlIHRvIGV4dHJhY3QgYWxsIHRlbXBsYXRlIGxvY2Fsc1xuICogcmVmZXJlbmNlZCB0aGF0IGNvdWxkIHBvc3NpYmxlIGNvbWUgZnJvbSB0aGUgcHJhZW50IHNjb3BlLiBDYW4gZXhjbHVkZSBrbm93biBrZXl3b3Jkc1xuICogb3B0aW9uYWxseS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFRlbXBsYXRlTG9jYWxzKFxuICBodG1sOiBzdHJpbmcsXG4gIG9wdGlvbnM6IEdldFRlbXBsYXRlTG9jYWxzT3B0aW9ucyA9IHtcbiAgICBpbmNsdWRlSHRtbEVsZW1lbnRzOiBmYWxzZSxcbiAgICBpbmNsdWRlS2V5d29yZHM6IGZhbHNlLFxuICB9XG4pOiBzdHJpbmdbXSB7XG4gIGNvbnN0IGFzdCA9IHByZXByb2Nlc3MoaHRtbCk7XG4gIGNvbnN0IHRva2Vuc1NldCA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICBjb25zdCBzY29wZWRUb2tlbnM6IHN0cmluZ1tdID0gW107XG5cbiAgdHJhdmVyc2UoYXN0LCB7XG4gICAgQmxvY2s6IHtcbiAgICAgIGVudGVyKHsgYmxvY2tQYXJhbXMgfSkge1xuICAgICAgICBibG9ja1BhcmFtcy5mb3JFYWNoKChwYXJhbSkgPT4ge1xuICAgICAgICAgIHNjb3BlZFRva2Vucy5wdXNoKHBhcmFtKTtcbiAgICAgICAgfSk7XG4gICAgICB9LFxuXG4gICAgICBleGl0KHsgYmxvY2tQYXJhbXMgfSkge1xuICAgICAgICBibG9ja1BhcmFtcy5mb3JFYWNoKCgpID0+IHtcbiAgICAgICAgICBzY29wZWRUb2tlbnMucG9wKCk7XG4gICAgICAgIH0pO1xuICAgICAgfSxcbiAgICB9LFxuXG4gICAgRWxlbWVudE5vZGU6IHtcbiAgICAgIGVudGVyKG5vZGUpIHtcbiAgICAgICAgbm9kZS5ibG9ja1BhcmFtcy5mb3JFYWNoKChwYXJhbSkgPT4ge1xuICAgICAgICAgIHNjb3BlZFRva2Vucy5wdXNoKHBhcmFtKTtcbiAgICAgICAgfSk7XG4gICAgICAgIGFkZFRva2Vucyh0b2tlbnNTZXQsIG5vZGUsIHNjb3BlZFRva2Vucywgb3B0aW9ucyk7XG4gICAgICB9LFxuXG4gICAgICBleGl0KHsgYmxvY2tQYXJhbXMgfSkge1xuICAgICAgICBibG9ja1BhcmFtcy5mb3JFYWNoKCgpID0+IHtcbiAgICAgICAgICBzY29wZWRUb2tlbnMucG9wKCk7XG4gICAgICAgIH0pO1xuICAgICAgfSxcbiAgICB9LFxuXG4gICAgUGF0aEV4cHJlc3Npb24obm9kZSkge1xuICAgICAgYWRkVG9rZW5zKHRva2Vuc1NldCwgbm9kZSwgc2NvcGVkVG9rZW5zLCBvcHRpb25zKTtcbiAgICB9LFxuICB9KTtcblxuICBsZXQgdG9rZW5zOiBzdHJpbmdbXSA9IFtdO1xuXG4gIHRva2Vuc1NldC5mb3JFYWNoKChzKSA9PiB0b2tlbnMucHVzaChzKSk7XG5cbiAgaWYgKCFvcHRpb25zPy5pbmNsdWRlS2V5d29yZHMpIHtcbiAgICB0b2tlbnMgPSB0b2tlbnMuZmlsdGVyKCh0b2tlbikgPT4gIWlzS2V5d29yZCh0b2tlbikpO1xuICB9XG5cbiAgcmV0dXJuIHRva2Vucztcbn1cbiJdLCJzb3VyY2VSb290IjoiIn0=