From f85e4b2a3a08d06b14b0ece4f30e085ab70157b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aykut=20Karda=C5=9F?= Date: Fri, 23 Feb 2024 16:23:57 +0300 Subject: [PATCH] refactor: fix types, remove applyMethod function and update tests --- src/config/applyMethods.ts | 23 ------------ src/config/getConfig.ts | 7 ++-- src/config/parseSelector.ts | 47 +++++++++++++++++++----- src/config/types.ts | 16 +++++++-- src/parser/getValue.ts | 4 +-- src/parser/methods/boolean.ts | 2 +- src/parser/methods/email.ts | 2 +- src/parser/methods/float.ts | 2 +- src/parser/methods/length.ts | 2 +- src/parser/methods/lowercase.ts | 2 +- src/parser/methods/number.ts | 2 +- src/parser/methods/uppercase.ts | 2 +- src/parser/methods/url.ts | 2 +- src/parser/transformValue.ts | 5 ++- tests/getConfig.spec.ts | 63 +++++++++++++++------------------ tests/getValue.spec.ts | 2 +- tests/parseSelector.spec.ts | 3 +- tests/transformValue.spec.ts | 38 ++++++++++---------- 18 files changed, 115 insertions(+), 109 deletions(-) delete mode 100644 src/config/applyMethods.ts diff --git a/src/config/applyMethods.ts b/src/config/applyMethods.ts deleted file mode 100644 index 9530c2e..0000000 --- a/src/config/applyMethods.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { RawConfig } from './types'; - -export function applyMethods( - config: RawConfig -): typeof config { - const { methods } = config; - - if (!methods) return config; - - const type = methods.includes('array') ? 'array' : config.type; - const html = methods.includes('html') ? true : config.html; - const exist = methods.includes('exist') ? true : config.exist; - let trim = methods.includes('trim') ? true : config.trim; - - trim = methods.includes('non-trim') ? false : config.trim; - - if (type) config.type = type; - if (html) config.html = html; - if (exist) config.exist = exist; - if (typeof trim === 'boolean') config.trim = trim; - - return config; -} diff --git a/src/config/getConfig.ts b/src/config/getConfig.ts index e3f6b7f..81b4d8b 100644 --- a/src/config/getConfig.ts +++ b/src/config/getConfig.ts @@ -1,7 +1,6 @@ import parseSelector from './parseSelector'; -import { ElementPassArg } from '../parser/types'; -import { Config, RawConfig } from './types'; -import { applyMethods } from './applyMethods'; +import { type ElementPassArg } from '../parser/types'; +import { type Config, type RawConfig } from './types'; function getConfig( { $, el }: ElementPassArg, @@ -51,7 +50,7 @@ function getConfig( }; } - return applyMethods(config); + return config; } export default getConfig; diff --git a/src/config/parseSelector.ts b/src/config/parseSelector.ts index cbffcc3..413c44b 100644 --- a/src/config/parseSelector.ts +++ b/src/config/parseSelector.ts @@ -1,4 +1,4 @@ -import { Selector, RawConfig } from './types'; +import { type Selector, type RawConfig, type Method } from './types'; function parseSelector( selector: Selector @@ -14,7 +14,43 @@ function parseSelector( if (selector.includes('|')) { [$selector, ...methods] = selector.split('|').map((key) => key.trim()); - methods = methods.map((p: string) => p.trim()); + if (methods.length > 0) { + const validMethods = [ + 'boolean', + 'float', + 'number', + 'length', + 'lowercase', + 'uppercase', + 'email', + 'url' + ]; + + const acceptedMethods = methods.filter((method: string) => + validMethods.includes(method) + ) as Method[]; + + const type = methods.includes('array') ? 'array' : config.type; + const html = methods.includes('html') ? true : config.html; + const exist = methods.includes('exist') ? true : config.exist; + + let trim = config.trim; + + if (methods.includes('trim')) { + trim = true; + } else if (methods.includes('non-trim')) { + trim = false; + } + + if (type) config.type = type; + if (html) config.html = html; + if (exist) config.exist = exist; + if (typeof trim === 'boolean') config.trim = trim; + + if (acceptedMethods.length > 0) { + config.methods = acceptedMethods; + } + } } if ($selector === undefined) { @@ -34,13 +70,6 @@ function parseSelector( if (attr) config.attr = attr; - if (methods?.length) { - if (methods.includes('array')) { - config.type = 'array'; - } - config.methods = methods.filter((i) => i !== 'array'); - } - return config; } diff --git a/src/config/types.ts b/src/config/types.ts index dd3938d..7f7fa97 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -25,20 +25,30 @@ export type ElementFilterFunction = ( $: CheerioAPI ) => boolean; -export type ConfigTypeValues = 'number' | 'float' | 'boolean' | 'array'; +export type Method = + | 'boolean' + | 'number' + | 'float' + | 'length' + | 'lowercase' + | 'uppercase' + | 'email' + | 'url'; + +export type Types = 'number' | 'float' | 'boolean' | 'array'; export interface RawConfig { selector?: Selector; html?: boolean; attr?: string | string[]; - type?: ConfigTypeValues; + type?: Types; trim?: boolean; exist?: boolean; rootScope?: boolean; elementFilter?: ElementFilterFunction; initial?: Initial; fill?: any; - methods?: string[]; + methods?: Method[]; regex?: RegexConfig; transform?: TransformFunction; arrayTransform?: TransformFunction; diff --git a/src/parser/getValue.ts b/src/parser/getValue.ts index 9e68cfe..b261a22 100644 --- a/src/parser/getValue.ts +++ b/src/parser/getValue.ts @@ -29,9 +29,7 @@ function getValue( const { schema } = rest; const elemExists = element.length > 0; - if (exist || config.methods?.includes('exist')) { - return elemExists; - } + if (exist) return elemExists; if (condition && !condition($(el))) { return rest.initial ?? null; diff --git a/src/parser/methods/boolean.ts b/src/parser/methods/boolean.ts index 2119680..358296f 100644 --- a/src/parser/methods/boolean.ts +++ b/src/parser/methods/boolean.ts @@ -1,3 +1,3 @@ -const boolean = (val: any): boolean => Boolean(val); +const boolean = (val: any) => Boolean(val); export default boolean; diff --git a/src/parser/methods/email.ts b/src/parser/methods/email.ts index 892a470..6c15653 100644 --- a/src/parser/methods/email.ts +++ b/src/parser/methods/email.ts @@ -1,5 +1,5 @@ import execRegex from '../regex/execRegex'; -const email = (val: any): string => execRegex(val, 'email'); +const email = (val: any) => execRegex(val, 'email'); export default email; diff --git a/src/parser/methods/float.ts b/src/parser/methods/float.ts index ef03cdf..afb83e6 100644 --- a/src/parser/methods/float.ts +++ b/src/parser/methods/float.ts @@ -1,3 +1,3 @@ -const float = (val: string): number => parseFloat(val); +const float = (val: string) => parseFloat(val); export default float; diff --git a/src/parser/methods/length.ts b/src/parser/methods/length.ts index 0c0e2f5..5accd97 100644 --- a/src/parser/methods/length.ts +++ b/src/parser/methods/length.ts @@ -1,3 +1,3 @@ -const length = (val: any): number => val?.length || 0; +const length = (val: any) => val?.length || 0; export default length; diff --git a/src/parser/methods/lowercase.ts b/src/parser/methods/lowercase.ts index c6d4b22..304827b 100644 --- a/src/parser/methods/lowercase.ts +++ b/src/parser/methods/lowercase.ts @@ -1,3 +1,3 @@ -const lowercase = (val: string): string => val.toLowerCase(); +const lowercase = (val: string) => val.toLowerCase(); export default lowercase; diff --git a/src/parser/methods/number.ts b/src/parser/methods/number.ts index a7229e8..0528d10 100644 --- a/src/parser/methods/number.ts +++ b/src/parser/methods/number.ts @@ -1,3 +1,3 @@ -const number = (val: string): number => parseInt(val); +const number = (val: string) => parseInt(val); export default number; diff --git a/src/parser/methods/uppercase.ts b/src/parser/methods/uppercase.ts index f99e0e0..8df211a 100644 --- a/src/parser/methods/uppercase.ts +++ b/src/parser/methods/uppercase.ts @@ -1,3 +1,3 @@ -const uppercase = (val: string): string => val.toUpperCase(); +const uppercase = (val: string) => val.toUpperCase(); export default uppercase; diff --git a/src/parser/methods/url.ts b/src/parser/methods/url.ts index ecf3a17..0dc4415 100644 --- a/src/parser/methods/url.ts +++ b/src/parser/methods/url.ts @@ -1,5 +1,5 @@ import execRegex from '../regex/execRegex'; -const url = (val: any): string => execRegex(val, 'url'); +const url = (val: any) => execRegex(val, 'url'); export default url; diff --git a/src/parser/transformValue.ts b/src/parser/transformValue.ts index ea6a37c..3e53326 100644 --- a/src/parser/transformValue.ts +++ b/src/parser/transformValue.ts @@ -2,10 +2,9 @@ import { Cheerio, Element } from 'cheerio'; import { RawConfig } from '../config/types'; import Methods from './methods'; import execRegex from './regex/execRegex'; -import { Value } from './value'; function transformValue( - value: Value, + value: any, config: RawConfig, element: Cheerio ) { @@ -19,7 +18,7 @@ function transformValue( if (value) value = value.trim(); } - if (type) { + if (type && type !== 'array') { methods.push(type); } diff --git a/tests/getConfig.spec.ts b/tests/getConfig.spec.ts index 6278bfd..9aaee3e 100644 --- a/tests/getConfig.spec.ts +++ b/tests/getConfig.spec.ts @@ -1,49 +1,49 @@ import { describe, it, expect } from 'vitest'; import getConfig from '../src/config/getConfig'; -import parseSelector from '../src/config/parseSelector'; +import { RawConfig } from '../src/config/types'; describe('getConfig Tests', () => { - it('Case 1: string config: @ attr', () => { - const config = { selector: '@ href' }; + it('should return empty selector and "href" attribute when given a string config with "@ attr"', () => { + const config: RawConfig = { selector: '@ href' }; const value = getConfig({}, config); const expected = { selector: '', attr: 'href' }; expect(value).to.deep.equal(expected); }); - it('Case 2: string config: selector', () => { - const config = { selector: 'a.link' }; + it('should return the same selector when given a string config without "@ attr"', () => { + const config: RawConfig = { selector: 'a.link' }; const value = getConfig({}, config); expect({ selector: 'a.link' }).to.deep.equal(value); }); - it('Case 3: string config: selector @ attr', () => { - const config = { selector: 'a.link @ href' }; + it('should return the selector and "href" attribute when given a string config with "selector @ attr"', () => { + const config: RawConfig = { selector: 'a.link @ href' }; const value = getConfig({}, config); expect({ selector: 'a.link', attr: 'href' }).to.deep.equal(value); }); - it('Case 4: array config: [selector, selector]', () => { - const config = { selector: 'a.link, b.link' }; + it('should return the same selector when given an array config with multiple selectors', () => { + const config: RawConfig = { selector: 'a.link, b.link' }; const value = getConfig({}, config); expect({ selector: 'a.link, b.link' }).to.deep.equal(value); }); - it('Case 5: object config: { selector, attr }', () => { - const config = { selector: 'a.link', attr: 'href' }; + it('should return the selector and attribute when given an object config with "selector" and "attr"', () => { + const config: RawConfig = { selector: 'a.link', attr: 'href' }; const value = getConfig({}, config); expect({ selector: 'a.link', attr: 'href' }).to.deep.equal(value); }); - it('Case 6: object config: { selector @ attr }', () => { - const config = { selector: 'a.link @ href' }; + it('should return the selector and attribute when given an object config with "selector @ attr"', () => { + const config: RawConfig = { selector: 'a.link @ href' }; const value = getConfig({}, config); expect({ selector: 'a.link', attr: 'href' }).to.deep.equal(value); }); - it('Case 7: object config: { selector @ attr | method }', () => { - const config = { selector: 'a.link @ href | url' }; + it('should return the selector, attribute, and methods when given an object config with "selector @ attr | method"', () => { + const config: RawConfig = { selector: 'a.link @ href | url' }; const value = getConfig({}, config); expect({ selector: 'a.link', @@ -52,58 +52,53 @@ describe('getConfig Tests', () => { }).to.deep.equal(value); }); - it('Case 8: object config: { selector @ attr | array* }', () => { - const config = { selector: 'a.link @ href | array' }; + it('should return the selector, attribute, and type when given an object config with "selector @ attr | array"', () => { + const config: RawConfig = { selector: 'a.link @ href | array' }; const value = getConfig({}, config); expect({ selector: 'a.link', attr: 'href', - type: 'array', - methods: [] + type: 'array' }).to.deep.equal(value); }); - it('Case 9: object config: { selector @ attr | html* }', () => { - const config = { selector: 'a.link @ href | html' }; + it('should return the selector, attribute, and html flag when given an object config with "selector @ attr | html"', () => { + const config: RawConfig = { selector: 'a.link @ href | html' }; const value = getConfig({}, config); expect({ selector: 'a.link', attr: 'href', - html: true, - methods: ['html'] + html: true }).to.deep.equal(value); }); - it('Case 10: object config: () => ({ selector @ attr | html* })', () => { - const config = { + it('should return the selector, attribute, and html flag when given an object config as a function', () => { + const config: RawConfig = { selector: 'a.link @ href | html' }; const value = getConfig({}, config); const expected = { selector: 'a.link', attr: 'href', - html: true, - methods: ['html'] + html: true }; expect(value).to.deep.equal(expected); }); - it('Case 11: object config: () => ({ selector | exist })', () => { - const config = { selector: 'a.link | exist' }; + it('should return the selector and exist flag when given an object config as a function', () => { + const config: RawConfig = { selector: 'a.link | exist' }; const value = getConfig({}, config); expect({ selector: 'a.link', - exist: true, - methods: ['exist'] + exist: true }).to.deep.equal(value); }); - it('MultipleStringSelectors', () => { + it('should return the parsed selectors when given an array of string selectors', () => { const selectors = ['a.link', 'b.link']; const result = getConfig({}, selectors); - const expected = selectors.map((s) => parseSelector(s)); - + const expected = [{ selector: 'a.link' }, { selector: 'b.link' }]; expect(result).to.deep.equal(expected); }); }); diff --git a/tests/getValue.spec.ts b/tests/getValue.spec.ts index fc879ac..03c9ba4 100644 --- a/tests/getValue.spec.ts +++ b/tests/getValue.spec.ts @@ -309,7 +309,7 @@ describe('getValue Tests', () => { it('Case 17: { selector, non-exist }', () => { const el = $('.parent'); const selector = '.non-exist-child'; - const value = getValue({ $, el }, { selector, methods: ['exist'] }); + const value = getValue({ $, el }, { selector, exist: true }); expect(value).to.deep.equal(false); }); diff --git a/tests/parseSelector.spec.ts b/tests/parseSelector.spec.ts index 2514b12..c39fbbc 100644 --- a/tests/parseSelector.spec.ts +++ b/tests/parseSelector.spec.ts @@ -68,8 +68,7 @@ describe('parseSelector Tests', () => { const value = parseSelector(selector); expect({ selector: '.parent div', - type: 'array', - methods: [] + type: 'array' }).to.deep.equal(value); }); diff --git a/tests/transformValue.spec.ts b/tests/transformValue.spec.ts index 6523233..a76ba34 100644 --- a/tests/transformValue.spec.ts +++ b/tests/transformValue.spec.ts @@ -1,8 +1,8 @@ import { describe, it, expect } from 'vitest'; -import { applyMethods } from '../src/config/applyMethods'; import transformValue from '../src/parser/transformValue'; import { load } from 'cheerio'; +import { RawConfig } from '../src/config/types'; const SAMPLE_HTML = `
@@ -13,65 +13,65 @@ const SAMPLE_HTML = ` const $ = load(SAMPLE_HTML); describe('transformValue Tests', () => { - it('Case 1: boolean - false', () => { - const config = { selector: '', methods: ['boolean'] }; + it('should transform empty string to boolean false', () => { + const config: RawConfig = { selector: '', methods: ['boolean'] }; const value = ''; const result = transformValue(value, config, $('div')); expect(false).to.deep.equal(result); }); - it('Case 2: boolean - true', () => { - const config = { selector: '', methods: ['boolean'] }; + it('should transform non-empty string to boolean true', () => { + const config: RawConfig = { selector: '', methods: ['boolean'] }; const value = 'Test'; const result = transformValue(value, config, $('div')); expect(true).to.deep.equal(result); }); - it('Case 3: number', () => { - const config = { selector: '', methods: ['number'] }; + it('should transform string to number', () => { + const config: RawConfig = { selector: '', methods: ['number'] }; const value = '12'; const result = transformValue(value, config, $('div')); expect(12).to.deep.equal(result); }); - it('Case 4: float', () => { - const config = { selector: '', methods: ['float'] }; + it('should transform string to float', () => { + const config: RawConfig = { selector: '', methods: ['float'] }; const value = '3.5'; const result = transformValue(value, config, $('div')); expect(3.5).to.deep.equal(result); }); - it('Case 5: trim', () => { - const config = { selector: '', methods: ['trim'] }; + it('should trim the string', () => { + const config: RawConfig = { selector: '', trim: true }; const value = ' content '; const result = transformValue(value, config, $('div')); expect('content').to.deep.equal(result); }); - it('Case 6: non-trim', () => { - const config = applyMethods({ selector: '', methods: ['non-trim'] }); + it('should not trim the string', () => { + const config: RawConfig = { selector: '', trim: false }; const value = ' content '; const result = transformValue(value, config, $('div')); expect(result).to.deep.equal(value); }); - it('Case 7: lowercase', () => { - const config = { selector: '', methods: ['lowercase'] }; + it('should convert string to lowercase', () => { + const config: RawConfig = { selector: '', methods: ['lowercase'] }; const value = 'CONTENT'; const result = transformValue(value, config, $('div')); expect('content').to.deep.equal(result); }); - it('Case 8: uppercase', () => { - const config = { selector: '', methods: ['uppercase'] }; + it('should convert string to uppercase', () => { + const config: RawConfig = { selector: '', methods: ['uppercase'] }; const value = 'content'; const result = transformValue(value, config, $('div')); expect('CONTENT').to.deep.equal(result); }); - it('Case 9: length', () => { - const config = { selector: '', methods: ['length'] }; + it('should return the length of the string', () => { + const config: RawConfig = { selector: '', methods: ['length'] }; const value = 'content'; const result = transformValue(value, config, $('div')); expect(7).to.deep.equal(result);