Skip to content

Commit

Permalink
feat: show loading indicator
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Apr 8, 2024
1 parent b00151c commit 23c6135
Show file tree
Hide file tree
Showing 11 changed files with 128 additions and 53 deletions.
25 changes: 10 additions & 15 deletions app/app.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<script setup lang="ts">
import { useHead } from '@unhead/vue'
import { ensureDataFetch, errorInfo } from '~/composables/payload'
import { version } from '~~/package.json'
import { errorInfo, isLoading } from '~/composables/payload'
import 'floating-vue/dist/style.css'
import './styles/global.css'
Expand All @@ -10,22 +9,11 @@ import './composables/dark'
useHead({
title: 'ESLint Config Inspector',
})
await ensureDataFetch()
</script>

<template>
<div v-if="errorInfo" bg-base color-base grid h-full w-full place-content-center whitespace-pre-line>
<div font-200 text-xl mb6>
<a
href="https://github.com/eslint/config-inspector" target="_blank"
flex="inline gap-2 items-center" mr1
>
<img src="/favicon.svg" inline-block h-1em>
<span op75>ESLint Config Inspector</span>
</a>
<sup op50>v{{ version }}</sup>
</div>
<div v-if="errorInfo" grid h-full w-full place-content-center whitespace-pre-line p4>
<ConfigInspectorBadge font-200 text-xl mb6 />

<div text-2xl text-red5 font-bold>
Failed to load <span rounded bg-red:5 px2>eslint.config.js</span><br>
Expand All @@ -41,6 +29,13 @@ await ensureDataFetch()
only works with the <a href="https://eslint.org/docs/latest/use/configure/configuration-files-new" target="_blank" font-bold hover:underline>flat config format</a>.
</div>
</div>
<div v-else-if="isLoading" p4 flex="~ col" w-full h-full items-center justify-center>
<div animate-pulse flex="~ gap-2 items-center" text-xl flex-auto>
<div i-svg-spinners-90-ring-with-bg />
Loading config...
</div>
<ConfigInspectorBadge font-200 text-xl mt6 :show-version="false" />
</div>
<div v-else px4 py6 lg:px14 lg:py10>
<NavBar />
<NuxtPage />
Expand Down
30 changes: 30 additions & 0 deletions app/components/ConfigInspectorBadge.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<script setup lang="ts">
import { version } from '~~/package.json'
withDefaults(
defineProps<{
showVersion?: boolean
}>(),
{
showVersion: true,
},
)
</script>

<template>
<div>
<a
href="https://github.com/eslint/config-inspector" target="_blank"
flex="inline gap-2 items-center" mr1
>
<img src="/favicon.svg" inline-block h-1em> ESLint Config Inspector
</a>
<a
v-if="showVersion"
op50 font-mono inline-block translate-y--5 ml1 text-0.8em
:href="`https://github.com/eslint/config-inspector/releases/tag/v${version}`" target="_blank"
>
v{{ version }}
</a>
</div>
</template>
27 changes: 11 additions & 16 deletions app/components/NavBar.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
<script setup lang="ts">
import { computed } from 'vue'
import { useTimeAgo } from '@vueuse/core'
import { version } from '../../package.json'
import { filtersRules as filters, stateStorage } from '~/composables/state'
import { useRouter } from '#app/composables/router'
import { payload } from '~/composables/payload'
import { isFetching, payload } from '~/composables/payload'
import { toggleDark } from '~/composables/dark'
const lastUpdate = useTimeAgo(() => payload.value.meta.lastUpdate)
Expand All @@ -30,20 +29,7 @@ function toggleRuleView() {
</script>

<template>
<div text-3xl font-200>
<a
href="https://github.com/eslint/config-inspector" target="_blank"
flex="inline gap-2 items-center" mr1
>
<img src="/favicon.svg" inline-block h-1em> ESLint Config Inspector
</a>
<a
op50 font-mono text-base inline-block translate-y--5 ml1
:href="`https://github.com/eslint/config-inspector/releases/tag/v${version}`" target="_blank"
>
v{{ version }}
</a>
</div>
<ConfigInspectorBadge text-3xl font-200 />
<div v-if="payload.meta.configPath" flex="~ gap-1 items-center" text-sm my1>
<span font-mono op35>{{ payload.meta.configPath }}</span>
</div>
Expand All @@ -52,6 +38,14 @@ function toggleRuleView() {
<span font-bold>{{ payload.configs.length }}</span>
<span op50>config items, updated</span>
<span op75>{{ lastUpdate }}</span>
<div
v-if="isFetching"
flex="~ gap-2 items-center"
text-green ml2 animate-pulse
>
<div i-svg-spinners-90-ring-with-bg text-sm flex-none />
Fetching updates...
</div>
</div>
<div flex="~ gap-3 items-center wrap" py4>
<NuxtLink
Expand All @@ -71,6 +65,7 @@ function toggleRuleView() {
Rules
</NuxtLink>
<NuxtLink
v-if="payload.files"
to="/files" active-class="op100! bg-active"
px3 py1 op50 border="~ base rounded"
flex="~ gap-2 items-center"
Expand Down
19 changes: 17 additions & 2 deletions app/composables/payload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,38 @@ const data = ref<Payload>({
rules: {},
configs: [],
meta: {} as any,
files: [],
})

/**
* State of initial loading
*/
export const isLoading = ref(true)
/**
* State of fetching, used for loading indicator
*/
export const isFetching = ref(false)
/**
* Error information
*/
export const errorInfo = ref<ErrorInfo>()

function isErrorInfo(payload: Payload | ErrorInfo): payload is ErrorInfo {
return 'error' in payload
}

async function get() {
isFetching.value = true
const payload = await $fetch<Payload | ErrorInfo>('/api/payload.json')
if (isErrorInfo(payload)) {
errorInfo.value = payload
isLoading.value = false
isFetching.value = false
return
}
errorInfo.value = undefined
data.value = payload
isLoading.value = false
isFetching.value = false
console.log(LOG_NAME, 'Config payload', payload)
return payload
}
Expand Down Expand Up @@ -99,7 +114,7 @@ export function resolvePayload(payload: Payload): ResolvedPayload {
.filter((idx): idx is number => idx !== undefined)

const filesMatchedConfigsMap = new Map<string, FileConfigMatchResult[]>()
payload.files.forEach((file) => {
payload.files?.forEach((file) => {
filesMatchedConfigsMap.set(file, getMatchedConfigs(file, payload.configs))
})

Expand Down
2 changes: 1 addition & 1 deletion app/pages/configs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const filteredConfigs = computed(() => {
})
const autoCompleteFuse = computed(() => {
return new Fuse(payload.value.files, {
return new Fuse(payload.value.files || [], {
threshold: 0.3,
includeMatches: true,
})
Expand Down
7 changes: 6 additions & 1 deletion app/pages/files.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { payload } from '~/composables/payload'
</script>

<template>
<div flex="~ col gap-4" my4>
<div v-if="payload.files" flex="~ col gap-4" my4>
<div text-gray:75>
This tab shows the preview for files match from the workspace.
This feature is <span text-amber>experimental</span> and may not be 100% accurate.
Expand Down Expand Up @@ -46,4 +46,9 @@ import { payload } from '~/composables/payload'
</div>
</div>
</div>
<div v-else>
<div op50 italic p3>
No matched files found in the workspace.
</div>
</div>
</template>
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"@iconify-json/logos": "^1.1.42",
"@iconify-json/ph": "^1.1.12",
"@iconify-json/simple-icons": "^1.1.98",
"@iconify-json/svg-spinners": "^1.1.2",
"@iconify-json/twemoji": "^1.1.15",
"@iconify-json/vscode-icons": "^1.1.33",
"@nuxt/eslint": "^0.3.1",
Expand Down
9 changes: 9 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion shared/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ export type RuleLevel = 'off' | 'warn' | 'error'

export interface Payload {
configs: FlatESLintConfigItem[]
files: string[]
rules: Record<string, RuleInfo>
meta: PayloadMeta
files?: string[]
}

export interface ErrorInfo {
Expand Down
6 changes: 5 additions & 1 deletion src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ const cli = cac()
cli
.command('build', 'Build inspector with current config file for static hosting')
.option('--config <configFile>', 'Config file path')
.option('--files', 'Include matched file paths in payload', { default: true })
.option('--basePath <basePath>', 'Base directory for globs to resolve. Default to directory of config file if not provided')
.option('--out-dir <dir>', 'Output directory', { default: '.eslint-config-inspector' })
.option('--outDir <dir>', 'Output directory', { default: '.eslint-config-inspector' })
.action(async (options) => {
console.log('Building static ESLint config inspector...')

Expand All @@ -28,6 +29,7 @@ cli
cwd,
userConfigPath: options.config,
userBasePath: options.basePath,
globMatchedFiles: options.files,
})

if (existsSync(outDir))
Expand All @@ -47,6 +49,7 @@ cli
cli
.command('', 'Start dev inspector')
.option('--config <configFile>', 'Config file path')
.option('--files', 'Include matched file paths in payload', { default: true })
.option('--basePath <basePath>', 'Base directory for globs to resolve. Default to directory of config file if not provided')
.option('--host <host>', 'Host', { default: process.env.HOST || '127.0.0.1' })
.option('--port <port>', 'Port', { default: process.env.PORT || 7777 })
Expand All @@ -65,6 +68,7 @@ cli
cwd,
userConfigPath: options.config,
userBasePath: options.basePath,
globMatchedFiles: options.files,
})

server.listen(port, host)
Expand Down
53 changes: 37 additions & 16 deletions src/configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { Linter } from 'eslint'
import fg from 'fast-glob'
import { findUp } from 'find-up'
import type { FlatESLintConfigItem, Payload, RuleInfo } from '../shared/types'
import { isIgnoreOnlyConfig } from '~~/shared/configs'

const configFilenames = [
'eslint.config.js',
Expand All @@ -29,6 +30,12 @@ export interface ReadConfigOptions {
* Override base path. When not provided, will use directory of discovered config file.
*/
userBasePath?: string
/**
* Glob file paths matched by the configs
*
* @default true
*/
globMatchedFiles?: boolean
/**
* Change current working directory to basePath
* @default true
Expand All @@ -50,6 +57,7 @@ export async function readConfig(
userConfigPath,
userBasePath,
chdir = true,
globMatchedFiles: globFiles = true,
}: ReadConfigOptions,
): Promise<{ configs: FlatESLintConfigItem[], payload: Payload, dependencies: string[] }> {
if (userBasePath)
Expand Down Expand Up @@ -120,25 +128,12 @@ export async function readConfig(
}
})

const files = await fg(
configs.flatMap(i => i.files ?? []).filter(i => typeof i === 'string') as string[],
{
cwd: rootPath,
onlyFiles: true,
ignore: [
'**/node_modules/**',
...configs.flatMap(i => i.ignores ?? []).filter(i => typeof i === 'string') as string[],
],
deep: 5,
},
)

files.sort()

const payload: Payload = {
configs,
rules,
files,
files: globFiles
? await globMatchedFiles(rootPath, configs)
: undefined,
meta: {
lastUpdate: Date.now(),
rootPath,
Expand All @@ -152,3 +147,29 @@ export async function readConfig(
payload,
}
}

export async function globMatchedFiles(
rootPath: string,
configs: FlatESLintConfigItem[],
): Promise<string[]> {
const files = await fg(
configs.flatMap(i => i.files ?? []).filter(i => typeof i === 'string') as string[],
{
cwd: rootPath,
onlyFiles: true,
ignore: [
'**/node_modules/**',
'**/dist/**',
'**/.git/**',
...configs
.filter(i => isIgnoreOnlyConfig(i))
.flatMap(i => i.files ?? [])
.filter(i => typeof i === 'string') as string[],
],
deep: 5,
},
)

files.sort()
return files
}

0 comments on commit 23c6135

Please sign in to comment.