Skip to content

Commit

Permalink
feature(#285): Implement More Types, Refactor, Test in KtCol
Browse files Browse the repository at this point in the history
  • Loading branch information
FlorianWendelborn committed Sep 13, 2020
1 parent a8b04f5 commit eec3cad
Show file tree
Hide file tree
Showing 18 changed files with 420 additions and 134 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@
"postpublish": "yarn run postpublish:deploy",
"postpublish:deploy": "yarn --cwd packages/documentation run deploy",
"prepublishOnly": "yarn run lint && lerna run --no-private build",
"watch": "yarn workspace @3yourmind/sass-node-modules-importer run build && nodemon --watch packages/kotti-ui/source --ignore packages/kotti-ui/source/kotti-style/tokens.css -e js,jsx,ts,tsx,vue,scss,css,json --exec \"yarn --cwd packages/kotti-ui run build && yarn --cwd packages/documentation run serve\""
"watch": "yarn workspace @3yourmind/sass-node-modules-importer run build && yarn workspace @3yourmind/vue-props-validators run build && nodemon --watch packages/kotti-ui/source --ignore packages/kotti-ui/source/kotti-style/tokens.css -e js,jsx,ts,tsx,vue,scss,css,json --exec \"yarn --cwd packages/kotti-ui run build && yarn --cwd packages/documentation run serve\""
},
"version": "1.0.0",
"workspaces": [
Expand Down
1 change: 1 addition & 0 deletions packages/kotti-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"url": "https://github.com/3YOURMIND/kotti/issues"
},
"dependencies": {
"@3yourmind/vue-props-validators": "1.x",
"@popperjs/core": "2.0.6",
"color": "3.x",
"deep-eql": "^4.0.0",
Expand Down
66 changes: 54 additions & 12 deletions packages/kotti-ui/source/kotti-col/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { vuePropsValidators } from '@3yourmind/vue-props-validators'
import {
createElement,
computed,
Expand All @@ -16,18 +17,59 @@ type MediaQueryProps = {
export const KtCol = makeInstallable(
defineComponent({
name: 'KtCol',
props: {
lg: { default: null, type: Number },
md: { default: null, type: Number },
offset: { default: null, type: Number },
pull: { default: null, type: Number },
push: { default: null, type: Number },
sm: { default: null, type: Number },
span: { default: 24, type: Number },
tag: { default: 'div', type: String },
xl: { default: null, type: Number },
xs: { default: null, type: Number },
},
props: vuePropsValidators.create({
lg: {
default: () => null,
nullable: true,
type: vuePropsValidators.Type.INTEGER,
},
md: {
default: () => null,
nullable: true,
type: vuePropsValidators.Type.INTEGER,
},
offset: {
default: () => null,
nullable: true,
type: vuePropsValidators.Type.INTEGER,
},
pull: {
default: () => null,
nullable: true,
type: vuePropsValidators.Type.INTEGER,
},
push: {
default: () => null,
nullable: true,
type: vuePropsValidators.Type.INTEGER,
},
sm: {
default: () => null,
nullable: true,
type: vuePropsValidators.Type.INTEGER,
},
span: {
// eslint-disable-next-line no-magic-numbers
default: () => 24,
nullable: false,
type: vuePropsValidators.Type.INTEGER,
},
tag: {
default: () => 'div',
nullable: false,
type: vuePropsValidators.Type.STRING,
},
xl: {
default: () => null,
nullable: false,
type: vuePropsValidators.Type.INTEGER,
},
xs: {
default: () => null,
nullable: false,
type: vuePropsValidators.Type.INTEGER,
},
}),
setup(
props: {
offset: number | null
Expand Down
2 changes: 1 addition & 1 deletion packages/vue-props-validators/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import { vuePropsValidators } from '@3yourmind/vue-props-validators'

export default defineComponent {
props: vuePropsValidators({
props: vuePropsValidators.create({
example: {
nullable: true,
required: true,
Expand Down
12 changes: 6 additions & 6 deletions packages/vue-props-validators/source/common/resolve-default.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { REQUIRED } from '../constants'
import { Option } from '../modules'

export const resolveDefault = (
option: Option,
): Option['default'] extends typeof REQUIRED
? { required: true }
: { default: Option['default'] } =>
option.default === REQUIRED ? { required: true } : { default: option.default }
export const resolveDefault = <OPTION extends Option>(option: OPTION) =>
(option.default === REQUIRED
? { required: true }
: { default: option.default }) as OPTION['default'] extends typeof REQUIRED
? { required: true }
: { default: OPTION['default'] }
76 changes: 1 addition & 75 deletions packages/vue-props-validators/source/index.ts
Original file line number Diff line number Diff line change
@@ -1,75 +1 @@
import { resolveDefault } from './common/resolve-default'
import { REQUIRED } from './constants'
import { createEnum } from './modules/enum'
import { Options, ExtendsOne, Result } from './types'
import { isNumber } from './utilities'

export const vuePropsValidators = <PROPS extends Options>(
props: PROPS,
): {
[KEY in keyof PROPS]: ExtendsOne<
PROPS[KEY],
'enum',
Result<PROPS[KEY], StringConstructor>,
ExtendsOne<
PROPS[KEY],
'float',
Result<PROPS[KEY], NumberConstructor>,
ExtendsOne<
PROPS[KEY],
'integer',
Result<PROPS[KEY], NumberConstructor>,
never
>
>
>
} =>
Object.fromEntries(
Object.entries(props).map(([prop, option]) => {
switch (option.type) {
case 'enum':
return [prop, createEnum(option)]

case 'float':
return [
prop,
{
...resolveDefault(option),
type: Number,
validator: (value: unknown) => isNumber(value),
},
]

case 'integer':
return [
prop,
{
...resolveDefault(option),
type: Number,
validator: (value: unknown) => Number.isSafeInteger(value),
},
]
}

throw new Error('invalid')
}),
)

const X = vuePropsValidators({
example: {
default: REQUIRED,
nullable: true,
type: 'enum',
},
example2: {
default: REQUIRED,
nullable: true,
type: 'integer',
},
example3: {
// eslint-disable-next-line no-magic-numbers
default: () => 123,
nullable: true,
type: 'integer',
},
})
export * as vuePropsValidators from './namespace'
56 changes: 32 additions & 24 deletions packages/vue-props-validators/source/modules/enum.test.ts
Original file line number Diff line number Diff line change
@@ -1,54 +1,62 @@
import { vuePropsValidators } from '..'
import { REQUIRED } from '../constants'

const BASE_ENUM = {
default: REQUIRED as typeof REQUIRED,
nullable: false,
type: 'enum' as const,
import { TypeEnum } from './enum'

import { Type } from '.'

const BASE_ENUM: TypeEnum = {
default: () => null,
nullable: true,
type: Type.ENUM,
options: [],
}

test('enum has correct type', () =>
expect(
vuePropsValidators({
example: BASE_ENUM,
}),
).toMatchObject({ example: { type: String } }))
expect(vuePropsValidators.create({ example: BASE_ENUM })).toMatchObject({
example: { type: String },
}))

test('enum validator works', () => {
const { validator } = vuePropsValidators({
const { example } = vuePropsValidators.create({
example: { ...BASE_ENUM, options: ['test', 'example'] },
}).example
})

expect(validator('test')).toBeTruthy()
expect(validator('example')).toBeTruthy()
expect(validator('anything')).toBeFalsy()
expect(example.validator('test')).toBeTruthy()
expect(example.validator('example')).toBeTruthy()
expect(example.validator('anything')).toBeFalsy()
})

test('enum (nullable: false)', () =>
expect(
vuePropsValidators({
example: { ...BASE_ENUM, nullable: false },
}).example.validator(null),
vuePropsValidators
.create({
example: { ...BASE_ENUM, nullable: false },
})
.example.validator(null),
).toBeFalsy())

test('enum (nullable: true)', () =>
expect(
vuePropsValidators({
example: { ...BASE_ENUM, nullable: true },
}).example.validator(null),
vuePropsValidators
.create({
example: { ...BASE_ENUM, nullable: true },
})
.example.validator(null),
).toBeTruthy())

test('enum (default)', () =>
expect(
vuePropsValidators({
example: { ...BASE_ENUM, default: () => null },
}).example.default(),
vuePropsValidators
.create({
example: { ...BASE_ENUM, default: () => null },
})
.example.default(),
).toBe(null))

test('enum (required)', () =>
expect(
vuePropsValidators({
vuePropsValidators.create({
example: { ...BASE_ENUM, default: REQUIRED },
}),
).toMatchObject({
Expand Down
6 changes: 3 additions & 3 deletions packages/vue-props-validators/source/modules/enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { baseValidator } from '../common/base-validator'
import { resolveDefault } from '../common/resolve-default'
import { Result } from '../types'

import { TypeBase } from '.'
import { TypeBase, Type } from '.'

export type TypeEnum = TypeBase & {
options: string[]
type: 'enum'
options: ReadonlyArray<string>
type: Type.ENUM
}

export const createEnum = <OPTION extends TypeEnum>(
Expand Down
70 changes: 70 additions & 0 deletions packages/vue-props-validators/source/modules/float.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { vuePropsValidators } from '..'
import { REQUIRED } from '../constants'

import { TypeFloat } from './float'

import { Type } from '.'

const BASE_FLOAT: TypeFloat = {
default: () => null,
nullable: true,
type: Type.FLOAT,
}

test('float has correct type', () =>
expect(vuePropsValidators.create({ example: BASE_FLOAT })).toMatchObject({
example: { type: Number },
}))

test('float validator works', () => {
const { example } = vuePropsValidators.create({
example: BASE_FLOAT,
})

expect(example.validator('test')).toBeFalsy()
expect(example.validator(undefined)).toBeFalsy()
/* eslint-disable no-magic-numbers */
expect(example.validator(42)).toBeTruthy()
expect(example.validator(420)).toBeTruthy()
expect(example.validator(2.3)).toBeTruthy()
expect(example.validator(NaN)).toBeFalsy()
/* eslint-enable no-magic-numbers */
})

test('float (nullable: false)', () =>
expect(
vuePropsValidators
.create({
example: { ...BASE_FLOAT, nullable: false },
})
.example.validator(null),
).toBeFalsy())

test('float (nullable: true)', () =>
expect(
vuePropsValidators
.create({
example: { ...BASE_FLOAT, nullable: true },
})
.example.validator(null),
).toBeTruthy())

test('float (default)', () =>
expect(
vuePropsValidators
.create({
example: { ...BASE_FLOAT, default: () => null },
})
.example.default(),
).toBe(null))

test('float (required)', () =>
expect(
vuePropsValidators.create({
example: { ...BASE_FLOAT, default: REQUIRED },
}),
).toMatchObject({
example: {
required: true,
},
}))
17 changes: 15 additions & 2 deletions packages/vue-props-validators/source/modules/float.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
import { TypeBase } from '.'
import { baseValidator } from '../common/base-validator'
import { resolveDefault } from '../common/resolve-default'
import { Result } from '../types'
import { isNumber } from '../utilities'

import { TypeBase, Type } from '.'

export type TypeFloat = TypeBase & {
type: 'float'
type: Type.FLOAT
}

export const createFloat = <OPTION extends TypeFloat>(
option: OPTION,
): Result<OPTION, NumberConstructor> => ({
...resolveDefault(option),
type: Number,
validator: baseValidator(option, (value: unknown) => isNumber(value)),
})

0 comments on commit eec3cad

Please sign in to comment.