@effect/language-service 0.78.0 → 0.80.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cli.js CHANGED
@@ -25719,7 +25719,7 @@ var runWith2 = (command, config) => {
25719
25719
  // package.json
25720
25720
  var package_default = {
25721
25721
  name: "@effect/language-service",
25722
- version: "0.78.0",
25722
+ version: "0.80.0",
25723
25723
  publishConfig: {
25724
25724
  access: "public",
25725
25725
  directory: "dist"
@@ -25747,15 +25747,17 @@ var package_default = {
25747
25747
  ],
25748
25748
  scripts: {
25749
25749
  build: "tsup",
25750
+ codegen: "node --import tsx ./scripts/codegen.ts",
25750
25751
  dev: "tsup --watch",
25751
25752
  clean: "rimraf dist build .tsbuildinfo",
25752
25753
  lint: "eslint src test",
25753
25754
  "lint-fix": "eslint src test --fix",
25754
25755
  check: "tsc -b tsconfig.json",
25756
+ "check:codegen": "node --import tsx ./scripts/codegen.ts --check",
25755
25757
  circular: "madge --extensions ts --circular --no-color --no-spinner --warning src",
25756
25758
  test: "vitest",
25757
25759
  "test-update": "vitest --update",
25758
- "test-patch": "pnpm clean && pnpm build && pnpm effect-language-service unpatch && pnpm effect-language-service patch && pnpm check",
25760
+ "test-patch": "pnpm clean && pnpm build && node dist/cli.js unpatch && node dist/cli.js patch && pnpm check",
25759
25761
  coverage: "vitest run --coverage",
25760
25762
  perf: "tsx test/perf.ts"
25761
25763
  },
@@ -27527,10 +27529,151 @@ var defaults = {
27527
27529
  extendedKeyDetection: false,
27528
27530
  ignoreEffectWarningsInTscExitCode: false,
27529
27531
  ignoreEffectSuggestionsInTscExitCode: true,
27532
+ ignoreEffectErrorsInTscExitCode: false,
27530
27533
  pipeableMinArgCount: 2,
27531
27534
  effectFn: ["span"],
27532
27535
  layerGraphFollowDepth: 0,
27533
- mermaidProvider: "mermaid.live"
27536
+ mermaidProvider: "mermaid.live",
27537
+ skipDisabledOptimization: false
27538
+ };
27539
+ var booleanSchema = (description, defaultValue) => ({
27540
+ type: "boolean",
27541
+ description,
27542
+ default: defaultValue
27543
+ });
27544
+ var stringArraySchema = (description, defaultValue) => ({
27545
+ type: "array",
27546
+ description,
27547
+ default: defaultValue,
27548
+ items: { type: "string" }
27549
+ });
27550
+ var stringEnumSchema = (description, values2, defaultValue) => ({
27551
+ type: "string",
27552
+ description,
27553
+ enum: values2,
27554
+ default: defaultValue
27555
+ });
27556
+ var languageServicePluginAdditionalPropertiesJsonSchema = {
27557
+ refactors: booleanSchema("Controls Effect refactors.", defaults.refactors),
27558
+ diagnostics: booleanSchema("Controls Effect diagnostics.", defaults.diagnostics),
27559
+ diagnosticsName: booleanSchema(
27560
+ "Controls whether to include the rule name in diagnostic messages.",
27561
+ defaults.diagnosticsName
27562
+ ),
27563
+ missingDiagnosticNextLine: stringEnumSchema(
27564
+ "Controls the severity of warnings for unused @effect-diagnostics-next-line comments.",
27565
+ ["off", "error", "warning", "message", "suggestion"],
27566
+ defaults.missingDiagnosticNextLine
27567
+ ),
27568
+ includeSuggestionsInTsc: booleanSchema(
27569
+ "When patch mode is enabled, reports suggestion diagnostics as messages in TSC with a [suggestion] prefix.",
27570
+ defaults.includeSuggestionsInTsc
27571
+ ),
27572
+ ignoreEffectWarningsInTscExitCode: booleanSchema(
27573
+ "When enabled, Effect warnings do not affect the patched tsc exit code.",
27574
+ defaults.ignoreEffectWarningsInTscExitCode
27575
+ ),
27576
+ ignoreEffectErrorsInTscExitCode: booleanSchema(
27577
+ "When enabled, Effect errors do not affect the patched tsc exit code.",
27578
+ defaults.ignoreEffectErrorsInTscExitCode
27579
+ ),
27580
+ ignoreEffectSuggestionsInTscExitCode: booleanSchema(
27581
+ "When enabled, Effect suggestions do not affect the patched tsc exit code.",
27582
+ defaults.ignoreEffectSuggestionsInTscExitCode
27583
+ ),
27584
+ quickinfoEffectParameters: stringEnumSchema(
27585
+ "Controls when Effect quickinfo should include full type parameters.",
27586
+ ["always", "never", "whentruncated"],
27587
+ defaults.quickinfoEffectParameters
27588
+ ),
27589
+ quickinfo: booleanSchema("Controls Effect quickinfo.", defaults.quickinfo),
27590
+ quickinfoMaximumLength: {
27591
+ type: "number",
27592
+ description: "Controls the maximum quickinfo length. Use -1 to disable truncation.",
27593
+ default: defaults.quickinfoMaximumLength
27594
+ },
27595
+ keyPatterns: {
27596
+ type: "array",
27597
+ description: "Configures key patterns used for generated Effect service and error keys.",
27598
+ default: defaults.keyPatterns,
27599
+ items: {
27600
+ type: "object",
27601
+ properties: {
27602
+ target: stringEnumSchema("The key builder target.", ["service", "error", "custom"], "service"),
27603
+ pattern: stringEnumSchema(
27604
+ "The key generation pattern.",
27605
+ ["package-identifier", "default", "default-hashed"],
27606
+ "default"
27607
+ ),
27608
+ skipLeadingPath: stringArraySchema("Path prefixes to strip before generating keys.", ["src/"])
27609
+ }
27610
+ }
27611
+ },
27612
+ extendedKeyDetection: booleanSchema(
27613
+ "Enables extended heuristics when detecting key sources.",
27614
+ defaults.extendedKeyDetection
27615
+ ),
27616
+ completions: booleanSchema("Controls Effect completions.", defaults.completions),
27617
+ goto: booleanSchema("Controls Effect goto references support.", defaults.goto),
27618
+ inlays: booleanSchema("Controls Effect inlay hints.", defaults.inlays),
27619
+ allowedDuplicatedPackages: stringArraySchema(
27620
+ "Package names that are allowed to duplicate Effect as a peer dependency.",
27621
+ defaults.allowedDuplicatedPackages
27622
+ ),
27623
+ namespaceImportPackages: stringArraySchema(
27624
+ "Package names that should prefer namespace imports.",
27625
+ defaults.namespaceImportPackages
27626
+ ),
27627
+ topLevelNamedReexports: stringEnumSchema(
27628
+ "For namespaceImportPackages, controls how top-level named re-exports are handled.",
27629
+ ["ignore", "follow"],
27630
+ defaults.topLevelNamedReexports
27631
+ ),
27632
+ barrelImportPackages: stringArraySchema(
27633
+ "Package names that should prefer imports from their top-level barrel file.",
27634
+ defaults.barrelImportPackages
27635
+ ),
27636
+ importAliases: {
27637
+ type: "object",
27638
+ description: "Custom aliases to use for imported identifiers.",
27639
+ default: defaults.importAliases,
27640
+ additionalProperties: {
27641
+ type: "string"
27642
+ }
27643
+ },
27644
+ renames: booleanSchema("Controls Effect rename helpers.", defaults.renames),
27645
+ noExternal: booleanSchema(
27646
+ "Disables features that link to external websites.",
27647
+ defaults.noExternal
27648
+ ),
27649
+ pipeableMinArgCount: {
27650
+ type: "number",
27651
+ description: "Minimum argument count required before pipeable suggestions are emitted.",
27652
+ default: defaults.pipeableMinArgCount
27653
+ },
27654
+ effectFn: {
27655
+ type: "array",
27656
+ description: "Configures which Effect.fn variants should be suggested.",
27657
+ default: defaults.effectFn,
27658
+ items: {
27659
+ type: "string",
27660
+ enum: ["untraced", "span", "suggested-span", "inferred-span", "no-span"]
27661
+ }
27662
+ },
27663
+ layerGraphFollowDepth: {
27664
+ type: "number",
27665
+ description: "Controls how deeply layer graph analysis follows dependencies.",
27666
+ default: defaults.layerGraphFollowDepth
27667
+ },
27668
+ mermaidProvider: {
27669
+ type: "string",
27670
+ description: "Controls which Mermaid renderer is used for layer graphs.",
27671
+ default: defaults.mermaidProvider
27672
+ },
27673
+ skipDisabledOptimization: booleanSchema(
27674
+ "When enabled, disabled diagnostics are still processed so comment-based overrides can be honored.",
27675
+ defaults.skipDisabledOptimization
27676
+ )
27534
27677
  };
27535
27678
  function parseKeyPatterns(patterns) {
27536
27679
  const result3 = [];
@@ -27554,6 +27697,7 @@ function parse4(config) {
27554
27697
  includeSuggestionsInTsc: isObject(config) && hasProperty(config, "includeSuggestionsInTsc") && isBoolean(config.includeSuggestionsInTsc) ? config.includeSuggestionsInTsc : defaults.includeSuggestionsInTsc,
27555
27698
  ignoreEffectWarningsInTscExitCode: isObject(config) && hasProperty(config, "ignoreEffectWarningsInTscExitCode") && isBoolean(config.ignoreEffectWarningsInTscExitCode) ? config.ignoreEffectWarningsInTscExitCode : defaults.ignoreEffectWarningsInTscExitCode,
27556
27699
  ignoreEffectSuggestionsInTscExitCode: isObject(config) && hasProperty(config, "ignoreEffectSuggestionsInTscExitCode") && isBoolean(config.ignoreEffectSuggestionsInTscExitCode) ? config.ignoreEffectSuggestionsInTscExitCode : defaults.ignoreEffectSuggestionsInTscExitCode,
27700
+ ignoreEffectErrorsInTscExitCode: isObject(config) && hasProperty(config, "ignoreEffectErrorsInTscExitCode") && isBoolean(config.ignoreEffectErrorsInTscExitCode) ? config.ignoreEffectErrorsInTscExitCode : defaults.ignoreEffectErrorsInTscExitCode,
27557
27701
  quickinfo: isObject(config) && hasProperty(config, "quickinfo") && isBoolean(config.quickinfo) ? config.quickinfo : defaults.quickinfo,
27558
27702
  quickinfoEffectParameters: isObject(config) && hasProperty(config, "quickinfoEffectParameters") && isString(config.quickinfoEffectParameters) && ["always", "never", "whentruncated"].includes(config.quickinfoEffectParameters.toLowerCase()) ? config.quickinfoEffectParameters.toLowerCase() : defaults.quickinfoEffectParameters,
27559
27703
  quickinfoMaximumLength: isObject(config) && hasProperty(config, "quickinfoMaximumLength") && isNumber(config.quickinfoMaximumLength) ? config.quickinfoMaximumLength : defaults.quickinfoMaximumLength,
@@ -27574,7 +27718,8 @@ function parse4(config) {
27574
27718
  (_) => _.toLowerCase()
27575
27719
  ) : defaults.effectFn,
27576
27720
  layerGraphFollowDepth: isObject(config) && hasProperty(config, "layerGraphFollowDepth") && isNumber(config.layerGraphFollowDepth) ? config.layerGraphFollowDepth : defaults.layerGraphFollowDepth,
27577
- mermaidProvider: isObject(config) && hasProperty(config, "mermaidProvider") && isString(config.mermaidProvider) ? config.mermaidProvider : defaults.mermaidProvider
27721
+ mermaidProvider: isObject(config) && hasProperty(config, "mermaidProvider") && isString(config.mermaidProvider) ? config.mermaidProvider : defaults.mermaidProvider,
27722
+ skipDisabledOptimization: isObject(config) && hasProperty(config, "skipDisabledOptimization") && isBoolean(config.skipDisabledOptimization) ? config.skipDisabledOptimization : defaults.skipDisabledOptimization
27578
27723
  };
27579
27724
  }
27580
27725
 
@@ -27758,7 +27903,7 @@ var createDiagnosticExecutor = fn3("LSP.createCommentDirectivesProcessor")(
27758
27903
  if (skippedRules.indexOf(ruleNameLowered) > -1 || skippedRules.indexOf("*") > -1) {
27759
27904
  return { diagnostics: diagnostics3, codeFixes };
27760
27905
  }
27761
- if (defaultLevel === "off" && (lineOverrides[ruleNameLowered] || sectionOverrides[ruleNameLowered] || lineOverrides["*"] || sectionOverrides["*"] || []).length === 0) {
27906
+ if (!pluginOptions.skipDisabledOptimization && defaultLevel === "off" && (lineOverrides[ruleNameLowered] || sectionOverrides[ruleNameLowered] || lineOverrides["*"] || sectionOverrides["*"] || []).length === 0) {
27762
27907
  return { diagnostics: diagnostics3, codeFixes };
27763
27908
  }
27764
27909
  const fixByDisableNextLine = (node) => ({
@@ -31656,6 +31801,8 @@ var anyUnknownInErrorContext = createDiagnostic({
31656
31801
  code: 28,
31657
31802
  description: "Detects 'any' or 'unknown' types in Effect error or requirements channels",
31658
31803
  severity: "off",
31804
+ fixable: false,
31805
+ supportedEffect: ["v3", "v4"],
31659
31806
  apply: fn3("anyUnknownInErrorContext.apply")(function* (sourceFile, report) {
31660
31807
  const ts = yield* service2(TypeScriptApi);
31661
31808
  const typeChecker = yield* service2(TypeCheckerApi);
@@ -31759,6 +31906,8 @@ var catchAllToMapError = createDiagnostic({
31759
31906
  code: 39,
31760
31907
  description: "Suggests using Effect.mapError instead of Effect.catchAll when the callback only wraps the error with Effect.fail",
31761
31908
  severity: "suggestion",
31909
+ fixable: true,
31910
+ supportedEffect: ["v3", "v4"],
31762
31911
  apply: fn3("catchAllToMapError.apply")(function* (sourceFile, report) {
31763
31912
  const ts = yield* service2(TypeScriptApi);
31764
31913
  const typeParser = yield* service2(TypeParser);
@@ -31856,6 +32005,8 @@ var catchUnfailableEffect = createDiagnostic({
31856
32005
  code: 2,
31857
32006
  description: "Warns when using error handling on Effects that never fail (error type is 'never')",
31858
32007
  severity: "suggestion",
32008
+ fixable: false,
32009
+ supportedEffect: ["v3", "v4"],
31859
32010
  apply: fn3("catchUnfailableEffect.apply")(function* (sourceFile, report) {
31860
32011
  const ts = yield* service2(TypeScriptApi);
31861
32012
  const typeParser = yield* service2(TypeParser);
@@ -31905,6 +32056,8 @@ var classSelfMismatch = createDiagnostic({
31905
32056
  code: 20,
31906
32057
  description: "Ensures Self type parameter matches the class name in Service/Tag/Schema classes",
31907
32058
  severity: "error",
32059
+ fixable: true,
32060
+ supportedEffect: ["v3", "v4"],
31908
32061
  apply: fn3("classSelfMismatch.apply")(function* (sourceFile, report) {
31909
32062
  const ts = yield* service2(TypeScriptApi);
31910
32063
  const typeParser = yield* service2(TypeParser);
@@ -32043,6 +32196,8 @@ var deterministicKeys = createDiagnostic({
32043
32196
  code: 25,
32044
32197
  description: "Enforces deterministic naming for service/tag/error identifiers based on class names",
32045
32198
  severity: "off",
32199
+ fixable: true,
32200
+ supportedEffect: ["v3", "v4"],
32046
32201
  apply: fn3("deterministicKeys.apply")(function* (sourceFile, report) {
32047
32202
  const ts = yield* service2(TypeScriptApi);
32048
32203
  const typeParser = yield* service2(TypeParser);
@@ -32160,6 +32315,8 @@ var duplicatePackage = createDiagnostic({
32160
32315
  code: 6,
32161
32316
  description: "Detects when multiple versions of the same Effect package are loaded",
32162
32317
  severity: "warning",
32318
+ fixable: false,
32319
+ supportedEffect: ["v3", "v4"],
32163
32320
  apply: fn3("duplicatePackage.apply")(function* (sourceFile, report) {
32164
32321
  const typeParser = yield* service2(TypeParser);
32165
32322
  const options = yield* service2(LanguageServicePluginOptions);
@@ -32189,6 +32346,8 @@ var effectFnIife = createDiagnostic({
32189
32346
  code: 46,
32190
32347
  description: "Effect.fn or Effect.fnUntraced is called as an IIFE (Immediately Invoked Function Expression). Use Effect.gen instead.",
32191
32348
  severity: "warning",
32349
+ fixable: true,
32350
+ supportedEffect: ["v3", "v4"],
32192
32351
  apply: fn3("effectFnIife.apply")(function* (sourceFile, report) {
32193
32352
  const ts = yield* service2(TypeScriptApi);
32194
32353
  const typeParser = yield* service2(TypeParser);
@@ -32291,6 +32450,8 @@ var effectFnOpportunity = createDiagnostic({
32291
32450
  code: 41,
32292
32451
  description: "Suggests using Effect.fn for functions that returns an Effect",
32293
32452
  severity: "suggestion",
32453
+ fixable: true,
32454
+ supportedEffect: ["v3", "v4"],
32294
32455
  apply: fn3("effectFnOpportunity.apply")(function* (sourceFile, report) {
32295
32456
  const ts = yield* service2(TypeScriptApi);
32296
32457
  const typeChecker = yield* service2(TypeCheckerApi);
@@ -32883,6 +33044,8 @@ var effectGenUsesAdapter = createDiagnostic({
32883
33044
  code: 23,
32884
33045
  description: "Warns when using the deprecated adapter parameter in Effect.gen",
32885
33046
  severity: "warning",
33047
+ fixable: false,
33048
+ supportedEffect: ["v3", "v4"],
32886
33049
  apply: fn3("effectGenUsesAdapter.apply")(function* (sourceFile, report) {
32887
33050
  const ts = yield* service2(TypeScriptApi);
32888
33051
  const typeParser = yield* service2(TypeParser);
@@ -32921,6 +33084,8 @@ var effectInFailure = createDiagnostic({
32921
33084
  code: 49,
32922
33085
  description: "Warns when an Effect is used inside an Effect failure channel",
32923
33086
  severity: "warning",
33087
+ fixable: false,
33088
+ supportedEffect: ["v3", "v4"],
32924
33089
  apply: fn3("effectInFailure.apply")(function* (sourceFile, report) {
32925
33090
  const ts = yield* service2(TypeScriptApi);
32926
33091
  const typeChecker = yield* service2(TypeCheckerApi);
@@ -32985,6 +33150,8 @@ var effectInVoidSuccess = createDiagnostic({
32985
33150
  code: 14,
32986
33151
  description: "Detects nested Effects in void success channels that may cause unexecuted effects",
32987
33152
  severity: "warning",
33153
+ fixable: false,
33154
+ supportedEffect: ["v3", "v4"],
32988
33155
  apply: fn3("effectInVoidSuccess.apply")(function* (sourceFile, report) {
32989
33156
  const ts = yield* service2(TypeScriptApi);
32990
33157
  const typeChecker = yield* service2(TypeCheckerApi);
@@ -33034,6 +33201,8 @@ var effectMapVoid = createDiagnostic({
33034
33201
  code: 40,
33035
33202
  description: "Suggests using Effect.asVoid instead of Effect.map(() => void 0), Effect.map(() => undefined), or Effect.map(() => {})",
33036
33203
  severity: "suggestion",
33204
+ fixable: true,
33205
+ supportedEffect: ["v3", "v4"],
33037
33206
  apply: fn3("effectMapVoid.apply")(function* (sourceFile, report) {
33038
33207
  const ts = yield* service2(TypeScriptApi);
33039
33208
  const typeParser = yield* service2(TypeParser);
@@ -33098,6 +33267,8 @@ var effectSucceedWithVoid = createDiagnostic({
33098
33267
  code: 47,
33099
33268
  description: "Suggests using Effect.void instead of Effect.succeed(undefined) or Effect.succeed(void 0)",
33100
33269
  severity: "suggestion",
33270
+ fixable: true,
33271
+ supportedEffect: ["v3", "v4"],
33101
33272
  apply: fn3("effectSucceedWithVoid.apply")(function* (sourceFile, report) {
33102
33273
  const ts = yield* service2(TypeScriptApi);
33103
33274
  const typeParser = yield* service2(TypeParser);
@@ -33143,12 +33314,66 @@ var effectSucceedWithVoid = createDiagnostic({
33143
33314
  })
33144
33315
  });
33145
33316
 
33317
+ // src/diagnostics/extendsNativeError.ts
33318
+ var extendsNativeError = createDiagnostic({
33319
+ name: "extendsNativeError",
33320
+ code: 50,
33321
+ description: "Warns when a class directly extends the native Error class",
33322
+ severity: "off",
33323
+ fixable: false,
33324
+ supportedEffect: ["v3", "v4"],
33325
+ apply: fn3("extendsNativeError.apply")(function* (sourceFile, report) {
33326
+ const ts = yield* service2(TypeScriptApi);
33327
+ const typeChecker = yield* service2(TypeCheckerApi);
33328
+ const errorSymbol = typeChecker.resolveName("Error", void 0, ts.SymbolFlags.Type, false);
33329
+ if (!errorSymbol) return;
33330
+ const nodeToVisit = [];
33331
+ const appendNodeToVisit = (node) => {
33332
+ nodeToVisit.push(node);
33333
+ return void 0;
33334
+ };
33335
+ ts.forEachChild(sourceFile, appendNodeToVisit);
33336
+ while (nodeToVisit.length > 0) {
33337
+ const node = nodeToVisit.shift();
33338
+ if (ts.isClassDeclaration(node) && node.heritageClauses) {
33339
+ for (const clause of node.heritageClauses) {
33340
+ if (clause.token === ts.SyntaxKind.ExtendsKeyword && clause.types.length > 0) {
33341
+ const typeExpression = clause.types[0].expression;
33342
+ const exprSymbol = typeChecker.getSymbolAtLocation(typeExpression);
33343
+ const resolvedSymbol = exprSymbol && exprSymbol.flags & ts.SymbolFlags.Alias ? typeChecker.getAliasedSymbol(exprSymbol) : exprSymbol;
33344
+ const isNativeError = resolvedSymbol === errorSymbol || (() => {
33345
+ if (!resolvedSymbol || resolvedSymbol === errorSymbol) return false;
33346
+ const exprType = typeChecker.getTypeAtLocation(typeExpression);
33347
+ const constructSignatures = typeChecker.getSignaturesOfType(exprType, ts.SignatureKind.Construct);
33348
+ if (constructSignatures.length > 0) {
33349
+ const instanceType = typeChecker.getReturnTypeOfSignature(constructSignatures[0]);
33350
+ return instanceType.symbol === errorSymbol;
33351
+ }
33352
+ return false;
33353
+ })();
33354
+ if (isNativeError) {
33355
+ report({
33356
+ location: node.name ?? typeExpression,
33357
+ messageText: "Avoid extending the native 'Error' class directly. Consider using a tagged error (e.g. Data.TaggedError) to maintain type safety in the Effect failure channel.",
33358
+ fixes: []
33359
+ });
33360
+ }
33361
+ }
33362
+ }
33363
+ }
33364
+ ts.forEachChild(node, appendNodeToVisit);
33365
+ }
33366
+ })
33367
+ });
33368
+
33146
33369
  // src/diagnostics/floatingEffect.ts
33147
33370
  var floatingEffect = createDiagnostic({
33148
33371
  name: "floatingEffect",
33149
33372
  code: 3,
33150
33373
  description: "Ensures Effects are yielded or assigned to variables, not left floating",
33151
33374
  severity: "error",
33375
+ fixable: false,
33376
+ supportedEffect: ["v3", "v4"],
33152
33377
  apply: fn3("floatingEffect.apply")(function* (sourceFile, report) {
33153
33378
  const ts = yield* service2(TypeScriptApi);
33154
33379
  const typeChecker = yield* service2(TypeCheckerApi);
@@ -33200,6 +33425,8 @@ var genericEffectServices = createDiagnostic({
33200
33425
  code: 10,
33201
33426
  description: "Prevents services with type parameters that cannot be discriminated at runtime",
33202
33427
  severity: "warning",
33428
+ fixable: false,
33429
+ supportedEffect: ["v3", "v4"],
33203
33430
  apply: fn3("genericEffectServices.apply")(function* (sourceFile, report) {
33204
33431
  const ts = yield* service2(TypeScriptApi);
33205
33432
  const typeParser = yield* service2(TypeParser);
@@ -33247,6 +33474,8 @@ var globalErrorInEffectCatch = createDiagnostic({
33247
33474
  code: 36,
33248
33475
  description: "Warns when catch callbacks return global Error type instead of typed errors",
33249
33476
  severity: "warning",
33477
+ fixable: false,
33478
+ supportedEffect: ["v3", "v4"],
33250
33479
  apply: fn3("globalErrorInEffectCatch.apply")(function* (sourceFile, report) {
33251
33480
  const ts = yield* service2(TypeScriptApi);
33252
33481
  const typeParser = yield* service2(TypeParser);
@@ -33307,6 +33536,8 @@ var globalErrorInEffectFailure = createDiagnostic({
33307
33536
  code: 35,
33308
33537
  description: "Warns when the global Error type is used in an Effect failure channel",
33309
33538
  severity: "warning",
33539
+ fixable: false,
33540
+ supportedEffect: ["v3", "v4"],
33310
33541
  apply: fn3("globalErrorInEffectFailure.apply")(function* (sourceFile, report) {
33311
33542
  const ts = yield* service2(TypeScriptApi);
33312
33543
  const typeParser = yield* service2(TypeParser);
@@ -33360,6 +33591,8 @@ var importFromBarrel = createDiagnostic({
33360
33591
  code: 12,
33361
33592
  description: "Suggests importing from specific module paths instead of barrel exports",
33362
33593
  severity: "off",
33594
+ fixable: true,
33595
+ supportedEffect: ["v3", "v4"],
33363
33596
  apply: fn3("importFromBarrel.apply")(function* (sourceFile, report) {
33364
33597
  const languageServicePluginOptions = yield* service2(LanguageServicePluginOptions);
33365
33598
  if (languageServicePluginOptions.namespaceImportPackages.length === 0) return;
@@ -33500,6 +33733,8 @@ var instanceOfSchema = createDiagnostic({
33500
33733
  code: 45,
33501
33734
  description: "Suggests using Schema.is instead of instanceof for Effect Schema types",
33502
33735
  severity: "off",
33736
+ fixable: true,
33737
+ supportedEffect: ["v3", "v4"],
33503
33738
  apply: fn3("instanceOfSchema.apply")(function* (sourceFile, report) {
33504
33739
  const ts = yield* service2(TypeScriptApi);
33505
33740
  const typeParser = yield* service2(TypeParser);
@@ -33563,6 +33798,8 @@ var layerMergeAllWithDependencies = createDiagnostic({
33563
33798
  code: 37,
33564
33799
  description: "Detects interdependencies in Layer.mergeAll calls where one layer provides a service that another layer requires",
33565
33800
  severity: "warning",
33801
+ fixable: true,
33802
+ supportedEffect: ["v3", "v4"],
33566
33803
  apply: fn3("layerMergeAllWithDependencies.apply")(function* (sourceFile, report) {
33567
33804
  const ts = yield* service2(TypeScriptApi);
33568
33805
  const typeChecker = yield* service2(TypeCheckerApi);
@@ -33676,6 +33913,8 @@ var leakingRequirements = createDiagnostic({
33676
33913
  code: 8,
33677
33914
  description: "Detects implementation services leaked in service methods",
33678
33915
  severity: "suggestion",
33916
+ fixable: false,
33917
+ supportedEffect: ["v3", "v4"],
33679
33918
  apply: fn3("leakingRequirements.apply")(function* (sourceFile, report) {
33680
33919
  const ts = yield* service2(TypeScriptApi);
33681
33920
  const typeChecker = yield* service2(TypeCheckerApi);
@@ -33830,6 +34069,8 @@ var missedPipeableOpportunity = createDiagnostic({
33830
34069
  code: 26,
33831
34070
  description: "Enforces the use of pipeable style for nested function calls",
33832
34071
  severity: "off",
34072
+ fixable: true,
34073
+ supportedEffect: ["v3", "v4"],
33833
34074
  apply: fn3("missedPipeableOpportunity.apply")(function* (sourceFile, report) {
33834
34075
  const ts = yield* service2(TypeScriptApi);
33835
34076
  const typeChecker = yield* service2(TypeCheckerApi);
@@ -34010,6 +34251,8 @@ var missingEffectContext = createDiagnostic({
34010
34251
  code: 1,
34011
34252
  description: "Reports missing service requirements in Effect context channel",
34012
34253
  severity: "error",
34254
+ fixable: false,
34255
+ supportedEffect: ["v3", "v4"],
34013
34256
  apply: fn3("missingEffectContext.apply")(function* (sourceFile, report) {
34014
34257
  const typeChecker = yield* service2(TypeCheckerApi);
34015
34258
  const typeParser = yield* service2(TypeParser);
@@ -34059,6 +34302,8 @@ var missingEffectError = createDiagnostic({
34059
34302
  code: 1,
34060
34303
  description: "Reports missing error types in Effect error channel",
34061
34304
  severity: "error",
34305
+ fixable: true,
34306
+ supportedEffect: ["v3", "v4"],
34062
34307
  apply: fn3("missingEffectError.apply")(function* (sourceFile, report) {
34063
34308
  const ts = yield* service2(TypeScriptApi);
34064
34309
  const tsUtils = yield* service2(TypeScriptUtils);
@@ -34200,6 +34445,8 @@ var missingEffectServiceDependency = createDiagnostic({
34200
34445
  code: 22,
34201
34446
  description: "Checks that Effect.Service dependencies satisfy all required layer inputs",
34202
34447
  severity: "off",
34448
+ fixable: false,
34449
+ supportedEffect: ["v3"],
34203
34450
  apply: fn3("missingEffectServiceDependency.apply")(function* (sourceFile, report) {
34204
34451
  const ts = yield* service2(TypeScriptApi);
34205
34452
  const typeChecker = yield* service2(TypeCheckerApi);
@@ -34294,6 +34541,8 @@ var missingLayerContext = createDiagnostic({
34294
34541
  code: 38,
34295
34542
  description: "Reports missing service requirements in Layer context channel",
34296
34543
  severity: "error",
34544
+ fixable: false,
34545
+ supportedEffect: ["v3", "v4"],
34297
34546
  apply: fn3("missingLayerContext.apply")(function* (sourceFile, report) {
34298
34547
  const typeChecker = yield* service2(TypeCheckerApi);
34299
34548
  const typeParser = yield* service2(TypeParser);
@@ -34343,6 +34592,8 @@ var missingReturnYieldStar = createDiagnostic({
34343
34592
  code: 7,
34344
34593
  description: "Suggests using 'return yield*' for Effects with never success for better type narrowing",
34345
34594
  severity: "error",
34595
+ fixable: true,
34596
+ supportedEffect: ["v3", "v4"],
34346
34597
  apply: fn3("missingReturnYieldStar.apply")(function* (sourceFile, report) {
34347
34598
  const ts = yield* service2(TypeScriptApi);
34348
34599
  const typeCheckerUtils = yield* service2(TypeCheckerUtils);
@@ -34393,6 +34644,8 @@ var missingStarInYieldEffectGen = createDiagnostic({
34393
34644
  code: 4,
34394
34645
  description: "Enforces using 'yield*' instead of 'yield' when yielding Effects in generators",
34395
34646
  severity: "error",
34647
+ fixable: true,
34648
+ supportedEffect: ["v3", "v4"],
34396
34649
  apply: fn3("missingStarInYieldEffectGen.apply")(function* (sourceFile, report) {
34397
34650
  const ts = yield* service2(TypeScriptApi);
34398
34651
  const typeParser = yield* service2(TypeParser);
@@ -34468,6 +34721,8 @@ var multipleEffectProvide = createDiagnostic({
34468
34721
  code: 18,
34469
34722
  description: "Warns against chaining Effect.provide calls which can cause service lifecycle issues",
34470
34723
  severity: "warning",
34724
+ fixable: true,
34725
+ supportedEffect: ["v3", "v4"],
34471
34726
  apply: fn3("multipleEffectProvide.apply")(function* (sourceFile, report) {
34472
34727
  const ts = yield* service2(TypeScriptApi);
34473
34728
  const tsUtils = yield* service2(TypeScriptUtils);
@@ -34554,12 +34809,85 @@ var multipleEffectProvide = createDiagnostic({
34554
34809
  })
34555
34810
  });
34556
34811
 
34812
+ // src/diagnostics/nodeBuiltinImport.ts
34813
+ var moduleAlternativesV3 = /* @__PURE__ */ new Map([
34814
+ ["fs", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
34815
+ ["node:fs", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
34816
+ ["fs/promises", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
34817
+ ["node:fs/promises", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
34818
+ ["path", { alternative: "Path", module: "path", package: "@effect/platform" }],
34819
+ ["node:path", { alternative: "Path", module: "path", package: "@effect/platform" }],
34820
+ ["path/posix", { alternative: "Path", module: "path", package: "@effect/platform" }],
34821
+ ["node:path/posix", { alternative: "Path", module: "path", package: "@effect/platform" }],
34822
+ ["path/win32", { alternative: "Path", module: "path", package: "@effect/platform" }],
34823
+ ["node:path/win32", { alternative: "Path", module: "path", package: "@effect/platform" }],
34824
+ ["child_process", { alternative: "CommandExecutor", module: "child_process", package: "@effect/platform" }],
34825
+ ["node:child_process", { alternative: "CommandExecutor", module: "child_process", package: "@effect/platform" }]
34826
+ ]);
34827
+ var moduleAlternativesV4 = /* @__PURE__ */ new Map([
34828
+ ["fs", { alternative: "FileSystem", module: "fs", package: "effect" }],
34829
+ ["node:fs", { alternative: "FileSystem", module: "fs", package: "effect" }],
34830
+ ["fs/promises", { alternative: "FileSystem", module: "fs", package: "effect" }],
34831
+ ["node:fs/promises", { alternative: "FileSystem", module: "fs", package: "effect" }],
34832
+ ["path", { alternative: "Path", module: "path", package: "effect" }],
34833
+ ["node:path", { alternative: "Path", module: "path", package: "effect" }],
34834
+ ["path/posix", { alternative: "Path", module: "path", package: "effect" }],
34835
+ ["node:path/posix", { alternative: "Path", module: "path", package: "effect" }],
34836
+ ["path/win32", { alternative: "Path", module: "path", package: "effect" }],
34837
+ ["node:path/win32", { alternative: "Path", module: "path", package: "effect" }],
34838
+ ["child_process", { alternative: "ChildProcess", module: "child_process", package: "effect" }],
34839
+ ["node:child_process", { alternative: "ChildProcess", module: "child_process", package: "effect" }]
34840
+ ]);
34841
+ var nodeBuiltinImport = createDiagnostic({
34842
+ name: "nodeBuiltinImport",
34843
+ code: 52,
34844
+ description: "Warns when importing Node.js built-in modules that have Effect-native counterparts",
34845
+ severity: "off",
34846
+ fixable: false,
34847
+ supportedEffect: ["v3", "v4"],
34848
+ apply: fn3("nodeBuiltinImport.apply")(function* (sourceFile, report) {
34849
+ const ts = yield* service2(TypeScriptApi);
34850
+ const typeParser = yield* service2(TypeParser);
34851
+ const moduleAlternatives = typeParser.supportedEffect() === "v3" ? moduleAlternativesV3 : moduleAlternativesV4;
34852
+ for (const statement of sourceFile.statements) {
34853
+ if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) {
34854
+ const specifier = statement.moduleSpecifier.text;
34855
+ const match9 = moduleAlternatives.get(specifier);
34856
+ if (match9) {
34857
+ report({
34858
+ location: statement.moduleSpecifier,
34859
+ messageText: `Prefer using ${match9.alternative} from ${match9.package} instead of the Node.js '${match9.module}' module.`,
34860
+ fixes: []
34861
+ });
34862
+ }
34863
+ } else if (ts.isVariableStatement(statement)) {
34864
+ for (const decl of statement.declarationList.declarations) {
34865
+ if (decl.initializer && ts.isCallExpression(decl.initializer) && ts.isIdentifier(decl.initializer.expression) && ts.idText(decl.initializer.expression) === "require" && decl.initializer.arguments.length === 1 && ts.isStringLiteral(decl.initializer.arguments[0])) {
34866
+ const arg = decl.initializer.arguments[0];
34867
+ const specifier = arg.text;
34868
+ const match9 = moduleAlternatives.get(specifier);
34869
+ if (match9) {
34870
+ report({
34871
+ location: arg,
34872
+ messageText: `Prefer using ${match9.alternative} from ${match9.package} instead of the Node.js '${match9.module}' module.`,
34873
+ fixes: []
34874
+ });
34875
+ }
34876
+ }
34877
+ }
34878
+ }
34879
+ }
34880
+ })
34881
+ });
34882
+
34557
34883
  // src/diagnostics/nonObjectEffectServiceType.ts
34558
34884
  var nonObjectEffectServiceType = createDiagnostic({
34559
34885
  name: "nonObjectEffectServiceType",
34560
34886
  code: 24,
34561
34887
  description: "Ensures Effect.Service types are objects, not primitives",
34562
34888
  severity: "error",
34889
+ fixable: false,
34890
+ supportedEffect: ["v3"],
34563
34891
  apply: fn3("nonObjectEffectServiceType.apply")(function* (sourceFile, report) {
34564
34892
  const ts = yield* service2(TypeScriptApi);
34565
34893
  const typeChecker = yield* service2(TypeCheckerApi);
@@ -35342,6 +35670,8 @@ var outdatedApi = createDiagnostic({
35342
35670
  code: 48,
35343
35671
  description: "Detects usage of APIs that have been removed or renamed in Effect v4",
35344
35672
  severity: "warning",
35673
+ fixable: false,
35674
+ supportedEffect: ["v4"],
35345
35675
  apply: fn3("outdatedApi.apply")(function* (sourceFile, report) {
35346
35676
  const typeParser = yield* service2(TypeParser);
35347
35677
  const ts = yield* service2(TypeScriptApi);
@@ -35409,6 +35739,8 @@ var outdatedEffectCodegen = createDiagnostic({
35409
35739
  code: 19,
35410
35740
  description: "Detects when generated code is outdated and needs to be regenerated",
35411
35741
  severity: "warning",
35742
+ fixable: true,
35743
+ supportedEffect: ["v3", "v4"],
35412
35744
  apply: fn3("outdatedEffectCodegen.apply")(function* (sourceFile, _report) {
35413
35745
  const codegensWithRanges = yield* getCodegensForSourceFile(codegens, sourceFile);
35414
35746
  for (const { codegen: codegen2, hash: hash2, range: range2 } of codegensWithRanges) {
@@ -35455,6 +35787,8 @@ var overriddenSchemaConstructor = createDiagnostic({
35455
35787
  code: 30,
35456
35788
  description: "Prevents overriding constructors in Schema classes which breaks decoding behavior",
35457
35789
  severity: "error",
35790
+ fixable: true,
35791
+ supportedEffect: ["v3", "v4"],
35458
35792
  apply: fn3("overriddenSchemaConstructor.apply")(function* (sourceFile, report) {
35459
35793
  const ts = yield* service2(TypeScriptApi);
35460
35794
  const typeParser = yield* service2(TypeParser);
@@ -35592,6 +35926,8 @@ var preferSchemaOverJson = createDiagnostic({
35592
35926
  code: 44,
35593
35927
  description: "Suggests using Effect Schema for JSON operations instead of JSON.parse/JSON.stringify which may throw",
35594
35928
  severity: "suggestion",
35929
+ fixable: false,
35930
+ supportedEffect: ["v3", "v4"],
35595
35931
  apply: fn3("preferSchemaOverJson.apply")(function* (sourceFile, report) {
35596
35932
  const ts = yield* service2(TypeScriptApi);
35597
35933
  const typeParser = yield* service2(TypeParser);
@@ -35702,6 +36038,8 @@ var redundantSchemaTagIdentifier = createDiagnostic({
35702
36038
  code: 42,
35703
36039
  description: "Suggests removing redundant identifier argument when it equals the tag value in Schema.TaggedClass/TaggedError/TaggedRequest",
35704
36040
  severity: "suggestion",
36041
+ fixable: true,
36042
+ supportedEffect: ["v3", "v4"],
35705
36043
  apply: fn3("redundantSchemaTagIdentifier.apply")(function* (sourceFile, report) {
35706
36044
  const ts = yield* service2(TypeScriptApi);
35707
36045
  const typeParser = yield* service2(TypeParser);
@@ -35752,6 +36090,8 @@ var returnEffectInGen = createDiagnostic({
35752
36090
  code: 11,
35753
36091
  description: "Warns when returning an Effect in a generator causes nested Effect<Effect<...>>",
35754
36092
  severity: "suggestion",
36093
+ fixable: true,
36094
+ supportedEffect: ["v3", "v4"],
35755
36095
  apply: fn3("returnEffectInGen.apply")(function* (sourceFile, report) {
35756
36096
  const ts = yield* service2(TypeScriptApi);
35757
36097
  const typeCheckerUtils = yield* service2(TypeCheckerUtils);
@@ -35821,6 +36161,8 @@ var runEffectInsideEffect = createDiagnostic({
35821
36161
  code: 32,
35822
36162
  description: "Suggests using Runtime methods instead of Effect.run* inside Effect contexts",
35823
36163
  severity: "suggestion",
36164
+ fixable: true,
36165
+ supportedEffect: ["v3"],
35824
36166
  apply: fn3("runEffectInsideEffect.apply")(function* (sourceFile, report) {
35825
36167
  const ts = yield* service2(TypeScriptApi);
35826
36168
  const typeParser = yield* service2(TypeParser);
@@ -35945,6 +36287,8 @@ var schemaStructWithTag = createDiagnostic({
35945
36287
  code: 34,
35946
36288
  description: "Suggests using Schema.TaggedStruct instead of Schema.Struct with _tag field",
35947
36289
  severity: "suggestion",
36290
+ fixable: true,
36291
+ supportedEffect: ["v3", "v4"],
35948
36292
  apply: fn3("schemaStructWithTag.apply")(function* (sourceFile, report) {
35949
36293
  const ts = yield* service2(TypeScriptApi);
35950
36294
  const typeParser = yield* service2(TypeParser);
@@ -36037,6 +36381,8 @@ var schemaSyncInEffect = createDiagnostic({
36037
36381
  code: 43,
36038
36382
  description: "Suggests using Effect-based Schema methods instead of sync methods inside Effect generators",
36039
36383
  severity: "suggestion",
36384
+ fixable: false,
36385
+ supportedEffect: ["v3", "v4"],
36040
36386
  apply: fn3("schemaSyncInEffect.apply")(function* (sourceFile, report) {
36041
36387
  const ts = yield* service2(TypeScriptApi);
36042
36388
  const typeParser = yield* service2(TypeParser);
@@ -36086,6 +36432,8 @@ var schemaUnionOfLiterals = createDiagnostic({
36086
36432
  code: 33,
36087
36433
  description: "Simplifies Schema.Union of multiple Schema.Literal calls into single Schema.Literal",
36088
36434
  severity: "off",
36435
+ fixable: true,
36436
+ supportedEffect: ["v3"],
36089
36437
  apply: fn3("schemaUnionOfLiterals.apply")(function* (sourceFile, report) {
36090
36438
  const ts = yield* service2(TypeScriptApi);
36091
36439
  const typeParser = yield* service2(TypeParser);
@@ -36161,6 +36509,8 @@ var scopeInLayerEffect = createDiagnostic({
36161
36509
  code: 13,
36162
36510
  description: "Suggests using Layer.scoped instead of Layer.effect when Scope is in requirements",
36163
36511
  severity: "warning",
36512
+ fixable: true,
36513
+ supportedEffect: ["v3"],
36164
36514
  apply: fn3("scopeInLayerEffect.apply")(function* (sourceFile, report) {
36165
36515
  const ts = yield* service2(TypeScriptApi);
36166
36516
  const tsUtils = yield* service2(TypeScriptUtils);
@@ -36250,12 +36600,91 @@ Consider using "scoped" instead to get rid of the scope in the requirements.`,
36250
36600
  })
36251
36601
  });
36252
36602
 
36603
+ // src/diagnostics/serviceNotAsClass.ts
36604
+ var serviceNotAsClass = createDiagnostic({
36605
+ name: "serviceNotAsClass",
36606
+ code: 51,
36607
+ description: "Warns when ServiceMap.Service is used as a variable instead of a class declaration",
36608
+ severity: "off",
36609
+ fixable: true,
36610
+ supportedEffect: ["v4"],
36611
+ apply: fn3("serviceNotAsClass.apply")(function* (sourceFile, report) {
36612
+ const ts = yield* service2(TypeScriptApi);
36613
+ const typeParser = yield* service2(TypeParser);
36614
+ if (typeParser.supportedEffect() === "v3") return;
36615
+ const nodeToVisit = [];
36616
+ const appendNodeToVisit = (node) => {
36617
+ nodeToVisit.push(node);
36618
+ return void 0;
36619
+ };
36620
+ ts.forEachChild(sourceFile, appendNodeToVisit);
36621
+ while (nodeToVisit.length > 0) {
36622
+ const node = nodeToVisit.shift();
36623
+ ts.forEachChild(node, appendNodeToVisit);
36624
+ if (!ts.isVariableDeclaration(node)) continue;
36625
+ if (!node.initializer || !ts.isCallExpression(node.initializer)) continue;
36626
+ const callExpr = node.initializer;
36627
+ if (!callExpr.typeArguments || callExpr.typeArguments.length === 0) continue;
36628
+ const typeArgs = callExpr.typeArguments;
36629
+ const declList = node.parent;
36630
+ if (!ts.isVariableDeclarationList(declList)) continue;
36631
+ if (!(declList.flags & ts.NodeFlags.Const)) continue;
36632
+ const isServiceMapService = yield* pipe(
36633
+ typeParser.isNodeReferenceToServiceMapModuleApi("Service")(callExpr.expression),
36634
+ orUndefined
36635
+ );
36636
+ if (!isServiceMapService) continue;
36637
+ const variableName = ts.isIdentifier(node.name) ? ts.idText(node.name) : sourceFile.text.substring(ts.getTokenPosOfNode(node.name, sourceFile), node.name.end);
36638
+ const variableStatement = declList.parent;
36639
+ const argsText = callExpr.arguments.length > 0 ? callExpr.arguments.map((a) => sourceFile.text.substring(ts.getTokenPosOfNode(a, sourceFile), a.end)).join(", ") : "";
36640
+ const shapeText = typeArgs.length > 0 ? typeArgs.map((t) => sourceFile.text.substring(ts.getTokenPosOfNode(t, sourceFile), t.end)).join(", ") : "Shape";
36641
+ report({
36642
+ location: callExpr,
36643
+ messageText: `ServiceMap.Service should be used in a class declaration instead of as a variable. Use: class ${variableName} extends ServiceMap.Service<${variableName}, ${shapeText}>()("${argsText.replace(/['"]/g, "")}") {}`,
36644
+ fixes: [{
36645
+ fixName: "serviceNotAsClass",
36646
+ description: `Convert to class declaration`,
36647
+ apply: gen3(function* () {
36648
+ const changeTracker = yield* service2(ChangeTracker);
36649
+ const targetNode = ts.isVariableStatement(variableStatement) ? variableStatement : declList;
36650
+ const innerCall = ts.factory.createCallExpression(
36651
+ callExpr.expression,
36652
+ [ts.factory.createTypeReferenceNode(variableName), ...typeArgs],
36653
+ []
36654
+ );
36655
+ const outerCall = ts.factory.createCallExpression(
36656
+ innerCall,
36657
+ void 0,
36658
+ [...callExpr.arguments]
36659
+ );
36660
+ const heritageClause = ts.factory.createHeritageClause(
36661
+ ts.SyntaxKind.ExtendsKeyword,
36662
+ [ts.factory.createExpressionWithTypeArguments(outerCall, void 0)]
36663
+ );
36664
+ const modifiers = ts.isVariableStatement(variableStatement) ? variableStatement.modifiers : void 0;
36665
+ const classDeclaration = ts.factory.createClassDeclaration(
36666
+ modifiers,
36667
+ ts.isIdentifier(node.name) ? node.name : ts.factory.createIdentifier(variableName),
36668
+ void 0,
36669
+ [heritageClause],
36670
+ []
36671
+ );
36672
+ changeTracker.replaceNode(sourceFile, targetNode, classDeclaration);
36673
+ })
36674
+ }]
36675
+ });
36676
+ }
36677
+ })
36678
+ });
36679
+
36253
36680
  // src/diagnostics/strictBooleanExpressions.ts
36254
36681
  var strictBooleanExpressions = createDiagnostic({
36255
36682
  name: "strictBooleanExpressions",
36256
36683
  code: 17,
36257
36684
  description: "Enforces boolean types in conditional expressions for type safety",
36258
36685
  severity: "off",
36686
+ fixable: false,
36687
+ supportedEffect: ["v3", "v4"],
36259
36688
  apply: fn3("strictBooleanExpressions.apply")(function* (sourceFile, report) {
36260
36689
  const ts = yield* service2(TypeScriptApi);
36261
36690
  const typeChecker = yield* service2(TypeCheckerApi);
@@ -36327,6 +36756,8 @@ var strictEffectProvide = createDiagnostic({
36327
36756
  code: 27,
36328
36757
  description: "Warns when using Effect.provide with layers outside of application entry points",
36329
36758
  severity: "off",
36759
+ fixable: false,
36760
+ supportedEffect: ["v3", "v4"],
36330
36761
  apply: fn3("strictEffectProvide.apply")(function* (sourceFile, report) {
36331
36762
  const ts = yield* service2(TypeScriptApi);
36332
36763
  const typeCheckerUtils = yield* service2(TypeCheckerUtils);
@@ -36378,6 +36809,8 @@ var tryCatchInEffectGen = createDiagnostic({
36378
36809
  code: 15,
36379
36810
  description: "Discourages try/catch in Effect generators in favor of Effect error handling",
36380
36811
  severity: "suggestion",
36812
+ fixable: false,
36813
+ supportedEffect: ["v3", "v4"],
36381
36814
  apply: fn3("tryCatchInEffectGen.apply")(function* (sourceFile, report) {
36382
36815
  const ts = yield* service2(TypeScriptApi);
36383
36816
  const typeParser = yield* service2(TypeParser);
@@ -36435,6 +36868,8 @@ var unknownInEffectCatch = createDiagnostic({
36435
36868
  code: 31,
36436
36869
  description: "Warns when catch callbacks return unknown instead of typed errors",
36437
36870
  severity: "warning",
36871
+ fixable: false,
36872
+ supportedEffect: ["v3", "v4"],
36438
36873
  apply: fn3("unknownInEffectCatch.apply")(function* (sourceFile, report) {
36439
36874
  const ts = yield* service2(TypeScriptApi);
36440
36875
  const typeParser = yield* service2(TypeParser);
@@ -36496,6 +36931,8 @@ var unnecessaryEffectGen = createDiagnostic({
36496
36931
  code: 5,
36497
36932
  description: "Suggests removing Effect.gen when it contains only a single return statement",
36498
36933
  severity: "suggestion",
36934
+ fixable: true,
36935
+ supportedEffect: ["v3", "v4"],
36499
36936
  apply: fn3("unnecessaryEffectGen.apply")(function* (sourceFile, report) {
36500
36937
  const ts = yield* service2(TypeScriptApi);
36501
36938
  const typeParser = yield* service2(TypeParser);
@@ -36540,6 +36977,8 @@ var unnecessaryFailYieldableError = createDiagnostic({
36540
36977
  code: 29,
36541
36978
  description: "Suggests yielding yieldable errors directly instead of wrapping with Effect.fail",
36542
36979
  severity: "suggestion",
36980
+ fixable: true,
36981
+ supportedEffect: ["v3", "v4"],
36543
36982
  apply: fn3("unnecessaryFailYieldableError.apply")(function* (sourceFile, report) {
36544
36983
  const ts = yield* service2(TypeScriptApi);
36545
36984
  const typeParser = yield* service2(TypeParser);
@@ -36599,6 +37038,8 @@ var unnecessaryPipe = createDiagnostic({
36599
37038
  code: 9,
36600
37039
  description: "Removes pipe calls with no arguments",
36601
37040
  severity: "suggestion",
37041
+ fixable: true,
37042
+ supportedEffect: ["v3", "v4"],
36602
37043
  apply: fn3("unnecessaryPipe.apply")(function* (sourceFile, report) {
36603
37044
  const ts = yield* service2(TypeScriptApi);
36604
37045
  const typeParser = yield* service2(TypeParser);
@@ -36645,6 +37086,8 @@ var unnecessaryPipeChain = createDiagnostic({
36645
37086
  code: 16,
36646
37087
  description: "Simplifies chained pipe calls into a single pipe call",
36647
37088
  severity: "suggestion",
37089
+ fixable: true,
37090
+ supportedEffect: ["v3", "v4"],
36648
37091
  apply: fn3("unnecessaryPipeChain.apply")(function* (sourceFile, report) {
36649
37092
  const ts = yield* service2(TypeScriptApi);
36650
37093
  const typeParser = yield* service2(TypeParser);
@@ -36720,6 +37163,8 @@ var unsupportedServiceAccessors = createDiagnostic({
36720
37163
  code: 21,
36721
37164
  description: "Warns about service accessors that need codegen due to generic/complex signatures",
36722
37165
  severity: "warning",
37166
+ fixable: true,
37167
+ supportedEffect: ["v3", "v4"],
36723
37168
  apply: fn3("unsupportedServiceAccessors.apply")(function* (sourceFile, report) {
36724
37169
  const ts = yield* service2(TypeScriptApi);
36725
37170
  const nodeToVisit = [];
@@ -36822,7 +37267,10 @@ var diagnostics = [
36822
37267
  effectFnOpportunity,
36823
37268
  redundantSchemaTagIdentifier,
36824
37269
  schemaSyncInEffect,
36825
- preferSchemaOverJson
37270
+ preferSchemaOverJson,
37271
+ extendsNativeError,
37272
+ serviceNotAsClass,
37273
+ nodeBuiltinImport
36826
37274
  ];
36827
37275
 
36828
37276
  // src/cli/diagnostics.ts
@@ -36836,6 +37284,11 @@ var DiagnosticsFoundError = class extends TaggedError2("DiagnosticsFoundError")
36836
37284
  return `Found ${this.errorsCount} errors, ${this.warningsCount} warnings and ${this.messagesCount} messages.`;
36837
37285
  }
36838
37286
  };
37287
+ var InvalidLspConfigError = class extends TaggedError2("InvalidLspConfigError") {
37288
+ get message() {
37289
+ return `Invalid JSON lsp config: ${this.lspconfig}`;
37290
+ }
37291
+ };
36839
37292
  var categoryToSeverity = (category, tsInstance) => {
36840
37293
  switch (category) {
36841
37294
  case tsInstance.DiagnosticCategory.Error:
@@ -37031,9 +37484,15 @@ var diagnostics2 = Command_exports.make(
37031
37484
  progress: Flag_exports.boolean("progress").pipe(
37032
37485
  Flag_exports.withDefault(false),
37033
37486
  Flag_exports.withDescription("Show progress as files are checked (outputs to stderr)")
37487
+ ),
37488
+ lspconfig: Flag_exports.string("lspconfig").pipe(
37489
+ Flag_exports.optional,
37490
+ Flag_exports.withDescription(
37491
+ `An optional inline JSON lsp config that replaces the current project lsp config. e.g. '{ "effectFn": ["untraced"] }'`
37492
+ )
37034
37493
  )
37035
37494
  },
37036
- fn2("diagnostics")(function* ({ file: file4, format: format3, progress, project: project2, severity, strict }) {
37495
+ fn2("diagnostics")(function* ({ file: file4, format: format3, lspconfig, progress, project: project2, severity, strict }) {
37037
37496
  const path4 = yield* Path;
37038
37497
  const severityFilter = parseSeverityFilter(severity);
37039
37498
  const state = {
@@ -37097,7 +37556,14 @@ var diagnostics2 = Command_exports.make(
37097
37556
  if (!program) continue;
37098
37557
  const sourceFile = program.getSourceFile(filePath);
37099
37558
  if (!sourceFile) continue;
37100
- const pluginConfig = extractEffectLspOptions(program.getCompilerOptions());
37559
+ let pluginConfig = extractEffectLspOptions(program.getCompilerOptions());
37560
+ if (isSome2(lspconfig)) {
37561
+ try {
37562
+ pluginConfig = { name: "@effect/language-service", ...JSON.parse(lspconfig.value) };
37563
+ } catch {
37564
+ return yield* new InvalidLspConfigError({ lspconfig: lspconfig.value });
37565
+ }
37566
+ }
37101
37567
  if (!pluginConfig) continue;
37102
37568
  const rawResults = pipe(
37103
37569
  getSemanticDiagnosticsWithCodeFixes(diagnostics, sourceFile),
@@ -37757,7 +38223,10 @@ var import_project_service3 = __toESM(require_dist3());
37757
38223
  var getLocationFromDeclaration = (declaration, tsInstance) => {
37758
38224
  const sourceFile = declaration.getSourceFile();
37759
38225
  if (!sourceFile) return void 0;
37760
- const { character, line } = tsInstance.getLineAndCharacterOfPosition(sourceFile, declaration.getStart());
38226
+ const { character, line } = tsInstance.getLineAndCharacterOfPosition(
38227
+ sourceFile,
38228
+ tsInstance.getTokenPosOfNode(declaration, sourceFile)
38229
+ );
37761
38230
  return {
37762
38231
  filePath: sourceFile.fileName,
37763
38232
  line: line + 1,
@@ -38359,7 +38828,8 @@ function getExpressionName(tsApi, expr) {
38359
38828
  if (tsApi.isCallExpression(expr)) {
38360
38829
  return getExpressionName(tsApi, expr.expression);
38361
38830
  }
38362
- const text2 = expr.getText().replace(/\s+/g, " ");
38831
+ const sourceFile = expr.getSourceFile();
38832
+ const text2 = sourceFile.text.substring(tsApi.getTokenPosOfNode(expr, sourceFile), expr.end).replace(/\s+/g, " ");
38363
38833
  return text2.length > 30 ? text2.slice(0, 27) + "..." : text2;
38364
38834
  }
38365
38835
  var collectLayerInfoByName = (sourceFile, layerName, selectedOutputIndices) => gen3(function* () {
@@ -39377,6 +39847,7 @@ var assess = (input) => gen2(function* () {
39377
39847
  });
39378
39848
 
39379
39849
  // src/cli/setup/changes.ts
39850
+ var TSCONFIG_SCHEMA_URL = "https://raw.githubusercontent.com/Effect-TS/language-service/refs/heads/main/schema.json";
39380
39851
  function emptyFileChangesResult() {
39381
39852
  return {
39382
39853
  codeActions: [],
@@ -39723,8 +40194,17 @@ var computeTsConfigChanges = (current, target, lspVersion) => {
39723
40194
  const fileChanges = textChanges.ChangeTracker.with(
39724
40195
  { host, formatContext, preferences },
39725
40196
  (tracker) => {
40197
+ const schemaProperty = findPropertyInObject(ts, rootObj, "$schema");
39726
40198
  const pluginsProperty = findPropertyInObject(ts, compilerOptions, "plugins");
40199
+ const schemaPropertyAssignment = ts.factory.createPropertyAssignment(
40200
+ ts.factory.createStringLiteral("$schema"),
40201
+ ts.factory.createStringLiteral(TSCONFIG_SCHEMA_URL)
40202
+ );
39727
40203
  if (isNone2(lspVersion)) {
40204
+ if (schemaProperty) {
40205
+ descriptions.push("Remove $schema from tsconfig");
40206
+ deleteNodeFromList(tracker, current.sourceFile, rootObj.properties, schemaProperty);
40207
+ }
39728
40208
  if (pluginsProperty && ts.isArrayLiteralExpression(pluginsProperty.initializer)) {
39729
40209
  const pluginsArray = pluginsProperty.initializer;
39730
40210
  const lspPluginElement = pluginsArray.elements.find((element) => {
@@ -39742,6 +40222,13 @@ var computeTsConfigChanges = (current, target, lspVersion) => {
39742
40222
  }
39743
40223
  }
39744
40224
  } else {
40225
+ if (!schemaProperty) {
40226
+ descriptions.push("Add $schema to tsconfig");
40227
+ insertNodeAtEndOfList(tracker, current.sourceFile, rootObj.properties, schemaPropertyAssignment);
40228
+ } else if (!ts.isStringLiteral(schemaProperty.initializer) || schemaProperty.initializer.text !== TSCONFIG_SCHEMA_URL) {
40229
+ descriptions.push("Update $schema in tsconfig");
40230
+ tracker.replaceNode(current.sourceFile, schemaProperty.initializer, schemaPropertyAssignment.initializer);
40231
+ }
39745
40232
  const buildPluginObject = (severities) => {
39746
40233
  const nameProperty = ts.factory.createPropertyAssignment(
39747
40234
  ts.factory.createStringLiteral("name"),