Merge pull request #27836 from woocommerce/packages/api/add/repository-listing
@woocommerce/api: Added list() repository operation and classes for managing store settings
This commit is contained in:
commit
f9ef91adc1
File diff suppressed because it is too large
Load Diff
|
@ -37,9 +37,9 @@
|
||||||
"@babel/polyfill": "7.10.4",
|
"@babel/polyfill": "7.10.4",
|
||||||
"@babel/preset-env": "7.10.4",
|
"@babel/preset-env": "7.10.4",
|
||||||
"@babel/register": "7.10.4",
|
"@babel/register": "7.10.4",
|
||||||
"@typescript-eslint/eslint-plugin": "3.1.0",
|
"@typescript-eslint/eslint-plugin": "3.10.1",
|
||||||
"@typescript-eslint/experimental-utils": "^2.34.0",
|
"@typescript-eslint/experimental-utils": "3.10.1",
|
||||||
"@typescript-eslint/parser": "3.1.0",
|
"@typescript-eslint/parser": "3.10.1",
|
||||||
"@woocommerce/api": "file:tests/e2e/api",
|
"@woocommerce/api": "file:tests/e2e/api",
|
||||||
"@woocommerce/e2e-core-tests": "file:tests/e2e/core-tests",
|
"@woocommerce/e2e-core-tests": "file:tests/e2e/core-tests",
|
||||||
"@woocommerce/e2e-environment": "file:tests/e2e/env",
|
"@woocommerce/e2e-environment": "file:tests/e2e/env",
|
||||||
|
@ -84,7 +84,7 @@
|
||||||
"puppeteer": "^2.1.1",
|
"puppeteer": "^2.1.1",
|
||||||
"stylelint": "12.0.1",
|
"stylelint": "12.0.1",
|
||||||
"stylelint-config-wordpress": "16.0.0",
|
"stylelint-config-wordpress": "16.0.0",
|
||||||
"typescript": "3.9.5",
|
"typescript": "3.9.7",
|
||||||
"webpack": "4.44.1",
|
"webpack": "4.44.1",
|
||||||
"webpack-cli": "3.3.12",
|
"webpack-cli": "3.3.12",
|
||||||
"wp-textdomain": "1.0.1"
|
"wp-textdomain": "1.0.1"
|
||||||
|
|
|
@ -14,7 +14,7 @@ module.exports = {
|
||||||
'no-useless-constructor': 'off',
|
'no-useless-constructor': 'off',
|
||||||
'@typescript-eslint/no-useless-constructor': 2,
|
'@typescript-eslint/no-useless-constructor': 2,
|
||||||
},
|
},
|
||||||
'plugins': [
|
plugins: [
|
||||||
'@typescript-eslint'
|
'@typescript-eslint'
|
||||||
],
|
],
|
||||||
extends: [
|
extends: [
|
||||||
|
@ -22,17 +22,22 @@ module.exports = {
|
||||||
],
|
],
|
||||||
overrides: [
|
overrides: [
|
||||||
{
|
{
|
||||||
'files': [
|
files: [
|
||||||
'**/*.js',
|
'**/*.js',
|
||||||
'**/*.ts'
|
'**/*.ts'
|
||||||
]
|
],
|
||||||
|
settings: {
|
||||||
|
jsdoc: {
|
||||||
|
mode: 'typescript',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'files': [
|
files: [
|
||||||
'**/*.spec.ts',
|
'**/*.spec.ts',
|
||||||
'**/*.test.ts'
|
'**/*.test.ts'
|
||||||
],
|
],
|
||||||
'rules': {
|
rules: {
|
||||||
'no-console': 'off',
|
'no-console': 'off',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,8 @@ httpClient.get( '/wc/v3/products' ).then( ( response ) => {
|
||||||
response.headers;
|
response.headers;
|
||||||
// Access the data from the response, in this case, the products.
|
// Access the data from the response, in this case, the products.
|
||||||
response.data;
|
response.data;
|
||||||
|
}, ( error ) => {
|
||||||
|
// Handle errors that may have come up.
|
||||||
} );
|
} );
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
preset: 'ts-jest',
|
preset: 'ts-jest',
|
||||||
|
verbose: true,
|
||||||
rootDir: 'src',
|
rootDir: 'src',
|
||||||
testEnvironment: 'node',
|
testEnvironment: 'node',
|
||||||
testPathIgnorePatterns: [ '/node_modules/', '/dist/' ],
|
testPathIgnorePatterns: [ '/node_modules/', '/dist/' ],
|
||||||
|
|
|
@ -672,9 +672,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/babel__generator": {
|
"@types/babel__generator": {
|
||||||
"version": "7.6.1",
|
"version": "7.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz",
|
||||||
"integrity": "sha512-bBKm+2VPJcMRVwNhxKu8W+5/zT7pwNEqeokFOmbvVSqGzFneNxYcEBro9Ac7/N9tlsaPYnZLK8J1LWKkMsLAew==",
|
"integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/types": "^7.0.0"
|
"@babel/types": "^7.0.0"
|
||||||
|
@ -691,9 +691,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/babel__traverse": {
|
"@types/babel__traverse": {
|
||||||
"version": "7.0.14",
|
"version": "7.0.15",
|
||||||
"resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.14.tgz",
|
"resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.15.tgz",
|
||||||
"integrity": "sha512-8w9szzKs14ZtBVuP6Wn7nMLRJ0D6dfB0VEBEyRgxrZ/Ln49aNMykrghM2FaNn4FJRzNppCSa0Rv9pBRM5Xc3wg==",
|
"integrity": "sha512-Pzh9O3sTK8V6I1olsXpCfj2k/ygO2q1X0vhhnDrEQyYLHZesWz+zMZMVcwXLCYf0U36EtmyYaFGPfXlTtDHe3A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/types": "^7.3.0"
|
"@babel/types": "^7.3.0"
|
||||||
|
@ -4636,9 +4636,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "3.8.3",
|
"version": "3.9.7",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz",
|
||||||
"integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==",
|
"integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"union-value": {
|
"union-value": {
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
"jest-mock-extended": "^1.0.10",
|
"jest-mock-extended": "^1.0.10",
|
||||||
"moxios": "0.4.0",
|
"moxios": "0.4.0",
|
||||||
"ts-jest": "25.5.0",
|
"ts-jest": "25.5.0",
|
||||||
"typescript": "3.8.3"
|
"typescript": "3.9.7"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
|
|
|
@ -1,5 +1,17 @@
|
||||||
import { Model } from '../../models/model';
|
import { Model } from '../../models/model';
|
||||||
import { ModelRepository } from '../model-repository';
|
import {
|
||||||
|
CreatesModels,
|
||||||
|
DeletesChildModels,
|
||||||
|
DeletesModels,
|
||||||
|
ListsChildModels,
|
||||||
|
ListsModels,
|
||||||
|
ModelRepository,
|
||||||
|
ModelRepositoryParams,
|
||||||
|
ReadsChildModels,
|
||||||
|
ReadsModels,
|
||||||
|
UpdatesChildModels,
|
||||||
|
UpdatesModels,
|
||||||
|
} from '../model-repository';
|
||||||
|
|
||||||
class DummyModel extends Model {
|
class DummyModel extends Model {
|
||||||
public name: string = '';
|
public name: string = '';
|
||||||
|
@ -9,20 +21,103 @@ class DummyModel extends Model {
|
||||||
Object.assign( this, partial );
|
Object.assign( this, partial );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
type DummyModelParams = ModelRepositoryParams< DummyModel, never, { search: string }, 'name' >
|
||||||
|
|
||||||
|
class DummyChildModel extends Model {
|
||||||
|
public childName: string = '';
|
||||||
|
|
||||||
|
public constructor( partial?: Partial< DummyModel > ) {
|
||||||
|
super();
|
||||||
|
Object.assign( this, partial );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type DummyChildParams = ModelRepositoryParams< DummyChildModel, { parent: string }, { childSearch: string }, 'childName' >
|
||||||
|
|
||||||
describe( 'ModelRepository', () => {
|
describe( 'ModelRepository', () => {
|
||||||
|
it( 'should list', async () => {
|
||||||
|
const model = new DummyModel();
|
||||||
|
const callback = jest.fn().mockResolvedValue( [ model ] );
|
||||||
|
const repository: ListsModels< DummyModelParams > = new ModelRepository< DummyModelParams >(
|
||||||
|
callback,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
|
const listed = await repository.list( { search: 'test' } );
|
||||||
|
expect( listed ).toContain( model );
|
||||||
|
expect( callback ).toHaveBeenCalledWith( { search: 'test' } );
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'should list child', async () => {
|
||||||
|
const model = new DummyChildModel();
|
||||||
|
const callback = jest.fn().mockResolvedValue( [ model ] );
|
||||||
|
const repository: ListsChildModels< DummyChildParams > = new ModelRepository< DummyChildParams >(
|
||||||
|
callback,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
|
const listed = await repository.list( { parent: 'test' }, { childSearch: 'test' } );
|
||||||
|
expect( listed ).toContain( model );
|
||||||
|
expect( callback ).toHaveBeenCalledWith( { parent: 'test' }, { childSearch: 'test' } );
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'should throw error on list without callback', () => {
|
||||||
|
const repository: ListsModels< DummyModelParams > = new ModelRepository< DummyModelParams >(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect( () => repository.list() ).toThrowError( /not supported/i );
|
||||||
|
} );
|
||||||
|
|
||||||
it( 'should create', async () => {
|
it( 'should create', async () => {
|
||||||
const model = new DummyModel();
|
const model = new DummyModel();
|
||||||
const callback = jest.fn().mockResolvedValue( model );
|
const callback = jest.fn().mockResolvedValue( model );
|
||||||
const repository = new ModelRepository< DummyModel >( callback, null, null, null );
|
const repository: CreatesModels< DummyModelParams > = new ModelRepository< DummyModelParams >(
|
||||||
|
null,
|
||||||
|
callback,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
const created = await repository.create( { name: 'test' } );
|
const created = await repository.create( { name: 'test' } );
|
||||||
expect( created ).toBe( model );
|
expect( created ).toBe( model );
|
||||||
expect( callback ).toHaveBeenCalledWith( { name: 'test' } );
|
expect( callback ).toHaveBeenCalledWith( { name: 'test' } );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
it( 'should create child', async () => {
|
||||||
|
const model = new DummyChildModel();
|
||||||
|
const callback = jest.fn().mockResolvedValue( model );
|
||||||
|
const repository: CreatesModels< DummyChildParams > = new ModelRepository< DummyChildParams >(
|
||||||
|
null,
|
||||||
|
callback,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
|
const created = await repository.create( { childName: 'test' } );
|
||||||
|
expect( created ).toBe( model );
|
||||||
|
expect( callback ).toHaveBeenCalledWith( { childName: 'test' } );
|
||||||
|
} );
|
||||||
|
|
||||||
it( 'should throw error on create without callback', () => {
|
it( 'should throw error on create without callback', () => {
|
||||||
const repository = new ModelRepository< DummyModel >( null, null, null, null );
|
const repository: CreatesModels< DummyModelParams > = new ModelRepository< DummyModelParams >(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
expect( () => repository.create( { name: 'test' } ) ).toThrowError( /not supported/i );
|
expect( () => repository.create( { name: 'test' } ) ).toThrowError( /not supported/i );
|
||||||
} );
|
} );
|
||||||
|
@ -30,15 +125,43 @@ describe( 'ModelRepository', () => {
|
||||||
it( 'should read', async () => {
|
it( 'should read', async () => {
|
||||||
const model = new DummyModel();
|
const model = new DummyModel();
|
||||||
const callback = jest.fn().mockResolvedValue( model );
|
const callback = jest.fn().mockResolvedValue( model );
|
||||||
const repository = new ModelRepository< DummyModel >( null, callback, null, null );
|
const repository: ReadsModels< DummyModelParams > = new ModelRepository< DummyModelParams >(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
callback,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
const created = await repository.read( 1 );
|
const created = await repository.read( 1 );
|
||||||
expect( created ).toBe( model );
|
expect( created ).toBe( model );
|
||||||
expect( callback ).toHaveBeenCalledWith( 1 );
|
expect( callback ).toHaveBeenCalledWith( 1 );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
it( 'should read child', async () => {
|
||||||
|
const model = new DummyChildModel();
|
||||||
|
const callback = jest.fn().mockResolvedValue( model );
|
||||||
|
const repository: ReadsChildModels< DummyChildParams > = new ModelRepository< DummyChildParams >(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
callback,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
|
const created = await repository.read( { parent: 'yes' }, 1 );
|
||||||
|
expect( created ).toBe( model );
|
||||||
|
expect( callback ).toHaveBeenCalledWith( { parent: 'yes' }, 1 );
|
||||||
|
} );
|
||||||
|
|
||||||
it( 'should throw error on read without callback', () => {
|
it( 'should throw error on read without callback', () => {
|
||||||
const repository = new ModelRepository< DummyModel >( null, null, null, null );
|
const repository: ReadsModels< DummyModelParams > = new ModelRepository< DummyModelParams >(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
expect( () => repository.read( 1 ) ).toThrowError( /not supported/i );
|
expect( () => repository.read( 1 ) ).toThrowError( /not supported/i );
|
||||||
} );
|
} );
|
||||||
|
@ -46,30 +169,85 @@ describe( 'ModelRepository', () => {
|
||||||
it( 'should update', async () => {
|
it( 'should update', async () => {
|
||||||
const model = new DummyModel();
|
const model = new DummyModel();
|
||||||
const callback = jest.fn().mockResolvedValue( model );
|
const callback = jest.fn().mockResolvedValue( model );
|
||||||
const repository = new ModelRepository< DummyModel >( null, null, callback, null );
|
const repository: UpdatesModels< DummyModelParams > = new ModelRepository< DummyModelParams >(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
callback,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
const updated = await repository.update( 1, { name: 'new-name' } );
|
const updated = await repository.update( 1, { name: 'new-name' } );
|
||||||
expect( updated ).toBe( model );
|
expect( updated ).toBe( model );
|
||||||
expect( callback ).toHaveBeenCalledWith( 1, { name: 'new-name' } );
|
expect( callback ).toHaveBeenCalledWith( 1, { name: 'new-name' } );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
it( 'should update child', async () => {
|
||||||
|
const model = new DummyChildModel();
|
||||||
|
const callback = jest.fn().mockResolvedValue( model );
|
||||||
|
const repository: UpdatesChildModels< DummyChildParams > = new ModelRepository< DummyChildParams >(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
callback,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
|
const updated = await repository.update( { parent: 'test' }, 1, { childName: 'new-name' } );
|
||||||
|
expect( updated ).toBe( model );
|
||||||
|
expect( callback ).toHaveBeenCalledWith( { parent: 'test' }, 1, { childName: 'new-name' } );
|
||||||
|
} );
|
||||||
|
|
||||||
it( 'should throw error on update without callback', () => {
|
it( 'should throw error on update without callback', () => {
|
||||||
const repository = new ModelRepository< DummyModel >( null, null, null, null );
|
const repository: UpdatesModels< DummyModelParams > = new ModelRepository< DummyModelParams >(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
expect( () => repository.update( 1, { name: 'new-name' } ) ).toThrowError( /not supported/i );
|
expect( () => repository.update( 1, { name: 'new-name' } ) ).toThrowError( /not supported/i );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
it( 'should delete', async () => {
|
it( 'should delete', async () => {
|
||||||
const callback = jest.fn().mockResolvedValue( true );
|
const callback = jest.fn().mockResolvedValue( true );
|
||||||
const repository = new ModelRepository< DummyModel >( null, null, null, callback );
|
const repository: DeletesModels< DummyModelParams > = new ModelRepository< DummyModelParams >(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
callback,
|
||||||
|
);
|
||||||
|
|
||||||
const success = await repository.delete( 1 );
|
const success = await repository.delete( 1 );
|
||||||
expect( success ).toBe( true );
|
expect( success ).toBe( true );
|
||||||
expect( callback ).toHaveBeenCalledWith( 1 );
|
expect( callback ).toHaveBeenCalledWith( 1 );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
it( 'should delete child', async () => {
|
||||||
|
const callback = jest.fn().mockResolvedValue( true );
|
||||||
|
const repository: DeletesChildModels< DummyChildParams > = new ModelRepository< DummyChildParams >(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
callback,
|
||||||
|
);
|
||||||
|
|
||||||
|
const success = await repository.delete( { parent: 'yes' }, 1 );
|
||||||
|
expect( success ).toBe( true );
|
||||||
|
expect( callback ).toHaveBeenCalledWith( { parent: 'yes' }, 1 );
|
||||||
|
} );
|
||||||
|
|
||||||
it( 'should throw error on delete without callback', () => {
|
it( 'should throw error on delete without callback', () => {
|
||||||
const repository = new ModelRepository< DummyModel >( null, null, null, null );
|
const repository: DeletesModels< DummyModelParams > = new ModelRepository< DummyModelParams >(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
expect( () => repository.delete( 1 ) ).toThrowError( /not supported/i );
|
expect( () => repository.delete( 1 ) ).toThrowError( /not supported/i );
|
||||||
} );
|
} );
|
||||||
|
|
|
@ -1,69 +1,247 @@
|
||||||
import { Model } from '../models/model';
|
import { Model, ModelID } from '../models/model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for describing the shape of parent identifiers for repositories.
|
||||||
|
*
|
||||||
|
* @typedef ModelParentID
|
||||||
|
* @alias Object.<string,ModelID>
|
||||||
|
*/
|
||||||
|
interface ModelParentID {
|
||||||
|
[ key: number ]: ModelID
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This type describes the structure of different kinds of data that is extracted
|
||||||
|
* for use in the repository to provide type-safety to repository actions.
|
||||||
|
*/
|
||||||
|
export interface ModelRepositoryParams<
|
||||||
|
T extends Model = never,
|
||||||
|
// @ts-ignore
|
||||||
|
ParentID extends ModelID | ModelParentID = never,
|
||||||
|
// @ts-ignore
|
||||||
|
ListParams = never,
|
||||||
|
// @ts-ignore
|
||||||
|
UpdateParams extends keyof T = never,
|
||||||
|
> {
|
||||||
|
// Since TypeScript's type system is structural we need to add something to this type to prevent
|
||||||
|
// it from matching with everything else (since it is an empty interface).
|
||||||
|
thisTypeIsDeclarativeOnly: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These helpers will extract information about a model from its repository params to be used in the repository.
|
||||||
|
*/
|
||||||
|
type ModelClass< T extends ModelRepositoryParams > = [ T ] extends [ ModelRepositoryParams< infer X > ] ? X : never;
|
||||||
|
type ParentID< T extends ModelRepositoryParams > = [ T ] extends [ ModelRepositoryParams< any, infer X > ] ? X : never;
|
||||||
|
type ListParams< T extends ModelRepositoryParams > = [ T ] extends [ ModelRepositoryParams< any, any, infer X > ] ? X : never;
|
||||||
|
type UpdateParams< T extends ModelRepositoryParams > = [ T ] extends [ ModelRepositoryParams< infer C, any, any, infer X > ] ?
|
||||||
|
( [ X ] extends [ keyof C ] ? Pick< C, X > : never ) :
|
||||||
|
never;
|
||||||
|
type HasParent< T extends ModelRepositoryParams, P, C > = [ ParentID< T > ] extends [ never ] ? C : P;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A callback for listing models using a data source.
|
||||||
|
*
|
||||||
|
* @callback ListFn
|
||||||
|
* @param {L} [params] The list parameters for the query.
|
||||||
|
* @return {Promise.<Array.<T>>} Resolves to an array of created models.
|
||||||
|
* @template {Model} T
|
||||||
|
* @template L
|
||||||
|
*/
|
||||||
|
export type ListFn< T extends ModelRepositoryParams > = ( params?: ListParams< T > ) => Promise< ModelClass< T >[] >;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A callback for listing child models using a data source.
|
||||||
|
*
|
||||||
|
* @callback ListChildFn
|
||||||
|
* @param {P} parent The parent identifier for the model.
|
||||||
|
* @param {L} [params] The list parameters for the query.
|
||||||
|
* @return {Promise.<Array.<T>>} Resolves to an array of created models.
|
||||||
|
* @template {Model} T
|
||||||
|
* @template {ModelParentID} P
|
||||||
|
* @template L
|
||||||
|
*/
|
||||||
|
export type ListChildFn< T extends ModelRepositoryParams > = (
|
||||||
|
parent: ParentID< T >,
|
||||||
|
params?: ListParams< T >
|
||||||
|
) => Promise< ModelClass< T >[] >;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A callback for creating a model using a data source.
|
* A callback for creating a model using a data source.
|
||||||
*
|
*
|
||||||
* @callback CreateFn
|
* @callback CreateFn
|
||||||
* @param {Object} properties The properties of the model to create.
|
* @param {Partial.<T>} properties The properties of the model to create.
|
||||||
* @return {Promise.<Model>} Resolves to the created model.
|
* @return {Promise.<T>} Resolves to the created model.
|
||||||
|
* @template {Model} T
|
||||||
*/
|
*/
|
||||||
export type CreateFn< T > = ( properties: Partial< T > ) => Promise< T >;
|
export type CreateFn< T extends ModelRepositoryParams > = ( properties: Partial< ModelClass< T > > ) => Promise< ModelClass< T > >;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A callback for reading a model using a data source.
|
* A callback for reading a model using a data source.
|
||||||
*
|
*
|
||||||
* @callback ReadFn
|
* @callback ReadFn
|
||||||
* @param {number|Object} id The ID or object used to find the model.
|
* @param {ModelID} id The ID of the model.
|
||||||
* @return {Promise.<Model>} Resolves to the read model.
|
* @return {Promise.<T>} Resolves to the read model.
|
||||||
|
* @template {Model} T
|
||||||
*/
|
*/
|
||||||
export type ReadFn< IDParam, T > = ( id: IDParam ) => Promise< T >;
|
export type ReadFn< T extends ModelRepositoryParams > = ( id: ModelID ) => Promise< ModelClass< T > >;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A callback for reading a child model using a data source.
|
||||||
|
*
|
||||||
|
* @callback ReadChildFn
|
||||||
|
* @param {P} parent The parent identifier for the model.
|
||||||
|
* @param {ModelID} childID The ID of the model.
|
||||||
|
* @return {Promise.<T>} Resolves to the read model.
|
||||||
|
* @template {Model} T
|
||||||
|
* @template {ModelParentID} P
|
||||||
|
*/
|
||||||
|
export type ReadChildFn< T extends ModelRepositoryParams > = ( parent: ParentID< T >, childID: ModelID ) => Promise< ModelClass< T > >;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A callback for updating a model using a data source.
|
* A callback for updating a model using a data source.
|
||||||
*
|
*
|
||||||
* @callback UpdateFn
|
* @callback UpdateFn
|
||||||
* @param {number|Object} id The ID or object used to find the model.
|
* @param {ModelID} id The ID of the model.
|
||||||
* @return {Promise.<Model>} Resolves to the updated model.
|
* @param {Partial.<T>} properties The properties to update.
|
||||||
|
* @return {Promise.<T>} Resolves to the updated model.
|
||||||
|
* @template {Model} T
|
||||||
*/
|
*/
|
||||||
export type UpdateFn< IDParam, T > = ( id: IDParam, properties: Partial< T > ) => Promise< T >;
|
export type UpdateFn< T extends ModelRepositoryParams > = (
|
||||||
|
id: ModelID,
|
||||||
|
properties: UpdateParams< T >,
|
||||||
|
) => Promise< ModelClass< T > >;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A callback for updating a child model using a data source.
|
||||||
|
*
|
||||||
|
* @callback UpdateChildFn
|
||||||
|
* @param {P} parent The parent identifier for the model.
|
||||||
|
* @param {ModelID} childID The ID of the model.
|
||||||
|
* @param {Partial.<T>} properties The properties to update.
|
||||||
|
* @return {Promise.<T>} Resolves to the updated model.
|
||||||
|
* @template {Model} T
|
||||||
|
* @template {ModelParentID} P
|
||||||
|
*/
|
||||||
|
export type UpdateChildFn< T extends ModelRepositoryParams > = (
|
||||||
|
parent: ParentID< T >,
|
||||||
|
childID: ModelID,
|
||||||
|
properties: UpdateParams< T >,
|
||||||
|
) => Promise< ModelClass< T > >;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A callback for deleting a model from a data source.
|
* A callback for deleting a model from a data source.
|
||||||
*
|
*
|
||||||
* @callback DeleteFn
|
* @callback DeleteFn
|
||||||
* @param {number|Object} id The ID or object used to find the model.
|
* @param {ModelID} id The ID of the model.
|
||||||
* @return {Promise.<boolean>} Resolves to true once the model has been deleted.
|
* @return {Promise.<boolean>} Resolves to true once the model has been deleted.
|
||||||
*/
|
*/
|
||||||
export type DeleteFn< IDParam > = ( id: IDParam ) => Promise< boolean >;
|
export type DeleteFn = ( id: ModelID ) => Promise< boolean >;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A callback for deleting a child model from a data source.
|
||||||
|
*
|
||||||
|
* @callback DeleteChildFn
|
||||||
|
* @param {P} parent The parent identifier for the model.
|
||||||
|
* @param {ModelID} childID The ID of the model.
|
||||||
|
* @return {Promise.<boolean>} Resolves to true once the model has been deleted.
|
||||||
|
* @template {ModelParentID} P
|
||||||
|
*/
|
||||||
|
export type DeleteChildFn< T extends ModelRepositoryParams > = ( parent: ParentID< T >, childID: ModelID ) => Promise< boolean >;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for repositories that can list models.
|
||||||
|
*
|
||||||
|
* @typedef ListsModels
|
||||||
|
* @property {ListFn.<T,L>} list Lists models using the repository.
|
||||||
|
* @template {Model} T
|
||||||
|
* @template L
|
||||||
|
*/
|
||||||
|
export interface ListsModels< T extends ModelRepositoryParams > {
|
||||||
|
list( params?: HasParent< T, never, ListParams< T > > ): Promise< ModelClass< T >[] >;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for repositories that can list child models.
|
||||||
|
*
|
||||||
|
* @typedef ListsChildModels
|
||||||
|
* @property {ListChildFn.<T,P,L>} list Lists models using the repository.
|
||||||
|
* @template {Model} T
|
||||||
|
* @template {ModelParentID} P
|
||||||
|
* @template L
|
||||||
|
*/
|
||||||
|
export interface ListsChildModels< T extends ModelRepositoryParams > {
|
||||||
|
list(
|
||||||
|
parent: HasParent< T, ParentID< T >, never >,
|
||||||
|
params?: HasParent< T, ListParams< T >, never >,
|
||||||
|
): Promise< ModelClass< T >[] >;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface for repositories that can create models.
|
* An interface for repositories that can create models.
|
||||||
*
|
*
|
||||||
* @typedef CreatesModels
|
* @typedef CreatesModels
|
||||||
* @property {CreateFn} create Creates a model using the repository.
|
* @property {CreateFn.<T>} create Creates a model using the repository.
|
||||||
|
* @template {Model} T
|
||||||
*/
|
*/
|
||||||
export interface CreatesModels< T extends Model > {
|
export interface CreatesModels< T extends ModelRepositoryParams > {
|
||||||
create( properties: Partial< T > ): Promise< T >;
|
create( properties: Partial< ModelClass< T > > ): Promise< ModelClass< T > >;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface for repositories that can read models.
|
* An interface for repositories that can read models.
|
||||||
*
|
*
|
||||||
* @typedef ReadsModels
|
* @typedef ReadsModels
|
||||||
* @property {ReadFn} read Reads a model using the repository.
|
* @property {ReadFn.<T>} read Reads a model using the repository.
|
||||||
|
* @template {Model} T
|
||||||
*/
|
*/
|
||||||
export interface ReadsModels< T extends Model, IDParam = number > {
|
export interface ReadsModels< T extends ModelRepositoryParams > {
|
||||||
read( id: IDParam ): Promise< T >;
|
read( id: HasParent< T, never, ModelID > ): Promise< ModelClass< T > >;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for repositories that can read models that are children.
|
||||||
|
*
|
||||||
|
* @typedef ReadsChildModels
|
||||||
|
* @property {ReadChildFn.<T,P>} read Reads a model using the repository.
|
||||||
|
* @template {Model} T
|
||||||
|
* @template {ModelParentID} P
|
||||||
|
*/
|
||||||
|
export interface ReadsChildModels< T extends ModelRepositoryParams > {
|
||||||
|
read(
|
||||||
|
parent: HasParent< T, ParentID< T >, never >,
|
||||||
|
childID: HasParent< T, ModelID, never >,
|
||||||
|
): Promise< ModelClass< T > >;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface for repositories that can update models.
|
* An interface for repositories that can update models.
|
||||||
*
|
*
|
||||||
* @typedef UpdatesModels
|
* @typedef UpdatesModels
|
||||||
* @property {UpdateFn} update Updates a model using the repository.
|
* @property {UpdateFn.<T>} update Updates a model using the repository.
|
||||||
|
* @template {Model} T
|
||||||
*/
|
*/
|
||||||
export interface UpdatesModels< T extends Model, IDParam = number > {
|
export interface UpdatesModels< T extends ModelRepositoryParams > {
|
||||||
update( id: IDParam, properties: Partial< T > ): Promise< T >;
|
update(
|
||||||
|
id: HasParent< T, never, ModelID >,
|
||||||
|
properties: HasParent< T, never, UpdateParams< T > >,
|
||||||
|
): Promise< ModelClass< T > >;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for repositories that can update models.
|
||||||
|
*
|
||||||
|
* @typedef UpdatesChildModels
|
||||||
|
* @property {UpdateChildFn.<T,P>} update Updates a model using the repository.
|
||||||
|
* @template {Model} T
|
||||||
|
* @template {ModelParentID} P
|
||||||
|
*/
|
||||||
|
export interface UpdatesChildModels< T extends ModelRepositoryParams > {
|
||||||
|
update(
|
||||||
|
parent: HasParent< T, ParentID< T >, never >,
|
||||||
|
childID: HasParent< T, ModelID, never >,
|
||||||
|
properties: HasParent< T, UpdateParams< T >, never >,
|
||||||
|
): Promise< ModelClass< T > >;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -72,24 +250,54 @@ export interface UpdatesModels< T extends Model, IDParam = number > {
|
||||||
* @typedef DeletesModels
|
* @typedef DeletesModels
|
||||||
* @property {DeleteFn} delete Deletes a model using the repository.
|
* @property {DeleteFn} delete Deletes a model using the repository.
|
||||||
*/
|
*/
|
||||||
export interface DeletesModels< IDParam = number > {
|
export interface DeletesModels< T extends ModelRepositoryParams > {
|
||||||
delete( id: IDParam ): Promise< boolean >;
|
delete( id: HasParent< T, never, ModelID > ): Promise< boolean >;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for repositories that can delete models.
|
||||||
|
*
|
||||||
|
* @typedef DeletesModels
|
||||||
|
* @property {DeleteChildFn.<P>} delete Deletes a model using the repository.
|
||||||
|
* @template {ModelParentID} P
|
||||||
|
*/
|
||||||
|
export interface DeletesChildModels< T extends ModelRepositoryParams > {
|
||||||
|
delete(
|
||||||
|
parent: HasParent< T, ParentID< T >, never >,
|
||||||
|
childID: HasParent< T, ModelID, never >,
|
||||||
|
): Promise< boolean >;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class for performing CRUD operations on models using a number of internal hooks.
|
* A class for performing CRUD operations on models using a number of internal hooks.
|
||||||
* Note that if a model does not support a given operation then it will throw an
|
* Note that if a model does not support a given operation then it will throw an
|
||||||
* error when attempting to perform that action.
|
* error when attempting to perform that action.
|
||||||
|
*
|
||||||
|
* @template {Model} T
|
||||||
|
* @template {ModelParentID} P
|
||||||
|
* @template {Object} L
|
||||||
*/
|
*/
|
||||||
export class ModelRepository< T extends Model, IDParam = number > implements
|
export class ModelRepository< T extends ModelRepositoryParams > implements
|
||||||
CreatesModels< T >,
|
ListsModels< T >,
|
||||||
ReadsModels< T, IDParam >,
|
ListsChildModels< T >,
|
||||||
UpdatesModels< T, IDParam >,
|
ReadsModels< T >,
|
||||||
DeletesModels< IDParam > {
|
ReadsChildModels< T >,
|
||||||
|
UpdatesModels< T >,
|
||||||
|
UpdatesChildModels< T >,
|
||||||
|
DeletesModels< T >,
|
||||||
|
DeletesChildModels< T > {
|
||||||
|
/**
|
||||||
|
* The hook used to list models.
|
||||||
|
*
|
||||||
|
* @type {ListFn.<T,P,L>|ListChildFn<T,P,L>}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
private readonly listHook: HasParent< T, ListChildFn< T >, ListFn< T > > | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The hook used to create models
|
* The hook used to create models
|
||||||
*
|
*
|
||||||
* @type {CreateFn}
|
* @type {CreateFn.<T>}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
private readonly createHook: CreateFn< T > | null;
|
private readonly createHook: CreateFn< T > | null;
|
||||||
|
@ -97,41 +305,44 @@ export class ModelRepository< T extends Model, IDParam = number > implements
|
||||||
/**
|
/**
|
||||||
* The hook used to read models.
|
* The hook used to read models.
|
||||||
*
|
*
|
||||||
* @type {ReadFn}
|
* @type {ReadFn.<T>|ReadChildFn.<T,P>}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
private readonly readHook: ReadFn< IDParam, T > | null;
|
private readonly readHook: HasParent< T, ReadChildFn< T >, ReadFn< T > > | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The hook used to update models.
|
* The hook used to update models.
|
||||||
*
|
*
|
||||||
* @type {UpdateFn}
|
* @type {UpdateFn.<T>|UpdateChildFn.<T,P>}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
private readonly updateHook: UpdateFn< IDParam, T > | null;
|
private readonly updateHook: HasParent< T, UpdateChildFn< T >, UpdateFn< T > > | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The hook used to delete models.
|
* The hook used to delete models.
|
||||||
*
|
*
|
||||||
* @type {DeleteFn}
|
* @type {DeleteFn|DeleteChildFn.<P>}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
private readonly deleteHook: DeleteFn< IDParam > | null;
|
private readonly deleteHook: HasParent< T, DeleteChildFn< T >, DeleteFn > | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new repository instance.
|
* Creates a new repository instance.
|
||||||
*
|
*
|
||||||
* @param {CreateFn|null} createHook The hook for model creation.
|
* @param {ListFn.<T,L>|ListChildFn<T,P,L>} listHook The hook for model listing.
|
||||||
* @param {ReadFn|null} readHook The hook for model reading.
|
* @param {CreateFn.<T>|null} createHook The hook for model creation.
|
||||||
* @param {UpdateFn|null} updateHook The hook for model updating.
|
* @param {ReadFn.<T>|ReadChildFn.<T,P>|null} readHook The hook for model reading.
|
||||||
* @param {DeleteFn|null} deleteHook The hook for model deletion.
|
* @param {UpdateFn.<T>|UpdateChildFn.<T,P>|null} updateHook The hook for model updating.
|
||||||
|
* @param {DeleteFn|DeleteChildFn.<P>|null} deleteHook The hook for model deletion.
|
||||||
*/
|
*/
|
||||||
public constructor(
|
public constructor(
|
||||||
|
listHook: HasParent< T, ListChildFn< T >, ListFn< T > > | null,
|
||||||
createHook: CreateFn< T > | null,
|
createHook: CreateFn< T > | null,
|
||||||
readHook: ReadFn< IDParam, T > | null,
|
readHook: HasParent< T, ReadChildFn< T >, ReadFn< T > > | null,
|
||||||
updateHook: UpdateFn< IDParam, T > | null,
|
updateHook: HasParent< T, UpdateChildFn< T >, UpdateFn< T > > | null,
|
||||||
deleteHook: DeleteFn< IDParam > | null,
|
deleteHook: HasParent< T, DeleteChildFn< T >, DeleteFn > | null,
|
||||||
) {
|
) {
|
||||||
|
this.listHook = listHook;
|
||||||
this.createHook = createHook;
|
this.createHook = createHook;
|
||||||
this.readHook = readHook;
|
this.readHook = readHook;
|
||||||
this.updateHook = updateHook;
|
this.updateHook = updateHook;
|
||||||
|
@ -139,12 +350,39 @@ export class ModelRepository< T extends Model, IDParam = number > implements
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the given model.
|
* Lists models using the repository.
|
||||||
*
|
*
|
||||||
* @param {Object} properties The properties for the model we'd like to create.
|
* @param {L|P} [paramsOrParent] The params for the lookup or the parent to list if the model is a child.
|
||||||
* @return {Promise.<Model>} A promise that resolves to the model after creation.
|
* @param {L} [params] The params when using the parent.
|
||||||
|
* @return {Promise.<Array.<T>>} Resolves to the listed models.
|
||||||
*/
|
*/
|
||||||
public create( properties: Partial< T > ): Promise< T > {
|
public list(
|
||||||
|
paramsOrParent?: HasParent< T, ParentID< T >, ListParams< T > >,
|
||||||
|
params?: HasParent< T, ListParams< T >, never >,
|
||||||
|
): Promise< ModelClass< T >[] > {
|
||||||
|
if ( ! this.listHook ) {
|
||||||
|
throw new Error( 'The \'list\' operation is not supported on this model.' );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( params === undefined ) {
|
||||||
|
return ( this.listHook as ListFn< T > )(
|
||||||
|
paramsOrParent as ListParams< T >,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( this.listHook as ListChildFn< T > )(
|
||||||
|
paramsOrParent as ParentID< T >,
|
||||||
|
params,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new model using the repository.
|
||||||
|
*
|
||||||
|
* @param {Partial.<T>} properties The properties to create the model with.
|
||||||
|
* @return {Promise.<T>} Resolves to the created model.
|
||||||
|
*/
|
||||||
|
public create( properties: Partial< ModelClass< T > > ): Promise< ModelClass< T > > {
|
||||||
if ( ! this.createHook ) {
|
if ( ! this.createHook ) {
|
||||||
throw new Error( 'The \'create\' operation is not supported on this model.' );
|
throw new Error( 'The \'create\' operation is not supported on this model.' );
|
||||||
}
|
}
|
||||||
|
@ -153,45 +391,87 @@ export class ModelRepository< T extends Model, IDParam = number > implements
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the given model.
|
* Reads a model using the repository.
|
||||||
*
|
*
|
||||||
* @param {number|Object} id The identifier for the model to read.
|
* @param {ModelID|P} idOrParent The ID of the model or its parent if the model is a child.
|
||||||
* @return {Promise.<Model>} A promise that resolves to the model.
|
* @param {ModelID} [childID] The ID of the model when using the parent.
|
||||||
|
* @return {Promise.<T>} Resolves to the loaded model.
|
||||||
*/
|
*/
|
||||||
public read( id: IDParam ): Promise< T > {
|
public read(
|
||||||
|
idOrParent: HasParent< T, ParentID< T >, ModelID >,
|
||||||
|
childID?: HasParent< T, ModelID, never >,
|
||||||
|
): Promise< ModelClass< T > > {
|
||||||
if ( ! this.readHook ) {
|
if ( ! this.readHook ) {
|
||||||
throw new Error( 'The \'read\' operation is not supported on this model.' );
|
throw new Error( 'The \'read\' operation is not supported on this model.' );
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.readHook( id );
|
if ( childID === undefined ) {
|
||||||
|
return ( this.readHook as ReadFn< T > )(
|
||||||
|
idOrParent as ModelID,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( this.readHook as ReadChildFn< T > )(
|
||||||
|
idOrParent as ParentID< T >,
|
||||||
|
childID,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the given model.
|
* Updates the model's properties using the repository.
|
||||||
*
|
*
|
||||||
* @param {number|Object} id The identifier for the model to create.
|
* @param {ModelID|P} idOrParent The ID of the model or its parent if the model is a child.
|
||||||
* @param {Object} properties The model properties that we'd like to update.
|
* @param {Partial.<T>|ModelID} propertiesOrChildID The properties for the model or the ID when using the parent.
|
||||||
* @return {Promise.<Model>} A promise that resolves to the model after updating.
|
* @param {Partial.<T>} [properties] The properties for child models.
|
||||||
|
* @return {Promise.<T>} Resolves to the updated model.
|
||||||
*/
|
*/
|
||||||
public update( id: IDParam, properties: Partial< T > ): Promise< T > {
|
public update(
|
||||||
|
idOrParent: HasParent< T, ParentID< T >, ModelID >,
|
||||||
|
propertiesOrChildID: HasParent< T, ModelID, UpdateParams< T > >,
|
||||||
|
properties?: HasParent< T, UpdateParams< T >, never >,
|
||||||
|
): Promise< ModelClass< T > > {
|
||||||
if ( ! this.updateHook ) {
|
if ( ! this.updateHook ) {
|
||||||
throw new Error( 'The \'update\' operation is not supported on this model.' );
|
throw new Error( 'The \'update\' operation is not supported on this model.' );
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.updateHook( id, properties );
|
if ( properties === undefined ) {
|
||||||
|
return ( this.updateHook as UpdateFn< T > )(
|
||||||
|
idOrParent as ModelID,
|
||||||
|
propertiesOrChildID as UpdateParams< T >,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( this.updateHook as UpdateChildFn< T > )(
|
||||||
|
idOrParent as ParentID< T >,
|
||||||
|
propertiesOrChildID as ModelID,
|
||||||
|
properties,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes the given model.
|
* Deletes a model using the repository.
|
||||||
*
|
*
|
||||||
* @param {number|Object} id The identifier for the model to delete.
|
* @param {ModelID|P} idOrParent The ID of the model or its parent if the model is a child.
|
||||||
* @return {Promise.<boolean>} A promise that resolves to "true" on success.
|
* @param {ModelID} [childID] The ID of the model when using the parent.
|
||||||
|
* @return {Promise.<T>} Resolves to the loaded model.
|
||||||
*/
|
*/
|
||||||
public delete( id: IDParam ): Promise< boolean > {
|
public delete(
|
||||||
|
idOrParent: HasParent< T, ParentID< T >, ModelID >,
|
||||||
|
childID?: HasParent< T, ModelID, never >,
|
||||||
|
): Promise< boolean > {
|
||||||
if ( ! this.deleteHook ) {
|
if ( ! this.deleteHook ) {
|
||||||
throw new Error( 'The \'delete\' operation is not supported on this model.' );
|
throw new Error( 'The \'delete\' operation is not supported on this model.' );
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.deleteHook( id );
|
if ( childID === undefined ) {
|
||||||
|
return ( this.deleteHook as DeleteFn )(
|
||||||
|
idOrParent as ModelID,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( this.deleteHook as DeleteChildFn< T > )(
|
||||||
|
idOrParent as ParentID< T >,
|
||||||
|
childID,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
import axios, { AxiosInstance } from 'axios';
|
||||||
|
import * as moxios from 'moxios';
|
||||||
|
import { AxiosInterceptor } from '../axios-interceptor';
|
||||||
|
|
||||||
|
class TestInterceptor extends AxiosInterceptor {}
|
||||||
|
|
||||||
|
describe( 'AxiosInterceptor', () => {
|
||||||
|
let interceptors: TestInterceptor[];
|
||||||
|
let axiosInstance: AxiosInstance;
|
||||||
|
|
||||||
|
beforeEach( () => {
|
||||||
|
axiosInstance = axios.create();
|
||||||
|
moxios.install( axiosInstance );
|
||||||
|
interceptors = [];
|
||||||
|
} );
|
||||||
|
|
||||||
|
afterEach( () => {
|
||||||
|
for ( const interceptor of interceptors ) {
|
||||||
|
interceptor.stop( axiosInstance );
|
||||||
|
}
|
||||||
|
moxios.uninstall( axiosInstance );
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'should not break interceptor chaining for success', async () => {
|
||||||
|
moxios.stubRequest( 'http://test.test', { status: 200 } );
|
||||||
|
|
||||||
|
interceptors.push( new TestInterceptor() );
|
||||||
|
interceptors.push( new TestInterceptor() );
|
||||||
|
interceptors.push( new TestInterceptor() );
|
||||||
|
for ( const interceptor of interceptors ) {
|
||||||
|
interceptor.start( axiosInstance );
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await axiosInstance.get( 'http://test.test' );
|
||||||
|
|
||||||
|
expect( response.status ).toBe( 200 );
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'should not break interceptor chaining for errors', async () => {
|
||||||
|
moxios.stubRequest( 'http://test.test', { status: 401 } );
|
||||||
|
|
||||||
|
interceptors.push( new TestInterceptor() );
|
||||||
|
interceptors.push( new TestInterceptor() );
|
||||||
|
interceptors.push( new TestInterceptor() );
|
||||||
|
for ( const interceptor of interceptors ) {
|
||||||
|
interceptor.start( axiosInstance );
|
||||||
|
}
|
||||||
|
|
||||||
|
await expect( axiosInstance.get( 'http://test.test' ) ).rejects.toBeInstanceOf( Error );
|
||||||
|
} );
|
||||||
|
} );
|
|
@ -49,9 +49,7 @@ describe( 'AxiosResponseInterceptor', () => {
|
||||||
responseText: JSON.stringify( { code: 'error_code', message: 'value' } ),
|
responseText: JSON.stringify( { code: 'error_code', message: 'value' } ),
|
||||||
} );
|
} );
|
||||||
|
|
||||||
const response = await axiosInstance.get( 'http://test.test' );
|
await expect( axiosInstance.get( 'http://test.test' ) ).rejects.toMatchObject( {
|
||||||
|
|
||||||
expect( response ).toMatchObject( {
|
|
||||||
statusCode: 404,
|
statusCode: 404,
|
||||||
headers: {
|
headers: {
|
||||||
'content-type': 'application/json',
|
'content-type': 'application/json',
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { buildURL } from '../utils';
|
||||||
|
|
||||||
|
describe( 'buildURL', () => {
|
||||||
|
it( 'should use base when given no url', () => {
|
||||||
|
const url = buildURL( { baseURL: 'http://test.test' } );
|
||||||
|
expect( url ).toBe( 'http://test.test' );
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'should use url when given absolute', () => {
|
||||||
|
const url = buildURL( { baseURL: 'http://test.test', url: 'http://override.test' } );
|
||||||
|
expect( url ).toBe( 'http://override.test' );
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'should combine base and url', () => {
|
||||||
|
const url = buildURL( { baseURL: 'http://test.test', url: 'yes/test' } );
|
||||||
|
expect( url ).toBe( 'http://test.test/yes/test' );
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'should combine base and url with trailing/leading slashes', () => {
|
||||||
|
const url = buildURL( { baseURL: 'http://test.test/////', url: '////yes/test' } );
|
||||||
|
expect( url ).toBe( 'http://test.test/yes/test' );
|
||||||
|
} );
|
||||||
|
} );
|
|
@ -8,7 +8,7 @@ import { AxiosResponseInterceptor } from './axios-response-interceptor';
|
||||||
*/
|
*/
|
||||||
export class AxiosClient implements HTTPClient {
|
export class AxiosClient implements HTTPClient {
|
||||||
/**
|
/**
|
||||||
* An instance of the axios client for making HTTP requests.
|
* An instance of the Axios client for making HTTP requests.
|
||||||
*
|
*
|
||||||
* @type {AxiosInstance}
|
* @type {AxiosInstance}
|
||||||
* @private
|
* @private
|
||||||
|
|
|
@ -15,7 +15,7 @@ type ActiveInterceptor = {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A base class for encapsulating the start and stop functionality required by all axios interceptors.
|
* A base class for encapsulating the start and stop functionality required by all Axios interceptors.
|
||||||
*/
|
*/
|
||||||
export abstract class AxiosInterceptor {
|
export abstract class AxiosInterceptor {
|
||||||
/**
|
/**
|
||||||
|
@ -61,7 +61,7 @@ export abstract class AxiosInterceptor {
|
||||||
/**
|
/**
|
||||||
* An interceptor method for handling requests before they are made to the server.
|
* An interceptor method for handling requests before they are made to the server.
|
||||||
*
|
*
|
||||||
* @param {AxiosRequestConfig} config The axios request options.
|
* @param {AxiosRequestConfig} config The Axios request options.
|
||||||
*/
|
*/
|
||||||
protected handleRequest( config: AxiosRequestConfig ): AxiosRequestConfig {
|
protected handleRequest( config: AxiosRequestConfig ): AxiosRequestConfig {
|
||||||
return config;
|
return config;
|
||||||
|
@ -70,7 +70,7 @@ export abstract class AxiosInterceptor {
|
||||||
/**
|
/**
|
||||||
* An interceptor method for handling successful responses.
|
* An interceptor method for handling successful responses.
|
||||||
*
|
*
|
||||||
* @param {AxiosResponse} response The response from the axios client.
|
* @param {*} response The response from the Axios client.
|
||||||
*/
|
*/
|
||||||
protected onResponseSuccess( response: AxiosResponse ): any {
|
protected onResponseSuccess( response: AxiosResponse ): any {
|
||||||
return response;
|
return response;
|
||||||
|
@ -79,9 +79,9 @@ export abstract class AxiosInterceptor {
|
||||||
/**
|
/**
|
||||||
* An interceptor method for handling response failures.
|
* An interceptor method for handling response failures.
|
||||||
*
|
*
|
||||||
* @param {*} error The error that occurred.
|
* @param {Promise} error The error that occurred.
|
||||||
*/
|
*/
|
||||||
protected onResponseRejected( error: any ): any {
|
protected onResponseRejected( error: any ): any {
|
||||||
return error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import type { AxiosRequestConfig } from 'axios';
|
||||||
import * as createHmac from 'create-hmac';
|
import * as createHmac from 'create-hmac';
|
||||||
import * as OAuth from 'oauth-1.0a';
|
import * as OAuth from 'oauth-1.0a';
|
||||||
import { AxiosInterceptor } from './axios-interceptor';
|
import { AxiosInterceptor } from './axios-interceptor';
|
||||||
|
import { buildURL } from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A utility class for managing the lifecycle of an authentication interceptor.
|
* A utility class for managing the lifecycle of an authentication interceptor.
|
||||||
|
@ -43,7 +44,7 @@ export class AxiosOAuthInterceptor extends AxiosInterceptor {
|
||||||
* @return {AxiosRequestConfig} The request with the additional authorization headers.
|
* @return {AxiosRequestConfig} The request with the additional authorization headers.
|
||||||
*/
|
*/
|
||||||
protected handleRequest( request: AxiosRequestConfig ): AxiosRequestConfig {
|
protected handleRequest( request: AxiosRequestConfig ): AxiosRequestConfig {
|
||||||
const url = ( request.baseURL || '' ) + ( request.url || '' );
|
const url = buildURL( request );
|
||||||
if ( url.startsWith( 'https' ) ) {
|
if ( url.startsWith( 'https' ) ) {
|
||||||
request.auth = {
|
request.auth = {
|
||||||
username: this.oauth.consumer.key,
|
username: this.oauth.consumer.key,
|
||||||
|
|
|
@ -7,26 +7,21 @@ export class AxiosResponseInterceptor extends AxiosInterceptor {
|
||||||
* Transforms the Axios response into our HTTP response.
|
* Transforms the Axios response into our HTTP response.
|
||||||
*
|
*
|
||||||
* @param {AxiosResponse} response The response that we need to transform.
|
* @param {AxiosResponse} response The response that we need to transform.
|
||||||
* @return {Promise} A promise containing the HTTPResponse.
|
* @return {HTTPResponse} The HTTP response.
|
||||||
*/
|
*/
|
||||||
protected onResponseSuccess( response: AxiosResponse ): Promise< HTTPResponse > {
|
protected onResponseSuccess( response: AxiosResponse ): HTTPResponse {
|
||||||
return Promise.resolve< HTTPResponse >(
|
return new HTTPResponse( response.status, response.headers, response.data );
|
||||||
new HTTPResponse( response.status, response.headers, response.data ),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Axios throws HTTP errors so we need to eat those errors and pass them normally.
|
* Axios throws HTTP errors so we need to eat those errors and pass them normally.
|
||||||
*
|
*
|
||||||
* @param {*} error The error that was caught.
|
* @param {*} error The error that was caught.
|
||||||
* @return {Promise} A promise containing the HTTPResponse.
|
|
||||||
*/
|
*/
|
||||||
protected onResponseRejected( error: any ): Promise< HTTPResponse > {
|
protected onResponseRejected( error: any ): never {
|
||||||
// Convert HTTP response errors into a form that we can handle them with.
|
// Convert HTTP response errors into a form that we can handle them with.
|
||||||
if ( error.response ) {
|
if ( error.response ) {
|
||||||
return Promise.resolve< HTTPResponse >(
|
throw new HTTPResponse( error.response.status, error.response.headers, error.response.data );
|
||||||
new HTTPResponse( error.response.status, error.response.headers, error.response.data ),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw error;
|
throw error;
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { AxiosRequestConfig } from 'axios';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an Axios request config this function generates the URL that Axios will
|
||||||
|
* use to make the request.
|
||||||
|
*
|
||||||
|
* @param {AxiosRequestConfig} request The Axios request we're building the URL for.
|
||||||
|
* @return {string} The merged URL.
|
||||||
|
*/
|
||||||
|
export function buildURL( request: AxiosRequestConfig ): string {
|
||||||
|
const base = request.baseURL || '';
|
||||||
|
if ( ! request.url ) {
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Axios ignores the base when the URL is absolute.
|
||||||
|
const url = request.url;
|
||||||
|
if ( ! base || url.match( /^([a-z][a-z\d+\-.]*:)?\/\/[^\/]/i ) ) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove trailing slashes from the base and leading slashes from the URL so we can combine them consistently.
|
||||||
|
return base.replace( /\/+$/, '' ) + '/' + url.replace( /^\/+/, '' );
|
||||||
|
}
|
|
@ -1,2 +1,3 @@
|
||||||
export { HTTPClientFactory } from './http';
|
export { HTTPClientFactory } from './http';
|
||||||
export * from './models';
|
export * from './models';
|
||||||
|
export * from './services';
|
||||||
|
|
|
@ -1 +1,4 @@
|
||||||
export { SimpleProduct } from './products/simple-product';
|
export { SimpleProduct } from './products/simple-product';
|
||||||
|
|
||||||
|
export { SettingGroup } from './settings/setting-group';
|
||||||
|
export { Setting } from './settings/setting';
|
||||||
|
|
|
@ -1,11 +1,19 @@
|
||||||
/**
|
/**
|
||||||
* A base class for all models.
|
* The ID of a model.
|
||||||
|
*
|
||||||
|
* @typedef ModelID
|
||||||
|
* @alias string|number
|
||||||
|
*/
|
||||||
|
export type ModelID = string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base class for all models.
|
||||||
*/
|
*/
|
||||||
export abstract class Model {
|
export abstract class Model {
|
||||||
/**
|
/**
|
||||||
* The ID of the model if it exists.
|
* The ID of the model if it exists.
|
||||||
*
|
*
|
||||||
* @type {number|null}
|
* @type {string|number|null}
|
||||||
*/
|
*/
|
||||||
public readonly id: number | null = null;
|
public readonly id: ModelID | undefined;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,21 @@
|
||||||
import { AbstractProduct } from './abstract-product';
|
import { AbstractProduct } from './abstract-product';
|
||||||
import { HTTPClient } from '../../http';
|
import { HTTPClient } from '../../http';
|
||||||
import { CreatesModels } from '../../framework/model-repository';
|
|
||||||
import { simpleProductRESTRepository } from '../../repositories/rest/products/simple-product';
|
import { simpleProductRESTRepository } from '../../repositories/rest/products/simple-product';
|
||||||
|
import { CreatesModels, ModelRepositoryParams } from '../../framework/model-repository';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The parameters embedded in this generic can be used in the ModelRepository in order to give
|
||||||
|
* type-safety in an incredibly granular way.
|
||||||
|
*/
|
||||||
|
export type SimpleProductRepositoryParams = ModelRepositoryParams< SimpleProduct, never, never, 'regularPrice' >;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for creating simple products using the repository.
|
||||||
|
*
|
||||||
|
* @typedef CreatesSimpleProducts
|
||||||
|
* @alias CreatesModels.<SimpleProduct>
|
||||||
|
*/
|
||||||
|
export type CreatesSimpleProducts = CreatesModels< SimpleProductRepositoryParams >;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple product object.
|
* A simple product object.
|
||||||
|
@ -21,9 +35,8 @@ export class SimpleProduct extends AbstractProduct {
|
||||||
* Creates a model repository configured for communicating via the REST API.
|
* Creates a model repository configured for communicating via the REST API.
|
||||||
*
|
*
|
||||||
* @param {HTTPClient} httpClient The client for communicating via HTTP.
|
* @param {HTTPClient} httpClient The client for communicating via HTTP.
|
||||||
* @return {CreatesModels} The created repository.
|
|
||||||
*/
|
*/
|
||||||
public static restRepository( httpClient: HTTPClient ): CreatesModels< SimpleProduct > {
|
public static restRepository( httpClient: HTTPClient ): ReturnType< typeof simpleProductRESTRepository > {
|
||||||
return simpleProductRESTRepository( httpClient );
|
return simpleProductRESTRepository( httpClient );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
import { Model, ModelID } from '../model';
|
||||||
|
import { HTTPClient } from '../../http';
|
||||||
|
import { settingGroupRESTRepository } from '../../repositories/rest/settings/setting-group';
|
||||||
|
import { ListsModels, ModelRepositoryParams } from '../../framework/model-repository';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The parameters embedded in this generic can be used in the ModelRepository in order to give
|
||||||
|
* type-safety in an incredibly granular way.
|
||||||
|
*/
|
||||||
|
export type SettingGroupRepositoryParams = ModelRepositoryParams< SettingGroup >;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for listing setting groups using the repository.
|
||||||
|
*
|
||||||
|
* @typedef ListsSettingGroups
|
||||||
|
* @alias ListsModels.<SettingGroup>
|
||||||
|
*/
|
||||||
|
export type ListsSettingGroups = ListsModels< SettingGroupRepositoryParams >;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A settings group object.
|
||||||
|
*/
|
||||||
|
export class SettingGroup extends Model {
|
||||||
|
/**
|
||||||
|
* The label of the setting group.
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
public readonly label: string = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The description of the setting group.
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
public readonly description: string = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ID of the group this is a child of.
|
||||||
|
*
|
||||||
|
* @type {ModelID|null}
|
||||||
|
*/
|
||||||
|
public readonly parentID: ModelID | null = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new setting group instance with the given properties
|
||||||
|
*
|
||||||
|
* @param {Object} properties The properties to set in the object.
|
||||||
|
*/
|
||||||
|
public constructor( properties: Partial< SettingGroup > = {} ) {
|
||||||
|
super();
|
||||||
|
Object.assign( this, properties );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the repository for interacting with this type of model.
|
||||||
|
*
|
||||||
|
* @param {HTTPClient} httpClient The client for communicating via HTTP.
|
||||||
|
*/
|
||||||
|
public static restRepository( httpClient: HTTPClient ): ReturnType< typeof settingGroupRESTRepository > {
|
||||||
|
return settingGroupRESTRepository( httpClient );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
import { Model, ModelID } from '../model';
|
||||||
|
import { HTTPClient } from '../../http';
|
||||||
|
import { settingRESTRepository } from '../../repositories/rest/settings/setting';
|
||||||
|
import {
|
||||||
|
ModelRepositoryParams,
|
||||||
|
ListsChildModels,
|
||||||
|
ReadsChildModels,
|
||||||
|
UpdatesChildModels,
|
||||||
|
} from '../../framework/model-repository';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The parameters embedded in this generic can be used in the ModelRepository in order to give
|
||||||
|
* type-safety in an incredibly granular way.
|
||||||
|
*/
|
||||||
|
export type SettingRepositoryParams = ModelRepositoryParams< Setting, ModelID, never, 'value' >;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for listing settings using the repository.
|
||||||
|
*
|
||||||
|
* @typedef ListsSettings
|
||||||
|
* @alias ListsChildModels.<Setting,SettingParentID>
|
||||||
|
*/
|
||||||
|
export type ListsSettings = ListsChildModels< SettingRepositoryParams >;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for reading settings using the repository.
|
||||||
|
*
|
||||||
|
* @typedef ReadsSettings
|
||||||
|
* @alias ReadsChildModels.<Setting,SettingParentID>
|
||||||
|
*/
|
||||||
|
export type ReadsSettings = ReadsChildModels< SettingRepositoryParams >;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for updating settings using the repository.
|
||||||
|
*
|
||||||
|
* @typedef UpdatesSettings
|
||||||
|
* @alias UpdatesChildModels.<Setting,SettingParentID>
|
||||||
|
*/
|
||||||
|
export type UpdatesSettings = UpdatesChildModels< SettingRepositoryParams >;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default types of settings that are available.
|
||||||
|
*/
|
||||||
|
type SettingType = 'text' | 'select' | 'multiselect' | 'checkbox' | 'number';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A setting object.
|
||||||
|
*/
|
||||||
|
export class Setting extends Model {
|
||||||
|
/**
|
||||||
|
* The label of the setting.
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
public readonly label: string = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The description of the setting.
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
public readonly description: string = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the setting.
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
public readonly type: string | SettingType = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The options of the setting, if it has any.
|
||||||
|
*
|
||||||
|
* @type {Object.<string, string>|null}
|
||||||
|
*/
|
||||||
|
public readonly options: { [key: string]: string } | undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default value for the setting.
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
public readonly default: string = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current value of the setting.
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
public readonly value: string = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new setting instance with the given properties
|
||||||
|
*
|
||||||
|
* @param {Object} properties The properties to set in the object.
|
||||||
|
*/
|
||||||
|
public constructor( properties: Partial< Setting > = {} ) {
|
||||||
|
super();
|
||||||
|
Object.assign( this, properties );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the repository for interacting with this type of model.
|
||||||
|
*
|
||||||
|
* @param {HTTPClient} httpClient The client for communicating via HTTP.
|
||||||
|
*/
|
||||||
|
public static restRepository( httpClient: HTTPClient ): ReturnType< typeof settingRESTRepository > {
|
||||||
|
return settingRESTRepository( httpClient );
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,11 +2,10 @@ import { simpleProductRESTRepository } from '../simple-product';
|
||||||
import { mock, MockProxy } from 'jest-mock-extended';
|
import { mock, MockProxy } from 'jest-mock-extended';
|
||||||
import { HTTPClient, HTTPResponse } from '../../../../http';
|
import { HTTPClient, HTTPResponse } from '../../../../http';
|
||||||
import { SimpleProduct } from '../../../../models';
|
import { SimpleProduct } from '../../../../models';
|
||||||
import { CreatesModels } from '../../../../framework/model-repository';
|
|
||||||
|
|
||||||
describe( 'simpleProductRESTRepository', () => {
|
describe( 'simpleProductRESTRepository', () => {
|
||||||
let httpClient: MockProxy< HTTPClient >;
|
let httpClient: MockProxy< HTTPClient >;
|
||||||
let repository: CreatesModels< SimpleProduct >;
|
let repository: ReturnType< typeof simpleProductRESTRepository >;
|
||||||
|
|
||||||
beforeEach( () => {
|
beforeEach( () => {
|
||||||
httpClient = mock< HTTPClient >();
|
httpClient = mock< HTTPClient >();
|
||||||
|
|
|
@ -1,14 +1,9 @@
|
||||||
import { HTTPClient } from '../../../http';
|
import { HTTPClient } from '../../../http';
|
||||||
import { CreateFn, CreatesModels, ModelRepository } from '../../../framework/model-repository';
|
import { CreateFn, ModelRepository } from '../../../framework/model-repository';
|
||||||
import { SimpleProduct } from '../../../models';
|
import { SimpleProduct } from '../../../models';
|
||||||
|
import { CreatesSimpleProducts, SimpleProductRepositoryParams } from '../../../models/products/simple-product';
|
||||||
|
|
||||||
/**
|
function restCreate( httpClient: HTTPClient ): CreateFn< SimpleProductRepositoryParams > {
|
||||||
* Creates a callback for REST model creation.
|
|
||||||
*
|
|
||||||
* @param {HTTPClient} httpClient The HTTP client for requests.
|
|
||||||
* @return {CreateFn} The callback for creating models via the REST API.
|
|
||||||
*/
|
|
||||||
function restCreate( httpClient: HTTPClient ): CreateFn< SimpleProduct > {
|
|
||||||
return async ( properties ) => {
|
return async ( properties ) => {
|
||||||
const response = await httpClient.post(
|
const response = await httpClient.post(
|
||||||
'/wc/v3/products',
|
'/wc/v3/products',
|
||||||
|
@ -31,10 +26,11 @@ function restCreate( httpClient: HTTPClient ): CreateFn< SimpleProduct > {
|
||||||
* Creates a new ModelRepository instance for interacting with models via the REST API.
|
* Creates a new ModelRepository instance for interacting with models via the REST API.
|
||||||
*
|
*
|
||||||
* @param {HTTPClient} httpClient The HTTP client for the REST requests to be made using.
|
* @param {HTTPClient} httpClient The HTTP client for the REST requests to be made using.
|
||||||
* @return {CreatesModels} A repository for interacting with models via the REST API.
|
* @return {CreatesSimpleProducts} The created repository.
|
||||||
*/
|
*/
|
||||||
export function simpleProductRESTRepository( httpClient: HTTPClient ): CreatesModels< SimpleProduct > {
|
export function simpleProductRESTRepository( httpClient: HTTPClient ): CreatesSimpleProducts {
|
||||||
return new ModelRepository(
|
return new ModelRepository(
|
||||||
|
null,
|
||||||
restCreate( httpClient ),
|
restCreate( httpClient ),
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { mock, MockProxy } from 'jest-mock-extended';
|
||||||
|
import { HTTPClient, HTTPResponse } from '../../../../http';
|
||||||
|
import { settingGroupRESTRepository } from '../setting-group';
|
||||||
|
|
||||||
|
describe( 'settingGroupRESTRepository', () => {
|
||||||
|
let httpClient: MockProxy< HTTPClient >;
|
||||||
|
let repository: ReturnType< typeof settingGroupRESTRepository >;
|
||||||
|
|
||||||
|
beforeEach( () => {
|
||||||
|
httpClient = mock< HTTPClient >();
|
||||||
|
repository = settingGroupRESTRepository( httpClient );
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'should list', async () => {
|
||||||
|
httpClient.get.mockResolvedValue( new HTTPResponse(
|
||||||
|
200,
|
||||||
|
{},
|
||||||
|
[
|
||||||
|
{
|
||||||
|
id: 'group_1',
|
||||||
|
label: 'Test Group 1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'group_2',
|
||||||
|
label: 'Test Group 2',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
) );
|
||||||
|
|
||||||
|
const list = await repository.list();
|
||||||
|
|
||||||
|
expect( list ).toHaveLength( 2 );
|
||||||
|
expect( list[ 0 ] ).toMatchObject( { id: 'group_1', label: 'Test Group 1' } );
|
||||||
|
expect( list[ 1 ] ).toMatchObject( { id: 'group_2', label: 'Test Group 2' } );
|
||||||
|
expect( httpClient.get ).toHaveBeenCalledWith( '/wc/v3/settings' );
|
||||||
|
} );
|
||||||
|
} );
|
|
@ -0,0 +1,73 @@
|
||||||
|
import { mock, MockProxy } from 'jest-mock-extended';
|
||||||
|
import { HTTPClient, HTTPResponse } from '../../../../http';
|
||||||
|
import { settingRESTRepository } from '../setting';
|
||||||
|
|
||||||
|
describe( 'settingGroupRESTRepository', () => {
|
||||||
|
let httpClient: MockProxy< HTTPClient >;
|
||||||
|
let repository: ReturnType< typeof settingRESTRepository >;
|
||||||
|
|
||||||
|
beforeEach( () => {
|
||||||
|
httpClient = mock< HTTPClient >();
|
||||||
|
repository = settingRESTRepository( httpClient );
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'should list', async () => {
|
||||||
|
httpClient.get.mockResolvedValue( new HTTPResponse(
|
||||||
|
200,
|
||||||
|
{},
|
||||||
|
[
|
||||||
|
{
|
||||||
|
id: 'setting_1',
|
||||||
|
label: 'Test Setting 1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'setting_2',
|
||||||
|
label: 'Test Setting 2',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
) );
|
||||||
|
|
||||||
|
const list = await repository.list( 'general' );
|
||||||
|
|
||||||
|
expect( list ).toHaveLength( 2 );
|
||||||
|
expect( list[ 0 ] ).toMatchObject( { id: 'setting_1', label: 'Test Setting 1' } );
|
||||||
|
expect( list[ 1 ] ).toMatchObject( { id: 'setting_2', label: 'Test Setting 2' } );
|
||||||
|
expect( httpClient.get ).toHaveBeenCalledWith( '/wc/v3/settings/general' );
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'should read', async () => {
|
||||||
|
httpClient.get.mockResolvedValue( new HTTPResponse(
|
||||||
|
200,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
id: 'setting_1',
|
||||||
|
label: 'Test Setting',
|
||||||
|
},
|
||||||
|
) );
|
||||||
|
|
||||||
|
const read = await repository.read( 'general', 'setting_1' );
|
||||||
|
|
||||||
|
expect( read ).toMatchObject( { id: 'setting_1', label: 'Test Setting' } );
|
||||||
|
expect( httpClient.get ).toHaveBeenCalledWith( '/wc/v3/settings/general/setting_1' );
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'should update', async () => {
|
||||||
|
httpClient.patch.mockResolvedValue( new HTTPResponse(
|
||||||
|
200,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
id: 'setting_1',
|
||||||
|
label: 'Test Setting',
|
||||||
|
value: 'updated-value',
|
||||||
|
},
|
||||||
|
) );
|
||||||
|
|
||||||
|
const updated = await repository.update( 'general', 'setting_1', { value: 'test-value' } );
|
||||||
|
|
||||||
|
expect( updated ).toMatchObject( { id: 'setting_1', value: 'updated-value' } );
|
||||||
|
expect( httpClient.patch ).toHaveBeenCalledWith(
|
||||||
|
'/wc/v3/settings/general/setting_1',
|
||||||
|
{ value: 'test-value' },
|
||||||
|
);
|
||||||
|
} );
|
||||||
|
} );
|
|
@ -0,0 +1,38 @@
|
||||||
|
import { HTTPClient } from '../../../http';
|
||||||
|
import { ListFn, ModelRepository } from '../../../framework/model-repository';
|
||||||
|
import { SettingGroup } from '../../../models';
|
||||||
|
import { ListsSettingGroups, SettingGroupRepositoryParams } from '../../../models/settings/setting-group';
|
||||||
|
|
||||||
|
function restList( httpClient: HTTPClient ): ListFn< SettingGroupRepositoryParams > {
|
||||||
|
return async () => {
|
||||||
|
const response = await httpClient.get( '/wc/v3/settings' );
|
||||||
|
|
||||||
|
const list: SettingGroup[] = [];
|
||||||
|
for ( const raw of response.data ) {
|
||||||
|
list.push( new SettingGroup( {
|
||||||
|
id: raw.id,
|
||||||
|
label: raw.label,
|
||||||
|
description: raw.description,
|
||||||
|
parentID: raw.parent_id,
|
||||||
|
} ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve( list );
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new ModelRepository instance for interacting with models via the REST API.
|
||||||
|
*
|
||||||
|
* @param {HTTPClient} httpClient The HTTP client for the REST requests to be made using.
|
||||||
|
* @return {ListsSettingGroups} The created repository.
|
||||||
|
*/
|
||||||
|
export function settingGroupRESTRepository( httpClient: HTTPClient ): ListsSettingGroups {
|
||||||
|
return new ModelRepository(
|
||||||
|
restList( httpClient ),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
import { HTTPClient } from '../../../http';
|
||||||
|
import {
|
||||||
|
ListChildFn,
|
||||||
|
ModelRepository,
|
||||||
|
ReadChildFn,
|
||||||
|
UpdateChildFn,
|
||||||
|
} from '../../../framework/model-repository';
|
||||||
|
import { Setting } from '../../../models';
|
||||||
|
import {
|
||||||
|
ListsSettings,
|
||||||
|
ReadsSettings,
|
||||||
|
SettingRepositoryParams,
|
||||||
|
UpdatesSettings,
|
||||||
|
} from '../../../models/settings/setting';
|
||||||
|
|
||||||
|
function restList( httpClient: HTTPClient ): ListChildFn< SettingRepositoryParams > {
|
||||||
|
return async ( parent ) => {
|
||||||
|
const response = await httpClient.get( '/wc/v3/settings/' + parent );
|
||||||
|
|
||||||
|
const list: Setting[] = [];
|
||||||
|
for ( const raw of response.data ) {
|
||||||
|
list.push( new Setting( {
|
||||||
|
id: raw.id,
|
||||||
|
label: raw.label,
|
||||||
|
description: raw.description,
|
||||||
|
type: raw.type,
|
||||||
|
options: raw.options,
|
||||||
|
default: raw.default,
|
||||||
|
value: raw.value,
|
||||||
|
} ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve( list );
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function restRead( httpClient: HTTPClient ): ReadChildFn< SettingRepositoryParams > {
|
||||||
|
return async ( parent, id ) => {
|
||||||
|
const response = await httpClient.get( '/wc/v3/settings/' + parent + '/' + id );
|
||||||
|
|
||||||
|
return Promise.resolve( new Setting( {
|
||||||
|
id: response.data.id,
|
||||||
|
label: response.data.label,
|
||||||
|
description: response.data.description,
|
||||||
|
type: response.data.type,
|
||||||
|
options: response.data.options,
|
||||||
|
default: response.data.default,
|
||||||
|
value: response.data.value,
|
||||||
|
} ) );
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function restUpdate( httpClient: HTTPClient ): UpdateChildFn< SettingRepositoryParams > {
|
||||||
|
return async ( parent, id, params ) => {
|
||||||
|
const response = await httpClient.patch(
|
||||||
|
'/wc/v3/settings/' + parent + '/' + id,
|
||||||
|
params,
|
||||||
|
);
|
||||||
|
|
||||||
|
return Promise.resolve( new Setting( {
|
||||||
|
id: response.data.id,
|
||||||
|
label: response.data.label,
|
||||||
|
description: response.data.description,
|
||||||
|
type: response.data.type,
|
||||||
|
options: response.data.options,
|
||||||
|
default: response.data.default,
|
||||||
|
value: response.data.value,
|
||||||
|
} ) );
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new ModelRepository instance for interacting with models via the REST API.
|
||||||
|
*
|
||||||
|
* @param {HTTPClient} httpClient The HTTP client for the REST requests to be made using.
|
||||||
|
* @return {ListsSettings|ReadsSettings|UpdatesSettings} The created repository.
|
||||||
|
*/
|
||||||
|
export function settingRESTRepository( httpClient: HTTPClient ): ListsSettings & ReadsSettings & UpdatesSettings {
|
||||||
|
return new ModelRepository(
|
||||||
|
restList( httpClient ),
|
||||||
|
null,
|
||||||
|
restRead( httpClient ),
|
||||||
|
restUpdate( httpClient ),
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
import { mock, MockProxy } from 'jest-mock-extended';
|
||||||
|
import { UpdatesSettings } from '../../models/settings/setting';
|
||||||
|
import { SettingService } from '../setting-service';
|
||||||
|
|
||||||
|
describe( 'SettingService', () => {
|
||||||
|
let repository: MockProxy< UpdatesSettings >;
|
||||||
|
let service: SettingService;
|
||||||
|
|
||||||
|
beforeEach( () => {
|
||||||
|
repository = mock< UpdatesSettings >();
|
||||||
|
service = new SettingService( repository );
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( 'should update address', async () => {
|
||||||
|
const result = await service.updateStoreAddress(
|
||||||
|
'line1',
|
||||||
|
'line2',
|
||||||
|
'New York',
|
||||||
|
'US:NY',
|
||||||
|
'12345',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect( result ).toBeTruthy();
|
||||||
|
expect( repository.update ).toHaveBeenCalledTimes( 5 );
|
||||||
|
expect( repository.update ).toHaveBeenCalledWith( 'general', 'woocommerce_store_address', { value: 'line1' } );
|
||||||
|
expect( repository.update ).toHaveBeenCalledWith( 'general', 'woocommerce_store_address_2', { value: 'line2' } );
|
||||||
|
expect( repository.update ).toHaveBeenCalledWith( 'general', 'woocommerce_store_city', { value: 'New York' } );
|
||||||
|
expect( repository.update ).toHaveBeenCalledWith( 'general', 'woocommerce_default_country', { value: 'US:NY' } );
|
||||||
|
expect( repository.update ).toHaveBeenCalledWith( 'general', 'woocommerce_store_postcode', { value: '12345' } );
|
||||||
|
} );
|
||||||
|
} );
|
|
@ -0,0 +1 @@
|
||||||
|
export { SettingService } from './setting-service';
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { Setting, UpdatesSettings } from '../models/settings/setting';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A service that wraps setting changes in convenient methods.
|
||||||
|
*/
|
||||||
|
export class SettingService {
|
||||||
|
/**
|
||||||
|
* The repository that will be used to change the settings.
|
||||||
|
*
|
||||||
|
* @type {UpdatesSettings}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
private readonly repository: UpdatesSettings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new service class for easily changing store settings.
|
||||||
|
*
|
||||||
|
* @param {UpdatesSettings} repository The repository that will be used to change the settings.
|
||||||
|
*/
|
||||||
|
public constructor( repository: UpdatesSettings ) {
|
||||||
|
this.repository = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the address for the store.
|
||||||
|
*
|
||||||
|
* @param {string} address1 The first address line.
|
||||||
|
* @param {string} address2 The second address line.
|
||||||
|
* @param {string} city The city.
|
||||||
|
* @param {string} country The country or country/state.
|
||||||
|
* @param {string} postCode The postal code.
|
||||||
|
* @return {Promise.<boolean>} Resolves to true if all of the settings are updated.
|
||||||
|
*/
|
||||||
|
public updateStoreAddress( address1: string, address2: string, city: string, country: string, postCode: string ): Promise< boolean > {
|
||||||
|
const promises: Promise< Setting >[] = [];
|
||||||
|
|
||||||
|
promises.push( this.repository.update( 'general', 'woocommerce_store_address', { value: address1 } ) );
|
||||||
|
promises.push( this.repository.update( 'general', 'woocommerce_store_address_2', { value: address2 } ) );
|
||||||
|
promises.push( this.repository.update( 'general', 'woocommerce_store_city', { value: city } ) );
|
||||||
|
promises.push( this.repository.update( 'general', 'woocommerce_default_country', { value: country } ) );
|
||||||
|
promises.push( this.repository.update( 'general', 'woocommerce_store_postcode', { value: postCode } ) );
|
||||||
|
|
||||||
|
return Promise.all( promises ).then( () => true );
|
||||||
|
}
|
||||||
|
}
|
|
@ -2601,9 +2601,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/babel__generator": {
|
"@types/babel__generator": {
|
||||||
"version": "7.6.1",
|
"version": "7.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz",
|
||||||
"integrity": "sha512-bBKm+2VPJcMRVwNhxKu8W+5/zT7pwNEqeokFOmbvVSqGzFneNxYcEBro9Ac7/N9tlsaPYnZLK8J1LWKkMsLAew==",
|
"integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/types": "^7.0.0"
|
"@babel/types": "^7.0.0"
|
||||||
}
|
}
|
||||||
|
@ -2618,13 +2618,21 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/babel__traverse": {
|
"@types/babel__traverse": {
|
||||||
"version": "7.0.14",
|
"version": "7.0.15",
|
||||||
"resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.14.tgz",
|
"resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.15.tgz",
|
||||||
"integrity": "sha512-8w9szzKs14ZtBVuP6Wn7nMLRJ0D6dfB0VEBEyRgxrZ/Ln49aNMykrghM2FaNn4FJRzNppCSa0Rv9pBRM5Xc3wg==",
|
"integrity": "sha512-Pzh9O3sTK8V6I1olsXpCfj2k/ygO2q1X0vhhnDrEQyYLHZesWz+zMZMVcwXLCYf0U36EtmyYaFGPfXlTtDHe3A==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/types": "^7.3.0"
|
"@babel/types": "^7.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/cheerio": {
|
||||||
|
"version": "0.22.22",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.22.tgz",
|
||||||
|
"integrity": "sha512-05DYX4zU96IBfZFY+t3Mh88nlwSMtmmzSYaQkKN48T495VV1dkHSah6qYyDTN5ngaS0i0VonH37m+RuzSM0YiA==",
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/color-name": {
|
"@types/color-name": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
|
||||||
|
@ -3760,20 +3768,20 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-abstract": {
|
"es-abstract": {
|
||||||
"version": "1.17.6",
|
"version": "1.17.7",
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
|
||||||
"integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
|
"integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"es-to-primitive": "^1.2.1",
|
"es-to-primitive": "^1.2.1",
|
||||||
"function-bind": "^1.1.1",
|
"function-bind": "^1.1.1",
|
||||||
"has": "^1.0.3",
|
"has": "^1.0.3",
|
||||||
"has-symbols": "^1.0.1",
|
"has-symbols": "^1.0.1",
|
||||||
"is-callable": "^1.2.0",
|
"is-callable": "^1.2.2",
|
||||||
"is-regex": "^1.1.0",
|
"is-regex": "^1.1.1",
|
||||||
"object-inspect": "^1.7.0",
|
"object-inspect": "^1.8.0",
|
||||||
"object-keys": "^1.1.1",
|
"object-keys": "^1.1.1",
|
||||||
"object.assign": "^4.1.0",
|
"object.assign": "^4.1.1",
|
||||||
"string.prototype.trimend": "^1.0.1",
|
"string.prototype.trimend": "^1.0.1",
|
||||||
"string.prototype.trimstart": "^1.0.1"
|
"string.prototype.trimstart": "^1.0.1"
|
||||||
}
|
}
|
||||||
|
@ -3795,19 +3803,19 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-abstract": {
|
"es-abstract": {
|
||||||
"version": "1.17.6",
|
"version": "1.17.7",
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
|
||||||
"integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
|
"integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"es-to-primitive": "^1.2.1",
|
"es-to-primitive": "^1.2.1",
|
||||||
"function-bind": "^1.1.1",
|
"function-bind": "^1.1.1",
|
||||||
"has": "^1.0.3",
|
"has": "^1.0.3",
|
||||||
"has-symbols": "^1.0.1",
|
"has-symbols": "^1.0.1",
|
||||||
"is-callable": "^1.2.0",
|
"is-callable": "^1.2.2",
|
||||||
"is-regex": "^1.1.0",
|
"is-regex": "^1.1.1",
|
||||||
"object-inspect": "^1.7.0",
|
"object-inspect": "^1.8.0",
|
||||||
"object-keys": "^1.1.1",
|
"object-keys": "^1.1.1",
|
||||||
"object.assign": "^4.1.0",
|
"object.assign": "^4.1.1",
|
||||||
"string.prototype.trimend": "^1.0.1",
|
"string.prototype.trimend": "^1.0.1",
|
||||||
"string.prototype.trimstart": "^1.0.1"
|
"string.prototype.trimstart": "^1.0.1"
|
||||||
}
|
}
|
||||||
|
@ -3824,19 +3832,19 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-abstract": {
|
"es-abstract": {
|
||||||
"version": "1.17.6",
|
"version": "1.17.7",
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
|
||||||
"integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
|
"integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"es-to-primitive": "^1.2.1",
|
"es-to-primitive": "^1.2.1",
|
||||||
"function-bind": "^1.1.1",
|
"function-bind": "^1.1.1",
|
||||||
"has": "^1.0.3",
|
"has": "^1.0.3",
|
||||||
"has-symbols": "^1.0.1",
|
"has-symbols": "^1.0.1",
|
||||||
"is-callable": "^1.2.0",
|
"is-callable": "^1.2.2",
|
||||||
"is-regex": "^1.1.0",
|
"is-regex": "^1.1.1",
|
||||||
"object-inspect": "^1.7.0",
|
"object-inspect": "^1.8.0",
|
||||||
"object-keys": "^1.1.1",
|
"object-keys": "^1.1.1",
|
||||||
"object.assign": "^4.1.0",
|
"object.assign": "^4.1.1",
|
||||||
"string.prototype.trimend": "^1.0.1",
|
"string.prototype.trimend": "^1.0.1",
|
||||||
"string.prototype.trimstart": "^1.0.1"
|
"string.prototype.trimstart": "^1.0.1"
|
||||||
}
|
}
|
||||||
|
@ -3855,20 +3863,20 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-abstract": {
|
"es-abstract": {
|
||||||
"version": "1.17.6",
|
"version": "1.17.7",
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
|
||||||
"integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
|
"integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"es-to-primitive": "^1.2.1",
|
"es-to-primitive": "^1.2.1",
|
||||||
"function-bind": "^1.1.1",
|
"function-bind": "^1.1.1",
|
||||||
"has": "^1.0.3",
|
"has": "^1.0.3",
|
||||||
"has-symbols": "^1.0.1",
|
"has-symbols": "^1.0.1",
|
||||||
"is-callable": "^1.2.0",
|
"is-callable": "^1.2.2",
|
||||||
"is-regex": "^1.1.0",
|
"is-regex": "^1.1.1",
|
||||||
"object-inspect": "^1.7.0",
|
"object-inspect": "^1.8.0",
|
||||||
"object-keys": "^1.1.1",
|
"object-keys": "^1.1.1",
|
||||||
"object.assign": "^4.1.0",
|
"object.assign": "^4.1.1",
|
||||||
"string.prototype.trimend": "^1.0.1",
|
"string.prototype.trimend": "^1.0.1",
|
||||||
"string.prototype.trimstart": "^1.0.1"
|
"string.prototype.trimstart": "^1.0.1"
|
||||||
}
|
}
|
||||||
|
@ -4322,9 +4330,9 @@
|
||||||
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
|
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
|
||||||
},
|
},
|
||||||
"caniuse-lite": {
|
"caniuse-lite": {
|
||||||
"version": "1.0.30001137",
|
"version": "1.0.30001141",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001137.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001141.tgz",
|
||||||
"integrity": "sha512-54xKQZTqZrKVHmVz0+UvdZR6kQc7pJDgfhsMYDG19ID1BWoNnDMFm5Q3uSBSU401pBvKYMsHAt9qhEDcxmk8aw=="
|
"integrity": "sha512-EHfInJHoQTmlMdVZrEc5gmwPc0zyN/hVufmGHPbVNQwlk7tJfCmQ2ysRZMY2MeleBivALUTyyxXnQjK18XrVpA=="
|
||||||
},
|
},
|
||||||
"capture-exit": {
|
"capture-exit": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
|
@ -4976,9 +4984,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"electron-to-chromium": {
|
"electron-to-chromium": {
|
||||||
"version": "1.3.572",
|
"version": "1.3.576",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.572.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.576.tgz",
|
||||||
"integrity": "sha512-TKqdEukCCl7JC20SwEoWTbtnGt4YjfHWAv4tcNky0a9qGo0WdM+Lrd60tps+nkaJCmktKBJjr99fLtEBU1ipWQ=="
|
"integrity": "sha512-uSEI0XZ//5ic+0NdOqlxp0liCD44ck20OAGyLMSymIWTEAtHKVJi6JM18acOnRgUgX7Q65QqnI+sNncNvIy8ew=="
|
||||||
},
|
},
|
||||||
"emoji-regex": {
|
"emoji-regex": {
|
||||||
"version": "8.0.0",
|
"version": "8.0.0",
|
||||||
|
@ -5088,10 +5096,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"enzyme-to-json": {
|
"enzyme-to-json": {
|
||||||
"version": "3.5.0",
|
"version": "3.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/enzyme-to-json/-/enzyme-to-json-3.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/enzyme-to-json/-/enzyme-to-json-3.6.1.tgz",
|
||||||
"integrity": "sha512-clusXRsiaQhG7+wtyc4t7MU8N3zCOgf4eY9+CeSenYzKlFST4lxerfOvnWd4SNaToKhkuba+w6m242YpQOS7eA==",
|
"integrity": "sha512-15tXuONeq5ORoZjV/bUo2gbtZrN2IH+Z6DvL35QmZyKHgbY1ahn6wcnLd9Xv9OjiwbAXiiP8MRZwbZrCv1wYNg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
|
"@types/cheerio": "^0.22.22",
|
||||||
"lodash": "^4.17.15",
|
"lodash": "^4.17.15",
|
||||||
"react-is": "^16.12.0"
|
"react-is": "^16.12.0"
|
||||||
}
|
}
|
||||||
|
@ -5105,20 +5114,20 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"es-abstract": {
|
"es-abstract": {
|
||||||
"version": "1.18.0-next.0",
|
"version": "1.18.0-next.1",
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.0.tgz",
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz",
|
||||||
"integrity": "sha512-elZXTZXKn51hUBdJjSZGYRujuzilgXo8vSPQzjGYXLvSlGiCo8VO8ZGV3kjo9a0WNJJ57hENagwbtlRuHuzkcQ==",
|
"integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"es-to-primitive": "^1.2.1",
|
"es-to-primitive": "^1.2.1",
|
||||||
"function-bind": "^1.1.1",
|
"function-bind": "^1.1.1",
|
||||||
"has": "^1.0.3",
|
"has": "^1.0.3",
|
||||||
"has-symbols": "^1.0.1",
|
"has-symbols": "^1.0.1",
|
||||||
"is-callable": "^1.2.0",
|
"is-callable": "^1.2.2",
|
||||||
"is-negative-zero": "^2.0.0",
|
"is-negative-zero": "^2.0.0",
|
||||||
"is-regex": "^1.1.1",
|
"is-regex": "^1.1.1",
|
||||||
"object-inspect": "^1.8.0",
|
"object-inspect": "^1.8.0",
|
||||||
"object-keys": "^1.1.1",
|
"object-keys": "^1.1.1",
|
||||||
"object.assign": "^4.1.0",
|
"object.assign": "^4.1.1",
|
||||||
"string.prototype.trimend": "^1.0.1",
|
"string.prototype.trimend": "^1.0.1",
|
||||||
"string.prototype.trimstart": "^1.0.1"
|
"string.prototype.trimstart": "^1.0.1"
|
||||||
}
|
}
|
||||||
|
@ -5894,19 +5903,19 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-abstract": {
|
"es-abstract": {
|
||||||
"version": "1.17.6",
|
"version": "1.17.7",
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
|
||||||
"integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
|
"integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"es-to-primitive": "^1.2.1",
|
"es-to-primitive": "^1.2.1",
|
||||||
"function-bind": "^1.1.1",
|
"function-bind": "^1.1.1",
|
||||||
"has": "^1.0.3",
|
"has": "^1.0.3",
|
||||||
"has-symbols": "^1.0.1",
|
"has-symbols": "^1.0.1",
|
||||||
"is-callable": "^1.2.0",
|
"is-callable": "^1.2.2",
|
||||||
"is-regex": "^1.1.0",
|
"is-regex": "^1.1.1",
|
||||||
"object-inspect": "^1.7.0",
|
"object-inspect": "^1.8.0",
|
||||||
"object-keys": "^1.1.1",
|
"object-keys": "^1.1.1",
|
||||||
"object.assign": "^4.1.0",
|
"object.assign": "^4.1.1",
|
||||||
"string.prototype.trimend": "^1.0.1",
|
"string.prototype.trimend": "^1.0.1",
|
||||||
"string.prototype.trimstart": "^1.0.1"
|
"string.prototype.trimstart": "^1.0.1"
|
||||||
}
|
}
|
||||||
|
@ -6404,20 +6413,20 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-abstract": {
|
"es-abstract": {
|
||||||
"version": "1.17.6",
|
"version": "1.17.7",
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
|
||||||
"integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
|
"integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"es-to-primitive": "^1.2.1",
|
"es-to-primitive": "^1.2.1",
|
||||||
"function-bind": "^1.1.1",
|
"function-bind": "^1.1.1",
|
||||||
"has": "^1.0.3",
|
"has": "^1.0.3",
|
||||||
"has-symbols": "^1.0.1",
|
"has-symbols": "^1.0.1",
|
||||||
"is-callable": "^1.2.0",
|
"is-callable": "^1.2.2",
|
||||||
"is-regex": "^1.1.0",
|
"is-regex": "^1.1.1",
|
||||||
"object-inspect": "^1.7.0",
|
"object-inspect": "^1.8.0",
|
||||||
"object-keys": "^1.1.1",
|
"object-keys": "^1.1.1",
|
||||||
"object.assign": "^4.1.0",
|
"object.assign": "^4.1.1",
|
||||||
"string.prototype.trimend": "^1.0.1",
|
"string.prototype.trimend": "^1.0.1",
|
||||||
"string.prototype.trimstart": "^1.0.1"
|
"string.prototype.trimstart": "^1.0.1"
|
||||||
}
|
}
|
||||||
|
@ -9391,32 +9400,12 @@
|
||||||
"integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA=="
|
"integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA=="
|
||||||
},
|
},
|
||||||
"object-is": {
|
"object-is": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.3.tgz",
|
||||||
"integrity": "sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==",
|
"integrity": "sha512-teyqLvFWzLkq5B9ki8FVWA902UER2qkxmdA4nLf+wjOLAWgxzCWZNCxpDq9MvE8MmhWNr+I8w3BN49Vx36Y6Xg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"define-properties": "^1.1.3",
|
"define-properties": "^1.1.3",
|
||||||
"es-abstract": "^1.17.5"
|
"es-abstract": "^1.18.0-next.1"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"es-abstract": {
|
|
||||||
"version": "1.17.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
|
|
||||||
"integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
|
|
||||||
"requires": {
|
|
||||||
"es-to-primitive": "^1.2.1",
|
|
||||||
"function-bind": "^1.1.1",
|
|
||||||
"has": "^1.0.3",
|
|
||||||
"has-symbols": "^1.0.1",
|
|
||||||
"is-callable": "^1.2.0",
|
|
||||||
"is-regex": "^1.1.0",
|
|
||||||
"object-inspect": "^1.7.0",
|
|
||||||
"object-keys": "^1.1.1",
|
|
||||||
"object.assign": "^4.1.0",
|
|
||||||
"string.prototype.trimend": "^1.0.1",
|
|
||||||
"string.prototype.trimstart": "^1.0.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"object-keys": {
|
"object-keys": {
|
||||||
|
@ -9454,19 +9443,19 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-abstract": {
|
"es-abstract": {
|
||||||
"version": "1.17.6",
|
"version": "1.17.7",
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
|
||||||
"integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
|
"integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"es-to-primitive": "^1.2.1",
|
"es-to-primitive": "^1.2.1",
|
||||||
"function-bind": "^1.1.1",
|
"function-bind": "^1.1.1",
|
||||||
"has": "^1.0.3",
|
"has": "^1.0.3",
|
||||||
"has-symbols": "^1.0.1",
|
"has-symbols": "^1.0.1",
|
||||||
"is-callable": "^1.2.0",
|
"is-callable": "^1.2.2",
|
||||||
"is-regex": "^1.1.0",
|
"is-regex": "^1.1.1",
|
||||||
"object-inspect": "^1.7.0",
|
"object-inspect": "^1.8.0",
|
||||||
"object-keys": "^1.1.1",
|
"object-keys": "^1.1.1",
|
||||||
"object.assign": "^4.1.0",
|
"object.assign": "^4.1.1",
|
||||||
"string.prototype.trimend": "^1.0.1",
|
"string.prototype.trimend": "^1.0.1",
|
||||||
"string.prototype.trimstart": "^1.0.1"
|
"string.prototype.trimstart": "^1.0.1"
|
||||||
}
|
}
|
||||||
|
@ -9491,19 +9480,19 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-abstract": {
|
"es-abstract": {
|
||||||
"version": "1.17.6",
|
"version": "1.17.7",
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
|
||||||
"integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
|
"integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"es-to-primitive": "^1.2.1",
|
"es-to-primitive": "^1.2.1",
|
||||||
"function-bind": "^1.1.1",
|
"function-bind": "^1.1.1",
|
||||||
"has": "^1.0.3",
|
"has": "^1.0.3",
|
||||||
"has-symbols": "^1.0.1",
|
"has-symbols": "^1.0.1",
|
||||||
"is-callable": "^1.2.0",
|
"is-callable": "^1.2.2",
|
||||||
"is-regex": "^1.1.0",
|
"is-regex": "^1.1.1",
|
||||||
"object-inspect": "^1.7.0",
|
"object-inspect": "^1.8.0",
|
||||||
"object-keys": "^1.1.1",
|
"object-keys": "^1.1.1",
|
||||||
"object.assign": "^4.1.0",
|
"object.assign": "^4.1.1",
|
||||||
"string.prototype.trimend": "^1.0.1",
|
"string.prototype.trimend": "^1.0.1",
|
||||||
"string.prototype.trimstart": "^1.0.1"
|
"string.prototype.trimstart": "^1.0.1"
|
||||||
}
|
}
|
||||||
|
@ -9520,19 +9509,19 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-abstract": {
|
"es-abstract": {
|
||||||
"version": "1.17.6",
|
"version": "1.17.7",
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
|
||||||
"integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
|
"integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"es-to-primitive": "^1.2.1",
|
"es-to-primitive": "^1.2.1",
|
||||||
"function-bind": "^1.1.1",
|
"function-bind": "^1.1.1",
|
||||||
"has": "^1.0.3",
|
"has": "^1.0.3",
|
||||||
"has-symbols": "^1.0.1",
|
"has-symbols": "^1.0.1",
|
||||||
"is-callable": "^1.2.0",
|
"is-callable": "^1.2.2",
|
||||||
"is-regex": "^1.1.0",
|
"is-regex": "^1.1.1",
|
||||||
"object-inspect": "^1.7.0",
|
"object-inspect": "^1.8.0",
|
||||||
"object-keys": "^1.1.1",
|
"object-keys": "^1.1.1",
|
||||||
"object.assign": "^4.1.0",
|
"object.assign": "^4.1.1",
|
||||||
"string.prototype.trimend": "^1.0.1",
|
"string.prototype.trimend": "^1.0.1",
|
||||||
"string.prototype.trimstart": "^1.0.1"
|
"string.prototype.trimstart": "^1.0.1"
|
||||||
}
|
}
|
||||||
|
@ -9559,19 +9548,19 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-abstract": {
|
"es-abstract": {
|
||||||
"version": "1.17.6",
|
"version": "1.17.7",
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
|
||||||
"integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
|
"integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"es-to-primitive": "^1.2.1",
|
"es-to-primitive": "^1.2.1",
|
||||||
"function-bind": "^1.1.1",
|
"function-bind": "^1.1.1",
|
||||||
"has": "^1.0.3",
|
"has": "^1.0.3",
|
||||||
"has-symbols": "^1.0.1",
|
"has-symbols": "^1.0.1",
|
||||||
"is-callable": "^1.2.0",
|
"is-callable": "^1.2.2",
|
||||||
"is-regex": "^1.1.0",
|
"is-regex": "^1.1.1",
|
||||||
"object-inspect": "^1.7.0",
|
"object-inspect": "^1.8.0",
|
||||||
"object-keys": "^1.1.1",
|
"object-keys": "^1.1.1",
|
||||||
"object.assign": "^4.1.0",
|
"object.assign": "^4.1.1",
|
||||||
"string.prototype.trimend": "^1.0.1",
|
"string.prototype.trimend": "^1.0.1",
|
||||||
"string.prototype.trimstart": "^1.0.1"
|
"string.prototype.trimstart": "^1.0.1"
|
||||||
}
|
}
|
||||||
|
@ -10217,20 +10206,20 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-abstract": {
|
"es-abstract": {
|
||||||
"version": "1.17.6",
|
"version": "1.17.7",
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
|
||||||
"integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
|
"integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"es-to-primitive": "^1.2.1",
|
"es-to-primitive": "^1.2.1",
|
||||||
"function-bind": "^1.1.1",
|
"function-bind": "^1.1.1",
|
||||||
"has": "^1.0.3",
|
"has": "^1.0.3",
|
||||||
"has-symbols": "^1.0.1",
|
"has-symbols": "^1.0.1",
|
||||||
"is-callable": "^1.2.0",
|
"is-callable": "^1.2.2",
|
||||||
"is-regex": "^1.1.0",
|
"is-regex": "^1.1.1",
|
||||||
"object-inspect": "^1.7.0",
|
"object-inspect": "^1.8.0",
|
||||||
"object-keys": "^1.1.1",
|
"object-keys": "^1.1.1",
|
||||||
"object.assign": "^4.1.0",
|
"object.assign": "^4.1.1",
|
||||||
"string.prototype.trimend": "^1.0.1",
|
"string.prototype.trimend": "^1.0.1",
|
||||||
"string.prototype.trimstart": "^1.0.1"
|
"string.prototype.trimstart": "^1.0.1"
|
||||||
}
|
}
|
||||||
|
@ -10976,20 +10965,20 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-abstract": {
|
"es-abstract": {
|
||||||
"version": "1.17.6",
|
"version": "1.17.7",
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
|
||||||
"integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
|
"integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"es-to-primitive": "^1.2.1",
|
"es-to-primitive": "^1.2.1",
|
||||||
"function-bind": "^1.1.1",
|
"function-bind": "^1.1.1",
|
||||||
"has": "^1.0.3",
|
"has": "^1.0.3",
|
||||||
"has-symbols": "^1.0.1",
|
"has-symbols": "^1.0.1",
|
||||||
"is-callable": "^1.2.0",
|
"is-callable": "^1.2.2",
|
||||||
"is-regex": "^1.1.0",
|
"is-regex": "^1.1.1",
|
||||||
"object-inspect": "^1.7.0",
|
"object-inspect": "^1.8.0",
|
||||||
"object-keys": "^1.1.1",
|
"object-keys": "^1.1.1",
|
||||||
"object.assign": "^4.1.0",
|
"object.assign": "^4.1.1",
|
||||||
"string.prototype.trimend": "^1.0.1",
|
"string.prototype.trimend": "^1.0.1",
|
||||||
"string.prototype.trimstart": "^1.0.1"
|
"string.prototype.trimstart": "^1.0.1"
|
||||||
}
|
}
|
||||||
|
@ -11015,19 +11004,19 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-abstract": {
|
"es-abstract": {
|
||||||
"version": "1.17.6",
|
"version": "1.17.7",
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
|
||||||
"integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
|
"integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"es-to-primitive": "^1.2.1",
|
"es-to-primitive": "^1.2.1",
|
||||||
"function-bind": "^1.1.1",
|
"function-bind": "^1.1.1",
|
||||||
"has": "^1.0.3",
|
"has": "^1.0.3",
|
||||||
"has-symbols": "^1.0.1",
|
"has-symbols": "^1.0.1",
|
||||||
"is-callable": "^1.2.0",
|
"is-callable": "^1.2.2",
|
||||||
"is-regex": "^1.1.0",
|
"is-regex": "^1.1.1",
|
||||||
"object-inspect": "^1.7.0",
|
"object-inspect": "^1.8.0",
|
||||||
"object-keys": "^1.1.1",
|
"object-keys": "^1.1.1",
|
||||||
"object.assign": "^4.1.0",
|
"object.assign": "^4.1.1",
|
||||||
"string.prototype.trimend": "^1.0.1",
|
"string.prototype.trimend": "^1.0.1",
|
||||||
"string.prototype.trimstart": "^1.0.1"
|
"string.prototype.trimstart": "^1.0.1"
|
||||||
}
|
}
|
||||||
|
@ -11044,19 +11033,19 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-abstract": {
|
"es-abstract": {
|
||||||
"version": "1.17.6",
|
"version": "1.17.7",
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
|
||||||
"integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
|
"integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"es-to-primitive": "^1.2.1",
|
"es-to-primitive": "^1.2.1",
|
||||||
"function-bind": "^1.1.1",
|
"function-bind": "^1.1.1",
|
||||||
"has": "^1.0.3",
|
"has": "^1.0.3",
|
||||||
"has-symbols": "^1.0.1",
|
"has-symbols": "^1.0.1",
|
||||||
"is-callable": "^1.2.0",
|
"is-callable": "^1.2.2",
|
||||||
"is-regex": "^1.1.0",
|
"is-regex": "^1.1.1",
|
||||||
"object-inspect": "^1.7.0",
|
"object-inspect": "^1.8.0",
|
||||||
"object-keys": "^1.1.1",
|
"object-keys": "^1.1.1",
|
||||||
"object.assign": "^4.1.0",
|
"object.assign": "^4.1.1",
|
||||||
"string.prototype.trimend": "^1.0.1",
|
"string.prototype.trimend": "^1.0.1",
|
||||||
"string.prototype.trimstart": "^1.0.1"
|
"string.prototype.trimstart": "^1.0.1"
|
||||||
}
|
}
|
||||||
|
@ -11566,19 +11555,19 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-abstract": {
|
"es-abstract": {
|
||||||
"version": "1.17.6",
|
"version": "1.17.7",
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz",
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
|
||||||
"integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==",
|
"integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"es-to-primitive": "^1.2.1",
|
"es-to-primitive": "^1.2.1",
|
||||||
"function-bind": "^1.1.1",
|
"function-bind": "^1.1.1",
|
||||||
"has": "^1.0.3",
|
"has": "^1.0.3",
|
||||||
"has-symbols": "^1.0.1",
|
"has-symbols": "^1.0.1",
|
||||||
"is-callable": "^1.2.0",
|
"is-callable": "^1.2.2",
|
||||||
"is-regex": "^1.1.0",
|
"is-regex": "^1.1.1",
|
||||||
"object-inspect": "^1.7.0",
|
"object-inspect": "^1.8.0",
|
||||||
"object-keys": "^1.1.1",
|
"object-keys": "^1.1.1",
|
||||||
"object.assign": "^4.1.0",
|
"object.assign": "^4.1.1",
|
||||||
"string.prototype.trimend": "^1.0.1",
|
"string.prototype.trimend": "^1.0.1",
|
||||||
"string.prototype.trimstart": "^1.0.1"
|
"string.prototype.trimstart": "^1.0.1"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue