diff --git a/.circleci/config.yml b/.circleci/config.yml index d89ae9b..fa6d2fe 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -57,7 +57,8 @@ jobs: - run: | if git log -1 --pretty=%B | grep "^v\?[0-9]\+\.[0-9]\+\.[0-9]\+$"; then - lerna publish from-package -y + yarn global add lerna + lerna publish from-git --no-verify-access else echo "Not a release, skipping publish" fi diff --git a/package.json b/package.json index 8156238..76d462e 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "packages/*" ], "scripts": { - "build": "shx rm -rf ./packages/{http,types,utils}/**/{esm,lib} && tsc -b tsconfig.project.json && rollup --config rollup.config.js", + "build": "shx rm -rf ./packages/{di,http,types,utils}/**/{esm,lib} && shx rm -rf ./packages/**/tsconfig.tsbuildinfo && tsc -b tsconfig.project.json && rollup --config rollup.config.js", "circular": "madge --circular ./packages/{http,utils,types}/src/index.ts", "cover": "shx rm -rf .nyc_output && shx rm -rf coverage && nyc --reporter=html --reporter=lcov ava", "dev": "node tools/cli/webpack-cli.js", @@ -37,6 +37,7 @@ "prettier": "^1.16.4", "react": "^16.8.6", "react-dom": "^16.8.6", + "reflect-metadata": "^0.1.13", "rollup": "^1.7.4", "shx": "^0.3.2", "source-map-loader": "^0.2.4", diff --git a/packages/di/README.md b/packages/di/README.md new file mode 100644 index 0000000..3875564 --- /dev/null +++ b/packages/di/README.md @@ -0,0 +1,146 @@ +# `@asuka/di` + +> Dependencies injection library + +## Usage + +### Basic + +```ts +import { Injectable, InjectableFactory } from '@asuka/di' + +@Injectable() +class Engine { } + +@Injectable() +class Car { + constructor(public engine: Engine) { } +} + +const car = InjectableFactory.getInstance(Car) +expect(car).to.be.instanceof(Car) +expect(car.engine).to.be.instanceof(Engine) +``` + +### Value Provider + +```ts +import { Inject, InjectionToken, Injectable, InjectableFactory, ValueProvider } from '@asuka/di' +import Axios from 'axios' + +const token = new InjectionToken('Axios client') + +const provider: ValueProvider = { + provide: token, + useValue: Axios, +} + +@Injectable({ + providers: [provider], +}) +class HttpClient { + constructor(@Inject(token) public axios: Axios) { } +} + +const client = InjectableFactory.getInstance(HttpClient) +expect(client).to.be.instanceof(HttpClient) +expect(client.axios).to.equal(Axios) +``` + +### Factory Provider + +```ts +import { Inject, InjectionToken, Injectable, InjectableFactory, FactoryProvider } from '@asuka/di' +import Axios from 'axios' + +const token = new InjectionToken('Axios client') +const baseURL = 'https://leetcode-cn.com/api' +const provider: FactoryProvider = { + provide: token, + useFactory: () => { + return Axios.create({ + baseURL, + }) + }, +} + +@Injectable({ + providers: [provider], +}) +class HttpClient { + constructor(@Inject(token) public axios: Axios) { } +} + +const client = InjectableFactory.getInstance(HttpClient) +expect(client).to.be.instanceof(HttpClient) +expect(client.axios).to.equal(Axios) // baseURL of client.axios is 'https://leetcode-cn.com/api' +``` + +## Testing + +### Override Provider by configureModule + +```ts +function whatever() { + return true +} + +function replacement() { + return false +} + +const token = new InjectionToken('replacable') + +const provider: ValueProvider = { + useValue: replacement, + provide: token, +} + +@Injectable({ + providers: [provider], +}) +class Service { + constructor(@Inject(token) public dep: typeof whatever) {} +} + +const testModule = Test.createTestingModule({ providers: [{ provide: token, useValue: replacement }] }).compile() +const service = testModule.getInstance(Service) +t.true(service instanceof Service) +t.is(service.dep, replacement) +t.false(service.dep()) +``` + +### Override Provider by overrideProvider method + +```ts +function whatever() { + return true +} + +function replacement() { + return false +} + +const token = new InjectionToken('replacabel') + +const provider: ValueProvider = { + useValue: replacement, + provide: token, +} + +@Injectable({ + providers: [provider], +}) +class Service { + constructor(@Inject(token) public dep: typeof whatever) {} +} + +const testModule = Test.createTestingModule() + .overrideProvider(token) + .useValue(replacement) + .compile() +const service = testModule.getInstance(Service) +t.true(service instanceof Service) +t.is(service.dep, replacement) +t.false(service.dep()) +``` diff --git a/packages/di/package.json b/packages/di/package.json new file mode 100644 index 0000000..11757a9 --- /dev/null +++ b/packages/di/package.json @@ -0,0 +1,30 @@ +{ + "name": "@asuka/di", + "version": "0.0.5", + "description": "Dependencies inject library", + "keywords": [ + "DI", + "Dependencies inject", + "Injectable" + ], + "author": "LongYinan ", + "homepage": "https://github.com/LeetCode-OpenSource/asuka", + "license": "MIT", + "main": "lib/index.js", + "module": "esm/bundle.esm.js", + "typings": "esm/index.d.ts", + "sideEffects": false, + "repository": { + "type": "git", + "url": "git+https://github.com/LeetCode-OpenSource/asuka.git" + }, + "bugs": { + "url": "https://github.com/LeetCode-OpenSource/asuka/issues" + }, + "dependencies": { + "injection-js": "^2.2.1" + }, + "optionalDependencies": { + "reflect-metadata": "^0.1.13" + } +} diff --git a/packages/di/src/__tests__/injectable.spec.ts b/packages/di/src/__tests__/injectable.spec.ts new file mode 100644 index 0000000..7405a42 --- /dev/null +++ b/packages/di/src/__tests__/injectable.spec.ts @@ -0,0 +1,178 @@ +import 'reflect-metadata' +import test from 'ava' + +import { + Inject, + InjectionToken, + InjectableFactory, + Injectable, + ValueProvider, + FactoryProvider, + ClassProvider, +} from '../index' + +test.afterEach(() => { + InjectableFactory.reset() +}) + +test('should get single instance', (t) => { + @Injectable() + class Single {} + + const instance = InjectableFactory.getInstance(Single) + + t.true(instance instanceof Single) +}) + +test('should get dependencies', (t) => { + @Injectable() + class Dep {} + + @Injectable() + class DepTwo { + constructor(public dep: Dep) {} + } + + @Injectable() + class Service { + constructor(public dep: Dep, public depTwo: DepTwo) {} + } + + const service = InjectableFactory.getInstance(Service) + + t.true(InjectableFactory.getInstance(Dep) instanceof Dep) + t.true(InjectableFactory.getInstance(DepTwo) instanceof DepTwo) + t.true(service instanceof Service) +}) + +test('should singleton by default', (t) => { + @Injectable() + class Dep {} + + @Injectable() + class DepTwo { + constructor(public dep: Dep) {} + } + + @Injectable() + class Service { + constructor(public dep: Dep, public depTwo: DepTwo) {} + } + + const service = InjectableFactory.getInstance(Service) + const dep = InjectableFactory.getInstance(Dep) + const depTwo = InjectableFactory.getInstance(DepTwo) + + t.is(service.dep, dep) + t.is(service.depTwo, depTwo) +}) + +test('should be able to inject by useValue', (t) => { + function whatever() {} + const token = new InjectionToken('whatever') + + const provider: ValueProvider = { + provide: token, + useValue: whatever, + } + + @Injectable({ + providers: [provider], + }) + class Service { + constructor(@Inject(token) public dep: typeof whatever) {} + } + const service = InjectableFactory.getInstance(Service) + t.true(service instanceof Service) + t.is(service.dep, whatever) +}) + +test('should be able to inject by useFactory', (t) => { + class Dep { + constructor(public cacheSize: number) {} + } + + const cacheSize = 5 + + const token = new InjectionToken('whatever') + + const provider: FactoryProvider = { + provide: token, + useFactory() { + return new Dep(cacheSize) + }, + } + + @Injectable({ + providers: [provider], + }) + class Service { + constructor(@Inject(token) public dep: Dep) {} + } + + const service = InjectableFactory.getInstance(Service) + + t.true(service.dep instanceof Dep) + t.is(service.dep.cacheSize, cacheSize) +}) + +test('should be able to resolve deps from useFactory', (t) => { + class Dep { + constructor(public cacheSize: number, public depTwo: DepTwo) {} + } + + @Injectable() + class DepTwo {} + + const cacheSize = 5 + + const token = new InjectionToken('whatever') + + const provider: FactoryProvider = { + provide: token, + useFactory(depTwo: DepTwo) { + return new Dep(cacheSize, depTwo) + }, + deps: [DepTwo], + } + + @Injectable({ + providers: [provider], + }) + class Service { + constructor(@Inject(token) public dep: Dep) {} + } + + const service = InjectableFactory.getInstance(Service) + const depTwo = InjectableFactory.getInstance(DepTwo) + + t.true(service.dep instanceof Dep) + t.is(service.dep.cacheSize, cacheSize) + t.true(depTwo instanceof DepTwo) + t.is(service.dep.depTwo, depTwo) +}) + +test('should be able to inject by useClass', (t) => { + class Dep { + constructor() {} + } + + const token = new InjectionToken('whatever') + + const provider: ClassProvider = { + provide: token, + useClass: Dep, + } + + @Injectable({ + providers: [provider], + }) + class Service { + constructor(@Inject(token) public dep: Dep) {} + } + + const service = InjectableFactory.getInstance(Service) + + t.true(service instanceof Service) + t.true(service.dep instanceof Dep) +}) diff --git a/packages/di/src/__tests__/testbed.spec.ts b/packages/di/src/__tests__/testbed.spec.ts new file mode 100644 index 0000000..6a379cf --- /dev/null +++ b/packages/di/src/__tests__/testbed.spec.ts @@ -0,0 +1,134 @@ +import 'reflect-metadata' +import test from 'ava' + +import { Inject, Test, Injectable, InjectableFactory, InjectionToken, ValueProvider, FactoryProvider } from '../index' + +test.afterEach(() => { + InjectableFactory.reset() +}) + +test('should resolve dep instance', (t) => { + @Injectable() + class Dep {} + + @Injectable() + class Service { + constructor(public dep: Dep) {} + } + + const testModule = Test.createTestingModule().compile() + const service = testModule.getInstance(Service) + t.true(service instanceof Service) + t.true(service.dep instanceof Dep) +}) + +test('should override when createTestingModule', (t) => { + function whatever() { + return true + } + + function replacement() { + return false + } + + const token = new InjectionToken('replacable') + + const provider: ValueProvider = { + useValue: replacement, + provide: token, + } + + @Injectable({ + providers: [provider], + }) + class Service { + constructor(@Inject(token) public dep: typeof whatever) {} + } + + const testModule = Test.createTestingModule({ providers: [{ provide: token, useValue: replacement }] }).compile() + const service = testModule.getInstance(Service) + t.true(service instanceof Service) + t.is(service.dep, replacement) + t.false(service.dep()) +}) + +test('should override by overrideProvider method', (t) => { + function whatever() { + return true + } + + function replacement() { + return false + } + + const token = new InjectionToken('replacabel') + + const provider: ValueProvider = { + useValue: replacement, + provide: token, + } + + @Injectable({ + providers: [provider], + }) + class Service { + constructor(@Inject(token) public dep: typeof whatever) {} + } + + const testModule = Test.createTestingModule() + .overrideProvider(token) + .useValue(replacement) + .compile() + const service = testModule.getInstance(Service) + t.true(service instanceof Service) + t.is(service.dep, replacement) + t.false(service.dep()) +}) + +test('should override class', (t) => { + @Injectable() + class Dep {} + + @Injectable() + class Service { + constructor(public dep: Dep) {} + } + + class BetterDep {} + + const testModule = Test.createTestingModule() + .overrideProvider(Dep) + .useClass(BetterDep) + .compile() + + const service = testModule.getInstance(Service) + t.true(service instanceof Service) + t.true(service.dep instanceof BetterDep) +}) + +test('should ovrride factory', (t) => { + const token = new InjectionToken('whatever') + + const provider: FactoryProvider = { + provide: token, + useFactory: () => { + return '1' + }, + } + + @Injectable({ + providers: [provider], + }) + class Service { + constructor(@Inject(token) public fun: string) {} + } + + const testModule = Test.createTestingModule() + .overrideProvider(token) + .useFactory(() => '2') + .compile() + + const service = testModule.getInstance(Service) + + t.is(service.fun, '2') +}) diff --git a/packages/di/src/index.ts b/packages/di/src/index.ts new file mode 100644 index 0000000..accf386 --- /dev/null +++ b/packages/di/src/index.ts @@ -0,0 +1,14 @@ +export * from './injectable-factory' +export * from './injectable' +export * from './testbed' + +export { + Inject, + InjectionToken, + Type, + Provider, + ValueProvider, + FactoryProvider, + ClassProvider, + ExistingProvider, +} from 'injection-js' diff --git a/packages/di/src/injectable-factory.ts b/packages/di/src/injectable-factory.ts new file mode 100644 index 0000000..9621526 --- /dev/null +++ b/packages/di/src/injectable-factory.ts @@ -0,0 +1,31 @@ +import { ReflectiveInjector, InjectionToken, Provider } from 'injection-js' +import { ConstructorOf } from '@asuka/types' + +export class InjectableFactory { + // @internal + static providers = new Set() + // @internal + static injector = ReflectiveInjector.resolveAndCreate([]) + private static needRecreateInjector = true + + static getInstance(token: ConstructorOf | InjectionToken): T { + if (this.needRecreateInjector) { + this.injector = ReflectiveInjector.resolveAndCreate(Array.from(this.providers)) + this.needRecreateInjector = false + } + return this.injector.get(token) + } + + static addProviders(...providers: Provider[]) { + providers.forEach((provider) => { + this.providers.add(provider) + }) + this.needRecreateInjector = true + } + + static reset() { + this.providers.clear() + this.injector = ReflectiveInjector.resolveAndCreate([]) + this.needRecreateInjector = true + } +} diff --git a/packages/di/src/injectable.ts b/packages/di/src/injectable.ts new file mode 100644 index 0000000..9995ae5 --- /dev/null +++ b/packages/di/src/injectable.ts @@ -0,0 +1,14 @@ +import { InjectableFactory } from './injectable-factory' +import { Injectable as InjectionInjectable, Provider } from 'injection-js' + +export function Injectable(config?: { providers: Provider[] }) { + const providersToInject: Provider[] = [] + return function(target: any) { + if (config) { + providersToInject.push(...config.providers) + } + providersToInject.push(target) + InjectableFactory.addProviders(...providersToInject) + return InjectionInjectable()(target) + } +} diff --git a/packages/di/src/testbed.ts b/packages/di/src/testbed.ts new file mode 100644 index 0000000..09fdf3a --- /dev/null +++ b/packages/di/src/testbed.ts @@ -0,0 +1,70 @@ +import { InjectableFactory } from './index' +import { ReflectiveInjector, InjectionToken, Type, Provider, ClassProvider } from 'injection-js' +import { ConstructorOf } from '@asuka/types' + +export type Token = Type | InjectionToken + +export class Test { + static createTestingModule(overrideConfig?: { providers: Provider[] }) { + return new Test(overrideConfig ? overrideConfig.providers : []) + } + + // @internal + providers: Map, Provider> = new Map() + + private constructor(providers: Provider[]) { + this.providers = new Map() + + for (const provide of InjectableFactory.providers) { + if (typeof provide === 'function') { + this.providers.set(provide, provide) + } else { + this.providers.set((provide as ClassProvider).provide, provide) + } + } + + providers.forEach((provide) => { + if (typeof provide === 'function') { + this.providers.set(provide, provide) + } else { + this.providers.set((provide as ClassProvider).provide, provide) + } + }) + } + + overrideProvider(token: Type | InjectionToken) { + return new MockProvider(this, token) + } + + compile() { + const child = ReflectiveInjector.resolveAndCreate(Array.from(this.providers.values())) + return new TestModule(child) + } +} + +export class MockProvider { + constructor(private test: Test, private token: Type | InjectionToken) {} + + useClass(value: Type) { + this.test.providers.set(this.token, { provide: this.token, useClass: value }) + return this.test + } + + useValue(value: T) { + this.test.providers.set(this.token, { provide: this.token, useValue: value }) + return this.test + } + + useFactory(value: Function) { + this.test.providers.set(this.token, { provide: this.token, useFactory: value }) + return this.test + } +} + +export class TestModule { + constructor(private injector: ReflectiveInjector) {} + + getInstance(token: ConstructorOf | InjectionToken): T { + return this.injector.get(token) + } +} diff --git a/packages/di/tsconfig.json b/packages/di/tsconfig.json new file mode 100644 index 0000000..9f6d289 --- /dev/null +++ b/packages/di/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "module": "esnext", + "outDir": "esm", + "rootDir": "./src", + "composite": true + }, + "references": [ + { "path": "../types" }, + { "path": "../utils" } + ] +} \ No newline at end of file diff --git a/packages/types/tsconfig.json b/packages/types/tsconfig.json index dc308c3..93b409d 100644 --- a/packages/types/tsconfig.json +++ b/packages/types/tsconfig.json @@ -4,6 +4,9 @@ "module": "esnext", "composite": true, "outDir": "esm", - "rootDir": "./src" + "rootDir": "./src", + "paths": { + "@noj/*": ["./*/src"] + } } } \ No newline at end of file diff --git a/rollup.config.js b/rollup.config.js index 9e8315e..c51131a 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -12,6 +12,19 @@ export default [ } ] }, + { + input: './packages/di/esm/index.js', + output: [ + { + file: './packages/di/lib/index.js', + format: 'cjs' + }, + { + file: './packages/di/esm/bundle.esm.js', + format: 'esm' + } + ] + }, { input: './packages/utils/esm/index.js', output: [ diff --git a/tsconfig.project.json b/tsconfig.project.json index c459b42..470194d 100644 --- a/tsconfig.project.json +++ b/tsconfig.project.json @@ -3,7 +3,8 @@ "references": [ { "path": "./packages/types" }, { "path": "./packages/utils" }, - { "path": "./packages/http" } + { "path": "./packages/http" }, + { "path": "./packages/di" } ], "compilerOptions": { "noEmit": true @@ -11,6 +12,7 @@ "include": [ "./packages/types", "./packages/utils", - "./packages/http" + "./packages/http", + "./packages/di" ] } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 9630fea..159d174 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@ant-design/icons-react@~1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@ant-design/icons-react/-/icons-react-1.1.2.tgz#df25c4560864f8a3b687b305c3238daff048ed72" - integrity sha512-7Fgt9d8ABgxrhZxsFjHk/VpPcxodQJJhbJO8Lsh7u58pGN4NoxxW++92naeGTXCyqZsbDPBReP+SC0bdBtbsGQ== +"@ant-design/icons-react@~1.1.5": + version "1.1.5" + resolved "https://registry.npmjs.org/@ant-design/icons-react/-/icons-react-1.1.5.tgz#1b03da8dcced2a4bb982ef7b25c1d24014c35a68" + integrity sha512-p2ybKfO/r2lC1RZu4rDY2VBDZq2zqAaJzf/B1HrKTxGo8/mM1zOOEoob/LRXZphJ9jD5wCcTdcmcB9YMaAWW4Q== dependencies: ant-design-palettes "^1.1.3" babel-runtime "^6.26.0" @@ -362,9 +362,9 @@ "@emotion/utils" "0.11.1" "@emotion/weak-memoize" "0.2.2" -"@emotion/core@^10.0.6": +"@emotion/core@^10.0.10": version "10.0.10" - resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.0.10.tgz#8d3114e5a2f8b178a7067c603a2937516f180b08" + resolved "https://registry.npmjs.org/@emotion/core/-/core-10.0.10.tgz#8d3114e5a2f8b178a7067c603a2937516f180b08" integrity sha512-U1aE2cOWUscjc8ZJ3Cx32udOzLeRoJwGxBH93xQD850oQFpwPKZARzdUtdc9SByUOwzSFYxhDhrpXnV34FJmWg== dependencies: "@emotion/cache" "^10.0.9" @@ -425,9 +425,9 @@ "@emotion/utils" "0.11.1" object-assign "^4.1.1" -"@emotion/styled@^10.0.6": +"@emotion/styled@^10.0.10": version "10.0.10" - resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-10.0.10.tgz#ec241a9389a585b2c2638b709c262c28469ed92e" + resolved "https://registry.npmjs.org/@emotion/styled/-/styled-10.0.10.tgz#ec241a9389a585b2c2638b709c262c28469ed92e" integrity sha512-k4p5WxwYJUVYKBlwOmfpqxeSwdPHqUycLHJY9ftleEvMfphYLB8lt9oPEkEty5XH4URh/wyUfZ2wW2ojrHODWA== dependencies: "@emotion/styled-base" "^10.0.10" @@ -1167,10 +1167,10 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.0.tgz#4c48fed958d6dcf9487195a0ef6456d5f6e0163a" integrity sha512-eItQyV43bj4rR3JPV0Skpl1SncRCdziTEK9/v8VwXmV6d/qOUO8/EuWeHBbCZcsfSHfzI5UyMJLCSXtxxznyZg== -"@types/qs@^6.5.1": - version "6.5.2" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.5.2.tgz#7f347062655056662845ba4bb79dcbfdc382cd61" - integrity sha512-47kAAs3yV/hROraCTQYDMh4p/6zI9+gtssjD0kq9OWsGdLcBge59rl49FnCuJ+iWxEKiqFz6KXzeGH5DRVjNJA== +"@types/qs@^6.5.2": + version "6.5.3" + resolved "https://registry.npmjs.org/@types/qs/-/qs-6.5.3.tgz#1c3b71b091eaeaf5924538006b7f70603ce63d38" + integrity sha512-Jugo5V/1bS0fRhy2z8+cUAHEyWOATaz4rbyLVvcFs7+dXp5HfwpEwzF1Q11bB10ApUqHf+yTauxI0UXQDwGrbA== "@types/react-dom@^16.8.3": version "16.8.3" @@ -1514,13 +1514,13 @@ ant-design-palettes@^1.1.3: dependencies: tinycolor2 "^1.4.1" -antd@^3.13.0: - version "3.16.0" - resolved "https://registry.yarnpkg.com/antd/-/antd-3.16.0.tgz#3c8934e5ece43f88c5a96eadc9e0cb4207a106ab" - integrity sha512-o7CrjyDBtUULIiSUJu5yAfsMzl9XcRrJTcTMkDyi3gpI7UasuCzAzYjKno+nIRde8rvR9qcbt0m2cZW2oOeMLg== +antd@^3.16.0: + version "3.16.3" + resolved "https://registry.npmjs.org/antd/-/antd-3.16.3.tgz#66ecdbd96a31e2a4d239106a106b17629beaa141" + integrity sha512-Kg/6n6IRzwslMrSOosczpxcuXiWh7mkUmmcPRmfI/E3P6oa8jR3dXtPiZViH64HxvBCIFL7FjizuVjA21MmPnQ== dependencies: "@ant-design/icons" "~1.2.0" - "@ant-design/icons-react" "~1.1.2" + "@ant-design/icons-react" "~1.1.5" "@types/react-slick" "^0.23.3" array-tree-filter "^2.1.0" babel-runtime "6.x" @@ -4296,10 +4296,10 @@ fast-json-stable-stringify@^2.0.0: resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= -fast-json-stringify@^1.10.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/fast-json-stringify/-/fast-json-stringify-1.13.0.tgz#fd9bbc65a5ac083a8f4b53528fe21f7baa0ff0f7" - integrity sha512-3B+ENtJyVFBbcTodTQ0VC8NMWvb7R33S8RetnhjMJ12Nw85Hf4Ku9Enm8xqY6llLlmXUU+iNJ49c3/+C3/HiJw== +fast-json-stringify@^1.13.0: + version "1.14.0" + resolved "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-1.14.0.tgz#245b01dbd2087c96b5f315ea5ba835398e54dd6f" + integrity sha512-3VSblXsVxIE46E/YzRYHapyIeM3/igeA/kyzdL5xfAIYNnCLd8Oy+scrURnqZIRXMmtx0hfyp+okN5+r4W+GMQ== dependencies: ajv "^6.8.1" deepmerge "^3.0.0" @@ -5412,6 +5412,11 @@ init-package-json@^1.10.3: validate-npm-package-license "^3.0.1" validate-npm-package-name "^3.0.0" +injection-js@^2.2.1: + version "2.2.1" + resolved "https://registry.npmjs.org/injection-js/-/injection-js-2.2.1.tgz#a8d6a085b2f0b8d8650f6f4487f6abb8cc0d67ce" + integrity sha512-zHI+E+dM0PXix5FFTO1Y4/UOyAzE7zG1l/QwAn4jchTThOoBq+UYRFK4AVG7lQgFL+go62SbrzSsjXy9DFEZUg== + inquirer@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-5.2.0.tgz#db350c2b73daca77ff1243962e9f22f099685726" @@ -8315,9 +8320,9 @@ qs@6.5.2, qs@~6.5.2: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== -qs@^6.6.0: +qs@^6.7.0: version "6.7.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" + resolved "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== querystring-es3@^0.2.0: @@ -9013,6 +9018,11 @@ redent@^2.0.0: indent-string "^3.0.0" strip-indent "^2.0.0" +reflect-metadata@^0.1.13: + version "0.1.13" + resolved "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" + integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== + regenerate-unicode-properties@^8.0.2: version "8.0.2" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.0.2.tgz#7b38faa296252376d363558cfbda90c9ce709662"