Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/config-type-export.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@docker-doctor/cli": patch
---

Export the `DockerDoctorConfig` type (plus `RuleCategory`) and a `defineConfig` helper for typed `docker-doctor.config.ts` files, and fix the config type's `categories` field to accept a subset of categories (`Partial<Record<…>>`) — matching the validator's actual behavior and the documented examples.
32 changes: 32 additions & 0 deletions apps/web/content/docs/reference/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,36 @@ export default {

The five valid `categories` keys are `Security`, `Performance`, `Best Practices`, `Compose`, and `Image Size`.

## Typed config

`@docker-doctor/cli` exports the `DockerDoctorConfig` type and a `defineConfig` helper. Which one to use depends on how you run docker-doctor:

**Running via `npx` without installing** — use the type with `satisfies`. Type-only imports are erased when the config loads, so nothing needs to be installed at runtime (install `@docker-doctor/cli` as a devDependency if you want editor autocomplete):

```ts
// docker-doctor.config.ts
import type { DockerDoctorConfig } from "@docker-doctor/cli";

export default {
rules: {
"docker-doctor/no-root-user": "error",
},
} satisfies DockerDoctorConfig;
```

**`@docker-doctor/cli` installed as a devDependency** — `defineConfig` also works and gives the same autocomplete:

```ts
// docker-doctor.config.ts
import { defineConfig } from "@docker-doctor/cli";

export default defineConfig({
categories: {
"Image Size": "off",
},
});
```

`defineConfig` is a real runtime import — a config that uses it fails to load when the package isn't installed in the project, so prefer the `satisfies` form for npx-only projects.

Unknown top-level keys and unknown category names are silently dropped rather than rejected, matching the legacy config schema's behavior. Invalid severities throw a config error with the offending rule/category name.
7 changes: 7 additions & 0 deletions packages/core/src/config/define-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { DockerDoctorConfig } from "../types/index";

// Identity helper for typed docker-doctor.config.ts files. Unlike a type-only
// import of DockerDoctorConfig, a config using this must be able to resolve
// @docker-doctor/cli at load time.
export const defineConfig = (config: DockerDoctorConfig): DockerDoctorConfig =>
config;
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export {
allComposeRules,
findRule,
} from "./rules/index";
export { defineConfig } from "./config/define-config";
export { loadConfig } from "./config/loader";
export { calculateScore, getScoreBucket, SCORE_BUCKETS } from "./scoring";
export * from "./errors";
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/schemas/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const validateRules = (value: unknown): Record<string, RuleSeverity> => {

const validateCategories = (
value: unknown
): Record<RuleCategory, RuleSeverity> => {
): Partial<Record<RuleCategory, RuleSeverity>> => {
if (!isPlainObject(value)) {
throw new Error(
`Invalid config: "categories" must be an object, got ${typeof value}`
Expand All @@ -70,7 +70,7 @@ const validateCategories = (
result[key as RuleCategory] = severity;
}

return result as Record<RuleCategory, RuleSeverity>;
return result;
};

const validateIgnore = (value: unknown): { files?: string[] } => {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export interface ComposeRule extends RuleDefinition {

export interface DockerDoctorConfig {
rules?: Record<string, RuleSeverity>;
categories?: Record<RuleCategory, RuleSeverity>;
categories?: Partial<Record<RuleCategory, RuleSeverity>>;
ignore?: {
files?: string[];
};
Expand Down
8 changes: 6 additions & 2 deletions packages/docker-doctor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,19 @@ npx @docker-doctor/cli@latest

### 4. Configure

```js
```ts
// docker-doctor.config.ts
import type { DockerDoctorConfig } from "@docker-doctor/cli";

export default {
rules: {
"docker-doctor/no-root-user": "error",
},
};
} satisfies DockerDoctorConfig;
```

A `defineConfig` helper is also exported for projects with `@docker-doctor/cli` installed — see the [configuration docs](https://docker-doctor.vercel.app/docs/reference/configuration).

## How the score works

Every scan produces a 0-100 health score alongside a label (`Excellent 🏆`, `Good ✅`, `Needs Work ⚠️`, `Critical 🚨`).
Expand Down
8 changes: 7 additions & 1 deletion packages/docker-doctor/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,16 @@ export {
runDockerfileRules,
runComposeRules,
calculateScore,
defineConfig,
loadConfig,
allRules,
findRule,
toJsonReport,
} from "@docker-doctor/core";
export type { Diagnostic, RuleSeverity } from "@docker-doctor/core";
export type {
Diagnostic,
DockerDoctorConfig,
RuleCategory,
RuleSeverity,
} from "@docker-doctor/core";
export const { version } = packageJson;