(a: unknown[], b: unknown[])
| 157 | } |
| 158 | |
| 159 | function filterArray(a: unknown[], b: unknown[]): unknown[] { |
| 160 | // Prevent infinite loop with circular references with same filter |
| 161 | const memo = seen.get(a); |
| 162 | if (memo && (memo === b)) return a; |
| 163 | |
| 164 | seen.set(a, b); |
| 165 | |
| 166 | const filtered: unknown[] = []; |
| 167 | const count = Math.min(a.length, b.length); |
| 168 | |
| 169 | for (let i = 0; i < count; ++i) { |
| 170 | const value = a[i]; |
| 171 | const subset = b[i]; |
| 172 | |
| 173 | // On regexp references, keep value as it to avoid losing pattern and flags |
| 174 | if (value instanceof RegExp) { |
| 175 | filtered.push(value); |
| 176 | continue; |
| 177 | } |
| 178 | // On date references, keep value as it to avoid losing the timestamp |
| 179 | if (value instanceof Date) { |
| 180 | filtered.push(value); |
| 181 | continue; |
| 182 | } |
| 183 | |
| 184 | // On array references, build a filtered array and filter nested objects inside |
| 185 | if (Array.isArray(value) && Array.isArray(subset)) { |
| 186 | filtered.push(filterArray(value, subset)); |
| 187 | continue; |
| 188 | } |
| 189 | |
| 190 | // On nested objects references, build a filtered object recursively |
| 191 | if (isObject(value) && isObject(subset)) { |
| 192 | // When both operands are maps, build a filtered map with common keys and filter nested objects inside |
| 193 | if ((value instanceof Map) && (subset instanceof Map)) { |
| 194 | const map = new Map( |
| 195 | [...value].filter(([k]) => subset.has(k)) |
| 196 | .map(([k, v]) => { |
| 197 | const v2 = subset.get(k); |
| 198 | if (isObject(v) && isObject(v2)) { |
| 199 | return [k, filterObject(v as Loose, v2 as Loose)]; |
| 200 | } |
| 201 | |
| 202 | return [k, v]; |
| 203 | }), |
| 204 | ); |
| 205 | filtered.push(map); |
| 206 | continue; |
| 207 | } |
| 208 | |
| 209 | // When both operands are set, build a filtered set with common values |
| 210 | if ((value instanceof Set) && (subset instanceof Set)) { |
| 211 | filtered.push(value.intersection(subset)); |
| 212 | continue; |
| 213 | } |
| 214 | |
| 215 | filtered.push(filterObject(value as Loose, subset as Loose)); |
| 216 | continue; |
no test coverage detected