-
Notifications
You must be signed in to change notification settings - Fork 61.6k
/
Copy pathliquid-utils.js
152 lines (133 loc) · 4.91 KB
/
liquid-utils.js
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
import { Tokenizer, TokenKind } from 'liquidjs'
import { deprecated } from '#src/versions/lib/enterprise-server-releases.js'
const liquidTokenCache = new Map()
export function getLiquidTokens(content, { noCache = false } = {}) {
if (!content) return []
if (noCache) {
const tokenizer = new Tokenizer(content)
return tokenizer.readTopLevelTokens()
}
if (liquidTokenCache.has(content)) {
return liquidTokenCache.get(content)
}
const tokenizer = new Tokenizer(content)
const tokens = tokenizer.readTopLevelTokens()
liquidTokenCache.set(content, tokens)
return liquidTokenCache.get(content)
}
export const OUTPUT_OPEN = '{%'
export const OUTPUT_CLOSE = '%}'
export const TAG_OPEN = '{{'
export const TAG_CLOSE = '}}'
export const conditionalTags = ['if', 'elseif', 'unless', 'case', 'ifversion']
const CONDITIONAL_TAG_NAMES = ['if', 'ifversion', 'elsif', 'else', 'endif']
export function getPositionData(token, lines) {
// Liquid indexes are 0-based, but we want to
// covert to the system used by Markdownlint
const begin = token.begin + 1
const end = token.end + 1
// Account for the newline character at the end
// of each line that is not represented in the
// `lines` array
const lineLengths = lines.map((line) => line.length + 1)
let count = begin
let lineNumber = 1
for (const lineLength of lineLengths) {
if (count - lineLength <= 0) break
count = count - lineLength
lineNumber++
}
return { lineNumber, column: count, length: end - begin }
}
/* When looking for unused Liquid `ifversion` tags, there
* are a few ways content can be updated to remove
* deprecated conditional statements. This function is
* specific to tags in a statement that are removed along
* with the content in the statement. For example:
*
* {% ifversion < 1.0 %}This is removed{% endif %}
*
* Returns an array of error objects in the format expected
* by Markdownlint:
* [ { lineNumber: 1, column: 1, deleteCount: 3, }]
*/
export function getContentDeleteData(token, tokenEnd, lines) {
const { lineNumber, column } = getPositionData(token, lines)
const errorInfo = []
let begin = column - 1
// Subtract one from end of next token tag. The end of the
// current tag is one position before that.
const length = tokenEnd - token.begin
if (lines[lineNumber - 1].slice(begin).length >= length) {
return [{ lineNumber, column, deleteCount: length }]
}
let remainingLength = length
let incLineNumber = 0
while (remainingLength > 0) {
const zeroBasedLineNumber = lineNumber - 1 + incLineNumber
const line = lines[zeroBasedLineNumber]
const lineLength = line.length
let deleteCount
if (begin !== 0) {
deleteCount = line.slice(begin).length
remainingLength -= deleteCount + 1
} else if (remainingLength >= lineLength) {
deleteCount = -1
remainingLength -= lineLength + 1
} else {
deleteCount = remainingLength
remainingLength -= deleteCount
}
errorInfo.push({ lineNumber: zeroBasedLineNumber + 1, column: begin + 1, deleteCount })
begin = 0
incLineNumber++
}
return errorInfo
}
// This function returns all ifversion conditional statement tags
// and filters out any `if` conditional statements (including the
// related elsif, else, and endif tags).
// Docs doesn't use the standard `if` tag for versioning, instead the
// `ifversion` tag is used.
export function getLiquidIfVersionTokens(content) {
const tokens = getLiquidTokens(content)
.filter((token) => token.kind === TokenKind.Tag)
.filter((token) => CONDITIONAL_TAG_NAMES.includes(token.name))
let inIfStatement = false
const ifVersionTokens = []
for (const token of tokens) {
if (token.name === 'if') {
inIfStatement = true
continue
}
if (inIfStatement && token.name !== 'endif') continue
if (inIfStatement && token.name === 'endif') {
inIfStatement = false
continue
}
ifVersionTokens.push(token)
}
return ifVersionTokens
}
export function getSimplifiedSemverRange(release) {
// Liquid conditionals only use the format > or < but not
// >= or <=. Not sure exactly why.
// if startswith >, we'll check to see if the release number
// is in the deprecated list, meaning the > case can be removed
// or changed to '*'.
const releaseStrings = release.split(' ')
const releaseToCheckIndex = releaseStrings.indexOf('>') + 1
const releaseToCheck = releaseStrings[releaseToCheckIndex]
// If the release is not part of a range and the release number
// is deprecated, return '*' to indicate all ghes releases.
if (deprecated.includes(releaseToCheck) && releaseStrings.length === 2) {
return '*'
}
// When the release is a range and the lower range (e.g., `ghes > 3.12`)
// is now deprecated, return an empty string.
// Otherwise, return the release as-is.
const newRelease = deprecated.includes(releaseToCheck)
? release.replace(`> ${releaseToCheck}`, '')
: release
return newRelease
}