* Parse a single field:value filter
(field: string, valueWithOperator: string)
| 79 | * Parse a single field:value filter |
| 80 | */ |
| 81 | function parseFilter(field: string, valueWithOperator: string): ParsedFilter | null { |
| 82 | if (!(field in FILTER_FIELDS)) { |
| 83 | return null |
| 84 | } |
| 85 | |
| 86 | const filterField = field as FilterField |
| 87 | const fieldType = FILTER_FIELDS[filterField] |
| 88 | |
| 89 | let operator: ParsedFilter['operator'] = '=' |
| 90 | let value = valueWithOperator |
| 91 | |
| 92 | if (value.startsWith('>=')) { |
| 93 | operator = '>=' |
| 94 | value = value.slice(2) |
| 95 | } else if (value.startsWith('<=')) { |
| 96 | operator = '<=' |
| 97 | value = value.slice(2) |
| 98 | } else if (value.startsWith('!=')) { |
| 99 | operator = '!=' |
| 100 | value = value.slice(2) |
| 101 | } else if (value.startsWith('>')) { |
| 102 | operator = '>' |
| 103 | value = value.slice(1) |
| 104 | } else if (value.startsWith('<')) { |
| 105 | operator = '<' |
| 106 | value = value.slice(1) |
| 107 | } else if (value.startsWith('=')) { |
| 108 | operator = '=' |
| 109 | value = value.slice(1) |
| 110 | } |
| 111 | |
| 112 | const originalValue = value |
| 113 | if (value.startsWith('"') && value.endsWith('"')) { |
| 114 | value = value.slice(1, -1) |
| 115 | } |
| 116 | |
| 117 | let parsedValue: string | number | boolean = value |
| 118 | |
| 119 | if (fieldType === 'number') { |
| 120 | if (field === 'duration' && value.endsWith('ms')) { |
| 121 | parsedValue = Number.parseFloat(value.slice(0, -2)) |
| 122 | } else if (field === 'duration' && value.endsWith('s')) { |
| 123 | parsedValue = Number.parseFloat(value.slice(0, -1)) * 1000 // Convert to ms |
| 124 | } else { |
| 125 | parsedValue = Number.parseFloat(value) |
| 126 | } |
| 127 | |
| 128 | if (Number.isNaN(parsedValue)) { |
| 129 | return null |
| 130 | } |
| 131 | } |
| 132 | |
| 133 | return { |
| 134 | field: filterField, |
| 135 | operator, |
| 136 | value: parsedValue, |
| 137 | originalValue, |
| 138 | } |