Skip to content

Commit

Permalink
feat: added FieldMapper to simplify data mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
jerrythomas committed Jan 10, 2025
1 parent e8a8c25 commit b46074c
Show file tree
Hide file tree
Showing 17 changed files with 682 additions and 60 deletions.
Binary file modified bun.lockb
Binary file not shown.
3 changes: 0 additions & 3 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@
"clean": "rm -rf dist",
"build": "pnpm clean && pnpm prepublishOnly"
},
"devDependencies": {
"vitest": "latest"
},
"files": [
"src/**/*.js",
"dist/**/*.d.ts"
Expand Down
26 changes: 25 additions & 1 deletion packages/core/spec/constants.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest'
import { defaultIcons, stateIconsFromNames } from '../src/constants'
import { defaultIcons, stateIconsFromNames, defaultFields } from '../src/constants'

describe('Utility functions', () => {
it('should convert names to nested state icons object', () => {
Expand Down Expand Up @@ -75,4 +75,28 @@ describe('Utility functions', () => {
}
})
})

it('should have the defaultFields', () => {
expect(defaultFields).toEqual({
id: 'id',
url: 'url',
text: 'text',
value: 'value',
children: 'children',
icon: 'icon',
iconPrefix: null,
image: 'image',
component: 'component',
summary: 'summary',
notes: 'notes',
props: 'props',
target: 'target',
state: 'state',
isOpen: '_open',
isDeleted: '_deleted',
level: 'level',
parent: 'parent',
currency: 'currency'
})
})
})
122 changes: 122 additions & 0 deletions packages/core/spec/field-mapper.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { describe, it, expect } from 'vitest'
import { FieldMapper } from '../src/field-mapper'
import { defaultFields } from '../src/constants'

describe('FieldMapper', () => {
const data = {
id: 1,
text: 'Item 1',
value: 'Item 1',
_open: true,
children: [
{
id: 2,
text: 'Item 2',
value: 'Item 2',
children: [
{
id: 3,
text: 'Item 3',
value: 'Item 3'
}
]
}
]
}

it('should return a field mapping object', () => {
const fieldMapping = new FieldMapper()

expect(fieldMapping).toBeDefined()
expect(fieldMapping.fields).toEqual(defaultFields)
expect(fieldMapping.using).toEqual({})

fieldMapping.fields = { text: 'name' }
expect(fieldMapping.fields.text).toEqual('name')
expect(fieldMapping.fields).toEqual({ ...defaultFields, text: 'name' })

fieldMapping.using = { default: 'default' }
expect(fieldMapping.using).toEqual({ default: 'default' })
})

it('should return a component', () => {
const fieldMapping = new FieldMapper()
fieldMapping.using = { default: 'defaultComponent', abc: 'Component' }

expect(fieldMapping.getComponent({})).toEqual('defaultComponent')
expect(fieldMapping.getComponent({ component: 'abc' })).toEqual('Component')
})

it('should return an icon', () => {
const fieldMapping = new FieldMapper()

const data = { icon: { opened: 'folder-opened', closed: 'folder-closed' }, state: 'opened' }
expect(fieldMapping.getIcon(data)).toEqual('folder-opened')
data.state = 'closed'
expect(fieldMapping.getIcon(data)).toEqual('folder-closed')
data.icon = 'bunny'
expect(fieldMapping.getIcon(data)).toEqual('bunny')
fieldMapping.fields = { iconPrefix: 'fa' }
expect(fieldMapping.getIcon(data)).toEqual('fa-bunny')

expect(fieldMapping.getIcon(null)).toEqual(null)
})

it('should return the text', () => {
const fieldMapping = new FieldMapper()
expect(fieldMapping.getText(data)).toEqual('Item 1')
expect(fieldMapping.getText(data.children[0])).toEqual('Item 2')
expect(fieldMapping.getText(data.children[0].children[0])).toEqual('Item 3')
})

it('should return the value', () => {
const fieldMapping = new FieldMapper()
expect(fieldMapping.getValue(data)).toEqual('Item 1')
expect(fieldMapping.getValue(data.children[0])).toEqual('Item 2')
expect(fieldMapping.getValue(data.children[0].children[0])).toEqual('Item 3')
})

it('should return an attribute', () => {
const fieldMapping = new FieldMapper()
expect(fieldMapping.getAttribute(data, 'id')).toEqual(1)
expect(fieldMapping.getAttribute(data.children[0], 'id')).toEqual(2)
expect(fieldMapping.getAttribute(data.children[0].children[0], 'id')).toEqual(3)
})

it('should return a formatted text', () => {
const fieldMapping = new FieldMapper()
const formatter = (text) => text.toUpperCase()
expect(fieldMapping.getFormattedText(data, formatter)).toEqual('ITEM 1')
expect(fieldMapping.getFormattedText(data.children[0], formatter)).toEqual('ITEM 2')
expect(fieldMapping.getFormattedText(data.children[0].children[0], formatter)).toEqual('ITEM 3')
})

it('should return the using object', () => {
const fieldMapping = new FieldMapper()
fieldMapping.using = { default: 'default' }
expect(fieldMapping.using).toEqual({ default: 'default' })
fieldMapping.using = null
expect(fieldMapping.using).toEqual({})
})

it('should idenitify if node has children', () => {
const fieldMapping = new FieldMapper()
expect(fieldMapping.hasChildren(data)).toBeTruthy()
expect(fieldMapping.hasChildren(data.children[0])).toBeTruthy()
expect(fieldMapping.hasChildren(data.children[0].children[0])).toBeFalsy()
})

it('should identify if node is expanded', () => {
const fieldMapping = new FieldMapper()
expect(fieldMapping.isExpanded(data)).toBeTruthy()
expect(fieldMapping.isExpanded(data.children[0])).toBeFalsy()
expect(fieldMapping.isExpanded(data.children[0].children[0])).toBeFalsy()
})

it('should identify if node is nested', () => {
const fieldMapping = new FieldMapper()
expect(fieldMapping.isNested(data)).toBeFalsy()
expect(fieldMapping.isNested(data.children)).toBeTruthy()
expect(fieldMapping.isNested(data.children[0].children)).toBeFalsy()
})
})
24 changes: 13 additions & 11 deletions packages/core/spec/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { describe, it, expect } from 'vitest'
// skipcq: JS-C1003 - Importing all components for verification
import * as functions from '../src/index.js'

describe('utils', () => {
describe('@rokkit/core', () => {
it('should contain all exported functions', () => {
expect(Object.keys(functions)).toEqual([
'defaultColors',
Expand All @@ -16,22 +16,24 @@ describe('utils', () => {
'defaultThemeMapping',
'stateIconsFromNames',
'defaultStateIcons',
'getComponent',
'getIcon',
'getValue',
'getText',
'getAttribute',
'getFormattedText',
'hasChildren',
'isExpanded',
'isNested',
'getClosestAncestorWithAttribute',
'noop',
'id',
'isObject',
'toString',
'iconShortcuts',
'scaledPath'
'scaledPath',
'flattenNestedList',
'findValueFromPath',
'toInitCapCase',
'toPascalCase',
'toHyphenCase',
'compareStrings',
'sortByParts',
'uniqueId',
'compact',
'toHexString',
'FieldMapper'
])
})
})
11 changes: 0 additions & 11 deletions packages/core/spec/mapping.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -241,15 +241,4 @@ describe('mapping', () => {
expect(isExpanded(null, fields)).toBe(false)
})
})

describe('isNested', () => {
it('returns true if the item is nested', () => {
expect(isNested([{ children: [] }], fields)).toBe(true)
expect(isNested(['?', { children: [] }], fields)).toBe(true)
})

it('returns false if the item is not nested', () => {
expect(isNested([], fields)).toBe(false)
})
})
})
154 changes: 154 additions & 0 deletions packages/core/spec/nested.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import { describe, expect, it } from 'vitest'
import { flattenNestedList, findValueFromPath } from '../src/nested'
import { defaultFields } from '../src/constants'

describe('flattenNestedList', () => {
it('should flatten nested items', () => {
const items = [
{
id: 1,
children: [
{
id: 2,
children: [
{
id: 3,
children: []
}
]
}
]
},
{
id: 4
}
]

const result = flattenNestedList(items)

expect(result).toEqual([
{
id: 1,
level: 0,
parent: true
},
{
id: 2,
level: 1,
parent: true
},
{
id: 3,
level: 2,
parent: false
},
{
id: 4,
level: 0,
parent: false
}
])
})

it('should flatten nested items with custom fields', () => {
const items = [
{
id: 1,
sub: [
{
id: 2,
sub: [
{
id: 3,
sub: []
}
]
}
]
}
]

const fields = {
children: 'sub',
level: 'depth',
parent: 'isParent'
}

const result = flattenNestedList(items, fields)

expect(result).toEqual([
{
id: 1,
depth: 0,
isParent: true
},
{
id: 2,
depth: 1,
isParent: true
},
{
id: 3,
depth: 2,
isParent: false
}
])
})
})

describe('findValueFromPath', () => {
it('should find and return the correct value from the provided path', () => {
const slug = 'category/subcategory/item'
const data = [
{
key: 'category',
isOpen: false,
children: [
{
key: 'subcategory',
isOpen: false,
children: [
{
key: 'item',
value: 'Item Value'
}
]
}
]
}
]

const expectedResult = {
key: 'item',
value: 'Item Value'
}

const result = findValueFromPath(slug, data, { key: 'key' })
expect(result).toEqual(expectedResult)
})

it('should return null if the path does not exist in the data', () => {
const slug = 'nonexistent/path'
const data = [
{
key: 'category',
isOpen: false,
children: [
{
key: 'subcategory',
isOpen: false,
children: [
{
key: 'item',
value: 'Item Value'
}
]
}
]
}
]

const result = findValueFromPath(slug, data, defaultFields)
expect(result).toBeNull()
})
})
Loading

0 comments on commit b46074c

Please sign in to comment.