filter-parser.js 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. /* @flow */
  2. export function parseFilters (exp: string): string {
  3. let inSingle = false
  4. let inDouble = false
  5. let inTemplateString = false
  6. let inRegex = false
  7. let curly = 0
  8. let square = 0
  9. let paren = 0
  10. let lastFilterIndex = 0
  11. let c, prev, i, expression, filters
  12. for (i = 0; i < exp.length; i++) {
  13. prev = c
  14. c = exp.charCodeAt(i)
  15. if (inSingle) {
  16. if (c === 0x27 && prev !== 0x5C) inSingle = false
  17. } else if (inDouble) {
  18. if (c === 0x22 && prev !== 0x5C) inDouble = false
  19. } else if (inTemplateString) {
  20. if (c === 0x60 && prev !== 0x5C) inTemplateString = false
  21. } else if (inRegex) {
  22. if (c === 0x2f && prev !== 0x5C) inRegex = false
  23. } else if (
  24. c === 0x7C && // pipe
  25. exp.charCodeAt(i + 1) !== 0x7C &&
  26. exp.charCodeAt(i - 1) !== 0x7C &&
  27. !curly && !square && !paren
  28. ) {
  29. if (expression === undefined) {
  30. // first filter, end of expression
  31. lastFilterIndex = i + 1
  32. expression = exp.slice(0, i).trim()
  33. } else {
  34. pushFilter()
  35. }
  36. } else {
  37. switch (c) {
  38. case 0x22: inDouble = true; break // "
  39. case 0x27: inSingle = true; break // '
  40. case 0x60: inTemplateString = true; break // `
  41. case 0x28: paren++; break // (
  42. case 0x29: paren--; break // )
  43. case 0x5B: square++; break // [
  44. case 0x5D: square--; break // ]
  45. case 0x7B: curly++; break // {
  46. case 0x7D: curly--; break // }
  47. }
  48. if (c === 0x2f) { // /
  49. let j = i - 1
  50. let p
  51. // find first non-whitespace prev char
  52. for (; j >= 0; j--) {
  53. p = exp.charAt(j)
  54. if (p !== ' ') break
  55. }
  56. if (!p || !/[\w$]/.test(p)) {
  57. inRegex = true
  58. }
  59. }
  60. }
  61. }
  62. if (expression === undefined) {
  63. expression = exp.slice(0, i).trim()
  64. } else if (lastFilterIndex !== 0) {
  65. pushFilter()
  66. }
  67. function pushFilter () {
  68. (filters || (filters = [])).push(exp.slice(lastFilterIndex, i).trim())
  69. lastFilterIndex = i + 1
  70. }
  71. if (filters) {
  72. for (i = 0; i < filters.length; i++) {
  73. expression = wrapFilter(expression, filters[i])
  74. }
  75. }
  76. return expression
  77. }
  78. function wrapFilter (exp: string, filter: string): string {
  79. const i = filter.indexOf('(')
  80. if (i < 0) {
  81. // _f: resolveFilter
  82. return `_f("${filter}")(${exp})`
  83. } else {
  84. const name = filter.slice(0, i)
  85. const args = filter.slice(i + 1)
  86. return `_f("${name}")(${exp},${args}`
  87. }
  88. }