From 37bd2433525cb888def8cb58fe80b6f6992f6f6b Mon Sep 17 00:00:00 2001 From: Eugene Obrezkov Date: Sat, 25 Apr 2020 20:05:15 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20generic=20interface=20Sh?= =?UTF-8?q?apeObject=20over=20type=20and=20options?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ShapeObject interface from kittik-shape-basic is generic over type of the shape and options it can accept now --- packages/kittik-shape-basic/src/Shape.ts | 42 ++++++++++--------- .../kittik-shape-basic/src/ShapeObject.ts | 6 +-- packages/kittik-shape-code/src/Code.ts | 11 +++++ packages/kittik-shape-code/src/CodeObject.ts | 4 +- packages/kittik-shape-fig-text/src/FigText.ts | 11 ++--- .../src/FigTextObject.ts | 4 +- packages/kittik-shape-image/src/Image.ts | 11 ++--- .../kittik-shape-image/src/ImageObject.ts | 4 +- .../kittik-shape-rectangle/src/Rectangle.ts | 11 +++++ .../src/RectangleObject.ts | 4 +- packages/kittik-shape-text/src/Text.ts | 11 ++--- packages/kittik-shape-text/src/TextObject.ts | 4 +- packages/kittik-slide/spec/Slide.spec.ts | 4 +- .../kittik-slide/src/shape/ShapeBuilder.ts | 9 ++-- .../src/shape/ShapeDeclaration.ts | 4 +- packages/kittik-slide/src/shape/Shapes.ts | 10 +++-- packages/kittik-slide/src/slide/Slide.ts | 10 +++-- .../src/slide/SlideDeclaration.ts | 4 +- 18 files changed, 97 insertions(+), 67 deletions(-) diff --git a/packages/kittik-shape-basic/src/Shape.ts b/packages/kittik-shape-basic/src/Shape.ts index 12c3432..2e5f279 100644 --- a/packages/kittik-shape-basic/src/Shape.ts +++ b/packages/kittik-shape-basic/src/Shape.ts @@ -47,13 +47,14 @@ export class Shape implements ShapeOptions, ShapeRenderable { } } - public static create(options?: Partial): T - public static create(options?: Partial): T { - return (new this(options)) as T; + public static create >(options?: O): S { + return (new this(options)) as S; } - public static fromObject(obj: ShapeObject): T - public static fromObject(obj: O): T { + public static fromObject (obj: ShapeObject): S + public static fromObject (obj: ShapeObject): Shape + public static fromObject (obj: ShapeObject): 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}". ` + @@ -64,7 +65,7 @@ export class Shape implements ShapeOptions, ShapeRenderable { return this.create(obj.options); } - public static fromJSON(json: string): T { + public static fromJSON (json: string): S { return this.fromObject(JSON.parse(json)); } @@ -158,20 +159,21 @@ export class Shape implements ShapeOptions, ShapeRenderable { this.rawCanvas = canvas; } - public toObject(): 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 (): ShapeObject + public toObject (): ShapeObject + 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 { diff --git a/packages/kittik-shape-basic/src/ShapeObject.ts b/packages/kittik-shape-basic/src/ShapeObject.ts index 1522c49..67a1bb3 100644 --- a/packages/kittik-shape-basic/src/ShapeObject.ts +++ b/packages/kittik-shape-basic/src/ShapeObject.ts @@ -1,6 +1,6 @@ import { ShapeOptions } from './ShapeOptions'; -export interface ShapeObject { - type: string - options?: Partial +export interface ShapeObject { + type: T + options: O } diff --git a/packages/kittik-shape-code/src/Code.ts b/packages/kittik-shape-code/src/Code.ts index 82bdcd5..f42c270 100644 --- a/packages/kittik-shape-code/src/Code.ts +++ b/packages/kittik-shape-code/src/Code.ts @@ -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'; @@ -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 }; + } } diff --git a/packages/kittik-shape-code/src/CodeObject.ts b/packages/kittik-shape-code/src/CodeObject.ts index 731afa5..a1e93f3 100644 --- a/packages/kittik-shape-code/src/CodeObject.ts +++ b/packages/kittik-shape-code/src/CodeObject.ts @@ -1,6 +1,4 @@ import { CodeOptions } from './CodeOptions'; import { ShapeObject } from 'kittik-shape-basic'; -export interface CodeObject extends ShapeObject { - options?: Partial -} +export type CodeObject = ShapeObject<'Code', CodeOptions>; diff --git a/packages/kittik-shape-fig-text/src/FigText.ts b/packages/kittik-shape-fig-text/src/FigText.ts index a54e146..3124f98 100644 --- a/packages/kittik-shape-fig-text/src/FigText.ts +++ b/packages/kittik-shape-fig-text/src/FigText.ts @@ -69,10 +69,11 @@ export class FigText extends Shape implements FigTextOptions, ShapeRenderable { text.forEach((line, index) => canvas.moveTo(x, y + index).write(line)); } - public toObject(): 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, @@ -80,6 +81,6 @@ export class FigText extends Shape implements FigTextOptions, ShapeRenderable { verticalLayout: this.verticalLayout }; - return obj as T; + return { type, options }; } } diff --git a/packages/kittik-shape-fig-text/src/FigTextObject.ts b/packages/kittik-shape-fig-text/src/FigTextObject.ts index 1d55d10..1a6b1dd 100644 --- a/packages/kittik-shape-fig-text/src/FigTextObject.ts +++ b/packages/kittik-shape-fig-text/src/FigTextObject.ts @@ -1,6 +1,4 @@ import { FigTextOptions } from './FigTextOptions'; import { ShapeObject } from 'kittik-shape-basic'; -export interface FigTextObject extends ShapeObject { - options?: Partial -} +export type FigTextObject = ShapeObject<'FigText', FigTextOptions>; diff --git a/packages/kittik-shape-image/src/Image.ts b/packages/kittik-shape-image/src/Image.ts index 6a93607..5c5e2af 100644 --- a/packages/kittik-shape-image/src/Image.ts +++ b/packages/kittik-shape-image/src/Image.ts @@ -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 { - 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 }; } } diff --git a/packages/kittik-shape-image/src/ImageObject.ts b/packages/kittik-shape-image/src/ImageObject.ts index 09fd583..31081a5 100644 --- a/packages/kittik-shape-image/src/ImageObject.ts +++ b/packages/kittik-shape-image/src/ImageObject.ts @@ -1,6 +1,4 @@ import { ImageOptions } from './ImageOptions'; import { ShapeObject } from 'kittik-shape-basic'; -export interface ImageObject extends ShapeObject { - options?: Partial -} +export type ImageObject = ShapeObject<'Image', ImageOptions>; diff --git a/packages/kittik-shape-rectangle/src/Rectangle.ts b/packages/kittik-shape-rectangle/src/Rectangle.ts index b957b61..b632783 100644 --- a/packages/kittik-shape-rectangle/src/Rectangle.ts +++ b/packages/kittik-shape-rectangle/src/Rectangle.ts @@ -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'; @@ -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 }; + } } diff --git a/packages/kittik-shape-rectangle/src/RectangleObject.ts b/packages/kittik-shape-rectangle/src/RectangleObject.ts index 5b730a5..d3723b9 100644 --- a/packages/kittik-shape-rectangle/src/RectangleObject.ts +++ b/packages/kittik-shape-rectangle/src/RectangleObject.ts @@ -1,6 +1,4 @@ import { RectangleOptions } from './RectangleOptions'; import { ShapeObject } from 'kittik-shape-basic'; -export interface RectangleObject extends ShapeObject { - options?: Partial -} +export type RectangleObject = ShapeObject<'Rectangle', RectangleOptions>; diff --git a/packages/kittik-shape-text/src/Text.ts b/packages/kittik-shape-text/src/Text.ts index 1ac53fe..7b80125 100644 --- a/packages/kittik-shape-text/src/Text.ts +++ b/packages/kittik-shape-text/src/Text.ts @@ -91,10 +91,11 @@ export class Text extends Shape implements TextOptions, ShapeRenderable { }); } - public toObject(): 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, @@ -104,6 +105,6 @@ export class Text extends Shape implements TextOptions, ShapeRenderable { underlined: this.underlined }; - return obj as T; + return { type, options }; } } diff --git a/packages/kittik-shape-text/src/TextObject.ts b/packages/kittik-shape-text/src/TextObject.ts index 8929e39..86b79c7 100644 --- a/packages/kittik-shape-text/src/TextObject.ts +++ b/packages/kittik-shape-text/src/TextObject.ts @@ -1,6 +1,4 @@ import { ShapeObject } from 'kittik-shape-basic'; import { TextOptions } from './TextOptions'; -export interface TextObject extends ShapeObject { - options?: Partial -} +export type TextObject = ShapeObject<'Text', TextOptions>; diff --git a/packages/kittik-slide/spec/Slide.spec.ts b/packages/kittik-slide/spec/Slide.spec.ts index f563970..58cc6d1 100644 --- a/packages/kittik-slide/spec/Slide.spec.ts +++ b/packages/kittik-slide/spec/Slide.spec.ts @@ -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'; @@ -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: { diff --git a/packages/kittik-slide/src/shape/ShapeBuilder.ts b/packages/kittik-slide/src/shape/ShapeBuilder.ts index 87362c1..435c5f0 100644 --- a/packages/kittik-slide/src/shape/ShapeBuilder.ts +++ b/packages/kittik-slide/src/shape/ShapeBuilder.ts @@ -1,13 +1,16 @@ import { SHAPES, ShapeOptions, ShapeType } from './Shapes'; import { ShapeObject, ShapeRenderable } from 'kittik-shape-basic'; -export class ShapeBuilder> implements ShapeObject { +export class ShapeBuilder> implements ShapeObject { public type: T; - public options: Partial; + 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 >(type: T): ShapeBuilder { diff --git a/packages/kittik-slide/src/shape/ShapeDeclaration.ts b/packages/kittik-slide/src/shape/ShapeDeclaration.ts index 2f3a6e3..56e9393 100644 --- a/packages/kittik-slide/src/shape/ShapeDeclaration.ts +++ b/packages/kittik-slide/src/shape/ShapeDeclaration.ts @@ -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 extends ShapeObject { name: string } diff --git a/packages/kittik-slide/src/shape/Shapes.ts b/packages/kittik-slide/src/shape/Shapes.ts index d5dabed..910a526 100644 --- a/packages/kittik-slide/src/shape/Shapes.ts +++ b/packages/kittik-slide/src/shape/Shapes.ts @@ -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 'Code' ? CodeOptions : T extends 'FigText' @@ -17,8 +19,10 @@ export type ShapeOptions = 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 'Code' ? CodeObject : T extends 'FigText' @@ -29,7 +33,7 @@ export type ShapeObject = T extends 'Code' ? RectangleObject : T extends 'Text' ? TextObject - : never; + : BasicShapeObject; export const SHAPES = new Map([ ['Code', Code], diff --git a/packages/kittik-slide/src/slide/Slide.ts b/packages/kittik-slide/src/slide/Slide.ts index 0c01e3e..99cfdc1 100644 --- a/packages/kittik-slide/src/slide/Slide.ts +++ b/packages/kittik-slide/src/slide/Slide.ts @@ -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'; @@ -154,6 +154,10 @@ 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 }; } @@ -161,9 +165,9 @@ export class Slide< return JSON.stringify(this.toObject()); } - private initShapes (declaration: ShapeDeclaration[]): void { + private initShapes (declaration: Array>): 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( diff --git a/packages/kittik-slide/src/slide/SlideDeclaration.ts b/packages/kittik-slide/src/slide/SlideDeclaration.ts index 09cc0c6..2917b5d 100644 --- a/packages/kittik-slide/src/slide/SlideDeclaration.ts +++ b/packages/kittik-slide/src/slide/SlideDeclaration.ts @@ -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> animations?: AnimationDeclaration[] order: OrderDeclaration[] }