Skip to content

Commit 4bd6bce

Browse files
authored
Add knip checks (#274)
* Add knip checks * Restore @types/minimist to satisfy yarn * Narrow knip entry points * Apply knip fixes * Clean up CLI types for knip and lint * Refine knip export checks * Restore CLI APIError re-export
1 parent aa819be commit 4bd6bce

11 files changed

Lines changed: 620 additions & 131 deletions

File tree

.github/workflows/ci.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,17 @@ jobs:
3838
- run: corepack yarn
3939
- run: corepack yarn lint:js
4040

41+
knip:
42+
name: Knip
43+
runs-on: ubuntu-latest
44+
steps:
45+
- uses: actions/checkout@v4
46+
- uses: actions/setup-node@v4
47+
with:
48+
node-version: 22
49+
- run: corepack yarn
50+
- run: corepack yarn knip
51+
4152
typescript:
4253
name: Lint (TypeScript)
4354
runs-on: ubuntu-latest

knip.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import type { KnipConfig } from 'knip'
2+
3+
// Note: `yarn check` runs knip with --fix --allow-remove-files. This is safe because
4+
// lint:ts and tests run immediately after - they'll fail if knip removes something needed.
5+
const config: KnipConfig = {
6+
entry: ['src/Transloadit.ts', 'src/cli.ts', 'test/**/*.{ts,tsx,js,jsx}', 'vitest.config.ts'],
7+
project: ['{src,test}/**/*.{ts,tsx,js,jsx}'],
8+
ignore: [
9+
'dist/**',
10+
'coverage/**',
11+
'static-build/**',
12+
'node_modules/**',
13+
// alphalib is a shared utility library. Exclude it so knip does not remove
14+
// files that may only be used in other repos.
15+
'src/alphalib/**',
16+
],
17+
ignoreDependencies: [
18+
// Used in src/alphalib/** which is excluded from knip
19+
'@aws-sdk/client-s3',
20+
'@aws-sdk/s3-request-presigner',
21+
'@transloadit/sev-logger',
22+
'type-fest',
23+
'zod',
24+
// Repo-specific ignores
25+
'@types/minimist',
26+
'minimatch',
27+
'tsx',
28+
],
29+
ignoreExportsUsedInFile: {
30+
type: true,
31+
interface: true,
32+
},
33+
rules: {
34+
exports: 'warn',
35+
types: 'warn',
36+
nsExports: 'warn',
37+
nsTypes: 'warn',
38+
duplicates: 'warn',
39+
},
40+
}
41+
42+
export default config

package.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,22 @@
3232
"p-queue": "^9.0.1",
3333
"recursive-readdir": "^2.2.3",
3434
"tus-js-client": "^4.3.1",
35+
"typanion": "^3.14.0",
3536
"type-fest": "^4.41.0",
3637
"zod": "3.25.76"
3738
},
3839
"devDependencies": {
3940
"@biomejs/biome": "^2.2.4",
4041
"@types/debug": "^4.1.12",
42+
"@types/minimist": "^1.2.5",
43+
"@types/node": "^24.10.3",
4144
"@types/recursive-readdir": "^2.2.4",
4245
"@types/temp": "^0.9.4",
4346
"@vitest/coverage-v8": "^3.2.4",
4447
"badge-maker": "^5.0.2",
4548
"execa": "9.6.0",
4649
"image-size": "^2.0.2",
50+
"knip": "^5.73.3",
4751
"minimatch": "^10.1.1",
4852
"nock": "^14.0.10",
4953
"npm-run-all": "^4.1.5",
@@ -62,13 +66,16 @@
6266
"src": "./src"
6367
},
6468
"scripts": {
65-
"check": "yarn lint:ts && yarn fix && yarn test:unit",
69+
"check": "yarn knip --fix --allow-remove-files --no-config-hints && yarn lint:ts && yarn fix && yarn test:unit",
6670
"fix:js": "biome check --write .",
6771
"lint:ts": "tsc --build",
6872
"fix:js:unsafe": "biome check --write . --unsafe",
6973
"lint:js": "biome check .",
7074
"lint": "npm-run-all --parallel 'lint:js'",
7175
"fix": "npm-run-all --serial 'fix:js'",
76+
"lint:deps": "knip --dependencies --no-progress",
77+
"fix:deps": "knip --dependencies --no-progress --fix",
78+
"knip": "knip --no-config-hints --no-progress",
7279
"prepack": "rm -f tsconfig.tsbuildinfo tsconfig.build.tsbuildinfo && tsc --build tsconfig.build.json",
7380
"test:unit": "vitest run --coverage ./test/unit",
7481
"test:e2e": "vitest run ./test/e2e",

src/cli/OutputCtl.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Log levels following syslog severity (https://en.wikipedia.org/wiki/Syslog#Severity_level)
33
* Lower numbers = more severe, higher numbers = more verbose
44
*/
5-
export const LOG_LEVEL = {
5+
const LOG_LEVEL = {
66
ERR: 3, // Error conditions
77
WARN: 4, // Warning conditions
88
NOTICE: 5, // Normal but significant (default)

src/cli/commands/BaseCommand.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { getEnvCredentials } from '../helpers.ts'
66
import type { IOutputCtl } from '../OutputCtl.ts'
77
import OutputCtl, { LOG_LEVEL_DEFAULT, LOG_LEVEL_NAMES, parseLogLevel } from '../OutputCtl.ts'
88

9-
export abstract class BaseCommand extends Command {
9+
abstract class BaseCommand extends Command {
1010
logLevelOption = Option.String('-l,--log-level', {
1111
description: `Log level: ${LOG_LEVEL_NAMES.join(', ')} or 3-8 (default: notice)`,
1212
})

src/cli/commands/assemblies.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export interface AssemblyGetOptions {
3636
assemblies: string[]
3737
}
3838

39-
export interface AssemblyDeleteOptions {
39+
interface AssemblyDeleteOptions {
4040
assemblies: string[]
4141
}
4242

src/cli/commands/notifications.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ import { AuthenticatedCommand } from './BaseCommand.ts'
77

88
// --- Types and business logic ---
99

10-
export interface NotificationsReplayOptions {
10+
interface NotificationsReplayOptions {
1111
notify_url?: string
1212
assemblies: string[]
1313
}
1414

15-
export async function replay(
15+
async function replay(
1616
output: IOutputCtl,
1717
client: Transloadit,
1818
{ notify_url, assemblies }: NotificationsReplayOptions,

src/cli/commands/templates.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ export interface TemplateModifyOptions {
3333
file: string
3434
}
3535

36-
export interface TemplateDeleteOptions {
36+
interface TemplateDeleteOptions {
3737
templates: string[]
3838
}
3939

40-
export interface TemplateListOptions {
40+
interface TemplateListOptions {
4141
before?: string
4242
after?: string
4343
order?: 'asc' | 'desc'
@@ -162,7 +162,7 @@ const TemplateIdSchema = z.object({
162162
id: z.string(),
163163
})
164164

165-
export function list(
165+
function list(
166166
output: IOutputCtl,
167167
client: Transloadit,
168168
{ before, after, order, sort, fields }: TemplateListOptions,

src/cli/helpers.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import fs from 'node:fs'
22
import type { Readable } from 'node:stream'
3-
import type { APIError } from './types.ts'
43
import { isAPIError } from './types.ts'
54

65
export function getEnvCredentials(): { authKey: string; authSecret: string } | null {
@@ -35,8 +34,9 @@ export function formatAPIError(err: unknown): string {
3534
return String(err)
3635
}
3736

38-
// Re-export APIError type for convenience
39-
export type { APIError }
37+
// Re-export APIError type for CLI consumers relying on deep imports.
38+
/** @public */
39+
export type { APIError } from './types.ts'
4040

4141
export function zip<A, B>(listA: A[], listB: B[]): [A, B][]
4242
export function zip<T>(...lists: T[][]): T[][]

src/cli/types.ts

Lines changed: 2 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,15 @@
11
import { z } from 'zod'
22
import type { Steps } from '../alphalib/types/template.ts'
33
import { optionalStepsSchema } from '../alphalib/types/template.ts'
4-
import type { BillResponse, ListedTemplate, TemplateResponse } from '../apiTypes.ts'
5-
import type { AssemblyStatus, Transloadit } from '../Transloadit.ts'
6-
import type { IOutputCtl } from './OutputCtl.ts'
7-
8-
// Re-export transloadit types for CLI use
9-
export type { AssemblyStatus, BillResponse, ListedTemplate, TemplateResponse }
10-
export type { Transloadit }
11-
export type { CreateAssemblyOptions } from '../Transloadit.ts'
124

135
// Zod schemas for runtime validation
14-
export const APIErrorSchema = z.object({
6+
const APIErrorSchema = z.object({
157
error: z.string(),
168
message: z.string(),
179
})
1810
export type APIError = z.infer<typeof APIErrorSchema>
1911

20-
export const TransloaditAPIErrorSchema = z.object({
12+
const TransloaditAPIErrorSchema = z.object({
2113
error: z.string().optional(),
2214
message: z.string(),
2315
code: z.string().optional(),
@@ -54,98 +46,6 @@ export interface TemplateFile {
5446
data: TemplateFileData
5547
}
5648

57-
// Template list item (from API)
58-
export interface TemplateListItem {
59-
id: string
60-
modified: string
61-
name?: string
62-
}
63-
64-
// CLI Invocation types
65-
export interface BaseInvocation {
66-
error?: boolean
67-
message?: string
68-
mode: string
69-
action?: string
70-
logLevel?: number
71-
jsonMode?: boolean
72-
}
73-
74-
export interface AssemblyInvocation extends BaseInvocation {
75-
mode: 'assemblies'
76-
action?: 'create' | 'get' | 'list' | 'delete' | 'replay'
77-
inputs: string[]
78-
output?: string
79-
recursive?: boolean
80-
watch?: boolean
81-
del?: boolean
82-
reprocessStale?: boolean
83-
steps?: string
84-
template?: string
85-
fields?: Record<string, string>
86-
assemblies?: string[]
87-
before?: string
88-
after?: string
89-
keywords?: string[]
90-
notify_url?: string
91-
reparse?: boolean
92-
}
93-
94-
export interface TemplateInvocation extends BaseInvocation {
95-
mode: 'templates'
96-
action?: 'create' | 'get' | 'list' | 'delete' | 'modify' | 'sync'
97-
templates?: string[]
98-
template?: string
99-
name?: string
100-
file?: string
101-
files?: string[]
102-
before?: string
103-
after?: string
104-
order?: 'asc' | 'desc'
105-
sort?: string
106-
fields?: string[]
107-
recursive?: boolean
108-
}
109-
110-
export interface BillInvocation extends BaseInvocation {
111-
mode: 'bills'
112-
action?: 'get'
113-
months: string[]
114-
}
115-
116-
export interface NotificationInvocation extends BaseInvocation {
117-
mode: 'assembly-notifications'
118-
action?: 'list' | 'replay'
119-
assemblies?: string[]
120-
notify_url?: string
121-
type?: string
122-
assembly_id?: string
123-
pagesize?: number
124-
}
125-
126-
export interface HelpInvocation extends BaseInvocation {
127-
mode: 'help' | 'version' | 'register'
128-
}
129-
130-
export type Invocation =
131-
| AssemblyInvocation
132-
| TemplateInvocation
133-
| BillInvocation
134-
| NotificationInvocation
135-
| HelpInvocation
136-
137-
// Command handler type
138-
export type CommandHandler<T extends BaseInvocation = BaseInvocation> = (
139-
output: IOutputCtl,
140-
client: Transloadit | undefined,
141-
invocation: T,
142-
) => void | Promise<void>
143-
144-
// Type guard for Error
145-
export function isError(value: unknown): value is Error {
146-
return value instanceof Error
147-
}
148-
14949
// Helper to ensure error is Error type
15050
export function ensureError(value: unknown): Error {
15151
if (value instanceof Error) {
@@ -168,16 +68,3 @@ export function isTransloaditAPIError(value: unknown): value is TransloaditAPIEr
16868
export function isErrnoException(value: unknown): value is NodeJS.ErrnoException {
16969
return value instanceof Error && 'code' in value
17070
}
171-
172-
// Safe array access helper
173-
export function safeGet<T>(arr: T[], index: number): T | undefined {
174-
return arr[index]
175-
}
176-
177-
// Assert defined helper
178-
export function assertDefined<T>(value: T | undefined | null, message: string): T {
179-
if (value === undefined || value === null) {
180-
throw new Error(message)
181-
}
182-
return value
183-
}

0 commit comments

Comments
 (0)