Register
Login
Resources
Docs Blog Datasets Glossary Case Studies Tutorials & Webinars
Product
Data Engine LLMs Platform Enterprise
Pricing Explore
Connect to our Discord channel

remove-liquid-statements.js 10 KB

You have to be logged in to leave a comment. Sign In
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
  1. const { drop, dropRight, first, last } = require('lodash')
  2. // ----- START LIQUID PATTERNS ----- //
  3. const startTag = /(?:^ *?)?{%-?/
  4. const endTag = /-?%}/
  5. const contentRegex = /[\s\S]*?/gm
  6. const emptyString = /^\s*?$/m
  7. const nonEmptyString = /^.*?\S.*?/m
  8. const ifStatement = new RegExp(startTag.source + ' if .*?' + endTag.source)
  9. const ifRegex = new RegExp(ifStatement.source, 'gm')
  10. const firstIfRegex = new RegExp(ifStatement.source, 'm')
  11. const elseRegex = new RegExp(startTag.source + ' else ?' + endTag.source)
  12. const endRegex = new RegExp(startTag.source + ' endif ?' + endTag.source, 'g')
  13. const captureEndRegex = new RegExp('(' + endRegex.source + ')', 'g')
  14. const dropSecondEndIf = new RegExp('(' + endRegex.source + contentRegex.source + ')' + endRegex.source, 'm')
  15. const inlineEndRegex = new RegExp(nonEmptyString.source + endRegex.source, 'gm')
  16. const inlineIfRegex = new RegExp(nonEmptyString.source + ifStatement.source, 'gm')
  17. // include one level of nesting
  18. const liquidBlockRegex = new RegExp(ifRegex.source + '((' + ifRegex.source + contentRegex.source + endRegex.source + '|[\\s\\S])*?)' + endRegex.source, 'gm')
  19. const elseBlockRegex = new RegExp(elseRegex.source + '(?:' + ifRegex.source + contentRegex.source + endRegex.source + '|[\\s\\S])*?' + endRegex.source, 'gm')
  20. // ----- END LIQUID PATTERNS ----- //
  21. module.exports = function removeLiquidStatements (content, versionToDeprecate, nextOldestVersion) {
  22. // see tests/fixtures/remove-liquid-statements for examples
  23. const regexes = {
  24. // remove liquid only
  25. greaterThanVersionToDeprecate: new RegExp(startTag.source + ` if ?(?: currentVersion == ('|")'?free-pro-team@latest'?('|") ?or)? currentVersion ver_gt ('|")${versionToDeprecate}('|") ` + endTag.source, 'gm'),
  26. andGreaterThanVersionToDeprecate1: new RegExp('(' + startTag.source + ` if .*?) and currentVersion ver_gt (?:'|")${versionToDeprecate}(?:'|")( ` + endTag.source + ')', 'gm'),
  27. andGreaterThanVersionToDeprecate2: new RegExp('(' + startTag.source + ` if )currentVersion ver_gt (?:'|")${versionToDeprecate}(?:'|") and (.*? ` + endTag.source + ')', 'gm'),
  28. notEqualsVersionToDeprecate: new RegExp('(' + startTag.source + ` if)(?:( currentVersion .*?) or)? currentVersion != (?:'|")${versionToDeprecate}(?:'|")( ` + endTag.source + ')', 'gm'),
  29. andNotEqualsVersionToDeprecate: new RegExp('(' + startTag.source + ` if .*?) and currentVersion != (?:'|")${versionToDeprecate}(?:'|")( ` + endTag.source + ')', 'gm'),
  30. // remove liquid and content
  31. lessThanNextOldestVersion: new RegExp(startTag.source + ` if .*?ver_lt ('|")${nextOldestVersion}('|") ?` + endTag.source, 'm'),
  32. equalsVersionToDeprecate: new RegExp(startTag.source + ` if .*?== ('|")${versionToDeprecate}('|") ?` + endTag.source, 'm')
  33. }
  34. let allLiquidBlocks = getLiquidBlocks(content)
  35. if (!allLiquidBlocks) return content
  36. // remove markup like ver_gt "2.13" and leave content
  37. content = removeLiquidOnly(content, allLiquidBlocks, regexes)
  38. // get latest liquidBlocks based on updated content
  39. allLiquidBlocks = getLiquidBlocks(content)
  40. if (allLiquidBlocks) {
  41. // remove content and surrounding markup like ver_lt "2.14" and == "2.13"
  42. content = removeLiquidAndContent(content, allLiquidBlocks, regexes)
  43. }
  44. // clean up
  45. content = removeExtraNewlines(content)
  46. return content
  47. }
  48. function getLiquidBlocks (content) {
  49. const liquidBlocks = content.match(liquidBlockRegex)
  50. if (!liquidBlocks) return
  51. // handle up to one level of nesting
  52. const innerBlocks = getInnerBlocks(liquidBlocks)
  53. return innerBlocks ? liquidBlocks.concat(innerBlocks) : liquidBlocks
  54. }
  55. function getInnerBlocks (liquidBlocks) {
  56. const innerBlocks = []
  57. liquidBlocks.forEach(block => {
  58. const ifStatements = block.match(ifRegex)
  59. if (!ifStatements) return
  60. // only process blocks that have more than one if statement
  61. if (!(ifStatements.length > 1)) return
  62. // drop first character so we don't match outer if statement
  63. // because it's already included in array of blocks
  64. const newBlock = block.slice(1)
  65. const innerIfStatements = newBlock.match(liquidBlockRegex)
  66. // add each inner if statement to array of blocks
  67. innerIfStatements.forEach(innerIfStatement => {
  68. innerBlocks.push(innerIfStatement)
  69. })
  70. })
  71. return innerBlocks
  72. }
  73. function removeLiquidOnly (content, allLiquidBlocks, regexes) {
  74. const blocksToUpdate = allLiquidBlocks
  75. .filter(block => {
  76. // inner blocks are processed separately, so we only care about first if statements
  77. const firstIf = block.match(firstIfRegex)
  78. if (block.match(regexes.greaterThanVersionToDeprecate)) return firstIf[0] === block.match(regexes.greaterThanVersionToDeprecate)[0]
  79. if (block.match(regexes.andGreaterThanVersionToDeprecate1)) return firstIf[0] === block.match(regexes.andGreaterThanVersionToDeprecate1)[0]
  80. if (block.match(regexes.andGreaterThanVersionToDeprecate2)) return firstIf[0] === block.match(regexes.andGreaterThanVersionToDeprecate2)[0]
  81. if (block.match(regexes.notEqualsVersionToDeprecate)) return firstIf[0] === block.match(regexes.notEqualsVersionToDeprecate)[0]
  82. if (block.match(regexes.andNotEqualsVersionToDeprecate)) return firstIf[0] === block.match(regexes.andNotEqualsVersionToDeprecate)[0]
  83. return false
  84. })
  85. blocksToUpdate.forEach(block => {
  86. let newBlock = block
  87. if (newBlock.match(regexes.andGreaterThanVersionToDeprecate1)) {
  88. newBlock = newBlock.replace(regexes.andGreaterThanVersionToDeprecate1, matchAndStatement1)
  89. }
  90. if (newBlock.match(regexes.andGreaterThanVersionToDeprecate2)) {
  91. newBlock = newBlock.replace(regexes.andGreaterThanVersionToDeprecate2, matchAndStatement2)
  92. }
  93. if (newBlock.match(regexes.notEqualsVersionToDeprecate)) {
  94. newBlock = newBlock.replace(regexes.notEqualsVersionToDeprecate, matchNotEqualsStatement)
  95. }
  96. if (newBlock.match(regexes.andNotEqualsVersionToDeprecate)) {
  97. newBlock = newBlock.replace(regexes.andNotEqualsVersionToDeprecate, matchAndNotEqualsStatement)
  98. }
  99. // replace else block with endif
  100. const elseBlock = getElseBlock(newBlock)
  101. if (elseBlock) {
  102. newBlock = newBlock.replace(`${elseBlock}`, '{% endif %}')
  103. }
  104. if (newBlock.match(regexes.greaterThanVersionToDeprecate) || newBlock.match(regexes.notEqualsVersionToDeprecate)) {
  105. newBlock = newBlock.replace(liquidBlockRegex, matchGreaterThan)
  106. }
  107. // we need more context to determine whether an if tag is inline or not
  108. const startIndex = content.indexOf(block)
  109. const endIndex = startIndex + block.length
  110. const leftIndex = startIndex - 10
  111. const blockWithLeftContext = content.slice(leftIndex, endIndex)
  112. // only remove newlines around non-inline tags
  113. if (blockWithLeftContext.match(inlineIfRegex) && block.match(inlineEndRegex)) {
  114. newBlock = removeLastNewline(newBlock)
  115. } else if (blockWithLeftContext.match(inlineIfRegex) && !block.match(inlineEndRegex)) {
  116. newBlock = removeLastNewline(newBlock)
  117. } else if (!blockWithLeftContext.match(inlineIfRegex) && block.match(inlineEndRegex)) {
  118. newBlock = removeFirstNewline(newBlock)
  119. } else {
  120. newBlock = removeFirstAndLastNewlines(newBlock)
  121. }
  122. // final replacement
  123. content = content.replace(block, newBlock)
  124. })
  125. return content
  126. }
  127. function matchGreaterThan (match, p1) {
  128. return p1
  129. }
  130. function matchAndStatement1 (match, p1, p2) {
  131. return p1 + p2
  132. }
  133. function matchAndStatement2 (match, p1, p2) {
  134. return p1 + p2
  135. }
  136. function matchNotEqualsStatement (match, p1, p2, p3) {
  137. if (!p2) return match
  138. return p1 + p2 + p3
  139. }
  140. function matchAndNotEqualsStatement (match, p1, p2) {
  141. return p1 + p2
  142. }
  143. function removeLiquidAndContent (content, allLiquidBlocks, regexes) {
  144. const blocksToRemove = allLiquidBlocks
  145. .filter(block => {
  146. const firstIf = block.match(firstIfRegex)
  147. if (block.match(regexes.lessThanNextOldestVersion)) return firstIf[0] === block.match(regexes.lessThanNextOldestVersion)[0]
  148. if (block.match(regexes.equalsVersionToDeprecate)) return firstIf[0] === block.match(regexes.equalsVersionToDeprecate)[0]
  149. return false
  150. })
  151. blocksToRemove.forEach(block => {
  152. const elseBlock = getElseBlock(block)
  153. // remove else conditionals but leave content
  154. if (elseBlock) {
  155. const numberOfEndTags = elseBlock[0].match(captureEndRegex)
  156. // remove the endif as part of removing the else block
  157. // if there are two endifs block, only remove the second one
  158. // this applies specifically to example8 in less-than-next-oldest fixture
  159. let newBlock
  160. if (numberOfEndTags.length > 1) {
  161. const blockWithFirstElseRemoved = elseBlock[0].replace(elseRegex, '')
  162. newBlock = blockWithFirstElseRemoved.replace(dropSecondEndIf, '$1')
  163. } else {
  164. newBlock = elseBlock[0].replace(elseRegex, '').replace(captureEndRegex, '')
  165. }
  166. content = content.replace(block, newBlock.trim())
  167. } else {
  168. content = content.replace(block, '')
  169. }
  170. })
  171. return content
  172. }
  173. function removeFirstNewline (block) {
  174. const lines = block.split(/\r?\n/)
  175. if (!first(lines).match(emptyString)) return block
  176. return drop(lines, 1).join('\n')
  177. }
  178. function removeLastNewline (block) {
  179. const lines = block.split(/\r?\n/)
  180. if (!last(lines).match(emptyString)) return block
  181. return dropRight(lines, 1).join('\n')
  182. }
  183. function removeFirstAndLastNewlines (block) {
  184. block = removeFirstNewline(block)
  185. return removeLastNewline(block)
  186. }
  187. function getElseBlock (block) {
  188. const firstIf = block.match(firstIfRegex)
  189. const elseBlock = block.match(elseBlockRegex)
  190. // if no else block, return the null result
  191. if (!elseBlock) return elseBlock
  192. // if there is an else block, check for an inner block
  193. const blockWithFirstIfRemoved = block.replace(firstIf[0], '')
  194. const innerBlock = blockWithFirstIfRemoved.match(liquidBlockRegex)
  195. // if no inner block, we can safely return the else block as is
  196. if (!innerBlock) return elseBlock
  197. // if there is an inner block, check if it is contained by the else block
  198. // if so, we can safely return the else block as is
  199. // see example8 in less-than-next-oldest
  200. if (elseBlock[0].includes(innerBlock[0])) return block.match(elseBlockRegex)
  201. // if the inner block contains the else block,
  202. // drop the inner block and return any other else blocks
  203. // see example7 in greater-than fixtures
  204. if (innerBlock[0].includes(elseBlock[0])) {
  205. const newBlock = block.replace(innerBlock[0], '')
  206. return newBlock.match(elseBlockRegex)
  207. }
  208. // otherwise, return any else matches on the original block
  209. return block.match(elseBlockRegex)
  210. }
  211. function removeExtraNewlines (content) {
  212. return content.replace(/(\r?\n){3,4}/gm, '\n\n')
  213. }
Tip!

Press p or to see the previous file or, n or to see the next file

Comments

Loading...