mirror of
https://github.com/oxynote/oxynote.git
synced 2026-10-17 10:59:20 +02:00
clean up with knip in web
This commit is contained in:
parent
0382d19292
commit
100f3bd3ab
|
|
@ -127,7 +127,7 @@ ESLint ([eslint.config.mjs](eslint.config.mjs)) runs **type-aware**: `eslint.con
|
|||
- `@typescript-eslint/no-explicit-any` is off; `prefer-function-type` is off (keeps the `defineEmits<{ (e: ...): void }>()` style).
|
||||
- The vendored `packages/lezer-promql` fork is excluded so upstream re-syncs cannot break the gate.
|
||||
|
||||
**knip** ([knip.ts](knip.ts)) guards dead exports, unused files, and unused dependencies. Its blind spots are deliberate and documented in the config: the auto-import surface (`app/composables`, `app/stores`, `app/utils`) and all `.vue` components are entry points because nuxt wires them without import statements — unused exports there and unused components are **not** reported. `app/components/shadcn/` is ignored (vendored spares are expected). Knip's `unlisted` check is **off** by policy: the hoisted node_modules layout makes transitive packages importable, that is relied on deliberately, and `package.json` declares top-level intent only.
|
||||
**knip** ([knip.ts](knip.ts)) guards dead exports, unused files, and unused dependencies. Its nuxt plugin resolves auto-imports through the generated `.nuxt` maps, so unused components, stores, and utils **are** detected despite having no import statements. Remaining blind spots, documented in the config: `app/composables` are entry points (the auto-import map does not connect their `export default function useX` style, so their internal exports are unreported), and `app/components/shadcn/` is ignored (vendored spares are expected). Knip's `unlisted` check is **off** by policy: the hoisted node_modules layout makes transitive packages importable, that is relied on deliberately, and `package.json` declares top-level intent only. Knip runs with `--cache`, and the cache is keyed by knip version, **not** config — after editing [knip.ts](knip.ts), run `rm -rf node_modules/.cache/knip` or results are stale.
|
||||
|
||||
TypeScript strictness (set in [nuxt.config.ts](nuxt.config.ts)): `noUnusedLocals`, `noUnusedParameters`, `noUncheckedIndexedAccess`, `noImplicitOverride`, `verbatimModuleSyntax`, and `noImplicitAny` all on; `allowUnreachableCode: false` (mirrored in [electron/tsconfig.json](electron/tsconfig.json)). Path aliases `@/*` and `~/*` both point to `app/*`.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
<script lang="ts" setup>
|
||||
import type { InputProps } from "./shadcn/ui/input"
|
||||
import { cn } from "~/lib/utils"
|
||||
|
||||
// NOTE: currently, only "ghost" inputs are supported
|
||||
|
||||
const props = defineProps<
|
||||
Omit<InputProps, "modelValue" | "ghost"> & {
|
||||
inputClass?: string
|
||||
}
|
||||
>()
|
||||
const value = defineModel<string>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="cn('relative inline-grid min-w-0', props.class)">
|
||||
<span
|
||||
aria-hidden="true"
|
||||
:class="
|
||||
cn(
|
||||
props.inputClass,
|
||||
'pointer-events-none invisible block whitespace-pre [grid-area:1/1]',
|
||||
)
|
||||
"
|
||||
>
|
||||
{{ value || props.placeholder }}
|
||||
</span>
|
||||
<ShadcnUiInput
|
||||
v-model="value"
|
||||
v-bind="{
|
||||
...props,
|
||||
ghost: true,
|
||||
class: cn(props.inputClass, 'absolute inset-0 w-full [grid-area:1/1]'),
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
import IconStack from "./IconStack.vue"
|
||||
import { showToastMessage } from "../toast"
|
||||
|
||||
export interface ReviewerEntry {
|
||||
interface ReviewerEntry {
|
||||
id: string
|
||||
name: string
|
||||
email: string
|
||||
|
|
@ -11,7 +11,7 @@ export interface ReviewerEntry {
|
|||
previouslyApproved?: boolean
|
||||
}
|
||||
|
||||
export interface ReviewerInviteEntry {
|
||||
interface ReviewerInviteEntry {
|
||||
id: string
|
||||
name: string
|
||||
email?: string | null
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
import ConfigField from "./ConfigField.vue"
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
disabled?: boolean
|
||||
placeholder: string
|
||||
inputClass?: string
|
||||
}>(),
|
||||
{
|
||||
inputClass: "text-2sm md:text-2sm px-2 h-[1.775rem]",
|
||||
},
|
||||
)
|
||||
const value = defineModel<string | undefined>()
|
||||
</script>
|
||||
<template>
|
||||
<ConfigField>
|
||||
<template #label>
|
||||
<slot name="label" />
|
||||
</template>
|
||||
<template #default>
|
||||
<ShadcnUiInput
|
||||
v-model="value"
|
||||
:class="props.inputClass"
|
||||
type="url"
|
||||
:placeholder="props.placeholder"
|
||||
:disabled="props.disabled"
|
||||
disable-focus-effect
|
||||
/>
|
||||
</template>
|
||||
</ConfigField>
|
||||
</template>
|
||||
68
web/knip.ts
68
web/knip.ts
|
|
@ -1,9 +1,9 @@
|
|||
import type { KnipConfig } from "knip"
|
||||
import { parse } from "vue/compiler-sfc"
|
||||
|
||||
// knip's nuxt plugin only knows the nuxt 3 layout, so the nuxt 4 app/
|
||||
// conventions (and everything else referenced by convention rather than by
|
||||
// import) are declared as entries here explicitly.
|
||||
// knip's nuxt plugin handles the nuxt 4 app/ layout natively (it detects the
|
||||
// app/ srcDir) and resolves auto-imported components and named composables
|
||||
// through the generated .nuxt/imports.d.ts and .nuxt/components.d.ts maps —
|
||||
// so only the conventions it cannot know about are configured here.
|
||||
const config: KnipConfig = {
|
||||
// the vendored PromQL grammar fork is re-synced from upstream and must
|
||||
// not be reported against (see packages/README.lezer-promql.md)
|
||||
|
|
@ -17,56 +17,16 @@ const config: KnipConfig = {
|
|||
unlisted: "off",
|
||||
},
|
||||
|
||||
compilers: {
|
||||
// the SFC compiler recommended by knip's docs, extended to follow
|
||||
// tailwind v4 @reference/@plugin directives in <style> blocks
|
||||
vue: (text: string, filename: string) => {
|
||||
const { descriptor } = parse(text, { filename, sourceMap: false })
|
||||
|
||||
const scripts = [descriptor.script, descriptor.scriptSetup]
|
||||
.filter((block) => block !== null)
|
||||
.map((block) => (block.src ? `import '${block.src}'` : block.content))
|
||||
|
||||
const styles = descriptor.styles.flatMap((block) => [
|
||||
...[...block.content.matchAll(/(?<=@)import[^;]+/g)].map(String),
|
||||
...[
|
||||
...block.content.matchAll(/@(?:plugin|reference)\s+"([^"]+)"/g),
|
||||
].map((m) => `import "${m[1]}"`),
|
||||
])
|
||||
|
||||
return [...scripts, ...styles].join("\n")
|
||||
},
|
||||
// follows @import chains and tailwind v4 @plugin directives in the
|
||||
// css entries nuxt loads (main.css)
|
||||
css: (text: string) =>
|
||||
[
|
||||
...[...text.matchAll(/(?<=@)import[^;]+/g)].map(String),
|
||||
...[...text.matchAll(/@plugin\s+"([^"]+)"/g)].map(
|
||||
(m) => `import "${m[1]}"`,
|
||||
),
|
||||
].join("\n"),
|
||||
},
|
||||
|
||||
workspaces: {
|
||||
".": {
|
||||
entry: [
|
||||
// nuxt 4 app/ conventions: loaded by the framework, never
|
||||
// imported. Components are included because templates
|
||||
// reference them by tag through nuxt auto-registration,
|
||||
// which knip cannot resolve — a component no longer used by
|
||||
// any template is therefore NOT reported by knip.
|
||||
"app/pages/**/*.vue",
|
||||
"app/middleware/**/*.ts",
|
||||
"app/plugins/**/*.ts",
|
||||
"app/components/**/*.vue",
|
||||
// the whole auto-import surface: unimport makes everything
|
||||
// in these directories reachable without import statements,
|
||||
// so knip cannot trace their usage. The tradeoff: unused
|
||||
// exports inside these directories are NOT reported.
|
||||
// the auto-import map connects named exports, but not the
|
||||
// `export default function useX` style these composables
|
||||
// use — without this their defaults are reported unused.
|
||||
// The api/ barrel (index.ts) is also convention-load-bearing:
|
||||
// it is what makes the nested api/ composables auto-importable.
|
||||
"app/composables/**/*.ts",
|
||||
"app/stores/**/*.ts",
|
||||
"app/utils/**/*.ts",
|
||||
// module conventions loaded by name
|
||||
// module convention loaded by name (@pinia/colada-nuxt)
|
||||
"colada.options.ts",
|
||||
// electron main/preload world, built by forge + vite
|
||||
"electron/main.ts",
|
||||
|
|
@ -75,11 +35,6 @@ const config: KnipConfig = {
|
|||
"vite.electron.config.ts",
|
||||
],
|
||||
|
||||
// auto-imported by unimport (no import statements at use
|
||||
// sites), so the files must count as project members even when
|
||||
// nothing imports them
|
||||
project: ["app/**/*.{ts,vue,css}", "electron/**/*.ts", "*.ts"],
|
||||
|
||||
ignore: [
|
||||
// vendored shadcn-vue components: installed ahead of use and
|
||||
// regenerated by the CLI; unused spares and barrel exports
|
||||
|
|
@ -91,6 +46,9 @@ const config: KnipConfig = {
|
|||
// icon collections resolved by name at build time by
|
||||
// @nuxt/icon
|
||||
"@iconify-json/.*",
|
||||
// consumed only by the vendored shadcn drawer spares, which
|
||||
// are ignored above
|
||||
"vaul-vue",
|
||||
// never imported directly — declared as the umbrella that
|
||||
// provides the individually-imported @tiptap/extension-*
|
||||
// packages (see rules.unlisted above)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user