| 250 | const seenErrors = new Set(); |
| 251 | |
| 252 | export function $structuralCheck( |
| 253 | oldValue: any, |
| 254 | newValue: any, |
| 255 | variableName: string, |
| 256 | fnName: string, |
| 257 | kind: string, |
| 258 | loc: string, |
| 259 | ): void { |
| 260 | function error(l: string, r: string, path: string, depth: number) { |
| 261 | const str = `${fnName}:${loc} [${kind}] ${variableName}${path} changed from ${l} to ${r} at depth ${depth}`; |
| 262 | if (seenErrors.has(str)) { |
| 263 | return; |
| 264 | } |
| 265 | seenErrors.add(str); |
| 266 | console.error(str); |
| 267 | } |
| 268 | const depthLimit = 2; |
| 269 | function recur(oldValue: any, newValue: any, path: string, depth: number) { |
| 270 | if (depth > depthLimit) { |
| 271 | return; |
| 272 | } else if (oldValue === newValue) { |
| 273 | return; |
| 274 | } else if (typeof oldValue !== typeof newValue) { |
| 275 | error(`type ${typeof oldValue}`, `type ${typeof newValue}`, path, depth); |
| 276 | } else if (typeof oldValue === 'object') { |
| 277 | const oldArray = Array.isArray(oldValue); |
| 278 | const newArray = Array.isArray(newValue); |
| 279 | if (oldValue === null && newValue !== null) { |
| 280 | error('null', `type ${typeof newValue}`, path, depth); |
| 281 | } else if (newValue === null) { |
| 282 | error(`type ${typeof oldValue}`, 'null', path, depth); |
| 283 | } else if (oldValue instanceof Map) { |
| 284 | if (!(newValue instanceof Map)) { |
| 285 | error(`Map instance`, `other value`, path, depth); |
| 286 | } else if (oldValue.size !== newValue.size) { |
| 287 | error( |
| 288 | `Map instance with size ${oldValue.size}`, |
| 289 | `Map instance with size ${newValue.size}`, |
| 290 | path, |
| 291 | depth, |
| 292 | ); |
| 293 | } else { |
| 294 | for (const [k, v] of oldValue) { |
| 295 | if (!newValue.has(k)) { |
| 296 | error( |
| 297 | `Map instance with key ${k}`, |
| 298 | `Map instance without key ${k}`, |
| 299 | path, |
| 300 | depth, |
| 301 | ); |
| 302 | } else { |
| 303 | recur(v, newValue.get(k), `${path}.get(${k})`, depth + 1); |
| 304 | } |
| 305 | } |
| 306 | } |
| 307 | } else if (newValue instanceof Map) { |
| 308 | error('other value', `Map instance`, path, depth); |
| 309 | } else if (oldValue instanceof Set) { |