From 51cdf68556fb8931afdc441afc48c789a1d79833 Mon Sep 17 00:00:00 2001 From: Yauhen Date: Mon, 18 Mar 2019 16:24:38 +0300 Subject: [PATCH] feat(theme): styles validation --- .../theme/service/style/style.service.ts | 11 ++--- .../theme/service/style/style.spec.config.ts | 25 ++++++++++++ .../theme/service/style/style.spec.ts | 12 ++++++ .../service/style/styleConsumer.service.ts | 40 ++++++++++++++++--- .../ui/buttonGroup/buttonGroup.spec.config.ts | 3 ++ src/framework/ui/layout/layout.spec.config.ts | 21 +++++++++- 6 files changed, 98 insertions(+), 14 deletions(-) diff --git a/src/framework/theme/service/style/style.service.ts b/src/framework/theme/service/style/style.service.ts index db6480e53..709806ccd 100644 --- a/src/framework/theme/service/style/style.service.ts +++ b/src/framework/theme/service/style/style.service.ts @@ -5,15 +5,12 @@ import { } from '../../type'; import { getThemeValue } from '../theme'; -export function createThemedStyle(mapping: ThemedStyleType, theme: ThemeType): StyleType { +export function createThemedStyle(mapping: ThemedStyleType, + theme: ThemeType): StyleType { + return Object.keys(mapping).reduce((acc: StyleType, current: string): StyleType => { const mappingValue: any = mapping[current]; - - if (mappingValue instanceof Object) { - acc[current] = createThemedStyle(mappingValue, theme); - } else { - acc[current] = getThemeValue(mappingValue, theme, mappingValue); - } + acc[current] = getThemeValue(mappingValue, theme, mappingValue); return acc; }, {}); diff --git a/src/framework/theme/service/style/style.spec.config.ts b/src/framework/theme/service/style/style.spec.config.ts index 3a4cdca68..d67fa13f4 100644 --- a/src/framework/theme/service/style/style.spec.config.ts +++ b/src/framework/theme/service/style/style.spec.config.ts @@ -181,6 +181,31 @@ export const componentMapping: ThemeMappingType = { }, appearances: {}, }, + Invalid: { + meta: { + scope: 'mobile', + parameters: { + backgroundColor: { + type: 'string', + }, + }, + appearances: { + default: { + default: true, + }, + }, + variantGroups: {}, + states: {}, + }, + appearances: { + default: { + mapping: { + backgroundColor: 'black', + foregroundColor: 'white', + }, + }, + }, + }, }; export const theme: ThemeType = { diff --git a/src/framework/theme/service/style/style.spec.ts b/src/framework/theme/service/style/style.spec.ts index cb5a432c4..f8840f6b1 100644 --- a/src/framework/theme/service/style/style.spec.ts +++ b/src/framework/theme/service/style/style.spec.ts @@ -66,6 +66,18 @@ describe('@style: consumer service methods check', () => { expect(value).toMatchSnapshot(); }); + it('throws warning for undeclared mapping keys', () => { + service.getComponentStyleMapping( + config.componentMapping, + {}, + 'Invalid', + props, + [], + ); + + jest.spyOn(console, 'warn'); + }); + }); }); diff --git a/src/framework/theme/service/style/styleConsumer.service.ts b/src/framework/theme/service/style/styleConsumer.service.ts index 58d5d24de..67d153c29 100644 --- a/src/framework/theme/service/style/styleConsumer.service.ts +++ b/src/framework/theme/service/style/styleConsumer.service.ts @@ -49,27 +49,55 @@ export class StyleConsumerService { interaction: Interaction[]): ThemedStyleType { return this.safe(mapping[component], (componentMapping: ControlMappingType): ThemedStyleType => { - const { appearance, variants, states } = this.getDerivedStyleMeta(componentMapping, props); + const meta: ComponentStyleMetaType = this.getDerivedStyleMeta(componentMapping, props); + const validParameters: string[] = Object.keys(componentMapping.meta.parameters); const generatedStyles: ThemedStyleType = this.safe(styles[component], (componentStyles) => { const query: string = this.findGeneratedQuery(Object.keys(componentStyles), [ - appearance, - ...variants, + meta.appearance, + ...meta.variants, ...interaction, - ...states, + ...meta.states, ]); return componentStyles[query]; }); if (generatedStyles === undefined) { - return createStyle(mapping, component, appearance, variants, [...interaction, ...states]); + const createdStyles: ThemedStyleType = createStyle( + mapping, + component, + meta.appearance, + meta.variants, + [...interaction, ...meta.states], + ); + + return this.validateComponentStyleMapping(createdStyles, validParameters); } - return generatedStyles; + return this.validateComponentStyleMapping(generatedStyles, validParameters); }); } + private validateComponentStyleMapping(mapping: ThemedStyleType, parameters: string[]): ThemedStyleType { + const redundantKeys: string[] = []; + + Object.keys(mapping).forEach((key: string) => { + if (!parameters.includes(key)) { + redundantKeys.push(key); + delete mapping[key]; + } + }); + + if (redundantKeys.length !== 0) { + console.warn( + `Before using these variables, describe them in the component configuration: ${redundantKeys}`, + ); + } + + return mapping; + } + private getDerivedStyleMeta

(mapping: ControlMappingType, props: P): ComponentStyleMetaType { diff --git a/src/framework/ui/buttonGroup/buttonGroup.spec.config.ts b/src/framework/ui/buttonGroup/buttonGroup.spec.config.ts index 9cf576c58..a1025b90a 100644 --- a/src/framework/ui/buttonGroup/buttonGroup.spec.config.ts +++ b/src/framework/ui/buttonGroup/buttonGroup.spec.config.ts @@ -75,6 +75,9 @@ export const mapping: ThemeMappingType = { 'borderRadius': { 'type': 'number', }, + 'borderColor': { + 'type': 'string', + }, 'borderWidth': { 'type': 'number', }, diff --git a/src/framework/ui/layout/layout.spec.config.ts b/src/framework/ui/layout/layout.spec.config.ts index 3319be8b2..a5b9a94d7 100644 --- a/src/framework/ui/layout/layout.spec.config.ts +++ b/src/framework/ui/layout/layout.spec.config.ts @@ -5,7 +5,26 @@ export const mapping: ThemeMappingType = { 'Layout': { 'meta': { 'scope': 'mobile', - 'parameters': {}, + 'parameters': { + 'paddingHorizontal': { + 'type': 'number', + }, + 'paddingVertical': { + 'type': 'number', + }, + 'backgroundColor': { + 'type': 'string', + }, + 'borderColor': { + 'type': 'number', + }, + 'borderRadius': { + 'type': 'number', + }, + 'borderWidth': { + 'type': 'number', + }, + }, 'appearances': { 'default': { 'default': true,