@effect/language-service 0.56.0 → 0.57.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/index.js CHANGED
@@ -2799,6 +2799,51 @@ function make3(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
2799
2799
  if (!symbol3) return typeParserIssue("Node has no symbol", void 0, givenNode);
2800
2800
  return isSymbolExportOfPackageModule(symbol3, packageName, memberName, isCorrectSourceFile);
2801
2801
  };
2802
+ const findSymbolsMatchingPackageAndExportedName = (packageName, exportedSymbolName) => cachedBy(
2803
+ fn("TypeParser.findSymbolsMatchingPackageAndExportedName")(function* (_fromSourceFile) {
2804
+ const result = [];
2805
+ for (const sourceFile of program.getSourceFiles()) {
2806
+ const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
2807
+ if (!moduleSymbol) continue;
2808
+ const symbol3 = typeChecker.tryGetMemberInModuleExports(exportedSymbolName, moduleSymbol);
2809
+ if (!symbol3) continue;
2810
+ const packageInfo = yield* getSourceFilePackageInfo(sourceFile);
2811
+ if (!packageInfo || packageInfo.name.toLowerCase() !== packageName.toLowerCase()) continue;
2812
+ result.push([symbol3, sourceFile]);
2813
+ }
2814
+ return result;
2815
+ }),
2816
+ `TypeParser.findSymbolsMatchingPackageAndExportedName(${packageName}, ${exportedSymbolName})`,
2817
+ (sourceFile) => sourceFile
2818
+ );
2819
+ const isCauseTypeSourceFile = cachedBy(
2820
+ fn("TypeParser.isCauseTypeSourceFile")(function* (sourceFile) {
2821
+ const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
2822
+ if (!moduleSymbol) return yield* typeParserIssue("Node has no symbol", void 0, sourceFile);
2823
+ const causeTypeSymbol = typeChecker.tryGetMemberInModuleExports("Cause", moduleSymbol);
2824
+ if (!causeTypeSymbol) return yield* typeParserIssue("Cause type not found", void 0, sourceFile);
2825
+ const type = typeChecker.getDeclaredTypeOfSymbol(causeTypeSymbol);
2826
+ yield* pipeableType(type, sourceFile);
2827
+ return sourceFile;
2828
+ }),
2829
+ "TypeParser.isCauseTypeSourceFile",
2830
+ (sourceFile) => sourceFile
2831
+ );
2832
+ const effectCauseYieldableErrorTypes = cachedBy(
2833
+ fn("TypeParser.effectCauseYieldableErrorTypes")(function* (fromSourceFile) {
2834
+ const symbols = yield* findSymbolsMatchingPackageAndExportedName("effect", "YieldableError")(fromSourceFile);
2835
+ const result = [];
2836
+ for (const [symbol3, sourceFile] of symbols) {
2837
+ const causeFile = yield* isCauseTypeSourceFile(sourceFile);
2838
+ if (!causeFile) continue;
2839
+ const type = typeChecker.getDeclaredTypeOfSymbol(symbol3);
2840
+ result.push(type);
2841
+ }
2842
+ return result;
2843
+ }),
2844
+ "TypeParser.effectCauseYieldableErrorTypes",
2845
+ (fromSourceFile) => fromSourceFile
2846
+ );
2802
2847
  function covariantTypeArgument(type) {
2803
2848
  const signatures = typeChecker.getSignaturesOfType(type, ts.SignatureKind.Call);
2804
2849
  if (signatures.length !== 1) {
@@ -3788,6 +3833,7 @@ function make3(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3788
3833
  effectGen,
3789
3834
  effectFnUntracedGen,
3790
3835
  effectFnGen,
3836
+ effectCauseYieldableErrorTypes,
3791
3837
  unnecessaryEffectGen: unnecessaryEffectGen2,
3792
3838
  effectSchemaType,
3793
3839
  contextTag,
@@ -4098,8 +4144,93 @@ var accessors = createCodegen({
4098
4144
  })
4099
4145
  });
4100
4146
 
4147
+ // src/codegens/annotate.ts
4148
+ var annotate = createCodegen({
4149
+ name: "annotate",
4150
+ apply: fn("annotate.apply")(function* (sourceFile, textRange) {
4151
+ const ts = yield* service(TypeScriptApi);
4152
+ const tsUtils = yield* service(TypeScriptUtils);
4153
+ const typeChecker = yield* service(TypeCheckerApi);
4154
+ const typeCheckerUtils = yield* service(TypeCheckerUtils);
4155
+ const parse3 = (node) => gen(function* () {
4156
+ let variableDeclarations = [];
4157
+ const result = [];
4158
+ if (ts.isVariableStatement(node)) {
4159
+ variableDeclarations = [...variableDeclarations, ...node.declarationList.declarations];
4160
+ } else if (ts.isVariableDeclarationList(node)) {
4161
+ variableDeclarations = [...variableDeclarations, ...node.declarations];
4162
+ } else if (ts.isVariableDeclaration(node)) {
4163
+ variableDeclarations = [...variableDeclarations, node];
4164
+ }
4165
+ if (variableDeclarations.length === 0) {
4166
+ return yield* fail(new CodegenNotApplicableError("not a variable declaration"));
4167
+ }
4168
+ for (const variableDeclaration of variableDeclarations) {
4169
+ if (!variableDeclaration.initializer) continue;
4170
+ const initializerType = typeChecker.getTypeAtLocation(variableDeclaration.initializer);
4171
+ const initializerTypeNode = fromNullable(typeCheckerUtils.typeToSimplifiedTypeNode(
4172
+ initializerType,
4173
+ node,
4174
+ ts.NodeBuilderFlags.NoTruncation
4175
+ )).pipe(
4176
+ orElse(
4177
+ () => fromNullable(typeCheckerUtils.typeToSimplifiedTypeNode(
4178
+ initializerType,
4179
+ void 0,
4180
+ ts.NodeBuilderFlags.NoTruncation
4181
+ ))
4182
+ ),
4183
+ getOrUndefined
4184
+ );
4185
+ if (!initializerTypeNode) continue;
4186
+ const typeNodeString = typeChecker.typeToString(initializerType, void 0, ts.TypeFormatFlags.NoTruncation);
4187
+ const hash3 = cyrb53(typeNodeString);
4188
+ result.push({ variableDeclaration, initializerTypeNode, hash: hash3 });
4189
+ }
4190
+ if (result.length === 0) {
4191
+ return yield* fail(new CodegenNotApplicableError("no variable declarations with initializers"));
4192
+ }
4193
+ const hash2 = cyrb53(result.map((_) => _.hash).join("/"));
4194
+ return {
4195
+ hash: hash2,
4196
+ result
4197
+ };
4198
+ });
4199
+ const nodeAndCommentRange = tsUtils.findNodeWithLeadingCommentAtPosition(sourceFile, textRange.pos);
4200
+ if (!nodeAndCommentRange) return yield* fail(new CodegenNotApplicableError("no node and comment range"));
4201
+ return yield* pipe(
4202
+ parse3(nodeAndCommentRange.node),
4203
+ map5(
4204
+ (_) => ({
4205
+ hash: _.hash,
4206
+ description: "Annotate with type",
4207
+ apply: gen(function* () {
4208
+ const changeTracker = yield* service(ChangeTracker);
4209
+ for (const { initializerTypeNode, variableDeclaration } of _.result) {
4210
+ if (variableDeclaration.type) {
4211
+ changeTracker.deleteRange(sourceFile, {
4212
+ pos: variableDeclaration.name.end,
4213
+ end: variableDeclaration.type.end
4214
+ });
4215
+ }
4216
+ changeTracker.insertNodeAt(
4217
+ sourceFile,
4218
+ variableDeclaration.name.end,
4219
+ initializerTypeNode,
4220
+ {
4221
+ prefix: ": "
4222
+ }
4223
+ );
4224
+ }
4225
+ })
4226
+ })
4227
+ )
4228
+ );
4229
+ })
4230
+ });
4231
+
4101
4232
  // src/codegens.ts
4102
- var codegens = [accessors];
4233
+ var codegens = [accessors, annotate];
4103
4234
 
4104
4235
  // src/completions/effectCodegensComment.ts
4105
4236
  var effectCodegensComment = createCompletion({
@@ -8711,6 +8842,66 @@ var unnecessaryEffectGen = createDiagnostic({
8711
8842
  })
8712
8843
  });
8713
8844
 
8845
+ // src/diagnostics/unnecessaryFailYieldableError.ts
8846
+ var unnecessaryFailYieldableError = createDiagnostic({
8847
+ name: "unnecessaryFailYieldableError",
8848
+ code: 29,
8849
+ severity: "suggestion",
8850
+ apply: fn("unnecessaryFailYieldableError.apply")(function* (sourceFile, report) {
8851
+ const ts = yield* service(TypeScriptApi);
8852
+ const typeParser = yield* service(TypeParser);
8853
+ const typeChecker = yield* service(TypeCheckerApi);
8854
+ const yieldableErrorTypes = yield* pipe(
8855
+ typeParser.effectCauseYieldableErrorTypes(sourceFile),
8856
+ orElse2(() => succeed([]))
8857
+ );
8858
+ const nodeToVisit = [];
8859
+ const appendNodeToVisit = (node) => {
8860
+ nodeToVisit.push(node);
8861
+ return void 0;
8862
+ };
8863
+ ts.forEachChild(sourceFile, appendNodeToVisit);
8864
+ while (nodeToVisit.length > 0) {
8865
+ const node = nodeToVisit.shift();
8866
+ ts.forEachChild(node, appendNodeToVisit);
8867
+ if (ts.isYieldExpression(node) && node.asteriskToken && node.expression && ts.isCallExpression(node.expression)) {
8868
+ const callExpression = node.expression;
8869
+ yield* pipe(
8870
+ typeParser.isNodeReferenceToEffectModuleApi("fail")(callExpression.expression),
8871
+ map5(() => {
8872
+ if (callExpression.arguments.length > 0) {
8873
+ const failArgument = callExpression.arguments[0];
8874
+ const argumentType = typeChecker.getTypeAtLocation(failArgument);
8875
+ const isYieldableError = yieldableErrorTypes.some(
8876
+ (yieldableType) => typeChecker.isTypeAssignableTo(argumentType, yieldableType)
8877
+ );
8878
+ if (isYieldableError) {
8879
+ report({
8880
+ location: node,
8881
+ messageText: `This Effect.fail call uses a yieldable error type as argument. You can yield* the error directly instead.`,
8882
+ fixes: [{
8883
+ fixName: "unnecessaryFailYieldableError_fix",
8884
+ description: "Replace yield* Effect.fail with yield*",
8885
+ apply: gen(function* () {
8886
+ const changeTracker = yield* service(ChangeTracker);
8887
+ changeTracker.replaceNode(
8888
+ sourceFile,
8889
+ callExpression,
8890
+ failArgument
8891
+ );
8892
+ })
8893
+ }]
8894
+ });
8895
+ }
8896
+ }
8897
+ }),
8898
+ ignore
8899
+ );
8900
+ }
8901
+ }
8902
+ })
8903
+ });
8904
+
8714
8905
  // src/diagnostics/unnecessaryPipe.ts
8715
8906
  var unnecessaryPipe = createDiagnostic({
8716
8907
  name: "unnecessaryPipe",
@@ -8898,6 +9089,7 @@ var diagnostics = [
8898
9089
  floatingEffect,
8899
9090
  missingStarInYieldEffectGen,
8900
9091
  unnecessaryEffectGen,
9092
+ unnecessaryFailYieldableError,
8901
9093
  missingReturnYieldStar,
8902
9094
  leakingRequirements,
8903
9095
  unnecessaryPipe,