string.js 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. import number from "./number.js";
  2. var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,
  3. reB = new RegExp(reA.source, "g");
  4. function zero(b) {
  5. return function() {
  6. return b;
  7. };
  8. }
  9. function one(b) {
  10. return function(t) {
  11. return b(t) + "";
  12. };
  13. }
  14. export default function(a, b) {
  15. var bi = reA.lastIndex = reB.lastIndex = 0, // scan index for next number in b
  16. am, // current match in a
  17. bm, // current match in b
  18. bs, // string preceding current number in b, if any
  19. i = -1, // index in s
  20. s = [], // string constants and placeholders
  21. q = []; // number interpolators
  22. // Coerce inputs to strings.
  23. a = a + "", b = b + "";
  24. // Interpolate pairs of numbers in a & b.
  25. while ((am = reA.exec(a))
  26. && (bm = reB.exec(b))) {
  27. if ((bs = bm.index) > bi) { // a string precedes the next number in b
  28. bs = b.slice(bi, bs);
  29. if (s[i]) s[i] += bs; // coalesce with previous string
  30. else s[++i] = bs;
  31. }
  32. if ((am = am[0]) === (bm = bm[0])) { // numbers in a & b match
  33. if (s[i]) s[i] += bm; // coalesce with previous string
  34. else s[++i] = bm;
  35. } else { // interpolate non-matching numbers
  36. s[++i] = null;
  37. q.push({i: i, x: number(am, bm)});
  38. }
  39. bi = reB.lastIndex;
  40. }
  41. // Add remains of b.
  42. if (bi < b.length) {
  43. bs = b.slice(bi);
  44. if (s[i]) s[i] += bs; // coalesce with previous string
  45. else s[++i] = bs;
  46. }
  47. // Special optimization for only a single match.
  48. // Otherwise, interpolate each of the numbers and rejoin the string.
  49. return s.length < 2 ? (q[0]
  50. ? one(q[0].x)
  51. : zero(b))
  52. : (b = q.length, function(t) {
  53. for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
  54. return s.join("");
  55. });
  56. }