@effect/language-service 0.58.4 → 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.
@@ -2844,67 +2844,69 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
2844
2844
  "TypeParser.effectSubtype",
2845
2845
  (type) => type
2846
2846
  );
2847
- const importedContextModule = cachedBy(
2848
- fn("TypeParser.importedContextModule")(function* (node) {
2849
- if (!ts.isIdentifier(node)) {
2850
- return yield* typeParserIssue("Node is not an identifier", void 0, node);
2851
- }
2852
- const type = typeChecker.getTypeAtLocation(node);
2853
- const propertySymbol = typeChecker.getPropertyOfType(type, "Tag");
2854
- if (!propertySymbol) {
2855
- return yield* typeParserIssue("Type has no 'Tag' property", type, node);
2856
- }
2857
- const sourceFile = tsUtils.getSourceFileOfNode(node);
2858
- if (!sourceFile) {
2859
- return yield* typeParserIssue("Node is not in a source file", void 0, node);
2860
- }
2861
- const contextIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
2862
- sourceFile,
2863
- "effect",
2864
- "Context"
2865
- );
2866
- if (!contextIdentifier) {
2867
- return yield* typeParserIssue("Context module not found", void 0, node);
2868
- }
2869
- if (ts.idText(node) !== contextIdentifier) {
2870
- return yield* typeParserIssue("Node is not a context module reference", void 0, node);
2871
- }
2872
- return node;
2847
+ const isEffectContextSourceFile = cachedBy(
2848
+ fn("TypeParser.isEffectContextSourceFile")(function* (sourceFile) {
2849
+ const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
2850
+ if (!moduleSymbol) return yield* typeParserIssue("Node has no symbol", void 0, sourceFile);
2851
+ const contextSymbol = typeChecker.tryGetMemberInModuleExports("Context", moduleSymbol);
2852
+ if (!contextSymbol) return yield* typeParserIssue("Context not found", void 0, sourceFile);
2853
+ const tagSymbol = typeChecker.tryGetMemberInModuleExports("Tag", moduleSymbol);
2854
+ if (!tagSymbol) return yield* typeParserIssue("Tag not found", void 0, sourceFile);
2855
+ const tagType = typeChecker.getDeclaredTypeOfSymbol(tagSymbol);
2856
+ yield* contextTag(tagType, sourceFile);
2857
+ return sourceFile;
2858
+ }),
2859
+ "TypeParser.isEffectContextSourceFile",
2860
+ (sourceFile) => sourceFile
2861
+ );
2862
+ const isNodeReferenceToEffectContextModuleApi = (memberName) => cachedBy(
2863
+ fn("TypeParser.isNodeReferenceToEffectContextModuleApi")(function* (node) {
2864
+ return yield* isNodeReferenceToExportOfPackageModule(node, "effect", isEffectContextSourceFile, memberName);
2873
2865
  }),
2866
+ `TypeParser.isNodeReferenceToEffectContextModuleApi(${memberName})`,
2867
+ (node) => node
2868
+ );
2869
+ const importedContextModule = cachedBy(
2870
+ (node) => pipe(
2871
+ isNodeReferenceToPackageModule(node, "effect", isEffectContextSourceFile),
2872
+ map4(() => node)
2873
+ ),
2874
2874
  "TypeParser.importedContextModule",
2875
2875
  (node) => node
2876
2876
  );
2877
- const importedEffectModule = (node) => pipe(
2878
- isNodeReferenceToPackageModule(node, "effect", isEffectTypeSourceFile),
2879
- map4(() => node)
2877
+ const importedEffectModule = cachedBy(
2878
+ (node) => pipe(
2879
+ isNodeReferenceToPackageModule(node, "effect", isEffectTypeSourceFile),
2880
+ map4(() => node)
2881
+ ),
2882
+ "TypeParser.importedEffectModule",
2883
+ (node) => node
2884
+ );
2885
+ const isEffectDataSourceFile = cachedBy(
2886
+ fn("TypeParser.isEffectDataSourceFile")(function* (sourceFile) {
2887
+ const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
2888
+ if (!moduleSymbol) return yield* typeParserIssue("Node has no symbol", void 0, sourceFile);
2889
+ const taggedEnumSymbol = typeChecker.tryGetMemberInModuleExports("TaggedEnum", moduleSymbol);
2890
+ if (!taggedEnumSymbol) return yield* typeParserIssue("TaggedEnum not found", void 0, sourceFile);
2891
+ const taggedErrorSymbol = typeChecker.tryGetMemberInModuleExports("TaggedError", moduleSymbol);
2892
+ if (!taggedErrorSymbol) return yield* typeParserIssue("TaggedError not found", void 0, sourceFile);
2893
+ return sourceFile;
2894
+ }),
2895
+ "TypeParser.isEffectDataSourceFile",
2896
+ (sourceFile) => sourceFile
2880
2897
  );
2881
- const importedDataModule = cachedBy(
2882
- fn("TypeParser.importedDataModule")(function* (node) {
2883
- if (!ts.isIdentifier(node)) {
2884
- return yield* typeParserIssue("Node is not an expression", void 0, node);
2885
- }
2886
- const type = typeChecker.getTypeAtLocation(node);
2887
- const propertySymbol = typeChecker.getPropertyOfType(type, "TaggedError");
2888
- if (!propertySymbol) {
2889
- return yield* typeParserIssue("Type has no 'TaggedError' property", type, node);
2890
- }
2891
- const sourceFile = tsUtils.getSourceFileOfNode(node);
2892
- if (!sourceFile) {
2893
- return yield* typeParserIssue("Node is not in a source file", void 0, node);
2894
- }
2895
- const dataIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
2896
- sourceFile,
2897
- "effect",
2898
- "Data"
2899
- );
2900
- if (!dataIdentifier) {
2901
- return yield* typeParserIssue("Data module not found", void 0, node);
2902
- }
2903
- if (ts.idText(node) !== dataIdentifier) {
2904
- return yield* typeParserIssue("Node is not a data module reference", void 0, node);
2905
- }
2906
- return node;
2898
+ const isNodeReferenceToEffectDataModuleApi = (memberName) => cachedBy(
2899
+ fn("TypeParser.isNodeReferenceToEffectDataModuleApi")(function* (node) {
2900
+ return yield* isNodeReferenceToExportOfPackageModule(node, "effect", isEffectDataSourceFile, memberName);
2907
2901
  }),
2902
+ `TypeParser.isNodeReferenceToEffectDataModuleApi(${memberName})`,
2903
+ (node) => node
2904
+ );
2905
+ const importedDataModule = cachedBy(
2906
+ (node) => pipe(
2907
+ isNodeReferenceToPackageModule(node, "effect", isEffectDataSourceFile),
2908
+ map4(() => node)
2909
+ ),
2908
2910
  "TypeParser.importedDataModule",
2909
2911
  (node) => node
2910
2912
  );
@@ -3643,6 +3645,8 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3643
3645
  return {
3644
3646
  isNodeReferenceToEffectModuleApi,
3645
3647
  isNodeReferenceToEffectSchemaModuleApi,
3648
+ isNodeReferenceToEffectDataModuleApi,
3649
+ isNodeReferenceToEffectContextModuleApi,
3646
3650
  effectType,
3647
3651
  strictEffectType,
3648
3652
  layerType,
@@ -6046,6 +6050,85 @@ Consider extracting the Runtime by using for example Effect.runtime and then use
6046
6050
  })
6047
6051
  });
6048
6052
 
6053
+ // src/diagnostics/schemaStructWithTag.ts
6054
+ var schemaStructWithTag = createDiagnostic({
6055
+ name: "schemaStructWithTag",
6056
+ code: 34,
6057
+ severity: "suggestion",
6058
+ apply: fn("schemaStructWithTag.apply")(function* (sourceFile, report) {
6059
+ const ts = yield* service(TypeScriptApi);
6060
+ const typeParser = yield* service(TypeParser);
6061
+ const nodeToVisit = [];
6062
+ const appendNodeToVisit = (node) => {
6063
+ nodeToVisit.push(node);
6064
+ return void 0;
6065
+ };
6066
+ ts.forEachChild(sourceFile, appendNodeToVisit);
6067
+ while (nodeToVisit.length > 0) {
6068
+ const node = nodeToVisit.shift();
6069
+ if (ts.isCallExpression(node)) {
6070
+ const isSchemaStructCall = yield* pipe(
6071
+ typeParser.isNodeReferenceToEffectSchemaModuleApi("Struct")(node.expression),
6072
+ orElse2(() => void_)
6073
+ );
6074
+ if (isSchemaStructCall && node.arguments.length === 1) {
6075
+ const arg = node.arguments[0];
6076
+ if (ts.isObjectLiteralExpression(arg)) {
6077
+ const tagProperty = arg.properties.find(
6078
+ (prop) => ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && ts.idText(prop.name) === "_tag"
6079
+ );
6080
+ if (tagProperty && ts.isCallExpression(tagProperty.initializer)) {
6081
+ const isSchemaLiteralCall = yield* pipe(
6082
+ typeParser.isNodeReferenceToEffectSchemaModuleApi("Literal")(
6083
+ tagProperty.initializer.expression
6084
+ ),
6085
+ option
6086
+ );
6087
+ if (isSchemaLiteralCall._tag === "Some") {
6088
+ const literalCall = tagProperty.initializer;
6089
+ const literalArgs = fromIterable(literalCall.arguments);
6090
+ if (literalArgs.length === 1 && ts.isStringLiteral(literalArgs[0])) {
6091
+ const tagValue = literalArgs[0].text;
6092
+ const otherProperties = arg.properties.filter((prop) => prop !== tagProperty);
6093
+ report({
6094
+ location: node,
6095
+ messageText: "Schema.Struct with a _tag field can be simplified to Schema.TaggedStruct to make the tag optional in the constructor.",
6096
+ fixes: [{
6097
+ fixName: "schemaStructWithTag_fix",
6098
+ description: "Replace with Schema.TaggedStruct",
6099
+ apply: gen(function* () {
6100
+ const changeTracker = yield* service(ChangeTracker);
6101
+ const newObjectLiteral = ts.factory.createObjectLiteralExpression(
6102
+ otherProperties,
6103
+ true
6104
+ );
6105
+ const newNode = ts.factory.createCallExpression(
6106
+ ts.factory.createPropertyAccessExpression(
6107
+ // Reuse the Schema identifier from the original expression
6108
+ ts.isPropertyAccessExpression(node.expression) ? node.expression.expression : ts.factory.createIdentifier("Schema"),
6109
+ "TaggedStruct"
6110
+ ),
6111
+ void 0,
6112
+ [
6113
+ ts.factory.createStringLiteral(tagValue),
6114
+ newObjectLiteral
6115
+ ]
6116
+ );
6117
+ changeTracker.replaceNode(sourceFile, node, newNode);
6118
+ })
6119
+ }]
6120
+ });
6121
+ }
6122
+ }
6123
+ }
6124
+ }
6125
+ }
6126
+ }
6127
+ ts.forEachChild(node, appendNodeToVisit);
6128
+ }
6129
+ })
6130
+ });
6131
+
6049
6132
  // src/diagnostics/schemaUnionOfLiterals.ts
6050
6133
  var schemaUnionOfLiterals = createDiagnostic({
6051
6134
  name: "schemaUnionOfLiterals",
@@ -6737,7 +6820,8 @@ var diagnostics = [
6737
6820
  strictEffectProvide,
6738
6821
  unknownInEffectCatch,
6739
6822
  runEffectInsideEffect,
6740
- schemaUnionOfLiterals
6823
+ schemaUnionOfLiterals,
6824
+ schemaStructWithTag
6741
6825
  ];
6742
6826
 
6743
6827
  // src/effect-lsp-patch-utils.ts