using concurrent::AtomicInt** Definition of a Service.** 'ServiceDefs' are returned from [Registry.serviceDefs()]`Registry.serviceDefs`.@Jsconstmixin ServiceDef {** The service's unique ID.abstract Str id()** The Type of the service.abstract Type type()** Any aliases the service is also known as (IDs).abstract Str[] aliases()** Any aliases the service is also known as (Types).abstract Type[] aliasTypes()** The scopes this service was declared with.abstract Str[] declaredScopes()** The scopes this service has been matched with (and is able to be created in).abstract Str[] matchedScopes()** The number of services (to date) that have been built.abstract Int noOfInstancesBuilt()** Returns 'true' if the service ID or any aliases matches the given ID.abstract Bool matchesId(Str serviceId)** Returns 'true' if the service type or any aliases matches the given type.abstract Bool matchesType(Type serviceType)}@Jsinternalconstclass ServiceDefImpl : ServiceDef {overrideconst Str idoverrideconst Type typeoverrideconst Str[] declaredScopesoverrideconst Str[] matchedScopesoverrideconst Str[] aliasesoverrideconst Type[] aliasTypesconst Str[] serviceIdsconst Type[] serviceTypesconst Unsafe? contribFuncsRef // Unsafe because Javascript can't hold immutable funcsconst Unsafe builderFuncRef // Unsafe because Javascript can't hold immutable funcsconst Unsafe? buildHooksRef // Unsafe because Javascript can't hold immutable funcsconst AtomicInt noOfInstancesRef := AtomicInt(0)new make(|This|in){ in(this)this.type = this.type.toNonNullablethis.serviceTypes = this.serviceTypes.map |t->Type| { t.toNonNullable }this.aliases = this.serviceIds[1..-1]this.aliasTypes = this.serviceTypes[1..-1]} |Scope->Obj?| builderFunc(){ builderFuncRef.val } |Configuration|[]? contribFuncs(){ contribFuncsRef?.val}override Int noOfInstancesBuilt(){ noOfInstancesRef.val}override Bool matchesId(Str serviceId){ serviceIds.any {it.equalsIgnoreCase(serviceId)}}override Bool matchesType(Type serviceType){ serviceTypes.any {it == serviceType }} Obj? build(Scope currentScope){ instance := builderFunc.call(currentScope) noOfInstancesRef.incrementAndGetreturn instance} Void callBuildHooks(Scope currentScope, Obj? instance){ configs := (Func[]?) buildHooksRef?.valif(configs != null && configs.isEmpty.not){ config := ConfigurationImpl(currentScope, Str:|Scope, ServiceDef, Obj?|#, "afIoc::Scope.onCreate") configs.each {it.call(config) config.cleanupAfterMethod} hooks := (Str:Func) config.toMap hooks.each {it.call(currentScope, this, instance)}}} This validate(RegistryImpl registry){ declaredScopes.exclude |s1| { registry.scopeDefs_.keys.any |s2| { s1.equalsIgnoreCase(s2)}}{if(it.isEmpty.not)throw ArgNotFoundErr(ErrMsgs.serviceBuilder_scopesNotFound(id, it), registry.scopeDefs_.keys)}if(matchedScopes.isEmpty){ declaredScopes.each {if(type.isConst.not && registry.scopeDefs_[it].threaded.not)throw IocErr(ErrMsgs.serviceBuilder_scopeIsThreaded(id, it))}throw IocErr(ErrMsgs.serviceBuilder_noScopesMatched(id, registry.scopeDefs_.keys))}returnthis} Obj gatherConfiguration(Scope currentScope, Type configType){ config := ConfigurationImpl(currentScope, configType, id) contribFuncs?.each | |Configuration| func| { func.call(config) config.cleanupAfterMethod}if(configType.name == "List")return config.toListif(configType.name == "Map")return config.toMapthrow Err("WTF: ${configType.name} is neither a List nor a Map!?")} @NoDocoverride Str toStr(){ str := serviceIds.firstif(aliases.size > 0 || aliasTypes.size > 0){ alias := aliases.dup.addAll(aliasTypes.map {it.qname }) str += " (aliases: " + alias.join(", ") + ")"}return str}}