@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect/language-service",
3
- "version": "0.56.0",
3
+ "version": "0.57.0",
4
4
  "description": "A Language-Service Plugin to Refactor and Diagnostic effect-ts projects",
5
5
  "main": "index.cjs",
6
6
  "bin": {
package/transform.js CHANGED
@@ -88,6 +88,8 @@ var dual = function(arity, body) {
88
88
  }
89
89
  };
90
90
  var identity = (a) => a;
91
+ var constant = (value) => () => value;
92
+ var constUndefined = /* @__PURE__ */ constant(void 0);
91
93
  function pipe(a, ab, bc, cd, de, ef, fg, gh, hi) {
92
94
  switch (arguments.length) {
93
95
  case 1:
@@ -736,8 +738,10 @@ var none2 = () => none;
736
738
  var some2 = some;
737
739
  var isNone2 = isNone;
738
740
  var isSome2 = isSome;
741
+ var getOrElse2 = /* @__PURE__ */ dual(2, (self, onNone) => isNone2(self) ? onNone() : self.value);
739
742
  var orElse = /* @__PURE__ */ dual(2, (self, that) => isNone2(self) ? that() : self);
740
743
  var fromNullable = (nullableValue) => nullableValue == null ? none2() : some2(nullableValue);
744
+ var getOrUndefined = /* @__PURE__ */ getOrElse2(constUndefined);
741
745
 
742
746
  // node_modules/.pnpm/effect@3.19.0/node_modules/effect/dist/esm/Record.js
743
747
  var map2 = /* @__PURE__ */ dual(2, (self, f) => {
@@ -2597,6 +2601,51 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
2597
2601
  if (!symbol3) return typeParserIssue("Node has no symbol", void 0, givenNode);
2598
2602
  return isSymbolExportOfPackageModule(symbol3, packageName, memberName, isCorrectSourceFile);
2599
2603
  };
2604
+ const findSymbolsMatchingPackageAndExportedName = (packageName, exportedSymbolName) => cachedBy(
2605
+ fn("TypeParser.findSymbolsMatchingPackageAndExportedName")(function* (_fromSourceFile) {
2606
+ const result = [];
2607
+ for (const sourceFile of program.getSourceFiles()) {
2608
+ const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
2609
+ if (!moduleSymbol) continue;
2610
+ const symbol3 = typeChecker.tryGetMemberInModuleExports(exportedSymbolName, moduleSymbol);
2611
+ if (!symbol3) continue;
2612
+ const packageInfo = yield* getSourceFilePackageInfo(sourceFile);
2613
+ if (!packageInfo || packageInfo.name.toLowerCase() !== packageName.toLowerCase()) continue;
2614
+ result.push([symbol3, sourceFile]);
2615
+ }
2616
+ return result;
2617
+ }),
2618
+ `TypeParser.findSymbolsMatchingPackageAndExportedName(${packageName}, ${exportedSymbolName})`,
2619
+ (sourceFile) => sourceFile
2620
+ );
2621
+ const isCauseTypeSourceFile = cachedBy(
2622
+ fn("TypeParser.isCauseTypeSourceFile")(function* (sourceFile) {
2623
+ const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
2624
+ if (!moduleSymbol) return yield* typeParserIssue("Node has no symbol", void 0, sourceFile);
2625
+ const causeTypeSymbol = typeChecker.tryGetMemberInModuleExports("Cause", moduleSymbol);
2626
+ if (!causeTypeSymbol) return yield* typeParserIssue("Cause type not found", void 0, sourceFile);
2627
+ const type = typeChecker.getDeclaredTypeOfSymbol(causeTypeSymbol);
2628
+ yield* pipeableType(type, sourceFile);
2629
+ return sourceFile;
2630
+ }),
2631
+ "TypeParser.isCauseTypeSourceFile",
2632
+ (sourceFile) => sourceFile
2633
+ );
2634
+ const effectCauseYieldableErrorTypes = cachedBy(
2635
+ fn("TypeParser.effectCauseYieldableErrorTypes")(function* (fromSourceFile) {
2636
+ const symbols = yield* findSymbolsMatchingPackageAndExportedName("effect", "YieldableError")(fromSourceFile);
2637
+ const result = [];
2638
+ for (const [symbol3, sourceFile] of symbols) {
2639
+ const causeFile = yield* isCauseTypeSourceFile(sourceFile);
2640
+ if (!causeFile) continue;
2641
+ const type = typeChecker.getDeclaredTypeOfSymbol(symbol3);
2642
+ result.push(type);
2643
+ }
2644
+ return result;
2645
+ }),
2646
+ "TypeParser.effectCauseYieldableErrorTypes",
2647
+ (fromSourceFile) => fromSourceFile
2648
+ );
2600
2649
  function covariantTypeArgument(type) {
2601
2650
  const signatures = typeChecker.getSignaturesOfType(type, ts.SignatureKind.Call);
2602
2651
  if (signatures.length !== 1) {
@@ -3586,6 +3635,7 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3586
3635
  effectGen,
3587
3636
  effectFnUntracedGen,
3588
3637
  effectFnGen,
3638
+ effectCauseYieldableErrorTypes,
3589
3639
  unnecessaryEffectGen: unnecessaryEffectGen2,
3590
3640
  effectSchemaType,
3591
3641
  contextTag,
@@ -5504,8 +5554,93 @@ var accessors = createCodegen({
5504
5554
  })
5505
5555
  });
5506
5556
 
5557
+ // src/codegens/annotate.ts
5558
+ var annotate = createCodegen({
5559
+ name: "annotate",
5560
+ apply: fn("annotate.apply")(function* (sourceFile, textRange) {
5561
+ const ts = yield* service(TypeScriptApi);
5562
+ const tsUtils = yield* service(TypeScriptUtils);
5563
+ const typeChecker = yield* service(TypeCheckerApi);
5564
+ const typeCheckerUtils = yield* service(TypeCheckerUtils);
5565
+ const parse3 = (node) => gen(function* () {
5566
+ let variableDeclarations = [];
5567
+ const result = [];
5568
+ if (ts.isVariableStatement(node)) {
5569
+ variableDeclarations = [...variableDeclarations, ...node.declarationList.declarations];
5570
+ } else if (ts.isVariableDeclarationList(node)) {
5571
+ variableDeclarations = [...variableDeclarations, ...node.declarations];
5572
+ } else if (ts.isVariableDeclaration(node)) {
5573
+ variableDeclarations = [...variableDeclarations, node];
5574
+ }
5575
+ if (variableDeclarations.length === 0) {
5576
+ return yield* fail(new CodegenNotApplicableError("not a variable declaration"));
5577
+ }
5578
+ for (const variableDeclaration of variableDeclarations) {
5579
+ if (!variableDeclaration.initializer) continue;
5580
+ const initializerType = typeChecker.getTypeAtLocation(variableDeclaration.initializer);
5581
+ const initializerTypeNode = fromNullable(typeCheckerUtils.typeToSimplifiedTypeNode(
5582
+ initializerType,
5583
+ node,
5584
+ ts.NodeBuilderFlags.NoTruncation
5585
+ )).pipe(
5586
+ orElse(
5587
+ () => fromNullable(typeCheckerUtils.typeToSimplifiedTypeNode(
5588
+ initializerType,
5589
+ void 0,
5590
+ ts.NodeBuilderFlags.NoTruncation
5591
+ ))
5592
+ ),
5593
+ getOrUndefined
5594
+ );
5595
+ if (!initializerTypeNode) continue;
5596
+ const typeNodeString = typeChecker.typeToString(initializerType, void 0, ts.TypeFormatFlags.NoTruncation);
5597
+ const hash3 = cyrb53(typeNodeString);
5598
+ result.push({ variableDeclaration, initializerTypeNode, hash: hash3 });
5599
+ }
5600
+ if (result.length === 0) {
5601
+ return yield* fail(new CodegenNotApplicableError("no variable declarations with initializers"));
5602
+ }
5603
+ const hash2 = cyrb53(result.map((_) => _.hash).join("/"));
5604
+ return {
5605
+ hash: hash2,
5606
+ result
5607
+ };
5608
+ });
5609
+ const nodeAndCommentRange = tsUtils.findNodeWithLeadingCommentAtPosition(sourceFile, textRange.pos);
5610
+ if (!nodeAndCommentRange) return yield* fail(new CodegenNotApplicableError("no node and comment range"));
5611
+ return yield* pipe(
5612
+ parse3(nodeAndCommentRange.node),
5613
+ map4(
5614
+ (_) => ({
5615
+ hash: _.hash,
5616
+ description: "Annotate with type",
5617
+ apply: gen(function* () {
5618
+ const changeTracker = yield* service(ChangeTracker);
5619
+ for (const { initializerTypeNode, variableDeclaration } of _.result) {
5620
+ if (variableDeclaration.type) {
5621
+ changeTracker.deleteRange(sourceFile, {
5622
+ pos: variableDeclaration.name.end,
5623
+ end: variableDeclaration.type.end
5624
+ });
5625
+ }
5626
+ changeTracker.insertNodeAt(
5627
+ sourceFile,
5628
+ variableDeclaration.name.end,
5629
+ initializerTypeNode,
5630
+ {
5631
+ prefix: ": "
5632
+ }
5633
+ );
5634
+ }
5635
+ })
5636
+ })
5637
+ )
5638
+ );
5639
+ })
5640
+ });
5641
+
5507
5642
  // src/codegens.ts
5508
- var codegens = [accessors];
5643
+ var codegens = [accessors, annotate];
5509
5644
 
5510
5645
  // src/diagnostics/outdatedEffectCodegen.ts
5511
5646
  var outdatedEffectCodegen = createDiagnostic({
@@ -6237,6 +6372,66 @@ var unnecessaryEffectGen = createDiagnostic({
6237
6372
  })
6238
6373
  });
6239
6374
 
6375
+ // src/diagnostics/unnecessaryFailYieldableError.ts
6376
+ var unnecessaryFailYieldableError = createDiagnostic({
6377
+ name: "unnecessaryFailYieldableError",
6378
+ code: 29,
6379
+ severity: "suggestion",
6380
+ apply: fn("unnecessaryFailYieldableError.apply")(function* (sourceFile, report) {
6381
+ const ts = yield* service(TypeScriptApi);
6382
+ const typeParser = yield* service(TypeParser);
6383
+ const typeChecker = yield* service(TypeCheckerApi);
6384
+ const yieldableErrorTypes = yield* pipe(
6385
+ typeParser.effectCauseYieldableErrorTypes(sourceFile),
6386
+ orElse2(() => succeed([]))
6387
+ );
6388
+ const nodeToVisit = [];
6389
+ const appendNodeToVisit = (node) => {
6390
+ nodeToVisit.push(node);
6391
+ return void 0;
6392
+ };
6393
+ ts.forEachChild(sourceFile, appendNodeToVisit);
6394
+ while (nodeToVisit.length > 0) {
6395
+ const node = nodeToVisit.shift();
6396
+ ts.forEachChild(node, appendNodeToVisit);
6397
+ if (ts.isYieldExpression(node) && node.asteriskToken && node.expression && ts.isCallExpression(node.expression)) {
6398
+ const callExpression = node.expression;
6399
+ yield* pipe(
6400
+ typeParser.isNodeReferenceToEffectModuleApi("fail")(callExpression.expression),
6401
+ map4(() => {
6402
+ if (callExpression.arguments.length > 0) {
6403
+ const failArgument = callExpression.arguments[0];
6404
+ const argumentType = typeChecker.getTypeAtLocation(failArgument);
6405
+ const isYieldableError = yieldableErrorTypes.some(
6406
+ (yieldableType) => typeChecker.isTypeAssignableTo(argumentType, yieldableType)
6407
+ );
6408
+ if (isYieldableError) {
6409
+ report({
6410
+ location: node,
6411
+ messageText: `This Effect.fail call uses a yieldable error type as argument. You can yield* the error directly instead.`,
6412
+ fixes: [{
6413
+ fixName: "unnecessaryFailYieldableError_fix",
6414
+ description: "Replace yield* Effect.fail with yield*",
6415
+ apply: gen(function* () {
6416
+ const changeTracker = yield* service(ChangeTracker);
6417
+ changeTracker.replaceNode(
6418
+ sourceFile,
6419
+ callExpression,
6420
+ failArgument
6421
+ );
6422
+ })
6423
+ }]
6424
+ });
6425
+ }
6426
+ }
6427
+ }),
6428
+ ignore
6429
+ );
6430
+ }
6431
+ }
6432
+ })
6433
+ });
6434
+
6240
6435
  // src/diagnostics/unnecessaryPipe.ts
6241
6436
  var unnecessaryPipe = createDiagnostic({
6242
6437
  name: "unnecessaryPipe",
@@ -6424,6 +6619,7 @@ var diagnostics = [
6424
6619
  floatingEffect,
6425
6620
  missingStarInYieldEffectGen,
6426
6621
  unnecessaryEffectGen,
6622
+ unnecessaryFailYieldableError,
6427
6623
  missingReturnYieldStar,
6428
6624
  leakingRequirements,
6429
6625
  unnecessaryPipe,