Merge branch 'trunk' into bump-required-php-to-7.2

This commit is contained in:
Nestor Soriano 2022-03-29 10:45:07 +02:00
commit 25bf59d5e7
No known key found for this signature in database
GPG Key ID: 08110F3518C12CAD
312 changed files with 5076 additions and 12758 deletions

View File

@ -6,9 +6,6 @@ contact_links:
- name: ❓ Support Question
url: https://woocommerce.com/document/woocommerce-self-service-guide/
about: If you have a question please see our docs or use our forums, helpdesk, or Slack community!
- name: WooCommerce Admin
url: https://github.com/woocommerce/woocommerce-admin
about: Please report issues for WooCommerce Admin (such as Analytics and Onboarding) directly to it's repository.
- name: WooCommerce Blocks
url: https://github.com/woocommerce/woocommerce-gutenberg-products-block
about: Please report issues for WooCommerce Blocks directly to it's repository.

View File

@ -11,7 +11,7 @@ defaults:
jobs:
test:
name: PHP ${{ matrix.php }} WP ${{ matrix.wp }}
timeout-minutes: 15
timeout-minutes: 20
runs-on: ubuntu-latest
continue-on-error: ${{ matrix.wp == 'nightly' }}
strategy:
@ -67,6 +67,10 @@ jobs:
- name: Setup and install composer
run: pnpm nx composer-install woocommerce
- name: Build Admin feature config
working-directory: ./
run: pnpm nx build:feature-config woocommerce-admin
- name: Add PHP8 Compatibility.
run: |
if [ "$(php -r "echo version_compare(PHP_VERSION,'8.0','>=');")" ]; then

View File

@ -8,7 +8,7 @@ defaults:
jobs:
test:
name: PHP ${{ matrix.php }} WP ${{ matrix.wp }}
timeout-minutes: 15
timeout-minutes: 20
runs-on: ubuntu-latest
continue-on-error: ${{ matrix.wp == 'nightly' }}
strategy:

View File

@ -5,6 +5,7 @@ jobs:
feedback:
if: |
github.actor != 'github-actions' &&
github.actor == github.event.issue.user.login &&
github.event.issue &&
github.event.issue.state == 'open' &&
contains(github.event.issue.labels.*.name, 'needs: author feedback')

5
.gitignore vendored
View File

@ -4,7 +4,7 @@ Thumbs.db
# IDE files
.idea
.vscode/
.vscode/*
project.xml
project.properties
.project
@ -13,6 +13,9 @@ project.properties
*.sublime-workspace
.sublimelinterrc
# Excluded IDE Files for developer experience tooling within workspace
!.vscode/tasks.json
# Grunt
none

29
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,29 @@
{
"version": "2.0.0",
"tasks": [
{
"command": "pnpm tsc -b tsconfig.base.json",
"type": "shell",
"problemMatcher": [ "$tsc" ],
"label": "Typescript compile",
"detail": "Run tsc against tsconfig.base.json",
"runOptions": {
"runOn": "default"
}
},
{
"command": "pnpm tsc -b tsconfig.base.json --watch",
"type": "shell",
"problemMatcher": {
"base": "$tsc-watch",
"applyTo": "allDocuments"
},
"isBackground": true,
"label": "Incremental Typescript compile",
"detail": "Incremental background type checks",
"runOptions": {
"runOn": "folderOpen"
}
}
]
}

View File

@ -45,6 +45,21 @@ You might also want to run `pnpm start` to watch your CSS and JS changes if you
You're now ready to develop!
### Typescript Checking
Typescript is progressively being implemented in this repository, and you might come across some files that are `.ts` or `.tsx`. By default, a VSCode environment will run type checking on such files that are currently open.
As of now, some parts of the codebase that were imported from the Woocommerce-Admin repository, into the `plugins/woocommerce-admin/client` directory, still fail Typescript checking. This has been scheduled on the team's backlog to be fixed.
In order to run type checking across the entire repository, you can run this command in your shell, from the root of this repository:
```sh
pnpm tsc -b tsconfig.base.json
```
For better developer experience, the folder `.vscode/tasks.json` has two VSCode tasks to run these commands automatically as well as to parse the output and highlight the errors in the `Problems` tab and in the file explorer pane. The first task runs it once, the second one runs it in the background upon saving of any modified files. This task is also automatically prompted by VSCode to be run upon opening the folder.
## Using Xdebug
Please refer to [WP-ENV official README](https://github.com/WordPress/gutenberg/tree/master/packages/env#using-xdebug) section for setting up Xdebug.
@ -102,13 +117,12 @@ You can get the current MySQL port from the output of `wp-env start` command.
1. Open your choice of MySQL tool.
2. Use the following values to access the MySQL container.
3. You can omit the username and password.
| Name | Value |
| -------- | --------------------- |
| Host | 127.0.0.1 |
| Username | |
| Password | |
| Username | root |
| Password | password |
| Port | Port from the command |
## HOWTOs

View File

@ -19,13 +19,14 @@
"devDependencies": {
"@automattic/nx-composer": "^0.1.0",
"@nrwl/cli": "^13.3.4",
"@nrwl/linter": "^13.3.4",
"@nrwl/devkit": "^13.1.4",
"@nrwl/linter": "^13.3.4",
"@nrwl/tao": "13.3.4",
"@nrwl/web": "^13.3.4",
"@nrwl/workspace": "^13.3.4",
"@types/node": "14.14.33",
"@woocommerce/eslint-plugin": "^1.3.0",
"@woocommerce/eslint-plugin": "workspace:*",
"@wordpress/eslint-plugin": "^11.0.0",
"@wordpress/prettier-config": "^1.1.1",
"chalk": "^4.1.2",
"glob": "^7.2.0",

View File

@ -0,0 +1,4 @@
module.exports = {
extends: [ 'plugin:@woocommerce/eslint-plugin/recommended' ],
root: true,
};

View File

@ -37,6 +37,8 @@
"@types/puppeteer": "^5.4.5",
"@typescript-eslint/eslint-plugin": "^5.14.0",
"@woocommerce/api": "^0.2.0",
"@wordpress/eslint-plugin": "^11.0.0",
"eslint": "^8.12.0",
"jest": "^27.5.1",
"jest-cli": "^27.5.1",
"jest-mock-extended": "^1.0.18",
@ -48,8 +50,11 @@
"access": "public"
},
"scripts": {
"prepare": "pnpm run build",
"build": "tsc --build",
"start": "tsc --build --watch",
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
"lint": "eslint src",
"prepack": "pnpm run clean && pnpm run build"
}
}

View File

@ -21,6 +21,18 @@
"options": {
"script": "test"
}
}
},
"clean": {
"executor": "@nrwl/workspace:run-script",
"options": {
"script": "clean"
}
},
"prepare": {
"executor": "@nrwl/workspace:run-script",
"options": {
"script": "prepare"
}
}
}
}
}

View File

@ -47,15 +47,18 @@ async function deactivateAndDeletePlugin( pluginName: string ) {
}
export async function deactivateAndDeleteAllPlugins( except: string[] = [] ) {
let plugins = await getPlugins();
const skippedPlugins = [];
const promises = [];
for ( const plugin of plugins ) {
const splitPluginName = plugin.plugin.split( '/' );
const slug = splitPluginName[ 1 ] || splitPluginName[ 0 ];
if ( ! except.includes( slug ) ) {
promises.push( deactivateAndDeletePlugin( plugin.plugin ) );
} else {
skippedPlugins.push( slug );
}
}
await Promise.all( promises );
plugins = await getPlugins();
expect( plugins.length ).toEqual( except.length );
expect( plugins.length ).toEqual( skippedPlugins.length );
}

View File

@ -4,13 +4,23 @@
import { httpClient } from './http-client';
import { deactivateAndDeleteAllPlugins } from './plugins';
/* eslint-disable @typescript-eslint/no-var-requires */
const { utils } = require( '@woocommerce/e2e-utils' );
const { PLUGIN_NAME } = process.env;
const resetEndpoint = '/woocommerce-reset/v1/state';
const pluginName = PLUGIN_NAME ? PLUGIN_NAME : 'WooCommerce';
const pluginNameSlug = utils.getSlug( pluginName );
const skippedPlugins = [
'woocommerce',
'woocommerce-admin',
'woocommerce-reset',
'basic-auth',
'wp-mail-logging',
pluginNameSlug,
];
export async function resetWooCommerceState() {

View File

@ -16,14 +16,14 @@ export class ThemeSection extends BasePage {
async continueWithTheme( themeTitle: string ): Promise< void > {
const title = await waitForElementByText( 'h2', themeTitle );
const card = await title?.evaluateHandle( ( element ) => {
return element.closest( '.components-card' );
const chooseButton = await title?.evaluateHandle( ( element ) => {
const card = element.closest( '.components-card' );
return Array.from( card?.querySelectorAll( 'button' ) || [] ).find(
( el ) => el.textContent === 'Choose'
);
} );
const chooseButton = await card
?.asElement()
?.$x( `//button[contains(text(), "Choose")]` );
if ( chooseButton && chooseButton.length > 0 ) {
await chooseButton[ 0 ].click();
if ( chooseButton ) {
await chooseButton.asElement()?.click();
}
}
}

View File

@ -15,7 +15,12 @@ import {
} from '../model-repository';
import { DummyModel } from '../../__test_data__/dummy-model';
type DummyModelParams = ModelRepositoryParams< DummyModel, never, { search: string }, 'name' >
type DummyModelParams = ModelRepositoryParams<
DummyModel,
never,
{ search: string },
'name'
>;
class DummyChildModel extends Model {
public childName: string = '';
@ -25,7 +30,12 @@ class DummyChildModel extends Model {
Object.assign( this, partial );
}
}
type DummyChildParams = ModelRepositoryParams< DummyChildModel, { parent: string }, { childSearch: string }, 'childName' >
type DummyChildParams = ModelRepositoryParams<
DummyChildModel,
{ parent: string },
{ childSearch: string },
'childName'
>;
describe( 'ModelRepository', () => {
it( 'should list', async () => {
@ -36,7 +46,7 @@ describe( 'ModelRepository', () => {
null,
null,
null,
null,
null
);
const listed = await repository.list( { search: 'test' } );
@ -52,12 +62,18 @@ describe( 'ModelRepository', () => {
null,
null,
null,
null,
null
);
const listed = await repository.list( { parent: 'test' }, { childSearch: 'test' } );
const listed = await repository.list(
{ parent: 'test' },
{ childSearch: 'test' }
);
expect( listed ).toContain( model );
expect( callback ).toHaveBeenCalledWith( { parent: 'test' }, { childSearch: 'test' } );
expect( callback ).toHaveBeenCalledWith(
{ parent: 'test' },
{ childSearch: 'test' }
);
} );
it( 'should throw error on list without callback', () => {
@ -66,7 +82,7 @@ describe( 'ModelRepository', () => {
null,
null,
null,
null,
null
);
expect( () => repository.list() ).toThrowError( /not supported/i );
@ -80,7 +96,7 @@ describe( 'ModelRepository', () => {
callback,
null,
null,
null,
null
);
const created = await repository.create( { name: 'test' } );
@ -96,12 +112,18 @@ describe( 'ModelRepository', () => {
callback,
null,
null,
null,
null
);
const created = await repository.create( { parent: 'yes' }, { childName: 'test' } );
const created = await repository.create(
{ parent: 'yes' },
{ childName: 'test' }
);
expect( created ).toBe( model );
expect( callback ).toHaveBeenCalledWith( { parent: 'yes' }, { childName: 'test' } );
expect( callback ).toHaveBeenCalledWith(
{ parent: 'yes' },
{ childName: 'test' }
);
} );
it( 'should throw error on create without callback', () => {
@ -110,10 +132,12 @@ describe( 'ModelRepository', () => {
null,
null,
null,
null,
null
);
expect( () => repository.create( { name: 'test' } ) ).toThrowError( /not supported/i );
expect( () => repository.create( { name: 'test' } ) ).toThrowError(
/not supported/i
);
} );
it( 'should read', async () => {
@ -124,7 +148,7 @@ describe( 'ModelRepository', () => {
null,
callback,
null,
null,
null
);
const created = await repository.read( 1 );
@ -140,7 +164,7 @@ describe( 'ModelRepository', () => {
null,
callback,
null,
null,
null
);
const created = await repository.read( { parent: 'yes' }, 1 );
@ -154,7 +178,7 @@ describe( 'ModelRepository', () => {
null,
null,
null,
null,
null
);
expect( () => repository.read( 1 ) ).toThrowError( /not supported/i );
@ -168,7 +192,7 @@ describe( 'ModelRepository', () => {
null,
null,
callback,
null,
null
);
const updated = await repository.update( 1, { name: 'new-name' } );
@ -184,12 +208,16 @@ describe( 'ModelRepository', () => {
null,
null,
callback,
null,
null
);
const updated = await repository.update( { parent: 'test' }, 1, { childName: 'new-name' } );
const updated = await repository.update( { parent: 'test' }, 1, {
childName: 'new-name',
} );
expect( updated ).toBe( model );
expect( callback ).toHaveBeenCalledWith( { parent: 'test' }, 1, { childName: 'new-name' } );
expect( callback ).toHaveBeenCalledWith( { parent: 'test' }, 1, {
childName: 'new-name',
} );
} );
it( 'should throw error on update without callback', () => {
@ -198,10 +226,12 @@ describe( 'ModelRepository', () => {
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 () => {
@ -211,7 +241,7 @@ describe( 'ModelRepository', () => {
null,
null,
null,
callback,
callback
);
const success = await repository.delete( 1 );
@ -226,7 +256,7 @@ describe( 'ModelRepository', () => {
null,
null,
null,
callback,
callback
);
const success = await repository.delete( { parent: 'yes' }, 1 );
@ -240,7 +270,7 @@ describe( 'ModelRepository', () => {
null,
null,
null,
null,
null
);
expect( () => repository.delete( 1 ) ).toThrowError( /not supported/i );

View File

@ -35,15 +35,15 @@ describe( 'ModelTransformer', () => {
const fn2 = jest.fn();
fn2.mockReturnValue( { name: 'fn2' } );
const transformer = new ModelTransformer< DummyModel >(
[
// Ensure the orders are backwards so sorting is tested.
new DummyTransformation( 1, fn2 ),
new DummyTransformation( 0, fn1 ),
],
);
const transformer = new ModelTransformer< DummyModel >( [
// Ensure the orders are backwards so sorting is tested.
new DummyTransformation( 1, fn2 ),
new DummyTransformation( 0, fn1 ),
] );
let transformed = transformer.fromModel( new DummyModel( { name: 'fn0' } ) );
let transformed = transformer.fromModel(
new DummyModel( { name: 'fn0' } )
);
expect( fn1 ).toHaveBeenCalledWith( { name: 'fn0' } );
expect( fn2 ).toHaveBeenCalledWith( { name: 'fn1' } );
@ -61,17 +61,12 @@ describe( 'ModelTransformer', () => {
} );
it( 'should transform to model', () => {
const transformer = new ModelTransformer< DummyModel >(
[
new DummyTransformation(
0,
( p: any ) => {
p.name = 'Transformed-' + p.name;
return p;
},
),
],
);
const transformer = new ModelTransformer< DummyModel >( [
new DummyTransformation( 0, ( p: any ) => {
p.name = 'Transformed-' + p.name;
return p;
} ),
] );
const model = transformer.toModel( DummyModel, { name: 'Test' } );
@ -80,19 +75,16 @@ describe( 'ModelTransformer', () => {
} );
it( 'should transform from model', () => {
const transformer = new ModelTransformer< DummyModel >(
[
new DummyTransformation(
0,
( p: any ) => {
p.name = 'Transformed-' + p.name;
return p;
},
),
],
);
const transformer = new ModelTransformer< DummyModel >( [
new DummyTransformation( 0, ( p: any ) => {
p.name = 'Transformed-' + p.name;
return p;
} ),
] );
const transformed = transformer.fromModel( new DummyModel( { name: 'Test' } ) );
const transformed = transformer.fromModel(
new DummyModel( { name: 'Test' } )
);
expect( transformed ).not.toBeInstanceOf( DummyModel );
expect( transformed.name ).toEqual( 'Transformed-Test' );

View File

@ -7,7 +7,7 @@ import { Model, ModelID } from '../models';
* @alias Object.<string,ModelID>
*/
export interface ModelParentID {
[ key: number ]: ModelID
[ key: number ]: ModelID;
}
/**
@ -21,8 +21,8 @@ export interface ModelRepositoryParams<
// @ts-ignore
ListParams = never,
// @ts-ignore
UpdateParams extends keyof T = never,
> {
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;
@ -31,14 +31,34 @@ export interface ModelRepositoryParams<
/**
* These helpers will extract information about a model from its repository params to be used in the repository.
*/
export type ModelClass< T extends ModelRepositoryParams > = [ T ] extends [ ModelRepositoryParams< infer X > ] ? X : never;
export type ParentID< T extends ModelRepositoryParams > = [ T ] extends [ ModelRepositoryParams< any, infer X > ] ? X : never;
export type HasParent< T extends ModelRepositoryParams, P, C > = [ ParentID< T > ] extends [ never ] ? C : P;
type ListParams< T extends ModelRepositoryParams > = [ T ] extends [ ModelRepositoryParams< any, any, infer X > ] ? X : never;
type PickUpdateParams<T, K extends keyof T> = { [P in K]?: T[P]; };
type UpdateParams< T extends ModelRepositoryParams > = [ T ] extends [ ModelRepositoryParams< infer C, any, any, infer X > ] ?
( [ X ] extends [ keyof C ] ? PickUpdateParams< C, X > : never ) :
never;
export type ModelClass< T extends ModelRepositoryParams > = [ T ] extends [
ModelRepositoryParams< infer X >
]
? X
: never;
export type ParentID< T extends ModelRepositoryParams > = [ T ] extends [
ModelRepositoryParams< any, infer X >
]
? X
: never;
export type HasParent< T extends ModelRepositoryParams, P, C > = [
ParentID< T >
] extends [ never ]
? C
: P;
type ListParams< T extends ModelRepositoryParams > = [ T ] extends [
ModelRepositoryParams< any, any, infer X >
]
? X
: never;
type PickUpdateParams< T, K extends keyof T > = { [ P in K ]?: T[ P ] };
type UpdateParams< T extends ModelRepositoryParams > = [ T ] extends [
ModelRepositoryParams< infer C, any, any, infer X >
]
? [ X ] extends [ keyof C ]
? PickUpdateParams< C, X >
: never
: never;
/**
* A callback for listing models using a data source.
@ -49,7 +69,9 @@ type UpdateParams< T extends ModelRepositoryParams > = [ T ] extends [ ModelRepo
* @template {Model} T
* @template L
*/
export type ListFn< T extends ModelRepositoryParams > = ( params?: ListParams< T > ) => Promise< ModelClass< T >[] >;
export type ListFn< T extends ModelRepositoryParams > = (
params?: ListParams< T >
) => Promise< ModelClass< T >[] >;
/**
* A callback for listing child models using a data source.
@ -75,7 +97,9 @@ export type ListChildFn< T extends ModelRepositoryParams > = (
* @return {Promise.<T>} Resolves to the created model.
* @template {Model} T
*/
export type CreateFn< T extends ModelRepositoryParams > = ( properties: Partial< ModelClass< T > > ) => Promise< ModelClass< T > >;
export type CreateFn< T extends ModelRepositoryParams > = (
properties: Partial< ModelClass< T > >
) => Promise< ModelClass< T > >;
/**
* A callback for creating a child model using a data source.
@ -99,7 +123,9 @@ export type CreateChildFn< T extends ModelRepositoryParams > = (
* @return {Promise.<T>} Resolves to the read model.
* @template {Model} T
*/
export type ReadFn< T extends ModelRepositoryParams > = ( id: ModelID ) => Promise< ModelClass< T > >;
export type ReadFn< T extends ModelRepositoryParams > = (
id: ModelID
) => Promise< ModelClass< T > >;
/**
* A callback for reading a child model using a data source.
@ -111,7 +137,10 @@ export type ReadFn< T extends ModelRepositoryParams > = ( id: ModelID ) => Promi
* @template {Model} T
* @template {ModelParentID} P
*/
export type ReadChildFn< T extends ModelRepositoryParams > = ( parent: ParentID< T >, childID: ModelID ) => Promise< ModelClass< T > >;
export type ReadChildFn< T extends ModelRepositoryParams > = (
parent: ParentID< T >,
childID: ModelID
) => Promise< ModelClass< T > >;
/**
* A callback for updating a model using a data source.
@ -124,7 +153,7 @@ export type ReadChildFn< T extends ModelRepositoryParams > = ( parent: ParentID<
*/
export type UpdateFn< T extends ModelRepositoryParams > = (
id: ModelID,
properties: UpdateParams< T >,
properties: UpdateParams< T >
) => Promise< ModelClass< T > >;
/**
@ -141,7 +170,7 @@ export type UpdateFn< T extends ModelRepositoryParams > = (
export type UpdateChildFn< T extends ModelRepositoryParams > = (
parent: ParentID< T >,
childID: ModelID,
properties: UpdateParams< T >,
properties: UpdateParams< T >
) => Promise< ModelClass< T > >;
/**
@ -162,7 +191,10 @@ export type DeleteFn = ( id: ModelID ) => Promise< boolean >;
* @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 >;
export type DeleteChildFn< T extends ModelRepositoryParams > = (
parent: ParentID< T >,
childID: ModelID
) => Promise< boolean >;
/**
* An interface for repositories that can list models.
@ -173,7 +205,9 @@ export type DeleteChildFn< T extends ModelRepositoryParams > = ( parent: ParentI
* @template L
*/
export interface ListsModels< T extends ModelRepositoryParams > {
list( params?: HasParent< T, never, ListParams< T > > ): Promise< ModelClass< T >[] >;
list(
params?: HasParent< T, never, ListParams< T > >
): Promise< ModelClass< T >[] >;
}
/**
@ -188,7 +222,7 @@ export interface ListsModels< T extends ModelRepositoryParams > {
export interface ListsChildModels< T extends ModelRepositoryParams > {
list(
parent: HasParent< T, ParentID< T >, never >,
params?: HasParent< T, ListParams< T >, never >,
params?: HasParent< T, ListParams< T >, never >
): Promise< ModelClass< T >[] >;
}
@ -200,7 +234,9 @@ export interface ListsChildModels< T extends ModelRepositoryParams > {
* @template {Model} T
*/
export interface CreatesModels< T extends ModelRepositoryParams > {
create( properties: Partial< ModelClass< T > > ): Promise< ModelClass< T > >;
create(
properties: Partial< ModelClass< T > >
): Promise< ModelClass< T > >;
}
/**
@ -214,7 +250,7 @@ export interface CreatesModels< T extends ModelRepositoryParams > {
export interface CreatesChildModels< T extends ModelRepositoryParams > {
create(
parent: HasParent< T, ParentID< T >, never >,
properties: HasParent< T, Partial< ModelClass< T > >, never >,
properties: HasParent< T, Partial< ModelClass< T > >, never >
): Promise< ModelClass< T > >;
}
@ -240,7 +276,7 @@ export interface ReadsModels< T extends ModelRepositoryParams > {
export interface ReadsChildModels< T extends ModelRepositoryParams > {
read(
parent: HasParent< T, ParentID< T >, never >,
childID: HasParent< T, ModelID, never >,
childID: HasParent< T, ModelID, never >
): Promise< ModelClass< T > >;
}
@ -254,7 +290,7 @@ export interface ReadsChildModels< T extends ModelRepositoryParams > {
export interface UpdatesModels< T extends ModelRepositoryParams > {
update(
id: HasParent< T, never, ModelID >,
properties: HasParent< T, never, UpdateParams< T > >,
properties: HasParent< T, never, UpdateParams< T > >
): Promise< ModelClass< T > >;
}
@ -270,7 +306,7 @@ export interface UpdatesChildModels< T extends ModelRepositoryParams > {
update(
parent: HasParent< T, ParentID< T >, never >,
childID: HasParent< T, ModelID, never >,
properties: HasParent< T, UpdateParams< T >, never >,
properties: HasParent< T, UpdateParams< T >, never >
): Promise< ModelClass< T > >;
}
@ -294,7 +330,7 @@ export interface DeletesModels< T extends ModelRepositoryParams > {
export interface DeletesChildModels< T extends ModelRepositoryParams > {
delete(
parent: HasParent< T, ParentID< T >, never >,
childID: HasParent< T, ModelID, never >,
childID: HasParent< T, ModelID, never >
): Promise< boolean >;
}
@ -307,22 +343,27 @@ export interface DeletesChildModels< T extends ModelRepositoryParams > {
* @template {ModelParentID} P
* @template {Object} L
*/
export class ModelRepository< T extends ModelRepositoryParams > implements
ListsModels< T >,
ListsChildModels< T >,
ReadsModels< T >,
ReadsChildModels< T >,
UpdatesModels< T >,
UpdatesChildModels< T >,
DeletesModels< T >,
DeletesChildModels< T > {
export class ModelRepository< T extends ModelRepositoryParams >
implements
ListsModels< T >,
ListsChildModels< T >,
ReadsModels< T >,
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;
private readonly listHook: HasParent<
T,
ListChildFn< T >,
ListFn< T >
> | null;
/**
* The hook used to create models
@ -330,7 +371,11 @@ export class ModelRepository< T extends ModelRepositoryParams > implements
* @type {CreateFn.<T>}
* @private
*/
private readonly createHook: HasParent< T, CreateChildFn< T >, CreateFn< T > > | null;
private readonly createHook: HasParent<
T,
CreateChildFn< T >,
CreateFn< T >
> | null;
/**
* The hook used to read models.
@ -338,7 +383,11 @@ export class ModelRepository< T extends ModelRepositoryParams > implements
* @type {ReadFn.<T>|ReadChildFn.<T,P>}
* @private
*/
private readonly readHook: HasParent< T, ReadChildFn< T >, ReadFn< T > > | null;
private readonly readHook: HasParent<
T,
ReadChildFn< T >,
ReadFn< T >
> | null;
/**
* The hook used to update models.
@ -346,7 +395,11 @@ export class ModelRepository< T extends ModelRepositoryParams > implements
* @type {UpdateFn.<T>|UpdateChildFn.<T,P>}
* @private
*/
private readonly updateHook: HasParent< T, UpdateChildFn< T >, UpdateFn< T > > | null;
private readonly updateHook: HasParent<
T,
UpdateChildFn< T >,
UpdateFn< T >
> | null;
/**
* The hook used to delete models.
@ -354,7 +407,11 @@ export class ModelRepository< T extends ModelRepositoryParams > implements
* @type {DeleteFn|DeleteChildFn.<P>}
* @private
*/
private readonly deleteHook: HasParent< T, DeleteChildFn< T >, DeleteFn > | null;
private readonly deleteHook: HasParent<
T,
DeleteChildFn< T >,
DeleteFn
> | null;
/**
* Creates a new repository instance.
@ -370,7 +427,7 @@ export class ModelRepository< T extends ModelRepositoryParams > implements
createHook: HasParent< T, CreateChildFn< T >, CreateFn< T > > | null,
readHook: HasParent< T, ReadChildFn< T >, ReadFn< T > > | null,
updateHook: HasParent< T, UpdateChildFn< T >, UpdateFn< T > > | null,
deleteHook: HasParent< T, DeleteChildFn< T >, DeleteFn > | null,
deleteHook: HasParent< T, DeleteChildFn< T >, DeleteFn > | null
) {
this.listHook = listHook;
this.createHook = createHook;
@ -388,21 +445,23 @@ export class ModelRepository< T extends ModelRepositoryParams > implements
*/
public list(
paramsOrParent?: HasParent< T, ParentID< T >, ListParams< T > >,
params?: HasParent< T, ListParams< T >, never >,
params?: HasParent< T, ListParams< T >, never >
): Promise< ModelClass< T >[] > {
if ( ! this.listHook ) {
throw new Error( 'The \'list\' operation is not supported on this model.' );
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 >,
paramsOrParent as ListParams< T >
);
}
return ( this.listHook as ListChildFn< T > )(
( paramsOrParent as unknown ) as ParentID< T >,
params,
params
);
}
@ -414,22 +473,28 @@ export class ModelRepository< T extends ModelRepositoryParams > implements
* @return {Promise.<T>} Resolves to the created model.
*/
public create(
propertiesOrParent?: HasParent< T, ParentID< T >, Partial< ModelClass<T> > >,
properties?: HasParent< T, Partial< ModelClass<T> >, never >,
propertiesOrParent?: HasParent<
T,
ParentID< T >,
Partial< ModelClass< T > >
>,
properties?: HasParent< T, Partial< ModelClass< T > >, never >
): Promise< ModelClass< T > > {
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."
);
}
if ( properties === undefined ) {
return ( this.createHook as CreateFn< T > )(
propertiesOrParent as Partial< ModelClass<T> >,
propertiesOrParent as Partial< ModelClass< T > >
);
}
return ( this.createHook as CreateChildFn< T > )(
( propertiesOrParent as unknown ) as ParentID<T>,
properties as Partial< ModelClass<T> >,
( propertiesOrParent as unknown ) as ParentID< T >,
properties as Partial< ModelClass< T > >
);
}
@ -442,21 +507,21 @@ export class ModelRepository< T extends ModelRepositoryParams > implements
*/
public read(
idOrParent: HasParent< T, ParentID< T >, ModelID >,
childID?: HasParent< T, ModelID, never >,
childID?: HasParent< T, ModelID, never >
): Promise< ModelClass< T > > {
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."
);
}
if ( childID === undefined ) {
return ( this.readHook as ReadFn< T > )(
idOrParent as ModelID,
);
return ( this.readHook as ReadFn< T > )( idOrParent as ModelID );
}
return ( this.readHook as ReadChildFn< T > )(
( idOrParent as unknown ) as ParentID< T >,
childID,
childID
);
}
@ -471,23 +536,25 @@ export class ModelRepository< T extends ModelRepositoryParams > implements
public update(
idOrParent: HasParent< T, ParentID< T >, ModelID >,
propertiesOrChildID: HasParent< T, ModelID, UpdateParams< T > >,
properties?: HasParent< T, UpdateParams< T >, never >,
properties?: HasParent< T, UpdateParams< T >, never >
): Promise< ModelClass< T > > {
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."
);
}
if ( properties === undefined ) {
return ( this.updateHook as UpdateFn< T > )(
idOrParent as ModelID,
( propertiesOrChildID as unknown ) as UpdateParams< T >,
( propertiesOrChildID as unknown ) as UpdateParams< T >
);
}
return ( this.updateHook as UpdateChildFn< T > )(
( idOrParent as unknown ) as ParentID< T >,
propertiesOrChildID as ModelID,
( properties as unknown ) as UpdateParams< T >,
( properties as unknown ) as UpdateParams< T >
);
}
@ -500,21 +567,21 @@ export class ModelRepository< T extends ModelRepositoryParams > implements
*/
public delete(
idOrParent: HasParent< T, ParentID< T >, ModelID >,
childID?: HasParent< T, ModelID, never >,
childID?: HasParent< T, ModelID, never >
): Promise< boolean > {
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."
);
}
if ( childID === undefined ) {
return ( this.deleteHook as DeleteFn )(
idOrParent as ModelID,
);
return ( this.deleteHook as DeleteFn )( idOrParent as ModelID );
}
return ( this.deleteHook as DeleteChildFn< T > )(
( idOrParent as unknown ) as ParentID< T >,
childID,
childID
);
}
}

View File

@ -45,7 +45,7 @@ export enum TransformationOrder {
* A special value reserved for transformations that MUST come after all orders due to
* the way that they destroy the property keys or values.
*/
VeryLast = 2000000
VeryLast = 2000000,
}
/**
@ -67,7 +67,9 @@ export class ModelTransformer< T extends Model > {
*/
public constructor( transformations: ModelTransformation[] ) {
// Ensure that the transformations are sorted by priority.
transformations.sort( ( a, b ) => ( a.fromModelOrder > b.fromModelOrder ) ? 1 : -1 );
transformations.sort( ( a, b ) =>
a.fromModelOrder > b.fromModelOrder ? 1 : -1
);
this.transformations = transformations;
}
@ -87,7 +89,7 @@ export class ModelTransformer< T extends Model > {
( properties: any, transformer: ModelTransformation ) => {
return transformer.fromModel( properties );
},
raw,
raw
);
}
@ -104,7 +106,7 @@ export class ModelTransformer< T extends Model > {
( properties: any, transformer: ModelTransformation ) => {
return transformer.toModel( properties );
},
data,
data
);
return new modelClass( transformed );

View File

@ -6,51 +6,51 @@ describe( 'AddPropertyTransformation', () => {
beforeEach( () => {
transformation = new AddPropertyTransformation(
{ toProperty: 'Test' },
{ fromProperty: 'Test' },
{ fromProperty: 'Test' }
);
} );
it( 'should add property when missing', () => {
let transformed = transformation.toModel( { id: 1, name: 'Test' } );
expect( transformed ).toMatchObject(
{
id: 1,
name: 'Test',
toProperty: 'Test',
},
);
expect( transformed ).toMatchObject( {
id: 1,
name: 'Test',
toProperty: 'Test',
} );
transformed = transformation.fromModel( { id: 1, name: 'Test' } );
expect( transformed ).toMatchObject(
{
id: 1,
name: 'Test',
fromProperty: 'Test',
},
);
expect( transformed ).toMatchObject( {
id: 1,
name: 'Test',
fromProperty: 'Test',
} );
} );
it( 'should not add property when present', () => {
let transformed = transformation.toModel( { id: 1, name: 'Test', toProperty: 'Existing' } );
let transformed = transformation.toModel( {
id: 1,
name: 'Test',
toProperty: 'Existing',
} );
expect( transformed ).toMatchObject(
{
id: 1,
name: 'Test',
toProperty: 'Existing',
},
);
expect( transformed ).toMatchObject( {
id: 1,
name: 'Test',
toProperty: 'Existing',
} );
transformed = transformation.fromModel( { id: 1, name: 'Test', fromProperty: 'Existing' } );
transformed = transformation.fromModel( {
id: 1,
name: 'Test',
fromProperty: 'Existing',
} );
expect( transformed ).toMatchObject(
{
id: 1,
name: 'Test',
fromProperty: 'Existing',
},
);
expect( transformed ).toMatchObject( {
id: 1,
name: 'Test',
fromProperty: 'Existing',
} );
} );
} );

View File

@ -7,7 +7,9 @@ describe( 'CustomTransformation', () => {
const expected = { test: 'Test' };
expect( transformation.toModel( expected ) ).toMatchObject( expected );
expect( transformation.fromModel( expected ) ).toMatchObject( expected );
expect( transformation.fromModel( expected ) ).toMatchObject(
expected
);
} );
it( 'should execute hooks', () => {
@ -18,9 +20,13 @@ describe( 'CustomTransformation', () => {
const transformation = new CustomTransformation( 0, toHook, fromHook );
expect( transformation.toModel( { test: 'Test' } ) ).toMatchObject( { toModel: 'Test' } );
expect( transformation.toModel( { test: 'Test' } ) ).toMatchObject( {
toModel: 'Test',
} );
expect( toHook ).toHaveBeenCalledWith( { test: 'Test' } );
expect( transformation.fromModel( { test: 'Test' } ) ).toMatchObject( { fromModel: 'Test' } );
expect( transformation.fromModel( { test: 'Test' } ) ).toMatchObject( {
fromModel: 'Test',
} );
expect( fromHook ).toHaveBeenCalledWith( { test: 'Test' } );
} );
} );

View File

@ -8,22 +8,18 @@ describe( 'IgnorePropertyTransformation', () => {
} );
it( 'should remove ignored properties', () => {
let transformed = transformation.fromModel(
{
test: 'Test',
skip: 'Test',
},
);
let transformed = transformation.fromModel( {
test: 'Test',
skip: 'Test',
} );
expect( transformed ).toHaveProperty( 'test', 'Test' );
expect( transformed ).not.toHaveProperty( 'skip' );
transformed = transformation.toModel(
{
test: 'Test',
skip: 'Test',
},
);
transformed = transformation.toModel( {
test: 'Test',
skip: 'Test',
} );
expect( transformed ).toHaveProperty( 'test', 'Test' );
expect( transformed ).not.toHaveProperty( 'skip' );

View File

@ -5,15 +5,15 @@ describe( 'KeyChangeTransformation', () => {
let transformation: KeyChangeTransformation< DummyModel >;
beforeEach( () => {
transformation = new KeyChangeTransformation< DummyModel >(
{
name: 'new-name',
},
);
transformation = new KeyChangeTransformation< DummyModel >( {
name: 'new-name',
} );
} );
it( 'should transform to model', () => {
const transformed = transformation.toModel( { 'new-name': 'Test Name' } );
const transformed = transformation.toModel( {
'new-name': 'Test Name',
} );
expect( transformed ).toHaveProperty( 'name', 'Test Name' );
expect( transformed ).not.toHaveProperty( 'new-name' );

View File

@ -1,4 +1,4 @@
import { mocked } from 'ts-jest/utils'
import { mocked } from 'ts-jest/utils';
import { ModelTransformerTransformation } from '../model-transformer-transformation';
import { ModelTransformer } from '../../model-transformer';
import { DummyModel } from '../../../__test_data__/dummy-model';
@ -14,19 +14,26 @@ describe( 'ModelTransformerTransformation', () => {
transformation = new ModelTransformerTransformation< DummyModel >(
'test',
DummyModel,
propertyTransformer,
propertyTransformer
);
} );
it( 'should execute child transformer', () => {
mocked( propertyTransformer.toModel ).mockReturnValue( { toModel: 'Test' } );
mocked( propertyTransformer.toModel ).mockReturnValue( {
toModel: 'Test',
} );
let transformed = transformation.toModel( { test: 'Test' } );
expect( transformed ).toMatchObject( { test: { toModel: 'Test' } } );
expect( propertyTransformer.toModel ).toHaveBeenCalledWith( DummyModel, 'Test' );
expect( propertyTransformer.toModel ).toHaveBeenCalledWith(
DummyModel,
'Test'
);
mocked( propertyTransformer.fromModel ).mockReturnValue( { fromModel: 'Test' } );
mocked( propertyTransformer.fromModel ).mockReturnValue( {
fromModel: 'Test',
} );
transformed = transformation.fromModel( { test: 'Test' } );
@ -35,19 +42,35 @@ describe( 'ModelTransformerTransformation', () => {
} );
it( 'should execute child transformer on array', () => {
mocked( propertyTransformer.toModel ).mockReturnValue( { toModel: 'Test' } );
mocked( propertyTransformer.toModel ).mockReturnValue( {
toModel: 'Test',
} );
let transformed = transformation.toModel( { test: [ 'Test', 'Test2' ] } );
let transformed = transformation.toModel( {
test: [ 'Test', 'Test2' ],
} );
expect( transformed ).toMatchObject( { test: [ { toModel: 'Test' }, { toModel: 'Test' } ] } );
expect( propertyTransformer.toModel ).toHaveBeenCalledWith( DummyModel, 'Test' );
expect( propertyTransformer.toModel ).toHaveBeenCalledWith( DummyModel, 'Test2' );
expect( transformed ).toMatchObject( {
test: [ { toModel: 'Test' }, { toModel: 'Test' } ],
} );
expect( propertyTransformer.toModel ).toHaveBeenCalledWith(
DummyModel,
'Test'
);
expect( propertyTransformer.toModel ).toHaveBeenCalledWith(
DummyModel,
'Test2'
);
mocked( propertyTransformer.fromModel ).mockReturnValue( { fromModel: 'Test' } );
mocked( propertyTransformer.fromModel ).mockReturnValue( {
fromModel: 'Test',
} );
transformed = transformation.fromModel( { test: [ 'Test', 'Test2' ] } );
expect( transformed ).toMatchObject( { test: [ { fromModel: 'Test' }, { fromModel: 'Test' } ] } );
expect( transformed ).toMatchObject( {
test: [ { fromModel: 'Test' }, { fromModel: 'Test' } ],
} );
expect( propertyTransformer.fromModel ).toHaveBeenCalledWith( 'Test' );
expect( propertyTransformer.fromModel ).toHaveBeenCalledWith( 'Test2' );
} );

View File

@ -1,19 +1,20 @@
import { PropertyType, PropertyTypeTransformation } from '../property-type-transformation';
import {
PropertyType,
PropertyTypeTransformation,
} from '../property-type-transformation';
describe( 'PropertyTypeTransformation', () => {
let transformation: PropertyTypeTransformation;
beforeEach( () => {
transformation = new PropertyTypeTransformation(
{
string: PropertyType.String,
integer: PropertyType.Integer,
float: PropertyType.Float,
boolean: PropertyType.Boolean,
date: PropertyType.Date,
callback: ( value: string ) => 'Transformed-' + value,
},
);
transformation = new PropertyTypeTransformation( {
string: PropertyType.String,
integer: PropertyType.Integer,
float: PropertyType.Float,
boolean: PropertyType.Boolean,
date: PropertyType.Date,
callback: ( value: string ) => 'Transformed-' + value,
} );
} );
it( 'should convert strings', () => {
@ -57,11 +58,17 @@ describe( 'PropertyTypeTransformation', () => {
} );
it( 'should convert dates', () => {
let transformed = transformation.toModel( { date: '2020-11-06T03:11:41.000Z' } );
let transformed = transformation.toModel( {
date: '2020-11-06T03:11:41.000Z',
} );
expect( transformed.date ).toStrictEqual( new Date( '2020-11-06T03:11:41.000Z' ) );
expect( transformed.date ).toStrictEqual(
new Date( '2020-11-06T03:11:41.000Z' )
);
transformed = transformation.fromModel( { date: new Date( '2020-11-06T03:11:41.000Z' ) } );
transformed = transformation.fromModel( {
date: new Date( '2020-11-06T03:11:41.000Z' ),
} );
expect( transformed.date ).toStrictEqual( '2020-11-06T03:11:41.000Z' );
} );
@ -77,11 +84,15 @@ describe( 'PropertyTypeTransformation', () => {
} );
it( 'should convert arrays', () => {
let transformed = transformation.toModel( { integer: [ '100', '200', '300' ] } );
let transformed = transformation.toModel( {
integer: [ '100', '200', '300' ],
} );
expect( transformed.integer ).toStrictEqual( [ 100, 200, 300 ] );
transformed = transformation.fromModel( { integer: [ 100, 200, 300 ] } );
transformed = transformation.fromModel( {
integer: [ 100, 200, 300 ],
} );
expect( transformed.integer ).toStrictEqual( [ '100', '200', '300' ] );
} );

View File

@ -35,7 +35,10 @@ export class AddPropertyTransformation implements ModelTransformation {
* @param {AdditionalProperties} toProperties The properties to add when executing toModel.
* @param {AdditionalProperties} fromProperties The properties to add when executing fromModel.
*/
public constructor( toProperties: AdditionalProperties, fromProperties: AdditionalProperties ) {
public constructor(
toProperties: AdditionalProperties,
fromProperties: AdditionalProperties
) {
this.toProperties = toProperties;
this.fromProperties = fromProperties;
}

View File

@ -41,7 +41,7 @@ export class CustomTransformation implements ModelTransformation {
public constructor(
order: number,
toHook: TransformationCallback | null,
fromHook: TransformationCallback | null,
fromHook: TransformationCallback | null
) {
this.fromModelOrder = order;
this.toHook = toHook;

View File

@ -5,14 +5,17 @@ import { Model } from '../../models';
* @typedef KeyChanges
* @alias Object.<string,string>
*/
type KeyChanges< T extends Model > = { readonly [ key in keyof Partial< T > ]: string };
type KeyChanges< T extends Model > = {
readonly [ key in keyof Partial< T > ]: string;
};
/**
* A model transformation that can be used to change property keys between two formats.
* This transformation has a very high priority so that it will be executed after all
* other transformations to prevent the changed key from causing problems.
*/
export class KeyChangeTransformation< T extends Model > implements ModelTransformation {
export class KeyChangeTransformation< T extends Model >
implements ModelTransformation {
/**
* Ensure that this transformation always happens at the very end since it changes the keys
* in the transformed object.

View File

@ -1,4 +1,8 @@
import { ModelTransformation, ModelTransformer, TransformationOrder } from '../model-transformer';
import {
ModelTransformation,
ModelTransformer,
TransformationOrder,
} from '../model-transformer';
import { Model, ModelConstructor } from '../../models';
/**
@ -6,7 +10,8 @@ import { Model, ModelConstructor } from '../../models';
*
* @template T
*/
export class ModelTransformerTransformation< T extends Model > implements ModelTransformation {
export class ModelTransformerTransformation< T extends Model >
implements ModelTransformation {
public readonly fromModelOrder = TransformationOrder.Normal;
/**
@ -42,10 +47,14 @@ export class ModelTransformerTransformation< T extends Model > implements ModelT
* @param {ModelTransformer} transformer The transformer we want to apply.
* @template T
*/
public constructor( property: string, modelClass: ModelConstructor< T >, transformer: ModelTransformer< T > ) {
public constructor(
property: string,
modelClass: ModelConstructor< T >,
transformer: ModelTransformer< T >
) {
// Developer-friendly error to make sure this doesn't go unnoticed.
if (property.includes('_')) {
throw new Error('The property must be camelCase');
if ( property.includes( '_' ) ) {
throw new Error( 'The property must be camelCase' );
}
this.property = property;
this.modelClass = modelClass;
@ -62,7 +71,9 @@ export class ModelTransformerTransformation< T extends Model > implements ModelT
const val = properties[ this.property ];
if ( val ) {
if ( Array.isArray( val ) ) {
properties[ this.property ] = val.map( ( v ) => this.transformer.fromModel( v ) );
properties[ this.property ] = val.map( ( v ) =>
this.transformer.fromModel( v )
);
} else {
properties[ this.property ] = this.transformer.fromModel( val );
}
@ -81,9 +92,14 @@ export class ModelTransformerTransformation< T extends Model > implements ModelT
const val = properties[ this.property ];
if ( val ) {
if ( Array.isArray( val ) ) {
properties[ this.property ] = val.map( ( v ) => this.transformer.toModel( this.modelClass, v ) );
properties[ this.property ] = val.map( ( v ) =>
this.transformer.toModel( this.modelClass, v )
);
} else {
properties[ this.property ] = this.transformer.toModel( this.modelClass, val );
properties[ this.property ] = this.transformer.toModel(
this.modelClass,
val
);
}
}

View File

@ -116,20 +116,29 @@ export class PropertyTypeTransformation implements ModelTransformation {
* @return {*} The converted type.
* @private
*/
private convertTo( value: any, type: PropertyType ): PropertyTypeTypes | PropertyTypeTypes[] {
private convertTo(
value: any,
type: PropertyType
): PropertyTypeTypes | PropertyTypeTypes[] {
if ( Array.isArray( value ) ) {
return value.map( ( v: string ) => this.convertTo( v, type ) as PropertyTypeTypes );
return value.map(
( v: string ) => this.convertTo( v, type ) as PropertyTypeTypes
);
}
if ( null === value ) {
if ( value === null ) {
return null;
}
switch ( type ) {
case PropertyType.String: return String( value );
case PropertyType.Integer: return parseInt( value );
case PropertyType.Float: return parseFloat( value );
case PropertyType.Boolean: return Boolean( value );
case PropertyType.String:
return String( value );
case PropertyType.Integer:
return parseInt( value );
case PropertyType.Float:
return parseFloat( value );
case PropertyType.Boolean:
return Boolean( value );
case PropertyType.Date:
return new Date( value );
}
@ -143,12 +152,15 @@ export class PropertyTypeTransformation implements ModelTransformation {
* @return {*} The converted type.
* @private
*/
private convertFrom( value: PropertyTypeTypes | PropertyTypeTypes[], type: PropertyType ): any {
private convertFrom(
value: PropertyTypeTypes | PropertyTypeTypes[],
type: PropertyType
): any {
if ( Array.isArray( value ) ) {
return value.map( ( v ) => this.convertFrom( v, type ) );
}
if ( null === value ) {
if ( value === null ) {
return null;
}

View File

@ -47,6 +47,8 @@ describe( 'AxiosInterceptor', () => {
interceptor.start( axiosInstance );
}
await expect( axiosInstance.get( 'http://test.test' ) ).rejects.toBeInstanceOf( Error );
await expect(
axiosInstance.get( 'http://test.test' )
).rejects.toBeInstanceOf( Error );
} );
} );

View File

@ -12,7 +12,7 @@ describe( 'AxiosOAuthInterceptor', () => {
adapter = new MockAdapter( axiosInstance );
apiAuthInterceptor = new AxiosOAuthInterceptor(
'consumer_key',
'consumer_secret',
'consumer_secret'
);
apiAuthInterceptor.start( axiosInstance );
} );
@ -39,7 +39,7 @@ describe( 'AxiosOAuthInterceptor', () => {
// focus on ensuring that the header looks roughly correct given what we readily know.
expect( response.config.headers! ).toHaveProperty( 'Authorization' );
expect( response.config.headers!.Authorization ).toMatch(
/^OAuth oauth_consumer_key="consumer_key".*oauth_signature_method="HMAC-SHA256".*oauth_version="1.0"/,
/^OAuth oauth_consumer_key="consumer_key".*oauth_signature_method="HMAC-SHA256".*oauth_version="1.0"/
);
} );

View File

@ -20,11 +20,13 @@ describe( 'AxiosResponseInterceptor', () => {
} );
it( 'should transform responses into an HTTPResponse', async () => {
adapter.onGet( 'http://test.test' ).reply(
200,
{ test: 'value' },
{ 'content-type': 'application/json' }
);
adapter
.onGet( 'http://test.test' )
.reply(
200,
{ test: 'value' },
{ 'content-type': 'application/json' }
);
const response = await axiosInstance.get( 'http://test.test' );
@ -40,13 +42,17 @@ describe( 'AxiosResponseInterceptor', () => {
} );
it( 'should transform error responses into an HTTPResponse', async () => {
adapter.onGet( 'http://test.test' ).reply(
404,
{ code: 'error_code', message: 'value' },
{ 'content-type': 'application/json' }
);
adapter
.onGet( 'http://test.test' )
.reply(
404,
{ code: 'error_code', message: 'value' },
{ 'content-type': 'application/json' }
);
await expect( axiosInstance.get( 'http://test.test' ) ).rejects.toMatchObject( {
await expect(
axiosInstance.get( 'http://test.test' )
).rejects.toMatchObject( {
statusCode: 404,
headers: {
'content-type': 'application/json',
@ -61,8 +67,8 @@ describe( 'AxiosResponseInterceptor', () => {
it( 'should bubble non-response errors', async () => {
adapter.onGet( 'http://test.test' ).timeout();
await expect( axiosInstance.get( 'http://test.test' ) ).rejects.toMatchObject(
new Error( 'timeout of 0ms exceeded' ),
);
await expect(
axiosInstance.get( 'http://test.test' )
).rejects.toMatchObject( new Error( 'timeout of 0ms exceeded' ) );
} );
} );

View File

@ -20,16 +20,17 @@ describe( 'AxiosURLToQueryInterceptor', () => {
} );
it( 'should put path in query string', async () => {
adapter.onGet(
'http://test.test/',
{ params: { test: '/test/route' } }
).reply(
200,
{ test: 'value' },
{ 'content-type': 'application/json' }
);
adapter
.onGet( 'http://test.test/', { params: { test: '/test/route' } } )
.reply(
200,
{ test: 'value' },
{ 'content-type': 'application/json' }
);
const response = await axiosInstance.get( 'http://test.test/test/route' );
const response = await axiosInstance.get(
'http://test.test/test/route'
);
expect( response.status ).toEqual( 200 );
} );

View File

@ -7,12 +7,18 @@ describe( 'buildURL', () => {
} );
it( 'should use url when given absolute', () => {
const url = buildURL( { baseURL: 'http://test.test', url: 'http://override.test' } );
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' } );
const url = buildURL( {
baseURL: 'http://test.test',
url: 'yes/test',
} );
expect( url ).toBe( 'http://test.test/yes/test' );
} );
} );
@ -24,7 +30,10 @@ describe( 'buildURLWithParams', () => {
} );
it( 'should append query string', () => {
const url = buildURLWithParams( { baseURL: 'http://test.test', params: { test: 'yes' } } );
const url = buildURLWithParams( {
baseURL: 'http://test.test',
params: { test: 'yes' },
} );
expect( url ).toBe( 'http://test.test?test=yes' );
} );
} );

View File

@ -29,7 +29,10 @@ export class AxiosClient implements HTTPClient {
* @param {AxiosRequestConfig} config The request configuration.
* @param {AxiosInterceptor[]} extraInterceptors An array of additional interceptors to apply to the client.
*/
public constructor( config: AxiosRequestConfig, extraInterceptors: AxiosInterceptor[] = [] ) {
public constructor(
config: AxiosRequestConfig,
extraInterceptors: AxiosInterceptor[] = []
) {
this.client = axios.create( config );
this.interceptors = extraInterceptors;
@ -52,8 +55,8 @@ export class AxiosClient implements HTTPClient {
*/
public get< T = any >(
path: string,
params?: object,
): Promise< HTTPResponse< T >> {
params?: object
): Promise< HTTPResponse< T > > {
return this.client.get( path, { params } );
}
@ -66,8 +69,8 @@ export class AxiosClient implements HTTPClient {
*/
public post< T = any >(
path: string,
data?: object,
): Promise< HTTPResponse< T >> {
data?: object
): Promise< HTTPResponse< T > > {
return this.client.post( path, data );
}
@ -80,8 +83,8 @@ export class AxiosClient implements HTTPClient {
*/
public put< T = any >(
path: string,
data?: object,
): Promise< HTTPResponse< T >> {
data?: object
): Promise< HTTPResponse< T > > {
return this.client.put( path, data );
}
@ -94,8 +97,8 @@ export class AxiosClient implements HTTPClient {
*/
public patch< T = any >(
path: string,
data?: object,
): Promise< HTTPResponse< T >> {
data?: object
): Promise< HTTPResponse< T > > {
return this.client.patch( path, data );
}
@ -108,8 +111,8 @@ export class AxiosClient implements HTTPClient {
*/
public delete< T = any >(
path: string,
data?: object,
): Promise< HTTPResponse< T >> {
data?: object
): Promise< HTTPResponse< T > > {
return this.client.delete( path, { data } );
}
}

View File

@ -12,7 +12,7 @@ type ActiveInterceptor = {
client: AxiosInstance;
requestInterceptorID: number;
responseInterceptorID: number;
}
};
/**
* A base class for encapsulating the start and stop functionality required by all Axios interceptors.
@ -33,13 +33,17 @@ export abstract class AxiosInterceptor {
*/
public start( client: AxiosInstance ): void {
const requestInterceptorID = client.interceptors.request.use(
( response ) => this.handleRequest( response ),
( response ) => this.handleRequest( response )
);
const responseInterceptorID = client.interceptors.response.use(
( response ) => this.onResponseSuccess( response ),
( error ) => this.onResponseRejected( error ),
( error ) => this.onResponseRejected( error )
);
this.activeInterceptors.push( { client, requestInterceptorID, responseInterceptorID } );
this.activeInterceptors.push( {
client,
requestInterceptorID,
responseInterceptorID,
} );
}
/**
@ -51,8 +55,12 @@ export abstract class AxiosInterceptor {
for ( let i = this.activeInterceptors.length - 1; i >= 0; --i ) {
const active = this.activeInterceptors[ i ];
if ( client === active.client ) {
client.interceptors.request.eject( active.requestInterceptorID );
client.interceptors.response.eject( active.responseInterceptorID );
client.interceptors.request.eject(
active.requestInterceptorID
);
client.interceptors.response.eject(
active.responseInterceptorID
);
this.activeInterceptors.splice( i, 1 );
}
}

View File

@ -32,7 +32,9 @@ export class AxiosOAuthInterceptor extends AxiosInterceptor {
},
signature_method: 'HMAC-SHA256',
hash_function: ( base: any, key: any ) => {
return createHmac( 'sha256', key ).update( base ).digest( 'base64' );
return createHmac( 'sha256', key )
.update( base )
.digest( 'base64' );
},
} );
}
@ -55,7 +57,7 @@ export class AxiosOAuthInterceptor extends AxiosInterceptor {
this.oauth.authorize( {
url,
method: request.method!,
} ),
} )
).Authorization;
}

View File

@ -13,7 +13,11 @@ export class AxiosResponseInterceptor extends AxiosInterceptor {
* @return {HTTPResponse} The HTTP response.
*/
protected onResponseSuccess( response: AxiosResponse ): HTTPResponse {
return new HTTPResponse( response.status, response.headers, response.data );
return new HTTPResponse(
response.status,
response.headers,
response.data
);
}
/**
@ -24,7 +28,11 @@ export class AxiosResponseInterceptor extends AxiosInterceptor {
protected onResponseRejected( error: any ): never {
// Convert HTTP response errors into a form that we can handle them with.
if ( error.response ) {
throw new HTTPResponse( error.response.status, error.response.headers, error.response.data );
throw new HTTPResponse(
error.response.status,
error.response.headers,
error.response.data
);
}
throw error;

View File

@ -24,5 +24,9 @@ export function buildURL( request: AxiosRequestConfig ): string {
* @return {string} The merged URL.
*/
export function buildURLWithParams( request: AxiosRequestConfig ): string {
return appendParams( buildURL( request ), request.params, request.paramsSerializer );
return appendParams(
buildURL( request ),
request.params,
request.paramsSerializer
);
}

View File

@ -8,23 +8,23 @@ import { AxiosURLToQueryInterceptor } from './axios/axios-url-to-query-intercept
* These types describe the shape of the different auth methods our factory supports.
*/
type OAuthMethod = {
type: 'oauth',
key: string,
secret: string,
type: 'oauth';
key: string;
secret: string;
};
type BasicAuthMethod = {
type: 'basic',
username: string,
password: string,
}
type: 'basic';
username: string;
password: string;
};
/**
* An interface for describing the shape of a client to create using the factory.
*/
interface BuildParams {
wpURL: string,
useIndexPermalinks?: boolean,
auth?: OAuthMethod | BasicAuthMethod,
wpURL: string;
useIndexPermalinks?: boolean;
auth?: OAuthMethod | BasicAuthMethod;
}
/**
@ -129,8 +129,8 @@ export class HTTPClientFactory {
interceptors.push(
new AxiosOAuthInterceptor(
this.clientConfig.auth.key,
this.clientConfig.auth.secret,
),
this.clientConfig.auth.secret
)
);
break;
}

View File

@ -9,16 +9,19 @@ import {
UpdatesModels,
DeletesModels,
} from '../../framework';
import {
CouponUpdateParams,
} from './shared';
import { CouponUpdateParams } from './shared';
import { ObjectLinks } from '../shared-types';
/**
* 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 CouponRepositoryParams = ModelRepositoryParams< Coupon, never, never, CouponUpdateParams >;
export type CouponRepositoryParams = ModelRepositoryParams<
Coupon,
never,
never,
CouponUpdateParams
>;
/**
* An interface for creating coupons using the repository.
@ -137,14 +140,14 @@ export class Coupon extends Model {
*
* @type {ReadonlyArray.<number>}
*/
public readonly productIds: Array<number> = [];
public readonly productIds: Array< number > = [];
/**
* List of Product IDs that the coupon cannot be applied to.
*
* @type {ReadonlyArray.<number>}
*/
public readonly excludedProductIds: Array<number> = [];
public readonly excludedProductIds: Array< number > = [];
/**
* How many times the coupon can be used.
@ -179,14 +182,14 @@ export class Coupon extends Model {
*
* @type {ReadonlyArray.<number>}
*/
public readonly productCategories: Array<number> = [];
public readonly productCategories: Array< number > = [];
/**
* List of Category IDs the coupon does not apply to.
*
* @type {ReadonlyArray.<number>}
*/
public readonly excludedProductCategories: Array<number> = [];
public readonly excludedProductCategories: Array< number > = [];
/**
* Flags if the coupon applies to items on sale.
@ -214,14 +217,14 @@ export class Coupon extends Model {
*
* @type {ReadonlyArray.<string>}
*/
public readonly emailRestrictions: Array<string> = [];
public readonly emailRestrictions: Array< string > = [];
/**
* List of user IDs (or guest emails) that have used the coupon.
*
* @type {ReadonlyArray.<string>}
*/
public readonly usedBy: Array<string> = [];
public readonly usedBy: Array< string > = [];
/**
* The coupon's links.
@ -248,7 +251,9 @@ export class Coupon extends Model {
*
* @param {HTTPClient} httpClient The client for communicating via HTTP.
*/
public static restRepository( httpClient: HTTPClient ): ReturnType< typeof couponRESTRepository > {
public static restRepository(
httpClient: HTTPClient
): ReturnType< typeof couponRESTRepository > {
return couponRESTRepository( httpClient );
}
}

View File

@ -1,7 +1,23 @@
/**
* Coupon properties that can be updated
*/
export type CouponUpdateParams = 'code' | 'amount' | 'description' | 'discountType' | 'dateExpires' | 'individualUse'
| 'usageCount' | 'productIds' | 'excludedProductIds' | 'usageLimit' | 'usageLimitPerUser' | 'limitUsageToXItems'
| 'freeShipping' | 'productCategories' | 'excludedProductCategories' | 'excludeSaleItems' | 'minimumAmount'
| 'maximumAmount' | 'emailRestrictions';
export type CouponUpdateParams =
| 'code'
| 'amount'
| 'description'
| 'discountType'
| 'dateExpires'
| 'individualUse'
| 'usageCount'
| 'productIds'
| 'excludedProductIds'
| 'usageLimit'
| 'usageLimitPerUser'
| 'limitUsageToXItems'
| 'freeShipping'
| 'productCategories'
| 'excludedProductCategories'
| 'excludeSaleItems'
| 'minimumAmount'
| 'maximumAmount'
| 'emailRestrictions';

View File

@ -35,22 +35,27 @@ import { ObjectLinks } from '../shared-types';
/**
* The parameters that orders can update.
*/
type OrderUpdateParams = BillingOrderAddressUpdateParams
& ShippingOrderAddressUpdateParams
& OrderCouponUpdateParams
& OrderDataUpdateParams
& OrderFeeUpdateParams
& OrderLineItemUpdateParams
& OrderRefundUpdateParams
& OrderShippingUpdateParams
& OrderTaxUpdateParams
& OrderTotalUpdateParams;
type OrderUpdateParams = BillingOrderAddressUpdateParams &
ShippingOrderAddressUpdateParams &
OrderCouponUpdateParams &
OrderDataUpdateParams &
OrderFeeUpdateParams &
OrderLineItemUpdateParams &
OrderRefundUpdateParams &
OrderShippingUpdateParams &
OrderTaxUpdateParams &
OrderTotalUpdateParams;
/**
* 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 OrderRepositoryParams = ModelRepositoryParams< Order, never, never, OrderUpdateParams >;
export type OrderRepositoryParams = ModelRepositoryParams<
Order,
never,
never,
OrderUpdateParams
>;
/**
* An interface for creating orders using the repository.
@ -366,7 +371,9 @@ export class Order extends OrderItemMeta {
*
* @param {HTTPClient} httpClient The client for communicating via HTTP.
*/
public static restRepository( httpClient: HTTPClient ): ReturnType< typeof orderRESTRepository > {
public static restRepository(
httpClient: HTTPClient
): ReturnType< typeof orderRESTRepository > {
return orderRESTRepository( httpClient );
}
}

View File

@ -1,5 +1,5 @@
import { MetaData } from '../../shared-types';
import {Model, ModelID} from '../../model';
import { Model, ModelID } from '../../model';
import { TaxStatus } from './types';
/**

View File

@ -3,8 +3,16 @@
*
* @typedef OrderStatus
*/
export type OrderStatus = 'pending' | 'processing' | 'complete' | 'on-hold' | 'refunded'
| 'cancelled' | 'failed' | 'trash' | string;
export type OrderStatus =
| 'pending'
| 'processing'
| 'complete'
| 'on-hold'
| 'refunded'
| 'cancelled'
| 'failed'
| 'trash'
| string;
/**
* An fee's tax status.
@ -16,11 +24,32 @@ export type TaxStatus = 'taxable' | 'none';
/**
* Base order properties
*/
export type OrderDataUpdateParams = 'id' | 'parentId' | 'status' | 'currency' | 'version'
| 'pricesIncludeTax' | 'discountTotal' | 'discountTax' | 'shippingTotal' | 'shippingTax'
| 'cartTax' | 'customerId' | 'orderKey' | 'paymentMethod' | 'paymentMethodTitle'
| 'transactionId' | 'customerIpAddress' | 'customerUserAgent' | 'createdVia' | 'datePaid'
| 'customerNote' | 'dateCompleted' | 'cartHash' | 'orderNumber' | 'currencySymbol';
export type OrderDataUpdateParams =
| 'id'
| 'parentId'
| 'status'
| 'currency'
| 'version'
| 'pricesIncludeTax'
| 'discountTotal'
| 'discountTax'
| 'shippingTotal'
| 'shippingTax'
| 'cartTax'
| 'customerId'
| 'orderKey'
| 'paymentMethod'
| 'paymentMethodTitle'
| 'transactionId'
| 'customerIpAddress'
| 'customerUserAgent'
| 'createdVia'
| 'datePaid'
| 'customerNote'
| 'dateCompleted'
| 'cartHash'
| 'orderNumber'
| 'currencySymbol';
/**
* Common total properties
@ -30,30 +59,59 @@ export type OrderTotalUpdateParams = 'total' | 'totalTax';
/**
* Billing address properties
*/
export type BillingOrderAddressUpdateParams = ShippingOrderAddressUpdateParams | 'email' | 'phone';
export type BillingOrderAddressUpdateParams =
| ShippingOrderAddressUpdateParams
| 'email'
| 'phone';
/**
* Shipping address properties
*/
export type ShippingOrderAddressUpdateParams = 'firstName' | 'lastName' | 'company' | 'address1'
| 'address2' | 'city' | 'state' | 'postCode' | 'country';
export type ShippingOrderAddressUpdateParams =
| 'firstName'
| 'lastName'
| 'company'
| 'address1'
| 'address2'
| 'city'
| 'state'
| 'postCode'
| 'country';
/**
* Line item properties
*/
export type OrderLineItemUpdateParams = 'name' | 'ProductId' | 'variationId' | 'quantity'
| 'taxClass' | 'subtotal' | 'subtotalTax' | 'sku' | 'price' | 'parentName';
export type OrderLineItemUpdateParams =
| 'name'
| 'ProductId'
| 'variationId'
| 'quantity'
| 'taxClass'
| 'subtotal'
| 'subtotalTax'
| 'sku'
| 'price'
| 'parentName';
/**
* Tax rate properties
*/
export type OrderTaxUpdateParams = 'rateCode' | 'rateId' | 'label' | 'compoundRate'
| 'taxTotal' | 'shippingTaxTotal' | 'ratePercent';
export type OrderTaxUpdateParams =
| 'rateCode'
| 'rateId'
| 'label'
| 'compoundRate'
| 'taxTotal'
| 'shippingTaxTotal'
| 'ratePercent';
/**
* Order shipping properties
*/
export type OrderShippingUpdateParams = 'methodTitle' | 'methodId' | 'instanceId';
export type OrderShippingUpdateParams =
| 'methodTitle'
| 'methodId'
| 'instanceId';
/**
* Order fee properties

View File

@ -1,10 +1,6 @@
import { AbstractProductData } from './data';
import { ModelID } from '../../model';
import {
CatalogVisibility,
ProductTerm,
ProductAttribute,
} from '../shared';
import { CatalogVisibility, ProductTerm, ProductAttribute } from '../shared';
import { ObjectLinks } from '../../shared-types';
/**
@ -33,7 +29,8 @@ export const buildProductURL = ( id: ModelID ) => baseProductURL() + id;
* @param {ModelID} id the id of the product.
* @return {string} RESTful Url.
*/
export const deleteProductURL = ( id: ModelID ) => buildProductURL( id ) + '?force=true';
export const deleteProductURL = ( id: ModelID ) =>
buildProductURL( id ) + '?force=true';
/**
* The base for all product types.
@ -100,7 +97,8 @@ export abstract class AbstractProduct extends AbstractProductData {
*
* @type {CatalogVisibility}
*/
public readonly catalogVisibility: CatalogVisibility = CatalogVisibility.Everywhere;
public readonly catalogVisibility: CatalogVisibility =
CatalogVisibility.Everywhere;
/**
* The count of sales of the product
@ -135,7 +133,7 @@ export abstract class AbstractProduct extends AbstractProductData {
*
* @type {ReadonlyArray.<number>}
*/
public readonly relatedIds: Array<number> = [];
public readonly relatedIds: Array< number > = [];
/**
* The attributes for the product.

View File

@ -9,7 +9,7 @@ abstract class AbstractProductCrossSells extends Model {
*
* @type {ReadonlyArray.<number>}
*/
public readonly crossSellIds: Array<number> = [];
public readonly crossSellIds: Array< number > = [];
}
export interface IProductCrossSells extends AbstractProductCrossSells {}

View File

@ -9,14 +9,14 @@ abstract class AbstractProductExternal extends Model {
*
* @type {string}
*/
public readonly buttonText: string = ''
public readonly buttonText: string = '';
/**
* The product's external URL.
*
* @type {string}
*/
public readonly externalUrl: string = ''
public readonly externalUrl: string = '';
}
export interface IProductExternal extends AbstractProductExternal {}

View File

@ -9,7 +9,7 @@ abstract class AbstractProductGrouped extends Model {
*
* @type {ReadonlyArray.<number>}
*/
public readonly groupedProducts: Array<number> = [];
public readonly groupedProducts: Array< number > = [];
}
export interface IProductGrouped extends AbstractProductGrouped {}

View File

@ -1,8 +1,5 @@
import { Model } from '../../model';
import {
BackorderStatus,
StockStatus,
} from '../shared';
import { BackorderStatus, StockStatus } from '../shared';
/**
* The base for inventory products.

View File

@ -9,7 +9,7 @@ abstract class AbstractProductUpSells extends Model {
*
* @type {ReadonlyArray.<number>}
*/
public readonly upSellIds: Array<number> = [];
public readonly upSellIds: Array< number > = [];
}
export interface IProductUpSells extends AbstractProductUpSells {}

View File

@ -29,17 +29,21 @@ import {
/**
* The parameters that external products can update.
*/
type ExternalProductUpdateParams = ProductCommonUpdateParams
& ProductExternalUpdateParams
& ProductPriceUpdateParams
& ProductSalesTaxUpdateParams
& ProductUpSellUpdateParams;
type ExternalProductUpdateParams = ProductCommonUpdateParams &
ProductExternalUpdateParams &
ProductPriceUpdateParams &
ProductSalesTaxUpdateParams &
ProductUpSellUpdateParams;
/**
* 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 ExternalProductRepositoryParams =
ModelRepositoryParams< ExternalProduct, never, ProductSearchParams, ExternalProductUpdateParams >;
export type ExternalProductRepositoryParams = ModelRepositoryParams<
ExternalProduct,
never,
ProductSearchParams,
ExternalProductUpdateParams
>;
/**
* An interface for listing external products using the repository.
@ -84,17 +88,19 @@ export type DeletesExternalProducts = DeletesModels< ExternalProductRepositoryPa
/**
* The base for the external product object.
*/
export class ExternalProduct extends AbstractProduct implements
IProductCommon,
IProductExternal,
IProductPrice,
IProductSalesTax,
IProductUpSells {
export class ExternalProduct
extends AbstractProduct
implements
IProductCommon,
IProductExternal,
IProductPrice,
IProductSalesTax,
IProductUpSells {
/**
* @see ./abstracts/external.ts
*/
public readonly buttonText: string = ''
public readonly externalUrl: string = ''
public readonly buttonText: string = '';
public readonly externalUrl: string = '';
/**
* @see ./abstracts/price.ts
@ -110,7 +116,7 @@ export class ExternalProduct extends AbstractProduct implements
/**
* @see ./abstracts/upsell.ts
*/
public readonly upSellIds: Array<number> = [];
public readonly upSellIds: Array< number > = [];
/**
* @see ./abstracts/sales-tax.ts
@ -133,7 +139,9 @@ export class ExternalProduct extends AbstractProduct implements
*
* @param {HTTPClient} httpClient The client for communicating via HTTP.
*/
public static restRepository( httpClient: HTTPClient ): ReturnType< typeof externalProductRESTRepository > {
public static restRepository(
httpClient: HTTPClient
): ReturnType< typeof externalProductRESTRepository > {
return externalProductRESTRepository( httpClient );
}
}

View File

@ -24,15 +24,19 @@ import {
/**
* The parameters that Grouped products can update.
*/
type GroupedProductUpdateParams = ProductCommonUpdateParams
& ProductGroupedUpdateParams
& ProductUpSellUpdateParams;
type GroupedProductUpdateParams = ProductCommonUpdateParams &
ProductGroupedUpdateParams &
ProductUpSellUpdateParams;
/**
* 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 GroupedProductRepositoryParams =
ModelRepositoryParams< GroupedProduct, never, ProductSearchParams, GroupedProductUpdateParams >;
export type GroupedProductRepositoryParams = ModelRepositoryParams<
GroupedProduct,
never,
ProductSearchParams,
GroupedProductUpdateParams
>;
/**
* An interface for listing Grouped products using the repository.
@ -77,19 +81,18 @@ export type DeletesGroupedProducts = DeletesModels< GroupedProductRepositoryPara
/**
* The base for the Grouped product object.
*/
export class GroupedProduct extends AbstractProduct implements
IProductCommon,
IProductGrouped,
IProductUpSells {
export class GroupedProduct
extends AbstractProduct
implements IProductCommon, IProductGrouped, IProductUpSells {
/**
* @see ./abstracts/grouped.ts
*/
public readonly groupedProducts: Array<number> = [];
public readonly groupedProducts: Array< number > = [];
/**
* @see ./abstracts/upsell.ts
*/
public readonly upSellIds: Array<number> = [];
public readonly upSellIds: Array< number > = [];
/**
* Creates a new Grouped product instance with the given properties
@ -106,7 +109,9 @@ export class GroupedProduct extends AbstractProduct implements
*
* @param {HTTPClient} httpClient The client for communicating via HTTP.
*/
public static restRepository( httpClient: HTTPClient ): ReturnType< typeof groupedProductRESTRepository > {
public static restRepository(
httpClient: HTTPClient
): ReturnType< typeof groupedProductRESTRepository > {
return groupedProductRESTRepository( httpClient );
}
}

View File

@ -22,7 +22,7 @@ export enum CatalogVisibility {
/**
* The product should be hidden everywhere.
*/
Hidden = 'hidden'
Hidden = 'hidden',
}
/**
@ -44,7 +44,7 @@ export enum Taxability {
/**
* The product and shipping are not taxable.
*/
None = 'none'
None = 'none',
}
/**
@ -66,5 +66,5 @@ export enum BackorderStatus {
/**
* The product is not allowed to be backordered.
*/
NotAllowed = 'no'
NotAllowed = 'no',
}

View File

@ -4,24 +4,47 @@
* @typedef StockStatus
* @alias 'instock'|'outofstock'|'onbackorder'|string
*/
export type StockStatus = 'instock' | 'outofstock' | 'onbackorder' | string
export type StockStatus = 'instock' | 'outofstock' | 'onbackorder' | string;
/**
* Base product properties.
*/
export type ProductDataUpdateParams = 'created' | 'postStatus'
| 'id' | 'permalink' | 'price' | 'priceHtml'
| 'description' | 'sku' | 'attributes' | 'images'
| 'regularPrice' | 'salePrice' | 'saleStart' | 'saleEnd'
| 'metaData' | 'menuOrder' | 'parentId' | 'links';
export type ProductDataUpdateParams =
| 'created'
| 'postStatus'
| 'id'
| 'permalink'
| 'price'
| 'priceHtml'
| 'description'
| 'sku'
| 'attributes'
| 'images'
| 'regularPrice'
| 'salePrice'
| 'saleStart'
| 'saleEnd'
| 'metaData'
| 'menuOrder'
| 'parentId'
| 'links';
/**
* Properties common to all product types.
*/
export type ProductCommonUpdateParams = 'name' | 'slug' | 'shortDescription'
| 'categories' | 'tags' | 'isFeatured' | 'averageRating' | 'numRatings'
| 'catalogVisibility' | 'allowReviews' | 'upsellIds' | 'type'
& ProductDataUpdateParams;
export type ProductCommonUpdateParams =
| 'name'
| 'slug'
| 'shortDescription'
| 'categories'
| 'tags'
| 'isFeatured'
| 'averageRating'
| 'numRatings'
| 'catalogVisibility'
| 'allowReviews'
| 'upsellIds'
| ( 'type' & ProductDataUpdateParams );
/**
* Cross sells property.
@ -31,8 +54,13 @@ export type ProductCrossUpdateParams = 'crossSellIds';
/**
* Price properties.
*/
export type ProductPriceUpdateParams = 'price' | 'priceHtml' | 'regularPrice'
| 'salePrice' | 'saleStart' | 'saleEnd';
export type ProductPriceUpdateParams =
| 'price'
| 'priceHtml'
| 'regularPrice'
| 'salePrice'
| 'saleStart'
| 'saleEnd';
/**
* Upsells property.
@ -52,8 +80,13 @@ export type ProductGroupedUpdateParams = 'groupedProducts';
/**
* Properties related to tracking inventory.
*/
export type ProductInventoryUpdateParams = 'backorderStatus' | 'canBackorder' | 'trackInventory'
| 'onePerOrder' | 'remainingStock' | 'lowStockThreshold';
export type ProductInventoryUpdateParams =
| 'backorderStatus'
| 'canBackorder'
| 'trackInventory'
| 'onePerOrder'
| 'remainingStock'
| 'lowStockThreshold';
/**
* Properties related to sales tax.
@ -63,14 +96,23 @@ export type ProductSalesTaxUpdateParams = 'taxClass' | 'taxStatus';
/**
* Properties related to shipping.
*/
export type ProductShippingUpdateParams = 'height' | 'length' | 'weight' | 'width'
| 'shippingClass' | 'shippingClassId';
export type ProductShippingUpdateParams =
| 'height'
| 'length'
| 'weight'
| 'width'
| 'shippingClass'
| 'shippingClassId';
/**
* Properties exclusive to the Simple product type.
*/
export type ProductDeliveryUpdateParams = 'daysToDownload' | 'downloadLimit' | 'downloads'
| 'purchaseNote' | 'isVirtual';
export type ProductDeliveryUpdateParams =
| 'daysToDownload'
| 'downloadLimit'
| 'downloads'
| 'purchaseNote'
| 'isVirtual';
/**
* Properties exclusive to the Variable product type.

View File

@ -38,19 +38,24 @@ import {
/**
* The parameters that simple products can update.
*/
type SimpleProductUpdateParams = ProductDeliveryUpdateParams
& ProductCommonUpdateParams
& ProductCrossUpdateParams
& ProductInventoryUpdateParams
& ProductPriceUpdateParams
& ProductSalesTaxUpdateParams
& ProductShippingUpdateParams
& ProductUpSellUpdateParams;
type SimpleProductUpdateParams = ProductDeliveryUpdateParams &
ProductCommonUpdateParams &
ProductCrossUpdateParams &
ProductInventoryUpdateParams &
ProductPriceUpdateParams &
ProductSalesTaxUpdateParams &
ProductShippingUpdateParams &
ProductUpSellUpdateParams;
/**
* 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, ProductSearchParams, SimpleProductUpdateParams >;
export type SimpleProductRepositoryParams = ModelRepositoryParams<
SimpleProduct,
never,
ProductSearchParams,
SimpleProductUpdateParams
>;
/**
* An interface for listing simple products using the repository.
@ -95,24 +100,26 @@ export type DeletesSimpleProducts = DeletesModels< SimpleProductRepositoryParams
/**
* The base for the simple product object.
*/
export class SimpleProduct extends AbstractProduct implements
IProductCommon,
IProductCrossSells,
IProductDelivery,
IProductInventory,
IProductPrice,
IProductSalesTax,
IProductShipping,
IProductUpSells {
export class SimpleProduct
extends AbstractProduct
implements
IProductCommon,
IProductCrossSells,
IProductDelivery,
IProductInventory,
IProductPrice,
IProductSalesTax,
IProductShipping,
IProductUpSells {
/**
* @see ./abstracts/cross-sells.ts
*/
public readonly crossSellIds: Array<number> = [];
public readonly crossSellIds: Array< number > = [];
/**
* @see ./abstracts/upsell.ts
*/
public readonly upSellIds: Array<number> = [];
public readonly upSellIds: Array< number > = [];
/**
* @see ./abstracts/delivery.ts
@ -180,7 +187,9 @@ export class SimpleProduct extends AbstractProduct implements
*
* @param {HTTPClient} httpClient The client for communicating via HTTP.
*/
public static restRepository( httpClient: HTTPClient ): ReturnType< typeof simpleProductRESTRepository > {
public static restRepository(
httpClient: HTTPClient
): ReturnType< typeof simpleProductRESTRepository > {
return simpleProductRESTRepository( httpClient );
}
}

View File

@ -35,19 +35,23 @@ import {
/**
* The parameters that variable products can update.
*/
type VariableProductUpdateParams = ProductVariableUpdateParams
& ProductCommonUpdateParams
& ProductCrossUpdateParams
& ProductInventoryUpdateParams
& ProductSalesTaxUpdateParams
& ProductShippingUpdateParams
& ProductUpSellUpdateParams;
type VariableProductUpdateParams = ProductVariableUpdateParams &
ProductCommonUpdateParams &
ProductCrossUpdateParams &
ProductInventoryUpdateParams &
ProductSalesTaxUpdateParams &
ProductShippingUpdateParams &
ProductUpSellUpdateParams;
/**
* 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 VariableProductRepositoryParams =
ModelRepositoryParams< VariableProduct, never, ProductSearchParams, VariableProductUpdateParams >;
export type VariableProductRepositoryParams = ModelRepositoryParams<
VariableProduct,
never,
ProductSearchParams,
VariableProductUpdateParams
>;
/**
* An interface for listing variable products using the repository.
@ -92,22 +96,24 @@ export type DeletesVariableProducts = DeletesModels< VariableProductRepositoryPa
/**
* The base for the Variable product object.
*/
export class VariableProduct extends AbstractProduct implements
IProductCommon,
IProductCrossSells,
IProductInventory,
IProductSalesTax,
IProductShipping,
IProductUpSells {
export class VariableProduct
extends AbstractProduct
implements
IProductCommon,
IProductCrossSells,
IProductInventory,
IProductSalesTax,
IProductShipping,
IProductUpSells {
/**
* @see ./abstracts/cross-sells.ts
*/
public readonly crossSellIds: Array<number> = [];
public readonly crossSellIds: Array< number > = [];
/**
* @see ./abstracts/upsell.ts
*/
public readonly upSellIds: Array<number> = [];
public readonly upSellIds: Array< number > = [];
/**
* @see ./abstracts/inventory.ts
@ -151,7 +157,7 @@ export class VariableProduct extends AbstractProduct implements
*
* @type {ReadonlyArray.<number>}
*/
public readonly variations: Array<number> = [];
public readonly variations: Array< number > = [];
/**
* Creates a new Variable product instance with the given properties
@ -168,7 +174,9 @@ export class VariableProduct extends AbstractProduct implements
*
* @param {HTTPClient} httpClient The client for communicating via HTTP.
*/
public static restRepository( httpClient: HTTPClient ): ReturnType< typeof variableProductRESTRepository > {
public static restRepository(
httpClient: HTTPClient
): ReturnType< typeof variableProductRESTRepository > {
return variableProductRESTRepository( httpClient );
}
}

View File

@ -36,18 +36,22 @@ import { productVariationRESTRepository } from '../../repositories';
/**
* The parameters that product variations can update.
*/
type ProductVariationUpdateParams = ProductDataUpdateParams
& ProductDeliveryUpdateParams
& ProductInventoryUpdateParams
& ProductPriceUpdateParams
& ProductSalesTaxUpdateParams
& ProductShippingUpdateParams;
type ProductVariationUpdateParams = ProductDataUpdateParams &
ProductDeliveryUpdateParams &
ProductInventoryUpdateParams &
ProductPriceUpdateParams &
ProductSalesTaxUpdateParams &
ProductShippingUpdateParams;
/**
* 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 ProductVariationRepositoryParams =
ModelRepositoryParams< ProductVariation, ModelID, ProductSearchParams, ProductVariationUpdateParams >;
export type ProductVariationRepositoryParams = ModelRepositoryParams<
ProductVariation,
ModelID,
ProductSearchParams,
ProductVariationUpdateParams
>;
/**
* An interface for listing variable products using the repository.
@ -92,12 +96,14 @@ export type DeletesProductVariations = DeletesChildModels< ProductVariationRepos
/**
* The base for the product variation object.
*/
export class ProductVariation extends AbstractProductData implements
IProductDelivery,
IProductInventory,
IProductPrice,
IProductSalesTax,
IProductShipping {
export class ProductVariation
extends AbstractProductData
implements
IProductDelivery,
IProductInventory,
IProductPrice,
IProductSalesTax,
IProductShipping {
/**
* @see ./abstracts/delivery.ts
*/
@ -114,7 +120,7 @@ export class ProductVariation extends AbstractProductData implements
public readonly onePerOrder: boolean = false;
public readonly trackInventory: boolean = false;
public readonly remainingStock: number = -1;
public readonly stockStatus: StockStatus = ''
public readonly stockStatus: StockStatus = '';
public readonly backorderStatus: BackorderStatus = BackorderStatus.Allowed;
public readonly canBackorder: boolean = false;
public readonly isOnBackorder: boolean = false;
@ -182,7 +188,9 @@ export class ProductVariation extends AbstractProductData implements
*
* @param {HTTPClient} httpClient The client for communicating via HTTP.
*/
public static restRepository( httpClient: HTTPClient ): ReturnType< typeof productVariationRESTRepository > {
public static restRepository(
httpClient: HTTPClient
): ReturnType< typeof productVariationRESTRepository > {
return productVariationRESTRepository( httpClient );
}
}

View File

@ -57,7 +57,9 @@ export class SettingGroup extends Model {
*
* @param {HTTPClient} httpClient The client for communicating via HTTP.
*/
public static restRepository( httpClient: HTTPClient ): ReturnType< typeof settingGroupRESTRepository > {
public static restRepository(
httpClient: HTTPClient
): ReturnType< typeof settingGroupRESTRepository > {
return settingGroupRESTRepository( httpClient );
}
}

View File

@ -12,7 +12,12 @@ import {
* 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' >;
export type SettingRepositoryParams = ModelRepositoryParams<
Setting,
ModelID,
never,
'value'
>;
/**
* An interface for listing settings using the repository.
@ -73,7 +78,7 @@ export class Setting extends Model {
*
* @type {Object.<string, string>|null}
*/
public readonly options: { [key: string]: string } | undefined;
public readonly options: { [ key: string ]: string } | undefined;
/**
* The default value for the setting.
@ -104,7 +109,9 @@ export class Setting extends Model {
*
* @param {HTTPClient} httpClient The client for communicating via HTTP.
*/
public static restRepository( httpClient: HTTPClient ): ReturnType< typeof settingRESTRepository > {
public static restRepository(
httpClient: HTTPClient
): ReturnType< typeof settingRESTRepository > {
return settingRESTRepository( httpClient );
}
}

View File

@ -7,7 +7,9 @@ import { Model } from './model';
* @alias Function.<T>
* @template T
*/
export type ModelConstructor< T extends Model > = new ( properties: Partial< T > ) => T;
export type ModelConstructor< T extends Model > = new (
properties: Partial< T >
) => T;
/**
* A post's status.

View File

@ -4,7 +4,8 @@ import { ModelTransformer, ModelRepositoryParams } from '../../../framework';
import { DummyModel } from '../../../__test_data__/dummy-model';
import {
restCreate,
restDelete, restDeleteChild,
restDelete,
restDeleteChild,
restList,
restListChild,
restRead,
@ -14,7 +15,12 @@ import {
} from '../shared';
import { Model } from '../../../models';
type DummyModelParams = ModelRepositoryParams< DummyModel, never, { search: string }, 'name' >
type DummyModelParams = ModelRepositoryParams<
DummyModel,
never,
{ search: string },
'name'
>;
class DummyChildModel extends Model {
public childName: string = '';
@ -24,7 +30,12 @@ class DummyChildModel extends Model {
Object.assign( this, partial );
}
}
type DummyChildParams = ModelRepositoryParams< DummyChildModel, { parent: string }, { childSearch: string }, 'childName' >
type DummyChildParams = ModelRepositoryParams<
DummyChildModel,
{ parent: string },
{ childSearch: string },
'childName'
>;
jest.mock( '../../../framework/model-transformer' );
@ -44,10 +55,8 @@ describe( 'Shared REST Functions', () => {
} );
it( 'restList', async () => {
mocked( mockClient.get ).mockResolvedValue( new HTTPResponse(
200,
{},
[
mocked( mockClient.get ).mockResolvedValue(
new HTTPResponse( 200, {}, [
{
id: 'Test-1',
label: 'Test 1',
@ -56,27 +65,44 @@ describe( 'Shared REST Functions', () => {
id: 'Test-2',
label: 'Test 2',
},
],
) );
mocked( mockTransformer.toModel ).mockReturnValue( new DummyModel( { name: 'Test' } ) );
] )
);
mocked( mockTransformer.toModel ).mockReturnValue(
new DummyModel( { name: 'Test' } )
);
const fn = restList< DummyModelParams >( () => 'test-url', DummyModel, mockClient, mockTransformer );
const fn = restList< DummyModelParams >(
() => 'test-url',
DummyModel,
mockClient,
mockTransformer
);
const result = await fn( { search: 'Test' } );
expect( result ).toHaveLength( 2 );
expect( result[ 0 ] ).toMatchObject( new DummyModel( { name: 'Test' } ) );
expect( result[ 1 ] ).toMatchObject( new DummyModel( { name: 'Test' } ) );
expect( mockClient.get ).toHaveBeenCalledWith( 'test-url', { search: 'Test' } );
expect( mockTransformer.toModel ).toHaveBeenCalledWith( DummyModel, { id: 'Test-1', label: 'Test 1' } );
expect( mockTransformer.toModel ).toHaveBeenCalledWith( DummyModel, { id: 'Test-2', label: 'Test 2' } );
expect( result[ 0 ] ).toMatchObject(
new DummyModel( { name: 'Test' } )
);
expect( result[ 1 ] ).toMatchObject(
new DummyModel( { name: 'Test' } )
);
expect( mockClient.get ).toHaveBeenCalledWith( 'test-url', {
search: 'Test',
} );
expect( mockTransformer.toModel ).toHaveBeenCalledWith( DummyModel, {
id: 'Test-1',
label: 'Test 1',
} );
expect( mockTransformer.toModel ).toHaveBeenCalledWith( DummyModel, {
id: 'Test-2',
label: 'Test 2',
} );
} );
it( 'restListChildren', async () => {
mocked( mockClient.get ).mockResolvedValue( new HTTPResponse(
200,
{},
[
mocked( mockClient.get ).mockResolvedValue(
new HTTPResponse( 200, {}, [
{
id: 'Test-1',
label: 'Test 1',
@ -85,152 +111,238 @@ describe( 'Shared REST Functions', () => {
id: 'Test-2',
label: 'Test 2',
},
],
) );
mocked( mockTransformer.toModel ).mockReturnValue( new DummyChildModel( { name: 'Test' } ) );
] )
);
mocked( mockTransformer.toModel ).mockReturnValue(
new DummyChildModel( { name: 'Test' } )
);
const fn = restListChild< DummyChildParams >(
( parent ) => 'test-url-' + parent.parent,
DummyChildModel,
mockClient,
mockTransformer,
mockTransformer
);
const result = await fn( { parent: '123' }, { childSearch: 'Test' } );
expect( result ).toHaveLength( 2 );
expect( result[ 0 ] ).toMatchObject( new DummyChildModel( { name: 'Test' } ) );
expect( result[ 1 ] ).toMatchObject( new DummyChildModel( { name: 'Test' } ) );
expect( mockClient.get ).toHaveBeenCalledWith( 'test-url-123', { childSearch: 'Test' } );
expect( mockTransformer.toModel ).toHaveBeenCalledWith( DummyChildModel, { id: 'Test-1', label: 'Test 1' } );
expect( mockTransformer.toModel ).toHaveBeenCalledWith( DummyChildModel, { id: 'Test-2', label: 'Test 2' } );
expect( result[ 0 ] ).toMatchObject(
new DummyChildModel( { name: 'Test' } )
);
expect( result[ 1 ] ).toMatchObject(
new DummyChildModel( { name: 'Test' } )
);
expect( mockClient.get ).toHaveBeenCalledWith( 'test-url-123', {
childSearch: 'Test',
} );
expect( mockTransformer.toModel ).toHaveBeenCalledWith(
DummyChildModel,
{ id: 'Test-1', label: 'Test 1' }
);
expect( mockTransformer.toModel ).toHaveBeenCalledWith(
DummyChildModel,
{ id: 'Test-2', label: 'Test 2' }
);
} );
it( 'restCreate', async () => {
mocked( mockClient.post ).mockResolvedValue( new HTTPResponse(
200,
{},
{
id: 'Test-1',
label: 'Test 1',
},
) );
mocked( mockTransformer.fromModel ).mockReturnValue( { name: 'From-Test' } );
mocked( mockTransformer.toModel ).mockReturnValue( new DummyModel( { name: 'Test' } ) );
mocked( mockClient.post ).mockResolvedValue(
new HTTPResponse(
200,
{},
{
id: 'Test-1',
label: 'Test 1',
}
)
);
mocked( mockTransformer.fromModel ).mockReturnValue( {
name: 'From-Test',
} );
mocked( mockTransformer.toModel ).mockReturnValue(
new DummyModel( { name: 'Test' } )
);
const fn = restCreate< DummyModelParams >(
( properties ) => 'test-url-' + properties.name,
DummyModel,
mockClient,
mockTransformer,
mockTransformer
);
const result = await fn( { name: 'Test' } );
expect( result ).toMatchObject( new DummyModel( { name: 'Test' } ) );
expect( mockTransformer.fromModel ).toHaveBeenCalledWith( { name: 'Test' } );
expect( mockClient.post ).toHaveBeenCalledWith( 'test-url-Test', { name: 'From-Test' } );
expect( mockTransformer.toModel ).toHaveBeenCalledWith( DummyModel, { id: 'Test-1', label: 'Test 1' } );
expect( mockTransformer.fromModel ).toHaveBeenCalledWith( {
name: 'Test',
} );
expect( mockClient.post ).toHaveBeenCalledWith( 'test-url-Test', {
name: 'From-Test',
} );
expect( mockTransformer.toModel ).toHaveBeenCalledWith( DummyModel, {
id: 'Test-1',
label: 'Test 1',
} );
} );
it( 'restRead', async () => {
mocked( mockClient.get ).mockResolvedValue( new HTTPResponse(
200,
{},
{
id: 'Test-1',
label: 'Test 1',
},
) );
mocked( mockTransformer.toModel ).mockReturnValue( new DummyModel( { name: 'Test' } ) );
mocked( mockClient.get ).mockResolvedValue(
new HTTPResponse(
200,
{},
{
id: 'Test-1',
label: 'Test 1',
}
)
);
mocked( mockTransformer.toModel ).mockReturnValue(
new DummyModel( { name: 'Test' } )
);
const fn = restRead< DummyModelParams >( ( id ) => 'test-url-' + id, DummyModel, mockClient, mockTransformer );
const fn = restRead< DummyModelParams >(
( id ) => 'test-url-' + id,
DummyModel,
mockClient,
mockTransformer
);
const result = await fn( 123 );
expect( result ).toMatchObject( new DummyModel( { name: 'Test' } ) );
expect( mockClient.get ).toHaveBeenCalledWith( 'test-url-123' );
expect( mockTransformer.toModel ).toHaveBeenCalledWith( DummyModel, { id: 'Test-1', label: 'Test 1' } );
expect( mockTransformer.toModel ).toHaveBeenCalledWith( DummyModel, {
id: 'Test-1',
label: 'Test 1',
} );
} );
it( 'restReadChildren', async () => {
mocked( mockClient.get ).mockResolvedValue( new HTTPResponse(
200,
{},
{
id: 'Test-1',
label: 'Test 1',
},
) );
mocked( mockTransformer.toModel ).mockReturnValue( new DummyChildModel( { name: 'Test' } ) );
mocked( mockClient.get ).mockResolvedValue(
new HTTPResponse(
200,
{},
{
id: 'Test-1',
label: 'Test 1',
}
)
);
mocked( mockTransformer.toModel ).mockReturnValue(
new DummyChildModel( { name: 'Test' } )
);
const fn = restReadChild< DummyChildParams >(
( parent, id ) => 'test-url-' + parent.parent + '-' + id,
DummyChildModel,
mockClient,
mockTransformer,
mockTransformer
);
const result = await fn( { parent: '123' }, 456 );
expect( result ).toMatchObject( new DummyModel( { name: 'Test' } ) );
expect( mockClient.get ).toHaveBeenCalledWith( 'test-url-123-456' );
expect( mockTransformer.toModel ).toHaveBeenCalledWith( DummyChildModel, { id: 'Test-1', label: 'Test 1' } );
expect( mockTransformer.toModel ).toHaveBeenCalledWith(
DummyChildModel,
{ id: 'Test-1', label: 'Test 1' }
);
} );
it( 'restUpdate', async () => {
mocked( mockClient.patch ).mockResolvedValue( new HTTPResponse(
200,
{},
{
id: 'Test-1',
label: 'Test 1',
},
) );
mocked( mockTransformer.fromModel ).mockReturnValue( { name: 'From-Test' } );
mocked( mockTransformer.toModel ).mockReturnValue( new DummyModel( { name: 'Test' } ) );
mocked( mockClient.patch ).mockResolvedValue(
new HTTPResponse(
200,
{},
{
id: 'Test-1',
label: 'Test 1',
}
)
);
mocked( mockTransformer.fromModel ).mockReturnValue( {
name: 'From-Test',
} );
mocked( mockTransformer.toModel ).mockReturnValue(
new DummyModel( { name: 'Test' } )
);
const fn = restUpdate< DummyModelParams >( ( id ) => 'test-url-' + id, DummyModel, mockClient, mockTransformer );
const fn = restUpdate< DummyModelParams >(
( id ) => 'test-url-' + id,
DummyModel,
mockClient,
mockTransformer
);
const result = await fn( 123, { name: 'Test' } );
expect( result ).toMatchObject( new DummyModel( { name: 'Test' } ) );
expect( mockTransformer.fromModel ).toHaveBeenCalledWith( { name: 'Test' } );
expect( mockClient.patch ).toHaveBeenCalledWith( 'test-url-123', { name: 'From-Test' } );
expect( mockTransformer.toModel ).toHaveBeenCalledWith( DummyModel, { id: 'Test-1', label: 'Test 1' } );
expect( mockTransformer.fromModel ).toHaveBeenCalledWith( {
name: 'Test',
} );
expect( mockClient.patch ).toHaveBeenCalledWith( 'test-url-123', {
name: 'From-Test',
} );
expect( mockTransformer.toModel ).toHaveBeenCalledWith( DummyModel, {
id: 'Test-1',
label: 'Test 1',
} );
} );
it( 'restUpdateChildren', async () => {
mocked( mockClient.patch ).mockResolvedValue( new HTTPResponse(
200,
{},
{
id: 'Test-1',
label: 'Test 1',
},
) );
mocked( mockTransformer.fromModel ).mockReturnValue( { name: 'From-Test' } );
mocked( mockTransformer.toModel ).mockReturnValue( new DummyChildModel( { name: 'Test' } ) );
mocked( mockClient.patch ).mockResolvedValue(
new HTTPResponse(
200,
{},
{
id: 'Test-1',
label: 'Test 1',
}
)
);
mocked( mockTransformer.fromModel ).mockReturnValue( {
name: 'From-Test',
} );
mocked( mockTransformer.toModel ).mockReturnValue(
new DummyChildModel( { name: 'Test' } )
);
const fn = restUpdateChild< DummyChildParams >(
( parent, id ) => 'test-url-' + parent.parent + '-' + id,
DummyChildModel,
mockClient,
mockTransformer,
mockTransformer
);
const result = await fn( { parent: '123' }, 456, { childName: 'Test' } );
const result = await fn( { parent: '123' }, 456, {
childName: 'Test',
} );
expect( result ).toMatchObject( new DummyChildModel( { name: 'Test' } ) );
expect( mockTransformer.fromModel ).toHaveBeenCalledWith( { childName: 'Test' } );
expect( mockClient.patch ).toHaveBeenCalledWith( 'test-url-123-456', { name: 'From-Test' } );
expect( mockTransformer.toModel ).toHaveBeenCalledWith( DummyChildModel, { id: 'Test-1', label: 'Test 1' } );
expect( result ).toMatchObject(
new DummyChildModel( { name: 'Test' } )
);
expect( mockTransformer.fromModel ).toHaveBeenCalledWith( {
childName: 'Test',
} );
expect( mockClient.patch ).toHaveBeenCalledWith( 'test-url-123-456', {
name: 'From-Test',
} );
expect( mockTransformer.toModel ).toHaveBeenCalledWith(
DummyChildModel,
{ id: 'Test-1', label: 'Test 1' }
);
} );
it( 'restDelete', async () => {
mocked( mockClient.delete ).mockResolvedValue( new HTTPResponse( 200, {}, {} ) );
mocked( mockClient.delete ).mockResolvedValue(
new HTTPResponse( 200, {}, {} )
);
const fn = restDelete< DummyModelParams >( ( id ) => 'test-url-' + id, mockClient );
const fn = restDelete< DummyModelParams >(
( id ) => 'test-url-' + id,
mockClient
);
const result = await fn( 123 );
@ -239,11 +351,13 @@ describe( 'Shared REST Functions', () => {
} );
it( 'restDeleteChildren', async () => {
mocked( mockClient.delete ).mockResolvedValue( new HTTPResponse( 200, {}, {} ) );
mocked( mockClient.delete ).mockResolvedValue(
new HTTPResponse( 200, {}, {} )
);
const fn = restDeleteChild< DummyChildParams >(
( parent, id ) => 'test-url-' + parent.parent + '-' + id,
mockClient,
mockClient
);
const result = await fn( { parent: '123' }, 456 );

View File

@ -1,7 +1,5 @@
import { HTTPClient } from '../../../http';
import {
ModelRepository,
} from '../../../framework';
import { ModelRepository } from '../../../framework';
import {
ModelID,
Coupon,
@ -34,22 +32,45 @@ import { createCouponTransformer } from './transformer';
* DeletesCoupons
* } The created repository.
*/
export default function couponRESTRepository( httpClient: HTTPClient ): CreatesCoupons
& ListsCoupons
& ReadsCoupons
& UpdatesCoupons
& DeletesCoupons {
export default function couponRESTRepository(
httpClient: HTTPClient
): CreatesCoupons &
ListsCoupons &
ReadsCoupons &
UpdatesCoupons &
DeletesCoupons {
const buildURL = ( id: ModelID ) => '/wc/v3/coupons/' + id;
// Using `?force=true` permanently deletes the coupon
const buildDeleteUrl = ( id: ModelID ) => `/wc/v3/coupons/${ id }?force=true`;
const buildDeleteUrl = ( id: ModelID ) =>
`/wc/v3/coupons/${ id }?force=true`;
const transformer = createCouponTransformer();
return new ModelRepository(
restList< CouponRepositoryParams >( () => '/wc/v3/coupons', Coupon, httpClient, transformer ),
restCreate< CouponRepositoryParams >( () => '/wc/v3/coupons', Coupon, httpClient, transformer ),
restRead< CouponRepositoryParams >( buildURL, Coupon, httpClient, transformer ),
restUpdate< CouponRepositoryParams >( buildURL, Coupon, httpClient, transformer ),
restDelete< CouponRepositoryParams >( buildDeleteUrl, httpClient ),
restList< CouponRepositoryParams >(
() => '/wc/v3/coupons',
Coupon,
httpClient,
transformer
),
restCreate< CouponRepositoryParams >(
() => '/wc/v3/coupons',
Coupon,
httpClient,
transformer
),
restRead< CouponRepositoryParams >(
buildURL,
Coupon,
httpClient,
transformer
),
restUpdate< CouponRepositoryParams >(
buildURL,
Coupon,
httpClient,
transformer
),
restDelete< CouponRepositoryParams >( buildDeleteUrl, httpClient )
);
}

View File

@ -14,52 +14,46 @@ import { Coupon } from '../../../models';
* @return {ModelTransformer} The created transformer.
*/
export function createCouponTransformer(): ModelTransformer< Coupon > {
return new ModelTransformer(
[
new IgnorePropertyTransformation( [ 'date_created', 'date_modified' ] ),
new PropertyTypeTransformation(
{
code: PropertyType.String,
amount: PropertyType.String,
dateCreated: PropertyType.Date,
dateModified: PropertyType.Date,
discountType: PropertyType.String,
dateExpires: PropertyType.Date,
usageCount: PropertyType.Integer,
individualUse: PropertyType.Boolean,
usageLimit: PropertyType.Integer,
usageLimitPerUser: PropertyType.Integer,
limitUsageToXItems: PropertyType.Integer,
freeShipping: PropertyType.Boolean,
excludeSaleItems: PropertyType.Boolean,
minimumAmount: PropertyType.String,
maximumAmount: PropertyType.String,
},
),
new KeyChangeTransformation< Coupon >(
{
dateCreated: 'date_created_gmt',
dateModified: 'date_modified_gmt',
discountType: 'discount_type',
dateExpires: 'date_expires',
usageCount: 'usage_count',
individualUse: 'individual_use',
productIds: 'product_ids',
excludedProductIds: 'excluded_product_ids',
usageLimit: 'usage_limit',
usageLimitPerUser: 'usage_limit_per_user',
limitUsageToXItems: 'limit_usage_to_x_items',
freeShipping: 'free_shipping',
productCategories: 'product_categories',
excludedProductCategories: 'excluded_product_categories',
excludeSaleItems: 'exclude_sale_items',
minimumAmount: 'minimum_amount',
maximumAmount: 'maximum_amount',
emailRestrictions: 'email_restrictions',
usedBy: 'used_by',
links: '_links',
},
),
],
);
return new ModelTransformer( [
new IgnorePropertyTransformation( [ 'date_created', 'date_modified' ] ),
new PropertyTypeTransformation( {
code: PropertyType.String,
amount: PropertyType.String,
dateCreated: PropertyType.Date,
dateModified: PropertyType.Date,
discountType: PropertyType.String,
dateExpires: PropertyType.Date,
usageCount: PropertyType.Integer,
individualUse: PropertyType.Boolean,
usageLimit: PropertyType.Integer,
usageLimitPerUser: PropertyType.Integer,
limitUsageToXItems: PropertyType.Integer,
freeShipping: PropertyType.Boolean,
excludeSaleItems: PropertyType.Boolean,
minimumAmount: PropertyType.String,
maximumAmount: PropertyType.String,
} ),
new KeyChangeTransformation< Coupon >( {
dateCreated: 'date_created_gmt',
dateModified: 'date_modified_gmt',
discountType: 'discount_type',
dateExpires: 'date_expires',
usageCount: 'usage_count',
individualUse: 'individual_use',
productIds: 'product_ids',
excludedProductIds: 'excluded_product_ids',
usageLimit: 'usage_limit',
usageLimitPerUser: 'usage_limit_per_user',
limitUsageToXItems: 'limit_usage_to_x_items',
freeShipping: 'free_shipping',
productCategories: 'product_categories',
excludedProductCategories: 'excluded_product_categories',
excludeSaleItems: 'exclude_sale_items',
minimumAmount: 'minimum_amount',
maximumAmount: 'maximum_amount',
emailRestrictions: 'email_restrictions',
usedBy: 'used_by',
links: '_links',
} ),
] );
}

View File

@ -8,14 +8,14 @@ import {
OrderTaxRate,
OrderCouponLine,
MetaData,
OrderRefundLine
} from "../../../../models";
OrderRefundLine,
} from '../../../../models';
import {
createBillingAddressTransformer,
createOrderTransformer,
createShippingAddressTransformer
} from "../transformer";
createShippingAddressTransformer,
} from '../transformer';
/*
This Object is a JSON representation of single Order GET operation from the WooCommerce REST API.
@ -23,7 +23,7 @@ import {
We use JSON.stringify here to convert an Object into a String, as JavaScript passes Objects
around by reference, and we don't want tests to modify the original `responseOrderJson` variable.
*/
const responseOrderJson = JSON.stringify({
const responseOrderJson = JSON.stringify( {
id: 1218,
parent_id: 0,
status: 'pending',
@ -52,7 +52,7 @@ const responseOrderJson = JSON.stringify({
postcode: 'Billing Postcode',
country: 'Billing Country',
email: 'Billing Email',
phone: 'Billing Phone'
phone: 'Billing Phone',
},
shipping: {
first_name: 'Shipping First Name',
@ -64,7 +64,7 @@ const responseOrderJson = JSON.stringify({
state: 'Shipping State',
postcode: 'Shipping Postcode',
country: 'Shipping Country',
phone: 'Shipping Phone'
phone: 'Shipping Phone',
},
payment_method: 'Foo Payment Method',
payment_method_title: 'Foo Payment Method Title',
@ -80,9 +80,9 @@ const responseOrderJson = JSON.stringify({
meta_data: [
{
id: 123,
key: "Foo Metadata Key 1",
value: "Foo Metadata Value 1"
}
key: 'Foo Metadata Key 1',
value: 'Foo Metadata Value 1',
},
],
line_items: [
{
@ -100,8 +100,8 @@ const responseOrderJson = JSON.stringify({
meta_data: [],
sku: 'woo-belt',
price: 50,
parent_name: null
}
parent_name: null,
},
],
tax_lines: [
{
@ -113,8 +113,8 @@ const responseOrderJson = JSON.stringify({
tax_total: '6.00',
shipping_tax_total: '0.00',
rate_percent: 12,
meta_data: []
}
meta_data: [],
},
],
shipping_lines: [
{
@ -124,8 +124,8 @@ const responseOrderJson = JSON.stringify({
total: '5.00',
total_taxes: '10.00',
taxes: [ { id: 1, total: '6', subtotal: '6.6' } ],
meta_data: []
}
meta_data: [],
},
],
fee_lines: [
{
@ -135,8 +135,8 @@ const responseOrderJson = JSON.stringify({
total: '5.00',
total_taxes: '10.00',
taxes: [ { id: 1, total: '6', subtotal: '6.6' } ],
meta_data: []
}
meta_data: [],
},
],
coupon_lines: [
{
@ -155,12 +155,12 @@ const responseOrderJson = JSON.stringify({
date_created: {
date: '2021-05-19 04:28:31.000000',
timezone_type: 3,
timezone: 'Pacific/Auckland'
timezone: 'Pacific/Auckland',
},
date_modified: {
date: '2021-05-19 04:28:31.000000',
timezone_type: 3,
timezone: 'Pacific/Auckland'
timezone: 'Pacific/Auckland',
},
date_expires: null,
discount_type: 'fixed_cart',
@ -180,18 +180,18 @@ const responseOrderJson = JSON.stringify({
maximum_amount: '',
email_restrictions: [],
virtual: false,
meta_data: []
meta_data: [],
},
}
]
}
},
],
},
],
refunds: [
{
id: 123,
reason: 'Foo Reason',
total: '5.00'
}
total: '5.00',
},
],
date_created_gmt: '2021-11-30T16:43:38',
date_modified_gmt: '2021-11-30T18:31:05',
@ -201,80 +201,91 @@ const responseOrderJson = JSON.stringify({
_links: {
self: [
{
href: 'http://local.wordpress.test/wp-json/wc/v3/orders/1218'
}
href: 'http://local.wordpress.test/wp-json/wc/v3/orders/1218',
},
],
collection: [
{
href: 'http://local.wordpress.test/wp-json/wc/v3/orders'
}
]
}
});
href: 'http://local.wordpress.test/wp-json/wc/v3/orders',
},
],
},
} );
describe( 'OrderTransformer', () => {
it( 'should transform an order JSON', () => {
const order = createOrderTransformer().toModel( Order, JSON.parse(responseOrderJson) );
const billing = createBillingAddressTransformer().toModel(BillingOrderAddress, JSON.parse(responseOrderJson).billing);
const shipping = createShippingAddressTransformer().toModel(ShippingOrderAddress, JSON.parse(responseOrderJson).shipping);
const order = createOrderTransformer().toModel(
Order,
JSON.parse( responseOrderJson )
);
const billing = createBillingAddressTransformer().toModel(
BillingOrderAddress,
JSON.parse( responseOrderJson ).billing
);
const shipping = createShippingAddressTransformer().toModel(
ShippingOrderAddress,
JSON.parse( responseOrderJson ).shipping
);
// Order
expect( order ).toBeInstanceOf( Order );
expect( order.id ).toStrictEqual(1218);
expect( order.parentId ).toStrictEqual(0);
expect( order.status ).toStrictEqual('pending');
expect( order.currency ).toStrictEqual('USD');
expect( order.version ).toStrictEqual('6.1.0');
expect( order.pricesIncludeTax ).toStrictEqual(false);
expect( order.id ).toStrictEqual( 1218 );
expect( order.parentId ).toStrictEqual( 0 );
expect( order.status ).toStrictEqual( 'pending' );
expect( order.currency ).toStrictEqual( 'USD' );
expect( order.version ).toStrictEqual( '6.1.0' );
expect( order.pricesIncludeTax ).toStrictEqual( false );
//expect( model.dateCreated ).toStrictEqual('2021-12-01T05:43:38');
//expect( model.dateModified ).toStrictEqual('2021-12-01T07:31:05');
expect( order.discountTotal ).toStrictEqual('5.00');
expect( order.discountTax ).toStrictEqual('0.60');
expect( order.shippingTotal ).toStrictEqual('0.00');
expect( order.shippingTax ).toStrictEqual('0.00');
expect( order.cartTax ).toStrictEqual('6.00');
expect( order.total ).toStrictEqual('56.00');
expect( order.totalTax ).toStrictEqual('6.00');
expect( order.customerId ).toStrictEqual(0);
expect( order.discountTotal ).toStrictEqual( '5.00' );
expect( order.discountTax ).toStrictEqual( '0.60' );
expect( order.shippingTotal ).toStrictEqual( '0.00' );
expect( order.shippingTax ).toStrictEqual( '0.00' );
expect( order.cartTax ).toStrictEqual( '6.00' );
expect( order.total ).toStrictEqual( '56.00' );
expect( order.totalTax ).toStrictEqual( '6.00' );
expect( order.customerId ).toStrictEqual( 0 );
//expect( model.orderKey ).toStrictEqual('wc_order_GFHWVmAiamh0B');
expect( order.billing ).toStrictEqual(billing);
expect( order.shipping ).toStrictEqual(shipping);
expect( order.paymentMethod ).toStrictEqual('Foo Payment Method');
expect( order.billing ).toStrictEqual( billing );
expect( order.shipping ).toStrictEqual( shipping );
expect( order.paymentMethod ).toStrictEqual( 'Foo Payment Method' );
//expect( order.paymentMethodTitle ).toStrictEqual('Foo Payment Method Title');
expect( order.transactionId ).toStrictEqual('Foo Transaction ID');
expect( order.transactionId ).toStrictEqual( 'Foo Transaction ID' );
//expect( order.customerIpAddress ).toStrictEqual('Foo Customer IP Address');
//expect( order.customerUserAgent ).toStrictEqual('Foo Customer User Agent');
//expect( order.createdVia ).toStrictEqual('admin');
expect( order.customerNote ).toStrictEqual('Foo Customer Note');
expect( order.customerNote ).toStrictEqual( 'Foo Customer Note' );
//expect( order.dateCompleted ).toStrictEqual('Foo Date Completed');
//expect( order.datePaid ).toStrictEqual('Foo Date Paid');
//expect( order.cartHash ).toStrictEqual('Foo Cart Hash');
//expect( order.orderNumber ).toStrictEqual('1218');
// Billing
expect(billing.firstName).toStrictEqual('Billing First Name');
expect(billing.lastName).toStrictEqual('Billing Last Name');
expect(billing.company).toStrictEqual('Billing Company');
expect(billing.address1).toStrictEqual('Billing Address 1');
expect(billing.address2).toStrictEqual('Billing Address 2');
expect(billing.city).toStrictEqual('Billing City');
expect(billing.state).toStrictEqual('Billing State');
expect(billing.postCode).toStrictEqual('Billing Postcode');
expect(billing.country).toStrictEqual('Billing Country');
expect(billing.email).toStrictEqual('Billing Email');
expect(billing.phone).toStrictEqual('Billing Phone');
expect( createBillingAddressTransformer().fromModel(billing) ).toStrictEqual(JSON.parse(responseOrderJson).billing);
expect( billing.firstName ).toStrictEqual( 'Billing First Name' );
expect( billing.lastName ).toStrictEqual( 'Billing Last Name' );
expect( billing.company ).toStrictEqual( 'Billing Company' );
expect( billing.address1 ).toStrictEqual( 'Billing Address 1' );
expect( billing.address2 ).toStrictEqual( 'Billing Address 2' );
expect( billing.city ).toStrictEqual( 'Billing City' );
expect( billing.state ).toStrictEqual( 'Billing State' );
expect( billing.postCode ).toStrictEqual( 'Billing Postcode' );
expect( billing.country ).toStrictEqual( 'Billing Country' );
expect( billing.email ).toStrictEqual( 'Billing Email' );
expect( billing.phone ).toStrictEqual( 'Billing Phone' );
expect(
createBillingAddressTransformer().fromModel( billing )
).toStrictEqual( JSON.parse( responseOrderJson ).billing );
// Shipping
expect(shipping.firstName).toStrictEqual('Shipping First Name');
expect(shipping.lastName).toStrictEqual('Shipping Last Name');
expect(shipping.company).toStrictEqual('Shipping Company');
expect(shipping.address1).toStrictEqual('Shipping Address 1');
expect(shipping.address2).toStrictEqual('Shipping Address 2');
expect(shipping.city).toStrictEqual('Shipping City');
expect(shipping.state).toStrictEqual('Shipping State');
expect(shipping.postCode).toStrictEqual('Shipping Postcode');
expect(shipping.country).toStrictEqual('Shipping Country');
expect( shipping.firstName ).toStrictEqual( 'Shipping First Name' );
expect( shipping.lastName ).toStrictEqual( 'Shipping Last Name' );
expect( shipping.company ).toStrictEqual( 'Shipping Company' );
expect( shipping.address1 ).toStrictEqual( 'Shipping Address 1' );
expect( shipping.address2 ).toStrictEqual( 'Shipping Address 2' );
expect( shipping.city ).toStrictEqual( 'Shipping City' );
expect( shipping.state ).toStrictEqual( 'Shipping State' );
expect( shipping.postCode ).toStrictEqual( 'Shipping Postcode' );
expect( shipping.country ).toStrictEqual( 'Shipping Country' );
/*
* Shipping Address does not have e-mail or phone fields according to WooCommerce API
@ -282,87 +293,100 @@ describe( 'OrderTransformer', () => {
*/
//expect(shipping.email).toStrictEqual('Shipping Email');
//expect(shipping.phone).toStrictEqual('Shipping Phone');
expect( createShippingAddressTransformer().fromModel(shipping) ).toStrictEqual(JSON.parse(responseOrderJson).shipping);
expect(
createShippingAddressTransformer().fromModel( shipping )
).toStrictEqual( JSON.parse( responseOrderJson ).shipping );
// Metadata
expect(order.metaData).toHaveLength(1);
expect( order.metaData ).toHaveLength( 1 );
//expect(order.metaData[0]['id']).toStrictEqual(123);
expect(order.metaData[0]['key']).toStrictEqual('Foo Metadata Key 1');
expect(order.metaData[0]['value']).toStrictEqual('Foo Metadata Value 1');
expect( order.metaData[ 0 ].key ).toStrictEqual( 'Foo Metadata Key 1' );
expect( order.metaData[ 0 ].value ).toStrictEqual(
'Foo Metadata Value 1'
);
// Line Items
expect(order.lineItems).toHaveLength(1);
expect(order.lineItems[0]).toBeInstanceOf(OrderLineItem);
expect(order.lineItems[0].id).toStrictEqual(6137);
expect(order.lineItems[0].name).toStrictEqual('Belt');
expect(order.lineItems[0].productId).toStrictEqual(16);
expect(order.lineItems[0].variationId).toStrictEqual(0);
expect(order.lineItems[0].quantity).toStrictEqual(1);
expect(order.lineItems[0].taxClass).toStrictEqual('');
expect(order.lineItems[0].subtotal).toStrictEqual('55.00');
expect(order.lineItems[0].subtotalTax).toStrictEqual('6.60');
expect(order.lineItems[0].total).toStrictEqual('50.00');
expect(order.lineItems[0].totalTax).toStrictEqual('6.00');
expect( order.lineItems ).toHaveLength( 1 );
expect( order.lineItems[ 0 ] ).toBeInstanceOf( OrderLineItem );
expect( order.lineItems[ 0 ].id ).toStrictEqual( 6137 );
expect( order.lineItems[ 0 ].name ).toStrictEqual( 'Belt' );
expect( order.lineItems[ 0 ].productId ).toStrictEqual( 16 );
expect( order.lineItems[ 0 ].variationId ).toStrictEqual( 0 );
expect( order.lineItems[ 0 ].quantity ).toStrictEqual( 1 );
expect( order.lineItems[ 0 ].taxClass ).toStrictEqual( '' );
expect( order.lineItems[ 0 ].subtotal ).toStrictEqual( '55.00' );
expect( order.lineItems[ 0 ].subtotalTax ).toStrictEqual( '6.60' );
expect( order.lineItems[ 0 ].total ).toStrictEqual( '50.00' );
expect( order.lineItems[ 0 ].totalTax ).toStrictEqual( '6.00' );
//expect(order.lineItems[0].taxes).toStrictEqual([ { id: 1, total: '6', subtotal: '6.6' } ]);
expect(order.lineItems[0].metaData).toStrictEqual([]);
expect(order.lineItems[0].sku).toStrictEqual('woo-belt');
expect(order.lineItems[0].price).toStrictEqual(50);
expect(order.lineItems[0].parentName).toStrictEqual(null);
expect( order.lineItems[ 0 ].metaData ).toStrictEqual( [] );
expect( order.lineItems[ 0 ].sku ).toStrictEqual( 'woo-belt' );
expect( order.lineItems[ 0 ].price ).toStrictEqual( 50 );
expect( order.lineItems[ 0 ].parentName ).toStrictEqual( null );
// Tax Lines
expect(order.taxLines).toHaveLength(1);
expect(order.taxLines[0]).toBeInstanceOf(OrderTaxRate);
expect( order.taxLines ).toHaveLength( 1 );
expect( order.taxLines[ 0 ] ).toBeInstanceOf( OrderTaxRate );
//expect(order.taxLines[0].id).toStrictEqual(6139);
expect(order.taxLines[0].rateCode).toStrictEqual('US-TAX-1');
expect(order.taxLines[0].rateId).toStrictEqual(1);
expect(order.taxLines[0].label).toStrictEqual('Tax');
expect( order.taxLines[ 0 ].rateCode ).toStrictEqual( 'US-TAX-1' );
expect( order.taxLines[ 0 ].rateId ).toStrictEqual( 1 );
expect( order.taxLines[ 0 ].label ).toStrictEqual( 'Tax' );
//expect(order.taxLines[0].compound).toStrictEqual(false);
expect(order.taxLines[0].taxTotal).toStrictEqual('6.00');
expect(order.taxLines[0].shippingTaxTotal).toStrictEqual('0.00');
expect(order.taxLines[0].ratePercent).toStrictEqual(12);
expect( order.taxLines[ 0 ].taxTotal ).toStrictEqual( '6.00' );
expect( order.taxLines[ 0 ].shippingTaxTotal ).toStrictEqual( '0.00' );
expect( order.taxLines[ 0 ].ratePercent ).toStrictEqual( 12 );
//expect(order.taxLines[0].metaData).toStrictEqual([]);
// Shipping Lines
expect(order.shippingLines).toHaveLength(1);
expect(order.shippingLines[0]).toBeInstanceOf(OrderShippingLine);
expect( order.shippingLines ).toHaveLength( 1 );
expect( order.shippingLines[ 0 ] ).toBeInstanceOf( OrderShippingLine );
//expect(order.shippingLines[0].id).toStrictEqual(123);
expect(order.shippingLines[0].methodTitle).toStrictEqual('Foo Method Title');
expect(order.shippingLines[0].methodId).toStrictEqual(456);
expect(order.shippingLines[0].total).toStrictEqual('5.00');
expect( order.shippingLines[ 0 ].methodTitle ).toStrictEqual(
'Foo Method Title'
);
expect( order.shippingLines[ 0 ].methodId ).toStrictEqual( 456 );
expect( order.shippingLines[ 0 ].total ).toStrictEqual( '5.00' );
//expect(order.shippingLines[0].totalTaxes).toStrictEqual('5.00');
//expect(order.shippingLines[0].totalTax).toStrictEqual('10.00');
//expect(order.shippingLines[0].taxes).toStrictEqual([ { id: 1, total: '6', subtotal: '6.6' } ]);
expect(order.shippingLines[0].metaData).toStrictEqual([]);
expect( order.shippingLines[ 0 ].metaData ).toStrictEqual( [] );
// Fee Lines
expect(order.feeLines).toHaveLength(1);
expect(order.feeLines[0]).toBeInstanceOf(OrderFeeLine);
expect( order.feeLines ).toHaveLength( 1 );
expect( order.feeLines[ 0 ] ).toBeInstanceOf( OrderFeeLine );
//expect(order.feeLines[0].id).toStrictEqual(123);
expect(order.feeLines[0].name).toStrictEqual('Foo Name');
expect(order.feeLines[0].total).toStrictEqual('5.00');
expect( order.feeLines[ 0 ].name ).toStrictEqual( 'Foo Name' );
expect( order.feeLines[ 0 ].total ).toStrictEqual( '5.00' );
//expect(order.feeLines[0].totalTaxes).toStrictEqual('5.00');
//expect(order.feeLines[0].totalTax).toStrictEqual('10.00');
//expect(order.feeLines[0].taxes).toStrictEqual([ { id: 1, total: '6', subtotal: '6.6' } ]);
expect(order.feeLines[0].metaData).toStrictEqual([]);
expect( order.feeLines[ 0 ].metaData ).toStrictEqual( [] );
// Coupon Lines
expect(order.couponLines).toHaveLength(1);
expect(order.couponLines[0]).toBeInstanceOf(OrderCouponLine);
expect( order.couponLines ).toHaveLength( 1 );
expect( order.couponLines[ 0 ] ).toBeInstanceOf( OrderCouponLine );
//expect(order.couponLines[0].id).toStrictEqual(6138);
expect(order.couponLines[0].code).toStrictEqual('save5');
expect(order.couponLines[0].discount).toStrictEqual('5');
expect(order.couponLines[0].discountTax).toStrictEqual('0.6');
expect(order.couponLines[0].metaData).toHaveLength(1);
expect(order.couponLines[0].metaData[0]).toBeInstanceOf(MetaData);
expect( order.couponLines[ 0 ].code ).toStrictEqual( 'save5' );
expect( order.couponLines[ 0 ].discount ).toStrictEqual( '5' );
expect( order.couponLines[ 0 ].discountTax ).toStrictEqual( '0.6' );
expect( order.couponLines[ 0 ].metaData ).toHaveLength( 1 );
expect( order.couponLines[ 0 ].metaData[ 0 ] ).toBeInstanceOf(
MetaData
);
//expect(order.couponLines[0].metaData[0].id).toStrictEqual(57112);
expect(order.couponLines[0].metaData[0].key).toStrictEqual('coupon_data');
expect(order.couponLines[0].metaData[0].value).toStrictEqual( JSON.parse(responseOrderJson).coupon_lines[0].meta_data[0].value);
expect( order.couponLines[ 0 ].metaData[ 0 ].key ).toStrictEqual(
'coupon_data'
);
expect( order.couponLines[ 0 ].metaData[ 0 ].value ).toStrictEqual(
JSON.parse( responseOrderJson ).coupon_lines[ 0 ].meta_data[ 0 ]
.value
);
// Refunds
expect(order.refunds).toHaveLength(1);
expect(order.refunds[0]).toBeInstanceOf(OrderRefundLine);
expect( order.refunds ).toHaveLength( 1 );
expect( order.refunds[ 0 ] ).toBeInstanceOf( OrderRefundLine );
//expect(order.refunds[0].id).toStrictEqual(123);
expect(order.refunds[0].reason).toStrictEqual('Foo Reason');
expect(order.refunds[0].total).toStrictEqual('5.00');
expect( order.refunds[ 0 ].reason ).toStrictEqual( 'Foo Reason' );
expect( order.refunds[ 0 ].total ).toStrictEqual( '5.00' );
} );
} );

View File

@ -1,7 +1,5 @@
import { HTTPClient } from '../../../http';
import {
ModelRepository,
} from '../../../framework';
import { ModelRepository } from '../../../framework';
import {
ModelID,
Order,
@ -26,22 +24,41 @@ import { createOrderTransformer } from './transformer';
*
* @param {HTTPClient} httpClient The HTTP client for the REST requests to be made using.
*/
export default function orderRESTRepository( httpClient: HTTPClient ): CreatesOrders
& ListsOrders
& ReadsOrders
& UpdatesOrders
& DeletesOrders {
export default function orderRESTRepository(
httpClient: HTTPClient
): CreatesOrders & ListsOrders & ReadsOrders & UpdatesOrders & DeletesOrders {
const buildURL = ( id: ModelID ) => '/wc/v3/orders/' + id;
// Using `?force=true` permanently deletes the order
const buildDeleteUrl = ( id: ModelID ) => `/wc/v3/orders/${ id }?force=true`;
const buildDeleteUrl = ( id: ModelID ) =>
`/wc/v3/orders/${ id }?force=true`;
const transformer = createOrderTransformer();
return new ModelRepository(
restList< OrderRepositoryParams >( () => '/wc/v3/orders', Order, httpClient, transformer ),
restCreate< OrderRepositoryParams >( () => '/wc/v3/orders', Order, httpClient, transformer ),
restRead< OrderRepositoryParams >( buildURL, Order, httpClient, transformer ),
restUpdate< OrderRepositoryParams >( buildURL, Order, httpClient, transformer ),
restDelete< OrderRepositoryParams >( buildDeleteUrl, httpClient ),
restList< OrderRepositoryParams >(
() => '/wc/v3/orders',
Order,
httpClient,
transformer
),
restCreate< OrderRepositoryParams >(
() => '/wc/v3/orders',
Order,
httpClient,
transformer
),
restRead< OrderRepositoryParams >(
buildURL,
Order,
httpClient,
transformer
),
restUpdate< OrderRepositoryParams >(
buildURL,
Order,
httpClient,
transformer
),
restDelete< OrderRepositoryParams >( buildDeleteUrl, httpClient )
);
}

View File

@ -18,7 +18,7 @@ import {
OrderTaxRate,
MetaData,
} from '../../../models';
import {createMetaDataTransformer} from "../shared";
import { createMetaDataTransformer } from '../shared';
/**
* Creates a transformer for an order object.
@ -26,62 +26,92 @@ import {createMetaDataTransformer} from "../shared";
* @return {ModelTransformer} The created transformer.
*/
export function createOrderTransformer(): ModelTransformer< Order > {
return new ModelTransformer(
[
new IgnorePropertyTransformation( [ 'date_created', 'date_modified' ] ),
new ModelTransformerTransformation( 'billing', BillingOrderAddress, createBillingAddressTransformer() ),
new ModelTransformerTransformation( 'shipping', ShippingOrderAddress, createShippingAddressTransformer() ),
new ModelTransformerTransformation( 'taxLines', OrderTaxRate, createOrderTaxRateTransformer() ),
new ModelTransformerTransformation( 'refunds', OrderRefundLine, createOrderRefundLineTransformer() ),
new ModelTransformerTransformation( 'couponLines', OrderCouponLine, createOrdeCouponLineTransformer() ),
new ModelTransformerTransformation( 'feeLines', OrderFeeLine, createOrderFeeLineTransformer() ),
new ModelTransformerTransformation( 'lineItems', OrderLineItem, createOrderLineItemTransformer() ),
new ModelTransformerTransformation( 'shippingLines', OrderShippingLine, createOrderShippingItemTransformer() ),
new ModelTransformerTransformation( 'metaData', MetaData, createMetaDataTransformer() ),
return new ModelTransformer( [
new IgnorePropertyTransformation( [ 'date_created', 'date_modified' ] ),
new ModelTransformerTransformation(
'billing',
BillingOrderAddress,
createBillingAddressTransformer()
),
new ModelTransformerTransformation(
'shipping',
ShippingOrderAddress,
createShippingAddressTransformer()
),
new ModelTransformerTransformation(
'taxLines',
OrderTaxRate,
createOrderTaxRateTransformer()
),
new ModelTransformerTransformation(
'refunds',
OrderRefundLine,
createOrderRefundLineTransformer()
),
new ModelTransformerTransformation(
'couponLines',
OrderCouponLine,
createOrdeCouponLineTransformer()
),
new ModelTransformerTransformation(
'feeLines',
OrderFeeLine,
createOrderFeeLineTransformer()
),
new ModelTransformerTransformation(
'lineItems',
OrderLineItem,
createOrderLineItemTransformer()
),
new ModelTransformerTransformation(
'shippingLines',
OrderShippingLine,
createOrderShippingItemTransformer()
),
new ModelTransformerTransformation(
'metaData',
MetaData,
createMetaDataTransformer()
),
new PropertyTypeTransformation(
{
status: PropertyType.String,
currency: PropertyType.String,
discountTotal: PropertyType.String,
discountTax: PropertyType.String,
shippingTotal: PropertyType.String,
shippingTax: PropertyType.String,
cartTax: PropertyType.String,
total: PropertyType.String,
totalTax: PropertyType.String,
pricesIncludeTax: PropertyType.Boolean,
customerId: PropertyType.Integer,
customerNote: PropertyType.String,
paymentMethod: PropertyType.String,
transactionId: PropertyType.String,
setPaid: PropertyType.Boolean,
},
),
new KeyChangeTransformation< Order >(
{
discountTotal: 'discount_total',
discountTax: 'discount_tax',
shippingTotal: 'shipping_total',
shippingTax: 'shipping_tax',
cartTax: 'cart_tax',
totalTax: 'total_tax',
pricesIncludeTax: 'prices_include_tax',
customerId: 'customer_id',
customerNote: 'customer_note',
paymentMethod: 'payment_method',
transactionId: 'transaction_id',
setPaid: 'set_paid',
lineItems: 'line_items',
taxLines: 'tax_lines',
shippingLines: 'shipping_lines',
feeLines: 'fee_lines',
couponLines: 'coupon_lines',
metaData: 'meta_data',
},
),
],
);
new PropertyTypeTransformation( {
status: PropertyType.String,
currency: PropertyType.String,
discountTotal: PropertyType.String,
discountTax: PropertyType.String,
shippingTotal: PropertyType.String,
shippingTax: PropertyType.String,
cartTax: PropertyType.String,
total: PropertyType.String,
totalTax: PropertyType.String,
pricesIncludeTax: PropertyType.Boolean,
customerId: PropertyType.Integer,
customerNote: PropertyType.String,
paymentMethod: PropertyType.String,
transactionId: PropertyType.String,
setPaid: PropertyType.Boolean,
} ),
new KeyChangeTransformation< Order >( {
discountTotal: 'discount_total',
discountTax: 'discount_tax',
shippingTotal: 'shipping_total',
shippingTax: 'shipping_tax',
cartTax: 'cart_tax',
totalTax: 'total_tax',
pricesIncludeTax: 'prices_include_tax',
customerId: 'customer_id',
customerNote: 'customer_note',
paymentMethod: 'payment_method',
transactionId: 'transaction_id',
setPaid: 'set_paid',
lineItems: 'line_items',
taxLines: 'tax_lines',
shippingLines: 'shipping_lines',
feeLines: 'fee_lines',
couponLines: 'coupon_lines',
metaData: 'meta_data',
} ),
] );
}
/**
@ -90,34 +120,28 @@ export function createOrderTransformer(): ModelTransformer< Order > {
* @return {ModelTransformer} The created transformer.
*/
export function createBillingAddressTransformer(): ModelTransformer< BillingOrderAddress > {
return new ModelTransformer(
[
new PropertyTypeTransformation(
{
firstName: PropertyType.String,
lastName: PropertyType.String,
company: PropertyType.String,
address1: PropertyType.String,
address2: PropertyType.String,
city: PropertyType.String,
state: PropertyType.String,
postCode: PropertyType.String,
country: PropertyType.String,
phone: PropertyType.String,
email: PropertyType.String,
},
),
new KeyChangeTransformation< BillingOrderAddress >(
{
firstName: 'first_name',
lastName: 'last_name',
address1: 'address_1',
address2: 'address_2',
postCode: 'postcode',
},
),
],
);
return new ModelTransformer( [
new PropertyTypeTransformation( {
firstName: PropertyType.String,
lastName: PropertyType.String,
company: PropertyType.String,
address1: PropertyType.String,
address2: PropertyType.String,
city: PropertyType.String,
state: PropertyType.String,
postCode: PropertyType.String,
country: PropertyType.String,
phone: PropertyType.String,
email: PropertyType.String,
} ),
new KeyChangeTransformation< BillingOrderAddress >( {
firstName: 'first_name',
lastName: 'last_name',
address1: 'address_1',
address2: 'address_2',
postCode: 'postcode',
} ),
] );
}
/**
@ -126,32 +150,26 @@ export function createBillingAddressTransformer(): ModelTransformer< BillingOrde
* @return {ModelTransformer} The created transformer.
*/
export function createShippingAddressTransformer(): ModelTransformer< ShippingOrderAddress > {
return new ModelTransformer(
[
new PropertyTypeTransformation(
{
firstName: PropertyType.String,
lastName: PropertyType.String,
company: PropertyType.String,
address1: PropertyType.String,
address2: PropertyType.String,
city: PropertyType.String,
state: PropertyType.String,
postCode: PropertyType.String,
country: PropertyType.String
},
),
new KeyChangeTransformation< ShippingOrderAddress >(
{
firstName: 'first_name',
lastName: 'last_name',
address1: 'address_1',
address2: 'address_2',
postCode: 'postcode',
},
),
],
);
return new ModelTransformer( [
new PropertyTypeTransformation( {
firstName: PropertyType.String,
lastName: PropertyType.String,
company: PropertyType.String,
address1: PropertyType.String,
address2: PropertyType.String,
city: PropertyType.String,
state: PropertyType.String,
postCode: PropertyType.String,
country: PropertyType.String,
} ),
new KeyChangeTransformation< ShippingOrderAddress >( {
firstName: 'first_name',
lastName: 'last_name',
address1: 'address_1',
address2: 'address_2',
postCode: 'postcode',
} ),
] );
}
/**
@ -160,31 +178,25 @@ export function createShippingAddressTransformer(): ModelTransformer< ShippingOr
* @return {ModelTransformer} The created transformer.
*/
function createOrderTaxRateTransformer(): ModelTransformer< OrderTaxRate > {
return new ModelTransformer(
[
new PropertyTypeTransformation(
{
rateCode: PropertyType.String,
rateId: PropertyType.Integer,
label: PropertyType.String,
compoundRate: PropertyType.Boolean,
taxTotal: PropertyType.String,
shippingTaxTotal: PropertyType.String,
ratePercent: PropertyType.Integer,
},
),
new KeyChangeTransformation< OrderTaxRate >(
{
rateCode: 'rate_code',
ratePercent: 'rate_percent',
rateId: 'rate_id',
compoundRate: 'compound',
taxTotal: 'tax_total',
shippingTaxTotal: 'shipping_tax_total',
},
),
],
);
return new ModelTransformer( [
new PropertyTypeTransformation( {
rateCode: PropertyType.String,
rateId: PropertyType.Integer,
label: PropertyType.String,
compoundRate: PropertyType.Boolean,
taxTotal: PropertyType.String,
shippingTaxTotal: PropertyType.String,
ratePercent: PropertyType.Integer,
} ),
new KeyChangeTransformation< OrderTaxRate >( {
rateCode: 'rate_code',
ratePercent: 'rate_percent',
rateId: 'rate_id',
compoundRate: 'compound',
taxTotal: 'tax_total',
shippingTaxTotal: 'shipping_tax_total',
} ),
] );
}
/**
@ -193,16 +205,12 @@ function createOrderTaxRateTransformer(): ModelTransformer< OrderTaxRate > {
* @return {ModelTransformer} The created transformer.
*/
function createOrderRefundLineTransformer(): ModelTransformer< OrderRefundLine > {
return new ModelTransformer(
[
new PropertyTypeTransformation(
{
reason: PropertyType.String,
total: PropertyType.String,
},
),
],
);
return new ModelTransformer( [
new PropertyTypeTransformation( {
reason: PropertyType.String,
total: PropertyType.String,
} ),
] );
}
/**
@ -211,24 +219,22 @@ function createOrderRefundLineTransformer(): ModelTransformer< OrderRefundLine >
* @return {ModelTransformer} The created transformer.
*/
function createOrdeCouponLineTransformer(): ModelTransformer< OrderCouponLine > {
return new ModelTransformer(
[
new ModelTransformerTransformation( 'metaData', MetaData, createMetaDataTransformer() ),
new PropertyTypeTransformation(
{
code: PropertyType.String,
discount: PropertyType.String,
discountTax: PropertyType.String,
},
),
new KeyChangeTransformation< OrderCouponLine >(
{
discountTax: 'discount_tax',
metaData: 'meta_data'
},
),
],
);
return new ModelTransformer( [
new ModelTransformerTransformation(
'metaData',
MetaData,
createMetaDataTransformer()
),
new PropertyTypeTransformation( {
code: PropertyType.String,
discount: PropertyType.String,
discountTax: PropertyType.String,
} ),
new KeyChangeTransformation< OrderCouponLine >( {
discountTax: 'discount_tax',
metaData: 'meta_data',
} ),
] );
}
/**
@ -237,27 +243,25 @@ function createOrdeCouponLineTransformer(): ModelTransformer< OrderCouponLine >
* @return {ModelTransformer} The created transformer.
*/
function createOrderFeeLineTransformer(): ModelTransformer< OrderFeeLine > {
return new ModelTransformer(
[
new ModelTransformerTransformation( 'taxes', OrderTaxRate, createOrderTaxRateTransformer() ),
new PropertyTypeTransformation(
{
name: PropertyType.String,
taxClass: PropertyType.String,
taxStatus: PropertyType.String,
total: PropertyType.String,
totalTax: PropertyType.String,
},
),
new KeyChangeTransformation< OrderFeeLine >(
{
taxClass: 'tax_class',
taxStatus: 'tax_status',
totalTax: 'total_tax',
},
),
],
);
return new ModelTransformer( [
new ModelTransformerTransformation(
'taxes',
OrderTaxRate,
createOrderTaxRateTransformer()
),
new PropertyTypeTransformation( {
name: PropertyType.String,
taxClass: PropertyType.String,
taxStatus: PropertyType.String,
total: PropertyType.String,
totalTax: PropertyType.String,
} ),
new KeyChangeTransformation< OrderFeeLine >( {
taxClass: 'tax_class',
taxStatus: 'tax_status',
totalTax: 'total_tax',
} ),
] );
}
/**
@ -266,36 +270,34 @@ function createOrderFeeLineTransformer(): ModelTransformer< OrderFeeLine > {
* @return {ModelTransformer} The created transformer.
*/
function createOrderLineItemTransformer(): ModelTransformer< OrderLineItem > {
return new ModelTransformer(
[
new ModelTransformerTransformation( 'taxes', OrderTaxRate, createOrderTaxRateTransformer() ),
new PropertyTypeTransformation(
{
name: PropertyType.String,
productId: PropertyType.Integer,
variationId: PropertyType.Integer,
quantity: PropertyType.Integer,
taxClass: PropertyType.String,
subtotal: PropertyType.String,
subtotalTax: PropertyType.String,
total: PropertyType.String,
totalTax: PropertyType.String,
sku: PropertyType.String,
price: PropertyType.Integer,
parentName: PropertyType.String,
},
),
new KeyChangeTransformation< OrderLineItem >(
{
productId: 'product_id',
variationId: 'variation_id',
taxClass: 'tax_class',
subtotalTax: 'subtotal_tax',
totalTax: 'total_tax',
},
),
],
);
return new ModelTransformer( [
new ModelTransformerTransformation(
'taxes',
OrderTaxRate,
createOrderTaxRateTransformer()
),
new PropertyTypeTransformation( {
name: PropertyType.String,
productId: PropertyType.Integer,
variationId: PropertyType.Integer,
quantity: PropertyType.Integer,
taxClass: PropertyType.String,
subtotal: PropertyType.String,
subtotalTax: PropertyType.String,
total: PropertyType.String,
totalTax: PropertyType.String,
sku: PropertyType.String,
price: PropertyType.Integer,
parentName: PropertyType.String,
} ),
new KeyChangeTransformation< OrderLineItem >( {
productId: 'product_id',
variationId: 'variation_id',
taxClass: 'tax_class',
subtotalTax: 'subtotal_tax',
totalTax: 'total_tax',
} ),
] );
}
/**
@ -304,24 +306,22 @@ function createOrderLineItemTransformer(): ModelTransformer< OrderLineItem > {
* @return {ModelTransformer} The created transformer.
*/
function createOrderShippingItemTransformer(): ModelTransformer< OrderShippingLine > {
return new ModelTransformer(
[
new ModelTransformerTransformation( 'taxes', OrderTaxRate, createOrderTaxRateTransformer() ),
new PropertyTypeTransformation(
{
methodTitle: PropertyType.String,
methodId: PropertyType.Integer,
total: PropertyType.String,
totalTax: PropertyType.String,
},
),
new KeyChangeTransformation< OrderShippingLine >(
{
methodTitle: 'method_title',
methodId: 'method_id',
totalTax: 'total_tax',
},
),
],
);
return new ModelTransformer( [
new ModelTransformerTransformation(
'taxes',
OrderTaxRate,
createOrderTaxRateTransformer()
),
new PropertyTypeTransformation( {
methodTitle: PropertyType.String,
methodId: PropertyType.Integer,
total: PropertyType.String,
totalTax: PropertyType.String,
} ),
new KeyChangeTransformation< OrderShippingLine >( {
methodTitle: 'method_title',
methodId: 'method_id',
totalTax: 'total_tax',
} ),
] );
}

View File

@ -39,29 +39,52 @@ import {
* DeletesExternalProducts
* } The created repository.
*/
export function externalProductRESTRepository( httpClient: HTTPClient ): ListsExternalProducts
& CreatesExternalProducts
& ReadsExternalProducts
& UpdatesExternalProducts
& DeletesExternalProducts {
export function externalProductRESTRepository(
httpClient: HTTPClient
): ListsExternalProducts &
CreatesExternalProducts &
ReadsExternalProducts &
UpdatesExternalProducts &
DeletesExternalProducts {
const external = createProductExternalTransformation();
const price = createProductPriceTransformation();
const salesTax = createProductSalesTaxTransformation();
const upsells = createProductUpSellsTransformation();
const transformations = [
...external,
...price,
...salesTax,
...upsells,
];
const transformations = [ ...external, ...price, ...salesTax, ...upsells ];
const transformer = createProductTransformer<ExternalProduct>( 'external', transformations );
const transformer = createProductTransformer< ExternalProduct >(
'external',
transformations
);
return new ModelRepository(
restList< ExternalProductRepositoryParams >( baseProductURL, ExternalProduct, httpClient, transformer ),
restCreate< ExternalProductRepositoryParams >( baseProductURL, ExternalProduct, httpClient, transformer ),
restRead< ExternalProductRepositoryParams >( buildProductURL, ExternalProduct, httpClient, transformer ),
restUpdate< ExternalProductRepositoryParams >( buildProductURL, ExternalProduct, httpClient, transformer ),
restDelete< ExternalProductRepositoryParams >( deleteProductURL, httpClient ),
restList< ExternalProductRepositoryParams >(
baseProductURL,
ExternalProduct,
httpClient,
transformer
),
restCreate< ExternalProductRepositoryParams >(
baseProductURL,
ExternalProduct,
httpClient,
transformer
),
restRead< ExternalProductRepositoryParams >(
buildProductURL,
ExternalProduct,
httpClient,
transformer
),
restUpdate< ExternalProductRepositoryParams >(
buildProductURL,
ExternalProduct,
httpClient,
transformer
),
restDelete< ExternalProductRepositoryParams >(
deleteProductURL,
httpClient
)
);
}

View File

@ -37,25 +37,50 @@ import {
* DeletesGroupedProducts
* } The created repository.
*/
export function groupedProductRESTRepository( httpClient: HTTPClient ): ListsGroupedProducts
& CreatesGroupedProducts
& ReadsGroupedProducts
& UpdatesGroupedProducts
& DeletesGroupedProducts {
export function groupedProductRESTRepository(
httpClient: HTTPClient
): ListsGroupedProducts &
CreatesGroupedProducts &
ReadsGroupedProducts &
UpdatesGroupedProducts &
DeletesGroupedProducts {
const upsells = createProductUpSellsTransformation();
const grouped = createProductGroupedTransformation();
const transformations = [
...upsells,
...grouped,
];
const transformations = [ ...upsells, ...grouped ];
const transformer = createProductTransformer<GroupedProduct>( 'grouped', transformations );
const transformer = createProductTransformer< GroupedProduct >(
'grouped',
transformations
);
return new ModelRepository(
restList< GroupedProductRepositoryParams >( baseProductURL, GroupedProduct, httpClient, transformer ),
restCreate< GroupedProductRepositoryParams >( baseProductURL, GroupedProduct, httpClient, transformer ),
restRead< GroupedProductRepositoryParams >( buildProductURL, GroupedProduct, httpClient, transformer ),
restUpdate< GroupedProductRepositoryParams >( buildProductURL, GroupedProduct, httpClient, transformer ),
restDelete< GroupedProductRepositoryParams >( deleteProductURL, httpClient ),
restList< GroupedProductRepositoryParams >(
baseProductURL,
GroupedProduct,
httpClient,
transformer
),
restCreate< GroupedProductRepositoryParams >(
baseProductURL,
GroupedProduct,
httpClient,
transformer
),
restRead< GroupedProductRepositoryParams >(
buildProductURL,
GroupedProduct,
httpClient,
transformer
),
restUpdate< GroupedProductRepositoryParams >(
buildProductURL,
GroupedProduct,
httpClient,
transformer
),
restDelete< GroupedProductRepositoryParams >(
deleteProductURL,
httpClient
)
);
}

View File

@ -37,11 +37,9 @@ import { createMetaDataTransformer } from '../shared';
* @return {ModelTransformer} The created transformer.
*/
function createProductTermTransformer(): ModelTransformer< ProductTerm > {
return new ModelTransformer(
[
new PropertyTypeTransformation( { id: PropertyType.Integer } ),
],
);
return new ModelTransformer( [
new PropertyTypeTransformation( { id: PropertyType.Integer } ),
] );
}
/**
@ -50,25 +48,19 @@ function createProductTermTransformer(): ModelTransformer< ProductTerm > {
* @return {ModelTransformer} The created transformer.
*/
function createProductAttributeTransformer(): ModelTransformer< ProductAttribute > {
return new ModelTransformer(
[
new PropertyTypeTransformation(
{
id: PropertyType.Integer,
sortOrder: PropertyType.Integer,
isVisibleOnProductPage: PropertyType.Boolean,
isForVariations: PropertyType.Boolean,
},
),
new KeyChangeTransformation< ProductAttribute >(
{
sortOrder: 'position',
isVisibleOnProductPage: 'visible',
isForVariations: 'variation',
},
),
],
);
return new ModelTransformer( [
new PropertyTypeTransformation( {
id: PropertyType.Integer,
sortOrder: PropertyType.Integer,
isVisibleOnProductPage: PropertyType.Boolean,
isForVariations: PropertyType.Boolean,
} ),
new KeyChangeTransformation< ProductAttribute >( {
sortOrder: 'position',
isVisibleOnProductPage: 'visible',
isForVariations: 'variation',
} ),
] );
}
/**
@ -77,26 +69,20 @@ function createProductAttributeTransformer(): ModelTransformer< ProductAttribute
* @return {ModelTransformer} The created transformer.
*/
function createProductImageTransformer(): ModelTransformer< ProductImage > {
return new ModelTransformer(
[
new IgnorePropertyTransformation( [ 'date_created', 'date_modified' ] ),
new PropertyTypeTransformation(
{
id: PropertyType.Integer,
created: PropertyType.Date,
modified: PropertyType.Date,
},
),
new KeyChangeTransformation< ProductImage >(
{
created: 'date_created_gmt',
modified: 'date_modified_gmt',
url: 'src',
altText: 'altText',
},
),
],
);
return new ModelTransformer( [
new IgnorePropertyTransformation( [ 'date_created', 'date_modified' ] ),
new PropertyTypeTransformation( {
id: PropertyType.Integer,
created: PropertyType.Date,
modified: PropertyType.Date,
} ),
new KeyChangeTransformation< ProductImage >( {
created: 'date_created_gmt',
modified: 'date_modified_gmt',
url: 'src',
altText: 'altText',
} ),
] );
}
/**
@ -105,11 +91,9 @@ function createProductImageTransformer(): ModelTransformer< ProductImage > {
* @return {ModelTransformer} The created transformer.
*/
function createProductDownloadTransformer(): ModelTransformer< ProductDownload > {
return new ModelTransformer(
[
new KeyChangeTransformation< ProductDownload >( { url: 'file' } ),
],
);
return new ModelTransformer( [
new KeyChangeTransformation< ProductDownload >( { url: 'file' } ),
] );
}
/**
@ -119,43 +103,42 @@ function createProductDownloadTransformer(): ModelTransformer< ProductDownload >
* @return {ModelTransformer} The created transformer.
*/
export function createProductDataTransformer< T extends AbstractProductData >(
transformations?: ModelTransformation[],
transformations?: ModelTransformation[]
): ModelTransformer< T > {
if ( ! transformations ) {
transformations = [];
}
transformations.push(
new IgnorePropertyTransformation(
[
'date_created',
'date_modified',
],
new IgnorePropertyTransformation( [ 'date_created', 'date_modified' ] ),
new ModelTransformerTransformation(
'images',
ProductImage,
createProductImageTransformer()
),
new ModelTransformerTransformation( 'images', ProductImage, createProductImageTransformer() ),
new ModelTransformerTransformation( 'metaData', MetaData, createMetaDataTransformer() ),
new PropertyTypeTransformation(
{
created: PropertyType.Date,
modified: PropertyType.Date,
isPurchasable: PropertyType.Boolean,
parentId: PropertyType.Integer,
menuOrder: PropertyType.Integer,
permalink: PropertyType.String,
},
),
new KeyChangeTransformation< AbstractProductData >(
{
created: 'date_created_gmt',
modified: 'date_modified_gmt',
postStatus: 'status',
isPurchasable: 'purchasable',
metaData: 'meta_data',
parentId: 'parent_id',
menuOrder: 'menu_order',
links: '_links',
},
new ModelTransformerTransformation(
'metaData',
MetaData,
createMetaDataTransformer()
),
new PropertyTypeTransformation( {
created: PropertyType.Date,
modified: PropertyType.Date,
isPurchasable: PropertyType.Boolean,
parentId: PropertyType.Integer,
menuOrder: PropertyType.Integer,
permalink: PropertyType.String,
} ),
new KeyChangeTransformation< AbstractProductData >( {
created: 'date_created_gmt',
modified: 'date_modified_gmt',
postStatus: 'status',
isPurchasable: 'purchasable',
metaData: 'meta_data',
parentId: 'parent_id',
menuOrder: 'menu_order',
links: '_links',
} )
);
return new ModelTransformer( transformations );
@ -170,7 +153,7 @@ export function createProductDataTransformer< T extends AbstractProductData >(
*/
export function createProductTransformer< T extends AbstractProduct >(
type: string,
transformations?: ModelTransformation[],
transformations?: ModelTransformation[]
): ModelTransformer< T > {
if ( ! transformations ) {
transformations = [];
@ -178,31 +161,39 @@ export function createProductTransformer< T extends AbstractProduct >(
transformations.push(
new AddPropertyTransformation( {}, { type } ),
new ModelTransformerTransformation( 'categories', ProductTerm, createProductTermTransformer() ),
new ModelTransformerTransformation( 'tags', ProductTerm, createProductTermTransformer() ),
new ModelTransformerTransformation( 'attributes', ProductAttribute, createProductAttributeTransformer() ),
new PropertyTypeTransformation(
{
isFeatured: PropertyType.Boolean,
allowReviews: PropertyType.Boolean,
averageRating: PropertyType.Integer,
numRatings: PropertyType.Integer,
totalSales: PropertyType.Integer,
relatedIds: PropertyType.Integer,
},
new ModelTransformerTransformation(
'categories',
ProductTerm,
createProductTermTransformer()
),
new KeyChangeTransformation< AbstractProduct >(
{
shortDescription: 'short_description',
isFeatured: 'featured',
catalogVisibility: 'catalog_visibility',
allowReviews: 'reviews_allowed',
averageRating: 'average_rating',
numRatings: 'rating_count',
totalSales: 'total_sales',
relatedIds: 'related_ids',
},
new ModelTransformerTransformation(
'tags',
ProductTerm,
createProductTermTransformer()
),
new ModelTransformerTransformation(
'attributes',
ProductAttribute,
createProductAttributeTransformer()
),
new PropertyTypeTransformation( {
isFeatured: PropertyType.Boolean,
allowReviews: PropertyType.Boolean,
averageRating: PropertyType.Integer,
numRatings: PropertyType.Integer,
totalSales: PropertyType.Integer,
relatedIds: PropertyType.Integer,
} ),
new KeyChangeTransformation< AbstractProduct >( {
shortDescription: 'short_description',
isFeatured: 'featured',
catalogVisibility: 'catalog_visibility',
allowReviews: 'reviews_allowed',
averageRating: 'average_rating',
numRatings: 'rating_count',
totalSales: 'total_sales',
relatedIds: 'related_ids',
} )
);
return createProductDataTransformer< T >( transformations );
@ -213,30 +204,24 @@ export function createProductTransformer< T extends AbstractProduct >(
*/
export function createProductPriceTransformation(): ModelTransformation[] {
const transformations = [
new IgnorePropertyTransformation(
[
'date_on_sale_from',
'date_on_sale_to',
],
),
new PropertyTypeTransformation(
{
onSale: PropertyType.Boolean,
saleStart: PropertyType.Date,
saleEnd: PropertyType.Date,
priceHtml: PropertyType.String,
},
),
new KeyChangeTransformation< IProductPrice >(
{
regularPrice: 'regular_price',
onSale: 'on_sale',
salePrice: 'sale_price',
saleStart: 'date_on_sale_from_gmt',
saleEnd: 'date_on_sale_to_gmt',
priceHtml: 'price_html',
},
),
new IgnorePropertyTransformation( [
'date_on_sale_from',
'date_on_sale_to',
] ),
new PropertyTypeTransformation( {
onSale: PropertyType.Boolean,
saleStart: PropertyType.Date,
saleEnd: PropertyType.Date,
priceHtml: PropertyType.String,
} ),
new KeyChangeTransformation< IProductPrice >( {
regularPrice: 'regular_price',
onSale: 'on_sale',
salePrice: 'sale_price',
saleStart: 'date_on_sale_from_gmt',
saleEnd: 'date_on_sale_to_gmt',
priceHtml: 'price_html',
} ),
];
return transformations;
@ -247,16 +232,12 @@ export function createProductPriceTransformation(): ModelTransformation[] {
*/
export function createProductCrossSellsTransformation(): ModelTransformation[] {
const transformations = [
new PropertyTypeTransformation(
{
crossSellIds: PropertyType.Integer,
},
),
new KeyChangeTransformation< IProductCrossSells >(
{
crossSellIds: 'cross_sell_ids',
},
),
new PropertyTypeTransformation( {
crossSellIds: PropertyType.Integer,
} ),
new KeyChangeTransformation< IProductCrossSells >( {
crossSellIds: 'cross_sell_ids',
} ),
];
return transformations;
@ -267,16 +248,12 @@ export function createProductCrossSellsTransformation(): ModelTransformation[] {
*/
export function createProductUpSellsTransformation(): ModelTransformation[] {
const transformations = [
new PropertyTypeTransformation(
{
upSellIds: PropertyType.Integer,
},
),
new KeyChangeTransformation< IProductUpSells >(
{
upSellIds: 'upsell_ids',
},
),
new PropertyTypeTransformation( {
upSellIds: PropertyType.Integer,
} ),
new KeyChangeTransformation< IProductUpSells >( {
upSellIds: 'upsell_ids',
} ),
];
return transformations;
@ -287,16 +264,12 @@ export function createProductUpSellsTransformation(): ModelTransformation[] {
*/
export function createProductGroupedTransformation(): ModelTransformation[] {
const transformations = [
new PropertyTypeTransformation(
{
groupedProducts: PropertyType.Integer,
},
),
new KeyChangeTransformation< IProductGrouped >(
{
groupedProducts: 'grouped_products',
},
),
new PropertyTypeTransformation( {
groupedProducts: PropertyType.Integer,
} ),
new KeyChangeTransformation< IProductGrouped >( {
groupedProducts: 'grouped_products',
} ),
];
return transformations;
@ -307,25 +280,25 @@ export function createProductGroupedTransformation(): ModelTransformation[] {
*/
export function createProductDeliveryTransformation(): ModelTransformation[] {
const transformations = [
new ModelTransformerTransformation( 'downloads', ProductDownload, createProductDownloadTransformer() ),
new PropertyTypeTransformation(
{
isVirtual: PropertyType.Boolean,
isDownloadable: PropertyType.Boolean,
downloadLimit: PropertyType.Integer,
daysToDownload: PropertyType.Integer,
purchaseNote: PropertyType.String,
},
),
new KeyChangeTransformation< IProductDelivery >(
{
isVirtual: 'virtual',
isDownloadable: 'downloadable',
downloadLimit: 'download_limit',
daysToDownload: 'download_expiry',
purchaseNote: 'purchase_note',
},
new ModelTransformerTransformation(
'downloads',
ProductDownload,
createProductDownloadTransformer()
),
new PropertyTypeTransformation( {
isVirtual: PropertyType.Boolean,
isDownloadable: PropertyType.Boolean,
downloadLimit: PropertyType.Integer,
daysToDownload: PropertyType.Integer,
purchaseNote: PropertyType.String,
} ),
new KeyChangeTransformation< IProductDelivery >( {
isVirtual: 'virtual',
isDownloadable: 'downloadable',
downloadLimit: 'download_limit',
daysToDownload: 'download_expiry',
purchaseNote: 'purchase_note',
} ),
];
return transformations;
@ -336,30 +309,26 @@ export function createProductDeliveryTransformation(): ModelTransformation[] {
*/
export function createProductInventoryTransformation(): ModelTransformation[] {
const transformations = [
new PropertyTypeTransformation(
{
trackInventory: PropertyType.Boolean,
remainingStock: PropertyType.Integer,
canBackorder: PropertyType.Boolean,
isOnBackorder: PropertyType.Boolean,
onePerOrder: PropertyType.Boolean,
stockStatus: PropertyType.String,
backOrderStatus: PropertyType.String,
lowStockThreshold: PropertyType.Integer,
},
),
new KeyChangeTransformation< IProductInventory >(
{
trackInventory: 'manage_stock',
remainingStock: 'stock_quantity',
stockStatus: 'stock_status',
onePerOrder: 'sold_individually',
backorderStatus: 'backorders',
canBackorder: 'backorders_allowed',
isOnBackorder: 'backordered',
lowStockThreshold: 'low_stock_amount',
},
),
new PropertyTypeTransformation( {
trackInventory: PropertyType.Boolean,
remainingStock: PropertyType.Integer,
canBackorder: PropertyType.Boolean,
isOnBackorder: PropertyType.Boolean,
onePerOrder: PropertyType.Boolean,
stockStatus: PropertyType.String,
backOrderStatus: PropertyType.String,
lowStockThreshold: PropertyType.Integer,
} ),
new KeyChangeTransformation< IProductInventory >( {
trackInventory: 'manage_stock',
remainingStock: 'stock_quantity',
stockStatus: 'stock_status',
onePerOrder: 'sold_individually',
backorderStatus: 'backorders',
canBackorder: 'backorders_allowed',
isOnBackorder: 'backordered',
lowStockThreshold: 'low_stock_amount',
} ),
];
return transformations;
@ -370,18 +339,14 @@ export function createProductInventoryTransformation(): ModelTransformation[] {
*/
export function createProductSalesTaxTransformation(): ModelTransformation[] {
const transformations = [
new PropertyTypeTransformation(
{
taxClass: PropertyType.String,
taxStatus: PropertyType.String,
},
),
new KeyChangeTransformation< IProductSalesTax >(
{
taxStatus: 'tax_status',
taxClass: 'tax_class',
},
),
new PropertyTypeTransformation( {
taxClass: PropertyType.String,
taxStatus: PropertyType.String,
} ),
new KeyChangeTransformation< IProductSalesTax >( {
taxStatus: 'tax_status',
taxClass: 'tax_class',
} ),
];
return transformations;
@ -405,9 +370,11 @@ export function createProductShippingTransformation(): ModelTransformation[] {
return properties;
},
( properties: any ) => {
if ( properties.hasOwnProperty( 'length ' ) ||
if (
properties.hasOwnProperty( 'length ' ) ||
properties.hasOwnProperty( 'width' ) ||
properties.hasOwnProperty( 'height' ) ) {
properties.hasOwnProperty( 'height' )
) {
properties.dimensions = {
length: properties.length,
width: properties.width,
@ -419,25 +386,21 @@ export function createProductShippingTransformation(): ModelTransformation[] {
}
return properties;
},
),
new PropertyTypeTransformation(
{
requiresShipping: PropertyType.Boolean,
isShippingTaxable: PropertyType.Boolean,
shippingClass: PropertyType.String,
shippingClassId: PropertyType.Integer,
weight: PropertyType.String,
},
),
new KeyChangeTransformation< IProductShipping >(
{
requiresShipping: 'shipping_required',
isShippingTaxable: 'shipping_taxable',
shippingClass: 'shipping_class',
shippingClassId: 'shipping_class_id',
},
}
),
new PropertyTypeTransformation( {
requiresShipping: PropertyType.Boolean,
isShippingTaxable: PropertyType.Boolean,
shippingClass: PropertyType.String,
shippingClassId: PropertyType.Integer,
weight: PropertyType.String,
} ),
new KeyChangeTransformation< IProductShipping >( {
requiresShipping: 'shipping_required',
isShippingTaxable: 'shipping_taxable',
shippingClass: 'shipping_class',
shippingClassId: 'shipping_class_id',
} ),
];
return transformations;
@ -448,19 +411,15 @@ export function createProductShippingTransformation(): ModelTransformation[] {
*/
export function createProductVariableTransformation(): ModelTransformation[] {
const transformations = [
new PropertyTypeTransformation(
{
id: PropertyType.Integer,
name: PropertyType.String,
option: PropertyType.String,
variations: PropertyType.Integer,
},
),
new KeyChangeTransformation< VariableProduct >(
{
defaultAttributes: 'default_attributes',
},
),
new PropertyTypeTransformation( {
id: PropertyType.Integer,
name: PropertyType.String,
option: PropertyType.String,
variations: PropertyType.Integer,
} ),
new KeyChangeTransformation< VariableProduct >( {
defaultAttributes: 'default_attributes',
} ),
];
return transformations;
@ -471,18 +430,14 @@ export function createProductVariableTransformation(): ModelTransformation[] {
*/
export function createProductExternalTransformation(): ModelTransformation[] {
const transformations = [
new PropertyTypeTransformation(
{
buttonText: PropertyType.String,
externalUrl: PropertyType.String,
},
),
new KeyChangeTransformation< IProductExternal >(
{
buttonText: 'button_text',
externalUrl: 'external_url',
},
),
new PropertyTypeTransformation( {
buttonText: PropertyType.String,
externalUrl: PropertyType.String,
} ),
new KeyChangeTransformation< IProductExternal >( {
buttonText: 'button_text',
externalUrl: 'external_url',
} ),
];
return transformations;

View File

@ -42,11 +42,13 @@ import {
* DeletesSimpleProducts
* } The created repository.
*/
export function simpleProductRESTRepository( httpClient: HTTPClient ): ListsSimpleProducts
& CreatesSimpleProducts
& ReadsSimpleProducts
& UpdatesSimpleProducts
& DeletesSimpleProducts {
export function simpleProductRESTRepository(
httpClient: HTTPClient
): ListsSimpleProducts &
CreatesSimpleProducts &
ReadsSimpleProducts &
UpdatesSimpleProducts &
DeletesSimpleProducts {
const crossSells = createProductCrossSellsTransformation();
const delivery = createProductDeliveryTransformation();
const inventory = createProductInventoryTransformation();
@ -64,13 +66,39 @@ export function simpleProductRESTRepository( httpClient: HTTPClient ): ListsSimp
...upsells,
];
const transformer = createProductTransformer<SimpleProduct>( 'simple', transformations );
const transformer = createProductTransformer< SimpleProduct >(
'simple',
transformations
);
return new ModelRepository(
restList< SimpleProductRepositoryParams >( baseProductURL, SimpleProduct, httpClient, transformer ),
restCreate< SimpleProductRepositoryParams >( baseProductURL, SimpleProduct, httpClient, transformer ),
restRead< SimpleProductRepositoryParams >( buildProductURL, SimpleProduct, httpClient, transformer ),
restUpdate< SimpleProductRepositoryParams >( buildProductURL, SimpleProduct, httpClient, transformer ),
restDelete< SimpleProductRepositoryParams >( deleteProductURL, httpClient ),
restList< SimpleProductRepositoryParams >(
baseProductURL,
SimpleProduct,
httpClient,
transformer
),
restCreate< SimpleProductRepositoryParams >(
baseProductURL,
SimpleProduct,
httpClient,
transformer
),
restRead< SimpleProductRepositoryParams >(
buildProductURL,
SimpleProduct,
httpClient,
transformer
),
restUpdate< SimpleProductRepositoryParams >(
buildProductURL,
SimpleProduct,
httpClient,
transformer
),
restDelete< SimpleProductRepositoryParams >(
deleteProductURL,
httpClient
)
);
}

View File

@ -41,11 +41,13 @@ import {
* DeletesVariableProducts
* } The created repository.
*/
export function variableProductRESTRepository( httpClient: HTTPClient ): ListsVariableProducts
& CreatesVariableProducts
& ReadsVariableProducts
& UpdatesVariableProducts
& DeletesVariableProducts {
export function variableProductRESTRepository(
httpClient: HTTPClient
): ListsVariableProducts &
CreatesVariableProducts &
ReadsVariableProducts &
UpdatesVariableProducts &
DeletesVariableProducts {
const crossSells = createProductCrossSellsTransformation();
const inventory = createProductInventoryTransformation();
const salesTax = createProductSalesTaxTransformation();
@ -61,13 +63,39 @@ export function variableProductRESTRepository( httpClient: HTTPClient ): ListsVa
...variable,
];
const transformer = createProductTransformer<VariableProduct>( 'variable', transformations );
const transformer = createProductTransformer< VariableProduct >(
'variable',
transformations
);
return new ModelRepository(
restList< VariableProductRepositoryParams >( baseProductURL, VariableProduct, httpClient, transformer ),
restCreate< VariableProductRepositoryParams >( baseProductURL, VariableProduct, httpClient, transformer ),
restRead< VariableProductRepositoryParams >( buildProductURL, VariableProduct, httpClient, transformer ),
restUpdate< VariableProductRepositoryParams >( buildProductURL, VariableProduct, httpClient, transformer ),
restDelete< VariableProductRepositoryParams >( deleteProductURL, httpClient ),
restList< VariableProductRepositoryParams >(
baseProductURL,
VariableProduct,
httpClient,
transformer
),
restCreate< VariableProductRepositoryParams >(
baseProductURL,
VariableProduct,
httpClient,
transformer
),
restRead< VariableProductRepositoryParams >(
buildProductURL,
VariableProduct,
httpClient,
transformer
),
restUpdate< VariableProductRepositoryParams >(
buildProductURL,
VariableProduct,
httpClient,
transformer
),
restDelete< VariableProductRepositoryParams >(
deleteProductURL,
httpClient
)
);
}

View File

@ -39,14 +39,19 @@ import {
* DeletesProductVariations
* } The created repository.
*/
export function productVariationRESTRepository( httpClient: HTTPClient ): ListsProductVariations
& CreatesProductVariations
& ReadsProductVariations
& UpdatesProductVariations
& DeletesProductVariations {
const buildURL = ( parent: ModelID ) => buildProductURL( parent ) + '/variations/';
const buildChildURL = ( parent: ModelID, id: ModelID ) => buildURL( parent ) + id;
const buildDeleteURL = ( parent: ModelID, id: ModelID ) => buildChildURL( parent, id ) + '?force=true';
export function productVariationRESTRepository(
httpClient: HTTPClient
): ListsProductVariations &
CreatesProductVariations &
ReadsProductVariations &
UpdatesProductVariations &
DeletesProductVariations {
const buildURL = ( parent: ModelID ) =>
buildProductURL( parent ) + '/variations/';
const buildChildURL = ( parent: ModelID, id: ModelID ) =>
buildURL( parent ) + id;
const buildDeleteURL = ( parent: ModelID, id: ModelID ) =>
buildChildURL( parent, id ) + '?force=true';
const delivery = createProductDeliveryTransformation();
const inventory = createProductInventoryTransformation();
@ -61,13 +66,38 @@ export function productVariationRESTRepository( httpClient: HTTPClient ): ListsP
...shipping,
];
const transformer = createProductDataTransformer<ProductVariation>( transformations );
const transformer = createProductDataTransformer< ProductVariation >(
transformations
);
return new ModelRepository(
restListChild< ProductVariationRepositoryParams >( buildURL, ProductVariation, httpClient, transformer ),
restCreateChild< ProductVariationRepositoryParams >( buildURL, ProductVariation, httpClient, transformer ),
restReadChild< ProductVariationRepositoryParams >( buildChildURL, ProductVariation, httpClient, transformer ),
restUpdateChild< ProductVariationRepositoryParams >( buildChildURL, ProductVariation, httpClient, transformer ),
restDeleteChild< ProductVariationRepositoryParams >( buildDeleteURL, httpClient ),
restListChild< ProductVariationRepositoryParams >(
buildURL,
ProductVariation,
httpClient,
transformer
),
restCreateChild< ProductVariationRepositoryParams >(
buildURL,
ProductVariation,
httpClient,
transformer
),
restReadChild< ProductVariationRepositoryParams >(
buildChildURL,
ProductVariation,
httpClient,
transformer
),
restUpdateChild< ProductVariationRepositoryParams >(
buildChildURL,
ProductVariation,
httpClient,
transformer
),
restDeleteChild< ProductVariationRepositoryParams >(
buildDeleteURL,
httpClient
)
);
}

View File

@ -1,7 +1,4 @@
import settingRESTRepository from './setting';
import settingGroupRESTRepository from './setting-group';
export {
settingRESTRepository,
settingGroupRESTRepository,
};
export { settingRESTRepository, settingGroupRESTRepository };

View File

@ -12,11 +12,11 @@ import {
import { restList } from '../shared';
function createTransformer(): ModelTransformer< SettingGroup > {
return new ModelTransformer(
[
new KeyChangeTransformation< SettingGroup >( { parentID: 'parent_id' } ),
],
);
return new ModelTransformer( [
new KeyChangeTransformation< SettingGroup >( {
parentID: 'parent_id',
} ),
] );
}
/**
@ -25,14 +25,21 @@ function createTransformer(): ModelTransformer< SettingGroup > {
* @param {HTTPClient} httpClient The HTTP client for the REST requests to be made using.
* @return {ListsSettingGroups} The created repository.
*/
export default function settingGroupRESTRepository( httpClient: HTTPClient ): ListsSettingGroups {
export default function settingGroupRESTRepository(
httpClient: HTTPClient
): ListsSettingGroups {
const transformer = createTransformer();
return new ModelRepository(
restList< SettingGroupRepositoryParams >( () => '/wc/v3/settings', SettingGroup, httpClient, transformer ),
null,
restList< SettingGroupRepositoryParams >(
() => '/wc/v3/settings',
SettingGroup,
httpClient,
transformer
),
null,
null,
null,
null
);
}

View File

@ -24,15 +24,35 @@ function createTransformer(): ModelTransformer< Setting > {
* @param {HTTPClient} httpClient The HTTP client for the REST requests to be made using.
* @return {ListsSettings|ReadsSettings|UpdatesSettings} The created repository.
*/
export default function settingRESTRepository( httpClient: HTTPClient ): ListsSettings & ReadsSettings & UpdatesSettings {
const buildURL = ( parent: ParentID< SettingRepositoryParams >, id: ModelID ) => '/wc/v3/settings/' + parent + '/' + id;
export default function settingRESTRepository(
httpClient: HTTPClient
): ListsSettings & ReadsSettings & UpdatesSettings {
const buildURL = (
parent: ParentID< SettingRepositoryParams >,
id: ModelID
) => '/wc/v3/settings/' + parent + '/' + id;
const transformer = createTransformer();
return new ModelRepository(
restListChild< SettingRepositoryParams >( ( parent ) => '/wc/v3/settings/' + parent, Setting, httpClient, transformer ),
null,
restReadChild< SettingRepositoryParams >( buildURL, Setting, httpClient, transformer ),
restUpdateChild< SettingRepositoryParams >( buildURL, Setting, httpClient, transformer ),
restListChild< SettingRepositoryParams >(
( parent ) => '/wc/v3/settings/' + parent,
Setting,
httpClient,
transformer
),
null,
restReadChild< SettingRepositoryParams >(
buildURL,
Setting,
httpClient,
transformer
),
restUpdateChild< SettingRepositoryParams >(
buildURL,
Setting,
httpClient,
transformer
),
null
);
}

View File

@ -20,11 +20,7 @@ import {
// @ts-ignore
ModelParentID,
} from '../../framework';
import {
ModelID,
MetaData,
ModelConstructor,
} from '../../models';
import { ModelID, MetaData, ModelConstructor } from '../../models';
/**
* Creates a new transformer for metadata models.
@ -32,17 +28,13 @@ import {
* @return {ModelTransformer} The created transformer.
*/
export function createMetaDataTransformer(): ModelTransformer< MetaData > {
return new ModelTransformer(
[
new IgnorePropertyTransformation( [ 'id' ] ),
new KeyChangeTransformation< MetaData >(
{
displayKey: 'display_key',
displayValue: 'display_value',
},
),
],
);
return new ModelTransformer( [
new IgnorePropertyTransformation( [ 'id' ] ),
new KeyChangeTransformation< MetaData >( {
displayKey: 'display_key',
displayValue: 'display_value',
} ),
] );
}
/**
@ -52,7 +44,11 @@ export function createMetaDataTransformer(): ModelTransformer< MetaData > {
* @param {ModelID} [id] The ID of the model we're dealing with if used for the request.
* @return {string} The URL to make the request to.
*/
type BuildURLFn< T extends ( 'list' | 'general' ) = 'general' > = [ T ] extends [ 'list' ] ? () => string : ( id: ModelID ) => string;
type BuildURLFn< T extends 'list' | 'general' = 'general' > = [ T ] extends [
'list'
]
? () => string
: ( id: ModelID ) => string;
/**
* A callback to build a URL for a request.
@ -63,7 +59,10 @@ type BuildURLFn< T extends ( 'list' | 'general' ) = 'general' > = [ T ] extends
* @return {string} The URL to make the request to.
* @template {ModelParentID} P
*/
type BuildURLWithParentFn< P extends ModelRepositoryParams, T extends ( 'list' | 'general' ) = 'general' > = [ T ] extends [ 'list' ]
type BuildURLWithParentFn<
P extends ModelRepositoryParams,
T extends 'list' | 'general' = 'general'
> = [ T ] extends [ 'list' ]
? ( parent: ParentID< P > ) => string
: ( parent: ParentID< P >, id: ModelID ) => string;
@ -80,7 +79,7 @@ export function restList< T extends ModelRepositoryParams >(
buildURL: HasParent< T, never, BuildURLFn< 'list' > >,
modelClass: ModelConstructor< ModelClass< T > >,
httpClient: HTTPClient,
transformer: ModelTransformer< ModelClass< T > >,
transformer: ModelTransformer< ModelClass< T > >
): ListFn< T > {
return async ( params ) => {
const response = await httpClient.get( buildURL(), params );
@ -107,7 +106,7 @@ export function restListChild< T extends ModelRepositoryParams >(
buildURL: HasParent< T, BuildURLWithParentFn< T, 'list' >, never >,
modelClass: ModelConstructor< ModelClass< T > >,
httpClient: HTTPClient,
transformer: ModelTransformer< ModelClass< T > >,
transformer: ModelTransformer< ModelClass< T > >
): ListChildFn< T > {
return async ( parent, params ) => {
const response = await httpClient.get( buildURL( parent ), params );
@ -134,15 +133,17 @@ export function restCreate< T extends ModelRepositoryParams >(
buildURL: ( properties: Partial< ModelClass< T > > ) => string,
modelClass: ModelConstructor< ModelClass< T > >,
httpClient: HTTPClient,
transformer: ModelTransformer< ModelClass< T > >,
transformer: ModelTransformer< ModelClass< T > >
): CreateFn< T > {
return async ( properties ) => {
const response = await httpClient.post(
buildURL( properties ),
transformer.fromModel( properties ),
transformer.fromModel( properties )
);
return Promise.resolve( transformer.toModel( modelClass, response.data ) );
return Promise.resolve(
transformer.toModel( modelClass, response.data )
);
};
}
@ -156,18 +157,23 @@ export function restCreate< T extends ModelRepositoryParams >(
* @return {CreateChildFn} The callback for the repository.
*/
export function restCreateChild< T extends ModelRepositoryParams >(
buildURL: ( parent: ParentID< T >, properties: Partial< ModelClass< T > > ) => string,
buildURL: (
parent: ParentID< T >,
properties: Partial< ModelClass< T > >
) => string,
modelClass: ModelConstructor< ModelClass< T > >,
httpClient: HTTPClient,
transformer: ModelTransformer< ModelClass< T > >,
transformer: ModelTransformer< ModelClass< T > >
): CreateChildFn< T > {
return async ( parent, properties ) => {
const response = await httpClient.post(
buildURL( parent, properties ),
transformer.fromModel( properties ),
transformer.fromModel( properties )
);
return Promise.resolve( transformer.toModel( modelClass, response.data ) );
return Promise.resolve(
transformer.toModel( modelClass, response.data )
);
};
}
@ -184,11 +190,13 @@ export function restRead< T extends ModelRepositoryParams >(
buildURL: HasParent< T, never, BuildURLFn >,
modelClass: ModelConstructor< ModelClass< T > >,
httpClient: HTTPClient,
transformer: ModelTransformer< ModelClass< T > >,
transformer: ModelTransformer< ModelClass< T > >
): ReadFn< T > {
return async ( id ) => {
const response = await httpClient.get( buildURL( id ) );
return Promise.resolve( transformer.toModel( modelClass, response.data ) );
return Promise.resolve(
transformer.toModel( modelClass, response.data )
);
};
}
@ -205,11 +213,13 @@ export function restReadChild< T extends ModelRepositoryParams >(
buildURL: HasParent< T, BuildURLWithParentFn< T >, never >,
modelClass: ModelConstructor< ModelClass< T > >,
httpClient: HTTPClient,
transformer: ModelTransformer< ModelClass< T > >,
transformer: ModelTransformer< ModelClass< T > >
): ReadChildFn< T > {
return async ( parent, id ) => {
const response = await httpClient.get( buildURL( parent, id ) );
return Promise.resolve( transformer.toModel( modelClass, response.data ) );
return Promise.resolve(
transformer.toModel( modelClass, response.data )
);
};
}
@ -226,15 +236,17 @@ export function restUpdate< T extends ModelRepositoryParams >(
buildURL: HasParent< T, never, BuildURLFn >,
modelClass: ModelConstructor< ModelClass< T > >,
httpClient: HTTPClient,
transformer: ModelTransformer< ModelClass< T > >,
transformer: ModelTransformer< ModelClass< T > >
): UpdateFn< T > {
return async ( id, params ) => {
const response = await httpClient.patch(
buildURL( id ),
transformer.fromModel( params as any ),
transformer.fromModel( params as any )
);
return Promise.resolve( transformer.toModel( modelClass, response.data ) );
return Promise.resolve(
transformer.toModel( modelClass, response.data )
);
};
}
@ -251,15 +263,17 @@ export function restUpdateChild< T extends ModelRepositoryParams >(
buildURL: HasParent< T, BuildURLWithParentFn< T >, never >,
modelClass: ModelConstructor< ModelClass< T > >,
httpClient: HTTPClient,
transformer: ModelTransformer< ModelClass< T > >,
transformer: ModelTransformer< ModelClass< T > >
): UpdateChildFn< T > {
return async ( parent, id, params ) => {
const response = await httpClient.patch(
buildURL( parent, id ),
transformer.fromModel( params as any ),
transformer.fromModel( params as any )
);
return Promise.resolve( transformer.toModel( modelClass, response.data ) );
return Promise.resolve(
transformer.toModel( modelClass, response.data )
);
};
}
@ -272,7 +286,7 @@ export function restUpdateChild< T extends ModelRepositoryParams >(
*/
export function restDelete< T extends ModelRepositoryParams >(
buildURL: HasParent< T, never, BuildURLFn >,
httpClient: HTTPClient,
httpClient: HTTPClient
): DeleteFn {
return ( id ) => {
return httpClient.delete( buildURL( id ) ).then( () => true );
@ -288,7 +302,7 @@ export function restDelete< T extends ModelRepositoryParams >(
*/
export function restDeleteChild< T extends ModelRepositoryParams >(
buildURL: HasParent< T, BuildURLWithParentFn< T >, never >,
httpClient: HTTPClient,
httpClient: HTTPClient
): DeleteChildFn< T > {
return ( parent, id ) => {
return httpClient.delete( buildURL( parent, id ) ).then( () => true );

View File

@ -18,15 +18,35 @@ describe( 'SettingService', () => {
'line2',
'New York',
'US:NY',
'12345',
'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' } );
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' }
);
} );
} );

View File

@ -31,14 +31,40 @@ export class SettingService {
* @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 > {
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 } ) );
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 );
}

View File

@ -12,56 +12,44 @@ const { options: babelDefaultConfig } = babel.loadPartialConfig( {
} );
const plugins = babelDefaultConfig.plugins;
if ( ! process.env.SKIP_JSX_PRAGMA_TRANSFORM ) {
plugins.push( [ '@wordpress/babel-plugin-import-jsx-pragma', {
scopeVariable: 'createElement',
source: '@wordpress/element',
isDefault: false,
} ] );
plugins.push( [
'@wordpress/babel-plugin-import-jsx-pragma',
{
scopeVariable: 'createElement',
source: '@wordpress/element',
isDefault: false,
},
] );
}
const overrideOptions = ( target, targetName, options ) => {
if ( get( target, [ 'file', 'request' ] ) === targetName ) {
return [ targetName, Object.assign(
{},
target.options,
options
) ];
return [ targetName, Object.assign( {}, target.options, options ) ];
}
return target;
};
const babelConfigs = {
main: Object.assign(
{},
babelDefaultConfig,
{
plugins,
presets: map(
babelDefaultConfig.presets,
( preset ) => overrideOptions( preset, '@babel/preset-env', {
modules: 'commonjs',
} )
),
}
),
module: Object.assign(
{},
babelDefaultConfig,
{
plugins: map(
plugins,
( plugin ) => overrideOptions( plugin, '@babel/plugin-transform-runtime', {
useESModules: true,
} )
),
presets: map(
babelDefaultConfig.presets,
( preset ) => overrideOptions( preset, '@babel/preset-env', {
modules: false,
} )
),
}
),
main: Object.assign( {}, babelDefaultConfig, {
plugins,
presets: map( babelDefaultConfig.presets, ( preset ) =>
overrideOptions( preset, '@babel/preset-env', {
modules: 'commonjs',
} )
),
} ),
module: Object.assign( {}, babelDefaultConfig, {
plugins: map( plugins, ( plugin ) =>
overrideOptions( plugin, '@babel/plugin-transform-runtime', {
useESModules: true,
} )
),
presets: map( babelDefaultConfig.presets, ( preset ) =>
overrideOptions( preset, '@babel/preset-env', {
modules: false,
} )
),
} ),
};
function getBabelConfig( environment ) {

View File

@ -0,0 +1,19 @@
module.exports = {
extends: [ 'plugin:@woocommerce/eslint-plugin/recommended' ],
root: true,
overrides: [
{
files: [
'**/stories/*.js',
'**/stories/*.jsx',
'**/docs/example.js',
],
rules: {
'import/no-unresolved': [
'warn',
{ ignore: [ '@woocommerce/components' ] },
],
},
},
],
};

View File

@ -95,9 +95,11 @@
"@testing-library/user-event": "^13.5.0",
"@woocommerce/style-build": "workspace:*",
"@wordpress/browserslist-config": "^4.1.1",
"@wordpress/eslint-plugin": "^11.0.0",
"@wordpress/scripts": "^12.6.1",
"concurrently": "^7.0.0",
"css-loader": "^3.6.0",
"eslint": "^8.12.0",
"jest": "^27.5.1",
"jest-cli": "^27.5.1",
"postcss-loader": "^3.0.0",
@ -113,6 +115,7 @@
"build:js": "tsc --build ./tsconfig.json ./tsconfig-cjs.json",
"build:css": "webpack",
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
"lint": "eslint src --ext=js,ts,tsx",
"prepack": "pnpm run clean && pnpm run build",
"start": "concurrently \"tsc --build ./tsconfig.json --watch\" \"webpack --watch\"",
"test": "pnpm run build && pnpm run test:nobuild",

View File

@ -0,0 +1,4 @@
module.exports = {
extends: [ 'plugin:@woocommerce/eslint-plugin/recommended' ],
root: true,
};

View File

@ -32,12 +32,15 @@
"build": "tsc --build ./tsconfig.json ./tsconfig-cjs.json",
"start": "tsc --build --watch",
"prepack": "pnpm run clean && pnpm run build",
"lint": "eslint src",
"test": "pnpm run build && pnpm run test:nobuild",
"test:nobuild": "jest --config ./jest.config.json",
"test-staged": "jest --bail --config ./jest.config.json --findRelatedTests"
},
"devDependencies": {
"@babel/core": "^7.17.5",
"@wordpress/eslint-plugin": "^11.0.0",
"eslint": "^8.12.0",
"jest": "^27.5.1",
"jest-cli": "^27.5.1",
"rimraf": "^3.0.2",

View File

@ -0,0 +1,4 @@
module.exports = {
extends: [ 'plugin:@woocommerce/eslint-plugin/recommended' ],
root: true,
};

View File

@ -25,7 +25,7 @@ const total = storeCurrency.formatAmount( 20.923 ); // '$20.92'
// Get the rounded decimal value of a number at the precision used for the current currency,
// from the settings api. Defaults to 2.
const total = storeCurrency.formatDecimal( '6.2892' ); // 6.29 https://google.com/?q=test
const total = storeCurrency.formatDecimal( '6.2892' ); // 6.29
// Get the string representation of a floating point number to the precision used by the current
// currency. This is different from `formatAmount` by not returning the currency symbol.

View File

@ -35,12 +35,15 @@
"build": "tsc --build ./tsconfig.json ./tsconfig-cjs.json",
"start": "tsc --build --watch",
"prepack": "pnpm run clean && pnpm run build",
"lint": "eslint src",
"test": "pnpm run build && pnpm run test:nobuild",
"test:nobuild": "jest --config ./jest.config.json",
"test-staged": "jest --bail --config ./jest.config.json --findRelatedTests"
},
"devDependencies": {
"@babel/core": "^7.17.5",
"@wordpress/eslint-plugin": "^11.0.0",
"eslint": "^8.12.0",
"jest": "^27.5.1",
"jest-cli": "^27.5.1",
"rimraf": "^3.0.2",

View File

@ -7,6 +7,22 @@ import { sprintf } from '@wordpress/i18n';
import { numberFormat } from '@woocommerce/number';
import deprecated from '@wordpress/deprecated';
/**
* @typedef {import('@woocommerce/number').NumberConfig} NumberConfig
*/
/**
* @typedef {Object} CurrencyProps
* @property {string} code Currency ISO code.
* @property {string} symbol Symbol, can be multi-character.
* @property {string} symbolPosition Where the symbol should be relative to the amount. One of `'left' | 'right' | 'left_space | 'right_space'`.
* @typedef {NumberConfig & CurrencyProps} CurrencyConfig
*/
/**
*
* @param {CurrencyConfig} currencySetting
* @return {Object} currency object
*/
const CurrencyFactory = function ( currencySetting ) {
let currency;
@ -63,7 +79,6 @@ const CurrencyFactory = function ( currencySetting ) {
* Formats money value.
*
* @deprecated
*
* @param {number|string} number number to format
* @return {?string} A formatted string.
*/
@ -80,7 +95,7 @@ const CurrencyFactory = function ( currencySetting ) {
/**
* Get the default price format from a currency.
*
* @param {Object} config Currency configuration.
* @param {CurrencyConfig} config Currency configuration.
* @return {string} Price format.
*/
function getPriceFormat( config ) {
@ -108,7 +123,7 @@ const CurrencyFactory = function ( currencySetting ) {
* @param {string} countryCode Country code.
* @param {Object} localeInfo Locale info by country code.
* @param {Object} currencySymbols Currency symbols by symbol code.
* @return {Object} Formatted currency data for country.
* @return {CurrencyConfig | {}} Formatted currency data for country.
*/
function getDataForCountry(
countryCode,
@ -211,7 +226,6 @@ export default CurrencyFactory;
* Dev Note: When adding new currencies below, the exchange rate array should also be updated in WooCommerce Admin's `business-details.js`.
*
* @deprecated
*
* @return {Object} Curreny data.
*/
export function getCurrencyData() {

View File

@ -1,6 +1,7 @@
{
"extends": "../tsconfig-cjs",
"compilerOptions": {
"declaration": true,
"outDir": "build"
}
}

View File

@ -1,6 +1,7 @@
{
"extends": "../tsconfig",
"compilerOptions": {
"declaration": true,
"rootDir": "src",
"outDir": "build-module"
}

View File

@ -0,0 +1,4 @@
module.exports = {
extends: [ 'plugin:@woocommerce/eslint-plugin/recommended' ],
root: true,
};

View File

@ -41,8 +41,10 @@
"@types/wordpress__components": "^9.8.6",
"@woocommerce/style-build": "workspace:*",
"@wordpress/browserslist-config": "^4.1.1",
"@wordpress/eslint-plugin": "^11.0.0",
"concurrently": "^7.0.0",
"css-loader": "^3.6.0",
"eslint": "^8.12.0",
"jest": "^27.5.1",
"jest-cli": "^27.5.1",
"postcss-loader": "^3.0.0",
@ -64,6 +66,7 @@
"build:css": "webpack",
"start": "concurrently \"tsc --build --watch\" \"webpack --watch\"",
"prepack": "pnpm run clean && pnpm run build",
"lint": "eslint src",
"test": "pnpm run build && pnpm run test:nobuild",
"test:nobuild": "jest --config ./jest.config.json",
"test-staged": "jest --bail --config ./jest.config.json --findRelatedTests"

View File

@ -0,0 +1,4 @@
module.exports = {
extends: [ 'plugin:@woocommerce/eslint-plugin/recommended' ],
root: true,
};

View File

@ -46,6 +46,8 @@
"@testing-library/react": "^12.1.3",
"@testing-library/react-hooks": "^7.0.2",
"@types/wordpress__data-controls": "^2.2.0",
"@wordpress/eslint-plugin": "^11.0.0",
"eslint": "^8.12.0",
"jest": "^27.5.1",
"jest-cli": "^27.5.1",
"rimraf": "^3.0.2",
@ -63,6 +65,7 @@
"build": "tsc --build ./tsconfig.json ./tsconfig-cjs.json",
"start": "tsc --build --watch",
"prepack": "pnpm run clean && pnpm run build",
"lint": "eslint src",
"test": "pnpm run build && pnpm run test:nobuild",
"test:nobuild": "jest --config ./jest.config.json",
"test-staged": "jest --bail --config ./jest.config.json --findRelatedTests"

View File

@ -33,6 +33,7 @@ const TYPES = {
ACTION_TASK_ERROR: 'ACTION_TASK_ERROR',
ACTION_TASK_REQUEST: 'ACTION_TASK_REQUEST',
ACTION_TASK_SUCCESS: 'ACTION_TASK_SUCCESS',
VISITED_TASK: 'VISITED_TASK',
};
export default TYPES;

View File

@ -201,6 +201,13 @@ export function optimisticallyCompleteTaskRequest( taskId ) {
};
}
export function visitedTask( taskId ) {
return {
type: TYPES.VISITED_TASK,
taskId,
};
}
export function setPaymentMethods( paymentMethods ) {
return {
type: TYPES.GET_PAYMENT_METHODS_SUCCESS,

View File

@ -380,6 +380,14 @@ const onboarding = (
isComplete: true,
} ),
};
case TYPES.VISITED_TASK:
return {
...state,
taskLists: getUpdatedTaskLists( state.taskLists, {
id: taskId,
isVisited: true,
} ),
};
case TYPES.ACTION_TASK_ERROR:
return {
...state,

View File

@ -6,13 +6,13 @@ export type TaskType = {
isComplete: boolean;
isDismissable: boolean;
isDismissed: boolean;
isVisible: boolean;
isSnoozed: boolean;
isVisible: boolean;
isSnoozable: boolean;
snoozedUntil: number;
time: string;
title: string;
isVisited?: boolean;
isVisited: boolean;
};
export type TaskListType = {
@ -24,4 +24,5 @@ export type TaskListType = {
tasks: TaskType[];
title: string;
eventPrefix: string;
displayProgressHeader: boolean;
};

View File

@ -0,0 +1,4 @@
module.exports = {
extends: [ 'plugin:@woocommerce/eslint-plugin/recommended' ],
root: true,
};

View File

@ -28,7 +28,9 @@
},
"devDependencies": {
"@babel/core": "^7.17.5",
"@wordpress/eslint-plugin": "^11.0.0",
"d3-time-format": "^2.3.0",
"eslint": "^8.12.0",
"jest": "^27.5.1",
"jest-cli": "^27.5.1",
"rimraf": "^3.0.2",
@ -46,6 +48,7 @@
"build": "tsc --build ./tsconfig.json ./tsconfig-cjs.json",
"start": "tsc --build --watch",
"prepack": "pnpm run clean && pnpm run build",
"lint": "eslint src",
"test": "pnpm run build && pnpm run test:nobuild",
"test:nobuild": "jest --config ./jest.config.json",
"test-staged": "jest --bail --config ./jest.config.json --findRelatedTests"

Some files were not shown because too many files have changed in this diff Show More