assemblerjs 0.0.91 → 0.0.93

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/dist/index.d.ts CHANGED
@@ -16,6 +16,7 @@ export declare abstract class AbstractAssembler {
16
16
  abstract register<T>(injection: Injection<T>): void;
17
17
  abstract has<T>(identifier: Identifier<T>): boolean;
18
18
  abstract require<T>(identifier: Identifier<T>): T;
19
+ abstract tagged(...tags: string[]): any[];
19
20
  }
20
21
 
21
22
  /**
@@ -32,6 +33,7 @@ export declare const Assemblage: (definition?: AssemblageDefinition) => ClassDec
32
33
 
33
34
  declare interface AssemblageDefinition {
34
35
  singleton?: false;
36
+ events?: string[];
35
37
  inject?: Injection<unknown>[][];
36
38
  tags?: string | string[];
37
39
  controller?: true;
@@ -64,9 +66,10 @@ export declare class Assembler implements AbstractAssembler {
64
66
  * @returns { T } An instance of Concrete<T>.
65
67
  */
66
68
  require<T>(identifier: Identifier<T>): T;
69
+ tagged(...tags: string[]): any[];
67
70
  }
68
71
 
69
- declare class AssemblerContext {
72
+ export declare class AssemblerContext {
70
73
  /**
71
74
  * User-defined data. Can be used to add properties to context after creation.
72
75
  */
@@ -74,6 +77,7 @@ declare class AssemblerContext {
74
77
  register: AbstractAssembler['register'];
75
78
  has: AbstractAssembler['has'];
76
79
  require: AbstractAssembler['require'];
80
+ tagged: AbstractAssembler['tagged'];
77
81
  constructor(assembler: AbstractAssembler);
78
82
  /**
79
83
  * Add a value to user-defined data.
@@ -172,6 +176,13 @@ declare class Injectable<T> {
172
176
  * Injectable assemblage's dependencies passed as 'constructor' parameters.
173
177
  */
174
178
  get dependencies(): (Identifier<unknown> | any)[];
179
+ /**
180
+ * Tags passed in assemblage's definition or in its parent definition.
181
+ */
182
+ get tags(): string[];
183
+ /**
184
+ * Metadatas passed in assemblage's definition or in its parent definition.
185
+ */
175
186
  get metadata(): Record<string, any>;
176
187
  }
177
188
 
package/dist/index.js CHANGED
@@ -1,306 +1 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
-
5
- class AbstractAssemblage {
6
- }
7
-
8
- const ReflectCustomPrefix = '__';
9
- const ReflectCustomSuffix = '__';
10
- const ReflectParamTypes = 'design:paramtypes';
11
- const ReflectIsAssemblageFlag = `is_assemblage`;
12
- const ReflectIsSingletonFlag = `is_singleton`;
13
- const ReflectIsControllerFlag = `is_controller`;
14
- const ReflectContextParamIndex = `context_param_index`;
15
- const ReflectConfigurationParamIndex = `config_param_index`;
16
- const ReflectMetadataParamIndex = `metadata_param_index`;
17
-
18
- const defineCustomMetadata = (a, o, n)=>{
19
- Reflect.defineMetadata(`${ReflectCustomPrefix}${a}${ReflectCustomSuffix}`, o, n);
20
- };
21
- const getCustomMetadata = (a, o)=>{
22
- return Reflect.getMetadata(`${ReflectCustomPrefix}${a}${ReflectCustomSuffix}`, o);
23
- };
24
- const getOwnCustomMetadata = (a, o)=>{
25
- return Reflect.getOwnMetadata(`${ReflectCustomPrefix}${a}${ReflectCustomSuffix}`, o);
26
- };
27
-
28
- const Assemblage = (n)=>{
29
- const s = n || {};
30
- return (n)=>{
31
- defineCustomMetadata(ReflectIsAssemblageFlag, true, n);
32
- defineCustomMetadata(ReflectIsSingletonFlag, true, n);
33
- for(const e in s){
34
- if (s.hasOwnProperty(e)) {
35
- switch(e){
36
- case 'singleton':
37
- {
38
- if (s.singleton === false) {
39
- defineCustomMetadata(ReflectIsSingletonFlag, false, n);
40
- }
41
- break;
42
- }
43
- case 'controller':
44
- {
45
- if (s.controller === true) {
46
- if (typeof s.path !== 'string') {
47
- throw new Error(`Controller assemblage '${n.name}' must define a path.`);
48
- }
49
- defineCustomMetadata(ReflectIsControllerFlag, true, n);
50
- }
51
- break;
52
- }
53
- default:
54
- {
55
- defineCustomMetadata(e, s[e], n);
56
- }
57
- }
58
- }
59
- }
60
- return n;
61
- };
62
- };
63
-
64
- class AbstractAssembler {
65
- }
66
-
67
- const NoOp = (...e)=>{};
68
- const isClass = (e)=>{
69
- return e && typeof e === 'function' && typeof e.constructor !== 'undefined';
70
- };
71
- const isObject = (e)=>typeof e === 'object' && !Array.isArray(e) && !isClass(e);
72
- const switchCase = (e, t)=>(o, ...s)=>e[o] ? e[o](...s) : t ? t(o, ...s) : NoOp();
73
- const pipe = (...e)=>(t)=>e.reduce((e, t)=>t(e), t);
74
- const conditionally = (e)=>(t)=>{
75
- return e.if(t) ? e.then(t) : e.else ? e.else(t) : undefined;
76
- };
77
-
78
- const i = (n)=>{
79
- return {
80
- identifier: n[0],
81
- concrete: n[0],
82
- configuration: {}
83
- };
84
- };
85
- const c = (r)=>{
86
- const i = ()=>isClass(r[0]) && isClass(r[1]);
87
- const c = ()=>isClass(r[0]) && isObject(r[1]);
88
- const u = ()=>pipe(conditionally({
89
- if: ()=>i(),
90
- then: ()=>{
91
- return {
92
- identifier: r[0],
93
- concrete: r[1],
94
- configuration: {}
95
- };
96
- }
97
- }), conditionally({
98
- if: ()=>c(),
99
- then: ()=>{
100
- return {
101
- identifier: r[0],
102
- concrete: r[0],
103
- configuration: r[1]
104
- };
105
- },
106
- else: (n)=>n
107
- }))();
108
- return u();
109
- };
110
- const u = (n)=>{
111
- return {
112
- identifier: n[0],
113
- concrete: n[1],
114
- configuration: n[2]
115
- };
116
- };
117
- const resolveInjectionTuple = (n)=>switchCase({
118
- 1: ()=>i(n),
119
- 2: ()=>c(n),
120
- 3: ()=>u(n)
121
- }, ()=>{
122
- throw new Error(`Injection tuple must be of length 1, 2 or 3.`);
123
- })(n.length);
124
-
125
- function t(t, e, n) {
126
- if (e in t) {
127
- Object.defineProperty(t, e, {
128
- value: n,
129
- enumerable: true,
130
- configurable: true,
131
- writable: true
132
- });
133
- } else {
134
- t[e] = n;
135
- }
136
- return t;
137
- }
138
- class Injectable {
139
- static of(t, e) {
140
- return new Injectable(t, e);
141
- }
142
- build() {
143
- if (this.singleton) return this.singleton;
144
- const t = this.resolveDependencies();
145
- const e = new this.concrete(...t);
146
- if (this.isSingleton) {
147
- this.singleton = e;
148
- }
149
- return e;
150
- }
151
- resolveDependencies() {
152
- const t = [];
153
- const i = getOwnCustomMetadata(ReflectContextParamIndex, this.concrete) || [];
154
- const s = getOwnCustomMetadata(ReflectConfigurationParamIndex, this.concrete) || [];
155
- const h = getCustomMetadata(ReflectMetadataParamIndex, this.concrete) || [];
156
- let u = 0;
157
- for (const e of this.dependencies){
158
- if (i.includes(u)) {
159
- t.push(this.context);
160
- u++;
161
- continue;
162
- }
163
- if (s.includes(u)) {
164
- t.push(this.configuration);
165
- u++;
166
- continue;
167
- }
168
- if (h.includes(u)) {
169
- t.push(this.metadata);
170
- u++;
171
- continue;
172
- }
173
- t.push(this.context.require(e));
174
- u++;
175
- }
176
- return t;
177
- }
178
- get isSingleton() {
179
- return getOwnCustomMetadata(ReflectIsSingletonFlag, this.concrete) || false;
180
- }
181
- get injections() {
182
- return getOwnCustomMetadata('inject', this.concrete) || [];
183
- }
184
- get dependencies() {
185
- return Reflect.getMetadata(ReflectParamTypes, this.concrete) || [];
186
- }
187
- get metadata() {
188
- return getCustomMetadata('metadata', this.concrete) || {};
189
- }
190
- constructor(e, n){
191
- t(this, "context", undefined);
192
- t(this, "identifier", undefined);
193
- t(this, "concrete", undefined);
194
- t(this, "configuration", undefined);
195
- t(this, "singleton", undefined);
196
- this.context = n;
197
- const i = resolveInjectionTuple(e);
198
- this.identifier = i.identifier;
199
- this.concrete = i.concrete;
200
- this.configuration = i.configuration;
201
- for (const t of this.injections){
202
- this.context.register(t);
203
- }
204
- }
205
- }
206
-
207
- function e$2(e, r, t) {
208
- if (r in e) {
209
- Object.defineProperty(e, r, {
210
- value: t,
211
- enumerable: true,
212
- configurable: true,
213
- writable: true
214
- });
215
- } else {
216
- e[r] = t;
217
- }
218
- return e;
219
- }
220
- class AssemblerContext {
221
- set(e, r) {
222
- if (this.userData[e]) {
223
- throw new Error(`Key '${e}' is already defined in context's user data.`);
224
- }
225
- this.userData[e] = r;
226
- return this;
227
- }
228
- get(e) {
229
- return this.userData[e];
230
- }
231
- constructor(r){
232
- e$2(this, "userData", {});
233
- e$2(this, "register", undefined);
234
- e$2(this, "has", undefined);
235
- e$2(this, "require", undefined);
236
- this.register = r.register.bind(r);
237
- this.has = r.has.bind(r);
238
- this.require = r.require.bind(r);
239
- }
240
- }
241
-
242
- function e$1(e, t, i) {
243
- if (t in e) {
244
- Object.defineProperty(e, t, {
245
- value: i,
246
- enumerable: true,
247
- configurable: true,
248
- writable: true
249
- });
250
- } else {
251
- e[t] = i;
252
- }
253
- return e;
254
- }
255
- class Assembler {
256
- static build(e) {
257
- return new Assembler(e);
258
- }
259
- register(e) {
260
- const t = Injectable.of(e, this.context);
261
- if (this.has(t.identifier)) {
262
- throw new Error(`An assemblage is already registered with identifier '${t.identifier.name}'.`);
263
- }
264
- this.injectables.set(t.identifier, t);
265
- return t;
266
- }
267
- has(e) {
268
- return this.injectables.has(e);
269
- }
270
- require(e) {
271
- if (!this.injectables.has(e)) {
272
- throw new Error(`Assemblage with identifier '${e.name}' has not been registered.`);
273
- }
274
- const t = this.injectables.get(e);
275
- return t.build();
276
- }
277
- constructor(r){
278
- e$1(this, "injectables", new Map());
279
- e$1(this, "context", undefined);
280
- this.context = new AssemblerContext(this);
281
- defineCustomMetadata(ReflectIsSingletonFlag, true, r);
282
- const s = this.register([
283
- r
284
- ]);
285
- return s.build();
286
- }
287
- }
288
-
289
- const m = (o)=>()=>{
290
- return (t, n, m)=>{
291
- const s = getOwnCustomMetadata(o, t) || [];
292
- s.push(m);
293
- defineCustomMetadata(o, s, t);
294
- };
295
- };
296
- const s = m(ReflectContextParamIndex);
297
- const e = m(ReflectConfigurationParamIndex);
298
- const a = m(ReflectMetadataParamIndex);
299
-
300
- exports.AbstractAssemblage = AbstractAssemblage;
301
- exports.AbstractAssembler = AbstractAssembler;
302
- exports.Assemblage = Assemblage;
303
- exports.Assembler = Assembler;
304
- exports.Configuration = e;
305
- exports.Context = s;
306
- exports.Metadata = a;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e="__",t="__",i="is_singleton",r="context_param_index",n="config_param_index",s="metadata_param_index",o=(i,r,n)=>{Reflect.defineMetadata(`${e}${i}${t}`,r,n)},a=(i,r)=>Reflect.getMetadata(`${e}${i}${t}`,r),c=(i,r)=>Reflect.getOwnMetadata(`${e}${i}${t}`,r);const h=e=>e&&"function"==typeof e&&void 0!==e.constructor,u=e=>t=>e.if(t)?e.then(t):e.else?e.else(t):void 0,l=e=>{const t=()=>h(e[0])&&(e=>"object"==typeof e&&!Array.isArray(e)&&!h(e))(e[1]);return((...e)=>t=>e.reduce(((e,t)=>t(e)),t))(u({if:()=>h(e[0])&&h(e[1]),then:()=>({identifier:e[0],concrete:e[1],configuration:{}})}),u({if:()=>t(),then:()=>({identifier:e[0],concrete:e[0],configuration:e[1]}),else:e=>e}))()},d=e=>((e,t)=>(i,...r)=>e[i]?e[i](...r):t?t(i,...r):void 0)({1:()=>(e=>({identifier:e[0],concrete:e[0],configuration:{}}))(e),2:()=>l(e),3:()=>(e=>({identifier:e[0],concrete:e[1],configuration:e[2]}))(e)},(()=>{throw new Error("Injection tuple must be of length 1, 2 or 3.")}))(e.length);function f(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}class g{static of(e,t){return new g(e,t)}build(){if(this.singleton)return this.singleton;const e=this.resolveDependencies(),t=new this.concrete(...e);return this.isSingleton&&(this.singleton=t),t}resolveDependencies(){const e=[],t=c(r,this.concrete)||[],i=c(n,this.concrete)||[],o=a(s,this.concrete)||[];let h=0;for(const r of this.dependencies)t.includes(h)?(e.push(this.context),h++):i.includes(h)?(e.push(this.configuration),h++):o.includes(h)?(e.push(this.metadata),h++):(e.push(this.context.require(r)),h++);return e}get isSingleton(){return c(i,this.concrete)||!1}get injections(){return c("inject",this.concrete)||[]}get dependencies(){return Reflect.getMetadata("design:paramtypes",this.concrete)||[]}get tags(){return a("tags",this.concrete)||[]}get metadata(){return a("metadata",this.concrete)||{}}constructor(e,t){f(this,"context",void 0),f(this,"identifier",void 0),f(this,"concrete",void 0),f(this,"configuration",void 0),f(this,"singleton",void 0),this.context=t;const i=d(e);this.identifier=i.identifier,this.concrete=i.concrete,this.configuration=i.configuration;for(const r of this.injections)this.context.register(r)}}function b(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}class p{set(e,t){if(this.userData[e])throw new Error(`Key '${e}' is already defined in context's user data.`);return this.userData[e]=t,this}get(e){return this.userData[e]}constructor(e){b(this,"userData",{}),b(this,"register",void 0),b(this,"has",void 0),b(this,"require",void 0),b(this,"tagged",void 0),this.register=e.register.bind(e),this.has=e.has.bind(e),this.require=e.require.bind(e),this.tagged=e.tagged.bind(e)}}function m(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}class w{static build(e){return new w(e)}register(e){const t=g.of(e,this.context);if(this.has(t.identifier))throw new Error(`An assemblage is already registered with identifier '${t.identifier.name}'.`);return this.injectables.set(t.identifier,t),t}has(e){return this.injectables.has(e)}require(e){if(!this.injectables.has(e))throw new Error(`Assemblage with identifier '${e.name}' has not been registered.`);return this.injectables.get(e).build()}tagged(...e){const t=[];for(const i of e)for(const[e,r]of this.injectables)r.tags.includes(i)&&t.push(r.build());return t}constructor(e){m(this,"injectables",new Map),m(this,"context",void 0),this.context=new p(this),o(i,!0,e);return this.register([e]).build()}}const y=e=>()=>(t,i,r)=>{const n=c(e,t)||[];n.push(r),o(e,n,t)},x=y(r),j=y(n),A=y(s);exports.AbstractAssemblage=class{},exports.AbstractAssembler=class{},exports.Assemblage=e=>{const t=e||{};return e=>{o("is_assemblage",!0,e),o(i,!0,e);for(const r in t)if(t.hasOwnProperty(r))switch(r){case"singleton":!1===t.singleton&&o(i,!1,e);break;case"controller":if(!0===t.controller){if("string"!=typeof t.path)throw new Error(`Controller assemblage '${e.name}' must define a path.`);o("is_controller",!0,e)}break;case"tags":if(void 0!==t.tags)if("string"==typeof t.tags)o("tags",[t.tags],e);else{if(!Array.isArray(t.tags))throw new Error("Assemblage's 'tags' must be o type 'string' or 'Array'.");o("tags",t.tags,e)}break;case"inject":if(!Array.isArray(t.inject))throw new Error("Assemblage's definition 'inject' property must be an array of 'Injection' tuples.");for(const e of t.inject)if(!Array.isArray(e))throw new Error("'Injection' must be an 'Array'.");default:o(r,t[r],e)}return e}},exports.Assembler=w,exports.AssemblerContext=p,exports.Configuration=j,exports.Context=x,exports.Metadata=A;
package/dist/index.mjs CHANGED
@@ -21,39 +21,65 @@ const getOwnCustomMetadata = (a, o)=>{
21
21
  return Reflect.getOwnMetadata(`${ReflectCustomPrefix}${a}${ReflectCustomSuffix}`, o);
22
22
  };
23
23
 
24
- const Assemblage = (n)=>{
25
- const s = n || {};
26
- return (n)=>{
27
- defineCustomMetadata(ReflectIsAssemblageFlag, true, n);
28
- defineCustomMetadata(ReflectIsSingletonFlag, true, n);
29
- for(const e in s){
30
- if (s.hasOwnProperty(e)) {
31
- switch(e){
24
+ const Assemblage = (o)=>{
25
+ const n = o || {};
26
+ return (o)=>{
27
+ defineCustomMetadata(ReflectIsAssemblageFlag, true, o);
28
+ defineCustomMetadata(ReflectIsSingletonFlag, true, o);
29
+ for(const r in n){
30
+ if (n.hasOwnProperty(r)) {
31
+ switch(r){
32
32
  case 'singleton':
33
33
  {
34
- if (s.singleton === false) {
35
- defineCustomMetadata(ReflectIsSingletonFlag, false, n);
34
+ if (n.singleton === false) {
35
+ defineCustomMetadata(ReflectIsSingletonFlag, false, o);
36
36
  }
37
37
  break;
38
38
  }
39
39
  case 'controller':
40
40
  {
41
- if (s.controller === true) {
42
- if (typeof s.path !== 'string') {
43
- throw new Error(`Controller assemblage '${n.name}' must define a path.`);
41
+ if (n.controller === true) {
42
+ if (typeof n.path !== 'string') {
43
+ throw new Error(`Controller assemblage '${o.name}' must define a path.`);
44
44
  }
45
- defineCustomMetadata(ReflectIsControllerFlag, true, n);
45
+ defineCustomMetadata(ReflectIsControllerFlag, true, o);
46
46
  }
47
47
  break;
48
48
  }
49
+ case 'tags':
50
+ {
51
+ if (typeof n.tags !== 'undefined') {
52
+ if (typeof n.tags === 'string') {
53
+ defineCustomMetadata('tags', [
54
+ n.tags
55
+ ], o);
56
+ } else if (Array.isArray(n.tags)) {
57
+ defineCustomMetadata('tags', n.tags, o);
58
+ } else {
59
+ throw new Error(`Assemblage's 'tags' must be o type 'string' or 'Array'.`);
60
+ }
61
+ }
62
+ break;
63
+ }
64
+ case 'inject':
65
+ {
66
+ if (!Array.isArray(n.inject)) {
67
+ throw new Error(`Assemblage's definition 'inject' property must be an array of 'Injection' tuples.`);
68
+ }
69
+ for (const r of n.inject){
70
+ if (!Array.isArray(r)) {
71
+ throw new Error(`'Injection' must be an 'Array'.`);
72
+ }
73
+ }
74
+ }
49
75
  default:
50
76
  {
51
- defineCustomMetadata(e, s[e], n);
77
+ defineCustomMetadata(r, n[r], o);
52
78
  }
53
79
  }
54
80
  }
55
81
  }
56
- return n;
82
+ return o;
57
83
  };
58
84
  };
59
85
 
@@ -180,6 +206,9 @@ class Injectable {
180
206
  get dependencies() {
181
207
  return Reflect.getMetadata(ReflectParamTypes, this.concrete) || [];
182
208
  }
209
+ get tags() {
210
+ return getCustomMetadata('tags', this.concrete) || [];
211
+ }
183
212
  get metadata() {
184
213
  return getCustomMetadata('metadata', this.concrete) || {};
185
214
  }
@@ -200,38 +229,40 @@ class Injectable {
200
229
  }
201
230
  }
202
231
 
203
- function e$2(e, r, t) {
204
- if (r in e) {
205
- Object.defineProperty(e, r, {
206
- value: t,
232
+ function e$2(e, t, r) {
233
+ if (t in e) {
234
+ Object.defineProperty(e, t, {
235
+ value: r,
207
236
  enumerable: true,
208
237
  configurable: true,
209
238
  writable: true
210
239
  });
211
240
  } else {
212
- e[r] = t;
241
+ e[t] = r;
213
242
  }
214
243
  return e;
215
244
  }
216
245
  class AssemblerContext {
217
- set(e, r) {
246
+ set(e, t) {
218
247
  if (this.userData[e]) {
219
248
  throw new Error(`Key '${e}' is already defined in context's user data.`);
220
249
  }
221
- this.userData[e] = r;
250
+ this.userData[e] = t;
222
251
  return this;
223
252
  }
224
253
  get(e) {
225
254
  return this.userData[e];
226
255
  }
227
- constructor(r){
256
+ constructor(t){
228
257
  e$2(this, "userData", {});
229
258
  e$2(this, "register", undefined);
230
259
  e$2(this, "has", undefined);
231
260
  e$2(this, "require", undefined);
232
- this.register = r.register.bind(r);
233
- this.has = r.has.bind(r);
234
- this.require = r.require.bind(r);
261
+ e$2(this, "tagged", undefined);
262
+ this.register = t.register.bind(t);
263
+ this.has = t.has.bind(t);
264
+ this.require = t.require.bind(t);
265
+ this.tagged = t.tagged.bind(t);
235
266
  }
236
267
  }
237
268
 
@@ -270,6 +301,15 @@ class Assembler {
270
301
  const t = this.injectables.get(e);
271
302
  return t.build();
272
303
  }
304
+ tagged(...e) {
305
+ const t = [];
306
+ for (const i of e){
307
+ for (const [e, r] of this.injectables){
308
+ if (r.tags.includes(i)) t.push(r.build());
309
+ }
310
+ }
311
+ return t;
312
+ }
273
313
  constructor(r){
274
314
  e$1(this, "injectables", new Map());
275
315
  e$1(this, "context", undefined);
@@ -293,4 +333,4 @@ const s = m(ReflectContextParamIndex);
293
333
  const e = m(ReflectConfigurationParamIndex);
294
334
  const a = m(ReflectMetadataParamIndex);
295
335
 
296
- export { AbstractAssemblage, AbstractAssembler, Assemblage, Assembler, e as Configuration, s as Context, a as Metadata };
336
+ export { AbstractAssemblage, AbstractAssembler, Assemblage, Assembler, AssemblerContext, e as Configuration, s as Context, a as Metadata };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "assemblerjs",
3
3
  "description": "A simple and zero-dependency DI package written in typescript.",
4
- "version": "0.0.91",
4
+ "version": "0.0.93",
5
5
  "author": "Benoît LAHOZ <info@benoitlahoz.io>",
6
6
  "bugs": "https://github.com/benoitlahoz/assemblerjs/issues",
7
7
  "devDependencies": {