nodes = world.generator((w) => {
try {
const scenarios = w.scenarios()
function dedupe(uses, fn, fallbackValue, collisionValue) {
let value
let collision = false
for (const use of uses) {
const v = fn(use)
if (v === undefined) {
continue
}
if (value === undefined) {
value = v
continue
}
if (value != v) {
console.log("!!collision", value, "!=", v, fn, {use, uses, fallbackValue})
collision = true
break
}
}
if (collision) {
value = collisionValue
}
if (value === undefined) {
return fallbackValue
}
return value
}
if (scenarios.length === 0) {
return []
}
function asNumber(d) {
const value = d === undefined ? d : +d
if (typeof value === "number" && isNaN(value)) {
console.warn(`Got NaN from ${d}`)
}
return value
}
const scenario = scenarios[0].ui
const components = Array.from(scenario.components(), ({def, uses}) => {
// Not a fan of the need to do this canonicalDef vs def business...
if (def.canonicalDef) {
def = def.canonicalDef
}
const users = []
const usesByUser = new Map()
for (const use of uses) {
if (use.user === undefined || use.user === scenario.rootUse) {
continue
}
// Not a fan of the need to do this canonicalDef vs def business...
const userTemps = (use.user.canonicalDef || use.user.def).temps
let userUses = usesByUser.get(userTemps)
if (userUses === undefined) {
users.push(userTemps)
usesByUser.set(userTemps, userUses = [])
}
userUses.push(use)
}
const stage = dedupe(uses, use => asNumber(use.attrs.stage), 0)
const substage = dedupe(uses, use => asNumber(use.attrs.substage), 0.5)
delete def.temps.stage
Object.defineProperty(def.temps, 'stage', {
get() { return stage },
configurable: true,
set(v) {
console.log("setting stage to", v) //, def.rawAttrs.stage.sourceLocation)
return true
},
})
delete def.temps.substage
Object.defineProperty(def.temps, 'substage', {
get() { return substage },
configurable: true,
set(v) {
console.log("setting substage to", v) //, def.rawAttrs.stage.sourceLocation)
return true
},
})
return Object.assign(
def.temps,
{
key: def.key,
name: def.name,
meta: def.meta,
uses,
sourceLocation: def.sourceLocation,
users,
depth: dedupe(uses, use => asNumber(use.attrs.depth), 1),
label: dedupe(uses, use => use.attrs.label, def.name),
fill: dedupe(uses, use => use.attrs.fill, "white"),
fontFamily: dedupe(uses, use => use.attrs.fontFamily, undefined),
fontColor: dedupe(uses, use => use.attrs.fontColor, "#333"),
fontWeight: dedupe(uses, use => asNumber(use.attrs.fontWeight), 500),
fontStyle: dedupe(uses, use => asNumber(use.attrs.fontStyle), undefined),
fontSize: dedupe(uses, use => asNumber(use.attrs.fontSize), undefined),
stroke: dedupe(uses, use => use.attrs.stroke, "#333"),
strokeWidth: dedupe(uses, use => asNumber(use.attrs.strokeWidth), 2),
hidden: dedupe(uses, use => use.attrs.hidden, undefined),
contour: dedupe(uses, use => use.attrs.contour, undefined),
contourRadius: dedupe(uses, use => use.attrs.contourRadius, undefined),
showVoronoi: dedupe(uses, use => asNumber(use.attrs.showVoronoi), false),
showAnchor: dedupe(uses, use => asNumber(use.attrs.showAnchor), false),
radius: dedupe(uses, use => asNumber(use.attrs.radius), 7),
compactRadius: dedupe(uses, use => asNumber(use.attrs.compactRadius), 5),
userEdges: Array.from(usesByUser, ([sourceDef, userUses]) => ({
target: def.temps,
source: sourceDef,
need: def.temps,
user: sourceDef,
label: dedupe(userUses, use => use.attrs.edgeLabel),
stroke: dedupe(userUses, use => use.attrs.edgeStroke, "#777"),
strokeOpacity: dedupe(userUses, use => asNumber(use.attrs.edgeStrokeOpacity), 0.3),
strokeWidth: dedupe(userUses, use => asNumber(use.attrs.edgeStrokeWidth), 1.5),
})),
})
}
)
return components
} catch (e) { console.log(e); throw e }
})