From 112a004c4a452dafb48c1be8262ebc829f5ca6ef Mon Sep 17 00:00:00 2001 From: Cory Gottschalk Date: Wed, 10 Apr 2019 12:05:27 -0700 Subject: [PATCH 1/3] Add TypeScript Definitions Add typescript definitions for TypeScript and Code Editors --- package.json | 2 + src/api.d.ts | 5 + src/hooks.d.ts | 5 + src/main.d.ts | 1 + src/tools.d.ts | 6 ++ src/typings/api.d.ts | 226 +++++++++++++++++++++++++++++++++++++++++ src/typings/hooks.d.ts | 63 ++++++++++++ src/typings/index.d.ts | 22 ++++ src/typings/tools.d.ts | 17 ++++ 9 files changed, 347 insertions(+) create mode 100644 src/api.d.ts create mode 100644 src/hooks.d.ts create mode 100644 src/main.d.ts create mode 100644 src/tools.d.ts create mode 100644 src/typings/api.d.ts create mode 100644 src/typings/hooks.d.ts create mode 100644 src/typings/index.d.ts create mode 100644 src/typings/tools.d.ts diff --git a/package.json b/package.json index 44c11d5..9ef18e6 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,8 @@ "url": "git://github.com/bigcommerce/stencil-utils.git" }, "dependencies": { + "@types/eventemitter2": "^2.2.1", + "@types/jquery": "^3.3.29", "eventemitter2": "^0.4.14", "jquery": "^3.3.1", "query-string": "^5.0.0" diff --git a/src/api.d.ts b/src/api.d.ts new file mode 100644 index 0000000..abe9c3a --- /dev/null +++ b/src/api.d.ts @@ -0,0 +1,5 @@ +export * from './typings/api'; +import { Api } from './typings/api'; + +declare const api: Api; +export default api; diff --git a/src/hooks.d.ts b/src/hooks.d.ts new file mode 100644 index 0000000..d70529a --- /dev/null +++ b/src/hooks.d.ts @@ -0,0 +1,5 @@ +export * from './typings/hooks'; +import { Hooks } from './typings/hooks'; + +declare const hooks: Hooks; +export default hooks; diff --git a/src/main.d.ts b/src/main.d.ts new file mode 100644 index 0000000..3f80fbc --- /dev/null +++ b/src/main.d.ts @@ -0,0 +1 @@ +export * from './typings'; diff --git a/src/tools.d.ts b/src/tools.d.ts new file mode 100644 index 0000000..41cf0c3 --- /dev/null +++ b/src/tools.d.ts @@ -0,0 +1,6 @@ +export * from './typings/tools'; +import { Tools } from './typings/tools'; + +declare const tools: Tools; + +export default tools; diff --git a/src/typings/api.d.ts b/src/typings/api.d.ts new file mode 100644 index 0000000..5f61572 --- /dev/null +++ b/src/typings/api.d.ts @@ -0,0 +1,226 @@ +/// + +export declare namespace Api { + type StringObject = { [key: string]: string; }; + type GenericObject = { [key: string]: any; }; + + type Template = string|string[]|StringObject; + type ValidMethods = 'GET'|'POST'|'PUT'|'DELETE'; + type RequestTemplate = T extends keyof O ? O[T] : {} extends O ? string : never; + type TemplateResponse = T extends string[]|StringObject ? GenericObject : string; + type TemplateRequestCallback = (error: string, response: TemplateResponse) => void|any; + type JsonRequestCallback = (error: string, response: T) => void|any; + type QuantityRequestCallback = (error: string, response: number) => void|any; + type GetShippingQuoteRequestCallback = (error: string, response: GetShippingQuoteResponse) => void|any; + + interface RequestOptions { + baseUrl?: string; + formData?: FormData; + params?: any; + config?: any; + template?: Template; + includeOptions?: boolean; + } + + interface Cart { + baseAmount: number; + cartAmount: number; + coupons: any[]; + createdTime: string; + currency: Currency; + customerId: number; + discountAmount: number; + discounts: Discount[]; + email: string; + id: string; + isTaxIncluded: boolean; + lineItems: { + customItems: CustomProduct[]; + digitalItems: DigitalProduct[]; + giftCertificates: GiftCertificateProduct[]; + physicalItems: PhysicalProduct[] + } + } + + interface Currency { + code: string; + decimalPlaces: number; + name: string; + symbol: string; + } + + interface Discount { + id: number; + discountedAmount: number; + } + + interface BaseProduct { + id: string; + parentId: string; + variantId: string; + productId: number; + sku: string; + name: string; + url: string; + quantity: number; + isTaxable: boolean; + imageUrl: string; + discounts: Discount[]; + discountAmount: number; + couponAmount: number; + listPrice: number; + salePrice: number; + extendedListPrice: number; + extendedSalePrice: number; + Options: ProductOption[]; + brand: string; + } + + interface PhysicalProduct extends BaseProduct {} + + interface DigitalProduct extends BaseProduct {} + + interface CustomProduct { + id: string; + sku: string; + name: string; + quantity: number; + listPrice: number; + extendedListPrice: number; + } + + interface GiftCertificateProduct { + id: string; + name: string; + theme: string; + amount: number; + isTaxable: boolean; + sender: { + name: string; + email: string; + }; + recipient: { + name: string; + email: string; + }; + message: string; + } + + interface ProductOption { + name: string; + nameId: number; + value: string; + valueId: number; + } + + interface AddedCartItem { + hash: string; + id: string; + product_id: number; + thumbnail: string; + url: string; + } + + interface CartUpdateItem { + id: string; + quantity: number; + } + + interface ShippingMethod { + id: number; + type: string; + cost: { + formatted: string; + value: number; + }; + provider_name: string; + } + + interface UpsShippingMethod extends ShippingMethod { + logo_path?: string; + description: string; + } + + interface GetShippingQuoteResponse { + content: TemplateResponse; + data: { + quotes: { + shipping_methods: ShippingMethod[]; + ups_shipping_methods: UpsShippingMethod[]; + }; + }; + } + + interface ApiStatusResponse { + errors: string[]; + status: string; + } + + class BaseApi { + constructor(version: string); + remoteVersion: string; + remoteBaseEndpoint: string; + + makeRequest>(url: string, method: ValidMethods, options: RequestOptions & O, remote: boolean, callback: TemplateRequestCallback): void; + remoteRequest>(endpoint: string, method: ValidMethods, options: RequestOptions & O, callback: TemplateRequestCallback): void; + } + + class CountryApi extends BaseApi { + endpoint: string; + getById(id: number, callback: TemplateRequestCallback): void; + getByName(name: string, callback: TemplateRequestCallback): void; + } + + class ProductAttributesApi extends BaseApi { + endpoint: string; + inCartEndpoint: string; + + optionChange(productId: number, params: any, callback: TemplateRequestCallback): void; + optionChange(productId: number, params: any, template: Template & T, callback: TemplateRequestCallback): void; + configureInCart>(itemId: number, params: RequestOptions & O, callback: TemplateRequestCallback): void; + } + + class ProductApi extends BaseApi { + endpoint: string; + getById(productId: number, callback: TemplateRequestCallback): void; + getById>(productId: number, params: RequestOptions & O, callback: TemplateRequestCallback): void; + } + + class SearchApi extends BaseApi { + endpoint: string; + search(query: string, callback: TemplateRequestCallback): void; + search>(query: string, params: RequestOptions & O, callback: TemplateRequestCallback): void; + } + + class CartApi extends BaseApi { + getCart(options: RequestOptions, callback: JsonRequestCallback): void; + getCartQuantity(options: RequestOptions, callback: QuantityRequestCallback): void; + itemAdd(formData: FormData, callback: JsonRequestCallback<{ data: { cart_item: AddedCartItem; }; }>): void; + itemUpdate(itemId: string, qty: number, callback: JsonRequestCallback<{ data: ApiStatusResponse; }>): void; + itemUpdate(itemId: CartUpdateItem[], callback: JsonRequestCallback<{ data: ApiStatusResponse; }>): void; + itemRemove(itemId: string, callback: JsonRequestCallback<{ data: ApiStatusResponse; }>): void; + update(items: CartUpdateItem[], callback: JsonRequestCallback<{ data: ApiStatusResponse; }>): void; + getContent(callback: TemplateRequestCallback): void; + getContent>(options: RequestOptions & O, callback: TemplateRequestCallback): void; + getShippingQuotes(params: any, callback: GetShippingQuoteRequestCallback): void; + getShippingQuotes(params: any, renderWith: Template & T, callback: GetShippingQuoteRequestCallback): void; + submitShippingQuote(quoteId: number, callback: (error: string) => void): void; + applyCode(code: string, callback: JsonRequestCallback<{ data: ApiStatusResponse; }>): void; + applyGiftCertificate(code: string, callback: JsonRequestCallback<{ data: ApiStatusResponse; }>): void; + } + + interface Internals { + getPage>(url: string, options: RequestOptions & O, callback: TemplateRequestCallback): void; + } +} + +export interface Api { + country: Api.CountryApi; + productAttributes: Api.ProductAttributesApi; + product: Api.ProductApi; + search: Api.SearchApi; + cart: Api.CartApi; + getPage: Api.Internals['getPage']; +} + +export default Api; diff --git a/src/typings/hooks.d.ts b/src/typings/hooks.d.ts new file mode 100644 index 0000000..05c8337 --- /dev/null +++ b/src/typings/hooks.d.ts @@ -0,0 +1,63 @@ +/// +/// + +export declare namespace Hooks { + class BaseHooks extends EventEmitter2 { + $body: JQuery + } + + class CartHooks extends BaseHooks { + itemAdd(): void; + } + + class CookieHooks extends BaseHooks {} + + class CurrencySelectorHooks extends BaseHooks { + currencySelector(): void; + } + + class ProductHooks extends BaseHooks { + optionsChange(): void; + } + + class SearchHooks extends BaseHooks { + quickSearch(): void; + } + + class FacetedSearchHooks extends BaseHooks { + searchEvents(): void; + } + + class SortByHooks extends BaseHooks { + sortByEvents(): void; + } + + + namespace Internals { + interface Classes { + cart: CartHooks; + cookie: CookieHooks; + currencySelector: CurrencySelectorHooks; + product: ProductHooks; + search: SearchHooks; + facetedSearch: FacetedSearchHooks; + sortBy: SortByHooks; + } + + export const classes: Classes + } + + interface Internals { + classes: Internals.Classes; + parseHooks(hookName: H): Internals.Classes[T]; + } +} + + +export declare class Hooks { + on(hookname: H, callback: () => void|any): ReturnType; + off(hookname: H, callback: () => void|any): ReturnType; + emit(hookname: H, callback: () => void|any): ReturnType; +} + +export default Hooks; diff --git a/src/typings/index.d.ts b/src/typings/index.d.ts new file mode 100644 index 0000000..b359fe9 --- /dev/null +++ b/src/typings/index.d.ts @@ -0,0 +1,22 @@ +// Type definitions for Stencil Utils v4.1.0 +// Project: https://github.com/bigcommerce/stencil-utils +// Definitions by: Arctic Leaf +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// Documentation: https://developer.bigcommerce.com/stencil-docs/adding-event-hooks-to-your-theme/stencil-utils-api-reference + +import Api from './api'; +import Hooks from './hooks'; +import Tools from './tools'; + +interface StencilUtils { + api: Api; + hooks: Hooks; + tools: Tools; +} + +declare const utils: StencilUtils; + +export const api: Api; +export const hooks: Hooks; +export const tools: Tools; +export default utils; diff --git a/src/typings/tools.d.ts b/src/typings/tools.d.ts new file mode 100644 index 0000000..22c351b --- /dev/null +++ b/src/typings/tools.d.ts @@ -0,0 +1,17 @@ +export declare namespace Tools { + class ImageTool { + getSrc(path: string, dimensions: string): string; + } + + class StorageTools { + storageAvailable(type: string): boolean; + localStorageAvailable(): boolean; + } +} + +export interface Tools { + image: Tools.ImageTool; + storage: Tools.StorageTools; +} + +export default Tools; From 38c6a7636784424c81b092c45dafe1c41b564b90 Mon Sep 17 00:00:00 2001 From: Cory Gottschalk Date: Wed, 10 Apr 2019 16:24:16 -0700 Subject: [PATCH 2/3] Update type definitions - adds a type definition for the getItemGiftWrappingOptions method - adds a type definition for the submitItemGiftWrappingOption method - updates the callback type in the submitShippingQuote type definition - makes the errors array optional on the ApiStatusResponse interface --- src/typings/api.d.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/typings/api.d.ts b/src/typings/api.d.ts index 5f61572..a2ad343 100644 --- a/src/typings/api.d.ts +++ b/src/typings/api.d.ts @@ -152,7 +152,7 @@ export declare namespace Api { } interface ApiStatusResponse { - errors: string[]; + errors?: string[]; status: string; } @@ -199,12 +199,16 @@ export declare namespace Api { itemUpdate(itemId: string, qty: number, callback: JsonRequestCallback<{ data: ApiStatusResponse; }>): void; itemUpdate(itemId: CartUpdateItem[], callback: JsonRequestCallback<{ data: ApiStatusResponse; }>): void; itemRemove(itemId: string, callback: JsonRequestCallback<{ data: ApiStatusResponse; }>): void; + getItemGiftWrappingOptions(itemId: string, callback: TemplateRequestCallback): void; + getItemGiftWrappingOptions>(itemId: string, options: RequestOptions & O, callback: TemplateRequestCallback): void; + submitItemGiftWrappingOption(itemId: string, callback: JsonRequestCallback<{ data: ApiStatusResponse; }>): void; + submitItemGiftWrappingOption>(itemId: string, params: RequestOptions & O, callback: JsonRequestCallback<{ data: ApiStatusResponse; }>): void; update(items: CartUpdateItem[], callback: JsonRequestCallback<{ data: ApiStatusResponse; }>): void; getContent(callback: TemplateRequestCallback): void; getContent>(options: RequestOptions & O, callback: TemplateRequestCallback): void; getShippingQuotes(params: any, callback: GetShippingQuoteRequestCallback): void; getShippingQuotes(params: any, renderWith: Template & T, callback: GetShippingQuoteRequestCallback): void; - submitShippingQuote(quoteId: number, callback: (error: string) => void): void; + submitShippingQuote(quoteId: number, callback: (error: string, response: JsonRequestCallback<{ data: ApiStatusResponse; }>) => void): void; applyCode(code: string, callback: JsonRequestCallback<{ data: ApiStatusResponse; }>): void; applyGiftCertificate(code: string, callback: JsonRequestCallback<{ data: ApiStatusResponse; }>): void; } From 084c7db0b1687706c1fa911dd42ca9b8d2a012b6 Mon Sep 17 00:00:00 2001 From: Cory Gottschalk Date: Wed, 10 Apr 2019 16:24:58 -0700 Subject: [PATCH 3/3] Add JSDoc comments to type definitions --- src/typings/api.d.ts | 196 +++++++++++++++++++++++++++++++++++++++++ src/typings/tools.d.ts | 6 ++ 2 files changed, 202 insertions(+) diff --git a/src/typings/api.d.ts b/src/typings/api.d.ts index a2ad343..3366947 100644 --- a/src/typings/api.d.ts +++ b/src/typings/api.d.ts @@ -167,7 +167,21 @@ export declare namespace Api { class CountryApi extends BaseApi { endpoint: string; + + /** + * + * Get country data by id wrapper + * + * @param {Number} id + * @param {Function} callback + */ getById(id: number, callback: TemplateRequestCallback): void; + + /** + * Get country data by country name + * @param {String} name + * @param callback + */ getByName(name: string, callback: TemplateRequestCallback): void; } @@ -175,45 +189,227 @@ export declare namespace Api { endpoint: string; inCartEndpoint: string; + /** + * Get product attributes from selected options + * + * @param {Number} productId + * @param {Object} params + * @param callback + */ optionChange(productId: number, params: any, callback: TemplateRequestCallback): void; + + /** + * Get product attributes from selected options + * + * @param {Number} productId + * @param {Object} params + * @param {String|Array|Object} + * @param callback + */ optionChange(productId: number, params: any, template: Template & T, callback: TemplateRequestCallback): void; + + /** + * Get product attributes from selected options while editing in cart + * @param {Number} itemId + * @param {Object} params + * @param callback + */ configureInCart>(itemId: number, params: RequestOptions & O, callback: TemplateRequestCallback): void; } class ProductApi extends BaseApi { endpoint: string; + + /** + * Get product by ID + * + * @param {Number} productId + * @param {Function} callback + */ getById(productId: number, callback: TemplateRequestCallback): void; + + /** + * Get product by ID + * + * @param {Number} productId + * @param {Object} params + * @param {Function} callback + */ getById>(productId: number, params: RequestOptions & O, callback: TemplateRequestCallback): void; } class SearchApi extends BaseApi { endpoint: string; + + /** + * Get search results + * @param {String} query + * @param {Function} callback + */ search(query: string, callback: TemplateRequestCallback): void; + + /** + * Get search results + * @param {String} query + * @param {Object} params + * @param {Function} callback + */ search>(query: string, params: RequestOptions & O, callback: TemplateRequestCallback): void; } class CartApi extends BaseApi { + /** + * Get the current Cart's details, either with or without Product Option selections. + * + * @param options + * @param {Function} callback + */ getCart(options: RequestOptions, callback: JsonRequestCallback): void; + + /** + * Get a sum of the cart line item quantities + * + * @param options + * @param {Function} callback + */ getCartQuantity(options: RequestOptions, callback: QuantityRequestCallback): void; + + /** + * Add item to cart with options (variants) + * + * @param {FormData} formData + * @param {Function} callback + */ itemAdd(formData: FormData, callback: JsonRequestCallback<{ data: { cart_item: AddedCartItem; }; }>): void; + + /** + * Update cart item quantity + * + * @param {String} itemId + * @param {Number} qty + * @param {Function} callback + */ itemUpdate(itemId: string, qty: number, callback: JsonRequestCallback<{ data: ApiStatusResponse; }>): void; + + /** + * Update cart item quantity + * + * @param {Object} itemId + * @param {Function} callback + */ itemUpdate(itemId: CartUpdateItem[], callback: JsonRequestCallback<{ data: ApiStatusResponse; }>): void; + + /** + * Remove cart items + * + * Calls the internal update function with quantity: 0 + * + * @param {String} itemId + * @param {Function} callback + */ itemRemove(itemId: string, callback: JsonRequestCallback<{ data: ApiStatusResponse; }>): void; + + /** + * Get giftwrapping options + * @param {String} itemId + * @param {Function} callback + */ getItemGiftWrappingOptions(itemId: string, callback: TemplateRequestCallback): void; + + /** + * Get giftwrapping options + * @param {String} itemId + * @param {Object} options + * @param {Function} callback + */ getItemGiftWrappingOptions>(itemId: string, options: RequestOptions & O, callback: TemplateRequestCallback): void; + + /** + * Submit giftwrapping options + * + * @param {String} itemId + * @param {Function} callback + */ submitItemGiftWrappingOption(itemId: string, callback: JsonRequestCallback<{ data: ApiStatusResponse; }>): void; + + /** + * Submit giftwrapping options + * + * @param {String} itemId + * @param {Object} params + * @param {Function} callback + */ submitItemGiftWrappingOption>(itemId: string, params: RequestOptions & O, callback: JsonRequestCallback<{ data: ApiStatusResponse; }>): void; + + /** + * Update cart items + * + * @param {Array} items + * @param {Function} callback + */ update(items: CartUpdateItem[], callback: JsonRequestCallback<{ data: ApiStatusResponse; }>): void; + + /** + * Get cart content + * + * @param {Function} callback + */ getContent(callback: TemplateRequestCallback): void; + + /** + * Get cart content + * + * @param {Object} options + * @param {Function} callback + */ getContent>(options: RequestOptions & O, callback: TemplateRequestCallback): void; + + /** + * Get cart shipping quote + * + * @param {Object} params + * @param {Function} callback + */ getShippingQuotes(params: any, callback: GetShippingQuoteRequestCallback): void; + + /** + * Get cart shipping quote + * + * @param {Object} params + * @param {String|Array|Object} renderWith + * @param {Function} callback + */ getShippingQuotes(params: any, renderWith: Template & T, callback: GetShippingQuoteRequestCallback): void; + + /** + * Submit shipping quote based on quoteId + * + * @param {Number} quoteId + * @param {Function} callback + */ submitShippingQuote(quoteId: number, callback: (error: string, response: JsonRequestCallback<{ data: ApiStatusResponse; }>) => void): void; + + /** + * Apply a coupon code or gift certificate to the cart + * + * @param {String} code + * @param {Function} callback + */ applyCode(code: string, callback: JsonRequestCallback<{ data: ApiStatusResponse; }>): void; + + /** + * Apply a coupon code or gift certificate to the cart + * + * @param {Number} code + * @param {Function} callback + */ applyGiftCertificate(code: string, callback: JsonRequestCallback<{ data: ApiStatusResponse; }>): void; } interface Internals { + /** + * Convenience function to request a page via ajax + */ getPage>(url: string, options: RequestOptions & O, callback: TemplateRequestCallback): void; } } diff --git a/src/typings/tools.d.ts b/src/typings/tools.d.ts index 22c351b..d0dc46a 100644 --- a/src/typings/tools.d.ts +++ b/src/typings/tools.d.ts @@ -4,6 +4,12 @@ export declare namespace Tools { } class StorageTools { + /** + * Check if a storage type (like localStorage or sessionStorage) is available for use + * https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API#Testing_for_availability + * @param type + * @returns boolean + */ storageAvailable(type: string): boolean; localStorageAvailable(): boolean; }