Skip to content

Commit 05d3ba9

Browse files
Merge pull request #5 from TeemuKoivisto/fix-max-depth
Fix depth increment when recursing, convert symbols to string properly
2 parents c0fd921 + c6e7c7e commit 05d3ba9

File tree

18 files changed

+1702
-1181
lines changed

18 files changed

+1702
-1181
lines changed

README.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Library to show Javascript objects in a nice tree layout. It's written in Svelte
88

99
## How to use
1010

11-
At one point there were some issues packaging this library with SvelteKit, partly because I've written it in TypeScript. Currently the only extra config that I'm aware which you must add is for ensuring you import the library with the "svelte" entry point, not "main" or "module" eg:
11+
At one point there were some issues packaging this library with SvelteKit, partly because it's written in TypeScript. Now the only extra config that I'm aware you must add is for ensuring you import the library using "svelte" entry point, not "main" or "module" eg:
1212

1313
```ts
1414
import nodeResolve from 'rollup-plugin-node-resolve'
@@ -17,13 +17,11 @@ import nodeResolve from 'rollup-plugin-node-resolve'
1717
export default {
1818
...
1919
plugins: [
20-
...
2120
nodeResolve({
2221
browser: true,
2322
mainFields: ['svelte', 'browser', 'module', 'main'],
2423
dedupe: ['svelte']
2524
}),
26-
...
2725
],
2826
...
2927
}
@@ -50,7 +48,7 @@ import TreeView from 'svelte-tree-view'
5048
/>
5149
```
5250

53-
Or if you are not using Svelte (NOTE: to use it with TS you must install svelte as a devDependency for the types):
51+
Or if you are not using Svelte (NOTE: if you're using TS you must install svelte as a devDependency for the types):
5452

5553
```ts
5654
import { TreeView } from 'svelte-tree-view'
@@ -152,7 +150,7 @@ export type ValueComponent = new (...args: any) => SvelteComponentTyped<{
152150
}>
153151

154152
export interface TreeViewProps {
155-
data: object // Data can be basically any non-primitive value
153+
data: unknown // Data can be basically any non-primitive value
156154
class?: string // Top node has 'svelte-tree-view' class by default
157155
theme?: Base16Theme
158156
showLogButton?: boolean

core/.prettierignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
node_modules
22
dist
3-
package
3+
package
4+
.svelte-kit

core/build.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,7 @@ async function writePackageExports() {
4242

4343
async function build() {
4444
await cleanCurrentExports()
45-
await Promise.all([
46-
exec('yarn build:pkg'),
47-
exec('yarn build:dist'),
48-
])
45+
await Promise.all([exec('yarn build:pkg'), exec('yarn build:dist')])
4946
await writePackageExports()
5047
await exec('rm ./package/.npmignore && rm ./package/package.json')
5148
await checkFilesBuilt()
@@ -57,7 +54,7 @@ async function checkFilesBuilt() {
5754
fs.access('./dist/index.es.js'),
5855
fs.access('./dist/index.css'),
5956
fs.access('./dist/types.d.ts'),
60-
fs.access('./package/index.js'),
57+
fs.access('./package/index.js')
6158
])
6259
}
6360

core/cypress/integration/log-copy.spec.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ it('Should show functioning log & copy buttons', () => {
1515
cy.get('.log-copy-button').eq(1).click()
1616
cy.get('@write').should('be.calledWith', JSON.stringify(item1))
1717
cy.get('.log-copy-button').eq(0).click()
18-
cy.get('@consoleInfo').should('be.calledWith', '%c [svelte-tree-view]: Property added to window._node')
18+
cy.get('@consoleInfo').should(
19+
'be.calledWith',
20+
'%c [svelte-tree-view]: Property added to window._node'
21+
)
1922
cy.get('@consoleLog').should('be.calledWith', item1)
2023
cy.get('@consoleError').should('be.callCount', 0)
21-
})
24+
})

core/cypress/support/commands.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@
88
// https://on.cypress.io/custom-commands
99
// ***********************************************
1010

11-
export {}
11+
export {}

core/package.json

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -65,39 +65,39 @@
6565
"cy": "cypress"
6666
},
6767
"devDependencies": {
68-
"@rollup/plugin-commonjs": "^20.0.0",
69-
"@rollup/plugin-node-resolve": "^13.0.4",
70-
"@sveltejs/kit": "^1.0.0-next.184",
68+
"@rollup/plugin-commonjs": "^21.0.1",
69+
"@rollup/plugin-node-resolve": "^13.0.6",
70+
"@sveltejs/kit": "^1.0.0-next.192",
7171
"@testing-library/cypress": "^8.0.1",
7272
"@testing-library/jest-dom": "^5.14.1",
7373
"@testing-library/svelte": "^3.0.3",
74-
"@types/jest": "^27.0.1",
75-
"cypress": "^8.4.1",
76-
"eslint": "^7.32.0",
74+
"@types/jest": "^27.0.2",
75+
"cypress": "^8.7.0",
76+
"eslint": "^8.1.0",
7777
"eslint-config-prettier": "^8.3.0",
78-
"eslint-plugin-import": "^2.24.2",
79-
"eslint-plugin-prettier": "^3.4.1",
80-
"eslint-plugin-svelte3": "^3.2.0",
81-
"jest": "^27.1.0",
78+
"eslint-plugin-import": "^2.25.2",
79+
"eslint-plugin-prettier": "^4.0.0",
80+
"eslint-plugin-svelte3": "^3.2.1",
81+
"jest": "^27.3.1",
8282
"jest-scss-transform": "^1.0.1",
8383
"node-sass": "^6.0.1",
84-
"postcss": "^8.3.6",
85-
"prettier": "^2.3.2",
84+
"postcss": "^8.3.11",
85+
"prettier": "^2.4.1",
8686
"prettier-plugin-svelte": "^2.4.0",
8787
"rimraf": "^3.0.2",
88-
"rollup": "^2.56.3",
88+
"rollup": "^2.58.3",
8989
"rollup-plugin-scss": "^3.0.0",
9090
"rollup-plugin-svelte": "^7.1.0",
91-
"rollup-plugin-ts": "^1.4.1",
92-
"sass": "^1.41.0",
93-
"svelte": "^3.42.4",
94-
"svelte-check": "^2.2.5",
95-
"svelte-jester": "^1.8.2",
96-
"svelte-preprocess": "^4.9.5",
97-
"svelte2tsx": "^0.4.6",
98-
"ts-jest": "^27.0.1",
91+
"rollup-plugin-ts": "^1.4.7",
92+
"sass": "^1.43.4",
93+
"svelte": "^3.44.0",
94+
"svelte-check": "^2.2.8",
95+
"svelte-jester": "^2.1.5",
96+
"svelte-preprocess": "^4.9.8",
97+
"svelte2tsx": "^0.4.8",
98+
"ts-jest": "^27.0.7",
9999
"tslib": "^2.3.1",
100-
"typescript": "^4.4.2"
100+
"typescript": "^4.4.4"
101101
},
102102
"dependencies": {},
103103
"jest": {
@@ -129,4 +129,4 @@
129129
"src/**/*.{ts,svelte}"
130130
]
131131
}
132-
}
132+
}

core/src/lib/TreeView.svelte

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,7 @@
33
import { get } from 'svelte/store'
44
55
import { recomputeTree } from './tree-utils'
6-
import {
7-
createPropsStore,
8-
createRootElementStore,
9-
createTreeStore,
10-
} from './stores'
6+
import { createPropsStore, createRootElementStore, createTreeStore } from './stores'
117
128
import TreeViewNode from './TreeViewNode.svelte'
139
@@ -20,7 +16,7 @@
2016
TreeRecursionOpts
2117
} from './types'
2218
23-
export let data: object,
19+
export let data: unknown,
2420
theme: Base16Theme | undefined = undefined,
2521
showLogButton = false,
2622
showCopyButton = false,
@@ -69,11 +65,12 @@
6965
const recomputeExpandNode =
7066
props?.recursionOpts?.shouldExpandNode !== newRecursionOpts.shouldExpandNode
7167
const oldTreeMap = get(treeStore.treeMap)
72-
const {
73-
treeMap,
74-
tree,
75-
iteratedValues
76-
} = recomputeTree(data, oldTreeMap, newRecursionOpts, recomputeExpandNode)
68+
const { treeMap, tree, iteratedValues } = recomputeTree(
69+
data,
70+
oldTreeMap,
71+
newRecursionOpts,
72+
recomputeExpandNode
73+
)
7774
treeStore.init(tree, treeMap, iteratedValues)
7875
props.recursionOpts = newRecursionOpts
7976
propsStore.setProps(props)
@@ -97,7 +94,7 @@
9794
setContext<Stores>('svelte-tree-view', {
9895
propsStore,
9996
rootElementStore,
100-
treeStore,
97+
treeStore
10198
})
10299
103100
onMount(() => {

core/src/lib/TreeViewNode.svelte

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
// Should explode rather than have logic written around undefinedness
1414
// as this component should be unmounted if it's undefined.
1515
if (!found) {
16-
throw Error('[svelte-tree-view] TreeViewNode.svelte received undefined node from treeMapStore whereas it should be already unmounted!')
16+
throw Error(
17+
'[svelte-tree-view] TreeViewNode.svelte received undefined node from treeMapStore whereas it should be already unmounted!'
18+
)
1719
}
1820
node = found
1921
}

core/src/lib/__tests__/TreeView.spec.ts

Lines changed: 139 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* @jest-environment jsdom
33
*/
44

5-
import { render } from '@testing-library/svelte'
5+
import { render, fireEvent, findAllByText } from '@testing-library/svelte'
66
import TreeView from '../TreeView.svelte'
77

88
import example1 from './__fixtures__/example1.json'
@@ -12,6 +12,19 @@ import type { TreeNode } from '../types'
1212

1313
// https://sveltesociety.dev/recipes/testing-and-debugging/unit-testing-svelte-component/
1414

15+
async function clickByText(container: HTMLElement, text: string, index = 0) {
16+
const el = (await findAllByText(container, text))[index]
17+
if (el) {
18+
return fireEvent(
19+
el,
20+
new MouseEvent('click', {
21+
bubbles: true,
22+
cancelable: true
23+
})
24+
)
25+
}
26+
}
27+
1528
describe('TreeView', () => {
1629
it('should render', async () => {
1730
const results = render(TreeView, {
@@ -23,11 +36,8 @@ describe('TreeView', () => {
2336
}
2437
})
2538

26-
const lists = results.container.querySelectorAll('ul')
27-
const rows = results.container.querySelectorAll('li')
28-
29-
expect(lists.length).toEqual(37)
30-
expect(rows.length).toEqual(270)
39+
expect(results.container.querySelectorAll('ul').length).toEqual(37)
40+
expect(results.container.querySelectorAll('li').length).toEqual(270)
3141
expect(results.container).toBeInTheDocument()
3242
expect(results.container).toMatchSnapshot()
3343
})
@@ -99,12 +109,130 @@ describe('TreeView', () => {
99109
}
100110
})
101111

102-
const lists = results.container.querySelectorAll('ul')
103-
const rows = results.container.querySelectorAll('li')
104-
105-
expect(lists.length).toEqual(34)
106-
expect(rows.length).toEqual(118)
112+
expect(results.container.querySelectorAll('ul').length).toEqual(34)
113+
expect(results.container.querySelectorAll('li').length).toEqual(118)
107114
expect(results.container).toBeInTheDocument()
108115
expect(results.container).toMatchSnapshot()
109116
})
117+
118+
it('should respect maxDepth and collapse nodes correctly', async () => {
119+
const data = {
120+
a: [1, 2, 3],
121+
b: new Map<string, any>([
122+
['c', { d: null }],
123+
['e', { f: [9, 8, 7] }]
124+
])
125+
}
126+
const results = render(TreeView, {
127+
props: {
128+
data,
129+
recursionOpts: {
130+
maxDepth: 4
131+
}
132+
}
133+
})
134+
window.HTMLElement.prototype.scrollIntoView = jest.fn()
135+
136+
expect(results.container.querySelectorAll('li').length).toEqual(2)
137+
expect(results.container).toBeInTheDocument()
138+
139+
await clickByText(results.container, 'b:')
140+
expect(results.container.querySelectorAll('li').length).toEqual(5)
141+
142+
await clickByText(results.container, '[map entry 1]:')
143+
expect(results.container.querySelectorAll('li').length).toEqual(8)
144+
145+
await clickByText(results.container, '[value]:')
146+
expect(results.container.querySelectorAll('li').length).toEqual(10)
147+
148+
// Here should not expand the 'f:' value since it's beyond maxDepth
149+
await clickByText(results.container, 'f:')
150+
expect(results.container.querySelectorAll('li').length).toEqual(10)
151+
152+
// Collapsing and uncollapsing should not change anything
153+
await clickByText(results.container, '[value]:')
154+
await clickByText(results.container, '[value]:')
155+
expect(results.container.querySelectorAll('li').length).toEqual(10)
156+
157+
await clickByText(results.container, 'b:')
158+
await clickByText(results.container, 'b:')
159+
expect(results.container.querySelectorAll('li').length).toEqual(10)
160+
161+
// Add circular node to the data and use stopCircularRecursion
162+
data.b = data.b.set('g', data.b.get('e'))
163+
results.rerender({
164+
props: {
165+
data,
166+
recursionOpts: {
167+
maxDepth: 5,
168+
stopCircularRecursion: true
169+
}
170+
}
171+
})
172+
173+
// Rerendering should collapse again everything
174+
expect(results.container.querySelectorAll('li').length).toEqual(2)
175+
176+
await clickByText(results.container, 'b:')
177+
expect(results.container.querySelectorAll('li').length).toEqual(6)
178+
179+
await clickByText(results.container, '[map entry 1]:')
180+
expect(results.container.querySelectorAll('li').length).toEqual(9)
181+
182+
await clickByText(results.container, '[value]:')
183+
expect(results.container.querySelectorAll('li').length).toEqual(11)
184+
185+
// Now clicking f: should expand more nodes since maxDepth was increased
186+
await clickByText(results.container, 'f:')
187+
expect(results.container.querySelectorAll('li').length).toEqual(15)
188+
189+
// Clicking the added 'g' value open
190+
await clickByText(results.container, '[map entry 2]:')
191+
expect(results.container.querySelectorAll('li').length).toEqual(18)
192+
193+
// Should not expand since it's a circular value
194+
await clickByText(results.container, '[value]:', 1)
195+
expect(results.container.querySelectorAll('li').length).toEqual(18)
196+
})
197+
198+
it('should respect maxDepth and collapse nodes correctly', async () => {
199+
const results = render(TreeView, {
200+
props: {
201+
data: undefined
202+
}
203+
})
204+
window.HTMLElement.prototype.scrollIntoView = jest.fn()
205+
206+
expect(results.container.querySelectorAll('li').length).toEqual(0)
207+
208+
const nonTreeValues = [
209+
null,
210+
Symbol('foo'),
211+
NaN,
212+
123,
213+
BigInt('0x1fffffffffffff'),
214+
'asdf',
215+
/\w+/,
216+
() => undefined,
217+
function () {
218+
return 0
219+
},
220+
document.createElement('li')
221+
]
222+
nonTreeValues.forEach(val => {
223+
results.rerender({
224+
props: {
225+
data: val
226+
}
227+
})
228+
expect(results.container.querySelectorAll('li').length).toEqual(0)
229+
})
230+
231+
results.rerender({
232+
props: {
233+
data: nonTreeValues
234+
}
235+
})
236+
expect(results.container.querySelectorAll('li').length).toEqual(10)
237+
})
110238
})

0 commit comments

Comments
 (0)