Skip to content

Commit b282d69

Browse files
authored
refactor: modernize TypeScript config and Vue component patterns (#517)
- Enable stricter TypeScript checks (noUnusedLocals, noUnusedParameters, noFallthroughCasesInSwitch, noUncheckedIndexedAccess) - Upgrade ESLint config to use 'flat/strongly-recommended' ruleset - Add type-check script to package.json for standalone type checking - Integrate type-checking into build process - Adopt Vue 3.5+ props destructure pattern with default values - Enable Vue compiler optimizations (propsDestructure, defineModel, hoistStatic) - Simplify return type annotations by leveraging type inference - Remove redundant env.d.ts in favor of inline types configuration - Standardize to kebab-case for component props in templates - Improve null handling in getValueColorVariable utility - Update tsconfig.node.json to include playwright.config.ts - Set Vite build target to 'baseline-widely-available' for broader compatibility
1 parent fd0d214 commit b282d69

File tree

10 files changed

+73
-59
lines changed

10 files changed

+73
-59
lines changed

env.d.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

eslint.config.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@ export default defineConfigWithVueTs(
88
ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**']
99
},
1010

11-
pluginVue.configs['flat/essential'],
11+
pluginVue.configs['flat/strongly-recommended'],
1212
vueTsConfigs.recommended,
13-
1413
pluginPrettierRecommended,
1514

1615
{

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,9 @@
3939
},
4040
"scripts": {
4141
"dev": "vite",
42-
"build": "vite build && vue-tsc --emitDeclarationOnly",
42+
"build": "vue-tsc --noEmit && vite build && vue-tsc --emitDeclarationOnly",
4343
"preview": "vite preview",
44+
"type-check": "vue-tsc --noEmit",
4445
"lint": "eslint .",
4546
"format": "prettier --write src/",
4647
"deps:update": "npx npm-check-updates -u && npm install",

src/App.vue

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ const onSelected = (event: SelectedData) => {
1212
<template>
1313
<div class="theme-light">
1414
<JsonTreeView
15-
rootKey="root"
16-
colorScheme="light"
15+
root-key="root"
16+
color-scheme="light"
1717
:json="json"
18-
:maxDepth="2"
18+
:max-depth="2"
1919
@selected="onSelected"
2020
/>
2121
</div>
2222
<div class="theme-dark">
23-
<JsonTreeView colorScheme="dark" :json="json" @selected="onSelected" />
23+
<JsonTreeView color-scheme="dark" :json="json" @selected="onSelected" />
2424
</div>
2525
</template>
2626

src/components/JsonTreeView.vue

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<script lang="ts">
22
export type ColorScheme = 'light' | 'dark'
33
4-
export type Props = {
4+
export interface Props {
55
json: string
66
rootKey?: string
77
maxDepth?: number
@@ -23,25 +23,21 @@ defineOptions({
2323
name: 'JsonTreeView'
2424
})
2525
26-
const props = withDefaults(defineProps<Props>(), {
27-
rootKey: '/',
28-
maxDepth: 1,
29-
colorScheme: 'light'
30-
})
26+
const { json, rootKey = '/', maxDepth = 1, colorScheme = 'light' } = defineProps<Props>()
3127
3228
const emit = defineEmits<{
3329
(e: 'selected', value: SelectedData): void
3430
}>()
3531
36-
const onSelected = (selectedData: SelectedData): void => emit('selected', selectedData)
32+
const onSelected = (selectedData: SelectedData) => emit('selected', selectedData)
3733
3834
const buildArrayItem = (
3935
key: string,
4036
array: unknown[],
4137
depth: number,
4238
path: string,
4339
includeKey: boolean
44-
): ItemData => {
40+
) => {
4541
const children = array.map((element, index) =>
4642
buildItemData(
4743
index.toString(),
@@ -68,7 +64,7 @@ const buildObjectItem = (
6864
depth: number,
6965
path: string,
7066
includeKey: boolean
71-
): ItemData => {
67+
) => {
7268
const children = Object.entries(obj).map(([childKey, childValue]) =>
7369
buildItemData(childKey, childValue, depth + 1, buildPath(path, key, includeKey), true)
7470
)
@@ -89,7 +85,7 @@ const buildValueItem = (
8985
depth: number,
9086
path: string,
9187
includeKey: boolean
92-
): ItemData => ({
88+
) => ({
9389
key,
9490
type: ItemType.VALUE,
9591
path: buildValuePath(path, key, includeKey),
@@ -115,21 +111,21 @@ const buildItemData = (
115111
return buildValueItem(key, value as PrimitiveTypes, depth, path, includeKey)
116112
}
117113
118-
const parseJsonToItemData = (json: string, rootKey: string): ItemData => {
114+
const parseJsonToItemData = (jsonStr: string, key: string): ItemData => {
119115
try {
120-
const data = JSON.parse(json)
116+
const data = JSON.parse(jsonStr)
121117
122118
if (isObject(data) || isArray(data)) {
123-
return buildItemData(rootKey, data, 0, '', true)
119+
return buildItemData(key, data, 0, '', true)
124120
}
125121
126-
return buildValueItem(rootKey, data as PrimitiveTypes, 0, '', true)
122+
return buildValueItem(key, data as PrimitiveTypes, 0, '', true)
127123
} catch {
128-
return buildValueItem(rootKey, json, 0, '', true)
124+
return buildValueItem(key, jsonStr, 0, '', true)
129125
}
130126
}
131127
132-
const parsed = computed((): ItemData => parseJsonToItemData(props.json, props.rootKey))
128+
const parsed = computed(() => parseJsonToItemData(json, rootKey))
133129
</script>
134130

135131
<template>

src/components/JsonTreeViewItem.vue

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export type ItemData = {
2323
value?: PrimitiveTypes
2424
}
2525
26-
export type Props = {
26+
export interface Props {
2727
data: ItemData
2828
maxDepth?: number
2929
canSelect?: boolean
@@ -38,54 +38,51 @@ defineOptions({
3838
name: 'JsonTreeViewItem'
3939
})
4040
41-
const props = withDefaults(defineProps<Props>(), {
42-
maxDepth: 1,
43-
canSelect: false
44-
})
41+
const { data, maxDepth = 1, canSelect = false } = defineProps<Props>()
4542
4643
const emit = defineEmits<{
4744
(e: 'selected', value: SelectedData): void
4845
}>()
4946
50-
const isOpen = ref<boolean>(props.data.depth < props.maxDepth)
47+
const isOpen = ref(data.depth < maxDepth)
5148
52-
const toggleOpen = (): void => {
49+
const toggleOpen = () => {
5350
isOpen.value = !isOpen.value
5451
}
5552
56-
const onClick = (data: ItemData): void => {
53+
const onClick = (itemData: ItemData) => {
5754
const selectedData: SelectedData = {
58-
key: data.key,
59-
value: data.value!,
60-
path: data.path
55+
key: itemData.key,
56+
value: itemData.value!,
57+
path: itemData.path
6158
}
6259
emit('selected', selectedData)
6360
}
6461
65-
const onSelected = (data: SelectedData): void => emit('selected', data)
62+
const onSelected = (selectedData: SelectedData) => emit('selected', selectedData)
6663
67-
const chevronClasses = computed<Record<string, boolean>>(() => ({
64+
const chevronClasses = computed(() => ({
6865
'chevron-arrow': true,
6966
opened: isOpen.value
7067
}))
7168
72-
const valueClasses = computed<Record<string, boolean>>(() => ({
69+
const valueClasses = computed(() => ({
7370
'value-key': true,
74-
'can-select': props.canSelect
71+
'can-select': canSelect
7572
}))
7673
77-
const lengthString = computed<string>(() => {
78-
const { length, type } = props.data
74+
const lengthString = computed(() => {
75+
const { length, type } = data
7976
if (length === undefined) return ''
8077
8178
return getLengthString(length, type === ItemType.ARRAY)
8279
})
8380
84-
const dataValue = computed<string>(() => JSON.stringify(props.data.value))
81+
const dataValue = computed(() => JSON.stringify(data.value))
8582
86-
const getItemKey = (item: ItemData): string => formatKey(item.key)
83+
const getItemKey = (item: ItemData) => formatKey(item.key)
8784
88-
const getValueColor = (value: PrimitiveTypes): string => getValueColorVariable(value)
85+
const getValueColor = (value: PrimitiveTypes) => getValueColorVariable(value)
8986
</script>
9087

9188
<template>

src/components/utils.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,26 @@ export const isPrimitive = (value: unknown): value is PrimitiveTypes =>
1111
typeof value === 'number' ||
1212
typeof value === 'boolean'
1313

14-
export const getValueColorVariable = (value: PrimitiveTypes): string => {
14+
export const getValueColorVariable = (value: PrimitiveTypes) => {
15+
if (value === null) {
16+
return 'var(--jtv-null-color)'
17+
}
18+
1519
const typeColorMap: Record<string, string> = {
1620
string: 'var(--jtv-string-color)',
1721
number: 'var(--jtv-number-color)',
18-
boolean: 'var(--jtv-boolean-color)',
19-
object: 'var(--jtv-null-color)'
22+
boolean: 'var(--jtv-boolean-color)'
2023
}
2124

2225
return typeColorMap[typeof value] ?? 'var(--jtv-valueKey-color)'
2326
}
2427

25-
export const formatKey = (key: string): string => {
28+
export const formatKey = (key: string) => {
2629
const numericKey = Number(key)
2730
return Number.isNaN(numericKey) ? `"${key}":` : `${key}":`
2831
}
2932

30-
export const getLengthString = (length: number, isArray: boolean): string => {
33+
export const getLengthString = (length: number, isArray: boolean) => {
3134
const unit = isArray ? 'element' : 'property'
3235
const pluralUnit = isArray ? 'elements' : 'properties'
3336
return length === 1 ? `${length} ${unit}` : `${length} ${pluralUnit}`
@@ -37,8 +40,8 @@ export const buildPath = (
3740
basePath: string,
3841
key: string,
3942
includeKey: boolean,
40-
isArrayElement: boolean = false
41-
): string => {
43+
isArrayElement = false
44+
) => {
4245
if (!includeKey) return basePath
4346

4447
if (isArrayElement) {
@@ -48,7 +51,7 @@ export const buildPath = (
4851
return `${basePath}${key}.`
4952
}
5053

51-
export const buildValuePath = (basePath: string, key: string, includeKey: boolean): string => {
54+
export const buildValuePath = (basePath: string, key: string, includeKey: boolean) => {
5255
if (!includeKey) {
5356
return basePath.slice(0, -1)
5457
}

tsconfig.json

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,23 @@
11
{
22
"extends": ["@vue/tsconfig/tsconfig.dom.json", "@vue/tsconfig/tsconfig.lib.json"],
33
"compilerOptions": {
4-
"target": "ES2020",
5-
"lib": ["ES2020", "DOM", "DOM.Iterable"],
64
"moduleResolution": "bundler",
75
"resolveJsonModule": true,
6+
"strict": true,
7+
"noUnusedLocals": true,
8+
"noUnusedParameters": true,
9+
"noFallthroughCasesInSwitch": true,
10+
"noUncheckedIndexedAccess": true,
811
"declaration": true,
912
"declarationMap": true,
1013
"emitDeclarationOnly": true,
1114
"outDir": "dist",
12-
"sourceMap": true
15+
"sourceMap": true,
16+
"isolatedModules": true,
17+
"skipLibCheck": true,
18+
"types": ["vite/client"]
1319
},
14-
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
20+
"include": ["src/**/*", "src/**/*.vue"],
1521
"exclude": ["src/**/__tests__/*", "src/App.vue", "src/main.ts"],
1622
"references": [{ "path": "./tsconfig.node.json" }]
1723
}

tsconfig.node.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
"skipLibCheck": true,
55
"module": "ESNext",
66
"moduleResolution": "bundler",
7-
"allowSyntheticDefaultImports": true
7+
"allowSyntheticDefaultImports": true,
8+
"types": ["node"]
89
},
9-
"include": ["vite.config.ts"]
10+
"include": ["vite.config.ts", "playwright.config.ts"]
1011
}

vite.config.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,20 @@ import { libInjectCss } from 'vite-plugin-lib-inject-css'
66
const name = 'json-tree-view-vue3'
77

88
export default defineConfig({
9-
plugins: [vue(), libInjectCss()],
9+
plugins: [
10+
vue({
11+
features: {
12+
propsDestructure: true
13+
},
14+
script: {
15+
defineModel: true,
16+
hoistStatic: true
17+
}
18+
}),
19+
libInjectCss()
20+
],
1021
build: {
22+
target: 'baseline-widely-available',
1123
lib: {
1224
entry: fileURLToPath(new URL('./src/index.ts', import.meta.url)),
1325
name,

0 commit comments

Comments
 (0)