100 lines
2.4 KiB
TypeScript
100 lines
2.4 KiB
TypeScript
export type DirectiveToken = {
|
|
type: "if" | "elseif" | "else" | "endif"
|
|
condition?: string
|
|
index: number
|
|
end: number
|
|
}
|
|
|
|
function readCondition(text: string, start: number): { condition: string; end: number } | null {
|
|
let depth = 0
|
|
let inString = false
|
|
let escaped = false
|
|
|
|
for (let i = start; i < text.length; i++) {
|
|
const char = text[i]!
|
|
if (escaped) {
|
|
escaped = false
|
|
continue
|
|
}
|
|
if (char === "\\") {
|
|
escaped = true
|
|
continue
|
|
}
|
|
if (char === "\"") {
|
|
inString = !inString
|
|
continue
|
|
}
|
|
if (inString) continue
|
|
if (char === "(") {
|
|
depth += 1
|
|
continue
|
|
}
|
|
if (char === ")") {
|
|
depth -= 1
|
|
if (depth === 0 && text[i + 1] === ">") {
|
|
return { condition: text.slice(start + 1, i), end: i + 2 }
|
|
}
|
|
}
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
export function getDirectiveTokens(text: string): DirectiveToken[] {
|
|
const tokens: DirectiveToken[] = []
|
|
for (let i = 0; i < text.length; i++) {
|
|
if (text[i] !== "<" || text[i + 1] !== "@") continue
|
|
const rest = text.slice(i + 2)
|
|
const type = ["elseif", "endif", "else", "if"].find(name => rest.startsWith(name)) as DirectiveToken["type"] | undefined
|
|
if (!type) continue
|
|
const afterName = i + 2 + type.length
|
|
if ((type === "if" || type === "elseif") && text[afterName] === "(") {
|
|
const parsed = readCondition(text, afterName)
|
|
if (!parsed) continue
|
|
tokens.push({ type, condition: parsed.condition, index: i, end: parsed.end })
|
|
i = parsed.end - 1
|
|
} else if ((type === "else" || type === "endif") && text[afterName] === ">") {
|
|
tokens.push({ type, index: i, end: afterName + 1 })
|
|
i = afterName
|
|
}
|
|
}
|
|
return tokens
|
|
}
|
|
|
|
export function splitArgs(args: string): string[] {
|
|
const result: string[] = []
|
|
let current = ""
|
|
let depth = 0
|
|
let inString = false
|
|
let escaped = false
|
|
|
|
for (const char of args) {
|
|
if (escaped) {
|
|
current += char
|
|
escaped = false
|
|
continue
|
|
}
|
|
if (char === "\\") {
|
|
current += char
|
|
escaped = true
|
|
continue
|
|
}
|
|
if (char === "\"") {
|
|
current += char
|
|
inString = !inString
|
|
continue
|
|
}
|
|
if (!inString && char === "(") depth += 1
|
|
if (!inString && char === ")") depth -= 1
|
|
if (!inString && depth === 0 && char === ",") {
|
|
result.push(current.trim())
|
|
current = ""
|
|
continue
|
|
}
|
|
current += char
|
|
}
|
|
|
|
if (current.trim() !== "") result.push(current.trim())
|
|
return result
|
|
}
|