TemplateLiteralTransformer.ts 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import { injectable, inject } from 'inversify';
  2. import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
  3. import * as ESTree from 'estree';
  4. import { IOptions } from '../../interfaces/options/IOptions';
  5. import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
  6. import { Node } from '../../node/Node';
  7. import { Nodes } from '../../node/Nodes';
  8. /**
  9. * Transform ES2015 template literals to ES5
  10. * Thanks to Babel for algorithm
  11. */
  12. @injectable()
  13. export class TemplateLiteralTransformer extends AbstractNodeTransformer {
  14. /**
  15. * @param options
  16. */
  17. constructor (
  18. @inject(ServiceIdentifiers.IOptions) options: IOptions
  19. ) {
  20. super(options);
  21. }
  22. /**
  23. * @param node
  24. * @return {boolean}
  25. */
  26. private static isLiteralNodeWithStringValue (node: ESTree.Node): boolean {
  27. return node && Node.isLiteralNode(node) && typeof node.value === 'string';
  28. }
  29. /**
  30. * @param templateLiteralNode
  31. * @param parentNode
  32. * @returns {ESTree.Node}
  33. */
  34. public transformNode (templateLiteralNode: ESTree.TemplateLiteral, parentNode: ESTree.Node): ESTree.Node {
  35. const templateLiteralExpressions: ESTree.Expression[] = templateLiteralNode.expressions;
  36. let nodes: (ESTree.Literal | ESTree.Expression)[] = [];
  37. for (const templateElement of templateLiteralNode.quasis) {
  38. nodes.push(Nodes.getLiteralNode(templateElement.value.cooked));
  39. const expression: ESTree.Expression | undefined = templateLiteralExpressions.shift();
  40. if (!expression) {
  41. continue;
  42. }
  43. nodes.push(expression);
  44. }
  45. nodes = nodes.filter((node: ESTree.Literal | ESTree.Expression) => {
  46. return !(Node.isLiteralNode(node) && node.value === '');
  47. });
  48. // since `+` is left-to-right associative
  49. // ensure the first node is a string if first/second isn't
  50. if (
  51. !TemplateLiteralTransformer.isLiteralNodeWithStringValue(nodes[0]) &&
  52. !TemplateLiteralTransformer.isLiteralNodeWithStringValue(nodes[1])
  53. ) {
  54. nodes.unshift(Nodes.getLiteralNode(''));
  55. }
  56. if (nodes.length > 1) {
  57. let root: ESTree.BinaryExpression = Nodes.getBinaryExpressionNode(
  58. '+',
  59. <ESTree.Literal>nodes.shift(),
  60. <ESTree.Expression>nodes.shift()
  61. );
  62. for (const node of nodes) {
  63. root = Nodes.getBinaryExpressionNode('+', root, <ESTree.Literal | ESTree.Expression>node);
  64. }
  65. return root;
  66. }
  67. return nodes[0];
  68. }
  69. }