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/strict-diagnostic-preset.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@effect/tsgo": minor
---

Add a `strict` diagnostic preset that promotes every default-enabled diagnostic to an error. Expose the complete preset catalog consistently through TypeScript setup and the generated Oxlint presets.
2 changes: 1 addition & 1 deletion _packages/tsgo/src/cli/presets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ interface MetadataDocument {
readonly presets: ReadonlyArray<DiagnosticPreset>
}

const metadata = metadataJson as MetadataDocument
const metadata = metadataJson as unknown as MetadataDocument

const severityRank: Record<RuleSeverity, number> = {
off: 0,
Expand Down
2 changes: 1 addition & 1 deletion _packages/tsgo/src/cli/setup/rule-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export function getAllGroups(): ReadonlyArray<GroupInfo> {
}

export function getAllPresets(): ReadonlyArray<DiagnosticPresetInfo> {
return (metadataJson as { presets?: ReadonlyArray<DiagnosticPresetInfo> }).presets ?? []
return (metadataJson as unknown as { presets?: ReadonlyArray<DiagnosticPresetInfo> }).presets ?? []
}

export function cycleSeverity(
Expand Down
284 changes: 284 additions & 0 deletions _packages/tsgo/src/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,231 @@
}
],
"presets": [
{
"name": "recommended",
"description": "Enable diagnostics at their default severities.",
"diagnosticSeverity": {
"abortControllerInEffect": "suggestion",
"acquireReleaseDisposable": "suggestion",
"allOfMapToForEach": "suggestion",
"catchAllTagDispatchToCatchTag": "suggestion",
"catchAllToMapError": "suggestion",
"catchChainToFirstSuccessOf": "suggestion",
"catchConditionalRefailToCatchIf": "suggestion",
"catchDieToOrDie": "suggestion",
"catchIfTagToCatchTag": "suggestion",
"catchRefailToTapError": "suggestion",
"catchTagToCatchReason": "suggestion",
"catchToIgnore": "suggestion",
"catchToOrElseSucceed": "suggestion",
"catchUnfailableEffect": "suggestion",
"classSelfMismatch": "error",
"duplicatePackage": "warning",
"effectFnIife": "warning",
"effectFnImplicitAny": "error",
"effectFnOpportunity": "suggestion",
"effectGenUsesAdapter": "warning",
"effectInFailure": "warning",
"effectInVoidSuccess": "warning",
"effectMapFlatten": "suggestion",
"effectMapVoid": "suggestion",
"effectSucceedWithVoid": "suggestion",
"flatMapConditionalToFilterOrFail": "suggestion",
"flatMapIgnoredParamToAndThen": "suggestion",
"flatMapToMap": "suggestion",
"floatingEffect": "error",
"floatingEffectInVitest": "error",
"genericEffectServices": "warning",
"globalErrorInEffectCatch": "warning",
"globalErrorInEffectFailure": "warning",
"layerMergeAllWithDependencies": "warning",
"lazyEffect": "suggestion",
"lazyPromiseInEffectSync": "warning",
"leakingRequirements": "suggestion",
"mapSomeToAsSome": "suggestion",
"matchEffectToMapBoth": "suggestion",
"matchEffectToMatch": "suggestion",
"missingEffectContext": "error",
"missingEffectError": "error",
"missingLayerContext": "error",
"missingReturnYieldStar": "error",
"missingStarInYieldEffectGen": "error",
"multipleCatchTag": "suggestion",
"multipleEffectProvide": "warning",
"nonObjectEffectServiceType": "error",
"obsoleteMatchImport": "warning",
"obsoleteSchemaImport": "warning",
"optionMatchToFromOption": "suggestion",
"outdatedApi": "warning",
"overriddenSchemaConstructor": "error",
"preferSucceedSomeOrNone": "suggestion",
"preferTypedSchemaDecoder": "suggestion",
"preferUnsafeConstructor": "suggestion",
"promiseInEffectSuccess": "warning",
"provideLayerSucceedToProvideService": "suggestion",
"raceFirstWithSleepToTimeout": "suggestion",
"redundantMapError": "suggestion",
"redundantOrDie": "suggestion",
"redundantSchemaTagIdentifier": "suggestion",
"returnEffectInGen": "suggestion",
"runEffectInsideEffect": "suggestion",
"runOfExitToRunExit": "suggestion",
"schemaLiteralNonFinite": "error",
"schemaNumber": "suggestion",
"schemaOpaqueInstanceMember": "error",
"schemaStructWithTag": "suggestion",
"schemaSyncInEffect": "suggestion",
"scopeInLayerEffect": "warning",
"syncToSucceed": "suggestion",
"timeoutCatchTagToTimeoutOrElse": "suggestion",
"tryCatchInEffectGen": "suggestion",
"unknownInEffectCatch": "warning",
"unnecessaryEffectGen": "suggestion",
"unnecessaryFailYieldableError": "suggestion",
"unnecessaryPipe": "suggestion",
"unnecessaryPipeChain": "suggestion",
"unnecessaryTypeofType": "suggestion"
}
},
{
"name": "strict",
"description": "Treat every diagnostic enabled by default as an error.",
"diagnosticSeverity": {
"abortControllerInEffect": "error",
"acquireReleaseDisposable": "error",
"allOfMapToForEach": "error",
"catchAllTagDispatchToCatchTag": "error",
"catchAllToMapError": "error",
"catchChainToFirstSuccessOf": "error",
"catchConditionalRefailToCatchIf": "error",
"catchDieToOrDie": "error",
"catchIfTagToCatchTag": "error",
"catchRefailToTapError": "error",
"catchTagToCatchReason": "error",
"catchToIgnore": "error",
"catchToOrElseSucceed": "error",
"catchUnfailableEffect": "error",
"classSelfMismatch": "error",
"duplicatePackage": "error",
"effectFnIife": "error",
"effectFnImplicitAny": "error",
"effectFnOpportunity": "error",
"effectGenUsesAdapter": "error",
"effectInFailure": "error",
"effectInVoidSuccess": "error",
"effectMapFlatten": "error",
"effectMapVoid": "error",
"effectSucceedWithVoid": "error",
"flatMapConditionalToFilterOrFail": "error",
"flatMapIgnoredParamToAndThen": "error",
"flatMapToMap": "error",
"floatingEffect": "error",
"floatingEffectInVitest": "error",
"genericEffectServices": "error",
"globalErrorInEffectCatch": "error",
"globalErrorInEffectFailure": "error",
"layerMergeAllWithDependencies": "error",
"lazyEffect": "error",
"lazyPromiseInEffectSync": "error",
"leakingRequirements": "error",
"mapSomeToAsSome": "error",
"matchEffectToMapBoth": "error",
"matchEffectToMatch": "error",
"missingEffectContext": "error",
"missingEffectError": "error",
"missingLayerContext": "error",
"missingReturnYieldStar": "error",
"missingStarInYieldEffectGen": "error",
"multipleCatchTag": "error",
"multipleEffectProvide": "error",
"nonObjectEffectServiceType": "error",
"obsoleteMatchImport": "error",
"obsoleteSchemaImport": "error",
"optionMatchToFromOption": "error",
"outdatedApi": "error",
"overriddenSchemaConstructor": "error",
"preferSucceedSomeOrNone": "error",
"preferTypedSchemaDecoder": "error",
"preferUnsafeConstructor": "error",
"promiseInEffectSuccess": "error",
"provideLayerSucceedToProvideService": "error",
"raceFirstWithSleepToTimeout": "error",
"redundantMapError": "error",
"redundantOrDie": "error",
"redundantSchemaTagIdentifier": "error",
"returnEffectInGen": "error",
"runEffectInsideEffect": "error",
"runOfExitToRunExit": "error",
"schemaLiteralNonFinite": "error",
"schemaNumber": "error",
"schemaOpaqueInstanceMember": "error",
"schemaStructWithTag": "error",
"schemaSyncInEffect": "error",
"scopeInLayerEffect": "error",
"syncToSucceed": "error",
"timeoutCatchTagToTimeoutOrElse": "error",
"tryCatchInEffectGen": "error",
"unknownInEffectCatch": "error",
"unnecessaryEffectGen": "error",
"unnecessaryFailYieldableError": "error",
"unnecessaryPipe": "error",
"unnecessaryPipeChain": "error",
"unnecessaryTypeofType": "error"
}
},
{
"name": "correctness",
"description": "Enable all correctness diagnostics at warning level.",
"diagnosticSeverity": {
"anyUnknownInErrorContext": "warning",
"classSelfMismatch": "warning",
"duplicatePackage": "warning",
"effectFnImplicitAny": "warning",
"floatingEffect": "warning",
"floatingEffectInVitest": "warning",
"genericEffectServices": "warning",
"missingEffectContext": "warning",
"missingEffectError": "warning",
"missingLayerContext": "warning",
"missingReturnYieldStar": "warning",
"missingStarInYieldEffectGen": "warning",
"nonObjectEffectServiceType": "warning",
"obsoleteMatchImport": "warning",
"obsoleteSchemaImport": "warning",
"outdatedApi": "warning",
"overriddenSchemaConstructor": "warning",
"promiseInEffectSuccess": "warning",
"schemaLiteralNonFinite": "warning",
"schemaOpaqueInstanceMember": "warning",
"unsafeEffectTypeAssertion": "warning"
}
},
{
"name": "antipattern",
"description": "Enable all anti-pattern diagnostics at warning level.",
"diagnosticSeverity": {
"catchUnfailableEffect": "warning",
"effectFnIife": "warning",
"effectGenUsesAdapter": "warning",
"effectInFailure": "warning",
"effectInVoidSuccess": "warning",
"globalErrorInEffectCatch": "warning",
"globalErrorInEffectFailure": "warning",
"layerMergeAllWithDependencies": "warning",
"lazyEffect": "warning",
"lazyPromiseInEffectSync": "warning",
"leakingRequirements": "warning",
"multipleEffectProvide": "warning",
"preferUnsafeConstructor": "warning",
"returnEffectInGen": "warning",
"runEffectInsideEffect": "warning",
"schemaSyncInEffect": "warning",
"scopeInLayerEffect": "warning",
"strictEffectProvide": "warning",
"tryCatchInEffectGen": "warning",
"unknownInEffectCatch": "warning"
}
},
{
"name": "effect-native",
"description": "Enable all Effect-native diagnostics at warning level.",
Expand Down Expand Up @@ -49,6 +274,65 @@
"processEnvInEffect": "warning",
"schemaSync": "warning"
}
},
{
"name": "style",
"description": "Enable all style diagnostics at warning level.",
"diagnosticSeverity": {
"acquireReleaseDisposable": "warning",
"allOfMapToForEach": "warning",
"catchAllTagDispatchToCatchTag": "warning",
"catchAllToMapError": "warning",
"catchChainToFirstSuccessOf": "warning",
"catchConditionalRefailToCatchIf": "warning",
"catchDieToOrDie": "warning",
"catchIfTagToCatchTag": "warning",
"catchRefailToTapError": "warning",
"catchTagToCatchReason": "warning",
"catchToIgnore": "warning",
"catchToOrElseSucceed": "warning",
"deterministicKeys": "warning",
"effectDoNotation": "warning",
"effectFnOpportunity": "warning",
"effectMapFlatten": "warning",
"effectMapVoid": "warning",
"effectSucceedWithVoid": "warning",
"flatMapConditionalToFilterOrFail": "warning",
"flatMapIgnoredParamToAndThen": "warning",
"flatMapToMap": "warning",
"mapSomeToAsSome": "warning",
"matchEffectToMapBoth": "warning",
"matchEffectToMatch": "warning",
"missedPipeableOpportunity": "warning",
"missingEffectServiceDependency": "warning",
"missingPipeableSignature": "warning",
"multipleCatchTag": "warning",
"nestedEffectGenYield": "warning",
"newSchemaClass": "warning",
"optionMatchToFromOption": "warning",
"preferSchemaTypeProperty": "warning",
"preferSucceedSomeOrNone": "warning",
"preferTypedSchemaDecoder": "warning",
"provideLayerSucceedToProvideService": "warning",
"raceFirstWithSleepToTimeout": "warning",
"redundantMapError": "warning",
"redundantOrDie": "warning",
"redundantSchemaTagIdentifier": "warning",
"runOfExitToRunExit": "warning",
"schemaNumber": "warning",
"schemaStructWithTag": "warning",
"schemaUnionOfLiterals": "warning",
"serviceNotAsClass": "warning",
"strictBooleanExpressions": "warning",
"syncToSucceed": "warning",
"timeoutCatchTagToTimeoutOrElse": "warning",
"unnecessaryArrowBlock": "warning",
"unnecessaryEffectGen": "warning",
"unnecessaryFailYieldableError": "warning",
"unnecessaryPipe": "warning",
"unnecessaryPipeChain": "warning",
"unnecessaryTypeofType": "warning"
}
}
],
"rules": [
Expand Down
25 changes: 25 additions & 0 deletions _packages/tsgo/test/presets.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,31 @@ import {
} from "../src/cli/presets.js"

describe("diagnostic presets", () => {
it("exposes the complete preset catalog", () => {
expect(presets.map((preset) => preset.name)).toEqual([
"recommended",
"strict",
"correctness",
"antipattern",
"effect-native",
"style"
])
})

it("makes every diagnostic enabled by default an error in strict mode", () => {
const strict = presets.find((preset) => preset.name === "strict")!

expect(strict.diagnosticSeverity).not.toEqual({})
expect(Object.values(strict.diagnosticSeverity).every((severity) => severity === "error")).toBe(true)
})

it("uses only default-enabled diagnostics in the recommended preset", () => {
const recommended = presets.find((preset) => preset.name === "recommended")!

expect(recommended.diagnosticSeverity.floatingEffect).toBe("error")
expect(recommended.diagnosticSeverity.globalDate).toBeUndefined()
})

it("merges the selected preset severities", () => {
expect(mergePresetDiagnosticSeverities(["effect-native"])).toEqual(
presets.find((preset) => preset.name === "effect-native")!.diagnosticSeverity
Expand Down
4 changes: 2 additions & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Run pnpm install to install the dependencies and run the prepare script to patch
pnpm install
```

Effect rules require Oxlint's type-aware mode and the `effecttsgo` plugin. The recommended preset enables both and configures the recommended Effect rules. Use the schema shipped with `@effect/tsgo` for validation and completions:
Effect rules require Oxlint's type-aware mode and the `effecttsgo` plugin. The recommended preset enables both and configures every default-enabled Effect rule. Use the schema shipped with `@effect/tsgo` for validation and completions:

```json
{
Expand All @@ -52,7 +52,7 @@ Effect rules require Oxlint's type-aware mode and the `effecttsgo` plugin. The r
}
```

The package also provides presets for each diagnostic category: `correctness`, `antipattern`, `effect-native`, and `style`. Extended configurations are applied in order, and rules in the project configuration take precedence, so categories can be combined and individual rules can be adjusted:
The package also provides presets for each diagnostic category: `correctness`, `antipattern`, `effect-native`, and `style`. The `strict` preset promotes every diagnostic enabled by default to an error. Extended configurations are applied in order, and rules in the project configuration take precedence, so presets can be combined and individual rules can be adjusted:

```json
{
Expand Down
Loading