@effect/language-service 0.58.3 → 0.59.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.58.3",
3
+ "version": "0.59.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
@@ -2576,7 +2576,16 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
2576
2576
  const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
2577
2577
  if (!moduleSymbol) continue;
2578
2578
  const memberSymbol = typeChecker.tryGetMemberInModuleExports(memberName, moduleSymbol);
2579
- if (memberSymbol && memberSymbol === symbol3) result.push({ memberSymbol, moduleSymbol, sourceFile });
2579
+ if (memberSymbol) {
2580
+ if (memberSymbol === symbol3) {
2581
+ result.push({ memberSymbol, moduleSymbol, sourceFile });
2582
+ } else if (memberSymbol.flags & ts.SymbolFlags.Alias) {
2583
+ const aliased = typeChecker.getAliasedSymbol(memberSymbol);
2584
+ if (aliased === symbol3) {
2585
+ result.push({ memberSymbol, moduleSymbol, sourceFile });
2586
+ }
2587
+ }
2588
+ }
2580
2589
  }
2581
2590
  if (result.length > 0) {
2582
2591
  return result;
@@ -2831,67 +2840,69 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
2831
2840
  "TypeParser.effectSubtype",
2832
2841
  (type) => type
2833
2842
  );
2834
- const importedContextModule = cachedBy(
2835
- fn("TypeParser.importedContextModule")(function* (node) {
2836
- if (!ts.isIdentifier(node)) {
2837
- return yield* typeParserIssue("Node is not an identifier", void 0, node);
2838
- }
2839
- const type = typeChecker.getTypeAtLocation(node);
2840
- const propertySymbol = typeChecker.getPropertyOfType(type, "Tag");
2841
- if (!propertySymbol) {
2842
- return yield* typeParserIssue("Type has no 'Tag' property", type, node);
2843
- }
2844
- const sourceFile = tsUtils.getSourceFileOfNode(node);
2845
- if (!sourceFile) {
2846
- return yield* typeParserIssue("Node is not in a source file", void 0, node);
2847
- }
2848
- const contextIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
2849
- sourceFile,
2850
- "effect",
2851
- "Context"
2852
- );
2853
- if (!contextIdentifier) {
2854
- return yield* typeParserIssue("Context module not found", void 0, node);
2855
- }
2856
- if (ts.idText(node) !== contextIdentifier) {
2857
- return yield* typeParserIssue("Node is not a context module reference", void 0, node);
2858
- }
2859
- return node;
2843
+ const isEffectContextSourceFile = cachedBy(
2844
+ fn("TypeParser.isEffectContextSourceFile")(function* (sourceFile) {
2845
+ const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
2846
+ if (!moduleSymbol) return yield* typeParserIssue("Node has no symbol", void 0, sourceFile);
2847
+ const contextSymbol = typeChecker.tryGetMemberInModuleExports("Context", moduleSymbol);
2848
+ if (!contextSymbol) return yield* typeParserIssue("Context not found", void 0, sourceFile);
2849
+ const tagSymbol = typeChecker.tryGetMemberInModuleExports("Tag", moduleSymbol);
2850
+ if (!tagSymbol) return yield* typeParserIssue("Tag not found", void 0, sourceFile);
2851
+ const tagType = typeChecker.getDeclaredTypeOfSymbol(tagSymbol);
2852
+ yield* contextTag(tagType, sourceFile);
2853
+ return sourceFile;
2854
+ }),
2855
+ "TypeParser.isEffectContextSourceFile",
2856
+ (sourceFile) => sourceFile
2857
+ );
2858
+ const isNodeReferenceToEffectContextModuleApi = (memberName) => cachedBy(
2859
+ fn("TypeParser.isNodeReferenceToEffectContextModuleApi")(function* (node) {
2860
+ return yield* isNodeReferenceToExportOfPackageModule(node, "effect", isEffectContextSourceFile, memberName);
2860
2861
  }),
2862
+ `TypeParser.isNodeReferenceToEffectContextModuleApi(${memberName})`,
2863
+ (node) => node
2864
+ );
2865
+ const importedContextModule = cachedBy(
2866
+ (node) => pipe(
2867
+ isNodeReferenceToPackageModule(node, "effect", isEffectContextSourceFile),
2868
+ map4(() => node)
2869
+ ),
2861
2870
  "TypeParser.importedContextModule",
2862
2871
  (node) => node
2863
2872
  );
2864
- const importedEffectModule = (node) => pipe(
2865
- isNodeReferenceToPackageModule(node, "effect", isEffectTypeSourceFile),
2866
- map4(() => node)
2873
+ const importedEffectModule = cachedBy(
2874
+ (node) => pipe(
2875
+ isNodeReferenceToPackageModule(node, "effect", isEffectTypeSourceFile),
2876
+ map4(() => node)
2877
+ ),
2878
+ "TypeParser.importedEffectModule",
2879
+ (node) => node
2867
2880
  );
2868
- const importedDataModule = cachedBy(
2869
- fn("TypeParser.importedDataModule")(function* (node) {
2870
- if (!ts.isIdentifier(node)) {
2871
- return yield* typeParserIssue("Node is not an expression", void 0, node);
2872
- }
2873
- const type = typeChecker.getTypeAtLocation(node);
2874
- const propertySymbol = typeChecker.getPropertyOfType(type, "TaggedError");
2875
- if (!propertySymbol) {
2876
- return yield* typeParserIssue("Type has no 'TaggedError' property", type, node);
2877
- }
2878
- const sourceFile = tsUtils.getSourceFileOfNode(node);
2879
- if (!sourceFile) {
2880
- return yield* typeParserIssue("Node is not in a source file", void 0, node);
2881
- }
2882
- const dataIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
2883
- sourceFile,
2884
- "effect",
2885
- "Data"
2886
- );
2887
- if (!dataIdentifier) {
2888
- return yield* typeParserIssue("Data module not found", void 0, node);
2889
- }
2890
- if (ts.idText(node) !== dataIdentifier) {
2891
- return yield* typeParserIssue("Node is not a data module reference", void 0, node);
2892
- }
2893
- return node;
2881
+ const isEffectDataSourceFile = cachedBy(
2882
+ fn("TypeParser.isEffectDataSourceFile")(function* (sourceFile) {
2883
+ const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
2884
+ if (!moduleSymbol) return yield* typeParserIssue("Node has no symbol", void 0, sourceFile);
2885
+ const taggedEnumSymbol = typeChecker.tryGetMemberInModuleExports("TaggedEnum", moduleSymbol);
2886
+ if (!taggedEnumSymbol) return yield* typeParserIssue("TaggedEnum not found", void 0, sourceFile);
2887
+ const taggedErrorSymbol = typeChecker.tryGetMemberInModuleExports("TaggedError", moduleSymbol);
2888
+ if (!taggedErrorSymbol) return yield* typeParserIssue("TaggedError not found", void 0, sourceFile);
2889
+ return sourceFile;
2894
2890
  }),
2891
+ "TypeParser.isEffectDataSourceFile",
2892
+ (sourceFile) => sourceFile
2893
+ );
2894
+ const isNodeReferenceToEffectDataModuleApi = (memberName) => cachedBy(
2895
+ fn("TypeParser.isNodeReferenceToEffectDataModuleApi")(function* (node) {
2896
+ return yield* isNodeReferenceToExportOfPackageModule(node, "effect", isEffectDataSourceFile, memberName);
2897
+ }),
2898
+ `TypeParser.isNodeReferenceToEffectDataModuleApi(${memberName})`,
2899
+ (node) => node
2900
+ );
2901
+ const importedDataModule = cachedBy(
2902
+ (node) => pipe(
2903
+ isNodeReferenceToPackageModule(node, "effect", isEffectDataSourceFile),
2904
+ map4(() => node)
2905
+ ),
2895
2906
  "TypeParser.importedDataModule",
2896
2907
  (node) => node
2897
2908
  );
@@ -3630,6 +3641,8 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3630
3641
  return {
3631
3642
  isNodeReferenceToEffectModuleApi,
3632
3643
  isNodeReferenceToEffectSchemaModuleApi,
3644
+ isNodeReferenceToEffectDataModuleApi,
3645
+ isNodeReferenceToEffectContextModuleApi,
3633
3646
  effectType,
3634
3647
  strictEffectType,
3635
3648
  layerType,
@@ -5593,7 +5606,7 @@ var annotate = createCodegen({
5593
5606
  const initializerTypeNode = fromNullable(typeCheckerUtils.typeToSimplifiedTypeNode(
5594
5607
  initializerType,
5595
5608
  enclosingNode,
5596
- ts.NodeBuilderFlags.NoTruncation
5609
+ ts.NodeBuilderFlags.NoTruncation | ts.NodeBuilderFlags.IgnoreErrors
5597
5610
  )).pipe(
5598
5611
  getOrUndefined
5599
5612
  );
@@ -6033,6 +6046,85 @@ Consider extracting the Runtime by using for example Effect.runtime and then use
6033
6046
  })
6034
6047
  });
6035
6048
 
6049
+ // src/diagnostics/schemaStructWithTag.ts
6050
+ var schemaStructWithTag = createDiagnostic({
6051
+ name: "schemaStructWithTag",
6052
+ code: 34,
6053
+ severity: "suggestion",
6054
+ apply: fn("schemaStructWithTag.apply")(function* (sourceFile, report) {
6055
+ const ts = yield* service(TypeScriptApi);
6056
+ const typeParser = yield* service(TypeParser);
6057
+ const nodeToVisit = [];
6058
+ const appendNodeToVisit = (node) => {
6059
+ nodeToVisit.push(node);
6060
+ return void 0;
6061
+ };
6062
+ ts.forEachChild(sourceFile, appendNodeToVisit);
6063
+ while (nodeToVisit.length > 0) {
6064
+ const node = nodeToVisit.shift();
6065
+ if (ts.isCallExpression(node)) {
6066
+ const isSchemaStructCall = yield* pipe(
6067
+ typeParser.isNodeReferenceToEffectSchemaModuleApi("Struct")(node.expression),
6068
+ orElse2(() => void_)
6069
+ );
6070
+ if (isSchemaStructCall && node.arguments.length === 1) {
6071
+ const arg = node.arguments[0];
6072
+ if (ts.isObjectLiteralExpression(arg)) {
6073
+ const tagProperty = arg.properties.find(
6074
+ (prop) => ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && ts.idText(prop.name) === "_tag"
6075
+ );
6076
+ if (tagProperty && ts.isCallExpression(tagProperty.initializer)) {
6077
+ const isSchemaLiteralCall = yield* pipe(
6078
+ typeParser.isNodeReferenceToEffectSchemaModuleApi("Literal")(
6079
+ tagProperty.initializer.expression
6080
+ ),
6081
+ option
6082
+ );
6083
+ if (isSchemaLiteralCall._tag === "Some") {
6084
+ const literalCall = tagProperty.initializer;
6085
+ const literalArgs = fromIterable(literalCall.arguments);
6086
+ if (literalArgs.length === 1 && ts.isStringLiteral(literalArgs[0])) {
6087
+ const tagValue = literalArgs[0].text;
6088
+ const otherProperties = arg.properties.filter((prop) => prop !== tagProperty);
6089
+ report({
6090
+ location: node,
6091
+ messageText: "Schema.Struct with a _tag field can be simplified to Schema.TaggedStruct to make the tag optional in the constructor.",
6092
+ fixes: [{
6093
+ fixName: "schemaStructWithTag_fix",
6094
+ description: "Replace with Schema.TaggedStruct",
6095
+ apply: gen(function* () {
6096
+ const changeTracker = yield* service(ChangeTracker);
6097
+ const newObjectLiteral = ts.factory.createObjectLiteralExpression(
6098
+ otherProperties,
6099
+ true
6100
+ );
6101
+ const newNode = ts.factory.createCallExpression(
6102
+ ts.factory.createPropertyAccessExpression(
6103
+ // Reuse the Schema identifier from the original expression
6104
+ ts.isPropertyAccessExpression(node.expression) ? node.expression.expression : ts.factory.createIdentifier("Schema"),
6105
+ "TaggedStruct"
6106
+ ),
6107
+ void 0,
6108
+ [
6109
+ ts.factory.createStringLiteral(tagValue),
6110
+ newObjectLiteral
6111
+ ]
6112
+ );
6113
+ changeTracker.replaceNode(sourceFile, node, newNode);
6114
+ })
6115
+ }]
6116
+ });
6117
+ }
6118
+ }
6119
+ }
6120
+ }
6121
+ }
6122
+ }
6123
+ ts.forEachChild(node, appendNodeToVisit);
6124
+ }
6125
+ })
6126
+ });
6127
+
6036
6128
  // src/diagnostics/schemaUnionOfLiterals.ts
6037
6129
  var schemaUnionOfLiterals = createDiagnostic({
6038
6130
  name: "schemaUnionOfLiterals",
@@ -6724,7 +6816,8 @@ var diagnostics = [
6724
6816
  strictEffectProvide,
6725
6817
  unknownInEffectCatch,
6726
6818
  runEffectInsideEffect,
6727
- schemaUnionOfLiterals
6819
+ schemaUnionOfLiterals,
6820
+ schemaStructWithTag
6728
6821
  ];
6729
6822
 
6730
6823
  // src/transform.ts