(thangs, levelComponents, parentType)
| 349 | } |
| 350 | |
| 351 | sortThangComponents (thangs, levelComponents, parentType) { |
| 352 | // Here we have to sort the Components by their dependencies. |
| 353 | // It's a bit tricky though, because we don't have either soft dependencies or priority levels. |
| 354 | // Example: Programmable must come last, since it has to override any Component-provided methods that any other Component might have created. Can't enumerate all soft dependencies. |
| 355 | // Example: Plans needs to come after everything except Programmable, since other Components that add plannable methods need to have done so by the time Plans is attached. |
| 356 | // Example: Collides doesn't depend on Allied, but if both exist, Collides must come after Allied. Soft dependency example. Can't just figure out a proper priority to take care of it. |
| 357 | // Example: Moves doesn't depend on Acts, but if both exist, Moves must come after Acts. Another soft dependency example. |
| 358 | // Decision? Just special case the sort logic in here until we have more examples than these two and decide how best to handle most of the cases then, since we don't really know the whole of the problem yet. |
| 359 | // TODO: anything that depends on Programmable will break right now. |
| 360 | |
| 361 | const originalsToComponents = _.indexBy(levelComponents, 'original') // Optimization for speed |
| 362 | const alliedComponent = _.find(levelComponents, { name: 'Allied' }) |
| 363 | const actsComponent = _.find(levelComponents, { name: 'Acts' }) |
| 364 | |
| 365 | return (() => { |
| 366 | const result = [] |
| 367 | for (const thang of Array.from(thangs != null ? thangs : [])) { |
| 368 | const originalsToThangComponents = _.indexBy(thang.components, 'original') |
| 369 | const sorted = [] |
| 370 | const visit = function (c, namesToIgnore) { |
| 371 | let c2 |
| 372 | if (Array.from(sorted).includes(c)) { return } |
| 373 | const lc = originalsToComponents[c.original] |
| 374 | if (!lc) { console.error(thang.id || thang.name, 'couldn\'t find lc for', c, 'of', levelComponents) } |
| 375 | if (!lc) { return } |
| 376 | if (namesToIgnore && Array.from(namesToIgnore).includes(lc.name)) { return } |
| 377 | if (lc.name === 'Plans') { |
| 378 | // Plans always comes second-to-last, behind Programmable |
| 379 | for (c2 of Array.from(thang.components)) { visit(c2, [lc.name, 'Programmable']) } |
| 380 | } else if (lc.name === 'Programmable') { |
| 381 | // Programmable always comes last |
| 382 | for (c2 of Array.from(thang.components)) { visit(c2, [lc.name]) } |
| 383 | } else { |
| 384 | for (const d of Array.from(lc.dependencies || [])) { |
| 385 | c2 = originalsToThangComponents[d.original] |
| 386 | if (!c2) { |
| 387 | let dependent = originalsToComponents[d.original] |
| 388 | dependent = (dependent != null ? dependent.name : undefined) || d.original |
| 389 | console.error(parentType, thang.id || thang.name, 'does not have dependent Component', dependent, 'from', lc.name) |
| 390 | } |
| 391 | if (c2) { visit(c2) } |
| 392 | } |
| 393 | if ((lc.name === 'Collides') && alliedComponent) { |
| 394 | const allied = originalsToThangComponents[alliedComponent.original] |
| 395 | if (allied) { |
| 396 | visit(allied) |
| 397 | } |
| 398 | } |
| 399 | if ((lc.name === 'Moves') && actsComponent) { |
| 400 | const acts = originalsToThangComponents[actsComponent.original] |
| 401 | if (acts) { |
| 402 | visit(acts) |
| 403 | } |
| 404 | } |
| 405 | } |
| 406 | // console.log thang.id, 'sorted comps adding', lc.name |
| 407 | return sorted.push(c) |
| 408 | } |
no outgoing calls
no test coverage detected