Skip to content

Commit

Permalink
feat: 🎸 generic interface ShapeObject over type and options
Browse files Browse the repository at this point in the history
ShapeObject interface from kittik-shape-basic is generic over type of
the shape and options it can accept now
  • Loading branch information
ghaiklor committed Apr 25, 2020
1 parent fb2e063 commit 37bd243
Show file tree
Hide file tree
Showing 18 changed files with 97 additions and 67 deletions.
42 changes: 22 additions & 20 deletions packages/kittik-shape-basic/src/Shape.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,14 @@ export class Shape implements ShapeOptions, ShapeRenderable {
}
}

public static create<T extends Shape>(options?: Partial<ShapeOptions>): T
public static create<T extends Shape, O extends ShapeOptions>(options?: Partial<O>): T {
return (new this(options)) as T;
public static create <S extends Shape, O extends Partial<ShapeOptions>>(options?: O): S {
return (new this(options)) as S;
}

public static fromObject<T extends Shape>(obj: ShapeObject): T
public static fromObject<T extends Shape, O extends ShapeObject>(obj: O): T {
public static fromObject <T, O extends ShapeOptions, S extends Shape>(obj: ShapeObject<T, O>): S
public static fromObject <T, O extends ShapeOptions>(obj: ShapeObject<T, O>): Shape
public static fromObject <T>(obj: ShapeObject<T, ShapeOptions>): Shape
public static fromObject (obj: ShapeObject<'Basic', ShapeOptions>): Shape {
if (obj.type !== this.name) {
throw new Error(
`You specified configuration for "${obj.type}" but provided it to "${this.name}". ` +
Expand All @@ -64,7 +65,7 @@ export class Shape implements ShapeOptions, ShapeRenderable {
return this.create(obj.options);
}

public static fromJSON<T extends Shape>(json: string): T {
public static fromJSON <S extends Shape>(json: string): S {
return this.fromObject(JSON.parse(json));
}

Expand Down Expand Up @@ -158,20 +159,21 @@ export class Shape implements ShapeOptions, ShapeRenderable {
this.rawCanvas = canvas;
}

public toObject<T extends ShapeObject>(): T {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return {
type: this.constructor.name,
options: {
background: this.rawBackground,
foreground: this.rawForeground,
height: this.rawHeight,
text: this.rawText,
width: this.rawWidth,
x: this.rawX,
y: this.rawY
}
} as T;
public toObject <T, O extends ShapeOptions>(): ShapeObject<T, O>
public toObject <T>(): ShapeObject<T, ShapeOptions>
public toObject (): ShapeObject<'Basic', ShapeOptions> {
const type: 'Basic' = 'Basic' as const;
const options: ShapeOptions = {
background: this.rawBackground,
foreground: this.rawForeground,
height: this.rawHeight,
text: this.rawText,
width: this.rawWidth,
x: this.rawX,
y: this.rawY
};

return { type, options };
}

public toJSON (): string {
Expand Down
6 changes: 3 additions & 3 deletions packages/kittik-shape-basic/src/ShapeObject.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ShapeOptions } from './ShapeOptions';

export interface ShapeObject {
type: string
options?: Partial<ShapeOptions>
export interface ShapeObject<T, O extends ShapeOptions> {
type: T
options: O
}
11 changes: 11 additions & 0 deletions packages/kittik-shape-code/src/Code.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Shape, ShapeRenderable } from 'kittik-shape-basic';
import { Canvas } from 'terminal-canvas';
import { CodeObject } from './CodeObject';
import { CodeOptions } from './CodeOptions';
import { DEFAULT_THEME } from './themes/default';
import { js_beautify as beautify } from 'js-beautify';
Expand Down Expand Up @@ -47,4 +48,14 @@ export class Code extends Shape implements CodeOptions, ShapeRenderable {
}
});
}

public toObject (): CodeObject {
const base = super.toObject();
const type: CodeObject['type'] = 'Code';
const options: CodeObject['options'] = {
...base.options
};

return { type, options };
}
}
4 changes: 1 addition & 3 deletions packages/kittik-shape-code/src/CodeObject.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { CodeOptions } from './CodeOptions';
import { ShapeObject } from 'kittik-shape-basic';

export interface CodeObject extends ShapeObject {
options?: Partial<CodeOptions>
}
export type CodeObject = ShapeObject<'Code', CodeOptions>;
11 changes: 6 additions & 5 deletions packages/kittik-shape-fig-text/src/FigText.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,17 +69,18 @@ export class FigText extends Shape implements FigTextOptions, ShapeRenderable {
text.forEach((line, index) => canvas.moveTo(x, y + index).write(line));
}

public toObject<T extends FigTextObject>(): T {
const obj: FigTextObject = super.toObject();
obj.options = {
...obj.options,
public toObject (): FigTextObject {
const base = super.toObject();
const type: FigTextObject['type'] = 'FigText';
const options: FigTextObject['options'] = {
...base.options,
font: this.font,
horizontalLayout: this.horizontalLayout,
printDirection: this.printDirection,
showHardBlanks: this.showHardBlanks,
verticalLayout: this.verticalLayout
};

return obj as T;
return { type, options };
}
}
4 changes: 1 addition & 3 deletions packages/kittik-shape-fig-text/src/FigTextObject.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { FigTextOptions } from './FigTextOptions';
import { ShapeObject } from 'kittik-shape-basic';

export interface FigTextObject extends ShapeObject {
options?: Partial<FigTextOptions>
}
export type FigTextObject = ShapeObject<'FigText', FigTextOptions>;
11 changes: 6 additions & 5 deletions packages/kittik-shape-image/src/Image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,15 @@ export class Image extends Shape implements ImageOptions, ShapeRenderable {
canvas.stream.write(`\u001b[${y + 1};${x + 1}H\u001b]1337;File=${args}:${image}^G`);
}

public toObject<T extends ImageObject>(): T {
const obj: ImageObject = super.toObject();
obj.options = {
...obj.options,
public toObject (): ImageObject {
const base = super.toObject();
const type: ImageObject['type'] = 'Image';
const options: ImageObject['options'] = {
...base.options,
image: this.rawImageOrPath,
preserveAspectRatio: this.rawPreserveAspectRatio
};

return obj as T;
return { type, options };
}
}
4 changes: 1 addition & 3 deletions packages/kittik-shape-image/src/ImageObject.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { ImageOptions } from './ImageOptions';
import { ShapeObject } from 'kittik-shape-basic';

export interface ImageObject extends ShapeObject {
options?: Partial<ImageOptions>
}
export type ImageObject = ShapeObject<'Image', ImageOptions>;
11 changes: 11 additions & 0 deletions packages/kittik-shape-rectangle/src/Rectangle.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Shape, ShapeRenderable } from 'kittik-shape-basic';
import { Canvas } from 'terminal-canvas';
import { RectangleObject } from './RectangleObject';
import { RectangleOptions } from './RectangleOptions';

export { RectangleObject } from './RectangleObject';
Expand Down Expand Up @@ -30,4 +31,14 @@ export class Rectangle extends Shape implements RectangleOptions, ShapeRenderabl
.moveTo(x1 + (width / 2 - text.length / 2), y1 + height / 2)
.write(text);
}

public toObject (): RectangleObject {
const base = super.toObject();
const type: RectangleObject['type'] = 'Rectangle';
const options: RectangleObject['options'] = {
...base.options
};

return { type, options };
}
}
4 changes: 1 addition & 3 deletions packages/kittik-shape-rectangle/src/RectangleObject.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { RectangleOptions } from './RectangleOptions';
import { ShapeObject } from 'kittik-shape-basic';

export interface RectangleObject extends ShapeObject {
options?: Partial<RectangleOptions>
}
export type RectangleObject = ShapeObject<'Rectangle', RectangleOptions>;
11 changes: 6 additions & 5 deletions packages/kittik-shape-text/src/Text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,11 @@ export class Text extends Shape implements TextOptions, ShapeRenderable {
});
}

public toObject<T extends TextObject>(): T {
const obj: TextObject = super.toObject();
obj.options = {
...obj.options,
public toObject (): TextObject {
const base = super.toObject();
const type: TextObject['type'] = 'Text';
const options: TextObject['options'] = {
...base.options,
align: this.align,
blink: this.blink,
bold: this.bold,
Expand All @@ -104,6 +105,6 @@ export class Text extends Shape implements TextOptions, ShapeRenderable {
underlined: this.underlined
};

return obj as T;
return { type, options };
}
}
4 changes: 1 addition & 3 deletions packages/kittik-shape-text/src/TextObject.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { ShapeObject } from 'kittik-shape-basic';
import { TextOptions } from './TextOptions';

export interface TextObject extends ShapeObject {
options?: Partial<TextOptions>
}
export type TextObject = ShapeObject<'Text', TextOptions>;
4 changes: 2 additions & 2 deletions packages/kittik-slide/spec/Slide.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Text, TextObject } from 'kittik-shape-text';
import { Text, TextObject, TextOptions } from 'kittik-shape-text';
import { AnimationDeclaration } from '../src/animation/AnimationDeclaration';
import { AnimationObject } from 'kittik-animation-basic';
import { Canvas } from 'terminal-canvas';
Expand Down Expand Up @@ -33,7 +33,7 @@ const SLIDE_DECLARATION: SlideDeclaration = {
}]
};

const SERIALIZED_TEXT_DECLARATION: ShapeDeclaration & TextObject = {
const SERIALIZED_TEXT_DECLARATION: ShapeDeclaration<'Text', TextOptions> & TextObject = {
name: 'Hello',
type: 'Text',
options: {
Expand Down
9 changes: 6 additions & 3 deletions packages/kittik-slide/src/shape/ShapeBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { SHAPES, ShapeOptions, ShapeType } from './Shapes';
import { ShapeObject, ShapeRenderable } from 'kittik-shape-basic';

export class ShapeBuilder<T extends ShapeType, O extends ShapeOptions<T>> implements ShapeObject {
export class ShapeBuilder<T extends ShapeType, O extends ShapeOptions<T>> implements ShapeObject<T, O> {
public type: T;
public options: Partial<O>;
public options: O;

public constructor (type: T) {
this.type = type;
this.options = {};

// eslint-disable-next-line no-warning-comments
// TODO: hmm, think about this unknown
this.options = {} as unknown as O;
}

public static start <T extends ShapeType, O extends ShapeOptions<T>>(type: T): ShapeBuilder<T, O> {
Expand Down
4 changes: 2 additions & 2 deletions packages/kittik-slide/src/shape/ShapeDeclaration.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ShapeObject } from 'kittik-shape-basic';
import { ShapeObject, ShapeOptions } from 'kittik-shape-basic';

export interface ShapeDeclaration extends ShapeObject {
export interface ShapeDeclaration<T, O extends ShapeOptions> extends ShapeObject<T, O> {
name: string
}
10 changes: 7 additions & 3 deletions packages/kittik-slide/src/shape/Shapes.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { ShapeObject as BasicShapeObject, ShapeOptions as BasicShapeOptions, Shape } from 'kittik-shape-basic';
import { Code, CodeObject, CodeOptions } from 'kittik-shape-code';
import { FigText, FigTextObject, FigTextOptions } from 'kittik-shape-fig-text';
import { Image, ImageObject, ImageOptions } from 'kittik-shape-image';
import { Rectangle, RectangleObject, RectangleOptions } from 'kittik-shape-rectangle';
import { Text, TextObject, TextOptions } from 'kittik-shape-text';
import { Shape } from 'kittik-shape-basic';

export type ShapeType = 'Code' | 'FigText' | 'Image' | 'Rectangle' | 'Text';

// eslint-disable-next-line no-warning-comments
// TODO: refactor this
export type ShapeOptions<T extends ShapeType> = T extends 'Code'
? CodeOptions
: T extends 'FigText'
Expand All @@ -17,8 +19,10 @@ export type ShapeOptions<T extends ShapeType> = T extends 'Code'
? RectangleOptions
: T extends 'Text'
? TextOptions
: never;
: BasicShapeOptions;

// eslint-disable-next-line no-warning-comments
// TODO: refactor this
export type ShapeObject<T extends ShapeType> = T extends 'Code'
? CodeObject
: T extends 'FigText'
Expand All @@ -29,7 +33,7 @@ export type ShapeObject<T extends ShapeType> = T extends 'Code'
? RectangleObject
: T extends 'Text'
? TextObject
: never;
: BasicShapeObject<T, BasicShapeOptions>;

export const SHAPES = new Map<ShapeType, typeof Shape>([
['Code', Code],
Expand Down
10 changes: 7 additions & 3 deletions packages/kittik-slide/src/slide/Slide.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { ANIMATIONS, AnimationType } from '../animation/Animations';
import { SHAPES, ShapeType } from '../shape/Shapes';
import { ShapeOptions, ShapeRenderable } from 'kittik-shape-basic';
import { AnimationDeclaration } from '../animation/AnimationDeclaration';
import { Animationable } from 'kittik-animation-basic';
import { Canvas } from 'terminal-canvas';
import { OrderDeclaration } from './OrderDeclaration';
import { ShapeDeclaration } from '../shape/ShapeDeclaration';
import { ShapeRenderable } from 'kittik-shape-basic';
import { SlideDeclaration } from './SlideDeclaration';

export { AnimationBuilder } from '../animation/AnimationBuilder';
Expand Down Expand Up @@ -154,16 +154,20 @@ export class Slide<
const animations = [...this.animations.entries()]
.map(([animationName, animation]) => ({ ...animation.toObject(), name: animationName }));

// eslint-disable-next-line no-warning-comments
// TODO: think about these array declarations
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
return { animations, name, order, shapes };
}

public toJSON (): string {
return JSON.stringify(this.toObject());
}

private initShapes (declaration: ShapeDeclaration[]): void {
private initShapes (declaration: Array<ShapeDeclaration<ShapeType, ShapeOptions>>): void {
declaration.forEach((shapeDeclaration) => {
const ctor = SHAPES.get(shapeDeclaration.type as ShapeType);
const ctor = SHAPES.get(shapeDeclaration.type);

if (typeof ctor === 'undefined') {
throw new Error(
Expand Down
4 changes: 3 additions & 1 deletion packages/kittik-slide/src/slide/SlideDeclaration.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { AnimationDeclaration } from '../animation/AnimationDeclaration';
import { OrderDeclaration } from './OrderDeclaration';
import { ShapeDeclaration } from '../shape/ShapeDeclaration';
import { ShapeOptions } from 'kittik-shape-basic';
import { ShapeType } from '../shape/Shapes';

export interface SlideDeclaration {
name: string
shapes: ShapeDeclaration[]
shapes: Array<ShapeDeclaration<ShapeType, ShapeOptions>>
animations?: AnimationDeclaration[]
order: OrderDeclaration[]
}

0 comments on commit 37bd243

Please sign in to comment.