index.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. import generator from "../../babel-generator";
  2. import template from "../lib";
  3. import * as t from "@babel/types";
  4. const comments = "// Sum two numbers\nconst add = (a, b) => a + b;";
  5. describe("@babel/template", function() {
  6. it("import statements are allowed by default", function() {
  7. expect(function() {
  8. template("import foo from 'foo'")({});
  9. }).not.toThrow();
  10. });
  11. it("with statements are allowed with sourceType: script", function() {
  12. expect(function() {
  13. template("with({}){}", { sourceType: "script" })({});
  14. }).not.toThrow();
  15. });
  16. it("should strip comments by default", function() {
  17. const code = "const add = (a, b) => a + b;";
  18. const output = template(comments)();
  19. expect(generator(output).code).toBe(code);
  20. });
  21. it("should preserve comments with a flag", function() {
  22. const output = template(comments, { preserveComments: true })();
  23. expect(generator(output).code).toBe(comments);
  24. });
  25. describe("string-based", () => {
  26. it("should handle replacing values from an object", () => {
  27. const value = t.stringLiteral("some string value");
  28. const result = template(`
  29. if (SOME_VAR === "") {}
  30. `)({
  31. SOME_VAR: value,
  32. });
  33. expect(result.type).toBe("IfStatement");
  34. expect(result.test.type).toBe("BinaryExpression");
  35. expect(result.test.left).toBe(value);
  36. });
  37. it("should handle replacing values given an array", () => {
  38. const value = t.stringLiteral("some string value");
  39. const result = template(`
  40. if ($0 === "") {}
  41. `)([value]);
  42. expect(result.type).toBe("IfStatement");
  43. expect(result.test.type).toBe("BinaryExpression");
  44. expect(result.test.left).toBe(value);
  45. });
  46. it("should handle replacing values with null to remove them", () => {
  47. const result = template(`
  48. callee(ARG);
  49. `)({ ARG: null });
  50. expect(result.type).toBe("ExpressionStatement");
  51. expect(result.expression.type).toBe("CallExpression");
  52. expect(result.expression.arguments).toEqual([]);
  53. });
  54. it("should handle replacing values that are string content", () => {
  55. const result = template(`
  56. ("ARG");
  57. `)({ ARG: "some new content" });
  58. expect(result.type).toBe("ExpressionStatement");
  59. expect(result.expression.type).toBe("StringLiteral");
  60. expect(result.expression.value).toBe("some new content");
  61. });
  62. it("should automatically clone nodes if they are injected twice", () => {
  63. const id = t.identifier("someIdent");
  64. const result = template(`
  65. ID;
  66. ID;
  67. `)({ ID: id });
  68. expect(result[0].type).toBe("ExpressionStatement");
  69. expect(result[0].expression).toBe(id);
  70. expect(result[1].type).toBe("ExpressionStatement");
  71. expect(result[1].expression).not.toBe(id);
  72. expect(result[1].expression).toEqual(id);
  73. });
  74. it("should allow passing in a whitelist of replacement names", () => {
  75. const id = t.identifier("someIdent");
  76. const result = template(
  77. `
  78. some_id;
  79. `,
  80. { placeholderWhitelist: new Set(["some_id"]) },
  81. )({ some_id: id });
  82. expect(result.type).toBe("ExpressionStatement");
  83. expect(result.expression).toBe(id);
  84. });
  85. it("should allow passing in a RegExp to match replacement patterns", () => {
  86. const id = t.identifier("someIdent");
  87. const result = template(
  88. `
  89. ID;
  90. ANOTHER_ID;
  91. `,
  92. { placeholderPattern: /^ID$/ },
  93. )({ ID: id });
  94. expect(result[0].type).toBe("ExpressionStatement");
  95. expect(result[0].expression).toBe(id);
  96. expect(result[1].type).toBe("ExpressionStatement");
  97. expect(result[1].expression.type).toBe("Identifier");
  98. expect(result[1].expression.name).toBe("ANOTHER_ID");
  99. });
  100. it("should throw if unknown replacements are provided", () => {
  101. expect(() => {
  102. template(`
  103. ID;
  104. `)({ ID: t.identifier("someIdent"), ANOTHER_ID: null });
  105. }).toThrow('Unknown substitution "ANOTHER_ID" given');
  106. });
  107. it("should throw if placeholders are not given explicit values", () => {
  108. expect(() => {
  109. template(`
  110. ID;
  111. ANOTHER_ID;
  112. `)({ ID: t.identifier("someIdent") });
  113. }).toThrow(
  114. `Error: No substitution given for "ANOTHER_ID". If this is not meant to be a
  115. placeholder you may want to consider passing one of the following options to @babel/template:
  116. - { placeholderPattern: false, placeholderWhitelist: new Set(['ANOTHER_ID'])}
  117. - { placeholderPattern: /^ANOTHER_ID$/ }`,
  118. );
  119. });
  120. it("should return the AST directly when using .ast", () => {
  121. const result = template.ast(`
  122. if ("some string value" === "") {}
  123. `);
  124. expect(result.type).toBe("IfStatement");
  125. expect(result.test.type).toBe("BinaryExpression");
  126. expect(result.test.left.type).toBe("StringLiteral");
  127. expect(result.test.left.value).toBe("some string value");
  128. });
  129. });
  130. describe("literal-based", () => {
  131. it("should handle replacing values from an object", () => {
  132. const value = t.stringLiteral("some string value");
  133. const result = template`
  134. if (${value} === "") {}
  135. `();
  136. expect(result.type).toBe("IfStatement");
  137. expect(result.test.type).toBe("BinaryExpression");
  138. expect(result.test.left).toBe(value);
  139. });
  140. it("should handle replacing values with null to remove them", () => {
  141. const result = template`
  142. callee(${null});
  143. `();
  144. expect(result.type).toBe("ExpressionStatement");
  145. expect(result.expression.type).toBe("CallExpression");
  146. expect(result.expression.arguments).toEqual([]);
  147. });
  148. it("should handle replacing values that are string content", () => {
  149. const result = template`
  150. ("${"some new content"}");
  151. `();
  152. expect(result.type).toBe("ExpressionStatement");
  153. expect(result.expression.type).toBe("StringLiteral");
  154. expect(result.expression.value).toBe("some new content");
  155. });
  156. it("should allow setting options by passing an object", () => {
  157. const result = template({ sourceType: "script" })`
  158. with({}){}
  159. `();
  160. expect(result.type).toBe("WithStatement");
  161. });
  162. it("should return the AST directly when using .ast", () => {
  163. const value = t.stringLiteral("some string value");
  164. const result = template.ast`
  165. if (${value} === "") {}
  166. `;
  167. expect(result.type).toBe("IfStatement");
  168. expect(result.test.type).toBe("BinaryExpression");
  169. expect(result.test.left).toBe(value);
  170. });
  171. it("should replace JSX placeholder", () => {
  172. const result = template.expression(
  173. `
  174. <TAG>{'content'}</TAG>
  175. `,
  176. {
  177. plugins: ["jsx"],
  178. },
  179. )({
  180. TAG: t.jsxIdentifier("div"),
  181. });
  182. expect(generator(result).code).toEqual("<div>{'content'}</div>");
  183. });
  184. });
  185. });