@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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect/language-service",
3
- "version": "0.58.4",
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
@@ -2840,67 +2840,69 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
2840
2840
  "TypeParser.effectSubtype",
2841
2841
  (type) => type
2842
2842
  );
2843
- const importedContextModule = cachedBy(
2844
- fn("TypeParser.importedContextModule")(function* (node) {
2845
- if (!ts.isIdentifier(node)) {
2846
- return yield* typeParserIssue("Node is not an identifier", void 0, node);
2847
- }
2848
- const type = typeChecker.getTypeAtLocation(node);
2849
- const propertySymbol = typeChecker.getPropertyOfType(type, "Tag");
2850
- if (!propertySymbol) {
2851
- return yield* typeParserIssue("Type has no 'Tag' property", type, node);
2852
- }
2853
- const sourceFile = tsUtils.getSourceFileOfNode(node);
2854
- if (!sourceFile) {
2855
- return yield* typeParserIssue("Node is not in a source file", void 0, node);
2856
- }
2857
- const contextIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
2858
- sourceFile,
2859
- "effect",
2860
- "Context"
2861
- );
2862
- if (!contextIdentifier) {
2863
- return yield* typeParserIssue("Context module not found", void 0, node);
2864
- }
2865
- if (ts.idText(node) !== contextIdentifier) {
2866
- return yield* typeParserIssue("Node is not a context module reference", void 0, node);
2867
- }
2868
- 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);
2869
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
+ ),
2870
2870
  "TypeParser.importedContextModule",
2871
2871
  (node) => node
2872
2872
  );
2873
- const importedEffectModule = (node) => pipe(
2874
- isNodeReferenceToPackageModule(node, "effect", isEffectTypeSourceFile),
2875
- map4(() => node)
2873
+ const importedEffectModule = cachedBy(
2874
+ (node) => pipe(
2875
+ isNodeReferenceToPackageModule(node, "effect", isEffectTypeSourceFile),
2876
+ map4(() => node)
2877
+ ),
2878
+ "TypeParser.importedEffectModule",
2879
+ (node) => node
2880
+ );
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;
2890
+ }),
2891
+ "TypeParser.isEffectDataSourceFile",
2892
+ (sourceFile) => sourceFile
2876
2893
  );
2877
- const importedDataModule = cachedBy(
2878
- fn("TypeParser.importedDataModule")(function* (node) {
2879
- if (!ts.isIdentifier(node)) {
2880
- return yield* typeParserIssue("Node is not an expression", void 0, node);
2881
- }
2882
- const type = typeChecker.getTypeAtLocation(node);
2883
- const propertySymbol = typeChecker.getPropertyOfType(type, "TaggedError");
2884
- if (!propertySymbol) {
2885
- return yield* typeParserIssue("Type has no 'TaggedError' property", type, node);
2886
- }
2887
- const sourceFile = tsUtils.getSourceFileOfNode(node);
2888
- if (!sourceFile) {
2889
- return yield* typeParserIssue("Node is not in a source file", void 0, node);
2890
- }
2891
- const dataIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
2892
- sourceFile,
2893
- "effect",
2894
- "Data"
2895
- );
2896
- if (!dataIdentifier) {
2897
- return yield* typeParserIssue("Data module not found", void 0, node);
2898
- }
2899
- if (ts.idText(node) !== dataIdentifier) {
2900
- return yield* typeParserIssue("Node is not a data module reference", void 0, node);
2901
- }
2902
- return node;
2894
+ const isNodeReferenceToEffectDataModuleApi = (memberName) => cachedBy(
2895
+ fn("TypeParser.isNodeReferenceToEffectDataModuleApi")(function* (node) {
2896
+ return yield* isNodeReferenceToExportOfPackageModule(node, "effect", isEffectDataSourceFile, memberName);
2903
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
+ ),
2904
2906
  "TypeParser.importedDataModule",
2905
2907
  (node) => node
2906
2908
  );
@@ -3639,6 +3641,8 @@ function make2(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
3639
3641
  return {
3640
3642
  isNodeReferenceToEffectModuleApi,
3641
3643
  isNodeReferenceToEffectSchemaModuleApi,
3644
+ isNodeReferenceToEffectDataModuleApi,
3645
+ isNodeReferenceToEffectContextModuleApi,
3642
3646
  effectType,
3643
3647
  strictEffectType,
3644
3648
  layerType,
@@ -6042,6 +6046,85 @@ Consider extracting the Runtime by using for example Effect.runtime and then use
6042
6046
  })
6043
6047
  });
6044
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
+
6045
6128
  // src/diagnostics/schemaUnionOfLiterals.ts
6046
6129
  var schemaUnionOfLiterals = createDiagnostic({
6047
6130
  name: "schemaUnionOfLiterals",
@@ -6733,7 +6816,8 @@ var diagnostics = [
6733
6816
  strictEffectProvide,
6734
6817
  unknownInEffectCatch,
6735
6818
  runEffectInsideEffect,
6736
- schemaUnionOfLiterals
6819
+ schemaUnionOfLiterals,
6820
+ schemaStructWithTag
6737
6821
  ];
6738
6822
 
6739
6823
  // src/transform.ts