From 9c41a6eed1bba46e80ce282903ac86bb11493e84 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Sun, 25 Aug 2024 22:00:47 +1000 Subject: [PATCH] feat: Factory types --- src/Factory.ts | 115 ++++++++++++++++++++++++++++++++------ src/Node.ts | 6 +- src/Shape.ts | 5 ++ src/Validators.ts | 38 ++++++------- src/filters/Emboss.ts | 4 +- src/shapes/Label.ts | 5 +- src/shapes/TextPath.ts | 4 +- src/shapes/Transformer.ts | 2 - 8 files changed, 133 insertions(+), 46 deletions(-) diff --git a/src/Factory.ts b/src/Factory.ts index e50029579..b305a575b 100644 --- a/src/Factory.ts +++ b/src/Factory.ts @@ -1,17 +1,75 @@ import { Node } from './Node'; +import { GetSet } from './types'; import { Util } from './Util'; import { getComponentValidator } from './Validators'; -var GET = 'get', - SET = 'set'; +const GET = 'get'; +const SET = 'set'; + +/** + * Enforces that a type is a string. + */ +type EnforceString = T extends string ? T : never; + +/** + * Represents a class. + */ +type Constructor = abstract new (...args: any) => any; + +/** + * An attribute of an instance of the provided class. Attributes names be strings. + */ +type Attr = EnforceString>; + +/** + * A function that is called after a setter is called. + */ +type AfterFunc = (this: InstanceType) => void; + +/** + * Extracts the type of a GetSet. + */ +type ExtractGetSet = T extends GetSet ? U : never; + +/** + * Extracts the type of a GetSet class attribute. + */ +type Value> = ExtractGetSet< + InstanceType[U] +>; + +/** + * A function that validates a value. + */ +type ValidatorFunc = (val: ExtractGetSet, attr: string) => T; + +/** + * Extracts the "components" (keys) of a GetSet value. The value must be an object. + */ +type ExtractComponents> = Value< + T, + U +> extends Record + ? EnforceString>[] + : never; export const Factory = { - addGetterSetter(constructor, attr, def?, validator?, after?) { + addGetterSetter>( + constructor: T, + attr: U, + def?: Value, + validator?: ValidatorFunc>, + after?: AfterFunc + ): void { Factory.addGetter(constructor, attr, def); Factory.addSetter(constructor, attr, validator, after); Factory.addOverloadedGetterSetter(constructor, attr); }, - addGetter(constructor, attr, def?) { + addGetter>( + constructor: T, + attr: U, + def?: Value + ) { var method = GET + Util._capitalize(attr); constructor.prototype[method] = @@ -22,14 +80,25 @@ export const Factory = { }; }, - addSetter(constructor, attr, validator?, after?) { + addSetter>( + constructor: T, + attr: U, + validator?: ValidatorFunc>, + after?: AfterFunc + ) { var method = SET + Util._capitalize(attr); if (!constructor.prototype[method]) { Factory.overWriteSetter(constructor, attr, validator, after); } }, - overWriteSetter(constructor, attr, validator?, after?) { + + overWriteSetter>( + constructor: T, + attr: U, + validator?: ValidatorFunc>, + after?: AfterFunc + ) { var method = SET + Util._capitalize(attr); constructor.prototype[method] = function (val) { if (validator && val !== undefined && val !== null) { @@ -45,12 +114,13 @@ export const Factory = { return this; }; }, - addComponentsGetterSetter( - constructor, - attr: string, - components: Array, - validator?: Function, - after?: Function + + addComponentsGetterSetter>( + constructor: T, + attr: U, + components: ExtractComponents, + validator?: ValidatorFunc>, + after?: AfterFunc ) { var len = components.length, capitalize = Util._capitalize, @@ -79,7 +149,7 @@ export const Factory = { key; if (validator) { - val = validator.call(this, val); + val = validator.call(this, val, attr); } if (basicValidator) { @@ -109,7 +179,10 @@ export const Factory = { Factory.addOverloadedGetterSetter(constructor, attr); }, - addOverloadedGetterSetter(constructor, attr) { + addOverloadedGetterSetter>( + constructor: T, + attr: U + ) { var capitalizedAttr = Util._capitalize(attr), setter = SET + capitalizedAttr, getter = GET + capitalizedAttr; @@ -124,7 +197,12 @@ export const Factory = { return this[getter](); }; }, - addDeprecatedGetterSetter(constructor, attr, def, validator) { + addDeprecatedGetterSetter>( + constructor: T, + attr: U, + def: Value, + validator: ValidatorFunc> + ) { Util.error('Adding deprecated ' + attr); var method = GET + Util._capitalize(attr); @@ -142,7 +220,10 @@ export const Factory = { }); Factory.addOverloadedGetterSetter(constructor, attr); }, - backCompat(constructor, methods) { + backCompat( + constructor: T, + methods: Record + ) { Util.each(methods, function (oldMethodName, newMethodName) { var method = constructor.prototype[newMethodName]; var oldGetter = GET + Util._capitalize(oldMethodName); @@ -164,7 +245,7 @@ export const Factory = { constructor.prototype[oldSetter] = deprecated; }); }, - afterSetFilter(this: Node) { + afterSetFilter(this: Node): void { this._filterUpToDate = false; }, }; diff --git a/src/Node.ts b/src/Node.ts index 98a2f1eeb..d090e7279 100644 --- a/src/Node.ts +++ b/src/Node.ts @@ -2660,7 +2660,7 @@ export abstract class Node { rotation: GetSet; zIndex: GetSet; - scale: GetSet; + scale: GetSet; scaleX: GetSet; scaleY: GetSet; skew: GetSet; @@ -3102,7 +3102,7 @@ addGetterSetter(Node, 'offsetY', 0, getNumberValidator()); * node.offsetY(3); */ -addGetterSetter(Node, 'dragDistance', null, getNumberValidator()); +addGetterSetter(Node, 'dragDistance', undefined, getNumberValidator()); /** * get/set drag distance @@ -3193,7 +3193,7 @@ addGetterSetter(Node, 'listening', true, getBooleanValidator()); addGetterSetter(Node, 'preventDefault', true, getBooleanValidator()); -addGetterSetter(Node, 'filters', null, function (this: Node, val) { +addGetterSetter(Node, 'filters', undefined, function (this: Node, val) { this._filterUpToDate = false; return val; }); diff --git a/src/Shape.ts b/src/Shape.ts index e34abbfd6..45e5c1ffd 100644 --- a/src/Shape.ts +++ b/src/Shape.ts @@ -843,6 +843,11 @@ export class Shape< strokeLinearGradientStartPoint: GetSet; strokeLinearGradientEndPoint: GetSet; strokeLinearGradientColorStops: GetSet, this>; + strokeLinearGradientStartPointX: GetSet; + strokeLinearGradientStartPointY: GetSet; + strokeLinearGradientEndPointX: GetSet; + strokeLinearGradientEndPointY: GetSet; + fillRule: GetSet; } Shape.prototype._fillFunc = _fillFunc; diff --git a/src/Validators.ts b/src/Validators.ts index 175c320d3..a8534b3b9 100644 --- a/src/Validators.ts +++ b/src/Validators.ts @@ -33,9 +33,9 @@ export function alphaComponent(val: number) { return val; } -export function getNumberValidator() { +export function getNumberValidator() { if (Konva.isUnminified) { - return function (val: T, attr: string): T | void { + return function (val: T, attr: string): T { if (!Util._isNumber(val)) { Util.warn( _formatValue(val) + @@ -49,9 +49,9 @@ export function getNumberValidator() { } } -export function getNumberOrArrayOfNumbersValidator(noOfElements: number) { +export function getNumberOrArrayOfNumbersValidator(noOfElements: number) { if (Konva.isUnminified) { - return function (val: T, attr: string): T | void { + return function (val: T, attr: string): T { let isNumber = Util._isNumber(val); let isValidArray = Util._isArray(val) && val.length == noOfElements; if (!isNumber && !isValidArray) { @@ -69,9 +69,9 @@ export function getNumberOrArrayOfNumbersValidator(noOfElements: number) { } } -export function getNumberOrAutoValidator() { +export function getNumberOrAutoValidator() { if (Konva.isUnminified) { - return function (val: T, attr: string): T | void { + return function (val: T, attr: string): T { var isNumber = Util._isNumber(val); var isAuto = val === 'auto'; @@ -88,9 +88,9 @@ export function getNumberOrAutoValidator() { } } -export function getStringValidator() { +export function getStringValidator() { if (Konva.isUnminified) { - return function (val: any, attr: string) { + return function (val: T, attr: string): T { if (!Util._isString(val)) { Util.warn( _formatValue(val) + @@ -104,13 +104,13 @@ export function getStringValidator() { } } -export function getStringOrGradientValidator() { +export function getStringOrGradientValidator() { if (Konva.isUnminified) { - return function (val: any, attr: string) { + return function (val: T, attr: string): T { const isString = Util._isString(val); const isGradient = Object.prototype.toString.call(val) === '[object CanvasGradient]' || - (val && val.addColorStop); + (val && val['addColorStop']); if (!(isString || isGradient)) { Util.warn( _formatValue(val) + @@ -124,9 +124,9 @@ export function getStringOrGradientValidator() { } } -export function getFunctionValidator() { +export function getFunctionValidator() { if (Konva.isUnminified) { - return function (val: any, attr: string) { + return function (val: T, attr: string): T { if (!Util._isFunction(val)) { Util.warn( _formatValue(val) + @@ -139,9 +139,9 @@ export function getFunctionValidator() { }; } } -export function getNumberArrayValidator() { +export function getNumberArrayValidator() { if (Konva.isUnminified) { - return function (val: any, attr: string) { + return function (val: T, attr: string): T { // Retrieve TypedArray constructor as found in MDN (if TypedArray is available) // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray#description const TypedArray = Int8Array ? Object.getPrototypeOf(Int8Array) : null; @@ -172,9 +172,9 @@ export function getNumberArrayValidator() { }; } } -export function getBooleanValidator() { +export function getBooleanValidator() { if (Konva.isUnminified) { - return function (val: any, attr: string) { + return function (val: T, attr: string): T { var isBool = val === true || val === false; if (!isBool) { Util.warn( @@ -188,9 +188,9 @@ export function getBooleanValidator() { }; } } -export function getComponentValidator(components: any) { +export function getComponentValidator(components: string[]) { if (Konva.isUnminified) { - return function (val: any, attr: string) { + return function (val: T, attr: string): T { // ignore validation on undefined value, because it will reset to defalt if (val === undefined || val === null) { return val; diff --git a/src/filters/Emboss.ts b/src/filters/Emboss.ts index 99bebca5c..f6fd1943c 100644 --- a/src/filters/Emboss.ts +++ b/src/filters/Emboss.ts @@ -174,7 +174,7 @@ Factory.addGetterSetter( Node, 'embossDirection', 'top-left', - null, + undefined, Factory.afterSetFilter ); /** @@ -190,7 +190,7 @@ Factory.addGetterSetter( Node, 'embossBlend', false, - null, + undefined, Factory.afterSetFilter ); /** diff --git a/src/shapes/Label.ts b/src/shapes/Label.ts index 6ac09f5ff..69ccf2093 100644 --- a/src/shapes/Label.ts +++ b/src/shapes/Label.ts @@ -317,7 +317,10 @@ export class Tag extends Shape { }; } - pointerDirection: GetSet<'left' | 'top' | 'right' | 'bottom', this>; + pointerDirection: GetSet< + 'left' | 'top' | 'right' | 'bottom' | typeof NONE, + this + >; pointerWidth: GetSet; pointerHeight: GetSet; cornerRadius: GetSet; diff --git a/src/shapes/TextPath.ts b/src/shapes/TextPath.ts index f329ef3a2..d9f05ca55 100644 --- a/src/shapes/TextPath.ts +++ b/src/shapes/TextPath.ts @@ -551,7 +551,7 @@ Factory.addGetterSetter(TextPath, 'text', EMPTY_STRING); * // underline text * shape.textDecoration('underline'); */ -Factory.addGetterSetter(TextPath, 'textDecoration', null); +Factory.addGetterSetter(TextPath, 'textDecoration', undefined); /** * get/set kerning function. @@ -568,4 +568,4 @@ Factory.addGetterSetter(TextPath, 'textDecoration', null); * return 1; * }); */ -Factory.addGetterSetter(TextPath, 'kerningFunc', null); +Factory.addGetterSetter(TextPath, 'kerningFunc', undefined); diff --git a/src/shapes/Transformer.ts b/src/shapes/Transformer.ts index 859608875..004ab8755 100644 --- a/src/shapes/Transformer.ts +++ b/src/shapes/Transformer.ts @@ -1745,8 +1745,6 @@ Factory.addGetterSetter(Transformer, 'ignoreStroke', false); */ Factory.addGetterSetter(Transformer, 'padding', 0, getNumberValidator()); -Factory.addGetterSetter(Transformer, 'node'); - /** * get/set attached nodes of the Transformer. Transformer will adapt to their size and listen to their events * @method