@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/README.md CHANGED
@@ -72,6 +72,7 @@ And you're done! You'll now be able to use a set of refactors and diagnostics th
72
72
  - Warn when catch callbacks in `Effect.tryPromise`, `Effect.tryMap`, or `Effect.tryMapPromise` return `unknown` or `any` types
73
73
  - Warn when using `Effect.runSync`, `Effect.runPromise`, `Effect.runFork`, or `Effect.runCallback` inside an Effect
74
74
  - Warn when using `Schema.Union` with multiple `Schema.Literal` calls that can be simplified to a single `Schema.Literal` call
75
+ - Suggest using `Schema.TaggedStruct` instead of `Schema.Struct` when a `_tag` field with `Schema.Literal` is present to make the tag optional in the constructor
75
76
  - Warn when using `yield* Effect.fail()` with yieldable error types that can be yielded directly
76
77
 
77
78
  ### Completions
package/cli.js CHANGED
@@ -32065,7 +32065,16 @@ function make64(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
32065
32065
  const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
32066
32066
  if (!moduleSymbol) continue;
32067
32067
  const memberSymbol = typeChecker.tryGetMemberInModuleExports(memberName, moduleSymbol);
32068
- if (memberSymbol && memberSymbol === symbol3) result.push({ memberSymbol, moduleSymbol, sourceFile });
32068
+ if (memberSymbol) {
32069
+ if (memberSymbol === symbol3) {
32070
+ result.push({ memberSymbol, moduleSymbol, sourceFile });
32071
+ } else if (memberSymbol.flags & ts.SymbolFlags.Alias) {
32072
+ const aliased = typeChecker.getAliasedSymbol(memberSymbol);
32073
+ if (aliased === symbol3) {
32074
+ result.push({ memberSymbol, moduleSymbol, sourceFile });
32075
+ }
32076
+ }
32077
+ }
32069
32078
  }
32070
32079
  if (result.length > 0) {
32071
32080
  return result;
@@ -32320,67 +32329,69 @@ function make64(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
32320
32329
  "TypeParser.effectSubtype",
32321
32330
  (type2) => type2
32322
32331
  );
32323
- const importedContextModule = cachedBy(
32324
- fn2("TypeParser.importedContextModule")(function* (node) {
32325
- if (!ts.isIdentifier(node)) {
32326
- return yield* typeParserIssue("Node is not an identifier", void 0, node);
32327
- }
32328
- const type2 = typeChecker.getTypeAtLocation(node);
32329
- const propertySymbol = typeChecker.getPropertyOfType(type2, "Tag");
32330
- if (!propertySymbol) {
32331
- return yield* typeParserIssue("Type has no 'Tag' property", type2, node);
32332
- }
32333
- const sourceFile = tsUtils.getSourceFileOfNode(node);
32334
- if (!sourceFile) {
32335
- return yield* typeParserIssue("Node is not in a source file", void 0, node);
32336
- }
32337
- const contextIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
32338
- sourceFile,
32339
- "effect",
32340
- "Context"
32341
- );
32342
- if (!contextIdentifier) {
32343
- return yield* typeParserIssue("Context module not found", void 0, node);
32344
- }
32345
- if (ts.idText(node) !== contextIdentifier) {
32346
- return yield* typeParserIssue("Node is not a context module reference", void 0, node);
32347
- }
32348
- return node;
32332
+ const isEffectContextSourceFile = cachedBy(
32333
+ fn2("TypeParser.isEffectContextSourceFile")(function* (sourceFile) {
32334
+ const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
32335
+ if (!moduleSymbol) return yield* typeParserIssue("Node has no symbol", void 0, sourceFile);
32336
+ const contextSymbol = typeChecker.tryGetMemberInModuleExports("Context", moduleSymbol);
32337
+ if (!contextSymbol) return yield* typeParserIssue("Context not found", void 0, sourceFile);
32338
+ const tagSymbol = typeChecker.tryGetMemberInModuleExports("Tag", moduleSymbol);
32339
+ if (!tagSymbol) return yield* typeParserIssue("Tag not found", void 0, sourceFile);
32340
+ const tagType = typeChecker.getDeclaredTypeOfSymbol(tagSymbol);
32341
+ yield* contextTag(tagType, sourceFile);
32342
+ return sourceFile;
32343
+ }),
32344
+ "TypeParser.isEffectContextSourceFile",
32345
+ (sourceFile) => sourceFile
32346
+ );
32347
+ const isNodeReferenceToEffectContextModuleApi = (memberName) => cachedBy(
32348
+ fn2("TypeParser.isNodeReferenceToEffectContextModuleApi")(function* (node) {
32349
+ return yield* isNodeReferenceToExportOfPackageModule(node, "effect", isEffectContextSourceFile, memberName);
32349
32350
  }),
32351
+ `TypeParser.isNodeReferenceToEffectContextModuleApi(${memberName})`,
32352
+ (node) => node
32353
+ );
32354
+ const importedContextModule = cachedBy(
32355
+ (node) => pipe(
32356
+ isNodeReferenceToPackageModule(node, "effect", isEffectContextSourceFile),
32357
+ map34(() => node)
32358
+ ),
32350
32359
  "TypeParser.importedContextModule",
32351
32360
  (node) => node
32352
32361
  );
32353
- const importedEffectModule = (node) => pipe(
32354
- isNodeReferenceToPackageModule(node, "effect", isEffectTypeSourceFile),
32355
- map34(() => node)
32362
+ const importedEffectModule = cachedBy(
32363
+ (node) => pipe(
32364
+ isNodeReferenceToPackageModule(node, "effect", isEffectTypeSourceFile),
32365
+ map34(() => node)
32366
+ ),
32367
+ "TypeParser.importedEffectModule",
32368
+ (node) => node
32356
32369
  );
32357
- const importedDataModule = cachedBy(
32358
- fn2("TypeParser.importedDataModule")(function* (node) {
32359
- if (!ts.isIdentifier(node)) {
32360
- return yield* typeParserIssue("Node is not an expression", void 0, node);
32361
- }
32362
- const type2 = typeChecker.getTypeAtLocation(node);
32363
- const propertySymbol = typeChecker.getPropertyOfType(type2, "TaggedError");
32364
- if (!propertySymbol) {
32365
- return yield* typeParserIssue("Type has no 'TaggedError' property", type2, node);
32366
- }
32367
- const sourceFile = tsUtils.getSourceFileOfNode(node);
32368
- if (!sourceFile) {
32369
- return yield* typeParserIssue("Node is not in a source file", void 0, node);
32370
- }
32371
- const dataIdentifier = tsUtils.findImportedModuleIdentifierByPackageAndNameOrBarrel(
32372
- sourceFile,
32373
- "effect",
32374
- "Data"
32375
- );
32376
- if (!dataIdentifier) {
32377
- return yield* typeParserIssue("Data module not found", void 0, node);
32378
- }
32379
- if (ts.idText(node) !== dataIdentifier) {
32380
- return yield* typeParserIssue("Node is not a data module reference", void 0, node);
32381
- }
32382
- return node;
32370
+ const isEffectDataSourceFile = cachedBy(
32371
+ fn2("TypeParser.isEffectDataSourceFile")(function* (sourceFile) {
32372
+ const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
32373
+ if (!moduleSymbol) return yield* typeParserIssue("Node has no symbol", void 0, sourceFile);
32374
+ const taggedEnumSymbol = typeChecker.tryGetMemberInModuleExports("TaggedEnum", moduleSymbol);
32375
+ if (!taggedEnumSymbol) return yield* typeParserIssue("TaggedEnum not found", void 0, sourceFile);
32376
+ const taggedErrorSymbol = typeChecker.tryGetMemberInModuleExports("TaggedError", moduleSymbol);
32377
+ if (!taggedErrorSymbol) return yield* typeParserIssue("TaggedError not found", void 0, sourceFile);
32378
+ return sourceFile;
32383
32379
  }),
32380
+ "TypeParser.isEffectDataSourceFile",
32381
+ (sourceFile) => sourceFile
32382
+ );
32383
+ const isNodeReferenceToEffectDataModuleApi = (memberName) => cachedBy(
32384
+ fn2("TypeParser.isNodeReferenceToEffectDataModuleApi")(function* (node) {
32385
+ return yield* isNodeReferenceToExportOfPackageModule(node, "effect", isEffectDataSourceFile, memberName);
32386
+ }),
32387
+ `TypeParser.isNodeReferenceToEffectDataModuleApi(${memberName})`,
32388
+ (node) => node
32389
+ );
32390
+ const importedDataModule = cachedBy(
32391
+ (node) => pipe(
32392
+ isNodeReferenceToPackageModule(node, "effect", isEffectDataSourceFile),
32393
+ map34(() => node)
32394
+ ),
32384
32395
  "TypeParser.importedDataModule",
32385
32396
  (node) => node
32386
32397
  );
@@ -33119,6 +33130,8 @@ function make64(ts, tsUtils, typeChecker, typeCheckerUtils, program) {
33119
33130
  return {
33120
33131
  isNodeReferenceToEffectModuleApi,
33121
33132
  isNodeReferenceToEffectSchemaModuleApi,
33133
+ isNodeReferenceToEffectDataModuleApi,
33134
+ isNodeReferenceToEffectContextModuleApi,
33122
33135
  effectType,
33123
33136
  strictEffectType,
33124
33137
  layerType,
@@ -33467,7 +33480,7 @@ var annotate3 = createCodegen({
33467
33480
  const initializerTypeNode = fromNullable(typeCheckerUtils.typeToSimplifiedTypeNode(
33468
33481
  initializerType,
33469
33482
  enclosingNode,
33470
- ts.NodeBuilderFlags.NoTruncation
33483
+ ts.NodeBuilderFlags.NoTruncation | ts.NodeBuilderFlags.IgnoreErrors
33471
33484
  )).pipe(
33472
33485
  getOrUndefined
33473
33486
  );
@@ -35671,6 +35684,85 @@ Consider extracting the Runtime by using for example Effect.runtime and then use
35671
35684
  })
35672
35685
  });
35673
35686
 
35687
+ // src/diagnostics/schemaStructWithTag.ts
35688
+ var schemaStructWithTag = createDiagnostic({
35689
+ name: "schemaStructWithTag",
35690
+ code: 34,
35691
+ severity: "suggestion",
35692
+ apply: fn2("schemaStructWithTag.apply")(function* (sourceFile, report) {
35693
+ const ts = yield* service2(TypeScriptApi);
35694
+ const typeParser = yield* service2(TypeParser);
35695
+ const nodeToVisit = [];
35696
+ const appendNodeToVisit = (node) => {
35697
+ nodeToVisit.push(node);
35698
+ return void 0;
35699
+ };
35700
+ ts.forEachChild(sourceFile, appendNodeToVisit);
35701
+ while (nodeToVisit.length > 0) {
35702
+ const node = nodeToVisit.shift();
35703
+ if (ts.isCallExpression(node)) {
35704
+ const isSchemaStructCall = yield* pipe(
35705
+ typeParser.isNodeReferenceToEffectSchemaModuleApi("Struct")(node.expression),
35706
+ orElse14(() => void_8)
35707
+ );
35708
+ if (isSchemaStructCall && node.arguments.length === 1) {
35709
+ const arg = node.arguments[0];
35710
+ if (ts.isObjectLiteralExpression(arg)) {
35711
+ const tagProperty = arg.properties.find(
35712
+ (prop) => ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name) && ts.idText(prop.name) === "_tag"
35713
+ );
35714
+ if (tagProperty && ts.isCallExpression(tagProperty.initializer)) {
35715
+ const isSchemaLiteralCall = yield* pipe(
35716
+ typeParser.isNodeReferenceToEffectSchemaModuleApi("Literal")(
35717
+ tagProperty.initializer.expression
35718
+ ),
35719
+ option4
35720
+ );
35721
+ if (isSchemaLiteralCall._tag === "Some") {
35722
+ const literalCall = tagProperty.initializer;
35723
+ const literalArgs = fromIterable(literalCall.arguments);
35724
+ if (literalArgs.length === 1 && ts.isStringLiteral(literalArgs[0])) {
35725
+ const tagValue = literalArgs[0].text;
35726
+ const otherProperties = arg.properties.filter((prop) => prop !== tagProperty);
35727
+ report({
35728
+ location: node,
35729
+ messageText: "Schema.Struct with a _tag field can be simplified to Schema.TaggedStruct to make the tag optional in the constructor.",
35730
+ fixes: [{
35731
+ fixName: "schemaStructWithTag_fix",
35732
+ description: "Replace with Schema.TaggedStruct",
35733
+ apply: gen3(function* () {
35734
+ const changeTracker = yield* service2(ChangeTracker);
35735
+ const newObjectLiteral = ts.factory.createObjectLiteralExpression(
35736
+ otherProperties,
35737
+ true
35738
+ );
35739
+ const newNode = ts.factory.createCallExpression(
35740
+ ts.factory.createPropertyAccessExpression(
35741
+ // Reuse the Schema identifier from the original expression
35742
+ ts.isPropertyAccessExpression(node.expression) ? node.expression.expression : ts.factory.createIdentifier("Schema"),
35743
+ "TaggedStruct"
35744
+ ),
35745
+ void 0,
35746
+ [
35747
+ ts.factory.createStringLiteral(tagValue),
35748
+ newObjectLiteral
35749
+ ]
35750
+ );
35751
+ changeTracker.replaceNode(sourceFile, node, newNode);
35752
+ })
35753
+ }]
35754
+ });
35755
+ }
35756
+ }
35757
+ }
35758
+ }
35759
+ }
35760
+ }
35761
+ ts.forEachChild(node, appendNodeToVisit);
35762
+ }
35763
+ })
35764
+ });
35765
+
35674
35766
  // src/diagnostics/schemaUnionOfLiterals.ts
35675
35767
  var schemaUnionOfLiterals = createDiagnostic({
35676
35768
  name: "schemaUnionOfLiterals",
@@ -36362,7 +36454,8 @@ var diagnostics = [
36362
36454
  strictEffectProvide,
36363
36455
  unknownInEffectCatch,
36364
36456
  runEffectInsideEffect,
36365
- schemaUnionOfLiterals
36457
+ schemaUnionOfLiterals,
36458
+ schemaStructWithTag
36366
36459
  ];
36367
36460
 
36368
36461
  // src/cli/diagnostics.ts