@foxford/den 1.0.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/adapter.cjs +8 -42
- package/adapter.d.cts +1 -1
- package/adapter.d.ts +1 -1
- package/adapter.js +5 -13
- package/chunk-5DJZZML5.cjs +224 -0
- package/chunk-A6ZPAM6Z.cjs +26 -0
- package/chunk-C7BM4DGX.cjs +18 -0
- package/chunk-HJO26HIQ.js +41 -0
- package/chunk-LJE7K7VD.cjs +35 -0
- package/chunk-TCYGDT2A.js +35 -0
- package/chunk-TPBI6TOU.js +26 -0
- package/chunk-WBHHHICS.js +18 -0
- package/chunk-WRQC6BVJ.js +224 -0
- package/chunk-XHYR3SGG.cjs +41 -0
- package/define-repository-DZg34Tb3.d.ts +83 -0
- package/define-repository-OpMj-Q9O.d.cts +83 -0
- package/define-slot-ESU7FR9O.d.ts +74 -0
- package/define-slot-RfgqKa6n.d.cts +74 -0
- package/define.cjs +15 -271
- package/define.d.cts +3 -2
- package/define.d.ts +3 -2
- package/define.js +15 -236
- package/index.cjs +88 -372
- package/index.d.cts +11 -10
- package/index.d.ts +11 -10
- package/index.js +39 -271
- package/island/index.cjs +137 -0
- package/island/index.d.cts +158 -0
- package/island/index.d.ts +158 -0
- package/island/index.js +137 -0
- package/package.json +27 -7
- package/types-Deyolj1-.d.cts +802 -0
- package/types-Deyolj1-.d.ts +802 -0
- package/view-adapter-CL0vZ-rv.d.ts +110 -0
- package/view-adapter-vwO-7b1t.d.cts +110 -0
- package/define-slot--HM6B232.d.ts +0 -500
- package/define-slot-es1K6_-L.d.cts +0 -500
- package/types-B4Arep3V.d.cts +0 -415
- package/types-B4Arep3V.d.ts +0 -415
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveDefinition
|
|
3
|
+
} from "./chunk-WBHHHICS.js";
|
|
4
|
+
import {
|
|
5
|
+
unitLogger
|
|
6
|
+
} from "./chunk-TPBI6TOU.js";
|
|
7
|
+
|
|
8
|
+
// src/core/types.ts
|
|
9
|
+
import { createToken } from "@foxford/ioc";
|
|
10
|
+
var ContainerManagerToken = createToken("core:ContainerManager");
|
|
11
|
+
var GuardRunnerToken = createToken("core:GuardRunner");
|
|
12
|
+
var NavigationManagerToken = createToken("core:NavigationManager");
|
|
13
|
+
var StateSerializerToken = createToken("core:StateSerializer");
|
|
14
|
+
var StateRegistryToken = createToken("core:StateRegistry");
|
|
15
|
+
var SlotRegistryToken = createToken("core:SlotRegistry");
|
|
16
|
+
var ActivatableToken = createToken("core:Activatable");
|
|
17
|
+
var RequestContextToken = createToken("core:RequestContext");
|
|
18
|
+
|
|
19
|
+
// src/core/slot-registry.ts
|
|
20
|
+
var SlotRegistry = class {
|
|
21
|
+
constructor() {
|
|
22
|
+
/** Слоты по имени. Повторная регистрация с тем же именем перезаписывает. */
|
|
23
|
+
this.slots = /* @__PURE__ */ new Map();
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Регистрирует слот.
|
|
27
|
+
* @param entry - Запись слота (имя + непрозрачный view)
|
|
28
|
+
*/
|
|
29
|
+
add(entry) {
|
|
30
|
+
this.slots.set(entry.name, entry);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Возвращает слот по имени.
|
|
34
|
+
* @param name - Имя слота
|
|
35
|
+
*/
|
|
36
|
+
get(name) {
|
|
37
|
+
return this.slots.get(name);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Возвращает все зарегистрированные слоты.
|
|
41
|
+
*/
|
|
42
|
+
all() {
|
|
43
|
+
return [...this.slots.values()];
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// src/define-service.ts
|
|
48
|
+
import { inject, Lifecycle } from "@foxford/ioc";
|
|
49
|
+
function defineService(token, options) {
|
|
50
|
+
const { requires, create, activate, deactivate, serialize, deserialize, scope } = options;
|
|
51
|
+
const requireTokens = requires != null ? requires : [];
|
|
52
|
+
const participatesInState = serialize !== void 0 || deserialize !== void 0;
|
|
53
|
+
return {
|
|
54
|
+
__meta: { requires: requireTokens, scope: scope != null ? scope : "app" },
|
|
55
|
+
__type: "service",
|
|
56
|
+
/**
|
|
57
|
+
* Регистрирует сервис в IoC-контейнере как Singleton.
|
|
58
|
+
* Если передана create — биндит экземпляр класса напрямую.
|
|
59
|
+
* Иначе — биндит Activatable-обёртку с хуками lifecycle.
|
|
60
|
+
* Если объявлены serialize/deserialize — при создании экземпляра сервис
|
|
61
|
+
* регистрируется участником в StateRegistry этого контейнера.
|
|
62
|
+
* @param container - Контейнер для регистрации
|
|
63
|
+
*/
|
|
64
|
+
register(container) {
|
|
65
|
+
const unitLog = unitLogger(container, token.description);
|
|
66
|
+
const factory = inject(requireTokens, (...args) => {
|
|
67
|
+
unitLog.debug(`\u0441\u043E\u0437\u0434\u0430\u043D\u0438\u0435 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 (${create ? "\u0444\u0430\u0431\u0440\u0438\u043A\u0430" : "lifecycle-\u043E\u0431\u0451\u0440\u0442\u043A\u0430"})`);
|
|
68
|
+
let instance;
|
|
69
|
+
if (create) {
|
|
70
|
+
instance = create(args);
|
|
71
|
+
} else {
|
|
72
|
+
const service = {
|
|
73
|
+
activate(params) {
|
|
74
|
+
return activate == null ? void 0 : activate(args, params);
|
|
75
|
+
},
|
|
76
|
+
deactivate() {
|
|
77
|
+
return deactivate == null ? void 0 : deactivate(args);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
instance = service;
|
|
81
|
+
}
|
|
82
|
+
if (participatesInState) {
|
|
83
|
+
unitLog.debug("\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044F \u0443\u0447\u0430\u0441\u0442\u043D\u0438\u043A\u043E\u043C StateRegistry (serialize/deserialize)");
|
|
84
|
+
registerStateParticipant(container, token, instance, args, serialize, deserialize);
|
|
85
|
+
}
|
|
86
|
+
return instance;
|
|
87
|
+
});
|
|
88
|
+
container.bind(token).toFactory(factory, { lifecycle: Lifecycle.Singleton });
|
|
89
|
+
unitLog.debug(`\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044F \u0441\u0435\u0440\u0432\u0438\u0441\u0430 (scope=${scope != null ? scope : "app"}, requires=${requireTokens.length})`);
|
|
90
|
+
},
|
|
91
|
+
token
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function registerStateParticipant(container, token, instance, deps, serialize, deserialize) {
|
|
95
|
+
if (!container.has(StateRegistryToken)) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const resolved = container.resolve(StateRegistryToken);
|
|
99
|
+
if (resolved instanceof Promise) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
;
|
|
103
|
+
resolved.add(token.description, {
|
|
104
|
+
activate: (params) => {
|
|
105
|
+
var _a;
|
|
106
|
+
return (_a = instance.activate) == null ? void 0 : _a.call(instance, params);
|
|
107
|
+
},
|
|
108
|
+
fromJSON: deserialize ? (data) => deserialize(deps, data) : void 0,
|
|
109
|
+
toJSON: serialize ? () => serialize(deps) : void 0
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// src/define-view-model.ts
|
|
114
|
+
import { inject as inject2, Lifecycle as Lifecycle2 } from "@foxford/ioc";
|
|
115
|
+
function defineViewModel(token, options) {
|
|
116
|
+
const { requires, create } = options;
|
|
117
|
+
const requireTokens = requires != null ? requires : [];
|
|
118
|
+
return {
|
|
119
|
+
__meta: { requires: requireTokens },
|
|
120
|
+
__type: "view-model",
|
|
121
|
+
/**
|
|
122
|
+
* Регистрирует VM в IoC-контейнере как Singleton.
|
|
123
|
+
* Зависимости из requires резолвятся автоматически через inject.
|
|
124
|
+
* @param container - Контейнер для регистрации
|
|
125
|
+
*/
|
|
126
|
+
register(container) {
|
|
127
|
+
const unitLog = unitLogger(container, token.description);
|
|
128
|
+
const factory = inject2(requireTokens, (...args) => {
|
|
129
|
+
unitLog.debug("\u0441\u043E\u0437\u0434\u0430\u043D\u0438\u0435 view-model");
|
|
130
|
+
return create(args);
|
|
131
|
+
});
|
|
132
|
+
container.bind(token).toFactory(factory, { lifecycle: Lifecycle2.Singleton });
|
|
133
|
+
unitLog.debug(`\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044F view-model (requires=${requireTokens.length})`);
|
|
134
|
+
},
|
|
135
|
+
/**
|
|
136
|
+
* Резолвит VM через стратегию активного host-адаптера.
|
|
137
|
+
* Вызывайте когда контейнер уже инициализирован (в render-контексте).
|
|
138
|
+
*
|
|
139
|
+
* Дескриптор не знает, откуда берётся инстанс — стратегию ставит адаптер
|
|
140
|
+
* через `installResolver()` (см. `@foxford/den/adapter`):
|
|
141
|
+
* - Vike (дефолт) — async/global: подъём по parent-chain, pending Promise при промахе;
|
|
142
|
+
* - Next — sync/island: контейнер острова из React-контекста.
|
|
143
|
+
*
|
|
144
|
+
* @returns Экземпляр VM или Promise с экземпляром
|
|
145
|
+
*/
|
|
146
|
+
resolve() {
|
|
147
|
+
return resolveDefinition(token);
|
|
148
|
+
},
|
|
149
|
+
token,
|
|
150
|
+
/**
|
|
151
|
+
* Псевдоним для resolve(). Резолвит VM через стратегию активного адаптера.
|
|
152
|
+
* @returns Экземпляр VM или Promise с экземпляром
|
|
153
|
+
*/
|
|
154
|
+
use() {
|
|
155
|
+
return this.resolve();
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// src/define-repository.ts
|
|
161
|
+
import { inject as inject3, Lifecycle as Lifecycle3 } from "@foxford/ioc";
|
|
162
|
+
function defineRepository(token, options) {
|
|
163
|
+
const { requires, create, scope } = options;
|
|
164
|
+
const requireTokens = requires != null ? requires : [];
|
|
165
|
+
return {
|
|
166
|
+
__meta: { requires: requireTokens, scope: scope != null ? scope : "app" },
|
|
167
|
+
__type: "repository",
|
|
168
|
+
/**
|
|
169
|
+
* Регистрирует репозиторий в IoC-контейнере как Singleton.
|
|
170
|
+
* Зависимости из requires резолвятся автоматически через inject.
|
|
171
|
+
* @param container - Контейнер для регистрации
|
|
172
|
+
*/
|
|
173
|
+
register(container) {
|
|
174
|
+
const unitLog = unitLogger(container, token.description);
|
|
175
|
+
const factory = inject3(requireTokens, (...args) => {
|
|
176
|
+
unitLog.debug("\u0441\u043E\u0437\u0434\u0430\u043D\u0438\u0435 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F");
|
|
177
|
+
return create(args);
|
|
178
|
+
});
|
|
179
|
+
container.bind(token).toFactory(factory, { lifecycle: Lifecycle3.Singleton });
|
|
180
|
+
unitLog.debug(`\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044F \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F (scope=${scope != null ? scope : "app"}, requires=${requireTokens.length})`);
|
|
181
|
+
},
|
|
182
|
+
token
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// src/define-slot.ts
|
|
187
|
+
function defineSlot({ view, units = [], viewLayer } = {}) {
|
|
188
|
+
return {
|
|
189
|
+
__type: "slot",
|
|
190
|
+
register(container, name) {
|
|
191
|
+
const slotLog = unitLogger(container, `slot:${name}`);
|
|
192
|
+
for (const unit of units) {
|
|
193
|
+
unit.register(container);
|
|
194
|
+
}
|
|
195
|
+
const registry = container.has(SlotRegistryToken) ? container.resolve(SlotRegistryToken) : (() => {
|
|
196
|
+
const created = new SlotRegistry();
|
|
197
|
+
container.bind(SlotRegistryToken).toValue(created);
|
|
198
|
+
slotLog.debug("\u0441\u043E\u0437\u0434\u0430\u043D SlotRegistry \u043A\u043E\u043D\u0442\u0435\u0439\u043D\u0435\u0440\u0430");
|
|
199
|
+
return created;
|
|
200
|
+
})();
|
|
201
|
+
registry.add({ name, view, viewLayer });
|
|
202
|
+
slotLog.debug(`\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044F \u0441\u043B\u043E\u0442\u0430 (units=${units.length})`);
|
|
203
|
+
},
|
|
204
|
+
units,
|
|
205
|
+
view,
|
|
206
|
+
viewLayer
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export {
|
|
211
|
+
ContainerManagerToken,
|
|
212
|
+
GuardRunnerToken,
|
|
213
|
+
NavigationManagerToken,
|
|
214
|
+
StateSerializerToken,
|
|
215
|
+
StateRegistryToken,
|
|
216
|
+
SlotRegistryToken,
|
|
217
|
+
ActivatableToken,
|
|
218
|
+
RequestContextToken,
|
|
219
|
+
SlotRegistry,
|
|
220
|
+
defineService,
|
|
221
|
+
defineViewModel,
|
|
222
|
+
defineRepository,
|
|
223
|
+
defineSlot
|
|
224
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
3
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
4
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
5
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
|
+
var __spreadValues = (a, b) => {
|
|
7
|
+
for (var prop in b || (b = {}))
|
|
8
|
+
if (__hasOwnProp.call(b, prop))
|
|
9
|
+
__defNormalProp(a, prop, b[prop]);
|
|
10
|
+
if (__getOwnPropSymbols)
|
|
11
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
12
|
+
if (__propIsEnum.call(b, prop))
|
|
13
|
+
__defNormalProp(a, prop, b[prop]);
|
|
14
|
+
}
|
|
15
|
+
return a;
|
|
16
|
+
};
|
|
17
|
+
var __async = (__this, __arguments, generator) => {
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
var fulfilled = (value) => {
|
|
20
|
+
try {
|
|
21
|
+
step(generator.next(value));
|
|
22
|
+
} catch (e) {
|
|
23
|
+
reject(e);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var rejected = (value) => {
|
|
27
|
+
try {
|
|
28
|
+
step(generator.throw(value));
|
|
29
|
+
} catch (e) {
|
|
30
|
+
reject(e);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
34
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
exports.__spreadValues = __spreadValues; exports.__async = __async;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { x as DefineServiceOptions, K as ServiceDefinition, y as DefineViewModelOptions, X as ViewModelDefinition, w as DefineRepositoryOptions, I as RepositoryDefinition } from './types-Deyolj1-.js';
|
|
2
|
+
import { Token } from '@foxford/ioc';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Определяет сервис с IoC-биндингом и опциональными lifecycle-хуками activate/deactivate.
|
|
6
|
+
* Если передана опция create — регистрирует экземпляр класса напрямую (как Singleton).
|
|
7
|
+
* Если create не передана — создаёт Activatable-обёртку с хуками activate/deactivate.
|
|
8
|
+
*
|
|
9
|
+
* @template T - Тип регистрируемого сервиса
|
|
10
|
+
* @template Deps - Кортеж токенов зависимостей (по умолчанию пустой кортеж)
|
|
11
|
+
* @param token - Токен для регистрации сервиса в IoC
|
|
12
|
+
* @param options - Опции: requires, create, activate, deactivate
|
|
13
|
+
* @returns ServiceDefinition с методом register(container)
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* // С фабрикой create (сервис-класс регистрируется напрямую)
|
|
17
|
+
* const authService = defineService(AuthServiceToken, {
|
|
18
|
+
* create: () => new AuthService(),
|
|
19
|
+
* })
|
|
20
|
+
* authService.register(appContainer)
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* // С lifecycle-хуками (без create)
|
|
24
|
+
* const dataService = defineService(DataServiceToken, {
|
|
25
|
+
* requires: [RepoToken] as const,
|
|
26
|
+
* activate: ([repo], params) => repo.loadData(params.id),
|
|
27
|
+
* deactivate: ([repo]) => repo.cleanup(),
|
|
28
|
+
* })
|
|
29
|
+
* dataService.register(appContainer)
|
|
30
|
+
*/
|
|
31
|
+
declare function defineService<T, Deps extends readonly Token<unknown>[] = readonly []>(token: Token<T>, options: DefineServiceOptions<Deps, T>): ServiceDefinition<T, Deps>;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Определяет ViewModel с IoC-биндингом и proxy для прямого импорта из view.
|
|
35
|
+
* Поддерживает deferred resolution — контейнер не нужен на момент импорта модуля.
|
|
36
|
+
* Метод resolve() делегирует резолв стратегии активного host-адаптера
|
|
37
|
+
* (см. `@foxford/den/adapter` → `installResolver`).
|
|
38
|
+
*
|
|
39
|
+
* @template T - Тип ViewModel
|
|
40
|
+
* @template Deps - Кортеж токенов зависимостей (по умолчанию пустой кортеж)
|
|
41
|
+
* @param token - Токен для регистрации VM в IoC
|
|
42
|
+
* @param options - Опции: requires, create
|
|
43
|
+
* @returns ViewModelDefinition с методами register(container) и resolve()
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* // home.vm.ts — создаётся при импорте модуля
|
|
47
|
+
* export const homeVm = defineViewModel(HomeVmToken, {
|
|
48
|
+
* requires: [UserServiceToken] as const,
|
|
49
|
+
* create: ([userService]) => ({
|
|
50
|
+
* title: userService.getTitle(),
|
|
51
|
+
* }),
|
|
52
|
+
* })
|
|
53
|
+
*
|
|
54
|
+
* // home.view.tsx — контейнер уже инициализирован
|
|
55
|
+
* const vm = await homeVm.use()
|
|
56
|
+
*/
|
|
57
|
+
declare function defineViewModel<T, Deps extends readonly Token<unknown>[] = readonly []>(token: Token<T>, options: DefineViewModelOptions<Deps, T>): ViewModelDefinition<T, Deps>;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Определяет репозиторий уровня данных с IoC-биндингом.
|
|
61
|
+
* Регистрирует Singleton-фабрику в IoC-контейнере.
|
|
62
|
+
* В отличие от defineService, репозиторий не имеет activate/deactivate lifecycle —
|
|
63
|
+
* он предоставляет методы доступа к данным без управления состоянием страницы.
|
|
64
|
+
*
|
|
65
|
+
* @template T - Тип регистрируемого репозитория
|
|
66
|
+
* @template Deps - Кортеж токенов зависимостей (по умолчанию пустой кортеж)
|
|
67
|
+
* @param token - Токен для регистрации репозитория в IoC
|
|
68
|
+
* @param options - Опции: requires, create
|
|
69
|
+
* @returns RepositoryDefinition с методом register(container)
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* const userRepo = defineRepository(UserRepoToken, {
|
|
73
|
+
* requires: [HttpServiceToken] as const,
|
|
74
|
+
* create: ([http]) => ({
|
|
75
|
+
* getUser: (id: string) => http.get(`/users/${id}`),
|
|
76
|
+
* saveUser: (data: UserData) => http.post('/users', data),
|
|
77
|
+
* }),
|
|
78
|
+
* })
|
|
79
|
+
* userRepo.register(appContainer)
|
|
80
|
+
*/
|
|
81
|
+
declare function defineRepository<T, Deps extends readonly Token<unknown>[] = readonly []>(token: Token<T>, options: DefineRepositoryOptions<Deps, T>): RepositoryDefinition<T, Deps>;
|
|
82
|
+
|
|
83
|
+
export { defineService as a, defineViewModel as b, defineRepository as d };
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { x as DefineServiceOptions, K as ServiceDefinition, y as DefineViewModelOptions, X as ViewModelDefinition, w as DefineRepositoryOptions, I as RepositoryDefinition } from './types-Deyolj1-.cjs';
|
|
2
|
+
import { Token } from '@foxford/ioc';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Определяет сервис с IoC-биндингом и опциональными lifecycle-хуками activate/deactivate.
|
|
6
|
+
* Если передана опция create — регистрирует экземпляр класса напрямую (как Singleton).
|
|
7
|
+
* Если create не передана — создаёт Activatable-обёртку с хуками activate/deactivate.
|
|
8
|
+
*
|
|
9
|
+
* @template T - Тип регистрируемого сервиса
|
|
10
|
+
* @template Deps - Кортеж токенов зависимостей (по умолчанию пустой кортеж)
|
|
11
|
+
* @param token - Токен для регистрации сервиса в IoC
|
|
12
|
+
* @param options - Опции: requires, create, activate, deactivate
|
|
13
|
+
* @returns ServiceDefinition с методом register(container)
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* // С фабрикой create (сервис-класс регистрируется напрямую)
|
|
17
|
+
* const authService = defineService(AuthServiceToken, {
|
|
18
|
+
* create: () => new AuthService(),
|
|
19
|
+
* })
|
|
20
|
+
* authService.register(appContainer)
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* // С lifecycle-хуками (без create)
|
|
24
|
+
* const dataService = defineService(DataServiceToken, {
|
|
25
|
+
* requires: [RepoToken] as const,
|
|
26
|
+
* activate: ([repo], params) => repo.loadData(params.id),
|
|
27
|
+
* deactivate: ([repo]) => repo.cleanup(),
|
|
28
|
+
* })
|
|
29
|
+
* dataService.register(appContainer)
|
|
30
|
+
*/
|
|
31
|
+
declare function defineService<T, Deps extends readonly Token<unknown>[] = readonly []>(token: Token<T>, options: DefineServiceOptions<Deps, T>): ServiceDefinition<T, Deps>;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Определяет ViewModel с IoC-биндингом и proxy для прямого импорта из view.
|
|
35
|
+
* Поддерживает deferred resolution — контейнер не нужен на момент импорта модуля.
|
|
36
|
+
* Метод resolve() делегирует резолв стратегии активного host-адаптера
|
|
37
|
+
* (см. `@foxford/den/adapter` → `installResolver`).
|
|
38
|
+
*
|
|
39
|
+
* @template T - Тип ViewModel
|
|
40
|
+
* @template Deps - Кортеж токенов зависимостей (по умолчанию пустой кортеж)
|
|
41
|
+
* @param token - Токен для регистрации VM в IoC
|
|
42
|
+
* @param options - Опции: requires, create
|
|
43
|
+
* @returns ViewModelDefinition с методами register(container) и resolve()
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* // home.vm.ts — создаётся при импорте модуля
|
|
47
|
+
* export const homeVm = defineViewModel(HomeVmToken, {
|
|
48
|
+
* requires: [UserServiceToken] as const,
|
|
49
|
+
* create: ([userService]) => ({
|
|
50
|
+
* title: userService.getTitle(),
|
|
51
|
+
* }),
|
|
52
|
+
* })
|
|
53
|
+
*
|
|
54
|
+
* // home.view.tsx — контейнер уже инициализирован
|
|
55
|
+
* const vm = await homeVm.use()
|
|
56
|
+
*/
|
|
57
|
+
declare function defineViewModel<T, Deps extends readonly Token<unknown>[] = readonly []>(token: Token<T>, options: DefineViewModelOptions<Deps, T>): ViewModelDefinition<T, Deps>;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Определяет репозиторий уровня данных с IoC-биндингом.
|
|
61
|
+
* Регистрирует Singleton-фабрику в IoC-контейнере.
|
|
62
|
+
* В отличие от defineService, репозиторий не имеет activate/deactivate lifecycle —
|
|
63
|
+
* он предоставляет методы доступа к данным без управления состоянием страницы.
|
|
64
|
+
*
|
|
65
|
+
* @template T - Тип регистрируемого репозитория
|
|
66
|
+
* @template Deps - Кортеж токенов зависимостей (по умолчанию пустой кортеж)
|
|
67
|
+
* @param token - Токен для регистрации репозитория в IoC
|
|
68
|
+
* @param options - Опции: requires, create
|
|
69
|
+
* @returns RepositoryDefinition с методом register(container)
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* const userRepo = defineRepository(UserRepoToken, {
|
|
73
|
+
* requires: [HttpServiceToken] as const,
|
|
74
|
+
* create: ([http]) => ({
|
|
75
|
+
* getUser: (id: string) => http.get(`/users/${id}`),
|
|
76
|
+
* saveUser: (data: UserData) => http.post('/users', data),
|
|
77
|
+
* }),
|
|
78
|
+
* })
|
|
79
|
+
* userRepo.register(appContainer)
|
|
80
|
+
*/
|
|
81
|
+
declare function defineRepository<T, Deps extends readonly Token<unknown>[] = readonly []>(token: Token<T>, options: DefineRepositoryOptions<Deps, T>): RepositoryDefinition<T, Deps>;
|
|
82
|
+
|
|
83
|
+
export { defineService as a, defineViewModel as b, defineRepository as d };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { z as Definition, s as LayerDefinition } from './types-Deyolj1-.js';
|
|
2
|
+
import { Container } from '@foxford/ioc';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Дескриптор слота — host-агностичен: непрозрачный `view` + опциональные `units`.
|
|
6
|
+
*
|
|
7
|
+
* `view` типизирован как `unknown` — ядро не знает про React/Vue: рендерит его view-адаптер.
|
|
8
|
+
*
|
|
9
|
+
* Имени у слота НЕТ: его выдаёт тот, кто слот к себе взял, ключом в карте `slots` своего
|
|
10
|
+
* дескриптора. Так адрес места принадлежит хозяину места, а не пакету, который написал для
|
|
11
|
+
* него view, и занять чужое пространство имён нечем — префикс не в руках объявляющего.
|
|
12
|
+
*/
|
|
13
|
+
interface SlotDefinition {
|
|
14
|
+
/** Дискриминатор типа. */
|
|
15
|
+
readonly __type: 'slot';
|
|
16
|
+
/** Непрозрачная ссылка на view слота (компонент view-фреймворка). */
|
|
17
|
+
readonly view?: unknown;
|
|
18
|
+
/** Data/Business единицы слота (изолированная секция). */
|
|
19
|
+
readonly units: readonly Definition<unknown>[];
|
|
20
|
+
/** View-слой слота, если он переопределён (см. {@link DefineSlotOptions.viewLayer}). */
|
|
21
|
+
readonly viewLayer?: LayerDefinition;
|
|
22
|
+
/**
|
|
23
|
+
* Регистрирует единицы слота и кладёт сам слот в `SlotRegistry` контейнера.
|
|
24
|
+
* @param container - Контейнер (острова/страницы/запроса)
|
|
25
|
+
* @param name - Имя слота в этом контейнере — ключ из карты `slots` дескриптора
|
|
26
|
+
*/
|
|
27
|
+
register(container: Container, name: string): void;
|
|
28
|
+
}
|
|
29
|
+
/** Опции `defineSlot`. */
|
|
30
|
+
interface DefineSlotOptions {
|
|
31
|
+
/**
|
|
32
|
+
* Непрозрачная ссылка на view слота. Необязательна: чистое место под чужой контент
|
|
33
|
+
* своего содержимого не имеет.
|
|
34
|
+
*/
|
|
35
|
+
view?: unknown;
|
|
36
|
+
/** Data/Business единицы слота (по умолчанию пусто). */
|
|
37
|
+
units?: readonly Definition<unknown>[];
|
|
38
|
+
/**
|
|
39
|
+
* Переопределение view-слоя ДЛЯ ЭТОГО слота: `defineLayer(ViewLayerToken, { adapter })`.
|
|
40
|
+
*
|
|
41
|
+
* По умолчанию слот рисуется адаптером острова, в который попал, — так слот из чужого
|
|
42
|
+
* пакета встаёт в любое приложение. Указывать стоит там, где слот написан на другом
|
|
43
|
+
* фреймворке, чем принимающий остров.
|
|
44
|
+
*/
|
|
45
|
+
viewLayer?: LayerDefinition;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Объявляет слот — самостоятельную `define*`-единицу расширения.
|
|
49
|
+
*
|
|
50
|
+
* `register(container, name)` регистрирует `units` и добавляет `{ name, view }` в
|
|
51
|
+
* `SlotRegistry` контейнера (get-or-create). Реестр живёт в контейнере ОСТРОВА, поэтому
|
|
52
|
+
* имена в нём локальные и с соседними приложениями не пересекаются; глобальный адрес для
|
|
53
|
+
* `mountsInto` собирается из имени приложения (см. `slotAddress` в `@foxford/den/island`).
|
|
54
|
+
*
|
|
55
|
+
* Рендерит слот view-адаптер — по умолчанию тот же, что у принимающего острова; свой
|
|
56
|
+
* адаптер слот получает через `viewLayer`.
|
|
57
|
+
*
|
|
58
|
+
* @param options - Непрозрачный `view`, опциональные `units` и `viewLayer`
|
|
59
|
+
* @returns Дескриптор `SlotDefinition`
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* // приложение объявляет место у себя — имя даёт ключ в карте `slots`
|
|
63
|
+
* export default defineApp({
|
|
64
|
+
* name: 'market-app',
|
|
65
|
+
* slots: { aside: defineSlot({ view: AsideView }) },
|
|
66
|
+
* })
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* // любой пакет — экспортит слот-юнит, не зная, куда он смонтируется и как будет назван
|
|
70
|
+
* export const chatSlot = defineSlot({ view: ChatView, units: [chatRepository] })
|
|
71
|
+
*/
|
|
72
|
+
declare function defineSlot({ view, units, viewLayer }?: DefineSlotOptions): SlotDefinition;
|
|
73
|
+
|
|
74
|
+
export { type DefineSlotOptions as D, type SlotDefinition as S, defineSlot as d };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { z as Definition, s as LayerDefinition } from './types-Deyolj1-.cjs';
|
|
2
|
+
import { Container } from '@foxford/ioc';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Дескриптор слота — host-агностичен: непрозрачный `view` + опциональные `units`.
|
|
6
|
+
*
|
|
7
|
+
* `view` типизирован как `unknown` — ядро не знает про React/Vue: рендерит его view-адаптер.
|
|
8
|
+
*
|
|
9
|
+
* Имени у слота НЕТ: его выдаёт тот, кто слот к себе взял, ключом в карте `slots` своего
|
|
10
|
+
* дескриптора. Так адрес места принадлежит хозяину места, а не пакету, который написал для
|
|
11
|
+
* него view, и занять чужое пространство имён нечем — префикс не в руках объявляющего.
|
|
12
|
+
*/
|
|
13
|
+
interface SlotDefinition {
|
|
14
|
+
/** Дискриминатор типа. */
|
|
15
|
+
readonly __type: 'slot';
|
|
16
|
+
/** Непрозрачная ссылка на view слота (компонент view-фреймворка). */
|
|
17
|
+
readonly view?: unknown;
|
|
18
|
+
/** Data/Business единицы слота (изолированная секция). */
|
|
19
|
+
readonly units: readonly Definition<unknown>[];
|
|
20
|
+
/** View-слой слота, если он переопределён (см. {@link DefineSlotOptions.viewLayer}). */
|
|
21
|
+
readonly viewLayer?: LayerDefinition;
|
|
22
|
+
/**
|
|
23
|
+
* Регистрирует единицы слота и кладёт сам слот в `SlotRegistry` контейнера.
|
|
24
|
+
* @param container - Контейнер (острова/страницы/запроса)
|
|
25
|
+
* @param name - Имя слота в этом контейнере — ключ из карты `slots` дескриптора
|
|
26
|
+
*/
|
|
27
|
+
register(container: Container, name: string): void;
|
|
28
|
+
}
|
|
29
|
+
/** Опции `defineSlot`. */
|
|
30
|
+
interface DefineSlotOptions {
|
|
31
|
+
/**
|
|
32
|
+
* Непрозрачная ссылка на view слота. Необязательна: чистое место под чужой контент
|
|
33
|
+
* своего содержимого не имеет.
|
|
34
|
+
*/
|
|
35
|
+
view?: unknown;
|
|
36
|
+
/** Data/Business единицы слота (по умолчанию пусто). */
|
|
37
|
+
units?: readonly Definition<unknown>[];
|
|
38
|
+
/**
|
|
39
|
+
* Переопределение view-слоя ДЛЯ ЭТОГО слота: `defineLayer(ViewLayerToken, { adapter })`.
|
|
40
|
+
*
|
|
41
|
+
* По умолчанию слот рисуется адаптером острова, в который попал, — так слот из чужого
|
|
42
|
+
* пакета встаёт в любое приложение. Указывать стоит там, где слот написан на другом
|
|
43
|
+
* фреймворке, чем принимающий остров.
|
|
44
|
+
*/
|
|
45
|
+
viewLayer?: LayerDefinition;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Объявляет слот — самостоятельную `define*`-единицу расширения.
|
|
49
|
+
*
|
|
50
|
+
* `register(container, name)` регистрирует `units` и добавляет `{ name, view }` в
|
|
51
|
+
* `SlotRegistry` контейнера (get-or-create). Реестр живёт в контейнере ОСТРОВА, поэтому
|
|
52
|
+
* имена в нём локальные и с соседними приложениями не пересекаются; глобальный адрес для
|
|
53
|
+
* `mountsInto` собирается из имени приложения (см. `slotAddress` в `@foxford/den/island`).
|
|
54
|
+
*
|
|
55
|
+
* Рендерит слот view-адаптер — по умолчанию тот же, что у принимающего острова; свой
|
|
56
|
+
* адаптер слот получает через `viewLayer`.
|
|
57
|
+
*
|
|
58
|
+
* @param options - Непрозрачный `view`, опциональные `units` и `viewLayer`
|
|
59
|
+
* @returns Дескриптор `SlotDefinition`
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* // приложение объявляет место у себя — имя даёт ключ в карте `slots`
|
|
63
|
+
* export default defineApp({
|
|
64
|
+
* name: 'market-app',
|
|
65
|
+
* slots: { aside: defineSlot({ view: AsideView }) },
|
|
66
|
+
* })
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* // любой пакет — экспортит слот-юнит, не зная, куда он смонтируется и как будет назван
|
|
70
|
+
* export const chatSlot = defineSlot({ view: ChatView, units: [chatRepository] })
|
|
71
|
+
*/
|
|
72
|
+
declare function defineSlot({ view, units, viewLayer }?: DefineSlotOptions): SlotDefinition;
|
|
73
|
+
|
|
74
|
+
export { type DefineSlotOptions as D, type SlotDefinition as S, defineSlot as d };
|