Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
N
nfkit
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nanahira
nfkit
Commits
0c5d018f
Commit
0c5d018f
authored
Feb 16, 2026
by
nanahira
1
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix
parent
83dc2973
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
73 additions
and
23 deletions
+73
-23
src/app-context/app-context.ts
src/app-context/app-context.ts
+56
-23
tests/app-context.spec.ts
tests/app-context.spec.ts
+17
-0
No files found.
src/app-context/app-context.ts
View file @
0c5d018f
...
...
@@ -40,6 +40,7 @@ export class AppContextCore<Cur = Empty, Req = Empty> {
private
provideRecords
:
ProvideRecord
[]
=
[];
private
registry
=
new
Map
<
string
|
AnyClass
,
LoadEntry
>
();
private
objectSteps
:
ObjectStep
[]
=
[];
private
parentContexts
=
new
Set
<
AppContextCore
<
any
,
any
>>
();
started
=
false
;
private
starting
=
false
;
private
startingEntries
:
LoadEntry
[]
|
null
=
null
;
...
...
@@ -88,6 +89,57 @@ export class AppContextCore<Cur = Empty, Req = Empty> {
}
}
private applyUsedContext(other: AppContextCore<any, any>) {
// Copy provide records
if (Array.isArray(other?.provideRecords)) {
this.provideRecords.push(...other.provideRecords);
}
// Copy and apply object steps
if (Array.isArray(other?.objectSteps)) {
this.objectSteps.push(...other.objectSteps);
for (const step of other.objectSteps) {
step(this);
}
}
// If the other context has already started, copy loaded entries only.
// They should remain initialized by the source context and must not be re-initialized.
if (other?.started) {
if (other?.registry instanceof Map) {
for (const [key, value] of other.registry.entries()) {
this.registry.set(key, value);
}
}
}
}
private hasStartedInParentChain(
visited = new Set<AppContextCore<any, any>>(),
): boolean {
if (visited.has(this)) return false;
visited.add(this);
if (this.started) return true;
for (const parent of this.parentContexts) {
if (parent.hasStartedInParentChain(visited)) {
return true;
}
}
return false;
}
private propagateUsedContextToParents(
other: AppContextCore<any, any>,
visited = new Set<AppContextCore<any, any>>(),
) {
if (visited.has(this)) return;
visited.add(this);
for (const parent of this.parentContexts) {
parent.applyUsedContext(other);
parent.propagateUsedContextToParents(other, visited);
}
}
provide<
C extends AppServiceClass<Cur, Req>,
const P extends string = '',
...
...
@@ -234,34 +286,15 @@ export class AppContextCore<Cur = Empty, Req = Empty> {
for (const ctx of ctxes) {
const other = ctx as any as AppContextCore<any, any>;
if (this.
started
&& !other?.started) {
if (this.
hasStartedInParentChain()
&& !other?.started) {
throw new Error(
'Cannot use an unstarted context into a started context.',
);
}
// Copy provide records
if (Array.isArray(other?.provideRecords)) {
this.provideRecords.push(...other.provideRecords);
}
// Copy and apply object steps
if (Array.isArray(other?.objectSteps)) {
this.objectSteps.push(...other.objectSteps);
for (const step of other.objectSteps) {
step(this);
}
}
// If the other context has already started, copy loaded entries only.
// They should remain initialized by the source context and must not be re-initialized.
if (other?.started) {
if (other?.registry instanceof Map) {
for (const [key, value] of other.registry.entries()) {
this.registry.set(key, value);
}
}
}
this.applyUsedContext(other);
other.parentContexts.add(this);
this.propagateUsedContextToParents(other);
}
return this as any;
...
...
tests/app-context.spec.ts
View file @
0c5d018f
...
...
@@ -226,6 +226,23 @@ describe('app-context runtime', () => {
expect
(
root
.
needsCounter
.
counter
).
toBe
(
root
.
counter
);
expect
(
root
.
needsCounter
.
counter
.
value
).
toBe
(
34
);
});
test
(
'
late b.use(c) propagates to a and c can access providers from a
'
,
async
()
=>
{
const
p
=
createAppContext
()
.
provide
(
CounterService
,
55
,
{
provide
:
'
counter
'
})
.
define
();
const
b
=
createAppContext
().
define
();
const
a
=
createAppContext
().
use
(
p
).
use
(
b
).
define
();
const
c
=
createAppContext
()
.
provide
(
NeedsCounterService
,
{
provide
:
'
needsCounter
'
})
.
define
();
b
.
use
(
c
);
const
root
=
await
a
.
start
();
expect
((
root
as
any
).
needsCounter
.
counter
).
toBe
(
root
.
counter
);
expect
((
root
as
any
).
needsCounter
.
counter
.
value
).
toBe
(
55
);
});
});
describe
(
'
app-context type checks
'
,
()
=>
{
...
...
nanahira
@nanahira
mentioned in commit
08707118
·
Feb 16, 2026
mentioned in commit
08707118
mentioned in commit 08707118d5a23ffc85b759eb30abc34c48be8356
Toggle commit list
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment