targwire 1.0.4 → 1.1.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/README.md CHANGED
@@ -5,6 +5,7 @@ Mini **IoC container** tipado para TypeScript com **Singleton**, **Transient (Fa
5
5
  - ✅ Tokens tipados (`Token<T>`)
6
6
  - ✅ Ciclos de vida: `registerSingleton`, `registerFactory` (transient), `createScope` (scoped)
7
7
  - ✅ Overrides e reset (testes/HMR)
8
+ - ✅ Opcionalmente via decorators: `@Injectable`, `@Inject`, `@Resolve`
8
9
  - ✅ Plugin registry para registrar módulos do **app** e dar `bootstrapIOC()` uma vez só
9
10
 
10
11
  ---
@@ -105,6 +106,10 @@ import {
105
106
  overrideValue,
106
107
  overrideSingleton,
107
108
  overrideFactory,
109
+ // Decorators (opcional):
110
+ Injectable, // registra classe como singleton (default) ou transient
111
+ Inject, // força token de parâmetro no construtor
112
+ Resolve, // injeta propriedade via getter
108
113
  // Plugins/Bootstrap
109
114
  registerIOCPlugin, // (registrar: (c: Container) => void)
110
115
  bootstrapIOC, // executa todos os registrars uma vez
@@ -156,6 +161,51 @@ bootstrapIOC();
156
161
 
157
162
  ---
158
163
 
164
+ ## Uso com decorators (opcional)
165
+
166
+ Os decorators facilitam o registro/injeção via construtor. **Habilite decoradores** no seu projeto (`experimentalDecorators` + `emitDecoratorMetadata`) e, se quiser inferir tipos automaticamente, instale `reflect-metadata` e importe-a no entrypoint.
167
+
168
+ ```bash
169
+ npm i reflect-metadata # opcional
170
+ ```
171
+
172
+ ### Registrar classes
173
+ ```ts
174
+ import 'reflect-metadata'; // se quiser inferência automática de tipos
175
+ import { Injectable, Inject, defineToken, resolve } from 'targwire';
176
+
177
+ const RepoToken = defineToken<UserRepo>('Users.Repo');
178
+
179
+ @Injectable() // singleton padrão
180
+ class GetUsers {
181
+ constructor(@Inject(RepoToken) private repo: UserRepo) {}
182
+ }
183
+
184
+ @Injectable({ lifetime: 'transient' })
185
+ class Controller {
186
+ constructor(private usecase: GetUsers) {} // inferido via reflect-metadata
187
+ }
188
+
189
+ const controller = resolve(defineToken<Controller>('Controller')); // token padrão = nome da classe
190
+ ```
191
+
192
+ ### Injeção por propriedade
193
+ ```ts
194
+ import { Resolve, defineToken } from 'targwire';
195
+ import type { Logger } from './logger';
196
+
197
+ const LoggerToken = defineToken<Logger>('Logger');
198
+
199
+ class MyComponent {
200
+ @Resolve(LoggerToken)
201
+ logger!: Logger;
202
+ }
203
+ ```
204
+
205
+ > Sem `reflect-metadata`, anote parâmetros com `@Inject(Token)` para evitar erros de token ausente.
206
+
207
+ ---
208
+
159
209
  ## Exemplos
160
210
 
161
211
  ### Singleton
package/dist/index.cjs CHANGED
@@ -21,6 +21,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  Container: () => Container,
24
+ Inject: () => Inject,
25
+ Injectable: () => Injectable,
26
+ Resolve: () => Resolve,
24
27
  _clearIOCPlugins: () => _clearIOCPlugins,
25
28
  bootstrapIOC: () => bootstrapIOC,
26
29
  createScope: () => createScope,
@@ -131,9 +134,73 @@ function bootstrapIOC() {
131
134
  }
132
135
  bootstrapped = true;
133
136
  }
137
+
138
+ // src/decorators.ts
139
+ var ReflectMeta = Reflect;
140
+ var paramTokens = /* @__PURE__ */ new WeakMap();
141
+ function Inject(tokenOrDesc) {
142
+ return (target, _propertyKey, index) => {
143
+ var _a;
144
+ const existing = (_a = paramTokens.get(target)) != null ? _a : [];
145
+ const token = typeof tokenOrDesc === "string" ? defineToken(tokenOrDesc) : tokenOrDesc;
146
+ existing[index] = token;
147
+ paramTokens.set(target, existing);
148
+ };
149
+ }
150
+ function getConstructorTokens(target) {
151
+ var _a, _b;
152
+ const explicit = (_a = paramTokens.get(target)) != null ? _a : [];
153
+ const designTypes = (_b = ReflectMeta.getMetadata) == null ? void 0 : _b.call(ReflectMeta, "design:paramtypes", target);
154
+ const inferred = designTypes != null ? designTypes : [];
155
+ const max = Math.max(explicit.length, inferred.length);
156
+ const tokens = [];
157
+ for (let i = 0; i < max; i++) {
158
+ const provided = explicit[i];
159
+ if (provided) {
160
+ tokens.push(provided);
161
+ continue;
162
+ }
163
+ const type = inferred[i];
164
+ if (type && type.name && type.name !== "Object") {
165
+ tokens.push(defineToken(type.name));
166
+ continue;
167
+ }
168
+ throw new Error(`Token ausente para o par\xE2metro ${i} do construtor de ${target.name}. Adicione @Inject().`);
169
+ }
170
+ return tokens;
171
+ }
172
+ function Injectable(options = {}) {
173
+ return (ctor) => {
174
+ var _a, _b;
175
+ const container = (_a = options.container) != null ? _a : rootContainer;
176
+ const token = typeof options.token === "string" ? defineToken(options.token) : (_b = options.token) != null ? _b : defineToken(ctor.name);
177
+ const deps = getConstructorTokens(ctor);
178
+ const factory = () => new ctor(...deps.map((t) => container.resolve(t)));
179
+ if (options.lifetime === "transient") {
180
+ container.registerFactory(token, factory);
181
+ } else {
182
+ container.registerSingleton(token, factory);
183
+ }
184
+ };
185
+ }
186
+ function Resolve(tokenOrDesc) {
187
+ return (target, propertyKey) => {
188
+ const token = tokenOrDesc === void 0 ? defineToken(String(propertyKey)) : typeof tokenOrDesc === "string" ? defineToken(tokenOrDesc) : tokenOrDesc;
189
+ Object.defineProperty(target, propertyKey, {
190
+ get() {
191
+ return rootContainer.resolve(token);
192
+ },
193
+ enumerable: true,
194
+ configurable: true
195
+ });
196
+ };
197
+ }
134
198
  // Annotate the CommonJS export names for ESM import in node:
135
199
  0 && (module.exports = {
136
200
  Container,
201
+ Inject,
202
+ Injectable,
203
+ Resolve,
137
204
  _clearIOCPlugins,
138
205
  bootstrapIOC,
139
206
  createScope,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/container.ts","../src/plugins.ts","../src/bootstrap.ts"],"sourcesContent":["export * from './container';\nexport * from './plugins';\nexport * from './bootstrap';\n","// src/container.ts\ntype Factory<T> = () => T;\nexport type Token<T> = symbol & { __type?: T };\n\ntype Provider<T> =\n | { kind: 'value'; value: T }\n | { kind: 'singleton'; factory: Factory<T>; instance?: T }\n | { kind: 'factory'; factory: Factory<T> };\n\nexport class Container {\n private registry = new Map<Token<any>, Provider<any>>();\n constructor(private parent?: Container) {}\n\n defineToken<T>(desc: string): Token<T> {\n return Symbol.for(`ioc:${desc}`) as Token<T>;\n }\n\n registerValue<T>(token: Token<T>, value: T) {\n this.registry.set(token, { kind: 'value', value });\n }\n registerSingleton<T>(token: Token<T>, factory: Factory<T>) {\n this.registry.set(token, { kind: 'singleton', factory });\n }\n registerFactory<T>(token: Token<T>, factory: Factory<T>) {\n this.registry.set(token, { kind: 'factory', factory });\n }\n\n isRegistered<T>(token: Token<T>): boolean {\n return this.registry.has(token) || (!!this.parent && this.parent.isRegistered(token));\n }\n\n resolve<T>(token: Token<T>): T {\n if (this.registry.has(token)) {\n const prov = this.registry.get(token)!;\n switch (prov.kind) {\n case 'value': return prov.value as T;\n case 'singleton':\n if (prov.instance === undefined) prov.instance = prov.factory();\n return prov.instance as T;\n case 'factory': return prov.factory();\n }\n }\n if (this.parent) return this.parent.resolve(token);\n throw new Error(`Token not registered: ${String(token)}`);\n }\n\n override<T>(token: Token<T>, provider: Provider<T>) {\n this.registry.set(token, provider);\n }\n\n reset(tokens?: Token<any>[]) {\n if (!tokens) return void this.registry.clear();\n for (const t of tokens) this.registry.delete(t);\n }\n\n createScope(): Container {\n return new Container(this);\n }\n\n overrideValue<T>(token: Token<T>, value: T) { this.override(token, { kind: 'value', value }); }\n overrideSingleton<T>(token: Token<T>, factory: Factory<T>) { this.override(token, { kind: 'singleton', factory }); }\n overrideFactory<T>(token: Token<T>, factory: Factory<T>) { this.override(token, { kind: 'factory', factory }); }\n}\n\n// Root container + helpers\nexport const rootContainer = new Container();\nexport const defineToken = <T>(desc: string) => rootContainer.defineToken<T>(desc);\nexport const registerValue = <T>(t: Token<T>, v: T) => rootContainer.registerValue(t, v);\nexport const registerSingleton = <T>(t: Token<T>, f: Factory<T>) => rootContainer.registerSingleton(t, f);\nexport const registerFactory = <T>(t: Token<T>, f: Factory<T>) => rootContainer.registerFactory(t, f);\nexport const resolve = <T>(t: Token<T>) => rootContainer.resolve<T>(t);\nexport const isRegistered = <T>(t: Token<T>) => rootContainer.isRegistered<T>(t);\nexport const reset = (tokens?: Token<any>[]) => rootContainer.reset(tokens);\nexport const createScope = () => rootContainer.createScope();\nexport const overrideValue = <T>(t: Token<T>, v: T) => rootContainer.overrideValue(t, v);\nexport const overrideSingleton = <T>(t: Token<T>, f: Factory<T>) => rootContainer.overrideSingleton(t, f);\nexport const overrideFactory = <T>(t: Token<T>, f: Factory<T>) => rootContainer.overrideFactory(t, f);\n","// src/plugins.ts\nimport type { Container } from './container';\n\nexport type IOCRegistrar = (c: Container) => void;\n\nconst registrars: IOCRegistrar[] = [];\n\nexport function registerIOCPlugin(registrar: IOCRegistrar) {\n registrars.push(registrar);\n}\n\n/** Apenas leitura (sem expor o array interno) */\nexport function getIOCPlugins(): IOCRegistrar[] {\n return registrars.slice();\n}\n\n/** Para testes: limpar a lista de registrars */\nexport function _clearIOCPlugins() {\n registrars.length = 0;\n}\n","// src/bootstrap.ts\nimport { rootContainer } from './container';\nimport { getIOCPlugins } from './plugins';\n\nlet bootstrapped = false;\n\n/**\n * Executa todos os registrars previamente registrados (plugins de módulos).\n * Deve ser chamado uma única vez no início do app.\n */\nexport function bootstrapIOC(): void {\n if (bootstrapped) return;\n for (const reg of getIOCPlugins()) {\n reg(rootContainer);\n }\n bootstrapped = true;\n}\n\nexport default bootstrapIOC;\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/container.ts","../src/plugins.ts","../src/bootstrap.ts","../src/decorators.ts"],"sourcesContent":["export * from './container';\nexport * from './plugins';\nexport * from './bootstrap';\nexport * from './decorators';\n","// src/container.ts\ntype Factory<T> = () => T;\nexport type Token<T> = symbol & { __type?: T };\n\ntype Provider<T> =\n | { kind: 'value'; value: T }\n | { kind: 'singleton'; factory: Factory<T>; instance?: T }\n | { kind: 'factory'; factory: Factory<T> };\n\nexport class Container {\n private registry = new Map<Token<any>, Provider<any>>();\n constructor(private parent?: Container) {}\n\n defineToken<T>(desc: string): Token<T> {\n return Symbol.for(`ioc:${desc}`) as Token<T>;\n }\n\n registerValue<T>(token: Token<T>, value: T) {\n this.registry.set(token, { kind: 'value', value });\n }\n registerSingleton<T>(token: Token<T>, factory: Factory<T>) {\n this.registry.set(token, { kind: 'singleton', factory });\n }\n registerFactory<T>(token: Token<T>, factory: Factory<T>) {\n this.registry.set(token, { kind: 'factory', factory });\n }\n\n isRegistered<T>(token: Token<T>): boolean {\n return this.registry.has(token) || (!!this.parent && this.parent.isRegistered(token));\n }\n\n resolve<T>(token: Token<T>): T {\n if (this.registry.has(token)) {\n const prov = this.registry.get(token)!;\n switch (prov.kind) {\n case 'value': return prov.value as T;\n case 'singleton':\n if (prov.instance === undefined) prov.instance = prov.factory();\n return prov.instance as T;\n case 'factory': return prov.factory();\n }\n }\n if (this.parent) return this.parent.resolve(token);\n throw new Error(`Token not registered: ${String(token)}`);\n }\n\n override<T>(token: Token<T>, provider: Provider<T>) {\n this.registry.set(token, provider);\n }\n\n reset(tokens?: Token<any>[]) {\n if (!tokens) return void this.registry.clear();\n for (const t of tokens) this.registry.delete(t);\n }\n\n createScope(): Container {\n return new Container(this);\n }\n\n overrideValue<T>(token: Token<T>, value: T) { this.override(token, { kind: 'value', value }); }\n overrideSingleton<T>(token: Token<T>, factory: Factory<T>) { this.override(token, { kind: 'singleton', factory }); }\n overrideFactory<T>(token: Token<T>, factory: Factory<T>) { this.override(token, { kind: 'factory', factory }); }\n}\n\n// Root container + helpers\nexport const rootContainer = new Container();\nexport const defineToken = <T>(desc: string) => rootContainer.defineToken<T>(desc);\nexport const registerValue = <T>(t: Token<T>, v: T) => rootContainer.registerValue(t, v);\nexport const registerSingleton = <T>(t: Token<T>, f: Factory<T>) => rootContainer.registerSingleton(t, f);\nexport const registerFactory = <T>(t: Token<T>, f: Factory<T>) => rootContainer.registerFactory(t, f);\nexport const resolve = <T>(t: Token<T>) => rootContainer.resolve<T>(t);\nexport const isRegistered = <T>(t: Token<T>) => rootContainer.isRegistered<T>(t);\nexport const reset = (tokens?: Token<any>[]) => rootContainer.reset(tokens);\nexport const createScope = () => rootContainer.createScope();\nexport const overrideValue = <T>(t: Token<T>, v: T) => rootContainer.overrideValue(t, v);\nexport const overrideSingleton = <T>(t: Token<T>, f: Factory<T>) => rootContainer.overrideSingleton(t, f);\nexport const overrideFactory = <T>(t: Token<T>, f: Factory<T>) => rootContainer.overrideFactory(t, f);\n","// src/plugins.ts\nimport type { Container } from './container';\n\nexport type IOCRegistrar = (c: Container) => void;\n\nconst registrars: IOCRegistrar[] = [];\n\nexport function registerIOCPlugin(registrar: IOCRegistrar) {\n registrars.push(registrar);\n}\n\n/** Apenas leitura (sem expor o array interno) */\nexport function getIOCPlugins(): IOCRegistrar[] {\n return registrars.slice();\n}\n\n/** Para testes: limpar a lista de registrars */\nexport function _clearIOCPlugins() {\n registrars.length = 0;\n}\n","// src/bootstrap.ts\nimport { rootContainer } from './container';\nimport { getIOCPlugins } from './plugins';\n\nlet bootstrapped = false;\n\n/**\n * Executa todos os registrars previamente registrados (plugins de módulos).\n * Deve ser chamado uma única vez no início do app.\n */\nexport function bootstrapIOC(): void {\n if (bootstrapped) return;\n for (const reg of getIOCPlugins()) {\n reg(rootContainer);\n }\n bootstrapped = true;\n}\n\nexport default bootstrapIOC;\n","// src/decorators.ts\nimport { Container, Token, defineToken, rootContainer } from './container';\n\ntype Lifetime = 'singleton' | 'transient';\n\ntype InjectableOptions<T> = {\n token?: Token<T> | string;\n lifetime?: Lifetime;\n container?: Container;\n};\n\n// Guarded access to Reflect metadata so the lib works even without reflect-metadata.\ntype ReflectWithMetadata = typeof Reflect & { getMetadata?: (key: string, target: object) => any };\nconst ReflectMeta = Reflect as ReflectWithMetadata;\n\n// Internal store for constructor parameter tokens provided via @Inject.\nconst paramTokens = new WeakMap<Function, (Token<any> | undefined)[]>();\n\n/**\n * Marca um parâmetro do construtor para ser resolvido a partir de um Token.\n * Use quando o tipo não pode ser deduzido ou para customizar o Token.\n */\nexport function Inject(tokenOrDesc: Token<any> | string): ParameterDecorator {\n return (target, _propertyKey, index) => {\n const existing = paramTokens.get(target as unknown as Function) ?? [];\n const token =\n typeof tokenOrDesc === 'string'\n ? defineToken(tokenOrDesc)\n : tokenOrDesc;\n existing[index] = token;\n paramTokens.set(target as unknown as Function, existing);\n };\n}\n\n/**\n * Resolve os Tokens dos parâmetros do construtor usando:\n * 1) @Inject declarado explicitamente\n * 2) design:paramtypes (se reflect-metadata estiver carregado)\n */\nfunction getConstructorTokens(target: Function): Token<any>[] {\n const explicit = paramTokens.get(target) ?? [];\n const designTypes = ReflectMeta.getMetadata?.('design:paramtypes', target) as any[] | undefined;\n const inferred = designTypes ?? [];\n\n const max = Math.max(explicit.length, inferred.length);\n const tokens: Token<any>[] = [];\n\n for (let i = 0; i < max; i++) {\n const provided = explicit[i];\n if (provided) {\n tokens.push(provided);\n continue;\n }\n const type = inferred[i];\n if (type && type.name && type.name !== 'Object') {\n tokens.push(defineToken(type.name));\n continue;\n }\n throw new Error(`Token ausente para o parâmetro ${i} do construtor de ${target.name}. Adicione @Inject().`);\n }\n\n return tokens;\n}\n\n/**\n * Registra a classe no container e monta as dependências via construtor.\n *\n * - Por padrão registra como singleton no rootContainer.\n * - Se lifetime === 'transient', registra como factory.\n * - O token padrão é o nome da classe, mas pode ser passado via options.token.\n */\nexport function Injectable<T>(options: InjectableOptions<T> = {}): ClassDecorator {\n return (ctor: any) => {\n const container = options.container ?? rootContainer;\n const token =\n typeof options.token === 'string'\n ? defineToken<T>(options.token)\n : options.token ?? defineToken<T>(ctor.name);\n const deps = getConstructorTokens(ctor);\n const factory = () => new ctor(...deps.map((t) => container.resolve(t)));\n\n if (options.lifetime === 'transient') {\n container.registerFactory(token, factory);\n } else {\n container.registerSingleton(token, factory);\n }\n };\n}\n\n/**\n * Injeta uma dependência em um campo usando o rootContainer.\n * Útil para cenários React/Expo em que não queremos mudar o construtor.\n */\nexport function Resolve(tokenOrDesc?: Token<any> | string): PropertyDecorator {\n return (target, propertyKey) => {\n const token =\n tokenOrDesc === undefined\n ? defineToken(String(propertyKey))\n : typeof tokenOrDesc === 'string'\n ? defineToken(tokenOrDesc)\n : tokenOrDesc;\n\n Object.defineProperty(target, propertyKey, {\n get() {\n return rootContainer.resolve(token);\n },\n enumerable: true,\n configurable: true,\n });\n };\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -56,4 +56,29 @@ declare function _clearIOCPlugins(): void;
56
56
  */
57
57
  declare function bootstrapIOC(): void;
58
58
 
59
- export { Container, type IOCRegistrar, type Token, _clearIOCPlugins, bootstrapIOC, createScope, defineToken, getIOCPlugins, isRegistered, overrideFactory, overrideSingleton, overrideValue, registerFactory, registerIOCPlugin, registerSingleton, registerValue, reset, resolve, rootContainer };
59
+ type Lifetime = 'singleton' | 'transient';
60
+ type InjectableOptions<T> = {
61
+ token?: Token<T> | string;
62
+ lifetime?: Lifetime;
63
+ container?: Container;
64
+ };
65
+ /**
66
+ * Marca um parâmetro do construtor para ser resolvido a partir de um Token.
67
+ * Use quando o tipo não pode ser deduzido ou para customizar o Token.
68
+ */
69
+ declare function Inject(tokenOrDesc: Token<any> | string): ParameterDecorator;
70
+ /**
71
+ * Registra a classe no container e monta as dependências via construtor.
72
+ *
73
+ * - Por padrão registra como singleton no rootContainer.
74
+ * - Se lifetime === 'transient', registra como factory.
75
+ * - O token padrão é o nome da classe, mas pode ser passado via options.token.
76
+ */
77
+ declare function Injectable<T>(options?: InjectableOptions<T>): ClassDecorator;
78
+ /**
79
+ * Injeta uma dependência em um campo usando o rootContainer.
80
+ * Útil para cenários React/Expo em que não queremos mudar o construtor.
81
+ */
82
+ declare function Resolve(tokenOrDesc?: Token<any> | string): PropertyDecorator;
83
+
84
+ export { Container, type IOCRegistrar, Inject, Injectable, Resolve, type Token, _clearIOCPlugins, bootstrapIOC, createScope, defineToken, getIOCPlugins, isRegistered, overrideFactory, overrideSingleton, overrideValue, registerFactory, registerIOCPlugin, registerSingleton, registerValue, reset, resolve, rootContainer };
package/dist/index.d.ts CHANGED
@@ -56,4 +56,29 @@ declare function _clearIOCPlugins(): void;
56
56
  */
57
57
  declare function bootstrapIOC(): void;
58
58
 
59
- export { Container, type IOCRegistrar, type Token, _clearIOCPlugins, bootstrapIOC, createScope, defineToken, getIOCPlugins, isRegistered, overrideFactory, overrideSingleton, overrideValue, registerFactory, registerIOCPlugin, registerSingleton, registerValue, reset, resolve, rootContainer };
59
+ type Lifetime = 'singleton' | 'transient';
60
+ type InjectableOptions<T> = {
61
+ token?: Token<T> | string;
62
+ lifetime?: Lifetime;
63
+ container?: Container;
64
+ };
65
+ /**
66
+ * Marca um parâmetro do construtor para ser resolvido a partir de um Token.
67
+ * Use quando o tipo não pode ser deduzido ou para customizar o Token.
68
+ */
69
+ declare function Inject(tokenOrDesc: Token<any> | string): ParameterDecorator;
70
+ /**
71
+ * Registra a classe no container e monta as dependências via construtor.
72
+ *
73
+ * - Por padrão registra como singleton no rootContainer.
74
+ * - Se lifetime === 'transient', registra como factory.
75
+ * - O token padrão é o nome da classe, mas pode ser passado via options.token.
76
+ */
77
+ declare function Injectable<T>(options?: InjectableOptions<T>): ClassDecorator;
78
+ /**
79
+ * Injeta uma dependência em um campo usando o rootContainer.
80
+ * Útil para cenários React/Expo em que não queremos mudar o construtor.
81
+ */
82
+ declare function Resolve(tokenOrDesc?: Token<any> | string): PropertyDecorator;
83
+
84
+ export { Container, type IOCRegistrar, Inject, Injectable, Resolve, type Token, _clearIOCPlugins, bootstrapIOC, createScope, defineToken, getIOCPlugins, isRegistered, overrideFactory, overrideSingleton, overrideValue, registerFactory, registerIOCPlugin, registerSingleton, registerValue, reset, resolve, rootContainer };
package/dist/index.js CHANGED
@@ -89,8 +89,72 @@ function bootstrapIOC() {
89
89
  }
90
90
  bootstrapped = true;
91
91
  }
92
+
93
+ // src/decorators.ts
94
+ var ReflectMeta = Reflect;
95
+ var paramTokens = /* @__PURE__ */ new WeakMap();
96
+ function Inject(tokenOrDesc) {
97
+ return (target, _propertyKey, index) => {
98
+ var _a;
99
+ const existing = (_a = paramTokens.get(target)) != null ? _a : [];
100
+ const token = typeof tokenOrDesc === "string" ? defineToken(tokenOrDesc) : tokenOrDesc;
101
+ existing[index] = token;
102
+ paramTokens.set(target, existing);
103
+ };
104
+ }
105
+ function getConstructorTokens(target) {
106
+ var _a, _b;
107
+ const explicit = (_a = paramTokens.get(target)) != null ? _a : [];
108
+ const designTypes = (_b = ReflectMeta.getMetadata) == null ? void 0 : _b.call(ReflectMeta, "design:paramtypes", target);
109
+ const inferred = designTypes != null ? designTypes : [];
110
+ const max = Math.max(explicit.length, inferred.length);
111
+ const tokens = [];
112
+ for (let i = 0; i < max; i++) {
113
+ const provided = explicit[i];
114
+ if (provided) {
115
+ tokens.push(provided);
116
+ continue;
117
+ }
118
+ const type = inferred[i];
119
+ if (type && type.name && type.name !== "Object") {
120
+ tokens.push(defineToken(type.name));
121
+ continue;
122
+ }
123
+ throw new Error(`Token ausente para o par\xE2metro ${i} do construtor de ${target.name}. Adicione @Inject().`);
124
+ }
125
+ return tokens;
126
+ }
127
+ function Injectable(options = {}) {
128
+ return (ctor) => {
129
+ var _a, _b;
130
+ const container = (_a = options.container) != null ? _a : rootContainer;
131
+ const token = typeof options.token === "string" ? defineToken(options.token) : (_b = options.token) != null ? _b : defineToken(ctor.name);
132
+ const deps = getConstructorTokens(ctor);
133
+ const factory = () => new ctor(...deps.map((t) => container.resolve(t)));
134
+ if (options.lifetime === "transient") {
135
+ container.registerFactory(token, factory);
136
+ } else {
137
+ container.registerSingleton(token, factory);
138
+ }
139
+ };
140
+ }
141
+ function Resolve(tokenOrDesc) {
142
+ return (target, propertyKey) => {
143
+ const token = tokenOrDesc === void 0 ? defineToken(String(propertyKey)) : typeof tokenOrDesc === "string" ? defineToken(tokenOrDesc) : tokenOrDesc;
144
+ Object.defineProperty(target, propertyKey, {
145
+ get() {
146
+ return rootContainer.resolve(token);
147
+ },
148
+ enumerable: true,
149
+ configurable: true
150
+ });
151
+ };
152
+ }
92
153
  export {
93
154
  Container,
155
+ Inject,
156
+ Injectable,
157
+ Resolve,
94
158
  _clearIOCPlugins,
95
159
  bootstrapIOC,
96
160
  createScope,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/container.ts","../src/plugins.ts","../src/bootstrap.ts"],"sourcesContent":["// src/container.ts\ntype Factory<T> = () => T;\nexport type Token<T> = symbol & { __type?: T };\n\ntype Provider<T> =\n | { kind: 'value'; value: T }\n | { kind: 'singleton'; factory: Factory<T>; instance?: T }\n | { kind: 'factory'; factory: Factory<T> };\n\nexport class Container {\n private registry = new Map<Token<any>, Provider<any>>();\n constructor(private parent?: Container) {}\n\n defineToken<T>(desc: string): Token<T> {\n return Symbol.for(`ioc:${desc}`) as Token<T>;\n }\n\n registerValue<T>(token: Token<T>, value: T) {\n this.registry.set(token, { kind: 'value', value });\n }\n registerSingleton<T>(token: Token<T>, factory: Factory<T>) {\n this.registry.set(token, { kind: 'singleton', factory });\n }\n registerFactory<T>(token: Token<T>, factory: Factory<T>) {\n this.registry.set(token, { kind: 'factory', factory });\n }\n\n isRegistered<T>(token: Token<T>): boolean {\n return this.registry.has(token) || (!!this.parent && this.parent.isRegistered(token));\n }\n\n resolve<T>(token: Token<T>): T {\n if (this.registry.has(token)) {\n const prov = this.registry.get(token)!;\n switch (prov.kind) {\n case 'value': return prov.value as T;\n case 'singleton':\n if (prov.instance === undefined) prov.instance = prov.factory();\n return prov.instance as T;\n case 'factory': return prov.factory();\n }\n }\n if (this.parent) return this.parent.resolve(token);\n throw new Error(`Token not registered: ${String(token)}`);\n }\n\n override<T>(token: Token<T>, provider: Provider<T>) {\n this.registry.set(token, provider);\n }\n\n reset(tokens?: Token<any>[]) {\n if (!tokens) return void this.registry.clear();\n for (const t of tokens) this.registry.delete(t);\n }\n\n createScope(): Container {\n return new Container(this);\n }\n\n overrideValue<T>(token: Token<T>, value: T) { this.override(token, { kind: 'value', value }); }\n overrideSingleton<T>(token: Token<T>, factory: Factory<T>) { this.override(token, { kind: 'singleton', factory }); }\n overrideFactory<T>(token: Token<T>, factory: Factory<T>) { this.override(token, { kind: 'factory', factory }); }\n}\n\n// Root container + helpers\nexport const rootContainer = new Container();\nexport const defineToken = <T>(desc: string) => rootContainer.defineToken<T>(desc);\nexport const registerValue = <T>(t: Token<T>, v: T) => rootContainer.registerValue(t, v);\nexport const registerSingleton = <T>(t: Token<T>, f: Factory<T>) => rootContainer.registerSingleton(t, f);\nexport const registerFactory = <T>(t: Token<T>, f: Factory<T>) => rootContainer.registerFactory(t, f);\nexport const resolve = <T>(t: Token<T>) => rootContainer.resolve<T>(t);\nexport const isRegistered = <T>(t: Token<T>) => rootContainer.isRegistered<T>(t);\nexport const reset = (tokens?: Token<any>[]) => rootContainer.reset(tokens);\nexport const createScope = () => rootContainer.createScope();\nexport const overrideValue = <T>(t: Token<T>, v: T) => rootContainer.overrideValue(t, v);\nexport const overrideSingleton = <T>(t: Token<T>, f: Factory<T>) => rootContainer.overrideSingleton(t, f);\nexport const overrideFactory = <T>(t: Token<T>, f: Factory<T>) => rootContainer.overrideFactory(t, f);\n","// src/plugins.ts\nimport type { Container } from './container';\n\nexport type IOCRegistrar = (c: Container) => void;\n\nconst registrars: IOCRegistrar[] = [];\n\nexport function registerIOCPlugin(registrar: IOCRegistrar) {\n registrars.push(registrar);\n}\n\n/** Apenas leitura (sem expor o array interno) */\nexport function getIOCPlugins(): IOCRegistrar[] {\n return registrars.slice();\n}\n\n/** Para testes: limpar a lista de registrars */\nexport function _clearIOCPlugins() {\n registrars.length = 0;\n}\n","// src/bootstrap.ts\nimport { rootContainer } from './container';\nimport { getIOCPlugins } from './plugins';\n\nlet bootstrapped = false;\n\n/**\n * Executa todos os registrars previamente registrados (plugins de módulos).\n * Deve ser chamado uma única vez no início do app.\n */\nexport function bootstrapIOC(): void {\n if (bootstrapped) return;\n for (const reg of getIOCPlugins()) {\n reg(rootContainer);\n }\n bootstrapped = true;\n}\n\nexport default bootstrapIOC;\n"],"mappings":";AASO,IAAM,YAAN,MAAM,WAAU;AAAA,EAErB,YAAoB,QAAoB;AAApB;AADpB,SAAQ,WAAW,oBAAI,IAA+B;AAAA,EACb;AAAA,EAEzC,YAAe,MAAwB;AACrC,WAAO,OAAO,IAAI,OAAO,IAAI,EAAE;AAAA,EACjC;AAAA,EAEA,cAAiB,OAAiB,OAAU;AAC1C,SAAK,SAAS,IAAI,OAAO,EAAE,MAAM,SAAS,MAAM,CAAC;AAAA,EACnD;AAAA,EACA,kBAAqB,OAAiB,SAAqB;AACzD,SAAK,SAAS,IAAI,OAAO,EAAE,MAAM,aAAa,QAAQ,CAAC;AAAA,EACzD;AAAA,EACA,gBAAmB,OAAiB,SAAqB;AACvD,SAAK,SAAS,IAAI,OAAO,EAAE,MAAM,WAAW,QAAQ,CAAC;AAAA,EACvD;AAAA,EAEA,aAAgB,OAA0B;AACxC,WAAO,KAAK,SAAS,IAAI,KAAK,KAAM,CAAC,CAAC,KAAK,UAAU,KAAK,OAAO,aAAa,KAAK;AAAA,EACrF;AAAA,EAEA,QAAW,OAAoB;AAC7B,QAAI,KAAK,SAAS,IAAI,KAAK,GAAG;AAC5B,YAAM,OAAO,KAAK,SAAS,IAAI,KAAK;AACpC,cAAQ,KAAK,MAAM;AAAA,QACjB,KAAK;AAAS,iBAAO,KAAK;AAAA,QAC1B,KAAK;AACH,cAAI,KAAK,aAAa,OAAW,MAAK,WAAW,KAAK,QAAQ;AAC9D,iBAAO,KAAK;AAAA,QACd,KAAK;AAAW,iBAAO,KAAK,QAAQ;AAAA,MACtC;AAAA,IACF;AACA,QAAI,KAAK,OAAQ,QAAO,KAAK,OAAO,QAAQ,KAAK;AACjD,UAAM,IAAI,MAAM,yBAAyB,OAAO,KAAK,CAAC,EAAE;AAAA,EAC1D;AAAA,EAEA,SAAY,OAAiB,UAAuB;AAClD,SAAK,SAAS,IAAI,OAAO,QAAQ;AAAA,EACnC;AAAA,EAEA,MAAM,QAAuB;AAC3B,QAAI,CAAC,OAAQ,QAAO,KAAK,KAAK,SAAS,MAAM;AAC7C,eAAW,KAAK,OAAQ,MAAK,SAAS,OAAO,CAAC;AAAA,EAChD;AAAA,EAEA,cAAyB;AACvB,WAAO,IAAI,WAAU,IAAI;AAAA,EAC3B;AAAA,EAEA,cAAiB,OAAiB,OAAU;AAAE,SAAK,SAAS,OAAO,EAAE,MAAM,SAAS,MAAM,CAAC;AAAA,EAAG;AAAA,EAC9F,kBAAqB,OAAiB,SAAqB;AAAE,SAAK,SAAS,OAAO,EAAE,MAAM,aAAa,QAAQ,CAAC;AAAA,EAAG;AAAA,EACnH,gBAAmB,OAAiB,SAAqB;AAAE,SAAK,SAAS,OAAO,EAAE,MAAM,WAAW,QAAQ,CAAC;AAAA,EAAG;AACjH;AAGO,IAAM,gBAAgB,IAAI,UAAU;AACpC,IAAM,cAAc,CAAI,SAAiB,cAAc,YAAe,IAAI;AAC1E,IAAM,gBAAgB,CAAI,GAAa,MAAS,cAAc,cAAc,GAAG,CAAC;AAChF,IAAM,oBAAoB,CAAI,GAAa,MAAkB,cAAc,kBAAkB,GAAG,CAAC;AACjG,IAAM,kBAAkB,CAAI,GAAa,MAAkB,cAAc,gBAAgB,GAAG,CAAC;AAC7F,IAAM,UAAU,CAAI,MAAgB,cAAc,QAAW,CAAC;AAC9D,IAAM,eAAe,CAAI,MAAgB,cAAc,aAAgB,CAAC;AACxE,IAAM,QAAQ,CAAC,WAA0B,cAAc,MAAM,MAAM;AACnE,IAAM,cAAc,MAAM,cAAc,YAAY;AACpD,IAAM,gBAAgB,CAAI,GAAa,MAAS,cAAc,cAAc,GAAG,CAAC;AAChF,IAAM,oBAAoB,CAAI,GAAa,MAAkB,cAAc,kBAAkB,GAAG,CAAC;AACjG,IAAM,kBAAkB,CAAI,GAAa,MAAkB,cAAc,gBAAgB,GAAG,CAAC;;;ACvEpG,IAAM,aAA6B,CAAC;AAE7B,SAAS,kBAAkB,WAAyB;AACzD,aAAW,KAAK,SAAS;AAC3B;AAGO,SAAS,gBAAgC;AAC9C,SAAO,WAAW,MAAM;AAC1B;AAGO,SAAS,mBAAmB;AACjC,aAAW,SAAS;AACtB;;;ACfA,IAAI,eAAe;AAMZ,SAAS,eAAqB;AACnC,MAAI,aAAc;AAClB,aAAW,OAAO,cAAc,GAAG;AACjC,QAAI,aAAa;AAAA,EACnB;AACA,iBAAe;AACjB;","names":[]}
1
+ {"version":3,"sources":["../src/container.ts","../src/plugins.ts","../src/bootstrap.ts","../src/decorators.ts"],"sourcesContent":["// src/container.ts\ntype Factory<T> = () => T;\nexport type Token<T> = symbol & { __type?: T };\n\ntype Provider<T> =\n | { kind: 'value'; value: T }\n | { kind: 'singleton'; factory: Factory<T>; instance?: T }\n | { kind: 'factory'; factory: Factory<T> };\n\nexport class Container {\n private registry = new Map<Token<any>, Provider<any>>();\n constructor(private parent?: Container) {}\n\n defineToken<T>(desc: string): Token<T> {\n return Symbol.for(`ioc:${desc}`) as Token<T>;\n }\n\n registerValue<T>(token: Token<T>, value: T) {\n this.registry.set(token, { kind: 'value', value });\n }\n registerSingleton<T>(token: Token<T>, factory: Factory<T>) {\n this.registry.set(token, { kind: 'singleton', factory });\n }\n registerFactory<T>(token: Token<T>, factory: Factory<T>) {\n this.registry.set(token, { kind: 'factory', factory });\n }\n\n isRegistered<T>(token: Token<T>): boolean {\n return this.registry.has(token) || (!!this.parent && this.parent.isRegistered(token));\n }\n\n resolve<T>(token: Token<T>): T {\n if (this.registry.has(token)) {\n const prov = this.registry.get(token)!;\n switch (prov.kind) {\n case 'value': return prov.value as T;\n case 'singleton':\n if (prov.instance === undefined) prov.instance = prov.factory();\n return prov.instance as T;\n case 'factory': return prov.factory();\n }\n }\n if (this.parent) return this.parent.resolve(token);\n throw new Error(`Token not registered: ${String(token)}`);\n }\n\n override<T>(token: Token<T>, provider: Provider<T>) {\n this.registry.set(token, provider);\n }\n\n reset(tokens?: Token<any>[]) {\n if (!tokens) return void this.registry.clear();\n for (const t of tokens) this.registry.delete(t);\n }\n\n createScope(): Container {\n return new Container(this);\n }\n\n overrideValue<T>(token: Token<T>, value: T) { this.override(token, { kind: 'value', value }); }\n overrideSingleton<T>(token: Token<T>, factory: Factory<T>) { this.override(token, { kind: 'singleton', factory }); }\n overrideFactory<T>(token: Token<T>, factory: Factory<T>) { this.override(token, { kind: 'factory', factory }); }\n}\n\n// Root container + helpers\nexport const rootContainer = new Container();\nexport const defineToken = <T>(desc: string) => rootContainer.defineToken<T>(desc);\nexport const registerValue = <T>(t: Token<T>, v: T) => rootContainer.registerValue(t, v);\nexport const registerSingleton = <T>(t: Token<T>, f: Factory<T>) => rootContainer.registerSingleton(t, f);\nexport const registerFactory = <T>(t: Token<T>, f: Factory<T>) => rootContainer.registerFactory(t, f);\nexport const resolve = <T>(t: Token<T>) => rootContainer.resolve<T>(t);\nexport const isRegistered = <T>(t: Token<T>) => rootContainer.isRegistered<T>(t);\nexport const reset = (tokens?: Token<any>[]) => rootContainer.reset(tokens);\nexport const createScope = () => rootContainer.createScope();\nexport const overrideValue = <T>(t: Token<T>, v: T) => rootContainer.overrideValue(t, v);\nexport const overrideSingleton = <T>(t: Token<T>, f: Factory<T>) => rootContainer.overrideSingleton(t, f);\nexport const overrideFactory = <T>(t: Token<T>, f: Factory<T>) => rootContainer.overrideFactory(t, f);\n","// src/plugins.ts\nimport type { Container } from './container';\n\nexport type IOCRegistrar = (c: Container) => void;\n\nconst registrars: IOCRegistrar[] = [];\n\nexport function registerIOCPlugin(registrar: IOCRegistrar) {\n registrars.push(registrar);\n}\n\n/** Apenas leitura (sem expor o array interno) */\nexport function getIOCPlugins(): IOCRegistrar[] {\n return registrars.slice();\n}\n\n/** Para testes: limpar a lista de registrars */\nexport function _clearIOCPlugins() {\n registrars.length = 0;\n}\n","// src/bootstrap.ts\nimport { rootContainer } from './container';\nimport { getIOCPlugins } from './plugins';\n\nlet bootstrapped = false;\n\n/**\n * Executa todos os registrars previamente registrados (plugins de módulos).\n * Deve ser chamado uma única vez no início do app.\n */\nexport function bootstrapIOC(): void {\n if (bootstrapped) return;\n for (const reg of getIOCPlugins()) {\n reg(rootContainer);\n }\n bootstrapped = true;\n}\n\nexport default bootstrapIOC;\n","// src/decorators.ts\nimport { Container, Token, defineToken, rootContainer } from './container';\n\ntype Lifetime = 'singleton' | 'transient';\n\ntype InjectableOptions<T> = {\n token?: Token<T> | string;\n lifetime?: Lifetime;\n container?: Container;\n};\n\n// Guarded access to Reflect metadata so the lib works even without reflect-metadata.\ntype ReflectWithMetadata = typeof Reflect & { getMetadata?: (key: string, target: object) => any };\nconst ReflectMeta = Reflect as ReflectWithMetadata;\n\n// Internal store for constructor parameter tokens provided via @Inject.\nconst paramTokens = new WeakMap<Function, (Token<any> | undefined)[]>();\n\n/**\n * Marca um parâmetro do construtor para ser resolvido a partir de um Token.\n * Use quando o tipo não pode ser deduzido ou para customizar o Token.\n */\nexport function Inject(tokenOrDesc: Token<any> | string): ParameterDecorator {\n return (target, _propertyKey, index) => {\n const existing = paramTokens.get(target as unknown as Function) ?? [];\n const token =\n typeof tokenOrDesc === 'string'\n ? defineToken(tokenOrDesc)\n : tokenOrDesc;\n existing[index] = token;\n paramTokens.set(target as unknown as Function, existing);\n };\n}\n\n/**\n * Resolve os Tokens dos parâmetros do construtor usando:\n * 1) @Inject declarado explicitamente\n * 2) design:paramtypes (se reflect-metadata estiver carregado)\n */\nfunction getConstructorTokens(target: Function): Token<any>[] {\n const explicit = paramTokens.get(target) ?? [];\n const designTypes = ReflectMeta.getMetadata?.('design:paramtypes', target) as any[] | undefined;\n const inferred = designTypes ?? [];\n\n const max = Math.max(explicit.length, inferred.length);\n const tokens: Token<any>[] = [];\n\n for (let i = 0; i < max; i++) {\n const provided = explicit[i];\n if (provided) {\n tokens.push(provided);\n continue;\n }\n const type = inferred[i];\n if (type && type.name && type.name !== 'Object') {\n tokens.push(defineToken(type.name));\n continue;\n }\n throw new Error(`Token ausente para o parâmetro ${i} do construtor de ${target.name}. Adicione @Inject().`);\n }\n\n return tokens;\n}\n\n/**\n * Registra a classe no container e monta as dependências via construtor.\n *\n * - Por padrão registra como singleton no rootContainer.\n * - Se lifetime === 'transient', registra como factory.\n * - O token padrão é o nome da classe, mas pode ser passado via options.token.\n */\nexport function Injectable<T>(options: InjectableOptions<T> = {}): ClassDecorator {\n return (ctor: any) => {\n const container = options.container ?? rootContainer;\n const token =\n typeof options.token === 'string'\n ? defineToken<T>(options.token)\n : options.token ?? defineToken<T>(ctor.name);\n const deps = getConstructorTokens(ctor);\n const factory = () => new ctor(...deps.map((t) => container.resolve(t)));\n\n if (options.lifetime === 'transient') {\n container.registerFactory(token, factory);\n } else {\n container.registerSingleton(token, factory);\n }\n };\n}\n\n/**\n * Injeta uma dependência em um campo usando o rootContainer.\n * Útil para cenários React/Expo em que não queremos mudar o construtor.\n */\nexport function Resolve(tokenOrDesc?: Token<any> | string): PropertyDecorator {\n return (target, propertyKey) => {\n const token =\n tokenOrDesc === undefined\n ? defineToken(String(propertyKey))\n : typeof tokenOrDesc === 'string'\n ? defineToken(tokenOrDesc)\n : tokenOrDesc;\n\n Object.defineProperty(target, propertyKey, {\n get() {\n return rootContainer.resolve(token);\n },\n enumerable: true,\n configurable: true,\n });\n };\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "targwire",
3
- "version": "1.0.4",
3
+ "version": "1.1.0",
4
4
  "description": "TargWire – mini IoC para TS/JS com Singleton, Transient e Scoped (ideal para Expo/React Native).",
5
- "repository": {
5
+ "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/rtsouza26/targwire.git"
8
8
  },
@@ -34,9 +34,20 @@
34
34
  "clean": "rimraf dist",
35
35
  "prepublishOnly": "npm run clean && npm run build"
36
36
  },
37
+ "peerDependencies": {
38
+ "reflect-metadata": "^0.1.13"
39
+ },
40
+ "peerDependenciesMeta": {
41
+ "reflect-metadata": {
42
+ "optional": true
43
+ }
44
+ },
37
45
  "devDependencies": {
46
+ "rimraf": "^6.0.0",
38
47
  "tsup": "^8.0.0",
39
- "typescript": "^5.5.0",
40
- "rimraf": "^6.0.0"
48
+ "typescript": "^5.5.0"
49
+ },
50
+ "dependencies": {
51
+ "reflect-metadata": "^0.2.2"
41
52
  }
42
53
  }