@effect/language-service 0.78.0 → 0.79.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/transform.js CHANGED
@@ -1638,10 +1638,12 @@ var defaults = {
1638
1638
  extendedKeyDetection: false,
1639
1639
  ignoreEffectWarningsInTscExitCode: false,
1640
1640
  ignoreEffectSuggestionsInTscExitCode: true,
1641
+ ignoreEffectErrorsInTscExitCode: false,
1641
1642
  pipeableMinArgCount: 2,
1642
1643
  effectFn: ["span"],
1643
1644
  layerGraphFollowDepth: 0,
1644
- mermaidProvider: "mermaid.live"
1645
+ mermaidProvider: "mermaid.live",
1646
+ skipDisabledOptimization: false
1645
1647
  };
1646
1648
  function parseKeyPatterns(patterns) {
1647
1649
  const result = [];
@@ -1665,6 +1667,7 @@ function parse(config) {
1665
1667
  includeSuggestionsInTsc: isObject(config) && hasProperty(config, "includeSuggestionsInTsc") && isBoolean(config.includeSuggestionsInTsc) ? config.includeSuggestionsInTsc : defaults.includeSuggestionsInTsc,
1666
1668
  ignoreEffectWarningsInTscExitCode: isObject(config) && hasProperty(config, "ignoreEffectWarningsInTscExitCode") && isBoolean(config.ignoreEffectWarningsInTscExitCode) ? config.ignoreEffectWarningsInTscExitCode : defaults.ignoreEffectWarningsInTscExitCode,
1667
1669
  ignoreEffectSuggestionsInTscExitCode: isObject(config) && hasProperty(config, "ignoreEffectSuggestionsInTscExitCode") && isBoolean(config.ignoreEffectSuggestionsInTscExitCode) ? config.ignoreEffectSuggestionsInTscExitCode : defaults.ignoreEffectSuggestionsInTscExitCode,
1670
+ ignoreEffectErrorsInTscExitCode: isObject(config) && hasProperty(config, "ignoreEffectErrorsInTscExitCode") && isBoolean(config.ignoreEffectErrorsInTscExitCode) ? config.ignoreEffectErrorsInTscExitCode : defaults.ignoreEffectErrorsInTscExitCode,
1668
1671
  quickinfo: isObject(config) && hasProperty(config, "quickinfo") && isBoolean(config.quickinfo) ? config.quickinfo : defaults.quickinfo,
1669
1672
  quickinfoEffectParameters: isObject(config) && hasProperty(config, "quickinfoEffectParameters") && isString(config.quickinfoEffectParameters) && ["always", "never", "whentruncated"].includes(config.quickinfoEffectParameters.toLowerCase()) ? config.quickinfoEffectParameters.toLowerCase() : defaults.quickinfoEffectParameters,
1670
1673
  quickinfoMaximumLength: isObject(config) && hasProperty(config, "quickinfoMaximumLength") && isNumber(config.quickinfoMaximumLength) ? config.quickinfoMaximumLength : defaults.quickinfoMaximumLength,
@@ -1685,7 +1688,8 @@ function parse(config) {
1685
1688
  (_) => _.toLowerCase()
1686
1689
  ) : defaults.effectFn,
1687
1690
  layerGraphFollowDepth: isObject(config) && hasProperty(config, "layerGraphFollowDepth") && isNumber(config.layerGraphFollowDepth) ? config.layerGraphFollowDepth : defaults.layerGraphFollowDepth,
1688
- mermaidProvider: isObject(config) && hasProperty(config, "mermaidProvider") && isString(config.mermaidProvider) ? config.mermaidProvider : defaults.mermaidProvider
1691
+ mermaidProvider: isObject(config) && hasProperty(config, "mermaidProvider") && isString(config.mermaidProvider) ? config.mermaidProvider : defaults.mermaidProvider,
1692
+ skipDisabledOptimization: isObject(config) && hasProperty(config, "skipDisabledOptimization") && isBoolean(config.skipDisabledOptimization) ? config.skipDisabledOptimization : defaults.skipDisabledOptimization
1689
1693
  };
1690
1694
  }
1691
1695
 
@@ -2455,7 +2459,7 @@ var createDiagnosticExecutor = fn("LSP.createCommentDirectivesProcessor")(
2455
2459
  if (skippedRules.indexOf(ruleNameLowered) > -1 || skippedRules.indexOf("*") > -1) {
2456
2460
  return { diagnostics: diagnostics2, codeFixes };
2457
2461
  }
2458
- if (defaultLevel === "off" && (lineOverrides[ruleNameLowered] || sectionOverrides[ruleNameLowered] || lineOverrides["*"] || sectionOverrides["*"] || []).length === 0) {
2462
+ if (!pluginOptions.skipDisabledOptimization && defaultLevel === "off" && (lineOverrides[ruleNameLowered] || sectionOverrides[ruleNameLowered] || lineOverrides["*"] || sectionOverrides["*"] || []).length === 0) {
2459
2463
  return { diagnostics: diagnostics2, codeFixes };
2460
2464
  }
2461
2465
  const fixByDisableNextLine = (node) => ({
@@ -5127,6 +5131,8 @@ var anyUnknownInErrorContext = createDiagnostic({
5127
5131
  code: 28,
5128
5132
  description: "Detects 'any' or 'unknown' types in Effect error or requirements channels",
5129
5133
  severity: "off",
5134
+ fixable: false,
5135
+ supportedEffect: ["v3", "v4"],
5130
5136
  apply: fn("anyUnknownInErrorContext.apply")(function* (sourceFile, report) {
5131
5137
  const ts = yield* service(TypeScriptApi);
5132
5138
  const typeChecker = yield* service(TypeCheckerApi);
@@ -5230,6 +5236,8 @@ var catchAllToMapError = createDiagnostic({
5230
5236
  code: 39,
5231
5237
  description: "Suggests using Effect.mapError instead of Effect.catchAll when the callback only wraps the error with Effect.fail",
5232
5238
  severity: "suggestion",
5239
+ fixable: true,
5240
+ supportedEffect: ["v3", "v4"],
5233
5241
  apply: fn("catchAllToMapError.apply")(function* (sourceFile, report) {
5234
5242
  const ts = yield* service(TypeScriptApi);
5235
5243
  const typeParser = yield* service(TypeParser);
@@ -5327,6 +5335,8 @@ var catchUnfailableEffect = createDiagnostic({
5327
5335
  code: 2,
5328
5336
  description: "Warns when using error handling on Effects that never fail (error type is 'never')",
5329
5337
  severity: "suggestion",
5338
+ fixable: false,
5339
+ supportedEffect: ["v3", "v4"],
5330
5340
  apply: fn("catchUnfailableEffect.apply")(function* (sourceFile, report) {
5331
5341
  const ts = yield* service(TypeScriptApi);
5332
5342
  const typeParser = yield* service(TypeParser);
@@ -5376,6 +5386,8 @@ var classSelfMismatch = createDiagnostic({
5376
5386
  code: 20,
5377
5387
  description: "Ensures Self type parameter matches the class name in Service/Tag/Schema classes",
5378
5388
  severity: "error",
5389
+ fixable: true,
5390
+ supportedEffect: ["v3", "v4"],
5379
5391
  apply: fn("classSelfMismatch.apply")(function* (sourceFile, report) {
5380
5392
  const ts = yield* service(TypeScriptApi);
5381
5393
  const typeParser = yield* service(TypeParser);
@@ -5514,6 +5526,8 @@ var deterministicKeys = createDiagnostic({
5514
5526
  code: 25,
5515
5527
  description: "Enforces deterministic naming for service/tag/error identifiers based on class names",
5516
5528
  severity: "off",
5529
+ fixable: true,
5530
+ supportedEffect: ["v3", "v4"],
5517
5531
  apply: fn("deterministicKeys.apply")(function* (sourceFile, report) {
5518
5532
  const ts = yield* service(TypeScriptApi);
5519
5533
  const typeParser = yield* service(TypeParser);
@@ -5631,6 +5645,8 @@ var duplicatePackage = createDiagnostic({
5631
5645
  code: 6,
5632
5646
  description: "Detects when multiple versions of the same Effect package are loaded",
5633
5647
  severity: "warning",
5648
+ fixable: false,
5649
+ supportedEffect: ["v3", "v4"],
5634
5650
  apply: fn("duplicatePackage.apply")(function* (sourceFile, report) {
5635
5651
  const typeParser = yield* service(TypeParser);
5636
5652
  const options = yield* service(LanguageServicePluginOptions);
@@ -5660,6 +5676,8 @@ var effectFnIife = createDiagnostic({
5660
5676
  code: 46,
5661
5677
  description: "Effect.fn or Effect.fnUntraced is called as an IIFE (Immediately Invoked Function Expression). Use Effect.gen instead.",
5662
5678
  severity: "warning",
5679
+ fixable: true,
5680
+ supportedEffect: ["v3", "v4"],
5663
5681
  apply: fn("effectFnIife.apply")(function* (sourceFile, report) {
5664
5682
  const ts = yield* service(TypeScriptApi);
5665
5683
  const typeParser = yield* service(TypeParser);
@@ -5762,6 +5780,8 @@ var effectFnOpportunity = createDiagnostic({
5762
5780
  code: 41,
5763
5781
  description: "Suggests using Effect.fn for functions that returns an Effect",
5764
5782
  severity: "suggestion",
5783
+ fixable: true,
5784
+ supportedEffect: ["v3", "v4"],
5765
5785
  apply: fn("effectFnOpportunity.apply")(function* (sourceFile, report) {
5766
5786
  const ts = yield* service(TypeScriptApi);
5767
5787
  const typeChecker = yield* service(TypeCheckerApi);
@@ -6354,6 +6374,8 @@ var effectGenUsesAdapter = createDiagnostic({
6354
6374
  code: 23,
6355
6375
  description: "Warns when using the deprecated adapter parameter in Effect.gen",
6356
6376
  severity: "warning",
6377
+ fixable: false,
6378
+ supportedEffect: ["v3", "v4"],
6357
6379
  apply: fn("effectGenUsesAdapter.apply")(function* (sourceFile, report) {
6358
6380
  const ts = yield* service(TypeScriptApi);
6359
6381
  const typeParser = yield* service(TypeParser);
@@ -6392,6 +6414,8 @@ var effectInFailure = createDiagnostic({
6392
6414
  code: 49,
6393
6415
  description: "Warns when an Effect is used inside an Effect failure channel",
6394
6416
  severity: "warning",
6417
+ fixable: false,
6418
+ supportedEffect: ["v3", "v4"],
6395
6419
  apply: fn("effectInFailure.apply")(function* (sourceFile, report) {
6396
6420
  const ts = yield* service(TypeScriptApi);
6397
6421
  const typeChecker = yield* service(TypeCheckerApi);
@@ -6456,6 +6480,8 @@ var effectInVoidSuccess = createDiagnostic({
6456
6480
  code: 14,
6457
6481
  description: "Detects nested Effects in void success channels that may cause unexecuted effects",
6458
6482
  severity: "warning",
6483
+ fixable: false,
6484
+ supportedEffect: ["v3", "v4"],
6459
6485
  apply: fn("effectInVoidSuccess.apply")(function* (sourceFile, report) {
6460
6486
  const ts = yield* service(TypeScriptApi);
6461
6487
  const typeChecker = yield* service(TypeCheckerApi);
@@ -6505,6 +6531,8 @@ var effectMapVoid = createDiagnostic({
6505
6531
  code: 40,
6506
6532
  description: "Suggests using Effect.asVoid instead of Effect.map(() => void 0), Effect.map(() => undefined), or Effect.map(() => {})",
6507
6533
  severity: "suggestion",
6534
+ fixable: true,
6535
+ supportedEffect: ["v3", "v4"],
6508
6536
  apply: fn("effectMapVoid.apply")(function* (sourceFile, report) {
6509
6537
  const ts = yield* service(TypeScriptApi);
6510
6538
  const typeParser = yield* service(TypeParser);
@@ -6569,6 +6597,8 @@ var effectSucceedWithVoid = createDiagnostic({
6569
6597
  code: 47,
6570
6598
  description: "Suggests using Effect.void instead of Effect.succeed(undefined) or Effect.succeed(void 0)",
6571
6599
  severity: "suggestion",
6600
+ fixable: true,
6601
+ supportedEffect: ["v3", "v4"],
6572
6602
  apply: fn("effectSucceedWithVoid.apply")(function* (sourceFile, report) {
6573
6603
  const ts = yield* service(TypeScriptApi);
6574
6604
  const typeParser = yield* service(TypeParser);
@@ -6614,12 +6644,66 @@ var effectSucceedWithVoid = createDiagnostic({
6614
6644
  })
6615
6645
  });
6616
6646
 
6647
+ // src/diagnostics/extendsNativeError.ts
6648
+ var extendsNativeError = createDiagnostic({
6649
+ name: "extendsNativeError",
6650
+ code: 50,
6651
+ description: "Warns when a class directly extends the native Error class",
6652
+ severity: "off",
6653
+ fixable: false,
6654
+ supportedEffect: ["v3", "v4"],
6655
+ apply: fn("extendsNativeError.apply")(function* (sourceFile, report) {
6656
+ const ts = yield* service(TypeScriptApi);
6657
+ const typeChecker = yield* service(TypeCheckerApi);
6658
+ const errorSymbol = typeChecker.resolveName("Error", void 0, ts.SymbolFlags.Type, false);
6659
+ if (!errorSymbol) return;
6660
+ const nodeToVisit = [];
6661
+ const appendNodeToVisit = (node) => {
6662
+ nodeToVisit.push(node);
6663
+ return void 0;
6664
+ };
6665
+ ts.forEachChild(sourceFile, appendNodeToVisit);
6666
+ while (nodeToVisit.length > 0) {
6667
+ const node = nodeToVisit.shift();
6668
+ if (ts.isClassDeclaration(node) && node.heritageClauses) {
6669
+ for (const clause of node.heritageClauses) {
6670
+ if (clause.token === ts.SyntaxKind.ExtendsKeyword && clause.types.length > 0) {
6671
+ const typeExpression = clause.types[0].expression;
6672
+ const exprSymbol = typeChecker.getSymbolAtLocation(typeExpression);
6673
+ const resolvedSymbol = exprSymbol && exprSymbol.flags & ts.SymbolFlags.Alias ? typeChecker.getAliasedSymbol(exprSymbol) : exprSymbol;
6674
+ const isNativeError = resolvedSymbol === errorSymbol || (() => {
6675
+ if (!resolvedSymbol || resolvedSymbol === errorSymbol) return false;
6676
+ const exprType = typeChecker.getTypeAtLocation(typeExpression);
6677
+ const constructSignatures = typeChecker.getSignaturesOfType(exprType, ts.SignatureKind.Construct);
6678
+ if (constructSignatures.length > 0) {
6679
+ const instanceType = typeChecker.getReturnTypeOfSignature(constructSignatures[0]);
6680
+ return instanceType.symbol === errorSymbol;
6681
+ }
6682
+ return false;
6683
+ })();
6684
+ if (isNativeError) {
6685
+ report({
6686
+ location: node.name ?? typeExpression,
6687
+ 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.",
6688
+ fixes: []
6689
+ });
6690
+ }
6691
+ }
6692
+ }
6693
+ }
6694
+ ts.forEachChild(node, appendNodeToVisit);
6695
+ }
6696
+ })
6697
+ });
6698
+
6617
6699
  // src/diagnostics/floatingEffect.ts
6618
6700
  var floatingEffect = createDiagnostic({
6619
6701
  name: "floatingEffect",
6620
6702
  code: 3,
6621
6703
  description: "Ensures Effects are yielded or assigned to variables, not left floating",
6622
6704
  severity: "error",
6705
+ fixable: false,
6706
+ supportedEffect: ["v3", "v4"],
6623
6707
  apply: fn("floatingEffect.apply")(function* (sourceFile, report) {
6624
6708
  const ts = yield* service(TypeScriptApi);
6625
6709
  const typeChecker = yield* service(TypeCheckerApi);
@@ -6671,6 +6755,8 @@ var genericEffectServices = createDiagnostic({
6671
6755
  code: 10,
6672
6756
  description: "Prevents services with type parameters that cannot be discriminated at runtime",
6673
6757
  severity: "warning",
6758
+ fixable: false,
6759
+ supportedEffect: ["v3", "v4"],
6674
6760
  apply: fn("genericEffectServices.apply")(function* (sourceFile, report) {
6675
6761
  const ts = yield* service(TypeScriptApi);
6676
6762
  const typeParser = yield* service(TypeParser);
@@ -6718,6 +6804,8 @@ var globalErrorInEffectCatch = createDiagnostic({
6718
6804
  code: 36,
6719
6805
  description: "Warns when catch callbacks return global Error type instead of typed errors",
6720
6806
  severity: "warning",
6807
+ fixable: false,
6808
+ supportedEffect: ["v3", "v4"],
6721
6809
  apply: fn("globalErrorInEffectCatch.apply")(function* (sourceFile, report) {
6722
6810
  const ts = yield* service(TypeScriptApi);
6723
6811
  const typeParser = yield* service(TypeParser);
@@ -6778,6 +6866,8 @@ var globalErrorInEffectFailure = createDiagnostic({
6778
6866
  code: 35,
6779
6867
  description: "Warns when the global Error type is used in an Effect failure channel",
6780
6868
  severity: "warning",
6869
+ fixable: false,
6870
+ supportedEffect: ["v3", "v4"],
6781
6871
  apply: fn("globalErrorInEffectFailure.apply")(function* (sourceFile, report) {
6782
6872
  const ts = yield* service(TypeScriptApi);
6783
6873
  const typeParser = yield* service(TypeParser);
@@ -6831,6 +6921,8 @@ var importFromBarrel = createDiagnostic({
6831
6921
  code: 12,
6832
6922
  description: "Suggests importing from specific module paths instead of barrel exports",
6833
6923
  severity: "off",
6924
+ fixable: true,
6925
+ supportedEffect: ["v3", "v4"],
6834
6926
  apply: fn("importFromBarrel.apply")(function* (sourceFile, report) {
6835
6927
  const languageServicePluginOptions = yield* service(LanguageServicePluginOptions);
6836
6928
  if (languageServicePluginOptions.namespaceImportPackages.length === 0) return;
@@ -6971,6 +7063,8 @@ var instanceOfSchema = createDiagnostic({
6971
7063
  code: 45,
6972
7064
  description: "Suggests using Schema.is instead of instanceof for Effect Schema types",
6973
7065
  severity: "off",
7066
+ fixable: true,
7067
+ supportedEffect: ["v3", "v4"],
6974
7068
  apply: fn("instanceOfSchema.apply")(function* (sourceFile, report) {
6975
7069
  const ts = yield* service(TypeScriptApi);
6976
7070
  const typeParser = yield* service(TypeParser);
@@ -7034,6 +7128,8 @@ var layerMergeAllWithDependencies = createDiagnostic({
7034
7128
  code: 37,
7035
7129
  description: "Detects interdependencies in Layer.mergeAll calls where one layer provides a service that another layer requires",
7036
7130
  severity: "warning",
7131
+ fixable: true,
7132
+ supportedEffect: ["v3", "v4"],
7037
7133
  apply: fn("layerMergeAllWithDependencies.apply")(function* (sourceFile, report) {
7038
7134
  const ts = yield* service(TypeScriptApi);
7039
7135
  const typeChecker = yield* service(TypeCheckerApi);
@@ -7147,6 +7243,8 @@ var leakingRequirements = createDiagnostic({
7147
7243
  code: 8,
7148
7244
  description: "Detects implementation services leaked in service methods",
7149
7245
  severity: "suggestion",
7246
+ fixable: false,
7247
+ supportedEffect: ["v3", "v4"],
7150
7248
  apply: fn("leakingRequirements.apply")(function* (sourceFile, report) {
7151
7249
  const ts = yield* service(TypeScriptApi);
7152
7250
  const typeChecker = yield* service(TypeCheckerApi);
@@ -7301,6 +7399,8 @@ var missedPipeableOpportunity = createDiagnostic({
7301
7399
  code: 26,
7302
7400
  description: "Enforces the use of pipeable style for nested function calls",
7303
7401
  severity: "off",
7402
+ fixable: true,
7403
+ supportedEffect: ["v3", "v4"],
7304
7404
  apply: fn("missedPipeableOpportunity.apply")(function* (sourceFile, report) {
7305
7405
  const ts = yield* service(TypeScriptApi);
7306
7406
  const typeChecker = yield* service(TypeCheckerApi);
@@ -7481,6 +7581,8 @@ var missingEffectContext = createDiagnostic({
7481
7581
  code: 1,
7482
7582
  description: "Reports missing service requirements in Effect context channel",
7483
7583
  severity: "error",
7584
+ fixable: false,
7585
+ supportedEffect: ["v3", "v4"],
7484
7586
  apply: fn("missingEffectContext.apply")(function* (sourceFile, report) {
7485
7587
  const typeChecker = yield* service(TypeCheckerApi);
7486
7588
  const typeParser = yield* service(TypeParser);
@@ -7530,6 +7632,8 @@ var missingEffectError = createDiagnostic({
7530
7632
  code: 1,
7531
7633
  description: "Reports missing error types in Effect error channel",
7532
7634
  severity: "error",
7635
+ fixable: true,
7636
+ supportedEffect: ["v3", "v4"],
7533
7637
  apply: fn("missingEffectError.apply")(function* (sourceFile, report) {
7534
7638
  const ts = yield* service(TypeScriptApi);
7535
7639
  const tsUtils = yield* service(TypeScriptUtils);
@@ -7671,6 +7775,8 @@ var missingEffectServiceDependency = createDiagnostic({
7671
7775
  code: 22,
7672
7776
  description: "Checks that Effect.Service dependencies satisfy all required layer inputs",
7673
7777
  severity: "off",
7778
+ fixable: false,
7779
+ supportedEffect: ["v3"],
7674
7780
  apply: fn("missingEffectServiceDependency.apply")(function* (sourceFile, report) {
7675
7781
  const ts = yield* service(TypeScriptApi);
7676
7782
  const typeChecker = yield* service(TypeCheckerApi);
@@ -7765,6 +7871,8 @@ var missingLayerContext = createDiagnostic({
7765
7871
  code: 38,
7766
7872
  description: "Reports missing service requirements in Layer context channel",
7767
7873
  severity: "error",
7874
+ fixable: false,
7875
+ supportedEffect: ["v3", "v4"],
7768
7876
  apply: fn("missingLayerContext.apply")(function* (sourceFile, report) {
7769
7877
  const typeChecker = yield* service(TypeCheckerApi);
7770
7878
  const typeParser = yield* service(TypeParser);
@@ -7814,6 +7922,8 @@ var missingReturnYieldStar = createDiagnostic({
7814
7922
  code: 7,
7815
7923
  description: "Suggests using 'return yield*' for Effects with never success for better type narrowing",
7816
7924
  severity: "error",
7925
+ fixable: true,
7926
+ supportedEffect: ["v3", "v4"],
7817
7927
  apply: fn("missingReturnYieldStar.apply")(function* (sourceFile, report) {
7818
7928
  const ts = yield* service(TypeScriptApi);
7819
7929
  const typeCheckerUtils = yield* service(TypeCheckerUtils);
@@ -7864,6 +7974,8 @@ var missingStarInYieldEffectGen = createDiagnostic({
7864
7974
  code: 4,
7865
7975
  description: "Enforces using 'yield*' instead of 'yield' when yielding Effects in generators",
7866
7976
  severity: "error",
7977
+ fixable: true,
7978
+ supportedEffect: ["v3", "v4"],
7867
7979
  apply: fn("missingStarInYieldEffectGen.apply")(function* (sourceFile, report) {
7868
7980
  const ts = yield* service(TypeScriptApi);
7869
7981
  const typeParser = yield* service(TypeParser);
@@ -7939,6 +8051,8 @@ var multipleEffectProvide = createDiagnostic({
7939
8051
  code: 18,
7940
8052
  description: "Warns against chaining Effect.provide calls which can cause service lifecycle issues",
7941
8053
  severity: "warning",
8054
+ fixable: true,
8055
+ supportedEffect: ["v3", "v4"],
7942
8056
  apply: fn("multipleEffectProvide.apply")(function* (sourceFile, report) {
7943
8057
  const ts = yield* service(TypeScriptApi);
7944
8058
  const tsUtils = yield* service(TypeScriptUtils);
@@ -8025,12 +8139,85 @@ var multipleEffectProvide = createDiagnostic({
8025
8139
  })
8026
8140
  });
8027
8141
 
8142
+ // src/diagnostics/nodeBuiltinImport.ts
8143
+ var moduleAlternativesV3 = /* @__PURE__ */ new Map([
8144
+ ["fs", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
8145
+ ["node:fs", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
8146
+ ["fs/promises", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
8147
+ ["node:fs/promises", { alternative: "FileSystem", module: "fs", package: "@effect/platform" }],
8148
+ ["path", { alternative: "Path", module: "path", package: "@effect/platform" }],
8149
+ ["node:path", { alternative: "Path", module: "path", package: "@effect/platform" }],
8150
+ ["path/posix", { alternative: "Path", module: "path", package: "@effect/platform" }],
8151
+ ["node:path/posix", { alternative: "Path", module: "path", package: "@effect/platform" }],
8152
+ ["path/win32", { alternative: "Path", module: "path", package: "@effect/platform" }],
8153
+ ["node:path/win32", { alternative: "Path", module: "path", package: "@effect/platform" }],
8154
+ ["child_process", { alternative: "CommandExecutor", module: "child_process", package: "@effect/platform" }],
8155
+ ["node:child_process", { alternative: "CommandExecutor", module: "child_process", package: "@effect/platform" }]
8156
+ ]);
8157
+ var moduleAlternativesV4 = /* @__PURE__ */ new Map([
8158
+ ["fs", { alternative: "FileSystem", module: "fs", package: "effect" }],
8159
+ ["node:fs", { alternative: "FileSystem", module: "fs", package: "effect" }],
8160
+ ["fs/promises", { alternative: "FileSystem", module: "fs", package: "effect" }],
8161
+ ["node:fs/promises", { alternative: "FileSystem", module: "fs", package: "effect" }],
8162
+ ["path", { alternative: "Path", module: "path", package: "effect" }],
8163
+ ["node:path", { alternative: "Path", module: "path", package: "effect" }],
8164
+ ["path/posix", { alternative: "Path", module: "path", package: "effect" }],
8165
+ ["node:path/posix", { alternative: "Path", module: "path", package: "effect" }],
8166
+ ["path/win32", { alternative: "Path", module: "path", package: "effect" }],
8167
+ ["node:path/win32", { alternative: "Path", module: "path", package: "effect" }],
8168
+ ["child_process", { alternative: "ChildProcess", module: "child_process", package: "effect" }],
8169
+ ["node:child_process", { alternative: "ChildProcess", module: "child_process", package: "effect" }]
8170
+ ]);
8171
+ var nodeBuiltinImport = createDiagnostic({
8172
+ name: "nodeBuiltinImport",
8173
+ code: 52,
8174
+ description: "Warns when importing Node.js built-in modules that have Effect-native counterparts",
8175
+ severity: "off",
8176
+ fixable: false,
8177
+ supportedEffect: ["v3", "v4"],
8178
+ apply: fn("nodeBuiltinImport.apply")(function* (sourceFile, report) {
8179
+ const ts = yield* service(TypeScriptApi);
8180
+ const typeParser = yield* service(TypeParser);
8181
+ const moduleAlternatives = typeParser.supportedEffect() === "v3" ? moduleAlternativesV3 : moduleAlternativesV4;
8182
+ for (const statement of sourceFile.statements) {
8183
+ if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) {
8184
+ const specifier = statement.moduleSpecifier.text;
8185
+ const match2 = moduleAlternatives.get(specifier);
8186
+ if (match2) {
8187
+ report({
8188
+ location: statement.moduleSpecifier,
8189
+ messageText: `Prefer using ${match2.alternative} from ${match2.package} instead of the Node.js '${match2.module}' module.`,
8190
+ fixes: []
8191
+ });
8192
+ }
8193
+ } else if (ts.isVariableStatement(statement)) {
8194
+ for (const decl of statement.declarationList.declarations) {
8195
+ 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])) {
8196
+ const arg = decl.initializer.arguments[0];
8197
+ const specifier = arg.text;
8198
+ const match2 = moduleAlternatives.get(specifier);
8199
+ if (match2) {
8200
+ report({
8201
+ location: arg,
8202
+ messageText: `Prefer using ${match2.alternative} from ${match2.package} instead of the Node.js '${match2.module}' module.`,
8203
+ fixes: []
8204
+ });
8205
+ }
8206
+ }
8207
+ }
8208
+ }
8209
+ }
8210
+ })
8211
+ });
8212
+
8028
8213
  // src/diagnostics/nonObjectEffectServiceType.ts
8029
8214
  var nonObjectEffectServiceType = createDiagnostic({
8030
8215
  name: "nonObjectEffectServiceType",
8031
8216
  code: 24,
8032
8217
  description: "Ensures Effect.Service types are objects, not primitives",
8033
8218
  severity: "error",
8219
+ fixable: false,
8220
+ supportedEffect: ["v3"],
8034
8221
  apply: fn("nonObjectEffectServiceType.apply")(function* (sourceFile, report) {
8035
8222
  const ts = yield* service(TypeScriptApi);
8036
8223
  const typeChecker = yield* service(TypeCheckerApi);
@@ -8813,6 +9000,8 @@ var outdatedApi = createDiagnostic({
8813
9000
  code: 48,
8814
9001
  description: "Detects usage of APIs that have been removed or renamed in Effect v4",
8815
9002
  severity: "warning",
9003
+ fixable: false,
9004
+ supportedEffect: ["v4"],
8816
9005
  apply: fn("outdatedApi.apply")(function* (sourceFile, report) {
8817
9006
  const typeParser = yield* service(TypeParser);
8818
9007
  const ts = yield* service(TypeScriptApi);
@@ -9949,6 +10138,8 @@ var outdatedEffectCodegen = createDiagnostic({
9949
10138
  code: 19,
9950
10139
  description: "Detects when generated code is outdated and needs to be regenerated",
9951
10140
  severity: "warning",
10141
+ fixable: true,
10142
+ supportedEffect: ["v3", "v4"],
9952
10143
  apply: fn("outdatedEffectCodegen.apply")(function* (sourceFile, _report) {
9953
10144
  const codegensWithRanges = yield* getCodegensForSourceFile(codegens, sourceFile);
9954
10145
  for (const { codegen, hash: hash2, range } of codegensWithRanges) {
@@ -9995,6 +10186,8 @@ var overriddenSchemaConstructor = createDiagnostic({
9995
10186
  code: 30,
9996
10187
  description: "Prevents overriding constructors in Schema classes which breaks decoding behavior",
9997
10188
  severity: "error",
10189
+ fixable: true,
10190
+ supportedEffect: ["v3", "v4"],
9998
10191
  apply: fn("overriddenSchemaConstructor.apply")(function* (sourceFile, report) {
9999
10192
  const ts = yield* service(TypeScriptApi);
10000
10193
  const typeParser = yield* service(TypeParser);
@@ -10132,6 +10325,8 @@ var preferSchemaOverJson = createDiagnostic({
10132
10325
  code: 44,
10133
10326
  description: "Suggests using Effect Schema for JSON operations instead of JSON.parse/JSON.stringify which may throw",
10134
10327
  severity: "suggestion",
10328
+ fixable: false,
10329
+ supportedEffect: ["v3", "v4"],
10135
10330
  apply: fn("preferSchemaOverJson.apply")(function* (sourceFile, report) {
10136
10331
  const ts = yield* service(TypeScriptApi);
10137
10332
  const typeParser = yield* service(TypeParser);
@@ -10242,6 +10437,8 @@ var redundantSchemaTagIdentifier = createDiagnostic({
10242
10437
  code: 42,
10243
10438
  description: "Suggests removing redundant identifier argument when it equals the tag value in Schema.TaggedClass/TaggedError/TaggedRequest",
10244
10439
  severity: "suggestion",
10440
+ fixable: true,
10441
+ supportedEffect: ["v3", "v4"],
10245
10442
  apply: fn("redundantSchemaTagIdentifier.apply")(function* (sourceFile, report) {
10246
10443
  const ts = yield* service(TypeScriptApi);
10247
10444
  const typeParser = yield* service(TypeParser);
@@ -10292,6 +10489,8 @@ var returnEffectInGen = createDiagnostic({
10292
10489
  code: 11,
10293
10490
  description: "Warns when returning an Effect in a generator causes nested Effect<Effect<...>>",
10294
10491
  severity: "suggestion",
10492
+ fixable: true,
10493
+ supportedEffect: ["v3", "v4"],
10295
10494
  apply: fn("returnEffectInGen.apply")(function* (sourceFile, report) {
10296
10495
  const ts = yield* service(TypeScriptApi);
10297
10496
  const typeCheckerUtils = yield* service(TypeCheckerUtils);
@@ -10361,6 +10560,8 @@ var runEffectInsideEffect = createDiagnostic({
10361
10560
  code: 32,
10362
10561
  description: "Suggests using Runtime methods instead of Effect.run* inside Effect contexts",
10363
10562
  severity: "suggestion",
10563
+ fixable: true,
10564
+ supportedEffect: ["v3"],
10364
10565
  apply: fn("runEffectInsideEffect.apply")(function* (sourceFile, report) {
10365
10566
  const ts = yield* service(TypeScriptApi);
10366
10567
  const typeParser = yield* service(TypeParser);
@@ -10485,6 +10686,8 @@ var schemaStructWithTag = createDiagnostic({
10485
10686
  code: 34,
10486
10687
  description: "Suggests using Schema.TaggedStruct instead of Schema.Struct with _tag field",
10487
10688
  severity: "suggestion",
10689
+ fixable: true,
10690
+ supportedEffect: ["v3", "v4"],
10488
10691
  apply: fn("schemaStructWithTag.apply")(function* (sourceFile, report) {
10489
10692
  const ts = yield* service(TypeScriptApi);
10490
10693
  const typeParser = yield* service(TypeParser);
@@ -10577,6 +10780,8 @@ var schemaSyncInEffect = createDiagnostic({
10577
10780
  code: 43,
10578
10781
  description: "Suggests using Effect-based Schema methods instead of sync methods inside Effect generators",
10579
10782
  severity: "suggestion",
10783
+ fixable: false,
10784
+ supportedEffect: ["v3", "v4"],
10580
10785
  apply: fn("schemaSyncInEffect.apply")(function* (sourceFile, report) {
10581
10786
  const ts = yield* service(TypeScriptApi);
10582
10787
  const typeParser = yield* service(TypeParser);
@@ -10626,6 +10831,8 @@ var schemaUnionOfLiterals = createDiagnostic({
10626
10831
  code: 33,
10627
10832
  description: "Simplifies Schema.Union of multiple Schema.Literal calls into single Schema.Literal",
10628
10833
  severity: "off",
10834
+ fixable: true,
10835
+ supportedEffect: ["v3"],
10629
10836
  apply: fn("schemaUnionOfLiterals.apply")(function* (sourceFile, report) {
10630
10837
  const ts = yield* service(TypeScriptApi);
10631
10838
  const typeParser = yield* service(TypeParser);
@@ -10701,6 +10908,8 @@ var scopeInLayerEffect = createDiagnostic({
10701
10908
  code: 13,
10702
10909
  description: "Suggests using Layer.scoped instead of Layer.effect when Scope is in requirements",
10703
10910
  severity: "warning",
10911
+ fixable: true,
10912
+ supportedEffect: ["v3"],
10704
10913
  apply: fn("scopeInLayerEffect.apply")(function* (sourceFile, report) {
10705
10914
  const ts = yield* service(TypeScriptApi);
10706
10915
  const tsUtils = yield* service(TypeScriptUtils);
@@ -10790,12 +10999,91 @@ Consider using "scoped" instead to get rid of the scope in the requirements.`,
10790
10999
  })
10791
11000
  });
10792
11001
 
11002
+ // src/diagnostics/serviceNotAsClass.ts
11003
+ var serviceNotAsClass = createDiagnostic({
11004
+ name: "serviceNotAsClass",
11005
+ code: 51,
11006
+ description: "Warns when ServiceMap.Service is used as a variable instead of a class declaration",
11007
+ severity: "off",
11008
+ fixable: true,
11009
+ supportedEffect: ["v4"],
11010
+ apply: fn("serviceNotAsClass.apply")(function* (sourceFile, report) {
11011
+ const ts = yield* service(TypeScriptApi);
11012
+ const typeParser = yield* service(TypeParser);
11013
+ if (typeParser.supportedEffect() === "v3") return;
11014
+ const nodeToVisit = [];
11015
+ const appendNodeToVisit = (node) => {
11016
+ nodeToVisit.push(node);
11017
+ return void 0;
11018
+ };
11019
+ ts.forEachChild(sourceFile, appendNodeToVisit);
11020
+ while (nodeToVisit.length > 0) {
11021
+ const node = nodeToVisit.shift();
11022
+ ts.forEachChild(node, appendNodeToVisit);
11023
+ if (!ts.isVariableDeclaration(node)) continue;
11024
+ if (!node.initializer || !ts.isCallExpression(node.initializer)) continue;
11025
+ const callExpr = node.initializer;
11026
+ if (!callExpr.typeArguments || callExpr.typeArguments.length === 0) continue;
11027
+ const typeArgs = callExpr.typeArguments;
11028
+ const declList = node.parent;
11029
+ if (!ts.isVariableDeclarationList(declList)) continue;
11030
+ if (!(declList.flags & ts.NodeFlags.Const)) continue;
11031
+ const isServiceMapService = yield* pipe(
11032
+ typeParser.isNodeReferenceToServiceMapModuleApi("Service")(callExpr.expression),
11033
+ orUndefined
11034
+ );
11035
+ if (!isServiceMapService) continue;
11036
+ const variableName = ts.isIdentifier(node.name) ? ts.idText(node.name) : sourceFile.text.substring(ts.getTokenPosOfNode(node.name, sourceFile), node.name.end);
11037
+ const variableStatement = declList.parent;
11038
+ const argsText = callExpr.arguments.length > 0 ? callExpr.arguments.map((a) => sourceFile.text.substring(ts.getTokenPosOfNode(a, sourceFile), a.end)).join(", ") : "";
11039
+ const shapeText = typeArgs.length > 0 ? typeArgs.map((t) => sourceFile.text.substring(ts.getTokenPosOfNode(t, sourceFile), t.end)).join(", ") : "Shape";
11040
+ report({
11041
+ location: callExpr,
11042
+ 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, "")}") {}`,
11043
+ fixes: [{
11044
+ fixName: "serviceNotAsClass",
11045
+ description: `Convert to class declaration`,
11046
+ apply: gen(function* () {
11047
+ const changeTracker = yield* service(ChangeTracker);
11048
+ const targetNode = ts.isVariableStatement(variableStatement) ? variableStatement : declList;
11049
+ const innerCall = ts.factory.createCallExpression(
11050
+ callExpr.expression,
11051
+ [ts.factory.createTypeReferenceNode(variableName), ...typeArgs],
11052
+ []
11053
+ );
11054
+ const outerCall = ts.factory.createCallExpression(
11055
+ innerCall,
11056
+ void 0,
11057
+ [...callExpr.arguments]
11058
+ );
11059
+ const heritageClause = ts.factory.createHeritageClause(
11060
+ ts.SyntaxKind.ExtendsKeyword,
11061
+ [ts.factory.createExpressionWithTypeArguments(outerCall, void 0)]
11062
+ );
11063
+ const modifiers = ts.isVariableStatement(variableStatement) ? variableStatement.modifiers : void 0;
11064
+ const classDeclaration = ts.factory.createClassDeclaration(
11065
+ modifiers,
11066
+ ts.isIdentifier(node.name) ? node.name : ts.factory.createIdentifier(variableName),
11067
+ void 0,
11068
+ [heritageClause],
11069
+ []
11070
+ );
11071
+ changeTracker.replaceNode(sourceFile, targetNode, classDeclaration);
11072
+ })
11073
+ }]
11074
+ });
11075
+ }
11076
+ })
11077
+ });
11078
+
10793
11079
  // src/diagnostics/strictBooleanExpressions.ts
10794
11080
  var strictBooleanExpressions = createDiagnostic({
10795
11081
  name: "strictBooleanExpressions",
10796
11082
  code: 17,
10797
11083
  description: "Enforces boolean types in conditional expressions for type safety",
10798
11084
  severity: "off",
11085
+ fixable: false,
11086
+ supportedEffect: ["v3", "v4"],
10799
11087
  apply: fn("strictBooleanExpressions.apply")(function* (sourceFile, report) {
10800
11088
  const ts = yield* service(TypeScriptApi);
10801
11089
  const typeChecker = yield* service(TypeCheckerApi);
@@ -10867,6 +11155,8 @@ var strictEffectProvide = createDiagnostic({
10867
11155
  code: 27,
10868
11156
  description: "Warns when using Effect.provide with layers outside of application entry points",
10869
11157
  severity: "off",
11158
+ fixable: false,
11159
+ supportedEffect: ["v3", "v4"],
10870
11160
  apply: fn("strictEffectProvide.apply")(function* (sourceFile, report) {
10871
11161
  const ts = yield* service(TypeScriptApi);
10872
11162
  const typeCheckerUtils = yield* service(TypeCheckerUtils);
@@ -10918,6 +11208,8 @@ var tryCatchInEffectGen = createDiagnostic({
10918
11208
  code: 15,
10919
11209
  description: "Discourages try/catch in Effect generators in favor of Effect error handling",
10920
11210
  severity: "suggestion",
11211
+ fixable: false,
11212
+ supportedEffect: ["v3", "v4"],
10921
11213
  apply: fn("tryCatchInEffectGen.apply")(function* (sourceFile, report) {
10922
11214
  const ts = yield* service(TypeScriptApi);
10923
11215
  const typeParser = yield* service(TypeParser);
@@ -10975,6 +11267,8 @@ var unknownInEffectCatch = createDiagnostic({
10975
11267
  code: 31,
10976
11268
  description: "Warns when catch callbacks return unknown instead of typed errors",
10977
11269
  severity: "warning",
11270
+ fixable: false,
11271
+ supportedEffect: ["v3", "v4"],
10978
11272
  apply: fn("unknownInEffectCatch.apply")(function* (sourceFile, report) {
10979
11273
  const ts = yield* service(TypeScriptApi);
10980
11274
  const typeParser = yield* service(TypeParser);
@@ -11036,6 +11330,8 @@ var unnecessaryEffectGen = createDiagnostic({
11036
11330
  code: 5,
11037
11331
  description: "Suggests removing Effect.gen when it contains only a single return statement",
11038
11332
  severity: "suggestion",
11333
+ fixable: true,
11334
+ supportedEffect: ["v3", "v4"],
11039
11335
  apply: fn("unnecessaryEffectGen.apply")(function* (sourceFile, report) {
11040
11336
  const ts = yield* service(TypeScriptApi);
11041
11337
  const typeParser = yield* service(TypeParser);
@@ -11080,6 +11376,8 @@ var unnecessaryFailYieldableError = createDiagnostic({
11080
11376
  code: 29,
11081
11377
  description: "Suggests yielding yieldable errors directly instead of wrapping with Effect.fail",
11082
11378
  severity: "suggestion",
11379
+ fixable: true,
11380
+ supportedEffect: ["v3", "v4"],
11083
11381
  apply: fn("unnecessaryFailYieldableError.apply")(function* (sourceFile, report) {
11084
11382
  const ts = yield* service(TypeScriptApi);
11085
11383
  const typeParser = yield* service(TypeParser);
@@ -11139,6 +11437,8 @@ var unnecessaryPipe = createDiagnostic({
11139
11437
  code: 9,
11140
11438
  description: "Removes pipe calls with no arguments",
11141
11439
  severity: "suggestion",
11440
+ fixable: true,
11441
+ supportedEffect: ["v3", "v4"],
11142
11442
  apply: fn("unnecessaryPipe.apply")(function* (sourceFile, report) {
11143
11443
  const ts = yield* service(TypeScriptApi);
11144
11444
  const typeParser = yield* service(TypeParser);
@@ -11185,6 +11485,8 @@ var unnecessaryPipeChain = createDiagnostic({
11185
11485
  code: 16,
11186
11486
  description: "Simplifies chained pipe calls into a single pipe call",
11187
11487
  severity: "suggestion",
11488
+ fixable: true,
11489
+ supportedEffect: ["v3", "v4"],
11188
11490
  apply: fn("unnecessaryPipeChain.apply")(function* (sourceFile, report) {
11189
11491
  const ts = yield* service(TypeScriptApi);
11190
11492
  const typeParser = yield* service(TypeParser);
@@ -11260,6 +11562,8 @@ var unsupportedServiceAccessors = createDiagnostic({
11260
11562
  code: 21,
11261
11563
  description: "Warns about service accessors that need codegen due to generic/complex signatures",
11262
11564
  severity: "warning",
11565
+ fixable: true,
11566
+ supportedEffect: ["v3", "v4"],
11263
11567
  apply: fn("unsupportedServiceAccessors.apply")(function* (sourceFile, report) {
11264
11568
  const ts = yield* service(TypeScriptApi);
11265
11569
  const nodeToVisit = [];
@@ -11362,7 +11666,10 @@ var diagnostics = [
11362
11666
  effectFnOpportunity,
11363
11667
  redundantSchemaTagIdentifier,
11364
11668
  schemaSyncInEffect,
11365
- preferSchemaOverJson
11669
+ preferSchemaOverJson,
11670
+ extendsNativeError,
11671
+ serviceNotAsClass,
11672
+ nodeBuiltinImport
11366
11673
  ];
11367
11674
 
11368
11675
  // src/transform.ts