@effect/language-service 0.84.0 → 0.84.1

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/README.md CHANGED
@@ -81,7 +81,7 @@ Some diagnostics are off by default or have a default severity of suggestion, bu
81
81
  <tr><td><code>leakingRequirements</code></td><td>💡</td><td></td><td>Detects implementation services leaked in service methods</td><td>✓</td><td>✓</td></tr>
82
82
  <tr><td><code>multipleEffectProvide</code></td><td>⚠️</td><td>🔧</td><td>Warns against chaining Effect.provide calls which can cause service lifecycle issues</td><td>✓</td><td>✓</td></tr>
83
83
  <tr><td><code>returnEffectInGen</code></td><td>💡</td><td>🔧</td><td>Warns when returning an Effect in a generator causes nested Effect&lt;Effect&lt;...&gt;&gt;</td><td>✓</td><td>✓</td></tr>
84
- <tr><td><code>runEffectInsideEffect</code></td><td>💡</td><td>🔧</td><td>Suggests using Runtime methods instead of Effect.run* inside Effect contexts</td><td>✓</td><td></td></tr>
84
+ <tr><td><code>runEffectInsideEffect</code></td><td>💡</td><td>🔧</td><td>Suggests using Runtime or Effect.run*With methods instead of Effect.run* inside Effect contexts</td><td>✓</td><td>✓</td></tr>
85
85
  <tr><td><code>schemaSyncInEffect</code></td><td>💡</td><td></td><td>Suggests using Effect-based Schema methods instead of sync methods inside Effect generators</td><td>✓</td><td></td></tr>
86
86
  <tr><td><code>scopeInLayerEffect</code></td><td>⚠️</td><td>🔧</td><td>Suggests using Layer.scoped instead of Layer.effect when Scope is in requirements</td><td>✓</td><td></td></tr>
87
87
  <tr><td><code>strictEffectProvide</code></td><td>➖</td><td></td><td>Warns when using Effect.provide with layers outside of application entry points</td><td>✓</td><td>✓</td></tr>
package/cli.js CHANGED
@@ -25942,7 +25942,7 @@ var runWith2 = (command, config2) => {
25942
25942
  // package.json
25943
25943
  var package_default = {
25944
25944
  name: "@effect/language-service",
25945
- version: "0.84.0",
25945
+ version: "0.84.1",
25946
25946
  publishConfig: {
25947
25947
  access: "public",
25948
25948
  directory: "dist"
@@ -33935,12 +33935,14 @@ var getParameterName = (typescript, name) => {
33935
33935
  }
33936
33936
  return "parameter";
33937
33937
  };
33938
- var hasOuterContextualFunctionType = (typescript, typeChecker, node) => {
33938
+ var hasOuterContextualFunctionType = (typescript, typeChecker, typeCheckerUtils, node) => {
33939
33939
  const contextualType = typeChecker.getContextualType(node);
33940
33940
  if (!contextualType) {
33941
33941
  return false;
33942
33942
  }
33943
- return typeChecker.getSignaturesOfType(contextualType, typescript.SignatureKind.Call).length > 0;
33943
+ return typeCheckerUtils.unrollUnionMembers(contextualType).some(
33944
+ (type) => typeChecker.getSignaturesOfType(type, typescript.SignatureKind.Call).length > 0
33945
+ );
33944
33946
  };
33945
33947
  var effectFnImplicitAny = createDiagnostic({
33946
33948
  name: "effectFnImplicitAny",
@@ -33954,6 +33956,7 @@ var effectFnImplicitAny = createDiagnostic({
33954
33956
  const ts = yield* service2(TypeScriptApi);
33955
33957
  const program = yield* service2(TypeScriptProgram);
33956
33958
  const typeChecker = yield* service2(TypeCheckerApi);
33959
+ const typeCheckerUtils = yield* service2(TypeCheckerUtils);
33957
33960
  const typeParser = yield* service2(TypeParser);
33958
33961
  const noImplicitAny = program.getCompilerOptions().noImplicitAny ?? program.getCompilerOptions().strict ?? false;
33959
33962
  if (!noImplicitAny) {
@@ -33993,7 +33996,7 @@ var effectFnImplicitAny = createDiagnostic({
33993
33996
  ),
33994
33997
  orUndefined
33995
33998
  );
33996
- if (!parsed || hasOuterContextualFunctionType(ts, typeChecker, parsed.call)) {
33999
+ if (!parsed || hasOuterContextualFunctionType(ts, typeChecker, typeCheckerUtils, parsed.call)) {
33997
34000
  continue;
33998
34001
  }
33999
34002
  for (const parameter of parsed.fn.parameters) {
@@ -38088,16 +38091,16 @@ Nested Effect-able types may be intended if you plan to later manually flatten o
38088
38091
  var runEffectInsideEffect = createDiagnostic({
38089
38092
  name: "runEffectInsideEffect",
38090
38093
  code: 32,
38091
- description: "Suggests using Runtime methods instead of Effect.run* inside Effect contexts",
38094
+ description: "Suggests using Runtime or Effect.run*With methods instead of Effect.run* inside Effect contexts",
38092
38095
  group: "antipattern",
38093
38096
  severity: "suggestion",
38094
38097
  fixable: true,
38095
- supportedEffect: ["v3"],
38098
+ supportedEffect: ["v3", "v4"],
38096
38099
  apply: fn3("runEffectInsideEffect.apply")(function* (sourceFile, report) {
38097
38100
  const ts = yield* service2(TypeScriptApi);
38098
38101
  const typeParser = yield* service2(TypeParser);
38099
38102
  const tsUtils = yield* service2(TypeScriptUtils);
38100
- if (typeParser.supportedEffect() === "v4") return;
38103
+ const supportedEffect = typeParser.supportedEffect();
38101
38104
  const parseEffectMethod = (node, methodName) => pipe(
38102
38105
  typeParser.isNodeReferenceToEffectModuleApi(methodName)(node),
38103
38106
  map12(() => ({ node, methodName }))
@@ -38130,9 +38133,10 @@ var runEffectInsideEffect = createDiagnostic({
38130
38133
  if (scopeNode && scopeNode !== effectGen.generatorFunction) {
38131
38134
  const fixAddRuntime = gen3(function* () {
38132
38135
  const changeTracker = yield* service2(ChangeTracker);
38133
- const runtimeModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Runtime") || "Runtime";
38134
38136
  const effectModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Effect") || "Effect";
38137
+ const runtimeModuleIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(sourceFile, "effect", "Runtime") || "Runtime";
38135
38138
  let runtimeIdentifier = void 0;
38139
+ let servicesIdentifier = void 0;
38136
38140
  for (const statement of effectGen.generatorFunction.body.statements) {
38137
38141
  if (ts.isVariableStatement(statement) && statement.declarationList.declarations.length === 1) {
38138
38142
  const declaration = statement.declarationList.declarations[0];
@@ -38146,11 +38150,46 @@ var runEffectInsideEffect = createDiagnostic({
38146
38150
  if (isSome2(maybeEffectRuntime) && ts.isIdentifier(declaration.name)) {
38147
38151
  runtimeIdentifier = ts.idText(declaration.name);
38148
38152
  }
38153
+ const maybeEffectServices = yield* pipe(
38154
+ typeParser.isNodeReferenceToEffectModuleApi("services")(yieldedExpression.expression),
38155
+ option4
38156
+ );
38157
+ if (isSome2(maybeEffectServices) && ts.isIdentifier(declaration.name)) {
38158
+ servicesIdentifier = ts.idText(declaration.name);
38159
+ }
38149
38160
  }
38150
38161
  }
38151
38162
  }
38152
38163
  }
38153
- if (!runtimeIdentifier) {
38164
+ if (supportedEffect === "v4" && !servicesIdentifier) {
38165
+ changeTracker.insertNodeAt(
38166
+ sourceFile,
38167
+ effectGen.body.statements[0].pos,
38168
+ ts.factory.createVariableStatement(
38169
+ void 0,
38170
+ ts.factory.createVariableDeclarationList([ts.factory.createVariableDeclaration(
38171
+ "effectServices",
38172
+ void 0,
38173
+ void 0,
38174
+ ts.factory.createYieldExpression(
38175
+ ts.factory.createToken(ts.SyntaxKind.AsteriskToken),
38176
+ ts.factory.createCallExpression(
38177
+ ts.factory.createPropertyAccessExpression(
38178
+ ts.factory.createIdentifier(effectModuleIdentifier),
38179
+ "services"
38180
+ ),
38181
+ [ts.factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword)],
38182
+ []
38183
+ )
38184
+ )
38185
+ )], ts.NodeFlags.Const)
38186
+ ),
38187
+ {
38188
+ prefix: "\n",
38189
+ suffix: "\n"
38190
+ }
38191
+ );
38192
+ } else if (supportedEffect === "v3" && !runtimeIdentifier) {
38154
38193
  changeTracker.insertNodeAt(
38155
38194
  sourceFile,
38156
38195
  effectGen.body.statements[0].pos,
@@ -38186,16 +38225,19 @@ var runEffectInsideEffect = createDiagnostic({
38186
38225
  changeTracker.insertText(
38187
38226
  sourceFile,
38188
38227
  node.arguments[0].pos,
38189
- `${runtimeModuleIdentifier}.${isEffectRunCall.value.methodName}(${runtimeIdentifier || "effectRuntime"}, `
38228
+ supportedEffect === "v4" ? `${effectModuleIdentifier}.${isEffectRunCall.value.methodName}With(${servicesIdentifier || "effectServices"})(` : `${runtimeModuleIdentifier}.${isEffectRunCall.value.methodName}(${runtimeIdentifier || "effectRuntime"}, `
38190
38229
  );
38191
38230
  });
38231
+ const v4MethodName = `${isEffectRunCall.value.methodName}With`;
38232
+ const messageText = supportedEffect === "v4" ? `Using ${nodeText} inside an Effect is not recommended. The same services should generally be used instead to run child effects.
38233
+ Consider extracting the current services by using for example Effect.services and then use Effect.${v4MethodName} with the extracted services instead.` : `Using ${nodeText} inside an Effect is not recommended. The same runtime should generally be used instead to run child effects.
38234
+ Consider extracting the Runtime by using for example Effect.runtime and then use Runtime.${isEffectRunCall.value.methodName} with the extracted runtime instead.`;
38192
38235
  report({
38193
38236
  location: node.expression,
38194
- messageText: `Using ${nodeText} inside an Effect is not recommended. The same runtime should generally be used instead to run child effects.
38195
- Consider extracting the Runtime by using for example Effect.runtime and then use Runtime.${isEffectRunCall.value.methodName} with the extracted runtime instead.`,
38237
+ messageText,
38196
38238
  fixes: [{
38197
38239
  fixName: "runEffectInsideEffect_fix",
38198
- description: "Use a runtime to run the Effect",
38240
+ description: supportedEffect === "v4" ? "Use the current services to run the Effect" : "Use a runtime to run the Effect",
38199
38241
  apply: fixAddRuntime
38200
38242
  }]
38201
38243
  });
@@ -39861,11 +39903,12 @@ var metadata_default = {
39861
39903
  {
39862
39904
  name: "runEffectInsideEffect",
39863
39905
  group: "antipattern",
39864
- description: "Suggests using Runtime methods instead of Effect.run* inside Effect contexts",
39906
+ description: "Suggests using Runtime or Effect.run*With methods instead of Effect.run* inside Effect contexts",
39865
39907
  defaultSeverity: "suggestion",
39866
39908
  fixable: true,
39867
39909
  supportedEffect: [
39868
- "v3"
39910
+ "v3",
39911
+ "v4"
39869
39912
  ],
39870
39913
  preview: {
39871
39914
  sourceText: 'import { Effect } from "effect"\n\nexport const preview = Effect.gen(function*() {\n const run = () => Effect.runSync(Effect.succeed(1))\n return run()\n})\n',
@@ -39873,7 +39916,7 @@ var metadata_default = {
39873
39916
  {
39874
39917
  start: 101,
39875
39918
  end: 115,
39876
- text: "Using Effect.runSync inside an Effect is not recommended. The same runtime should generally be used instead to run child effects.\nConsider extracting the Runtime by using for example Effect.runtime and then use Runtime.runSync with the extracted runtime instead. effect(runEffectInsideEffect)"
39919
+ text: "Using Effect.runSync inside an Effect is not recommended. The same services should generally be used instead to run child effects.\nConsider extracting the current services by using for example Effect.services and then use Effect.runSyncWith with the extracted services instead. effect(runEffectInsideEffect)"
39877
39920
  }
39878
39921
  ]
39879
39922
  }