Skip to content

Commit

Permalink
feat: Factory types
Browse files Browse the repository at this point in the history
  • Loading branch information
psychedelicious committed Aug 25, 2024
1 parent 583fccf commit 9c41a6e
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 46 deletions.
115 changes: 98 additions & 17 deletions src/Factory.ts
Original file line number Diff line number Diff line change
@@ -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> = 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<T extends Constructor> = EnforceString<keyof InstanceType<T>>;

/**
* A function that is called after a setter is called.
*/
type AfterFunc<T extends Constructor> = (this: InstanceType<T>) => void;

/**
* Extracts the type of a GetSet.
*/
type ExtractGetSet<T> = T extends GetSet<infer U, any> ? U : never;

/**
* Extracts the type of a GetSet class attribute.
*/
type Value<T extends Constructor, U extends Attr<T>> = ExtractGetSet<
InstanceType<T>[U]
>;

/**
* A function that validates a value.
*/
type ValidatorFunc<T> = (val: ExtractGetSet<T>, attr: string) => T;

/**
* Extracts the "components" (keys) of a GetSet value. The value must be an object.
*/
type ExtractComponents<T extends Constructor, U extends Attr<T>> = Value<
T,
U
> extends Record<string, any>
? EnforceString<keyof Value<T, U>>[]
: never;

export const Factory = {
addGetterSetter(constructor, attr, def?, validator?, after?) {
addGetterSetter<T extends Constructor, U extends Attr<T>>(
constructor: T,
attr: U,
def?: Value<T, U>,
validator?: ValidatorFunc<Value<T, U>>,
after?: AfterFunc<T>
): void {
Factory.addGetter(constructor, attr, def);
Factory.addSetter(constructor, attr, validator, after);
Factory.addOverloadedGetterSetter(constructor, attr);
},
addGetter(constructor, attr, def?) {
addGetter<T extends Constructor, U extends Attr<T>>(
constructor: T,
attr: U,
def?: Value<T, U>
) {
var method = GET + Util._capitalize(attr);

constructor.prototype[method] =
Expand All @@ -22,14 +80,25 @@ export const Factory = {
};
},

addSetter(constructor, attr, validator?, after?) {
addSetter<T extends Constructor, U extends Attr<T>>(
constructor: T,
attr: U,
validator?: ValidatorFunc<Value<T, U>>,
after?: AfterFunc<T>
) {
var method = SET + Util._capitalize(attr);

if (!constructor.prototype[method]) {
Factory.overWriteSetter(constructor, attr, validator, after);
}
},
overWriteSetter(constructor, attr, validator?, after?) {

overWriteSetter<T extends Constructor, U extends Attr<T>>(
constructor: T,
attr: U,
validator?: ValidatorFunc<Value<T, U>>,
after?: AfterFunc<T>
) {
var method = SET + Util._capitalize(attr);
constructor.prototype[method] = function (val) {
if (validator && val !== undefined && val !== null) {
Expand All @@ -45,12 +114,13 @@ export const Factory = {
return this;
};
},
addComponentsGetterSetter(
constructor,
attr: string,
components: Array<string>,
validator?: Function,
after?: Function

addComponentsGetterSetter<T extends Constructor, U extends Attr<T>>(
constructor: T,
attr: U,
components: ExtractComponents<T, U>,
validator?: ValidatorFunc<Value<T, U>>,
after?: AfterFunc<T>
) {
var len = components.length,
capitalize = Util._capitalize,
Expand Down Expand Up @@ -79,7 +149,7 @@ export const Factory = {
key;

if (validator) {
val = validator.call(this, val);
val = validator.call(this, val, attr);
}

if (basicValidator) {
Expand Down Expand Up @@ -109,7 +179,10 @@ export const Factory = {

Factory.addOverloadedGetterSetter(constructor, attr);
},
addOverloadedGetterSetter(constructor, attr) {
addOverloadedGetterSetter<T extends Constructor, U extends Attr<T>>(
constructor: T,
attr: U
) {
var capitalizedAttr = Util._capitalize(attr),
setter = SET + capitalizedAttr,
getter = GET + capitalizedAttr;
Expand All @@ -124,7 +197,12 @@ export const Factory = {
return this[getter]();
};
},
addDeprecatedGetterSetter(constructor, attr, def, validator) {
addDeprecatedGetterSetter<T extends Constructor, U extends Attr<T>>(
constructor: T,
attr: U,
def: Value<T, U>,
validator: ValidatorFunc<Value<T, U>>
) {
Util.error('Adding deprecated ' + attr);

var method = GET + Util._capitalize(attr);
Expand All @@ -142,7 +220,10 @@ export const Factory = {
});
Factory.addOverloadedGetterSetter(constructor, attr);
},
backCompat(constructor, methods) {
backCompat<T extends Constructor>(
constructor: T,
methods: Record<string, string>
) {
Util.each(methods, function (oldMethodName, newMethodName) {
var method = constructor.prototype[newMethodName];
var oldGetter = GET + Util._capitalize(oldMethodName);
Expand All @@ -164,7 +245,7 @@ export const Factory = {
constructor.prototype[oldSetter] = deprecated;
});
},
afterSetFilter(this: Node) {
afterSetFilter(this: Node): void {
this._filterUpToDate = false;
},
};
6 changes: 3 additions & 3 deletions src/Node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2660,7 +2660,7 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
rotation: GetSet<number, this>;
zIndex: GetSet<number, this>;

scale: GetSet<Vector2d | undefined, this>;
scale: GetSet<Vector2d, this>;
scaleX: GetSet<number, this>;
scaleY: GetSet<number, this>;
skew: GetSet<Vector2d, this>;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
});
Expand Down
5 changes: 5 additions & 0 deletions src/Shape.ts
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,11 @@ export class Shape<
strokeLinearGradientStartPoint: GetSet<Vector2d, this>;
strokeLinearGradientEndPoint: GetSet<Vector2d, this>;
strokeLinearGradientColorStops: GetSet<Array<number | string>, this>;
strokeLinearGradientStartPointX: GetSet<number, this>;
strokeLinearGradientStartPointY: GetSet<number, this>;
strokeLinearGradientEndPointX: GetSet<number, this>;
strokeLinearGradientEndPointY: GetSet<number, this>;
fillRule: GetSet<CanvasFillRule, this>;
}

Shape.prototype._fillFunc = _fillFunc;
Expand Down
38 changes: 19 additions & 19 deletions src/Validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ export function alphaComponent(val: number) {
return val;
}

export function getNumberValidator() {
export function getNumberValidator<T>() {
if (Konva.isUnminified) {
return function <T>(val: T, attr: string): T | void {
return function (val: T, attr: string): T {
if (!Util._isNumber(val)) {
Util.warn(
_formatValue(val) +
Expand All @@ -49,9 +49,9 @@ export function getNumberValidator() {
}
}

export function getNumberOrArrayOfNumbersValidator(noOfElements: number) {
export function getNumberOrArrayOfNumbersValidator<T>(noOfElements: number) {
if (Konva.isUnminified) {
return function <T>(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) {
Expand All @@ -69,9 +69,9 @@ export function getNumberOrArrayOfNumbersValidator(noOfElements: number) {
}
}

export function getNumberOrAutoValidator() {
export function getNumberOrAutoValidator<T>() {
if (Konva.isUnminified) {
return function <T extends string>(val: T, attr: string): T | void {
return function (val: T, attr: string): T {
var isNumber = Util._isNumber(val);
var isAuto = val === 'auto';

Expand All @@ -88,9 +88,9 @@ export function getNumberOrAutoValidator() {
}
}

export function getStringValidator() {
export function getStringValidator<T>() {
if (Konva.isUnminified) {
return function (val: any, attr: string) {
return function (val: T, attr: string): T {
if (!Util._isString(val)) {
Util.warn(
_formatValue(val) +
Expand All @@ -104,13 +104,13 @@ export function getStringValidator() {
}
}

export function getStringOrGradientValidator() {
export function getStringOrGradientValidator<T>() {
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) +
Expand All @@ -124,9 +124,9 @@ export function getStringOrGradientValidator() {
}
}

export function getFunctionValidator() {
export function getFunctionValidator<T>() {
if (Konva.isUnminified) {
return function (val: any, attr: string) {
return function (val: T, attr: string): T {
if (!Util._isFunction(val)) {
Util.warn(
_formatValue(val) +
Expand All @@ -139,9 +139,9 @@ export function getFunctionValidator() {
};
}
}
export function getNumberArrayValidator() {
export function getNumberArrayValidator<T>() {
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;
Expand Down Expand Up @@ -172,9 +172,9 @@ export function getNumberArrayValidator() {
};
}
}
export function getBooleanValidator() {
export function getBooleanValidator<T>() {
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(
Expand All @@ -188,9 +188,9 @@ export function getBooleanValidator() {
};
}
}
export function getComponentValidator(components: any) {
export function getComponentValidator<T>(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;
Expand Down
4 changes: 2 additions & 2 deletions src/filters/Emboss.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ Factory.addGetterSetter(
Node,
'embossDirection',
'top-left',
null,
undefined,
Factory.afterSetFilter
);
/**
Expand All @@ -190,7 +190,7 @@ Factory.addGetterSetter(
Node,
'embossBlend',
false,
null,
undefined,
Factory.afterSetFilter
);
/**
Expand Down
5 changes: 4 additions & 1 deletion src/shapes/Label.ts
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,10 @@ export class Tag extends Shape<TagConfig> {
};
}

pointerDirection: GetSet<'left' | 'top' | 'right' | 'bottom', this>;
pointerDirection: GetSet<
'left' | 'top' | 'right' | 'bottom' | typeof NONE,
this
>;
pointerWidth: GetSet<number, this>;
pointerHeight: GetSet<number, this>;
cornerRadius: GetSet<number, this>;
Expand Down
4 changes: 2 additions & 2 deletions src/shapes/TextPath.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -568,4 +568,4 @@ Factory.addGetterSetter(TextPath, 'textDecoration', null);
* return 1;
* });
*/
Factory.addGetterSetter(TextPath, 'kerningFunc', null);
Factory.addGetterSetter(TextPath, 'kerningFunc', undefined);
2 changes: 0 additions & 2 deletions src/shapes/Transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 9c41a6e

Please sign in to comment.